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

add .net aspire support on sql server and sql database #3226

Merged
merged 26 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
7b7739d
add support on sql
hemarina Jan 25, 2024
8a06ef8
remove this case
hemarina Jan 25, 2024
635ee08
remove unwanted }}
hemarina Jan 25, 2024
3ac0428
remove
hemarina Jan 25, 2024
a387d66
debug
hemarina Jan 25, 2024
b993494
change function name and nest resources under sql/server
hemarina Jan 25, 2024
7045aaa
Merge branch 'sql' of https://github.com/hemarina/azure-dev into sql
hemarina Jan 25, 2024
42bad4e
use containerAppSecretConnectionString instead of directly output
hemarina Jan 26, 2024
c291bdf
debug
hemarina Jan 26, 2024
22b5a66
revert it
hemarina Jan 26, 2024
c289b0d
debug
hemarina Jan 26, 2024
b0cdfa1
lll
hemarina Jan 26, 2024
dbd2120
cspell
hemarina Jan 26, 2024
e8fbaf3
Merge branch 'main' of https://github.com/Azure/azure-dev into sql
hemarina Jan 26, 2024
e7f7022
add server
hemarina Jan 26, 2024
83f299e
lint
vhvb1989 Jan 26, 2024
4bb8557
Update cli/azd/pkg/project/service_target_dotnet_containerapp.go
hemarina Jan 26, 2024
99dfc33
simple the code based on feedback and merge
hemarina Jan 26, 2024
3675692
Merge branch 'sql' of https://github.com/hemarina/azure-dev into sql
hemarina Jan 26, 2024
025cb3d
remove v1 as bug fixed by aspire team
hemarina Jan 26, 2024
28eccf7
Merge branch 'main' of https://github.com/Azure/azure-dev into sql
hemarina Jan 26, 2024
dfbdf5e
run gofmt
hemarina Jan 26, 2024
70dfd87
add error check for each case in pointer
hemarina Jan 29, 2024
f81a4f1
apply nested resources
hemarina Jan 29, 2024
eed0f53
Update cli/azd/pkg/sqldb/sqldb.go
hemarina Jan 30, 2024
7fdaa09
Merge branch 'main' of https://github.com/Azure/azure-dev into sql
hemarina Jan 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cli/azd/.vscode/cspell-azd-dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ armappplatform
armcognitiveservices
armcosmos
armresourcegraph
armsql
asyncmy
asyncpg
azapi
Expand Down
23 changes: 22 additions & 1 deletion cli/azd/pkg/apphost/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ func newInfraGenerator() *infraGenerator {
AppConfigs: make(map[string]genAppConfig),
DaprComponents: make(map[string]genDaprComponent),
CosmosDbAccounts: make(map[string]genCosmosAccount),
SqlServers: make(map[string]genSqlServer),
},
containers: make(map[string]genContainer),
dapr: make(map[string]genDapr),
Expand Down Expand Up @@ -345,6 +346,10 @@ func (b *infraGenerator) LoadManifest(m *Manifest) error {
b.addCosmosDbAccount(name)
case "azure.cosmosdb.database.v0":
b.addCosmosDatabase(*comp.Parent, name)
case "azure.sql.v0", "sqlserver.server.v0":
b.addSqlServer(name)
case "azure.sql.database.v0", "sqlserver.database.v0":
b.addSqlDatabase(*comp.Parent, name)
case "postgres.server.v0":
// We currently use a ACA Postgres Service per database. Because of this, we don't need to retain any
// information from the server resource.
Expand Down Expand Up @@ -424,6 +429,18 @@ func (b *infraGenerator) addCosmosDatabase(cosmosDbAccount, dbName string) {
b.bicepContext.CosmosDbAccounts[cosmosDbAccount] = account
}

func (b *infraGenerator) addSqlServer(name string) {
if _, exists := b.bicepContext.SqlServers[name]; !exists {
b.bicepContext.SqlServers[name] = genSqlServer{}
}
}

func (b *infraGenerator) addSqlDatabase(sqlAccount, dbName string) {
account := b.bicepContext.SqlServers[sqlAccount]
account.Databases = append(account.Databases, dbName)
b.bicepContext.SqlServers[sqlAccount] = account
}

func (b *infraGenerator) addProject(
name string, path string, env map[string]string, bindings map[string]*Binding,
) {
Expand Down Expand Up @@ -887,7 +904,11 @@ func (b infraGenerator) evalBindingRef(v string, emitType inputEmitType) (string
case targetType == "postgres.database.v0" ||
targetType == "redis.v0" ||
targetType == "azure.cosmosdb.account.v0" ||
targetType == "azure.cosmosdb.database.v0":
targetType == "azure.cosmosdb.database.v0" ||
targetType == "azure.sql.v0" ||
targetType == "azure.sql.database.v0" ||
targetType == "sqlserver.server.v0" ||
targetType == "sqlserver.database.v0":
switch prop {
case "connectionString":
// returns something like {{ connectionString "resource" }}
Expand Down
5 changes: 5 additions & 0 deletions cli/azd/pkg/apphost/generate_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ type genInput struct {
DefaultMinLength int
}

type genSqlServer struct {
Databases []string
}

type genBicepTemplateContext struct {
HasContainerRegistry bool
HasContainerEnvironment bool
Expand All @@ -104,6 +108,7 @@ type genBicepTemplateContext struct {
AppConfigs map[string]genAppConfig
DaprComponents map[string]genDaprComponent
CosmosDbAccounts map[string]genCosmosAccount
SqlServers map[string]genSqlServer
}

type genContainerAppManifestTemplateContext struct {
Expand Down
4 changes: 4 additions & 0 deletions cli/azd/pkg/azd/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/azure/azure-dev/cli/azd/pkg/ioc"
"github.com/azure/azure-dev/cli/azd/pkg/platform"
"github.com/azure/azure-dev/cli/azd/pkg/project"
"github.com/azure/azure-dev/cli/azd/pkg/sqldb"
"github.com/azure/azure-dev/cli/azd/pkg/state"
"github.com/azure/azure-dev/cli/azd/pkg/templates"
"github.com/azure/azure-dev/cli/azd/pkg/tools/bicep"
Expand Down Expand Up @@ -111,6 +112,9 @@ func (p *DefaultPlatform) ConfigureContainer(container *ioc.NestedContainer) err
ioc.RegisterInstance(container, &arm.ClientOptions{})
container.MustRegisterSingleton(cosmosdb.NewCosmosDbService)

// sqldb
container.MustRegisterSingleton(sqldb.NewSqlDbService)

// Templates

// Gets a list of default template sources used in azd.
Expand Down
27 changes: 26 additions & 1 deletion cli/azd/pkg/project/service_target_dotnet_containerapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/azure/azure-dev/cli/azd/pkg/environment"
"github.com/azure/azure-dev/cli/azd/pkg/infra"
"github.com/azure/azure-dev/cli/azd/pkg/password"
"github.com/azure/azure-dev/cli/azd/pkg/sqldb"
"github.com/azure/azure-dev/cli/azd/pkg/tools"
"github.com/azure/azure-dev/cli/azd/pkg/tools/dotnet"
)
Expand All @@ -34,6 +35,7 @@ type dotnetContainerAppTarget struct {
resourceManager ResourceManager
dotNetCli dotnet.DotNetCli
cosmosDbService cosmosdb.CosmosDbService
sqlDbService sqldb.SqlDbService
}

// NewDotNetContainerAppTarget creates the Service Target for a Container App that is written in .NET. Unlike
Expand All @@ -51,6 +53,7 @@ func NewDotNetContainerAppTarget(
resourceManager ResourceManager,
dotNetCli dotnet.DotNetCli,
cosmosDbService cosmosdb.CosmosDbService,
sqlDbService sqldb.SqlDbService,
) ServiceTarget {
return &dotnetContainerAppTarget{
env: env,
Expand All @@ -59,6 +62,7 @@ func NewDotNetContainerAppTarget(
resourceManager: resourceManager,
dotNetCli: dotNetCli,
cosmosDbService: cosmosDbService,
sqlDbService: sqlDbService,
}
}

Expand Down Expand Up @@ -184,6 +188,7 @@ func (at *dotnetContainerAppTarget) Deploy(
targetResource: targetResource,
containerAppService: at.containerAppService,
cosmosDbService: at.cosmosDbService,
sqlDbService: at.sqlDbService,
env: at.env,
}

Expand Down Expand Up @@ -351,6 +356,7 @@ type containerAppTemplateManifestFuncs struct {
targetResource *environment.TargetResource
containerAppService containerapps.ContainerAppService
cosmosDbService cosmosdb.CosmosDbService
sqlDbService sqldb.SqlDbService
env *environment.Environment
}

Expand All @@ -366,7 +372,7 @@ func (_ *containerAppTemplateManifestFuncs) UrlHost(s string) (string, error) {
}

// ConnectionString returns the connection string for the given resource name. Presently, we only support resources of
// type `redis.v0`, `postgres.v0` and `cosmosdb.database.v0`.
// type `redis.v0`, `postgres.v0`, `cosmosdb.database.v0`, `azure.sql.database.v0` and `sqlserver.database.v0`.
//
// It is callable from a template under the name `connectionString`.
func (fns *containerAppTemplateManifestFuncs) ConnectionString(name string) (string, error) {
Expand Down Expand Up @@ -407,6 +413,10 @@ func (fns *containerAppTemplateManifestFuncs) ConnectionString(name string) (str
case "azure.cosmosdb.database.v0":
// get the parent resource name, which is the cosmos account name
return fns.cosmosConnectionString(*resource.Parent)
case "azure.sql.v0", "sqlserver.server.v0":
return fns.sqlConnectionString(name, "")
case "azure.sql.database.v0", "sqlserver.database.v0":
return fns.sqlConnectionString(*resource.Parent, name)
default:
return "", fmt.Errorf("connectionString: unsupported resource type '%s'", resource.Type)
}
Expand All @@ -428,6 +438,21 @@ func (fns *containerAppTemplateManifestFuncs) cosmosConnectionString(accountName
resourceName)
}

func (fns *containerAppTemplateManifestFuncs) sqlConnectionString(serverName, sqlDbName string) (string, error) {
serverNameKey := fmt.Sprintf("SERVICE_BINDING_%s_NAME", scaffold.AlphaSnakeUpper(serverName))
resourceName := fns.env.Getenv(serverNameKey)
if resourceName == "" {
return "", fmt.Errorf("the value for SERVICE_BINDING_%s_NAME was not found or is empty", serverName)
}

return fns.sqlDbService.ConnectionString(
fns.ctx,
fns.targetResource.SubscriptionId(),
fns.targetResource.ResourceGroupName(),
resourceName,
sqlDbName)
}

// secretValue returns the value of the secret with the given name, or an error if the secret is not found. A nil value
// is returned as "", without an error.
func (fns *containerAppTemplateManifestFuncs) secretValue(containerAppName string, secretName string) (string, error) {
Expand Down
62 changes: 62 additions & 0 deletions cli/azd/pkg/sqldb/sqldb.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package sqldb

import (
"context"
"fmt"

"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sql/armsql/v2"
)

// SqlDbService is the interface for the SqlDbService
type SqlDbService interface {
ConnectionString(ctx context.Context, subId, rgName, serverName string, dbName string) (string, error)
}

type sqlDbClient struct {
credential azcore.TokenCredential
options *arm.ClientOptions
}

// NewSqlDbService creates a new instance of the SqlDbService
func NewSqlDbService(
credential azcore.TokenCredential,
options *arm.ClientOptions,
) (SqlDbService, error) {
return &sqlDbClient{
credential: credential,
options: options,
}, nil
}

// ConnectionString returns the connection string for the CosmosDB account
func (c *sqlDbClient) ConnectionString(ctx context.Context, subId, rgName, serverName, dbName string) (string, error) {
clientFactory, err := armsql.NewClientFactory(subId, c.credential, c.options)
if err != nil {
return "", err
}

// get server fully qualified domain name
res, err := clientFactory.NewServersClient().Get(ctx, rgName, serverName, &armsql.ServersClientGetOptions{Expand: nil})
if err != nil {
return "", fmt.Errorf("failed getting server '%s' for resource group '%s'", serverName, rgName)
}

if res.Server.Properties == nil {
return "", fmt.Errorf("failed getting server properties from server '%s'", serverName)
}

if res.Server.Properties.FullyQualifiedDomainName == nil || len(*res.Server.Properties.FullyQualifiedDomainName) == 0 {
return "", fmt.Errorf("failed getting fully qualified domain name from server '%s'", serverName)
}

var initialCatalog string
if dbName != "" {
initialCatalog = fmt.Sprintf("Initial Catalog=%s;", dbName)
}

return fmt.Sprintf("Server=tcp:%s,1433;Encrypt=True;%s"+
"TrustServerCertificate=False;Connection Timeout=30;Authentication=\"Active Directory Default\";",
*res.Server.Properties.FullyQualifiedDomainName, initialCatalog), nil
}
3 changes: 3 additions & 0 deletions cli/azd/resources/apphost/templates/main.bicept
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,7 @@ output SERVICE_BINDING_{{alphaSnakeUpper $name}}_ENDPOINT string = resources.out
{{range $name, $value := .CosmosDbAccounts -}}
output SERVICE_BINDING_{{alphaSnakeUpper $name}}_NAME string = resources.outputs.SERVICE_BINDING_{{alphaSnakeUpper $name}}_NAME
{{end -}}
{{range $name, $value := .SqlServers -}}
output SERVICE_BINDING_{{alphaSnakeUpper $name}}_NAME string = resources.outputs.SERVICE_BINDING_{{alphaSnakeUpper $name}}_NAME
{{end -}}
{{ end}}
42 changes: 42 additions & 0 deletions cli/azd/resources/apphost/templates/resources.bicept
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,45 @@ resource {{bicepName $name}} 'Microsoft.DocumentDB/databaseAccounts@2023-04-15'
{{end -}}
}
{{end -}}

{{range $name, $value := .SqlServers}}
resource {{bicepName $name}} 'Microsoft.Sql/servers@2022-05-01-preview' = {
name: '{{$name}}-${resourceToken}'
location: location
tags: union(tags, {'aspire-resource-name': '{{$name}}'})
properties: {
minimalTlsVersion: '1.2'
publicNetworkAccess: 'Enabled'
administrators: {
administratorType: 'ActiveDirectory'
azureADOnlyAuthentication: true
login: managedIdentity.name
principalType: 'User'
sid: managedIdentity.properties.principalId
tenantId: subscription().tenantId
}
}

resource {{bicepName $name}}Firewall 'firewallRules@2022-05-01-preview' = {
name: 'fw-{{$name}}'
properties: {
startIpAddress: '0.0.0.0'
endIpAddress: '255.255.255.255'
}
}

{{range $cname := $value.Databases}}
resource {{bicepName $cname}} 'databases@2022-05-01-preview' = {
name: '{{$cname}}'
location: location
sku: {
name: 'S0'
}
tags: union(tags, {'aspire-resource-name': '{{$cname}}'})
}
{{end -}}
}
{{end -}}
output MANAGED_IDENTITY_CLIENT_ID string = managedIdentity.properties.clientId
{{if .HasContainerRegistry -}}
output AZURE_CONTAINER_REGISTRY_ENDPOINT string = containerRegistry.properties.loginServer
Expand Down Expand Up @@ -392,4 +431,7 @@ output SERVICE_BINDING_{{alphaSnakeUpper $name}}_ENDPOINT string = {{bicepName $
{{range $name, $value := .CosmosDbAccounts -}}
output SERVICE_BINDING_{{alphaSnakeUpper $name}}_NAME string = {{bicepName $name}}.name
{{end -}}
{{range $name, $value := .SqlServers -}}
output SERVICE_BINDING_{{alphaSnakeUpper $name}}_NAME string = {{bicepName $name}}.name
{{end -}}
{{ end}}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/apimanagement/armapimanagement v1.0.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/appconfiguration/armappconfiguration v1.0.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sql/armsql/v2 v2.0.0-beta.4
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cli/browser v1.1.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1/go.mod h1:c/wcGeGx5FUPbM/JltUYHZcKmigwyVLJlDq+4HdtXaw=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions v1.0.0 h1:xXmHA6JxGDHOY2anNQhpgIibZOiEaOvPLZOiAs07/4k=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions v1.0.0/go.mod h1:qkZjuhvy20x2Ckq4BzopZ8UjZLhib6nRJbRQiC6EFXY=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sql/armsql/v2 v2.0.0-beta.4 h1:REtDJygCJQ4IkwgSOAY3CUpI1+AWKuOVP3jIGPYYiPk=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sql/armsql/v2 v2.0.0-beta.4/go.mod h1:mXe/tbvI454sWulmm+3N5fkEs+yDvbQsA+8Xqr1kEQo=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0 h1:Ma67P/GGprNwsslzEH6+Kb8nybI8jpDTm4Wmzu2ReK8=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0/go.mod h1:c+Lifp3EDEamAkPVzMooRNOK6CZjNSdEnf1A7jsI9u4=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v0.13.0 h1:XY0plaTx8oeipK+XogAck2Qzv39KdnJNBwrxC4A0GL4=
Expand Down
Loading