Skip to content

Commit

Permalink
Merge pull request #21 from thetonymaster/loadbalancer-backend-addres…
Browse files Browse the repository at this point in the history
…s-pool

Loadbalancer backend address pool
  • Loading branch information
katbyte authored Aug 7, 2018
2 parents cab48ae + 60dcf42 commit 4da9392
Show file tree
Hide file tree
Showing 6 changed files with 591 additions and 32 deletions.
1 change: 1 addition & 0 deletions azurestack/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ func Provider() terraform.ResourceProvider {
"azurestack_network_security_rule": resourceArmNetworkSecurityRule(),
"azurestack_local_network_gateway": resourceArmLocalNetworkGateway(),
"azurestack_lb": resourceArmLoadBalancer(),
"azurestack_lb_backend_address_pool": resourceArmLoadBalancerBackendAddressPool(),
"azurestack_public_ip": resourceArmPublicIp(),
"azurestack_resource_group": resourceArmResourceGroup(),
"azurestack_storage_account": resourceArmStorageAccount(),
Expand Down
245 changes: 245 additions & 0 deletions azurestack/resource_arm_loadbalancer_backend_address_pool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
package azurestack

import (
"fmt"
"log"
"time"

"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2015-06-15/network"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/terraform-providers/terraform-provider-azurestack/azurestack/utils"
)

func resourceArmLoadBalancerBackendAddressPool() *schema.Resource {
return &schema.Resource{
Create: resourceArmLoadBalancerBackendAddressPoolCreate,
Read: resourceArmLoadBalancerBackendAddressPoolRead,
Delete: resourceArmLoadBalancerBackendAddressPoolDelete,
Importer: &schema.ResourceImporter{
State: loadBalancerSubResourceStateImporter,
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"resource_group_name": resourceGroupNameSchema(),

"loadbalancer_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"backend_ip_configurations": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},

"load_balancing_rules": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
},
}
}

func resourceArmLoadBalancerBackendAddressPoolCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).loadBalancerClient
ctx := meta.(*ArmClient).StopContext

loadBalancerID := d.Get("loadbalancer_id").(string)
armMutexKV.Lock(loadBalancerID)
defer armMutexKV.Unlock(loadBalancerID)

loadBalancer, exists, err := retrieveLoadBalancerById(loadBalancerID, meta)
if err != nil {
return errwrap.Wrapf("Error Getting LoadBalancer By ID {{err}}", err)
}
if !exists {
d.SetId("")
log.Printf("[INFO] LoadBalancer %q not found. Removing from state", d.Get("name").(string))
return nil
}

backendAddressPools := append(*loadBalancer.LoadBalancerPropertiesFormat.BackendAddressPools, expandAzureRmLoadBalancerBackendAddressPools(d))
existingPool, existingPoolIndex, exists := findLoadBalancerBackEndAddressPoolByName(loadBalancer, d.Get("name").(string))
if exists {
if d.Get("name").(string) == *existingPool.Name {
// this pool is being updated/reapplied remove old copy from the slice
backendAddressPools = append(backendAddressPools[:existingPoolIndex], backendAddressPools[existingPoolIndex+1:]...)
}
}

loadBalancer.LoadBalancerPropertiesFormat.BackendAddressPools = &backendAddressPools
resGroup, loadBalancerName, err := resourceGroupAndLBNameFromId(d.Get("loadbalancer_id").(string))
if err != nil {
return fmt.Errorf("Error parsing LoadBalancer Name and Group: %+v", err)
}

future, err := client.CreateOrUpdate(ctx, resGroup, loadBalancerName, *loadBalancer)
if err != nil {
return fmt.Errorf("Error Creating/Updating LoadBalancer %q (Resource Group %q): %+v", loadBalancerName, resGroup, err)
}

err = future.WaitForCompletion(ctx, client.Client)
if err != nil {
return fmt.Errorf("Error Creating/Updating LoadBalancer %q (Resource Group %q): %+v", loadBalancerName, resGroup, err)
}

read, err := client.Get(ctx, resGroup, loadBalancerName, "")
if err != nil {
return fmt.Errorf("Error retrieving Load Balancer %q (Resource Group %q): %+v", loadBalancerName, resGroup, err)
}
if read.ID == nil {
return fmt.Errorf("Cannot read LoadBalancer %q (Resource Group %q) ID", loadBalancerName, resGroup)
}

if read.LoadBalancerPropertiesFormat == nil {
return fmt.Errorf("Error creating LoadBalancer (%q Resource Group %q)", loadBalancerName, resGroup)
}

var poolId string
for _, BackendAddressPool := range *(*read.LoadBalancerPropertiesFormat).BackendAddressPools {
if *BackendAddressPool.Name == d.Get("name").(string) {
poolId = *BackendAddressPool.ID
}
}

