Skip to content

Commit

Permalink
Merge pull request #7 from Azure/user/linglingye/featureFlagSupport
Browse files Browse the repository at this point in the history
Feature flag support
  • Loading branch information
linglingye001 authored Jan 24, 2024
2 parents 04da47a + 1b7418e commit 237d661
Show file tree
Hide file tree
Showing 12 changed files with 942 additions and 454 deletions.
26 changes: 17 additions & 9 deletions api/v1/azureappconfigurationprovider_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ import (
type AzureAppConfigurationProviderSpec struct {
// The endpoint url of AppConfiguration which should sync the configuration key-values from.
// +kubebuilder:validation:Format=uri
Endpoint *string `json:"endpoint,omitempty"`
ConnectionStringReference *string `json:"connectionStringReference,omitempty"`
Target ConfigurationGenerationParameters `json:"target"`
Auth *AzureAppConfigurationProviderAuth `json:"auth,omitempty"`
Configuration AzureAppConfigurationKeyValueOptions `json:"configuration,omitempty"`
Secret *AzureKeyVaultReference `json:"secret,omitempty"`
Endpoint *string `json:"endpoint,omitempty"`
ConnectionStringReference *string `json:"connectionStringReference,omitempty"`
Target ConfigurationGenerationParameters `json:"target"`
Auth *AzureAppConfigurationProviderAuth `json:"auth,omitempty"`
Configuration AzureAppConfigurationKeyValueOptions `json:"configuration,omitempty"`
Secret *AzureKeyVaultReference `json:"secret,omitempty"`
FeatureFlag *AzureAppConfigurationFeatureFlagOptions `json:"featureFlag,omitempty"`
}

// AzureAppConfigurationProviderStatus defines the observed state of AzureAppConfigurationProvider
Expand All @@ -51,6 +52,7 @@ type AzureAppConfigurationProviderStatus struct {
type RefreshStatus struct {
LastKeyVaultReferenceRefreshTime metav1.Time `json:"lastKeyVaultReferenceRefreshTime,omitempty"`
LastSentinelBasedRefreshTime metav1.Time `json:"lastSentinelBasedRefreshTime,omitempty"`
LastFeatureFlagRefreshTime metav1.Time `json:"lastFeatureFlagRefreshTime,omitempty"`
}

// ConfigurationGenerationParameters defines the name of target ConfigMap
Expand All @@ -64,13 +66,19 @@ type ConfigurationGenerationParameters struct {

// AzureAppConfigurationKeyValueOptions defines the options of fetching key-values from AppConfiguration.
type AzureAppConfigurationKeyValueOptions struct {
Selectors []KeyValueSelector `json:"selectors,omitempty"`
Selectors []Selector `json:"selectors,omitempty"`
TrimKeyPrefixes []string `json:"trimKeyPrefixes,omitempty"`
Refresh *DynamicConfigurationRefreshParameters `json:"refresh,omitempty"`
}

// KeyValueSelector defines the filters when fetching the data from Azure AppConfiguration
type KeyValueSelector struct {
// AzureAppConfigurationFeatureFlagOptions defines the options of fetching feature flags from AppConfiguration.
type AzureAppConfigurationFeatureFlagOptions struct {
Selectors []Selector `json:"selectors,omitempty"`
Refresh *RefreshSettings `json:"refresh,omitempty"`
}

// KeyLabelSelector defines the filters when fetching the data from Azure AppConfiguration
type Selector struct {
KeyFilter string `json:"keyFilter"`
LabelFilter *string `json:"labelFilter,omitempty"`
}
Expand Down
75 changes: 54 additions & 21 deletions api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 34 additions & 1 deletion config/crd/bases/azconfig.io_azureappconfigurationproviders.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ spec:
type: object
selectors:
items:
description: KeyValueSelector defines the filters when fetching
description: KeyLabelSelector defines the filters when fetching
the data from Azure AppConfiguration
properties:
keyFilter:
Expand All @@ -131,6 +131,36 @@ spec:
the configuration key-values from.
format: uri
type: string
featureFlag:
description: AzureAppConfigurationFeatureFlagOptions defines the options
of fetching feature flags from AppConfiguration.
properties:
refresh:
description: Defines the settings for refresh.
properties:
enabled:
default: false
type: boolean
interval:
format: duration
type: string
required:
- interval
type: object
selectors:
items:
description: KeyLabelSelector defines the filters when fetching
the data from Azure AppConfiguration
properties:
keyFilter:
type: string
labelFilter:
type: string
required:
- keyFilter
type: object
type: array
type: object
secret:
description: AzureKeyVaultReference defines the authentication type
used to Azure KeyVault resolve KeyVaultReference
Expand Down Expand Up @@ -289,6 +319,9 @@ spec:
description: RefreshStatus defines last refresh time of configmap
and secret when dynamic feature is enabled
properties:
lastFeatureFlagRefreshTime:
format: date-time
type: string
lastKeyVaultReferenceRefreshTime:
format: date-time
type: string
Expand Down
3 changes: 2 additions & 1 deletion internal/controller/appconfigurationprovider_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type ReconciliationState struct {
SentinelETags map[acpv1.Sentinel]*azcore.ETag
NextSentinelBasedRefreshReconcileTime metav1.Time
NextKeyVaultReferenceRefreshReconcileTime metav1.Time
NextFeatureFlagRefreshReconcileTime metav1.Time
CachedSecretReferences map[string]loader.KeyVaultSecretUriSegment
}

Expand Down Expand Up @@ -192,7 +193,7 @@ func (reconciler *AzureAppConfigurationProviderReconciler) Reconcile(ctx context
ResolveSecretReference: nil,
}

if err := processor.PopulateSettings(&existingSecret); err != nil {
if err := processor.PopulateSettings(&existingConfigMap, &existingSecret); err != nil {
return reconciler.requeueWhenGetSettingsFailed(ctx, provider, err)
}

Expand Down
69 changes: 64 additions & 5 deletions internal/controller/appconfigurationprovider_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ var _ = Describe("AppConfiguationProvider controller", func() {
ConfigMapSettings: mapResult,
}

mockConfigurationSettings.EXPECT().CreateKeyValueSettings(gomock.Any(), gomock.Any()).Return(allSettings, nil)
mockConfigurationSettings.EXPECT().CreateTargetSettings(gomock.Any(), gomock.Any()).Return(allSettings, nil)

ctx := context.Background()
providerName := "test-appconfigurationprovider"
Expand Down Expand Up @@ -104,7 +104,7 @@ var _ = Describe("AppConfiguationProvider controller", func() {
ConfigMapSettings: mapResult,
}

mockConfigurationSettings.EXPECT().CreateKeyValueSettings(gomock.Any(), gomock.Any()).Return(allSettings, nil)
mockConfigurationSettings.EXPECT().CreateTargetSettings(gomock.Any(), gomock.Any()).Return(allSettings, nil)

ctx := context.Background()
providerName := "test-appconfigurationprovider-2"
Expand Down Expand Up @@ -155,7 +155,7 @@ var _ = Describe("AppConfiguationProvider controller", func() {
SecretSettings: mapResult,
}

mockConfigurationSettings.EXPECT().CreateKeyValueSettings(gomock.Any(), gomock.Any()).Return(allSettings, nil)
mockConfigurationSettings.EXPECT().CreateTargetSettings(gomock.Any(), gomock.Any()).Return(allSettings, nil)

ctx := context.Background()
providerName := "test-appconfigurationprovider-3"
Expand Down Expand Up @@ -218,7 +218,7 @@ var _ = Describe("AppConfiguationProvider controller", func() {
ConfigMapSettings: configMapResult,
}

mockConfigurationSettings.EXPECT().CreateKeyValueSettings(gomock.Any(), gomock.Any()).Return(allSettings, nil)
mockConfigurationSettings.EXPECT().CreateTargetSettings(gomock.Any(), gomock.Any()).Return(allSettings, nil)

ctx := context.Background()
providerName := "test-appconfigurationprovider-5"
Expand Down Expand Up @@ -287,7 +287,7 @@ var _ = Describe("AppConfiguationProvider controller", func() {
ConfigMapSettings: mapResult,
}

mockConfigurationSettings.EXPECT().CreateKeyValueSettings(gomock.Any(), gomock.Any()).Return(allSettings, nil)
mockConfigurationSettings.EXPECT().CreateTargetSettings(gomock.Any(), gomock.Any()).Return(allSettings, nil)

ctx := context.Background()
providerName := "test-appconfigurationprovider-7"
Expand Down Expand Up @@ -443,6 +443,65 @@ var _ = Describe("AppConfiguationProvider controller", func() {
Expect(verifyObject(configProviderSpec).Error()).Should(Equal("spec.target.configMapData.separator: separator field is not allowed when type is properties"))
})

It("Should return error if feature flag is set when data type is default", func() {
configMapName := "test-configmap"
configProviderSpec := acpv1.AzureAppConfigurationProviderSpec{
Endpoint: &EndpointName,
Target: acpv1.ConfigurationGenerationParameters{
ConfigMapName: configMapName,
},
FeatureFlag: &acpv1.AzureAppConfigurationFeatureFlagOptions{
Selectors: []acpv1.Selector{
{
KeyFilter: "testKey",
},
},
},
}

Expect(verifyObject(configProviderSpec).Error()).Should(Equal("spec.target.configMapData: configMap data type must be json or yaml when FeatureFlag is set"))
})

It("Should return error if feature flag is set when data type is properties", func() {
configMapName := "test-configmap"
configProviderSpec := acpv1.AzureAppConfigurationProviderSpec{
Endpoint: &EndpointName,
Target: acpv1.ConfigurationGenerationParameters{
ConfigMapName: configMapName,
ConfigMapData: &acpv1.ConfigMapDataOptions{
Type: acpv1.Properties,
Key: "testKey",
},
},
FeatureFlag: &acpv1.AzureAppConfigurationFeatureFlagOptions{
Selectors: []acpv1.Selector{
{
KeyFilter: "testKeyFilter",
},
},
},
}

Expect(verifyObject(configProviderSpec).Error()).Should(Equal("spec.target.configMapData: configMap data type must be json or yaml when FeatureFlag is set"))
})

It("Should return error if feature flag selector is not set", func() {
configMapName := "test-configmap"
configProviderSpec := acpv1.AzureAppConfigurationProviderSpec{
Endpoint: &EndpointName,
Target: acpv1.ConfigurationGenerationParameters{
ConfigMapName: configMapName,
ConfigMapData: &acpv1.ConfigMapDataOptions{
Type: acpv1.Json,
Key: "testKey",
},
},
FeatureFlag: &acpv1.AzureAppConfigurationFeatureFlagOptions{},
}

Expect(verifyObject(configProviderSpec).Error()).Should(Equal("spec.featureFlag.selectors: featureFlag.selectors must be specified when FeatureFlag is set"))
})

It("Should return error if both endpoint and connectionStringReference are not set", func() {
configMapName := "test-configmap"
configProviderSpec := acpv1.AzureAppConfigurationProviderSpec{
Expand Down
Loading

0 comments on commit 237d661

Please sign in to comment.