Migrate from urfave/cli to cobra (#1385)

This commit is contained in:
Ta-Ching Chen
2019-11-08 21:22:00 +08:00
committed by GitHub
parent 4b456db517
commit 1888cd2ac7
66 changed files with 2901 additions and 1130 deletions
+68
View File
@@ -0,0 +1,68 @@
package app
import (
"github.com/spf13/cobra"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra/helptemplate"
"github.com/fission/fission/pkg/fission-cli/cmd/canaryconfig"
"github.com/fission/fission/pkg/fission-cli/cmd/environment"
"github.com/fission/fission/pkg/fission-cli/cmd/function"
"github.com/fission/fission/pkg/fission-cli/cmd/httptrigger"
"github.com/fission/fission/pkg/fission-cli/cmd/kubewatch"
"github.com/fission/fission/pkg/fission-cli/cmd/mqtrigger"
_package "github.com/fission/fission/pkg/fission-cli/cmd/package"
"github.com/fission/fission/pkg/fission-cli/cmd/spec"
"github.com/fission/fission/pkg/fission-cli/cmd/support"
"github.com/fission/fission/pkg/fission-cli/cmd/timetrigger"
"github.com/fission/fission/pkg/fission-cli/cmd/version"
"github.com/fission/fission/pkg/fission-cli/console"
"github.com/fission/fission/pkg/fission-cli/flag"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
)
const (
usage = `Fission: Fast and Simple Serverless Functions for Kubernetes
* Github: https://github.com/fission/fission
* Documentation: https://docs.fission.io/docs
`
)
func App() *cobra.Command {
rootCmd := &cobra.Command{
Use: "fission",
Long: usage,
//SilenceUsage: true,
PreRunE: wrapper.Wrapper(
func(flags cli.Input) error {
console.Verbosity = flags.Int(flagkey.Verbosity)
return nil
},
),
}
// Workaround fix for not to show help command
// https://github.com/spf13/cobra/issues/587
rootCmd.SetHelpCommand(&cobra.Command{
Use: "no-help",
Hidden: true,
})
wrapper.SetFlags(rootCmd, flag.FlagSet{
Optional: []flag.Flag{flag.GlobalServerFlag, flag.GlobalVerbosityFlag},
})
groups := helptemplate.CommandGroups{}
groups = append(groups, helptemplate.CreateCmdGroup("Basic Commands", environment.Commands(), _package.Commands(), function.Commands()))
groups = append(groups, helptemplate.CreateCmdGroup("Trigger Commands", httptrigger.Commands(), mqtrigger.Commands(), timetrigger.Commands(), kubewatch.Commands()))
groups = append(groups, helptemplate.CreateCmdGroup("Deploy Strategies Commands", canaryconfig.Commands()))
groups = append(groups, helptemplate.CreateCmdGroup("Declarative Application Commands", spec.Commands()))
groups = append(groups, helptemplate.CreateCmdGroup("Other Commands", support.Commands(), version.Commands()))
groups.Add(rootCmd)
helptemplate.ActsAsRootCommand(rootCmd, nil, groups...)
return rootCmd
}
+2 -9
View File
@@ -17,16 +17,9 @@ limitations under the License.
package main
import (
"fmt"
"os"
fcli "github.com/fission/fission/pkg/fission-cli"
"github.com/fission/fission/cmd/fission-cli/app"
)
func main() {
err := fcli.NewCliApp().Run(os.Args)
if err != nil {
fmt.Printf("Error: %v\n", err.Error())
os.Exit(1)
}
app.App().Execute()
}
+5 -2
View File
@@ -40,7 +40,10 @@ require (
github.com/imdario/mergo v0.3.5
github.com/influxdata/influxdb v1.2.0
github.com/kr/pretty v0.1.0 // indirect
github.com/life1347/color v1.7.0
github.com/marstr/guid v0.0.0-20170427235115-8bdf7d1a087c // indirect
github.com/mattn/go-colorable v0.1.4 // indirect
github.com/mattn/go-isatty v0.0.10 // indirect
github.com/mholt/archiver v0.0.0-20180417220235-e4ef56d48eb0
github.com/nats-io/gnatsd v1.4.1 // indirect
github.com/nats-io/go-nats v1.6.0 // indirect
@@ -56,7 +59,8 @@ require (
github.com/prometheus/common v0.4.1
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967
github.com/satori/go.uuid v1.2.0
github.com/spf13/pflag v1.0.3
github.com/spf13/cobra v0.0.5
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.3.0
github.com/ulikunitz/xz v0.0.0-20180703112113-636d36a76670 // indirect
github.com/urfave/cli v1.20.0
@@ -69,7 +73,6 @@ require (
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 // indirect
golang.org/x/image v0.0.0-20190618124811-92942e4437e2 // indirect
golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b
golang.org/x/sys v0.0.0-20190619183051-17bc6164aac4 // indirect
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
google.golang.org/appengine v1.6.1 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
+34 -2
View File
@@ -31,6 +31,7 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/apache/thrift v0.12.0 h1:pODnxUFNcjP9UTLZGTdeh+j16A8lJbRvD3rOtrk/7bs=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
@@ -46,11 +47,15 @@ github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyV
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-oidc v0.0.0-20180117170138-065b426bd416/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.0.0-20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -188,12 +193,14 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/raft v1.0.0 h1:htBVktAOtGs4Le5Z7K8SF5H2+oWsQFYVmOgH5loro7Y=
github.com/hashicorp/raft v1.0.0/go.mod h1:DVSAWItjLjTOkVbSpWQ0j0kUADIvDaCtBxIcbNAQLkI=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb v1.2.0 h1:ZSB1cdZP9/8yyFzZhyaHimPL55Qo2kRDv2VhgnCePJ4=
github.com/influxdata/influxdb v1.2.0/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
@@ -214,15 +221,24 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/life1347/color v1.7.0 h1:Csr56ts64td/iG9T9o4p9cXNK46YB1/ZSq3V+qDwD4Y=
github.com/life1347/color v1.7.0/go.mod h1:yXW8vSPZhOJLmveaa6cN+24V2xrX2Cuf3X7nVpiRidw=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20180323154445-8b799c424f57/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/marstr/guid v0.0.0-20170427235115-8bdf7d1a087c h1:N7uWGS2fTwH/4BwxbHiJZNAFTSJ5yPU0emHsQWvkxEY=
github.com/marstr/guid v0.0.0-20170427235115-8bdf7d1a087c/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mholt/archiver v0.0.0-20180417220235-e4ef56d48eb0 h1:581DnhoG2Q33rqM3X6Is+8agf17B2vlzV/H52/Xvcd0=
github.com/mholt/archiver v0.0.0-20180417220235-e4ef56d48eb0/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -257,6 +273,7 @@ github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJ
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
@@ -288,14 +305,24 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967 h1:x7xEyJDP7Hv3LVgvWhzioQqbC/KtuUhTigKlH/8ehhE=
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.0-20180319062004-c439c4fa0937 h1:+ryWjMVzFAkEz5zT+Ms49aROZwxlJce3x3zLTFpkz3Y=
github.com/spf13/cobra v0.0.0-20180319062004-c439c4fa0937/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -303,6 +330,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ulikunitz/xz v0.0.0-20180703112113-636d36a76670 h1:HQWT4ta3wW5GZ790GaqLCS+w1dvuA3rMfEQxLi+UOYU=
github.com/ulikunitz/xz v0.0.0-20180703112113-636d36a76670/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
@@ -310,6 +338,7 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb
github.com/wcharczuk/go-chart v2.0.1+incompatible h1:0pz39ZAycJFF7ju/1mepnk26RLVLBCWz1STcD3doU0A=
github.com/wcharczuk/go-chart v2.0.1+incompatible/go.mod h1:PF5tmL4EIx/7Wf+hEkpCqYi5He4u90sw+0+6FhrryuE=
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
@@ -327,6 +356,7 @@ go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -379,15 +409,17 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190619183051-17bc6164aac4 h1:FFQWNXvutleFrNfNdz+TAJiRUdRxjFpjBtDMQ2y3psA=
golang.org/x/sys v0.0.0-20190619183051-17bc6164aac4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+5 -1
View File
@@ -421,7 +421,11 @@ func (spec EnvironmentSpec) Validate() error {
}
if spec.Poolsize < 0 {
result = multierror.Append(result, MakeValidationErr(ErrorInvalidValue, "EnvironmentSpec.Poolsize", spec.Poolsize, "Poolsize must be greater or equal to 0"))
result = multierror.Append(result, MakeValidationErr(ErrorInvalidValue, "EnvironmentSpec.Poolsize", spec.Poolsize, "must be greater or equal to 0"))
}
if spec.TerminationGracePeriod < 0 {
result = multierror.Append(result, MakeValidationErr(ErrorInvalidValue, "EnvironmentSpec.TerminationGracePeriod", spec.TerminationGracePeriod, "must be greater or equal to 0"))
}
return result.ErrorOrNil()
-464
View File
@@ -1,464 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fission_cli
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
"github.com/pkg/errors"
"github.com/urfave/cli"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/urfavecli"
"github.com/fission/fission/pkg/fission-cli/cmd/canaryconfig"
"github.com/fission/fission/pkg/fission-cli/cmd/environment"
"github.com/fission/fission/pkg/fission-cli/cmd/function"
"github.com/fission/fission/pkg/fission-cli/cmd/httptrigger"
"github.com/fission/fission/pkg/fission-cli/cmd/kubewatch"
"github.com/fission/fission/pkg/fission-cli/cmd/mqtrigger"
_package "github.com/fission/fission/pkg/fission-cli/cmd/package"
plugincmd "github.com/fission/fission/pkg/fission-cli/cmd/plugin"
"github.com/fission/fission/pkg/fission-cli/cmd/recorder"
"github.com/fission/fission/pkg/fission-cli/cmd/records"
"github.com/fission/fission/pkg/fission-cli/cmd/replay"
"github.com/fission/fission/pkg/fission-cli/cmd/spec"
"github.com/fission/fission/pkg/fission-cli/cmd/support"
"github.com/fission/fission/pkg/fission-cli/cmd/timetrigger"
"github.com/fission/fission/pkg/fission-cli/cmd/version"
"github.com/fission/fission/pkg/fission-cli/consolemsg"
"github.com/fission/fission/pkg/fission-cli/flag"
"github.com/fission/fission/pkg/info"
"github.com/fission/fission/pkg/plugin"
"github.com/fission/fission/pkg/types"
)
func cliHook(c *cli.Context) error {
consolemsg.Verbosity = c.Int("verbosity")
consolemsg.Verbose(2, "Verbosity = 2")
return flagValueParser(c.Args())
}
func NewCliApp() *cli.App {
app := cli.NewApp()
app.Name = "fission"
app.Usage = "Serverless functions for Kubernetes"
app.HideVersion = true
app.CustomAppHelpTemplate = helpTemplate
app.ExtraInfo = func() map[string]string {
pluginInfo := map[string]string{}
for _, pmd := range plugin.FindAll() {
names := strings.Join(append([]string{pmd.Name}, pmd.Aliases...), ", ")
pluginInfo[names] = pmd.Usage
}
return pluginInfo
}
app.Flags = []cli.Flag{
cli.StringFlag{Name: flag.FISSION_SERVER, Value: "", Usage: "Fission server URL"},
cli.IntFlag{Name: flag.GLOBAL_VERBOSITY, Value: 1, Usage: "CLI verbosity (0 is quiet, 1 is the default, 2 is verbose.)"},
cli.BoolFlag{Name: flag.GLOBAL_PLUGIN, Hidden: true},
}
// all resource create commands accept --spec
specSaveFlag := cli.BoolFlag{Name: "spec", Usage: "Save to the spec directory instead of creating on cluster"}
// namespace reference for all objects
fnNamespaceFlag := cli.StringFlag{Name: "fnNamespace, fns", Value: metav1.NamespaceDefault, Usage: "Namespace for function object"}
envNamespaceFlag := cli.StringFlag{Name: flag.GetCliFlagName(flag.ENVIRONMENT_NAMESPACE, flag.ENVIRONMENT_NAMESPACE_ALIAS), Value: metav1.NamespaceDefault, Usage: "Namespace for environment object"}
pkgNamespaceFlag := cli.StringFlag{Name: "pkgNamespace, pkgns", Value: metav1.NamespaceDefault, Usage: "Namespace for package object"}
triggerNamespaceFlag := cli.StringFlag{Name: "triggerNamespace, triggerns", Value: metav1.NamespaceDefault, Usage: "Namespace for trigger object"}
recorderNamespaceFlag := cli.StringFlag{Name: "recorderNamespace, recorderns", Value: metav1.NamespaceDefault, Usage: "Namespace for recorder object"}
canaryNamespaceFlag := cli.StringFlag{Name: "canaryNamespace, canaryns", Value: metav1.NamespaceDefault, Usage: "Namespace for canary config object"}
// trigger method and url flags (used in function and route CLIs)
htMethodFlag := cli.StringFlag{Name: "method", Value: http.MethodGet, Usage: "HTTP Method: GET|POST|PUT|DELETE|HEAD"}
htUrlFlag := cli.StringFlag{Name: "url", Usage: "URL pattern (See gorilla/mux supported patterns)"}
// Resource & scale related flags (Used in env and function)
minCpu := cli.IntFlag{Name: flag.RUNTIME_MINCPU, Usage: "Minimum CPU to be assigned to pod (In millicore, minimum 1)"}
maxCpu := cli.IntFlag{Name: flag.RUNTIME_MAXCPU, Usage: "Maximum CPU to be assigned to pod (In millicore, minimum 1)"}
minMem := cli.IntFlag{Name: flag.RUNTIME_MINMEMORY, Usage: "Minimum memory to be assigned to pod (In megabyte)"}
maxMem := cli.IntFlag{Name: flag.RUNTIME_MAXMEMORY, Usage: "Maximum memory to be assigned to pod (In megabyte)"}
minScale := cli.IntFlag{Name: flag.RUNTIME_MINSCALE, Usage: "Minimum number of pods (Uses resource inputs to configure HPA)"}
maxScale := cli.IntFlag{Name: flag.RUNTIME_MAXSCALE, Usage: "Maximum number of pods (Uses resource inputs to configure HPA)"}
targetcpu := cli.IntFlag{Name: flag.RUNTIME_TARGETCPU, Usage: "Target average CPU usage percentage across pods for scaling"}
specializationTimeoutFlag := cli.IntFlag{Name: "specializationtimeout, st", Value: 120, Usage: "Timeout for newdeploy to wait for function pod creation"}
// functions
fnNameFlag := cli.StringFlag{Name: "name", Usage: "function name"}
fnEnvNameFlag := cli.StringFlag{Name: "env", Usage: "environment name for function"}
fnCodeFlag := cli.StringFlag{Name: "code", Usage: "local path or URL for single file source code"}
fnDeployArchiveFlag := cli.StringSliceFlag{Name: "deployarchive, deploy", Usage: "local path or URL for deployment archive"}
fnSrcArchiveFlag := cli.StringSliceFlag{Name: "sourcearchive, src, source", Usage: "local path or URL for source archive"}
fnKeepURLFlag := cli.BoolFlag{Name: "keeparchiveurl, keepurl", Usage: "Keep the providing URL in archive instead of downloading file from it. (If set, no checksum will be generated for file integrity check. You must ensure the file won't be changed.)"}
fnPkgNameFlag := cli.StringFlag{Name: "pkgname, pkg", Usage: "Name of the existing package (--deploy and --src and --env will be ignored), should be in the same namespace as the function"}
fnPodFlag := cli.StringFlag{Name: "pod", Usage: "function pod name, optional (use latest if unspecified)"}
fnFollowFlag := cli.BoolFlag{Name: "follow, f", Usage: "specify if the logs should be streamed"}
fnDetailFlag := cli.BoolFlag{Name: "detail, d", Usage: "display detailed information"}
fnLogDBTypeFlag := cli.StringFlag{Name: "dbtype", Usage: "log database type, e.g. influxdb (currently only influxdb is supported)"}
fnBodyFlag := cli.StringFlag{Name: "body, b", Usage: "request body"}
fnHeaderFlag := cli.StringSliceFlag{Name: "header, H", Usage: "request headers"}
fnQueryFlag := cli.StringSliceFlag{Name: "query, q", Usage: "request query parameters: -q key1=value1 -q key2=value2"}
fnEntryPointFlag := cli.StringFlag{Name: "entrypoint", Usage: "entry point for environment v2 to load with"}
fnBuildCmdFlag := cli.StringFlag{Name: "buildcmd", Usage: "build command for builder to run with"}
fnSecretFlag := cli.StringSliceFlag{Name: "secret", Usage: "function access to secret, should be present in the same namespace as the function. You can provide multiple secrets using multiple --secrets flags. In the case of fn update the the secrets will be replaced by the provided list of secrets."}
fnCfgMapFlag := cli.StringSliceFlag{Name: "configmap", Usage: "function access to configmap, should be present in the same namespace as the function. You can provide multiple configmaps using multiple --configmap flags. In case of fn update the configmaps will be replaced by the provided list of configmaps."}
fnLogReverseQueryFlag := cli.BoolFlag{Name: "reverse, r", Usage: "specify the log reverse query base on time, it will be invalid if the 'follow' flag is specified"}
fnLogCountFlag := cli.StringFlag{Name: "recordcount", Usage: "the n most recent log records"}
fnForceFlag := cli.BoolFlag{Name: "force", Usage: "Force update a package even if it is used by one or more functions"}
fnExecutorTypeFlag := cli.StringFlag{Name: "executortype", Value: types.ExecutorTypePoolmgr, Usage: "Executor type for execution; one of 'poolmgr', 'newdeploy' defaults to 'poolmgr'"}
fnExecutionTimeoutFlag := cli.IntFlag{Name: "fntimeout, ft", Value: 60, Usage: "Time duration to wait for the response while executing the function. If the flag is not provided, by default it will wait of 60s for the response."}
fnTimeoutFlag := cli.DurationFlag{Name: "timeout, t", Value: 30 * time.Second, Usage: "The length of time to wait for the response. If set to zero or negative number, no timeout is set."}
fnSubcommands := []cli.Command{
{Name: "create", Usage: "Create new function (and optionally, an HTTP route to it)", Flags: []cli.Flag{fnNameFlag, fnNamespaceFlag, fnEnvNameFlag, envNamespaceFlag, specSaveFlag, fnCodeFlag, fnSrcArchiveFlag, fnDeployArchiveFlag, fnKeepURLFlag, fnEntryPointFlag, fnBuildCmdFlag, fnPkgNameFlag, htUrlFlag, htMethodFlag, minCpu, maxCpu, minMem, maxMem, minScale, maxScale, fnExecutorTypeFlag, targetcpu, fnCfgMapFlag, fnSecretFlag, specializationTimeoutFlag, fnExecutionTimeoutFlag}, Action: urfavecli.Wrapper(function.Create)},
{Name: "get", Usage: "Get function source code", Flags: []cli.Flag{fnNameFlag, fnNamespaceFlag}, Action: urfavecli.Wrapper(function.Get)},
{Name: "getmeta", Usage: "Get function metadata", Flags: []cli.Flag{fnNameFlag, fnNamespaceFlag}, Action: urfavecli.Wrapper(function.GetMeta)},
{Name: "update", Usage: "Update function source code", Flags: []cli.Flag{fnNameFlag, fnNamespaceFlag, fnEnvNameFlag, envNamespaceFlag, fnCodeFlag, fnSrcArchiveFlag, fnDeployArchiveFlag, fnKeepURLFlag, fnEntryPointFlag, fnPkgNameFlag, pkgNamespaceFlag, fnBuildCmdFlag, fnForceFlag, minCpu, maxCpu, minMem, maxMem, minScale, maxScale, fnExecutorTypeFlag, targetcpu, specializationTimeoutFlag, fnExecutionTimeoutFlag, fnSecretFlag, fnCfgMapFlag}, Action: urfavecli.Wrapper(function.Update)},
{Name: "delete", Usage: "Delete function", Flags: []cli.Flag{fnNameFlag, fnNamespaceFlag}, Action: urfavecli.Wrapper(function.Delete)},
// TODO : for fnList, i feel like it's nice to allow --fns all, to list functions across all namespaces for cluster admins, although, this is against ns isolation.
// so, in the future, if we end up using kubeconfig in fission cli and enforcing rolebindings to be created for users by admins etc, we can add this option at the time.
{Name: "list", Usage: "List all functions in a namespace if specified, else, list functions across all namespaces", Flags: []cli.Flag{fnNamespaceFlag}, Action: urfavecli.Wrapper(function.List)},
{Name: "logs", Usage: "Display function logs", Flags: []cli.Flag{fnNameFlag, fnNamespaceFlag, fnPodFlag, fnFollowFlag, fnDetailFlag, fnLogDBTypeFlag, fnLogReverseQueryFlag, fnLogCountFlag}, Action: urfavecli.Wrapper(function.Log)},
{Name: "test", Usage: "Test a function", Flags: []cli.Flag{fnNameFlag, fnNamespaceFlag, fnEnvNameFlag,
fnCodeFlag, fnSrcArchiveFlag, htMethodFlag, fnBodyFlag, fnHeaderFlag, fnQueryFlag, fnTimeoutFlag},
Action: urfavecli.Wrapper(function.Test)},
}
// httptriggers
htNameFlag := cli.StringFlag{Name: "name", Usage: "HTTP Trigger name"}
htHostFlag := cli.StringFlag{Name: "host", Usage: "(DEPRECATED) Use --ingressrule instead"}
htIngressFlag := cli.BoolFlag{Name: "createingress", Usage: "Creates ingress with same URL, defaults to false"}
htIngressRuleFlag := cli.StringFlag{Name: "ingressrule", Usage: "Host for Ingress rule: --ingressrule host=path (the format of host/path depends on what ingress controller you used)"}
htIngressAnnotationFlag := cli.StringSliceFlag{Name: "ingressannotation", Usage: "Annotation for Ingress: --ingressannotation key=value (the format of annotation depends on what ingress controller you used)"}
htIngressTLSFlag := cli.StringFlag{Name: "ingresstls", Usage: "Name of the Secret contains TLS key and crt for Ingress (the usability of TLS features depends on what ingress controller you used)"}
htFnNameFlag := cli.StringSliceFlag{Name: "function", Usage: "Name(s) of the function for this trigger. (If 2 functions are supplied with this flag, traffic gets routed to them based on weights supplied with --weight flag.)"}
htFnWeightFlag := cli.IntSliceFlag{Name: "weight", Usage: "Weight for each function supplied with --function flag, in the same order. Used for canary deployment"}
htFnFilterFlag := cli.StringFlag{Name: "function", Usage: "Name of the function for trigger(s)"}
htSubcommands := []cli.Command{
{Name: "create", Aliases: []string{"add"}, Usage: "Create HTTP trigger", Flags: []cli.Flag{htNameFlag, htMethodFlag, htUrlFlag, htFnNameFlag, htIngressRuleFlag, htIngressAnnotationFlag, htIngressTLSFlag, htIngressFlag, fnNamespaceFlag, specSaveFlag, htFnWeightFlag, htHostFlag}, Action: urfavecli.Wrapper(httptrigger.Create)},
{Name: "get", Usage: "Get HTTP trigger", Flags: []cli.Flag{htNameFlag}, Action: urfavecli.Wrapper(httptrigger.Get)},
{Name: "update", Usage: "Update HTTP trigger", Flags: []cli.Flag{htNameFlag, triggerNamespaceFlag, htFnNameFlag, htIngressRuleFlag, htIngressAnnotationFlag, htIngressTLSFlag, htIngressFlag, htFnWeightFlag, htHostFlag}, Action: urfavecli.Wrapper(httptrigger.Update)},
{Name: "delete", Usage: "Delete HTTP trigger", Flags: []cli.Flag{htNameFlag, triggerNamespaceFlag, htFnFilterFlag}, Action: urfavecli.Wrapper(httptrigger.Delete)},
{Name: "list", Usage: "List HTTP triggers", Flags: []cli.Flag{triggerNamespaceFlag, htFnFilterFlag}, Action: urfavecli.Wrapper(httptrigger.List)},
}
// timetriggers
ttNameFlag := cli.StringFlag{Name: "name", Usage: "Time Trigger name"}
ttCronFlag := cli.StringFlag{Name: "cron", Usage: "Time trigger cron spec with each asterisk representing respectively second, minute, hour, the day of the month, month and day of the week. Also supports readable formats like '@every 5m', '@hourly'"}
ttFnNameFlag := cli.StringFlag{Name: "function", Usage: "Function name"}
ttRoundFlag := cli.IntFlag{Name: "round", Value: 1, Usage: "Get next N rounds of invocation time"}
ttSubcommands := []cli.Command{
{Name: "create", Aliases: []string{"add"}, Usage: "Create time trigger", Flags: []cli.Flag{ttNameFlag, ttFnNameFlag, fnNamespaceFlag, ttCronFlag, specSaveFlag}, Action: urfavecli.Wrapper(timetrigger.Create)},
{Name: "update", Usage: "Update time trigger", Flags: []cli.Flag{ttNameFlag, triggerNamespaceFlag, ttCronFlag, ttFnNameFlag}, Action: urfavecli.Wrapper(timetrigger.Update)},
{Name: "delete", Usage: "Delete time trigger", Flags: []cli.Flag{ttNameFlag, triggerNamespaceFlag}, Action: urfavecli.Wrapper(timetrigger.Delete)},
{Name: "list", Usage: "List time triggers", Flags: []cli.Flag{triggerNamespaceFlag}, Action: urfavecli.Wrapper(timetrigger.List)},
{Name: "showschedule", Aliases: []string{"show"}, Usage: "Show schedule for cron spec", Flags: []cli.Flag{ttCronFlag, ttRoundFlag}, Action: urfavecli.Wrapper(timetrigger.Show)},
}
// Message queue trigger
mqtNameFlag := cli.StringFlag{Name: "name", Usage: "Message queue Trigger name"}
mqtFnNameFlag := cli.StringFlag{Name: "function", Usage: "Function name"}
mqtMQTypeFlag := cli.StringFlag{Name: "mqtype", Value: "nats-streaming", Usage: "Message queue type, e.g. nats-streaming, azure-storage-queue (optional)"}
mqtTopicFlag := cli.StringFlag{Name: "topic", Usage: "Message queue Topic the trigger listens on"}
mqtRespTopicFlag := cli.StringFlag{Name: "resptopic", Usage: "Topic that the function response is sent on (optional; response discarded if unspecified)"}
mqtErrorTopicFlag := cli.StringFlag{Name: "errortopic", Usage: "Topic that the function error messages are sent to (optional; errors discarded if unspecified"}
mqtMaxRetries := cli.IntFlag{Name: "maxretries", Value: 0, Usage: "Maximum number of times the function will be retried upon failure (optional; default is 0)"}
mqtMsgContentType := cli.StringFlag{Name: "contenttype, c", Value: "application/json", Usage: "Content type of messages that publish to the topic (optional)"}
mqtSubcommands := []cli.Command{
{Name: "create", Aliases: []string{"add"}, Usage: "Create Message queue trigger", Flags: []cli.Flag{mqtNameFlag, mqtFnNameFlag, fnNamespaceFlag, mqtMQTypeFlag, mqtTopicFlag, mqtRespTopicFlag, mqtErrorTopicFlag, mqtMaxRetries, mqtMsgContentType, specSaveFlag}, Action: urfavecli.Wrapper(mqtrigger.Create)},
{Name: "update", Usage: "Update message queue trigger", Flags: []cli.Flag{mqtNameFlag, triggerNamespaceFlag, mqtTopicFlag, mqtRespTopicFlag, mqtErrorTopicFlag, mqtMaxRetries, mqtFnNameFlag, mqtMsgContentType}, Action: urfavecli.Wrapper(mqtrigger.Update)},
{Name: "delete", Usage: "Delete message queue trigger", Flags: []cli.Flag{mqtNameFlag, triggerNamespaceFlag}, Action: urfavecli.Wrapper(mqtrigger.Delete)},
{Name: "list", Usage: "List message queue triggers", Flags: []cli.Flag{mqtMQTypeFlag, triggerNamespaceFlag}, Action: urfavecli.Wrapper(mqtrigger.List)},
}
// Recorders
recNameFlag := cli.StringFlag{Name: "name", Usage: "Recorder name"}
recFnFlag := cli.StringFlag{Name: "function", Usage: "Record Function name(s): --function=fnA"}
recTriggersFlag := cli.StringSliceFlag{Name: "trigger", Usage: "Record Trigger name(s): --trigger=trigger1,trigger2,trigger3"}
//recRetentionPolFlag := cli.StringFlag{Name: "retention", Usage: "Retention policy (number of days)"}
//recEvictionPolFlag := cli.StringFlag{Name: "eviction", Usage: "Eviction policy (default LRU)"}
recEnabled := cli.BoolFlag{Name: "enable", Usage: "Enable recorder"}
recDisabled := cli.BoolFlag{Name: "disable", Usage: "Disable recorder"}
recSubcommands := []cli.Command{
{Name: "create", Aliases: []string{"add"}, Usage: "Create recorder", Flags: []cli.Flag{recNameFlag, recFnFlag, recTriggersFlag, specSaveFlag}, Action: urfavecli.Wrapper(recorder.Create)},
{Name: "get", Usage: "Get recorder", Flags: []cli.Flag{recNameFlag}, Action: urfavecli.Wrapper(recorder.Get)},
{Name: "update", Usage: "Update recorder", Flags: []cli.Flag{recNameFlag, recFnFlag, recTriggersFlag, recEnabled, recDisabled}, Action: urfavecli.Wrapper(recorder.Update)},
{Name: "delete", Usage: "Delete recorder", Flags: []cli.Flag{recNameFlag, recorderNamespaceFlag}, Action: urfavecli.Wrapper(recorder.Delete)},
{Name: "list", Usage: "List recorders", Flags: []cli.Flag{}, Action: urfavecli.Wrapper(recorder.List)},
}
// View records
filterTimeFrom := cli.StringFlag{Name: "from", Usage: "Filter records by time interval; specify start of interval"}
filterTimeTo := cli.StringFlag{Name: "to", Usage: "Filter records by time interval; specify end of interval"}
filterFunction := cli.StringFlag{Name: "function", Usage: "Filter records by function"}
filterTrigger := cli.StringFlag{Name: "trigger", Usage: "Filter records by trigger"}
verbosityFlag := cli.BoolFlag{Name: "v", Usage: "Toggle verbosity -- view more detailed requests/responses"}
vvFlag := cli.BoolFlag{Name: "vv", Usage: "Toggle verbosity -- view raw requests/responses"}
recViewSubcommands := []cli.Command{
{Name: "view", Usage: "View existing records", Flags: []cli.Flag{filterTimeTo, filterTimeFrom, filterFunction, filterTrigger, verbosityFlag, vvFlag}, Action: urfavecli.Wrapper(records.View)},
}
// Replay records
reqIDFlag := cli.StringFlag{Name: "reqUID", Usage: "Replay a particular request by providing the reqUID (to view reqUIDs, do 'fission records view')"}
// environments
envNameFlag := cli.StringFlag{Name: flag.RESOURCE_NAME, Usage: "Environment name"}
envPoolsizeFlag := cli.IntFlag{Name: flag.ENVIRONMENT_POOLSIZE, Value: 3, Usage: "Size of the pool"}
envImageFlag := cli.StringFlag{Name: flag.ENVIRONMENT_IMAGE, Usage: "Environment image URL"}
envBuilderImageFlag := cli.StringFlag{Name: flag.ENVIRONMENT_BUILDER, Usage: "Environment builder image URL (optional)"}
envBuildCmdFlag := cli.StringFlag{Name: flag.ENVIRONMENT_BUILDCOMMAND, Usage: "Build command for environment builder to build source package (optional)"}
envKeepArchiveFlag := cli.BoolFlag{Name: flag.ENVIRONMENT_KEEPARCHIVE, Usage: "Keep the archive instead of extracting it into a directory (optional, defaults to false)"}
envExternalNetworkFlag := cli.BoolFlag{Name: flag.ENVIRONMENT_EXTERNAL_NETWORK, Usage: "Allow environment access external network when istio feature enabled (optional, defaults to false)"}
envTerminationGracePeriodFlag := cli.Int64Flag{Name: flag.GetCliFlagName(flag.ENVIRONMENT_GRACE_PERIOD, flag.ENVIRONMENT_GRACE_PERIOD_ALIAS), Value: 360, Usage: "The grace time (in seconds) for pod to perform connection draining before termination (optional)"}
envVersionFlag := cli.IntFlag{Name: flag.ENVIRONMENT_VERSION, Value: 1, Usage: "Environment API version (1 means v1 interface)"}
envSubcommands := []cli.Command{
{Name: "create", Aliases: []string{"add"}, Usage: "Add an environment", Flags: []cli.Flag{envNameFlag, envNamespaceFlag, envPoolsizeFlag, envImageFlag, envBuilderImageFlag, envBuildCmdFlag, envKeepArchiveFlag, minCpu, maxCpu, minMem, maxMem, envVersionFlag, envExternalNetworkFlag, envTerminationGracePeriodFlag, specSaveFlag}, Action: urfavecli.Wrapper(environment.Create)},
{Name: "get", Usage: "Get environment details", Flags: []cli.Flag{envNameFlag, envNamespaceFlag}, Action: urfavecli.Wrapper(environment.Get)},
{Name: "update", Usage: "Update environment", Flags: []cli.Flag{envNameFlag, envNamespaceFlag, envPoolsizeFlag, envImageFlag, envBuilderImageFlag, envBuildCmdFlag, envKeepArchiveFlag, minCpu, maxCpu, minMem, maxMem, envExternalNetworkFlag, envTerminationGracePeriodFlag}, Action: urfavecli.Wrapper(environment.Update)},
{Name: "delete", Usage: "Delete environment", Flags: []cli.Flag{envNameFlag, envNamespaceFlag}, Action: urfavecli.Wrapper(environment.Delete)},
{Name: "list", Usage: "List all environments", Flags: []cli.Flag{envNamespaceFlag}, Action: urfavecli.Wrapper(environment.List)},
}
// watches
wNameFlag := cli.StringFlag{Name: "name", Usage: "Watch name"}
wFnNameFlag := cli.StringFlag{Name: "function", Usage: "Function name"}
wNamespaceFlag := cli.StringFlag{Name: "ns", Usage: "Namespace of resource to watch"}
wObjTypeFlag := cli.StringFlag{Name: "type", Usage: "Type of resource to watch (Pod, Service, etc.)"}
wLabelsFlag := cli.StringFlag{Name: "labels", Usage: "Label selector of the form a=b,c=d"}
wSubCommands := []cli.Command{
{Name: "create", Aliases: []string{"add"}, Usage: "Create a watch", Flags: []cli.Flag{wFnNameFlag, fnNamespaceFlag, wNamespaceFlag, wObjTypeFlag, wLabelsFlag, specSaveFlag}, Action: urfavecli.Wrapper(kubewatch.Create)},
// TODO add update flag when supported
{Name: "delete", Usage: "Delete watch", Flags: []cli.Flag{wNameFlag, triggerNamespaceFlag}, Action: urfavecli.Wrapper(kubewatch.Delete)},
{Name: "list", Usage: "List all watches", Flags: []cli.Flag{triggerNamespaceFlag}, Action: urfavecli.Wrapper(kubewatch.List)},
}
// packages
pkgNameFlag := cli.StringFlag{Name: "name", Usage: "Package name"}
pkgForceFlag := cli.BoolFlag{Name: "force, f", Usage: "Force update a package even if it is used by one or more functions"}
pkgEnvironmentFlag := cli.StringFlag{Name: "env", Usage: "Environment name"}
pkgSrcArchiveFlag := cli.StringSliceFlag{Name: "sourcearchive, src", Usage: "Local path or URL for source archive"}
pkgDeployArchiveFlag := cli.StringSliceFlag{Name: "deployarchive, deploy", Usage: "Local path or URL for binary archive"}
pkgKeepURLFlag := cli.BoolFlag{Name: "keeparchiveurl, keepurl", Usage: "Keep the providing URL in archive instead of downloading file from it. (If set, no checksum will be generated for file integrity check. You must ensure the file won't be changed.)"}
pkgBuildCmdFlag := cli.StringFlag{Name: "buildcmd", Usage: "Build command for builder to run with"}
pkgOutputFlag := cli.StringFlag{Name: "output, o", Usage: "Output filename to save archive content"}
pkgStatusFlag := cli.StringFlag{Name: "status", Usage: `Filter packages by status`}
pkgOrphanFlag := cli.BoolFlag{Name: "orphan", Usage: "Orphan packages that are not referenced by any function"}
pkgSubCommands := []cli.Command{
{Name: "create", Usage: "Create new package", Flags: []cli.Flag{pkgNamespaceFlag, pkgEnvironmentFlag, envNamespaceFlag, pkgSrcArchiveFlag, pkgDeployArchiveFlag, pkgKeepURLFlag, pkgBuildCmdFlag}, Action: urfavecli.Wrapper(_package.Create)},
{Name: "update", Usage: "Update package", Flags: []cli.Flag{pkgNameFlag, pkgNamespaceFlag, pkgEnvironmentFlag, envNamespaceFlag, pkgSrcArchiveFlag, pkgDeployArchiveFlag, pkgKeepURLFlag, pkgBuildCmdFlag, pkgForceFlag}, Action: urfavecli.Wrapper(_package.Update)},
{Name: "rebuild", Usage: "Rebuild a failed package", Flags: []cli.Flag{pkgNameFlag, pkgNamespaceFlag}, Action: urfavecli.Wrapper(_package.Rebuild)},
{Name: "getsrc", Usage: "Get source archive content", Flags: []cli.Flag{pkgNameFlag, pkgNamespaceFlag, pkgOutputFlag}, Action: urfavecli.Wrapper(_package.GetSrc)},
{Name: "getdeploy", Usage: "Get deployment archive content", Flags: []cli.Flag{pkgNameFlag, pkgNamespaceFlag, pkgOutputFlag}, Action: urfavecli.Wrapper(_package.GetDeploy)},
{Name: "info", Usage: "Show package information", Flags: []cli.Flag{pkgNameFlag, pkgNamespaceFlag}, Action: urfavecli.Wrapper(_package.Info)},
{Name: "list", Usage: "List all packages", Flags: []cli.Flag{pkgOrphanFlag, pkgStatusFlag, pkgNamespaceFlag}, Action: urfavecli.Wrapper(_package.List)},
{Name: "delete", Usage: "Delete package", Flags: []cli.Flag{pkgNameFlag, pkgNamespaceFlag, pkgForceFlag, pkgOrphanFlag}, Action: urfavecli.Wrapper(_package.Delete)},
}
// specs
specDirFlag := cli.StringFlag{Name: "specdir", Usage: "Directory to store specs, defaults to ./specs"}
specNameFlag := cli.StringFlag{Name: "name", Usage: "(optional) Name for the app, applied to resources as a Kubernetes annotation"}
specDeployIDFlag := cli.StringFlag{Name: "deployid, id", Usage: "(optional) Deployment ID for the spec deployment config"}
specWaitFlag := cli.BoolFlag{Name: "wait", Usage: "Wait for package builds"}
specWatchFlag := cli.BoolFlag{Name: "watch", Usage: "Watch local files for change, and re-apply specs as necessary"}
specDeleteFlag := cli.BoolFlag{Name: "delete", Usage: "Allow apply to delete resources that no longer exist in the specification"}
specSubCommands := []cli.Command{
{Name: "init", Usage: "Create an initial declarative app specification", Flags: []cli.Flag{specDirFlag, specNameFlag, specDeployIDFlag}, Action: urfavecli.Wrapper(spec.Init)},
{Name: "validate", Usage: "Validate Fission app specification", Flags: []cli.Flag{specDirFlag}, Action: urfavecli.Wrapper(spec.Validate)},
{Name: "apply", Usage: "Create, update, or delete Fission resources from app specification", Flags: []cli.Flag{specDirFlag, specDeleteFlag, specWaitFlag, specWatchFlag}, Action: urfavecli.Wrapper(spec.Apply)},
{Name: "destroy", Usage: "Delete all Fission resources in the app specification", Flags: []cli.Flag{specDirFlag}, Action: urfavecli.Wrapper(spec.Destroy)},
}
// support
supportOutputFlag := cli.StringFlag{Name: "output, o", Value: support.DEFAULT_OUTPUT_DIR, Usage: "Output directory to save dump archive/files"}
supportNoZipFlag := cli.BoolFlag{Name: "nozip", Usage: "Save dump information into multiple files instead of single zip file"}
supportSubCommands := []cli.Command{
{Name: "dump", Usage: "Collect & dump all necessary for troubleshooting", Flags: []cli.Flag{supportOutputFlag, supportNoZipFlag}, Action: urfavecli.Wrapper(support.Dump)},
}
// canary configs
canaryConfigNameFlag := cli.StringFlag{Name: "name", Usage: "Name for the canary config"}
triggerNameFlag := cli.StringFlag{Name: "httptrigger", Usage: "Http trigger that this config references"}
newFunc := cli.StringFlag{Name: "newfunction", Usage: "New version of the function"}
oldFunc := cli.StringFlag{Name: "oldfunction", Usage: "Old stable version of the function"}
weightIncrementFlag := cli.IntFlag{Name: "increment-step", Value: 20, Usage: "Weight increment step for function"}
incrementIntervalFlag := cli.StringFlag{Name: "increment-interval", Value: "2m", Usage: "Weight increment interval, string representation of time.Duration, ex : 1m, 2h, 2d"}
failureThresholdFlag := cli.IntFlag{Name: "failure-threshold", Value: 10, Usage: "Threshold in percentage beyond which the new version of the function is considered unstable"}
canarySubCommands := []cli.Command{
{Name: "create", Usage: "Create a canary config", Flags: []cli.Flag{canaryConfigNameFlag, triggerNameFlag, newFunc, oldFunc, fnNamespaceFlag, weightIncrementFlag, incrementIntervalFlag, failureThresholdFlag}, Action: urfavecli.Wrapper(canaryconfig.Create)},
{Name: "get", Usage: "View parameters in a canary config", Flags: []cli.Flag{canaryConfigNameFlag, canaryNamespaceFlag}, Action: urfavecli.Wrapper(canaryconfig.Get)},
{Name: "update", Usage: "Update parameters of a canary config", Flags: []cli.Flag{canaryConfigNameFlag, canaryNamespaceFlag, incrementIntervalFlag, weightIncrementFlag, failureThresholdFlag}, Action: urfavecli.Wrapper(canaryconfig.Update)},
{Name: "delete", Usage: "Delete a canary config", Flags: []cli.Flag{canaryConfigNameFlag, canaryNamespaceFlag}, Action: urfavecli.Wrapper(canaryconfig.Delete)},
{Name: "list", Usage: "List all canary configs in a namespace", Flags: []cli.Flag{canaryNamespaceFlag}, Action: urfavecli.Wrapper(canaryconfig.List)},
}
pluginSubCommands := []cli.Command{
{Name: "list", Usage: "List installed client plugins", Action: urfavecli.Wrapper(plugincmd.List)},
}
app.Commands = []cli.Command{
{Name: "function", Aliases: []string{"fn"}, Usage: "Create, update and manage functions", Subcommands: fnSubcommands},
{Name: "httptrigger", Aliases: []string{"ht", "route"}, Usage: "Manage HTTP triggers (routes) for functions", Subcommands: htSubcommands},
{Name: "timetrigger", Aliases: []string{"tt", "timer"}, Usage: "Manage Time triggers (timers) for functions", Subcommands: ttSubcommands},
{Name: "mqtrigger", Aliases: []string{"mqt", "messagequeue"}, Usage: "Manage message queue triggers for functions", Subcommands: mqtSubcommands},
{Name: "recorder", Usage: "Manage recorders for functions", Subcommands: recSubcommands, Hidden: true},
{Name: "records", Usage: "View records with optional filters", Subcommands: recViewSubcommands, Hidden: true},
{Name: "replay", Usage: "Replay records", Flags: []cli.Flag{reqIDFlag}, Action: urfavecli.Wrapper(replay.Replay)},
{Name: "environment", Aliases: []string{"env"}, Usage: "Manage environments", Subcommands: envSubcommands},
{Name: "watch", Aliases: []string{"w"}, Usage: "Manage watches", Subcommands: wSubCommands},
{Name: "package", Aliases: []string{"pkg"}, Usage: "Manage packages", Subcommands: pkgSubCommands},
{Name: "spec", Aliases: []string{"specs"}, Usage: "Manage a declarative app specification", Subcommands: specSubCommands},
{Name: "support", Usage: "Collect an archive of diagnostic information for support", Subcommands: supportSubCommands},
{Name: "canary-config", Aliases: []string{}, Usage: "Create, Update and manage Canary Configs", Subcommands: canarySubCommands},
{Name: "plugin", Aliases: []string{"plugins"}, Usage: "Manage Fission CLI plugins", Subcommands: pluginSubCommands},
{Name: "version", Usage: "Version information", Action: urfavecli.Wrapper(version.Version)},
}
app.Before = cliHook
app.Action = handleNoCommand
return app
}
func handleNoCommand(ctx *cli.Context) error {
if ctx.GlobalBool("plugin") {
bs, err := json.Marshal(plugin.Metadata{
Version: info.Version,
Usage: ctx.App.Usage,
})
if err != nil {
return errors.Errorf("Failed to marshal plugin metadata to JSON: %v", err)
}
fmt.Println(string(bs))
return nil
}
if len(ctx.Args()) > 0 {
return handleCommandNotFound(ctx, ctx.Args().First())
}
return cli.ShowAppHelp(ctx)
}
func handleCommandNotFound(ctx *cli.Context, subCommand string) error {
pmd, err := plugin.Find(subCommand)
if err != nil {
switch err {
case plugin.ErrPluginNotFound:
url, ok := plugin.SearchRegistries(subCommand)
if !ok {
return errors.New("No help topic for '" + subCommand + "'")
}
return errors.Errorf(`Command '%v' is not installed.
It is available to download at '%v'.
To install it for your local Fission CLI:
1. Download the plugin binary for your OS from the URL
2. Ensure that the plugin binary is executable: chmod +x <binary>
2. Add the plugin binary to your $PATH: mv <binary> /usr/local/bin/fission-%v`, subCommand, url, subCommand)
default:
return errors.Wrap(err, "Error occurred when invoking "+subCommand)
}
}
// Rebuild global arguments string (urfave/cli does not have an option to get the raw input of the global flags)
var globalArgs []string
for _, globalFlagName := range ctx.GlobalFlagNames() {
if globalFlagName == "plugin" {
continue
}
val := fmt.Sprintf("%v", ctx.GlobalGeneric(globalFlagName))
if len(val) > 0 {
globalArgs = append(globalArgs, fmt.Sprintf("--%v", globalFlagName), val)
}
}
args := append(globalArgs, ctx.Args().Tail()...)
err = plugin.Exec(pmd, args)
if err != nil {
return err
}
return nil
}
func flagValueParser(args []string) error {
// all input value for flags are properly set
if len(args) == 0 {
return nil
}
var flagIndexes []int
var errorFlags []string
// find out all flag indexes
for i, v := range args {
// support both flags with "--" and "-"
if strings.HasPrefix(v, "-") {
flagIndexes = append(flagIndexes, i)
}
}
// add total length of args to indicate the end of args
flagIndexes = append(flagIndexes, len(args))
for i := 0; i < len(flagIndexes)-1; i++ {
// if the difference between the flag index i and i+1
// is bigger then 2 means that CLI receives extra arguments
// for one flag. For example,
// 1. fission fn create --name e1 --code examples/nodejs/* --env nodejs ...
// The wildcard will be extracted to multiple files and cause the difference between `--code` and `--env` large than 2.
// 2. fission fn create --spec --name e1 ...
// The difference between --spec and --name is 1.
if flagIndexes[i+1]-flagIndexes[i] > 2 {
index := flagIndexes[i]
errorFlags = append(errorFlags, args[index])
}
}
if len(errorFlags) > 0 {
return errors.Errorf("Unable to parse flags: %v\nThe argument should have only one input value. Please quote the input value if it contains wildcard characters(*).", strings.Join(errorFlags[:], ", "))
}
return nil
}
var helpTemplate = `NAME:
{{.Name}}{{if .Usage}} - {{.Usage}}{{end}}
USAGE:
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}}
VERSION:
{{.Version}}{{end}}{{end}}{{if .Description}}
DESCRIPTION:
{{.Description}}{{end}}{{if .VisibleCommands}}
COMMANDS:{{range .VisibleCategories}}{{if .Name}}
{{.Name}}:{{end}}{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
PLUGIN COMMANDS:{{ range $name, $usage := ExtraInfo }}
{{$name}}{{"\t"}}{{$usage}}{{end}}
GLOBAL OPTIONS:
{{range $index, $option := .VisibleFlags}}{{if $index}}
{{end}}{{$option}}{{end}}{{end}}
`
@@ -0,0 +1,286 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cobra
import (
"fmt"
"strings"
"time"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
wCli "github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra/helptemplate"
cmd "github.com/fission/fission/pkg/fission-cli/cmd"
"github.com/fission/fission/pkg/fission-cli/flag"
)
var _ wCli.Input = &Cli{}
type (
Cli struct {
c *cobra.Command
args []string
}
)
// Parse is only for converting urfave *cli.Context to Input and will be removed in future.
func Parse(cmd *cobra.Command, args []string) wCli.Input {
return Cli{c: cmd, args: args}
}
func Wrapper(action cmd.CommandAction) func(*cobra.Command, []string) error {
return func(c *cobra.Command, args []string) error {
return action(Cli{c: c, args: args})
}
}
func SetFlags(cmd *cobra.Command, flagSet flag.FlagSet) {
aliases := make(map[string]string)
// set required flags
for _, f := range flagSet.Required {
requiredFlags(cmd, f)
for _, alias := range f.Aliases {
aliases[alias] = f.Name
}
}
// set optional flags
for _, f := range flagSet.Optional {
optionalFlags(cmd, f)
for _, alias := range f.Aliases {
aliases[alias] = f.Name
}
}
// set flag alias normalize function
cmd.Flags().SetNormalizeFunc(
func(f *pflag.FlagSet, name string) pflag.NormalizedName {
n, ok := aliases[name]
if ok {
name = n
}
return pflag.NormalizedName(name)
},
)
cmd.Flags().SortFlags = false
}
func optionalFlags(cmd *cobra.Command, flags ...flag.Flag) {
for _, f := range flags {
toCobraFlag(cmd, f)
if f.Deprecated {
usage := fmt.Sprintf("Use --%v instead. The flag still works for now and will be removed in future", f.Substitute)
cmd.Flags().MarkDeprecated(f.Name, usage)
} else if f.Hidden {
cmd.Flags().MarkHidden(f.Name)
}
}
}
func requiredFlags(cmd *cobra.Command, flags ...flag.Flag) {
for _, f := range flags {
toCobraFlag(cmd, f)
cmd.MarkFlagRequired(f.Name)
}
}
func toCobraFlag(cmd *cobra.Command, f flag.Flag) {
// Workaround to pass aliases to templater for generating flag aliases.
if len(f.Aliases) > 0 {
var aliases []string
for _, alias := range f.Aliases {
dash := "--"
if len(alias) == 1 {
dash = "-"
f.Short = alias
}
aliases = append(aliases, dash+alias)
}
// Use separator to separator aliases and usage text.
f.Usage = fmt.Sprintf("%s%s%s",
strings.Join(aliases, helptemplate.AliasSeparator),
helptemplate.AliasSeparator, f.Usage)
}
switch f.Type {
case flag.Bool:
val, ok := f.DefaultValue.(bool)
if !ok {
val = false
}
cmd.Flags().BoolP(f.Name, f.Short, val, f.Usage)
case flag.String:
val, ok := f.DefaultValue.(string)
if !ok {
val = ""
}
cmd.Flags().StringP(f.Name, f.Short, val, f.Usage)
case flag.StringSlice:
val, ok := f.DefaultValue.([]string)
if !ok {
val = []string{}
}
cmd.Flags().StringArrayP(f.Name, f.Short, val, f.Usage)
case flag.Int:
val, ok := f.DefaultValue.(int)
if !ok {
val = 0
}
cmd.Flags().IntP(f.Name, f.Short, val, f.Usage)
case flag.IntSlice:
val, ok := f.DefaultValue.([]int)
if !ok {
val = []int{}
}
cmd.Flags().IntSliceP(f.Name, f.Short, val, f.Usage)
case flag.Int64:
val, ok := f.DefaultValue.(int64)
if !ok {
val = 0
}
cmd.Flags().Int64P(f.Name, f.Short, val, f.Usage)
case flag.Int64Slice:
val, ok := f.DefaultValue.([]int64)
if !ok {
val = []int64{}
}
cmd.Flags().Int64SliceP(f.Name, f.Short, val, f.Usage)
case flag.Float32:
val, ok := f.DefaultValue.(float32)
if !ok {
val = 0
}
cmd.Flags().Float32P(f.Name, f.Short, val, f.Usage)
case flag.Float64:
val, ok := f.DefaultValue.(float64)
if !ok {
val = 0
}
cmd.Flags().Float64P(f.Name, f.Short, val, f.Usage)
case flag.Duration:
val, ok := f.DefaultValue.(time.Duration)
if !ok {
val = 0
}
cmd.Flags().DurationP(f.Name, f.Short, val, f.Usage)
}
}
func WrapperChain(actions ...cmd.CommandAction) func(*cobra.Command, []string) error {
return func(c *cobra.Command, args []string) error {
for _, action := range actions {
err := action(Cli{c: c, args: args})
if err != nil {
return err
}
}
return nil
}
}
func (u Cli) IsSet(key string) bool {
return u.c.Flags().Changed(key)
}
func (u Cli) Bool(key string) bool {
// TODO: ignore the error here, but we should handle it properly in some ways.
v, _ := u.c.Flags().GetBool(key)
return v
}
func (u Cli) String(key string) string {
v, _ := u.c.Flags().GetString(key)
return v
}
func (u Cli) StringSlice(key string) []string {
// difference between StringSlice and StringArray
// --ss="one" --ss="two,three"
// StringSlice* - will result in []string{"one", "two", "three"}
// StringArray* - will result in []s
// https://github.com/spf13/cobra/issues/661#issuecomment-377684634
// Use StringArray here to fit our use case.
v, _ := u.c.Flags().GetStringArray(key)
return v
}
func (u Cli) Int(key string) int {
v, _ := u.c.Flags().GetInt(key)
return v
}
func (u Cli) IntSlice(key string) []int {
v, _ := u.c.Flags().GetIntSlice(key)
return v
}
func (u Cli) Int64(key string) int64 {
v, _ := u.c.Flags().GetInt64(key)
return v
}
func (u Cli) Int64Slice(key string) []int64 {
v, _ := u.c.Flags().GetIntSlice(key)
vals := make([]int64, len(v))
for _, i := range v {
vals = append(vals, int64(i))
}
return vals
}
func (u Cli) GlobalBool(key string) bool {
v, _ := u.c.Flags().GetBool(key)
return v
}
func (u Cli) GlobalString(key string) string {
v, _ := u.c.Flags().GetString(key)
return v
}
func (u Cli) GlobalStringSlice(key string) []string {
v, _ := u.c.Flags().GetStringArray(key)
return v
}
func (u Cli) GlobalInt(key string) int {
v, _ := u.c.Flags().GetInt(key)
return v
}
func (u Cli) GlobalIntSlice(key string) []int {
v, _ := u.c.Flags().GetIntSlice(key)
return v
}
func (u Cli) GlobalInt64(key string) int64 {
v, _ := u.c.Flags().GetInt64(key)
return v
}
func (u Cli) GlobalInt64Slice(key string) []int64 {
v, _ := u.c.Flags().GetInt64Slice(key)
return v
}
func (u Cli) Duration(key string) time.Duration {
v, _ := u.c.Flags().GetDuration(key)
return v
}
@@ -0,0 +1,61 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Original file location: https://github.com/kubernetes/kubectl/tree/master/pkg/util/templates
package helptemplate
import (
"github.com/spf13/cobra"
)
type CommandGroup struct {
Message string
Commands []*cobra.Command
}
type CommandGroups []CommandGroup
func (g CommandGroups) Add(c *cobra.Command) {
for _, group := range g {
c.AddCommand(group.Commands...)
}
}
func (g CommandGroups) Has(c *cobra.Command) bool {
for _, group := range g {
for _, command := range group.Commands {
if command == c {
return true
}
}
}
return false
}
func AddAdditionalCommands(g CommandGroups, message string, cmds []*cobra.Command) CommandGroups {
group := CommandGroup{Message: message}
for _, c := range cmds {
// Don't show commands that have no short description
if !g.Has(c) && len(c.Short) != 0 {
group.Commands = append(group.Commands, c)
}
}
if len(group.Commands) == 0 {
return g
}
return append(g, group)
}
@@ -0,0 +1,28 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package helptemplate
import (
"github.com/spf13/cobra"
)
func CreateCmdGroup(msg string, cmds ...*cobra.Command) CommandGroup {
return CommandGroup{
Message: msg,
Commands: cmds,
}
}
@@ -0,0 +1,347 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Original file location: https://github.com/kubernetes/kubectl/tree/master/pkg/util/templates
package helptemplate
import (
"bytes"
"fmt"
"os"
"strings"
"text/template"
"unicode"
"github.com/spf13/cobra"
flag "github.com/spf13/pflag"
)
const AliasSeparator = " |:|: "
type FlagExposer interface {
ExposeFlags(cmd *cobra.Command, flags ...string) FlagExposer
}
func ActsAsRootCommand(cmd *cobra.Command, filters []string, groups ...CommandGroup) FlagExposer {
if cmd == nil {
panic("nil root command")
}
templater := &templater{
RootCmd: cmd,
UsageTemplate: MainUsageTemplate(),
HelpTemplate: MainHelpTemplate(),
CommandGroups: groups,
Filtered: filters,
}
cmd.SetFlagErrorFunc(templater.FlagErrorFunc())
cmd.SetUsageFunc(templater.UsageFunc())
cmd.SetHelpFunc(templater.HelpFunc())
return templater
}
func UseOptionsTemplates(cmd *cobra.Command) {
templater := &templater{
UsageTemplate: OptionsUsageTemplate(),
HelpTemplate: OptionsHelpTemplate(),
}
cmd.SetUsageFunc(templater.UsageFunc())
cmd.SetHelpFunc(templater.HelpFunc())
}
type templater struct {
UsageTemplate string
HelpTemplate string
RootCmd *cobra.Command
CommandGroups
Filtered []string
}
func (templater *templater) FlagErrorFunc(exposedFlags ...string) func(*cobra.Command, error) error {
return func(c *cobra.Command, err error) error {
c.SilenceUsage = true
switch c.CalledAs() {
case "options":
return fmt.Errorf("%s\nRun '%s' without flags", err, c.CommandPath())
default:
return fmt.Errorf("%s\nSee '%s --help' for usage", err, c.CommandPath())
}
}
}
func (templater *templater) ExposeFlags(cmd *cobra.Command, flags ...string) FlagExposer {
cmd.SetUsageFunc(templater.UsageFunc(flags...))
return templater
}
func (templater *templater) HelpFunc() func(*cobra.Command, []string) {
return func(c *cobra.Command, s []string) {
t := template.New("help")
t.Funcs(templater.templateFuncs())
template.Must(t.Parse(templater.HelpTemplate))
err := t.Execute(os.Stdout, c)
if err != nil {
c.Println(err)
}
}
}
func (templater *templater) UsageFunc(exposedFlags ...string) func(*cobra.Command) error {
return func(c *cobra.Command) error {
t := template.New("usage")
t.Funcs(templater.templateFuncs(exposedFlags...))
template.Must(t.Parse(templater.UsageTemplate))
return t.Execute(os.Stdout, c)
}
}
func (templater *templater) templateFuncs(exposedFlags ...string) template.FuncMap {
return template.FuncMap{
"trim": strings.TrimSpace,
"trimRight": func(s string) string { return strings.TrimRightFunc(s, unicode.IsSpace) },
"trimLeft": func(s string) string { return strings.TrimLeftFunc(s, unicode.IsSpace) },
"gt": cobra.Gt,
"eq": cobra.Eq,
"rpad": rpad,
"appendIfNotPresent": appendIfNotPresent,
"flagsNotIntersected": flagsNotIntersected,
"visibleFlags": visibleFlags,
"flagsUsages": flagsUsages,
"cmdGroups": templater.cmdGroups,
"cmdGroupsString": templater.cmdGroupsString,
"rootCmd": templater.rootCmdName,
"isRootCmd": templater.isRootCmd,
"optionsCmdFor": templater.optionsCmdFor,
"usageLine": templater.usageLine,
"exposed": func(c *cobra.Command) *flag.FlagSet {
exposed := flag.NewFlagSet("exposed", flag.ContinueOnError)
exposed.SortFlags = false
if len(exposedFlags) > 0 {
for _, name := range exposedFlags {
if flag := c.Flags().Lookup(name); flag != nil {
exposed.AddFlag(flag)
}
}
}
return exposed
},
}
}
func (templater *templater) cmdGroups(c *cobra.Command, all []*cobra.Command) []CommandGroup {
if len(templater.CommandGroups) > 0 && c == templater.RootCmd {
all = filter(all, templater.Filtered...)
return AddAdditionalCommands(templater.CommandGroups, "Other Commands:", all)
}
all = filter(all, "options")
return []CommandGroup{
{
Message: "Available Commands:",
Commands: all,
},
}
}
func (t *templater) cmdGroupsString(c *cobra.Command) string {
groups := []string{}
for _, cmdGroup := range t.cmdGroups(c, c.Commands()) {
cmds := []string{cmdGroup.Message}
for _, cmd := range cmdGroup.Commands {
if cmd.IsAvailableCommand() {
cmds = append(cmds, " "+rpad(cmd.Name(), cmd.NamePadding())+" "+cmd.Short)
}
}
groups = append(groups, strings.Join(cmds, "\n"))
}
return strings.Join(groups, "\n\n")
}
func (t *templater) rootCmdName(c *cobra.Command) string {
return t.rootCmd(c).CommandPath()
}
func (t *templater) isRootCmd(c *cobra.Command) bool {
return t.rootCmd(c) == c
}
func (t *templater) parents(c *cobra.Command) []*cobra.Command {
parents := []*cobra.Command{c}
for current := c; !t.isRootCmd(current) && current.HasParent(); {
current = current.Parent()
parents = append(parents, current)
}
return parents
}
func (t *templater) rootCmd(c *cobra.Command) *cobra.Command {
if c != nil && !c.HasParent() {
return c
}
if t.RootCmd == nil {
panic("nil root cmd")
}
return t.RootCmd
}
func (t *templater) optionsCmdFor(c *cobra.Command) string {
if !c.Runnable() {
return ""
}
rootCmdStructure := t.parents(c)
for i := len(rootCmdStructure) - 1; i >= 0; i-- {
cmd := rootCmdStructure[i]
if _, _, err := cmd.Find([]string{"options"}); err == nil {
return cmd.CommandPath() + " options"
}
}
return ""
}
func (t *templater) usageLine(c *cobra.Command) string {
usage := c.UseLine()
suffix := "[options]"
if c.HasFlags() && !strings.Contains(usage, suffix) {
usage += " " + suffix
}
return usage
}
func flagsUsages(f *flag.FlagSet) string {
x := new(bytes.Buffer)
var flags [][]string
var maxPadLength int
f.VisitAll(func(flag *flag.Flag) {
if flag.Hidden {
return
}
format := "--%s=%s"
if flag.Value.Type() == "string" {
format = "--%s='%s'"
}
var usage string
var aliases []string
// extract aliases from usage text
u := strings.Split(flag.Usage, AliasSeparator)
if len(u) == 1 {
// means the flag has no aliases
usage = u[0]
format = format + " %s"
} else {
usage = u[len(u)-1]
aliases = u[0 : len(u)-1]
format = format + " (%s)"
}
aliasesStr := strings.Join(aliases, ", ")
flagName := fmt.Sprintf(format, flag.Name, flag.DefValue, aliasesStr)
flags = append(flags, []string{flagName, usage})
if len(flagName) > maxPadLength {
maxPadLength = len(flagName)
}
})
for _, v := range flags {
name := rpad(v[0], maxPadLength)
fmt.Fprintf(x, " %s %s\n", name, toFitUsagePadding(v[1], maxPadLength))
}
return x.String()
}
func toFitUsagePadding(u string, pad int) (usage string) {
us := strings.Split(u, " ")
length := pad
for _, chunk := range us {
if length+len(chunk) > 100 {
usage = usage + "\n" + lpad(chunk, pad+len(chunk)+4) // 4 for whitespace in format
length = pad
continue
}
usage = usage + " " + chunk
length += len(chunk) + 1 // 1 is for whitespace
}
return usage
}
func rpad(s string, padding int) string {
template := fmt.Sprintf("%%-%ds", padding)
return fmt.Sprintf(template, s)
}
func lpad(s string, padding int) string {
template := fmt.Sprintf("%%%ds", padding)
return fmt.Sprintf(template, s)
}
func appendIfNotPresent(s, stringToAppend string) string {
if strings.Contains(s, stringToAppend) {
return s
}
return s + " " + stringToAppend
}
func flagsNotIntersected(l *flag.FlagSet, r *flag.FlagSet) *flag.FlagSet {
f := flag.NewFlagSet("notIntersected", flag.ContinueOnError)
f.SortFlags = false // disable sorting flags
l.VisitAll(func(flag *flag.Flag) {
if r.Lookup(flag.Name) == nil {
f.AddFlag(flag)
}
})
return f
}
func visibleFlags(l *flag.FlagSet) *flag.FlagSet {
hidden := "help"
f := flag.NewFlagSet("visible", flag.ContinueOnError)
f.SortFlags = false // disable sorting flags
l.VisitAll(func(flag *flag.Flag) {
if flag.Name != hidden {
f.AddFlag(flag)
}
})
return f
}
func filter(cmds []*cobra.Command, names ...string) []*cobra.Command {
out := []*cobra.Command{}
for _, c := range cmds {
if c.Hidden {
continue
}
skip := false
for _, name := range names {
if name == c.Name() {
skip = true
break
}
}
if skip {
continue
}
out = append(out, c)
}
return out
}
@@ -0,0 +1,104 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Original file location: https://github.com/kubernetes/kubectl/tree/master/pkg/util/templates
package helptemplate
import (
"strings"
"unicode"
)
const (
// SectionVars is the help template section that declares variables to be used in the template.
SectionVars = `{{$isRootCmd := isRootCmd .}}` +
`{{$rootCmd := rootCmd .}}` +
`{{$visibleFlags := visibleFlags (flagsNotIntersected .LocalFlags .PersistentFlags)}}` +
`{{$explicitlyExposedFlags := exposed .}}` +
`{{$optionsCmdFor := optionsCmdFor .}}` +
`{{$usageLine := usageLine .}}`
// SectionAliases is the help template section that displays command aliases.
SectionAliases = `{{if gt .Aliases 0}}Aliases:
{{.NameAndAliases}}
{{end}}`
// SectionExamples is the help template section that displays command examples.
SectionExamples = `{{if .HasExample}}Examples:
{{trimRight .Example}}
{{end}}`
// SectionSubcommands is the help template section that displays the command's subcommands.
SectionSubcommands = `{{if .HasAvailableSubCommands}}{{cmdGroupsString .}}
{{end}}`
// SectionFlags is the help template section that displays the command's flags.
SectionFlags = `{{ if or $visibleFlags.HasFlags $explicitlyExposedFlags.HasFlags}}Options:
{{ if $visibleFlags.HasFlags}}{{trimRight (flagsUsages $visibleFlags)}}{{end}}{{ if $explicitlyExposedFlags.HasFlags}}{{ if $visibleFlags.HasFlags}}
{{end}}{{trimRight (flagsUsages $explicitlyExposedFlags)}}{{end}}
{{end}}`
// SectionUsage is the help template section that displays the command's usage.
SectionUsage = `{{if and .Runnable (ne .UseLine "") (ne .UseLine $rootCmd)}}Usage:
{{$usageLine}}
{{end}}`
// SectionTipsHelp is the help template section that displays the '--help' hint.
SectionTipsHelp = `{{if .HasSubCommands}}Use "{{$rootCmd}} <command> --help" for more information about a given command.{{end}}`
// SectionTipsGlobalOptions is the help template section that displays the 'options' hint for displaying global flags.
SectionTipsGlobalOptions = `{{if $optionsCmdFor}}Use "{{$optionsCmdFor}}" for a list of global command-line options (applies to all commands).{{end}}`
)
// MainHelpTemplate if the template for 'help' used by most commands.
func MainHelpTemplate() string {
return `{{with or .Long .Short }}{{. | trimRight}}
{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
}
// MainUsageTemplate if the template for 'usage' used by most commands.
func MainUsageTemplate() string {
sections := []string{
"\n",
SectionVars,
SectionAliases,
SectionExamples,
SectionSubcommands,
SectionFlags,
SectionUsage,
SectionTipsHelp,
SectionTipsGlobalOptions,
}
return strings.TrimRightFunc(strings.Join(sections, ""), unicode.IsSpace)
}
// OptionsHelpTemplate if the template for 'help' used by the 'options' command.
func OptionsHelpTemplate() string {
return ""
}
// OptionsUsageTemplate if the template for 'usage' used by the 'options' command.
func OptionsUsageTemplate() string {
return `{{ if .HasInheritedFlags}}The following options can be passed to any command:
{{flagsUsages .InheritedFlags}}{{end}}`
}
@@ -1,107 +0,0 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package urfavecli
import (
"time"
"github.com/urfave/cli"
fCli "github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cmd"
)
var _ fCli.Input = &Cli{}
type Cli struct {
c *cli.Context
}
// Parse is only for converting urfave *cli.Context to Input and will be removed in future.
func Parse(c *cli.Context) fCli.Input {
return Cli{c: c}
}
func Wrapper(action cmd.CommandAction) func(*cli.Context) error {
return func(c *cli.Context) error {
return action(Cli{c: c})
}
}
func (u Cli) IsSet(key string) bool {
return u.c.IsSet(key)
}
func (u Cli) Bool(key string) bool {
return u.c.Bool(key)
}
func (u Cli) String(key string) string {
return u.c.String(key)
}
func (u Cli) StringSlice(key string) []string {
return u.c.StringSlice(key)
}
func (u Cli) Int(key string) int {
return u.c.Int(key)
}
func (u Cli) IntSlice(key string) []int {
return u.c.IntSlice(key)
}
func (u Cli) Int64(key string) int64 {
return u.c.Int64(key)
}
func (u Cli) Int64Slice(key string) []int64 {
return u.c.Int64Slice(key)
}
func (u Cli) GlobalBool(key string) bool {
return u.c.GlobalBool(key)
}
func (u Cli) GlobalString(key string) string {
return u.c.GlobalString(key)
}
func (u Cli) GlobalStringSlice(key string) []string {
return u.c.GlobalStringSlice(key)
}
func (u Cli) GlobalInt(key string) int {
return u.c.GlobalInt(key)
}
func (u Cli) GlobalIntSlice(key string) []int {
return u.c.GlobalIntSlice(key)
}
func (u Cli) GlobalInt64(key string) int64 {
return u.c.GlobalInt64(key)
}
func (u Cli) GlobalInt64Slice(key string) []int64 {
return u.c.GlobalInt64Slice(key)
}
func (u Cli) Duration(key string) time.Duration {
return u.c.Duration(key)
}
@@ -0,0 +1,90 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package canaryconfig
import (
"github.com/spf13/cobra"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
"github.com/fission/fission/pkg/fission-cli/flag"
)
func Commands() *cobra.Command {
createCmd := &cobra.Command{
Use: "create",
Short: "Create a canary config",
RunE: wrapper.Wrapper(Create),
}
wrapper.SetFlags(createCmd, flag.FlagSet{
Required: []flag.Flag{flag.CanaryNameFlag, flag.CanaryTriggerNameFlag, flag.CanaryNewFuncFlag, flag.CanaryOldFuncFlag},
Optional: []flag.Flag{flag.NamespaceFunctionFlag, flag.CanaryWeightIncrementFlag, flag.CanaryIncrementIntervalFlag, flag.CanaryFailureThresholdFlag},
})
getCmd := &cobra.Command{
Use: "get",
Aliases: []string{},
Short: "View parameters in a canary config",
RunE: wrapper.Wrapper(Get),
}
wrapper.SetFlags(getCmd, flag.FlagSet{
Required: []flag.Flag{flag.CanaryNameFlag},
Optional: []flag.Flag{flag.NamespaceCanaryFlag},
})
updateCmd := &cobra.Command{
Use: "update",
Aliases: []string{},
Short: "Update parameters of a canary config",
RunE: wrapper.Wrapper(Update),
}
wrapper.SetFlags(updateCmd, flag.FlagSet{
Required: []flag.Flag{flag.CanaryNameFlag},
Optional: []flag.Flag{flag.NamespaceCanaryFlag, flag.CanaryWeightIncrementFlag, flag.CanaryIncrementIntervalFlag, flag.CanaryFailureThresholdFlag},
})
deleteCmd := &cobra.Command{
Use: "delete",
Aliases: []string{},
Short: "Delete a canary config",
RunE: wrapper.Wrapper(Delete),
}
wrapper.SetFlags(deleteCmd, flag.FlagSet{
Required: []flag.Flag{flag.CanaryNameFlag},
Optional: []flag.Flag{flag.NamespaceCanaryFlag},
})
listCmd := &cobra.Command{
Use: "list",
Aliases: []string{},
Short: "List canary configs",
Long: "List all canary configs in a namespace if specified, else, list canary configs across all namespaces",
RunE: wrapper.Wrapper(List),
}
wrapper.SetFlags(listCmd, flag.FlagSet{
Optional: []flag.Flag{flag.NamespaceCanaryFlag},
})
command := &cobra.Command{
Use: "canary",
Aliases: []string{"canary-config"},
Short: "Create, Update and manage canary configs",
}
command.AddCommand(createCmd, getCmd, updateCmd, deleteCmd, listCmd)
return command
}
+21 -22
View File
@@ -21,10 +21,12 @@ import (
"time"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
"github.com/fission/fission/pkg/types"
)
@@ -56,13 +58,14 @@ func (opts *CreateSubCommand) do(flags cli.Input) error {
func (opts *CreateSubCommand) complete(flags cli.Input) error {
// canary configs can be created for functions in the same namespace
trigger := flags.String("httptrigger")
newFunc := flags.String("newfunction")
oldFunc := flags.String("oldfunction")
ns := flags.String("fnNamespace")
incrementStep := flags.Int("increment-step")
failureThreshold := flags.Int("failure-threshold")
incrementInterval := flags.String("increment-interval")
name := flags.String(flagkey.CanaryName)
ht := flags.String(flagkey.CanaryHTTPTriggerName)
newFunc := flags.String(flagkey.CanaryNewFunc)
oldFunc := flags.String(flagkey.CanaryOldFunc)
fnNs := flags.String(flagkey.NamespaceFunction)
incrementStep := flags.Int(flagkey.CanaryWeightIncrement)
failureThreshold := flags.Int(flagkey.CanaryFailureThreshold)
incrementInterval := flags.String(flagkey.CanaryIncrementInterval)
// check for time parsing
_, err := time.ParseDuration(incrementInterval)
@@ -71,14 +74,12 @@ func (opts *CreateSubCommand) complete(flags cli.Input) error {
}
// check that the trigger exists in the same namespace.
m, err := util.GetMetadata("httptrigger", "fnNamespace", flags)
htTrigger, err := opts.client.HTTPTriggerGet(&metav1.ObjectMeta{
Name: ht,
Namespace: fnNs,
})
if err != nil {
return errors.Wrap(err, "error finding http trigger in given namespace")
}
htTrigger, err := opts.client.HTTPTriggerGet(m)
if err != nil {
return errors.Wrap(err, "error finding trigger referenced in the canary config")
return errors.Wrap(err, "error finding http trigger referenced in the canary config")
}
// check that the trigger has function reference type function weights
@@ -99,21 +100,19 @@ func (opts *CreateSubCommand) complete(flags cli.Input) error {
// check that the functions exist in the same namespace
fnList := []string{newFunc, oldFunc}
err = util.CheckFunctionExistence(opts.client, fnList, ns)
err = util.CheckFunctionExistence(opts.client, fnList, fnNs)
if err != nil {
return errors.Wrap(err, "error checking functions existence")
}
canaryMetadata, err := util.GetMetadata("name", "fnNamespace", flags)
if err != nil {
return err
}
// finally create canaryCfg in the same namespace as the functions referenced
opts.canary = &fv1.CanaryConfig{
Metadata: *canaryMetadata,
Metadata: metav1.ObjectMeta{
Name: name,
Namespace: fnNs,
},
Spec: fv1.CanaryConfigSpec{
Trigger: trigger,
Trigger: ht,
NewFunction: newFunc,
OldFunction: oldFunc,
WeightIncrement: incrementStep,
+12 -9
View File
@@ -20,9 +20,11 @@ import (
"fmt"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
)
@@ -30,27 +32,28 @@ type DeleteSubCommand struct {
client *client.Client
}
func Delete(flags cli.Input) error {
c, err := util.GetServer(flags)
func Delete(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := DeleteSubCommand{
client: c,
}
return opts.run(flags)
return opts.run(input)
}
func (opts *DeleteSubCommand) run(flags cli.Input) error {
metadata, err := util.GetMetadata("name", "canaryNamespace", flags)
if err != nil {
return err
func (opts *DeleteSubCommand) run(input cli.Input) error {
m := &metav1.ObjectMeta{
Name: input.String(flagkey.CanaryName),
Namespace: input.String(flagkey.NamespaceCanary),
}
err = opts.client.CanaryConfigDelete(metadata)
err := opts.client.CanaryConfigDelete(m)
if err != nil {
return errors.Wrap(err, "error deleting canary config")
}
fmt.Printf("canaryconfig '%v.%v' deleted\n", metadata.Name, metadata.Namespace)
fmt.Printf("canaryconfig '%v.%v' deleted\n", m.Name, m.Namespace)
return nil
}
+10 -10
View File
@@ -22,9 +22,11 @@ import (
"text/tabwriter"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
)
@@ -32,24 +34,22 @@ type GetSubCommand struct {
client *client.Client
}
func Get(flags cli.Input) error {
c, err := util.GetServer(flags)
func Get(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := GetSubCommand{
client: c,
}
return opts.run(flags)
return opts.run(input)
}
func (opts *GetSubCommand) run(flags cli.Input) error {
m, err := util.GetMetadata("name", "canaryNamespace", flags)
if err != nil {
return err
}
canaryCfg, err := opts.client.CanaryConfigGet(m)
func (opts *GetSubCommand) run(input cli.Input) error {
canaryCfg, err := opts.client.CanaryConfigGet(&metav1.ObjectMeta{
Name: input.String(flagkey.CanaryName),
Namespace: input.String(flagkey.NamespaceCanary),
})
if err != nil {
return errors.Wrap(err, "error getting canary config")
}
+8 -7
View File
@@ -25,6 +25,7 @@ import (
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
)
@@ -33,27 +34,27 @@ type ListSubCommand struct {
namespace string
}
func List(flags cli.Input) error {
c, err := util.GetServer(flags)
func List(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := ListSubCommand{
client: c,
}
return opts.do(flags)
return opts.do(input)
}
func (opts *ListSubCommand) do(flags cli.Input) error {
err := opts.complete(flags)
func (opts *ListSubCommand) do(input cli.Input) error {
err := opts.complete(input)
if err != nil {
return err
}
return opts.run(flags)
return opts.run(input)
}
func (opts *ListSubCommand) complete(flags cli.Input) error {
opts.namespace = flags.String("canaryNamespace")
opts.namespace = flags.String(flagkey.NamespaceCanary)
return nil
}
+20 -18
View File
@@ -21,10 +21,12 @@ import (
"time"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
)
@@ -33,43 +35,43 @@ type UpdateSubCommand struct {
canary *fv1.CanaryConfig
}
func Update(flags cli.Input) error {
c, err := util.GetServer(flags)
func Update(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := UpdateSubCommand{
client: c,
}
return opts.do(flags)
return opts.do(input)
}
func (opts *UpdateSubCommand) do(flags cli.Input) error {
err := opts.complete(flags)
func (opts *UpdateSubCommand) do(input cli.Input) error {
err := opts.complete(input)
if err != nil {
return err
}
return opts.run(flags)
return opts.run(input)
}
func (opts *UpdateSubCommand) complete(flags cli.Input) error {
func (opts *UpdateSubCommand) complete(input cli.Input) error {
// get the current config
m, err := util.GetMetadata("name", "canaryNamespace", flags)
if err != nil {
return err
}
incrementStep := flags.Int("increment-step")
failureThreshold := flags.Int("failure-threshold")
incrementInterval := flags.String("increment-interval")
name := input.String(flagkey.CanaryName)
ns := input.String(flagkey.NamespaceCanary)
incrementStep := input.Int(flagkey.CanaryWeightIncrement)
failureThreshold := input.Int(flagkey.CanaryFailureThreshold)
incrementInterval := input.String(flagkey.CanaryIncrementInterval)
// check for time parsing
_, err = time.ParseDuration(incrementInterval)
_, err := time.ParseDuration(incrementInterval)
if err != nil {
return errors.Wrap(err, "error parsing time duration")
}
canaryCfg, err := opts.client.CanaryConfigGet(m)
canaryCfg, err := opts.client.CanaryConfigGet(&metav1.ObjectMeta{
Name: name,
Namespace: ns,
})
if err != nil {
return errors.Wrap(err, "error getting canary config")
}
@@ -97,7 +99,7 @@ func (opts *UpdateSubCommand) complete(flags cli.Input) error {
return nil
}
func (opts *UpdateSubCommand) run(flags cli.Input) error {
func (opts *UpdateSubCommand) run(input cli.Input) error {
_, err := opts.client.CanaryConfigUpdate(opts.canary)
if err != nil {
return errors.Wrap(err, "error updating canary config")
@@ -0,0 +1,91 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package environment
import (
"github.com/spf13/cobra"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
"github.com/fission/fission/pkg/fission-cli/flag"
)
func Commands() *cobra.Command {
createCmd := &cobra.Command{
Use: "create",
Short: "Create an environment",
RunE: wrapper.Wrapper(Create),
}
wrapper.SetFlags(createCmd, flag.FlagSet{
Required: []flag.Flag{flag.EnvNameFlag, flag.EnvImageFlag},
Optional: []flag.Flag{flag.NamespaceEnvironmentFlag, flag.EnvPoolsizeFlag,
flag.EnvBuilderImageFlag, flag.EnvBuildCmdFlag, flag.EnvKeepArchiveFlag,
flag.RunTimeMinCPUFlag, flag.RunTimeMaxCPUFlag, flag.RunTimeMinMemoryFlag, flag.RunTimeMaxMemoryFlag,
flag.EnvVersionFlag, flag.EnvExternalNetworkFlag, flag.EnvTerminationGracePeriodFlag, flag.SpecSaveFlag},
})
getCmd := &cobra.Command{
Use: "get",
Short: "Get environment details",
RunE: wrapper.Wrapper(Get),
}
wrapper.SetFlags(getCmd, flag.FlagSet{
Required: []flag.Flag{flag.EnvNameFlag},
Optional: []flag.Flag{flag.NamespaceEnvironmentFlag},
})
updateCmd := &cobra.Command{
Use: "update",
Short: "Update an environment",
RunE: wrapper.Wrapper(Update),
}
wrapper.SetFlags(updateCmd, flag.FlagSet{
Required: []flag.Flag{flag.EnvNameFlag},
Optional: []flag.Flag{flag.EnvImageFlag, flag.NamespaceEnvironmentFlag, flag.EnvPoolsizeFlag,
flag.EnvBuilderImageFlag, flag.EnvBuildCmdFlag, flag.EnvKeepArchiveFlag,
flag.EnvExternalNetworkFlag, flag.EnvTerminationGracePeriodFlag, flag.SpecSaveFlag},
})
deleteCmd := &cobra.Command{
Use: "delete",
Short: "Delete an environment",
RunE: wrapper.Wrapper(Delete),
}
wrapper.SetFlags(deleteCmd, flag.FlagSet{
Required: []flag.Flag{flag.EnvNameFlag},
Optional: []flag.Flag{flag.NamespaceEnvironmentFlag},
})
listCmd := &cobra.Command{
Use: "list",
Short: "List environments",
Long: "List all environments in a namespace if specified, else, list environments across all namespaces",
RunE: wrapper.Wrapper(List),
}
wrapper.SetFlags(listCmd, flag.FlagSet{
Optional: []flag.Flag{flag.NamespaceEnvironmentFlag},
})
command := &cobra.Command{
Use: "environment",
Aliases: []string{"env"},
Short: "Create, update and manage environments",
}
command.AddCommand(createCmd, getCmd, updateCmd, deleteCmd, listCmd)
return command
}
+35 -49
View File
@@ -27,9 +27,10 @@ import (
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cmd/spec"
"github.com/fission/fission/pkg/fission-cli/consolemsg"
"github.com/fission/fission/pkg/fission-cli/flag"
"github.com/fission/fission/pkg/fission-cli/console"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
"github.com/fission/fission/pkg/utils"
)
type CreateSubCommand struct {
@@ -37,28 +38,28 @@ type CreateSubCommand struct {
env *fv1.Environment
}
func Create(flags cli.Input) error {
c, err := util.GetServer(flags)
func Create(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := CreateSubCommand{
client: c,
}
return opts.do(flags)
return opts.do(input)
}
func (opts *CreateSubCommand) do(flags cli.Input) error {
err := opts.complete(flags)
func (opts *CreateSubCommand) do(input cli.Input) error {
err := opts.complete(input)
if err != nil {
return err
}
return opts.run(flags)
return opts.run(input)
}
// complete creates a environment objects and populates it with default value and CLI inputs.
func (opts *CreateSubCommand) complete(flags cli.Input) error {
env, err := createEnvironmentFromCmd(flags)
func (opts *CreateSubCommand) complete(input cli.Input) error {
env, err := createEnvironmentFromCmd(input)
if err != nil {
return err
}
@@ -68,23 +69,21 @@ func (opts *CreateSubCommand) complete(flags cli.Input) error {
// run write the resource to a spec file or create a fission CRD with remote fission server.
// It also prints warning/error if necessary.
func (opts *CreateSubCommand) run(flags cli.Input) error {
m, err := util.GetMetadata(flag.RESOURCE_NAME, flag.ENVIRONMENT_NAMESPACE, flags)
if err != nil {
return err
}
func (opts *CreateSubCommand) run(input cli.Input) error {
m := opts.env.Metadata
envList, err := opts.client.EnvironmentList(m.Namespace)
if err != nil {
return err
} else if len(envList) > 0 {
consolemsg.Verbose(2, "%d environment(s) are present in the %s namespace. "+
console.Verbose(2, "%d environment(s) are present in the %s namespace. "+
"These environments are not isolated from each other; use separate namespaces if you need isolation.",
len(envList), m.Namespace)
}
// if we're writing a spec, don't call the API
// save to spec file
if flags.Bool(flag.SPEC_SPEC) {
if input.Bool(flagkey.SpecSave) {
specFile := fmt.Sprintf("env-%v.yaml", m.Name)
err = spec.SpecSave(*opts.env, specFile)
if err != nil {
@@ -103,39 +102,33 @@ func (opts *CreateSubCommand) run(flags cli.Input) error {
}
// createEnvironmentFromCmd creates environment initialized with CLI input.
func createEnvironmentFromCmd(flags cli.Input) (*fv1.Environment, error) {
e := &multierror.Error{}
func createEnvironmentFromCmd(input cli.Input) (*fv1.Environment, error) {
e := utils.MultiErrorWithFormat()
envNamespace := flags.String(flag.ENVIRONMENT_NAMESPACE)
envBuildCmd := flags.String(flag.ENVIRONMENT_BUILDCOMMAND)
envExternalNetwork := flags.Bool(flag.ENVIRONMENT_EXTERNAL_NETWORK)
keepArchive := flags.Bool(flag.ENVIRONMENT_KEEPARCHIVE)
envName := input.String(flagkey.EnvName)
envImg := input.String(flagkey.EnvImage)
envNamespace := input.String(flagkey.NamespaceEnvironment)
envBuildCmd := input.String(flagkey.EnvBuildcommand)
envExternalNetwork := input.Bool(flagkey.EnvExternalNetwork)
keepArchive := input.Bool(flagkey.EnvKeeparchive)
envGracePeriod := input.Int64(flagkey.EnvGracePeriod)
envName := flags.String(flag.RESOURCE_NAME)
if len(envName) == 0 {
e = multierror.Append(e, errors.New("Need a name, use --name."))
}
envImg := flags.String(flag.ENVIRONMENT_IMAGE)
if len(envImg) == 0 {
e = multierror.Append(e, errors.New("Need an image, use --image."))
}
envGracePeriod := flags.Int64(flag.ENVIRONMENT_GRACE_PERIOD)
if envGracePeriod <= 0 {
envGracePeriod = 360
}
envVersion := flags.Int(flag.ENVIRONMENT_VERSION)
envVersion := input.Int(flagkey.EnvVersion)
// Environment API interface version is not specified and
// builder image is empty, set default interface version
if envVersion == 0 {
envVersion = 1
}
envBuilderImg := flags.String(flag.ENVIRONMENT_BUILDER)
poolsize := input.Int(flagkey.EnvPoolsize)
if input.IsSet(flagkey.EnvPoolsize) {
// TODO: remove silently version 3 assignment, we need to warn user to set it explicitly.
envVersion = 3
}
envBuilderImg := input.String(flagkey.EnvBuilderImage)
if len(envBuilderImg) > 0 {
if !flags.IsSet(flag.ENVIRONMENT_VERSION) {
if !input.IsSet(flagkey.EnvVersion) {
// TODO: remove set env version to 2 silently, we need to warn user to set it explicitly.
envVersion = 2
}
@@ -144,14 +137,7 @@ func createEnvironmentFromCmd(flags cli.Input) (*fv1.Environment, error) {
}
}
poolsize := 3
if flags.IsSet(flag.ENVIRONMENT_POOLSIZE) {
poolsize = flags.Int(flag.ENVIRONMENT_POOLSIZE)
// TODO: remove silently version 3 assignment, we need to warn user to set it explicitly.
envVersion = 3
}
resourceReq, err := util.GetResourceReqs(flags, nil)
resourceReq, err := util.GetResourceReqs(input, nil)
if err != nil {
e = multierror.Append(e, err)
}
+10 -9
View File
@@ -20,10 +20,11 @@ import (
"fmt"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/flag"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
)
@@ -31,24 +32,24 @@ type DeleteSubCommand struct {
client *client.Client
}
func Delete(flags cli.Input) error {
c, err := util.GetServer(flags)
func Delete(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := DeleteSubCommand{
client: c,
}
return opts.do(flags)
return opts.do(input)
}
func (opts *DeleteSubCommand) do(flags cli.Input) error {
m, err := util.GetMetadata(flag.RESOURCE_NAME, flag.ENVIRONMENT_NAMESPACE, flags)
if err != nil {
return err
func (opts *DeleteSubCommand) do(input cli.Input) error {
m := &metav1.ObjectMeta{
Name: input.String(flagkey.EnvName),
Namespace: input.String(flagkey.NamespaceEnvironment),
}
err = opts.client.EnvironmentDelete(m)
err := opts.client.EnvironmentDelete(m)
if err != nil {
return errors.Wrap(err, "error deleting environment")
}
+9 -8
View File
@@ -22,10 +22,11 @@ import (
"text/tabwriter"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/flag"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
)
@@ -33,21 +34,21 @@ type GetSubCommand struct {
client *client.Client
}
func Get(flags cli.Input) error {
c, err := util.GetServer(flags)
func Get(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := GetSubCommand{
client: c,
}
return opts.do(flags)
return opts.do(input)
}
func (opts *GetSubCommand) do(flags cli.Input) error {
m, err := util.GetMetadata(flag.RESOURCE_NAME, flag.ENVIRONMENT_NAMESPACE, flags)
if err != nil {
return err
func (opts *GetSubCommand) do(input cli.Input) error {
m := &metav1.ObjectMeta{
Name: input.String(flagkey.EnvName),
Namespace: input.String(flagkey.NamespaceEnvironment),
}
env, err := opts.client.EnvironmentGet(m)
+6 -8
View File
@@ -25,7 +25,7 @@ import (
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/flag"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
)
@@ -33,21 +33,19 @@ type ListSubCommand struct {
client *client.Client
}
func List(flags cli.Input) error {
c, err := util.GetServer(flags)
func List(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := ListSubCommand{
client: c,
}
return opts.do(flags)
return opts.do(input)
}
func (opts *ListSubCommand) do(flags cli.Input) error {
envNamespace := flags.String(flag.ENVIRONMENT_NAMESPACE)
envs, err := opts.client.EnvironmentList(envNamespace)
func (opts *ListSubCommand) do(input cli.Input) error {
envs, err := opts.client.EnvironmentList(input.String(flagkey.NamespaceEnvironment))
if err != nil {
return errors.Wrap(err, "error listing environments")
}
+34 -33
View File
@@ -21,12 +21,14 @@ import (
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/flag"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
"github.com/fission/fission/pkg/utils"
)
type UpdateSubCommand struct {
@@ -34,37 +36,35 @@ type UpdateSubCommand struct {
env *fv1.Environment
}
func Update(flags cli.Input) error {
c, err := util.GetServer(flags)
func Update(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := UpdateSubCommand{
client: c,
}
return opts.do(flags)
return opts.do(input)
}
func (opts *UpdateSubCommand) do(flags cli.Input) error {
err := opts.complete(flags)
func (opts *UpdateSubCommand) do(input cli.Input) error {
err := opts.complete(input)
if err != nil {
return err
}
return opts.run(flags)
return opts.run(input)
}
func (opts *UpdateSubCommand) complete(flags cli.Input) error {
m, err := util.GetMetadata(flag.RESOURCE_NAME, flag.ENVIRONMENT_NAMESPACE, flags)
if err != nil {
return err
}
env, err := opts.client.EnvironmentGet(m)
func (opts *UpdateSubCommand) complete(input cli.Input) error {
env, err := opts.client.EnvironmentGet(&metav1.ObjectMeta{
Name: input.String(flagkey.EnvName),
Namespace: input.String(flagkey.NamespaceEnvironment),
})
if err != nil {
return errors.Wrap(err, "error finding environment")
}
env, err = updateExistingEnvironmentWithCmd(env, flags)
env, err = updateExistingEnvironmentWithCmd(env, input)
if err != nil {
return err
}
@@ -73,7 +73,7 @@ func (opts *UpdateSubCommand) complete(flags cli.Input) error {
return nil
}
func (opts *UpdateSubCommand) run(flags cli.Input) error {
func (opts *UpdateSubCommand) run(input cli.Input) error {
_, err := opts.client.EnvironmentUpdate(opts.env)
if err != nil {
return errors.Wrap(err, "error updating environment")
@@ -84,13 +84,13 @@ func (opts *UpdateSubCommand) run(flags cli.Input) error {
}
// updateExistingEnvironmentWithCmd updates a existing environment's value based on CLI input.
func updateExistingEnvironmentWithCmd(env *fv1.Environment, flags cli.Input) (*fv1.Environment, error) {
e := &multierror.Error{}
func updateExistingEnvironmentWithCmd(env *fv1.Environment, input cli.Input) (*fv1.Environment, error) {
e := utils.MultiErrorWithFormat()
envImg := flags.String(flag.ENVIRONMENT_IMAGE)
envBuilderImg := flags.String(flag.ENVIRONMENT_BUILDER)
envBuildCmd := flags.String(flag.ENVIRONMENT_BUILDCOMMAND)
envExternalNetwork := flags.Bool(flag.ENVIRONMENT_EXTERNAL_NETWORK)
envImg := input.String(flagkey.EnvImage)
envBuilderImg := input.String(flagkey.EnvBuilderImage)
envBuildCmd := input.String(flagkey.EnvBuildcommand)
envExternalNetwork := input.Bool(flagkey.EnvExternalNetwork)
if len(envImg) == 0 && len(envBuilderImg) == 0 && len(envBuildCmd) == 0 {
e = multierror.Append(e, errors.New("need --image to specify env image, or use --builder to specify env builder, or use --buildcmd to specify new build command"))
@@ -111,25 +111,26 @@ func updateExistingEnvironmentWithCmd(env *fv1.Environment, flags cli.Input) (*f
env.Spec.Builder.Command = envBuildCmd
}
if flags.IsSet(flag.ENVIRONMENT_POOLSIZE) {
env.Spec.Poolsize = flags.Int(flag.ENVIRONMENT_POOLSIZE)
if input.IsSet(flagkey.EnvPoolsize) {
env.Spec.Poolsize = input.Int(flagkey.EnvPoolsize)
}
if flags.IsSet(flag.ENVIRONMENT_GRACE_PERIOD) {
env.Spec.TerminationGracePeriod = flags.Int64(flag.ENVIRONMENT_GRACE_PERIOD)
if input.IsSet(flagkey.EnvGracePeriod) {
env.Spec.TerminationGracePeriod = input.Int64(flagkey.EnvGracePeriod)
}
if flags.IsSet(flag.ENVIRONMENT_KEEPARCHIVE) {
env.Spec.KeepArchive = flags.Bool(flag.ENVIRONMENT_KEEPARCHIVE)
if input.IsSet(flagkey.EnvKeeparchive) {
env.Spec.KeepArchive = input.Bool(flagkey.EnvKeeparchive)
}
env.Spec.AllowAccessToExternalNetwork = envExternalNetwork
if flags.IsSet(flag.RUNTIME_MINCPU) || flags.IsSet(flag.RUNTIME_MAXCPU) ||
flags.IsSet(flag.RUNTIME_MINMEMORY) || flags.IsSet(flag.RUNTIME_MAXMEMORY) ||
flags.IsSet(flag.RUNTIME_MINSCALE) || flags.IsSet(flag.RUNTIME_MAXSCALE) {
e = multierror.Append(e, errors.New("updating resource limits/requests for existing environments is currently unsupported; re-create the environment instead"))
}
// TODO: allow to update resource.
//if input.IsSet(flagkey.RuntimeMincpu) || input.IsSet(flagkey.RuntimeMaxcpu) ||
// input.IsSet(flagkey.RuntimeMinmemory) || input.IsSet(flagkey.RuntimeMaxmemory) ||
// input.IsSet(flagkey.ReplicasMinscale) || input.IsSet(flagkey.ReplicasMaxscale) {
// e = multierror.Append(e, errors.New("updating resource limits/requests for existing environments is currently unsupported; re-create the environment instead"))
//}
if e.ErrorOrNil() != nil {
return nil, e.ErrorOrNil()
+135
View File
@@ -0,0 +1,135 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package function
import (
"github.com/spf13/cobra"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
"github.com/fission/fission/pkg/fission-cli/flag"
)
func Commands() *cobra.Command {
createCmd := &cobra.Command{
Use: "create",
Short: "Create a function (and optionally, an HTTP route to it)",
RunE: wrapper.Wrapper(Create),
}
wrapper.SetFlags(createCmd, flag.FlagSet{
Required: []flag.Flag{flag.FnNameFlag},
Optional: []flag.Flag{flag.NamespaceFunctionFlag, flag.NamespaceEnvironmentFlag, flag.SpecSaveFlag,
flag.FnEnvNameFlag, flag.FnCodeFlag, flag.PkgSrcArchiveFlag, flag.PkgDeployArchiveFlag, flag.FnKeepURLFlag,
flag.FnEntryPointFlag, flag.FnBuildCmdFlag, flag.FnPkgNameFlag, flag.HtUrlFlag, flag.HtMethodFlag,
flag.RunTimeMinCPUFlag, flag.RunTimeMaxCPUFlag, flag.RunTimeMinMemoryFlag, flag.RunTimeMaxMemoryFlag,
flag.ReplicasMinFlag, flag.ReplicasMaxFlag, flag.FnExecutorTypeFlag, flag.RunTimeTargetCPUFlag,
flag.FnCfgMapFlag, flag.FnSecretFlag, flag.FnSpecializationTimeoutFlag, flag.FnExecutionTimeoutFlag},
})
getCmd := &cobra.Command{
Use: "get",
Aliases: []string{},
Short: "Get function source code",
RunE: wrapper.Wrapper(Get),
}
wrapper.SetFlags(getCmd, flag.FlagSet{
Required: []flag.Flag{flag.FnNameFlag},
Optional: []flag.Flag{flag.NamespaceFunctionFlag},
})
getmetaCmd := &cobra.Command{
Use: "getmeta",
Aliases: []string{},
Short: "Get function metadata",
RunE: wrapper.Wrapper(GetMeta),
}
wrapper.SetFlags(getmetaCmd, flag.FlagSet{
Required: []flag.Flag{flag.FnNameFlag},
Optional: []flag.Flag{flag.NamespaceFunctionFlag},
})
updateCmd := &cobra.Command{
Use: "update",
Aliases: []string{},
Short: "Update a function",
RunE: wrapper.Wrapper(Update),
}
wrapper.SetFlags(updateCmd, flag.FlagSet{
Required: []flag.Flag{flag.FnNameFlag},
Optional: []flag.Flag{flag.NamespaceFunctionFlag, flag.NamespaceEnvironmentFlag, flag.SpecSaveFlag,
flag.FnCodeFlag, flag.PkgSrcArchiveFlag, flag.PkgDeployArchiveFlag,
flag.FnKeepURLFlag, flag.FnEntryPointFlag, flag.FnBuildCmdFlag, flag.FnPkgNameFlag, flag.HtUrlFlag,
flag.HtMethodFlag, flag.RunTimeMinCPUFlag, flag.RunTimeMaxCPUFlag, flag.RunTimeMinMemoryFlag,
flag.RunTimeMaxMemoryFlag, flag.ReplicasMinFlag, flag.ReplicasMaxFlag, flag.FnExecutorTypeFlag,
flag.RunTimeTargetCPUFlag, flag.FnCfgMapFlag, flag.FnSecretFlag, flag.FnSpecializationTimeoutFlag,
flag.FnExecutionTimeoutFlag, flag.PkgForceFlag},
})
deleteCmd := &cobra.Command{
Use: "delete",
Aliases: []string{},
Short: "Delete a function",
RunE: wrapper.Wrapper(Delete),
}
wrapper.SetFlags(deleteCmd, flag.FlagSet{
Required: []flag.Flag{flag.FnNameFlag},
Optional: []flag.Flag{flag.NamespaceFunctionFlag},
})
listCmd := &cobra.Command{
Use: "list",
Aliases: []string{},
Short: "List all functions in a namespace if specified, else, list functions across all namespaces",
RunE: wrapper.Wrapper(List),
}
wrapper.SetFlags(listCmd, flag.FlagSet{
Optional: []flag.Flag{flag.NamespaceFunctionFlag},
})
logsCmd := &cobra.Command{
Use: "log",
Aliases: []string{"logs"},
Short: "Display function logs",
RunE: wrapper.Wrapper(Log),
}
wrapper.SetFlags(logsCmd, flag.FlagSet{
Required: []flag.Flag{flag.FnNameFlag},
Optional: []flag.Flag{flag.NamespaceFunctionFlag, flag.FnLogPodFlag, flag.FnLogFollowFlag,
flag.FnLogDetailFlag, flag.FnLogDBTypeFlag, flag.FnLogReverseQueryFlag, flag.FnLogCountFlag},
})
testCmd := &cobra.Command{
Use: "test",
Aliases: []string{},
Short: "Test a function",
RunE: wrapper.Wrapper(Test),
}
wrapper.SetFlags(testCmd, flag.FlagSet{
Required: []flag.Flag{flag.FnNameFlag},
Optional: []flag.Flag{flag.NamespaceFunctionFlag, flag.HtMethodFlag, flag.FnTestBodyFlag,
flag.FnTestHeaderFlag, flag.FnTestQueryFlag, flag.FnTestTimeoutFlag},
})
command := &cobra.Command{
Use: "function",
Aliases: []string{"fn"},
Short: "Create, update and manage functions",
}
command.AddCommand(createCmd, getCmd, getmetaCmd, updateCmd, deleteCmd, listCmd, logsCmd, testCmd)
return command
}
+58 -66
View File
@@ -33,7 +33,8 @@ import (
"github.com/fission/fission/pkg/fission-cli/cmd/httptrigger"
_package "github.com/fission/fission/pkg/fission-cli/cmd/package"
"github.com/fission/fission/pkg/fission-cli/cmd/spec"
"github.com/fission/fission/pkg/fission-cli/consolemsg"
"github.com/fission/fission/pkg/fission-cli/console"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
"github.com/fission/fission/pkg/types"
)
@@ -49,44 +50,40 @@ type CreateSubCommand struct {
specFile string
}
func Create(flags cli.Input) error {
c, err := util.GetServer(flags)
func Create(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := CreateSubCommand{
client: c,
}
return opts.do(flags)
return opts.do(input)
}
func (opts *CreateSubCommand) do(flags cli.Input) error {
err := opts.complete(flags)
func (opts *CreateSubCommand) do(input cli.Input) error {
err := opts.complete(input)
if err != nil {
return err
}
return opts.run(flags)
return opts.run(input)
}
func (opts *CreateSubCommand) complete(flags cli.Input) error {
fnNamespace := flags.String("fnNamespace")
envNamespace := flags.String("envNamespace")
fnName := flags.String("name")
if len(fnName) == 0 {
return errors.New("need --name argument")
}
func (opts *CreateSubCommand) complete(input cli.Input) error {
fnName := input.String(flagkey.FnName)
fnNamespace := input.String(flagkey.NamespaceFunction)
envNamespace := input.String(flagkey.NamespaceEnvironment)
// user wants a spec, create a yaml file with package and function
toSpec := false
if flags.Bool("spec") {
if input.Bool(flagkey.SpecSave) {
toSpec = true
opts.specFile = fmt.Sprintf("function-%v.yaml", fnName)
}
specDir := util.GetSpecDir(flags)
specDir := util.GetSpecDir(input)
// check for unique function names within a namespace
metadata, err := util.GetMetadata("name", "fnNamespace", flags)
metadata, err := util.GetMetadata(flagkey.FnName, flagkey.NamespaceFunction, input)
if err != nil {
return err
}
@@ -98,23 +95,23 @@ func (opts *CreateSubCommand) complete(flags cli.Input) error {
return errors.New("a function with the same name already exists")
}
entrypoint := flags.String("entrypoint")
entrypoint := input.String(flagkey.FnEntrypoint)
fnTimeout := flags.Int("fntimeout")
fnTimeout := input.Int(flagkey.FnExecutionTimeout)
if fnTimeout <= 0 {
return errors.New("fntimeout must be greater than 0")
}
pkgName := flags.String("pkg")
pkgName := input.String(flagkey.FnPackageName)
secretNames := flags.StringSlice("secret")
cfgMapNames := flags.StringSlice("configmap")
secretNames := input.StringSlice(flagkey.FnSecret)
cfgMapNames := input.StringSlice(flagkey.FnCfgMap)
invokeStrategy, err := getInvokeStrategy(flags, nil)
invokeStrategy, err := getInvokeStrategy(input, nil)
if err != nil {
return err
}
resourceReq, err := util.GetResourceReqs(flags, &apiv1.ResourceRequirements{})
resourceReq, err := util.GetResourceReqs(input, &apiv1.ResourceRequirements{})
if err != nil {
return err
}
@@ -132,13 +129,13 @@ func (opts *CreateSubCommand) complete(flags cli.Input) error {
}
pkgMetadata = &pkg.Metadata
envName = pkg.Spec.Environment.Name
if envName != flags.String("env") {
consolemsg.Warn("Function's environment is different than package's environment, package's environment will be used for creating function")
if envName != input.String(flagkey.FnEnvironmentName) {
console.Warn("Function's environment is different than package's environment, package's environment will be used for creating function")
}
envNamespace = pkg.Spec.Environment.Namespace
} else {
// need to specify environment for creating new package
envName = flags.String("env")
envName = input.String(flagkey.FnEnvironmentName)
if len(envName) == 0 {
return errors.New("need --env argument")
}
@@ -151,21 +148,21 @@ func (opts *CreateSubCommand) complete(flags cli.Input) error {
})
if err != nil {
if e, ok := err.(ferror.Error); ok && e.Code == ferror.ErrorNotFound {
consolemsg.Warn(fmt.Sprintf("Environment \"%v\" does not exist. Please create the environment before executing the function. \nFor example: `fission env create --name %v --envns %v --image <image>`\n", envName, envName, envNamespace))
console.Warn(fmt.Sprintf("Environment \"%v\" does not exist. Please create the environment before executing the function. \nFor example: `fission env create --name %v --envns %v --image <image>`\n", envName, envName, envNamespace))
} else {
return errors.Wrap(err, "error retrieving environment information")
}
}
}
srcArchiveFiles := flags.StringSlice("src")
srcArchiveFiles := input.StringSlice(flagkey.PkgSrcArchive)
var deployArchiveFiles []string
noZip := false
code := flags.String("code")
code := input.String(flagkey.FnCode)
if len(code) == 0 {
deployArchiveFiles = flags.StringSlice("deploy")
deployArchiveFiles = input.StringSlice(flagkey.PkgDeployArchive)
} else {
deployArchiveFiles = append(deployArchiveFiles, flags.String("code"))
deployArchiveFiles = append(deployArchiveFiles, input.String(flagkey.FnCode))
noZip = true
}
// return error when both src & deploy archive are empty
@@ -173,11 +170,11 @@ func (opts *CreateSubCommand) complete(flags cli.Input) error {
return errors.New("need --code or --deploy or --src argument")
}
buildcmd := flags.String("buildcmd")
keepURL := flags.Bool("keepurl")
buildcmd := input.String(flagkey.PkgBuildCmd)
keepURL := input.Bool(flagkey.PkgKeepURL)
// create new package in the same namespace as the function.
pkgMetadata, err = _package.CreatePackage(flags, opts.client, fnNamespace, envName, envNamespace,
pkgMetadata, err = _package.CreatePackage(input, opts.client, fnNamespace, envName, envNamespace,
srcArchiveFiles, deployArchiveFiles, buildcmd, specDir, opts.specFile, noZip, keepURL)
if err != nil {
return errors.Wrap(err, "error creating package")
@@ -196,7 +193,7 @@ func (opts *CreateSubCommand) complete(flags cli.Input) error {
})
if err != nil {
if k8serrors.IsNotFound(err) {
consolemsg.Warn(fmt.Sprintf("Secret %s not found in Namespace: %s. Secret needs to be present in the same namespace as function", secretName, fnNamespace))
console.Warn(fmt.Sprintf("Secret %s not found in Namespace: %s. Secret needs to be present in the same namespace as function", secretName, fnNamespace))
} else {
return errors.Wrap(err, "error checking secret")
}
@@ -220,7 +217,7 @@ func (opts *CreateSubCommand) complete(flags cli.Input) error {
})
if err != nil {
if k8serrors.IsNotFound(err) {
consolemsg.Warn(fmt.Sprintf("ConfigMap %s not found in Namespace: %s. ConfigMap needs to be present in the same namespace as function", cfgMapName, fnNamespace))
console.Warn(fmt.Sprintf("ConfigMap %s not found in Namespace: %s. ConfigMap needs to be present in the same namespace as function", cfgMapName, fnNamespace))
} else {
return errors.Wrap(err, "error checking configmap")
}
@@ -268,7 +265,7 @@ func (opts *CreateSubCommand) complete(flags cli.Input) error {
// It also prints warning/error if necessary.
func (opts *CreateSubCommand) run(flags cli.Input) error {
// if we're writing a spec, don't create the function
if flags.Bool("spec") {
if flags.Bool(flagkey.SpecSave) {
err := spec.SpecSave(*opts.function, opts.specFile)
if err != nil {
return errors.Wrap(err, "error creating function spec")
@@ -284,7 +281,7 @@ func (opts *CreateSubCommand) run(flags cli.Input) error {
fmt.Printf("function '%v' created\n", opts.function.Metadata.Name)
// Allow the user to specify an HTTP trigger while creating a function.
triggerUrl := flags.String("url")
triggerUrl := flags.String(flagkey.HtUrl)
if len(triggerUrl) == 0 {
return nil
}
@@ -292,7 +289,7 @@ func (opts *CreateSubCommand) run(flags cli.Input) error {
triggerUrl = fmt.Sprintf("/%s", triggerUrl)
}
method, err := httptrigger.GetMethod(flags.String("method"))
method, err := httptrigger.GetMethod(flags.String(flagkey.HtMethod))
if err != nil {
return errors.Wrap(err, "error getting HTTP trigger method")
}
@@ -325,7 +322,7 @@ func getInvokeStrategy(flags cli.Input, existingInvokeStrategy *fv1.InvokeStrate
var fnExecutor, newFnExecutor fv1.ExecutorType
switch flags.String("executortype") {
switch flags.String(flagkey.FnExecutorType) {
case "":
fallthrough
case types.ExecutorTypePoolmgr:
@@ -340,24 +337,24 @@ func getInvokeStrategy(flags cli.Input, existingInvokeStrategy *fv1.InvokeStrate
fnExecutor = existingInvokeStrategy.ExecutionStrategy.ExecutorType
// override the executor type if user specified a new executor type
if flags.IsSet("executortype") {
if flags.IsSet(flagkey.FnExecutorType) {
fnExecutor = newFnExecutor
}
} else {
fnExecutor = newFnExecutor
}
if flags.IsSet("specializationtimeout") && fnExecutor != types.ExecutorTypeNewdeploy {
return nil, errors.New("specializationtimeout flag is only applicable for newdeploy type of executor")
if flags.IsSet(flagkey.FnSpecializationTimeout) && fnExecutor != types.ExecutorTypeNewdeploy {
return nil, errors.Errorf("%v flag is only applicable for newdeploy type of executor", flagkey.FnSpecializationTimeout)
}
if fnExecutor == types.ExecutorTypePoolmgr {
if flags.IsSet("targetcpu") || flags.IsSet("minscale") || flags.IsSet("maxscale") {
if flags.IsSet(flagkey.RuntimeTargetcpu) || flags.IsSet(flagkey.ReplicasMinscale) || flags.IsSet(flagkey.ReplicasMaxscale) {
return nil, errors.New("to set target CPU or min/max scale for function, please specify \"--executortype newdeploy\"")
}
if flags.IsSet("mincpu") || flags.IsSet("maxcpu") || flags.IsSet("minmemory") || flags.IsSet("maxmemory") {
consolemsg.Warn("To limit CPU/Memory for function with executor type \"poolmgr\", please specify resources limits when creating environment")
if flags.IsSet(flagkey.RuntimeMincpu) || flags.IsSet(flagkey.RuntimeMaxcpu) || flags.IsSet(flagkey.RuntimeMinmemory) || flags.IsSet(flagkey.RuntimeMaxmemory) {
console.Warn("To limit CPU/Memory for function with executor type \"poolmgr\", please specify resources limits when creating environment")
}
strategy = &fv1.InvokeStrategy{
StrategyType: fv1.StrategyTypeExecution,
@@ -379,33 +376,33 @@ func getInvokeStrategy(flags cli.Input, existingInvokeStrategy *fv1.InvokeStrate
specializationTimeout = existingInvokeStrategy.ExecutionStrategy.SpecializationTimeout
}
if flags.IsSet("targetcpu") {
if flags.IsSet(flagkey.RuntimeTargetcpu) {
targetCPU, err = getTargetCPU(flags)
if err != nil {
return nil, err
}
}
if flags.IsSet("minscale") {
minScale = flags.Int("minscale")
if flags.IsSet(flagkey.ReplicasMinscale) {
minScale = flags.Int(flagkey.ReplicasMinscale)
}
if flags.IsSet("maxscale") {
maxScale = flags.Int("maxscale")
if flags.IsSet(flagkey.ReplicasMaxscale) {
maxScale = flags.Int(flagkey.ReplicasMaxscale)
if maxScale <= 0 {
return nil, errors.New("maxscale must be greater than 0")
return nil, errors.Errorf("%v must be greater than 0", flagkey.ReplicasMaxscale)
}
}
if flags.IsSet("specializationtimeout") {
specializationTimeout = flags.Int("specializationtimeout")
if flags.IsSet(flagkey.FnSpecializationTimeout) {
specializationTimeout = flags.Int(flagkey.FnSpecializationTimeout)
if specializationTimeout < fv1.DefaultSpecializationTimeOut {
return nil, errors.New("specializationtimeout must be greater than or equal to 120 seconds")
return nil, errors.Errorf("%v must be greater than or equal to 120 seconds", flagkey.FnSpecializationTimeout)
}
}
if minScale > maxScale {
return nil, fmt.Errorf("minscale provided: %v can not be greater than maxscale value %v", minScale, maxScale)
return nil, fmt.Errorf("minscale (%v) can not be greater than maxscale (%v)", minScale, maxScale)
}
// Right now a simple single case strategy implementation
@@ -426,14 +423,9 @@ func getInvokeStrategy(flags cli.Input, existingInvokeStrategy *fv1.InvokeStrate
}
func getTargetCPU(flags cli.Input) (int, error) {
var targetCPU int
if flags.IsSet("targetcpu") {
targetCPU = flags.Int("targetcpu")
if targetCPU <= 0 || targetCPU > 100 {
return 0, errors.New("TargetCPU must be a value between 1 - 100")
}
} else {
targetCPU = DEFAULT_TARGET_CPU_PERCENTAGE
targetCPU := flags.Int(flagkey.RuntimeTargetcpu)
if targetCPU <= 0 || targetCPU > 100 {
return 0, errors.Errorf("%v must be a value between 1 - 100", flagkey.RuntimeTargetcpu)
}
return targetCPU, nil
}
+10 -8
View File
@@ -20,9 +20,11 @@ import (
"fmt"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
)
@@ -30,24 +32,24 @@ type DeleteSubCommand struct {
client *client.Client
}
func Delete(flags cli.Input) error {
c, err := util.GetServer(flags)
func Delete(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := DeleteSubCommand{
client: c,
}
return opts.do(flags)
return opts.do(input)
}
func (opts *DeleteSubCommand) do(flags cli.Input) error {
m, err := util.GetMetadata("name", "fnNamespace", flags)
if err != nil {
return err
func (opts *DeleteSubCommand) do(input cli.Input) error {
m := &metav1.ObjectMeta{
Name: input.String(flagkey.FnName),
Namespace: input.String(flagkey.NamespaceFunction),
}
err = opts.client.FunctionDelete(m)
err := opts.client.FunctionDelete(m)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("delete function '%v'", m.Name))
}
+30 -29
View File
@@ -18,6 +18,7 @@ package function
import (
"fmt"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"testing"
"github.com/stretchr/testify/assert"
@@ -47,7 +48,7 @@ func TestGetInvokeStrategy(t *testing.T) {
},
{
// case: executor type set to poolmgr
testArgs: map[string]interface{}{"executortype": fv1.ExecutorTypePoolmgr},
testArgs: map[string]interface{}{flagkey.FnExecutorType: fv1.ExecutorTypePoolmgr},
existingInvokeStrategy: nil,
expectedResult: &fv1.InvokeStrategy{
StrategyType: fv1.StrategyTypeExecution,
@@ -59,7 +60,7 @@ func TestGetInvokeStrategy(t *testing.T) {
},
{
// case: executor type set to newdeploy
testArgs: map[string]interface{}{"executortype": fv1.ExecutorTypeNewdeploy},
testArgs: map[string]interface{}{flagkey.FnExecutorType: fv1.ExecutorTypeNewdeploy},
existingInvokeStrategy: nil,
expectedResult: &fv1.InvokeStrategy{
StrategyType: fv1.StrategyTypeExecution,
@@ -75,7 +76,7 @@ func TestGetInvokeStrategy(t *testing.T) {
},
{
// case: executor type change from poolmgr to newdeploy
testArgs: map[string]interface{}{"executortype": fv1.ExecutorTypeNewdeploy},
testArgs: map[string]interface{}{flagkey.FnExecutorType: fv1.ExecutorTypeNewdeploy},
existingInvokeStrategy: &fv1.InvokeStrategy{
StrategyType: fv1.StrategyTypeExecution,
ExecutionStrategy: fv1.ExecutionStrategy{
@@ -96,7 +97,7 @@ func TestGetInvokeStrategy(t *testing.T) {
},
{
// case: executor type change from newdeploy to poolmgr
testArgs: map[string]interface{}{"executortype": fv1.ExecutorTypePoolmgr},
testArgs: map[string]interface{}{flagkey.FnExecutorType: fv1.ExecutorTypePoolmgr},
existingInvokeStrategy: &fv1.InvokeStrategy{
StrategyType: fv1.StrategyTypeExecution,
ExecutionStrategy: fv1.ExecutionStrategy{
@@ -118,9 +119,9 @@ func TestGetInvokeStrategy(t *testing.T) {
{
// case: minscale < maxscale
testArgs: map[string]interface{}{
"executortype": fv1.ExecutorTypeNewdeploy,
"minscale": 2,
"maxscale": 3,
flagkey.FnExecutorType: fv1.ExecutorTypeNewdeploy,
flagkey.ReplicasMinscale: 2,
flagkey.ReplicasMaxscale: 3,
},
existingInvokeStrategy: nil,
expectedResult: &fv1.InvokeStrategy{
@@ -138,9 +139,9 @@ func TestGetInvokeStrategy(t *testing.T) {
{
// case: minscale > maxscale
testArgs: map[string]interface{}{
"executortype": fv1.ExecutorTypeNewdeploy,
"minscale": 5,
"maxscale": 3,
flagkey.FnExecutorType: fv1.ExecutorTypeNewdeploy,
flagkey.ReplicasMinscale: 5,
flagkey.ReplicasMaxscale: 3,
},
existingInvokeStrategy: nil,
expectedResult: nil,
@@ -149,8 +150,8 @@ func TestGetInvokeStrategy(t *testing.T) {
{
// case: maxscale not specified
testArgs: map[string]interface{}{
"executortype": fv1.ExecutorTypeNewdeploy,
"minscale": 5,
flagkey.FnExecutorType: fv1.ExecutorTypeNewdeploy,
flagkey.ReplicasMinscale: 5,
},
existingInvokeStrategy: nil,
expectedResult: nil,
@@ -159,8 +160,8 @@ func TestGetInvokeStrategy(t *testing.T) {
{
// case: minscale not specified
testArgs: map[string]interface{}{
"executortype": fv1.ExecutorTypeNewdeploy,
"maxscale": 3,
flagkey.FnExecutorType: fv1.ExecutorTypeNewdeploy,
flagkey.ReplicasMaxscale: 3,
},
existingInvokeStrategy: nil,
expectedResult: &fv1.InvokeStrategy{
@@ -178,8 +179,8 @@ func TestGetInvokeStrategy(t *testing.T) {
{
// case: maxscale set to 0
testArgs: map[string]interface{}{
"executortype": fv1.ExecutorTypeNewdeploy,
"maxscale": 0,
flagkey.FnExecutorType: fv1.ExecutorTypeNewdeploy,
flagkey.ReplicasMaxscale: 0,
},
existingInvokeStrategy: nil,
expectedResult: nil,
@@ -188,8 +189,8 @@ func TestGetInvokeStrategy(t *testing.T) {
{
// case: maxscale set to 9 when existing is 5
testArgs: map[string]interface{}{
"executortype": fv1.ExecutorTypeNewdeploy,
"maxscale": 9,
flagkey.FnExecutorType: fv1.ExecutorTypeNewdeploy,
flagkey.ReplicasMaxscale: 9,
},
existingInvokeStrategy: &fv1.InvokeStrategy{
StrategyType: fv1.StrategyTypeExecution,
@@ -216,7 +217,7 @@ func TestGetInvokeStrategy(t *testing.T) {
{
// case: change nothing for existing strategy
testArgs: map[string]interface{}{
"executortype": fv1.ExecutorTypeNewdeploy,
flagkey.FnExecutorType: fv1.ExecutorTypeNewdeploy,
},
existingInvokeStrategy: &fv1.InvokeStrategy{
StrategyType: fv1.StrategyTypeExecution,
@@ -243,8 +244,8 @@ func TestGetInvokeStrategy(t *testing.T) {
{
// case: set target cpu percentage
testArgs: map[string]interface{}{
"executortype": fv1.ExecutorTypeNewdeploy,
"targetcpu": 50,
flagkey.FnExecutorType: fv1.ExecutorTypeNewdeploy,
flagkey.RuntimeTargetcpu: 50,
},
existingInvokeStrategy: nil,
expectedResult: &fv1.InvokeStrategy{
@@ -262,8 +263,8 @@ func TestGetInvokeStrategy(t *testing.T) {
{
// case: change target cpu percentage
testArgs: map[string]interface{}{
"executortype": fv1.ExecutorTypeNewdeploy,
"targetcpu": 20,
flagkey.FnExecutorType: fv1.ExecutorTypeNewdeploy,
flagkey.RuntimeTargetcpu: 20,
},
existingInvokeStrategy: &fv1.InvokeStrategy{
StrategyType: fv1.StrategyTypeExecution,
@@ -290,8 +291,8 @@ func TestGetInvokeStrategy(t *testing.T) {
{
// case: change specializationtimeout
testArgs: map[string]interface{}{
"executortype": fv1.ExecutorTypeNewdeploy,
"specializationtimeout": 200,
flagkey.FnExecutorType: fv1.ExecutorTypeNewdeploy,
flagkey.FnSpecializationTimeout: 200,
},
existingInvokeStrategy: &fv1.InvokeStrategy{
StrategyType: fv1.StrategyTypeExecution,
@@ -317,8 +318,8 @@ func TestGetInvokeStrategy(t *testing.T) {
{
// case: specializationtimeout should not work for poolmgr
testArgs: map[string]interface{}{
"executortype": fv1.ExecutorTypePoolmgr,
"specializationtimeout": 10,
flagkey.FnExecutorType: fv1.ExecutorTypePoolmgr,
flagkey.FnSpecializationTimeout: 10,
},
existingInvokeStrategy: nil,
expectedResult: nil,
@@ -327,8 +328,8 @@ func TestGetInvokeStrategy(t *testing.T) {
{
// case: specializationtimeout should not be less than 120
testArgs: map[string]interface{}{
"executortype": fv1.ExecutorTypeNewdeploy,
"specializationtimeout": 90,
flagkey.FnExecutorType: fv1.ExecutorTypeNewdeploy,
flagkey.FnSpecializationTimeout: 90,
},
existingInvokeStrategy: nil,
expectedResult: nil,
+9 -10
View File
@@ -24,6 +24,7 @@ import (
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
)
@@ -31,24 +32,22 @@ type GetSubCommand struct {
client *client.Client
}
func Get(flags cli.Input) error {
c, err := util.GetServer(flags)
func Get(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := GetSubCommand{
client: c,
}
return opts.do(flags)
return opts.do(input)
}
func (opts *GetSubCommand) do(flags cli.Input) error {
m, err := util.GetMetadata("name", "fnNamespace", flags)
if err != nil {
return err
}
fn, err := opts.client.FunctionGet(m)
func (opts *GetSubCommand) do(input cli.Input) error {
fn, err := opts.client.FunctionGet(&metav1.ObjectMeta{
Name: input.String(flagkey.FnName),
Namespace: input.String(flagkey.NamespaceFunction),
})
if err != nil {
return errors.Wrap(err, "error getting function")
}
+10 -10
View File
@@ -22,9 +22,11 @@ import (
"text/tabwriter"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
)
@@ -32,24 +34,22 @@ type GetMetaSubCommand struct {
client *client.Client
}
func GetMeta(flags cli.Input) error {
c, err := util.GetServer(flags)
func GetMeta(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := GetMetaSubCommand{
client: c,
}
return opts.do(flags)
return opts.do(input)
}
func (opts *GetMetaSubCommand) do(flags cli.Input) error {
m, err := util.GetMetadata("name", "fnNamespace", flags)
if err != nil {
return err
}
fn, err := opts.client.FunctionGet(m)
func (opts *GetMetaSubCommand) do(input cli.Input) error {
fn, err := opts.client.FunctionGet(&metav1.ObjectMeta{
Name: input.String(flagkey.FnName),
Namespace: input.String(flagkey.NamespaceFunction),
})
if err != nil {
return errors.Wrap(err, "error getting function")
}
+6 -5
View File
@@ -26,6 +26,7 @@ import (
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
)
@@ -33,19 +34,19 @@ type ListSubCommand struct {
client *client.Client
}
func List(flags cli.Input) error {
c, err := util.GetServer(flags)
func List(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := ListSubCommand{
client: c,
}
return opts.do(flags)
return opts.do(input)
}
func (opts *ListSubCommand) do(flags cli.Input) error {
ns := flags.String("fnNamespace")
func (opts *ListSubCommand) do(input cli.Input) error {
ns := input.String(flagkey.NamespaceFunction)
fns, err := opts.client.FunctionList(ns)
if err != nil {
+16 -20
View File
@@ -22,9 +22,11 @@ import (
"time"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/logdb"
"github.com/fission/fission/pkg/fission-cli/util"
)
@@ -33,38 +35,32 @@ type LogSubCommand struct {
client *client.Client
}
func Log(flags cli.Input) error {
c, err := util.GetServer(flags)
func Log(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := LogSubCommand{
client: c,
}
return opts.do(flags)
return opts.do(input)
}
func (opts *LogSubCommand) do(flags cli.Input) error {
m, err := util.GetMetadata("name", "fnNamespace", flags)
if err != nil {
return err
}
func (opts *LogSubCommand) do(input cli.Input) error {
dbType := input.String(flagkey.FnLogDBType)
fnPod := input.String(flagkey.FnLogPod)
dbType := flags.String("dbtype")
if len(dbType) == 0 {
dbType = logdb.INFLUXDB
}
logReverseQuery := !input.Bool(flagkey.FnLogFollow) && input.Bool(flagkey.FnLogReverseQuery)
fnPod := flags.String("pod")
logReverseQuery := !flags.Bool("f") && flags.Bool("r")
recordLimit := flags.Int("recordcount")
recordLimit := input.Int(flagkey.FnLogCount)
if recordLimit <= 0 {
recordLimit = 1000
}
f, err := opts.client.FunctionGet(m)
f, err := opts.client.FunctionGet(&metav1.ObjectMeta{
Name: input.String(flagkey.FnName),
Namespace: input.String(flagkey.NamespaceFunction),
})
if err != nil {
return errors.Wrap(err, "error getting function")
}
@@ -104,7 +100,7 @@ func (opts *LogSubCommand) do(flags cli.Input) error {
return
}
for _, logEntry := range logEntries {
if flags.Bool("d") {
if input.Bool(flagkey.FnLogDetail) {
fmt.Printf("Timestamp: %s\nNamespace: %s\nFunction Name: %s\nFunction ID: %s\nPod: %s\nContainer: %s\nStream: %s\nLog: %s\n---\n",
logEntry.Timestamp, logEntry.Namespace, logEntry.FuncName, logEntry.FuncUid, logEntry.Pod, logEntry.Container, logEntry.Stream, logEntry.Message)
} else {
@@ -124,7 +120,7 @@ func (opts *LogSubCommand) do(flags cli.Input) error {
time.Sleep(1 * time.Second)
<-responseChan
if !flags.Bool("f") {
if !input.Bool(flagkey.FnLogFollow) {
ctx.Done()
break
}
+17 -16
View File
@@ -31,6 +31,7 @@ import (
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cmd/httptrigger"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
)
@@ -38,21 +39,21 @@ type TestSubCommand struct {
client *client.Client
}
func Test(flags cli.Input) error {
c, err := util.GetServer(flags)
func Test(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := TestSubCommand{
client: c,
}
return opts.do(flags)
return opts.do(input)
}
func (opts *TestSubCommand) do(flags cli.Input) error {
m, err := util.GetMetadata("name", "fnNamespace", flags)
if err != nil {
return err
func (opts *TestSubCommand) do(input cli.Input) error {
m := &metav1.ObjectMeta{
Name: input.String(flagkey.FnName),
Namespace: input.String(flagkey.NamespaceFunction),
}
routerURL := os.Getenv("FISSION_ROUTER")
@@ -76,7 +77,7 @@ func (opts *TestSubCommand) do(flags cli.Input) error {
if err != nil {
return err
}
queryParams := flags.StringSlice("query")
queryParams := input.StringSlice(flagkey.FnTestQuery)
if len(queryParams) > 0 {
query := url.Values{}
for _, q := range queryParams {
@@ -97,15 +98,15 @@ func (opts *TestSubCommand) do(flags cli.Input) error {
}
ctx := context.Background()
if deadline := flags.Duration("timeout"); deadline > 0 {
if deadline := input.Duration(flagkey.FnTestTimeout); deadline > 0 {
var closeCtx func()
ctx, closeCtx = context.WithTimeout(ctx, deadline)
defer closeCtx()
}
headers := flags.StringSlice("header")
headers := input.StringSlice(flagkey.FnTestHeader)
resp, err := doHTTPRequest(ctx, flags.String("method"), functionUrl.String(), flags.String("body"), headers)
resp, err := doHTTPRequest(ctx, input.String(flagkey.HtMethod), functionUrl.String(), input.String(flagkey.FnTestBody), headers)
if err != nil {
return err
}
@@ -123,9 +124,9 @@ func (opts *TestSubCommand) do(flags cli.Input) error {
}
fmt.Printf("Error calling function %s: %d; Please try again or fix the error: %s", m.Name, resp.StatusCode, string(body))
err = printPodLogs(flags)
err = printPodLogs(input)
if err != nil {
return Log(flags)
return Log(input)
}
return nil
@@ -157,8 +158,8 @@ func doHTTPRequest(ctx context.Context, method, url, body string, headers []stri
return resp, nil
}
func printPodLogs(flags cli.Input) error {
fnName := flags.String("name")
func printPodLogs(input cli.Input) error {
fnName := input.String(flagkey.FnName)
if len(fnName) == 0 {
return errors.New("need --name argument.")
}
@@ -174,7 +175,7 @@ func printPodLogs(flags cli.Input) error {
}
queryURL.Path = fmt.Sprintf("/proxy/logs/%s", fnName)
req, err := http.NewRequest("POST", queryURL.String(), nil)
req, err := http.NewRequest(http.MethodPost, queryURL.String(), nil)
if err != nil {
return errors.Wrap(err, "error creating logs request")
}
+35 -45
View File
@@ -18,6 +18,7 @@ package function
import (
"fmt"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/pkg/errors"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -27,7 +28,7 @@ import (
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
_package "github.com/fission/fission/pkg/fission-cli/cmd/package"
"github.com/fission/fission/pkg/fission-cli/consolemsg"
"github.com/fission/fission/pkg/fission-cli/console"
"github.com/fission/fission/pkg/fission-cli/util"
"github.com/fission/fission/pkg/types"
)
@@ -37,41 +38,30 @@ type UpdateSubCommand struct {
function *fv1.Function
}
func Update(flags cli.Input) error {
c, err := util.GetServer(flags)
func Update(input cli.Input) error {
c, err := util.GetServer(input)
if err != nil {
return err
}
opts := UpdateSubCommand{
client: c,
}
return opts.do(flags)
return opts.do(input)
}
func (opts *UpdateSubCommand) do(flags cli.Input) error {
err := opts.complete(flags)
func (opts *UpdateSubCommand) do(input cli.Input) error {
err := opts.complete(input)
if err != nil {
return err
}
return opts.run(flags)
return opts.run(input)
}
func (opts *UpdateSubCommand) complete(flags cli.Input) error {
if len(flags.String("package")) > 0 {
return errors.New("--package is deprecated, please use --deploy instead")
}
func (opts *UpdateSubCommand) complete(input cli.Input) error {
fnName := input.String(flagkey.FnName)
fnNamespace := input.String(flagkey.NamespaceFunction)
if len(flags.String("srcpkg")) > 0 {
return errors.New("--srcpkg is deprecated, please use --src instead.")
}
fnName := flags.String("name")
if len(fnName) == 0 {
return errors.New("Need name of function, use --name")
}
fnNamespace := flags.String("fnNamespace")
m, err := util.GetMetadata("name", "fnNamespace", flags)
m, err := util.GetMetadata("name", "fnNamespace", input)
if err != nil {
return err
}
@@ -81,8 +71,8 @@ func (opts *UpdateSubCommand) complete(flags cli.Input) error {
return errors.Wrap(err, fmt.Sprintf("read function '%v'", fnName))
}
envName := flags.String("env")
envNamespace := flags.String("envNamespace")
envName := input.String("env")
envNamespace := input.String("envNamespace")
// if the new env specified is the same as the old one, no need to update package
// same is true for all update parameters, but, for now, we dont check all of them - because, its ok to
// re-write the object with same old values, we just end up getting a new resource version for the object.
@@ -96,24 +86,24 @@ func (opts *UpdateSubCommand) complete(flags cli.Input) error {
var deployArchiveFiles []string
codeFlag := false
code := flags.String("code")
code := input.String("code")
if len(code) == 0 {
deployArchiveFiles = flags.StringSlice("deploy")
deployArchiveFiles = input.StringSlice("deploy")
} else {
deployArchiveFiles = append(deployArchiveFiles, flags.String("code"))
deployArchiveFiles = append(deployArchiveFiles, input.String("code"))
codeFlag = true
}
srcArchiveFiles := flags.StringSlice("src")
pkgName := flags.String("pkg")
entrypoint := flags.String("entrypoint")
buildcmd := flags.String("buildcmd")
force := flags.Bool("force")
srcArchiveFiles := input.StringSlice("src")
pkgName := input.String("pkg")
entrypoint := input.String("entrypoint")
buildcmd := input.String("buildcmd")
force := input.Bool("force")
secretNames := flags.StringSlice("secret")
cfgMapNames := flags.StringSlice("configmap")
secretNames := input.StringSlice("secret")
cfgMapNames := input.StringSlice("configmap")
specializationTimeout := flags.Int("specializationtimeout")
specializationTimeout := input.Int("specializationtimeout")
if len(srcArchiveFiles) > 0 && len(deployArchiveFiles) > 0 {
return errors.New("Need either of --src or --deploy and not both arguments.")
@@ -131,7 +121,7 @@ func (opts *UpdateSubCommand) complete(flags cli.Input) error {
Name: secretName,
})
if k8serrors.IsNotFound(err) {
consolemsg.Warn(fmt.Sprintf("secret %s not found in Namespace: %s. Secret needs to be present in the same namespace as function", secretName, fnNamespace))
console.Warn(fmt.Sprintf("secret %s not found in Namespace: %s. Secret needs to be present in the same namespace as function", secretName, fnNamespace))
}
}
@@ -155,7 +145,7 @@ func (opts *UpdateSubCommand) complete(flags cli.Input) error {
Name: cfgMapName,
})
if k8serrors.IsNotFound(err) {
consolemsg.Warn(fmt.Sprintf("ConfigMap %s not found in Namespace: %s. ConfigMap needs to be present in the same namespace as the function", cfgMapName, fnNamespace))
console.Warn(fmt.Sprintf("ConfigMap %s not found in Namespace: %s. ConfigMap needs to be present in the same namespace as the function", cfgMapName, fnNamespace))
}
}
@@ -181,8 +171,8 @@ func (opts *UpdateSubCommand) complete(flags cli.Input) error {
function.Spec.Package.FunctionName = entrypoint
}
if flags.IsSet("fntimeout") {
fnTimeout := flags.Int("fntimeout")
if input.IsSet("fntimeout") {
fnTimeout := input.Int("fntimeout")
if fnTimeout <= 0 {
return errors.New("fntimeout must be greater than 0")
}
@@ -193,13 +183,13 @@ func (opts *UpdateSubCommand) complete(flags cli.Input) error {
pkgName = function.Spec.Package.PackageRef.Name
}
strategy, err := getInvokeStrategy(flags, &function.Spec.InvokeStrategy)
strategy, err := getInvokeStrategy(input, &function.Spec.InvokeStrategy)
if err != nil {
return err
}
function.Spec.InvokeStrategy = *strategy
if flags.IsSet("specializationtimeout") {
if input.IsSet("specializationtimeout") {
if strategy.ExecutionStrategy.ExecutorType != types.ExecutorTypeNewdeploy {
return errors.New("specializationtimeout flag is only applicable for newdeploy type of executor")
}
@@ -211,7 +201,7 @@ func (opts *UpdateSubCommand) complete(flags cli.Input) error {
}
}
resReqs, err := util.GetResourceReqs(flags, &function.Spec.Resources)
resReqs, err := util.GetResourceReqs(input, &function.Spec.Resources)
if err != nil {
return err
}
@@ -238,7 +228,7 @@ func (opts *UpdateSubCommand) complete(flags cli.Input) error {
return errors.New("package is used by multiple functions, use --force to force update")
}
keepURL := flags.Bool("keepurl")
keepURL := input.Bool("keepurl")
pkgMetadata, err = _package.UpdatePackage(opts.client, pkg, envName, envNamespace, srcArchiveFiles, deployArchiveFiles, buildcmd, false, codeFlag, keepURL)
if err != nil {
@@ -271,7 +261,7 @@ func (opts *UpdateSubCommand) complete(flags cli.Input) error {
}
if function.Spec.Environment.Name != pkg.Spec.Environment.Name {
consolemsg.Warn("Function's environment is different than package's environment, package's environment will be used for updating function")
console.Warn("Function's environment is different than package's environment, package's environment will be used for updating function")
function.Spec.Environment.Name = pkg.Spec.Environment.Name
function.Spec.Environment.Namespace = pkg.Spec.Environment.Namespace
}
@@ -281,7 +271,7 @@ func (opts *UpdateSubCommand) complete(flags cli.Input) error {
return nil
}
func (opts *UpdateSubCommand) run(flags cli.Input) error {
func (opts *UpdateSubCommand) run(input cli.Input) error {
_, err := opts.client.FunctionUpdate(opts.function)
if err != nil {
return errors.Wrap(err, "error updating function")
@@ -0,0 +1,92 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package httptrigger
import (
"github.com/spf13/cobra"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
"github.com/fission/fission/pkg/fission-cli/flag"
)
func Commands() *cobra.Command {
createCmd := &cobra.Command{
Use: "create",
Short: "Create an HTTP trigger",
RunE: wrapper.Wrapper(Create),
}
wrapper.SetFlags(createCmd, flag.FlagSet{
Required: []flag.Flag{flag.HtUrlFlag, flag.HtFnNameFlag},
Optional: []flag.Flag{flag.HtNameFlag, flag.HtMethodFlag, flag.HtIngressRuleFlag,
flag.HtIngressAnnotationFlag, flag.HtIngressTLSFlag, flag.HtIngressFlag,
flag.HtFnWeightFlag, flag.HtHostFlag, flag.NamespaceFunctionFlag, flag.SpecSaveFlag},
})
getCmd := &cobra.Command{
Use: "get",
Aliases: []string{},
Short: "Get HTTP trigger details",
RunE: wrapper.Wrapper(Get),
}
wrapper.SetFlags(getCmd, flag.FlagSet{
Required: []flag.Flag{flag.HtNameFlag},
})
updateCmd := &cobra.Command{
Use: "update",
Aliases: []string{},
Short: "Update an HTTP trigger",
RunE: wrapper.Wrapper(Update),
}
wrapper.SetFlags(updateCmd, flag.FlagSet{
Required: []flag.Flag{flag.HtNameFlag},
Optional: []flag.Flag{flag.NamespaceTriggerFlag, flag.HtFnNameFlag, flag.HtUrlFlag,
flag.HtMethodFlag, flag.HtIngressRuleFlag, flag.HtIngressAnnotationFlag,
flag.HtIngressTLSFlag, flag.HtIngressFlag, flag.HtFnWeightFlag, flag.HtHostFlag},
})
deleteCmd := &cobra.Command{
Use: "delete",
Aliases: []string{},
Short: "Delete an HTTP trigger",
RunE: wrapper.Wrapper(Delete),
}
wrapper.SetFlags(deleteCmd, flag.FlagSet{
Required: []flag.Flag{flag.HtNameFlag},
Optional: []flag.Flag{flag.NamespaceTriggerFlag, flag.HtFnFilterFlag},
})
listCmd := &cobra.Command{
Use: "list",
Aliases: []string{},
Short: "List all HTTP triggers in a namespace if specified, else, list HTTP triggers across all namespaces",
RunE: wrapper.Wrapper(List),
}
wrapper.SetFlags(listCmd, flag.FlagSet{
Optional: []flag.Flag{flag.NamespaceTriggerFlag, flag.HtFnFilterFlag},
})
command := &cobra.Command{
Use: "httptrigger",
Aliases: []string{"ht", "route"},
Short: "Create, update and manage HTTP triggers",
}
command.AddCommand(createCmd, getCmd, updateCmd, deleteCmd, listCmd)
return command
}
+3 -3
View File
@@ -30,7 +30,7 @@ import (
ferror "github.com/fission/fission/pkg/error"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cmd/spec"
"github.com/fission/fission/pkg/fission-cli/consolemsg"
"github.com/fission/fission/pkg/fission-cli/console"
"github.com/fission/fission/pkg/fission-cli/util"
)
@@ -104,7 +104,7 @@ func (opts *CreateSubCommand) complete(flags cli.Input) error {
if !flags.Bool("spec") {
err = util.CheckFunctionExistence(opts.client, functionList, fnNamespace)
if err != nil {
consolemsg.Warn(err.Error())
console.Warn(err.Error())
}
}
@@ -118,7 +118,7 @@ func (opts *CreateSubCommand) complete(flags cli.Input) error {
host := flags.String("host")
if flags.IsSet("host") {
consolemsg.Warn(fmt.Sprintf("--host is now marked as deprecated, see 'help' for details"))
console.Warn(fmt.Sprintf("--host is now marked as deprecated, see 'help' for details"))
}
// just name triggers by uuid.
+6 -4
View File
@@ -19,12 +19,14 @@ package httptrigger
import (
"fmt"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/util"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/util"
"github.com/fission/fission/pkg/utils"
)
type DeleteSubCommand struct {
@@ -84,7 +86,7 @@ func (opts *DeleteSubCommand) run(flags cli.Input) error {
triggersToDelete = []string{opts.triggerName}
}
errs := &multierror.Error{}
errs := utils.MultiErrorWithFormat()
for _, name := range triggersToDelete {
err := opts.client.HTTPTriggerDelete(&metav1.ObjectMeta{
+3 -3
View File
@@ -25,7 +25,7 @@ import (
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/consolemsg"
"github.com/fission/fission/pkg/fission-cli/console"
"github.com/fission/fission/pkg/fission-cli/util"
)
@@ -73,7 +73,7 @@ func (opts *UpdateSubCommand) complete(flags cli.Input) error {
functionList := flags.StringSlice("function")
err := util.CheckFunctionExistence(opts.client, functionList, triggerNamespace)
if err != nil {
consolemsg.Warn(err.Error())
console.Warn(err.Error())
}
var functionWeightsList []int
@@ -96,7 +96,7 @@ func (opts *UpdateSubCommand) complete(flags cli.Input) error {
if flags.IsSet("host") {
ht.Spec.Host = flags.String("host")
consolemsg.Warn(fmt.Sprintf("--host is now marked as deprecated, see 'help' for details"))
console.Warn(fmt.Sprintf("--host is now marked as deprecated, see 'help' for details"))
}
if flags.IsSet("ingressrule") || flags.IsSet("ingressannotation") || flags.IsSet("ingresstls") {
+67
View File
@@ -0,0 +1,67 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kubewatch
import (
"github.com/spf13/cobra"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
"github.com/fission/fission/pkg/fission-cli/flag"
)
func Commands() *cobra.Command {
createCmd := &cobra.Command{
Use: "create",
Short: "Create a kube watcher",
RunE: wrapper.Wrapper(Create),
}
wrapper.SetFlags(createCmd, flag.FlagSet{
Required: []flag.Flag{flag.KwFnNameFlag, flag.KwObjTypeFlag},
Optional: []flag.Flag{flag.NamespaceFunctionFlag, flag.KwLabelsFlag, flag.SpecSaveFlag},
})
deleteCmd := &cobra.Command{
Use: "delete",
Aliases: []string{},
Short: "Delete a kube watcher",
RunE: wrapper.Wrapper(Delete),
}
wrapper.SetFlags(deleteCmd, flag.FlagSet{
Required: []flag.Flag{flag.KwFnNameFlag},
Optional: []flag.Flag{flag.NamespaceTriggerFlag},
})
listCmd := &cobra.Command{
Use: "list",
Aliases: []string{},
Short: "List all kube watchers in a namespace if specified, else, list kube watchers across all namespaces",
RunE: wrapper.Wrapper(List),
}
wrapper.SetFlags(listCmd, flag.FlagSet{
Optional: []flag.Flag{flag.NamespaceTriggerFlag},
})
command := &cobra.Command{
Use: "watch",
Aliases: []string{"w"},
Short: "Create, update and manage kube watcher",
}
command.AddCommand(createCmd, deleteCmd, listCmd)
return command
}
+81
View File
@@ -0,0 +1,81 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mqtrigger
import (
"github.com/spf13/cobra"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
"github.com/fission/fission/pkg/fission-cli/flag"
)
func Commands() *cobra.Command {
createCmd := &cobra.Command{
Use: "create",
Short: "Create a message queue trigger",
RunE: wrapper.Wrapper(Create),
}
wrapper.SetFlags(createCmd, flag.FlagSet{
Required: []flag.Flag{flag.MqtFnNameFlag, flag.MqtTopicFlag},
Optional: []flag.Flag{flag.MqtNameFlag, flag.NamespaceFunctionFlag, flag.MqtMQTypeFlag,
flag.MqtRespTopicFlag, flag.MqtErrorTopicFlag, flag.MqtMaxRetriesFlag, flag.MqtMsgContentTypeFlag,
flag.SpecSaveFlag},
})
updateCmd := &cobra.Command{
Use: "update",
Aliases: []string{},
Short: "Update a message queue trigger",
RunE: wrapper.Wrapper(Update),
}
wrapper.SetFlags(updateCmd, flag.FlagSet{
Required: []flag.Flag{flag.MqtNameFlag},
Optional: []flag.Flag{flag.NamespaceTriggerFlag, flag.MqtTopicFlag, flag.MqtRespTopicFlag,
flag.MqtErrorTopicFlag, flag.MqtMaxRetriesFlag, flag.MqtFnNameFlag, flag.MqtMsgContentTypeFlag},
})
deleteCmd := &cobra.Command{
Use: "delete",
Aliases: []string{},
Short: "Delete a message queue trigger",
RunE: wrapper.Wrapper(Delete),
}
wrapper.SetFlags(deleteCmd, flag.FlagSet{
Required: []flag.Flag{flag.MqtNameFlag},
Optional: []flag.Flag{flag.NamespaceTriggerFlag},
})
listCmd := &cobra.Command{
Use: "list",
Aliases: []string{},
Short: "List all message queue triggers in a namespace if specified, else, list message queue triggers across all namespaces",
RunE: wrapper.Wrapper(List),
}
wrapper.SetFlags(listCmd, flag.FlagSet{
Optional: []flag.Flag{flag.NamespaceTriggerFlag},
})
command := &cobra.Command{
Use: "mqtrigger",
Aliases: []string{"mqt"},
Short: "Create, update and manage message queue triggers",
}
command.AddCommand(createCmd, updateCmd, deleteCmd, listCmd)
return command
}
+116
View File
@@ -0,0 +1,116 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package _package
import (
"github.com/spf13/cobra"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
"github.com/fission/fission/pkg/fission-cli/flag"
)
func Commands() *cobra.Command {
createCmd := &cobra.Command{
Use: "create",
Short: "Create a package",
RunE: wrapper.Wrapper(Create),
}
wrapper.SetFlags(createCmd, flag.FlagSet{
Required: []flag.Flag{flag.PkgEnvironmentFlag},
Optional: []flag.Flag{flag.NamespacePackageFlag, flag.NamespaceEnvironmentFlag,
flag.PkgSrcArchiveFlag, flag.PkgDeployArchiveFlag, flag.PkgKeepURLFlag, flag.PkgBuildCmdFlag},
})
getSrcCmd := &cobra.Command{
Use: "getsrc",
Short: "Get package details",
RunE: wrapper.Wrapper(GetSrc),
}
wrapper.SetFlags(getSrcCmd, flag.FlagSet{
Required: []flag.Flag{flag.PkgNameFlag},
Optional: []flag.Flag{flag.NamespacePackageFlag, flag.PkgOutputFlag},
})
getDeployCmd := &cobra.Command{
Use: "getdeploy",
Short: "Get package details",
RunE: wrapper.Wrapper(GetDeploy),
}
wrapper.SetFlags(getDeployCmd, flag.FlagSet{
Required: []flag.Flag{flag.PkgNameFlag},
Optional: []flag.Flag{flag.NamespacePackageFlag, flag.PkgOutputFlag},
})
updateCmd := &cobra.Command{
Use: "update",
Short: "Update a package",
RunE: wrapper.Wrapper(Update),
}
wrapper.SetFlags(updateCmd, flag.FlagSet{
Required: []flag.Flag{flag.PkgNameFlag},
Optional: []flag.Flag{flag.NamespacePackageFlag, flag.PkgEnvironmentFlag, flag.NamespaceEnvironmentFlag,
flag.PkgSrcArchiveFlag, flag.PkgDeployArchiveFlag, flag.PkgKeepURLFlag,
flag.PkgBuildCmdFlag, flag.PkgForceFlag},
})
deleteCmd := &cobra.Command{
Use: "delete",
Short: "Delete a package",
RunE: wrapper.Wrapper(Delete),
}
wrapper.SetFlags(deleteCmd, flag.FlagSet{
Required: []flag.Flag{flag.PkgNameFlag},
Optional: []flag.Flag{flag.NamespacePackageFlag, flag.PkgForceFlag, flag.PkgOrphanFlag},
})
listCmd := &cobra.Command{
Use: "list",
Short: "List all packages in a namespace if specified, else, list packages across all namespaces",
RunE: wrapper.Wrapper(List),
}
wrapper.SetFlags(listCmd, flag.FlagSet{
Optional: []flag.Flag{flag.PkgOrphanFlag, flag.PkgStatusFlag, flag.NamespacePackageFlag},
})
infoCmd := &cobra.Command{
Use: "info",
Short: "Show package information",
RunE: wrapper.Wrapper(List),
}
wrapper.SetFlags(infoCmd, flag.FlagSet{
Optional: []flag.Flag{flag.PkgNameFlag, flag.NamespacePackageFlag},
})
rebuildCmd := &cobra.Command{
Use: "rebuild",
Short: "Rebuild a failed package",
RunE: wrapper.Wrapper(List),
}
wrapper.SetFlags(rebuildCmd, flag.FlagSet{
Optional: []flag.Flag{flag.PkgNameFlag, flag.NamespacePackageFlag},
})
command := &cobra.Command{
Use: "package",
Aliases: []string{"pkg"},
Short: "Create, update and manage packages",
}
command.AddCommand(createCmd, getSrcCmd, getDeployCmd, updateCmd, deleteCmd, listCmd, infoCmd, rebuildCmd)
return command
}
+2 -3
View File
@@ -41,8 +41,7 @@ import (
// upload the archive using client. noZip avoids zipping the
// includeFiles, but is ignored if there's more than one includeFile.
func CreateArchive(client *client.Client, includeFiles []string, noZip bool, keepURL bool, specDir string, specFile string) (*fv1.Archive, error) {
errs := &multierror.Error{}
errs := utils.MultiErrorWithFormat()
fileURL := ""
// check files existence
@@ -65,7 +64,7 @@ func CreateArchive(client *client.Client, includeFiles []string, noZip bool, kee
}
if len(files) == 0 {
errs = multierror.Append(errs, errors.New(fmt.Sprintf("Error finding any files with path \"%v\"", path)))
errs = multierror.Append(errs, errors.Errorf("Error finding any files with path \"%v\"", path))
}
}
+42
View File
@@ -0,0 +1,42 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package plugin
import (
"github.com/spf13/cobra"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
)
func Commands() *cobra.Command {
listCmd := &cobra.Command{
Use: "list",
Short: "List installed client plugins",
RunE: wrapper.Wrapper(List),
}
command := &cobra.Command{
Use: "plugin",
Aliases: []string{"plugins"},
Short: "Manage CLI plugins",
Hidden: true,
}
command.AddCommand(listCmd)
return command
}
+83
View File
@@ -0,0 +1,83 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package recorder
import (
"github.com/spf13/cobra"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
"github.com/fission/fission/pkg/fission-cli/flag"
)
func Commands() *cobra.Command {
createCmd := &cobra.Command{
Use: "create",
Short: "Create a recorder",
RunE: wrapper.Wrapper(Create),
}
wrapper.SetFlags(createCmd, flag.FlagSet{
Optional: []flag.Flag{flag.RecorderNameFlag, flag.RecorderFnFlag, flag.RecorderTriggersFlag, flag.SpecSaveFlag},
})
getCmd := &cobra.Command{
Use: "get",
Short: "Get recorder details",
RunE: wrapper.Wrapper(Get),
}
wrapper.SetFlags(getCmd, flag.FlagSet{
Required: []flag.Flag{flag.RecorderNameFlag},
})
updateCmd := &cobra.Command{
Use: "update",
Short: "Update a recorder",
RunE: wrapper.Wrapper(Update),
}
wrapper.SetFlags(getCmd, flag.FlagSet{
Required: []flag.Flag{flag.RecorderNameFlag},
Optional: []flag.Flag{flag.RecorderFnFlag, flag.RecorderTriggersFlag, flag.RecorderEnabledFlag, flag.RecorderDisabledFlag},
})
deleteCmd := &cobra.Command{
Use: "delete",
Short: "Delete a recorder",
RunE: wrapper.Wrapper(Delete),
}
wrapper.SetFlags(deleteCmd, flag.FlagSet{
Required: []flag.Flag{flag.RecorderNameFlag},
Optional: []flag.Flag{flag.NamespaceRecorderFlag},
})
listCmd := &cobra.Command{
Use: "list",
Short: "List all recorders in a namespace if specified, else, list recorders across all namespaces",
RunE: wrapper.Wrapper(List),
}
wrapper.SetFlags(deleteCmd, flag.FlagSet{
Optional: []flag.Flag{flag.NamespaceRecorderFlag},
})
command := &cobra.Command{
Use: "recorder",
Short: "Create, update and manage recorders",
Hidden: true,
}
command.AddCommand(createCmd, getCmd, updateCmd, deleteCmd, listCmd)
return command
}
+47
View File
@@ -0,0 +1,47 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package records
import (
"github.com/spf13/cobra"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
"github.com/fission/fission/pkg/fission-cli/flag"
)
func Commands() *cobra.Command {
viewCmd := &cobra.Command{
Use: "view",
Short: "View existing records",
RunE: wrapper.Wrapper(View),
}
wrapper.SetFlags(viewCmd, flag.FlagSet{
Optional: []flag.Flag{flag.RecordsFilterTimeToFlag, flag.RecordsFilterTimeFromFlag,
flag.RecordsFilterFunctionFlag, flag.RecordsFilterTriggerFlag, flag.RecordsVerbosityFlag,
flag.RecordsVvFlag},
})
command := &cobra.Command{
Use: "records",
Short: "View records with optional filters",
Hidden: true,
}
command.AddCommand(viewCmd)
return command
}
+45
View File
@@ -0,0 +1,45 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package replay
import (
"github.com/spf13/cobra"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
"github.com/fission/fission/pkg/fission-cli/flag"
)
func Commands() *cobra.Command {
replayCmd := &cobra.Command{
Use: "create",
Short: "Create a recorder",
RunE: wrapper.Wrapper(Replay),
}
wrapper.SetFlags(replayCmd, flag.FlagSet{
Required: []flag.Flag{flag.RecordsReqIDFlag},
})
command := &cobra.Command{
Use: "replay",
Short: "Replay records",
Hidden: true,
}
command.AddCommand(replayCmd)
return command
}
+2 -2
View File
@@ -37,7 +37,7 @@ import (
pkgutil "github.com/fission/fission/pkg/fission-cli/cmd/package/util"
spectypes "github.com/fission/fission/pkg/fission-cli/cmd/spec/types"
"github.com/fission/fission/pkg/fission-cli/consolemsg"
"github.com/fission/fission/pkg/fission-cli/console"
"github.com/fission/fission/pkg/fission-cli/util"
"github.com/fission/fission/pkg/types"
"github.com/fission/fission/pkg/utils"
@@ -430,7 +430,7 @@ func localArchiveFromSpec(specDir string, aus *spectypes.ArchiveUploadSpec) (*fv
absGlob := rootDir + "/" + relativeGlob
f, err := filepath.Glob(absGlob)
if err != nil {
consolemsg.Info(fmt.Sprintf("Invalid glob in archive %v: %v", aus.Name, relativeGlob))
console.Info(fmt.Sprintf("Invalid glob in archive %v: %v", aus.Name, relativeGlob))
return nil, err
}
files = append(files, f...)
+72
View File
@@ -0,0 +1,72 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package spec
import (
"github.com/spf13/cobra"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
"github.com/fission/fission/pkg/fission-cli/flag"
)
func Commands() *cobra.Command {
initCmd := &cobra.Command{
Use: "init",
Short: "Create an initial declarative application specification",
RunE: wrapper.Wrapper(Init),
}
wrapper.SetFlags(initCmd, flag.FlagSet{
Optional: []flag.Flag{flag.SpecDirFlag, flag.SpecNameFlag, flag.SpecDeployIDFlag},
})
validateCmd := &cobra.Command{
Use: "validate",
Short: "Validate declarative application specification",
RunE: wrapper.Wrapper(Validate),
}
wrapper.SetFlags(validateCmd, flag.FlagSet{
Optional: []flag.Flag{flag.SpecDirFlag},
})
applyCmd := &cobra.Command{
Use: "apply",
Short: "Create, update, or delete resources from application specification",
RunE: wrapper.Wrapper(Apply),
}
wrapper.SetFlags(applyCmd, flag.FlagSet{
Optional: []flag.Flag{flag.SpecDirFlag, flag.SpecDeployIDFlag, flag.SpecWaitFlag},
})
destroyCmd := &cobra.Command{
Use: "destroy",
Short: "Delete an environment",
RunE: wrapper.Wrapper(Destroy),
}
wrapper.SetFlags(destroyCmd, flag.FlagSet{
Optional: []flag.Flag{flag.SpecDirFlag},
})
command := &cobra.Command{
Use: "spec",
Aliases: []string{"specs"},
Short: "Manage a declarative application specification",
}
command.AddCommand(initCmd, validateCmd, applyCmd, destroyCmd)
return command
}
+12 -11
View File
@@ -32,10 +32,11 @@ import (
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cmd/spec/types"
"github.com/fission/fission/pkg/fission-cli/consolemsg"
"github.com/fission/fission/pkg/fission-cli/console"
"github.com/fission/fission/pkg/fission-cli/util"
"github.com/fission/fission/pkg/generator/encoder"
v1generator "github.com/fission/fission/pkg/generator/v1"
"github.com/fission/fission/pkg/utils"
)
var specDefaultEncoder = encoder.DefaultYAMLEncoder()
@@ -246,7 +247,7 @@ func (fr *FissionResources) validateFunctionReference(functions map[string]bool,
}
func (fr *FissionResources) Validate(flags cli.Input) error {
result := &multierror.Error{}
result := utils.MultiErrorWithFormat()
// check references: both dangling refs + garbage
// packages -> archives
@@ -357,7 +358,7 @@ func (fr *FissionResources) Validate(flags cli.Input) error {
Namespace: cm.Namespace,
})
if k8serrors.IsNotFound(err) {
consolemsg.Warn(fmt.Sprintf("Configmap %s is referred in the spec but not present in the cluster", cm.Name))
console.Warn(fmt.Sprintf("Configmap %s is referred in the spec but not present in the cluster", cm.Name))
}
}
@@ -367,7 +368,7 @@ func (fr *FissionResources) Validate(flags cli.Input) error {
Namespace: s.Namespace,
})
if k8serrors.IsNotFound(err) {
consolemsg.Warn(fmt.Sprintf("Secret %s is referred in the spec but not present in the cluster", s.Name))
console.Warn(fmt.Sprintf("Secret %s is referred in the spec but not present in the cluster", s.Name))
}
}
@@ -395,7 +396,7 @@ func (fr *FissionResources) Validate(flags cli.Input) error {
}
if len(t.Spec.Host) > 0 {
consolemsg.Warn(fmt.Sprintf("Host in HTTPTrigger spec.Host is now marked as deprecated, see 'help' for details"))
console.Warn(fmt.Sprintf("Host in HTTPTrigger spec.Host is now marked as deprecated, see 'help' for details"))
}
result = multierror.Append(result, t.Validate())
@@ -430,25 +431,25 @@ func (fr *FissionResources) Validate(flags cli.Input) error {
for _, e := range fr.Environments {
environments[fmt.Sprintf("%s:%s", e.Metadata.Name, e.Metadata.Namespace)] = struct{}{}
if ((e.Spec.Runtime.Container != nil) && (e.Spec.Runtime.PodSpec != nil)) || ((e.Spec.Builder.Container != nil) && (e.Spec.Builder.PodSpec != nil)) {
consolemsg.Warn("You have provided both - container spec and pod spec and while merging the pod spec will take precedence.")
console.Warn("You have provided both - container spec and pod spec and while merging the pod spec will take precedence.")
}
// Unlike CLI can change the environment version silently,
// we have to warn the user to modify spec file when this takes place.
if e.Spec.Version < 3 && e.Spec.Poolsize != 0 {
consolemsg.Warn("Poolsize can only be configured when environment version equals to 3, default poolsize 3 will be used for creating environment pool.")
console.Warn("Poolsize can only be configured when environment version equals to 3, default poolsize 3 will be used for creating environment pool.")
}
}
for _, f := range fr.Functions {
if _, ok := environments[fmt.Sprintf("%s:%s", f.Spec.Environment.Name, f.Spec.Environment.Namespace)]; !ok {
consolemsg.Warn(fmt.Sprintf("Environment %s is referenced in function %s but not declared in specs", f.Spec.Environment.Name, f.Metadata.Name))
console.Warn(fmt.Sprintf("Environment %s is referenced in function %s but not declared in specs", f.Spec.Environment.Name, f.Metadata.Name))
}
strategy := f.Spec.InvokeStrategy.ExecutionStrategy
if strategy.ExecutorType == fv1.ExecutorTypeNewdeploy && strategy.SpecializationTimeout < fv1.DefaultSpecializationTimeOut {
consolemsg.Warn(fmt.Sprintf("SpecializationTimeout in function spec.InvokeStrategy.ExecutionStrategy should be a value equal to or greater than %v", fv1.DefaultSpecializationTimeOut))
console.Warn(fmt.Sprintf("SpecializationTimeout in function spec.InvokeStrategy.ExecutionStrategy should be a value equal to or greater than %v", fv1.DefaultSpecializationTimeOut))
}
if f.Spec.FunctionTimeout <= 0 {
consolemsg.Warn(fmt.Sprintf("FunctionTimeout in function spec should be a field which should have a value greater than 0"))
console.Warn(fmt.Sprintf("FunctionTimeout in function spec should be a field which should have a value greater than 0"))
}
}
@@ -577,7 +578,7 @@ func (fr *FissionResources) ParseYaml(b []byte, loc *Location) error {
default:
// no need to error out just because there's some extra files around;
// also good for compatibility.
consolemsg.Warn(fmt.Sprintf("Ignoring unknown type %v in %v", tm.Kind, loc))
console.Warn(fmt.Sprintf("Ignoring unknown type %v in %v", tm.Kind, loc))
}
// add to source map, check for duplicates
+44
View File
@@ -0,0 +1,44 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package support
import (
"github.com/spf13/cobra"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
"github.com/fission/fission/pkg/fission-cli/flag"
)
func Commands() *cobra.Command {
dumpCmd := &cobra.Command{
Use: "dump",
Short: "Collect & dump all necessary information for troubleshooting",
RunE: wrapper.Wrapper(Dump),
}
wrapper.SetFlags(dumpCmd, flag.FlagSet{
Optional: []flag.Flag{flag.SupportNoZipFlag, flag.SupportOutputFlag},
})
command := &cobra.Command{
Use: "support",
Short: "Collect diagnostic information for support",
}
command.AddCommand(dumpCmd)
return command
}
+9 -9
View File
@@ -23,7 +23,7 @@ import (
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/consolemsg"
"github.com/fission/fission/pkg/fission-cli/console"
"github.com/fission/fission/pkg/types"
)
@@ -53,7 +53,7 @@ func (res CrdDumper) Dump(dumpDir string) {
case CrdEnvironment:
items, err := res.client.EnvironmentList(metav1.NamespaceAll)
if err != nil {
consolemsg.Info(fmt.Sprintf("Error getting %v list: %v", res.crdType, err))
console.Info(fmt.Sprintf("Error getting %v list: %v", res.crdType, err))
return
}
@@ -65,7 +65,7 @@ func (res CrdDumper) Dump(dumpDir string) {
case CrdFunction:
items, err := res.client.FunctionList(metav1.NamespaceAll)
if err != nil {
consolemsg.Info(fmt.Sprintf("Error getting %v list: %v", res.crdType, err))
console.Info(fmt.Sprintf("Error getting %v list: %v", res.crdType, err))
return
}
@@ -77,7 +77,7 @@ func (res CrdDumper) Dump(dumpDir string) {
case CrdPackage:
items, err := res.client.PackageList(metav1.NamespaceAll)
if err != nil {
consolemsg.Info(fmt.Sprintf("Error getting %v list: %v", res.crdType, err))
console.Info(fmt.Sprintf("Error getting %v list: %v", res.crdType, err))
return
}
@@ -90,7 +90,7 @@ func (res CrdDumper) Dump(dumpDir string) {
case CrdHttpTrigger:
items, err := res.client.HTTPTriggerList(metav1.NamespaceAll)
if err != nil {
consolemsg.Info(fmt.Sprintf("Error getting %v list: %v", res.crdType, err))
console.Info(fmt.Sprintf("Error getting %v list: %v", res.crdType, err))
return
}
@@ -102,7 +102,7 @@ func (res CrdDumper) Dump(dumpDir string) {
case CrdKubeWatcher:
items, err := res.client.WatchList(metav1.NamespaceAll)
if err != nil {
consolemsg.Info(fmt.Sprintf("Error getting %v list: %v", res.crdType, err))
console.Info(fmt.Sprintf("Error getting %v list: %v", res.crdType, err))
return
}
@@ -117,7 +117,7 @@ func (res CrdDumper) Dump(dumpDir string) {
for _, mqType := range []string{types.MessageQueueTypeNats, types.MessageQueueTypeASQ} {
l, err := res.client.MessageQueueTriggerList(mqType, metav1.NamespaceAll)
if err != nil {
consolemsg.Info(fmt.Sprintf("Error getting %v list: %v", res.crdType, err))
console.Info(fmt.Sprintf("Error getting %v list: %v", res.crdType, err))
break
}
triggers = append(triggers, l...)
@@ -131,7 +131,7 @@ func (res CrdDumper) Dump(dumpDir string) {
case CrdTimeTrigger:
items, err := res.client.TimeTriggerList(metav1.NamespaceAll)
if err != nil {
consolemsg.Info(fmt.Sprintf("Error getting %v list: %v", res.crdType, err))
console.Info(fmt.Sprintf("Error getting %v list: %v", res.crdType, err))
return
}
@@ -141,7 +141,7 @@ func (res CrdDumper) Dump(dumpDir string) {
}
default:
consolemsg.Info(fmt.Sprintf("Unknown type: %v", res.crdType))
console.Info(fmt.Sprintf("Unknown type: %v", res.crdType))
}
}
@@ -28,7 +28,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"github.com/fission/fission/pkg/fission-cli/consolemsg"
"github.com/fission/fission/pkg/fission-cli/console"
)
const (
@@ -52,7 +52,7 @@ func NewKubernetesVersion(clientset *kubernetes.Clientset) Resource {
func (res KubernetesVersion) Dump(dumpDir string) {
serverVer, err := res.client.ServerVersion()
if err != nil {
consolemsg.Info(fmt.Sprintf("Error setting up kubernetes client: %v", err))
console.Info(fmt.Sprintf("Error setting up kubernetes client: %v", err))
return
}
@@ -80,7 +80,7 @@ func (res KubernetesObjectDumper) Dump(dumpDir string) {
case KubernetesService:
objs, err := res.client.CoreV1().Services(metav1.NamespaceAll).List(metav1.ListOptions{LabelSelector: res.selector})
if err != nil {
consolemsg.Info(fmt.Sprintf("Error getting %v list with selector %v: %v", res.objType, res.selector, err))
console.Info(fmt.Sprintf("Error getting %v list with selector %v: %v", res.objType, res.selector, err))
return
}
@@ -93,7 +93,7 @@ func (res KubernetesObjectDumper) Dump(dumpDir string) {
case KubernetesDeployment:
objs, err := res.client.AppsV1().Deployments(metav1.NamespaceAll).List(metav1.ListOptions{LabelSelector: res.selector})
if err != nil {
consolemsg.Info(fmt.Sprintf("Error getting %v list with selector %v: %v", res.objType, res.selector, err))
console.Info(fmt.Sprintf("Error getting %v list with selector %v: %v", res.objType, res.selector, err))
return
}
@@ -105,7 +105,7 @@ func (res KubernetesObjectDumper) Dump(dumpDir string) {
case KubernetesPod:
objs, err := res.client.CoreV1().Pods(metav1.NamespaceAll).List(metav1.ListOptions{LabelSelector: res.selector})
if err != nil {
consolemsg.Info(fmt.Sprintf("Error getting %v list with selector %v: %v", res.objType, res.selector, err))
console.Info(fmt.Sprintf("Error getting %v list with selector %v: %v", res.objType, res.selector, err))
return
}
@@ -117,7 +117,7 @@ func (res KubernetesObjectDumper) Dump(dumpDir string) {
case KubernetesHPA:
objs, err := res.client.AutoscalingV2beta1().HorizontalPodAutoscalers(metav1.NamespaceAll).List(metav1.ListOptions{LabelSelector: res.selector})
if err != nil {
consolemsg.Info(fmt.Sprintf("Error getting %v list with selector %v: %v", res.objType, res.selector, err))
console.Info(fmt.Sprintf("Error getting %v list with selector %v: %v", res.objType, res.selector, err))
return
}
@@ -129,7 +129,7 @@ func (res KubernetesObjectDumper) Dump(dumpDir string) {
case KubernetesDaemonSet:
objs, err := res.client.AppsV1().DaemonSets(metav1.NamespaceAll).List(metav1.ListOptions{LabelSelector: res.selector})
if err != nil {
consolemsg.Info(fmt.Sprintf("Error getting %v list with selector %v: %v", res.objType, res.selector, err))
console.Info(fmt.Sprintf("Error getting %v list with selector %v: %v", res.objType, res.selector, err))
return
}
@@ -141,7 +141,7 @@ func (res KubernetesObjectDumper) Dump(dumpDir string) {
case KubernetesNode:
objs, err := res.client.CoreV1().Nodes().List(metav1.ListOptions{LabelSelector: res.selector})
if err != nil {
consolemsg.Info(fmt.Sprintf("Error getting %v list with selector %v: %v", res.objType, res.selector, err))
console.Info(fmt.Sprintf("Error getting %v list with selector %v: %v", res.objType, res.selector, err))
return
}
@@ -153,7 +153,7 @@ func (res KubernetesObjectDumper) Dump(dumpDir string) {
}
default:
consolemsg.Info(fmt.Sprintf("Unknown type: %v", res.objType))
console.Info(fmt.Sprintf("Unknown type: %v", res.objType))
return
}
}
@@ -199,7 +199,7 @@ func (res KubernetesPodLogDumper) Dump(dumpDir string) {
Pods(metav1.NamespaceAll).
List(metav1.ListOptions{LabelSelector: res.labelSelector})
if err != nil {
consolemsg.Info(fmt.Sprintf("Error getting controller list: %v", err))
console.Info(fmt.Sprintf("Error getting controller list: %v", err))
return
}
@@ -218,7 +218,7 @@ func (res KubernetesPodLogDumper) Dump(dumpDir string) {
stream, err := req.Stream()
if err != nil {
consolemsg.Info(fmt.Sprintf("Error streaming logs for pod %v: %v", pod.Name, err))
console.Info(fmt.Sprintf("Error streaming logs for pod %v: %v", pod.Name, err))
return
}
@@ -232,13 +232,13 @@ func (res KubernetesPodLogDumper) Dump(dumpDir string) {
stream.Close()
break
}
consolemsg.Info(fmt.Sprintf("Error reading logs from buffer: %v", err))
console.Info(fmt.Sprintf("Error reading logs from buffer: %v", err))
return
}
_, err = buffer.WriteString(string(line) + "\n")
if err != nil {
consolemsg.Info(fmt.Sprintf("Error writing bytes to buffer: %v", err))
console.Info(fmt.Sprintf("Error writing bytes to buffer: %v", err))
}
}
@@ -24,7 +24,7 @@ import (
"github.com/ghodss/yaml"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/pkg/fission-cli/consolemsg"
"github.com/fission/fission/pkg/fission-cli/console"
"github.com/fission/fission/pkg/utils"
)
@@ -45,7 +45,7 @@ func getPodFileName(dumpdir string, pod metav1.ObjectMeta, containerName string)
func writeToFile(file string, obj interface{}) {
bs, err := yaml.Marshal(obj)
if err != nil {
consolemsg.Info(fmt.Sprintf("Error encoding object: %v", err))
console.Info(fmt.Sprintf("Error encoding object: %v", err))
return
}
@@ -57,6 +57,6 @@ func writeToFile(file string, obj interface{}) {
err = ioutil.WriteFile(file, bs, 0644)
if err != nil {
consolemsg.Info(fmt.Sprintf("Error writing file %v: %v", file, err))
console.Info(fmt.Sprintf("Error writing file %v: %v", file, err))
}
}
@@ -0,0 +1,87 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package timetrigger
import (
"github.com/spf13/cobra"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
"github.com/fission/fission/pkg/fission-cli/flag"
)
func Commands() *cobra.Command {
createCmd := &cobra.Command{
Use: "create",
Short: "Create a time trigger",
RunE: wrapper.Wrapper(Create),
}
wrapper.SetFlags(createCmd, flag.FlagSet{
Optional: []flag.Flag{flag.TtNameFlag, flag.TtFnNameFlag, flag.NamespaceFunctionFlag, flag.TtCronFlag, flag.SpecSaveFlag},
})
updateCmd := &cobra.Command{
Use: "update",
Aliases: []string{},
Short: "Update a time trigger",
RunE: wrapper.Wrapper(Update),
}
wrapper.SetFlags(updateCmd, flag.FlagSet{
Required: []flag.Flag{flag.TtNameFlag},
Optional: []flag.Flag{flag.TtFnNameFlag, flag.NamespaceFunctionFlag, flag.TtCronFlag},
})
deleteCmd := &cobra.Command{
Use: "delete",
Aliases: []string{},
Short: "Delete a time trigger",
RunE: wrapper.Wrapper(Delete),
}
wrapper.SetFlags(deleteCmd, flag.FlagSet{
Required: []flag.Flag{flag.TtNameFlag},
Optional: []flag.Flag{flag.NamespaceTriggerFlag},
})
listCmd := &cobra.Command{
Use: "list",
Aliases: []string{},
Short: "List all time triggers in a namespace if specified, else, list time triggers across all namespaces",
RunE: wrapper.Wrapper(List),
}
wrapper.SetFlags(listCmd, flag.FlagSet{
Optional: []flag.Flag{flag.NamespaceTriggerFlag},
})
showCmd := &cobra.Command{
Use: "showschedule",
Aliases: []string{"show"},
Short: "Show schedule for cron spec",
RunE: wrapper.Wrapper(Show),
}
wrapper.SetFlags(showCmd, flag.FlagSet{
Optional: []flag.Flag{flag.TtCronFlag, flag.TtRoundFlag},
})
command := &cobra.Command{
Use: "timetrigger",
Aliases: []string{"tt", "timer"},
Short: "Create, update and manage time triggers",
}
command.AddCommand(createCmd, updateCmd, deleteCmd, listCmd, showCmd)
return command
}
+32
View File
@@ -0,0 +1,32 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package version
import (
"github.com/spf13/cobra"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
)
func Commands() *cobra.Command {
command := &cobra.Command{
Use: "version",
Short: "Version information",
RunE: wrapper.Wrapper(Version),
}
return command
}
@@ -14,11 +14,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package consolemsg
package console
import (
"fmt"
"os"
"github.com/life1347/color"
)
var (
@@ -26,13 +28,8 @@ var (
Verbosity int
)
func Fatal(msg interface{}) {
//os.Stderr.WriteString(fmt.Sprintf("Fatal error: %v\n", msg))
//os.Exit(1)
}
func Warn(msg interface{}) {
os.Stderr.WriteString(fmt.Sprintf("Warning: %v\n", msg))
os.Stdout.WriteString(fmt.Sprintf("%v: %v\n", color.YellowString("Warning"), msg))
}
func Info(msg interface{}) {
-56
View File
@@ -1,56 +0,0 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flag
import "strings"
const (
GLOBAL_VERBOSITY = "verbosity"
GLOBAL_PLUGIN = "plugin"
FISSION_SERVER = "server"
RESOURCE_NAME = "name"
ENVIRONMENT_NAMESPACE = "envNamespace"
ENVIRONMENT_NAMESPACE_ALIAS = "envns"
ENVIRONMENT_POOLSIZE = "poolsize"
ENVIRONMENT_IMAGE = "image"
ENVIRONMENT_BUILDER = "builder"
ENVIRONMENT_BUILDCOMMAND = "buildcmd"
ENVIRONMENT_KEEPARCHIVE = "keeparchive"
ENVIRONMENT_EXTERNAL_NETWORK = "externalnetwork"
ENVIRONMENT_GRACE_PERIOD = "graceperiod"
ENVIRONMENT_GRACE_PERIOD_ALIAS = "period"
ENVIRONMENT_VERSION = "version"
SPEC_SPEC = "spec"
SPEC_SPECDIR = "specdir"
RUNTIME_MINCPU = "mincpu"
RUNTIME_MAXCPU = "maxcpu"
RUNTIME_MINMEMORY = "minmemory"
RUNTIME_MAXMEMORY = "maxmemory"
RUNTIME_MINSCALE = "minscale"
RUNTIME_MAXSCALE = "maxscale"
RUNTIME_TARGETCPU = "targetcpu"
)
// GetCliFlagName concatenates flag and its alias into a command flag name.
func GetCliFlagName(flags ...string) string {
return strings.Join(flags, ", ")
}
+199
View File
@@ -0,0 +1,199 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flag
import (
"net/http"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/types"
)
type (
FlagType = int
FlagSet struct {
Required []Flag
Optional []Flag
}
Flag struct {
Name string
Type FlagType
Short string // one-letter abbreviated flag
Aliases []string
Usage string
DefaultValue interface{}
// If a flag is marked as deprecated, it will hided from
// the help message automatically. Hence, a flag cannot be
// marked as hidden and deprecated at the same time.
Hidden bool
Deprecated bool
// flag name to replace the deprecated flag
Substitute string
}
)
const (
Bool FlagType = iota + 1
String
StringSlice
Int
IntSlice
Int64
Int64Slice
Float32
Float64
Duration
)
var (
GlobalVerbosityFlag = Flag{Type: Int, Name: flagkey.Verbosity, Short: "v", Usage: "CLI verbosity (0 is quiet, 1 is the default, 2 is verbose)", DefaultValue: 1}
GlobalServerFlag = Flag{Type: String, Name: flagkey.Server, Usage: "Server URL"}
NamespaceFunctionFlag = Flag{Type: String, Name: flagkey.NamespaceFunction, Aliases: []string{"fns"}, Usage: "Namespace for function object", DefaultValue: metav1.NamespaceDefault}
NamespaceEnvironmentFlag = Flag{Type: String, Name: flagkey.NamespaceEnvironment, Aliases: []string{"envns"}, Usage: "Namespace for environment object", DefaultValue: metav1.NamespaceDefault}
NamespacePackageFlag = Flag{Type: String, Name: flagkey.NamespacePackage, Aliases: []string{"pkgns"}, Usage: "Namespace for package object", DefaultValue: metav1.NamespaceDefault}
NamespaceTriggerFlag = Flag{Type: String, Name: flagkey.NamespaceTrigger, Aliases: []string{"triggerns"}, Usage: "Namespace for trigger object", DefaultValue: metav1.NamespaceDefault}
NamespaceRecorderFlag = Flag{Type: String, Name: flagkey.NamespaceRecorder, Aliases: []string{"recorderns"}, Usage: "Namespace for recorder object", DefaultValue: metav1.NamespaceDefault}
NamespaceCanaryFlag = Flag{Type: String, Name: flagkey.NamespaceCanary, Aliases: []string{"canaryns"}, Usage: "Namespace for canary config object", DefaultValue: metav1.NamespaceDefault}
RunTimeMinCPUFlag = Flag{Type: Int, Name: flagkey.RuntimeMincpu, Usage: "Minimum CPU to be assigned to pod (In millicore, minimum 1)"}
RunTimeMaxCPUFlag = Flag{Type: Int, Name: flagkey.RuntimeMaxcpu, Usage: "Maximum CPU to be assigned to pod (In millicore, minimum 1)"}
RunTimeTargetCPUFlag = Flag{Type: Int, Name: flagkey.RuntimeTargetcpu, Usage: "Target average CPU usage percentage across pods for scaling", DefaultValue: 80}
RunTimeMinMemoryFlag = Flag{Type: Int, Name: flagkey.RuntimeMinmemory, Usage: "Minimum memory to be assigned to pod (In megabyte)"}
RunTimeMaxMemoryFlag = Flag{Type: Int, Name: flagkey.RuntimeMaxmemory, Usage: "Maximum memory to be assigned to pod (In megabyte)"}
ReplicasMinFlag = Flag{Type: Int, Name: flagkey.ReplicasMinscale, Usage: "Minimum number of pods (Uses resource inputs to configure HPA)", DefaultValue: 1}
ReplicasMaxFlag = Flag{Type: Int, Name: flagkey.ReplicasMaxscale, Usage: "Maximum number of pods (Uses resource inputs to configure HPA)", DefaultValue: 1}
FnNameFlag = Flag{Type: String, Name: flagkey.FnName, Usage: "Function name"}
FnSpecializationTimeoutFlag = Flag{Type: Int, Name: flagkey.FnSpecializationTimeout, Aliases: []string{"st"}, Usage: "Timeout for newdeploy to wait for function pod creation", DefaultValue: fv1.DefaultSpecializationTimeOut}
FnEnvNameFlag = Flag{Type: String, Name: flagkey.FnEnvironmentName, Usage: "Environment name for function"}
FnCodeFlag = Flag{Type: String, Name: flagkey.FnCode, Usage: "Local path or URL for single file source code"}
FnKeepURLFlag = Flag{Type: Bool, Name: flagkey.PkgKeepURL, Aliases: []string{"keepurl"}, Usage: "Keep the providing URL in archive instead of downloading file from it. (If set, no checksum will be generated for file integrity check. You must ensure the file won't be changed.)"}
FnPkgNameFlag = Flag{Type: String, Name: flagkey.FnPackageName, Aliases: []string{"pkg"}, Usage: "Name of the existing package (--deploy and --src and --env will be ignored), should be in the same namespace as the function"}
FnEntryPointFlag = Flag{Type: String, Name: flagkey.FnEntrypoint, Aliases: []string{"entry"}, Usage: "Entry point for environment v2 to load with"}
FnBuildCmdFlag = Flag{Type: String, Name: flagkey.FnBuildCmd, Usage: "Package build command for builder to run with"}
FnSecretFlag = Flag{Type: StringSlice, Name: flagkey.FnSecret, Usage: "Function access to secret, should be present in the same namespace as the function. You can provide multiple secrets using multiple --secrets flags. In the case of fn update the the secrets will be replaced by the provided list of secrets."}
FnCfgMapFlag = Flag{Type: StringSlice, Name: flagkey.FnCfgMap, Usage: "Function access to configmap, should be present in the same namespace as the function. You can provide multiple configmaps using multiple --configmap flags. In case of fn update the configmaps will be replaced by the provided list of configmaps."}
FnExecutorTypeFlag = Flag{Type: String, Name: flagkey.FnExecutorType, Usage: "Executor type for execution; one of 'poolmgr', 'newdeploy'", DefaultValue: types.ExecutorTypePoolmgr}
FnExecutionTimeoutFlag = Flag{Type: Int, Name: flagkey.FnExecutionTimeout, Aliases: []string{"ft"}, Usage: "Time duration to wait for the response while executing the function", DefaultValue: 60}
FnLogPodFlag = Flag{Type: String, Name: flagkey.FnLogPod, Usage: "Function pod name (use the latest pod name if unspecified)"}
FnLogFollowFlag = Flag{Type: Bool, Name: flagkey.FnLogFollow, Short: "f", Usage: "Specify if the logs should be streamed"}
FnLogDetailFlag = Flag{Type: Bool, Name: flagkey.FnLogDetail, Short: "d", Usage: "Display detailed information"}
FnLogDBTypeFlag = Flag{Type: String, Name: flagkey.FnLogDBType, Usage: "Log database type, e.g. influxdb (currently only influxdb is supported)", DefaultValue: "influxdb"}
FnLogReverseQueryFlag = Flag{Type: Bool, Name: flagkey.FnLogReverseQuery, Short: "r", Usage: "Specify the log reverse query base on time, it will be invalid if the 'follow' flag is specified"}
FnLogCountFlag = Flag{Type: Int, Name: flagkey.FnLogCount, Usage: "Get N most recent log records", DefaultValue: 20}
FnTestBodyFlag = Flag{Type: String, Name: flagkey.FnTestBody, Short: "b", Usage: "Request body"}
FnTestTimeoutFlag = Flag{Type: Duration, Name: flagkey.FnTestTimeout, Short: "t", Usage: "Length of time to wait for the response. If set to zero or negative number, no timeout is set", DefaultValue: 30 * time.Second}
FnTestHeaderFlag = Flag{Type: StringSlice, Name: flagkey.FnTestHeader, Short: "H", Usage: "Request headers"}
FnTestQueryFlag = Flag{Type: StringSlice, Name: flagkey.FnTestQuery, Short: "q", Usage: "Request query parameters: -q key1=value1 -q key2=value2"}
HtNameFlag = Flag{Type: String, Name: flagkey.HtName, Usage: "HTTP trigger name"}
HtMethodFlag = Flag{Type: String, Name: flagkey.HtMethod, Usage: "HTTP Method: GET|POST|PUT|DELETE|HEAD", DefaultValue: http.MethodGet}
HtUrlFlag = Flag{Type: String, Name: flagkey.HtUrl, Usage: "URL pattern (See gorilla/mux supported patterns)"}
HtHostFlag = Flag{Type: String, Name: flagkey.HtHost, Usage: "Use --ingressrule instead", Deprecated: true, Substitute: flagkey.HtIngressRule}
HtIngressFlag = Flag{Type: Bool, Name: flagkey.HtIngress, Usage: "Creates ingress with same URL"}
HtIngressRuleFlag = Flag{Type: String, Name: flagkey.HtIngressRule, Usage: "Host for Ingress rule: --ingressrule host=path (the format of host/path depends on what ingress controller you used)"}
HtIngressAnnotationFlag = Flag{Type: StringSlice, Name: flagkey.HtIngressAnnotation, Usage: "Annotation for Ingress: --ingressannotation key=value (the format of annotation depends on what ingress controller you used)"}
HtIngressTLSFlag = Flag{Type: String, Name: flagkey.HtIngressTLS, Usage: "Name of the Secret contains TLS key and crt for Ingress (the usability of TLS features depends on what ingress controller you used)"}
HtFnNameFlag = Flag{Type: StringSlice, Name: flagkey.HtFnName, Usage: "Name(s) of the function for this trigger. (If 2 functions are supplied with this flag, traffic gets routed to them based on weights supplied with --weight flag.)"}
HtFnWeightFlag = Flag{Type: IntSlice, Name: flagkey.HtFnWeight, Usage: "Weight for each function supplied with --function flag, in the same order. Used for canary deployment"}
HtFnFilterFlag = Flag{Type: String, Name: flagkey.HtFilter, Usage: "Name of the function for trigger(s)"}
TtNameFlag = Flag{Type: String, Name: flagkey.TtName, Usage: "Time Trigger name"}
TtCronFlag = Flag{Type: String, Name: flagkey.TtCron, Usage: "Time trigger cron spec with each asterisk representing respectively second, minute, hour, the day of the month, month and day of the week. Also supports readable formats like '@every 5m', '@hourly'"}
TtFnNameFlag = Flag{Type: String, Name: flagkey.TtFnName, Usage: "Function name"}
TtRoundFlag = Flag{Type: Int, Name: flagkey.TtRound, Usage: "Get next N rounds of invocation time", DefaultValue: 1}
MqtNameFlag = Flag{Type: String, Name: flagkey.MqtName, Usage: "Message queue trigger name"}
MqtFnNameFlag = Flag{Type: String, Name: flagkey.MqtFnName, Usage: "Function name"}
MqtMQTypeFlag = Flag{Type: String, Name: flagkey.MqtMQType, Usage: "Message queue type, e.g. nats-streaming, azure-storage-queue", DefaultValue: "nats-streaming"}
MqtTopicFlag = Flag{Type: String, Name: flagkey.MqtTopic, Usage: "Message queue Topic the trigger listens on"}
MqtRespTopicFlag = Flag{Type: String, Name: flagkey.MqtRespTopic, Usage: "Topic that the function response is sent on (response discarded if unspecified)"}
MqtErrorTopicFlag = Flag{Type: String, Name: flagkey.MqtErrorTopic, Usage: "Topic that the function error messages are sent to (errors discarded if unspecified"}
MqtMaxRetriesFlag = Flag{Type: Int, Name: flagkey.MqtMaxRetries, Usage: "Maximum number of times the function will be retried upon failure", DefaultValue: 0}
MqtMsgContentTypeFlag = Flag{Type: String, Name: flagkey.MqtMsgContentType, Short: "c", Usage: "Content type of messages that publish to the topic", DefaultValue: "application/json"}
RecorderNameFlag = Flag{Type: String, Name: flagkey.RecorderName, Usage: "Recorder name"}
RecorderFnFlag = Flag{Type: String, Name: flagkey.RecorderFn, Usage: "Record Function name(s): --function=fnA"}
RecorderTriggersFlag = Flag{Type: StringSlice, Name: flagkey.RecorderTriggers, Usage: "Record Trigger name(s): --trigger=trigger1,trigger2,trigger3"}
RecorderRetentionPolicyFlag = Flag{Type: String, Name: flagkey.RecorderRetentionPolicy, Usage: "Retention policy (number of days)"}
RecorderEvictionPolicyFlag = Flag{Type: String, Name: flagkey.RecorderEvictionPolcy, Usage: "Eviction policy (default LRU)"}
RecorderEnabledFlag = Flag{Type: Bool, Name: flagkey.RecorderEnabled, Usage: "Enable recorder"}
RecorderDisabledFlag = Flag{Type: Bool, Name: flagkey.RecorderDisabled, Usage: "Disable recorder"}
RecordsFilterTimeFromFlag = Flag{Type: String, Name: flagkey.RecordsFilterTimeFrom, Usage: "Filter records by time interval; specify start of interval"}
RecordsFilterTimeToFlag = Flag{Type: String, Name: flagkey.RecordsFilterTimeTo, Usage: "Filter records by time interval; specify end of interval"}
RecordsFilterFunctionFlag = Flag{Type: String, Name: flagkey.RecordsFilterFunction, Usage: "Filter records by function"}
RecordsFilterTriggerFlag = Flag{Type: String, Name: flagkey.RecordsFilterTrigger, Usage: "Filter records by trigger"}
RecordsVerbosityFlag = Flag{Type: Bool, Name: flagkey.RecordsVerbosity, Usage: "Toggle verbosity -- view more detailed requests/responses"}
RecordsVvFlag = Flag{Type: Bool, Name: flagkey.RecordsVv, Usage: "Toggle verbosity -- view raw requests/responses"}
RecordsReqIDFlag = Flag{Type: String, Name: flagkey.RecordsReqID, Usage: "Replay a particular request by providing the reqUID (to view reqUIDs, do 'fission records view')"}
EnvNameFlag = Flag{Type: String, Name: flagkey.EnvName, Usage: "Environment name"}
EnvPoolsizeFlag = Flag{Type: Int, Name: flagkey.EnvPoolsize, Usage: "Size of the pool", DefaultValue: 3}
EnvImageFlag = Flag{Type: String, Name: flagkey.EnvImage, Usage: "Environment image URL"}
EnvBuilderImageFlag = Flag{Type: String, Name: flagkey.EnvBuilderImage, Usage: "Environment builder image URL"}
EnvBuildCmdFlag = Flag{Type: String, Name: flagkey.EnvBuildcommand, Usage: "Build command for environment builder to build source package"}
EnvKeepArchiveFlag = Flag{Type: Bool, Name: flagkey.EnvKeeparchive, Usage: "Keep the archive instead of extracting it into a directory"}
EnvExternalNetworkFlag = Flag{Type: Bool, Name: flagkey.EnvExternalNetwork, Usage: "Allow environment access external network when istio feature enabled"}
EnvTerminationGracePeriodFlag = Flag{Type: Int, Name: flagkey.EnvGracePeriod, Aliases: []string{"period"}, Usage: "Grace time (in seconds) for pod to perform connection draining before termination", DefaultValue: 360}
EnvVersionFlag = Flag{Type: Int, Name: flagkey.EnvVersion, Usage: "Environment API version (1 means v1 interface)", DefaultValue: 1}
KwNameFlag = Flag{Type: String, Name: flagkey.KwName, Usage: "Watch name"}
KwFnNameFlag = Flag{Type: String, Name: flagkey.KwFnName, Usage: "Function name"}
KwNamespaceFlag = Flag{Type: String, Name: flagkey.KwNamespace, Usage: "Namespace of resource to watch"}
KwObjTypeFlag = Flag{Type: String, Name: flagkey.KwObjType, Usage: "Type of resource to watch (Pod, Service, etc.)"}
KwLabelsFlag = Flag{Type: String, Name: flagkey.KwLabels, Usage: "Label selector of the form a=b,c=d"}
PkgNameFlag = Flag{Type: String, Name: flagkey.PkgName, Usage: "Package name"}
PkgForceFlag = Flag{Type: Bool, Name: flagkey.PkgForce, Short: "f", Usage: "Force update a package even if it is used by one or more functions"}
PkgEnvironmentFlag = Flag{Type: String, Name: flagkey.PkgEnvironment, Usage: "Environment name"}
PkgKeepURLFlag = Flag{Type: Bool, Name: flagkey.PkgKeepURL, Aliases: []string{"keepurl"}, Usage: "Keep the providing URL in archive instead of downloading file from it. (If set, no checksum will be generated for file integrity check. You must ensure the file won't be changed.)"}
PkgBuildCmdFlag = Flag{Type: String, Name: flagkey.PkgBuildCmd, Usage: "Build command for builder to run with"}
PkgOutputFlag = Flag{Type: String, Name: flagkey.PkgOutput, Short: "o", Usage: "Output filename to save archive content"}
PkgStatusFlag = Flag{Type: String, Name: flagkey.PkgStatus, Usage: `Filter packages by status`}
PkgOrphanFlag = Flag{Type: Bool, Name: flagkey.PkgOrphan, Usage: "Orphan packages that are not referenced by any function"}
PkgDeployArchiveFlag = Flag{Type: StringSlice, Name: flagkey.PkgDeployArchive, Aliases: []string{"deploy"}, Usage: "Local path or URL for binary archive"}
PkgSrcArchiveFlag = Flag{Type: StringSlice, Name: flagkey.PkgSrcArchive, Aliases: []string{"source", "src"}, Usage: "Local path or URL for source archive"}
SpecSaveFlag = Flag{Type: Bool, Name: flagkey.SpecSave, Usage: "Save to the spec directory instead of creating on cluster"}
SpecDirFlag = Flag{Type: String, Name: flagkey.SpecDir, Usage: "Directory to store specs, defaults to ./specs"}
SpecNameFlag = Flag{Type: String, Name: flagkey.SpecName, Usage: "Name for the app, applied to resources as a Kubernetes annotation"}
SpecDeployIDFlag = Flag{Type: String, Name: flagkey.SpecDeployID, Aliases: []string{"id"}, Usage: "Deployment ID for the spec deployment config"}
SpecWaitFlag = Flag{Type: Bool, Name: flagkey.SpecWait, Usage: "Wait for package builds"}
SpecWatchFlag = Flag{Type: Bool, Name: flagkey.SpecWatch, Usage: "Watch local files for change, and re-apply specs as necessary"}
SpecDeleteFlag = Flag{Type: Bool, Name: flagkey.SpecDelete, Usage: "Allow apply to delete resources that no longer exist in the specification"}
SupportOutputFlag = Flag{Type: String, Name: flagkey.SupportOutput, Short: "o", Usage: "Output directory to save dump archive/files", DefaultValue: flagkey.DefaultSpecOutputDir}
SupportNoZipFlag = Flag{Type: Bool, Name: flagkey.SupportNoZip, Usage: "Save dump information into multiple files instead of single zip file"}
CanaryNameFlag = Flag{Type: String, Name: flagkey.CanaryName, Usage: "Name for the canary config"}
CanaryTriggerNameFlag = Flag{Type: String, Name: flagkey.CanaryHTTPTriggerName, Usage: "Http trigger that this config references"}
CanaryNewFuncFlag = Flag{Type: String, Name: flagkey.CanaryNewFunc, Aliases: []string{"newfn"}, Usage: "New version of the function"}
CanaryOldFuncFlag = Flag{Type: String, Name: flagkey.CanaryOldFunc, Aliases: []string{"oldfn"}, Usage: "Old stable version of the function"}
CanaryWeightIncrementFlag = Flag{Type: Int, Name: flagkey.CanaryWeightIncrement, Aliases: []string{"step"}, Usage: "Weight increment step for function", DefaultValue: 20}
CanaryIncrementIntervalFlag = Flag{Type: String, Name: flagkey.CanaryIncrementInterval, Aliases: []string{"internal"}, Usage: "Weight increment interval, string representation of time.Duration, ex : 1m, 2h, 2d", DefaultValue: "2m"}
CanaryFailureThresholdFlag = Flag{Type: Int, Name: flagkey.CanaryFailureThreshold, Aliases: []string{"threshold"}, Usage: "Threshold in percentage beyond which the new version of the function is considered unstable", DefaultValue: 10}
)
+154
View File
@@ -0,0 +1,154 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flagkey
const (
Verbosity = "verbosity"
Server = "server"
resourceName = "name"
force = "force"
Output = "output"
NamespaceFunction = "fnNamespace"
NamespaceEnvironment = "envNamespace"
NamespacePackage = "pkgNamespace"
NamespaceTrigger = "triggerNamespace"
NamespaceRecorder = "recorderNamespace"
NamespaceCanary = "canaryNamespace"
RuntimeMincpu = "mincpu"
RuntimeMaxcpu = "maxcpu"
RuntimeMinmemory = "minmemory"
RuntimeMaxmemory = "maxmemory"
RuntimeTargetcpu = "targetcpu"
ReplicasMinscale = "minscale"
ReplicasMaxscale = "maxscale"
FnName = resourceName
FnSpecializationTimeout = "specializationtimeout"
FnEnvironmentName = "env"
FnCode = "code"
FnPackageName = "pkgname"
FnEntrypoint = "entrypoint"
FnBuildCmd = "buildcmd"
FnSecret = "secret"
FnForce = force
FnCfgMap = "configmap"
FnExecutorType = "executortype"
FnExecutionTimeout = "fntimeout"
FnTestTimeout = "timeout"
FnLogPod = "pod"
FnLogFollow = "follow"
FnLogDetail = "detail"
FnLogDBType = "dbtype"
FnLogReverseQuery = "reverse"
FnLogCount = "recordcount"
FnTestBody = "body"
FnTestHeader = "header"
FnTestQuery = "query"
HtName = resourceName
HtMethod = "method"
HtUrl = "url"
HtHost = "host"
HtIngress = "createingress"
HtIngressRule = "ingressrule"
HtIngressAnnotation = "ingressannotation"
HtIngressTLS = "ingresstls"
HtFnName = "function"
HtFnWeight = "weight"
HtFilter = HtFnName
TtName = resourceName
TtCron = "cron"
TtFnName = "function"
TtRound = "round"
MqtName = resourceName
MqtFnName = "function"
MqtMQType = "mqtype"
MqtTopic = "topic"
MqtRespTopic = "resptopic"
MqtErrorTopic = "errortopic"
MqtMaxRetries = "maxretries"
MqtMsgContentType = "contenttype"
RecorderName = resourceName
RecorderFn = "function"
RecorderTriggers = "trigger"
RecorderRetentionPolicy = "retention"
RecorderEvictionPolcy = "eviction"
RecorderEnabled = "enable"
RecorderDisabled = "disable"
RecordsFilterTimeFrom = "from"
RecordsFilterTimeTo = "to"
RecordsFilterFunction = "function"
RecordsFilterTrigger = "trigger"
RecordsVerbosity = "v"
RecordsVv = "vv"
RecordsReqID = "reqUID"
EnvName = resourceName
EnvPoolsize = "poolsize"
EnvImage = "image"
EnvBuilderImage = "builder"
EnvBuildcommand = "buildcmd"
EnvKeeparchive = "keeparchive"
EnvExternalNetwork = "externalnetwork"
EnvGracePeriod = "graceperiod"
EnvVersion = "version"
KwName = resourceName
KwFnName = "function"
KwNamespace = "ns"
KwObjType = "type"
KwLabels = "labels"
PkgName = resourceName
PkgForce = force
PkgEnvironment = "env"
PkgSrcArchive = "sourcearchive"
PkgDeployArchive = "deployarchive"
PkgKeepURL = "keeparchiveurl"
PkgBuildCmd = "buildcmd"
PkgOutput = Output
PkgStatus = "status"
PkgOrphan = "orphan"
SpecSave = "spec"
SpecDir = "specdir"
SpecName = resourceName
SpecDeployID = "deployid"
SpecWait = "wait"
SpecWatch = "watch"
SpecDelete = "delete"
SupportOutput = Output
SupportNoZip = "nozip"
CanaryName = resourceName
CanaryHTTPTriggerName = "httptrigger"
CanaryNewFunc = "newfunction"
CanaryOldFunc = "oldfunction"
CanaryWeightIncrement = "increment-step"
CanaryIncrementInterval = "increment-interval"
CanaryFailureThreshold = "failure-threshold"
DefaultSpecOutputDir = "fission-dump"
)
+10 -10
View File
@@ -31,7 +31,7 @@ import (
"k8s.io/client-go/tools/portforward"
"k8s.io/client-go/transport/spdy"
"github.com/fission/fission/pkg/fission-cli/consolemsg"
"github.com/fission/fission/pkg/fission-cli/console"
"github.com/fission/fission/pkg/utils"
)
@@ -41,7 +41,7 @@ import (
// its targetPort. Once the port forward is started, wait for it to
// start accepting connections before returning.
func SetupPortForward(namespace, labelSelector string) (string, error) {
consolemsg.Verbose(2, "Setting up port forward to %s in namespace %s",
console.Verbose(2, "Setting up port forward to %s in namespace %s",
labelSelector, namespace)
localPort, err := findFreePort()
@@ -49,7 +49,7 @@ func SetupPortForward(namespace, labelSelector string) (string, error) {
return "", errors.Wrap(err, "error finding unused port")
}
consolemsg.Verbose(2, "Waiting for local port %v", localPort)
console.Verbose(2, "Waiting for local port %v", localPort)
for {
conn, _ := net.DialTimeout("tcp",
net.JoinHostPort("", localPort), time.Millisecond)
@@ -61,7 +61,7 @@ func SetupPortForward(namespace, labelSelector string) (string, error) {
time.Sleep(time.Millisecond * 50)
}
consolemsg.Verbose(2, "Starting port forward from local port %v", localPort)
console.Verbose(2, "Starting port forward from local port %v", localPort)
go func() {
err := runPortForward(labelSelector, localPort, namespace)
if err != nil {
@@ -70,7 +70,7 @@ func SetupPortForward(namespace, labelSelector string) (string, error) {
}
}()
consolemsg.Verbose(2, "Waiting for port forward %v to start...", localPort)
console.Verbose(2, "Waiting for port forward %v to start...", localPort)
for {
conn, _ := net.DialTimeout("tcp",
net.JoinHostPort("", localPort), time.Millisecond)
@@ -81,7 +81,7 @@ func SetupPortForward(namespace, labelSelector string) (string, error) {
time.Sleep(time.Millisecond * 50)
}
consolemsg.Verbose(2, "Port forward from local port %v started", localPort)
console.Verbose(2, "Port forward from local port %v started", localPort)
return localPort, nil
}
@@ -109,7 +109,7 @@ func runPortForward(labelSelector string, localPort string, ns string) error {
return err
}
consolemsg.Verbose(2, "Connected to Kubernetes API")
console.Verbose(2, "Connected to Kubernetes API")
// if namespace is unset, try to find a pod in any namespace
if len(ns) == 0 {
@@ -177,7 +177,7 @@ func runPortForward(labelSelector string, localPort string, ns string) error {
for _, servicePort := range service.Spec.Ports {
targetPort = servicePort.TargetPort.String()
}
consolemsg.Verbose(2, "Connecting to port %v on pod %v/%v", targetPort, podNameSpace, podNameSpace)
console.Verbose(2, "Connecting to port %v on pod %v/%v", targetPort, podNameSpace, podNameSpace)
stopChannel := make(chan struct{}, 1)
readyChannel := make(chan struct{})
@@ -199,7 +199,7 @@ func runPortForward(labelSelector string, localPort string, ns string) error {
dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", url)
outStream := os.Stdout
if consolemsg.Verbosity < 2 {
if console.Verbosity < 2 {
outStream = nil
}
fw, err := portforward.New(dialer, ports, stopChannel, readyChannel, outStream, os.Stderr)
@@ -207,6 +207,6 @@ func runPortForward(labelSelector string, localPort string, ns string) error {
return errors.Wrap(err, "error creating port forwarder")
}
consolemsg.Verbose(2, "Starting port forwarder")
console.Verbose(2, "Starting port forwarder")
return fw.ForwardPorts()
}
+18 -17
View File
@@ -36,10 +36,11 @@ import (
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/consolemsg"
"github.com/fission/fission/pkg/fission-cli/flag"
"github.com/fission/fission/pkg/fission-cli/console"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/info"
"github.com/fission/fission/pkg/plugin"
"github.com/fission/fission/pkg/utils"
)
func GetFissionNamespace() string {
@@ -111,7 +112,7 @@ func GetKubernetesClient() (*restclient.Config, *kubernetes.Clientset, error) {
// In case that user.Current() may be unable to work under some circumstances and return errors like
// "user: Current not implemented on darwin/amd64" due to cross-compilation problem. (https://github.com/golang/go/issues/6376).
// Instead of doing fatal here, we fallback to get home directory from the environment $HOME.
consolemsg.Warn(fmt.Sprintf("Could not get the current user's directory (%s), fallback to get it from env $HOME", err))
console.Warn(fmt.Sprintf("Could not get the current user's directory (%s), fallback to get it from env $HOME", err))
homeDir = os.Getenv("HOME")
} else {
homeDir = usr.HomeDir
@@ -123,9 +124,9 @@ func GetKubernetesClient() (*restclient.Config, *kubernetes.Clientset, error) {
"Set the KUBECONFIG environment variable to your kubeconfig's path.")
}
loadingRules.ExplicitPath = kubeConfigPath
consolemsg.Verbose(2, "Using kubeconfig from %q", kubeConfigPath)
console.Verbose(2, "Using kubeconfig from %q", kubeConfigPath)
} else {
consolemsg.Verbose(2, "Using kubeconfig from environment %q", kubeConfigPath)
console.Verbose(2, "Using kubeconfig from environment %q", kubeConfigPath)
}
config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
@@ -180,7 +181,7 @@ func GetVersion(client *client.Client) info.Versions {
serverInfo, err := client.ServerInfo()
if err != nil {
consolemsg.Warn(fmt.Sprintf("Error getting Fission API version: %v", err))
console.Warn(fmt.Sprintf("Error getting Fission API version: %v", err))
serverInfo = &info.ServerInfo{}
}
@@ -195,7 +196,7 @@ func GetVersion(client *client.Client) info.Versions {
}
func GetServer(flags cli.Input) (c *client.Client, err error) {
serverUrl := flags.GlobalString(flag.FISSION_SERVER)
serverUrl := flags.GlobalString(flagkey.Server)
if len(serverUrl) == 0 {
// starts local portforwarder etc.
serverUrl, err = GetApplicationUrl("application=fission-api")
@@ -230,10 +231,10 @@ func GetResourceReqs(flags cli.Input, resReqs *v1.ResourceRequirements) (*v1.Res
r.Limits = make(map[v1.ResourceName]resource.Quantity)
}
e := &multierror.Error{}
e := utils.MultiErrorWithFormat()
if flags.IsSet(flag.RUNTIME_MINCPU) {
mincpu := flags.Int(flag.RUNTIME_MINCPU)
if flags.IsSet(flagkey.RuntimeMincpu) {
mincpu := flags.Int(flagkey.RuntimeMincpu)
cpuRequest, err := resource.ParseQuantity(strconv.Itoa(mincpu) + "m")
if err != nil {
e = multierror.Append(e, errors.Wrap(err, "Failed to parse mincpu"))
@@ -241,8 +242,8 @@ func GetResourceReqs(flags cli.Input, resReqs *v1.ResourceRequirements) (*v1.Res
r.Requests[v1.ResourceCPU] = cpuRequest
}
if flags.IsSet(flag.RUNTIME_MINMEMORY) {
minmem := flags.Int(flag.RUNTIME_MINMEMORY)
if flags.IsSet(flagkey.RuntimeMinmemory) {
minmem := flags.Int(flagkey.RuntimeMinmemory)
memRequest, err := resource.ParseQuantity(strconv.Itoa(minmem) + "Mi")
if err != nil {
e = multierror.Append(e, errors.Wrap(err, "Failed to parse minmemory"))
@@ -250,8 +251,8 @@ func GetResourceReqs(flags cli.Input, resReqs *v1.ResourceRequirements) (*v1.Res
r.Requests[v1.ResourceMemory] = memRequest
}
if flags.IsSet(flag.RUNTIME_MAXCPU) {
maxcpu := flags.Int(flag.RUNTIME_MAXCPU)
if flags.IsSet(flagkey.RuntimeMaxcpu) {
maxcpu := flags.Int(flagkey.RuntimeMaxcpu)
cpuLimit, err := resource.ParseQuantity(strconv.Itoa(maxcpu) + "m")
if err != nil {
e = multierror.Append(e, errors.Wrap(err, "Failed to parse maxcpu"))
@@ -259,8 +260,8 @@ func GetResourceReqs(flags cli.Input, resReqs *v1.ResourceRequirements) (*v1.Res
r.Limits[v1.ResourceCPU] = cpuLimit
}
if flags.IsSet(flag.RUNTIME_MAXMEMORY) {
maxmem := flags.Int(flag.RUNTIME_MAXMEMORY)
if flags.IsSet(flagkey.RuntimeMaxmemory) {
maxmem := flags.Int(flagkey.RuntimeMaxmemory)
memLimit, err := resource.ParseQuantity(strconv.Itoa(maxmem) + "Mi")
if err != nil {
e = multierror.Append(e, errors.Wrap(err, "Failed to parse maxmemory"))
@@ -297,7 +298,7 @@ func GetResourceReqs(flags cli.Input, resReqs *v1.ResourceRequirements) (*v1.Res
}
func GetSpecDir(flags cli.Input) string {
specDir := flags.String(flag.SPEC_SPECDIR)
specDir := flags.String(flagkey.SpecDir)
if len(specDir) == 0 {
specDir = "specs"
}
+40
View File
@@ -0,0 +1,40 @@
/*
Copyright 2019 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package utils
import (
"fmt"
"strings"
"github.com/hashicorp/go-multierror"
)
func MultiErrorWithFormat() *multierror.Error {
return &multierror.Error{
ErrorFormat: DefaultErrorFormat,
}
}
func DefaultErrorFormat(es []error) string {
points := make([]string, len(es))
for i, err := range es {
points[i] = fmt.Sprintf("* %s", err)
}
return fmt.Sprintf(
"%d errors occurred:\n\t%s\n",
len(es), strings.Join(points, "\n\t"))
}
-22
View File
@@ -98,25 +98,3 @@ type (
errorCode int
)
//const (
// ErrorInternal = iota
//
// ErrorNotAuthorized
// ErrorNotFound
// ErrorNameExists
// ErrorInvalidArgument
// ErrorNoSpace
// ErrorNotImplmented
//)
//
//// must match order and len of the above const
//var errorDescriptions = []string{
// "Internal error",
// "Not authorized",
// "Resource not found",
// "Resource exists",
// "Invalid argument",
// "No space",
// "Not implemented",
//}
@@ -1,4 +1,5 @@
#!/bin/bash
#test:disabled
#
# Simple end-to-end test of record with POST
@@ -1,4 +1,5 @@
#!/bin/bash
#test:disabled
#
# Simple end-to-end test of record with GET
@@ -1,4 +1,5 @@
#!/bin/bash
#test:disabled
#
# Simple test of recorder updates