From dae0358bc0cb97cc12de16d0e5272c822dee3d22 Mon Sep 17 00:00:00 2001 From: wyike Date: Wed, 25 May 2022 16:44:46 +0800 Subject: [PATCH] Feat: mechanism to let user add relationship mapping rule by configmap (#3968) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * WIP add some code Signed-off-by: 楚岳 small fix Signed-off-by: 楚岳 fix all tests Signed-off-by: 楚岳 * add comment Signed-off-by: 楚岳 fix ci delete useless code Signed-off-by: 楚岳 go mod vendor Signed-off-by: 楚岳 * fix failed test Signed-off-by: 楚岳 * more test Signed-off-by: 楚岳 --- pkg/oam/labels.go | 2 + pkg/velaql/providers/query/handler.go | 5 ++ pkg/velaql/providers/query/handler_test.go | 2 +- pkg/velaql/providers/query/tree.go | 46 ++++++++++ pkg/velaql/providers/query/tree_test.go | 100 +++++++++++++++++++++ 5 files changed, 154 insertions(+), 1 deletion(-) diff --git a/pkg/oam/labels.go b/pkg/oam/labels.go index 972569bb2..fc774c8ad 100644 --- a/pkg/oam/labels.go +++ b/pkg/oam/labels.go @@ -96,6 +96,8 @@ const ( // LabelProject recorde the project the resource belong to LabelProject = "core.oam.dev/project" + + LabelResourceRules = "rules.oam.dev/resources" ) const ( diff --git a/pkg/velaql/providers/query/handler.go b/pkg/velaql/providers/query/handler.go index ed3466f5d..5095de6ff 100644 --- a/pkg/velaql/providers/query/handler.go +++ b/pkg/velaql/providers/query/handler.go @@ -156,6 +156,11 @@ func (h *provider) GetApplicationResourceTree(ctx wfContext.Context, v *value.Va if err != nil { return v.FillObject(err.Error(), "err") } + // merge user defined customize rule before every request. + err = mergeCustomRules(context.Background(), h.cli) + if err != nil { + return err + } for _, resource := range appResList { root := querytypes.ResourceTreeNode{ APIVersion: resource.APIVersion, diff --git a/pkg/velaql/providers/query/handler_test.go b/pkg/velaql/providers/query/handler_test.go index 979086b32..bb32b26be 100644 --- a/pkg/velaql/providers/query/handler_test.go +++ b/pkg/velaql/providers/query/handler_test.go @@ -740,7 +740,7 @@ options: { Name: "vela-system", }, }) - Expect(err).Should(BeNil()) + Expect(err).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) for _, s := range testServicelist { ns := "default" if s["namespace"] != nil { diff --git a/pkg/velaql/providers/query/tree.go b/pkg/velaql/providers/query/tree.go index afc9df282..1e5cdaeb2 100644 --- a/pkg/velaql/providers/query/tree.go +++ b/pkg/velaql/providers/query/tree.go @@ -20,6 +20,9 @@ import ( "context" "fmt" + velatypes "github.com/oam-dev/kubevela/apis/types" + "github.com/oam-dev/kubevela/pkg/oam" + "github.com/oam-dev/kubevela/pkg/apiserver/utils/log" appsv1 "k8s.io/api/apps/v1" @@ -31,11 +34,15 @@ import ( "k8s.io/kubectl/pkg/util/podutils" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/yaml" "github.com/oam-dev/kubevela/pkg/multicluster" "github.com/oam-dev/kubevela/pkg/velaql/providers/query/types" ) +// relationshipKey is the configmap key of relationShip rule +var relationshipKey = "rules" + // set the iterator max depth is 5 var maxDepth = 5 @@ -84,6 +91,12 @@ type ResourceType struct { Kind string `json:"kind,omitempty"` } +// customRule define the customize rule created by user +type customRule struct { + ParentResourceType *GroupResourceType `json:"parentResourceType,omitempty"` + ChildrenResourceType []ResourceType `json:"childrenResourceType,omitempty"` +} + // ChildrenResourcesRule define the relationShip between parentObject and children resource type ChildrenResourcesRule struct { // every subResourceType can have a specified genListOptionFunc. @@ -446,3 +459,36 @@ func iteratorChildResources(ctx context.Context, cluster string, k8sClient clien } return nil, nil } + +// mergeCustomRules merge the customize +func mergeCustomRules(ctx context.Context, k8sClient client.Client) error { + rulesList := v12.ConfigMapList{} + if err := k8sClient.List(ctx, &rulesList, client.InNamespace(velatypes.DefaultKubeVelaNS), client.HasLabels{oam.LabelResourceRules}); err != nil { + return err + } + for _, item := range rulesList.Items { + ruleStr := item.Data[relationshipKey] + var customRules []*customRule + err := yaml.Unmarshal([]byte(ruleStr), &customRules) + if err != nil { + // don't let one miss-config configmap brake whole process + log.Logger.Errorf("relationship rule configamp %s miss config %v", item.Name, err) + } + for _, rule := range customRules { + if cResource, ok := globalRule[*rule.ParentResourceType]; ok { + for _, resourceType := range rule.ChildrenResourceType { + if _, ok := cResource.CareResource[resourceType]; !ok { + cResource.CareResource[resourceType] = nil + } + } + } else { + caredResources := map[ResourceType]genListOptionFunc{} + for _, resourceType := range rule.ChildrenResourceType { + caredResources[resourceType] = nil + } + globalRule[*rule.ParentResourceType] = ChildrenResourcesRule{DefaultGenListOptionFunc: nil, CareResource: caredResources} + } + } + } + return nil +} diff --git a/pkg/velaql/providers/query/tree_test.go b/pkg/velaql/providers/query/tree_test.go index cd6f6de73..b4726e853 100644 --- a/pkg/velaql/providers/query/tree_test.go +++ b/pkg/velaql/providers/query/tree_test.go @@ -20,6 +20,8 @@ import ( "fmt" "testing" + types3 "github.com/oam-dev/kubevela/apis/types" + "github.com/oam-dev/kubevela/apis/core.oam.dev/common" "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" "github.com/oam-dev/kubevela/pkg/cue/model/value" @@ -844,3 +846,101 @@ var _ = Describe("unit-test to e2e test", func() { Expect(len(res.List)).Should(Equal(2)) }) }) + +var _ = Describe("test merge globalRules", func() { + cloneSetStr := ` +- parentResourceType: + group: apps.kruise.io + kind: CloneSet + childrenResourceType: + - apiVersion: v1 + kind: Pod + - apiVersion: apps/v1 + kind: ControllerRevision +` + daemonSetStr := ` +- parentResourceType: + group: apps + kind: DaemonSet + childrenResourceType: + - apiVersion: v1 + kind: Pod + - apiVersion: apps/v1 + kind: ControllerRevision +` + stsStr := ` +- parentResourceType: + group: apps + kind: StatefulSet + childrenResourceType: + - apiVersion: v1 + kind: Pod + - apiVersion: apps/v1 + kind: ControllerRevision +` + missConfigedStr := ` +- parentResourceType: + group: apps + kind: StatefulSet +childrenResourceType: + - apiVersion: v1 + kind: Pod + - apiVersion: apps/v1 + kind: ControllerRevision +` + + It("test merge rules", func() { + Expect(k8sClient.Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "vela-system"}})).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) + cloneSetConfigMap := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"}, + ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "cloneset", Labels: map[string]string{oam.LabelResourceRules: "true"}}, + Data: map[string]string{relationshipKey: cloneSetStr}, + } + Expect(k8sClient.Create(ctx, &cloneSetConfigMap)).Should(BeNil()) + + daemonSetConfigMap := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"}, + ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "daemonset", Labels: map[string]string{oam.LabelResourceRules: "true"}}, + Data: map[string]string{relationshipKey: daemonSetStr}, + } + Expect(k8sClient.Create(ctx, &daemonSetConfigMap)).Should(BeNil()) + + stsConfigMap := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"}, + ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "sts", Labels: map[string]string{oam.LabelResourceRules: "true"}}, + Data: map[string]string{relationshipKey: stsStr}, + } + Expect(k8sClient.Create(ctx, &stsConfigMap)).Should(BeNil()) + + missConfigedCm := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"}, + ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "miss-configed", Labels: map[string]string{oam.LabelResourceRules: "true"}}, + Data: map[string]string{relationshipKey: missConfigedStr}, + } + Expect(k8sClient.Create(ctx, &missConfigedCm)).Should(BeNil()) + + Expect(mergeCustomRules(ctx, k8sClient)).Should(BeNil()) + childrenResources, ok := globalRule[GroupResourceType{Group: "apps.kruise.io", Kind: "CloneSet"}] + Expect(ok).Should(BeTrue()) + Expect(childrenResources.DefaultGenListOptionFunc).Should(BeNil()) + Expect(len(childrenResources.CareResource)).Should(BeEquivalentTo(2)) + specifyFunc, ok := childrenResources.CareResource[ResourceType{APIVersion: "v1", Kind: "Pod"}] + Expect(ok).Should(BeTrue()) + Expect(specifyFunc).Should(BeNil()) + + dsChildrenResources, ok := globalRule[GroupResourceType{Group: "apps", Kind: "DaemonSet"}] + Expect(ok).Should(BeTrue()) + Expect(dsChildrenResources.DefaultGenListOptionFunc).Should(BeNil()) + Expect(len(dsChildrenResources.CareResource)).Should(BeEquivalentTo(2)) + dsSpecifyFunc, ok := dsChildrenResources.CareResource[ResourceType{APIVersion: "v1", Kind: "Pod"}] + Expect(ok).Should(BeTrue()) + Expect(dsSpecifyFunc).Should(BeNil()) + crSpecifyFunc, ok := dsChildrenResources.CareResource[ResourceType{APIVersion: "apps/v1", Kind: "ControllerRevision"}] + Expect(ok).Should(BeTrue()) + Expect(crSpecifyFunc).Should(BeNil()) + + stsChildrenResources, ok := globalRule[GroupResourceType{Group: "apps", Kind: "StatefulSet"}] + Expect(ok).Should(BeTrue()) + Expect(stsChildrenResources.DefaultGenListOptionFunc).Should(BeNil()) + Expect(len(stsChildrenResources.CareResource)).Should(BeEquivalentTo(2)) + stsCrSpecifyFunc, ok := stsChildrenResources.CareResource[ResourceType{APIVersion: "apps/v1", Kind: "ControllerRevision"}] + Expect(ok).Should(BeTrue()) + Expect(stsCrSpecifyFunc).Should(BeNil()) + }) +})