diff --git a/cli/azd/internal/cmd/add/add_configure.go b/cli/azd/internal/cmd/add/add_configure.go index f3e5ad18c0a..887b64fe2fb 100644 --- a/cli/azd/internal/cmd/add/add_configure.go +++ b/cli/azd/internal/cmd/add/add_configure.go @@ -3,6 +3,7 @@ package add import ( "context" "fmt" + "github.com/azure/azure-dev/cli/azd/internal" "slices" "strings" "unicode" @@ -32,7 +33,7 @@ func configure( return fillAiModelName(ctx, r, console, p) case project.ResourceTypeDbPostgres, project.ResourceTypeDbMongo: - return fillDatabaseName(ctx, r, console, p) + return fillDatabaseNameAndAuthType(ctx, r, console, p) case project.ResourceTypeDbRedis: if _, exists := p.prj.Resources["redis"]; exists { return nil, fmt.Errorf("only one Redis resource is allowed at this time") @@ -45,7 +46,7 @@ func configure( } } -func fillDatabaseName( +func fillDatabaseNameAndAuthType( ctx context.Context, r *project.ResourceConfig, console input.Console, @@ -56,6 +57,27 @@ func fillDatabaseName( for { dbName, err := console.Prompt(ctx, input.ConsoleOptions{ + Message: fmt.Sprintf("Input the name of the app database (%s)", r.Type.String()), + Help: "Hint: App database name\n\n" + + "Name of the database that the app connects to. " + + "This database will be created after running azd provision or azd up.", + }) + if err != nil { + return r, err + } + + if err := validateResourceName(dbName, p.prj); err != nil { + console.Message(ctx, err.Error()) + continue + } + + r.Name = dbName + break + } + + // prompt for the database name + for { + databaseName, err := console.Prompt(ctx, input.ConsoleOptions{ Message: fmt.Sprintf("Input the databaseName for %s "+ "(Not databaseServerName. This url can explain the difference: "+ "'jdbc:mysql://databaseServerName:3306/databaseName'):", r.Type.String()), @@ -67,18 +89,63 @@ func fillDatabaseName( return r, err } - if err := validateResourceName(dbName, p.prj); err != nil { + if err := validateResourceName(databaseName, p.prj); err != nil { console.Message(ctx, err.Error()) continue } - r.Name = dbName + switch r.Type { + case project.ResourceTypeDbPostgres: + modelProps, ok := r.Props.(project.PostgresProps) + if ok { + modelProps.DatabaseName = databaseName + r.Props = modelProps + } + case project.ResourceTypeDbMongo: + modelProps, ok := r.Props.(project.MongoDBProps) + if ok { + modelProps.DatabaseName = databaseName + r.Props = modelProps + } + } break } + if r.Type == project.ResourceTypeDbPostgres { + modelProps, ok := r.Props.(project.PostgresProps) + if ok { + authType, err := chooseAuthTypeByPrompt(r.Name, []internal.AuthType{ + internal.AuthTypePassword, internal.AuthTypeUserAssignedManagedIdentity}, ctx, console) + if err != nil { + return r, err + } + modelProps.AuthType = authType + r.Props = modelProps + } + } + return r, nil } +func chooseAuthTypeByPrompt( + name string, + authOptions []internal.AuthType, + ctx context.Context, + console input.Console) (internal.AuthType, error) { + var options []string + for _, option := range authOptions { + options = append(options, internal.GetAuthTypeDescription(option)) + } + selection, err := console.Select(ctx, input.ConsoleOptions{ + Message: "Choose auth type for " + name + ":", + Options: options, + }) + if err != nil { + return internal.AuthTypeUnspecified, err + } + return authOptions[selection], nil +} + func fillAiModelName( ctx context.Context, r *project.ResourceConfig, diff --git a/cli/azd/internal/cmd/add/add_select.go b/cli/azd/internal/cmd/add/add_select.go index 015be1d271b..14957093aef 100644 --- a/cli/azd/internal/cmd/add/add_select.go +++ b/cli/azd/internal/cmd/add/add_select.go @@ -54,5 +54,11 @@ func selectDatabase( } r.Type = resourceTypesDisplayMap[resourceTypesDisplay[dbOption]] + switch r.Type { + case project.ResourceTypeDbPostgres: + r.Props = project.PostgresProps{} + case project.ResourceTypeDbMongo: + r.Props = project.MongoDBProps{} + } return r, nil } diff --git a/cli/azd/internal/scaffold/scaffold_test.go b/cli/azd/internal/scaffold/scaffold_test.go index d5a7dc212fb..baacaf13981 100644 --- a/cli/azd/internal/scaffold/scaffold_test.go +++ b/cli/azd/internal/scaffold/scaffold_test.go @@ -2,6 +2,7 @@ package scaffold import ( "context" + "github.com/azure/azure-dev/cli/azd/internal" "os" "path/filepath" "strings" @@ -168,6 +169,29 @@ func TestExecInfra(t *testing.T) { }, }, }, + // with azd add, users could add only mongo resource + { + "Only Mongo", + InfraSpec{ + DbCosmosMongo: &DatabaseCosmosMongo{}, + }, + }, + // with azd add, users could add only redis resource + { + "Only Redis", + InfraSpec{ + DbRedis: &DatabaseRedis{}, + }, + }, + // with azd add, users could add only postgresql resource + { + "Only Postgres", + InfraSpec{ + DbPostgres: &DatabasePostgres{ + AuthType: internal.AuthTypeUserAssignedManagedIdentity, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/cli/azd/resources/scaffold/templates/resources.bicept b/cli/azd/resources/scaffold/templates/resources.bicept index 7cc9db9d53d..8997db4c67e 100644 --- a/cli/azd/resources/scaffold/templates/resources.bicept +++ b/cli/azd/resources/scaffold/templates/resources.bicept @@ -171,6 +171,7 @@ module postgreServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:0.1.4 skuName: 'Standard_B1ms' tier: 'Burstable' // Non-required parameters + tags: tags administratorLogin: postgreSqlDatabaseUser administratorLoginPassword: postgreSqlDatabasePassword geoRedundantBackup: 'Disabled' @@ -195,6 +196,11 @@ module postgreServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:0.1.4 principalType: 'ServicePrincipal' roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' } + { + principalId: principalId + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } ] {{- end}} } @@ -704,7 +710,7 @@ module redisConn './modules/set-redis-conn.bicep' = { } {{- end}} -{{- if .Services}} +{{- if (or .Services .DbCosmosMongo .DbRedis)}} // Create a keyvault to store secrets module keyVault 'br/public:avm/res/key-vault/vault:0.6.1' = { name: 'keyvault'