Skip to content

Commit

Permalink
Raw implementation of scalable Postgres replicaset
Browse files Browse the repository at this point in the history
  • Loading branch information
Aris van Ommeren committed Feb 27, 2021
1 parent 77bdb95 commit 9ead6e0
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 24 deletions.
5 changes: 5 additions & 0 deletions azurerm/internal/services/postgres/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Client struct {
ServerSecurityAlertPoliciesClient *postgresql.ServerSecurityAlertPoliciesClient
VirtualNetworkRulesClient *postgresql.VirtualNetworkRulesClient
ServerAdministratorsClient *postgresql.ServerAdministratorsClient
ReplicasClient *postgresql.ReplicasClient
}

func NewClient(o *common.ClientOptions) *Client {
Expand Down Expand Up @@ -41,6 +42,9 @@ func NewClient(o *common.ClientOptions) *Client {
serverAdministratorsClient := postgresql.NewServerAdministratorsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&serverAdministratorsClient.Client, o.ResourceManagerAuthorizer)

replicasClient := postgresql.NewReplicasClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&replicasClient.Client, o.ResourceManagerAuthorizer)

return &Client{
ConfigurationsClient: &configurationsClient,
DatabasesClient: &databasesClient,
Expand All @@ -50,5 +54,6 @@ func NewClient(o *common.ClientOptions) *Client {
ServerSecurityAlertPoliciesClient: &serverSecurityAlertPoliciesClient,
VirtualNetworkRulesClient: &virtualNetworkRulesClient,
ServerAdministratorsClient: &serverAdministratorsClient,
ReplicasClient: &replicasClient,
}
}
119 changes: 95 additions & 24 deletions azurerm/internal/services/postgres/postgresql_server_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/locks"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/postgres/parse"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/postgres/validate"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags"
Expand All @@ -28,6 +29,29 @@ const (
postgreSQLServerResourceName = "azurerm_postgresql_server"
)

var skuList = []string{
"B_Gen4_1",
"B_Gen4_2",
"B_Gen5_1",
"B_Gen5_2",
"GP_Gen4_2",
"GP_Gen4_4",
"GP_Gen4_8",
"GP_Gen4_16",
"GP_Gen4_32",
"GP_Gen5_2",
"GP_Gen5_4",
"GP_Gen5_8",
"GP_Gen5_16",
"GP_Gen5_32",
"GP_Gen5_64",
"MO_Gen5_2",
"MO_Gen5_4",
"MO_Gen5_8",
"MO_Gen5_16",
"MO_Gen5_32",
}

func resourcePostgreSQLServer() *schema.Resource {
return &schema.Resource{
Create: resourcePostgreSQLServerCreate,
Expand Down Expand Up @@ -70,30 +94,9 @@ func resourcePostgreSQLServer() *schema.Resource {
"resource_group_name": azure.SchemaResourceGroupName(),

"sku_name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{
"B_Gen4_1",
"B_Gen4_2",
"B_Gen5_1",
"B_Gen5_2",
"GP_Gen4_2",
"GP_Gen4_4",
"GP_Gen4_8",
"GP_Gen4_16",
"GP_Gen4_32",
"GP_Gen5_2",
"GP_Gen5_4",
"GP_Gen5_8",
"GP_Gen5_16",
"GP_Gen5_32",
"GP_Gen5_64",
"MO_Gen5_2",
"MO_Gen5_4",
"MO_Gen5_8",
"MO_Gen5_16",
"MO_Gen5_32",
}, false),
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice(skuList, false),
},

"version": {
Expand Down Expand Up @@ -569,6 +572,7 @@ func resourcePostgreSQLServerCreate(d *schema.ResourceData, meta interface{}) er
func resourcePostgreSQLServerUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Postgres.ServersClient
securityClient := meta.(*clients.Client).Postgres.ServerSecurityAlertPoliciesClient
replicasClient := meta.(*clients.Client).Postgres.ReplicasClient
ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d)
defer cancel()

Expand All @@ -581,6 +585,18 @@ func resourcePostgreSQLServerUpdate(d *schema.ResourceData, meta interface{}) er
return fmt.Errorf("parsing Postgres Server ID : %v", err)
}

// Locks for scaling of replica functionality
mode := postgresql.CreateMode(d.Get("create_mode").(string))
source := d.Get("creation_source_server_id").(string)

primaryID := id.String()
if mode == postgresql.CreateModeReplica {
primaryID = source
}

locks.ByID(primaryID)
defer locks.UnlockByID(primaryID)

sku, err := expandServerSkuName(d.Get("sku_name").(string))
if err != nil {
return fmt.Errorf("expanding `sku_name` for PostgreSQL Server %s (Resource Group %q): %v", id.Name, id.ResourceGroup, err)
Expand Down Expand Up @@ -612,6 +628,29 @@ func resourcePostgreSQLServerUpdate(d *schema.ResourceData, meta interface{}) er
Tags: tags.Expand(d.Get("tags").(map[string]interface{})),
}

if d.HasChange("sku_name") && mode != postgresql.CreateModeReplica {
oldRaw, newRaw := d.GetChange("sku_name")
old := oldRaw.(string)
new := newRaw.(string)

if indexOfSku(old) < indexOfSku(new) {
listReplicas, err := replicasClient.ListByServer(ctx, id.ResourceGroup, id.Name)
if err != nil {
return fmt.Errorf("request error for list of replicas for PostgreSQL Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err)
}
for _, replica := range *listReplicas.Value {
future, err := client.Update(ctx, id.ResourceGroup, *replica.Name, properties)
if err != nil {
return fmt.Errorf("updating PostgreSQL Server Replica %q (Resource Group %q): %+v", *replica.Name, id.ResourceGroup, err)
}

if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("waiting for update of PostgreSQL Server Replica %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err)
}
}
}
}

future, err := client.Update(ctx, id.ResourceGroup, id.Name, properties)
if err != nil {
return fmt.Errorf("updating PostgreSQL Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err)
Expand All @@ -621,6 +660,29 @@ func resourcePostgreSQLServerUpdate(d *schema.ResourceData, meta interface{}) er
return fmt.Errorf("waiting for update of PostgreSQL Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err)
}

if d.HasChange("sku_name") && mode != postgresql.CreateModeReplica {
oldRaw, newRaw := d.GetChange("sku_name")
old := oldRaw.(string)
new := newRaw.(string)

if indexOfSku(old) > indexOfSku(new) {
listReplicas, err := replicasClient.ListByServer(ctx, id.ResourceGroup, id.Name)
if err != nil {
return fmt.Errorf("request error for list of replicas for PostgreSQL Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err)
}
for _, replica := range *listReplicas.Value {
future, err := client.Update(ctx, id.ResourceGroup, *replica.Name, properties)
if err != nil {
return fmt.Errorf("updating PostgreSQL Server Replica %q (Resource Group %q): %+v", *replica.Name, id.ResourceGroup, err)
}

if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("waiting for update of PostgreSQL Server Replica %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err)
}
}
}
}

if v, ok := d.GetOk("threat_detection_policy"); ok {
alert := expandSecurityAlertPolicy(v)
if alert != nil {
Expand Down Expand Up @@ -750,6 +812,15 @@ func resourcePostgreSQLServerDelete(d *schema.ResourceData, meta interface{}) er
return nil
}

func indexOfSku(skuName string) int {
for k, v := range skuList {
if skuName == v {
return k
}
}
return -1 //not found.
}

func expandServerSkuName(skuName string) (*postgresql.Sku, error) {
parts := strings.Split(skuName, "_")
if len(parts) != 3 {
Expand Down

0 comments on commit 9ead6e0

Please sign in to comment.