Skip to content

Commit

Permalink
[Aspire] Add support for default.value for parameter.v0 (#4371)
Browse files Browse the repository at this point in the history
* Adding support for parameter.v0 default value

* support mapping to env vars during deploy
  • Loading branch information
vhvb1989 authored Oct 8, 2024
1 parent 8ca8960 commit e18ead3
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 10 deletions.
36 changes: 30 additions & 6 deletions cli/azd/pkg/apphost/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ func init() {
},
"removeDot": scaffold.RemoveDotAndDash,
"envFormat": scaffold.EnvFormat,
"bicepParameterValue": func(value *string) string {
if value == nil {
return ""
}
return fmt.Sprintf(" = '%s'", *value)
},
},
).
ParseFS(resources.AppHostTemplates, "apphost/templates/*")
Expand Down Expand Up @@ -298,6 +304,7 @@ func BicepTemplate(name string, manifest *Manifest, options AppHostOptions) (*me
Name string
Secret bool
Type string
Value *string
}
type autoGenInput struct {
genInput
Expand All @@ -317,14 +324,22 @@ func BicepTemplate(name string, manifest *Manifest, options AppHostOptions) (*me
for _, key := range genParametersKeys {
parameter := generator.bicepContext.InputParameters[key]
parameterMetadata := ""
if parameter.Default != nil && parameter.Default.Generate != nil {
pMetadata, err := inputMetadata(*parameter.Default.Generate)
if err != nil {
return nil, fmt.Errorf("generating input metadata for %s: %w", key, err)
var parameterDefaultValue *string
if parameter.Default != nil {
// main.bicep template handles *string for default.Value. If the value is nil, it will be ignored.
// if not nil, like empty string or any other string, it is used as `= '<value>'`
parameterDefaultValue = parameter.Default.Value
if parameter.Default.Generate != nil {
pMetadata, err := inputMetadata(*parameter.Default.Generate)
if err != nil {
return nil, fmt.Errorf("generating input metadata for %s: %w", key, err)
}
parameterMetadata = pMetadata
}
parameterMetadata = pMetadata
// Note: azd is not checking or validating that Default.Generate and Default.Value are not both set.
// The AppHost prevents this from happening by not allowing both to be set at the same time.
}
input := genInput{Name: key, Secret: parameter.Secret, Type: parameter.Type}
input := genInput{Name: key, Secret: parameter.Secret, Type: parameter.Type, Value: parameterDefaultValue}
parameters = append(parameters, autoGenInput{
genInput: input,
MetadataConfig: parameterMetadata,
Expand Down Expand Up @@ -1565,6 +1580,15 @@ func (b infraGenerator) evalBindingRef(v string, emitType inputEmitType) (string
case inputEmitTypeBicep:
return fmt.Sprintf("{{%s}}", replaceDash), nil
case inputEmitTypeYaml:
if param.Default != nil && param.Default.Value != nil {
if param.Secret {
return "", fmt.Errorf("default value for secured parameter %s is not supported", resource)
}
inputType = "parameterWithDefault"
// parameter with default value will either use the default value or the value passed in the environment
return fmt.Sprintf(`{{ %s "%s" "%s"}}`, inputType, replaceDash, *param.Default.Value), nil
}
// parameter without default value
return fmt.Sprintf(`{{ %s "%s" }}`, inputType, replaceDash), nil
default:
panic(fmt.Sprintf("unexpected parameter %s", string(emitType)))
Expand Down
1 change: 1 addition & 0 deletions cli/azd/pkg/apphost/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ type InputDefaultGenerate struct {

type InputDefault struct {
Generate *InputDefaultGenerate `json:"generate,omitempty"`
Value *string `json:"value,omitempty"`
}

// ManifestFromAppHost returns the Manifest from the given app host.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ param noVolume_pas_sw_ord string
})
@secure()
param noVolume_password string
param param_with_empty_value string = ''
param param_with_value string = 'default value for param'

var tags = {
'azd-env-name': environmentName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
"noVolume_password": {
"value": "${AZURE_NO_VOLUME_PASSWORD}"
},
"param_with_empty_value": {
"value": "${AZURE_PARAM_WITH_EMPTY_VALUE}"
},
"param_with_value": {
"value": "${AZURE_PARAM_WITH_VALUE}"
},
"environmentName": {
"value": "${AZURE_ENV_NAME}"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ properties:
env:
- name: AZURE_CLIENT_ID
value: {{ .Env.MANAGED_IDENTITY_CLIENT_ID }}
- name: EMPTY_VALUE
value: '{{ parameterWithDefault "param_with_empty_value" ""}}'
- name: WITH_VALUE
value: '{{ parameterWithDefault "param_with_value" "default value for param"}}'
- name: MYSQL_ROOT_PASSWORD
secretRef: mysql-root-password
- name: SpecialChar
Expand Down
30 changes: 29 additions & 1 deletion cli/azd/pkg/apphost/testdata/aspire-container.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,32 @@
}
}
},
"param-with-value": {
"type": "parameter.v0",
"value": "{param-with-value.inputs.value}",
"inputs": {
"value": {
"type": "string",
"secret": false,
"default":{
"value": "default value for param"
}
}
}
},
"param-with-empty-value": {
"type": "parameter.v0",
"value": "{param-with-empty-value.inputs.value}",
"inputs": {
"value": {
"type": "string",
"secret": false,
"default":{
"value": ""
}
}
}
},
"mysqlabstract-pas-sw-ord": {
"type": "parameter.v0",
"value": "{mysqlabstract-pas-sw-ord.inputs.value}",
Expand All @@ -38,7 +64,9 @@
"image": "mysql:latest",
"env": {
"MYSQL_ROOT_PASSWORD": "{mysqlabstract-password.value}",
"SpecialChar": "{mysqlabstract-pas-sw-ord.value}"
"SpecialChar": "{mysqlabstract-pas-sw-ord.value}",
"WITH_VALUE": "{param-with-value.value}",
"EMPTY_VALUE": "{param-with-empty-value.value}"
},
"volumes": [
{
Expand Down
27 changes: 25 additions & 2 deletions cli/azd/pkg/project/service_target_dotnet_containerapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"strings"
"text/template"

"github.com/azure/azure-dev/cli/azd/internal/scaffold"
"github.com/azure/azure-dev/cli/azd/pkg/alpha"
"github.com/azure/azure-dev/cli/azd/pkg/apphost"
"github.com/azure/azure-dev/cli/azd/pkg/async"
Expand Down Expand Up @@ -252,8 +253,9 @@ func (at *dotnetContainerAppTarget) Deploy(
}

funcMap := template.FuncMap{
"urlHost": fns.UrlHost,
"parameter": fns.Parameter,
"urlHost": fns.UrlHost,
"parameter": fns.Parameter,
"parameterWithDefault": fns.ParameterWithDefault,
// securedParameter gets a parameter the same way as parameter, but supporting the securedParameter
// allows to update the logic of pulling secret parameters in the future, if azd changes the way it
// stores the parameter value.
Expand Down Expand Up @@ -503,7 +505,16 @@ func (_ *containerAppTemplateManifestFuncs) UrlHost(s string) (string, error) {

const infraParametersKey = "infra.parameters."

// Parameter resolves the name of a parameter defined in the ACA yaml definition. The parameter can be mapped to a system
// environment variable or persisted in the azd environment configuration.
func (fns *containerAppTemplateManifestFuncs) Parameter(name string) (string, error) {
envVarMapping := scaffold.EnvFormat(name)
// map only to system environment variables. Not adding support for mapping to azd environment by design (b/c
// parameters could be secured)
if val, found := os.LookupEnv(envVarMapping); found {
return val, nil
}

key := infraParametersKey + name
val, found := fns.env.Config.Get(key)
if !found {
Expand All @@ -516,6 +527,18 @@ func (fns *containerAppTemplateManifestFuncs) Parameter(name string) (string, er
return valString, nil
}

// ParameterWithDefault resolves the name of a parameter defined in the ACA yaml definition.
// The parameter can be mapped to a system environment variable or be default to a value directly.
func (fns *containerAppTemplateManifestFuncs) ParameterWithDefault(name string, defaultValue string) (string, error) {
envVarMapping := scaffold.EnvFormat(name)
// map only to system environment variables. Not adding support for mapping to azd environment by design (b/c
// parameters could be secured)
if val, found := os.LookupEnv(envVarMapping); found {
return val, nil
}
return defaultValue, nil
}

// kvSecret gets the value of the secret with the given name from the KeyVault with the given host name. If the secret is
// not found, an error is returned.
func (fns *containerAppTemplateManifestFuncs) kvSecret(kvHost, secretName string) (string, error) {
Expand Down
2 changes: 1 addition & 1 deletion cli/azd/resources/apphost/templates/main.bicept
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ param principalId string = ''
{{- if $parameter.Secret }}
@secure()
{{- end}}
param {{bicepParameterName $parameter.Name}} {{$parameter.Type}}
param {{bicepParameterName $parameter.Name}} {{$parameter.Type}}{{bicepParameterValue $parameter.Value}}
{{- end}}

var tags = {
Expand Down

0 comments on commit e18ead3

Please sign in to comment.