From d9c1af704f1cfe290226c6567f3a97af7c7fc2ab Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Tue, 3 May 2022 09:45:28 +0000 Subject: [PATCH] [Feature] Recursive OwnerReference Discovery --- CHANGELOG.md | 1 + .../resources/inspector/acs_anonymous.go | 5 +- .../resources/inspector/ad_constants.go | 65 ++++ .../resources/inspector/am_anonymous.go | 5 +- .../resources/inspector/at_anonymous.go | 5 +- .../inspector/endpoints_anonymous.go | 5 +- pkg/deployment/resources/inspector/gvk.go | 67 ++++ .../resources/inspector/gvk_test.go | 64 ++++ .../resources/inspector/inspector.go | 30 ++ .../resources/inspector/nodes_anonymous.go | 5 +- pkg/deployment/resources/inspector/owner.go | 63 ++++ .../resources/inspector/owner_test.go | 331 ++++++++++++++++++ .../resources/inspector/pdbs_anonymous.go | 8 +- .../resources/inspector/pods_anonymous.go | 5 +- .../resources/inspector/pvcs_anonymous.go | 5 +- .../resources/inspector/sa_anonymous.go | 5 +- .../resources/inspector/secrets_anonymous.go | 5 +- .../resources/inspector/services_anonymous.go | 5 +- .../resources/inspector/sm_anonymous.go | 5 +- .../k8sutil/inspector/anonymous/anonymous.go | 38 +- pkg/util/k8sutil/inspector/inspector.go | 12 + 21 files changed, 703 insertions(+), 31 deletions(-) create mode 100644 pkg/deployment/resources/inspector/ad_constants.go create mode 100644 pkg/deployment/resources/inspector/gvk.go create mode 100644 pkg/deployment/resources/inspector/gvk_test.go create mode 100644 pkg/deployment/resources/inspector/owner.go create mode 100644 pkg/deployment/resources/inspector/owner_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 11d2297f4..0cc772b2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - (Feature) Add CoreV1 Endpoints Inspector - (Feature) Add Current ArangoDeployment Inspector - (Refactor) Anonymous inspector functions +- (Feature) Recursive OwnerReference discovery ## [1.2.11](https://github.com/arangodb/kube-arangodb/tree/1.2.11) (2022-04-30) - (Bugfix) Orphan PVC are not removed diff --git a/pkg/deployment/resources/inspector/acs_anonymous.go b/pkg/deployment/resources/inspector/acs_anonymous.go index 9fe487c49..af63a09d6 100644 --- a/pkg/deployment/resources/inspector/acs_anonymous.go +++ b/pkg/deployment/resources/inspector/acs_anonymous.go @@ -30,7 +30,10 @@ func (p *arangoClusterSynchronizationsInspector) Anonymous(gvk schema.GroupVersi if g.Kind == gvk.Kind && g.Group == gvk.Group { switch gvk.Version { - case ArangoClusterSynchronizationVersionV1: + case ArangoClusterSynchronizationVersionV1, DefaultVersion: + if p.v1 == nil || p.v1.err != nil { + return nil, false + } return &arangoClusterSynchronizationsInspectorAnonymousV1{i: p.v1}, true } } diff --git a/pkg/deployment/resources/inspector/ad_constants.go b/pkg/deployment/resources/inspector/ad_constants.go new file mode 100644 index 000000000..99154173d --- /dev/null +++ b/pkg/deployment/resources/inspector/ad_constants.go @@ -0,0 +1,65 @@ +// +// DISCLAIMER +// +// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package inspector + +import ( + "github.com/arangodb/kube-arangodb/pkg/apis/deployment" + deploymentv1 "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// ArangoDeployment +const ( + ArangoDeploymentGroup = deployment.ArangoDeploymentGroupName + ArangoDeploymentResource = deployment.ArangoDeploymentResourcePlural + ArangoDeploymentKind = deployment.ArangoDeploymentResourceKind + ArangoDeploymentVersionV1 = deploymentv1.ArangoDeploymentVersion +) + +func ArangoDeploymentGK() schema.GroupKind { + return schema.GroupKind{ + Group: ArangoDeploymentGroup, + Kind: ArangoDeploymentKind, + } +} + +func ArangoDeploymentGKv1() schema.GroupVersionKind { + return schema.GroupVersionKind{ + Group: ArangoDeploymentGroup, + Kind: ArangoDeploymentKind, + Version: ArangoDeploymentVersionV1, + } +} + +func ArangoDeploymentGR() schema.GroupResource { + return schema.GroupResource{ + Group: ArangoDeploymentGroup, + Resource: ArangoDeploymentResource, + } +} + +func ArangoDeploymentGRv1() schema.GroupVersionResource { + return schema.GroupVersionResource{ + Group: ArangoDeploymentGroup, + Resource: ArangoDeploymentResource, + Version: ArangoDeploymentVersionV1, + } +} diff --git a/pkg/deployment/resources/inspector/am_anonymous.go b/pkg/deployment/resources/inspector/am_anonymous.go index ffa78dadf..7e37e1e74 100644 --- a/pkg/deployment/resources/inspector/am_anonymous.go +++ b/pkg/deployment/resources/inspector/am_anonymous.go @@ -30,7 +30,10 @@ func (p *arangoMembersInspector) Anonymous(gvk schema.GroupVersionKind) (anonymo if g.Kind == gvk.Kind && g.Group == gvk.Group { switch gvk.Version { - case ArangoMemberVersionV1: + case ArangoMemberVersionV1, DefaultVersion: + if p.v1 == nil || p.v1.err != nil { + return nil, false + } return &arangoMembersInspectorAnonymousV1{i: p.v1}, true } } diff --git a/pkg/deployment/resources/inspector/at_anonymous.go b/pkg/deployment/resources/inspector/at_anonymous.go index 7ab452625..59576de31 100644 --- a/pkg/deployment/resources/inspector/at_anonymous.go +++ b/pkg/deployment/resources/inspector/at_anonymous.go @@ -30,7 +30,10 @@ func (p *arangoTasksInspector) Anonymous(gvk schema.GroupVersionKind) (anonymous if g.Kind == gvk.Kind && g.Group == gvk.Group { switch gvk.Version { - case ArangoTaskVersionV1: + case ArangoTaskVersionV1, DefaultVersion: + if p.v1 == nil || p.v1.err != nil { + return nil, false + } return &arangoTasksInspectorAnonymousV1{i: p.v1}, true } } diff --git a/pkg/deployment/resources/inspector/endpoints_anonymous.go b/pkg/deployment/resources/inspector/endpoints_anonymous.go index fd311eaf2..09aa356ce 100644 --- a/pkg/deployment/resources/inspector/endpoints_anonymous.go +++ b/pkg/deployment/resources/inspector/endpoints_anonymous.go @@ -30,7 +30,10 @@ func (p *endpointsInspector) Anonymous(gvk schema.GroupVersionKind) (anonymous.I if g.Kind == gvk.Kind && g.Group == gvk.Group { switch gvk.Version { - case EndpointsVersionV1: + case EndpointsVersionV1, DefaultVersion: + if p.v1 == nil || p.v1.err != nil { + return nil, false + } return &endpointsInspectorAnonymousV1{i: p.v1}, true } } diff --git a/pkg/deployment/resources/inspector/gvk.go b/pkg/deployment/resources/inspector/gvk.go new file mode 100644 index 000000000..9f5bd1476 --- /dev/null +++ b/pkg/deployment/resources/inspector/gvk.go @@ -0,0 +1,67 @@ +// +// DISCLAIMER +// +// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package inspector + +import ( + api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" + monitoring "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" + core "k8s.io/api/core/v1" + policyv1 "k8s.io/api/policy/v1" + policyv1beta1 "k8s.io/api/policy/v1beta1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func ExtractGVKFromObject(in interface{}) (schema.GroupVersionKind, bool) { + if in != nil { + switch in.(type) { + case *api.ArangoClusterSynchronization, api.ArangoClusterSynchronization: + return ArangoClusterSynchronizationGKv1(), true + case *api.ArangoMember, api.ArangoMember: + return ArangoMemberGKv1(), true + case *api.ArangoTask, api.ArangoTask: + return ArangoTaskGKv1(), true + case *core.Endpoints, core.Endpoints: + return EndpointsGKv1(), true + case *core.Node, core.Node: + return NodeGKv1(), true + case *policyv1.PodDisruptionBudget, policyv1.PodDisruptionBudget: + return PodDisruptionBudgetGKv1(), true + case *policyv1beta1.PodDisruptionBudget, policyv1beta1.PodDisruptionBudget: + return PodDisruptionBudgetGKv1Beta1(), true + case *core.Pod, core.Pod: + return PodGKv1(), true + case *core.ServiceAccount, core.ServiceAccount: + return ServiceAccountGKv1(), true + case *core.PersistentVolumeClaim, core.PersistentVolumeClaim: + return PersistentVolumeClaimGKv1(), true + case *core.Secret, core.Secret: + return SecretGKv1(), true + case *core.Service, core.Service: + return ServiceGKv1(), true + case *monitoring.ServiceMonitor, monitoring.ServiceMonitor: + return ServiceMonitorGKv1(), true + case *api.ArangoDeployment, api.ArangoDeployment: + return ArangoDeploymentGKv1(), true + } + } + + return schema.GroupVersionKind{}, false +} diff --git a/pkg/deployment/resources/inspector/gvk_test.go b/pkg/deployment/resources/inspector/gvk_test.go new file mode 100644 index 000000000..a17effc3f --- /dev/null +++ b/pkg/deployment/resources/inspector/gvk_test.go @@ -0,0 +1,64 @@ +// +// DISCLAIMER +// +// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package inspector + +import ( + "reflect" + "testing" + + api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" + monitoring "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" + "github.com/stretchr/testify/require" + core "k8s.io/api/core/v1" + policyv1 "k8s.io/api/policy/v1" + policyv1beta1 "k8s.io/api/policy/v1beta1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func Test_GVK(t *testing.T) { + testGVK(t, ArangoClusterSynchronizationGKv1(), &api.ArangoClusterSynchronization{}, api.ArangoClusterSynchronization{}) + testGVK(t, ArangoMemberGKv1(), &api.ArangoMember{}, api.ArangoMember{}) + testGVK(t, ArangoTaskGKv1(), &api.ArangoTask{}, api.ArangoTask{}) + testGVK(t, EndpointsGKv1(), &core.Endpoints{}, core.Endpoints{}) + testGVK(t, NodeGKv1(), &core.Node{}, core.Node{}) + testGVK(t, PodDisruptionBudgetGKv1(), &policyv1.PodDisruptionBudget{}, policyv1.PodDisruptionBudget{}) + testGVK(t, PodDisruptionBudgetGKv1Beta1(), &policyv1beta1.PodDisruptionBudget{}, policyv1beta1.PodDisruptionBudget{}) + testGVK(t, PodGKv1(), &core.Pod{}, core.Pod{}) + testGVK(t, ServiceAccountGKv1(), &core.ServiceAccount{}, core.ServiceAccount{}) + testGVK(t, ServiceGKv1(), &core.Service{}, core.Service{}) + testGVK(t, PersistentVolumeClaimGKv1(), &core.PersistentVolumeClaim{}, core.PersistentVolumeClaim{}) + testGVK(t, SecretGKv1(), &core.Secret{}, core.Secret{}) + testGVK(t, ServiceMonitorGKv1(), &monitoring.ServiceMonitor{}, monitoring.ServiceMonitor{}) + testGVK(t, ArangoDeploymentGKv1(), &api.ArangoDeployment{}, api.ArangoDeployment{}) +} + +func testGVK(t *testing.T, gvk schema.GroupVersionKind, in ...interface{}) { + t.Run(gvk.String(), func(t *testing.T) { + for _, z := range in { + zt := reflect.TypeOf(z) + t.Run(zt.String(), func(t *testing.T) { + g, ok := ExtractGVKFromObject(z) + require.True(t, ok) + require.Equal(t, gvk, g) + }) + } + }) +} diff --git a/pkg/deployment/resources/inspector/inspector.go b/pkg/deployment/resources/inspector/inspector.go index 712ebf647..d506912e8 100644 --- a/pkg/deployment/resources/inspector/inspector.go +++ b/pkg/deployment/resources/inspector/inspector.go @@ -48,10 +48,15 @@ import ( "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/throttle" "github.com/arangodb/kube-arangodb/pkg/util/kclient" "github.com/rs/zerolog" + core "k8s.io/api/core/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" ) +const ( + DefaultVersion = "" +) + var ( inspectorLoadersList inspectorLoaders inspectorLoadersLock sync.Mutex @@ -159,6 +164,31 @@ type inspectorState struct { initialised bool } +func extractGVKFromOwnerReference(o meta.OwnerReference) schema.GroupVersionKind { + z := strings.SplitN(o.APIVersion, "/", 2) + + switch len(z) { + case 1: + return schema.GroupVersionKind{ + Group: core.GroupName, + Version: z[0], + Kind: o.Kind, + } + case 2: + return schema.GroupVersionKind{ + Group: z[0], + Version: z[1], + Kind: o.Kind, + } + default: + return schema.GroupVersionKind{ + Group: core.GroupName, + Version: z[1], + Kind: o.APIVersion, + } + } +} + func (i *inspectorState) Anonymous(gvk schema.GroupVersionKind) (anonymous.Interface, bool) { for _, o := range i.AnonymousObjects() { if o == nil { diff --git a/pkg/deployment/resources/inspector/nodes_anonymous.go b/pkg/deployment/resources/inspector/nodes_anonymous.go index 3ac5a4edb..c67f970ee 100644 --- a/pkg/deployment/resources/inspector/nodes_anonymous.go +++ b/pkg/deployment/resources/inspector/nodes_anonymous.go @@ -30,7 +30,10 @@ func (p *nodesInspector) Anonymous(gvk schema.GroupVersionKind) (anonymous.Inter if g.Kind == gvk.Kind && g.Group == gvk.Group { switch gvk.Version { - case NodeVersionV1: + case NodeVersionV1, DefaultVersion: + if p.v1 == nil || p.v1.err != nil { + return nil, false + } return &nodesInspectorAnonymousV1{i: p.v1}, true } } diff --git a/pkg/deployment/resources/inspector/owner.go b/pkg/deployment/resources/inspector/owner.go new file mode 100644 index 000000000..3f03f26a9 --- /dev/null +++ b/pkg/deployment/resources/inspector/owner.go @@ -0,0 +1,63 @@ +// +// DISCLAIMER +// +// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package inspector + +import ( + "context" + + "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector" + "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/anonymous" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func (i *inspectorState) IsOwnerOf(ctx context.Context, owner inspector.Object, obj meta.Object) bool { + return i.isOwnerOf(ctx, 8, i.AnonymousObjects(), owner.GroupVersionKind(), owner, obj) +} + +func (i *inspectorState) isOwnerOf(ctx context.Context, jumps int, a []anonymous.Impl, gvk schema.GroupVersionKind, owner meta.Object, obj meta.Object) bool { + if jumps <= 0 { + return false + } + + for _, o := range obj.GetOwnerReferences() { + ogvk := extractGVKFromOwnerReference(o) + + if ogvk.Kind == gvk.Kind && ogvk.Group == gvk.Group && o.Name == owner.GetName() && o.UID == owner.GetUID() { + return true + } + + for _, q := range a { + if a == nil { + continue + } + if c, ok := q.Anonymous(ogvk); ok { + if nobj, err := c.Get(ctx, o.Name, meta.GetOptions{}); err == nil { + if i.isOwnerOf(ctx, jumps-1, a, gvk, owner, nobj) { + return true + } + } + } + } + } + + return false +} diff --git a/pkg/deployment/resources/inspector/owner_test.go b/pkg/deployment/resources/inspector/owner_test.go new file mode 100644 index 000000000..3e91beda4 --- /dev/null +++ b/pkg/deployment/resources/inspector/owner_test.go @@ -0,0 +1,331 @@ +// +// DISCLAIMER +// +// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package inspector + +import ( + "context" + "fmt" + "testing" + + api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" + "github.com/arangodb/kube-arangodb/pkg/util/kclient" + "github.com/stretchr/testify/require" + core "k8s.io/api/core/v1" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/uuid" +) + +func Test_OwnerRef(t *testing.T) { + t.Run("Missing owner", func(t *testing.T) { + obj1 := &core.Service{ + ObjectMeta: meta.ObjectMeta{ + Name: "obj1", + Namespace: "test", + UID: uuid.NewUUID(), + }, + } + obj2 := &api.ArangoDeployment{ + ObjectMeta: meta.ObjectMeta{ + Name: "obj2", + Namespace: "test", + UID: uuid.NewUUID(), + }, + } + + c := clientWithGVK(t, obj1, obj2) + + i := NewInspector(nil, c, "test", "test") + + require.NoError(t, i.Refresh(context.Background())) + + require.False(t, i.IsOwnerOf(context.Background(), obj2, obj1)) + }) + t.Run("Owner 1 hop", func(t *testing.T) { + obj2 := &api.ArangoDeployment{ + ObjectMeta: meta.ObjectMeta{ + Name: "obj2", + Namespace: "test", + UID: uuid.NewUUID(), + }, + } + obj1 := &core.Service{ + ObjectMeta: meta.ObjectMeta{ + Name: "obj1", + Namespace: "test", + UID: uuid.NewUUID(), + OwnerReferences: []meta.OwnerReference{ + obj2.AsOwner(), + }, + }, + } + + c := clientWithGVK(t, obj1, obj2) + + i := NewInspector(nil, c, "test", "test") + + require.NoError(t, i.Refresh(context.Background())) + + require.True(t, i.IsOwnerOf(context.Background(), obj2, obj1)) + }) + t.Run("Owner 2 hops", func(t *testing.T) { + obj3 := &api.ArangoDeployment{ + ObjectMeta: meta.ObjectMeta{ + Name: "obj2", + Namespace: "test", + UID: uuid.NewUUID(), + }, + } + obj2 := &core.Service{ + ObjectMeta: meta.ObjectMeta{ + Name: "obj2", + Namespace: "test", + UID: uuid.NewUUID(), + OwnerReferences: []meta.OwnerReference{ + obj3.AsOwner(), + }, + }, + } + sapi, skind := ServiceGKv1().ToAPIVersionAndKind() + obj1 := &core.Service{ + ObjectMeta: meta.ObjectMeta{ + Name: "obj1", + Namespace: "test", + UID: uuid.NewUUID(), + OwnerReferences: []meta.OwnerReference{ + { + APIVersion: sapi, + Kind: skind, + Name: obj2.Name, + UID: obj2.UID, + }, + }, + }, + } + + c := clientWithGVK(t, obj1, obj2, obj3) + + i := NewInspector(nil, c, "test", "test") + + require.NoError(t, i.Refresh(context.Background())) + + require.True(t, i.IsOwnerOf(context.Background(), obj3, obj1)) + }) + t.Run("Owner - infinite loop", func(t *testing.T) { + s2uid := uuid.NewUUID() + sapi, skind := ServiceGKv1().ToAPIVersionAndKind() + obj4 := &api.ArangoDeployment{ + ObjectMeta: meta.ObjectMeta{ + Name: "obj4", + Namespace: "test", + UID: uuid.NewUUID(), + }, + } + obj3 := &core.Service{ + ObjectMeta: meta.ObjectMeta{ + Name: "obj3", + Namespace: "test", + UID: s2uid, + OwnerReferences: []meta.OwnerReference{ + { + APIVersion: sapi, + Kind: skind, + Name: "obj2", + UID: s2uid, + }, + }, + }, + } + obj2 := &core.Service{ + ObjectMeta: meta.ObjectMeta{ + Name: "obj2", + Namespace: "test", + UID: s2uid, + OwnerReferences: []meta.OwnerReference{ + { + APIVersion: sapi, + Kind: skind, + Name: obj3.Name, + UID: obj3.UID, + }, + }, + }, + } + obj1 := &core.Service{ + ObjectMeta: meta.ObjectMeta{ + Name: "obj1", + Namespace: "test", + UID: uuid.NewUUID(), + OwnerReferences: []meta.OwnerReference{ + { + APIVersion: sapi, + Kind: skind, + Name: obj2.Name, + UID: obj2.UID, + }, + }, + }, + } + + c := clientWithGVK(t, obj1, obj2, obj3, obj4) + + i := NewInspector(nil, c, "test", "test") + + require.NoError(t, i.Refresh(context.Background())) + + require.False(t, i.IsOwnerOf(context.Background(), obj4, obj1)) + }) + t.Run("Owner - above limit", func(t *testing.T) { + objs := make([]GVKEnsurer, 10) + + depl := &api.ArangoDeployment{ + ObjectMeta: meta.ObjectMeta{ + Name: "depl", + Namespace: "test", + UID: uuid.NewUUID(), + }, + } + sapi, skind := ServiceGKv1().ToAPIVersionAndKind() + + last := &core.Service{ + ObjectMeta: meta.ObjectMeta{ + Name: "obj8", + Namespace: "test", + UID: uuid.NewUUID(), + OwnerReferences: []meta.OwnerReference{ + depl.AsOwner(), + }, + }, + } + + objs[len(objs)-1] = depl + objs[len(objs)-2] = last + + for i := len(objs) - 3; i >= 0; i-- { + n := &core.Service{ + ObjectMeta: meta.ObjectMeta{ + Name: fmt.Sprintf("obj%d", i), + Namespace: "test", + UID: uuid.NewUUID(), + OwnerReferences: []meta.OwnerReference{ + { + APIVersion: sapi, + Kind: skind, + Name: last.Name, + UID: last.UID, + }, + }, + }, + } + objs[i] = n + last = n + } + + c := clientWithGVK(t, objs...) + + i := NewInspector(nil, c, "test", "test") + + require.NoError(t, i.Refresh(context.Background())) + + require.False(t, i.IsOwnerOf(context.Background(), depl, last)) + }) + t.Run("Owner - on limit", func(t *testing.T) { + objs := make([]GVKEnsurer, 9) + + depl := &api.ArangoDeployment{ + ObjectMeta: meta.ObjectMeta{ + Name: "depl", + Namespace: "test", + UID: uuid.NewUUID(), + }, + } + sapi, skind := ServiceGKv1().ToAPIVersionAndKind() + + last := &core.Service{ + ObjectMeta: meta.ObjectMeta{ + Name: "obj8", + Namespace: "test", + UID: uuid.NewUUID(), + OwnerReferences: []meta.OwnerReference{ + depl.AsOwner(), + }, + }, + } + + objs[len(objs)-1] = depl + objs[len(objs)-2] = last + + for i := len(objs) - 3; i >= 0; i-- { + n := &core.Service{ + ObjectMeta: meta.ObjectMeta{ + Name: fmt.Sprintf("obj%d", i), + Namespace: "test", + UID: uuid.NewUUID(), + OwnerReferences: []meta.OwnerReference{ + { + APIVersion: sapi, + Kind: skind, + Name: last.Name, + UID: last.UID, + }, + }, + }, + } + objs[i] = n + last = n + } + + c := clientWithGVK(t, objs...) + + i := NewInspector(nil, c, "test", "test") + + require.NoError(t, i.Refresh(context.Background())) + + require.True(t, i.IsOwnerOf(context.Background(), depl, last)) + }) +} + +type GVKEnsurer interface { + runtime.Object + SetGroupVersionKind(gvk schema.GroupVersionKind) +} + +func clientWithGVK(t *testing.T, obj ...GVKEnsurer) kclient.Client { + ensureGVK(t, obj...) + + f := kclient.NewFakeClientBuilder() + + for _, o := range obj { + f = f.Add(o) + } + + return f.Client() +} + +func ensureGVK(t *testing.T, objs ...GVKEnsurer) { + for _, o := range objs { + gvk, ok := ExtractGVKFromObject(o) + require.True(t, ok) + + o.SetGroupVersionKind(gvk) + } +} diff --git a/pkg/deployment/resources/inspector/pdbs_anonymous.go b/pkg/deployment/resources/inspector/pdbs_anonymous.go index 22d09071c..e7ee9dbfe 100644 --- a/pkg/deployment/resources/inspector/pdbs_anonymous.go +++ b/pkg/deployment/resources/inspector/pdbs_anonymous.go @@ -30,9 +30,15 @@ func (p *podDisruptionBudgetsInspector) Anonymous(gvk schema.GroupVersionKind) ( if g.Kind == gvk.Kind && g.Group == gvk.Group { switch gvk.Version { - case PodDisruptionBudgetVersionV1: + case PodDisruptionBudgetVersionV1, DefaultVersion: + if p.v1 == nil || p.v1.err != nil { + return nil, false + } return &podDisruptionBudgetsInspectorAnonymousV1{i: p.v1}, true case PodDisruptionBudgetVersionV1Beta1: + if p.v1beta1 == nil || p.v1beta1.err != nil { + return nil, false + } return &podDisruptionBudgetsInspectorAnonymousV1Beta1{i: p.v1beta1}, true } } diff --git a/pkg/deployment/resources/inspector/pods_anonymous.go b/pkg/deployment/resources/inspector/pods_anonymous.go index b5c0b9dee..72fd808ef 100644 --- a/pkg/deployment/resources/inspector/pods_anonymous.go +++ b/pkg/deployment/resources/inspector/pods_anonymous.go @@ -30,7 +30,10 @@ func (p *podsInspector) Anonymous(gvk schema.GroupVersionKind) (anonymous.Interf if g.Kind == gvk.Kind && g.Group == gvk.Group { switch gvk.Version { - case PodVersionV1: + case PodVersionV1, DefaultVersion: + if p.v1 == nil || p.v1.err != nil { + return nil, false + } return &podsInspectorAnonymousV1{i: p.v1}, true } } diff --git a/pkg/deployment/resources/inspector/pvcs_anonymous.go b/pkg/deployment/resources/inspector/pvcs_anonymous.go index 8762d7f14..6aa30cf85 100644 --- a/pkg/deployment/resources/inspector/pvcs_anonymous.go +++ b/pkg/deployment/resources/inspector/pvcs_anonymous.go @@ -30,7 +30,10 @@ func (p *persistentVolumeClaimsInspector) Anonymous(gvk schema.GroupVersionKind) if g.Kind == gvk.Kind && g.Group == gvk.Group { switch gvk.Version { - case PersistentVolumeClaimVersionV1: + case PersistentVolumeClaimVersionV1, DefaultVersion: + if p.v1 == nil || p.v1.err != nil { + return nil, false + } return &persistentVolumeClaimsInspectorAnonymousV1{i: p.v1}, true } } diff --git a/pkg/deployment/resources/inspector/sa_anonymous.go b/pkg/deployment/resources/inspector/sa_anonymous.go index fd972fa1c..6a2c741b9 100644 --- a/pkg/deployment/resources/inspector/sa_anonymous.go +++ b/pkg/deployment/resources/inspector/sa_anonymous.go @@ -30,7 +30,10 @@ func (p *serviceAccountsInspector) Anonymous(gvk schema.GroupVersionKind) (anony if g.Kind == gvk.Kind && g.Group == gvk.Group { switch gvk.Version { - case ServiceAccountVersionV1: + case ServiceAccountVersionV1, DefaultVersion: + if p.v1 == nil || p.v1.err != nil { + return nil, false + } return &serviceAccountsInspectorAnonymousV1{i: p.v1}, true } } diff --git a/pkg/deployment/resources/inspector/secrets_anonymous.go b/pkg/deployment/resources/inspector/secrets_anonymous.go index 464dbde0b..7c710a213 100644 --- a/pkg/deployment/resources/inspector/secrets_anonymous.go +++ b/pkg/deployment/resources/inspector/secrets_anonymous.go @@ -30,7 +30,10 @@ func (p *secretsInspector) Anonymous(gvk schema.GroupVersionKind) (anonymous.Int if g.Kind == gvk.Kind && g.Group == gvk.Group { switch gvk.Version { - case SecretVersionV1: + case SecretVersionV1, DefaultVersion: + if p.v1 == nil || p.v1.err != nil { + return nil, false + } return &secretsInspectorAnonymousV1{i: p.v1}, true } } diff --git a/pkg/deployment/resources/inspector/services_anonymous.go b/pkg/deployment/resources/inspector/services_anonymous.go index 311b1c482..6bf51103d 100644 --- a/pkg/deployment/resources/inspector/services_anonymous.go +++ b/pkg/deployment/resources/inspector/services_anonymous.go @@ -30,7 +30,10 @@ func (p *servicesInspector) Anonymous(gvk schema.GroupVersionKind) (anonymous.In if g.Kind == gvk.Kind && g.Group == gvk.Group { switch gvk.Version { - case ServiceVersionV1: + case ServiceVersionV1, DefaultVersion: + if p.v1 == nil || p.v1.err != nil { + return nil, false + } return &servicesInspectorAnonymousV1{i: p.v1}, true } } diff --git a/pkg/deployment/resources/inspector/sm_anonymous.go b/pkg/deployment/resources/inspector/sm_anonymous.go index cc9df7a67..cedd0a971 100644 --- a/pkg/deployment/resources/inspector/sm_anonymous.go +++ b/pkg/deployment/resources/inspector/sm_anonymous.go @@ -30,7 +30,10 @@ func (p *serviceMonitorsInspector) Anonymous(gvk schema.GroupVersionKind) (anony if g.Kind == gvk.Kind && g.Group == gvk.Group { switch gvk.Version { - case ServiceMonitorVersionV1: + case ServiceMonitorVersionV1, DefaultVersion: + if p.v1 == nil || p.v1.err != nil { + return nil, false + } return &serviceMonitorsInspectorAnonymousV1{i: p.v1}, true } } diff --git a/pkg/util/k8sutil/inspector/anonymous/anonymous.go b/pkg/util/k8sutil/inspector/anonymous/anonymous.go index 0db404a2b..f52a6114b 100644 --- a/pkg/util/k8sutil/inspector/anonymous/anonymous.go +++ b/pkg/util/k8sutil/inspector/anonymous/anonymous.go @@ -1,22 +1,22 @@ -// // -// // DISCLAIMER -// // -// // Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany -// // -// // Licensed under the Apache License, Version 2.0 (the "License"); -// // you may not use this file except in compliance with the License. -// // You may obtain a copy of the License at -// // -// // http://www.apache.org/licenses/LICENSE-2.0 -// // -// // Unless required by applicable law or agreed to in writing, software -// // distributed under the License is distributed on an "AS IS" BASIS, -// // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// // See the License for the specific language governing permissions and -// // limitations under the License. -// // -// // Copyright holder is ArangoDB GmbH, Cologne, Germany -// // +// +// DISCLAIMER +// +// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// package anonymous diff --git a/pkg/util/k8sutil/inspector/inspector.go b/pkg/util/k8sutil/inspector/inspector.go index 2356ef656..325b1f45e 100644 --- a/pkg/util/k8sutil/inspector/inspector.go +++ b/pkg/util/k8sutil/inspector/inspector.go @@ -25,6 +25,8 @@ import ( "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/refresh" "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/server" + "context" + "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/anonymous" "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/arangoclustersynchronization" "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/arangodeployment" @@ -40,8 +42,16 @@ import ( "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/servicemonitor" "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/throttle" "github.com/arangodb/kube-arangodb/pkg/util/kclient" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" ) +type Object interface { + meta.Object + + GroupVersionKind() schema.GroupVersionKind +} + type Inspector interface { Client() kclient.Client Namespace() string @@ -50,6 +60,8 @@ type Inspector interface { anonymous.Impl + IsOwnerOf(ctx context.Context, owner Object, obj meta.Object) bool + AnonymousObjects() []anonymous.Impl refresh.Inspector