github.com/jsoriano/terraform@v0.6.7-0.20151026070445-8b70867fdd95/builtin/providers/openstack/resource_openstack_lb_pool_v1.go (about)

     1  package openstack
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  
     8  	"github.com/hashicorp/terraform/helper/hashcode"
     9  	"github.com/hashicorp/terraform/helper/schema"
    10  	"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/members"
    11  	"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/pools"
    12  	"github.com/rackspace/gophercloud/pagination"
    13  )
    14  
    15  func resourceLBPoolV1() *schema.Resource {
    16  	return &schema.Resource{
    17  		Create: resourceLBPoolV1Create,
    18  		Read:   resourceLBPoolV1Read,
    19  		Update: resourceLBPoolV1Update,
    20  		Delete: resourceLBPoolV1Delete,
    21  
    22  		Schema: map[string]*schema.Schema{
    23  			"region": &schema.Schema{
    24  				Type:        schema.TypeString,
    25  				Required:    true,
    26  				ForceNew:    true,
    27  				DefaultFunc: envDefaultFuncAllowMissing("OS_REGION_NAME"),
    28  			},
    29  			"name": &schema.Schema{
    30  				Type:     schema.TypeString,
    31  				Required: true,
    32  				ForceNew: false,
    33  			},
    34  			"protocol": &schema.Schema{
    35  				Type:     schema.TypeString,
    36  				Required: true,
    37  				ForceNew: true,
    38  			},
    39  			"subnet_id": &schema.Schema{
    40  				Type:     schema.TypeString,
    41  				Required: true,
    42  				ForceNew: true,
    43  			},
    44  
    45  			"lb_method": &schema.Schema{
    46  				Type:     schema.TypeString,
    47  				Required: true,
    48  				ForceNew: false,
    49  			},
    50  			"tenant_id": &schema.Schema{
    51  				Type:     schema.TypeString,
    52  				Optional: true,
    53  				ForceNew: true,
    54  				Computed: true,
    55  			},
    56  			"member": &schema.Schema{
    57  				Type:     schema.TypeSet,
    58  				Optional: true,
    59  				Elem: &schema.Resource{
    60  					Schema: map[string]*schema.Schema{
    61  						"region": &schema.Schema{
    62  							Type:        schema.TypeString,
    63  							Required:    true,
    64  							ForceNew:    true,
    65  							DefaultFunc: envDefaultFuncAllowMissing("OS_REGION_NAME"),
    66  						},
    67  						"tenant_id": &schema.Schema{
    68  							Type:     schema.TypeString,
    69  							Optional: true,
    70  							ForceNew: true,
    71  						},
    72  						"address": &schema.Schema{
    73  							Type:     schema.TypeString,
    74  							Required: true,
    75  							ForceNew: true,
    76  						},
    77  						"port": &schema.Schema{
    78  							Type:     schema.TypeInt,
    79  							Required: true,
    80  							ForceNew: true,
    81  						},
    82  						"admin_state_up": &schema.Schema{
    83  							Type:     schema.TypeBool,
    84  							Required: true,
    85  							ForceNew: false,
    86  						},
    87  					},
    88  				},
    89  				Set: resourceLBMemberV1Hash,
    90  			},
    91  			"monitor_ids": &schema.Schema{
    92  				Type:     schema.TypeSet,
    93  				Optional: true,
    94  				ForceNew: false,
    95  				Elem:     &schema.Schema{Type: schema.TypeString},
    96  				Set: func(v interface{}) int {
    97  					return hashcode.String(v.(string))
    98  				},
    99  			},
   100  		},
   101  	}
   102  }
   103  
   104  func resourceLBPoolV1Create(d *schema.ResourceData, meta interface{}) error {
   105  	config := meta.(*Config)
   106  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   107  	if err != nil {
   108  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   109  	}
   110  
   111  	createOpts := pools.CreateOpts{
   112  		Name:     d.Get("name").(string),
   113  		Protocol: d.Get("protocol").(string),
   114  		SubnetID: d.Get("subnet_id").(string),
   115  		LBMethod: d.Get("lb_method").(string),
   116  		TenantID: d.Get("tenant_id").(string),
   117  	}
   118  
   119  	log.Printf("[DEBUG] Create Options: %#v", createOpts)
   120  	p, err := pools.Create(networkingClient, createOpts).Extract()
   121  	if err != nil {
   122  		return fmt.Errorf("Error creating OpenStack LB pool: %s", err)
   123  	}
   124  	log.Printf("[INFO] LB Pool ID: %s", p.ID)
   125  
   126  	d.SetId(p.ID)
   127  
   128  	if mIDs := resourcePoolMonitorIDsV1(d); mIDs != nil {
   129  		for _, mID := range mIDs {
   130  			_, err := pools.AssociateMonitor(networkingClient, p.ID, mID).Extract()
   131  			if err != nil {
   132  				return fmt.Errorf("Error associating monitor (%s) with OpenStack LB pool (%s): %s", mID, p.ID, err)
   133  			}
   134  		}
   135  	}
   136  
   137  	if memberOpts := resourcePoolMembersV1(d); memberOpts != nil {
   138  		for _, memberOpt := range memberOpts {
   139  			_, err := members.Create(networkingClient, memberOpt).Extract()
   140  			if err != nil {
   141  				return fmt.Errorf("Error creating OpenStack LB member: %s", err)
   142  			}
   143  		}
   144  	}
   145  
   146  	return resourceLBPoolV1Read(d, meta)
   147  }
   148  
   149  func resourceLBPoolV1Read(d *schema.ResourceData, meta interface{}) error {
   150  	config := meta.(*Config)
   151  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   152  	if err != nil {
   153  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   154  	}
   155  
   156  	p, err := pools.Get(networkingClient, d.Id()).Extract()
   157  	if err != nil {
   158  		return CheckDeleted(d, err, "LB pool")
   159  	}
   160  
   161  	log.Printf("[DEBUG] Retreived OpenStack LB Pool %s: %+v", d.Id(), p)
   162  
   163  	d.Set("name", p.Name)
   164  	d.Set("protocol", p.Protocol)
   165  	d.Set("subnet_id", p.SubnetID)
   166  	d.Set("lb_method", p.LBMethod)
   167  	d.Set("tenant_id", p.TenantID)
   168  	d.Set("monitor_ids", p.MonitorIDs)
   169  	d.Set("member_ids", p.MemberIDs)
   170  
   171  	return nil
   172  }
   173  
   174  func resourceLBPoolV1Update(d *schema.ResourceData, meta interface{}) error {
   175  	config := meta.(*Config)
   176  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   177  	if err != nil {
   178  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   179  	}
   180  
   181  	var updateOpts pools.UpdateOpts
   182  	// If either option changed, update both.
   183  	// Gophercloud complains if one is empty.
   184  	if d.HasChange("name") || d.HasChange("lb_method") {
   185  		updateOpts.Name = d.Get("name").(string)
   186  		updateOpts.LBMethod = d.Get("lb_method").(string)
   187  	}
   188  
   189  	log.Printf("[DEBUG] Updating OpenStack LB Pool %s with options: %+v", d.Id(), updateOpts)
   190  
   191  	_, err = pools.Update(networkingClient, d.Id(), updateOpts).Extract()
   192  	if err != nil {
   193  		return fmt.Errorf("Error updating OpenStack LB Pool: %s", err)
   194  	}
   195  
   196  	if d.HasChange("monitor_ids") {
   197  		oldMIDsRaw, newMIDsRaw := d.GetChange("security_groups")
   198  		oldMIDsSet, newMIDsSet := oldMIDsRaw.(*schema.Set), newMIDsRaw.(*schema.Set)
   199  		monitorsToAdd := newMIDsSet.Difference(oldMIDsSet)
   200  		monitorsToRemove := oldMIDsSet.Difference(newMIDsSet)
   201  
   202  		log.Printf("[DEBUG] Monitors to add: %v", monitorsToAdd)
   203  
   204  		log.Printf("[DEBUG] Monitors to remove: %v", monitorsToRemove)
   205  
   206  		for _, m := range monitorsToAdd.List() {
   207  			_, err := pools.AssociateMonitor(networkingClient, d.Id(), m.(string)).Extract()
   208  			if err != nil {
   209  				return fmt.Errorf("Error associating monitor (%s) with OpenStack server (%s): %s", m.(string), d.Id(), err)
   210  			}
   211  			log.Printf("[DEBUG] Associated monitor (%s) with pool (%s)", m.(string), d.Id())
   212  		}
   213  
   214  		for _, m := range monitorsToRemove.List() {
   215  			_, err := pools.DisassociateMonitor(networkingClient, d.Id(), m.(string)).Extract()
   216  			if err != nil {
   217  				return fmt.Errorf("Error disassociating monitor (%s) from OpenStack server (%s): %s", m.(string), d.Id(), err)
   218  			}
   219  			log.Printf("[DEBUG] Disassociated monitor (%s) from pool (%s)", m.(string), d.Id())
   220  		}
   221  	}
   222  
   223  	if d.HasChange("member") {
   224  		oldMembersRaw, newMembersRaw := d.GetChange("member")
   225  		oldMembersSet, newMembersSet := oldMembersRaw.(*schema.Set), newMembersRaw.(*schema.Set)
   226  		membersToAdd := newMembersSet.Difference(oldMembersSet)
   227  		membersToRemove := oldMembersSet.Difference(newMembersSet)
   228  
   229  		log.Printf("[DEBUG] Members to add: %v", membersToAdd)
   230  
   231  		log.Printf("[DEBUG] Members to remove: %v", membersToRemove)
   232  
   233  		for _, m := range membersToRemove.List() {
   234  			oldMember := resourcePoolMemberV1(d, m)
   235  			listOpts := members.ListOpts{
   236  				PoolID:       d.Id(),
   237  				Address:      oldMember.Address,
   238  				ProtocolPort: oldMember.ProtocolPort,
   239  			}
   240  			err = members.List(networkingClient, listOpts).EachPage(func(page pagination.Page) (bool, error) {
   241  				extractedMembers, err := members.ExtractMembers(page)
   242  				if err != nil {
   243  					return false, err
   244  				}
   245  				for _, member := range extractedMembers {
   246  					err := members.Delete(networkingClient, member.ID).ExtractErr()
   247  					if err != nil {
   248  						return false, fmt.Errorf("Error deleting member (%s) from OpenStack LB pool (%s): %s", member.ID, d.Id(), err)
   249  					}
   250  					log.Printf("[DEBUG] Deleted member (%s) from pool (%s)", member.ID, d.Id())
   251  				}
   252  				return true, nil
   253  			})
   254  		}
   255  
   256  		for _, m := range membersToAdd.List() {
   257  			createOpts := resourcePoolMemberV1(d, m)
   258  			newMember, err := members.Create(networkingClient, createOpts).Extract()
   259  			if err != nil {
   260  				return fmt.Errorf("Error creating LB member: %s", err)
   261  			}
   262  			log.Printf("[DEBUG] Created member (%s) in OpenStack LB pool (%s)", newMember.ID, d.Id())
   263  		}
   264  	}
   265  
   266  	return resourceLBPoolV1Read(d, meta)
   267  }
   268  
   269  func resourceLBPoolV1Delete(d *schema.ResourceData, meta interface{}) error {
   270  	config := meta.(*Config)
   271  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   272  	if err != nil {
   273  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   274  	}
   275  
   276  	err = pools.Delete(networkingClient, d.Id()).ExtractErr()
   277  	if err != nil {
   278  		return fmt.Errorf("Error deleting OpenStack LB Pool: %s", err)
   279  	}
   280  
   281  	d.SetId("")
   282  	return nil
   283  }
   284  
   285  func resourcePoolMonitorIDsV1(d *schema.ResourceData) []string {
   286  	mIDsRaw := d.Get("monitor_ids").(*schema.Set)
   287  	mIDs := make([]string, mIDsRaw.Len())
   288  	for i, raw := range mIDsRaw.List() {
   289  		mIDs[i] = raw.(string)
   290  	}
   291  	return mIDs
   292  }
   293  
   294  func resourcePoolMembersV1(d *schema.ResourceData) []members.CreateOpts {
   295  	memberOptsRaw := d.Get("member").(*schema.Set)
   296  	memberOpts := make([]members.CreateOpts, memberOptsRaw.Len())
   297  	for i, raw := range memberOptsRaw.List() {
   298  		rawMap := raw.(map[string]interface{})
   299  		memberOpts[i] = members.CreateOpts{
   300  			TenantID:     rawMap["tenant_id"].(string),
   301  			Address:      rawMap["address"].(string),
   302  			ProtocolPort: rawMap["port"].(int),
   303  			PoolID:       d.Id(),
   304  		}
   305  	}
   306  	return memberOpts
   307  }
   308  
   309  func resourcePoolMemberV1(d *schema.ResourceData, raw interface{}) members.CreateOpts {
   310  	rawMap := raw.(map[string]interface{})
   311  	return members.CreateOpts{
   312  		TenantID:     rawMap["tenant_id"].(string),
   313  		Address:      rawMap["address"].(string),
   314  		ProtocolPort: rawMap["port"].(int),
   315  		PoolID:       d.Id(),
   316  	}
   317  }
   318  
   319  func resourceLBMemberV1Hash(v interface{}) int {
   320  	var buf bytes.Buffer
   321  	m := v.(map[string]interface{})
   322  	buf.WriteString(fmt.Sprintf("%s-", m["region"].(string)))
   323  	buf.WriteString(fmt.Sprintf("%s-", m["tenant_id"].(string)))
   324  	buf.WriteString(fmt.Sprintf("%s-", m["address"].(string)))
   325  	buf.WriteString(fmt.Sprintf("%d-", m["port"].(int)))
   326  
   327  	return hashcode.String(buf.String())
   328  }