Skip to content

feat: PoC FeatureFlagSource API refactoring [WIP] #628

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 15 commits into from
24 changes: 24 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Code generated by tool. DO NOT EDIT.
# This file is used to track the info used to scaffold your project
# and allow the plugins properly work.
# More info: https://book.kubebuilder.io/reference/project-config.html
domain: openfeature.dev
layout:
- go.kubebuilder.io/v3
Expand Down Expand Up @@ -59,4 +63,24 @@ resources:
kind: FeatureFlagSource
path: github.com/open-feature/open-feature-operator/apis/core/v1beta1
version: v1beta1
- api:
crdVersion: v1
namespaced: true
domain: openfeature.dev
group: core
kind: FeatureFlagSource
path: github.com/open-feature/open-feature-operator/apis/core/v1beta2
version: v1beta2
webhooks:
conversion: true
validation: true
webhookVersion: v1
- api:
crdVersion: v1
namespaced: true
domain: openfeature.dev
group: core
kind: FeatureFlag
path: github.com/open-feature/open-feature-operator/apis/core/v1beta2
version: v1beta2
version: "3"
54 changes: 0 additions & 54 deletions apis/core/v1beta1/common/common.go
Original file line number Diff line number Diff line change
@@ -1,57 +1,3 @@
package common

import "fmt"

type SyncProviderType string

const (
SyncProviderKubernetes SyncProviderType = "kubernetes"
SyncProviderFilepath SyncProviderType = "file"
SyncProviderHttp SyncProviderType = "http"
SyncProviderGrpc SyncProviderType = "grpc"
SyncProviderFlagdProxy SyncProviderType = "flagd-proxy"
)

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

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

func (s SyncProviderType) IsFilepath() bool {
return s == SyncProviderFilepath
}

func (s SyncProviderType) IsGrpc() bool {
return s == SyncProviderGrpc
}

func (s SyncProviderType) IsFlagdProxy() bool {
return s == SyncProviderFlagdProxy
}

func TrueVal() *bool {
b := true
return &b
}

func FalseVal() *bool {
b := false
return &b
}

func EnvVarKey(prefix string, suffix string) string {
return fmt.Sprintf("%s_%s", prefix, suffix)
}

// unique string used to create unique volume mount and file name
func FeatureFlagConfigurationId(namespace, name string) string {
return EnvVarKey(namespace, name)
}

// unique key (and filename) for configMap data
func FeatureFlagConfigMapKey(namespace, name string) string {
return fmt.Sprintf("%s.flagd.json", FeatureFlagConfigurationId(namespace, name))
}
33 changes: 0 additions & 33 deletions apis/core/v1beta1/featureflag_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ 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"
)

Expand Down Expand Up @@ -62,7 +60,6 @@ type FeatureFlagStatus struct {
//+kubebuilder:resource:shortName="ff"
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
//+kubebuilder:storageversion

// FeatureFlag is the Schema for the featureflags API
type FeatureFlag struct {
Expand All @@ -85,33 +82,3 @@ 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
}
143 changes: 143 additions & 0 deletions apis/core/v1beta1/featureflagsource_conversion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package v1beta1

import (
"fmt"

"github.com/open-feature/open-feature-operator/apis/core/v1beta1/common"
"github.com/open-feature/open-feature-operator/apis/core/v1beta2"
v1beta2common "github.com/open-feature/open-feature-operator/apis/core/v1beta2/common"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/conversion"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)

var featureflagsourcelog = logf.Log.WithName("featureflagsource-resource")

// ConvertTo converts the src v1beta1.FeatureFlagSource to the hub version (v1beta1.FeatureFlagSource)
//
//nolint:gocyclo
func (src *FeatureFlagSource) ConvertTo(dstRaw conversion.Hub) error {
dst, ok := dstRaw.(*v1beta2.FeatureFlagSource)

if !ok {
return fmt.Errorf("type %T %s", dstRaw, "unable to convert to v1beta2.FeatureFlagSource")
}

featureflagsourcelog.Info("conversion ConvertTo", "obj", src)

// Copy equal stuff to new object
dst.ObjectMeta = src.ObjectMeta

dst.Spec.EnvVarPrefix = "FLAGD"
if src.Spec.EnvVarPrefix != "" {
dst.Spec.EnvVarPrefix = src.Spec.EnvVarPrefix
}
dst.Spec.RPC = &v1beta2.RPCConf{
ManagementPort: 8014,
Port: 8013,
SocketPath: src.Spec.SocketPath,
Evaluator: "json",
RolloutOnChange: false,
DefaultSyncProvider: v1beta2common.SyncProviderKubernetes,
LogFormat: "json", //
ProbesEnabled: true,
DebugLogging: false,
OtelCollectorUri: src.Spec.OtelCollectorUri,
}
if src.Spec.ManagementPort != 0 {
dst.Spec.RPC.ManagementPort = src.Spec.ManagementPort
}
if src.Spec.Port != 0 {
dst.Spec.RPC.Port = src.Spec.Port
}
if src.Spec.Evaluator != "" {
dst.Spec.RPC.Evaluator = src.Spec.Evaluator
}
if src.Spec.DefaultSyncProvider != "" {
dst.Spec.RPC.DefaultSyncProvider = v1beta2common.SyncProviderType(src.Spec.DefaultSyncProvider)
}
if src.Spec.LogFormat != "" {
dst.Spec.RPC.LogFormat = src.Spec.LogFormat
}
if src.Spec.RolloutOnChange != nil {
dst.Spec.RPC.RolloutOnChange = *src.Spec.RolloutOnChange
}
if src.Spec.ProbesEnabled != nil {
dst.Spec.RPC.ProbesEnabled = *src.Spec.ProbesEnabled
}
if src.Spec.DebugLogging != nil {
dst.Spec.RPC.DebugLogging = *src.Spec.DebugLogging
}
dst.Spec.RPC.Resources.Limits = src.Spec.Resources.Limits
dst.Spec.RPC.Resources.Requests = src.Spec.Resources.Requests
copy(dst.Spec.RPC.Resources.Claims, src.Spec.Resources.Claims)
dst.Spec.RPC.SyncProviderArgs = make([]string, len(src.Spec.SyncProviderArgs))
copy(dst.Spec.RPC.SyncProviderArgs, src.Spec.SyncProviderArgs)
dst.Spec.RPC.EnvVars = make([]corev1.EnvVar, len(src.Spec.EnvVars))
copy(dst.Spec.RPC.EnvVars, src.Spec.EnvVars)
dst.Spec.RPC.Sources = make([]v1beta2.Source, len(src.Spec.Sources))
for idx, item := range src.Spec.Sources {
dst.Spec.RPC.Sources[idx] = v1beta2.Source{
Source: item.Source,
Provider: v1beta2common.SyncProviderType(item.Provider),
HttpSyncBearerToken: item.HttpSyncBearerToken,
TLS: item.TLS,
CertPath: item.CertPath,
ProviderID: item.ProviderID,
Selector: item.Selector,
Interval: item.Interval,
}
}

return nil
}

// ConvertFrom converts from the hub version (v1beta2.FeatureFlagSource) to this version (v1beta1.FeatureFlagSource)
//
//nolint:gocyclo
func (dst *FeatureFlagSource) ConvertFrom(srcRaw conversion.Hub) error {
src, ok := srcRaw.(*v1beta2.FeatureFlagSource)

if !ok {
return fmt.Errorf("type %T %s", srcRaw, "unable to convert from v1beta2.FeatureFlagSource")
}

featureflagsourcelog.Info("conversion ConvertFrom", "obj", src)

// Copy equal stuff to new object
dst.ObjectMeta = src.ObjectMeta

dst.Spec.EnvVarPrefix = src.Spec.EnvVarPrefix
dst.Spec.ManagementPort = src.Spec.RPC.ManagementPort
dst.Spec.Port = src.Spec.RPC.Port
dst.Spec.SocketPath = src.Spec.RPC.SocketPath
dst.Spec.RolloutOnChange = &src.Spec.RPC.RolloutOnChange
dst.Spec.Evaluator = src.Spec.RPC.Evaluator
dst.Spec.DefaultSyncProvider = common.SyncProviderType(src.Spec.RPC.DefaultSyncProvider)
dst.Spec.LogFormat = src.Spec.RPC.LogFormat
dst.Spec.ProbesEnabled = &src.Spec.RPC.ProbesEnabled
dst.Spec.DebugLogging = &src.Spec.RPC.DebugLogging
dst.Spec.OtelCollectorUri = src.Spec.RPC.OtelCollectorUri
dst.Spec.Resources.Limits = src.Spec.RPC.Resources.Limits
dst.Spec.Resources.Requests = src.Spec.RPC.Resources.Requests
copy(dst.Spec.Resources.Claims, src.Spec.RPC.Resources.Claims)
dst.Spec.SyncProviderArgs = make([]string, len(src.Spec.RPC.SyncProviderArgs))
copy(dst.Spec.SyncProviderArgs, src.Spec.RPC.SyncProviderArgs)
dst.Spec.EnvVars = make([]corev1.EnvVar, len(src.Spec.RPC.EnvVars))
copy(dst.Spec.EnvVars, src.Spec.RPC.EnvVars)
dst.Spec.Sources = make([]Source, len(src.Spec.RPC.Sources))
for idx, item := range src.Spec.RPC.Sources {
dst.Spec.Sources[idx] = Source{
Source: item.Source,
Provider: common.SyncProviderType(item.Provider),
HttpSyncBearerToken: item.HttpSyncBearerToken,
TLS: item.TLS,
CertPath: item.CertPath,
ProviderID: item.ProviderID,
Selector: item.Selector,
Interval: item.Interval,
}
}

return nil
}
Loading
Loading