github.com/pmcatominey/terraform@v0.7.0-rc2.0.20160708105029-1401a52a5cc5/builtin/providers/openstack/resource_openstack_lb_pool_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 resourcePoolV2() *schema.Resource { 16 return &schema.Resource{ 17 Create: resourcePoolV2Create, 18 Read: resourcePoolV2Read, 19 Update: resourcePoolV2Update, 20 Delete: resourcePoolV2Delete, 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 "tenant_id": &schema.Schema{ 31 Type: schema.TypeString, 32 Optional: true, 33 Computed: true, 34 ForceNew: true, 35 }, 36 37 "name": &schema.Schema{ 38 Type: schema.TypeString, 39 Optional: true, 40 }, 41 42 "description": &schema.Schema{ 43 Type: schema.TypeString, 44 Optional: true, 45 }, 46 47 "protocol": &schema.Schema{ 48 Type: schema.TypeString, 49 Required: true, 50 ForceNew: true, 51 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 52 value := v.(string) 53 if value != "lTCP" && value != "HTTP" && value != "HTTPS" { 54 errors = append(errors, fmt.Errorf( 55 "Only 'TCP', 'HTTP', and 'HTTPS' are supported values for 'protocol'")) 56 } 57 return 58 }, 59 }, 60 61 // One of loadbalancer_id or listener_id must be provided 62 "loadbalancer_id": &schema.Schema{ 63 Type: schema.TypeString, 64 Optional: true, 65 ForceNew: true, 66 }, 67 68 // One of loadbalancer_id or listener_id must be provided 69 "listener_id": &schema.Schema{ 70 Type: schema.TypeString, 71 Optional: true, 72 ForceNew: true, 73 }, 74 75 "lb_method": &schema.Schema{ 76 Type: schema.TypeString, 77 Required: true, 78 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 79 value := v.(string) 80 if value != "ROUND_ROBIN" && value != "LEAST_CONNECTIONS" && value != "SOURCE_IP" { 81 errors = append(errors, fmt.Errorf( 82 "Only 'ROUND_ROBIN', 'LEAST_CONNECTIONS', and 'SOURCE_IP' are supported values for 'lb_method'")) 83 } 84 return 85 }, 86 }, 87 88 "persistence": &schema.Schema{ 89 Type: schema.TypeList, 90 Optional: true, 91 ForceNew: true, 92 Elem: &schema.Resource{ 93 Schema: map[string]*schema.Schema{ 94 "type": &schema.Schema{ 95 Type: schema.TypeString, 96 Required: true, 97 ForceNew: true, 98 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 99 value := v.(string) 100 if value != "SOURCE_IP" && value != "HTTP_COOKIE" && value != "APP_COOKIE" { 101 errors = append(errors, fmt.Errorf( 102 "Only 'SOURCE_IP', 'HTTP_COOKIE', and 'APP_COOKIE' are supported values for 'persistence'")) 103 } 104 return 105 }, 106 }, 107 108 "cookie_name": &schema.Schema{ 109 Type: schema.TypeString, 110 Required: true, 111 ForceNew: true, 112 }, 113 }, 114 }, 115 }, 116 117 "admin_state_up": &schema.Schema{ 118 Type: schema.TypeBool, 119 Optional: true, 120 }, 121 122 "id": &schema.Schema{ 123 Type: schema.TypeString, 124 Optional: true, 125 Computed: true, 126 }, 127 }, 128 } 129 } 130 131 func resourcePoolV2Create(d *schema.ResourceData, meta interface{}) error { 132 config := meta.(*Config) 133 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 134 if err != nil { 135 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 136 } 137 138 adminStateUp := d.Get("admin_state_up").(bool) 139 var persistence pools.SessionPersistence 140 if p, ok := d.GetOk("persistence"); ok { 141 pV := (p.([]interface{}))[0].(map[string]interface{}) 142 143 persistence = pools.SessionPersistence{ 144 Type: pV["type"].(string), 145 CookieName: pV["cookie_name"].(string), 146 } 147 } 148 createOpts := pools.CreateOpts{ 149 TenantID: d.Get("tenant_id").(string), 150 Name: d.Get("name").(string), 151 Description: d.Get("description").(string), 152 Protocol: pools.Protocol(d.Get("protocol").(string)), 153 LoadbalancerID: d.Get("loadbalancer_id").(string), 154 ListenerID: d.Get("listener_id").(string), 155 LBMethod: pools.LBMethod(d.Get("lb_method").(string)), 156 AdminStateUp: &adminStateUp, 157 } 158 // Must omit if not set 159 if persistence != (pools.SessionPersistence{}) { 160 createOpts.Persistence = &persistence 161 } 162 163 log.Printf("[DEBUG] Create Options: %#v", createOpts) 164 pool, err := pools.Create(networkingClient, createOpts).Extract() 165 if err != nil { 166 return fmt.Errorf("Error creating OpenStack LBaaSV2 pool: %s", err) 167 } 168 log.Printf("[INFO] pool ID: %s", pool.ID) 169 170 log.Printf("[DEBUG] Waiting for Openstack LBaaSV2 pool (%s) to become available.", pool.ID) 171 172 stateConf := &resource.StateChangeConf{ 173 Pending: []string{"PENDING_CREATE"}, 174 Target: []string{"ACTIVE"}, 175 Refresh: waitForPoolActive(networkingClient, pool.ID), 176 Timeout: 2 * time.Minute, 177 Delay: 5 * time.Second, 178 MinTimeout: 3 * time.Second, 179 } 180 181 _, err = stateConf.WaitForState() 182 if err != nil { 183 return err 184 } 185 186 d.SetId(pool.ID) 187 188 return resourcePoolV2Read(d, meta) 189 } 190 191 func resourcePoolV2Read(d *schema.ResourceData, meta interface{}) error { 192 config := meta.(*Config) 193 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 194 if err != nil { 195 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 196 } 197 198 pool, err := pools.Get(networkingClient, d.Id()).Extract() 199 if err != nil { 200 return CheckDeleted(d, err, "LBV2 Pool") 201 } 202 203 log.Printf("[DEBUG] Retreived OpenStack LBaaSV2 Pool %s: %+v", d.Id(), pool) 204 205 d.Set("lb_method", pool.LBMethod) 206 d.Set("protocol", pool.Protocol) 207 d.Set("description", pool.Description) 208 d.Set("tenant_id", pool.TenantID) 209 d.Set("admin_state_up", pool.AdminStateUp) 210 d.Set("name", pool.Name) 211 d.Set("id", pool.ID) 212 d.Set("persistence", pool.Persistence) 213 214 return nil 215 } 216 217 func resourcePoolV2Update(d *schema.ResourceData, meta interface{}) error { 218 config := meta.(*Config) 219 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 220 if err != nil { 221 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 222 } 223 224 var updateOpts pools.UpdateOpts 225 if d.HasChange("lb_method") { 226 updateOpts.LBMethod = pools.LBMethod(d.Get("lb_method").(string)) 227 } 228 if d.HasChange("name") { 229 updateOpts.Name = d.Get("name").(string) 230 } 231 if d.HasChange("description") { 232 updateOpts.Description = d.Get("description").(string) 233 } 234 if d.HasChange("admin_state_up") { 235 asu := d.Get("admin_state_up").(bool) 236 updateOpts.AdminStateUp = &asu 237 } 238 239 log.Printf("[DEBUG] Updating OpenStack LBaaSV2 Pool %s with options: %+v", d.Id(), updateOpts) 240 241 _, err = pools.Update(networkingClient, d.Id(), updateOpts).Extract() 242 if err != nil { 243 return fmt.Errorf("Error updating OpenStack LBaaSV2 Pool: %s", err) 244 } 245 246 return resourcePoolV2Read(d, meta) 247 } 248 249 func resourcePoolV2Delete(d *schema.ResourceData, meta interface{}) error { 250 config := meta.(*Config) 251 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 252 if err != nil { 253 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 254 } 255 256 stateConf := &resource.StateChangeConf{ 257 Pending: []string{"ACTIVE", "PENDING_DELETE"}, 258 Target: []string{"DELETED"}, 259 Refresh: waitForPoolDelete(networkingClient, d.Id()), 260 Timeout: 2 * time.Minute, 261 Delay: 5 * time.Second, 262 MinTimeout: 3 * time.Second, 263 } 264 265 _, err = stateConf.WaitForState() 266 if err != nil { 267 return fmt.Errorf("Error deleting OpenStack LBaaSV2 Pool: %s", err) 268 } 269 270 d.SetId("") 271 return nil 272 } 273 274 func waitForPoolActive(networkingClient *gophercloud.ServiceClient, poolID string) resource.StateRefreshFunc { 275 return func() (interface{}, string, error) { 276 pool, err := pools.Get(networkingClient, poolID).Extract() 277 if err != nil { 278 return nil, "", err 279 } 280 281 // The pool resource has no Status attribute, so a successful Get is the best we can do 282 log.Printf("[DEBUG] OpenStack LBaaSV2 Pool: %+v", pool) 283 return pool, "ACTIVE", nil 284 } 285 } 286 287 func waitForPoolDelete(networkingClient *gophercloud.ServiceClient, poolID string) resource.StateRefreshFunc { 288 return func() (interface{}, string, error) { 289 log.Printf("[DEBUG] Attempting to delete OpenStack LBaaSV2 Pool %s", poolID) 290 291 pool, err := pools.Get(networkingClient, poolID).Extract() 292 if err != nil { 293 errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) 294 if !ok { 295 return pool, "ACTIVE", err 296 } 297 if errCode.Actual == 404 { 298 log.Printf("[DEBUG] Successfully deleted OpenStack LBaaSV2 Pool %s", poolID) 299 return pool, "DELETED", nil 300 } 301 } 302 303 log.Printf("[DEBUG] Openstack LBaaSV2 Pool: %+v", pool) 304 err = pools.Delete(networkingClient, poolID).ExtractErr() 305 if err != nil { 306 errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) 307 if !ok { 308 return pool, "ACTIVE", err 309 } 310 if errCode.Actual == 404 { 311 log.Printf("[DEBUG] Successfully deleted OpenStack LBaaSV2 Pool %s", poolID) 312 return pool, "DELETED", nil 313 } 314 } 315 316 log.Printf("[DEBUG] OpenStack LBaaSV2 Pool %s still active.", poolID) 317 return pool, "ACTIVE", nil 318 } 319 }