diff --git a/chart/open-feature-operator/README.md b/chart/open-feature-operator/README.md index cd8894d09..6a5f12a53 100644 --- a/chart/open-feature-operator/README.md +++ b/chart/open-feature-operator/README.md @@ -96,6 +96,7 @@ The command removes all the Kubernetes components associated with the chart and | Name | Description | Value | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------ | | `defaultNamespace` | To override the namespace use the `--namespace` flag. This default is provided to ensure that the kustomize build charts in `/templates` deploy correctly when no `namespace` is provided via the `-n` flag. | `open-feature-operator-system` | +| `imagePullSecret` | Secret containing credentials for images pulled by the operator (flagdProxyConfiguration.image, flagdConfiguration.image, controllerManager.manager.image, controllerManager.kubeRbacProxy.image). | `""` | ### Sidecar configuration @@ -166,7 +167,7 @@ The command removes all the Kubernetes components associated with the chart and | `controllerManager.kubeRbacProxy.resources.requests.cpu` | Sets cpu resource requests for kube-rbac-proxy. | `5m` | | `controllerManager.kubeRbacProxy.resources.requests.memory` | Sets memory resource requests for kube-rbac-proxy. | `64Mi` | | `controllerManager.manager.image.repository` | Sets the image for the operator. | `ghcr.io/open-feature/open-feature-operator` | -| `controllerManager.manager.image.tag` | Sets the version tag for the operator. | `v0.5.7` | +| `controllerManager.manager.image.tag` | Sets the version tag for the operator. | `v0.6.0` | | `controllerManager.manager.resources.limits.cpu` | Sets cpu resource limits for operator. | `500m` | | `controllerManager.manager.resources.limits.memory` | Sets memory resource limits for operator. | `128Mi` | | `controllerManager.manager.resources.requests.cpu` | Sets cpu resource requests for operator. | `10m` | diff --git a/chart/open-feature-operator/values.yaml b/chart/open-feature-operator/values.yaml index 0500e0f93..822cfc010 100644 --- a/chart/open-feature-operator/values.yaml +++ b/chart/open-feature-operator/values.yaml @@ -2,6 +2,8 @@ ## @section Global ## @param defaultNamespace To override the namespace use the `--namespace` flag. This default is provided to ensure that the kustomize build charts in `/templates` deploy correctly when no `namespace` is provided via the `-n` flag. defaultNamespace: open-feature-operator-system +## @param imagePullSecret Secret containing credentials for images pulled by the operator (flagdProxyConfiguration.image, flagdConfiguration.image, controllerManager.manager.image, controllerManager.kubeRbacProxy.image). +imagePullSecret: "" ## @section Sidecar configuration sidecarConfiguration: diff --git a/common/flagdproxy/flagdproxy.go b/common/flagdproxy/flagdproxy.go index f410b5c0b..e1ea4932c 100644 --- a/common/flagdproxy/flagdproxy.go +++ b/common/flagdproxy/flagdproxy.go @@ -38,9 +38,10 @@ type FlagdProxyConfiguration struct { Tag string Namespace string OperatorDeploymentName string + ImagePullSecret string } -func NewFlagdProxyConfiguration(env types.EnvConfig) *FlagdProxyConfiguration { +func NewFlagdProxyConfiguration(env types.EnvConfig, imagePullSecret string) *FlagdProxyConfiguration { return &FlagdProxyConfiguration{ Image: env.FlagdProxyImage, Tag: env.FlagdProxyTag, @@ -49,6 +50,7 @@ func NewFlagdProxyConfiguration(env types.EnvConfig) *FlagdProxyConfiguration { Port: env.FlagdProxyPort, ManagementPort: env.FlagdProxyManagementPort, DebugLogging: env.FlagdProxyDebugLogging, + ImagePullSecret: imagePullSecret, } } @@ -143,6 +145,13 @@ func (f *FlagdProxyHandler) newFlagdProxyManifest(ownerReference *metav1.OwnerRe if f.config.DebugLogging { args = append(args, "--debug") } + imagePullSecrets := []corev1.LocalObjectReference{} + if f.config.ImagePullSecret != "" { + imagePullSecrets = append(imagePullSecrets, corev1.LocalObjectReference{ + Name: f.config.ImagePullSecret, + }) + } + return &appsV1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: FlagdProxyDeploymentName, @@ -172,6 +181,7 @@ func (f *FlagdProxyHandler) newFlagdProxyManifest(ownerReference *metav1.OwnerRe }, Spec: corev1.PodSpec{ ServiceAccountName: FlagdProxyServiceAccountName, + ImagePullSecrets: imagePullSecrets, Containers: []corev1.Container{ { Image: fmt.Sprintf("%s:%s", f.config.Image, f.config.Tag), diff --git a/common/flagdproxy/flagdproxy_test.go b/common/flagdproxy/flagdproxy_test.go index 4a2fcc8e4..112336fc3 100644 --- a/common/flagdproxy/flagdproxy_test.go +++ b/common/flagdproxy/flagdproxy_test.go @@ -19,11 +19,14 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" ) +const pullSecret = "test-pullSecret" + func TestNewFlagdProxyConfiguration(t *testing.T) { + kpConfig := NewFlagdProxyConfiguration(types.EnvConfig{ FlagdProxyPort: 8015, FlagdProxyManagementPort: 8016, - }) + }, pullSecret) require.NotNil(t, kpConfig) require.Equal(t, &FlagdProxyConfiguration{ @@ -31,6 +34,7 @@ func TestNewFlagdProxyConfiguration(t *testing.T) { ManagementPort: 8016, DebugLogging: false, OperatorDeploymentName: common.OperatorDeploymentName, + ImagePullSecret: pullSecret, }, kpConfig) } @@ -44,7 +48,7 @@ func TestNewFlagdProxyConfiguration_OverrideEnvVars(t *testing.T) { FlagdProxyDebugLogging: true, } - kpConfig := NewFlagdProxyConfiguration(env) + kpConfig := NewFlagdProxyConfiguration(env, pullSecret) require.NotNil(t, kpConfig) require.Equal(t, &FlagdProxyConfiguration{ @@ -55,11 +59,12 @@ func TestNewFlagdProxyConfiguration_OverrideEnvVars(t *testing.T) { Tag: "my-tag", Namespace: "my-namespace", OperatorDeploymentName: common.OperatorDeploymentName, + ImagePullSecret: pullSecret, }, kpConfig) } func TestNewFlagdProxyHandler(t *testing.T) { - kpConfig := NewFlagdProxyConfiguration(types.EnvConfig{}) + kpConfig := NewFlagdProxyConfiguration(types.EnvConfig{}, pullSecret) require.NotNil(t, kpConfig) @@ -95,7 +100,7 @@ func TestDoesFlagdProxyExist(t *testing.T) { }, } - kpConfig := NewFlagdProxyConfiguration(env) + kpConfig := NewFlagdProxyConfiguration(env, pullSecret) require.NotNil(t, kpConfig) @@ -123,7 +128,7 @@ func TestFlagdProxyHandler_HandleFlagdProxy_ProxyExistsWithBadVersion(t *testing env := types.EnvConfig{ PodNamespace: "ns", } - kpConfig := NewFlagdProxyConfiguration(env) + kpConfig := NewFlagdProxyConfiguration(env, pullSecret) require.NotNil(t, kpConfig) @@ -182,7 +187,7 @@ func TestFlagdProxyHandler_HandleFlagdProxy_ProxyExistsWithoutLabel(t *testing.T env := types.EnvConfig{ PodNamespace: "ns", } - kpConfig := NewFlagdProxyConfiguration(env) + kpConfig := NewFlagdProxyConfiguration(env, pullSecret) require.NotNil(t, kpConfig) @@ -231,7 +236,7 @@ func TestFlagdProxyHandler_HandleFlagdProxy_ProxyExistsWithNewestVersion(t *test env := types.EnvConfig{ PodNamespace: "ns", } - kpConfig := NewFlagdProxyConfiguration(env) + kpConfig := NewFlagdProxyConfiguration(env, pullSecret) require.NotNil(t, kpConfig) @@ -275,7 +280,7 @@ func TestFlagdProxyHandler_HandleFlagdProxy_CreateProxy(t *testing.T) { FlagdProxyManagementPort: 90, FlagdProxyDebugLogging: true, } - kpConfig := NewFlagdProxyConfiguration(env) + kpConfig := NewFlagdProxyConfiguration(env, pullSecret) require.NotNil(t, kpConfig) @@ -356,6 +361,9 @@ func TestFlagdProxyHandler_HandleFlagdProxy_CreateProxy(t *testing.T) { }, Spec: corev1.PodSpec{ ServiceAccountName: FlagdProxyServiceAccountName, + ImagePullSecrets: []corev1.LocalObjectReference{ + {Name: pullSecret}, + }, Containers: []corev1.Container{ { Image: "image:tag", diff --git a/config/crd/bases/core.openfeature.dev_flagds.yaml b/config/crd/bases/core.openfeature.dev_flagds.yaml index b736c4f5f..8240f52d2 100644 --- a/config/crd/bases/core.openfeature.dev_flagds.yaml +++ b/config/crd/bases/core.openfeature.dev_flagds.yaml @@ -61,7 +61,9 @@ spec: Default: /flagd.evaluation.v1.Service type: string hosts: - description: Hosts list of hosts to be added to the ingress + description: |- + Hosts list of hosts to be added to the ingress. + Empty string corresponds to rule with no host. items: type: string type: array @@ -109,6 +111,8 @@ spec: type: string type: object type: array + required: + - hosts type: object replicas: default: 1 diff --git a/config/overlays/helm/manager.yaml b/config/overlays/helm/manager.yaml index 4f7e2a48a..e2c48c051 100644 --- a/config/overlays/helm/manager.yaml +++ b/config/overlays/helm/manager.yaml @@ -6,7 +6,9 @@ metadata: spec: replicas: 0{{ .Values.controllerManager.replicas }} template: - spec: + spec: + imagePullSecrets: + - name: "{{ .Values.imagePullSecret }}" containers: - name: manager image: "{{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag }}" @@ -17,7 +19,7 @@ spec: requests: cpu: "{{ .Values.controllerManager.manager.resources.requests.cpu }}" memory: "{{ .Values.controllerManager.manager.resources.requests.memory }}" - env: + env: - name: SIDECAR_MANAGEMENT_PORT value: "{{ .Values.sidecarConfiguration.managementPort }}" - name: SIDECAR_PORT @@ -90,6 +92,7 @@ spec: - --sidecar-ram-limit={{ .Values.sidecarConfiguration.resources.limits.memory }} - --sidecar-cpu-request={{ .Values.sidecarConfiguration.resources.requests.cpu }} - --sidecar-ram-request={{ .Values.sidecarConfiguration.resources.requests.memory }} + - --image-pull-secret={{ .Values.imagePullSecret }} - name: kube-rbac-proxy image: "{{ .Values.controllerManager.kubeRbacProxy.image.repository }}:{{ .Values.controllerManager.kubeRbacProxy.image.tag }}" resources: diff --git a/controllers/core/featureflagsource/controller_test.go b/controllers/core/featureflagsource/controller_test.go index ea4b1e821..b1069ef83 100644 --- a/controllers/core/featureflagsource/controller_test.go +++ b/controllers/core/featureflagsource/controller_test.go @@ -27,6 +27,7 @@ func TestFeatureFlagSourceReconciler_Reconcile(t *testing.T) { testNamespace = "test-namespace" fsConfigName = "test-config" deploymentName = "test-deploy" + pullSecret = "test-pullsecret" ) tests := []struct { @@ -92,7 +93,7 @@ func TestFeatureFlagSourceReconciler_Reconcile(t *testing.T) { kpConfig := flagdproxy.NewFlagdProxyConfiguration(commontypes.EnvConfig{ FlagdProxyImage: "ghcr.io/open-feature/flagd-proxy", FlagdProxyTag: flagdProxyTag, - }) + }, pullSecret) kpConfig.Namespace = testNamespace kph := flagdproxy.NewFlagdProxyHandler( diff --git a/controllers/core/flagd/common/common.go b/controllers/core/flagd/common/common.go index 2ca793707..b66abe506 100644 --- a/controllers/core/flagd/common/common.go +++ b/controllers/core/flagd/common/common.go @@ -1,13 +1,14 @@ package resources type FlagdConfiguration struct { - FlagdPort int - OFREPPort int - SyncPort int - ManagementPort int - DebugLogging bool - Image string - Tag string + FlagdPort int + OFREPPort int + SyncPort int + ManagementPort int + DebugLogging bool + Image string + Tag string + ImagePullSecret string OperatorNamespace string OperatorDeploymentName string diff --git a/controllers/core/flagd/config.go b/controllers/core/flagd/config.go index 3b0548966..624301954 100644 --- a/controllers/core/flagd/config.go +++ b/controllers/core/flagd/config.go @@ -3,10 +3,10 @@ package flagd import ( "github.com/open-feature/open-feature-operator/common" "github.com/open-feature/open-feature-operator/common/types" - "github.com/open-feature/open-feature-operator/controllers/core/flagd/common" + resources "github.com/open-feature/open-feature-operator/controllers/core/flagd/common" ) -func NewFlagdConfiguration(env types.EnvConfig) resources.FlagdConfiguration { +func NewFlagdConfiguration(env types.EnvConfig, imagePullSecret string) resources.FlagdConfiguration { return resources.FlagdConfiguration{ Image: env.FlagdImage, Tag: env.FlagdTag, @@ -16,5 +16,6 @@ func NewFlagdConfiguration(env types.EnvConfig) resources.FlagdConfiguration { SyncPort: env.FlagdSyncPort, ManagementPort: env.FlagdManagementPort, DebugLogging: env.FlagdDebugLogging, + ImagePullSecret: imagePullSecret, } } diff --git a/controllers/core/flagd/resources/deployment.go b/controllers/core/flagd/resources/deployment.go index 285f8f285..dca133c1c 100644 --- a/controllers/core/flagd/resources/deployment.go +++ b/controllers/core/flagd/resources/deployment.go @@ -10,7 +10,7 @@ import ( api "github.com/open-feature/open-feature-operator/apis/core/v1beta1" "github.com/open-feature/open-feature-operator/common" "github.com/open-feature/open-feature-operator/common/flagdinjector" - "github.com/open-feature/open-feature-operator/controllers/core/flagd/common" + resources "github.com/open-feature/open-feature-operator/controllers/core/flagd/common" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -77,6 +77,12 @@ func (r *FlagdDeployment) GetResource(ctx context.Context, flagd *api.Flagd) (cl } featureFlagSource := &api.FeatureFlagSource{} + imagePullSecrets := []corev1.LocalObjectReference{} + if r.FlagdConfig.ImagePullSecret != "" { + imagePullSecrets = append(imagePullSecrets, corev1.LocalObjectReference{ + Name: r.FlagdConfig.ImagePullSecret, + }) + } if err := r.Client.Get(ctx, client.ObjectKey{ Namespace: flagd.Namespace, @@ -94,8 +100,9 @@ func (r *FlagdDeployment) GetResource(ctx context.Context, flagd *api.Flagd) (cl return nil, errors.New("no flagd container has been injected into deployment") } - // override settings for the injected container for flagd standalone deployment mode + deployment.Spec.Template.Spec.ImagePullSecrets = imagePullSecrets + // override settings for the injected container for flagd standalone deployment mode deployment.Spec.Template.Spec.Containers[0].Image = fmt.Sprintf("%s:%s", r.FlagdConfig.Image, r.FlagdConfig.Tag) deployment.Spec.Template.Spec.Containers[0].Ports = []corev1.ContainerPort{ diff --git a/docs/crds.md b/docs/crds.md index 3ab15217a..669653fd1 100644 --- a/docs/crds.md +++ b/docs/crds.md @@ -925,6 +925,14 @@ Ingress