From ecef32a7f31ab5dac181796b3a0842cc5d9993aa Mon Sep 17 00:00:00 2001 From: Zheng Xi Zhou Date: Thu, 2 Sep 2021 20:51:34 +0800 Subject: [PATCH] Fix: add flag `--label` to filer components and traits (#2217) Added flag `--flag` to filter when executing `vela componnets` and `vela traits` Fix https://github.com/oam-dev/kubevela.io/pull/222#discussion_r699214816 --- apis/types/capability.go | 1 + apis/types/types.go | 3 ++ .../definitions/terraform-alibaba-ack.yaml | 1 + .../definitions/terraform-alibaba-oss.yaml | 1 + .../definitions/terraform-alibaba-rds.yaml | 1 + e2e/workload/workload_test.go | 15 +++++-- references/cli/capability.go | 7 +++- references/cli/components.go | 20 ++++++++-- references/cli/traits.go | 18 +++++++-- references/common/capability.go | 12 ++++++ references/common/capability_test.go | 39 +++++++++++++++++++ references/plugins/capcenter.go | 4 +- references/plugins/cluster.go | 12 +++--- references/plugins/cluster_test.go | 2 + 14 files changed, 118 insertions(+), 18 deletions(-) diff --git a/apis/types/capability.go b/apis/types/capability.go index 87ff44563..375b0d72e 100644 --- a/apis/types/capability.go +++ b/apis/types/capability.go @@ -162,6 +162,7 @@ type Capability struct { Center string `json:"center,omitempty"` Status string `json:"status,omitempty"` Description string `json:"description,omitempty"` + Labels map[string]string `json:"labels,omitempty"` Category CapabilityCategory `json:"category,omitempty"` // trait only diff --git a/apis/types/types.go b/apis/types/types.go index a7a186af6..b4ddc4dec 100644 --- a/apis/types/types.go +++ b/apis/types/types.go @@ -71,3 +71,6 @@ const ( // TypePlugin defines one category used in Kubectl Plugin TypePlugin = "Plugin Command" ) + +// LabelArg is the argument `label` of a definition +const LabelArg = "label" diff --git a/charts/vela-core/templates/definitions/terraform-alibaba-ack.yaml b/charts/vela-core/templates/definitions/terraform-alibaba-ack.yaml index 75f89d228..1bca11b22 100644 --- a/charts/vela-core/templates/definitions/terraform-alibaba-ack.yaml +++ b/charts/vela-core/templates/definitions/terraform-alibaba-ack.yaml @@ -5,6 +5,7 @@ metadata: namespace: {{.Values.systemDefinitionNamespace}} annotations: definition.oam.dev/description: Terraform configuration for Alibaba Cloud ACK cluster + labels: type: terraform spec: workload: diff --git a/charts/vela-core/templates/definitions/terraform-alibaba-oss.yaml b/charts/vela-core/templates/definitions/terraform-alibaba-oss.yaml index 170bc9387..ae049faa9 100644 --- a/charts/vela-core/templates/definitions/terraform-alibaba-oss.yaml +++ b/charts/vela-core/templates/definitions/terraform-alibaba-oss.yaml @@ -5,6 +5,7 @@ metadata: namespace: {{.Values.systemDefinitionNamespace}} annotations: definition.oam.dev/description: Terraform configuration for Alibaba Cloud OSS object + labels: type: terraform spec: workload: diff --git a/charts/vela-core/templates/definitions/terraform-alibaba-rds.yaml b/charts/vela-core/templates/definitions/terraform-alibaba-rds.yaml index 5339e5d74..0bdce7bb0 100644 --- a/charts/vela-core/templates/definitions/terraform-alibaba-rds.yaml +++ b/charts/vela-core/templates/definitions/terraform-alibaba-rds.yaml @@ -5,6 +5,7 @@ metadata: namespace: {{.Values.systemDefinitionNamespace}} annotations: definition.oam.dev/description: Terraform configuration for Alibaba Cloud RDS object + labels: type: terraform spec: workload: diff --git a/e2e/workload/workload_test.go b/e2e/workload/workload_test.go index 2a4e31d01..1b79b9a62 100644 --- a/e2e/workload/workload_test.go +++ b/e2e/workload/workload_test.go @@ -17,16 +17,25 @@ limitations under the License. package e2e import ( - "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" "github.com/oam-dev/kubevela/e2e" ) -var _ = ginkgo.Describe("Workload", func() { +var _ = Describe("Workload", func() { e2e.WorkloadCapabilityListContext() + + Context("list components with `label` filter", func() { + It("list components with the specified label", func() { + output, err := e2e.Exec("vela components --label type=terraform") + Expect(err).NotTo(HaveOccurred()) + Expect(output).To(ContainSubstring("alibaba-oss")) + }) + }) }) -var _ = ginkgo.Describe("Test vela show", func() { +var _ = Describe("Test vela show", func() { e2e.ShowCapabilityReference("show webservice", "webservice") env := "namespace-xxxfwrr23erfm" diff --git a/references/cli/capability.go b/references/cli/capability.go index df558fc2e..956871c8f 100644 --- a/references/cli/capability.go +++ b/references/cli/capability.go @@ -204,7 +204,7 @@ func NewCapListCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Comma return err } - err = printCenterCapabilities(env.Namespace, repoName, c, ioStreams, nil) + err = printCenterCapabilities(env.Namespace, repoName, c, ioStreams, nil, "") if err != nil { return err } @@ -268,7 +268,7 @@ func removeCapCenter(args []string, ioStreams cmdutil.IOStreams) error { } return err } -func printCenterCapabilities(namespace, repoName string, args common2.Args, ioStreams cmdutil.IOStreams, option *types.CapType) error { +func printCenterCapabilities(namespace, repoName string, args common2.Args, ioStreams cmdutil.IOStreams, option *types.CapType, label string) error { capabilityList, err := common.ListCapabilities(namespace, args, repoName) if err != nil { return err @@ -277,6 +277,9 @@ func printCenterCapabilities(namespace, repoName string, args common2.Args, ioSt table.AddRow("NAME", "CENTER", "TYPE", "DEFINITION", "STATUS", "APPLIES-TO") for _, c := range capabilityList { + if label != "" && !common.CheckLabelExistence(c.Labels, label) { + continue + } if option == nil { table.AddRow(c.Name, c.Center, c.Type, c.CrdName, c.Status, c.AppliesTo) } diff --git a/references/cli/components.go b/references/cli/components.go index 7b3dfee3b..6a065899e 100644 --- a/references/cli/components.go +++ b/references/cli/components.go @@ -19,6 +19,7 @@ package cli import ( "context" "fmt" + "strings" "github.com/spf13/cobra" "k8s.io/apimachinery/pkg/runtime" @@ -54,11 +55,20 @@ func NewComponentsCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Co if err != nil { return err } + + label, err := cmd.Flags().GetString(types.LabelArg) + if err != nil { + return err + } + if label != "" && len(strings.Split(label, "=")) != 2 { + return fmt.Errorf("label %s is not in the right format", label) + } + if !isDiscover { - return printComponentList(env.Namespace, c, ioStreams) + return printComponentList(env.Namespace, c, ioStreams, label) } option := types.TypeComponentDefinition - err = printCenterCapabilities(env.Namespace, "", c, ioStreams, &option) + err = printCenterCapabilities(env.Namespace, "", c, ioStreams, &option, label) if err != nil { return err } @@ -70,11 +80,12 @@ func NewComponentsCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Co }, } cmd.Flags().Bool("discover", false, "discover traits in capability centers") + cmd.Flags().String(types.LabelArg, "", "a label to filter components, the format is `--label type=terraform`") cmd.SetOut(ioStreams.Out) return cmd } -func printComponentList(userNamespace string, c common2.Args, ioStreams cmdutil.IOStreams) error { +func printComponentList(userNamespace string, c common2.Args, ioStreams cmdutil.IOStreams, label string) error { def, err := common.ListRawComponentDefinitions(userNamespace, c) if err != nil { return err @@ -89,6 +100,9 @@ func printComponentList(userNamespace string, c common2.Args, ioStreams cmdutil. table.AddRow("NAME", "NAMESPACE", "WORKLOAD", "DESCRIPTION") for _, r := range def { + if label != "" && !common.CheckLabelExistence(r.Labels, label) { + continue + } var workload string if r.Spec.Workload.Type != "" { workload = r.Spec.Workload.Type diff --git a/references/cli/traits.go b/references/cli/traits.go index a29a895e7..42179a2bf 100644 --- a/references/cli/traits.go +++ b/references/cli/traits.go @@ -54,11 +54,19 @@ func NewTraitsCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Comman if err != nil { return err } + label, err := cmd.Flags().GetString(types.LabelArg) + if err != nil { + return err + } + if label != "" && len(strings.Split(label, "=")) != 2 { + return fmt.Errorf("label %s is not in the right format", label) + + } if !isDiscover { - return printTraitList(env.Namespace, c, ioStreams) + return printTraitList(env.Namespace, c, ioStreams, label) } option := types.TypeTrait - err = printCenterCapabilities(env.Namespace, "", c, ioStreams, &option) + err = printCenterCapabilities(env.Namespace, "", c, ioStreams, &option, label) if err != nil { return err } @@ -70,11 +78,12 @@ func NewTraitsCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Comman }, } cmd.Flags().Bool("discover", false, "discover traits in capability centers") + cmd.Flags().String(types.LabelArg, "", "a label to filter components, the format is `--label type=terraform`") cmd.SetOut(ioStreams.Out) return cmd } -func printTraitList(userNamespace string, c common2.Args, ioStreams cmdutil.IOStreams) error { +func printTraitList(userNamespace string, c common2.Args, ioStreams cmdutil.IOStreams, label string) error { table := newUITable() table.Wrap = true @@ -84,6 +93,9 @@ func printTraitList(userNamespace string, c common2.Args, ioStreams cmdutil.IOSt } table.AddRow("NAME", "NAMESPACE", "APPLIES-TO", "CONFLICTS-WITH", "POD-DISRUPTIVE", "DESCRIPTION") for _, t := range traitDefinitionList { + if label != "" && !common.CheckLabelExistence(t.Labels, label) { + continue + } table.AddRow(t.Name, t.Namespace, strings.Join(t.Spec.AppliesToWorkloads, ","), strings.Join(t.Spec.ConflictsWith, ","), t.Spec.PodDisruptive, plugins.GetDescription(t.Annotations)) } ioStreams.Info(table.String()) diff --git a/references/common/capability.go b/references/common/capability.go index 5cf512520..ccaa6e373 100644 --- a/references/common/capability.go +++ b/references/common/capability.go @@ -504,3 +504,15 @@ func GetCapabilityConfigMap(kubeClient client.Client, capabilityName string) (co err := kubeClient.Get(context.Background(), client.ObjectKey{Namespace: types.DefaultKubeVelaNS, Name: cmName}, &cm) return cm, err } + +// CheckLabelExistence checks whether a label `key=value` exists in definition labels +func CheckLabelExistence(labels map[string]string, label string) bool { + splitLabel := strings.Split(label, "=") + k, v := splitLabel[0], splitLabel[1] + if labelValue, ok := labels[k]; ok { + if labelValue == v { + return true + } + } + return false +} diff --git a/references/common/capability_test.go b/references/common/capability_test.go index c6dae1851..405d1f44a 100644 --- a/references/common/capability_test.go +++ b/references/common/capability_test.go @@ -21,6 +21,7 @@ import ( "reflect" "testing" + "gotest.tools/assert" "k8s.io/apimachinery/pkg/runtime" "github.com/oam-dev/kubevela/apis/types" @@ -51,3 +52,41 @@ func TestAddSourceIntoDefinition(t *testing.T) { t.Errorf("error result want %s, got %s", result, testcase) } } + +func TestCheckLabelExistence(t *testing.T) { + cases := map[string]struct { + labels map[string]string + label string + existed bool + }{ + "label exists": { + labels: map[string]string{ + "env": "prod", + }, + label: "env=prod", + existed: true, + }, + + "label's key matches": { + labels: map[string]string{ + "env": "prod", + }, + label: "env=dev", + existed: false, + }, + "label's key doesn't match": { + labels: map[string]string{ + "env": "prod", + }, + label: "type=terraform", + existed: false, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + result := CheckLabelExistence(tc.labels, tc.label) + assert.Equal(t, result, tc.existed) + }) + } +} diff --git a/references/plugins/capcenter.go b/references/plugins/capcenter.go index 5dd78da75..5cf77f57d 100644 --- a/references/plugins/capcenter.go +++ b/references/plugins/capcenter.go @@ -245,14 +245,14 @@ func ParseCapability(mapper discoverymapper.DiscoveryMapper, data []byte) (types if err != nil { return types.Capability{}, err } - return HandleDefinition(cd.Name, ref.Name, cd.Annotations, cd.Spec.Extension, types.TypeComponentDefinition, nil, cd.Spec.Schematic) + return HandleDefinition(cd.Name, ref.Name, cd.Annotations, cd.Labels, cd.Spec.Extension, types.TypeComponentDefinition, nil, cd.Spec.Schematic) case "TraitDefinition": var td v1beta1.TraitDefinition err = yaml.Unmarshal(data, &td) if err != nil { return types.Capability{}, err } - return HandleDefinition(td.Name, td.Spec.Reference.Name, td.Annotations, td.Spec.Extension, types.TypeTrait, td.Spec.AppliesToWorkloads, td.Spec.Schematic) + return HandleDefinition(td.Name, td.Spec.Reference.Name, td.Annotations, td.Labels, td.Spec.Extension, types.TypeTrait, td.Spec.AppliesToWorkloads, td.Spec.Schematic) case "ScopeDefinition": // TODO(wonderflow): support scope definition here. } diff --git a/references/plugins/cluster.go b/references/plugins/cluster.go index e6d8c8786..42f781e44 100644 --- a/references/plugins/cluster.go +++ b/references/plugins/cluster.go @@ -205,7 +205,8 @@ func validateCapabilities(tmp *types.Capability, dm discoverymapper.DiscoveryMap } // HandleDefinition will handle definition to capability -func HandleDefinition(name, crdName string, annotation map[string]string, extension *runtime.RawExtension, tp types.CapType, applyTo []string, schematic *commontypes.Schematic) (types.Capability, error) { +func HandleDefinition(name, crdName string, annotation, labels map[string]string, extension *runtime.RawExtension, tp types.CapType, + applyTo []string, schematic *commontypes.Schematic) (types.Capability, error) { var tmp types.Capability tmp, err := HandleTemplate(extension, schematic, name) if err != nil { @@ -217,6 +218,7 @@ func HandleDefinition(name, crdName string, annotation map[string]string, extens } tmp.CrdName = crdName tmp.Description = GetDescription(annotation) + tmp.Labels = labels return tmp, nil } @@ -352,8 +354,8 @@ func GetCapabilityByName(ctx context.Context, c common.Args, capabilityName stri // GetCapabilityByComponentDefinitionObject gets capability by ComponentDefinition object func GetCapabilityByComponentDefinitionObject(componentDef v1beta1.ComponentDefinition, referenceName string) (*types.Capability, error) { - capability, err := HandleDefinition(componentDef.Name, referenceName, - componentDef.Annotations, componentDef.Spec.Extension, types.TypeComponentDefinition, nil, componentDef.Spec.Schematic) + capability, err := HandleDefinition(componentDef.Name, referenceName, componentDef.Annotations, componentDef.Labels, + componentDef.Spec.Extension, types.TypeComponentDefinition, nil, componentDef.Spec.Schematic) if err != nil { return nil, errors.Wrap(err, "failed to handle ComponentDefinition") } @@ -367,8 +369,8 @@ func GetCapabilityByTraitDefinitionObject(traitDef v1beta1.TraitDefinition) (*ty capability types.Capability err error ) - capability, err = HandleDefinition(traitDef.Name, traitDef.Spec.Reference.Name, - traitDef.Annotations, traitDef.Spec.Extension, types.TypeTrait, nil, traitDef.Spec.Schematic) + capability, err = HandleDefinition(traitDef.Name, traitDef.Spec.Reference.Name, traitDef.Annotations, traitDef.Labels, + traitDef.Spec.Extension, types.TypeTrait, nil, traitDef.Spec.Schematic) if err != nil { return nil, errors.Wrap(err, "failed to handle TraitDefinition") } diff --git a/references/plugins/cluster_test.go b/references/plugins/cluster_test.go index 81f4cb669..f0c002b26 100644 --- a/references/plugins/cluster_test.go +++ b/references/plugins/cluster_test.go @@ -79,6 +79,7 @@ var _ = Describe("DefinitionFiles", func() { APIVersion: "apps/v1", Kind: "Deployment", }, + Labels: map[string]string{"usecase": "forplugintest"}, } websvc := types.Capability{ @@ -108,6 +109,7 @@ var _ = Describe("DefinitionFiles", func() { APIVersion: "apps/v1", Kind: "Deployment", }, + Labels: map[string]string{"usecase": "forplugintest"}, } req, _ := labels.NewRequirement("usecase", selection.Equals, []string{"forplugintest"})