Skip to content
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

Allow app settings to be configured in main.parameters.json for simplified init apps #2875

Merged
merged 5 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 20 additions & 1 deletion cli/azd/internal/scaffold/funcs.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package scaffold

import "strings"
import (
"encoding/json"
"fmt"
"strings"
)

// BicepName returns a name suitable for use as a bicep variable name.
//
Expand Down Expand Up @@ -106,3 +110,18 @@ func ContainerAppName(name string) string {

return sb.String()
}

// Formats a parameter value for use in a bicep file.
// If the value is a string, it is quoted inline with no indentation.
// Otherwise, the value is marshaled with indentation specified by prefix and indent.
func FormatParameter(prefix string, indent string, value any) (string, error) {
if valueStr, ok := value.(string); ok {
return fmt.Sprintf("\"%s\"", valueStr), nil
}

val, err := json.MarshalIndent(value, prefix, indent)
if err != nil {
return "", err
}
return string(val), nil
}
3 changes: 3 additions & 0 deletions cli/azd/internal/scaffold/scaffold.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func Load() (*template.Template, error) {
"containerAppName": ContainerAppName,
"upper": strings.ToUpper,
"lower": strings.ToLower,
"formatParam": FormatParameter,
}

t, err := template.New("templates").
Expand Down Expand Up @@ -164,5 +165,7 @@ func preExecExpand(spec *InfraSpec) {
// containerapp requires a global '_exist' parameter for each service
spec.Parameters = append(spec.Parameters,
containerAppExistsParameter(svc.Name))
spec.Parameters = append(spec.Parameters,
serviceDefPlaceholder(svc.Name))
}
}
42 changes: 41 additions & 1 deletion cli/azd/internal/scaffold/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type InfraSpec struct {

type Parameter struct {
Name string
Value string
Value any
Type string
Secret bool
}
Expand Down Expand Up @@ -69,3 +69,43 @@ func containerAppExistsParameter(serviceName string) Parameter {
Type: "bool",
}
}

type serviceDef struct {
Settings []serviceDefSettings `json:"settings"`
}

type serviceDefSettings struct {
Name string `json:"name"`
Value string `json:"value"`
Secret bool `json:"secret,omitempty"`
SecretRef string `json:"secretRef,omitempty"`
CommentName string `json:"_comment_name,omitempty"`
CommentValue string `json:"_comment_value,omitempty"`
}

func serviceDefPlaceholder(serviceName string) Parameter {
return Parameter{
Name: BicepName(serviceName) + "Definition",
Value: serviceDef{
Settings: []serviceDefSettings{
{
Name: "",
Value: "${VAR}",
CommentName: "The name of the environment variable when running in Azure. If empty, ignored.",
weikanglim marked this conversation as resolved.
Show resolved Hide resolved
//nolint:lll
CommentValue: "The value to provide. This can be a fixed literal, or an expression like ${VAR} to use the value of 'VAR' from the current environment.",
},
{
Name: "",
Value: "${VAR_S}",
Secret: true,
CommentName: "The name of the environment variable when running in Azure. If empty, ignored.",
//nolint:lll
CommentValue: "The value to provide. This can be a fixed literal, or an expression like ${VAR_S} to use the value of 'VAR_S' from the current environment.",
},
},
},
Type: "object",
Secret: true,
}
}
30 changes: 26 additions & 4 deletions cli/azd/resources/scaffold/templates/host-containerapp.bicept
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,19 @@ param apiUrls array
param allowedOrigins array
{{- end}}
param exists bool
@secure()
param appDefinition object

var appSettingsArray = filter(array(appDefinition.settings), i => i.name != '')
var secrets = map(filter(appSettingsArray, i => i.?secret != null), i => {
name: i.name
value: i.value
secretRef: i.?secretRef ?? take(replace(replace(toLower(i.name), '_', '-'), '.', '-'), 32)
})
var env = map(filter(appSettingsArray, i => i.?secret == null), i => {
name: i.name
value: i.value
})

resource identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
name: identityName
Expand Down Expand Up @@ -94,7 +107,7 @@ resource app 'Microsoft.App/containerApps@2023-04-01-preview' = {
identity: identity.id
}
]
secrets: [
secrets: union([
{{- if .DbCosmosMongo}}
{
name: 'azure-cosmos-connection-string'
Expand All @@ -107,14 +120,18 @@ resource app 'Microsoft.App/containerApps@2023-04-01-preview' = {
value: databasePassword
}
{{- end}}
]
],
map(secrets, secret => {
name: secret.secretRef
value: secret.value
}))
}
template: {
containers: [
{
image: fetchLatestImage.outputs.?containers[?0].?image ?? 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest'
name: 'main'
env: [
env: union([
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: applicationInsights.properties.ConnectionString
Expand Down Expand Up @@ -161,7 +178,12 @@ resource app 'Microsoft.App/containerApps@2023-04-01-preview' = {
value: '{{ .Port }}'
}
{{- end}}
]
],
env,
map(secrets, secret => {
name: secret.name
secretRef: secret.secretRef
}))
resources: {
cpu: json('1.0')
memory: '2.0Gi'
Expand Down
1 change: 1 addition & 0 deletions cli/azd/resources/scaffold/templates/main.bicept
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ module {{bicepName .Name}} './app/{{.Name}}.bicep' = {
containerAppsEnvironmentName: appsEnv.outputs.name
containerRegistryName: registry.outputs.name
exists: {{bicepName .Name}}Exists
appDefinition: {{bicepName .Name}}Definition
{{- if .DbCosmosMongo}}
cosmosDbConnectionString: vault.getSecret(cosmosDb.outputs.connectionStringKey)
{{- end}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
},
{{- range .Parameters}}
"{{.Name}}": {
"value": "{{.Value}}"
"value": {{formatParam " " " " .Value}}
},
{{- end}}
"principalId": {
Expand Down
5 changes: 2 additions & 3 deletions cli/azd/resources/scaffold/templates/next-steps.mdt
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@

### Define environment variables for running services

weikanglim marked this conversation as resolved.
Show resolved Hide resolved
1. Modify or add environment variables to configure the running application. Environment variables can be configured by modifying the `env` node in the following files:
1. Modify or add environment variables to configure the running application. Environment variables can be configured by updating the `settings` node(s) for each service in [main.parameters.json](./infra/main.parameters.json).
2. For services using a database, environment variables have been pre-configured under the `env` node in the following files to allow connection to the database. Modify the name of these variables as needed to match your application.
{{- range .Services}}
- [app/{{.Name}}.bicep](./infra/app/{{.Name}}.bicep)
{{- end}}
2. For services using a database, environment variables have been pre-configured under `env` to allow connection to the database. Modify the name of these variables as needed to match your application.
3. To set a secret or API key as an environment variable under `env`, the variable should be added with a `secretRef` pointing to a `secrets` entry or a stored KeyVault secret.

### Provision infrastructure and deploy application code

Expand Down