-
Notifications
You must be signed in to change notification settings - Fork 169
Azure App Configuration / Feature Flags #1244
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| [<AutoOpen>] | ||
| module Farmer.Arm.ConfigurationStore | ||
|
|
||
| open Farmer | ||
|
|
||
| let configurationStores = | ||
| ResourceType("Microsoft.AppConfiguration/configurationStores", "2024-05-01") | ||
|
|
||
| let keyValues = | ||
| ResourceType("Microsoft.AppConfiguration/configurationStores/keyValues", "2024-05-01") | ||
|
|
||
| type AzFeatureFlag = { | ||
| Name: string | ||
| Description: string | ||
| Label: string | ||
| State: bool | ||
| ConfigurationStoreId: ResourceId | ||
| } with | ||
|
|
||
| member this.ResourceName = | ||
| ResourceName | ||
| $"[format('{{0}}/{{1}}', '{this.ConfigurationStoreId.Name.Value}', format('.appconfig.featureflag~2F{{0}}${{1}}', '{this.Name}', '{this.Label}'))]" | ||
|
|
||
| interface IArmResource with | ||
| member this.ResourceId = keyValues.resourceId this.ResourceName | ||
|
|
||
| member this.JsonModel = | ||
| let enabled = this.State |> string |> _.ToLower() | ||
|
|
||
| let featureFlagValue = | ||
| $"""{{"id":"{this.Name}","description":"{this.Description}","enabled":{enabled}}}""" | ||
|
|
||
| {| | ||
| keyValues.Create(this.ResourceName, dependsOn = [ this.ConfigurationStoreId ]) with | ||
| properties = {| | ||
| value = featureFlagValue | ||
| contentType = "application/vnd.microsoft.appconfig.ff+json;charset=utf-8" | ||
| |} | ||
| |} | ||
|
|
||
| type ConfigSku = | ||
| | Free | ||
| | Developer | ||
| | Standard | ||
| | Premium | ||
|
|
||
| member this.ArmValue = | ||
| match this with | ||
| | Free -> "free" | ||
| | Developer -> "developer" | ||
| | Standard -> "standard" | ||
| | Premium -> "premium" | ||
|
|
||
| type DataPlaneAuthenticationMode = | ||
| | Local | ||
| | Passthrough | ||
|
|
||
| member this.ArmValue = | ||
| match this with | ||
| | Local -> "Local" | ||
| | Passthrough -> "Pass-through" | ||
|
|
||
| type ConfigurationStore = { | ||
| Name: ResourceName | ||
| Location: Location | ||
| Sku: ConfigSku | ||
| DisableLocalAuth: bool | ||
| DataPlaneAuthenticationMode: DataPlaneAuthenticationMode | ||
| Tags: Map<string, string> | ||
| } with | ||
|
|
||
| interface IArmResource with | ||
| member this.ResourceId = configurationStores.resourceId this.Name | ||
|
|
||
| member this.JsonModel = {| | ||
| configurationStores.Create(this.Name, this.Location, tags = this.Tags) with | ||
| sku = {| name = this.Sku.ArmValue |} | ||
| properties = {| | ||
| disableLocalAuth = this.DisableLocalAuth | ||
| dataPlaneProxy = {| | ||
| authenticationMode = this.DataPlaneAuthenticationMode.ArmValue | ||
| |} | ||
| |} | ||
| |} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| [<AutoOpen>] | ||
| module Farmer.Builders.ConfigurationStore | ||
|
|
||
| open Farmer | ||
| open Farmer.Arm.ConfigurationStore | ||
|
|
||
| type FeatureFlagConfig = { | ||
| Name: string | ||
| Description: string | ||
| Label: string | ||
| State: bool | ||
| } with | ||
|
|
||
| member this.BuildResource(configurationStore: ResourceId) = | ||
| { | ||
| Name = this.Name | ||
| Description = this.Description | ||
| Label = this.Label | ||
| State = this.State | ||
| ConfigurationStoreId = configurationStore | ||
| } | ||
| :> IArmResource | ||
|
|
||
| type ConfigurationStoreConfig = { | ||
| Name: ResourceName | ||
| Location: Location | ||
| Sku: ConfigSku | ||
| DisableLocalAuth: bool | ||
| DataPlaneAuthenticationMode: DataPlaneAuthenticationMode | ||
| FeatureFlags: FeatureFlagConfig list | ||
| Tags: Map<string, string> | ||
| } with | ||
|
|
||
| interface IBuilder with | ||
| member this.ResourceId = configurationStores.resourceId this.Name | ||
|
|
||
| member this.BuildResources location = [ | ||
| { | ||
| Name = this.Name | ||
| Location = location | ||
| Sku = this.Sku | ||
| DisableLocalAuth = this.DisableLocalAuth | ||
| DataPlaneAuthenticationMode = this.DataPlaneAuthenticationMode | ||
| Tags = this.Tags | ||
| } | ||
| yield! | ||
| this.FeatureFlags | ||
| |> List.map (fun ff -> ff.BuildResource(configurationStores.resourceId this.Name)) | ||
| ] | ||
|
|
||
| type ConfigurationStoreBuilder() = | ||
| member _.Yield _ = { | ||
| Name = ResourceName.Empty | ||
| Location = Location.NorthEurope | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This shouldn't be in the builder - it will get set on the resulting resource in the |
||
| Sku = ConfigSku.Free | ||
| DisableLocalAuth = true | ||
| DataPlaneAuthenticationMode = DataPlaneAuthenticationMode.Passthrough | ||
| FeatureFlags = [] | ||
| Tags = Map.empty | ||
| } | ||
|
|
||
| /// Sets the name of the configuration store. | ||
| [<CustomOperation "name">] | ||
| member _.Name(state: ConfigurationStoreConfig, name) = { state with Name = ResourceName name } | ||
|
|
||
| /// Sets the location of the configuration store. | ||
| [<CustomOperation "location">] | ||
| member _.Location(state: ConfigurationStoreConfig, location) = { state with Location = location } | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can also remove this |
||
|
|
||
| /// Sets the SKU of the configuration store. | ||
| [<CustomOperation "sku">] | ||
| member _.Sku(state: ConfigurationStoreConfig, sku) = { state with Sku = sku } | ||
|
|
||
| /// Disables local authentication for the configuration store. | ||
| [<CustomOperation "disable_local_auth">] | ||
| member _.DisableLocalAuth(state: ConfigurationStoreConfig, disable: bool) = { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this member is called "disable_local_auth", it doesn't need the boolean argument and should just set |
||
| state with | ||
| DisableLocalAuth = disable | ||
| } | ||
|
|
||
| /// Sets the data plane authentication mode for the configuration store. | ||
| [<CustomOperation "data_plane_authentication_mode">] | ||
| member _.DataPlaneAuthenticationMode(state: ConfigurationStoreConfig, mode) = { | ||
| state with | ||
| DataPlaneAuthenticationMode = mode | ||
| } | ||
|
|
||
| /// Adds a feature flag to the configuration store. | ||
| [<CustomOperation "feature_flags">] | ||
| member _.FeatureFlags(state: ConfigurationStoreConfig, featureFlags: FeatureFlagConfig list) = { | ||
| state with | ||
| FeatureFlags = featureFlags | ||
| } | ||
|
|
||
| interface ITaggable<ConfigurationStoreConfig> with | ||
| /// Adds a tag to this Configuration Store. | ||
| member _.Add state tags = { | ||
| state with | ||
| Tags = state.Tags |> Map.merge tags | ||
| } | ||
|
|
||
| let configurationStore = ConfigurationStoreBuilder() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is freeform text, so it will need JSON escaping. One quick way would be like: