Skip to content

Commit 0d505d0

Browse files
authored
feat(flagd): add support for azure blob (#779)
Signed-off-by: vmai <[email protected]>
1 parent c5e1158 commit 0d505d0

File tree

6 files changed

+72
-1
lines changed

6 files changed

+72
-1
lines changed

api/core/v1beta1/common/common.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package common
22

33
import (
44
"fmt"
5+
"strings"
56

67
corev1 "k8s.io/api/core/v1"
78
)
@@ -11,6 +12,7 @@ type SyncProviderType string
1112
const (
1213
SyncProviderKubernetes SyncProviderType = "kubernetes"
1314
SyncProviderFilepath SyncProviderType = "file"
15+
SyncProviderAzureBlob SyncProviderType = "azblob"
1416
SyncProviderGcs SyncProviderType = "gcs"
1517
SyncProviderHttp SyncProviderType = "http"
1618
SyncProviderGrpc SyncProviderType = "grpc"
@@ -54,6 +56,10 @@ func (s SyncProviderType) IsKubernetes() bool {
5456
return s == SyncProviderKubernetes
5557
}
5658

59+
func (s SyncProviderType) IsAzureBlob() bool {
60+
return s == SyncProviderAzureBlob
61+
}
62+
5763
func (s SyncProviderType) IsHttp() bool {
5864
return s == SyncProviderHttp
5965
}
@@ -85,6 +91,10 @@ func FalseVal() *bool {
8591
}
8692

8793
func EnvVarKey(prefix string, suffix string) string {
94+
// If prefix is blank (empty or whitespace), return just the suffix as the env var key
95+
if strings.TrimSpace(prefix) == "" {
96+
return suffix
97+
}
8898
return fmt.Sprintf("%s_%s", prefix, suffix)
8999
}
90100

api/core/v1beta1/common/common_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,35 @@ func Test_FeatureFlagSource_SyncProvider(t *testing.T) {
1313
h := SyncProviderHttp
1414
g := SyncProviderGrpc
1515
gcs := SyncProviderGcs
16+
azureBlob := SyncProviderAzureBlob
1617

1718
require.True(t, k.IsKubernetes())
1819
require.True(t, f.IsFilepath())
1920
require.True(t, h.IsHttp())
2021
require.True(t, g.IsGrpc())
2122
require.True(t, gcs.IsGcs())
23+
require.True(t, azureBlob.IsAzureBlob())
2224

2325
require.False(t, f.IsKubernetes())
2426
require.False(t, h.IsFilepath())
2527
require.False(t, k.IsGrpc())
2628
require.False(t, g.IsHttp())
2729
require.False(t, g.IsGcs())
30+
require.False(t, gcs.IsAzureBlob())
2831
}
2932

3033
func Test_FLagSourceConfiguration_EnvVarKey(t *testing.T) {
3134
require.Equal(t, "pre_suf", EnvVarKey("pre", "suf"))
3235
}
3336

37+
func Test_FLagSourceConfiguration_EnvVarKey_EmptyPre(t *testing.T) {
38+
require.Equal(t, "suf", EnvVarKey(" ", "suf"))
39+
}
40+
41+
func Test_FLagSourceConfiguration_EnvVarKey_NoPre(t *testing.T) {
42+
require.Equal(t, "suf", EnvVarKey("", "suf"))
43+
}
44+
3445
func Test_FLagSourceConfiguration_FeatureFlagConfigurationId(t *testing.T) {
3546
require.Equal(t, "pre_suf", FeatureFlagConfigurationId("pre", "suf"))
3647
}

api/core/v1beta1/featureflagsource_types.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package v1beta1
1818

1919
import (
2020
"fmt"
21+
"strings"
2122

2223
"github.com/open-feature/open-feature-operator/apis/core/v1beta1/common"
2324
corev1 "k8s.io/api/core/v1"
@@ -209,12 +210,19 @@ func (fc *FeatureFlagSourceSpec) Merge(new *FeatureFlagSourceSpec) {
209210
}
210211
}
211212

213+
func (fc *FeatureFlagSourceSpec) decorateEnvVarName(original string) string {
214+
if strings.HasPrefix(original, "AZURE_STORAGE") {
215+
return original
216+
}
217+
return common.EnvVarKey(fc.EnvVarPrefix, original)
218+
}
219+
212220
func (fc *FeatureFlagSourceSpec) ToEnvVars() []corev1.EnvVar {
213221
envs := []corev1.EnvVar{}
214222

215223
for _, envVar := range fc.EnvVars {
216224
envs = append(envs, corev1.EnvVar{
217-
Name: common.EnvVarKey(fc.EnvVarPrefix, envVar.Name),
225+
Name: fc.decorateEnvVarName(envVar.Name),
218226
Value: envVar.Value,
219227
})
220228
}

api/core/v1beta1/featureflagsource_types_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,14 @@ func Test_FLagSourceConfiguration_ToEnvVars(t *testing.T) {
180180
Name: "env2",
181181
Value: "val2",
182182
},
183+
{
184+
Name: "AZURE_STORAGE_ACCOUNT",
185+
Value: "account123",
186+
},
187+
{
188+
Name: "AZURE_STORAGE_KEY",
189+
Value: "key456",
190+
},
183191
},
184192
EnvVarPrefix: "PRE",
185193
ManagementPort: 22,
@@ -198,6 +206,14 @@ func Test_FLagSourceConfiguration_ToEnvVars(t *testing.T) {
198206
Name: "PRE_env2",
199207
Value: "val2",
200208
},
209+
{
210+
Name: "AZURE_STORAGE_ACCOUNT",
211+
Value: "account123",
212+
},
213+
{
214+
Name: "AZURE_STORAGE_KEY",
215+
Value: "key456",
216+
},
201217
{
202218
Name: "PRE_MANAGEMENT_PORT",
203219
Value: "22",

docs/feature_flag_source.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,22 @@ sources:
8383
selector: 'source=database,app=weatherapp' # flag filtering options
8484
```
8585

86+
### Azure Blob Storage
87+
88+
Given below is an example configuration with provider type `azblob` and supported options,
89+
90+
```yaml
91+
sources:
92+
- source: azblob://my-bucket/test.json # my-bucket - container name
93+
provider: azblob
94+
envVars:
95+
- name: AZURE_STORAGE_ACCOUNT
96+
value: <account_name>
97+
- name: AZURE_STORAGE_SAS_TOKEN
98+
value: <SAS token>
99+
```
100+
Other type of credentials for Azure Blob Storage are supported, for details (see [AZ credentials config](https://pkg.go.dev/gocloud.dev/blob/azureblob#hdr-URLs))
101+
86102
## Sidecar configurations
87103

88104
`FeatureFlagSource` provides configurations to the injected flagd sidecar.

internal/common/flagdinjector/flagdinjector.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ func (fi *FlagdContainerInjector) newSourceConfig(ctx context.Context, source ap
236236
sourceCfg = fi.toGrpcProviderConfig(source)
237237
case source.Provider.IsFlagdProxy():
238238
sourceCfg, err = fi.toFlagdProxyConfig(ctx, objectMeta, source)
239+
case source.Provider.IsAzureBlob():
240+
sourceCfg = fi.toAzureBlobConfig(source)
239241
default:
240242
err = fmt.Errorf("could not add provider %s: %w", source.Provider, common.ErrUnrecognizedSyncProvider)
241243
}
@@ -327,6 +329,14 @@ func (fi *FlagdContainerInjector) toGrpcProviderConfig(source api.Source) types.
327329
}
328330
}
329331

332+
func (fi *FlagdContainerInjector) toAzureBlobConfig(source api.Source) types.SourceConfig {
333+
return types.SourceConfig{
334+
URI: source.Source,
335+
Provider: string(apicommon.SyncProviderAzureBlob),
336+
Interval: source.Interval,
337+
}
338+
}
339+
330340
func (fi *FlagdContainerInjector) toFlagdProxyConfig(ctx context.Context, objectMeta *metav1.ObjectMeta, source api.Source) (types.SourceConfig, error) {
331341
// does the proxy exist
332342
exists, ready, err := fi.isFlagdProxyReady(ctx)

0 commit comments

Comments
 (0)