if poolId == "" {
return fmt.Errorf("Cannot find created LoadBalancer Backend Address Pool ID %q", poolId)
}

d.SetId(poolId)

// TODO: is this still needed?
log.Printf("[DEBUG] Waiting for LoadBalancer (%s) to become available", loadBalancerName)
stateConf := &resource.StateChangeConf{
Pending: []string{"Accepted", "Updating"},
Target: []string{"Succeeded"},
Refresh: loadbalancerStateRefreshFunc(ctx, client, resGroup, loadBalancerName),
Timeout: 10 * time.Minute,
}
if _, err := stateConf.WaitForState(); err != nil {
return fmt.Errorf("Error waiting for LoadBalancer (%q Resource Group %q) to become available: %+v", loadBalancerName, resGroup, err)
}

return resourceArmLoadBalancerBackendAddressPoolRead(d, meta)
}

func resourceArmLoadBalancerBackendAddressPoolRead(d *schema.ResourceData, meta interface{}) error {
id, err := parseAzureResourceID(d.Id())
if err != nil {
return err
}
name := id.Path["backendAddressPools"]

loadBalancer, exists, err := retrieveLoadBalancerById(d.Get("loadbalancer_id").(string), meta)
if err != nil {
return fmt.Errorf("Error retrieving Load Balancer by ID: %+v", err)
}
if !exists {
d.SetId("")
log.Printf("[INFO] LoadBalancer %q not found. Removing from state", name)
return nil
}

config, _, exists := findLoadBalancerBackEndAddressPoolByName(loadBalancer, name)
if !exists {
d.SetId("")
log.Printf("[INFO] LoadBalancer Backend Address Pool %q not found. Removing from state", name)
return nil
}

d.Set("name", config.Name)
d.Set("resource_group_name", id.ResourceGroup)

var backendIpConfigurations []string
var loadBalancingRules []string

if props := config.BackendAddressPoolPropertiesFormat; props != nil {
if configs := props.BackendIPConfigurations; configs != nil {
for _, backendConfig := range *configs {
backendIpConfigurations = append(backendIpConfigurations, *backendConfig.ID)
}
}

if rules := props.LoadBalancingRules; rules != nil {
for _, rule := range *rules {
loadBalancingRules = append(loadBalancingRules, *rule.ID)
}
}
}

d.Set("backend_ip_configurations", backendIpConfigurations)
d.Set("load_balancing_rules", loadBalancingRules)

return nil
}

func resourceArmLoadBalancerBackendAddressPoolDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).loadBalancerClient
ctx := meta.(*ArmClient).StopContext

loadBalancerID := d.Get("loadbalancer_id").(string)
armMutexKV.Lock(loadBalancerID)
defer armMutexKV.Unlock(loadBalancerID)

loadBalancer, exists, err := retrieveLoadBalancerById(loadBalancerID, meta)
if err != nil {
return fmt.Errorf("Error retrieving Load Balancer by ID: %+v", err)
}
if !exists {
d.SetId("")
return nil
}

_, index, exists := findLoadBalancerBackEndAddressPoolByName(loadBalancer, d.Get("name").(string))
if !exists {
return nil
}

oldBackEndPools := *loadBalancer.LoadBalancerPropertiesFormat.BackendAddressPools
newBackEndPools := append(oldBackEndPools[:index], oldBackEndPools[index+1:]...)
loadBalancer.LoadBalancerPropertiesFormat.BackendAddressPools = &newBackEndPools

resGroup, loadBalancerName, err := resourceGroupAndLBNameFromId(d.Get("loadbalancer_id").(string))
if err != nil {
return errwrap.Wrapf("Error Getting LoadBalancer Name and Group: {{err}}", err)
}

future, err := client.CreateOrUpdate(ctx, resGroup, loadBalancerName, *loadBalancer)
if err != nil {
return fmt.Errorf("Error Creating/Updating LoadBalancer: %+v", err)
}

err = future.WaitForCompletion(ctx, client.Client)
if err != nil {
return fmt.Errorf("Error waiting for the completion for the LoadBalancer: %+v", err)
}

read, err := client.Get(ctx, resGroup, loadBalancerName, "")
if err != nil {
return fmt.Errorf("Error retrieving the LoadBalancer %q (Resource Group %q): %+v", loadBalancerName, resGroup, err)
}
if read.ID == nil {
return fmt.Errorf("Cannot read LoadBalancer %q (resource group %q) ID", loadBalancerName, resGroup)
}

return nil
}

func expandAzureRmLoadBalancerBackendAddressPools(d *schema.ResourceData) network.BackendAddressPool {
return network.BackendAddressPool{
Name: utils.String(d.Get("name").(string)),
}
}
Loading

0 comments on commit 4da9392

Please sign in to comment.