Skip to content

Commit

Permalink
Provision AzureDb on an existing server / pool (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
lghinet authored Sep 6, 2022
1 parent 1ae820b commit 04427cd
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 124 deletions.
36 changes: 18 additions & 18 deletions helm/crds/provisioning.totalsoft.ro_azuredatabases.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ spec:
type: array
exports:
properties:
password:
dbName:
properties:
toConfigMap:
properties:
Expand Down Expand Up @@ -85,33 +85,33 @@ spec:
- keyTemplate
type: object
type: object
userName:
properties:
toConfigMap:
properties:
keyTemplate:
type: string
required:
- keyTemplate
type: object
toVault:
properties:
keyTemplate:
type: string
required:
- keyTemplate
type: object
type: object
type: object
platformRef:
description: Target platform (custom resource name).
type: string
sku:
type: string
sqlServer:
description: Azure Sql Server spec. New database will be created on
this server
properties:
elasticPoolName:
type: string
resourceGroupName:
description: Azure Sql Server resource group.
type: string
serverName:
description: Azure Sql Server name.
type: string
required:
- resourceGroupName
- serverName
type: object
required:
- dbName
- domains
- platformRef
- sqlServer
type: object
required:
- spec
Expand Down
101 changes: 45 additions & 56 deletions internal/provisioners/pulumi/azure_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,86 +4,75 @@ import (
"fmt"

azureSql "github.com/pulumi/pulumi-azure-native/sdk/go/azure/sql"
vault "github.com/pulumi/pulumi-vault/sdk/v5/go/vault/generic"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
platformv1 "totalsoft.ro/platform-controllers/pkg/apis/platform/v1alpha1"
provisioningv1 "totalsoft.ro/platform-controllers/pkg/apis/provisioning/v1alpha1"
)

func azureDbDeployFunc(platform string, tenant *platformv1.Tenant, resourceGroupName string,
func azureDbDeployFunc(platform string, tenant *platformv1.Tenant,
azureDbs []*provisioningv1.AzureDatabase) pulumi.RunFunc {

valueExporter := handleValueExport(platform, tenant)
gvk := provisioningv1.SchemeGroupVersion.WithKind("AzureDatabase")

return func(ctx *pulumi.Context) error {
if len(azureDbs) > 0 {
const pwdKey = "pass"
const userKey = "user"
adminPwd := generatePassword()
adminUser := fmt.Sprintf("sqlUser%s", tenant.Name)
secretPath := fmt.Sprintf("%s/__provisioner/%s/azure-databases/server", platform, tenant.Name)
secret, err := vault.LookupSecret(ctx, &vault.LookupSecretArgs{Path: secretPath})
if secret != nil && secret.Data[pwdKey] != nil {
adminPwd = secret.Data[pwdKey].(string)
}
for _, dbSpec := range azureDbs {

server, err := azureSql.NewServer(ctx, fmt.Sprintf("%s-sqlserver", tenant.Name),
&azureSql.ServerArgs{
ResourceGroupName: pulumi.String(resourceGroupName),
AdministratorLogin: pulumi.String(adminUser),
AdministratorLoginPassword: pulumi.String(adminPwd),
Version: pulumi.String("12.0"),
},
pulumi.RetainOnDelete(PulumiRetainOnDelete),
)
server, err := azureSql.LookupServer(ctx, &azureSql.LookupServerArgs{
ResourceGroupName: dbSpec.Spec.SqlServer.ResourceGroupName,
ServerName: dbSpec.Spec.SqlServer.ServerName,
})
if err != nil {
return err
}
if server == nil {
return fmt.Errorf("sqlServer %s not found", dbSpec.Spec.SqlServer.ServerName)
}

for _, dbSpec := range azureDbs {
sku := "S0"
if dbSpec.Spec.Sku != "" {
sku = dbSpec.Spec.Sku
}
dbArgs := &azureSql.DatabaseArgs{
ResourceGroupName: pulumi.String(dbSpec.Spec.SqlServer.ResourceGroupName),
ServerName: pulumi.String(server.Name),
}

db, err := azureSql.NewDatabase(ctx, dbSpec.Spec.DbName,
&azureSql.DatabaseArgs{
ResourceGroupName: pulumi.String(resourceGroupName),
ServerName: server.Name,
Sku: &azureSql.SkuArgs{
Name: pulumi.String(sku),
},
},
pulumi.RetainOnDelete(PulumiRetainOnDelete),
)
if dbSpec.Spec.SqlServer.ElasticPoolName != "" {
pool, err := azureSql.LookupElasticPool(ctx, &azureSql.LookupElasticPoolArgs{
ResourceGroupName: dbSpec.Spec.SqlServer.ResourceGroupName,
ServerName: dbSpec.Spec.SqlServer.ServerName,
ElasticPoolName: dbSpec.Spec.SqlServer.ElasticPoolName,
})
if err != nil {
return err
}

ctx.Export(fmt.Sprintf("azureDb:%s", dbSpec.Spec.DbName), db.Name)
//ctx.Export(fmt.Sprintf("azureDbPassword_%s", dbSpec.Spec.Name), pulumi.ToSecret(pwd))

for _, domain := range dbSpec.Spec.Domains {
err = valueExporter(newExportContext(ctx, domain, dbSpec.Name, dbSpec.ObjectMeta, gvk),
map[string]exportTemplateWithValue{
"username": {dbSpec.Spec.Exports.UserName, pulumi.String(adminUser)},
"password": {dbSpec.Spec.Exports.Password, pulumi.String(adminPwd)},
"server": {dbSpec.Spec.Exports.Server, server.Name}})
if err != nil {
return err
}
if pool == nil {
return fmt.Errorf("elasticPool %s not found", dbSpec.Spec.SqlServer.ElasticPoolName)
}
dbArgs.ElasticPoolId = pulumi.String(pool.Id)
} else {
sku := "S0"
if dbSpec.Spec.Sku != "" {
sku = dbSpec.Spec.Sku
}
dbArgs.Sku = &azureSql.SkuArgs{
Name: pulumi.String(sku),
}
}
_, err = vault.NewSecret(ctx, secretPath,
&vault.SecretArgs{
DataJson: pulumi.String(fmt.Sprintf(`{"%s":"%s", "%s":"%s"}`, pwdKey, adminPwd, userKey, adminUser)),
Path: pulumi.String(secretPath),
},
pulumi.RetainOnDelete(PulumiRetainOnDelete),
)

dbName := fmt.Sprintf("%s_%s_%s", dbSpec.Spec.DbName, platform, tenant.Name)
db, err := azureSql.NewDatabase(ctx, dbName, dbArgs, pulumi.RetainOnDelete(PulumiRetainOnDelete))
if err != nil {
return err
}
ctx.Export("azureDbName", db.Name)

for _, domain := range dbSpec.Spec.Domains {
err = valueExporter(newExportContext(ctx, domain, dbSpec.Name, dbSpec.ObjectMeta, gvk),
map[string]exportTemplateWithValue{
"dbName": {dbSpec.Spec.Exports.DbName, db.Name},
"server": {dbSpec.Spec.Exports.Server, pulumi.String(server.FullyQualifiedDomainName)}})
if err != nil {
return err
}
}
}
return nil
}
Expand Down
46 changes: 1 addition & 45 deletions internal/provisioners/pulumi/pulumi.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"strconv"
"time"

azureResources "github.com/pulumi/pulumi-azure-native/sdk/go/azure/resources"
"github.com/pulumi/pulumi/sdk/v3/go/auto"
"github.com/pulumi/pulumi/sdk/v3/go/auto/optdestroy"
"github.com/pulumi/pulumi/sdk/v3/go/auto/optup"
Expand All @@ -29,57 +28,21 @@ const (
PulumiRetainOnDelete = true
)

func azureRGDeployFunc(platform string, tenant *platformv1.Tenant) pulumi.RunFunc {
return func(ctx *pulumi.Context) error {
resourceGroup, err := azureResources.NewResourceGroup(ctx,
fmt.Sprintf("%s_%s_RG", platform, tenant.Name),
nil,
pulumi.RetainOnDelete(PulumiRetainOnDelete))

if err != nil {
return err
}

ctx.Export("azureRGName", resourceGroup.Name)

return nil
}
}

func Create(platform string, tenant *platformv1.Tenant, infra *provisioners.InfrastructureManifests) provisioners.ProvisioningResult {
result := provisioners.ProvisioningResult{}
upRes := auto.UpResult{}
destroyRes := auto.DestroyResult{}
azureRGStackName := fmt.Sprintf("%s_rg", tenant.Name)
emptyDeployFunc := func(ctx *pulumi.Context) error { return nil }

skipAzureDb, _ := strconv.ParseBool(os.Getenv(PulumiSkipAzureDb))
anyAzureDb := len(infra.AzureDbs) > 0
skipManagedAzureDb, _ := strconv.ParseBool(os.Getenv(PulumiSkipAzureManagedDb))
anyManagedAzureDb := len(infra.AzureManagedDbs) > 0
skipResourceGroup := skipAzureDb && skipManagedAzureDb
anyResourceGroup := (!skipAzureDb && anyAzureDb) || (!skipAzureDb && anyManagedAzureDb)

if skipResourceGroup {
return result
}

if anyResourceGroup {
upRes, result.Error = updateStack(azureRGStackName, platform, azureRGDeployFunc(platform, tenant))
if result.Error != nil {
return result
}
}

if !skipAzureDb {
azureDbStackName := fmt.Sprintf("%s_azure_db", tenant.Name)
if anyAzureDb {
azureRGName, ok := upRes.Outputs["azureRGName"].Value.(string)
if !ok {
klog.Errorf("Failed to get azureRGName: %s", upRes.StdErr)
return result
}
upRes, result.Error = updateStack(azureDbStackName, platform, azureDbDeployFunc(platform, tenant, azureRGName, infra.AzureDbs))
upRes, result.Error = updateStack(azureDbStackName, platform, azureDbDeployFunc(platform, tenant, infra.AzureDbs))
if result.Error != nil {
return result
}
Expand Down Expand Up @@ -111,13 +74,6 @@ func Create(platform string, tenant *platformv1.Tenant, infra *provisioners.Infr
}
}

if !anyResourceGroup {
destroyRes, result.Error = tryDestroyAndDeleteStack(azureRGStackName, platform, emptyDeployFunc)
if result.Error != nil {
return result
}
}

return result
}

Expand Down
15 changes: 12 additions & 3 deletions pkg/apis/provisioning/v1alpha1/azureDatabaseTypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,26 @@ type AzureDatabaseSpec struct {
Domains []string `json:"domains"`
// Database name prefix. Will have platform and tenant suffix.
DbName string `json:"dbName"`
// Azure Sql Server spec. New database will be created on this server
SqlServer SqlServerSpec `json:"sqlServer"`
// +optional
Sku string `json:"sku,omitempty"`
// +optional
Exports AzureDatabaseExportsSpec `json:"exports,omitempty"`
}

type AzureDatabaseExportsSpec struct {
type SqlServerSpec struct {
// Azure Sql Server resource group.
ResourceGroupName string `json:"resourceGroupName"`
// Azure Sql Server name.
ServerName string `json:"serverName"`
// +optional
UserName ValueExport `json:"userName,omitempty"`
ElasticPoolName string `json:"elasticPoolName,omitempty"`
}

type AzureDatabaseExportsSpec struct {
// +optional
Password ValueExport `json:"password,omitempty"`
DbName ValueExport `json:"dbName,omitempty"`
// +optional
Server ValueExport `json:"server,omitempty"`
}
Expand Down
20 changes: 18 additions & 2 deletions pkg/apis/provisioning/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 04427cd

Please sign in to comment.