From 1da7fda417d1d053fc6c0f1b52324a49857027c8 Mon Sep 17 00:00:00 2001 From: Gavin Williams Date: Thu, 1 Jun 2017 06:19:59 +0100 Subject: [PATCH] provider/openstack: Add support for FWaaS routerinsertion extension (#12589) * vendor: Add gophercloud/routerinsertion package and update gophercloud/firewall to support router insertion * provider/openstack: Add support for associating `openstack_fw_firewall_v1` resources with router(s). Added `associated_routers` and `no_routers` arguments. * website: Add documentation for `associated_routers`and `no_routers` arguments on `openstack_fw_firewall_v1` resource. * provider/openstack: Add `AddValueSpecs` function and refactor existing uses. --- .../resource_openstack_fw_firewall_v1.go | 116 +++++++--- .../resource_openstack_fw_firewall_v1_test.go | 215 +++++++++++++++++- builtin/providers/openstack/types.go | 25 +- builtin/providers/openstack/util.go | 20 +- .../v2/extensions/fwaas/firewalls/results.go | 22 +- .../extensions/fwaas/routerinsertion/doc.go | 2 + .../fwaas/routerinsertion/requests.go | 43 ++++ .../fwaas/routerinsertion/results.go | 7 + vendor/vendor.json | 12 +- .../openstack/r/fw_firewall_v1.html.markdown | 10 + 10 files changed, 422 insertions(+), 50 deletions(-) create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion/doc.go create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion/requests.go create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion/results.go diff --git a/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go b/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go index 7fb5055eea..66601b9988 100644 --- a/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go +++ b/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go @@ -7,6 +7,7 @@ import ( "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" ) @@ -57,6 +58,18 @@ func resourceFWFirewallV1() *schema.Resource { ForceNew: true, Computed: true, }, + "associated_routers": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + ConflictsWith: []string{"no_routers"}, + }, + "no_routers": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"associated_routers"}, + }, "value_specs": &schema.Schema{ Type: schema.TypeMap, Optional: true, @@ -74,22 +87,49 @@ func resourceFWFirewallV1Create(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("Error creating OpenStack networking client: %s", err) } - adminStateUp := d.Get("admin_state_up").(bool) + var createOpts firewalls.CreateOptsBuilder - firewallConfiguration := FirewallCreateOpts{ - firewalls.CreateOpts{ - Name: d.Get("name").(string), - Description: d.Get("description").(string), - PolicyID: d.Get("policy_id").(string), - AdminStateUp: &adminStateUp, - TenantID: d.Get("tenant_id").(string), - }, + adminStateUp := d.Get("admin_state_up").(bool) + createOpts = &firewalls.CreateOpts{ + Name: d.Get("name").(string), + Description: d.Get("description").(string), + PolicyID: d.Get("policy_id").(string), + AdminStateUp: &adminStateUp, + TenantID: d.Get("tenant_id").(string), + } + + associatedRoutersRaw := d.Get("associated_routers").(*schema.Set).List() + if len(associatedRoutersRaw) > 0 { + log.Printf("[DEBUG] Will attempt to associate Firewall with router(s): %+v", associatedRoutersRaw) + + var routerIds []string + for _, v := range associatedRoutersRaw { + routerIds = append(routerIds, v.(string)) + } + + createOpts = &routerinsertion.CreateOptsExt{ + CreateOptsBuilder: createOpts, + RouterIDs: routerIds, + } + } + + if d.Get("no_routers").(bool) { + routerIds := make([]string, 0) + log.Println("[DEBUG] No routers specified. Setting to empty slice") + createOpts = &routerinsertion.CreateOptsExt{ + CreateOptsBuilder: createOpts, + RouterIDs: routerIds, + } + } + + createOpts = &FirewallCreateOpts{ + createOpts, MapValueSpecs(d), } - log.Printf("[DEBUG] Create firewall: %#v", firewallConfiguration) + log.Printf("[DEBUG] Create firewall: %#v", createOpts) - firewall, err := firewalls.Create(networkingClient, firewallConfiguration).Extract() + firewall, err := firewalls.Create(networkingClient, createOpts).Extract() if err != nil { return err } @@ -106,6 +146,7 @@ func resourceFWFirewallV1Create(d *schema.ResourceData, meta interface{}) error } _, err = stateConf.WaitForState() + log.Printf("[DEBUG] Firewall (%s) is active.", firewall.ID) d.SetId(firewall.ID) @@ -121,7 +162,8 @@ func resourceFWFirewallV1Read(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } - firewall, err := firewalls.Get(networkingClient, d.Id()).Extract() + var firewall Firewall + err = firewalls.Get(networkingClient, d.Id()).ExtractInto(&firewall) if err != nil { return CheckDeleted(d, err, "firewall") } @@ -134,6 +176,7 @@ func resourceFWFirewallV1Read(d *schema.ResourceData, meta interface{}) error { d.Set("admin_state_up", firewall.AdminStateUp) d.Set("tenant_id", firewall.TenantID) d.Set("region", GetRegion(d)) + d.Set("associated_routers", firewall.RouterIDs) return nil } @@ -146,7 +189,10 @@ func resourceFWFirewallV1Update(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("Error creating OpenStack networking client: %s", err) } - opts := firewalls.UpdateOpts{} + // PolicyID is required + opts := firewalls.UpdateOpts{ + PolicyID: d.Get("policy_id").(string), + } if d.HasChange("name") { opts.Name = d.Get("name").(string) @@ -156,16 +202,39 @@ func resourceFWFirewallV1Update(d *schema.ResourceData, meta interface{}) error opts.Description = d.Get("description").(string) } - if d.HasChange("policy_id") { - opts.PolicyID = d.Get("policy_id").(string) - } - if d.HasChange("admin_state_up") { adminStateUp := d.Get("admin_state_up").(bool) opts.AdminStateUp = &adminStateUp } - log.Printf("[DEBUG] Updating firewall with id %s: %#v", d.Id(), opts) + var updateOpts firewalls.UpdateOptsBuilder + var routerIds []string + if d.HasChange("associated_routers") || d.HasChange("no_routers") { + // 'no_routers' = true means 'associated_routers' will be empty... + if d.Get("no_routers").(bool) { + log.Printf("[DEBUG] 'no_routers' is true.") + routerIds = make([]string, 0) + } else { + associatedRoutersRaw := d.Get("associated_routers").(*schema.Set).List() + for _, v := range associatedRoutersRaw { + routerIds = append(routerIds, v.(string)) + } + } + + updateOpts = routerinsertion.UpdateOptsExt{ + UpdateOptsBuilder: opts, + RouterIDs: routerIds, + } + } else { + updateOpts = opts + } + + log.Printf("[DEBUG] Updating firewall with id %s: %#v", d.Id(), updateOpts) + + err = firewalls.Update(networkingClient, d.Id(), updateOpts).Err + if err != nil { + return err + } stateConf := &resource.StateChangeConf{ Pending: []string{"PENDING_CREATE", "PENDING_UPDATE"}, @@ -178,11 +247,6 @@ func resourceFWFirewallV1Update(d *schema.ResourceData, meta interface{}) error _, err = stateConf.WaitForState() - err = firewalls.Update(networkingClient, d.Id(), opts).Err - if err != nil { - return err - } - return resourceFWFirewallV1Read(d, meta) } @@ -230,9 +294,9 @@ func resourceFWFirewallV1Delete(d *schema.ResourceData, meta interface{}) error func waitForFirewallActive(networkingClient *gophercloud.ServiceClient, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - fw, err := firewalls.Get(networkingClient, id).Extract() - log.Printf("[DEBUG] Get firewall %s => %#v", id, fw) + var fw Firewall + err := firewalls.Get(networkingClient, id).ExtractInto(&fw) if err != nil { return nil, "", err } @@ -244,7 +308,7 @@ func waitForFirewallDeletion(networkingClient *gophercloud.ServiceClient, id str return func() (interface{}, string, error) { fw, err := firewalls.Get(networkingClient, id).Extract() - log.Printf("[DEBUG] Get firewall %s => %#v", id, fw) + log.Printf("[DEBUG] Got firewall %s => %#v", id, fw) if err != nil { if _, ok := err.(gophercloud.ErrDefault404); ok { diff --git a/builtin/providers/openstack/resource_openstack_fw_firewall_v1_test.go b/builtin/providers/openstack/resource_openstack_fw_firewall_v1_test.go index c476a77b75..f3d41aa016 100644 --- a/builtin/providers/openstack/resource_openstack_fw_firewall_v1_test.go +++ b/builtin/providers/openstack/resource_openstack_fw_firewall_v1_test.go @@ -22,13 +22,13 @@ func TestAccFWFirewallV1_basic(t *testing.T) { resource.TestStep{ Config: testAccFWFirewallV1_basic_1, Check: resource.ComposeTestCheckFunc( - testAccCheckFWFirewallV1Exists("openstack_fw_firewall_v1.fw_1", "", "", policyID), + testAccCheckFWFirewallV1("openstack_fw_firewall_v1.fw_1", "", "", policyID), ), }, resource.TestStep{ Config: testAccFWFirewallV1_basic_2, Check: resource.ComposeTestCheckFunc( - testAccCheckFWFirewallV1Exists( + testAccCheckFWFirewallV1( "openstack_fw_firewall_v1.fw_1", "fw_1", "terraform acceptance test", policyID), ), }, @@ -47,7 +47,98 @@ func TestAccFWFirewallV1_timeout(t *testing.T) { resource.TestStep{ Config: testAccFWFirewallV1_timeout, Check: resource.ComposeTestCheckFunc( - testAccCheckFWFirewallV1Exists("openstack_fw_firewall_v1.fw_1", "", "", policyID), + testAccCheckFWFirewallV1("openstack_fw_firewall_v1.fw_1", "", "", policyID), + ), + }, + }, + }) +} + +func TestAccFWFirewallV1_router(t *testing.T) { + var firewall Firewall + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckFWFirewallV1Destroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccFWFirewallV1_router, + Check: resource.ComposeTestCheckFunc( + testAccCheckFWFirewallV1Exists("openstack_fw_firewall_v1.fw_1", &firewall), + testAccCheckFWFirewallRouterCount(&firewall, 1), + ), + }, + }, + }) +} + +func TestAccFWFirewallV1_no_router(t *testing.T) { + var firewall Firewall + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckFWFirewallV1Destroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccFWFirewallV1_no_router, + Check: resource.ComposeTestCheckFunc( + testAccCheckFWFirewallV1Exists("openstack_fw_firewall_v1.fw_1", &firewall), + resource.TestCheckResourceAttr("openstack_fw_firewall_v1.fw_1", "description", "firewall router test"), + testAccCheckFWFirewallRouterCount(&firewall, 0), + ), + }, + }, + }) +} + +func TestAccFWFirewallV1_router_update(t *testing.T) { + var firewall Firewall + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckFWFirewallV1Destroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccFWFirewallV1_router, + Check: resource.ComposeTestCheckFunc( + testAccCheckFWFirewallV1Exists("openstack_fw_firewall_v1.fw_1", &firewall), + testAccCheckFWFirewallRouterCount(&firewall, 1), + ), + }, + resource.TestStep{ + Config: testAccFWFirewallV1_router_add, + Check: resource.ComposeTestCheckFunc( + testAccCheckFWFirewallV1Exists("openstack_fw_firewall_v1.fw_1", &firewall), + testAccCheckFWFirewallRouterCount(&firewall, 2), + ), + }, + }, + }) +} + +func TestAccFWFirewallV1_router_remove(t *testing.T) { + var firewall Firewall + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckFWFirewallV1Destroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccFWFirewallV1_router, + Check: resource.ComposeTestCheckFunc( + testAccCheckFWFirewallV1Exists("openstack_fw_firewall_v1.fw_1", &firewall), + testAccCheckFWFirewallRouterCount(&firewall, 1), + ), + }, + resource.TestStep{ + Config: testAccFWFirewallV1_router_remove, + Check: resource.ComposeTestCheckFunc( + testAccCheckFWFirewallV1Exists("openstack_fw_firewall_v1.fw_1", &firewall), + testAccCheckFWFirewallRouterCount(&firewall, 0), ), }, }, @@ -76,7 +167,50 @@ func testAccCheckFWFirewallV1Destroy(s *terraform.State) error { return nil } -func testAccCheckFWFirewallV1Exists(n, expectedName, expectedDescription string, policyID *string) resource.TestCheckFunc { +func testAccCheckFWFirewallV1Exists(n string, firewall *Firewall) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("Exists) Error creating OpenStack networking client: %s", err) + } + + var found Firewall + err = firewalls.Get(networkingClient, rs.Primary.ID).ExtractInto(&found) + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("Firewall not found") + } + + *firewall = found + + return nil + } +} + +func testAccCheckFWFirewallRouterCount(firewall *Firewall, expected int) resource.TestCheckFunc { + return func(s *terraform.State) error { + if len(firewall.RouterIDs) != expected { + return fmt.Errorf("Expected %d Routers, got %d", expected, len(firewall.RouterIDs)) + } + + return nil + } +} + +func testAccCheckFWFirewallV1(n, expectedName, expectedDescription string, policyID *string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -169,3 +303,76 @@ resource "openstack_fw_policy_v1" "policy_1" { name = "policy_1" } ` + +const testAccFWFirewallV1_router = ` +resource "openstack_networking_router_v2" "router_1" { + name = "router_1" + admin_state_up = "true" + distributed = "false" +} + +resource "openstack_fw_policy_v1" "policy_1" { + name = "policy_1" +} + +resource "openstack_fw_firewall_v1" "fw_1" { + name = "firewall_1" + description = "firewall router test" + policy_id = "${openstack_fw_policy_v1.policy_1.id}" + associated_routers = ["${openstack_networking_router_v2.router_1.id}"] +} +` + +const testAccFWFirewallV1_router_add = ` +resource "openstack_networking_router_v2" "router_1" { + name = "router_1" + admin_state_up = "true" + distributed = "false" +} + +resource "openstack_networking_router_v2" "router_2" { + name = "router_2" + admin_state_up = "true" + distributed = "false" +} + +resource "openstack_fw_policy_v1" "policy_1" { + name = "policy_1" +} + +resource "openstack_fw_firewall_v1" "fw_1" { + name = "firewall_1" + description = "firewall router test" + policy_id = "${openstack_fw_policy_v1.policy_1.id}" + associated_routers = [ + "${openstack_networking_router_v2.router_1.id}", + "${openstack_networking_router_v2.router_2.id}" + ] +} +` + +const testAccFWFirewallV1_router_remove = ` +resource "openstack_fw_policy_v1" "policy_1" { + name = "policy_1" +} + +resource "openstack_fw_firewall_v1" "fw_1" { + name = "firewall_1" + description = "firewall router test" + policy_id = "${openstack_fw_policy_v1.policy_1.id}" + no_routers = true +} +` + +const testAccFWFirewallV1_no_router = ` +resource "openstack_fw_policy_v1" "policy_1" { + name = "policy_1" +} + +resource "openstack_fw_firewall_v1" "fw_1" { + name = "firewall_1" + description = "firewall router test" + policy_id = "${openstack_fw_policy_v1.policy_1.id}" + no_routers = true +} +` diff --git a/builtin/providers/openstack/types.go b/builtin/providers/openstack/types.go index a4f4cd69a6..28565ffa4f 100644 --- a/builtin/providers/openstack/types.go +++ b/builtin/providers/openstack/types.go @@ -17,6 +17,7 @@ import ( "github.com/gophercloud/gophercloud/openstack/dns/v2/zones" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/policies" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers" @@ -163,15 +164,35 @@ func (lrt *LogRoundTripper) formatJSON(raw []byte) string { return string(pretty) } +// Firewall is an OpenStack firewall. +type Firewall struct { + firewalls.Firewall + routerinsertion.FirewallExt +} + // FirewallCreateOpts represents the attributes used when creating a new firewall. type FirewallCreateOpts struct { - firewalls.CreateOpts + firewalls.CreateOptsBuilder ValueSpecs map[string]string `json:"value_specs,omitempty"` } -// ToFirewallCreateMap casts a CreateOpts struct to a map. +// ToFirewallCreateMap casts a CreateOptsExt struct to a map. // It overrides firewalls.ToFirewallCreateMap to add the ValueSpecs field. func (opts FirewallCreateOpts) ToFirewallCreateMap() (map[string]interface{}, error) { + body, err := opts.CreateOptsBuilder.ToFirewallCreateMap() + if err != nil { + return nil, err + } + + return AddValueSpecs(body), nil +} + +//FirewallUpdateOpts +type FirewallUpdateOpts struct { + firewalls.UpdateOptsBuilder +} + +func (opts FirewallUpdateOpts) ToFirewallUpdateMap() (map[string]interface{}, error) { return BuildRequest(opts, "firewall") } diff --git a/builtin/providers/openstack/util.go b/builtin/providers/openstack/util.go index eb5ccdf090..5d27509665 100644 --- a/builtin/providers/openstack/util.go +++ b/builtin/providers/openstack/util.go @@ -18,12 +18,7 @@ func BuildRequest(opts interface{}, parent string) (map[string]interface{}, erro return nil, err } - if b["value_specs"] != nil { - for k, v := range b["value_specs"].(map[string]interface{}) { - b[k] = v - } - delete(b, "value_specs") - } + b = AddValueSpecs(b) return map[string]interface{}{parent: b}, nil } @@ -52,6 +47,19 @@ func GetRegion(d *schema.ResourceData) string { return "" } +// AddValueSpecs expands the 'value_specs' object and removes 'value_specs' +// from the reqeust body. +func AddValueSpecs(body map[string]interface{}) map[string]interface{} { + if body["value_specs"] != nil { + for k, v := range body["value_specs"].(map[string]interface{}) { + body[k] = v + } + delete(body, "value_specs") + } + + return body +} + // MapValueSpecs converts ResourceData into a map func MapValueSpecs(d *schema.ResourceData) map[string]string { m := make(map[string]string) diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls/results.go index ab6cf8e141..1403ced2ba 100644 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls/results.go +++ b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls/results.go @@ -22,11 +22,17 @@ type commonResult struct { // Extract is a function that accepts a result and extracts a firewall. func (r commonResult) Extract() (*Firewall, error) { - var s struct { - Firewall *Firewall `json:"firewall"` - } + var s Firewall err := r.ExtractInto(&s) - return s.Firewall, err + return &s, err +} + +func (r commonResult) ExtractInto(v interface{}) error { + return r.Result.ExtractIntoStructPtr(v, "firewall") +} + +func ExtractFirewallsInto(r pagination.Page, v interface{}) error { + return r.(FirewallPage).Result.ExtractIntoSlicePtr(v, "firewalls") } // FirewallPage is the page returned by a pager when traversing over a @@ -59,11 +65,9 @@ func (r FirewallPage) IsEmpty() (bool, error) { // and extracts the elements into a slice of Router structs. In other words, // a generic collection is mapped into a relevant slice. func ExtractFirewalls(r pagination.Page) ([]Firewall, error) { - var s struct { - Firewalls []Firewall `json:"firewalls" json:"firewalls"` - } - err := (r.(FirewallPage)).ExtractInto(&s) - return s.Firewalls, err + var s []Firewall + err := ExtractFirewallsInto(r, &s) + return s, err } // GetResult represents the result of a get operation. diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion/doc.go new file mode 100644 index 0000000000..9b847e2f5e --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion/doc.go @@ -0,0 +1,2 @@ +// Package routerinsertion implements the fwaasrouterinsertion FWaaS extension. +package routerinsertion diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion/requests.go new file mode 100644 index 0000000000..fce100f87e --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion/requests.go @@ -0,0 +1,43 @@ +package routerinsertion + +import ( + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls" +) + +// CreateOptsExt adds a RouterIDs option to the base CreateOpts. +type CreateOptsExt struct { + firewalls.CreateOptsBuilder + RouterIDs []string `json:"router_ids"` +} + +// ToFirewallCreateMap adds router_ids to the base firewall creation options. +func (opts CreateOptsExt) ToFirewallCreateMap() (map[string]interface{}, error) { + base, err := opts.CreateOptsBuilder.ToFirewallCreateMap() + if err != nil { + return nil, err + } + + firewallMap := base["firewall"].(map[string]interface{}) + firewallMap["router_ids"] = opts.RouterIDs + + return base, nil +} + +// UpdateOptsExt updates a RouterIDs option to the base UpdateOpts. +type UpdateOptsExt struct { + firewalls.UpdateOptsBuilder + RouterIDs []string `json:"router_ids"` +} + +// ToFirewallUpdateMap adds router_ids to the base firewall update options. +func (opts UpdateOptsExt) ToFirewallUpdateMap() (map[string]interface{}, error) { + base, err := opts.UpdateOptsBuilder.ToFirewallUpdateMap() + if err != nil { + return nil, err + } + + firewallMap := base["firewall"].(map[string]interface{}) + firewallMap["router_ids"] = opts.RouterIDs + + return base, nil +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion/results.go new file mode 100644 index 0000000000..85c288e51e --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion/results.go @@ -0,0 +1,7 @@ +package routerinsertion + +// FirewallExt is an extension to the base Firewall object +type FirewallExt struct { + // RouterIDs are the routers that the firewall is attached to. + RouterIDs []string `json:"router_ids"` +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 9c501fd8eb..2aafd3f8b2 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -1799,10 +1799,10 @@ "revisionTime": "2017-03-10T01:59:53Z" }, { - "checksumSHA1": "aTHxjMlfNXFJ3l2TZyvIwqt/3kM=", + "checksumSHA1": "YqqqrMdOCKY2xwFkwxskkx8XtTQ=", "path": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls", - "revision": "0f64da0e36de86a0ca1a8f2fc1b0570a0d3f7504", - "revisionTime": "2017-03-10T01:59:53Z" + "revision": "3027adb1ce72bc52b87b2decccc7852574b90031", + "revisionTime": "2017-05-24T13:09:59Z" }, { "checksumSHA1": "14ZhP0wE/WCL/6oujcML755AaH4=", @@ -1810,6 +1810,12 @@ "revision": "0f64da0e36de86a0ca1a8f2fc1b0570a0d3f7504", "revisionTime": "2017-03-10T01:59:53Z" }, + { + "checksumSHA1": "nHGhVRP69paJsebTRp4Q1cfQtag=", + "path": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion", + "revision": "3027adb1ce72bc52b87b2decccc7852574b90031", + "revisionTime": "2017-05-24T13:09:59Z" + }, { "checksumSHA1": "sYET5A7WTyJ7dpuxR/VXYoReldw=", "path": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules", diff --git a/website/source/docs/providers/openstack/r/fw_firewall_v1.html.markdown b/website/source/docs/providers/openstack/r/fw_firewall_v1.html.markdown index 9df57dc087..0cd99be02f 100644 --- a/website/source/docs/providers/openstack/r/fw_firewall_v1.html.markdown +++ b/website/source/docs/providers/openstack/r/fw_firewall_v1.html.markdown @@ -71,6 +71,14 @@ The following arguments are supported: to create a firewall for another tenant. Changing this creates a new firewall. +* `associated_routers` - (Optional) Router(s) to associate this firewall instance + with. Must be a list of strings. Changing this updates the associated routers + of an existing firewall. Conflicts with `no_routers`. + +* `no_routers` - (Optional) Should this firewall not be associated with any routers + (must be "true" or "false" if provide - defaults to "false"). + Conflicts with `associated_routers`. + * `value_specs` - (Optional) Map of additional options. ## Attributes Reference @@ -83,6 +91,8 @@ The following attributes are exported: * `description` - See Argument Reference above. * `admin_state_up` - See Argument Reference above. * `tenant_id` - See Argument Reference above. +* `associated_routers` - See Argument Reference above. +* `no_routers` - See Argument Reference above. ## Import