github.com/minamijoyo/terraform@v0.7.8-0.20161029001309-18b3736ba44b/builtin/providers/azurerm/resource_arm_loadbalancer_rule.go (about)

     1  package azurerm
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"regexp"
     7  	"time"
     8  
     9  	"github.com/Azure/azure-sdk-for-go/arm/network"
    10  	"github.com/hashicorp/errwrap"
    11  	"github.com/hashicorp/terraform/helper/resource"
    12  	"github.com/hashicorp/terraform/helper/schema"
    13  	"github.com/jen20/riviera/azure"
    14  )
    15  
    16  func resourceArmLoadBalancerRule() *schema.Resource {
    17  	return &schema.Resource{
    18  		Create: resourceArmLoadBalancerRuleCreate,
    19  		Read:   resourceArmLoadBalancerRuleRead,
    20  		Update: resourceArmLoadBalancerRuleCreate,
    21  		Delete: resourceArmLoadBalancerRuleDelete,
    22  
    23  		Schema: map[string]*schema.Schema{
    24  			"name": {
    25  				Type:         schema.TypeString,
    26  				Required:     true,
    27  				ForceNew:     true,
    28  				ValidateFunc: validateArmLoadBalancerRuleName,
    29  			},
    30  
    31  			"location": {
    32  				Type:      schema.TypeString,
    33  				Required:  true,
    34  				ForceNew:  true,
    35  				StateFunc: azureRMNormalizeLocation,
    36  			},
    37  
    38  			"resource_group_name": {
    39  				Type:     schema.TypeString,
    40  				Required: true,
    41  				ForceNew: true,
    42  			},
    43  
    44  			"loadbalancer_id": {
    45  				Type:     schema.TypeString,
    46  				Required: true,
    47  				ForceNew: true,
    48  			},
    49  
    50  			"frontend_ip_configuration_name": {
    51  				Type:     schema.TypeString,
    52  				Required: true,
    53  			},
    54  
    55  			"frontend_ip_configuration_id": {
    56  				Type:     schema.TypeString,
    57  				Computed: true,
    58  			},
    59  
    60  			"backend_address_pool_id": {
    61  				Type:     schema.TypeString,
    62  				Optional: true,
    63  				Computed: true,
    64  			},
    65  
    66  			"protocol": {
    67  				Type:     schema.TypeString,
    68  				Required: true,
    69  			},
    70  
    71  			"frontend_port": {
    72  				Type:     schema.TypeInt,
    73  				Required: true,
    74  			},
    75  
    76  			"backend_port": {
    77  				Type:     schema.TypeInt,
    78  				Required: true,
    79  			},
    80  
    81  			"probe_id": {
    82  				Type:     schema.TypeString,
    83  				Optional: true,
    84  				Computed: true,
    85  			},
    86  
    87  			"enable_floating_ip": {
    88  				Type:     schema.TypeBool,
    89  				Optional: true,
    90  				Default:  false,
    91  			},
    92  
    93  			"idle_timeout_in_minutes": {
    94  				Type:     schema.TypeInt,
    95  				Optional: true,
    96  				Computed: true,
    97  			},
    98  
    99  			"load_distribution": {
   100  				Type:     schema.TypeString,
   101  				Optional: true,
   102  				Computed: true,
   103  			},
   104  		},
   105  	}
   106  }
   107  
   108  func resourceArmLoadBalancerRuleCreate(d *schema.ResourceData, meta interface{}) error {
   109  	client := meta.(*ArmClient)
   110  	lbClient := client.loadBalancerClient
   111  
   112  	loadBalancerID := d.Get("loadbalancer_id").(string)
   113  	armMutexKV.Lock(loadBalancerID)
   114  	defer armMutexKV.Unlock(loadBalancerID)
   115  
   116  	loadBalancer, exists, err := retrieveLoadBalancerById(loadBalancerID, meta)
   117  	if err != nil {
   118  		return errwrap.Wrapf("Error Getting LoadBalancer By ID {{err}}", err)
   119  	}
   120  	if !exists {
   121  		d.SetId("")
   122  		log.Printf("[INFO] LoadBalancer %q not found. Removing from state", d.Get("name").(string))
   123  		return nil
   124  	}
   125  
   126  	_, _, exists = findLoadBalancerRuleByName(loadBalancer, d.Get("name").(string))
   127  	if exists {
   128  		return fmt.Errorf("A LoadBalancer Rule with name %q already exists.", d.Get("name").(string))
   129  	}
   130  
   131  	newLbRule, err := expandAzureRmLoadBalancerRule(d, loadBalancer)
   132  	if err != nil {
   133  		return errwrap.Wrapf("Error Exanding LoadBalancer Rule {{err}}", err)
   134  	}
   135  
   136  	lbRules := append(*loadBalancer.Properties.LoadBalancingRules, *newLbRule)
   137  	loadBalancer.Properties.LoadBalancingRules = &lbRules
   138  	resGroup, loadBalancerName, err := resourceGroupAndLBNameFromId(d.Get("loadbalancer_id").(string))
   139  	if err != nil {
   140  		return errwrap.Wrapf("Error Getting LoadBalancer Name and Group: {{err}}", err)
   141  	}
   142  
   143  	_, err = lbClient.CreateOrUpdate(resGroup, loadBalancerName, *loadBalancer, make(chan struct{}))
   144  	if err != nil {
   145  		return errwrap.Wrapf("Error Creating/Updating LoadBalancer {{err}}", err)
   146  	}
   147  
   148  	read, err := lbClient.Get(resGroup, loadBalancerName, "")
   149  	if err != nil {
   150  		return errwrap.Wrapf("Error Getting LoadBalancer {{err}}", err)
   151  	}
   152  	if read.ID == nil {
   153  		return fmt.Errorf("Cannot read LoadBalancer %s (resource group %s) ID", loadBalancerName, resGroup)
   154  	}
   155  
   156  	var rule_id string
   157  	for _, LoadBalancingRule := range *(*read.Properties).LoadBalancingRules {
   158  		if *LoadBalancingRule.Name == d.Get("name").(string) {
   159  			rule_id = *LoadBalancingRule.ID
   160  		}
   161  	}
   162  
   163  	if rule_id != "" {
   164  		d.SetId(rule_id)
   165  	} else {
   166  		return fmt.Errorf("Cannot find created LoadBalancer Rule ID %q", rule_id)
   167  	}
   168  
   169  	log.Printf("[DEBUG] Waiting for LoadBalancer (%s) to become available", loadBalancerName)
   170  	stateConf := &resource.StateChangeConf{
   171  		Pending: []string{"Accepted", "Updating"},
   172  		Target:  []string{"Succeeded"},
   173  		Refresh: loadbalancerStateRefreshFunc(client, resGroup, loadBalancerName),
   174  		Timeout: 10 * time.Minute,
   175  	}
   176  	if _, err := stateConf.WaitForState(); err != nil {
   177  		return fmt.Errorf("Error waiting for LoadBalancer (%s) to become available: %s", loadBalancerName, err)
   178  	}
   179  
   180  	return resourceArmLoadBalancerRuleRead(d, meta)
   181  }
   182  
   183  func resourceArmLoadBalancerRuleRead(d *schema.ResourceData, meta interface{}) error {
   184  	loadBalancer, exists, err := retrieveLoadBalancerById(d.Get("loadbalancer_id").(string), meta)
   185  	if err != nil {
   186  		return errwrap.Wrapf("Error Getting LoadBalancer By ID {{err}}", err)
   187  	}
   188  	if !exists {
   189  		d.SetId("")
   190  		log.Printf("[INFO] LoadBalancer %q not found. Removing from state", d.Get("name").(string))
   191  		return nil
   192  	}
   193  
   194  	configs := *loadBalancer.Properties.LoadBalancingRules
   195  	for _, config := range configs {
   196  		if *config.Name == d.Get("name").(string) {
   197  			d.Set("name", config.Name)
   198  
   199  			d.Set("protocol", config.Properties.Protocol)
   200  			d.Set("frontend_port", config.Properties.FrontendPort)
   201  			d.Set("backend_port", config.Properties.BackendPort)
   202  
   203  			if config.Properties.EnableFloatingIP != nil {
   204  				d.Set("enable_floating_ip", config.Properties.EnableFloatingIP)
   205  			}
   206  
   207  			if config.Properties.IdleTimeoutInMinutes != nil {
   208  				d.Set("idle_timeout_in_minutes", config.Properties.IdleTimeoutInMinutes)
   209  			}
   210  
   211  			if config.Properties.FrontendIPConfiguration != nil {
   212  				d.Set("frontend_ip_configuration_id", config.Properties.FrontendIPConfiguration.ID)
   213  			}
   214  
   215  			if config.Properties.BackendAddressPool != nil {
   216  				d.Set("backend_address_pool_id", config.Properties.BackendAddressPool.ID)
   217  			}
   218  
   219  			if config.Properties.Probe != nil {
   220  				d.Set("probe_id", config.Properties.Probe.ID)
   221  			}
   222  
   223  			if config.Properties.LoadDistribution != "" {
   224  				d.Set("load_distribution", config.Properties.LoadDistribution)
   225  			}
   226  		}
   227  	}
   228  
   229  	return nil
   230  }
   231  
   232  func resourceArmLoadBalancerRuleDelete(d *schema.ResourceData, meta interface{}) error {
   233  	client := meta.(*ArmClient)
   234  	lbClient := client.loadBalancerClient
   235  
   236  	loadBalancerID := d.Get("loadbalancer_id").(string)
   237  	armMutexKV.Lock(loadBalancerID)
   238  	defer armMutexKV.Unlock(loadBalancerID)
   239  
   240  	loadBalancer, exists, err := retrieveLoadBalancerById(loadBalancerID, meta)
   241  	if err != nil {
   242  		return errwrap.Wrapf("Error Getting LoadBalancer By ID {{err}}", err)
   243  	}
   244  	if !exists {
   245  		d.SetId("")
   246  		return nil
   247  	}
   248  
   249  	_, index, exists := findLoadBalancerRuleByName(loadBalancer, d.Get("name").(string))
   250  	if !exists {
   251  		return nil
   252  	}
   253  
   254  	oldLbRules := *loadBalancer.Properties.LoadBalancingRules
   255  	newLbRules := append(oldLbRules[:index], oldLbRules[index+1:]...)
   256  	loadBalancer.Properties.LoadBalancingRules = &newLbRules
   257  
   258  	resGroup, loadBalancerName, err := resourceGroupAndLBNameFromId(d.Get("loadbalancer_id").(string))
   259  	if err != nil {
   260  		return errwrap.Wrapf("Error Getting LoadBalancer Name and Group: {{err}}", err)
   261  	}
   262  
   263  	_, err = lbClient.CreateOrUpdate(resGroup, loadBalancerName, *loadBalancer, make(chan struct{}))
   264  	if err != nil {
   265  		return errwrap.Wrapf("Error Creating/Updating LoadBalancer {{err}}", err)
   266  	}
   267  
   268  	read, err := lbClient.Get(resGroup, loadBalancerName, "")
   269  	if err != nil {
   270  		return errwrap.Wrapf("Error Getting LoadBalancer {{err}}", err)
   271  	}
   272  	if read.ID == nil {
   273  		return fmt.Errorf("Cannot read LoadBalancer %s (resource group %s) ID", loadBalancerName, resGroup)
   274  	}
   275  
   276  	return nil
   277  }
   278  
   279  func expandAzureRmLoadBalancerRule(d *schema.ResourceData, lb *network.LoadBalancer) (*network.LoadBalancingRule, error) {
   280  
   281  	properties := network.LoadBalancingRulePropertiesFormat{
   282  		Protocol:         network.TransportProtocol(d.Get("protocol").(string)),
   283  		FrontendPort:     azure.Int32(int32(d.Get("frontend_port").(int))),
   284  		BackendPort:      azure.Int32(int32(d.Get("backend_port").(int))),
   285  		EnableFloatingIP: azure.Bool(d.Get("enable_floating_ip").(bool)),
   286  	}
   287  
   288  	if v, ok := d.GetOk("idle_timeout_in_minutes"); ok {
   289  		properties.IdleTimeoutInMinutes = azure.Int32(int32(v.(int)))
   290  	}
   291  
   292  	if v := d.Get("load_distribution").(string); v != "" {
   293  		properties.LoadDistribution = network.LoadDistribution(v)
   294  	}
   295  
   296  	if v := d.Get("frontend_ip_configuration_name").(string); v != "" {
   297  		rule, _, exists := findLoadBalancerFrontEndIpConfigurationByName(lb, v)
   298  		if !exists {
   299  			return nil, fmt.Errorf("[ERROR] Cannot find FrontEnd IP Configuration with the name %s", v)
   300  		}
   301  
   302  		feip := network.SubResource{
   303  			ID: rule.ID,
   304  		}
   305  
   306  		properties.FrontendIPConfiguration = &feip
   307  	}
   308  
   309  	if v := d.Get("backend_address_pool_id").(string); v != "" {
   310  		beAP := network.SubResource{
   311  			ID: &v,
   312  		}
   313  
   314  		properties.BackendAddressPool = &beAP
   315  	}
   316  
   317  	if v := d.Get("probe_id").(string); v != "" {
   318  		pid := network.SubResource{
   319  			ID: &v,
   320  		}
   321  
   322  		properties.Probe = &pid
   323  	}
   324  
   325  	lbRule := network.LoadBalancingRule{
   326  		Name:       azure.String(d.Get("name").(string)),
   327  		Properties: &properties,
   328  	}
   329  
   330  	return &lbRule, nil
   331  }
   332  
   333  func validateArmLoadBalancerRuleName(v interface{}, k string) (ws []string, errors []error) {
   334  	value := v.(string)
   335  	if !regexp.MustCompile(`^[a-zA-Z_0-9.-]+$`).MatchString(value) {
   336  		errors = append(errors, fmt.Errorf(
   337  			"only word characters, numbers, underscores, periods, and hyphens allowed in %q: %q",
   338  			k, value))
   339  	}
   340  
   341  	if len(value) > 80 {
   342  		errors = append(errors, fmt.Errorf(
   343  			"%q cannot be longer than 80 characters: %q", k, value))
   344  	}
   345  
   346  	if len(value) == 0 {
   347  		errors = append(errors, fmt.Errorf(
   348  			"%q cannot be an empty string: %q", k, value))
   349  	}
   350  	if !regexp.MustCompile(`[a-zA-Z0-9_]$`).MatchString(value) {
   351  		errors = append(errors, fmt.Errorf(
   352  			"%q must end with a word character, number, or underscore: %q", k, value))
   353  	}
   354  
   355  	if !regexp.MustCompile(`^[a-zA-Z0-9]`).MatchString(value) {
   356  		errors = append(errors, fmt.Errorf(
   357  			"%q must start with a word character or number: %q", k, value))
   358  	}
   359  
   360  	return
   361  }