diff --git a/cmd/node-observability-operator/main.go b/cmd/node-observability-operator/main.go index bf34dc52..292b8871 100644 --- a/cmd/node-observability-operator/main.go +++ b/cmd/node-observability-operator/main.go @@ -59,7 +59,7 @@ func main() { var operatorNamespace string var operandImage string - flag.StringVar(&operatorNamespace, "operator-namespace", "node-observability-opertaor", "The node observability operator namespace.") + flag.StringVar(&operatorNamespace, "operator-namespace", "node-observability-operator", "The node observability operator namespace.") flag.StringVar(&operandImage, "operand-image", "quay.io/openshif/node-observability-operator:lates", "The operand container image to use.") flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") @@ -79,6 +79,7 @@ func main() { HealthProbeBindAddress: probeAddr, LeaderElection: enableLeaderElection, LeaderElectionID: "94c735b6.olm.openshift.io", + Namespace: "node-observability-operator", }) if err != nil { setupLog.Error(err, "unable to start manager") diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml index 19109eba..68cdf0d4 100644 --- a/config/default/kustomization.yaml +++ b/config/default/kustomization.yaml @@ -44,7 +44,7 @@ patchesStrategicMerge: #- webhookcainjection_patch.yaml # the following config is for teaching kustomize how to do var substitution -vars: +# vars: # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. #- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR # objref: diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index de74d0ec..3b40b6ba 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -10,15 +10,6 @@ rules: - /debug/* verbs: - get -- apiGroups: - - apps - resources: - - daemonsets - verbs: - - create - - get - - list - - watch - apiGroups: - "" resources: @@ -40,14 +31,6 @@ rules: verbs: - get - list -- apiGroups: - - "" - resources: - - secrets - verbs: - - create - - get - - list - watch - apiGroups: - "" @@ -55,6 +38,7 @@ rules: - serviceaccounts verbs: - create + - delete - get - list - watch @@ -116,6 +100,7 @@ rules: - clusterrolebindings verbs: - create + - delete - get - list - watch @@ -125,6 +110,7 @@ rules: - clusterroles verbs: - create + - delete - get - list - watch @@ -134,7 +120,56 @@ rules: - securitycontextconstraints verbs: - create + - delete - get - list - use - watch + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + creationTimestamp: null + name: manager-role + namespace: node-observability-operator +rules: +- apiGroups: + - apps + resources: + - daemonsets + verbs: + - create + - get + - list + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - delete + - get + - list + - watch +- apiGroups: + - rbac.authorization.k8s.io + resources: + - rolebindings + verbs: + - create + - delete + - get + - list + - watch +- apiGroups: + - rbac.authorization.k8s.io + resources: + - roles + verbs: + - create + - delete + - get + - list + - watch diff --git a/config/rbac/role_binding.yaml b/config/rbac/role_binding.yaml index 2070ede4..352bdaad 100644 --- a/config/rbac/role_binding.yaml +++ b/config/rbac/role_binding.yaml @@ -1,3 +1,5 @@ + +--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: @@ -10,3 +12,16 @@ subjects: - kind: ServiceAccount name: controller-manager namespace: system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: manager-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/pkg/operator/controller/nodeobservability/controller.go b/pkg/operator/controller/nodeobservability/controller.go index 4dbbcc1b..cffc71cb 100644 --- a/pkg/operator/controller/nodeobservability/controller.go +++ b/pkg/operator/controller/nodeobservability/controller.go @@ -27,6 +27,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" utilclock "k8s.io/apimachinery/pkg/util/clock" + utilerrors "k8s.io/apimachinery/pkg/util/errors" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -36,6 +37,7 @@ import ( const ( terminating = "Terminating" + finalizer = "NodeObservability" ) var ( @@ -54,16 +56,18 @@ type NodeObservabilityReconciler struct { //+kubebuilder:rbac:groups=nodeobservability.olm.openshift.io,resources=nodeobservabilities,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=nodeobservability.olm.openshift.io,resources=nodeobservabilities/status,verbs=get;update;patch //+kubebuilder:rbac:groups=nodeobservability.olm.openshift.io,resources=nodeobservabilities/finalizers,verbs=update -//+kubebuilder:rbac:groups=apps,resources=daemonsets,verbs=list;get;create;watch; -//+kubebuilder:rbac:groups=core,resources=secrets,verbs=list;get;create;watch; -//+kubebuilder:rbac:groups=core,resources=serviceaccounts,verbs=list;get;create;watch; -//+kubebuilder:rbac:groups=core,resources=pods,verbs=list;get; +//+kubebuilder:rbac:groups=apps,namespace=node-observability-operator,resources=daemonsets,verbs=list;get;create;watch; +//+kubebuilder:rbac:groups=core,namespace=node-observability-operator,resources=secrets,verbs=list;get;create;watch;delete; +//+kubebuilder:rbac:groups=core,resources=serviceaccounts,verbs=list;get;create;watch;delete; +//+kubebuilder:rbac:groups=core,resources=pods,verbs=list;get;watch //+kubebuilder:rbac:groups=core,resources=nodes,verbs=list;get; //+kubebuilder:rbac:groups=core,resources=nodes/proxy,verbs=list;get; //+kubebuilder:rbac:urls=/debug/*,verbs=get; -//+kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterroles,verbs=list;get;create;watch; -//+kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterrolebindings,verbs=list;get;create;watch; -//+kubebuilder:rbac:groups=security.openshift.io,resources=securitycontextconstraints,verbs=list;get;create;watch;use; +//+kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterroles,verbs=list;get;create;watch;delete; +//+kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterrolebindings,verbs=list;get;create;watch;delete; +//+kubebuilder:rbac:groups=rbac.authorization.k8s.io,namespace=node-observability-operator,resources=roles,verbs=list;get;create;watch;delete; +//+kubebuilder:rbac:groups=rbac.authorization.k8s.io,namespace=node-observability-operator,resources=rolebindings,verbs=list;get;create;watch;delete; +//+kubebuilder:rbac:groups=security.openshift.io,resources=securitycontextconstraints,verbs=list;get;create;watch;use;delete; // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. @@ -91,12 +95,26 @@ func (r *NodeObservabilityReconciler) Reconcile(ctx context.Context, req ctrl.Re r.Log.Error(err, "Failed to get NodeObservability") return ctrl.Result{}, err } + if nodeObs.DeletionTimestamp != nil { + r.Log.Info("NodeObservability resource is going to be deleted. Taking action") + if err := r.ensureNodeObservabilityDeleted(ctx, nodeObs); err != nil { + return reconcile.Result{}, fmt.Errorf("failed to ensure nodeobservability deletion: %w", err) + } + return reconcile.Result{}, nil + + } r.Log.Info(fmt.Sprintf("NodeObservability resource found : Namespace %s : Name %s ", req.NamespacedName.Namespace, nodeObs.Name)) + // Set finalizers on the NodeObservability resource + updated, err := r.withFinalizers(nodeObs) + if err != nil { + return reconcile.Result{}, fmt.Errorf("failed to update NodeObservability with finalizers:, %w", err) + } + nodeObs = updated + // For the pods to deploy on each node and execute the crio & kubelet script we need the following // - custom scc (mainly allowHostPathDirPlugin set to true) // - serviceaccount - // - secret // - clusterrole (use the scc) // - clusterrolebinding (bind the sa to the role) @@ -109,17 +127,8 @@ func (r *NodeObservabilityReconciler) Reconcile(ctx context.Context, req ctrl.Re } r.Log.Info(fmt.Sprintf("SecurityContextConstraints : %s", scc.Name)) - // ensure secret - haveSecret, secret, err := r.ensureSecret(ctx, nodeObs) - if err != nil { - return reconcile.Result{}, fmt.Errorf("failed to ensure secret : %w", err) - } else if !haveSecret { - return reconcile.Result{}, fmt.Errorf("failed to get secret") - } - r.Log.Info(fmt.Sprintf("Secret : %s", secret.Name)) - - // ensure serviceaccount with the secret - haveSA, sa, err := r.ensureServiceAccount(ctx, nodeObs, secret) + // ensure serviceaccount + haveSA, sa, err := r.ensureServiceAccount(ctx, nodeObs) if err != nil { return reconcile.Result{}, fmt.Errorf("failed to ensure serviceaccount : %w", err) } else if !haveSA { @@ -195,3 +204,71 @@ func (r *NodeObservabilityReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&appsv1.DaemonSet{}). Complete(r) } + +func hasFinalizer(nodeObs *operatorv1alpha1.NodeObservability) bool { + hasFinalizer := false + for _, f := range nodeObs.Finalizers { + if f == finalizer { + hasFinalizer = true + break + } + } + return hasFinalizer +} + +func (r *NodeObservabilityReconciler) withoutFinalizers(ctx context.Context, nodeObs *operatorv1alpha1.NodeObservability, finalizerFlag string) (*operatorv1alpha1.NodeObservability, error) { + withoutFinalizers := nodeObs.DeepCopy() + + newFinalizers := make([]string, 0) + for _, item := range withoutFinalizers.Finalizers { + if item == finalizerFlag { + continue + } + newFinalizers = append(newFinalizers, item) + } + if len(newFinalizers) == 0 { + // Sanitize for unit tests so we don't need to distinguish empty array + // and nil. + newFinalizers = nil + } + withoutFinalizers.Finalizers = newFinalizers + if err := r.Update(ctx, withoutFinalizers); err != nil { + return withoutFinalizers, fmt.Errorf("failed to remove finalizers: %w", err) + } + return withoutFinalizers, nil +} + +func (r *NodeObservabilityReconciler) withFinalizers(nodeObs *operatorv1alpha1.NodeObservability) (*operatorv1alpha1.NodeObservability, error) { + withFinalizers := nodeObs.DeepCopy() + + if !hasFinalizer(withFinalizers) { + withFinalizers.Finalizers = append(withFinalizers.Finalizers, finalizer) + } + + if err := r.Update(context.TODO(), withFinalizers); err != nil { + return withFinalizers, fmt.Errorf("failed to update finalizers: %w", err) + } + return withFinalizers, nil +} + +func (r *NodeObservabilityReconciler) ensureNodeObservabilityDeleted(ctx context.Context, nodeObs *operatorv1alpha1.NodeObservability) error { + errs := []error{} + + if err := r.deleteClusterRole(nodeObs); err != nil { + errs = append(errs, fmt.Errorf("failed to delete clusterrole : %w", err)) + } + if err := r.deleteClusterRoleBinding(nodeObs); err != nil { + errs = append(errs, fmt.Errorf("failed to delete clusterrolebinding : %w", err)) + } + if err := r.deleteSecurityContextConstraints(nodeObs); err != nil { + errs = append(errs, fmt.Errorf("failed to delete SCC : %w", err)) + } + if len(errs) == 0 && hasFinalizer(nodeObs) { + // Remove the finalizer. + _, err := r.withoutFinalizers(ctx, nodeObs, finalizer) + if err != nil { + errs = append(errs, fmt.Errorf("failed to remove finalizer from nodeobservability %s/%s: %w", nodeObs.Namespace, nodeObs.Name, err)) + } + } + return utilerrors.NewAggregate(errs) +} diff --git a/pkg/operator/controller/nodeobservability/controller_test.go b/pkg/operator/controller/nodeobservability/controller_test.go index 4ea14da2..34ea4f4b 100644 --- a/pkg/operator/controller/nodeobservability/controller_test.go +++ b/pkg/operator/controller/nodeobservability/controller_test.go @@ -1,18 +1,18 @@ -/* -Copyright 2021. +// /* +// Copyright 2021. -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 +// 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 +// 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. -*/ +// 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. +// */ package nodeobservabilitycontroller @@ -23,11 +23,9 @@ import ( "time" "github.com/google/go-cmp/cmp" - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/watch" @@ -64,14 +62,6 @@ func TestReconcile(t *testing.T) { sccObj: false, }, }, - { - Set: map[string]bool{ - secretObj: true, - }, - NotFound: map[string]bool{ - secretObj: false, - }, - }, { Set: map[string]bool{ saObj: true, @@ -112,14 +102,6 @@ func TestReconcile(t *testing.T) { sccObj: true, }, }, - { - Set: map[string]bool{ - secretObj: true, - }, - NotFound: map[string]bool{ - secretObj: true, - }, - }, { Set: map[string]bool{ saObj: true, @@ -172,6 +154,15 @@ func TestReconcile(t *testing.T) { }, } + teDel := test.Event{ + EventType: watch.Deleted, + ObjType: "nodeobservability", + NamespacedName: types.NamespacedName{ + Namespace: "", + Name: "test", + }, + } + testCases := []struct { name string existingObjects []runtime.Object @@ -183,18 +174,24 @@ func TestReconcile(t *testing.T) { errExpected bool }{ { - name: "Bootstrap", + name: "Bootstrapping", existingObjects: []runtime.Object{testNodeObservability()}, inputRequest: testRequest(), expectedResult: reconcile.Result{}, expectedEvents: []test.Event{}, }, { - name: "Delete", + name: "Deleted", existingObjects: []runtime.Object{}, inputRequest: testRequest(), expectedResult: reconcile.Result{}, }, + { + name: "Deleting", + existingObjects: []runtime.Object{testNodeObservabilityToBeDeleted()}, + inputRequest: testRequest(), + expectedResult: reconcile.Result{}, + }, } // loop through test cases (bootstrap and delete) @@ -214,16 +211,28 @@ func TestReconcile(t *testing.T) { Err: errTest, } // only check for errors when the ErrorTestObject Set and NotFound maps are nill - tc.errExpected = (errTest.Set != nil || errTest.NotFound != nil) && tc.name != "Delete" + tc.errExpected = (errTest.Set != nil || errTest.NotFound != nil) && tc.name == "Bootstrapping" // the add and modify events should only be added when there are no 'simulated' errors - if (errTest.Set == nil && errTest.NotFound == nil) && tc.name != "Delete" { + if (errTest.Set == nil && errTest.NotFound == nil) && tc.name == "Bootstrapping" { + //update finalizer + tc.expectedEvents = append(tc.expectedEvents, teMod) + //add daemonset tc.expectedEvents = append(tc.expectedEvents, teAdd) + //update status + tc.expectedEvents = append(tc.expectedEvents, teMod) + } + if /*(errTest.Set == nil && errTest.NotFound == nil) &&*/ tc.name == "Deleting" { + //update finalizer + tc.expectedEvents = append(tc.expectedEvents, teDel) + } + if (errTest.Set != nil || errTest.NotFound != nil) && tc.name == "Bootstrapping" { + //update finalizer tc.expectedEvents = append(tc.expectedEvents, teMod) } // special case for daemonset - if errTest.Set[dsObj] && tc.name != "Delete" { + if errTest.Set[dsObj] && tc.name == "Bootstrapping" { tc.expectedEvents = append(tc.expectedEvents, teAdd) } @@ -264,7 +273,7 @@ func TestReconcile(t *testing.T) { } } -// testRquest - used to create request +// // testRquest - used to create request func testRequest() ctrl.Request { return ctrl.Request{ NamespacedName: types.NamespacedName{ @@ -286,3 +295,12 @@ func testNodeObservability() *operatorv1alpha1.NodeObservability { }, } } + +func testNodeObservabilityToBeDeleted() *operatorv1alpha1.NodeObservability { + nobs := testNodeObservability() + nobs.Finalizers = append(nobs.Finalizers, finalizer) + nobs.DeletionTimestamp = &metav1.Time{ + Time: time.Now(), + } + return nobs +} diff --git a/pkg/operator/controller/nodeobservability/daemonset.go b/pkg/operator/controller/nodeobservability/daemonset.go index 664c043b..7e1be068 100644 --- a/pkg/operator/controller/nodeobservability/daemonset.go +++ b/pkg/operator/controller/nodeobservability/daemonset.go @@ -9,7 +9,6 @@ import ( "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" v1alpha1 "github.com/openshift/node-observability-operator/api/v1alpha1" ) @@ -39,8 +38,6 @@ func (r *NodeObservabilityReconciler) ensureDaemonSet(ctx context.Context, nodeO } return r.currentDaemonSet(ctx, nameSpace) } - // Set NodeObservability instance as the owner and controller - err = ctrl.SetControllerReference(nodeObs, desired, r.Scheme) return true, current, err } @@ -80,6 +77,14 @@ func (r *NodeObservabilityReconciler) desiredDaemonSet(nodeObs *v1alpha1.NodeObs ObjectMeta: metav1.ObjectMeta{ Name: daemonSetName, Namespace: nodeObs.Namespace, + OwnerReferences: []metav1.OwnerReference{ + { + Name: nodeObs.Name, + Kind: nodeObs.Kind, + UID: nodeObs.UID, + APIVersion: nodeObs.APIVersion, + }, + }, }, Spec: appsv1.DaemonSetSpec{ Selector: &metav1.LabelSelector{ diff --git a/pkg/operator/controller/nodeobservability/daemonset_test.go b/pkg/operator/controller/nodeobservability/daemonset_test.go index b68e7ed4..e8a87841 100644 --- a/pkg/operator/controller/nodeobservability/daemonset_test.go +++ b/pkg/operator/controller/nodeobservability/daemonset_test.go @@ -133,16 +133,7 @@ func TestEnsureDaemonset(t *testing.T) { Log: zap.New(zap.UseDevMode(true)), } nodeObs := &operatorv1alpha1.NodeObservability{} - // ensure secret - _, secret, err := r.ensureSecret(context.TODO(), nodeObs) - if err != nil { - if !tc.errExpected { - t.Fatalf("unexpected error received: %v", err) - } - return - } - r.Log.Info(fmt.Sprintf("Secret : %s", secret.Name)) - _, serviceAccount, err := r.ensureServiceAccount(context.TODO(), nodeObs, secret) + _, serviceAccount, err := r.ensureServiceAccount(context.TODO(), nodeObs) if err != nil { if !tc.errExpected { t.Fatalf("unexpected error received: %v", err) diff --git a/pkg/operator/controller/nodeobservability/rbac.go b/pkg/operator/controller/nodeobservability/rbac.go index 8eba3280..1370974b 100644 --- a/pkg/operator/controller/nodeobservability/rbac.go +++ b/pkg/operator/controller/nodeobservability/rbac.go @@ -8,7 +8,6 @@ import ( "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" v1alpha1 "github.com/openshift/node-observability-operator/api/v1alpha1" ) @@ -47,8 +46,6 @@ func (r *NodeObservabilityReconciler) ensureClusterRole(ctx context.Context, nod } return r.currentClusterRole(ctx, nameSpace) } - // Set NodeObservability instance as the owner and controller - err = ctrl.SetControllerReference(nodeObs, desired, r.Scheme) return true, current, err } @@ -122,8 +119,6 @@ func (r *NodeObservabilityReconciler) ensureClusterRoleBinding(ctx context.Conte } return r.currentClusterRoleBinding(ctx, nameSpace) } - // Set NodeObservability instance as the owner and controller - err = ctrl.SetControllerReference(nodeObs, desired, r.Scheme) return true, current, err } @@ -180,3 +175,27 @@ func (r *NodeObservabilityReconciler) desiredClusterRoleBinding(nodeObs *v1alpha func labelsForClusterRole(name string) map[string]string { return map[string]string{"scc": "node-observability-scc-role", "role": name} } + +func (r *NodeObservabilityReconciler) deleteClusterRole(nodeObs *v1alpha1.NodeObservability) error { + cr := &rbacv1.ClusterRole{} + cr.Name = clusterRoleName + if err := r.Client.Delete(context.TODO(), cr); err != nil { + if errors.IsNotFound(err) { + return nil + } + return err + } + return nil +} + +func (r *NodeObservabilityReconciler) deleteClusterRoleBinding(nodeObs *v1alpha1.NodeObservability) error { + crb := &rbacv1.ClusterRoleBinding{} + crb.Name = clusterRoleBindingName + if err := r.Client.Delete(context.TODO(), crb); err != nil { + if errors.IsNotFound(err) { + return nil + } + return err + } + return nil +} diff --git a/pkg/operator/controller/nodeobservability/rbac_test.go b/pkg/operator/controller/nodeobservability/rbac_test.go index 006210fd..ec3c309c 100644 --- a/pkg/operator/controller/nodeobservability/rbac_test.go +++ b/pkg/operator/controller/nodeobservability/rbac_test.go @@ -22,7 +22,9 @@ import ( "testing" rbacv1 "k8s.io/api/rbac/v1" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -32,57 +34,176 @@ import ( "github.com/openshift/node-observability-operator/pkg/operator/controller/test" ) -func TestEnsureClusterRole(t *testing.T) { - makeClusterRole := func() *rbacv1.ClusterRole { - nodeObs := &operatorv1alpha1.NodeObservability{} - clusterRole := rbacv1.ClusterRole{ - ObjectMeta: metav1.ObjectMeta{ - Name: clusterRoleName, - Namespace: nodeObs.Namespace, - Labels: labelsForClusterRole(clusterRoleName), +func makeClusterRole() *rbacv1.ClusterRole { + nodeObs := &operatorv1alpha1.NodeObservability{} + clusterRole := rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: clusterRoleName, + Namespace: nodeObs.Namespace, + Labels: labelsForClusterRole(clusterRoleName), + }, + Rules: []rbacv1.PolicyRule{ + { + APIGroups: []string{secGroup}, + Resources: []string{secResource}, + ResourceNames: []string{secResourceName}, + Verbs: []string{use}, }, - Rules: []rbacv1.PolicyRule{ - { - APIGroups: []string{secGroup}, - Resources: []string{secResource}, - ResourceNames: []string{secResourceName}, - Verbs: []string{use}, - }, - { - Verbs: []string{get, list}, - APIGroups: []string{""}, - Resources: []string{nodes, nodesProxy, pods}, - }, - { - Verbs: []string{get}, - NonResourceURLs: []string{url}, - }, + { + Verbs: []string{get, list}, + APIGroups: []string{""}, + Resources: []string{nodes, nodesProxy, pods}, }, - } - return &clusterRole + { + Verbs: []string{get}, + NonResourceURLs: []string{url}, + }, + }, } - makeClusterRoleBinding := func() *rbacv1.ClusterRoleBinding { - nodeObs := &operatorv1alpha1.NodeObservability{} - clusterRoleBinding := rbacv1.ClusterRoleBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: clusterRoleBindingName, - Namespace: nodeObs.Namespace, + return &clusterRole +} + +func makeClusterRoleBinding() *rbacv1.ClusterRoleBinding { + nodeObs := &operatorv1alpha1.NodeObservability{} + clusterRoleBinding := rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: clusterRoleBindingName, + Namespace: nodeObs.Namespace, + }, + Subjects: []rbacv1.Subject{ + { + Kind: serviceAccount, + Name: serviceAccountName, + Namespace: test.TestNamespace, }, - Subjects: []rbacv1.Subject{ - { - Kind: serviceAccount, - Name: serviceAccountName, - Namespace: test.TestNamespace, - }, + }, + RoleRef: rbacv1.RoleRef{ + Kind: clusterRole, + Name: clusterRoleName, + APIGroup: apiGroup, + }, + } + return &clusterRoleBinding +} +func TestDeleteClusterRole(t *testing.T) { + testCasesClusterRole := []struct { + name string + existingObjects []runtime.Object + expectedExist bool + errExpected bool + }{ + { + name: "Does not exist", + existingObjects: []runtime.Object{}, + errExpected: false, + expectedExist: false, + }, + { + name: "Exists", + existingObjects: []runtime.Object{ + makeClusterRole(), }, - RoleRef: rbacv1.RoleRef{ - Kind: clusterRole, - Name: clusterRoleName, - APIGroup: apiGroup, + expectedExist: false, + errExpected: false, + }, + } + testCasesClusterRoleBinding := []struct { + name string + existingObjects []runtime.Object + expectedExist bool + errExpected bool + }{ + { + name: "Does not exist", + existingObjects: []runtime.Object{}, + errExpected: false, + expectedExist: false, + }, + { + name: "Exists", + existingObjects: []runtime.Object{ + makeClusterRoleBinding(), }, - } - return &clusterRoleBinding + expectedExist: false, + errExpected: false, + }, + } + + for _, tc := range testCasesClusterRole { + t.Run(tc.name, func(t *testing.T) { + cl := fake.NewClientBuilder().WithRuntimeObjects(tc.existingObjects...).Build() + r := &NodeObservabilityReconciler{ + Client: cl, + Scheme: test.Scheme, + Log: zap.New(zap.UseDevMode(true)), + } + nodeObs := testNodeObservability() + err := r.deleteClusterRole(nodeObs) + if err != nil { + if !tc.errExpected { + t.Fatalf("unexpected error received: %v", err) + } + return + } + if tc.errExpected { + t.Fatalf("Error expected but wasn't received") + } + name := types.NamespacedName{ + Namespace: nodeObs.Namespace, + Name: clusterRoleName, + } + err = cl.Get(context.TODO(), name, &rbacv1.ClusterRole{}) + gotExist := true + if errors.IsNotFound(err) { + gotExist = false + } else if !tc.errExpected { + t.Fatalf("unexpected error received: %v", err) + } + if gotExist != tc.expectedExist { + t.Errorf("expected clusterrole's exist to be %t, got %t", tc.expectedExist, gotExist) + } + }) + } + + for _, tc := range testCasesClusterRoleBinding { + t.Run(tc.name, func(t *testing.T) { + cl := fake.NewClientBuilder().WithRuntimeObjects(tc.existingObjects...).Build() + r := &NodeObservabilityReconciler{ + Client: cl, + Scheme: test.Scheme, + Log: zap.New(zap.UseDevMode(true)), + } + nodeObs := testNodeObservability() + err := r.deleteClusterRoleBinding(nodeObs) + if err != nil { + if !tc.errExpected { + t.Fatalf("unexpected error received: %v", err) + } + return + } + if tc.errExpected { + t.Fatalf("Error expected but wasn't received") + } + name := types.NamespacedName{ + Namespace: nodeObs.Namespace, + Name: clusterRoleBindingName, + } + err = cl.Get(context.TODO(), name, &rbacv1.ClusterRoleBinding{}) + gotExist := true + if errors.IsNotFound(err) { + gotExist = false + } else if !tc.errExpected { + t.Fatalf("unexpected error received: %v", err) + } + if gotExist != tc.expectedExist { + t.Errorf("expected clusterrolebinding's exist to be %t, got %t", tc.expectedExist, gotExist) + } + }) } +} + +func TestEnsureClusterRole(t *testing.T) { + testCasesClusterRole := []struct { name string existingObjects []runtime.Object @@ -161,23 +282,14 @@ func TestEnsureClusterRole(t *testing.T) { Log: zap.New(zap.UseDevMode(true)), } nodeObs := &operatorv1alpha1.NodeObservability{} - // ensure secret - _, secret, err := r.ensureSecret(context.TODO(), nodeObs) - if err != nil { - if !tc.errExpected { - t.Fatalf("unexpected error received: %v", err) - } - return - } - r.Log.Info(fmt.Sprintf("Secret : %s", secret.Name)) - _, serviceAccount, err := r.ensureServiceAccount(context.TODO(), nodeObs, secret) + _, serviceAccount, err := r.ensureServiceAccount(context.TODO(), nodeObs) if err != nil { if !tc.errExpected { t.Fatalf("unexpected error received: %v", err) } return } - r.Log.Info(fmt.Sprintf("Secret : %s", serviceAccount.Name)) + r.Log.Info(fmt.Sprintf("ServiceAccount : %s", serviceAccount.Name)) gotExist, _, err := r.ensureClusterRoleBinding(context.TODO(), nodeObs, serviceAccount.Name) if err != nil { diff --git a/pkg/operator/controller/nodeobservability/scc.go b/pkg/operator/controller/nodeobservability/scc.go index 09fe3d68..ef5efb80 100644 --- a/pkg/operator/controller/nodeobservability/scc.go +++ b/pkg/operator/controller/nodeobservability/scc.go @@ -9,7 +9,6 @@ import ( "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" v1alpha1 "github.com/openshift/node-observability-operator/api/v1alpha1" ) @@ -33,8 +32,6 @@ func (r *NodeObservabilityReconciler) ensureSecurityContextConstraints(ctx conte } return r.currentSecurityContextConstraints(ctx, nodeObs) } - // Set NodeObservability instance as the owner and controller - err = ctrl.SetControllerReference(nodeObs, desired, r.Scheme) return true, current, err } @@ -102,3 +99,15 @@ func (r *NodeObservabilityReconciler) desiredSecurityContextConstraints(nodeObs } return scc } + +func (r *NodeObservabilityReconciler) deleteSecurityContextConstraints(nodeObs *v1alpha1.NodeObservability) error { + scc := &securityv1.SecurityContextConstraints{} + scc.Name = sccName + if err := r.Client.Delete(context.TODO(), scc); err != nil { + if errors.IsNotFound(err) { + return nil + } + return err + } + return nil +} diff --git a/pkg/operator/controller/nodeobservability/scc_test.go b/pkg/operator/controller/nodeobservability/scc_test.go index ca5cb4b5..ada6c960 100644 --- a/pkg/operator/controller/nodeobservability/scc_test.go +++ b/pkg/operator/controller/nodeobservability/scc_test.go @@ -22,8 +22,10 @@ import ( securityv1 "github.com/openshift/api/security/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/log/zap" @@ -31,44 +33,45 @@ import ( test "github.com/openshift/node-observability-operator/pkg/operator/controller/test" ) -func TestEnsureScc(t *testing.T) { +func makeScc() *securityv1.SecurityContextConstraints { var priority int32 = 10 nodeObs := &operatorv1alpha1.NodeObservability{} - makeScc := func() *securityv1.SecurityContextConstraints { - scc := securityv1.SecurityContextConstraints{ - ObjectMeta: metav1.ObjectMeta{ - Name: sccName, - Namespace: nodeObs.Namespace, - }, - AllowPrivilegedContainer: true, - AllowHostIPC: false, - AllowHostNetwork: true, - AllowHostPID: false, - AllowHostPorts: false, - // This allows us to mount the hosts /var/run/crio/crio.sock into the container - AllowHostDirVolumePlugin: true, - AllowedCapabilities: nil, - DefaultAddCapabilities: nil, - FSGroup: securityv1.FSGroupStrategyOptions{ - Type: securityv1.FSGroupStrategyRunAsAny, - }, - Groups: []string{"system:cluster-admins", "system:nodes"}, - Priority: &priority, - ReadOnlyRootFilesystem: false, - RequiredDropCapabilities: []corev1.Capability{"MKNOD"}, - RunAsUser: securityv1.RunAsUserStrategyOptions{ - Type: securityv1.RunAsUserStrategyRunAsAny, - }, - SELinuxContext: securityv1.SELinuxContextStrategyOptions{ - Type: securityv1.SELinuxStrategyMustRunAs, - }, - SupplementalGroups: securityv1.SupplementalGroupsStrategyOptions{ - Type: securityv1.SupplementalGroupsStrategyRunAsAny, - }, - Volumes: []securityv1.FSType{securityv1.FSTypeHostPath, securityv1.FSTypeSecret}, - } - return &scc + scc := securityv1.SecurityContextConstraints{ + ObjectMeta: metav1.ObjectMeta{ + Name: sccName, + Namespace: nodeObs.Namespace, + }, + AllowPrivilegedContainer: true, + AllowHostIPC: false, + AllowHostNetwork: true, + AllowHostPID: false, + AllowHostPorts: false, + // This allows us to mount the hosts /var/run/crio/crio.sock into the container + AllowHostDirVolumePlugin: true, + AllowedCapabilities: nil, + DefaultAddCapabilities: nil, + FSGroup: securityv1.FSGroupStrategyOptions{ + Type: securityv1.FSGroupStrategyRunAsAny, + }, + Groups: []string{"system:cluster-admins", "system:nodes"}, + Priority: &priority, + ReadOnlyRootFilesystem: false, + RequiredDropCapabilities: []corev1.Capability{"MKNOD"}, + RunAsUser: securityv1.RunAsUserStrategyOptions{ + Type: securityv1.RunAsUserStrategyRunAsAny, + }, + SELinuxContext: securityv1.SELinuxContextStrategyOptions{ + Type: securityv1.SELinuxStrategyMustRunAs, + }, + SupplementalGroups: securityv1.SupplementalGroupsStrategyOptions{ + Type: securityv1.SupplementalGroupsStrategyRunAsAny, + }, + Volumes: []securityv1.FSType{securityv1.FSTypeHostPath, securityv1.FSTypeSecret}, } + return &scc +} +func TestEnsureScc(t *testing.T) { + testCases := []struct { name string existingObjects []runtime.Object @@ -117,3 +120,63 @@ func TestEnsureScc(t *testing.T) { }) } } + +func TestDeleteSCC(t *testing.T) { + testCasesSCC := []struct { + name string + existingObjects []runtime.Object + expectedExist bool + errExpected bool + }{ + { + name: "Does not exist", + existingObjects: []runtime.Object{}, + errExpected: false, + expectedExist: false, + }, + { + name: "Exists", + existingObjects: []runtime.Object{ + makeScc(), + }, + expectedExist: false, + errExpected: false, + }, + } + + for _, tc := range testCasesSCC { + t.Run(tc.name, func(t *testing.T) { + cl := fake.NewClientBuilder().WithScheme(test.Scheme).WithRuntimeObjects(tc.existingObjects...).Build() + r := &NodeObservabilityReconciler{ + Client: cl, + Scheme: test.Scheme, + Log: zap.New(zap.UseDevMode(true)), + } + nodeObs := testNodeObservability() + err := r.deleteSecurityContextConstraints(nodeObs) + if err != nil { + if !tc.errExpected { + t.Fatalf("unexpected error received: %v", err) + } + return + } + if tc.errExpected { + t.Fatalf("Error expected but wasn't received") + } + name := types.NamespacedName{ + Namespace: nodeObs.Namespace, + Name: sccName, + } + err = cl.Get(context.TODO(), name, &securityv1.SecurityContextConstraints{}) + gotExist := true + if errors.IsNotFound(err) { + gotExist = false + } else if !tc.errExpected { + t.Fatalf("unexpected error received: %v", err) + } + if gotExist != tc.expectedExist { + t.Errorf("expected SCC's exist to be %t, got %t", tc.expectedExist, gotExist) + } + }) + } +} diff --git a/pkg/operator/controller/nodeobservability/secret.go b/pkg/operator/controller/nodeobservability/secret.go deleted file mode 100644 index 95f60388..00000000 --- a/pkg/operator/controller/nodeobservability/secret.go +++ /dev/null @@ -1,82 +0,0 @@ -package nodeobservabilitycontroller - -import ( - "context" - "fmt" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - - v1alpha1 "github.com/openshift/node-observability-operator/api/v1alpha1" -) - -const ( - secretName = "node-observability-secret" -) - -// ensureSecret ensures that the secret exists -// Returns a Boolean value indicating whether it exists, a pointer to the -// secret and an error when relevant -func (r *NodeObservabilityReconciler) ensureSecret(ctx context.Context, nodeObs *v1alpha1.NodeObservability) (bool, *corev1.Secret, error) { - nameSpace := types.NamespacedName{Namespace: nodeObs.Namespace, Name: secretName} - desired := r.desiredSecret(nodeObs) - exist, current, err := r.currentSecret(ctx, nameSpace) - if err != nil { - return false, nil, fmt.Errorf("failed to get Secret: %v", err) - } - if !exist { - if err := r.createSecret(ctx, desired); err != nil { - return false, nil, err - } - return r.currentSecret(ctx, nameSpace) - } - // Set NodeObservability instance as the owner and controller - err = ctrl.SetControllerReference(nodeObs, desired, r.Scheme) - return true, current, err -} - -// currentSecret checks that the serviceaccount exists -func (r *NodeObservabilityReconciler) currentSecret(ctx context.Context, nameSpace types.NamespacedName) (bool, *corev1.Secret, error) { - secret := &corev1.Secret{} - if err := r.Get(ctx, nameSpace, secret); err != nil || r.Err.Set[secretObj] { - if errors.IsNotFound(err) || r.Err.NotFound[secretObj] { - return false, nil, nil - } - if r.Err.Set[secretObj] { - err = fmt.Errorf("failed to get Secret: simulated error") - } - return false, nil, err - } - return true, secret, nil -} - -// createSecret creates the serviceaccount -func (r *NodeObservabilityReconciler) createSecret(ctx context.Context, secret *corev1.Secret) error { - if err := r.Create(ctx, secret); err != nil { - return fmt.Errorf("failed to create Secret %s/%s: %w", secret.Namespace, secret.Name, err) - } - r.Log.Info("created Secret", "Secret.Namespace", secret.Namespace, "Secret.Name", secret.Name) - return nil -} - -// desiredSecret returns a Secret object -func (r *NodeObservabilityReconciler) desiredSecret(nodeObs *v1alpha1.NodeObservability) *corev1.Secret { - - s := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: nodeObs.Namespace, - Name: secretName, - Annotations: annotationsForSecret(), - }, - Type: corev1.SecretTypeServiceAccountToken, - } - return s -} - -// annotationsForSecret returns the annotations for the secret -func annotationsForSecret() map[string]string { - return map[string]string{"kubernetes.io/service-account.name": "profiling"} -} diff --git a/pkg/operator/controller/nodeobservability/secret_test.go b/pkg/operator/controller/nodeobservability/secret_test.go deleted file mode 100644 index af2de314..00000000 --- a/pkg/operator/controller/nodeobservability/secret_test.go +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright 2021. - -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. -*/ - -package nodeobservabilitycontroller - -import ( - "context" - "testing" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - fake "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - operatorv1alpha1 "github.com/openshift/node-observability-operator/api/v1alpha1" - test "github.com/openshift/node-observability-operator/pkg/operator/controller/test" -) - -func TestEnsureSecret(t *testing.T) { - nodeObs := &operatorv1alpha1.NodeObservability{} - makeSecret := func() *corev1.Secret { - secret := corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: nodeObs.Namespace, - Name: secretName, - Annotations: annotationsForSecret(), - }, - Type: corev1.SecretTypeServiceAccountToken, - } - return &secret - - } - testCases := []struct { - name string - existingObjects []runtime.Object - expectedExist bool - expectedSecret *corev1.Secret - errExpected bool - }{ - { - name: "Does not exist", - existingObjects: []runtime.Object{}, - expectedExist: true, - expectedSecret: makeSecret(), - }, - { - name: "Exists", - existingObjects: []runtime.Object{ - makeSecret(), - }, - expectedExist: true, - expectedSecret: makeSecret(), - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - cl := fake.NewClientBuilder().WithRuntimeObjects(tc.existingObjects...).Build() - r := &NodeObservabilityReconciler{ - Client: cl, - Scheme: test.Scheme, - Log: zap.New(zap.UseDevMode(true)), - } - nodeObs := &operatorv1alpha1.NodeObservability{} - gotExist, _, err := r.ensureSecret(context.TODO(), nodeObs) - if err != nil { - if !tc.errExpected { - t.Fatalf("unexpected error received: %v", err) - } - return - } - if tc.errExpected { - t.Fatalf("Error expected but wasn't received") - } - if gotExist != tc.expectedExist { - t.Errorf("expected service account's exist to be %t, got %t", tc.expectedExist, gotExist) - } - }) - } -} diff --git a/pkg/operator/controller/nodeobservability/serviceaccount.go b/pkg/operator/controller/nodeobservability/serviceaccount.go index 254995de..6df9633a 100644 --- a/pkg/operator/controller/nodeobservability/serviceaccount.go +++ b/pkg/operator/controller/nodeobservability/serviceaccount.go @@ -8,7 +8,6 @@ import ( "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" v1alpha1 "github.com/openshift/node-observability-operator/api/v1alpha1" ) @@ -20,9 +19,9 @@ const ( // ensureServiceAccount ensures that the serviceaccount exists // Returns a Boolean value indicating whether it exists, a pointer to the // serviceaccount and an error when relevant -func (r *NodeObservabilityReconciler) ensureServiceAccount(ctx context.Context, nodeObs *v1alpha1.NodeObservability, secret *corev1.Secret) (bool, *corev1.ServiceAccount, error) { +func (r *NodeObservabilityReconciler) ensureServiceAccount(ctx context.Context, nodeObs *v1alpha1.NodeObservability) (bool, *corev1.ServiceAccount, error) { nameSpace := types.NamespacedName{Namespace: nodeObs.Namespace, Name: serviceAccountName} - desired := r.desiredServiceAccount(nodeObs, secret) + desired := r.desiredServiceAccount(nodeObs) exist, current, err := r.currentServiceAccount(ctx, nameSpace) if err != nil { return false, nil, fmt.Errorf("failed to get ServiceAccount: %v", err) @@ -33,8 +32,6 @@ func (r *NodeObservabilityReconciler) ensureServiceAccount(ctx context.Context, } return r.currentServiceAccount(ctx, nameSpace) } - // Set NodeObservability instance as the owner and controller - err = ctrl.SetControllerReference(nodeObs, desired, r.Scheme) return true, current, err } @@ -63,16 +60,21 @@ func (r *NodeObservabilityReconciler) createServiceAccount(ctx context.Context, } // desiredServiceAccount returns a serviceaccount object -func (r *NodeObservabilityReconciler) desiredServiceAccount(nodeObs *v1alpha1.NodeObservability, secret *corev1.Secret) *corev1.ServiceAccount { +func (r *NodeObservabilityReconciler) desiredServiceAccount(nodeObs *v1alpha1.NodeObservability) *corev1.ServiceAccount { sa := &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Namespace: nodeObs.Namespace, Name: serviceAccountName, + OwnerReferences: []metav1.OwnerReference{ + { + Name: nodeObs.Name, + Kind: nodeObs.Kind, + UID: nodeObs.UID, + APIVersion: nodeObs.APIVersion, + }, + }, }, - Secrets: []corev1.ObjectReference{{ - Name: secret.Name, - }}, } return sa } diff --git a/pkg/operator/controller/nodeobservability/serviceaccount_test.go b/pkg/operator/controller/nodeobservability/serviceaccount_test.go index 4e11c0f9..2483bde2 100644 --- a/pkg/operator/controller/nodeobservability/serviceaccount_test.go +++ b/pkg/operator/controller/nodeobservability/serviceaccount_test.go @@ -18,7 +18,6 @@ package nodeobservabilitycontroller import ( "context" - "fmt" "testing" corev1 "k8s.io/api/core/v1" @@ -40,9 +39,6 @@ func TestEnsureServiceAccount(t *testing.T) { Name: serviceAccountName, Namespace: nodeObs.Namespace, }, - Secrets: []corev1.ObjectReference{{ - Name: test.SecretName, - }}, } return &sa } @@ -78,17 +74,8 @@ func TestEnsureServiceAccount(t *testing.T) { Log: zap.New(zap.UseDevMode(true)), } nodeObs := &operatorv1alpha1.NodeObservability{} - // ensure secret - _, secret, err := r.ensureSecret(context.TODO(), nodeObs) - if err != nil { - if !tc.errExpected { - t.Fatalf("unexpected error received: %v", err) - } - return - } - r.Log.Info(fmt.Sprintf("Secret : %s", secret.Name)) - gotExist, _, err := r.ensureServiceAccount(context.TODO(), nodeObs, secret) + gotExist, _, err := r.ensureServiceAccount(context.TODO(), nodeObs) if err != nil { if !tc.errExpected { t.Fatalf("unexpected error received: %v", err) diff --git a/pkg/operator/controller/nodeobservability/simulate-error-schema.go b/pkg/operator/controller/nodeobservability/simulate-error-schema.go index 9e850202..4da687e8 100644 --- a/pkg/operator/controller/nodeobservability/simulate-error-schema.go +++ b/pkg/operator/controller/nodeobservability/simulate-error-schema.go @@ -1,12 +1,11 @@ package nodeobservabilitycontroller const ( - saObj = "serviceaccount" - sccObj = "securitycontextconstraint" - crObj = "clusterrole" - crbObj = "clusterrolebinding" - secretObj = "secret" - dsObj = "daemonset" + saObj = "serviceaccount" + sccObj = "securitycontextconstraint" + crObj = "clusterrole" + crbObj = "clusterrolebinding" + dsObj = "daemonset" ) // ErrTestObject - simple struct used to inject errors for testing