Skip to content

Commit 17a547f

Browse files
odubajDTbacherfl
andauthored
chore: refactor code to decrease complexity (#554)
Signed-off-by: odubajDT <[email protected]> Signed-off-by: odubajDT <[email protected]> Co-authored-by: Florian Bacher <[email protected]>
1 parent ccc0471 commit 17a547f

File tree

19 files changed

+453
-322
lines changed

19 files changed

+453
-322
lines changed

apis/core/v1beta1/featureflagsource_types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ func (fc *FeatureFlagSourceSpec) Merge(new *FeatureFlagSourceSpec) {
194194
if len(new.EnvVars) != 0 {
195195
fc.EnvVars = append(fc.EnvVars, new.EnvVars...)
196196
}
197-
if new.SyncProviderArgs != nil && len(new.SyncProviderArgs) > 0 {
197+
if len(new.SyncProviderArgs) != 0 {
198198
fc.SyncProviderArgs = append(fc.SyncProviderArgs, new.SyncProviderArgs...)
199199
}
200200
if new.EnvVarPrefix != "" {

common/common.go

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,46 +2,38 @@ package common
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"time"
78

89
api "github.com/open-feature/open-feature-operator/apis/core/v1beta1"
910
appsV1 "k8s.io/api/apps/v1"
11+
corev1 "k8s.io/api/core/v1"
1012
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1113
"sigs.k8s.io/controller-runtime/pkg/client"
1214
)
1315

1416
const (
15-
ReconcileErrorInterval = 10 * time.Second
16-
ReconcileSuccessInterval = 120 * time.Second
17-
FinalizerName = "featureflag.core.openfeature.dev/finalizer"
18-
OpenFeatureAnnotationPath = "spec.template.metadata.annotations.openfeature.dev/openfeature.dev"
19-
FeatureFlagSourceAnnotation = "featureflagsource"
20-
OpenFeatureAnnotationRoot = "openfeature.dev"
17+
ReconcileErrorInterval = 10 * time.Second
18+
ReconcileSuccessInterval = 120 * time.Second
19+
FinalizerName = "featureflag.core.openfeature.dev/finalizer"
20+
OpenFeatureAnnotationPath = "spec.template.metadata.annotations.openfeature.dev/openfeature.dev"
21+
OpenFeatureAnnotationRoot = "openfeature.dev"
22+
FlagdImagePullPolicy corev1.PullPolicy = "Always"
23+
ClusterRoleBindingName string = "open-feature-operator-flagd-kubernetes-sync"
24+
AllowKubernetesSyncAnnotation = "allowkubernetessync"
25+
OpenFeatureAnnotationPrefix = "openfeature.dev"
26+
PodOpenFeatureAnnotationPath = "metadata.annotations.openfeature.dev"
27+
SourceConfigParam = "--sources"
28+
ProbeReadiness = "/readyz"
29+
ProbeLiveness = "/healthz"
30+
ProbeInitialDelay = 5
31+
FeatureFlagSourceAnnotation = "featureflagsource"
32+
EnabledAnnotation = "enabled"
2133
)
2234

23-
type EnvConfig struct {
24-
PodNamespace string `envconfig:"POD_NAMESPACE" default:"open-feature-operator-system"`
25-
FlagdProxyImage string `envconfig:"FLAGD_PROXY_IMAGE" default:"ghcr.io/open-feature/flagd-proxy"`
26-
// renovate: datasource=github-tags depName=open-feature/flagd/flagd-proxy
27-
FlagdProxyTag string `envconfig:"FLAGD_PROXY_TAG" default:"v0.3.0"`
28-
FlagdProxyPort int `envconfig:"FLAGD_PROXY_PORT" default:"8015"`
29-
FlagdProxyManagementPort int `envconfig:"FLAGD_PROXY_MANAGEMENT_PORT" default:"8016"`
30-
FlagdProxyDebugLogging bool `envconfig:"FLAGD_PROXY_DEBUG_LOGGING" default:"false"`
31-
32-
SidecarEnvVarPrefix string `envconfig:"SIDECAR_ENV_VAR_PREFIX" default:"FLAGD"`
33-
SidecarManagementPort int `envconfig:"SIDECAR_MANAGEMENT_PORT" default:"8014"`
34-
SidecarPort int `envconfig:"SIDECAR_PORT" default:"8013"`
35-
SidecarImage string `envconfig:"SIDECAR_IMAGE" default:"ghcr.io/open-feature/flagd"`
36-
// renovate: datasource=github-tags depName=open-feature/flagd/flagd-proxy
37-
SidecarTag string `envconfig:"SIDECAR_TAG" default:"v0.7.0"`
38-
SidecarSocketPath string `envconfig:"SIDECAR_SOCKET_PATH" default:""`
39-
SidecarEvaluator string `envconfig:"SIDECAR_EVALUATOR" default:"json"`
40-
SidecarProviderArgs string `envconfig:"SIDECAR_PROVIDER_ARGS" default:""`
41-
SidecarSyncProvider string `envconfig:"SIDECAR_SYNC_PROVIDER" default:"kubernetes"`
42-
SidecarLogFormat string `envconfig:"SIDECAR_LOG_FORMAT" default:"json"`
43-
SidecarProbesEnabled bool `envconfig:"SIDECAR_PROBES_ENABLED" default:"true"`
44-
}
35+
var ErrFlagdProxyNotReady = errors.New("flagd-proxy is not ready, deferring pod admission")
36+
var ErrUnrecognizedSyncProvider = errors.New("unrecognized sync provider")
4537

4638
func FeatureFlagSourceIndex(o client.Object) []string {
4739
deployment, ok := o.(*appsV1.Deployment)

common/constant/configuration.go

Lines changed: 0 additions & 17 deletions
This file was deleted.

common/constant/errors.go

Lines changed: 0 additions & 6 deletions
This file was deleted.

common/flagdinjector/flagdinjector.go

Lines changed: 73 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
api "github.com/open-feature/open-feature-operator/apis/core/v1beta1"
1111
apicommon "github.com/open-feature/open-feature-operator/apis/core/v1beta1/common"
1212
"github.com/open-feature/open-feature-operator/common"
13-
"github.com/open-feature/open-feature-operator/common/constant"
1413
"github.com/open-feature/open-feature-operator/common/flagdproxy"
1514
"github.com/open-feature/open-feature-operator/common/types"
1615
"github.com/open-feature/open-feature-operator/common/utils"
@@ -46,7 +45,7 @@ type FlagdContainerInjector struct {
4645
Client client.Client
4746
Logger logr.Logger
4847
FlagdProxyConfig *flagdproxy.FlagdProxyConfiguration
49-
FlagDResourceRequirements corev1.ResourceRequirements
48+
FlagdResourceRequirements corev1.ResourceRequirements
5049
Image string
5150
Tag string
5251
}
@@ -63,8 +62,8 @@ func (fi *FlagdContainerInjector) InjectFlagd(
6362

6463
// Enable probes
6564
if flagSourceConfig.ProbesEnabled != nil && *flagSourceConfig.ProbesEnabled {
66-
flagdContainer.LivenessProbe = buildProbe(constant.ProbeLiveness, int(flagSourceConfig.ManagementPort))
67-
flagdContainer.ReadinessProbe = buildProbe(constant.ProbeReadiness, int(flagSourceConfig.ManagementPort))
65+
flagdContainer.LivenessProbe = buildProbe(common.ProbeLiveness, int(flagSourceConfig.ManagementPort))
66+
flagdContainer.ReadinessProbe = buildProbe(common.ProbeReadiness, int(flagSourceConfig.ManagementPort))
6867
}
6968

7069
if err := fi.handleSidecarSources(ctx, objectMeta, podSpec, flagSourceConfig, &flagdContainer); err != nil {
@@ -128,48 +127,63 @@ func (fi *FlagdContainerInjector) InjectFlagd(
128127
// service account under the given namespace (required for kubernetes sync provider)
129128
func (fi *FlagdContainerInjector) EnableClusterRoleBinding(ctx context.Context, namespace, serviceAccountName string) error {
130129
serviceAccount := client.ObjectKey{
131-
Name: serviceAccountName,
130+
Name: determineServiceAccountName(serviceAccountName),
132131
Namespace: namespace,
133132
}
134-
if serviceAccountName == "" {
135-
serviceAccount.Name = "default"
136-
}
133+
137134
// Check if the service account exists
138135
fi.Logger.V(1).Info(fmt.Sprintf("Fetching serviceAccount: %s/%s", serviceAccount.Namespace, serviceAccount.Name))
139136
sa := corev1.ServiceAccount{}
140137
if err := fi.Client.Get(ctx, serviceAccount, &sa); err != nil {
141138
fi.Logger.V(1).Info(fmt.Sprintf("ServiceAccount not found: %s/%s", serviceAccount.Namespace, serviceAccount.Name))
142139
return err
143140
}
144-
fi.Logger.V(1).Info(fmt.Sprintf("Fetching clusterrolebinding: %s", constant.ClusterRoleBindingName))
141+
142+
fi.Logger.V(1).Info(fmt.Sprintf("Fetching clusterrolebinding: %s", common.ClusterRoleBindingName))
145143
// Fetch service account if it exists
146144
crb := rbacv1.ClusterRoleBinding{}
147-
if err := fi.Client.Get(ctx, client.ObjectKey{Name: constant.ClusterRoleBindingName}, &crb); errors.IsNotFound(err) {
148-
fi.Logger.V(1).Info(fmt.Sprintf("ClusterRoleBinding not found: %s", constant.ClusterRoleBindingName))
145+
if err := fi.Client.Get(ctx, client.ObjectKey{Name: common.ClusterRoleBindingName}, &crb); errors.IsNotFound(err) {
146+
fi.Logger.V(1).Info(fmt.Sprintf("ClusterRoleBinding not found: %s", common.ClusterRoleBindingName))
149147
return err
150148
}
151-
found := false
149+
150+
if !fi.isServiceAccountSet(&crb, serviceAccount) {
151+
return fi.updateServiceAccount(ctx, &crb, serviceAccount)
152+
}
153+
154+
return nil
155+
}
156+
157+
func determineServiceAccountName(name string) string {
158+
if name == "" {
159+
return "default"
160+
}
161+
return name
162+
}
163+
164+
func (fi *FlagdContainerInjector) isServiceAccountSet(crb *rbacv1.ClusterRoleBinding, serviceAccount client.ObjectKey) bool {
152165
for _, subject := range crb.Subjects {
153166
if subject.Kind == "ServiceAccount" && subject.Name == serviceAccount.Name && subject.Namespace == serviceAccount.Namespace {
154167
fi.Logger.V(1).Info(fmt.Sprintf("ClusterRoleBinding already exists for service account: %s/%s", serviceAccount.Namespace, serviceAccount.Name))
155-
found = true
168+
return true
156169
}
157170
}
158-
if !found {
159-
fi.Logger.V(1).Info(fmt.Sprintf("Updating ClusterRoleBinding %s for service account: %s/%s", crb.Name,
160-
serviceAccount.Namespace, serviceAccount.Name))
161-
crb.Subjects = append(crb.Subjects, rbacv1.Subject{
162-
Kind: "ServiceAccount",
163-
Name: serviceAccount.Name,
164-
Namespace: serviceAccount.Namespace,
165-
})
166-
if err := fi.Client.Update(ctx, &crb); err != nil {
167-
fi.Logger.V(1).Info(fmt.Sprintf("Failed to update ClusterRoleBinding: %s", err.Error()))
168-
return err
169-
}
171+
return false
172+
}
173+
174+
func (fi *FlagdContainerInjector) updateServiceAccount(ctx context.Context, crb *rbacv1.ClusterRoleBinding, serviceAccount client.ObjectKey) error {
175+
fi.Logger.V(1).Info(fmt.Sprintf("Updating ClusterRoleBinding %s for service account: %s/%s", crb.Name,
176+
serviceAccount.Namespace, serviceAccount.Name))
177+
crb.Subjects = append(crb.Subjects, rbacv1.Subject{
178+
Kind: "ServiceAccount",
179+
Name: serviceAccount.Name,
180+
Namespace: serviceAccount.Namespace,
181+
})
182+
if err := fi.Client.Update(ctx, crb); err != nil {
183+
fi.Logger.V(1).Info(fmt.Sprintf("Failed to update ClusterRoleBinding: %s", err.Error()))
184+
return err
170185
}
171186
fi.Logger.V(1).Info(fmt.Sprintf("Updated ClusterRoleBinding: %s", crb.Name))
172-
173187
return nil
174188
}
175189

@@ -186,7 +200,6 @@ func (fi *FlagdContainerInjector) handleSidecarSources(ctx context.Context, obje
186200
return nil
187201
}
188202

189-
//nolint:gocyclo
190203
func (fi *FlagdContainerInjector) buildSources(ctx context.Context, objectMeta *metav1.ObjectMeta, flagSourceConfig *api.FeatureFlagSourceSpec, podSpec *corev1.PodSpec, sidecar *corev1.Container) ([]types.SourceConfig, error) {
191204
var sourceCfgCollection []types.SourceConfig
192205

@@ -195,40 +208,40 @@ func (fi *FlagdContainerInjector) buildSources(ctx context.Context, objectMeta *
195208
source.Provider = flagSourceConfig.DefaultSyncProvider
196209
}
197210

198-
var sourceCfg types.SourceConfig
199-
var err error
200-
201-
switch {
202-
case source.Provider.IsKubernetes():
203-
sourceCfg, err = fi.toKubernetesProviderConfig(ctx, objectMeta, podSpec, source)
204-
if err != nil {
205-
return []types.SourceConfig{}, err
206-
}
207-
case source.Provider.IsFilepath():
208-
sourceCfg, err = fi.toFilepathProviderConfig(ctx, objectMeta, podSpec, sidecar, source)
209-
if err != nil {
210-
return []types.SourceConfig{}, err
211-
}
212-
case source.Provider.IsHttp():
213-
sourceCfg = fi.toHttpProviderConfig(source)
214-
case source.Provider.IsGrpc():
215-
sourceCfg = fi.toGrpcProviderConfig(source)
216-
case source.Provider.IsFlagdProxy():
217-
sourceCfg, err = fi.toFlagdProxyConfig(ctx, objectMeta, source)
218-
if err != nil {
219-
return []types.SourceConfig{}, err
220-
}
221-
default:
222-
return []types.SourceConfig{}, fmt.Errorf("could not add provider %s: %w", source.Provider, constant.ErrUnrecognizedSyncProvider)
211+
sourceCfg, err := fi.newSourceConfig(ctx, source, objectMeta, podSpec, sidecar)
212+
if err != nil {
213+
return []types.SourceConfig{}, err
223214
}
224215

225-
sourceCfgCollection = append(sourceCfgCollection, sourceCfg)
216+
sourceCfgCollection = append(sourceCfgCollection, *sourceCfg)
226217

227218
}
228219

229220
return sourceCfgCollection, nil
230221
}
231222

223+
func (fi *FlagdContainerInjector) newSourceConfig(ctx context.Context, source api.Source, objectMeta *metav1.ObjectMeta, podSpec *corev1.PodSpec, sidecar *corev1.Container) (*types.SourceConfig, error) {
224+
sourceCfg := types.SourceConfig{}
225+
var err error = nil
226+
227+
switch {
228+
case source.Provider.IsKubernetes():
229+
sourceCfg, err = fi.toKubernetesProviderConfig(ctx, objectMeta, podSpec, source)
230+
case source.Provider.IsFilepath():
231+
sourceCfg, err = fi.toFilepathProviderConfig(ctx, objectMeta, podSpec, sidecar, source)
232+
case source.Provider.IsHttp():
233+
sourceCfg = fi.toHttpProviderConfig(source)
234+
case source.Provider.IsGrpc():
235+
sourceCfg = fi.toGrpcProviderConfig(source)
236+
case source.Provider.IsFlagdProxy():
237+
sourceCfg, err = fi.toFlagdProxyConfig(ctx, objectMeta, source)
238+
default:
239+
err = fmt.Errorf("could not add provider %s: %w", source.Provider, common.ErrUnrecognizedSyncProvider)
240+
}
241+
242+
return &sourceCfg, err
243+
}
244+
232245
func (fi *FlagdContainerInjector) toFilepathProviderConfig(ctx context.Context, objectMeta *metav1.ObjectMeta, podSpec *corev1.PodSpec, sidecar *corev1.Container, source api.Source) (types.SourceConfig, error) {
233246
// create config map
234247
ns, n := utils.ParseAnnotation(source.Source, objectMeta.Namespace)
@@ -312,7 +325,7 @@ func (fi *FlagdContainerInjector) toFlagdProxyConfig(ctx context.Context, object
312325
return types.SourceConfig{}, err
313326
}
314327
if !exists || (exists && !ready) {
315-
return types.SourceConfig{}, constant.ErrFlagdProxyNotReady
328+
return types.SourceConfig{}, common.ErrFlagdProxyNotReady
316329
}
317330
ns, n := utils.ParseAnnotation(source.Source, objectMeta.Namespace)
318331
return types.SourceConfig{
@@ -339,7 +352,7 @@ func (fi *FlagdContainerInjector) isFlagdProxyReady(ctx context.Context) (bool,
339352
return true, false, fmt.Errorf(
340353
"flagd-proxy not ready after 3 minutes, was created at %s: %w",
341354
d.CreationTimestamp.Time.String(),
342-
constant.ErrFlagdProxyNotReady,
355+
common.ErrFlagdProxyNotReady,
343356
)
344357
}
345358
return true, false, nil
@@ -365,7 +378,7 @@ func (fi *FlagdContainerInjector) toKubernetesProviderConfig(ctx context.Context
365378
if objectMeta.Annotations == nil {
366379
objectMeta.Annotations = map[string]string{}
367380
}
368-
objectMeta.Annotations[fmt.Sprintf("%s/%s", constant.OpenFeatureAnnotationPrefix, constant.AllowKubernetesSyncAnnotation)] = "true"
381+
objectMeta.Annotations[fmt.Sprintf("%s/%s", common.OpenFeatureAnnotationPrefix, common.AllowKubernetesSyncAnnotation)] = "true"
369382

370383
// build K8s config
371384
return types.SourceConfig{
@@ -381,7 +394,7 @@ func (fi *FlagdContainerInjector) generateBasicFlagdContainer(flagSourceConfig *
381394
Args: []string{
382395
"start",
383396
},
384-
ImagePullPolicy: constant.FlagDImagePullPolicy,
397+
ImagePullPolicy: common.FlagdImagePullPolicy,
385398
VolumeMounts: []corev1.VolumeMount{},
386399
Env: []corev1.EnvVar{},
387400
Ports: []corev1.ContainerPort{
@@ -391,7 +404,7 @@ func (fi *FlagdContainerInjector) generateBasicFlagdContainer(flagSourceConfig *
391404
},
392405
},
393406
SecurityContext: getSecurityContext(),
394-
Resources: fi.FlagDResourceRequirements,
407+
Resources: fi.FlagdResourceRequirements,
395408
}
396409
}
397410

@@ -437,7 +450,7 @@ func appendSources(sources []types.SourceConfig, sidecar *corev1.Container) erro
437450
return err
438451
}
439452

440-
sidecar.Args = append(sidecar.Args, constant.SourceConfigParam, string(bytes))
453+
sidecar.Args = append(sidecar.Args, common.SourceConfigParam, string(bytes))
441454
return nil
442455
}
443456

@@ -479,6 +492,6 @@ func buildProbe(path string, port int) *corev1.Probe {
479492
ProbeHandler: corev1.ProbeHandler{
480493
HTTPGet: httpGetAction,
481494
},
482-
InitialDelaySeconds: constant.ProbeInitialDelay,
495+
InitialDelaySeconds: common.ProbeInitialDelay,
483496
}
484497
}

0 commit comments

Comments
 (0)