diff --git a/Makefile b/Makefile index 6f2145991..6f1cfa479 100644 --- a/Makefile +++ b/Makefile @@ -151,7 +151,7 @@ release-manifests: manifests kustomize fi .PHONY: deploy -deploy: generate manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. +deploy: generate kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG) $(KUSTOMIZE) build config/default | kubectl apply -f - diff --git a/apis/core/v1alpha1/featureflagconfiguration_types_test.go b/apis/core/v1alpha1/featureflagconfiguration_types_test.go index 23dac2ce6..839207946 100644 --- a/apis/core/v1alpha1/featureflagconfiguration_types_test.go +++ b/apis/core/v1alpha1/featureflagconfiguration_types_test.go @@ -1,9 +1,9 @@ package v1alpha1 import ( - "github.com/open-feature/open-feature-operator/apis/core/v1alpha1/common" "testing" + "github.com/open-feature/open-feature-operator/apis/core/v1alpha1/common" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/apis/core/v1alpha1/flagsourceconfiguration_types.go b/apis/core/v1alpha1/flagsourceconfiguration_types.go index a949cce4b..d54a0b380 100644 --- a/apis/core/v1alpha1/flagsourceconfiguration_types.go +++ b/apis/core/v1alpha1/flagsourceconfiguration_types.go @@ -18,11 +18,11 @@ package v1alpha1 import ( "fmt" - "github.com/open-feature/open-feature-operator/apis/core/v1alpha1/common" "os" "strconv" "strings" + "github.com/open-feature/open-feature-operator/apis/core/v1alpha1/common" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -30,33 +30,32 @@ import ( type SyncProviderType string const ( - SidecarEnvVarPrefix string = "SIDECAR_ENV_VAR_PREFIX" - InputConfigurationEnvVarPrefix string = "SIDECAR" - SidecarMetricPortEnvVar string = "METRICS_PORT" - SidecarPortEnvVar string = "PORT" - SidecarSocketPathEnvVar string = "SOCKET_PATH" - SidecarEvaluatorEnvVar string = "EVALUATOR" - SidecarImageEnvVar string = "IMAGE" - SidecarVersionEnvVar string = "TAG" - SidecarProviderArgsEnvVar string = "PROVIDER_ARGS" - SidecarDefaultSyncProviderEnvVar string = "SYNC_PROVIDER" - SidecarLogFormatEnvVar string = "LOG_FORMAT" - SidecarProbesEnabledVar string = "PROBES_ENABLED" - defaultSidecarEnvVarPrefix string = "FLAGD" - DefaultMetricPort int32 = 8014 - defaultPort int32 = 8013 - defaultSocketPath string = "" - defaultEvaluator string = "json" - defaultImage string = "ghcr.io/open-feature/flagd" - // renovate: datasource=github-tags depName=open-feature/flagd/flagd - defaultTag string = "v0.6.3" - defaultLogFormat string = "json" - defaultProbesEnabled bool = true - SyncProviderKubernetes SyncProviderType = "kubernetes" - SyncProviderFilepath SyncProviderType = "filepath" - SyncProviderHttp SyncProviderType = "http" - SyncProviderGrpc SyncProviderType = "grpc" - SyncProviderFlagdProxy SyncProviderType = "flagd-proxy" + SidecarEnvVarPrefix string = "SIDECAR_ENV_VAR_PREFIX" + InputConfigurationEnvVarPrefix string = "SIDECAR" + SidecarMetricPortEnvVar string = "METRICS_PORT" + SidecarPortEnvVar string = "PORT" + SidecarSocketPathEnvVar string = "SOCKET_PATH" + SidecarEvaluatorEnvVar string = "EVALUATOR" + SidecarImageEnvVar string = "IMAGE" + SidecarVersionEnvVar string = "TAG" + SidecarProviderArgsEnvVar string = "PROVIDER_ARGS" + SidecarDefaultSyncProviderEnvVar string = "SYNC_PROVIDER" + SidecarLogFormatEnvVar string = "LOG_FORMAT" + SidecarProbesEnabledVar string = "PROBES_ENABLED" + defaultSidecarEnvVarPrefix string = "FLAGD" + DefaultMetricPort int32 = 8014 + defaultPort int32 = 8013 + defaultSocketPath string = "" + defaultEvaluator string = "json" + defaultImage string = "ghcr.io/open-feature/flagd" + defaultTag string = "v0.6.3" + defaultLogFormat string = "json" + defaultProbesEnabled bool = true + SyncProviderKubernetes SyncProviderType = "kubernetes" + SyncProviderFilepath SyncProviderType = "filepath" + SyncProviderHttp SyncProviderType = "http" + SyncProviderGrpc SyncProviderType = "grpc" + SyncProviderFlagdProxy SyncProviderType = "flagd-proxy" ) // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! diff --git a/apis/core/v1alpha1/flagsourceconfiguration_types_test.go b/apis/core/v1alpha1/flagsourceconfiguration_types_test.go index ff7fb8639..57ddbeebb 100644 --- a/apis/core/v1alpha1/flagsourceconfiguration_types_test.go +++ b/apis/core/v1alpha1/flagsourceconfiguration_types_test.go @@ -1,9 +1,9 @@ package v1alpha1 import ( - "github.com/open-feature/open-feature-operator/apis/core/v1alpha1/common" "testing" + "github.com/open-feature/open-feature-operator/apis/core/v1alpha1/common" "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" ) diff --git a/apis/core/v1beta1/featureflag_types.go b/apis/core/v1beta1/featureflag_types.go index ee327fb8d..bc76d881d 100644 --- a/apis/core/v1beta1/featureflag_types.go +++ b/apis/core/v1beta1/featureflag_types.go @@ -19,6 +19,8 @@ package v1beta1 import ( "encoding/json" + "github.com/open-feature/open-feature-operator/apis/core/v1beta1/common" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -61,6 +63,7 @@ type FeatureFlagStatus struct { //+kubebuilder:resource:shortName="ffc" //+kubebuilder:object:root=true //+kubebuilder:subresource:status +//+kubebuilder:storageversion // FeatureFlag is the Schema for the featureflags API type FeatureFlag struct { @@ -83,3 +86,33 @@ type FeatureFlagList struct { func init() { SchemeBuilder.Register(&FeatureFlag{}, &FeatureFlagList{}) } + +func (ff *FeatureFlag) GetReference() metav1.OwnerReference { + return metav1.OwnerReference{ + APIVersion: ff.APIVersion, + Kind: ff.Kind, + Name: ff.Name, + UID: ff.UID, + Controller: common.TrueVal(), + } +} + +func (ff *FeatureFlag) GenerateConfigMap(name string, namespace string, references []metav1.OwnerReference) (*corev1.ConfigMap, error) { + b, err := json.Marshal(ff.Spec.FlagSpec) + if err != nil { + return nil, err + } + return &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Annotations: map[string]string{ + "openfeature.dev/featureflag": name, + }, + OwnerReferences: references, + }, + Data: map[string]string{ + common.FeatureFlagConfigMapKey(namespace, name): string(b), + }, + }, nil +} diff --git a/apis/core/v1beta1/featureflag_types_test.go b/apis/core/v1beta1/featureflag_types_test.go new file mode 100644 index 000000000..d5bcc6514 --- /dev/null +++ b/apis/core/v1beta1/featureflag_types_test.go @@ -0,0 +1,70 @@ +package v1beta1 + +import ( + "testing" + + "github.com/open-feature/open-feature-operator/apis/core/v1beta1/common" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +func Test_FeatureFlag(t *testing.T) { + ff := FeatureFlag{ + ObjectMeta: v1.ObjectMeta{ + Name: "ffconf1", + Namespace: "test", + OwnerReferences: []v1.OwnerReference{ + { + APIVersion: "ver", + Kind: "kind", + Name: "ffconf1", + UID: types.UID("5"), + Controller: common.TrueVal(), + }, + }, + }, + Spec: FeatureFlagSpec{ + FlagSpec: FlagSpec{ + Flags: map[string]Flag{}, + }, + }, + } + + require.Equal(t, v1.OwnerReference{ + APIVersion: ff.APIVersion, + Kind: ff.Kind, + Name: ff.Name, + UID: ff.UID, + Controller: common.TrueVal(), + }, ff.GetReference()) + + name := "cmname" + namespace := "cmnamespace" + references := []v1.OwnerReference{ + { + APIVersion: "ver", + Kind: "kind", + Name: "ffconf1", + UID: types.UID("5"), + Controller: common.TrueVal(), + }, + } + + cm, _ := ff.GenerateConfigMap(name, namespace, references) + + require.Equal(t, corev1.ConfigMap{ + ObjectMeta: v1.ObjectMeta{ + Name: name, + Namespace: namespace, + Annotations: map[string]string{ + "openfeature.dev/featureflag": name, + }, + OwnerReferences: references, + }, + Data: map[string]string{ + "cmnamespace_cmname.flagd.json": "{\"flags\":{}}", + }, + }, *cm) +} diff --git a/apis/core/v1beta1/featureflagsource_types.go b/apis/core/v1beta1/featureflagsource_types.go index 12dea98a6..25b5555d4 100644 --- a/apis/core/v1beta1/featureflagsource_types.go +++ b/apis/core/v1beta1/featureflagsource_types.go @@ -17,16 +17,46 @@ limitations under the License. package v1beta1 import ( + "fmt" + "os" + "strconv" + "strings" + "github.com/open-feature/open-feature-operator/apis/core/v1beta1/common" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +const ( + SidecarEnvVarPrefix string = "SIDECAR_ENV_VAR_PREFIX" + InputConfigurationEnvVarPrefix string = "SIDECAR" + SidecarMetricPortEnvVar string = "MANAGEMENT_PORT" + SidecarPortEnvVar string = "PORT" + SidecarSocketPathEnvVar string = "SOCKET_PATH" + SidecarEvaluatorEnvVar string = "EVALUATOR" + SidecarImageEnvVar string = "IMAGE" + SidecarVersionEnvVar string = "TAG" + SidecarProviderArgsEnvVar string = "PROVIDER_ARGS" + SidecarDefaultSyncProviderEnvVar string = "SYNC_PROVIDER" + SidecarLogFormatEnvVar string = "LOG_FORMAT" + SidecarProbesEnabledVar string = "PROBES_ENABLED" + defaultSidecarEnvVarPrefix string = "FLAGD" + DefaultMetricPort int32 = 8014 + defaultPort int32 = 8013 + defaultSocketPath string = "" + defaultEvaluator string = "json" + defaultImage string = "ghcr.io/open-feature/flagd" + // renovate: datasource=github-tags depName=open-feature/flagd/flagd + defaultTag string = "v0.7.0" + defaultLogFormat string = "json" + defaultProbesEnabled bool = true +) + // FeatureFlagSourceSpec defines the desired state of FeatureFlagSource type FeatureFlagSourceSpec struct { - // MetricsPort defines the port to serve metrics on, defaults to 8014 + // ManagemetPort defines the port to serve management on, defaults to 8014 // +optional - MetricsPort int32 `json:"metricsPort"` + ManagementPort int32 `json:"managementPort"` // Port defines the port to listen on, defaults to 8013 // +optional @@ -52,7 +82,7 @@ type FeatureFlagSourceSpec struct { // +kubebuilder:validation:MinItems=1 Sources []Source `json:"sources"` - // EnvVars define the env vars to be applied to the sidecar, any env vars in FeatureFlagConfiguration CRs + // 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 // +optional EnvVars []corev1.EnvVar `json:"envVars"` @@ -131,6 +161,7 @@ type FeatureFlagSourceStatus struct { //+kubebuilder:resource:shortName="ffs" //+kubebuilder:object:root=true //+kubebuilder:subresource:status +//+kubebuilder:storageversion // FeatureFlagSource is the Schema for the FeatureFlagSources API type FeatureFlagSource struct { @@ -153,3 +184,189 @@ type FeatureFlagSourceList struct { func init() { SchemeBuilder.Register(&FeatureFlagSource{}, &FeatureFlagSourceList{}) } + +//nolint:gocyclo +func NewFeatureFlagSourceSpec() (*FeatureFlagSourceSpec, error) { + fsc := &FeatureFlagSourceSpec{ + ManagementPort: DefaultMetricPort, + Port: defaultPort, + SocketPath: defaultSocketPath, + Evaluator: defaultEvaluator, + Image: defaultImage, + Tag: defaultTag, + Sources: []Source{}, + EnvVars: []corev1.EnvVar{}, + SyncProviderArgs: []string{}, + DefaultSyncProvider: common.SyncProviderKubernetes, + EnvVarPrefix: defaultSidecarEnvVarPrefix, + LogFormat: defaultLogFormat, + RolloutOnChange: nil, + DebugLogging: common.FalseVal(), + OtelCollectorUri: "", + } + + // set default value derived from constant default + probes := defaultProbesEnabled + fsc.ProbesEnabled = &probes + + if managementPort := os.Getenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarMetricPortEnvVar)); managementPort != "" { + managementPortI, err := strconv.Atoi(managementPort) + if err != nil { + return fsc, fmt.Errorf("unable to parse management port value %s to int32: %w", managementPort, err) + } + fsc.ManagementPort = int32(managementPortI) + } + + if port := os.Getenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarPortEnvVar)); port != "" { + portI, err := strconv.Atoi(port) + if err != nil { + return fsc, fmt.Errorf("unable to parse sidecar port value %s to int32: %w", port, err) + } + fsc.Port = int32(portI) + } + + if socketPath := os.Getenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarSocketPathEnvVar)); socketPath != "" { + fsc.SocketPath = socketPath + } + + if evaluator := os.Getenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarEvaluatorEnvVar)); evaluator != "" { + fsc.Evaluator = evaluator + } + + if image := os.Getenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarImageEnvVar)); image != "" { + fsc.Image = image + } + + if tag := os.Getenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarVersionEnvVar)); tag != "" { + fsc.Tag = tag + } + + if syncProviderArgs := os.Getenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarProviderArgsEnvVar)); syncProviderArgs != "" { + fsc.SyncProviderArgs = strings.Split(syncProviderArgs, ",") // todo: add documentation for this + } + + if syncProvider := os.Getenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarDefaultSyncProviderEnvVar)); syncProvider != "" { + fsc.DefaultSyncProvider = common.SyncProviderType(syncProvider) + } + + if logFormat := os.Getenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarLogFormatEnvVar)); logFormat != "" { + fsc.LogFormat = logFormat + } + + if envVarPrefix := os.Getenv(SidecarEnvVarPrefix); envVarPrefix != "" { + fsc.EnvVarPrefix = envVarPrefix + } + + if probesEnabled := os.Getenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarProbesEnabledVar)); probesEnabled != "" { + b, err := strconv.ParseBool(probesEnabled) + if err != nil { + return fsc, fmt.Errorf("unable to parse sidecar probes enabled %s to boolean: %w", probesEnabled, err) + } + fsc.ProbesEnabled = &b + } + + return fsc, nil +} + +//nolint:gocyclo +func (fc *FeatureFlagSourceSpec) Merge(new *FeatureFlagSourceSpec) { + if new == nil { + return + } + if new.ManagementPort != 0 { + fc.ManagementPort = new.ManagementPort + } + if new.Port != 0 { + fc.Port = new.Port + } + if new.SocketPath != "" { + fc.SocketPath = new.SocketPath + } + if new.Evaluator != "" { + fc.Evaluator = new.Evaluator + } + if new.Image != "" { + fc.Image = new.Image + } + if new.Tag != "" { + fc.Tag = new.Tag + } + if len(new.Sources) != 0 { + fc.Sources = append(fc.Sources, new.Sources...) + } + if len(new.EnvVars) != 0 { + fc.EnvVars = append(fc.EnvVars, new.EnvVars...) + } + if new.SyncProviderArgs != nil && len(new.SyncProviderArgs) > 0 { + fc.SyncProviderArgs = append(fc.SyncProviderArgs, new.SyncProviderArgs...) + } + if new.EnvVarPrefix != "" { + fc.EnvVarPrefix = new.EnvVarPrefix + } + if new.DefaultSyncProvider != "" { + fc.DefaultSyncProvider = new.DefaultSyncProvider + } + if new.LogFormat != "" { + fc.LogFormat = new.LogFormat + } + if new.RolloutOnChange != nil { + fc.RolloutOnChange = new.RolloutOnChange + } + if new.ProbesEnabled != nil { + fc.ProbesEnabled = new.ProbesEnabled + } + if new.DebugLogging != nil { + fc.DebugLogging = new.DebugLogging + } + if new.OtelCollectorUri != "" { + fc.OtelCollectorUri = new.OtelCollectorUri + } +} + +func (fc *FeatureFlagSourceSpec) ToEnvVars() []corev1.EnvVar { + envs := []corev1.EnvVar{} + + for _, envVar := range fc.EnvVars { + envs = append(envs, corev1.EnvVar{ + Name: common.EnvVarKey(fc.EnvVarPrefix, envVar.Name), + Value: envVar.Value, + }) + } + + if fc.ManagementPort != DefaultMetricPort { + envs = append(envs, corev1.EnvVar{ + Name: common.EnvVarKey(fc.EnvVarPrefix, SidecarMetricPortEnvVar), + Value: fmt.Sprintf("%d", fc.ManagementPort), + }) + } + + if fc.Port != defaultPort { + envs = append(envs, corev1.EnvVar{ + Name: common.EnvVarKey(fc.EnvVarPrefix, SidecarPortEnvVar), + Value: fmt.Sprintf("%d", fc.Port), + }) + } + + if fc.Evaluator != defaultEvaluator { + envs = append(envs, corev1.EnvVar{ + Name: common.EnvVarKey(fc.EnvVarPrefix, SidecarEvaluatorEnvVar), + Value: fc.Evaluator, + }) + } + + if fc.SocketPath != defaultSocketPath { + envs = append(envs, corev1.EnvVar{ + Name: common.EnvVarKey(fc.EnvVarPrefix, SidecarSocketPathEnvVar), + Value: fc.SocketPath, + }) + } + + if fc.LogFormat != defaultLogFormat { + envs = append(envs, corev1.EnvVar{ + Name: common.EnvVarKey(fc.EnvVarPrefix, SidecarLogFormatEnvVar), + Value: fc.LogFormat, + }) + } + + return envs +} diff --git a/apis/core/v1beta1/featureflagsource_types_test.go b/apis/core/v1beta1/featureflagsource_types_test.go new file mode 100644 index 000000000..acc3a697a --- /dev/null +++ b/apis/core/v1beta1/featureflagsource_types_test.go @@ -0,0 +1,282 @@ +package v1beta1 + +import ( + "testing" + + "github.com/open-feature/open-feature-operator/apis/core/v1beta1/common" + "github.com/stretchr/testify/require" + v1 "k8s.io/api/core/v1" +) + +func Test_FLagSourceConfiguration_Merge(t *testing.T) { + ff_old := &FeatureFlagSource{ + Spec: FeatureFlagSourceSpec{ + EnvVars: []v1.EnvVar{ + { + Name: "env1", + Value: "val1", + }, + { + Name: "env2", + Value: "val2", + }, + }, + EnvVarPrefix: "PRE", + ManagementPort: 22, + Port: 33, + Evaluator: "evaluator", + SocketPath: "socket-path", + LogFormat: "log", + Image: "img", + Tag: "tag", + Sources: []Source{ + { + Source: "src1", + Provider: common.SyncProviderGrpc, + TLS: true, + CertPath: "etc/cert.ca", + ProviderID: "app", + Selector: "source=database", + }, + }, + SyncProviderArgs: []string{"arg1", "arg2"}, + DefaultSyncProvider: common.SyncProviderKubernetes, + RolloutOnChange: common.TrueVal(), + ProbesEnabled: common.TrueVal(), + DebugLogging: common.TrueVal(), + OtelCollectorUri: "", + }, + } + + ff_old.Spec.Merge(nil) + + require.Equal(t, &FeatureFlagSource{ + Spec: FeatureFlagSourceSpec{ + EnvVars: []v1.EnvVar{ + { + Name: "env1", + Value: "val1", + }, + { + Name: "env2", + Value: "val2", + }, + }, + EnvVarPrefix: "PRE", + ManagementPort: 22, + Port: 33, + Evaluator: "evaluator", + SocketPath: "socket-path", + LogFormat: "log", + Image: "img", + Tag: "tag", + Sources: []Source{ + { + Source: "src1", + Provider: common.SyncProviderGrpc, + TLS: true, + CertPath: "etc/cert.ca", + ProviderID: "app", + Selector: "source=database", + }, + }, + SyncProviderArgs: []string{"arg1", "arg2"}, + DefaultSyncProvider: common.SyncProviderKubernetes, + RolloutOnChange: common.TrueVal(), + ProbesEnabled: common.TrueVal(), + DebugLogging: common.TrueVal(), + OtelCollectorUri: "", + }, + }, ff_old) + + ff_new := &FeatureFlagSource{ + Spec: FeatureFlagSourceSpec{ + EnvVars: []v1.EnvVar{ + { + Name: "env3", + Value: "val3", + }, + { + Name: "env4", + Value: "val4", + }, + }, + EnvVarPrefix: "PREFIX", + ManagementPort: 221, + Port: 331, + Evaluator: "evaluator1", + SocketPath: "socket-path1", + LogFormat: "log1", + Image: "img1", + Tag: "tag1", + Sources: []Source{ + { + Source: "src2", + Provider: common.SyncProviderFilepath, + }, + }, + SyncProviderArgs: []string{"arg3", "arg4"}, + DefaultSyncProvider: common.SyncProviderFilepath, + RolloutOnChange: common.FalseVal(), + ProbesEnabled: common.FalseVal(), + DebugLogging: common.FalseVal(), + OtelCollectorUri: "", + }, + } + + ff_old.Spec.Merge(&ff_new.Spec) + + require.Equal(t, &FeatureFlagSource{ + Spec: FeatureFlagSourceSpec{ + EnvVars: []v1.EnvVar{ + { + Name: "env1", + Value: "val1", + }, + { + Name: "env2", + Value: "val2", + }, + { + Name: "env3", + Value: "val3", + }, + { + Name: "env4", + Value: "val4", + }, + }, + EnvVarPrefix: "PREFIX", + ManagementPort: 221, + Port: 331, + Evaluator: "evaluator1", + SocketPath: "socket-path1", + LogFormat: "log1", + Image: "img1", + Tag: "tag1", + Sources: []Source{ + { + Source: "src1", + Provider: common.SyncProviderGrpc, + TLS: true, + CertPath: "etc/cert.ca", + ProviderID: "app", + Selector: "source=database", + }, + { + Source: "src2", + Provider: common.SyncProviderFilepath, + }, + }, + SyncProviderArgs: []string{"arg1", "arg2", "arg3", "arg4"}, + DefaultSyncProvider: common.SyncProviderFilepath, + RolloutOnChange: common.FalseVal(), + ProbesEnabled: common.FalseVal(), + DebugLogging: common.FalseVal(), + OtelCollectorUri: "", + }, + }, ff_old) +} + +func Test_FLagSourceConfiguration_NewFeatureFlagSourceSpec(t *testing.T) { + //happy path + t.Setenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarMetricPortEnvVar), "22") + t.Setenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarPortEnvVar), "33") + t.Setenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarSocketPathEnvVar), "val1") + t.Setenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarEvaluatorEnvVar), "val2") + t.Setenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarImageEnvVar), "val3") + t.Setenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarVersionEnvVar), "val4") + t.Setenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarProviderArgsEnvVar), "val11,val22") + t.Setenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarDefaultSyncProviderEnvVar), "kubernetes") + t.Setenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarLogFormatEnvVar), "val5") + t.Setenv(SidecarEnvVarPrefix, "val6") + t.Setenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarProbesEnabledVar), "true") + + fs, err := NewFeatureFlagSourceSpec() + + require.Nil(t, err) + require.Equal(t, &FeatureFlagSourceSpec{ + ManagementPort: 22, + Port: 33, + SocketPath: "val1", + Evaluator: "val2", + Image: "val3", + Tag: "val4", + Sources: []Source{}, + EnvVars: []v1.EnvVar{}, + SyncProviderArgs: []string{"val11", "val22"}, + DefaultSyncProvider: common.SyncProviderKubernetes, + EnvVarPrefix: "val6", + LogFormat: "val5", + ProbesEnabled: common.TrueVal(), + DebugLogging: common.FalseVal(), + OtelCollectorUri: "", + }, fs) + + //error paths + t.Setenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarProbesEnabledVar), "blah") + _, err = NewFeatureFlagSourceSpec() + require.NotNil(t, err) + + t.Setenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarPortEnvVar), "blah") + _, err = NewFeatureFlagSourceSpec() + require.NotNil(t, err) + + t.Setenv(common.EnvVarKey(InputConfigurationEnvVarPrefix, SidecarMetricPortEnvVar), "blah") + _, err = NewFeatureFlagSourceSpec() + require.NotNil(t, err) +} + +func Test_FLagSourceConfiguration_ToEnvVars(t *testing.T) { + ff := FeatureFlagSource{ + Spec: FeatureFlagSourceSpec{ + EnvVars: []v1.EnvVar{ + { + Name: "env1", + Value: "val1", + }, + { + Name: "env2", + Value: "val2", + }, + }, + EnvVarPrefix: "PRE", + ManagementPort: 22, + Port: 33, + Evaluator: "evaluator", + SocketPath: "socket-path", + LogFormat: "log", + }, + } + expected := []v1.EnvVar{ + { + Name: "PRE_env1", + Value: "val1", + }, + { + Name: "PRE_env2", + Value: "val2", + }, + { + Name: "PRE_METRICS_PORT", + Value: "22", + }, + { + Name: "PRE_PORT", + Value: "33", + }, + { + Name: "PRE_EVALUATOR", + Value: "evaluator", + }, + { + Name: "PRE_SOCKET_PATH", + Value: "socket-path", + }, + { + Name: "PRE_LOG_FORMAT", + Value: "log", + }, + } + require.Equal(t, expected, ff.Spec.ToEnvVars()) +}