diff --git a/Makefile b/Makefile
index a6cb01c78..cc7baab29 100644
--- a/Makefile
+++ b/Makefile
@@ -260,9 +260,9 @@ helm-package: set-helm-overlay generate release-manifests helm
install-mockgen:
go install github.com/golang/mock/mockgen@v1.6.0
mockgen: install-mockgen
- mockgen -source=./common/flagdinjector/flagdinjector.go -destination=./common/flagdinjector/mock/flagd-injector.go -package=commonmock
- mockgen -source=./controllers/core/flagd/controller.go -destination=controllers/core/flagd/mock/mock.go -package=commonmock
- mockgen -source=./controllers/core/flagd/resources/interface.go -destination=controllers/core/flagd/resources/mock/mock.go -package=commonmock
+ mockgen -source=./internal/common/flagdinjector/flagdinjector.go -destination=./internal/common/flagdinjector/mock/flagd-injector.go -package=commonmock
+ mockgen -source=./internal/controller/core/flagd/controller.go -destination=./internal/controller/core/flagd/mock/mock.go -package=commonmock
+ mockgen -source=./internal/controller/core/flagd/resources/interface.go -destination=./internal/controller/core/flagd/resources/mock/mock.go -package=commonmock
workspace-init: workspace-clean
go work init
diff --git a/api/core/v1beta1/common/common.go b/api/core/v1beta1/common/common.go
index ca9ad0d77..a7dbf7dae 100644
--- a/api/core/v1beta1/common/common.go
+++ b/api/core/v1beta1/common/common.go
@@ -14,6 +14,7 @@ const (
SyncProviderFilepath SyncProviderType = "file"
SyncProviderAzureBlob SyncProviderType = "azblob"
SyncProviderGcs SyncProviderType = "gcs"
+ SyncProviderS3 SyncProviderType = "s3"
SyncProviderHttp SyncProviderType = "http"
SyncProviderGrpc SyncProviderType = "grpc"
SyncProviderFlagdProxy SyncProviderType = "flagd-proxy"
@@ -68,6 +69,10 @@ func (s SyncProviderType) IsGcs() bool {
return s == SyncProviderGcs
}
+func (s SyncProviderType) IsS3() bool {
+ return s == SyncProviderS3
+}
+
func (s SyncProviderType) IsFilepath() bool {
return s == SyncProviderFilepath
}
diff --git a/api/core/v1beta1/common/common_test.go b/api/core/v1beta1/common/common_test.go
index d9e4ffcc0..2aebc4954 100644
--- a/api/core/v1beta1/common/common_test.go
+++ b/api/core/v1beta1/common/common_test.go
@@ -14,6 +14,7 @@ func Test_FeatureFlagSource_SyncProvider(t *testing.T) {
g := SyncProviderGrpc
gcs := SyncProviderGcs
azureBlob := SyncProviderAzureBlob
+ s3 := SyncProviderS3
require.True(t, k.IsKubernetes())
require.True(t, f.IsFilepath())
@@ -21,6 +22,7 @@ func Test_FeatureFlagSource_SyncProvider(t *testing.T) {
require.True(t, g.IsGrpc())
require.True(t, gcs.IsGcs())
require.True(t, azureBlob.IsAzureBlob())
+ require.True(t, s3.IsS3())
require.False(t, f.IsKubernetes())
require.False(t, h.IsFilepath())
@@ -28,6 +30,8 @@ func Test_FeatureFlagSource_SyncProvider(t *testing.T) {
require.False(t, g.IsHttp())
require.False(t, g.IsGcs())
require.False(t, gcs.IsAzureBlob())
+ require.False(t, s3.IsGcs())
+ require.False(t, azureBlob.IsS3())
}
func Test_FLagSourceConfiguration_EnvVarKey(t *testing.T) {
diff --git a/api/core/v1beta1/featureflagsource_types.go b/api/core/v1beta1/featureflagsource_types.go
index 7454a3a64..c373f1dd4 100644
--- a/api/core/v1beta1/featureflagsource_types.go
+++ b/api/core/v1beta1/featureflagsource_types.go
@@ -116,7 +116,7 @@ type Source struct {
// Source is a URI of the flag sources
Source string `json:"source"`
- // Provider type - kubernetes, http(s), grpc(s) or file
+ // Provider type - kubernetes, file, http(s), grpc(s), gcs, azblob, s3 or flagd-proxy
// +optional
Provider common.SyncProviderType `json:"provider"`
@@ -266,7 +266,12 @@ func (fc *FeatureFlagSourceSpec) Merge(new *FeatureFlagSourceSpec) {
}
func (fc *FeatureFlagSourceSpec) decorateEnvVarName(original string) string {
- if strings.HasPrefix(original, "AZURE_STORAGE") {
+ // credential env vars for cloud blob sync providers must reach the sidecar
+ // unmodified; flagd/gocloud reads the vendor-native names directly
+ // (AZURE_STORAGE_* for azblob, AWS_* for s3, GOOGLE_* for gcs)
+ if strings.HasPrefix(original, "AZURE_STORAGE") ||
+ strings.HasPrefix(original, "AWS_") ||
+ strings.HasPrefix(original, "GOOGLE_") {
return original
}
return common.EnvVarKey(fc.EnvVarPrefix, original)
diff --git a/api/core/v1beta1/featureflagsource_types_test.go b/api/core/v1beta1/featureflagsource_types_test.go
index 560c2cc55..de9e83e3b 100644
--- a/api/core/v1beta1/featureflagsource_types_test.go
+++ b/api/core/v1beta1/featureflagsource_types_test.go
@@ -246,6 +246,18 @@ func Test_FLagSourceConfiguration_ToEnvVars(t *testing.T) {
Name: "AZURE_STORAGE_KEY",
Value: "key456",
},
+ {
+ Name: "AWS_ACCESS_KEY_ID",
+ Value: "AKIAIOSFODNN7EXAMPLE",
+ },
+ {
+ Name: "AWS_REGION",
+ Value: "us-east-1",
+ },
+ {
+ Name: "GOOGLE_APPLICATION_CREDENTIALS",
+ Value: "/var/run/secrets/gcp/key.json",
+ },
},
EnvVarPrefix: "PRE",
ManagementPort: 22,
@@ -272,6 +284,18 @@ func Test_FLagSourceConfiguration_ToEnvVars(t *testing.T) {
Name: "AZURE_STORAGE_KEY",
Value: "key456",
},
+ {
+ Name: "AWS_ACCESS_KEY_ID",
+ Value: "AKIAIOSFODNN7EXAMPLE",
+ },
+ {
+ Name: "AWS_REGION",
+ Value: "us-east-1",
+ },
+ {
+ Name: "GOOGLE_APPLICATION_CREDENTIALS",
+ Value: "/var/run/secrets/gcp/key.json",
+ },
{
Name: "PRE_MANAGEMENT_PORT",
Value: "22",
diff --git a/chart/open-feature-operator/README.md b/chart/open-feature-operator/README.md
index 03c3e695f..0e9f1c657 100644
--- a/chart/open-feature-operator/README.md
+++ b/chart/open-feature-operator/README.md
@@ -126,7 +126,7 @@ The command removes all the Kubernetes components associated with the chart and
| `sidecarConfiguration.image.tag` | Sets the version tag for the injected sidecar. | `v0.15.4` |
| `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`, `file` and `http`. | `kubernetes` |
+| `sidecarConfiguration.defaultSyncProvider` | Sets the value of the `XXX_SYNC_PROVIDER` environment variable for the injected sidecar container. Valid sync providers: `kubernetes`, `file`, `http`, `grpc`, `gcs`, `azblob`, `s3` and `flagd-proxy`. | `kubernetes` |
| `sidecarConfiguration.evaluator` | Sets the value of the `XXX_EVALUATOR` environment variable for the injected sidecar container. | `json` |
| `sidecarConfiguration.logFormat` | Sets the value of the `XXX_LOG_FORMAT` environment variable for the injected sidecar container. There are 2 valid log formats: `json` and `console`. | `json` |
| `sidecarConfiguration.probesEnabled` | Enable or Disable Liveness and Readiness probes of the flagd sidecar. When enabled, HTTP probes( paths - `/readyz`, `/healthz`) are set with an initial delay of 5 seconds. | `true` |
diff --git a/chart/open-feature-operator/values.yaml b/chart/open-feature-operator/values.yaml
index c14808a90..cb48e23df 100644
--- a/chart/open-feature-operator/values.yaml
+++ b/chart/open-feature-operator/values.yaml
@@ -42,7 +42,7 @@ sidecarConfiguration:
providerArgs: ""
## @param sidecarConfiguration.envVarPrefix Sets the prefix for all environment variables set in the injected sidecar.
envVarPrefix: "FLAGD"
- ## @param 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`, `file` and `http`.
+ ## @param sidecarConfiguration.defaultSyncProvider Sets the value of the `XXX_SYNC_PROVIDER` environment variable for the injected sidecar container. Valid sync providers: `kubernetes`, `file`, `http`, `grpc`, `gcs`, `azblob`, `s3` and `flagd-proxy`.
defaultSyncProvider: kubernetes
## @param sidecarConfiguration.evaluator Sets the value of the `XXX_EVALUATOR` environment variable for the injected sidecar container.
evaluator: json
diff --git a/common/flagdinjector/mock/flagd-injector.go b/common/flagdinjector/mock/flagd-injector.go
new file mode 100644
index 000000000..0f77b2718
--- /dev/null
+++ b/common/flagdinjector/mock/flagd-injector.go
@@ -0,0 +1,66 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: ./internal/common/flagdinjector/flagdinjector.go
+
+// Package commonmock is a generated GoMock package.
+package commonmock
+
+import (
+ context "context"
+ reflect "reflect"
+
+ gomock "github.com/golang/mock/gomock"
+ v1beta1 "github.com/open-feature/open-feature-operator/api/core/v1beta1"
+ 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 *v1beta1.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 *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/config/crd/bases/core.openfeature.dev_featureflagsources.yaml b/config/crd/bases/core.openfeature.dev_featureflagsources.yaml
index 77639e42f..81360d900 100644
--- a/config/crd/bases/core.openfeature.dev_featureflagsources.yaml
+++ b/config/crd/bases/core.openfeature.dev_featureflagsources.yaml
@@ -312,8 +312,8 @@ spec:
format: int32
type: integer
provider:
- description: Provider type - kubernetes, http(s), grpc(s) or
- file
+ description: Provider type - kubernetes, file, http(s), grpc(s),
+ gcs, azblob, s3 or flagd-proxy
type: string
providerID:
description: ProviderID is an identifier to be used in grpc
diff --git a/docs/crds.md b/docs/crds.md
index 98c88b910..cbdd48888 100644
--- a/docs/crds.md
+++ b/docs/crds.md
@@ -473,7 +473,7 @@ detected in this CR, defaults to false