diff --git a/README.md b/README.md index 4f547fb19..48f1546cb 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,13 @@ Vela is a command-line tool to use OAM based micro-app engine. ## Develop Check out [DEVELOPMENT.md](./DEVELOPMENT.md) to see how to develop with RudrX -## Build `vela` binary +## Install `vela` binary + ```shell script -$ go build -o /usr/local/bin/vela cmd/vela/main.go -$ chmod +x /usr/local/bin/vela +git clone git@github.com:cloud-native-application/RudrX.git +cd RudrX +make +mv bin/vela /usr/local/bin ``` ## Vela commands @@ -23,24 +26,45 @@ Usage: vela [command] Available Commands: - ManualScaler Attach ManualScaler trait to an app - SimpleRollout Attach SimpleRollout trait to an app - app:delete Delete OAM Applications - app:ls List applications - app:status get status of an application - completion Output shell completion code for the specified shell (bash or zsh) - containerized:run Run containerized workloads - deployment:run Run deployment workloads - env List environments - env:delete Delete environment - env:init Create environments - env:sw Switch environments - help Help about any command - init Initialize RudrX on both client and server - route Attach route trait to an app - traits List traits - version Prints out build version information - workloads List workloads + + Getting Started: + env List all environments + env:delete Delete environment + env:init Create environment and switch to it + env:sw switch to another environment + version Prints out build version information + + Applications: + app:delete [APPLICATION_NAME] Delete OAM Applications + app:ls List applications with workloads, traits, status and created time + app:status get status of an application, including its workload and trait + + Workloads: + containerized:run [args] Run containerized workloads + deployment:run [args] Run deployment workloads + + Traits: + manualscaler [args] Attach manualscaler trait to an app + manualscaler:detach Detach manualscaler trait from an app + rollout [args] Attach rollout trait to an app + rollout:detach Detach rollout trait from an app + route [args] Attach route trait to an app + route:detach Detach route trait from an app + + Release: + + + Others: + addon:config Set the addon center, default is local (built-in ones) + addon:ls List addons of workloads and traits + + System: + completion [bash|zsh] Output shell completion code for the specified shell (bash or zsh... + refresh Refresh and sync definition files from cluster + system:info show vela client and cluster version + system:init [flags] Install OAM runtime and vela builtin capabilities. + +Use "vela [command] --help" for more information about a command. ``` diff --git a/api/types/types.go b/api/types/types.go index b9416edfa..782f4cbd2 100644 --- a/api/types/types.go +++ b/api/types/types.go @@ -126,3 +126,15 @@ func (app *Application) GetTraits(componentName string) (map[string]interface{}, type EnvMeta struct { Namespace string `json:"namespace"` } + +const ( + TagCommandType = "commandType" + + TypeStart = "Getting Started" + TypeApp = "Applications" + TypeWorkloads = "Workloads" + TypeTraits = "Traits" + TypeRelease = "Release" + TypeOthers = "Others" + TypeSystem = "System" +) diff --git a/cmd/vela/main.go b/cmd/vela/main.go index 6ccd1afd3..5d31a7724 100644 --- a/cmd/vela/main.go +++ b/cmd/vela/main.go @@ -1,12 +1,18 @@ package main import ( + "flag" "fmt" "math/rand" "os" "runtime" + "strings" "time" + "github.com/gosuri/uitable" + + "k8s.io/klog" + "github.com/cloud-native-application/rudrx/api/types" "sigs.k8s.io/controller-runtime/pkg/client/config" @@ -90,32 +96,39 @@ func newCommand() *cobra.Command { } cmds.AddCommand( - cmd.NewAdminInitCommand(commandArgs, ioStream), - cmd.NewAdminInfoCommand(VelaVersion, ioStream), - - cmd.NewTraitsCommand(ioStream), - cmd.NewWorkloadsCommand(ioStream), - cmd.NewRefreshCommand(commandArgs, ioStream), - - cmd.NewDeleteCommand(commandArgs, ioStream, os.Args[1:]), - cmd.NewAppsCommand(commandArgs, ioStream), - cmd.NewAppStatusCommand(commandArgs, ioStream), - + // Getting Start cmd.NewEnvInitCommand(commandArgs, ioStream), cmd.NewEnvSwitchCommand(ioStream), cmd.NewEnvDeleteCommand(ioStream), cmd.NewEnvCommand(ioStream), + NewVersionCommand(), + // Apps + cmd.NewAppsCommand(commandArgs, ioStream), + cmd.NewDeleteCommand(commandArgs, ioStream, os.Args[1:]), + cmd.NewAppStatusCommand(commandArgs, ioStream), + + // Others cmd.NewAddonConfigCommand(ioStream), cmd.NewAddonListCommand(commandArgs, ioStream), + // System + cmd.NewAdminInitCommand(commandArgs, ioStream), + cmd.NewAdminInfoCommand(VelaVersion, ioStream), + cmd.NewRefreshCommand(commandArgs, ioStream), cmd.NewCompletionCommand(), - NewVersionCommand(), + + cmd.NewTraitsCommand(ioStream), + cmd.NewWorkloadsCommand(ioStream), ) + + // Workloads if err = cmd.AddWorkloadPlugins(cmds, commandArgs, ioStream); err != nil { fmt.Println("Add plugins from workloadDefinition err", err) os.Exit(1) } + + // Traits if err = cmd.AddTraitPlugins(cmds, commandArgs, ioStream); err != nil { fmt.Println("Add plugins from traitDefinition err", err) os.Exit(1) @@ -124,9 +137,44 @@ func newCommand() *cobra.Command { fmt.Println("Add plugins from traitDefinition err", err) os.Exit(1) } + + cmds.SetHelpFunc(func(cmd *cobra.Command, args []string) { + allCommands := cmd.Commands() + cmd.Printf("✈️ A Micro App Plafrom for Kubernetes.\n\nUsage:\n vela [flags]\n vela [command]\n\nAvailable Commands:\n\n") + PrintHelpByTag(cmd, allCommands, types.TypeStart) + PrintHelpByTag(cmd, allCommands, types.TypeApp) + PrintHelpByTag(cmd, allCommands, types.TypeWorkloads) + PrintHelpByTag(cmd, allCommands, types.TypeTraits) + PrintHelpByTag(cmd, allCommands, types.TypeRelease) + PrintHelpByTag(cmd, allCommands, types.TypeOthers) + PrintHelpByTag(cmd, allCommands, types.TypeSystem) + cmd.Println("Flags:") + cmd.Println(" -h, --help help for vela") + cmd.Println() + cmd.Println(`Use "vela [command] --help" for more information about a command.`) + + }) + + // this is for mute klog + fset := flag.NewFlagSet("logs", flag.ContinueOnError) + klog.InitFlags(fset) + fset.Set("v", "-1") return cmds } +func PrintHelpByTag(cmd *cobra.Command, all []*cobra.Command, tag string) { + cmd.Printf(" %s:\n", tag) + table := uitable.New() + for _, c := range all { + useline := strings.TrimPrefix(c.UseLine(), "vela ") + if val, ok := c.Annotations[types.TagCommandType]; ok && val == tag { + table.AddRow(" "+useline, c.Long) + } + } + cmd.Println(table.String()) + cmd.Println() +} + func runHelp(cmd *cobra.Command, args []string) { cmd.Help() } @@ -135,6 +183,7 @@ func NewVersionCommand() *cobra.Command { return &cobra.Command{ Use: "version", Short: "Prints out build version information", + Long: "Prints out build version information", Run: func(cmd *cobra.Command, args []string) { fmt.Printf(`Version: %v GitRevision: %v @@ -144,5 +193,8 @@ GolangVersion: %v GitRevision, runtime.Version()) }, + Annotations: map[string]string{ + types.TagCommandType: types.TypeStart, + }, } } diff --git a/pkg/builtin/deployment.go b/pkg/builtin/deployment.go new file mode 100644 index 000000000..e901456c0 --- /dev/null +++ b/pkg/builtin/deployment.go @@ -0,0 +1,40 @@ +package builtin + +var Deployment = `apiVersion: core.oam.dev/v1alpha2 +kind: WorkloadDefinition +metadata: + name: deployments.apps + annotations: + oam.appengine.info/apiVersion: "apps/v1" + oam.appengine.info/kind: "Deployment" +spec: + definitionRef: + name: deployments.apps + extension: + template: | + #Template: { + apiVersion: "apps/v1" + kind: "Deployment" + metadata: name: deployment.name + spec: { + containers: [{ + image: deployment.image + name: deployment.name + env: deployment.env + ports: [{ + containerPort: deployment.port + protocol: "TCP" + name: "default" + }] + }] + } + } + deployment: { + name: string + image: string + port: *8080 | int + env: [...{ + name: string + value: string + }] + }` diff --git a/pkg/cmd/addon.go b/pkg/cmd/addon.go index ec5744f2e..b7d3cecee 100644 --- a/pkg/cmd/addon.go +++ b/pkg/cmd/addon.go @@ -78,6 +78,9 @@ func NewAddonConfigCommand(ioStreams cmdutil.IOStreams) *cobra.Command { ioStreams.Errorf("Unnecessary arguments are specified, please try again") } }, + Annotations: map[string]string{ + types.TagCommandType: types.TypeOthers, + }, } return cmd } @@ -104,6 +107,9 @@ func NewAddonListCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Comma } return nil }, + Annotations: map[string]string{ + types.TagCommandType: types.TypeOthers, + }, } return cmd } diff --git a/pkg/cmd/init.go b/pkg/cmd/admin.go similarity index 91% rename from pkg/cmd/init.go rename to pkg/cmd/admin.go index df7fdbcc6..e6f16fbc0 100644 --- a/pkg/cmd/init.go +++ b/pkg/cmd/admin.go @@ -7,6 +7,8 @@ import ( "log" "os" + "github.com/cloud-native-application/rudrx/pkg/builtin" + "helm.sh/helm/v3/pkg/release" "github.com/cloud-native-application/rudrx/api/types" @@ -38,14 +40,6 @@ var ( settings = cli.New() ) -const initDesc = ` -This command installs oam-kubernetes-runtime onto your Kubernetes Cluster. -As with the rest of the Vela commands, 'vela init' discovers Kubernetes clusters -by reading $KUBECONFIG (default '~/.kube/config') and using the default context. -When installing oam-kubernetes-runtime, 'vela init' will attempt to install the latest released -version. -` - type initCmd struct { namespace string out io.Writer @@ -70,13 +64,7 @@ var ( } workloadResource = map[string]string{ - "statefulset": "statefulsets.apps", - "daemonset": "daemonsets.apps", - "deployment": "deployments.apps", - "job": "jobs.batch", - "secret": "secrets", - "service": "services", - "configmap": "configmaps", + "deployment": builtin.Deployment, } ) @@ -84,11 +72,15 @@ func NewAdminInfoCommand(version string, ioStreams cmdutil.IOStreams) *cobra.Com i := &infoCmd{out: ioStreams.Out} cmd := &cobra.Command{ - Use: "admin:info", + Use: "system:info", Short: "show vela client and cluster version", + Long: "show vela client and cluster version", RunE: func(cmd *cobra.Command, args []string) error { return i.run(version, ioStreams) }, + Annotations: map[string]string{ + types.TagCommandType: types.TypeSystem, + }, } return cmd } @@ -111,9 +103,9 @@ func NewAdminInitCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Comma i := &initCmd{out: ioStreams.Out} cmd := &cobra.Command{ - Use: "admin:init", - Short: "Initialize Vela on both client and server", - Long: initDesc, + Use: "system:init", + Short: "Initialize vela on both client and server", + Long: "Install OAM runtime and vela builtin capabilities.", RunE: func(cmd *cobra.Command, args []string) error { newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema}) if err != nil { @@ -123,6 +115,9 @@ func NewAdminInitCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Comma i.namespace = types.DefaultOAMNS return i.run(ioStreams) }, + Annotations: map[string]string{ + types.TagCommandType: types.TypeSystem, + }, } flag := cmd.Flags() diff --git a/pkg/cmd/completion.go b/pkg/cmd/completion.go index c634d50bc..e6ea39f48 100644 --- a/pkg/cmd/completion.go +++ b/pkg/cmd/completion.go @@ -2,20 +2,20 @@ package cmd import ( "fmt" - "github.com/spf13/cobra" "io" "os" "path/filepath" + + "github.com/cloud-native-application/rudrx/api/types" + "github.com/spf13/cobra" ) -const completionDesc = ` -Output shell completion code for the specified shell (bash or zsh). +const completionDesc = `Output shell completion code for the specified shell (bash or zsh). The shell code must be evaluated to provide interactive completion of vela commands. ` -const bashCompDesc = ` -Generate the autocompletion script for Vela for the bash shell. +const bashCompDesc = `Generate the autocompletion script for Vela for the bash shell. To load completions in your current shell session: $ source <(vela completion bash) @@ -27,8 +27,7 @@ MacOS: $ vela completion bash > /usr/local/etc/bash_completion.d/vela ` -const zshCompDesc = ` -Generate the autocompletion script for Vela for the zsh shell. +const zshCompDesc = `Generate the autocompletion script for Vela for the zsh shell. To load completions in your current shell session: $ source <(vela completion zsh) @@ -43,6 +42,9 @@ func NewCompletionCommand() *cobra.Command { Short: "Output shell completion code for the specified shell (bash or zsh)", Long: completionDesc, Args: cobra.NoArgs, + Annotations: map[string]string{ + types.TagCommandType: types.TypeSystem, + }, } bash := &cobra.Command{ diff --git a/pkg/cmd/delete.go b/pkg/cmd/delete.go index 48e6647cc..a74dc01e3 100644 --- a/pkg/cmd/delete.go +++ b/pkg/cmd/delete.go @@ -31,6 +31,9 @@ func newDeleteCommand() *cobra.Command { DisableFlagsInUseLine: true, Short: "Delete OAM Applications", Long: "Delete OAM Applications", + Annotations: map[string]string{ + types.TagCommandType: types.TypeApp, + }, Example: ` vela delete frontend `} diff --git a/pkg/cmd/env.go b/pkg/cmd/env.go index 647d850bb..b6c0bbfb5 100644 --- a/pkg/cmd/env.go +++ b/pkg/cmd/env.go @@ -32,6 +32,9 @@ func NewEnvCommand(ioStreams cmdutil.IOStreams) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { return ListEnvs(ctx, args, ioStreams) }, + Annotations: map[string]string{ + types.TagCommandType: types.TypeStart, + }, } cmd.SetOut(ioStreams.Out) cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) { @@ -60,6 +63,9 @@ func NewEnvInitCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command } return CreateOrUpdateEnv(ctx, newClient, &envArgs, args, ioStreams) }, + Annotations: map[string]string{ + types.TagCommandType: types.TypeStart, + }, } cmd.SetOut(ioStreams.Out) cmd.Flags().StringVar(&envArgs.Namespace, "namespace", "default", "specify K8s namespace for env") @@ -77,6 +83,9 @@ func NewEnvDeleteCommand(ioStreams cmdutil.IOStreams) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { return DeleteEnv(ctx, args, ioStreams) }, + Annotations: map[string]string{ + types.TagCommandType: types.TypeStart, + }, } cmd.SetOut(ioStreams.Out) return cmd @@ -93,6 +102,9 @@ func NewEnvSwitchCommand(ioStreams cmdutil.IOStreams) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { return SwitchEnv(ctx, args, ioStreams) }, + Annotations: map[string]string{ + types.TagCommandType: types.TypeStart, + }, } cmd.SetOut(ioStreams.Out) return cmd diff --git a/pkg/cmd/ls.go b/pkg/cmd/ls.go index 7b68bcc1a..23e2a017d 100644 --- a/pkg/cmd/ls.go +++ b/pkg/cmd/ls.go @@ -32,6 +32,9 @@ func NewAppsCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command { printApplicationList(ctx, newClient, "", env.Namespace) return nil }, + Annotations: map[string]string{ + types.TagCommandType: types.TypeApp, + }, } cmd.PersistentFlags().StringP("app", "a", "", "Application name") diff --git a/pkg/cmd/refresh.go b/pkg/cmd/refresh.go index 8cfcc6582..f1514d324 100644 --- a/pkg/cmd/refresh.go +++ b/pkg/cmd/refresh.go @@ -28,6 +28,9 @@ func NewRefreshCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command } return RefreshDefinitions(ctx, newClient, ioStreams) }, + Annotations: map[string]string{ + types.TagCommandType: types.TypeSystem, + }, } cmd.SetOut(ioStreams.Out) return cmd diff --git a/pkg/cmd/status.go b/pkg/cmd/status.go index 9b83727b6..b9316a1de 100644 --- a/pkg/cmd/status.go +++ b/pkg/cmd/status.go @@ -39,6 +39,9 @@ func NewAppStatusCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Comma } return printApplicationStatus(ctx, newClient, ioStreams, appName, namespace) }, + Annotations: map[string]string{ + types.TagCommandType: types.TypeApp, + }, } cmd.SetOut(ioStreams.Out) return cmd diff --git a/pkg/cmd/trait_bind.go b/pkg/cmd/trait_bind.go index 1e7de9639..e48d3b61b 100644 --- a/pkg/cmd/trait_bind.go +++ b/pkg/cmd/trait_bind.go @@ -72,6 +72,9 @@ func AddTraitPlugins(parentCmd *cobra.Command, c types.Args, ioStreams cmdutil.I } return o.Run(cmd, ctx) }, + Annotations: map[string]string{ + types.TagCommandType: types.TypeTraits, + }, } pluginCmd.SetOut(o.Out) for _, v := range tmp.Parameters { @@ -196,6 +199,9 @@ func DetachTraitPlugins(parentCmd *cobra.Command, c types.Args, ioStreams cmduti } return o.Run(cmd, ctx) }, + Annotations: map[string]string{ + types.TagCommandType: types.TypeTraits, + }, } pluginCmd.SetOut(o.Out) o.TraitAlias = name diff --git a/pkg/cmd/workload_run.go b/pkg/cmd/workload_run.go index ed686189c..23ab673a4 100644 --- a/pkg/cmd/workload_run.go +++ b/pkg/cmd/workload_run.go @@ -75,6 +75,9 @@ func AddWorkloadPlugins(parentCmd *cobra.Command, c types.Args, ioStreams cmduti } return o.Run(cmd) }, + Annotations: map[string]string{ + types.TagCommandType: types.TypeWorkloads, + }, } pluginCmd.SetOut(o.Out) for _, v := range tmp.Parameters { diff --git a/pkg/utils/logs/logs.go b/pkg/utils/logs/logs.go index f9656712b..e39c718ae 100644 --- a/pkg/utils/logs/logs.go +++ b/pkg/utils/logs/logs.go @@ -18,6 +18,7 @@ package logs import ( "flag" + "io/ioutil" "log" "time" @@ -41,8 +42,10 @@ func (writer KlogWriter) Write(data []byte) (n int, err error) { // InitLogs initializes logs the way we want for kubernetes. func InitLogs() { - log.SetOutput(KlogWriter{}) - log.SetFlags(0) + log.SetOutput(ioutil.Discard) + klog.SetOutput(ioutil.Discard) + log.SetFlags(-1) + // The default glog flush interval is one second. go wait.Until(klog.Flush, time.Second, wait.NeverStop) }