github.com/koding/terraform@v0.6.4-0.20170608090606-5d7e0339779d/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go (about) 1 package openstack 2 3 import ( 4 "fmt" 5 "log" 6 "time" 7 8 "github.com/gophercloud/gophercloud" 9 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls" 10 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion" 11 "github.com/hashicorp/terraform/helper/resource" 12 "github.com/hashicorp/terraform/helper/schema" 13 ) 14 15 func resourceFWFirewallV1() *schema.Resource { 16 return &schema.Resource{ 17 Create: resourceFWFirewallV1Create, 18 Read: resourceFWFirewallV1Read, 19 Update: resourceFWFirewallV1Update, 20 Delete: resourceFWFirewallV1Delete, 21 Importer: &schema.ResourceImporter{ 22 State: schema.ImportStatePassthrough, 23 }, 24 25 Timeouts: &schema.ResourceTimeout{ 26 Create: schema.DefaultTimeout(10 * time.Minute), 27 Update: schema.DefaultTimeout(10 * time.Minute), 28 Delete: schema.DefaultTimeout(10 * time.Minute), 29 }, 30 31 Schema: map[string]*schema.Schema{ 32 "region": &schema.Schema{ 33 Type: schema.TypeString, 34 Required: true, 35 ForceNew: true, 36 DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""), 37 }, 38 "name": &schema.Schema{ 39 Type: schema.TypeString, 40 Optional: true, 41 }, 42 "description": &schema.Schema{ 43 Type: schema.TypeString, 44 Optional: true, 45 }, 46 "policy_id": &schema.Schema{ 47 Type: schema.TypeString, 48 Required: true, 49 }, 50 "admin_state_up": &schema.Schema{ 51 Type: schema.TypeBool, 52 Optional: true, 53 Default: true, 54 }, 55 "tenant_id": &schema.Schema{ 56 Type: schema.TypeString, 57 Optional: true, 58 ForceNew: true, 59 Computed: true, 60 }, 61 "associated_routers": &schema.Schema{ 62 Type: schema.TypeSet, 63 Optional: true, 64 Elem: &schema.Schema{Type: schema.TypeString}, 65 Set: schema.HashString, 66 ConflictsWith: []string{"no_routers"}, 67 }, 68 "no_routers": &schema.Schema{ 69 Type: schema.TypeBool, 70 Optional: true, 71 ConflictsWith: []string{"associated_routers"}, 72 }, 73 "value_specs": &schema.Schema{ 74 Type: schema.TypeMap, 75 Optional: true, 76 ForceNew: true, 77 }, 78 }, 79 } 80 } 81 82 func resourceFWFirewallV1Create(d *schema.ResourceData, meta interface{}) error { 83 84 config := meta.(*Config) 85 networkingClient, err := config.networkingV2Client(GetRegion(d)) 86 if err != nil { 87 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 88 } 89 90 var createOpts firewalls.CreateOptsBuilder 91 92 adminStateUp := d.Get("admin_state_up").(bool) 93 createOpts = &firewalls.CreateOpts{ 94 Name: d.Get("name").(string), 95 Description: d.Get("description").(string), 96 PolicyID: d.Get("policy_id").(string), 97 AdminStateUp: &adminStateUp, 98 TenantID: d.Get("tenant_id").(string), 99 } 100 101 associatedRoutersRaw := d.Get("associated_routers").(*schema.Set).List() 102 if len(associatedRoutersRaw) > 0 { 103 log.Printf("[DEBUG] Will attempt to associate Firewall with router(s): %+v", associatedRoutersRaw) 104 105 var routerIds []string 106 for _, v := range associatedRoutersRaw { 107 routerIds = append(routerIds, v.(string)) 108 } 109 110 createOpts = &routerinsertion.CreateOptsExt{ 111 CreateOptsBuilder: createOpts, 112 RouterIDs: routerIds, 113 } 114 } 115 116 if d.Get("no_routers").(bool) { 117 routerIds := make([]string, 0) 118 log.Println("[DEBUG] No routers specified. Setting to empty slice") 119 createOpts = &routerinsertion.CreateOptsExt{ 120 CreateOptsBuilder: createOpts, 121 RouterIDs: routerIds, 122 } 123 } 124 125 createOpts = &FirewallCreateOpts{ 126 createOpts, 127 MapValueSpecs(d), 128 } 129 130 log.Printf("[DEBUG] Create firewall: %#v", createOpts) 131 132 firewall, err := firewalls.Create(networkingClient, createOpts).Extract() 133 if err != nil { 134 return err 135 } 136 137 log.Printf("[DEBUG] Firewall created: %#v", firewall) 138 139 stateConf := &resource.StateChangeConf{ 140 Pending: []string{"PENDING_CREATE"}, 141 Target: []string{"ACTIVE"}, 142 Refresh: waitForFirewallActive(networkingClient, firewall.ID), 143 Timeout: d.Timeout(schema.TimeoutCreate), 144 Delay: 0, 145 MinTimeout: 2 * time.Second, 146 } 147 148 _, err = stateConf.WaitForState() 149 log.Printf("[DEBUG] Firewall (%s) is active.", firewall.ID) 150 151 d.SetId(firewall.ID) 152 153 return resourceFWFirewallV1Read(d, meta) 154 } 155 156 func resourceFWFirewallV1Read(d *schema.ResourceData, meta interface{}) error { 157 log.Printf("[DEBUG] Retrieve information about firewall: %s", d.Id()) 158 159 config := meta.(*Config) 160 networkingClient, err := config.networkingV2Client(GetRegion(d)) 161 if err != nil { 162 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 163 } 164 165 var firewall Firewall 166 err = firewalls.Get(networkingClient, d.Id()).ExtractInto(&firewall) 167 if err != nil { 168 return CheckDeleted(d, err, "firewall") 169 } 170 171 log.Printf("[DEBUG] Read OpenStack Firewall %s: %#v", d.Id(), firewall) 172 173 d.Set("name", firewall.Name) 174 d.Set("description", firewall.Description) 175 d.Set("policy_id", firewall.PolicyID) 176 d.Set("admin_state_up", firewall.AdminStateUp) 177 d.Set("tenant_id", firewall.TenantID) 178 d.Set("region", GetRegion(d)) 179 d.Set("associated_routers", firewall.RouterIDs) 180 181 return nil 182 } 183 184 func resourceFWFirewallV1Update(d *schema.ResourceData, meta interface{}) error { 185 186 config := meta.(*Config) 187 networkingClient, err := config.networkingV2Client(GetRegion(d)) 188 if err != nil { 189 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 190 } 191 192 // PolicyID is required 193 opts := firewalls.UpdateOpts{ 194 PolicyID: d.Get("policy_id").(string), 195 } 196 197 if d.HasChange("name") { 198 opts.Name = d.Get("name").(string) 199 } 200 201 if d.HasChange("description") { 202 opts.Description = d.Get("description").(string) 203 } 204 205 if d.HasChange("admin_state_up") { 206 adminStateUp := d.Get("admin_state_up").(bool) 207 opts.AdminStateUp = &adminStateUp 208 } 209 210 var updateOpts firewalls.UpdateOptsBuilder 211 var routerIds []string 212 if d.HasChange("associated_routers") || d.HasChange("no_routers") { 213 // 'no_routers' = true means 'associated_routers' will be empty... 214 if d.Get("no_routers").(bool) { 215 log.Printf("[DEBUG] 'no_routers' is true.") 216 routerIds = make([]string, 0) 217 } else { 218 associatedRoutersRaw := d.Get("associated_routers").(*schema.Set).List() 219 for _, v := range associatedRoutersRaw { 220 routerIds = append(routerIds, v.(string)) 221 } 222 } 223 224 updateOpts = routerinsertion.UpdateOptsExt{ 225 UpdateOptsBuilder: opts, 226 RouterIDs: routerIds, 227 } 228 } else { 229 updateOpts = opts 230 } 231 232 log.Printf("[DEBUG] Updating firewall with id %s: %#v", d.Id(), updateOpts) 233 234 err = firewalls.Update(networkingClient, d.Id(), updateOpts).Err 235 if err != nil { 236 return err 237 } 238 239 stateConf := &resource.StateChangeConf{ 240 Pending: []string{"PENDING_CREATE", "PENDING_UPDATE"}, 241 Target: []string{"ACTIVE"}, 242 Refresh: waitForFirewallActive(networkingClient, d.Id()), 243 Timeout: d.Timeout(schema.TimeoutUpdate), 244 Delay: 0, 245 MinTimeout: 2 * time.Second, 246 } 247 248 _, err = stateConf.WaitForState() 249 250 return resourceFWFirewallV1Read(d, meta) 251 } 252 253 func resourceFWFirewallV1Delete(d *schema.ResourceData, meta interface{}) error { 254 log.Printf("[DEBUG] Destroy firewall: %s", d.Id()) 255 256 config := meta.(*Config) 257 networkingClient, err := config.networkingV2Client(GetRegion(d)) 258 if err != nil { 259 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 260 } 261 262 // Ensure the firewall was fully created/updated before being deleted. 263 stateConf := &resource.StateChangeConf{ 264 Pending: []string{"PENDING_CREATE", "PENDING_UPDATE"}, 265 Target: []string{"ACTIVE"}, 266 Refresh: waitForFirewallActive(networkingClient, d.Id()), 267 Timeout: d.Timeout(schema.TimeoutUpdate), 268 Delay: 0, 269 MinTimeout: 2 * time.Second, 270 } 271 272 _, err = stateConf.WaitForState() 273 274 err = firewalls.Delete(networkingClient, d.Id()).Err 275 276 if err != nil { 277 return err 278 } 279 280 stateConf = &resource.StateChangeConf{ 281 Pending: []string{"DELETING"}, 282 Target: []string{"DELETED"}, 283 Refresh: waitForFirewallDeletion(networkingClient, d.Id()), 284 Timeout: d.Timeout(schema.TimeoutDelete), 285 Delay: 0, 286 MinTimeout: 2 * time.Second, 287 } 288 289 _, err = stateConf.WaitForState() 290 291 return err 292 } 293 294 func waitForFirewallActive(networkingClient *gophercloud.ServiceClient, id string) resource.StateRefreshFunc { 295 296 return func() (interface{}, string, error) { 297 var fw Firewall 298 299 err := firewalls.Get(networkingClient, id).ExtractInto(&fw) 300 if err != nil { 301 return nil, "", err 302 } 303 return fw, fw.Status, nil 304 } 305 } 306 307 func waitForFirewallDeletion(networkingClient *gophercloud.ServiceClient, id string) resource.StateRefreshFunc { 308 309 return func() (interface{}, string, error) { 310 fw, err := firewalls.Get(networkingClient, id).Extract() 311 log.Printf("[DEBUG] Got firewall %s => %#v", id, fw) 312 313 if err != nil { 314 if _, ok := err.(gophercloud.ErrDefault404); ok { 315 log.Printf("[DEBUG] Firewall %s is actually deleted", id) 316 return "", "DELETED", nil 317 } 318 return nil, "", fmt.Errorf("Unexpected error: %s", err) 319 } 320 321 log.Printf("[DEBUG] Firewall %s deletion is pending", id) 322 return fw, "DELETING", nil 323 } 324 }