diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 65496d534..a53882f84 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -62,7 +62,6 @@ func Provider() terraform.ResourceProvider { "openstack_compute_instance_v2": resourceComputeInstanceV2(), "openstack_compute_keypair_v2": resourceComputeKeypairV2(), "openstack_compute_secgroup_v2": resourceComputeSecGroupV2(), - "openstack_lb_member_v1": resourceLBMemberV1(), "openstack_lb_monitor_v1": resourceLBMonitorV1(), "openstack_lb_pool_v1": resourceLBPoolV1(), "openstack_lb_vip_v1": resourceLBVipV1(), diff --git a/builtin/providers/openstack/resource_openstack_lb_member_v1.go b/builtin/providers/openstack/resource_openstack_lb_member_v1.go deleted file mode 100644 index 9cadfef90..000000000 --- a/builtin/providers/openstack/resource_openstack_lb_member_v1.go +++ /dev/null @@ -1,144 +0,0 @@ -package openstack - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform/helper/schema" - "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/members" -) - -func resourceLBMemberV1() *schema.Resource { - return &schema.Resource{ - Create: resourceLBMemberV1Create, - Read: resourceLBMemberV1Read, - Update: resourceLBMemberV1Update, - Delete: resourceLBMemberV1Delete, - - Schema: map[string]*schema.Schema{ - "region": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - DefaultFunc: envDefaultFunc("OS_REGION_NAME"), - }, - "tenant_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - }, - "address": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "port": &schema.Schema{ - Type: schema.TypeInt, - Required: true, - ForceNew: true, - }, - "pool_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "admin_state_up": &schema.Schema{ - Type: schema.TypeBool, - Required: true, - ForceNew: false, - }, - }, - } -} - -func resourceLBMemberV1Create(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - networkingClient, err := config.networkingV2Client(d.Get("region").(string)) - if err != nil { - return fmt.Errorf("Error creating OpenStack networking client: %s", err) - } - - createOpts := members.CreateOpts{ - //TenantID: d.Get("tenant_id").(string), - Address: d.Get("address").(string), - ProtocolPort: d.Get("port").(int), - PoolID: d.Get("pool_id").(string), - } - - log.Printf("[INFO] Requesting lb member creation") - p, err := members.Create(networkingClient, createOpts).Extract() - if err != nil { - return fmt.Errorf("Error creating OpenStack LB member: %s", err) - } - log.Printf("[INFO] LB Member ID: %s", p.ID) - - d.SetId(p.ID) - - return resourceLBMemberV1Read(d, meta) -} - -func resourceLBMemberV1Read(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - networkingClient, err := config.networkingV2Client(d.Get("region").(string)) - if err != nil { - return fmt.Errorf("Error creating OpenStack networking client: %s", err) - } - - p, err := members.Get(networkingClient, d.Id()).Extract() - if err != nil { - return fmt.Errorf("Error retrieving OpenStack LB Member: %s", err) - } - - log.Printf("[DEBUG] Retreived OpenStack LB Member %s: %+v", d.Id(), p) - - d.Set("region", d.Get("region").(string)) - d.Set("address", p.Address) - d.Set("port", p.ProtocolPort) - d.Set("pool_id", p.PoolID) - - if t, exists := d.GetOk("tenant_id"); exists && t != "" { - d.Set("tenant_id", p.TenantID) - } else { - d.Set("tenant_id", "") - } - - return nil -} - -func resourceLBMemberV1Update(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - networkingClient, err := config.networkingV2Client(d.Get("region").(string)) - if err != nil { - return fmt.Errorf("Error creating OpenStack networking client: %s", err) - } - - var updateOpts members.UpdateOpts - if d.HasChange("admin_state_up") { - updateOpts.AdminStateUp = d.Get("admin_state_up").(bool) - } - - log.Printf("[DEBUG] Updating OpenStack LB Member %s with options: %+v", d.Id(), updateOpts) - - _, err = members.Update(networkingClient, d.Id(), updateOpts).Extract() - if err != nil { - return fmt.Errorf("Error updating OpenStack LB Member: %s", err) - } - - return resourceLBMemberV1Read(d, meta) -} - -func resourceLBMemberV1Delete(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - networkingClient, err := config.networkingV2Client(d.Get("region").(string)) - if err != nil { - return fmt.Errorf("Error creating OpenStack networking client: %s", err) - } - - err = members.Delete(networkingClient, d.Id()).ExtractErr() - if err != nil { - return fmt.Errorf("Error deleting OpenStack LB Member: %s", err) - } - - d.SetId("") - return nil -} diff --git a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go index 3cadc2858..a7b5abbaf 100644 --- a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go @@ -1,12 +1,15 @@ package openstack import ( + "bytes" "fmt" "log" "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/members" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/pools" + "github.com/rackspace/gophercloud/pagination" ) func resourceLBPoolV1() *schema.Resource { @@ -49,6 +52,41 @@ func resourceLBPoolV1() *schema.Resource { Optional: true, ForceNew: true, }, + "member": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, + "tenant_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "address": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + "admin_state_up": &schema.Schema{ + Type: schema.TypeBool, + Required: true, + ForceNew: false, + }, + }, + }, + Set: resourceLBMemberV1Hash, + }, "monitor_ids": &schema.Schema{ Type: schema.TypeSet, Optional: true, @@ -95,6 +133,15 @@ func resourceLBPoolV1Create(d *schema.ResourceData, meta interface{}) error { } } + if memberOpts := resourcePoolMembersV1(d); memberOpts != nil { + for _, memberOpt := range memberOpts { + _, err := members.Create(networkingClient, memberOpt).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack LB member: %s", err) + } + } + } + return resourceLBPoolV1Read(d, meta) } @@ -125,6 +172,7 @@ func resourceLBPoolV1Read(d *schema.ResourceData, meta interface{}) error { } d.Set("monitor_ids", p.MonitorIDs) + d.Set("member_ids", p.MemberIDs) return nil } @@ -178,6 +226,49 @@ func resourceLBPoolV1Update(d *schema.ResourceData, meta interface{}) error { } } + if d.HasChange("member") { + oldMembersRaw, newMembersRaw := d.GetChange("member") + oldMembersSet, newMembersSet := oldMembersRaw.(*schema.Set), newMembersRaw.(*schema.Set) + membersToAdd := newMembersSet.Difference(oldMembersSet) + membersToRemove := oldMembersSet.Difference(newMembersSet) + + log.Printf("[DEBUG] Members to add: %v", membersToAdd) + + log.Printf("[DEBUG] Members to remove: %v", membersToRemove) + + for _, m := range membersToRemove.List() { + oldMember := resourcePoolMemberV1(d, m) + listOpts := members.ListOpts{ + PoolID: d.Id(), + Address: oldMember.Address, + ProtocolPort: oldMember.ProtocolPort, + } + err = members.List(networkingClient, listOpts).EachPage(func(page pagination.Page) (bool, error) { + extractedMembers, err := members.ExtractMembers(page) + if err != nil { + return false, err + } + for _, member := range extractedMembers { + err := members.Delete(networkingClient, member.ID).ExtractErr() + if err != nil { + return false, fmt.Errorf("Error deleting member (%s) from OpenStack LB pool (%s): %s", member.ID, d.Id(), err) + } + log.Printf("[DEBUG] Deleted member (%s) from pool (%s)", member.ID, d.Id()) + } + return true, nil + }) + } + + for _, m := range membersToAdd.List() { + createOpts := resourcePoolMemberV1(d, m) + newMember, err := members.Create(networkingClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating LB member: %s", err) + } + log.Printf("[DEBUG] Created member (%s) in OpenStack LB pool (%s)", newMember.ID, d.Id()) + } + } + return resourceLBPoolV1Read(d, meta) } @@ -205,3 +296,39 @@ func resourcePoolMonitorIDsV1(d *schema.ResourceData) []string { } return mIDs } + +func resourcePoolMembersV1(d *schema.ResourceData) []members.CreateOpts { + memberOptsRaw := (d.Get("member")).(*schema.Set) + memberOpts := make([]members.CreateOpts, memberOptsRaw.Len()) + for i, raw := range memberOptsRaw.List() { + rawMap := raw.(map[string]interface{}) + memberOpts[i] = members.CreateOpts{ + TenantID: rawMap["tenant_id"].(string), + Address: rawMap["address"].(string), + ProtocolPort: rawMap["port"].(int), + PoolID: d.Id(), + } + } + return memberOpts +} + +func resourcePoolMemberV1(d *schema.ResourceData, raw interface{}) members.CreateOpts { + rawMap := raw.(map[string]interface{}) + return members.CreateOpts{ + TenantID: rawMap["tenant_id"].(string), + Address: rawMap["address"].(string), + ProtocolPort: rawMap["port"].(int), + PoolID: d.Id(), + } +} + +func resourceLBMemberV1Hash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", m["region"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["tenant_id"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["address"].(string))) + buf.WriteString(fmt.Sprintf("%d-", m["port"].(int))) + + return hashcode.String(buf.String()) +}