From e91dceac4b25575262b0a1a012c2ed01cfb85d52 Mon Sep 17 00:00:00 2001 From: zzxwill Date: Wed, 29 Jul 2020 22:21:59 +0800 Subject: [PATCH] Make modification for latest xxxdefinition.spec.extension --- cmd/rudrx/main.go | 12 +- .../containerizedworkload_definition.yaml | 49 ------ .../core.oam.dev_v1alpha2_template.yaml | 34 ---- ...nualscalertrait.core.oam.dev-template.yaml | 19 -- .../manualscaletrait_definition.yaml | 12 -- .../simplerollout_trait_definition.yaml | 14 -- ...rollouttraits.extend.oam.dev-template.yaml | 38 ---- .../traits/manualscaletrait_definition.yaml | 23 +++ .../traits/simplerollouttrait_definition.yaml | 44 +++++ .../containerizedworkload_definition.yaml | 41 +++++ .../workloads/deployment_definition.yaml | 36 ++++ pkg/cmd/bind.go | 162 +++++++----------- pkg/cmd/ls.go | 9 +- pkg/cmd/run.go | 51 ++---- pkg/cmd/traits.go | 26 +-- pkg/cmd/util/helpers.go | 146 +++++++++++++++- pkg/cmd/util/template_types.go | 47 +---- 17 files changed, 395 insertions(+), 368 deletions(-) delete mode 100644 config/samples/components/ContainerizedWorkload/containerizedworkload_definition.yaml delete mode 100644 config/samples/components/ContainerizedWorkload/core.oam.dev_v1alpha2_template.yaml delete mode 100644 config/samples/traits/ManualScalerTrait/manualscalertrait.core.oam.dev-template.yaml delete mode 100644 config/samples/traits/ManualScalerTrait/manualscaletrait_definition.yaml delete mode 100644 config/samples/traits/SimpleRollout/simplerollout_trait_definition.yaml delete mode 100644 config/samples/traits/SimpleRollout/simplerollouttraits.extend.oam.dev-template.yaml create mode 100644 config/samples/traits/manualscaletrait_definition.yaml create mode 100644 config/samples/traits/simplerollouttrait_definition.yaml create mode 100644 config/samples/workloads/containerizedworkload_definition.yaml create mode 100644 config/samples/workloads/deployment_definition.yaml diff --git a/cmd/rudrx/main.go b/cmd/rudrx/main.go index b8e77c908..8f0b55fe4 100644 --- a/cmd/rudrx/main.go +++ b/cmd/rudrx/main.go @@ -47,7 +47,7 @@ func init() { func main() { rand.Seed(time.Now().UnixNano()) - command := newCommand(os.Args[1:]) + command := newCommand() logs.InitLogs() defer logs.FlushLogs() @@ -55,7 +55,7 @@ func main() { command.Execute() } -func newCommand(args []string) *cobra.Command { +func newCommand() *cobra.Command { ioStream := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr} cmds := &cobra.Command{ @@ -82,12 +82,12 @@ func newCommand(args []string) *cobra.Command { } cmds.AddCommand( - cmd.NewRunCommand(f, client, ioStream, args), - cmd.NewTraitsCommand(f, client, ioStream, args), + cmd.NewRunCommand(f, client, ioStream, os.Args[1:]), + cmd.NewTraitsCommand(f, client, ioStream), cmd.NewWorkloadsCommand(f, client, ioStream, args), - cmd.NewBindCommand(f, client, ioStream, args), + cmd.NewBindCommand(f, client, ioStream), cmd.NewInitCommand(f, client, ioStream), - cmd.NewDeleteCommand(f, client, ioStream, args), + cmd.NewDeleteCommand(f, client, ioStream, os.Args[1:]), cmd.NewAppsCommand(f, client, ioStream), NewVersionCommand(), ) diff --git a/config/samples/components/ContainerizedWorkload/containerizedworkload_definition.yaml b/config/samples/components/ContainerizedWorkload/containerizedworkload_definition.yaml deleted file mode 100644 index 9ca16a007..000000000 --- a/config/samples/components/ContainerizedWorkload/containerizedworkload_definition.yaml +++ /dev/null @@ -1,49 +0,0 @@ -apiVersion: core.oam.dev/v1alpha2 -kind: WorkloadDefinition -metadata: - name: containerizedworkloads.core.oam.dev - annotations: - short: containerized -spec: - definitionRef: - name: containerizedworkloads.core.oam.dev - childResourceKinds: - - apiVersion: apps/v1 - kind: Deployment - - apiVersion: v1 - kind: Service - extension: - template: - apiVersion: admin.oam.dev/v1alpha2 - kind: Template - metadata: - annotations: - version: 0.0.1 - spec: - object: - apiVersion: core.oam.dev/v1alpha2 - kind: ContainerizedWorkload - metadata: - name: tbd - spec: - containers: - - image: myrepo/myapp:v1 - name: master - ports: - - containerPort: 6379 - protocol: TCP - name: tbd # TODO(zzxwill) A temporary workaround for ContainerizedWorkload - lastCommandParam: image - parameters: - - name: image - short: i - required: true - type: string - fieldPaths: - - "spec.containers[0].image" - - name: port - short: p - required: false - type: int - fieldPaths: - - "spec.containers[0].ports[0].containerPort" diff --git a/config/samples/components/ContainerizedWorkload/core.oam.dev_v1alpha2_template.yaml b/config/samples/components/ContainerizedWorkload/core.oam.dev_v1alpha2_template.yaml deleted file mode 100644 index 55bb571d3..000000000 --- a/config/samples/components/ContainerizedWorkload/core.oam.dev_v1alpha2_template.yaml +++ /dev/null @@ -1,34 +0,0 @@ -apiVersion: admin.oam.dev/v1alpha2 -kind: Template -metadata: - annotations: - version: 0.0.1 - name: containerizedworkload-template -spec: - object: - apiVersion: core.oam.dev/v1alpha2 - kind: ContainerizedWorkload - metadata: - name: tbd - spec: - containers: - - image: myrepo/myapp:v1 - name: master - ports: - - containerPort: 6379 - protocol: TCP - name: tbd # TODO(zzxwill) A temporary workaround for ContainerizedWorkload - lastCommandParam: image - parameters: - - name: image - short: i - required: true - type: string - fieldPaths: - - "spec.containers[0].image" - - name: port - short: p - required: false - type: int - fieldPaths: - - "spec.containers[0].ports[0].containerPort" \ No newline at end of file diff --git a/config/samples/traits/ManualScalerTrait/manualscalertrait.core.oam.dev-template.yaml b/config/samples/traits/ManualScalerTrait/manualscalertrait.core.oam.dev-template.yaml deleted file mode 100644 index 728166f68..000000000 --- a/config/samples/traits/ManualScalerTrait/manualscalertrait.core.oam.dev-template.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: admin.oam.dev/v1alpha2 -kind: Template -metadata: - annotations: - version: 0.0.1 - name: manualscalertrait.core.oam.dev-template -spec: - object: - apiVersion: core.oam.dev/v1alpha2 - kind: ManualScalerTrait - spec: - replicaCount: 2 - parameters: - - name: replicaCount - required: true - type: int - default: "5" - fieldPaths: - - "spec.replicaCount" diff --git a/config/samples/traits/ManualScalerTrait/manualscaletrait_definition.yaml b/config/samples/traits/ManualScalerTrait/manualscaletrait_definition.yaml deleted file mode 100644 index 560eca544..000000000 --- a/config/samples/traits/ManualScalerTrait/manualscaletrait_definition.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: core.oam.dev/v1alpha2 -kind: TraitDefinition -metadata: - name: manualscalertrait.core.oam.dev - annotations: - rudrx.oam.dev/template: manualscalertrait.core.oam.dev-template - short: ManualScaler -spec: - appliesToWorkloads: - - core.oam.dev/v1alpha2.ContainerizedWorkload - definitionRef: - name: manualscalertrait.core.oam.dev \ No newline at end of file diff --git a/config/samples/traits/SimpleRollout/simplerollout_trait_definition.yaml b/config/samples/traits/SimpleRollout/simplerollout_trait_definition.yaml deleted file mode 100644 index ab403dfa6..000000000 --- a/config/samples/traits/SimpleRollout/simplerollout_trait_definition.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: core.oam.dev/v1alpha2 -kind: TraitDefinition -metadata: - name: simplerollouttraits.extend.oam.dev - annotations: - rudrx.oam.dev/template: simplerollouttraits.extend.oam.dev-template - short: SimpleRollout -spec: - revisionEnabled: true - appliesToWorkloads: - - core.oam.dev/v1alpha2.ContainerizedWorkload - - deployments.apps - definitionRef: - name: simplerollouttraits.extend.oam.dev diff --git a/config/samples/traits/SimpleRollout/simplerollouttraits.extend.oam.dev-template.yaml b/config/samples/traits/SimpleRollout/simplerollouttraits.extend.oam.dev-template.yaml deleted file mode 100644 index f916e5036..000000000 --- a/config/samples/traits/SimpleRollout/simplerollouttraits.extend.oam.dev-template.yaml +++ /dev/null @@ -1,38 +0,0 @@ -apiVersion: admin.oam.dev/v1alpha2 -kind: Template -metadata: - annotations: - version: 0.0.1 - name: simplerollouttraits.extend.oam.dev-template -spec: - object: - apiVersion: extend.oam.dev/v1alpha2 - kind: SimpleRolloutTrait - metadata: - name: example-rollout-trait - spec: - replica: 6 - maxUnavailable: 2 - batch: 2 - parameters: - - name: replica - required: true - type: int - default: "6" - short: r - fieldPaths: - - "spec.replica" - - name: maxUnavailable - required: true - type: int - default: "2" - short: u - fieldPaths: - - "spec.maxUnavailable" - - name: batch - required: true - type: int - default: "2" - short: b - fieldPaths: - - "spec.batch" \ No newline at end of file diff --git a/config/samples/traits/manualscaletrait_definition.yaml b/config/samples/traits/manualscaletrait_definition.yaml new file mode 100644 index 000000000..bf8a443bb --- /dev/null +++ b/config/samples/traits/manualscaletrait_definition.yaml @@ -0,0 +1,23 @@ +apiVersion: core.oam.dev/v1alpha2 +kind: TraitDefinition +metadata: + name: manualscalertrait.core.oam.dev +spec: + appliesToWorkloads: + - core.oam.dev/v1alpha2.ContainerizedWorkload + definitionRef: + name: manualscalertrait.core.oam.dev + extension: + alias: ManualScaler + object: + apiVersion: core.oam.dev/v1alpha2 + kind: ManualScalerTrait + spec: + replicaCount: 2 + parameters: + - name: replicaCount + required: true + type: int + default: "5" + fieldPaths: + - "spec.replicaCount" diff --git a/config/samples/traits/simplerollouttrait_definition.yaml b/config/samples/traits/simplerollouttrait_definition.yaml new file mode 100644 index 000000000..6f3b71ef6 --- /dev/null +++ b/config/samples/traits/simplerollouttrait_definition.yaml @@ -0,0 +1,44 @@ +apiVersion: core.oam.dev/v1alpha2 +kind: TraitDefinition +metadata: + name: simplerollouttraits.extend.oam.dev +spec: + revisionEnabled: true + appliesToWorkloads: + - core.oam.dev/v1alpha2.ContainerizedWorkload + - deployments.apps + definitionRef: + name: simplerollouttraits.extend.oam.dev + extension: + alias: SimpleRollout + object: + apiVersion: extend.oam.dev/v1alpha2 + kind: SimpleRolloutTrait + metadata: + name: example-rollout-trait + spec: + replica: 6 + maxUnavailable: 2 + batch: 2 + parameters: + - name: replica + required: true + type: int + default: "6" + short: r + fieldPaths: + - "spec.replica" + - name: maxUnavailable + required: true + type: int + default: "2" + short: u + fieldPaths: + - "spec.maxUnavailable" + - name: batch + required: true + type: int + default: "2" + short: b + fieldPaths: + - "spec.batch" diff --git a/config/samples/workloads/containerizedworkload_definition.yaml b/config/samples/workloads/containerizedworkload_definition.yaml new file mode 100644 index 000000000..41f0ccf12 --- /dev/null +++ b/config/samples/workloads/containerizedworkload_definition.yaml @@ -0,0 +1,41 @@ +apiVersion: core.oam.dev/v1alpha2 +kind: WorkloadDefinition +metadata: + name: containerizedworkloads.core.oam.dev +spec: + definitionRef: + name: containerizedworkloads.core.oam.dev + childResourceKinds: + - apiVersion: apps/v1 + kind: Deployment + - apiVersion: v1 + kind: Service + extension: + alias: containerized + object: + apiVersion: core.oam.dev/v1alpha2 + kind: ContainerizedWorkload + metadata: + name: tbd + spec: + containers: + - image: myrepo/myapp:v1 + name: master + ports: + - containerPort: 6379 + protocol: TCP + name: tbd # TODO(zzxwill) A temporary workaround for ContainerizedWorkload + lastCommandParam: image + parameters: + - name: image + short: i + required: true + type: string + fieldPaths: + - "spec.containers[0].image" + - name: port + short: p + required: false + type: int + fieldPaths: + - "spec.containers[0].ports[0].containerPort" diff --git a/config/samples/workloads/deployment_definition.yaml b/config/samples/workloads/deployment_definition.yaml new file mode 100644 index 000000000..540d0990f --- /dev/null +++ b/config/samples/workloads/deployment_definition.yaml @@ -0,0 +1,36 @@ +apiVersion: core.oam.dev/v1alpha2 +kind: WorkloadDefinition +metadata: + name: deployments.apps +spec: + definitionRef: + name: deployments.apps + extension: + alias: deployment + object: + apiVersion: core.oam.dev/v1alpha2 + kind: deployment + metadata: + name: tbd + spec: + containers: + - image: myrepo/myapp:v1 + name: master + ports: + - containerPort: 6379 + protocol: TCP + name: tbd # TODO(zzxwill) A temporary workaround for ContainerizedWorkload + lastCommandParam: image + parameters: + - name: image + short: i + required: true + type: string + fieldPaths: + - "spec.containers[0].image" + - name: port + short: p + required: false + type: int + fieldPaths: + - "spec.containers[0].ports[0].containerPort" diff --git a/pkg/cmd/bind.go b/pkg/cmd/bind.go index ced3da655..4196133d1 100644 --- a/pkg/cmd/bind.go +++ b/pkg/cmd/bind.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "os" "strconv" "strings" @@ -24,152 +25,124 @@ type commandOptions struct { cmdutil.IOStreams } -// NewCommandOptions bind command options func NewCommandOptions(ioStreams cmdutil.IOStreams) *commandOptions { return &commandOptions{IOStreams: ioStreams} } -// NewBindCommand return bind command -func NewBindCommand(f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOStreams, args []string) *cobra.Command { - cmd := newBindCommand() - cmd.SetArgs(args) - cmd.SetOut(ioStreams.Out) - cmd.DisableFlagParsing = true - - cmd.RunE = func(cmd *cobra.Command, args []string) error { - return runSubBindCommand(cmd, f, c, ioStreams, args) - } - return cmd -} - -func runSubBindCommand(parentCmd *cobra.Command, f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOStreams, args []string) error { +func NewBindCommand(f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOStreams) *cobra.Command { ctx := context.Background() + o := NewCommandOptions(ioStreams) o.Client = c - - // init fake command and pass args to fake command - // flags and subcommand append to fake comand and parent command - // run fake command only, show tips in parent command only - fakeCommand := newBindCommand() - fakeCommand.SilenceUsage = true - fakeCommand.SilenceErrors = true - fakeCommand.DisableAutoGenTag = true - fakeCommand.DisableFlagsInUseLine = true - fakeCommand.DisableSuggestions = true - fakeCommand.SetOut(o.Out) - if len(args) > 0 { - fakeCommand.SetArgs(args) - } else { - fakeCommand.SetArgs([]string{}) + cmd := &cobra.Command{ + Use: "bind APPLICATION-NAME TRAIT-NAME [FLAG]", + DisableFlagsInUseLine: true, + Short: "Attach a trait to a component", + Long: "Attach a trait to a component.", + Example: `rudr bind frontend scaler --max=5`, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(o.Complete(f, cmd, args, ctx)) + cmdutil.CheckErr(o.Run(f, cmd, ctx)) + }, } var traitDefinitions corev1alpha2.TraitDefinitionList - err := c.List(ctx, &traitDefinitions) - if err != nil { - return fmt.Errorf("listing trait definitions hit an issue: %v", err) - } + c.List(ctx, &traitDefinitions) + //if err != nil { + // fmt.Println("Listing trait definitions hit an issue:", err) + // os.Exit(1) + //} for _, t := range traitDefinitions.Items { var traitTemplate cmdutil.Template traitTemplate, err := cmdutil.ConvertTemplateJson2Object(t.Spec.Extension) if err != nil { - return fmt.Errorf("applying the trait hit an issue: %s", err) + fmt.Errorf("applying the trait hit an issue: %s", err) } - for _, p := range traitTemplate.Spec.Parameters { + for _, p := range traitTemplate.Parameters { if p.Type == "int" { v, err := strconv.Atoi(p.Default) if err != nil { - return fmt.Errorf("Parameters type is wrong: %v .Please report this to OAM maintainer, thanks.", err) + fmt.Println("Parameters type is wrong: ", err, ".Please report this to OAM maintainer, thanks.") } - fakeCommand.PersistentFlags().Int(p.Name, v, p.Usage) - parentCmd.PersistentFlags().Int(p.Name, v, p.Usage) + cmd.PersistentFlags().Int(p.Name, v, p.Usage) } else { - fakeCommand.PersistentFlags().String(p.Name, p.Default, p.Usage) - parentCmd.PersistentFlags().String(p.Name, p.Default, p.Usage) + cmd.PersistentFlags().String(p.Name, p.Default, p.Usage) } } } - fakeCommand.RunE = func(cmd *cobra.Command, args []string) error { - if err := o.Complete(fakeCommand, f, args, ctx); err != nil { - return err - } - return o.Run(f, fakeCommand, ctx) - } - return fakeCommand.Execute() + return cmd } -func (o *commandOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args []string, ctx context.Context) error { +func (o *commandOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string, ctx context.Context) error { argsLength := len(args) var componentName string + c := o.Client + namespace := cmd.Flag("namespace").Value.String() + if namespace == "" { + namespace = "default" + } + if argsLength == 0 { return errors.New("please append the name of an application. Use `rudr bind -h` for more detailed information") } else if argsLength <= 2 { componentName = args[0] - err := c.Get(ctx, client.ObjectKey{Namespace: "default", Name: componentName}, &o.AppConfig) + err := c.Get(ctx, client.ObjectKey{Namespace: namespace, Name: componentName}, &o.AppConfig) if err != nil { - return err + fmt.Println(err) + os.Exit(1) } - ns := o.AppConfig.Namespace var component corev1alpha2.Component - err = c.Get(ctx, client.ObjectKey{Namespace: ns, Name: componentName}, &component) + err = c.Get(ctx, client.ObjectKey{Namespace: namespace, Name: componentName}, &component) if err != nil { - return fmt.Errorf("%s. Please choose an existed component name", err) + errMsg := fmt.Sprintf("%s. Please choose an existed component name.", err) + cmdutil.PrintErrorMessage(errMsg, 1) } // Retrieve all traits which can be used for the following 1) help and 2) validating - traitList, err := RetrieveTraitsByWorkload(ctx, o.Client, "") - if err != nil { - return fmt.Errorf("list available traits hit an issue: %s", err) - } + traitList, _ := RetrieveTraitsByWorkload(ctx, o.Client, namespace, "") + //if err != nil { + // errMsg := fmt.Sprintf("List available traits hit an issue: %s", err) + // cmdutil.PrintErrorMessage(errMsg, 1) + //} switch argsLength { case 1: // Validate component and suggest trait - errTip := "Error: No trait specified.\nPlease choose a trait: " - for _, trait := range traitList { - n := trait.Short + fmt.Print("Error: No trait specified.\nPlease choose a trait: ") + for _, t := range traitList { + n := t.Short if n == "" { - n = trait.Name + n = t.Name } - errTip += n + " " + fmt.Print(n, " ") } - return errors.New(errTip) + os.Exit(1) + case 2: // validate trait traitName := args[1] - var traitLongName string + traitLongName, _, _ := cmdutil.GetTraitNameAliasKind(ctx, c, namespace, traitName) - validTrait := false - for _, trait := range traitList { - // Support trait name or trait short name case-sensitively - if strings.EqualFold(trait.Name, traitName) || strings.EqualFold(trait.Short, traitName) { - validTrait = true - traitLongName = trait.Name - break - } + traitDefinition, err := cmdutil.GetTraitDefinitionByName(ctx, c, namespace, traitLongName) + if err != nil { + errMsg := fmt.Sprintf("trait name [%s] is not valid, please try again", traitName) + cmdutil.PrintErrorMessage(errMsg, 1) } - if !validTrait { - return fmt.Errorf("The trait `%s` is NOT valid, please try a valid one.", traitName) - } - - var traitDefinition corev1alpha2.TraitDefinition - c.Get(ctx, client.ObjectKey{Namespace: ns, Name: traitLongName}, &traitDefinition) - - var traitTemplate cmdutil.Template traitTemplate, err := cmdutil.ConvertTemplateJson2Object(traitDefinition.Spec.Extension) if err != nil { - return fmt.Errorf("applying the trait hit an issue: %s", err) + return fmt.Errorf("attaching the trait hit an issue: %s", err) } - pvd := fieldpath.Pave(traitTemplate.Spec.Object.Object) - for _, v := range traitTemplate.Spec.Parameters { + pvd := fieldpath.Pave(traitTemplate.Object.Object) + for _, v := range traitTemplate.Parameters { flagSet := cmd.Flag(v.Name) for _, path := range v.FieldPaths { fValue := flagSet.Value.String() @@ -195,30 +168,21 @@ func (o *commandOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args [] } } } else { - return errors.New("Unknown command is specified, please check and try again.") + cmdutil.PrintErrorMessage("Unknown command is specified, please check and try again.", 1) } return nil } -// Run command func (o *commandOptions) Run(f cmdutil.Factory, cmd *cobra.Command, ctx context.Context) error { - o.Infof("Applying trait for component %s\n", o.Component.Name) + fmt.Println("Applying trait for component", o.Component.Name) c := o.Client err := c.Update(ctx, &o.AppConfig) if err != nil { - return fmt.Errorf("Applying trait hit an issue: %s", err) + msg := fmt.Sprintf("Applying trait hit an issue: %s", err) + cmdutil.PrintErrorMessage(msg, 1) } - o.Info("Succeeded!") + msg := fmt.Sprintf("Succeeded!") + fmt.Println(msg) return nil } - -func newBindCommand() *cobra.Command { - return &cobra.Command{ - Use: "bind APPLICATION-NAME TRAIT-NAME [FLAG]", - DisableFlagsInUseLine: true, - Short: "Attach a trait to a component", - Long: "Attach a trait to a component.", - Example: `rudr bind frontend scaler --max=5`, - } -} diff --git a/pkg/cmd/ls.go b/pkg/cmd/ls.go index 95d8ce7fc..c2e6d8766 100644 --- a/pkg/cmd/ls.go +++ b/pkg/cmd/ls.go @@ -20,18 +20,19 @@ func NewAppsCommand(f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOStre Long: "List applications with workloads, traits, status and created time", Example: `rudr ls`, Run: func(cmd *cobra.Command, args []string) { - workloadName := cmd.Flag("name").Value.String() + //appName := cmd.Flag("app").Value.String() + appName := cmd.Flag("app").Value.String() namespace := cmd.Flag("namespace").Value.String() - printApplicationList(ctx, c, workloadName, namespace) + printApplicationList(ctx, c, appName, namespace) }, } - cmd.PersistentFlags().String("name", "", "Application name") + cmd.PersistentFlags().StringP("app", "a", "", "Application name") return cmd } func printApplicationList(ctx context.Context, c client.Client, appName string, namespace string) { - applicationMetaList, err := cmdutil.RetrieveApplicationsByApplicationName(ctx, c, appName, namespace) + applicationMetaList, err := cmdutil.RetrieveApplicationsByName(ctx, c, appName, namespace) table := uitable.New() table.MaxColWidth = 60 diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go index 98c673a5d..2374ca32f 100644 --- a/pkg/cmd/run.go +++ b/pkg/cmd/run.go @@ -75,31 +75,19 @@ func runSubRunCommand(parentCmd *cobra.Command, f cmdutil.Factory, c client.Clie parentCmd.PersistentFlags().StringP("namespace", "n", "default", "namespace for apps") var workloadDefs corev1alpha2.WorkloadDefinitionList - //err := c.List(ctx, &workloadDefs) - //if err != nil { - // return fmt.Errorf("listing Workload definition hit an issue: %s", err) - //} - - // TODO(zzxwill) Need to check err later - c.List(ctx, &workloadDefs) - workloadDefsItem := workloadDefs.Items - if len(workloadDefsItem) == 0 { - // TODO(zzxwill) Refine this prompt message - return errors.New("somehow Workload definitions are NOT preconfigured, please report this to OAM maintainers") + err := c.List(ctx, &workloadDefs) + if err != nil { + return fmt.Errorf("listing Workload definition hit an issue: %s", err) } - for _, wd := range workloadDefsItem { - name := wd.ObjectMeta.Annotations["short"] - if name == "" { - name = wd.Name - } - workloadNames = append(workloadNames, name) - + for _, wd := range workloadDefs.Items { var tmp cmdutil.Template tmp, err := cmdutil.ConvertTemplateJson2Object(wd.Spec.Extension) if err != nil { return fmt.Errorf("deploying application hit an issue: %s", err) } + name := tmp.Alias + workloadNames = append(workloadNames, name) subcmd := &cobra.Command{ Use: name + " [args]", @@ -114,14 +102,15 @@ func runSubRunCommand(parentCmd *cobra.Command, f cmdutil.Factory, c client.Clie }, } subcmd.SetOut(o.Out) - for _, v := range tmp.Spec.Parameters { - if tmp.Spec.LastCommandParam != v.Name { + for _, v := range tmp.Parameters { + if tmp.LastCommandParam != v.Name { subcmd.PersistentFlags().StringP(v.Name, v.Short, v.Default, v.Usage) } } // Comment this line as template content will get mixed when there are more than two WorkloadDefinitions // tmp.DeepCopyInto(&o.Template) + o.Template = tmp fakeCommand.AddCommand(subcmd) parentCmd.AddCommand(subcmd) } @@ -138,7 +127,7 @@ func (o *runOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri } argsLength := len(args) - lastCommandParam := o.Template.Spec.LastCommandParam + lastCommandParam := o.Template.LastCommandParam if argsLength < 1 { return errors.New("must specify name for workload") @@ -151,21 +140,9 @@ func (o *runOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri return fmt.Errorf("You must specify `%s` as the last command.\nSee 'rudr run -h' for help and examples", lastCommandParam) case argsLength == 2: - c := o.client - - var w corev1alpha2.WorkloadDefinition - c.Get(ctx, client.ObjectKey{Namespace: namespace, Name: workloadName}, &w) - - var workloadTemplate cmdutil.Template - workloadTemplate, err := cmdutil.ConvertTemplateJson2Object(w.Spec.Extension) - o.Template = workloadTemplate - - if err != nil { - return fmt.Errorf("deploying application hit an issue: %s", err) - } - - pvd := fieldpath.Pave(workloadTemplate.Spec.Object.Object) - for _, v := range workloadTemplate.Spec.Parameters { + workloadTemplate := o.Template + pvd := fieldpath.Pave(workloadTemplate.Object.Object) + for _, v := range workloadTemplate.Parameters { lastCommandValue := args[argsLength-1] var paraV string if v.Name == lastCommandParam { @@ -189,7 +166,7 @@ func (o *runOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri } } - pvd.SetString("metadata.name", workloadName) + pvd.SetString("metadata.name", strings.ToLower(workloadName)) namespaceCover := cmd.Flag("namespace").Value.String() if namespaceCover != "" { namespace = namespaceCover diff --git a/pkg/cmd/traits.go b/pkg/cmd/traits.go index 350af6d46..5d25e3959 100644 --- a/pkg/cmd/traits.go +++ b/pkg/cmd/traits.go @@ -12,7 +12,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -func NewTraitsCommand(f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOStreams, args []string) *cobra.Command { +func NewTraitsCommand(f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOStreams) *cobra.Command { ctx := context.Background() var workloadName string cmd := &cobra.Command{ @@ -37,17 +37,16 @@ func printTraitList(ctx context.Context, c client.Client, workloadName *string, table := uitable.New() table.MaxColWidth = 60 - if err != nil { - return fmt.Errorf("Listing Trait Definition hit an issue: %s", err) - } + //if err != nil { + // errMsg := fmt.Sprintf("Listing Trait Definition hit an issue: %s", err) + // cmdutil.PrintErrorMessage(errMsg, 1) + //} - table.AddRow("NAME", "SHORT", "DEFINITION", "APPLIES TO", "STATUS") + table.AddRow("NAME", "Alias", "DEFINITION", "APPLIES TO", "STATUS") for _, r := range traitList { table.AddRow(r.Name, r.Short, r.Definition, r.AppliesTo, r.Status) } - ioStreams.Info(table.String()) - - return nil + fmt.Print(table.String()) } type TraitMeta struct { @@ -58,13 +57,14 @@ type TraitMeta struct { Status string `json:"status,omitempty"` } -func RetrieveTraitsByWorkload(ctx context.Context, c client.Client, workloadName string) ([]TraitMeta, error) { - /* - Get trait list by optional filter `workloadName` - */ +// RetrieveTraitsByWorkload Get trait list by optional filter `workloadName` +func RetrieveTraitsByWorkload(ctx context.Context, c client.Client, namespace string, workloadName string) ([]TraitMeta, error) { var traitList []TraitMeta var traitDefinitionList corev1alpha2.TraitDefinitionList - err := c.List(ctx, &traitDefinitionList) + if namespace == "" { + namespace = "default" + } + err := c.List(ctx, &traitDefinitionList, client.InNamespace(namespace)) for _, r := range traitDefinitionList.Items { var appliesTo string diff --git a/pkg/cmd/util/helpers.go b/pkg/cmd/util/helpers.go index d5bd1bf0a..1ea3e5675 100644 --- a/pkg/cmd/util/helpers.go +++ b/pkg/cmd/util/helpers.go @@ -5,6 +5,8 @@ import ( "os" "strings" + v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + corev1alpha2 "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" "sigs.k8s.io/controller-runtime/pkg/client" @@ -70,21 +72,31 @@ func GetComponent(ctx context.Context, c client.Client, componentName string, na return component, err } -func GetTraitNames(app corev1alpha2.ApplicationConfiguration) []string { +func GetTraitNamesByApplicationConfiguration(app corev1alpha2.ApplicationConfiguration) []string { var traitNames []string + + traitDefinitionList := ListTraitDefinitionsByApplicationConfiguration(app) + for _, t := range traitDefinitionList { + traitNames = append(traitNames, t.Name) + } + return traitNames +} + +func ListTraitDefinitionsByApplicationConfiguration(app corev1alpha2.ApplicationConfiguration) []corev1alpha2.TraitDefinition { + var traitDefinitionList []corev1alpha2.TraitDefinition for _, t := range app.Spec.Components[0].Traits { var trait corev1alpha2.TraitDefinition json.Unmarshal(t.Trait.Raw, &trait) - traitNames = append(traitNames, trait.Kind) + traitDefinitionList = append(traitDefinitionList, trait) } - return traitNames + return traitDefinitionList } /* Get application list by optional filter `applicationName` Application name is equal to Component name as currently rudrx only supports one component exists in one application */ -func RetrieveApplicationsByApplicationName(ctx context.Context, c client.Client, applicationName string, namespace string) ([]ApplicationMeta, error) { +func RetrieveApplicationsByName(ctx context.Context, c client.Client, applicationName string, namespace string) ([]ApplicationMeta, error) { var applicationMetaList []ApplicationMeta if namespace == "" { @@ -121,7 +133,7 @@ func RetrieveApplicationsByApplicationName(ctx context.Context, c client.Client, json.Unmarshal(component.Spec.Workload.Raw, &workload) workloadName := workload.TypeMeta.Kind - traitNames := GetTraitNames(a) + traitNames := GetTraitNamesByApplicationConfiguration(a) applicationMetaList = append(applicationMetaList, ApplicationMeta{ Name: a.Name, @@ -134,3 +146,127 @@ func RetrieveApplicationsByApplicationName(ctx context.Context, c client.Client, return applicationMetaList, nil } + +func GetTraitAliasByTraitDefinition(traitDefinition corev1alpha2.TraitDefinition) string { + return traitDefinition.Annotations["short"] +} + +func GetTraitDefinitionByName(ctx context.Context, c client.Client, namespace string, traitName string) (corev1alpha2.TraitDefinition, error) { + var t corev1alpha2.TraitDefinition + err := c.Get(ctx, client.ObjectKey{Name: traitName, Namespace: namespace}, &t) + return t, err +} + +func GetTraitAliasByName(ctx context.Context, c client.Client, namespace string, traitName string) string { + var traitAlias string + t, err := GetTraitDefinitionByName(ctx, c, namespace, traitName) + if err == nil { + traitAlias = GetTraitAliasByTraitDefinition(t) + } + return traitAlias +} + +func GetTraitDefinitionByAlias(ctx context.Context, c client.Client, traitAlias string) (corev1alpha2.TraitDefinition, error) { + var traitDefinitionList corev1alpha2.TraitDefinitionList + var traitDefinition corev1alpha2.TraitDefinition + err := c.List(ctx, &traitDefinitionList) + if err == nil { + for _, t := range traitDefinitionList.Items { + template, err := ConvertTemplateJson2Object(t.Spec.Extension) + if err == nil && strings.EqualFold(template.Alias, traitAlias) { + traitDefinition = t + break + } + } + } + return traitDefinition, err +} + +// GetTraitNameAndAlias return the name and alias of a TraitDefinition by a string which might be +// the trait name, the trait alias, or invalid name +func GetTraitNameAliasKind(ctx context.Context, c client.Client, namespace string, name string) (string, string, string) { + var tName, tAlias, tKind string + + t, err := GetTraitDefinitionByName(ctx, c, namespace, name) + + if err == nil { + template, err := ConvertTemplateJson2Object(t.Spec.Extension) + if err == nil { + tName, tAlias = t.Name, template.Alias + } + } else { + t, err := GetTraitDefinitionByAlias(ctx, c, name) + if err == nil { + template, err := ConvertTemplateJson2Object(t.Spec.Extension) + if err == nil { + tName, tAlias = t.Name, template.Alias + } + } + } + + if tName == "" { + tKind = name + } else { + tKind = GetCRDKind(ctx, c, namespace, tName) + } + + return tName, tAlias, tKind +} + +func GetCRDByName(ctx context.Context, c client.Client, namespace string, name string) v1.CustomResourceDefinition { + var crd v1.CustomResourceDefinition + c.Get(ctx, client.ObjectKey{Namespace: namespace, Name: name}, &crd) + return crd +} + +func GetCRDKind(ctx context.Context, c client.Client, namespace string, name string) string { + crd := GetCRDByName(ctx, c, namespace, name) + return crd.Spec.Names.Kind +} + +func GetWorkloadNameAliasKind(ctx context.Context, c client.Client, namespace string, workloadName string) (string, string, string) { + var name, alias, kind string + + w, err := GetWorkloadDefinitionByName(ctx, c, namespace, workloadName) + + if err == nil { // workloadName is complete name + var workloadTemplate Template + workloadTemplate, err := ConvertTemplateJson2Object(w.Spec.Extension) + if err == nil { + name, alias = w.Name, workloadTemplate.Alias + } + } else { // workloadName is alias or kind + w, err := GetWorkloadDefinitionByAlias(ctx, c, name) + if err == nil { + workloadTemplate, err := ConvertTemplateJson2Object(w.Spec.Extension) + if err == nil { + name, alias, kind = w.Name, workloadTemplate.Alias, w.Kind + } + + } + } + + return name, alias, kind +} + +func GetWorkloadDefinitionByName(ctx context.Context, c client.Client, namespace string, name string) (corev1alpha2.WorkloadDefinition, error) { + var w corev1alpha2.WorkloadDefinition + err := c.Get(ctx, client.ObjectKey{Name: name, Namespace: namespace}, &w) + return w, err +} + +func GetWorkloadDefinitionByAlias(ctx context.Context, c client.Client, traitAlias string) (corev1alpha2.WorkloadDefinition, error) { + var workloadDefinitionList corev1alpha2.WorkloadDefinitionList + var workloadDefinition corev1alpha2.WorkloadDefinition + // TODO(zzxwill) Need to check return error + c.List(ctx, &workloadDefinitionList) + + for _, t := range workloadDefinitionList.Items { + if strings.EqualFold(t.ObjectMeta.Annotations["short"], traitAlias) { + workloadDefinition = t + break + } + } + + return workloadDefinition, nil +} diff --git a/pkg/cmd/util/template_types.go b/pkg/cmd/util/template_types.go index 7476691d4..904106885 100644 --- a/pkg/cmd/util/template_types.go +++ b/pkg/cmd/util/template_types.go @@ -19,7 +19,8 @@ package util import ( "encoding/json" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) @@ -27,9 +28,10 @@ import ( // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. // TemplateSpec defines the desired state of Template -type TemplateSpec struct { +type Template struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file + Alias string `json:alias,omitempty` Object unstructured.Unstructured `json:"object"` LastCommandParam string `json:"lastCommandParam,omitempty"` Parameters []Parameter `json:"parameters,omitempty"` @@ -45,44 +47,13 @@ type Parameter struct { Type string `json:"type,omitempty"` } -//// TemplateStatus defines the observed state of Template -//type TemplateStatus struct { -// // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster -// // Important: Run "make" to regenerate code after modifying this file -//} -// - -// Template is the Schema for the templates API -type Template struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec TemplateSpec `json:"spec,omitempty"` - //Status TemplateStatus `json:"status,omitempty"` -} - -// TemplateList contains a list of Template -type TemplateList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []Template `json:"items"` -} - -//func init() { -// v1alpha2.SchemeBuilder.Register(&Template{}, &TemplateList{}) -//} - -type DefinitionExtensionTemplate struct { - ExtensionTemplate Template `json:"template,omitempty"` -} - -func ConvertTemplateJson2Object(in *unstructured.Unstructured) (Template, error) { +// ConvertTemplateJson2Object convert spec.extension to object +func ConvertTemplateJson2Object(in runtime.RawExtension) (Template, error) { var t Template - var extension DefinitionExtensionTemplate - templateJson, _ := in.MarshalJSON() - err := json.Unmarshal(templateJson, &extension) + var extension Template + err := json.Unmarshal(in.Raw, &extension) if err == nil { - t = extension.ExtensionTemplate + t = extension } return t, err