Skip to content

Commit

Permalink
feat: default sync provider configuration (#320)
Browse files Browse the repository at this point in the history
Signed-off-by: James Milligan <james@omnant.co.uk>
  • Loading branch information
james-milligan authored Jan 27, 2023
1 parent b04928b commit 7cba7e1
Show file tree
Hide file tree
Showing 12 changed files with 112 additions and 59 deletions.
14 changes: 1 addition & 13 deletions apis/core/v1alpha1/featureflagconfiguration_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ type FlagDSpec struct {
}

type FeatureFlagSyncProvider struct {
Name string `json:"name"`
Name SyncProviderType `json:"name"`
// +optional
// +nullable
HttpSyncConfiguration *HttpSyncConfiguration `json:"httpSyncConfiguration"`
Expand All @@ -67,18 +67,6 @@ type HttpSyncConfiguration struct {
BearerToken string `json:"bearerToken,omitempty"`
}

func (ffsp FeatureFlagSyncProvider) IsKubernetes() bool {
return ffsp.Name == "kubernetes"
}

func (ffsp FeatureFlagSyncProvider) IsHttp() bool {
return ffsp.Name == "http"
}

func (ffsp FeatureFlagSyncProvider) IsFilepath() bool {
return ffsp.Name == "filepath"
}

type FeatureFlagServiceProvider struct {
// +kubebuilder:validation:Enum=flagd
Name string `json:"name"`
Expand Down
77 changes: 54 additions & 23 deletions apis/core/v1alpha1/flagsourceconfiguration_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,30 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type SyncProviderType string

const (
SidecarEnvVarPrefix string = "SIDECAR_ENV_VAR_PREFIX"
SidecarMetricPortEnvVar string = "METRICS_PORT"
SidecarPortEnvVar string = "PORT"
SidecarSocketPathEnvVar string = "SOCKET_PATH"
SidecarEvaluatorEnvVar string = "EVALUATOR"
SidecarImageEnvVar string = "IMAGE"
SidecarVersionEnvVar string = "TAG"
SidecarProviderArgsEnvVar string = "PROVIDER_ARGS"
defaultSidecarEnvVarPrefix string = "FLAGD"
InputConfigurationEnvVarPrefix string = "SIDECAR"
defaultMetricPort int32 = 8014
defaultPort int32 = 8013
defaultSocketPath string = ""
defaultEvaluator string = "json"
defaultImage string = "ghcr.io/open-feature/flagd"
defaultTag string = "v0.3.1"
SidecarEnvVarPrefix string = "SIDECAR_ENV_VAR_PREFIX"
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"
defaultSidecarEnvVarPrefix string = "FLAGD"
InputConfigurationEnvVarPrefix string = "SIDECAR"
defaultMetricPort int32 = 8014
defaultPort int32 = 8013
defaultSocketPath string = ""
defaultEvaluator string = "json"
defaultImage string = "ghcr.io/open-feature/flagd"
defaultTag string = "v0.3.1"
SyncProviderKubernetes SyncProviderType = "kubernetes"
SyncProviderFilepath SyncProviderType = "filepath"
SyncProviderHttp SyncProviderType = "http"
defaultSyncProvider = SyncProviderKubernetes
)

// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
Expand Down Expand Up @@ -80,17 +87,22 @@ type FlagSourceConfigurationSpec struct {
// Tag to be appended to the sidecar image, defaults to 'main'
// +optional
Tag string `json:"tag"`

// DefaultSyncProvider defines the default sync provider
// +optional
DefaultSyncProvider SyncProviderType `json:"defaultSyncProvider"`
}

func NewFlagSourceConfigurationSpec() (*FlagSourceConfigurationSpec, error) {
fsc := &FlagSourceConfigurationSpec{
MetricsPort: defaultMetricPort,
Port: defaultPort,
SocketPath: defaultSocketPath,
SyncProviderArgs: []string{},
Evaluator: defaultEvaluator,
Image: defaultImage,
Tag: defaultTag,
MetricsPort: defaultMetricPort,
Port: defaultPort,
SocketPath: defaultSocketPath,
SyncProviderArgs: []string{},
Evaluator: defaultEvaluator,
Image: defaultImage,
Tag: defaultTag,
DefaultSyncProvider: SyncProviderKubernetes,
}

if metricsPort := os.Getenv(fmt.Sprintf("%s_%s", InputConfigurationEnvVarPrefix, SidecarMetricPortEnvVar)); metricsPort != "" {
Expand Down Expand Up @@ -129,6 +141,10 @@ func NewFlagSourceConfigurationSpec() (*FlagSourceConfigurationSpec, error) {
fsc.SyncProviderArgs = strings.Split(syncProviderArgs, ",") // todo: add documentation for this
}

if syncProvider := os.Getenv(fmt.Sprintf("%s_%s", InputConfigurationEnvVarPrefix, SidecarDefaultSyncProviderEnvVar)); syncProvider != "" {
fsc.DefaultSyncProvider = SyncProviderType(syncProvider)
}

return fsc, nil
}

Expand Down Expand Up @@ -157,6 +173,9 @@ func (fc *FlagSourceConfigurationSpec) Merge(new *FlagSourceConfigurationSpec) {
if new.SyncProviderArgs != nil && len(new.SyncProviderArgs) > 0 {
fc.SyncProviderArgs = append(fc.SyncProviderArgs, new.SyncProviderArgs...)
}
if new.DefaultSyncProvider != "" {
fc.DefaultSyncProvider = new.DefaultSyncProvider
}
}

func (fc *FlagSourceConfigurationSpec) ToEnvVars() []corev1.EnvVar {
Expand Down Expand Up @@ -229,3 +248,15 @@ type FlagSourceConfigurationList struct {
func init() {
SchemeBuilder.Register(&FlagSourceConfiguration{}, &FlagSourceConfigurationList{})
}

func (s SyncProviderType) IsKubernetes() bool {
return s == SyncProviderKubernetes
}

func (s SyncProviderType) IsHttp() bool {
return s == SyncProviderHttp
}

func (s SyncProviderType) IsFilepath() bool {
return s == SyncProviderFilepath
}
4 changes: 2 additions & 2 deletions apis/core/v1alpha2/featureflagconfiguration_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (src *FeatureFlagConfiguration) ConvertTo(dstRaw conversion.Hub) error {
}

if src.Spec.SyncProvider != nil {
dst.Spec.SyncProvider = &v1alpha1.FeatureFlagSyncProvider{Name: src.Spec.SyncProvider.Name}
dst.Spec.SyncProvider = &v1alpha1.FeatureFlagSyncProvider{Name: v1alpha1.SyncProviderType(src.Spec.SyncProvider.Name)}
if src.Spec.SyncProvider.HttpSyncConfiguration != nil {
dst.Spec.SyncProvider.HttpSyncConfiguration = &v1alpha1.HttpSyncConfiguration{
Target: src.Spec.SyncProvider.HttpSyncConfiguration.Target,
Expand Down Expand Up @@ -79,7 +79,7 @@ func (dst *FeatureFlagConfiguration) ConvertFrom(srcRaw conversion.Hub) error {

if src.Spec.SyncProvider != nil {
dst.Spec.SyncProvider = &FeatureFlagSyncProvider{
Name: src.Spec.SyncProvider.Name,
Name: string(src.Spec.SyncProvider.Name),
}
if src.Spec.SyncProvider.HttpSyncConfiguration != nil {
dst.Spec.SyncProvider.HttpSyncConfiguration = &HttpSyncConfiguration{
Expand Down
30 changes: 16 additions & 14 deletions apis/core/v1alpha2/flagsourceconfiguration_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,14 @@ func (src *FlagSourceConfiguration) ConvertTo(dstRaw conversion.Hub) error {

dst.ObjectMeta = src.ObjectMeta
dst.Spec = v1alpha1.FlagSourceConfigurationSpec{
MetricsPort: src.Spec.MetricsPort,
Port: src.Spec.Port,
SocketPath: src.Spec.SocketPath,
SyncProviderArgs: src.Spec.SyncProviderArgs,
Evaluator: src.Spec.Evaluator,
Image: src.Spec.Image,
Tag: src.Spec.Tag,
MetricsPort: src.Spec.MetricsPort,
Port: src.Spec.Port,
SocketPath: src.Spec.SocketPath,
SyncProviderArgs: src.Spec.SyncProviderArgs,
Evaluator: src.Spec.Evaluator,
Image: src.Spec.Image,
Tag: src.Spec.Tag,
DefaultSyncProvider: v1alpha1.SyncProviderType(src.Spec.DefaultSyncProvider),
}
return nil
}
Expand All @@ -49,13 +50,14 @@ func (dst *FlagSourceConfiguration) ConvertFrom(srcRaw conversion.Hub) error {

dst.ObjectMeta = src.ObjectMeta
dst.Spec = FlagSourceConfigurationSpec{
MetricsPort: src.Spec.MetricsPort,
Port: src.Spec.Port,
SocketPath: src.Spec.SocketPath,
SyncProviderArgs: src.Spec.SyncProviderArgs,
Evaluator: src.Spec.Evaluator,
Image: src.Spec.Image,
Tag: src.Spec.Tag,
MetricsPort: src.Spec.MetricsPort,
Port: src.Spec.Port,
SocketPath: src.Spec.SocketPath,
SyncProviderArgs: src.Spec.SyncProviderArgs,
Evaluator: src.Spec.Evaluator,
Image: src.Spec.Image,
Tag: src.Spec.Tag,
DefaultSyncProvider: string(src.Spec.DefaultSyncProvider),
}
return nil
}
4 changes: 4 additions & 0 deletions apis/core/v1alpha2/flagsourceconfiguration_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ type FlagSourceConfigurationSpec struct {
// Tag to be appended to the sidecar image, defaults to 'main'
// +optional
Tag string `json:"tag"`

// DefaultSyncProvider defines the default sync provider
// +optional
DefaultSyncProvider string `json:"defaultSyncProvider"`
}

// FlagSourceConfigurationStatus defines the observed state of FlagSourceConfiguration
Expand Down
5 changes: 3 additions & 2 deletions chart/open-feature-operator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ The command removes all the Kubernetes components associated with the chart and
| `sidecarConfiguration.port` | 8013 | Sets the value of the `XXX_PORT` environment variable for the injected sidecar container.|
| `sidecarConfiguration.metricsPort` | 8014 | Sets the value of the `XXX_METRICS_PORT` environment variable for the injected sidecar container.|
| `sidecarConfiguration.socketPath` | `""` | Sets the value of the `XXX_SOCKET_PATH` environment variable for the injected sidecar container.|
| `sidecarConfiguration.repository` | `ghcr.io/open-feature/flagd` | Sets the image for the injected sidecar container. |
| `sidecarConfiguration.tag` | current flagd version: `v0.3.2` | Sets the version tag for the injected sidecar container. |
| `sidecarConfiguration.image.repository` | `ghcr.io/open-feature/flagd` | Sets the image for the injected sidecar container. |
| `sidecarConfiguration.image.tag` | current flagd version: `v0.3.2` | Sets the version tag for the injected sidecar container. |
| `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.defaultSyncProvider` | `kubernetes` | Sets the value of the `XXX_SYNC_PROVIDER` environment variable for the injected sidecar container. There are 3 valid sync providers: `kubernetes`, `filepath` and `http` |

### Operator resource configuration
<!-- x-release-please-start-version -->
Expand Down
8 changes: 8 additions & 0 deletions chart/open-feature-operator/templates/rendered.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,9 @@ spec:
description: FlagSourceConfigurationSpec defines the desired state of
FlagSourceConfiguration
properties:
defaultSyncProvider:
description: DefaultSyncProvider defines the default sync provider
type: string
evaluator:
description: Evaluator sets an evaluator, defaults to 'json'
type: string
Expand Down Expand Up @@ -668,6 +671,9 @@ spec:
description: FlagSourceConfigurationSpec defines the desired state of
FlagSourceConfiguration
properties:
defaultSyncProvider:
description: DefaultSyncProvider defines the default sync provider
type: string
evaluator:
description: Evaluator sets an evaluator, defaults to 'json'
type: string
Expand Down Expand Up @@ -1035,6 +1041,8 @@ spec:
value: '{{ .Values.sidecarConfiguration.providerArgs }}'
- name: SIDECAR_ENV_VAR_PREFIX
value: '{{ .Values.sidecarConfiguration.envVarPrefix }}'
- name: SIDECAR_SYNC_PROVIDER
value: '{{ .Values.sidecarConfiguration.defaultSyncProvider }}'
image: '{{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag
}}'
imagePullPolicy: IfNotPresent
Expand Down
1 change: 1 addition & 0 deletions chart/open-feature-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ sidecarConfiguration:
tag: v0.3.2
providerArgs: ""
envVarPrefix: "FLAGD"
defaultSyncProvider: kubernetes

controllerManager:
kubeRbacProxy:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ spec:
description: FlagSourceConfigurationSpec defines the desired state of
FlagSourceConfiguration
properties:
defaultSyncProvider:
description: DefaultSyncProvider defines the default sync provider
type: string
evaluator:
description: Evaluator sets an evaluator, defaults to 'json'
type: string
Expand Down Expand Up @@ -100,6 +103,9 @@ spec:
description: FlagSourceConfigurationSpec defines the desired state of
FlagSourceConfiguration
properties:
defaultSyncProvider:
description: DefaultSyncProvider defines the default sync provider
type: string
evaluator:
description: Evaluator sets an evaluator, defaults to 'json'
type: string
Expand Down
2 changes: 2 additions & 0 deletions config/overlays/helm/manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ spec:
value: "{{ .Values.sidecarConfiguration.providerArgs }}"
- name: SIDECAR_ENV_VAR_PREFIX
value: "{{ .Values.sidecarConfiguration.envVarPrefix }}"
- name: SIDECAR_SYNC_PROVIDER
value: "{{ .Values.sidecarConfiguration.defaultSyncProvider }}"
- name: kube-rbac-proxy
image: "{{ .Values.controllerManager.kubeRbacProxy.image.repository }}:{{ .Values.controllerManager.kubeRbacProxy.image.tag }}"
resources:
Expand Down
13 changes: 9 additions & 4 deletions webhooks/pod_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,12 @@ func (m *PodMutator) Handle(ctx context.Context, req admission.Request) admissio
m.Log.V(1).Info(fmt.Sprintf("FeatureFlagConfiguration could not be found for %s", ffName))
return admission.Errored(http.StatusBadRequest, err)
}
if ff.Spec.SyncProvider != nil && !ff.Spec.SyncProvider.IsKubernetes() {
if ff.Spec.SyncProvider == nil || ff.Spec.SyncProvider.Name == "" {
ff.Spec.SyncProvider = &corev1alpha1.FeatureFlagSyncProvider{
Name: flagSourceConfigurationSpec.DefaultSyncProvider,
}
}
if !ff.Spec.SyncProvider.Name.IsKubernetes() {
// Check for ConfigMap and create it if it doesn't exist (only required if sync provider isn't kubernetes)
cm := corev1.ConfigMap{}
if err := m.Client.Get(ctx, client.ObjectKey{Name: name, Namespace: req.Namespace}, &cm); errors.IsNotFound(err) {
Expand Down Expand Up @@ -343,7 +348,7 @@ func (m *PodMutator) injectSidecar(
}
switch {
// kubernetes sync is the default state
case featureFlag.Spec.SyncProvider == nil || featureFlag.Spec.SyncProvider.IsKubernetes():
case featureFlag.Spec.SyncProvider == nil || featureFlag.Spec.SyncProvider.Name.IsKubernetes():
m.Log.V(1).Info(fmt.Sprintf("FeatureFlagConfiguration %s using kubernetes sync implementation", featureFlag.Name))
commandSequence = append(
commandSequence,
Expand All @@ -355,7 +360,7 @@ func (m *PodMutator) injectSidecar(
),
)
// if http is explicitly set
case featureFlag.Spec.SyncProvider.IsHttp():
case featureFlag.Spec.SyncProvider.Name.IsHttp():
m.Log.V(1).Info(fmt.Sprintf("FeatureFlagConfiguration %s using http sync implementation", featureFlag.Name))
if featureFlag.Spec.SyncProvider.HttpSyncConfiguration != nil {
commandSequence = append(
Expand All @@ -375,7 +380,7 @@ func (m *PodMutator) injectSidecar(
m.Log.V(1).Error(err, "unable to add http sync provider")
}
// if filepath is explicitly set
case featureFlag.Spec.SyncProvider.IsFilepath():
case featureFlag.Spec.SyncProvider.Name.IsFilepath():
m.Log.V(1).Info(fmt.Sprintf("FeatureFlagConfiguration %s using filepath sync implementation", featureFlag.Name))
commandSequence = append(
commandSequence,
Expand Down
7 changes: 6 additions & 1 deletion webhooks/pod_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,10 +434,12 @@ var _ = Describe("pod mutation webhook", func() {
os.Setenv(fmt.Sprintf("%s_%s", corev1alpha1.InputConfigurationEnvVarPrefix, corev1alpha1.SidecarEvaluatorEnvVar), "evaluator")
os.Setenv(fmt.Sprintf("%s_%s", corev1alpha1.InputConfigurationEnvVarPrefix, corev1alpha1.SidecarImageEnvVar), "image")
os.Setenv(fmt.Sprintf("%s_%s", corev1alpha1.InputConfigurationEnvVarPrefix, corev1alpha1.SidecarVersionEnvVar), "version")
os.Setenv(fmt.Sprintf("%s_%s", corev1alpha1.InputConfigurationEnvVarPrefix, corev1alpha1.SidecarDefaultSyncProviderEnvVar), "filepath")
os.Setenv(fmt.Sprintf("%s_%s", corev1alpha1.InputConfigurationEnvVarPrefix, corev1alpha1.SidecarProviderArgsEnvVar), "key=value,key2=value2")

pod := testPod(defaultPodName, defaultPodServiceAccountName, map[string]string{
"openfeature.dev": "enabled",
"openfeature.dev": "enabled",
"openfeature.dev/featureflagconfiguration": fmt.Sprintf("%s/%s", mutatePodNamespace, featureFlagConfigurationName),
})
err := k8sClient.Create(testCtx, pod)
Expect(err).ShouldNot(HaveOccurred())
Expand All @@ -453,6 +455,8 @@ var _ = Describe("pod mutation webhook", func() {
Expect(pod.Spec.Containers[1].Image).To(Equal("image:version"))
Expect(pod.Spec.Containers[1].Args).To(Equal([]string{
"start",
"--uri",
"file:/etc/flagd/test-feature-flag-configuration.json",
"--sync-provider-args",
"key=value",
"--sync-provider-args",
Expand All @@ -469,6 +473,7 @@ var _ = Describe("pod mutation webhook", func() {
os.Setenv(fmt.Sprintf("%s_%s", corev1alpha1.InputConfigurationEnvVarPrefix, corev1alpha1.SidecarEvaluatorEnvVar), "")
os.Setenv(fmt.Sprintf("%s_%s", corev1alpha1.InputConfigurationEnvVarPrefix, corev1alpha1.SidecarImageEnvVar), "")
os.Setenv(fmt.Sprintf("%s_%s", corev1alpha1.InputConfigurationEnvVarPrefix, corev1alpha1.SidecarVersionEnvVar), "")
os.Setenv(fmt.Sprintf("%s_%s", corev1alpha1.InputConfigurationEnvVarPrefix, corev1alpha1.SidecarDefaultSyncProviderEnvVar), "")
os.Setenv(fmt.Sprintf("%s_%s", corev1alpha1.InputConfigurationEnvVarPrefix, corev1alpha1.SidecarProviderArgsEnvVar), "key=value,key2=value2")

pod := testPod(defaultPodName, defaultPodServiceAccountName, map[string]string{
Expand Down

0 comments on commit 7cba7e1

Please sign in to comment.