diff --git a/.github/scripts/create-reports.sh b/.github/scripts/create-reports.sh index 5b71a57a0..ca6840273 100755 --- a/.github/scripts/create-reports.sh +++ b/.github/scripts/create-reports.sh @@ -31,7 +31,7 @@ for namespace in $(kubectl get namespaces -o jsonpath='{.items[*].metadata.name} createResourceReport "$logsDir/$namespace" "$namespace" "Daemonsets" false createResourceReport "$logsDir/$namespace" "$namespace" "Statefulsets" false createResourceReport "$logsDir/$namespace" "$namespace" "Jobs" false - createResourceReport "$logsDir/$namespace" "$namespace" "FeatureFlagConfiguration" false - createResourceReport "$logsDir/$namespace" "$namespace" "FlagSourceConfiguration" false + createResourceReport "$logsDir/$namespace" "$namespace" "FeatureFlag" false + createResourceReport "$logsDir/$namespace" "$namespace" "FeatureFlagSource" false done diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 434615a07..eed3e37cd 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -141,12 +141,12 @@ jobs: IMG=open-feature-operator-local:${{ github.sha }} make deploy-operator IMG=open-feature-operator-local:${{ github.sha }} make e2e-test-kuttl - name: Create reports - if: always() + if: failure() working-directory: ./.github/scripts run: ./create-reports.sh - name: Upload cluster logs - if: always() + if: failure() uses: actions/upload-artifact@v3 with: name: e2e-tests diff --git a/.gitignore b/.gitignore index cfd1841c7..6b323cd6b 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ testbin/* *.swo *~ +go.work +go.work.sum diff --git a/Dockerfile b/Dockerfile index 05dc2c319..39902ae41 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ COPY main.go main.go COPY apis/ apis/ COPY webhooks/ webhooks/ COPY controllers/ controllers/ -COPY pkg/ pkg/ +COPY common/ common/ ARG TARGETOS ARG TARGETARCH diff --git a/chart/open-feature-operator/README.md b/chart/open-feature-operator/README.md index cbd97ec25..c63554cb3 100644 --- a/chart/open-feature-operator/README.md +++ b/chart/open-feature-operator/README.md @@ -54,16 +54,16 @@ OpenFeature Operator's CRDs are templated, and can be updated apart from the ope helm template openfeature/open-feature-operator -s templates/{CRD} | kubectl apply -f - ``` -For the `featureflagconfigurations.core.openfeature.dev` CRD: +For the `featureflags.core.openfeature.dev` CRD: ```sh -helm template openfeature/open-feature-operator -s templates/apiextensions.k8s.io_v1_customresourcedefinition_featureflagconfigurations.core.openfeature.dev.yaml | kubectl apply -f - +helm template openfeature/open-feature-operator -s templates/apiextensions.k8s.io_v1_customresourcedefinition_featureflags.core.openfeature.dev.yaml | kubectl apply -f - ``` -For the `flagsourceconfigurations.core.openfeature.dev` CRD: +For the `featureflagsources.core.openfeature.dev` CRD: ```sh -helm template openfeature/open-feature-operator -s templates/apiextensions.k8s.io_v1_customresourcedefinition_flagsourceconfigurations.core.openfeature.dev.yaml | kubectl apply -f - +helm template openfeature/open-feature-operator -s templates/apiextensions.k8s.io_v1_customresourcedefinition_featureflagsources.core.openfeature.dev.yaml | kubectl apply -f - ``` Keep in mind, you can set values as usual during this process: @@ -95,10 +95,10 @@ The command removes all the Kubernetes components associated with the chart and | Name | Description | Value | | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | | `sidecarConfiguration.port` | Sets the value of the `XXX_PORT` environment variable for the injected sidecar. | `8013` | -| `sidecarConfiguration.metricsPort` | Sets the value of the `XXX_METRICS_PORT` environment variable for the injected sidecar. | `8014` | +| `sidecarConfiguration.managementPort` | Sets the value of the `XXX_MANAGEMENT_PORT` environment variable for the injected sidecar. | `8014` | | `sidecarConfiguration.socketPath` | Sets the value of the `XXX_SOCKET_PATH` environment variable for the injected sidecar. | `""` | | `sidecarConfiguration.image.repository` | Sets the image for the injected sidecar. | `ghcr.io/open-feature/flagd` | -| `sidecarConfiguration.image.tag` | Sets the version tag for the injected sidecar. | `v0.6.3` | +| `sidecarConfiguration.image.tag` | Sets the version tag for the injected sidecar. | `v0.7.0` | | `sidecarConfiguration.providerArgs` | Used to append arguments to the sidecar startup command. This value is a comma separated string of key values separated by '=', e.g. `key=value,key2=value2` results in the appending of `--sync-provider-args key=value --sync-provider-args key2=value2`. | `""` | | `sidecarConfiguration.envVarPrefix` | Sets the prefix for all environment variables set in the injected sidecar. | `FLAGD` | | `sidecarConfiguration.defaultSyncProvider` | Sets the value of the `XXX_SYNC_PROVIDER` environment variable for the injected sidecar container. There are 4 valid sync providers: `kubernetes`, `grpc`, `filepath` and `http`. | `kubernetes` | @@ -114,7 +114,7 @@ The command removes all the Kubernetes components associated with the chart and | Name | Description | Value | | ------------------------------------------ | ------------------------------------------------------------------------------- | ---------------------------------- | | `flagdProxyConfiguration.port` | Sets the port to expose the sync API on. | `8015` | -| `flagdProxyConfiguration.metricsPort` | Sets the port to expose the metrics API on. | `8016` | +| `flagdProxyConfiguration.managementPort` | Sets the port to expose the management API on. | `8016` | | `flagdProxyConfiguration.image.repository` | Sets the image for the flagd-proxy deployment. | `ghcr.io/open-feature/flagd-proxy` | | `flagdProxyConfiguration.image.tag` | Sets the tag for the flagd-proxy deployment. | `v0.2.8` | | `flagdProxyConfiguration.debugLogging` | Controls the addition of the `--debug` flag to the container startup arguments. | `false` | diff --git a/chart/open-feature-operator/values.yaml b/chart/open-feature-operator/values.yaml index b414a6a3f..6f1174c74 100644 --- a/chart/open-feature-operator/values.yaml +++ b/chart/open-feature-operator/values.yaml @@ -7,8 +7,8 @@ defaultNamespace: open-feature-operator-system sidecarConfiguration: ## @param sidecarConfiguration.port Sets the value of the `XXX_PORT` environment variable for the injected sidecar. port: 8013 - ## @param sidecarConfiguration.metricsPort Sets the value of the `XXX_METRICS_PORT` environment variable for the injected sidecar. - metricsPort: 8014 + ## @param sidecarConfiguration.managementPort Sets the value of the `XXX_MANAGEMENT_PORT` environment variable for the injected sidecar. + managementPort: 8014 ## @param sidecarConfiguration.socketPath Sets the value of the `XXX_SOCKET_PATH` environment variable for the injected sidecar. socketPath: "" image: @@ -16,7 +16,7 @@ sidecarConfiguration: ## @param sidecarConfiguration.image.repository Sets the image for the injected sidecar. repository: "ghcr.io/open-feature/flagd" ## @param sidecarConfiguration.image.tag Sets the version tag for the injected sidecar. - tag: v0.6.3 + tag: v0.7.0 ## @param sidecarConfiguration.providerArgs Used to append arguments to the sidecar startup command. This value is a comma separated string of key values separated by '=', e.g. `key=value,key2=value2` results in the appending of `--sync-provider-args key=value --sync-provider-args key2=value2`. providerArgs: "" ## @param sidecarConfiguration.envVarPrefix Sets the prefix for all environment variables set in the injected sidecar. @@ -40,8 +40,8 @@ sidecarConfiguration: flagdProxyConfiguration: ## @param flagdProxyConfiguration.port Sets the port to expose the sync API on. port: 8015 - ## @param flagdProxyConfiguration.metricsPort Sets the port to expose the metrics API on. - metricsPort: 8016 + ## @param flagdProxyConfiguration.managementPort Sets the port to expose the management API on. + managementPort: 8016 image: ## @param flagdProxyConfiguration.image.repository Sets the image for the flagd-proxy deployment. repository: "ghcr.io/open-feature/flagd-proxy" diff --git a/controllers/common/common.go b/common/common.go similarity index 58% rename from controllers/common/common.go rename to common/common.go index 4ad4e9c97..a6c714919 100644 --- a/controllers/common/common.go +++ b/common/common.go @@ -5,22 +5,22 @@ import ( "fmt" "time" - "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" + api "github.com/open-feature/open-feature-operator/apis/core/v1beta1" appsV1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" ) const ( - ReconcileErrorInterval = 10 * time.Second - ReconcileSuccessInterval = 120 * time.Second - FinalizerName = "featureflagconfiguration.core.openfeature.dev/finalizer" - OpenFeatureAnnotationPath = "spec.template.metadata.annotations.openfeature.dev/openfeature.dev" - FlagSourceConfigurationAnnotation = "flagsourceconfiguration" - OpenFeatureAnnotationRoot = "openfeature.dev" + ReconcileErrorInterval = 10 * time.Second + ReconcileSuccessInterval = 120 * time.Second + FinalizerName = "featureflag.core.openfeature.dev/finalizer" + OpenFeatureAnnotationPath = "spec.template.metadata.annotations.openfeature.dev/openfeature.dev" + FeatureFlagSourceAnnotation = "featureflagsource" + OpenFeatureAnnotationRoot = "openfeature.dev" ) -func FlagSourceConfigurationIndex(o client.Object) []string { +func FeatureFlagSourceIndex(o client.Object) []string { deployment, ok := o.(*appsV1.Deployment) if !ok { return []string{ @@ -33,7 +33,7 @@ func FlagSourceConfigurationIndex(o client.Object) []string { "false", } } - if _, ok := deployment.Spec.Template.ObjectMeta.Annotations[fmt.Sprintf("openfeature.dev/%s", FlagSourceConfigurationAnnotation)]; ok { + if _, ok := deployment.Spec.Template.ObjectMeta.Annotations[fmt.Sprintf("openfeature.dev/%s", FeatureFlagSourceAnnotation)]; ok { return []string{ "true", } @@ -43,8 +43,8 @@ func FlagSourceConfigurationIndex(o client.Object) []string { } } -func FindFlagConfig(ctx context.Context, c client.Client, namespace string, name string) (*v1alpha1.FeatureFlagConfiguration, error) { - ffConfig := &v1alpha1.FeatureFlagConfiguration{} +func FindFlagConfig(ctx context.Context, c client.Client, namespace string, name string) (*api.FeatureFlag, error) { + ffConfig := &api.FeatureFlag{} if err := c.Get(ctx, client.ObjectKey{Name: name, Namespace: namespace}, ffConfig); err != nil { return nil, err } diff --git a/controllers/common/common_test.go b/common/common_test.go similarity index 56% rename from controllers/common/common_test.go rename to common/common_test.go index 8422141b8..155955fbb 100644 --- a/controllers/common/common_test.go +++ b/common/common_test.go @@ -1,17 +1,21 @@ package common import ( + "context" "fmt" "testing" + api "github.com/open-feature/open-feature-operator/apis/core/v1beta1" "github.com/stretchr/testify/require" appsV1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/scheme" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" ) -func TestFlagSourceConfigurationIndex(t *testing.T) { +func TestFeatureFlagSourceIndex(t *testing.T) { tests := []struct { name string obj client.Object @@ -49,7 +53,7 @@ func TestFlagSourceConfigurationIndex(t *testing.T) { Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ - fmt.Sprintf("openfeature.dev/%s", FlagSourceConfigurationAnnotation): "true", + fmt.Sprintf("openfeature.dev/%s", FeatureFlagSourceAnnotation): "true", }, }, }, @@ -61,7 +65,7 @@ func TestFlagSourceConfigurationIndex(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - out := FlagSourceConfigurationIndex(tt.obj) + out := FeatureFlagSourceIndex(tt.obj) require.Equal(t, tt.out, out) }) @@ -102,8 +106,60 @@ func TestSharedOwnership(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := SharedOwnership(tt.owner1, tt.owner2); got != tt.want { - t.Errorf("podOwnerIsOwner() = %v, want %v", got, tt.want) + t.Errorf("SharedOwnership() = %v, want %v", got, tt.want) } }) } } + +func TestFindFlagConfig(t *testing.T) { + ff := &api.FeatureFlag{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + } + + tests := []struct { + name string + ns string + obj *api.FeatureFlag + want *api.FeatureFlag + wantErr bool + }{ + { + name: "test", + ns: "default", + obj: ff, + want: ff, + wantErr: false, + }, + { + name: "non-existing", + ns: "default", + obj: ff, + want: nil, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := api.AddToScheme(scheme.Scheme) + require.Nil(t, err) + fakeClient := fake.NewClientBuilder().WithScheme(scheme.Scheme).WithObjects(tt.obj).Build() + + got, err := FindFlagConfig(context.TODO(), fakeClient, tt.ns, tt.name) + + if (err != nil) != tt.wantErr { + t.Errorf("FindFlagConfig() = expected error %t, got %v", tt.wantErr, err) + } + + if !tt.wantErr { + require.Equal(t, tt.want.Name, got.Name) + require.Equal(t, tt.want.Namespace, got.Namespace) + } + + }) + } +} diff --git a/controllers/common/constant/configuration.go b/common/constant/configuration.go similarity index 73% rename from controllers/common/constant/configuration.go rename to common/constant/configuration.go index 3201eeb83..b3115d4ea 100644 --- a/controllers/common/constant/configuration.go +++ b/common/constant/configuration.go @@ -7,8 +7,11 @@ const ( ClusterRoleBindingName string = "open-feature-operator-flagd-kubernetes-sync" AllowKubernetesSyncAnnotation = "allowkubernetessync" OpenFeatureAnnotationPrefix = "openfeature.dev" + OpenFeatureAnnotationPath = "metadata.annotations.openfeature.dev" SourceConfigParam = "--sources" ProbeReadiness = "/readyz" ProbeLiveness = "/healthz" ProbeInitialDelay = 5 + FeatureFlagSourceAnnotation = "featureflagsource" + EnabledAnnotation = "enabled" ) diff --git a/controllers/common/constant/errors.go b/common/constant/errors.go similarity index 100% rename from controllers/common/constant/errors.go rename to common/constant/errors.go diff --git a/common/flagdinjector/fake/flagdinjector_mock.go b/common/flagdinjector/fake/flagdinjector_mock.go new file mode 100644 index 000000000..150db2954 --- /dev/null +++ b/common/flagdinjector/fake/flagdinjector_mock.go @@ -0,0 +1,65 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: controllers/common/flagd-injector.go + +// Package commonmock is a generated GoMock package. +package commonmock + +import ( + context "context" + gomock "github.com/golang/mock/gomock" + api "github.com/open-feature/open-feature-operator/apis/core/v1beta1" + v1 "k8s.io/api/core/v1" + v10 "k8s.io/apimachinery/pkg/apis/meta/v1" + reflect "reflect" +) + +// MockFlagdContainerInjector is a mock of IFlagdContainerInjector interface. +type MockFlagdContainerInjector struct { + ctrl *gomock.Controller + recorder *MockFlagdContainerInjectorMockRecorder +} + +// MockFlagdContainerInjectorMockRecorder is the mock recorder for MockFlagdContainerInjector. +type MockFlagdContainerInjectorMockRecorder struct { + mock *MockFlagdContainerInjector +} + +// NewMockFlagdContainerInjector creates a new mock instance. +func NewMockFlagdContainerInjector(ctrl *gomock.Controller) *MockFlagdContainerInjector { + mock := &MockFlagdContainerInjector{ctrl: ctrl} + mock.recorder = &MockFlagdContainerInjectorMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockFlagdContainerInjector) EXPECT() *MockFlagdContainerInjectorMockRecorder { + return m.recorder +} + +// EnableClusterRoleBinding mocks base method. +func (m *MockFlagdContainerInjector) EnableClusterRoleBinding(ctx context.Context, namespace, serviceAccountName string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EnableClusterRoleBinding", ctx, namespace, serviceAccountName) + ret0, _ := ret[0].(error) + return ret0 +} + +// EnableClusterRoleBinding indicates an expected call of EnableClusterRoleBinding. +func (mr *MockFlagdContainerInjectorMockRecorder) EnableClusterRoleBinding(ctx, namespace, serviceAccountName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnableClusterRoleBinding", reflect.TypeOf((*MockFlagdContainerInjector)(nil).EnableClusterRoleBinding), ctx, namespace, serviceAccountName) +} + +// InjectFlagd mocks base method. +func (m *MockFlagdContainerInjector) InjectFlagd(ctx context.Context, objectMeta *v10.ObjectMeta, podSpec *v1.PodSpec, flagSourceConfig *api.FeatureFlagSourceSpec) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InjectFlagd", ctx, objectMeta, podSpec, flagSourceConfig) + ret0, _ := ret[0].(error) + return ret0 +} + +// InjectFlagd indicates an expected call of InjectFlagd. +func (mr *MockFlagdContainerInjectorMockRecorder) InjectFlagd(ctx, objectMeta, podSpec, flagSourceConfig interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InjectFlagd", reflect.TypeOf((*MockFlagdContainerInjector)(nil).InjectFlagd), ctx, objectMeta, podSpec, flagSourceConfig) +} diff --git a/controllers/common/flagd-injector.go b/common/flagdinjector/flagdinjector.go similarity index 83% rename from controllers/common/flagd-injector.go rename to common/flagdinjector/flagdinjector.go index 3cd732e2c..d315bb00f 100644 --- a/controllers/common/flagd-injector.go +++ b/common/flagdinjector/flagdinjector.go @@ -1,4 +1,4 @@ -package common +package flagdinjector import ( "context" @@ -7,10 +7,13 @@ import ( "time" "github.com/go-logr/logr" - "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" - "github.com/open-feature/open-feature-operator/controllers/common/constant" - "github.com/open-feature/open-feature-operator/pkg/types" - "github.com/open-feature/open-feature-operator/pkg/utils" + api "github.com/open-feature/open-feature-operator/apis/core/v1beta1" + apicommon "github.com/open-feature/open-feature-operator/apis/core/v1beta1/common" + "github.com/open-feature/open-feature-operator/common" + "github.com/open-feature/open-feature-operator/common/constant" + "github.com/open-feature/open-feature-operator/common/flagdproxy" + "github.com/open-feature/open-feature-operator/common/types" + "github.com/open-feature/open-feature-operator/common/utils" appsV1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -29,7 +32,7 @@ type IFlagdContainerInjector interface { ctx context.Context, objectMeta *metav1.ObjectMeta, podSpec *corev1.PodSpec, - flagSourceConfig *v1alpha1.FlagSourceConfigurationSpec, + flagSourceConfig *api.FeatureFlagSourceSpec, ) error EnableClusterRoleBinding( @@ -42,7 +45,7 @@ type IFlagdContainerInjector interface { type FlagdContainerInjector struct { Client client.Client Logger logr.Logger - FlagdProxyConfig *FlagdProxyConfiguration + FlagdProxyConfig *flagdproxy.FlagdProxyConfiguration FlagDResourceRequirements corev1.ResourceRequirements } @@ -51,15 +54,15 @@ func (fi *FlagdContainerInjector) InjectFlagd( ctx context.Context, objectMeta *metav1.ObjectMeta, podSpec *corev1.PodSpec, - flagSourceConfig *v1alpha1.FlagSourceConfigurationSpec, + flagSourceConfig *api.FeatureFlagSourceSpec, ) error { fi.Logger.V(1).Info(fmt.Sprintf("creating flagdContainer for pod %s/%s", objectMeta.Namespace, objectMeta.Name)) flagdContainer := fi.generateBasicFlagdContainer(flagSourceConfig) // Enable probes if flagSourceConfig.ProbesEnabled != nil && *flagSourceConfig.ProbesEnabled { - flagdContainer.LivenessProbe = buildProbe(constant.ProbeLiveness, int(flagSourceConfig.MetricsPort)) - flagdContainer.ReadinessProbe = buildProbe(constant.ProbeReadiness, int(flagSourceConfig.MetricsPort)) + flagdContainer.LivenessProbe = buildProbe(constant.ProbeLiveness, int(flagSourceConfig.ManagementPort)) + flagdContainer.ReadinessProbe = buildProbe(constant.ProbeReadiness, int(flagSourceConfig.ManagementPort)) } if err := fi.handleSidecarSources(ctx, objectMeta, podSpec, flagSourceConfig, &flagdContainer); err != nil { @@ -168,7 +171,7 @@ func (fi *FlagdContainerInjector) EnableClusterRoleBinding(ctx context.Context, return nil } -func (fi *FlagdContainerInjector) handleSidecarSources(ctx context.Context, objectMeta *metav1.ObjectMeta, podSpec *corev1.PodSpec, flagSourceConfig *v1alpha1.FlagSourceConfigurationSpec, sidecar *corev1.Container) error { +func (fi *FlagdContainerInjector) handleSidecarSources(ctx context.Context, objectMeta *metav1.ObjectMeta, podSpec *corev1.PodSpec, flagSourceConfig *api.FeatureFlagSourceSpec, sidecar *corev1.Container) error { sources, err := fi.buildSources(ctx, objectMeta, flagSourceConfig, podSpec, sidecar) if err != nil { return err @@ -182,7 +185,7 @@ func (fi *FlagdContainerInjector) handleSidecarSources(ctx context.Context, obje } //nolint:gocyclo -func (fi *FlagdContainerInjector) buildSources(ctx context.Context, objectMeta *metav1.ObjectMeta, flagSourceConfig *v1alpha1.FlagSourceConfigurationSpec, podSpec *corev1.PodSpec, sidecar *corev1.Container) ([]types.SourceConfig, error) { +func (fi *FlagdContainerInjector) buildSources(ctx context.Context, objectMeta *metav1.ObjectMeta, flagSourceConfig *api.FeatureFlagSourceSpec, podSpec *corev1.PodSpec, sidecar *corev1.Container) ([]types.SourceConfig, error) { var sourceCfgCollection []types.SourceConfig for _, source := range flagSourceConfig.Sources { @@ -224,7 +227,7 @@ func (fi *FlagdContainerInjector) buildSources(ctx context.Context, objectMeta * return sourceCfgCollection, nil } -func (fi *FlagdContainerInjector) toFilepathProviderConfig(ctx context.Context, objectMeta *metav1.ObjectMeta, podSpec *corev1.PodSpec, sidecar *corev1.Container, source v1alpha1.Source) (types.SourceConfig, error) { +func (fi *FlagdContainerInjector) toFilepathProviderConfig(ctx context.Context, objectMeta *metav1.ObjectMeta, podSpec *corev1.PodSpec, sidecar *corev1.Container, source api.Source) (types.SourceConfig, error) { // create config map ns, n := utils.ParseAnnotation(source.Source, objectMeta.Namespace) cm := corev1.ConfigMap{} @@ -237,7 +240,7 @@ func (fi *FlagdContainerInjector) toFilepathProviderConfig(ctx context.Context, } // Add owner reference of the pod's owner - if !SharedOwnership(objectMeta.OwnerReferences, cm.OwnerReferences) { + if !common.SharedOwnership(objectMeta.OwnerReferences, cm.OwnerReferences) { fi.updateCMOwnerReference(ctx, objectMeta, cm) } @@ -253,7 +256,7 @@ func (fi *FlagdContainerInjector) toFilepathProviderConfig(ctx context.Context, }, }) - mountPath := fmt.Sprintf("%s/%s", rootFileSyncMountPath, utils.FeatureFlagConfigurationId(ns, n)) + mountPath := fmt.Sprintf("%s/%s", rootFileSyncMountPath, utils.FeatureFlagId(ns, n)) sidecar.VolumeMounts = append(sidecar.VolumeMounts, corev1.VolumeMount{ Name: n, // create a directory mount per featureFlag spec @@ -262,7 +265,7 @@ func (fi *FlagdContainerInjector) toFilepathProviderConfig(ctx context.Context, }) return types.SourceConfig{ - URI: fmt.Sprintf("%s/%s", mountPath, utils.FeatureFlagConfigurationConfigMapKey(ns, n)), + URI: fmt.Sprintf("%s/%s", mountPath, utils.FeatureFlagConfigMapKey(ns, n)), // todo - this constant needs to be aligned with flagd. We have a mixed usage of file vs filepath Provider: "file", }, nil @@ -281,18 +284,18 @@ func (fi *FlagdContainerInjector) updateCMOwnerReference(ctx context.Context, ob } } -func (fi *FlagdContainerInjector) toHttpProviderConfig(source v1alpha1.Source) types.SourceConfig { +func (fi *FlagdContainerInjector) toHttpProviderConfig(source api.Source) types.SourceConfig { return types.SourceConfig{ URI: source.Source, - Provider: string(v1alpha1.SyncProviderHttp), + Provider: string(apicommon.SyncProviderHttp), BearerToken: source.HttpSyncBearerToken, } } -func (fi *FlagdContainerInjector) toGrpcProviderConfig(source v1alpha1.Source) types.SourceConfig { +func (fi *FlagdContainerInjector) toGrpcProviderConfig(source api.Source) types.SourceConfig { return types.SourceConfig{ URI: source.Source, - Provider: string(v1alpha1.SyncProviderGrpc), + Provider: string(apicommon.SyncProviderGrpc), TLS: source.TLS, CertPath: source.CertPath, ProviderID: source.ProviderID, @@ -300,7 +303,7 @@ func (fi *FlagdContainerInjector) toGrpcProviderConfig(source v1alpha1.Source) t } } -func (fi *FlagdContainerInjector) toFlagdProxyConfig(ctx context.Context, objectMeta *metav1.ObjectMeta, source v1alpha1.Source) (types.SourceConfig, error) { +func (fi *FlagdContainerInjector) toFlagdProxyConfig(ctx context.Context, objectMeta *metav1.ObjectMeta, source api.Source) (types.SourceConfig, error) { // does the proxy exist exists, ready, err := fi.isFlagdProxyReady(ctx) if err != nil { @@ -313,13 +316,13 @@ func (fi *FlagdContainerInjector) toFlagdProxyConfig(ctx context.Context, object return types.SourceConfig{ Provider: "grpc", Selector: fmt.Sprintf("core.openfeature.dev/%s/%s", ns, n), - URI: fmt.Sprintf("%s.%s.svc.cluster.local:%d", FlagdProxyServiceName, fi.FlagdProxyConfig.Namespace, fi.FlagdProxyConfig.Port), + URI: fmt.Sprintf("%s.%s.svc.cluster.local:%d", flagdproxy.FlagdProxyServiceName, fi.FlagdProxyConfig.Namespace, fi.FlagdProxyConfig.Port), }, nil } func (fi *FlagdContainerInjector) isFlagdProxyReady(ctx context.Context) (bool, bool, error) { d := appsV1.Deployment{} - err := fi.Client.Get(ctx, client.ObjectKey{Name: FlagdProxyDeploymentName, Namespace: fi.FlagdProxyConfig.Namespace}, &d) + err := fi.Client.Get(ctx, client.ObjectKey{Name: flagdproxy.FlagdProxyDeploymentName, Namespace: fi.FlagdProxyConfig.Namespace}, &d) if err != nil { if errors.IsNotFound(err) { // does not exist, is not ready, no error @@ -343,12 +346,12 @@ func (fi *FlagdContainerInjector) isFlagdProxyReady(ctx context.Context) (bool, return true, true, nil } -func (fi *FlagdContainerInjector) toKubernetesProviderConfig(ctx context.Context, objectMeta *metav1.ObjectMeta, podSpec *corev1.PodSpec, source v1alpha1.Source) (types.SourceConfig, error) { +func (fi *FlagdContainerInjector) toKubernetesProviderConfig(ctx context.Context, objectMeta *metav1.ObjectMeta, podSpec *corev1.PodSpec, source api.Source) (types.SourceConfig, error) { ns, n := utils.ParseAnnotation(source.Source, objectMeta.Namespace) - // ensure that the FeatureFlagConfiguration exists - if _, err := FindFlagConfig(ctx, fi.Client, ns, n); err != nil { - return types.SourceConfig{}, fmt.Errorf("could not retrieve feature flag configuration %s/%s: %w", ns, n, err) + // ensure that the FeatureFlag exists + if _, err := common.FindFlagConfig(ctx, fi.Client, ns, n); err != nil { + return types.SourceConfig{}, fmt.Errorf("could not retrieve featureflag %s/%s: %w", ns, n, err) } // add permissions to pod @@ -365,11 +368,11 @@ func (fi *FlagdContainerInjector) toKubernetesProviderConfig(ctx context.Context // build K8s config return types.SourceConfig{ URI: fmt.Sprintf("%s/%s", ns, n), - Provider: string(v1alpha1.SyncProviderKubernetes), + Provider: string(apicommon.SyncProviderKubernetes), }, nil } -func (fi *FlagdContainerInjector) generateBasicFlagdContainer(flagSourceConfig *v1alpha1.FlagSourceConfigurationSpec) corev1.Container { +func (fi *FlagdContainerInjector) generateBasicFlagdContainer(flagSourceConfig *api.FeatureFlagSourceSpec) corev1.Container { return corev1.Container{ Name: "flagd", Image: fmt.Sprintf("%s:%s", flagSourceConfig.Image, flagSourceConfig.Tag), @@ -382,7 +385,7 @@ func (fi *FlagdContainerInjector) generateBasicFlagdContainer(flagSourceConfig * Ports: []corev1.ContainerPort{ { Name: "metrics", - ContainerPort: flagSourceConfig.MetricsPort, + ContainerPort: flagSourceConfig.ManagementPort, }, }, SecurityContext: getSecurityContext(), @@ -397,16 +400,19 @@ func (fi *FlagdContainerInjector) createConfigMap(ctx context.Context, namespace references = append(references, ownerReferences[0]) references[0].Controller = utils.FalseVal() } - ff, err := FindFlagConfig(ctx, fi.Client, namespace, name) + ff, err := common.FindFlagConfig(ctx, fi.Client, namespace, name) if err != nil { - return fmt.Errorf("could not retrieve feature flag configuration %s/%s: %w", namespace, name, err) + return fmt.Errorf("could not retrieve featureflag %s/%s: %w", namespace, name, err) } references = append(references, ff.GetReference()) - cm := ff.GenerateConfigMap(name, namespace, references) + cm, err := ff.GenerateConfigMap(name, namespace, references) + if err != nil { + return fmt.Errorf("could generate configmap for featureflag %s/%s: %w", namespace, name, err) + } - return fi.Client.Create(ctx, &cm) + return fi.Client.Create(ctx, cm) } func addFlagdContainer(spec *corev1.PodSpec, flagdContainer corev1.Container) { diff --git a/controllers/common/flagd-injector_test.go b/common/flagdinjector/flagdinjector_test.go similarity index 91% rename from controllers/common/flagd-injector_test.go rename to common/flagdinjector/flagdinjector_test.go index 37ef4ebcb..fc902cb65 100644 --- a/controllers/common/flagd-injector_test.go +++ b/common/flagdinjector/flagdinjector_test.go @@ -1,4 +1,4 @@ -package common +package flagdinjector import ( "context" @@ -7,9 +7,11 @@ import ( "testing" "github.com/go-logr/logr/testr" - "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" - "github.com/open-feature/open-feature-operator/controllers/common/constant" - "github.com/open-feature/open-feature-operator/pkg/utils" + api "github.com/open-feature/open-feature-operator/apis/core/v1beta1" + apicommon "github.com/open-feature/open-feature-operator/apis/core/v1beta1/common" + "github.com/open-feature/open-feature-operator/common/constant" + "github.com/open-feature/open-feature-operator/common/flagdproxy" + "github.com/open-feature/open-feature-operator/common/utils" "github.com/stretchr/testify/require" appsV1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -45,9 +47,9 @@ func TestFlagdContainerInjector_InjectDefaultSyncProvider(t *testing.T) { flagSourceConfig := getFlagSourceConfigSpec() - flagSourceConfig.DefaultSyncProvider = v1alpha1.SyncProviderGrpc + flagSourceConfig.DefaultSyncProvider = apicommon.SyncProviderGrpc - flagSourceConfig.Sources = []v1alpha1.Source{{}} + flagSourceConfig.Sources = []api.Source{{}} err := fi.InjectFlagd(context.Background(), &deployment.ObjectMeta, &deployment.Spec.Template.Spec, flagSourceConfig) require.Nil(t, err) @@ -82,11 +84,11 @@ func TestFlagdContainerInjector_InjectDefaultSyncProvider_WithDebugLogging(t *te flagSourceConfig := getFlagSourceConfigSpec() - flagSourceConfig.DefaultSyncProvider = v1alpha1.SyncProviderGrpc + flagSourceConfig.DefaultSyncProvider = apicommon.SyncProviderGrpc flagSourceConfig.DebugLogging = utils.TrueVal() - flagSourceConfig.Sources = []v1alpha1.Source{{}} + flagSourceConfig.Sources = []api.Source{{}} err := fi.InjectFlagd(context.Background(), &deployment.ObjectMeta, &deployment.Spec.Template.Spec, flagSourceConfig) require.Nil(t, err) @@ -121,11 +123,11 @@ func TestFlagdContainerInjector_InjectDefaultSyncProvider_WithOtelCollectorUri(t flagSourceConfig := getFlagSourceConfigSpec() - flagSourceConfig.DefaultSyncProvider = v1alpha1.SyncProviderGrpc + flagSourceConfig.DefaultSyncProvider = apicommon.SyncProviderGrpc flagSourceConfig.OtelCollectorUri = "localhost:4317" - flagSourceConfig.Sources = []v1alpha1.Source{{}} + flagSourceConfig.Sources = []api.Source{{}} err := fi.InjectFlagd(context.Background(), &deployment.ObjectMeta, &deployment.Spec.Template.Spec, flagSourceConfig) require.Nil(t, err) @@ -160,7 +162,7 @@ func TestFlagdContainerInjector_InjectDefaultSyncProvider_WithResources(t *testi flagSourceConfig := getFlagSourceConfigSpec() - flagSourceConfig.DefaultSyncProvider = v1alpha1.SyncProviderGrpc + flagSourceConfig.DefaultSyncProvider = apicommon.SyncProviderGrpc flagSourceConfig.Resources = corev1.ResourceRequirements{ Limits: map[corev1.ResourceName]resource.Quantity{ @@ -173,7 +175,7 @@ func TestFlagdContainerInjector_InjectDefaultSyncProvider_WithResources(t *testi }, } - flagSourceConfig.Sources = []v1alpha1.Source{{}} + flagSourceConfig.Sources = []api.Source{{}} err := fi.InjectFlagd(context.Background(), &deployment.ObjectMeta, &deployment.Spec.Template.Spec, flagSourceConfig) require.Nil(t, err) @@ -211,9 +213,9 @@ func TestFlagdContainerInjector_InjectDefaultSyncProvider_WithSyncProviderArgs(t flagSourceConfig.SyncProviderArgs = []string{"arg-1", "arg-2"} - flagSourceConfig.DefaultSyncProvider = v1alpha1.SyncProviderGrpc + flagSourceConfig.DefaultSyncProvider = apicommon.SyncProviderGrpc - flagSourceConfig.Sources = []v1alpha1.Source{{}} + flagSourceConfig.Sources = []api.Source{{}} err := fi.InjectFlagd(context.Background(), &deployment.ObjectMeta, &deployment.Spec.Template.Spec, flagSourceConfig) require.Nil(t, err) @@ -247,10 +249,10 @@ func TestFlagdContainerInjector_InjectFlagdKubernetesSource(t *testing.T) { flagSourceConfig := getFlagSourceConfigSpec() - flagSourceConfig.Sources = []v1alpha1.Source{ + flagSourceConfig.Sources = []api.Source{ { Source: "my-namespace/server-side", - Provider: v1alpha1.SyncProviderKubernetes, + Provider: apicommon.SyncProviderKubernetes, }, } @@ -299,10 +301,10 @@ func TestFlagdContainerInjector_InjectFlagdFilePathSource(t *testing.T) { flagSourceConfig := getFlagSourceConfigSpec() - flagSourceConfig.Sources = []v1alpha1.Source{ + flagSourceConfig.Sources = []api.Source{ { Source: "my-namespace/server-side", - Provider: v1alpha1.SyncProviderFilepath, + Provider: apicommon.SyncProviderFilepath, }, } @@ -383,10 +385,10 @@ func TestFlagdContainerInjector_InjectFlagdFilePathSource_UpdateReferencedConfig flagSourceConfig := getFlagSourceConfigSpec() - flagSourceConfig.Sources = []v1alpha1.Source{ + flagSourceConfig.Sources = []api.Source{ { Source: "my-namespace/server-side", - Provider: v1alpha1.SyncProviderFilepath, + Provider: apicommon.SyncProviderFilepath, }, } @@ -454,11 +456,11 @@ func TestFlagdContainerInjector_InjectHttpSource(t *testing.T) { flagSourceConfig := getFlagSourceConfigSpec() - flagSourceConfig.Sources = []v1alpha1.Source{ + flagSourceConfig.Sources = []api.Source{ { Source: "http://localhost:8013", HttpSyncBearerToken: "my-token", - Provider: v1alpha1.SyncProviderHttp, + Provider: apicommon.SyncProviderHttp, }, } @@ -496,10 +498,10 @@ func TestFlagdContainerInjector_InjectGrpcSource(t *testing.T) { flagSourceConfig := getFlagSourceConfigSpec() - flagSourceConfig.Sources = []v1alpha1.Source{ + flagSourceConfig.Sources = []api.Source{ { Source: "grpc://localhost:8013", - Provider: v1alpha1.SyncProviderGrpc, + Provider: apicommon.SyncProviderGrpc, TLS: true, CertPath: "cert-path", ProviderID: "provider-id", @@ -541,9 +543,9 @@ func TestFlagdContainerInjector_InjectProxySource_ProxyNotAvailable(t *testing.T flagSourceConfig := getFlagSourceConfigSpec() - flagSourceConfig.Sources = []v1alpha1.Source{ + flagSourceConfig.Sources = []api.Source{ { - Provider: v1alpha1.SyncProviderFlagdProxy, + Provider: apicommon.SyncProviderFlagdProxy, }, } @@ -559,7 +561,7 @@ func TestFlagdContainerInjector_InjectProxySource_ProxyNotReady(t *testing.T) { namespace, fakeClient := initContainerInjectionTestEnv() flagdProxyDeployment := &appsV1.Deployment{ - ObjectMeta: metav1.ObjectMeta{Name: FlagdProxyDeploymentName, Namespace: namespace}, + ObjectMeta: metav1.ObjectMeta{Name: flagdproxy.FlagdProxyDeploymentName, Namespace: namespace}, } err := fakeClient.Create(context.Background(), flagdProxyDeployment) @@ -582,9 +584,9 @@ func TestFlagdContainerInjector_InjectProxySource_ProxyNotReady(t *testing.T) { flagSourceConfig := getFlagSourceConfigSpec() - flagSourceConfig.Sources = []v1alpha1.Source{ + flagSourceConfig.Sources = []api.Source{ { - Provider: v1alpha1.SyncProviderFlagdProxy, + Provider: apicommon.SyncProviderFlagdProxy, }, } @@ -598,7 +600,7 @@ func TestFlagdContainerInjector_InjectProxySource_ProxyIsReady(t *testing.T) { namespace, fakeClient := initContainerInjectionTestEnv() flagdProxyDeployment := &appsV1.Deployment{ - ObjectMeta: metav1.ObjectMeta{Name: FlagdProxyDeploymentName, Namespace: namespace}, + ObjectMeta: metav1.ObjectMeta{Name: flagdproxy.FlagdProxyDeploymentName, Namespace: namespace}, } err := fakeClient.Create(context.Background(), flagdProxyDeployment) @@ -626,9 +628,9 @@ func TestFlagdContainerInjector_InjectProxySource_ProxyIsReady(t *testing.T) { flagSourceConfig := getFlagSourceConfigSpec() - flagSourceConfig.Sources = []v1alpha1.Source{ + flagSourceConfig.Sources = []api.Source{ { - Provider: v1alpha1.SyncProviderFlagdProxy, + Provider: apicommon.SyncProviderFlagdProxy, }, } @@ -707,7 +709,7 @@ func TestFlagdContainerInjector_InjectUnknownSyncProvider(t *testing.T) { flagSourceConfig := getFlagSourceConfigSpec() - flagSourceConfig.Sources = []v1alpha1.Source{ + flagSourceConfig.Sources = []api.Source{ { Provider: "unknown", }, @@ -721,7 +723,7 @@ func TestFlagdContainerInjector_InjectUnknownSyncProvider(t *testing.T) { func TestFlagdContainerInjector_createConfigMap(t *testing.T) { - _ = v1alpha1.AddToScheme(scheme.Scheme) + _ = api.AddToScheme(scheme.Scheme) fakeClientBuilder := fake.NewClientBuilder(). WithScheme(scheme.Scheme) @@ -736,7 +738,7 @@ func TestFlagdContainerInjector_createConfigMap(t *testing.T) { wantErr error }{ { - name: "feature flag config not found", + name: "featureflag not found", flagdInjector: &FlagdContainerInjector{ Client: fakeClientBuilder.Build(), Logger: testr.New(t), @@ -744,12 +746,12 @@ func TestFlagdContainerInjector_createConfigMap(t *testing.T) { namespace: "myns", confname: "mypod", ownerRefs: []metav1.OwnerReference{{}}, - wantErr: errors.New("could not retrieve feature flag configuration myns/mypod: featureflagconfigurations.core.openfeature.dev \"mypod\" not found"), + wantErr: errors.New("could not retrieve featureflag myns/mypod: featureflags.core.openfeature.dev \"mypod\" not found"), }, { - name: "feature flag config found, config map created", + name: "featureflag found, config map created", flagdInjector: &FlagdContainerInjector{ - Client: fakeClientBuilder.WithObjects(&v1alpha1.FeatureFlagConfiguration{ + Client: fakeClientBuilder.WithObjects(&api.FeatureFlag{ ObjectMeta: metav1.ObjectMeta{ Name: "myconf", Namespace: "myns", @@ -776,7 +778,7 @@ func TestFlagdContainerInjector_createConfigMap(t *testing.T) { require.Nil(t, err) require.Equal(t, map[string]string{ - "openfeature.dev/featureflagconfiguration": tt.confname, + "openfeature.dev/featureflag": tt.confname, }, ffConfig.Annotations) require.EqualValues(t, utils.FalseVal(), ffConfig.OwnerReferences[0].Controller) @@ -795,7 +797,7 @@ func TestFlagdContainerInjector_createConfigMap(t *testing.T) { func initContainerInjectionTestEnv() (string, client.WithWatch) { namespace := "my-namespace" - _ = v1alpha1.AddToScheme(scheme.Scheme) + _ = api.AddToScheme(scheme.Scheme) serviceAccount := &v1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ @@ -810,12 +812,12 @@ func initContainerInjectionTestEnv() (string, client.WithWatch) { }, } - ffConfig := &v1alpha1.FeatureFlagConfiguration{ + ffConfig := &api.FeatureFlag{ ObjectMeta: metav1.ObjectMeta{ Name: "server-side", Namespace: namespace, }, - Spec: v1alpha1.FeatureFlagConfigurationSpec{}, + Spec: api.FeatureFlagSpec{}, } fakeClientBuilder := fake.NewClientBuilder(). @@ -825,14 +827,14 @@ func initContainerInjectionTestEnv() (string, client.WithWatch) { return namespace, fakeClient } -func getFlagSourceConfigSpec() *v1alpha1.FlagSourceConfigurationSpec { +func getFlagSourceConfigSpec() *api.FeatureFlagSourceSpec { probesEnabled := true - return &v1alpha1.FlagSourceConfigurationSpec{ - MetricsPort: 8014, - Port: 8013, - Image: "flagd", - Tag: "0.5.0", + return &api.FeatureFlagSourceSpec{ + ManagementPort: 8014, + Port: 8013, + Image: "flagd", + Tag: "0.5.0", EnvVars: []v1.EnvVar{ { Name: "my-env-var", @@ -944,14 +946,14 @@ func intPtr(i int64) *int64 { return &i } -func getProxyConfig() *FlagdProxyConfiguration { - return &FlagdProxyConfiguration{ - Port: 8013, - MetricsPort: 8014, - DebugLogging: false, - Image: "flagd", - Tag: "0.5.0", - Namespace: "my-namespace", +func getProxyConfig() *flagdproxy.FlagdProxyConfiguration { + return &flagdproxy.FlagdProxyConfiguration{ + Port: 8013, + ManagementPort: 8014, + DebugLogging: false, + Image: "flagd", + Tag: "0.5.0", + Namespace: "my-namespace", } } @@ -1181,7 +1183,7 @@ func TestFlagdContainerInjector_EnableClusterRoleBinding_ServiceAccountNotFound( func initEnableClusterroleBindingTestEnv() (string, client.WithWatch) { namespace := "my-namespace" - _ = v1alpha1.AddToScheme(scheme.Scheme) + _ = api.AddToScheme(scheme.Scheme) fakeClientBuilder := fake.NewClientBuilder(). WithScheme(scheme.Scheme) diff --git a/controllers/common/flagd-proxy.go b/common/flagdproxy/flagdproxy.go similarity index 85% rename from controllers/common/flagd-proxy.go rename to common/flagdproxy/flagdproxy.go index 43475cf42..c40249a9d 100644 --- a/controllers/common/flagd-proxy.go +++ b/common/flagdproxy/flagdproxy.go @@ -1,4 +1,4 @@ -package common +package flagdproxy import ( "context" @@ -6,8 +6,7 @@ import ( "os" "github.com/go-logr/logr" - corev1alpha1 "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" - "github.com/open-feature/open-feature-operator/pkg/utils" + "github.com/open-feature/open-feature-operator/common/utils" appsV1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -22,20 +21,20 @@ const ( FlagdProxyServiceAccountName = "open-feature-operator-flagd-proxy" FlagdProxyServiceName = "flagd-proxy-svc" // renovate: datasource=github-tags depName=open-feature/flagd/flagd-proxy - DefaultFlagdProxyTag = "v0.2.8" - DefaultFlagdProxyImage = "ghcr.io/open-feature/flagd-proxy" - DefaultFlagdProxyPort = 8015 - DefaultFlagdProxyMetricsPort = 8016 - DefaultFlagdProxyDebugLogging = false - DefaultFlagdProxyNamespace = "open-feature-operator-system" - - envVarPodNamespace = "POD_NAMESPACE" - envVarProxyImage = "FLAGD_PROXY_IMAGE" - envVarProxyTag = "FLAGD_PROXY_TAG" - envVarProxyPort = "FLAGD_PROXY_PORT" - envVarProxyMetricsPort = "FLAGD_PROXY_METRICS_PORT" - envVarProxyDebugLogging = "FLAGD_PROXY_DEBUG_LOGGING" - operatorDeploymentName = "open-feature-operator-controller-manager" + DefaultFlagdProxyTag = "v0.3.0" + DefaultFlagdProxyImage = "ghcr.io/open-feature/flagd-proxy" + DefaultFlagdProxyPort = 8015 + DefaultFlagdProxyManagementPort = 8016 + DefaultFlagdProxyDebugLogging = false + DefaultFlagdProxyNamespace = "open-feature-operator-system" + + envVarPodNamespace = "POD_NAMESPACE" + envVarProxyImage = "FLAGD_PROXY_IMAGE" + envVarProxyTag = "FLAGD_PROXY_TAG" + envVarProxyPort = "FLAGD_PROXY_PORT" + envVarProxyManagementPort = "FLAGD_PROXY_MANAGEMENT_PORT" + envVarProxyDebugLogging = "FLAGD_PROXY_DEBUG_LOGGING" + operatorDeploymentName = "open-feature-operator-controller-manager" ) type FlagdProxyHandler struct { @@ -46,7 +45,7 @@ type FlagdProxyHandler struct { type FlagdProxyConfiguration struct { Port int - MetricsPort int + ManagementPort int DebugLogging bool Image string Tag string @@ -79,11 +78,11 @@ func NewFlagdProxyConfiguration() (*FlagdProxyConfiguration, error) { } config.Port = port - metricsPort, err := utils.GetIntEnvVar(envVarProxyMetricsPort, DefaultFlagdProxyMetricsPort) + managementPort, err := utils.GetIntEnvVar(envVarProxyManagementPort, DefaultFlagdProxyManagementPort) if err != nil { return config, err } - config.MetricsPort = metricsPort + config.ManagementPort = managementPort kpDebugLogging, err := utils.GetBoolEnvVar(envVarProxyDebugLogging, DefaultFlagdProxyDebugLogging) if err != nil { @@ -106,7 +105,7 @@ func (f *FlagdProxyHandler) Config() *FlagdProxyConfiguration { return f.config } -func (f *FlagdProxyHandler) HandleFlagdProxy(ctx context.Context, flagSourceConfiguration *corev1alpha1.FlagSourceConfiguration) error { +func (f *FlagdProxyHandler) HandleFlagdProxy(ctx context.Context) error { exists, err := f.doesFlagdProxyExist(ctx) if err != nil { return err @@ -165,7 +164,7 @@ func (f *FlagdProxyHandler) newFlagdProxyManifest(ownerReferences []metav1.Owner args := []string{ "start", "--metrics-port", - fmt.Sprintf("%d", f.config.MetricsPort), + fmt.Sprintf("%d", f.config.ManagementPort), } if f.config.DebugLogging { args = append(args, "--debug") @@ -210,7 +209,7 @@ func (f *FlagdProxyHandler) newFlagdProxyManifest(ownerReferences []metav1.Owner }, { Name: "metrics-port", - ContainerPort: int32(f.config.MetricsPort), + ContainerPort: int32(f.config.ManagementPort), }, }, Args: args, diff --git a/controllers/common/flagd-proxy_test.go b/common/flagdproxy/flagdproxy_test.go similarity index 93% rename from controllers/common/flagd-proxy_test.go rename to common/flagdproxy/flagdproxy_test.go index 11b90bc03..2dd461d61 100644 --- a/controllers/common/flagd-proxy_test.go +++ b/common/flagdproxy/flagdproxy_test.go @@ -1,4 +1,4 @@ -package common +package flagdproxy import ( "context" @@ -20,7 +20,7 @@ func TestNewFlagdProxyConfiguration(t *testing.T) { require.NotNil(t, kpConfig) require.Equal(t, &FlagdProxyConfiguration{ Port: 8015, - MetricsPort: 8016, + ManagementPort: 8016, DebugLogging: false, Image: DefaultFlagdProxyImage, Tag: DefaultFlagdProxyTag, @@ -35,7 +35,7 @@ func TestNewFlagdProxyConfiguration_OverrideEnvVars(t *testing.T) { t.Setenv(envVarProxyTag, "my-tag") t.Setenv(envVarPodNamespace, "my-namespace") t.Setenv(envVarProxyPort, "8080") - t.Setenv(envVarProxyMetricsPort, "8081") + t.Setenv(envVarProxyManagementPort, "8081") t.Setenv(envVarProxyDebugLogging, "true") kpConfig, err := NewFlagdProxyConfiguration() @@ -44,7 +44,7 @@ func TestNewFlagdProxyConfiguration_OverrideEnvVars(t *testing.T) { require.NotNil(t, kpConfig) require.Equal(t, &FlagdProxyConfiguration{ Port: 8080, - MetricsPort: 8081, + ManagementPort: 8081, DebugLogging: true, Image: "my-image", Tag: "my-tag", @@ -96,7 +96,7 @@ func TestFlagdProxyHandler_HandleFlagdProxy_ProxyExists(t *testing.T) { require.NotNil(t, ph) - err = ph.HandleFlagdProxy(context.Background(), nil) + err = ph.HandleFlagdProxy(context.Background()) require.Nil(t, err) @@ -125,7 +125,7 @@ func TestFlagdProxyHandler_HandleFlagdProxy_CreateProxy(t *testing.T) { require.NotNil(t, ph) - err = ph.HandleFlagdProxy(context.Background(), nil) + err = ph.HandleFlagdProxy(context.Background()) require.Nil(t, err) diff --git a/pkg/types/source-config.go b/common/types/source-config.go similarity index 100% rename from pkg/types/source-config.go rename to common/types/source-config.go diff --git a/pkg/utils/utils.go b/common/utils/utils.go similarity index 84% rename from pkg/utils/utils.go rename to common/utils/utils.go index a8c6b1070..a9b530b85 100644 --- a/pkg/utils/utils.go +++ b/common/utils/utils.go @@ -59,11 +59,11 @@ func GetBoolEnvVar(key string, defaultVal bool) (bool, error) { } // unique string used to create unique volume mount and file name -func FeatureFlagConfigurationId(namespace, name string) string { +func FeatureFlagId(namespace, name string) string { return fmt.Sprintf("%s_%s", namespace, name) } // unique key (and filename) for configMap data -func FeatureFlagConfigurationConfigMapKey(namespace, name string) string { - return fmt.Sprintf("%s.flagd.json", FeatureFlagConfigurationId(namespace, name)) +func FeatureFlagConfigMapKey(namespace, name string) string { + return fmt.Sprintf("%s.flagd.json", FeatureFlagId(namespace, name)) } diff --git a/pkg/utils/utils_test.go b/common/utils/utils_test.go similarity index 66% rename from pkg/utils/utils_test.go rename to common/utils/utils_test.go index 7e7b6d170..441bf1d45 100644 --- a/pkg/utils/utils_test.go +++ b/common/utils/utils_test.go @@ -6,12 +6,12 @@ import ( "github.com/stretchr/testify/require" ) -func Test_FeatureFlagConfigurationId(t *testing.T) { - require.Equal(t, "namespace_name", FeatureFlagConfigurationId("namespace", "name")) +func Test_FeatureFlagId(t *testing.T) { + require.Equal(t, "namespace_name", FeatureFlagId("namespace", "name")) } -func Test_FeatureFlagConfigurationConfigMapKey(t *testing.T) { - require.Equal(t, "namespace_name.flagd.json", FeatureFlagConfigurationConfigMapKey("namespace", "name")) +func Test_FeatureFlagConfigMapKey(t *testing.T) { + require.Equal(t, "namespace_name.flagd.json", FeatureFlagConfigMapKey("namespace", "name")) } func Test_FalseVal(t *testing.T) { diff --git a/config/crd/bases/core.openfeature.dev_featureflagsources.yaml b/config/crd/bases/core.openfeature.dev_featureflagsources.yaml index 1324cfed2..534b071b7 100644 --- a/config/crd/bases/core.openfeature.dev_featureflagsources.yaml +++ b/config/crd/bases/core.openfeature.dev_featureflagsources.yaml @@ -50,8 +50,8 @@ spec: type: string envVars: description: EnvVars define the env vars to be applied to the sidecar, - any env vars in FeatureFlagConfiguration CRs are added at the lowest - index, all values will have the EnvVarPrefix applied, default FLAGD + any env vars in FeatureFlag CRs are added at the lowest index, all + values will have the EnvVarPrefix applied, default FLAGD items: description: EnvVar represents an environment variable present in a Container. @@ -170,9 +170,9 @@ spec: description: LogFormat allows for the sidecar log format to be overridden, defaults to 'json' type: string - metricsPort: - description: MetricsPort defines the port to serve metrics on, defaults - to 8014 + managementPort: + description: ManagemetPort defines the port to serve management on, + defaults to 8014 format: int32 type: integer otelCollectorUri: diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 7c73909b0..b7902f7e0 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -2,8 +2,6 @@ # since it depends on service name and namespace that are out of this kustomize package. # It should be run by config/default resources: -- bases/core.openfeature.dev_featureflagconfigurations.yaml -- bases/core.openfeature.dev_flagsourceconfigurations.yaml - bases/core.openfeature.dev_featureflags.yaml - bases/core.openfeature.dev_featureflagsources.yaml #+kubebuilder:scaffold:crdkustomizeresource @@ -11,16 +9,12 @@ resources: patchesStrategicMerge: # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. # patches here are for enabling the conversion webhook for each CRD -- patches/webhook_in_featureflagconfigurations.yaml -- patches/webhook_in_flagsourceconfigurations.yaml #- patches/webhook_in_featureflags.yaml #- patches/webhook_in_featureflagsources.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. # patches here are for enabling the CA injection for each CRD -- patches/cainjection_in_featureflagconfigurations.yaml -- patches/cainjection_in_flagsourceconfigurations.yaml #- patches/cainjection_in_featureflags.yaml #- patches/cainjection_in_featureflagsources.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch diff --git a/config/crd/patches/cainjection_in_core_flagsourceconfigurations.yaml b/config/crd/patches/cainjection_in_core_flagsourceconfigurations.yaml deleted file mode 100644 index 11e3fce17..000000000 --- a/config/crd/patches/cainjection_in_core_flagsourceconfigurations.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) - name: flagsourceconfigurations.core.openfeature.dev diff --git a/config/crd/patches/cainjection_in_featureflagconfigurations.yaml b/config/crd/patches/cainjection_in_featureflagconfigurations.yaml deleted file mode 100644 index 74c4735c4..000000000 --- a/config/crd/patches/cainjection_in_featureflagconfigurations.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) - name: featureflagconfigurations.core.openfeature.dev diff --git a/config/crd/patches/cainjection_in_flagsourceconfigurations.yaml b/config/crd/patches/cainjection_in_flagsourceconfigurations.yaml deleted file mode 100644 index 11e3fce17..000000000 --- a/config/crd/patches/cainjection_in_flagsourceconfigurations.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) - name: flagsourceconfigurations.core.openfeature.dev diff --git a/config/crd/patches/webhook_in_core_featureflags.yaml b/config/crd/patches/webhook_in_core_featureflags.yaml deleted file mode 100644 index d52034067..000000000 --- a/config/crd/patches/webhook_in_core_featureflags.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: featureflags.core.openfeature.dev -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/config/crd/patches/webhook_in_core_featureflagsources.yaml b/config/crd/patches/webhook_in_core_featureflagsources.yaml deleted file mode 100644 index 624268108..000000000 --- a/config/crd/patches/webhook_in_core_featureflagsources.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: featureflagsources.core.openfeature.dev -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/config/crd/patches/webhook_in_core_flagsourceconfigurations.yaml b/config/crd/patches/webhook_in_core_flagsourceconfigurations.yaml deleted file mode 100644 index 2ae67ba6a..000000000 --- a/config/crd/patches/webhook_in_core_flagsourceconfigurations.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: flagsourceconfigurations.core.openfeature.dev -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/config/crd/patches/webhook_in_featureflagconfigurations.yaml b/config/crd/patches/webhook_in_featureflagconfigurations.yaml deleted file mode 100644 index 0983a2ebb..000000000 --- a/config/crd/patches/webhook_in_featureflagconfigurations.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: featureflagconfigurations.core.openfeature.dev -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/config/crd/patches/webhook_in_flagsourceconfigurations.yaml b/config/crd/patches/webhook_in_flagsourceconfigurations.yaml deleted file mode 100644 index 2ae67ba6a..000000000 --- a/config/crd/patches/webhook_in_flagsourceconfigurations.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: flagsourceconfigurations.core.openfeature.dev -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/config/default/webhookcainjection_patch.yaml b/config/default/webhookcainjection_patch.yaml index 02ab515d4..28b1826d4 100644 --- a/config/default/webhookcainjection_patch.yaml +++ b/config/default/webhookcainjection_patch.yaml @@ -6,10 +6,3 @@ metadata: name: mutating-webhook-configuration annotations: cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) ---- -apiVersion: admissionregistration.k8s.io/v1 -kind: ValidatingWebhookConfiguration -metadata: - name: validating-webhook-configuration - annotations: - cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) diff --git a/config/overlays/helm/manager.yaml b/config/overlays/helm/manager.yaml index 5b7098fe5..94818e3b1 100644 --- a/config/overlays/helm/manager.yaml +++ b/config/overlays/helm/manager.yaml @@ -18,8 +18,8 @@ spec: cpu: "{{ .Values.controllerManager.manager.resources.requests.cpu }}" memory: "{{ .Values.controllerManager.manager.resources.requests.memory }}" env: - - name: SIDECAR_METRICS_PORT - value: "{{ .Values.sidecarConfiguration.metricsPort }}" + - name: SIDECAR_MANAGEMENT_PORT + value: "{{ .Values.sidecarConfiguration.managementPort }}" - name: SIDECAR_PORT value: "{{ .Values.sidecarConfiguration.port }}" - name: SIDECAR_SOCKET_PATH @@ -46,8 +46,8 @@ spec: value: "{{ .Values.flagdProxyConfiguration.image.tag }}" - name: FLAGD_PROXY_PORT value: "{{ .Values.flagdProxyConfiguration.port }}" - - name: FLAGD_PROXY_METRICS_PORT - value: "{{ .Values.flagdProxyConfiguration.metricsPort }}" + - name: FLAGD_PROXY_MANAGEMENT_PORT + value: "{{ .Values.flagdProxyConfiguration.managementPort }}" - name: FLAGD_PROXY_DEBUG_LOGGING value: "{{ .Values.flagdProxyConfiguration.debugLogging }}" - name: kube-rbac-proxy diff --git a/config/rbac/core_flagsourceconfiguration_editor_role.yaml b/config/rbac/core_flagsourceconfiguration_editor_role.yaml deleted file mode 100644 index 16e463740..000000000 --- a/config/rbac/core_flagsourceconfiguration_editor_role.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# permissions for end users to edit flagsourceconfigurations. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: flagsourceconfiguration-editor-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: open-feature-operator - app.kubernetes.io/part-of: open-feature-operator - app.kubernetes.io/managed-by: kustomize - name: flagsourceconfiguration-editor-role -rules: -- apiGroups: - - core.openfeature.dev - resources: - - flagsourceconfigurations - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - core.openfeature.dev - resources: - - flagsourceconfigurations/status - verbs: - - get diff --git a/config/rbac/core_flagsourceconfiguration_viewer_role.yaml b/config/rbac/core_flagsourceconfiguration_viewer_role.yaml deleted file mode 100644 index 1193eed64..000000000 --- a/config/rbac/core_flagsourceconfiguration_viewer_role.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# permissions for end users to view flagsourceconfigurations. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: flagsourceconfiguration-viewer-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: open-feature-operator - app.kubernetes.io/part-of: open-feature-operator - app.kubernetes.io/managed-by: kustomize - name: flagsourceconfiguration-viewer-role -rules: -- apiGroups: - - core.openfeature.dev - resources: - - flagsourceconfigurations - verbs: - - get - - list - - watch -- apiGroups: - - core.openfeature.dev - resources: - - flagsourceconfigurations/status - verbs: - - get diff --git a/config/rbac/featureflagconfiguration_editor_role.yaml b/config/rbac/featureflagconfiguration_editor_role.yaml deleted file mode 100644 index ecc6f1600..000000000 --- a/config/rbac/featureflagconfiguration_editor_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# permissions for end users to edit featureflagconfigurations. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: featureflagconfiguration-editor-role -rules: -- apiGroups: - - config.openfeature.dev - resources: - - featureflagconfigurations - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - config.openfeature.dev - resources: - - featureflagconfigurations/status - verbs: - - get diff --git a/config/rbac/featureflagconfiguration_viewer_role.yaml b/config/rbac/featureflagconfiguration_viewer_role.yaml deleted file mode 100644 index 1a2c23ba3..000000000 --- a/config/rbac/featureflagconfiguration_viewer_role.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# permissions for end users to view featureflagconfigurations. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: featureflagconfiguration-viewer-role -rules: -- apiGroups: - - config.openfeature.dev - resources: - - featureflagconfigurations - verbs: - - get - - list - - watch -- apiGroups: - - config.openfeature.dev - resources: - - featureflagconfigurations/status - verbs: - - get diff --git a/config/rbac/flagd_kubernetes_sync_clusterrole.yaml b/config/rbac/flagd_kubernetes_sync_clusterrole.yaml index b6849439e..65e20af9b 100644 --- a/config/rbac/flagd_kubernetes_sync_clusterrole.yaml +++ b/config/rbac/flagd_kubernetes_sync_clusterrole.yaml @@ -5,5 +5,5 @@ metadata: name: flagd-kubernetes-sync rules: - apiGroups: ["core.openfeature.dev"] - resources: ["flagsourceconfigurations", "featureflagconfigurations"] + resources: ["featureflagsources", "featureflags"] verbs: ["get", "watch", "list"] diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index eca339434..0fb890069 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -60,7 +60,7 @@ rules: - apiGroups: - core.openfeature.dev resources: - - featureflagconfigurations + - featureflagsources verbs: - create - delete @@ -72,39 +72,13 @@ rules: - apiGroups: - core.openfeature.dev resources: - - featureflagconfigurations/finalizers + - featureflagsources/finalizers verbs: - update - apiGroups: - core.openfeature.dev resources: - - featureflagconfigurations/status - verbs: - - get - - patch - - update -- apiGroups: - - core.openfeature.dev - resources: - - flagsourceconfigurations - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - core.openfeature.dev - resources: - - flagsourceconfigurations/finalizers - verbs: - - update -- apiGroups: - - core.openfeature.dev - resources: - - flagsourceconfigurations/status + - featureflagsources/status verbs: - get - patch diff --git a/config/samples/core_v1beta1_featureflagsource.yaml b/config/samples/core_v1beta1_featureflagsource.yaml index 9e5c9f9d1..c1651528a 100644 --- a/config/samples/core_v1beta1_featureflagsource.yaml +++ b/config/samples/core_v1beta1_featureflagsource.yaml @@ -3,7 +3,7 @@ kind: FeatureFlagSource metadata: name: featureflagsource-sample spec: - metricsPort: 8080 + managementPort: 8080 evaluator: json defaultSyncProvider: file tag: latest diff --git a/config/samples/crds/custom_provider.yaml b/config/samples/crds/custom_provider.yaml deleted file mode 100644 index 79dcad67e..000000000 --- a/config/samples/crds/custom_provider.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: core.openfeature.dev/v1alpha1 -kind: FeatureFlagConfiguration -metadata: - name: featureflagconfiguration-sample -spec: - flagDSpec: - envs: - - name: FOO - value: BAR - serviceProvider: - name: "flagd" - credentials: - name: "sample-provider-secret" - namespace: "default" - featureFlagSpec: | - {} diff --git a/config/samples/crds/featureflagconfiguration.yaml b/config/samples/crds/featureflagconfiguration.yaml deleted file mode 100644 index 427e4c5f7..000000000 --- a/config/samples/crds/featureflagconfiguration.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: core.openfeature.dev/v1alpha1 -kind: FeatureFlagConfiguration -metadata: - name: featureflagconfiguration-sample -spec: - flagDSpec: - envs: - - name: FOO - value: BAR - featureFlagSpec: | - {} \ No newline at end of file diff --git a/config/samples/deployment.yaml b/config/samples/deployment.yaml index 95eb3dadf..218b7b5ba 100644 --- a/config/samples/deployment.yaml +++ b/config/samples/deployment.yaml @@ -13,7 +13,7 @@ spec: app: nginx annotations: openfeature.dev/enabled: "true" - openfeature.dev/featureflagconfiguration: "featureflagconfiguration-sample" + openfeature.dev/featureflagsource: "configuration-sample" spec: containers: - name: nginx @@ -36,7 +36,7 @@ spec: app: nginx annotations: openfeature.dev/enabled: "true" - openfeature.dev/featureflagconfiguration: "featureflagconfiguration-sample" + openfeature.dev/featureflagsource: "configuration-sample" spec: containers: - name: nginx diff --git a/config/samples/end-to-end.yaml b/config/samples/end-to-end.yaml index 4403a55a9..27485bf81 100644 --- a/config/samples/end-to-end.yaml +++ b/config/samples/end-to-end.yaml @@ -4,48 +4,22 @@ kind: Namespace metadata: name: open-feature-demo --- -apiVersion: core.openfeature.dev/v1alpha2 -kind: FeatureFlagConfiguration +apiVersion: core.openfeature.dev/v1beta1 +kind: FeatureFlag metadata: - name: end-to-end - namespace: open-feature-demo + name: featureflag-sample spec: - featureFlagSpec: + flagSpec: flags: - new-welcome-message: - state: ENABLED + "simple-flag": + state: "ENABLED" variants: "on": true "off": false defaultVariant: "on" - hex-color: - state: ENABLED - variants: - red: CC0000 - green: 00CC00 - blue: 0000CC - yellow: yellow - defaultVariant: blue - fib-algo: - state: ENABLED - variants: - recursive: recursive - memo: memo - loop: loop - binet: binet - defaultVariant: recursive - "targeting": { - "if": [ - { - "in": [ "@faas.com", { - "var": [ "email" ] - } ] - }, "binet", null - ] - } --- -apiVersion: core.openfeature.dev/v1alpha2 -kind: FlagSourceConfiguration +apiVersion: core.openfeature.dev/v1beta1 +kind: FeatureFlagSource metadata: name: end-to-end namespace: open-feature-demo @@ -73,7 +47,7 @@ spec: app: open-feature-demo annotations: openfeature.dev/enabled: "true" - openfeature.dev/flagsourceconfiguration: "end-to-end" + openfeature.dev/featureflagsource: "end-to-end" spec: serviceAccountName: open-feature-demo-sa containers: diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml index 4c44bd898..e03b39199 100644 --- a/config/webhook/manifests.yaml +++ b/config/webhook/manifests.yaml @@ -25,30 +25,3 @@ webhooks: resources: - pods sideEffects: NoneOnDryRun ---- -apiVersion: admissionregistration.k8s.io/v1 -kind: ValidatingWebhookConfiguration -metadata: - creationTimestamp: null - name: validating-webhook-configuration -webhooks: -- admissionReviewVersions: - - v1 - clientConfig: - service: - name: webhook-service - namespace: system - path: /validate-v1alpha1-featureflagconfiguration - failurePolicy: Fail - name: validate.featureflagconfiguration.openfeature.dev - rules: - - apiGroups: - - core.openfeature.dev - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - featureflagconfigurations - sideEffects: None diff --git a/controllers/common/mock/flagd-injector.go b/controllers/common/mock/flagd-injector.go deleted file mode 100644 index d08494763..000000000 --- a/controllers/common/mock/flagd-injector.go +++ /dev/null @@ -1,65 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: controllers/common/flagd-injector.go - -// Package commonmock is a generated GoMock package. -package commonmock - -import ( - context "context" - reflect "reflect" - gomock "github.com/golang/mock/gomock" - v1alpha1 "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" - v1 "k8s.io/api/core/v1" - v10 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// MockIFlagdContainerInjector is a mock of IFlagdContainerInjector interface. -type MockIFlagdContainerInjector struct { - ctrl *gomock.Controller - recorder *MockIFlagdContainerInjectorMockRecorder -} - -// MockIFlagdContainerInjectorMockRecorder is the mock recorder for MockIFlagdContainerInjector. -type MockIFlagdContainerInjectorMockRecorder struct { - mock *MockIFlagdContainerInjector -} - -// NewMockIFlagdContainerInjector creates a new mock instance. -func NewMockIFlagdContainerInjector(ctrl *gomock.Controller) *MockIFlagdContainerInjector { - mock := &MockIFlagdContainerInjector{ctrl: ctrl} - mock.recorder = &MockIFlagdContainerInjectorMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockIFlagdContainerInjector) EXPECT() *MockIFlagdContainerInjectorMockRecorder { - return m.recorder -} - -// EnableClusterRoleBinding mocks base method. -func (m *MockIFlagdContainerInjector) EnableClusterRoleBinding(ctx context.Context, namespace, serviceAccountName string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EnableClusterRoleBinding", ctx, namespace, serviceAccountName) - ret0, _ := ret[0].(error) - return ret0 -} - -// EnableClusterRoleBinding indicates an expected call of EnableClusterRoleBinding. -func (mr *MockIFlagdContainerInjectorMockRecorder) EnableClusterRoleBinding(ctx, namespace, serviceAccountName interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnableClusterRoleBinding", reflect.TypeOf((*MockIFlagdContainerInjector)(nil).EnableClusterRoleBinding), ctx, namespace, serviceAccountName) -} - -// InjectFlagd mocks base method. -func (m *MockIFlagdContainerInjector) InjectFlagd(ctx context.Context, objectMeta *v10.ObjectMeta, podSpec *v1.PodSpec, flagSourceConfig *v1alpha1.FlagSourceConfigurationSpec) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InjectFlagd", ctx, objectMeta, podSpec, flagSourceConfig) - ret0, _ := ret[0].(error) - return ret0 -} - -// InjectFlagd indicates an expected call of InjectFlagd. -func (mr *MockIFlagdContainerInjectorMockRecorder) InjectFlagd(ctx, objectMeta, podSpec, flagSourceConfig interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InjectFlagd", reflect.TypeOf((*MockIFlagdContainerInjector)(nil).InjectFlagd), ctx, objectMeta, podSpec, flagSourceConfig) -} diff --git a/controllers/core/featureflagconfiguration/controller.go b/controllers/core/featureflagconfiguration/controller.go deleted file mode 100644 index 564a438e5..000000000 --- a/controllers/core/featureflagconfiguration/controller.go +++ /dev/null @@ -1,187 +0,0 @@ -/* -Copyright 2022. - -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 featureflagconfiguration - -import ( - "context" - - "github.com/go-logr/logr" - corev1alpha1 "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" - "github.com/open-feature/open-feature-operator/controllers/common" - "github.com/open-feature/open-feature-operator/pkg/utils" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/builder" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/predicate" -) - -// FeatureFlagConfigurationReconciler reconciles a FeatureFlagConfiguration object -type FeatureFlagConfigurationReconciler struct { - client.Client - - // Scheme contains the scheme of this controller - Scheme *runtime.Scheme - // ReqLogger contains the Logger of this controller - Log logr.Logger -} - -//+kubebuilder:rbac:groups=core.openfeature.dev,resources=featureflagconfigurations,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=core.openfeature.dev,resources=featureflagconfigurations/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=core.openfeature.dev,resources=featureflagconfigurations/finalizers,verbs=update - -// Reconcile is part of the main kubernetes reconciliation loop which aims to -// move the current state of the cluster closer to the desired state. -// TODO(user): Modify the Reconcile function to compare the state specified by -// the FeatureFlagConfiguration object against the actual cluster state, and then -// perform operations to make the cluster state reflect the state specified by -// the user. -// -// For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.11.0/pkg/reconcile - -const CrdName = "FeatureFlagConfiguration" - -//nolint:gocognit,gocyclo -func (r *FeatureFlagConfigurationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - r.Log.Info("Reconciling" + CrdName) - - ffconf := &corev1alpha1.FeatureFlagConfiguration{} - if err := r.Client.Get(ctx, req.NamespacedName, ffconf); err != nil { - if errors.IsNotFound(err) { - // taking down all associated K8s resources is handled by K8s - r.Log.Info(CrdName + " resource not found. Ignoring since object must be deleted") - return r.finishReconcile(nil, false) - } - r.Log.Error(err, "Failed to get the "+CrdName) - return r.finishReconcile(err, false) - } - - if ffconf.ObjectMeta.DeletionTimestamp.IsZero() { - // The object is not being deleted, so if it does not have our finalizer, - // then lets add the finalizer and update the object. This is equivalent - // registering our finalizer. - if !utils.ContainsString(ffconf.GetFinalizers(), common.FinalizerName) { - controllerutil.AddFinalizer(ffconf, common.FinalizerName) - if err := r.Update(ctx, ffconf); err != nil { - return r.finishReconcile(err, false) - } - } - } else { - // The object is being deleted - if utils.ContainsString(ffconf.GetFinalizers(), common.FinalizerName) { - controllerutil.RemoveFinalizer(ffconf, common.FinalizerName) - if err := r.Update(ctx, ffconf); err != nil { - return ctrl.Result{}, err - } - } - // Stop reconciliation as the item is being deleted - return r.finishReconcile(nil, false) - } - - // Check the provider on the FeatureFlagConfiguration - if !ffconf.Spec.ServiceProvider.IsSet() { - r.Log.Info("No service provider specified for FeatureFlagConfiguration, using FlagD") - ffconf.Spec.ServiceProvider = &corev1alpha1.FeatureFlagServiceProvider{ - Name: "flagd", - } - if err := r.Update(ctx, ffconf); err != nil { - r.Log.Error(err, "Failed to update FeatureFlagConfiguration service provider") - return r.finishReconcile(err, false) - } - } - - // Get list of configmaps - configMapList := &corev1.ConfigMapList{} - var ffConfigMapList []corev1.ConfigMap - if err := r.List(ctx, configMapList); err != nil { - return r.finishReconcile(err, false) - } - - // Get list of configmaps with annotation - for _, cm := range configMapList.Items { - val, ok := cm.GetAnnotations()["openfeature.dev/featureflagconfiguration"] - if ok && val == ffconf.Name { - ffConfigMapList = append(ffConfigMapList, cm) - } - } - - for _, cm := range ffConfigMapList { - // Append OwnerReference if not set - if !r.featureFlagResourceIsOwner(ffconf, cm) { - r.Log.Info("Setting owner reference for " + cm.Name) - cm.OwnerReferences = append(cm.OwnerReferences, ffconf.GetReference()) - err := r.Client.Update(ctx, &cm) - if err != nil { - return r.finishReconcile(err, true) - } - } else if len(cm.OwnerReferences) == 1 { - // Delete ConfigMap if the Controller is the only reference - r.Log.Info("Deleting configmap " + cm.Name) - err := r.Client.Delete(ctx, &cm) - return r.finishReconcile(err, true) - } - // Update ConfigMap Spec - r.Log.Info("Updating ConfigMap Spec " + cm.Name) - cm.Data = map[string]string{ - utils.FeatureFlagConfigurationConfigMapKey(cm.Namespace, cm.Name): ffconf.Spec.FeatureFlagSpec, - } - err := r.Client.Update(ctx, &cm) - if err != nil { - return r.finishReconcile(err, true) - } - } - - return r.finishReconcile(nil, false) -} - -func (r *FeatureFlagConfigurationReconciler) finishReconcile(err error, requeueImmediate bool) (ctrl.Result, error) { - if err != nil { - interval := common.ReconcileErrorInterval - if requeueImmediate { - interval = 0 - } - r.Log.Error(err, "Finished Reconciling "+CrdName+" with error: %w") - return ctrl.Result{Requeue: true, RequeueAfter: interval}, err - } - interval := common.ReconcileSuccessInterval - if requeueImmediate { - interval = 0 - } - r.Log.Info("Finished Reconciling " + CrdName) - return ctrl.Result{Requeue: true, RequeueAfter: interval}, nil -} - -func (r *FeatureFlagConfigurationReconciler) featureFlagResourceIsOwner(ff *corev1alpha1.FeatureFlagConfiguration, cm corev1.ConfigMap) bool { - for _, cmOwner := range cm.OwnerReferences { - if cmOwner.UID == ff.GetReference().UID { - return true - } - } - return false -} - -// SetupWithManager sets up the controller with the Manager. -func (r *FeatureFlagConfigurationReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&corev1alpha1.FeatureFlagConfiguration{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). - Owns(&corev1.ConfigMap{}). - Complete(r) -} diff --git a/controllers/core/featureflagconfiguration/controller_test.go b/controllers/core/featureflagconfiguration/controller_test.go deleted file mode 100644 index f26d7d0f0..000000000 --- a/controllers/core/featureflagconfiguration/controller_test.go +++ /dev/null @@ -1,175 +0,0 @@ -package featureflagconfiguration - -import ( - "context" - "testing" - - "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" - "github.com/open-feature/open-feature-operator/pkg/utils" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes/scheme" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client/fake" -) - -func TestFlagSourceConfigurationReconciler_Reconcile(t *testing.T) { - const ( - testNamespace = "test-namespace" - ffConfigName = "test-config" - cmName = "test-cm" - ) - - tests := []struct { - name string - ffConfig *v1alpha1.FeatureFlagConfiguration - cm *corev1.ConfigMap - wantProvider string - wantCM *corev1.ConfigMap - cmDeleted bool - }{ - { - name: "no provider set + no owner set -> ffconfig and cm will be updated", - cm: &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: cmName, - Namespace: testNamespace, - Annotations: map[string]string{ - "openfeature.dev/featureflagconfiguration": ffConfigName, - }, - }, - }, - ffConfig: createTestFFConfig(ffConfigName, testNamespace, cmName, ""), - wantProvider: "flagd", - wantCM: &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: cmName, - Namespace: testNamespace, - Annotations: map[string]string{ - "openfeature.dev/featureflagconfiguration": ffConfigName, - }, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "core.openfeature.dev/v1alpha1", - Kind: "FeatureFlagConfiguration", - Name: ffConfigName, - }, - }, - }, - Data: map[string]string{ - utils.FeatureFlagConfigurationConfigMapKey(testNamespace, cmName): "spec", - }, - }, - cmDeleted: false, - }, - { - name: "one owner ref set -> cm will be deleted", - cm: &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: cmName, - Namespace: testNamespace, - Annotations: map[string]string{ - "openfeature.dev/featureflagconfiguration": ffConfigName, - }, - }, - }, - ffConfig: createTestFFConfig(ffConfigName, testNamespace, cmName, ""), - wantProvider: "flagd", - wantCM: &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: cmName, - Namespace: testNamespace, - Annotations: map[string]string{ - "openfeature.dev/featureflagconfiguration": ffConfigName, - }, - }, - }, - cmDeleted: true, - }, - } - - err := v1alpha1.AddToScheme(scheme.Scheme) - require.Nil(t, err) - req := ctrl.Request{ - NamespacedName: types.NamespacedName{ - Namespace: testNamespace, - Name: ffConfigName, - }, - } - - ctx := context.TODO() - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // set up k8s fake client - fakeClient := fake.NewClientBuilder().WithScheme(scheme.Scheme).WithObjects(tt.ffConfig, tt.cm).Build() - - r := &FeatureFlagConfigurationReconciler{ - Client: fakeClient, - Log: ctrl.Log.WithName("featureflagconfiguration-controller"), - Scheme: fakeClient.Scheme(), - } - - if tt.cmDeleted { - // if configMap should be deleted, we need to set ffConfig as the only OwnerRef before executing the Reconcile function - ffConfig := &v1alpha1.FeatureFlagConfiguration{} - err = fakeClient.Get(ctx, types.NamespacedName{Name: ffConfigName, Namespace: testNamespace}, ffConfig) - require.Nil(t, err) - - cm := &corev1.ConfigMap{} - err = fakeClient.Get(ctx, types.NamespacedName{Name: cmName, Namespace: testNamespace}, cm) - require.Nil(t, err) - - cm.OwnerReferences = append(cm.OwnerReferences, ffConfig.GetReference()) - err := r.Client.Update(ctx, cm) - require.Nil(t, err) - } - - // reconcile - _, err = r.Reconcile(ctx, req) - require.Nil(t, err) - - ffConfig := &v1alpha1.FeatureFlagConfiguration{} - err = fakeClient.Get(ctx, types.NamespacedName{Name: ffConfigName, Namespace: testNamespace}, ffConfig) - require.Nil(t, err) - - // check that the provider name is set correctly - require.Equal(t, tt.wantProvider, ffConfig.Spec.ServiceProvider.Name) - - cm := &corev1.ConfigMap{} - err = fakeClient.Get(ctx, types.NamespacedName{Name: cmName, Namespace: testNamespace}, cm) - - if !tt.cmDeleted { - // if configMap should not be deleted, check the correct values - require.Nil(t, err) - require.Equal(t, tt.wantCM.Data, cm.Data) - require.Len(t, cm.OwnerReferences, len(tt.wantCM.OwnerReferences)) - require.Equal(t, tt.wantCM.OwnerReferences[0].APIVersion, cm.OwnerReferences[0].APIVersion) - require.Equal(t, tt.wantCM.OwnerReferences[0].Name, cm.OwnerReferences[0].Name) - require.Equal(t, tt.wantCM.OwnerReferences[0].Kind, cm.OwnerReferences[0].Kind) - } else { - // if configMap should be deleted, we expect error - require.NotNil(t, err) - } - }) - } -} - -func createTestFFConfig(ffConfigName string, testNamespace string, cmName string, provider string) *v1alpha1.FeatureFlagConfiguration { - fsConfig := &v1alpha1.FeatureFlagConfiguration{ - ObjectMeta: metav1.ObjectMeta{ - Name: ffConfigName, - Namespace: testNamespace, - }, - Spec: v1alpha1.FeatureFlagConfigurationSpec{ - ServiceProvider: &v1alpha1.FeatureFlagServiceProvider{ - Name: provider, - }, - FeatureFlagSpec: "spec", - }, - } - - return fsConfig -} diff --git a/controllers/core/flagsourceconfiguration/controller.go b/controllers/core/featureflagsource/controller.go similarity index 69% rename from controllers/core/flagsourceconfiguration/controller.go rename to controllers/core/featureflagsource/controller.go index 07894641d..93c62e87c 100644 --- a/controllers/core/flagsourceconfiguration/controller.go +++ b/controllers/core/featureflagsource/controller.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package flagsourceconfiguration +package featureflagsource import ( "context" @@ -23,8 +23,9 @@ import ( "time" "github.com/go-logr/logr" - corev1alpha1 "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" - "github.com/open-feature/open-feature-operator/controllers/common" + 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/flagdproxy" appsV1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" @@ -34,20 +35,20 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" ) -// FlagSourceConfigurationReconciler reconciles a FlagSourceConfiguration object -type FlagSourceConfigurationReconciler struct { +// FeatureFlagSourceReconciler reconciles a FeatureFlagSource object +type FeatureFlagSourceReconciler struct { client.Client Scheme *runtime.Scheme // ReqLogger contains the Logger of this controller Log logr.Logger - FlagdProxy *common.FlagdProxyHandler + FlagdProxy *flagdproxy.FlagdProxyHandler } -//+kubebuilder:rbac:groups=core.openfeature.dev,resources=flagsourceconfigurations,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=core.openfeature.dev,resources=flagsourceconfigurations/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=core.openfeature.dev,resources=featureflagsources,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=core.openfeature.dev,resources=featureflagsources/status,verbs=get;update;patch //+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups="",resources=services,verbs=get;list;create -//+kubebuilder:rbac:groups=core.openfeature.dev,resources=flagsourceconfigurations/finalizers,verbs=update +//+kubebuilder:rbac:groups=core.openfeature.dev,resources=featureflagsources/finalizers,verbs=update // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. @@ -56,11 +57,11 @@ type FlagSourceConfigurationReconciler struct { // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.13.0/pkg/reconcile // //nolint:gocyclo -func (r *FlagSourceConfigurationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - r.Log.Info("Searching for FlagSourceConfiguration") +func (r *FeatureFlagSourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + r.Log.Info("Searching for FeatureFlagSource") - // Fetch the FlagSourceConfiguration from the cache - fsConfig := &corev1alpha1.FlagSourceConfiguration{} + // Fetch the FeatureFlagSource from the cache + fsConfig := &api.FeatureFlagSource{} if err := r.Client.Get(ctx, req.NamespacedName, fsConfig); err != nil { if errors.IsNotFound(err) { // taking down all associated K8s resources is handled by K8s @@ -73,8 +74,8 @@ func (r *FlagSourceConfigurationReconciler) Reconcile(ctx context.Context, req c for _, source := range fsConfig.Spec.Sources { if source.Provider.IsFlagdProxy() { - r.Log.Info(fmt.Sprintf("flagsourceconfiguration %s uses flagd-proxy, checking deployment", req.NamespacedName)) - if err := r.FlagdProxy.HandleFlagdProxy(ctx, fsConfig); err != nil { + r.Log.Info(fmt.Sprintf("featureflagsource %s uses flagd-proxy, checking deployment", req.NamespacedName)) + if err := r.FlagdProxy.HandleFlagdProxy(ctx); err != nil { r.Log.Error(err, "error handling the flagd-proxy deployment") } break @@ -90,17 +91,17 @@ func (r *FlagSourceConfigurationReconciler) Reconcile(ctx context.Context, req c // and our resource exists within the cluster deployList := &appsV1.DeploymentList{} if err := r.Client.List(ctx, deployList, client.MatchingFields{ - fmt.Sprintf("%s/%s", common.OpenFeatureAnnotationPath, common.FlagSourceConfigurationAnnotation): "true", + fmt.Sprintf("%s/%s", common.OpenFeatureAnnotationPath, common.FeatureFlagSourceAnnotation): "true", }); err != nil { - r.Log.Error(err, fmt.Sprintf("Failed to get the pods with annotation %s/%s", common.OpenFeatureAnnotationPath, common.FlagSourceConfigurationAnnotation)) + r.Log.Error(err, fmt.Sprintf("Failed to get the pods with annotation %s/%s", common.OpenFeatureAnnotationPath, common.FeatureFlagSourceAnnotation)) return r.finishReconcile(err, false) } - // Loop through all deployments containing the openfeature.dev/flagsourceconfiguration annotation + // Loop through all deployments containing the openfeature.dev/featureflagsource annotation // and trigger a restart for any which have our resource listed as a configuration for _, deployment := range deployList.Items { annotations := deployment.Spec.Template.Annotations - annotation, ok := annotations[fmt.Sprintf("%s/%s", common.OpenFeatureAnnotationRoot, common.FlagSourceConfigurationAnnotation)] + annotation, ok := annotations[fmt.Sprintf("%s/%s", common.OpenFeatureAnnotationRoot, common.FeatureFlagSourceAnnotation)] if !ok { continue } @@ -117,7 +118,7 @@ func (r *FlagSourceConfigurationReconciler) Reconcile(ctx context.Context, req c return r.finishReconcile(nil, false) } -func (r *FlagSourceConfigurationReconciler) isUsingConfiguration(namespace string, name string, deploymentNamespace string, annotation string) bool { +func (r *FeatureFlagSourceReconciler) isUsingConfiguration(namespace string, name string, deploymentNamespace string, annotation string) bool { s := strings.Split(annotation, ",") // parse annotation list for _, target := range s { ss := strings.Split(strings.TrimSpace(target), "/") @@ -131,23 +132,23 @@ func (r *FlagSourceConfigurationReconciler) isUsingConfiguration(namespace strin return false } -func (r *FlagSourceConfigurationReconciler) finishReconcile(err error, requeueImmediate bool) (ctrl.Result, error) { +func (r *FeatureFlagSourceReconciler) finishReconcile(err error, requeueImmediate bool) (ctrl.Result, error) { if err != nil { interval := common.ReconcileErrorInterval if requeueImmediate { interval = 0 } - r.Log.Error(err, "Finished Reconciling FlagSourceConfiguration with error: %w") + r.Log.Error(err, "Finished Reconciling FeatureFlagSource with error: %w") return ctrl.Result{Requeue: true, RequeueAfter: interval}, err } - r.Log.Info("Finished Reconciling FlagSourceConfiguration") + r.Log.Info("Finished Reconciling FeatureFlagSource") return ctrl.Result{Requeue: false}, nil } // SetupWithManager sets up the controller with the Manager. -func (r *FlagSourceConfigurationReconciler) SetupWithManager(mgr ctrl.Manager) error { +func (r *FeatureFlagSourceReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&corev1alpha1.FlagSourceConfiguration{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). + For(&api.FeatureFlagSource{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). // we are only interested in update events for this reconciliation loop WithEventFilter(predicate.GenerationChangedPredicate{}). Complete(r) diff --git a/controllers/core/flagsourceconfiguration/controller_test.go b/controllers/core/featureflagsource/controller_test.go similarity index 75% rename from controllers/core/flagsourceconfiguration/controller_test.go rename to controllers/core/featureflagsource/controller_test.go index 39a905e03..e2693698f 100644 --- a/controllers/core/flagsourceconfiguration/controller_test.go +++ b/controllers/core/featureflagsource/controller_test.go @@ -1,4 +1,4 @@ -package flagsourceconfiguration +package featureflagsource import ( "context" @@ -6,8 +6,10 @@ import ( "testing" "time" - "github.com/open-feature/open-feature-operator/apis/core/v1alpha1" - "github.com/open-feature/open-feature-operator/controllers/common" + api "github.com/open-feature/open-feature-operator/apis/core/v1beta1" + apicommon "github.com/open-feature/open-feature-operator/apis/core/v1beta1/common" + "github.com/open-feature/open-feature-operator/common" + "github.com/open-feature/open-feature-operator/common/flagdproxy" "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -19,7 +21,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" ) -func TestFlagSourceConfigurationReconciler_Reconcile(t *testing.T) { +func TestFeatureFlagSourceReconciler_Reconcile(t *testing.T) { const ( testNamespace = "test-namespace" fsConfigName = "test-config" @@ -28,7 +30,7 @@ func TestFlagSourceConfigurationReconciler_Reconcile(t *testing.T) { tests := []struct { name string - fsConfig *v1alpha1.FlagSourceConfiguration + fsConfig *api.FeatureFlagSource deployment *appsv1.Deployment restartedAtValueBeforeReconcile string restartedAtValueAfterReconcile string @@ -36,28 +38,28 @@ func TestFlagSourceConfigurationReconciler_Reconcile(t *testing.T) { }{ { name: "deployment gets restarted with rollout", - fsConfig: createTestFSConfig(fsConfigName, testNamespace, deploymentName, true, v1alpha1.SyncProviderHttp), + fsConfig: createTestFSConfig(fsConfigName, testNamespace, deploymentName, true, apicommon.SyncProviderHttp), deployment: createTestDeployment(fsConfigName, testNamespace, deploymentName), restartedAtValueBeforeReconcile: "", restartedAtValueAfterReconcile: time.Now().Format(time.RFC3339), }, { name: "deployment without rollout", - fsConfig: createTestFSConfig(fsConfigName, testNamespace, deploymentName, false, v1alpha1.SyncProviderHttp), + fsConfig: createTestFSConfig(fsConfigName, testNamespace, deploymentName, false, apicommon.SyncProviderHttp), deployment: createTestDeployment(fsConfigName, testNamespace, deploymentName), restartedAtValueBeforeReconcile: "", restartedAtValueAfterReconcile: "", }, { name: "no deployment", - fsConfig: createTestFSConfig(fsConfigName, testNamespace, deploymentName, true, v1alpha1.SyncProviderHttp), + fsConfig: createTestFSConfig(fsConfigName, testNamespace, deploymentName, true, apicommon.SyncProviderHttp), deployment: nil, restartedAtValueBeforeReconcile: "", restartedAtValueAfterReconcile: "", }, { name: "no deployment, kube proxy deployment", - fsConfig: createTestFSConfig(fsConfigName, testNamespace, deploymentName, true, v1alpha1.SyncProviderFlagdProxy), + fsConfig: createTestFSConfig(fsConfigName, testNamespace, deploymentName, true, apicommon.SyncProviderFlagdProxy), deployment: nil, restartedAtValueBeforeReconcile: "", restartedAtValueAfterReconcile: "", @@ -65,7 +67,7 @@ func TestFlagSourceConfigurationReconciler_Reconcile(t *testing.T) { }, } - err := v1alpha1.AddToScheme(scheme.Scheme) + err := api.AddToScheme(scheme.Scheme) require.Nil(t, err) req := ctrl.Request{ @@ -82,23 +84,23 @@ func TestFlagSourceConfigurationReconciler_Reconcile(t *testing.T) { // setting up fake k8s client var fakeClient client.Client if tt.deployment != nil { - fakeClient = fake.NewClientBuilder().WithScheme(scheme.Scheme).WithObjects(tt.fsConfig, tt.deployment).WithIndex(&appsv1.Deployment{}, fmt.Sprintf("%s/%s", common.OpenFeatureAnnotationPath, common.FlagSourceConfigurationAnnotation), common.FlagSourceConfigurationIndex).Build() + fakeClient = fake.NewClientBuilder().WithScheme(scheme.Scheme).WithObjects(tt.fsConfig, tt.deployment).WithIndex(&appsv1.Deployment{}, fmt.Sprintf("%s/%s", common.OpenFeatureAnnotationPath, common.FeatureFlagSourceAnnotation), common.FeatureFlagSourceIndex).Build() } else { - fakeClient = fake.NewClientBuilder().WithScheme(scheme.Scheme).WithObjects(tt.fsConfig).WithIndex(&appsv1.Deployment{}, fmt.Sprintf("%s/%s", common.OpenFeatureAnnotationPath, common.FlagSourceConfigurationAnnotation), common.FlagSourceConfigurationIndex).Build() + fakeClient = fake.NewClientBuilder().WithScheme(scheme.Scheme).WithObjects(tt.fsConfig).WithIndex(&appsv1.Deployment{}, fmt.Sprintf("%s/%s", common.OpenFeatureAnnotationPath, common.FeatureFlagSourceAnnotation), common.FeatureFlagSourceIndex).Build() } - kpConfig, err := common.NewFlagdProxyConfiguration() + kpConfig, err := flagdproxy.NewFlagdProxyConfiguration() require.Nil(t, err) kpConfig.Namespace = testNamespace - kph := common.NewFlagdProxyHandler( + kph := flagdproxy.NewFlagdProxyHandler( kpConfig, fakeClient, - ctrl.Log.WithName("flagsourceconfiguration-FlagdProxyhandler"), + ctrl.Log.WithName("featureflagsource-FlagdProxyhandler"), ) - r := &FlagSourceConfigurationReconciler{ + r := &FeatureFlagSourceReconciler{ Client: fakeClient, - Log: ctrl.Log.WithName("flagsourceconfiguration-controller"), + Log: ctrl.Log.WithName("featureflagsource-controller"), Scheme: fakeClient.Scheme(), FlagdProxy: kph, } @@ -129,14 +131,14 @@ func TestFlagSourceConfigurationReconciler_Reconcile(t *testing.T) { // check that a deployment exists in the default namespace with the correct image and tag // ensure that the associated service has also been deployed deployment := &appsv1.Deployment{} - err = fakeClient.Get(ctx, types.NamespacedName{Name: common.FlagdProxyDeploymentName, Namespace: testNamespace}, deployment) + err = fakeClient.Get(ctx, types.NamespacedName{Name: flagdproxy.FlagdProxyDeploymentName, Namespace: testNamespace}, deployment) require.Nil(t, err) require.Equal(t, len(deployment.Spec.Template.Spec.Containers), 1) require.Equal(t, len(deployment.Spec.Template.Spec.Containers[0].Ports), 2) - require.Equal(t, deployment.Spec.Template.Spec.Containers[0].Image, fmt.Sprintf("%s:%s", common.DefaultFlagdProxyImage, common.DefaultFlagdProxyTag)) + require.Equal(t, deployment.Spec.Template.Spec.Containers[0].Image, fmt.Sprintf("%s:%s", flagdproxy.DefaultFlagdProxyImage, flagdproxy.DefaultFlagdProxyTag)) service := &corev1.Service{} - err = fakeClient.Get(ctx, types.NamespacedName{Name: common.FlagdProxyServiceName, Namespace: testNamespace}, service) + err = fakeClient.Get(ctx, types.NamespacedName{Name: flagdproxy.FlagdProxyServiceName, Namespace: testNamespace}, service) require.Nil(t, err) require.Equal(t, len(service.Spec.Ports), 1) require.Equal(t, service.Spec.Ports[0].TargetPort.IntVal, deployment.Spec.Template.Spec.Containers[0].Ports[0].ContainerPort) @@ -155,8 +157,8 @@ func createTestDeployment(fsConfigName string, testNamespace string, deploymentN Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ - fmt.Sprintf("%s/%s", common.OpenFeatureAnnotationPath, common.FlagSourceConfigurationAnnotation): "true", - fmt.Sprintf("%s/%s", common.OpenFeatureAnnotationRoot, common.FlagSourceConfigurationAnnotation): fmt.Sprintf("%s/%s", testNamespace, fsConfigName), + fmt.Sprintf("%s/%s", common.OpenFeatureAnnotationPath, common.FeatureFlagSourceAnnotation): "true", + fmt.Sprintf("%s/%s", common.OpenFeatureAnnotationRoot, common.FeatureFlagSourceAnnotation): fmt.Sprintf("%s/%s", testNamespace, fsConfigName), }, Labels: map[string]string{ "app": "test", @@ -186,15 +188,15 @@ func createTestDeployment(fsConfigName string, testNamespace string, deploymentN return deployment } -func createTestFSConfig(fsConfigName string, testNamespace string, deploymentName string, rollout bool, provider v1alpha1.SyncProviderType) *v1alpha1.FlagSourceConfiguration { - fsConfig := &v1alpha1.FlagSourceConfiguration{ +func createTestFSConfig(fsConfigName string, testNamespace string, deploymentName string, rollout bool, provider apicommon.SyncProviderType) *api.FeatureFlagSource { + fsConfig := &api.FeatureFlagSource{ ObjectMeta: metav1.ObjectMeta{ Name: fsConfigName, Namespace: testNamespace, }, - Spec: v1alpha1.FlagSourceConfigurationSpec{ + Spec: api.FeatureFlagSourceSpec{ Image: deploymentName, - Sources: []v1alpha1.Source{ + Sources: []api.Source{ { Source: "my-source", Provider: provider, diff --git a/docs/crds.md b/docs/crds.md index a1dd3fc05..3c0832885 100644 --- a/docs/crds.md +++ b/docs/crds.md @@ -2,2613 +2,28 @@ Packages: -- [core.openfeature.dev/v1alpha1](#coreopenfeaturedevv1alpha1) -- [core.openfeature.dev/v1alpha2](#coreopenfeaturedevv1alpha2) - [core.openfeature.dev/v1beta1](#coreopenfeaturedevv1beta1) -- [core.openfeature.dev/v1alpha3](#coreopenfeaturedevv1alpha3) -# core.openfeature.dev/v1alpha1 - -Resource Types: - -- [FeatureFlagConfiguration](#featureflagconfiguration) - -- [FlagSourceConfiguration](#flagsourceconfiguration) - - - - -## FeatureFlagConfiguration -[↩ Parent](#coreopenfeaturedevv1alpha1 ) - - - - - - -FeatureFlagConfiguration is the Schema for the featureflagconfigurations API - -
Name | -Type | -Description | -Required | -
---|---|---|---|
apiVersion | -string | -core.openfeature.dev/v1alpha1 | -true | -
kind | -string | -FeatureFlagConfiguration | -true | -
metadata | -object | -Refer to the Kubernetes API documentation for the fields of the `metadata` field. | -true | -
spec | -object | -
- FeatureFlagConfigurationSpec defines the desired state of FeatureFlagConfiguration - |
- false | -
status | -object | -
- FeatureFlagConfigurationStatus defines the observed state of FeatureFlagConfiguration - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
featureFlagSpec | -string | -
- FeatureFlagSpec is the json representation of the feature flag - |
- false | -
flagDSpec | -object | -
- FlagDSpec [DEPRECATED]: superseded by FlagSourceConfiguration - |
- false | -
serviceProvider | -object | -
- ServiceProvider [DEPRECATED]: superseded by FlagSourceConfiguration - |
- false | -
syncProvider | -object | -
- SyncProvider [DEPRECATED]: superseded by FlagSourceConfiguration - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
envs | -[]object | -
- - |
- false | -
metricsPort | -integer | -
- - - Format: int32 - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
name | -string | -
- Name of the environment variable. Must be a C_IDENTIFIER. - |
- true | -
value | -string | -
- Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "". - |
- false | -
valueFrom | -object | -
- Source for the environment variable's value. Cannot be used if value is not empty. - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
configMapKeyRef | -object | -
- Selects a key of a ConfigMap. - |
- false | -
fieldRef | -object | -
- Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['<KEY>']`, `metadata.annotations['<KEY>']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - |
- false | -
resourceFieldRef | -object | -
- Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - |
- false | -
secretKeyRef | -object | -
- Selects a key of a secret in the pod's namespace - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
key | -string | -
- The key to select. - |
- true | -
name | -string | -
- Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid? - |
- false | -
optional | -boolean | -
- Specify whether the ConfigMap or its key must be defined - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
fieldPath | -string | -
- Path of the field to select in the specified API version. - |
- true | -
apiVersion | -string | -
- Version of the schema the FieldPath is written in terms of, defaults to "v1". - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
resource | -string | -
- Required: resource to select - |
- true | -
containerName | -string | -
- Container name: required for volumes, optional for env vars - |
- false | -
divisor | -int or string | -
- Specifies the output format of the exposed resources, defaults to "1" - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
key | -string | -
- The key of the secret to select from. Must be a valid secret key. - |
- true | -
name | -string | -
- Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid? - |
- false | -
optional | -boolean | -
- Specify whether the Secret or its key must be defined - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
name | -enum | -
- - - Enum: flagd - |
- true | -
credentials | -object | -
- ObjectReference contains enough information to let you inspect or modify the referred object. --- New uses of this type are discouraged because of difficulty describing its usage when embedded in APIs. 1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage. 2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular restrictions like, "must refer only to types A and B" or "UID not honored" or "name must be restricted". Those cannot be well described when embedded. 3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen. 4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple and the version of the actual struct is irrelevant. 5. We cannot easily change it. Because this type is embedded in many locations, updates to this type will affect numerous schemas. Don't make new APIs embed an underspecified API type they do not control.
- Instead of using this type, create a locally provided and used type that is well-focused on your reference. For example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 . - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
apiVersion | -string | -
- API version of the referent. - |
- false | -
fieldPath | -string | -
- If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: "spec.containers{name}" (where "name" refers to the name of the container that triggered the event) or if no container name is specified "spec.containers[2]" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object. TODO: this design is not final and this field is subject to change in the future. - |
- false | -
kind | -string | -
- Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - |
- false | -
name | -string | -
- Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - |
- false | -
namespace | -string | -
- Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - |
- false | -
resourceVersion | -string | -
- Specific resourceVersion to which this reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - |
- false | -
uid | -string | -
- UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
name | -string | -
- - |
- true | -
httpSyncConfiguration | -object | -
- HttpSyncConfiguration defines the desired configuration for a http sync - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
target | -string | -
- Target is the target url for flagd to poll - |
- true | -
bearerToken | -string | -
- - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
apiVersion | -string | -core.openfeature.dev/v1alpha1 | -true | -
kind | -string | -FlagSourceConfiguration | -true | -
metadata | -object | -Refer to the Kubernetes API documentation for the fields of the `metadata` field. | -true | -
spec | -object | -
- FlagSourceConfigurationSpec defines the desired state of FlagSourceConfiguration - |
- false | -
status | -object | -
- FlagSourceConfigurationStatus defines the observed state of FlagSourceConfiguration - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
sources | -[]object | -
- Sources defines the syncProviders and associated configuration to be applied to the sidecar - |
- true | -
debugLogging | -boolean | -
- DebugLogging defines whether to enable --debug flag of flagd sidecar. Default false (disabled). - |
- false | -
defaultSyncProvider | -string | -
- DefaultSyncProvider defines the default sync provider - |
- false | -
envVarPrefix | -string | -
- EnvVarPrefix defines the prefix to be applied to all environment variables applied to the sidecar, default FLAGD - |
- false | -
envVars | -[]object | -
- EnvVars define the env vars to be applied to the sidecar, any env vars in FeatureFlagConfiguration CRs are added at the lowest index, all values will have the EnvVarPrefix applied - |
- false | -
evaluator | -string | -
- Evaluator sets an evaluator, defaults to 'json' - |
- false | -
image | -string | -
- Image allows for the sidecar image to be overridden, defaults to 'ghcr.io/open-feature/flagd' - |
- false | -
logFormat | -string | -
- LogFormat allows for the sidecar log format to be overridden, defaults to 'json' - |
- false | -
metricsPort | -integer | -
- MetricsPort defines the port to serve metrics on, defaults to 8014 - - Format: int32 - |
- false | -
otelCollectorUri | -string | -
- OtelCollectorUri defines whether to enable --otel-collector-uri flag of flagd sidecar. Default false (disabled). - |
- false | -
port | -integer | -
- Port defines the port to listen on, defaults to 8013 - - Format: int32 - |
- false | -
probesEnabled | -boolean | -
- ProbesEnabled defines whether to enable liveness and readiness probes of flagd sidecar. Default true (enabled). - |
- false | -
resources | -object | -
- Resources defines flagd sidecar resources. Default to operator sidecar-cpu-* and sidecar-ram-* flags. - |
- false | -
rolloutOnChange | -boolean | -
- RolloutOnChange dictates whether annotated deployments will be restarted when configuration changes are detected in this CR, defaults to false - |
- false | -
socketPath | -string | -
- SocketPath defines the unix socket path to listen on - |
- false | -
syncProviderArgs | -[]string | -
- SyncProviderArgs are string arguments passed to all sync providers, defined as key values separated by = - |
- false | -
tag | -string | -
- Tag to be appended to the sidecar image, defaults to 'main' - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
source | -string | -
- Source is a URI of the flag sources - |
- true | -
certPath | -string | -
- CertPath is a path of a certificate to be used by grpc TLS connection - |
- false | -
httpSyncBearerToken | -string | -
- HttpSyncBearerToken is a bearer token. Used by http(s) sync provider only - |
- false | -
provider | -string | -
- Provider type - kubernetes, http, grpc or filepath - |
- false | -
providerID | -string | -
- ProviderID is an identifier to be used in grpc provider - |
- false | -
selector | -string | -
- Selector is a flag configuration selector used by grpc provider - |
- false | -
tls | -boolean | -
- TLS - Enable/Disable secure TLS connectivity. Currently used only by GRPC sync - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
name | -string | -
- Name of the environment variable. Must be a C_IDENTIFIER. - |
- true | -
value | -string | -
- Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "". - |
- false | -
valueFrom | -object | -
- Source for the environment variable's value. Cannot be used if value is not empty. - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
configMapKeyRef | -object | -
- Selects a key of a ConfigMap. - |
- false | -
fieldRef | -object | -
- Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['<KEY>']`, `metadata.annotations['<KEY>']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - |
- false | -
resourceFieldRef | -object | -
- Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - |
- false | -
secretKeyRef | -object | -
- Selects a key of a secret in the pod's namespace - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
key | -string | -
- The key to select. - |
- true | -
name | -string | -
- Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid? - |
- false | -
optional | -boolean | -
- Specify whether the ConfigMap or its key must be defined - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
fieldPath | -string | -
- Path of the field to select in the specified API version. - |
- true | -
apiVersion | -string | -
- Version of the schema the FieldPath is written in terms of, defaults to "v1". - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
resource | -string | -
- Required: resource to select - |
- true | -
containerName | -string | -
- Container name: required for volumes, optional for env vars - |
- false | -
divisor | -int or string | -
- Specifies the output format of the exposed resources, defaults to "1" - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
key | -string | -
- The key of the secret to select from. Must be a valid secret key. - |
- true | -
name | -string | -
- Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid? - |
- false | -
optional | -boolean | -
- Specify whether the Secret or its key must be defined - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
claims | -[]object | -
- Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container.
- This is an alpha field and requires enabling the DynamicResourceAllocation feature gate.
- This field is immutable. It can only be set for containers. - |
- false | -
limits | -map[string]int or string | -
- Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - |
- false | -
requests | -map[string]int or string | -
- Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
name | -string | -
- Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container. - |
- true | -
Name | -Type | -Description | -Required | -
---|---|---|---|
apiVersion | -string | -core.openfeature.dev/v1alpha2 | -true | -
kind | -string | -FeatureFlagConfiguration | -true | -
metadata | -object | -Refer to the Kubernetes API documentation for the fields of the `metadata` field. | -true | -
spec | -object | -
- FeatureFlagConfigurationSpec defines the desired state of FeatureFlagConfiguration - |
- false | -
status | -object | -
- FeatureFlagConfigurationStatus defines the observed state of FeatureFlagConfiguration - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
featureFlagSpec | -object | -
- FeatureFlagSpec is the structured representation of the feature flag specification - |
- false | -
flagDSpec | -object | -
- FlagDSpec [DEPRECATED]: superseded by FlagSourceConfiguration - |
- false | -
resources | -object | -
- Resources defines flagd sidecar resources. Default to operator sidecar-cpu-* and sidecar-ram-* flags. - |
- false | -
serviceProvider | -object | -
- ServiceProvider [DEPRECATED]: superseded by FlagSourceConfiguration - |
- false | -
syncProvider | -object | -
- SyncProvider [DEPRECATED]: superseded by FlagSourceConfiguration - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
flags | -map[string]object | -
- - |
- true | -
$evaluators | -object | -
- - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
defaultVariant | -string | -
- - |
- true | -
state | -enum | -
- - - Enum: ENABLED, DISABLED - |
- true | -
variants | -object | -
- - |
- true | -
targeting | -object | -
- Targeting is the json targeting rule - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
envs | -[]object | -
- - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
name | -string | -
- Name of the environment variable. Must be a C_IDENTIFIER. - |
- true | -
value | -string | -
- Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "". - |
- false | -
valueFrom | -object | -
- Source for the environment variable's value. Cannot be used if value is not empty. - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
configMapKeyRef | -object | -
- Selects a key of a ConfigMap. - |
- false | -
fieldRef | -object | -
- Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['<KEY>']`, `metadata.annotations['<KEY>']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - |
- false | -
resourceFieldRef | -object | -
- Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - |
- false | -
secretKeyRef | -object | -
- Selects a key of a secret in the pod's namespace - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
key | -string | -
- The key to select. - |
- true | -
name | -string | -
- Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid? - |
- false | -
optional | -boolean | -
- Specify whether the ConfigMap or its key must be defined - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
fieldPath | -string | -
- Path of the field to select in the specified API version. - |
- true | -
apiVersion | -string | -
- Version of the schema the FieldPath is written in terms of, defaults to "v1". - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
resource | -string | -
- Required: resource to select - |
- true | -
containerName | -string | -
- Container name: required for volumes, optional for env vars - |
- false | -
divisor | -int or string | -
- Specifies the output format of the exposed resources, defaults to "1" - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
key | -string | -
- The key of the secret to select from. Must be a valid secret key. - |
- true | -
name | -string | -
- Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid? - |
- false | -
optional | -boolean | -
- Specify whether the Secret or its key must be defined - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
claims | -[]object | -
- Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container.
- This is an alpha field and requires enabling the DynamicResourceAllocation feature gate.
- This field is immutable. It can only be set for containers. - |
- false | -
limits | -map[string]int or string | -
- Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - |
- false | -
requests | -map[string]int or string | -
- Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
name | -string | -
- Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container. - |
- true | -
Name | -Type | -Description | -Required | -
---|---|---|---|
name | -enum | -
- - - Enum: flagd - |
- true | -
credentials | -object | -
- ObjectReference contains enough information to let you inspect or modify the referred object. --- New uses of this type are discouraged because of difficulty describing its usage when embedded in APIs. 1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage. 2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular restrictions like, "must refer only to types A and B" or "UID not honored" or "name must be restricted". Those cannot be well described when embedded. 3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen. 4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple and the version of the actual struct is irrelevant. 5. We cannot easily change it. Because this type is embedded in many locations, updates to this type will affect numerous schemas. Don't make new APIs embed an underspecified API type they do not control.
- Instead of using this type, create a locally provided and used type that is well-focused on your reference. For example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 . - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
apiVersion | -string | -
- API version of the referent. - |
- false | -
fieldPath | -string | -
- If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: "spec.containers{name}" (where "name" refers to the name of the container that triggered the event) or if no container name is specified "spec.containers[2]" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object. TODO: this design is not final and this field is subject to change in the future. - |
- false | -
kind | -string | -
- Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - |
- false | -
name | -string | -
- Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - |
- false | -
namespace | -string | -
- Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - |
- false | -
resourceVersion | -string | -
- Specific resourceVersion to which this reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - |
- false | -
uid | -string | -
- UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
name | -string | -
- - |
- true | -
httpSyncConfiguration | -object | -
- HttpSyncConfiguration defines the desired configuration for a http sync - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
target | -string | -
- Target is the target url for flagd to poll - |
- true | -
bearerToken | -string | -
- - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
apiVersion | -string | -core.openfeature.dev/v1alpha2 | -true | -
kind | -string | -FlagSourceConfiguration | -true | -
metadata | -object | -Refer to the Kubernetes API documentation for the fields of the `metadata` field. | -true | -
spec | -object | -
- FlagSourceConfigurationSpec defines the desired state of FlagSourceConfiguration - |
- false | -
status | -object | -
- FlagSourceConfigurationStatus defines the observed state of FlagSourceConfiguration - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
defaultSyncProvider | -string | -
- DefaultSyncProvider defines the default sync provider - |
- false | -
evaluator | -string | -
- Evaluator sets an evaluator, defaults to 'json' - |
- false | -
image | -string | -
- Image allows for the sidecar image to be overridden, defaults to 'ghcr.io/open-feature/flagd' - |
- false | -
logFormat | -string | -
- LogFormat allows for the sidecar log format to be overridden, defaults to 'json' - |
- false | -
metricsPort | -integer | -
- MetricsPort defines the port to serve metrics on, defaults to 8013 - - Format: int32 - |
- false | -
otelCollectorUri | -string | -
- OtelCollectorUri defines whether to enable --otel-collector-uri flag of flagd sidecar. Default false (disabled). - |
- false | -
port | -integer | -
- Port defines the port to listen on, defaults to 8014 - - Format: int32 - |
- false | -
probesEnabled | -boolean | -
- ProbesEnabled defines whether to enable liveness and readiness probes of flagd sidecar. Default true (enabled). - |
- false | -
socketPath | -string | -
- SocketPath defines the unix socket path to listen on - |
- false | -
syncProviderArgs | -[]string | -
- SyncProviderArgs are string arguments passed to all sync providers, defined as key values separated by = - |
- false | -
tag | -string | -
- Tag to be appended to the sidecar image, defaults to 'main' - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
apiVersion | -string | -core.openfeature.dev/v1beta1 | -true | -
kind | -string | -FeatureFlag | -true | -
metadata | -object | -Refer to the Kubernetes API documentation for the fields of the `metadata` field. | -true | -
spec | -object | -
- FeatureFlagSpec defines the desired state of FeatureFlag - |
- false | -
status | -object | -
- FeatureFlagStatus defines the observed state of FeatureFlag - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
flagSpec | -object | -
- FlagSpec is the structured representation of the feature flag specification - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
flags | -map[string]object | -
- - |
- true | -
$evaluators | -object | -
- - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
defaultVariant | -string | -
- - |
- true | -
state | -enum | -
- - - Enum: ENABLED, DISABLED - |
- true | -
variants | -object | -
- - |
- true | -
targeting | -object | -
- Targeting is the json targeting rule - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
apiVersion | -string | -core.openfeature.dev/v1beta1 | -true | -
kind | -string | -FeatureFlagSource | -true | -
metadata | -object | -Refer to the Kubernetes API documentation for the fields of the `metadata` field. | -true | -
spec | -object | -
- FeatureFlagSourceSpec defines the desired state of FeatureFlagSource - |
- false | -
status | -object | -
- FeatureFlagSourceStatus defines the observed state of FeatureFlagSource - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
sources | -[]object | -
- SyncProviders define the syncProviders and associated configuration to be applied to the sidecar - |
- true | -
debugLogging | -boolean | -
- DebugLogging defines whether to enable --debug flag of flagd sidecar. Default false (disabled). - |
- false | -
defaultSyncProvider | -string | -
- DefaultSyncProvider defines the default sync provider - |
- false | -
envVarPrefix | -string | -
- EnvVarPrefix defines the prefix to be applied to all environment variables applied to the sidecar, default FLAGD - |
- false | -
envVars | -[]object | -
- EnvVars define the env vars to be applied to the sidecar, any env vars in FeatureFlagConfiguration CRs are added at the lowest index, all values will have the EnvVarPrefix applied, default FLAGD - |
- false | -
evaluator | -string | -
- Evaluator sets an evaluator, defaults to 'json' - |
- false | -
image | -string | -
- Image allows for the sidecar image to be overridden, defaults to 'ghcr.io/open-feature/flagd' - |
- false | -
logFormat | -string | -
- LogFormat allows for the sidecar log format to be overridden, defaults to 'json' - |
- false | -
metricsPort | -integer | -
- MetricsPort defines the port to serve metrics on, defaults to 8014 - - Format: int32 - |
- false | -
otelCollectorUri | -string | -
- OtelCollectorUri defines whether to enable --otel-collector-uri flag of flagd sidecar. Default false (disabled). - |
- false | -
port | -integer | -
- Port defines the port to listen on, defaults to 8013 - - Format: int32 - |
- false | -
probesEnabled | -boolean | -
- ProbesEnabled defines whether to enable liveness and readiness probes of flagd sidecar. Default true (enabled). - |
- false | -
resources | -object | -
- Resources defines flagd sidecar resources. Default to operator sidecar-cpu-* and sidecar-ram-* flags. - |
- false | -
rolloutOnChange | -boolean | -
- RolloutOnChange dictates whether annotated deployments will be restarted when configuration changes are detected in this CR, defaults to false - |
- false | -
socketPath | -string | -
- SocketPath defines the unix socket path to listen on - |
- false | -
syncProviderArgs | -[]string | -
- SyncProviderArgs are string arguments passed to all sync providers, defined as key values separated by = - |
- false | -
tag | -string | -
- Tag to be appended to the sidecar image, defaults to 'main' - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
source | -string | -
- Source is a URI of the flag sources - |
- true | -
certPath | -string | -
- CertPath is a path of a certificate to be used by grpc TLS connection - |
- false | -
httpSyncBearerToken | -string | -
- HttpSyncBearerToken is a bearer token. Used by http(s) sync provider only - |
- false | -
provider | -string | -
- Provider type - kubernetes, http(s), grpc(s) or filepath - |
- false | -
providerID | -string | -
- ProviderID is an identifier to be used in grpc provider - |
- false | -
selector | -string | -
- Selector is a flag configuration selector used by grpc provider - |
- false | -
tls | -boolean | -
- TLS - Enable/Disable secure TLS connectivity. Currently used only by GRPC sync - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
name | -string | -
- Name of the environment variable. Must be a C_IDENTIFIER. - |
- true | -
value | -string | -
- Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "". - |
- false | -
valueFrom | -object | -
- Source for the environment variable's value. Cannot be used if value is not empty. - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
configMapKeyRef | -object | -
- Selects a key of a ConfigMap. - |
- false | -
fieldRef | -object | -
- Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['<KEY>']`, `metadata.annotations['<KEY>']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - |
- false | -
resourceFieldRef | -object | -
- Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - |
- false | -
secretKeyRef | -object | -
- Selects a key of a secret in the pod's namespace - |
- false | -
Name | -Type | -Description | -Required | -
---|---|---|---|
key | -string | -
- The key to select. - |
- true | -
name | -string | -
- Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid? - |
- false | -
optional | -boolean | -
- Specify whether the ConfigMap or its key must be defined - |
- false | -
fieldPath | -string | +apiVersion | +string | +core.openfeature.dev/v1beta1 | +true | +
kind | +string | +FeatureFlag | +true | +||
metadata | +object | +Refer to the Kubernetes API documentation for the fields of the `metadata` field. | +true | +||
spec | +object |
- Path of the field to select in the specified API version. + FeatureFlagSpec defines the desired state of FeatureFlag |
- true | +false | |
apiVersion | -string | +status | +object |
- Version of the schema the FieldPath is written in terms of, defaults to "v1". + FeatureFlagStatus defines the observed state of FeatureFlag |
false |
resource | -string | -
- Required: resource to select - |
- true | -||
containerName | -string | -
- Container name: required for volumes, optional for env vars - |
- false | -||
divisor | -int or string | +flagSpec | +object |
- Specifies the output format of the exposed resources, defaults to "1" + FlagSpec is the structured representation of the feature flag specification |
false |
key | -string | +flags | +map[string]object |
- The key of the secret to select from. Must be a valid secret key. + |
true |
name | -string | -
- Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid? - |
- false | -||
optional | -boolean | +$evaluators | +object |
- Specify whether the Secret or its key must be defined + |
false |
claims | -[]object | +defaultVariant | +string |
- Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container.
- This is an alpha field and requires enabling the DynamicResourceAllocation feature gate.
- This field is immutable. It can only be set for containers. + |
- false | +true |
limits | -map[string]int or string | +state | +enum |
- Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + + + Enum: ENABLED, DISABLED |
- false | +true |
requests | -map[string]int or string | +variants | +object |
- Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + |
- false | -
Name | -Type | -Description | -Required | -|
---|---|---|---|---|
name | -string | +true | +||
targeting | +object |
- Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container. + Targeting is the json targeting rule |
- true | +false |
apiVersion | string | -core.openfeature.dev/v1alpha3 | +core.openfeature.dev/v1beta1 | true |
kind | string | -FlagSourceConfiguration | +FeatureFlagSource | true |
Refer to the Kubernetes API documentation for the fields of the `metadata` field. | true | |||
spec | +spec | object |
- FlagSourceConfigurationSpec defines the desired state of FlagSourceConfiguration + FeatureFlagSourceSpec defines the desired state of FeatureFlagSource |
false |
status | object |
- FlagSourceConfigurationStatus defines the observed state of FlagSourceConfiguration + FeatureFlagSourceStatus defines the observed state of FeatureFlagSource |
false |
sources | +sources | []object |
SyncProviders define the syncProviders and associated configuration to be applied to the sidecar @@ -2896,10 +278,10 @@ FlagSourceConfigurationSpec defines the desired state of FlagSourceConfiguration |
false |
envVars | +envVars | []object |
- EnvVars define the env vars to be applied to the sidecar, any env vars in FeatureFlagConfiguration CRs are added at the lowest index, all values will have the EnvVarPrefix applied, default FLAGD + EnvVars define the env vars to be applied to the sidecar, any env vars in FeatureFlag CRs are added at the lowest index, all values will have the EnvVarPrefix applied, default FLAGD |
false |
false | ||||
metricsPort | +managementPort | integer |
- MetricsPort defines the port to serve metrics on, defaults to 8014 + ManagemetPort defines the port to serve management on, defaults to 8014 Format: int32 |
@@ -2956,7 +338,7 @@ FlagSourceConfigurationSpec defines the desired state of FlagSourceConfiguration
false |
resources | +resources | object |
Resources defines flagd sidecar resources. Default to operator sidecar-cpu-* and sidecar-ram-* flags. @@ -2994,8 +376,8 @@ FlagSourceConfigurationSpec defines the desired state of FlagSourceConfiguration |