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

Loadbalancer backend address pool #21

Merged
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