github.com/pmcatominey/terraform@v0.7.0-rc2.0.20160708105029-1401a52a5cc5/builtin/providers/openstack/resource_openstack_lb_member_v2.go (about) 1 package openstack 2 3 import ( 4 "fmt" 5 "log" 6 "time" 7 8 "github.com/hashicorp/terraform/helper/resource" 9 "github.com/hashicorp/terraform/helper/schema" 10 11 "github.com/rackspace/gophercloud" 12 "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools" 13 ) 14 15 func resourceMemberV2() *schema.Resource { 16 return &schema.Resource{ 17 Create: resourceMemberV2Create, 18 Read: resourceMemberV2Read, 19 Update: resourceMemberV2Update, 20 Delete: resourceMemberV2Delete, 21 22 Schema: map[string]*schema.Schema{ 23 "region": &schema.Schema{ 24 Type: schema.TypeString, 25 Required: true, 26 ForceNew: true, 27 DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""), 28 }, 29 30 "name": &schema.Schema{ 31 Type: schema.TypeString, 32 Optional: true, 33 }, 34 35 "tenant_id": &schema.Schema{ 36 Type: schema.TypeString, 37 Optional: true, 38 Computed: true, 39 ForceNew: true, 40 }, 41 42 "address": &schema.Schema{ 43 Type: schema.TypeString, 44 Required: true, 45 ForceNew: true, 46 }, 47 48 "protocol_port": &schema.Schema{ 49 Type: schema.TypeInt, 50 Required: true, 51 ForceNew: true, 52 }, 53 54 "weight": &schema.Schema{ 55 Type: schema.TypeInt, 56 Optional: true, 57 Computed: true, 58 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 59 value := v.(int) 60 if value < 1 { 61 errors = append(errors, fmt.Errorf( 62 "Only numbers greater than 0 are supported values for 'weight'")) 63 } 64 return 65 }, 66 }, 67 68 "subnet_id": &schema.Schema{ 69 Type: schema.TypeString, 70 Required: true, 71 ForceNew: true, 72 }, 73 74 "admin_state_up": &schema.Schema{ 75 Type: schema.TypeBool, 76 Optional: true, 77 }, 78 79 "pool_id": &schema.Schema{ 80 Type: schema.TypeString, 81 Required: true, 82 ForceNew: true, 83 }, 84 85 "id": &schema.Schema{ 86 Type: schema.TypeString, 87 Optional: true, 88 Computed: true, 89 }, 90 }, 91 } 92 } 93 94 func resourceMemberV2Create(d *schema.ResourceData, meta interface{}) error { 95 config := meta.(*Config) 96 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 97 if err != nil { 98 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 99 } 100 101 subnetID := d.Get("subnet_id").(string) 102 adminStateUp := d.Get("admin_state_up").(bool) 103 createOpts := pools.MemberCreateOpts{ 104 Name: d.Get("name").(string), 105 TenantID: d.Get("tenant_id").(string), 106 Address: d.Get("address").(string), 107 ProtocolPort: d.Get("protocol_port").(int), 108 Weight: d.Get("weight").(int), 109 AdminStateUp: &adminStateUp, 110 } 111 // Must omit if not set 112 if subnetID != "" { 113 createOpts.SubnetID = subnetID 114 } 115 116 poolID := d.Get("pool_id").(string) 117 118 log.Printf("[DEBUG] Create Options: %#v", createOpts) 119 member, err := pools.CreateAssociateMember(networkingClient, poolID, createOpts).ExtractMember() 120 if err != nil { 121 return fmt.Errorf("Error creating OpenStack LBaaSV2 member: %s", err) 122 } 123 log.Printf("[INFO] member ID: %s", member.ID) 124 125 log.Printf("[DEBUG] Waiting for Openstack LBaaSV2 member (%s) to become available.", member.ID) 126 127 stateConf := &resource.StateChangeConf{ 128 Pending: []string{"PENDING_CREATE"}, 129 Target: []string{"ACTIVE"}, 130 Refresh: waitForMemberActive(networkingClient, poolID, member.ID), 131 Timeout: 2 * time.Minute, 132 Delay: 5 * time.Second, 133 MinTimeout: 3 * time.Second, 134 } 135 136 _, err = stateConf.WaitForState() 137 if err != nil { 138 return err 139 } 140 141 d.SetId(member.ID) 142 143 return resourceMemberV2Read(d, meta) 144 } 145 146 func resourceMemberV2Read(d *schema.ResourceData, meta interface{}) error { 147 config := meta.(*Config) 148 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 149 if err != nil { 150 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 151 } 152 153 member, err := pools.GetAssociateMember(networkingClient, d.Get("pool_id").(string), d.Id()).ExtractMember() 154 if err != nil { 155 return CheckDeleted(d, err, "LBV2 Member") 156 } 157 158 log.Printf("[DEBUG] Retreived OpenStack LBaaSV2 Member %s: %+v", d.Id(), member) 159 160 d.Set("name", member.Name) 161 d.Set("weight", member.Weight) 162 d.Set("admin_state_up", member.AdminStateUp) 163 d.Set("tenant_id", member.TenantID) 164 d.Set("subnet_id", member.SubnetID) 165 d.Set("address", member.Address) 166 d.Set("protocol_port", member.ProtocolPort) 167 d.Set("id", member.ID) 168 169 return nil 170 } 171 172 func resourceMemberV2Update(d *schema.ResourceData, meta interface{}) error { 173 config := meta.(*Config) 174 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 175 if err != nil { 176 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 177 } 178 179 var updateOpts pools.MemberUpdateOpts 180 if d.HasChange("name") { 181 updateOpts.Name = d.Get("name").(string) 182 } 183 if d.HasChange("weight") { 184 updateOpts.Weight = d.Get("weight").(int) 185 } 186 if d.HasChange("admin_state_up") { 187 asu := d.Get("admin_state_up").(bool) 188 updateOpts.AdminStateUp = &asu 189 } 190 191 log.Printf("[DEBUG] Updating OpenStack LBaaSV2 Member %s with options: %+v", d.Id(), updateOpts) 192 193 _, err = pools.UpdateAssociateMember(networkingClient, d.Get("pool_id").(string), d.Id(), updateOpts).ExtractMember() 194 if err != nil { 195 return fmt.Errorf("Error updating OpenStack LBaaSV2 Member: %s", err) 196 } 197 198 return resourceMemberV2Read(d, meta) 199 } 200 201 func resourceMemberV2Delete(d *schema.ResourceData, meta interface{}) error { 202 config := meta.(*Config) 203 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 204 if err != nil { 205 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 206 } 207 208 stateConf := &resource.StateChangeConf{ 209 Pending: []string{"ACTIVE", "PENDING_DELETE"}, 210 Target: []string{"DELETED"}, 211 Refresh: waitForMemberDelete(networkingClient, d.Get("pool_id").(string), d.Id()), 212 Timeout: 2 * time.Minute, 213 Delay: 5 * time.Second, 214 MinTimeout: 3 * time.Second, 215 } 216 217 _, err = stateConf.WaitForState() 218 if err != nil { 219 return fmt.Errorf("Error deleting OpenStack LBaaSV2 Member: %s", err) 220 } 221 222 d.SetId("") 223 return nil 224 } 225 226 func waitForMemberActive(networkingClient *gophercloud.ServiceClient, poolID string, memberID string) resource.StateRefreshFunc { 227 return func() (interface{}, string, error) { 228 member, err := pools.GetAssociateMember(networkingClient, poolID, memberID).ExtractMember() 229 if err != nil { 230 return nil, "", err 231 } 232 233 // The member resource has no Status attribute, so a successful Get is the best we can do 234 log.Printf("[DEBUG] OpenStack LBaaSV2 Member: %+v", member) 235 return member, "ACTIVE", nil 236 } 237 } 238 239 func waitForMemberDelete(networkingClient *gophercloud.ServiceClient, poolID string, memberID string) resource.StateRefreshFunc { 240 return func() (interface{}, string, error) { 241 log.Printf("[DEBUG] Attempting to delete OpenStack LBaaSV2 Member %s", memberID) 242 243 member, err := pools.GetAssociateMember(networkingClient, poolID, memberID).ExtractMember() 244 if err != nil { 245 errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) 246 if !ok { 247 return member, "ACTIVE", err 248 } 249 if errCode.Actual == 404 { 250 log.Printf("[DEBUG] Successfully deleted OpenStack LBaaSV2 Member %s", memberID) 251 return member, "DELETED", nil 252 } 253 } 254 255 log.Printf("[DEBUG] Openstack LBaaSV2 Member: %+v", member) 256 err = pools.DeleteMember(networkingClient, poolID, memberID).ExtractErr() 257 if err != nil { 258 errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) 259 if !ok { 260 return member, "ACTIVE", err 261 } 262 if errCode.Actual == 404 { 263 log.Printf("[DEBUG] Successfully deleted OpenStack LBaaSV2 Member %s", memberID) 264 return member, "DELETED", nil 265 } 266 } 267 268 log.Printf("[DEBUG] OpenStack LBaaSV2 Member %s still active.", memberID) 269 return member, "ACTIVE", nil 270 } 271 }