diff --git a/go.mod b/go.mod index 2f4f45697..1c51f0380 100644 --- a/go.mod +++ b/go.mod @@ -110,7 +110,10 @@ require ( gomodules.xyz/jsonpatch/v2 v2.2.0 ) -require github.com/google/go-containerregistry v0.9.0 +require ( + github.com/google/go-containerregistry v0.9.0 + gopkg.in/yaml.v2 v2.4.0 +) require ( cloud.google.com/go/compute v1.6.1 // indirect @@ -297,7 +300,6 @@ require ( gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect istio.io/api v0.0.0-20210128181506-0c4b8e54850f // indirect istio.io/gogo-genproto v0.0.0-20190930162913-45029607206a // indirect oras.land/oras-go v0.4.0 // indirect 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/tree.go b/pkg/velaql/providers/query/tree.go index afc9df282..60c4c7003 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,16 @@ type ResourceType struct { Kind string `json:"kind,omitempty"` } +// CustomRules define the customize rule created by user +type CustomRule struct { + ParentResourceType *GroupResourceType `json:"parentResourceType,omitempty"` + ChildrenResourceType []ResourceType `json:"childrenResourceType,omitempty"` +} + +type CustomRules struct { + CustomRules []CustomRule `json:"customRules"` +} + // ChildrenResourcesRule define the relationShip between parentObject and children resource type ChildrenResourcesRule struct { // every subResourceType can have a specified genListOptionFunc. @@ -446,3 +463,35 @@ 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 { + return 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..d6b60513a 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,67 @@ 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 +` + + 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()) + + 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"}] + //rule := globalRule + //fmt.Println(rule) + Expect(ok).Should(BeTrue()) + Expect(childrenResources.DefaultGenListOptionFunc).Should(BeNil()) + Expect(len(dsChildrenResources.CareResource)).Should(BeEquivalentTo(2)) + dsSpecifyFunc, ok := childrenResources.CareResource[ResourceType{APIVersion: "v1", Kind: "Pod"}] + Expect(ok).Should(BeTrue()) + Expect(dsSpecifyFunc).Should(BeNil()) + crSpecifyFunc, ok := childrenResources.CareResource[ResourceType{APIVersion: "apps/v1", Kind: "ControllerRevision"}] + Expect(ok).Should(BeTrue()) + Expect(crSpecifyFunc).Should(BeNil()) + + Expect(k8sClient.Delete(ctx, &cloneSetConfigMap)).Should(BeNil()) + Expect(k8sClient.Delete(ctx, &daemonSetConfigMap)).Should(BeNil()) + Expect(k8sClient.Delete(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "vela-system"}})).Should(BeNil()) + }) +})