Repository: kubernetes-sigs/security-profiles-operator
Pull request #206 (2021-01-18 12:00:51)

Use typed bindata for DaemonSet


#### What type of PR is this?

/kind cleanup


#### What this PR does / why we need it:
This allows us more type-safe refactorings and reduces some possible
error paths per design.
#### Which issue(s) this PR fixes:

<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.

Fixes #

or

None
-->
None
#### Special notes for your reviewer:
None
#### Does this PR introduce a user-facing change?

<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".

For more information on release notes see: https://git.k8s.io/community/contributors/guide/release-notes.md
-->

```release-note
None
```


k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/206#" title="Author self-approved">saschagrunert</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fsecurity-profiles-operator).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubernetes-sigs/security-profiles-operator/blob/master/OWNERS)~~ [saschagrunert]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
k8s-ci-robot: @saschagrunert: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-test-e2e | bbfbf6b2a6ea143b44eef8633169ea4ac9d301dd | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/206/pull-security-profiles-operator-test-e2e/1351137478756536320) | `/test pull-security-profiles-operator-test-e2e`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=206). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Asaschagrunert). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @JAORMX: changing LGTM is restricted to collaborators

<details>

In response to [this](https://github.com/kubernetes-sigs/security-profiles-operator/pull/206#pullrequestreview-570438887):

>/lgtm


Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
JAORMX: One reason why I initially submitted this with yaml format as opposed to the straight library-go implementation was that I was hoping that once we upgrade to go 1.16, we could use the new go file embedding and start linting the daemon yaml with a standard kubernetes linter. But I'm not opposed to this change.
k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/206#pullrequestreview-570466881" title="Approved">jhrozek</a>*, *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/206#" title="Author self-approved">saschagrunert</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fsecurity-profiles-operator).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubernetes-sigs/security-profiles-operator/blob/master/OWNERS)~~ [saschagrunert]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/.gitignore b/.gitignore
index 897bb1b07..6a06c1a94 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 *.orig
 build
+.idea
diff --git a/OWNERS b/OWNERS
index 75c799295..a246eeca7 100644
--- a/OWNERS
+++ b/OWNERS
@@ -6,3 +6,4 @@ approvers:
   - saschagrunert
 reviewers:
   - cmurphy
+  - JAORMX
diff --git a/api/seccompprofile/v1alpha1/seccompprofile_types.go b/api/seccompprofile/v1alpha1/seccompprofile_types.go
index e6f4d54b0..89285090a 100644
--- a/api/seccompprofile/v1alpha1/seccompprofile_types.go
+++ b/api/seccompprofile/v1alpha1/seccompprofile_types.go
@@ -28,7 +28,6 @@ type SeccompProfileSpec struct {
 	TargetWorkload string `json:"targetWorkload"`
 
 	// name of base profile (in the same namespace) what will be unioned into this profile
-	//nolint:lll
 	BaseProfileName string `json:"baseProfileName,omitempty"`
 
 	// Properties from containers/common/pkg/seccomp.Seccomp type
diff --git a/api/seccompprofile/v1alpha1/zz_generated.deepcopy.go b/api/seccompprofile/v1alpha1/zz_generated.deepcopy.go
index bcf65b3cd..6f1e34541 100644
--- a/api/seccompprofile/v1alpha1/zz_generated.deepcopy.go
+++ b/api/seccompprofile/v1alpha1/zz_generated.deepcopy.go
@@ -1,7 +1,7 @@
 // +build !ignore_autogenerated
 
 /*
-Copyright 2020 The Kubernetes Authors.
+Copyright 2021 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/selinuxpolicy/v1alpha1/zz_generated.deepcopy.go b/api/selinuxpolicy/v1alpha1/zz_generated.deepcopy.go
index 3255eda16..af4287ced 100644
--- a/api/selinuxpolicy/v1alpha1/zz_generated.deepcopy.go
+++ b/api/selinuxpolicy/v1alpha1/zz_generated.deepcopy.go
@@ -1,7 +1,7 @@
 // +build !ignore_autogenerated
 
 /*
-Copyright 2020 The Kubernetes Authors.
+Copyright 2021 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/cmd/security-profiles-operator/main.go b/cmd/security-profiles-operator/main.go
index dadbb9b42..5ba08c74f 100644
--- a/cmd/security-profiles-operator/main.go
+++ b/cmd/security-profiles-operator/main.go
@@ -175,9 +175,10 @@ func getTunables() (spod.DaemonTunables, error) {
 	if operatorImage == "" {
 		return dt, errors.New("invalid operator image")
 	}
+
 	nonRootEnableImage := os.Getenv(nonRootEnablerImageKey)
-	if operatorImage == "" {
-		return dt, errors.New("invalid operator image")
+	if nonRootEnableImage == "" {
+		return dt, errors.New("invalid non-root enabler image")
 	}
 
 	dt.DaemonImage = operatorImage
diff --git a/internal/pkg/controllers/spod/bindata/bindata.go b/internal/pkg/controllers/spod/bindata/bindata.go
deleted file mode 100644
index ec293cc69..000000000
--- a/internal/pkg/controllers/spod/bindata/bindata.go
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-Copyright 2020 The Kubernetes Authors.
-
-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 bindata
-
-import (
-	"fmt"
-	"strings"
-
-	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
-	k8syaml "k8s.io/apimachinery/pkg/util/yaml"
-)
-
-func rawObjectToUnstructured(in string) (*unstructured.Unstructured, error) {
-	obj := &unstructured.Unstructured{}
-	dec := k8syaml.NewYAMLToJSONDecoder(strings.NewReader(in))
-	if err := dec.Decode(obj); err != nil {
-		return nil, fmt.Errorf("couldn't decode YAML: %w", err)
-	}
-	return obj, nil
-}
diff --git a/internal/pkg/controllers/spod/bindata/spod.go b/internal/pkg/controllers/spod/bindata/spod.go
index 8dd24cfa7..dc2bc4b4f 100644
--- a/internal/pkg/controllers/spod/bindata/spod.go
+++ b/internal/pkg/controllers/spod/bindata/spod.go
@@ -17,157 +17,219 @@ limitations under the License.
 package bindata
 
 import (
-	"fmt"
-
 	appsv1 "k8s.io/api/apps/v1"
-	"k8s.io/apimachinery/pkg/runtime"
+	v1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/api/resource"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	"sigs.k8s.io/security-profiles-operator/internal/pkg/config"
 )
 
-// NOTE(jaosorior): We should switch this for a proper bindata solution.
-// nolint: lll
-const spodManifest = `---
-apiVersion: apps/v1
-kind: DaemonSet
-metadata:
-  name: security-profiles-operator
-  namespace: security-profiles-operator
-spec:
-  selector:
-    matchLabels:
-      app: spod
-  template:
-    metadata:
-      annotations:
-        openshift.io/scc: privileged
-        seccomp.security.alpha.kubernetes.io/pod: runtime/default
-        container.seccomp.security.alpha.kubernetes.io/security-profiles-operator: localhost/security-profiles-operator.json
-      labels:
-        app: spod
-    spec:
-      serviceAccountName: security-profiles-operator
-      initContainers:
-        - name: non-root-enabler
-          image: bash
-          # Creates folder /var/lib/security-profiles-operator, sets 2000:2000 as its
-          # owner and symlink it to /var/lib/kubelet/seccomp/operator. This is
-          # required to allow the main container to run as non-root.
-          command: [bash, -c]
-          args:
-            - |+
-              set -euo pipefail
+var (
+	falsely                         = false
+	truly                           = true
+	userRoot                  int64 = 0
+	userRootless              int64 = 2000
+	hostPathDirectory               = v1.HostPathDirectory
+	hostPathDirectoryOrCreate       = v1.HostPathDirectoryOrCreate
+)
 
-              if [ ! -d $KUBELET_SECCOMP_ROOT ]; then
-                /bin/mkdir -m 0744 -p $KUBELET_SECCOMP_ROOT
-              fi
+var Manifest = &appsv1.DaemonSet{
+	ObjectMeta: metav1.ObjectMeta{
+		Name:      config.OperatorName,
+		Namespace: config.OperatorName,
+	},
+	Spec: appsv1.DaemonSetSpec{
+		Selector: &metav1.LabelSelector{
+			MatchLabels: map[string]string{"app": "spod"},
+		},
+		Template: v1.PodTemplateSpec{
+			ObjectMeta: metav1.ObjectMeta{
+				Annotations: map[string]string{
+					"openshift.io/scc":                         "privileged",
+					"seccomp.security.alpha.kubernetes.io/pod": "runtime/default",
+					"container.seccomp.security.alpha.kubernetes.io/security-profiles-operator": "localhost/security-profiles-operator.json", // nolint: lll
+				},
+				Labels: map[string]string{
+					"app": "spod",
+				},
+			},
+			Spec: v1.PodSpec{
+				ServiceAccountName: config.OperatorName,
+				InitContainers: []v1.Container{{
+					Name:  "non-root-enabler",
+					Image: "bash:5.0",
+					// Creates directory /var/lib/security-profiles-operator,
+					// sets 2000:2000 as its owner and symlink it to
+					// /var/lib/kubelet/seccomp/operator. This is required
+					// to allow the main container to run as non-root.
+					Command: []string{"bash", "-c"},
+					Args: []string{`
+						set -euo pipefail
 
-              /bin/mkdir -p $OPERATOR_ROOT
-              /bin/chmod 0744 $OPERATOR_ROOT
+						if [ ! -d $KUBELET_SECCOMP_ROOT ]; then
+							/bin/mkdir -m 0744 -p $KUBELET_SECCOMP_ROOT
+						fi
 
-              if [ ! -L $OPERATOR_SYMLINK ]; then
-                /bin/ln -s $OPERATOR_ROOT $OPERATOR_SYMLINK
-              fi
+						/bin/mkdir -p $OPERATOR_ROOT
+						/bin/chmod 0744 $OPERATOR_ROOT
 
-              /bin/chown -R 2000:2000 $OPERATOR_ROOT
-              cp -f -v /opt/seccomp-profiles/* $KUBELET_SECCOMP_ROOT
-          env:
-            - name: KUBELET_SECCOMP_ROOT
-              value: /var/lib/kubelet/seccomp
-            - name: OPERATOR_SYMLINK
-              value: $(KUBELET_SECCOMP_ROOT)/operator
-            - name: OPERATOR_ROOT
-              value: /var/lib/security-profiles-operator
-          volumeMounts:
-            - name: host-varlib-volume
-              mountPath: /var/lib
-            - name: profile-configmap-volume
-              mountPath: /opt/seccomp-profiles
-              readOnly: true
-          securityContext:
-            allowPrivilegeEscalation: false
-            readOnlyRootFilesystem: true
-            capabilities:
-              drop: ["ALL"]
-              add: ["CHOWN", "FOWNER", "FSETID", "DAC_OVERRIDE"]
-            runAsUser: 0
-            seLinuxOptions:
-              # FIXME(jaosorior): Use a more restricted selinux type
-              type: spc_t
-          resources:
-            requests:
-              memory: "32Mi"
-              cpu: "100m"
-              ephemeral-storage: "10Mi"
-            limits:
-              memory: "64Mi"
-              cpu: "250m"
-              ephemeral-storage: "50Mi"
-      containers:
-        - name: security-profiles-operator
-          image: security-profiles-operator
-          args:
-          - daemon
-          imagePullPolicy: Always
-          volumeMounts:
-          - name: host-operator-volume
-            mountPath: /var/lib/kubelet/seccomp/operator
-          securityContext:
-            allowPrivilegeEscalation: false
-            readOnlyRootFilesystem: true
-            runAsUser: 2000
-            runAsGroup: 2000
-            capabilities:
-              drop: ["ALL"]
-            seLinuxOptions:
-              # FIXME(jaosorior): Use a more restricted selinux type
-              type: spc_t
-          resources:
-            requests:
-              memory: "64Mi"
-              cpu: "100m"
-              ephemeral-storage: "50Mi"
-            limits:
-              memory: "128Mi"
-              cpu: "300m"
-              ephemeral-storage: "200Mi"
-          env:
-            - name: NODE_NAME
-              valueFrom:
-                fieldRef:
-                  fieldPath: spec.nodeName
-      volumes:
-      # /var/lib is used as symlinks cannot be created across different volumes
-      - name: host-varlib-volume
-        hostPath:
-          path: /var/lib
-          type: Directory
-      - name: host-operator-volume
-        hostPath:
-          path: /var/lib/security-profiles-operator
-          type: DirectoryOrCreate
-      - name: profile-configmap-volume
-        configMap:
-          name: security-profiles-operator-profile
-      tolerations:
-        - effect: NoSchedule
-          key: node-role.kubernetes.io/master
-        - effect: NoSchedule
-          key: node-role.kubernetes.io/control-plane
-        - effect: NoExecute
-          key: node.kubernetes.io/not-ready
-          operator: Exists
-      nodeSelector:
-        kubernetes.io/os: linux
-`
+						if [ ! -L $OPERATOR_SYMLINK ]; then
+							/bin/ln -s $OPERATOR_ROOT $OPERATOR_SYMLINK
+						fi
 
-func GetReferenceSPOd() (*appsv1.DaemonSet, error) {
-	rawDS, err := rawObjectToUnstructured(spodManifest)
-	if err != nil {
-		return nil, fmt.Errorf("error parsing DS manifest: %w", err)
-	}
-	spod := &appsv1.DaemonSet{}
-	err = runtime.DefaultUnstructuredConverter.FromUnstructured(rawDS.Object, spod)
-	if err != nil {
-		return nil, fmt.Errorf("error converting unstructured DS to implementation object: %w", err)
-	}
-	return spod, nil
+						/bin/chown -R 2000:2000 $OPERATOR_ROOT
+						cp -f -v /opt/seccomp-profiles/* $KUBELET_SECCOMP_ROOT
+					`},
+					Env: []v1.EnvVar{
+						{
+							Name:  "KUBELET_SECCOMP_ROOT",
+							Value: config.KubeletSeccompRootPath,
+						},
+						{
+							Name:  "OPERATOR_SYMLINK",
+							Value: "$(KUBELET_SECCOMP_ROOT)/operator",
+						},
+						{
+							Name:  "OPERATOR_ROOT",
+							Value: "/var/lib/security-profiles-operator",
+						},
+					},
+					VolumeMounts: []v1.VolumeMount{
+						{
+							Name:      "host-varlib-volume",
+							MountPath: "/var/lib",
+						},
+						{
+							Name:      "profile-configmap-volume",
+							MountPath: "/opt/seccomp-profiles",
+							ReadOnly:  true,
+						},
+					},
+					SecurityContext: &v1.SecurityContext{
+						AllowPrivilegeEscalation: &falsely,
+						ReadOnlyRootFilesystem:   &truly,
+						Capabilities: &v1.Capabilities{
+							Drop: []v1.Capability{"ALL"},
+							Add:  []v1.Capability{"CHOWN", "FOWNER", "FSETID", "DAC_OVERRIDE"},
+						},
+						RunAsUser: &userRoot,
+						SELinuxOptions: &v1.SELinuxOptions{
+							// TODO(jaosorior): Use a more restricted selinux type
+							Type: "spc_t",
+						},
+					},
+					Resources: v1.ResourceRequirements{
+						Requests: v1.ResourceList{
+							v1.ResourceMemory:           resource.MustParse("32Mi"),
+							v1.ResourceCPU:              resource.MustParse("100m"),
+							v1.ResourceEphemeralStorage: resource.MustParse("10Mi"),
+						},
+						Limits: v1.ResourceList{
+							v1.ResourceMemory:           resource.MustParse("64Mi"),
+							v1.ResourceCPU:              resource.MustParse("250m"),
+							v1.ResourceEphemeralStorage: resource.MustParse("50Mi"),
+						},
+					},
+				}},
+				Containers: []v1.Container{{
+					Name:            config.OperatorName,
+					Image:           config.OperatorName,
+					Args:            []string{"daemon"},
+					ImagePullPolicy: v1.PullAlways,
+					VolumeMounts: []v1.VolumeMount{
+						{
+							Name:      "host-operator-volume",
+							MountPath: config.ProfilesRootPath,
+						},
+					},
+					SecurityContext: &v1.SecurityContext{
+						AllowPrivilegeEscalation: &falsely,
+						ReadOnlyRootFilesystem:   &truly,
+						Capabilities: &v1.Capabilities{
+							Drop: []v1.Capability{"ALL"},
+						},
+						RunAsUser:  &userRootless,
+						RunAsGroup: &userRootless,
+						SELinuxOptions: &v1.SELinuxOptions{
+							// TODO(jaosorior): Use a more restricted selinux type
+							Type: "spc_t",
+						},
+					},
+					Resources: v1.ResourceRequirements{
+						Requests: v1.ResourceList{
+							v1.ResourceMemory:           resource.MustParse("64Mi"),
+							v1.ResourceCPU:              resource.MustParse("100m"),
+							v1.ResourceEphemeralStorage: resource.MustParse("50Mi"),
+						},
+						Limits: v1.ResourceList{
+							v1.ResourceMemory:           resource.MustParse("128Mi"),
+							v1.ResourceCPU:              resource.MustParse("300m"),
+							v1.ResourceEphemeralStorage: resource.MustParse("200Mi"),
+						},
+					},
+					Env: []v1.EnvVar{
+						{
+							Name: config.NodeNameEnvKey,
+							ValueFrom: &v1.EnvVarSource{
+								FieldRef: &v1.ObjectFieldSelector{
+									FieldPath: "spec.nodeName",
+								},
+							},
+						},
+					},
+				}},
+				Volumes: []v1.Volume{
+					// /var/lib is used as symlinks cannot be created across
+					// different volumes
+					{
+						Name: "host-varlib-volume",
+						VolumeSource: v1.VolumeSource{
+							HostPath: &v1.HostPathVolumeSource{
+								Path: "/var/lib",
+								Type: &hostPathDirectory,
+							},
+						},
+					},
+					{
+						Name: "host-operator-volume",
+						VolumeSource: v1.VolumeSource{
+							HostPath: &v1.HostPathVolumeSource{
+								Path: "/var/lib/security-profiles-operator",
+								Type: &hostPathDirectoryOrCreate,
+							},
+						},
+					},
+					{
+						Name: "profile-configmap-volume",
+						VolumeSource: v1.VolumeSource{
+							ConfigMap: &v1.ConfigMapVolumeSource{
+								LocalObjectReference: v1.LocalObjectReference{
+									Name: "security-profiles-operator-profile",
+								},
+							},
+						},
+					},
+				},
+				Tolerations: []v1.Toleration{
+					{
+						Effect: v1.TaintEffectNoSchedule,
+						Key:    "node-role.kubernetes.io/master",
+					},
+					{
+						Effect: v1.TaintEffectNoSchedule,
+						Key:    "node-role.kubernetes.io/control-plane",
+					},
+					{
+						Effect:   v1.TaintEffectNoExecute,
+						Key:      "node.kubernetes.io/not-ready",
+						Operator: v1.TolerationOpExists,
+					},
+				},
+				NodeSelector: map[string]string{
+					"kubernetes.io/os": "linux",
+				},
+			},
+		},
+	},
 }
diff --git a/internal/pkg/controllers/spod/setup.go b/internal/pkg/controllers/spod/setup.go
index 70582840b..cddb36d05 100644
--- a/internal/pkg/controllers/spod/setup.go
+++ b/internal/pkg/controllers/spod/setup.go
@@ -18,7 +18,6 @@ package spod
 
 import (
 	"context"
-	"fmt"
 
 	"github.com/crossplane/crossplane-runtime/pkg/event"
 	"github.com/crossplane/crossplane-runtime/pkg/resource"
@@ -45,17 +44,13 @@ type DaemonTunables struct {
 
 // Setup adds a controller that reconciles the SPOd DaemonSet.
 func Setup(ctx context.Context, mgr ctrl.Manager, dt DaemonTunables, l logr.Logger) error {
-	refSPOd, err := getEffectiveSPOd(dt)
-	if err != nil {
-		return err
-	}
 	return ctrl.NewControllerManagedBy(mgr).
 		Named("spod-config").
 		For(&corev1.ConfigMap{}).
 		WithEventFilter(resource.NewPredicates(isSPOdConfig)).
 		Owns(&appsv1.DaemonSet{}).
 		Complete(&ReconcileSPOd{
-			baseSPOd: refSPOd,
+			baseSPOd: getEffectiveSPOd(dt),
 			client:   mgr.GetClient(),
 			log:      l,
 			record:   event.NewAPIRecorder(mgr.GetEventRecorderFor("spod-config")),
@@ -63,11 +58,8 @@ func Setup(ctx context.Context, mgr ctrl.Manager, dt DaemonTunables, l logr.Logg
 		})
 }
 
-func getEffectiveSPOd(dt DaemonTunables) (*appsv1.DaemonSet, error) {
-	refSPOd, err := bindata.GetReferenceSPOd()
-	if err != nil {
-		return nil, fmt.Errorf("couldn't get reference SPO DaemonSet: %w", err)
-	}
+func getEffectiveSPOd(dt DaemonTunables) *appsv1.DaemonSet {
+	refSPOd := bindata.Manifest.DeepCopy()
 	cnt := &refSPOd.Spec.Template.Spec.Containers[0]
 	cnt.Image = dt.DaemonImage
 	if dt.WatchNamespace != "" {
@@ -79,7 +71,7 @@ func getEffectiveSPOd(dt DaemonTunables) (*appsv1.DaemonSet, error) {
 
 	initcnt := &refSPOd.Spec.Template.Spec.InitContainers[0]
 	initcnt.Image = dt.NonRootEnablerImage
-	return refSPOd, nil
+	return refSPOd
 }
 
 func isSPOdConfig(obj runtime.Object) bool {


Test patch:
diff --git a/internal/pkg/controllers/spod/setup_test.go b/internal/pkg/controllers/spod/setup_test.go
index 1cc74ff0e..56d4246d6 100644
--- a/internal/pkg/controllers/spod/setup_test.go
+++ b/internal/pkg/controllers/spod/setup_test.go
@@ -44,11 +44,7 @@ func Test_getEffectiveSPOd(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			got, err := getEffectiveSPOd(tt.dt)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("getEffectiveSPOd() error = %v, wantErr %v", err, tt.wantErr)
-				return
-			}
+			got := getEffectiveSPOd(tt.dt)
 			require.Equal(t, tt.dt.DaemonImage, got.Spec.Template.Spec.Containers[0].Image)
 			require.Equal(t, tt.dt.NonRootEnablerImage, got.Spec.Template.Spec.InitContainers[0].Image)
 			var found bool