From db47721e158050079452c71744d68a635f3d451d Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Thu, 25 May 2017 00:53:26 -0600 Subject: [PATCH] provider/openstack: Enable Security Group Updates (#14815) * vendor: Updating Gophercloud for OpenStack Provider * provider/openstack: Enable Security Group Updates This commit enables security group names and descriptions to be updated without causing a recreate. --- ...ource_openstack_networking_port_v2_test.go | 42 +++++++++++++++++++ ...source_openstack_networking_secgroup_v2.go | 34 ++++++++++++++- ...e_openstack_networking_secgroup_v2_test.go | 2 + .../v2/extensions/security/groups/requests.go | 34 ++++++++++++++- .../v2/extensions/security/groups/results.go | 5 +++ vendor/vendor.json | 10 ++--- .../r/networking_secgroup_v2.html.markdown | 6 +-- 7 files changed, 120 insertions(+), 13 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_networking_port_v2_test.go b/builtin/providers/openstack/resource_openstack_networking_port_v2_test.go index a9d7281af..4a47cd0fd 100644 --- a/builtin/providers/openstack/resource_openstack_networking_port_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_networking_port_v2_test.go @@ -204,6 +204,17 @@ func TestAccNetworkingV2Port_updateSecurityGroups(t *testing.T) { }, resource.TestStep{ Config: testAccNetworkingV2Port_updateSecurityGroups_3, + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkingV2SubnetExists("openstack_networking_subnet_v2.subnet_1", &subnet), + testAccCheckNetworkingV2NetworkExists("openstack_networking_network_v2.network_1", &network), + testAccCheckNetworkingV2PortExists("openstack_networking_port_v2.port_1", &port), + testAccCheckNetworkingV2SecGroupExists( + "openstack_networking_secgroup_v2.secgroup_1", &security_group), + testAccCheckNetworkingV2PortCountSecurityGroups(&port, 1), + ), + }, + resource.TestStep{ + Config: testAccNetworkingV2Port_updateSecurityGroups_4, Check: resource.ComposeTestCheckFunc( testAccCheckNetworkingV2SubnetExists("openstack_networking_subnet_v2.subnet_1", &subnet), testAccCheckNetworkingV2NetworkExists("openstack_networking_network_v2.network_1", &network), @@ -606,6 +617,37 @@ resource "openstack_networking_subnet_v2" "subnet_1" { network_id = "${openstack_networking_network_v2.network_1.id}" } +resource "openstack_networking_secgroup_v2" "secgroup_1" { + name = "security_group_1" + description = "terraform security group acceptance test" +} + +resource "openstack_networking_port_v2" "port_1" { + name = "port_1" + admin_state_up = "true" + network_id = "${openstack_networking_network_v2.network_1.id}" + security_group_ids = ["${openstack_networking_secgroup_v2.secgroup_1.id}"] + + fixed_ip { + subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}" + ip_address = "192.168.199.23" + } +} +` + +const testAccNetworkingV2Port_updateSecurityGroups_4 = ` +resource "openstack_networking_network_v2" "network_1" { + name = "network_1" + admin_state_up = "true" +} + +resource "openstack_networking_subnet_v2" "subnet_1" { + name = "subnet_1" + cidr = "192.168.199.0/24" + ip_version = 4 + network_id = "${openstack_networking_network_v2.network_1.id}" +} + resource "openstack_networking_secgroup_v2" "secgroup_1" { name = "security_group" description = "terraform security group acceptance test" diff --git a/builtin/providers/openstack/resource_openstack_networking_secgroup_v2.go b/builtin/providers/openstack/resource_openstack_networking_secgroup_v2.go index 8dad6fad8..effe0e746 100644 --- a/builtin/providers/openstack/resource_openstack_networking_secgroup_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_secgroup_v2.go @@ -17,6 +17,7 @@ func resourceNetworkingSecGroupV2() *schema.Resource { return &schema.Resource{ Create: resourceNetworkingSecGroupV2Create, Read: resourceNetworkingSecGroupV2Read, + Update: resourceNetworkingSecGroupV2Update, Delete: resourceNetworkingSecGroupV2Delete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, @@ -36,12 +37,10 @@ func resourceNetworkingSecGroupV2() *schema.Resource { "name": &schema.Schema{ Type: schema.TypeString, Required: true, - ForceNew: true, }, "description": &schema.Schema{ Type: schema.TypeString, Optional: true, - ForceNew: true, Computed: true, }, "tenant_id": &schema.Schema{ @@ -121,6 +120,37 @@ func resourceNetworkingSecGroupV2Read(d *schema.ResourceData, meta interface{}) return nil } +func resourceNetworkingSecGroupV2Update(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(GetRegion(d)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + var update bool + var updateOpts groups.UpdateOpts + + if d.HasChange("name") { + update = true + updateOpts.Name = d.Get("name").(string) + } + + if d.HasChange("description") { + update = true + updateOpts.Name = d.Get("description").(string) + } + + if update { + log.Printf("[DEBUG] Updating SecGroup %s with options: %#v", d.Id(), updateOpts) + _, err = groups.Update(networkingClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack SecGroup: %s", err) + } + } + + return resourceNetworkingSecGroupV2Read(d, meta) +} + func resourceNetworkingSecGroupV2Delete(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Destroy security group: %s", d.Id()) diff --git a/builtin/providers/openstack/resource_openstack_networking_secgroup_v2_test.go b/builtin/providers/openstack/resource_openstack_networking_secgroup_v2_test.go index aa6e7fff8..09b77a197 100644 --- a/builtin/providers/openstack/resource_openstack_networking_secgroup_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_networking_secgroup_v2_test.go @@ -29,6 +29,8 @@ func TestAccNetworkingV2SecGroup_basic(t *testing.T) { resource.TestStep{ Config: testAccNetworkingV2SecGroup_update, Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPtr( + "openstack_networking_secgroup_v2.secgroup_1", "id", &security_group.ID), resource.TestCheckResourceAttr( "openstack_networking_secgroup_v2.secgroup_1", "name", "security_group_2"), ), diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/requests.go index 5ca485038..7e1f60812 100644 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/requests.go +++ b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/requests.go @@ -40,9 +40,9 @@ type CreateOptsBuilder interface { // CreateOpts contains all the values needed to create a new security group. type CreateOpts struct { - // Required. Human-readable name for the VIP. Does not have to be unique. + // Required. Human-readable name for the Security Group. Does not have to be unique. Name string `json:"name" required:"true"` - // Required for admins. Indicates the owner of the VIP. + // Required for admins. Indicates the owner of the Security Group. TenantID string `json:"tenant_id,omitempty"` // Optional. Describes the security group. Description string `json:"description,omitempty"` @@ -64,6 +64,36 @@ func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResul return } +type UpdateOptsBuilder interface { + ToSecGroupUpdateMap() (map[string]interface{}, error) +} + +// UpdateOpts contains all the values needed to update an existing security group. +type UpdateOpts struct { + // Human-readable name for the Security Group. Does not have to be unique. + Name string `json:"name,omitempty"` + // Optional. Describes the security group. + Description string `json:"description,omitempty"` +} + +func (opts UpdateOpts) ToSecGroupUpdateMap() (map[string]interface{}, error) { + return gophercloud.BuildRequestBody(opts, "security_group") +} + +// Update is an operation which updates an existing security group. +func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { + b, err := opts.ToSecGroupUpdateMap() + if err != nil { + r.Err = err + return + } + + _, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + // Get retrieves a particular security group based on its unique ID. func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { _, r.Err = c.Get(resourceURL(c, id), &r.Body, nil) diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/results.go index ea3ad65f2..d737abb06 100644 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/results.go +++ b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/results.go @@ -83,6 +83,11 @@ type CreateResult struct { commonResult } +// UpdateResult represents the result of an update operation. +type UpdateResult struct { + commonResult +} + // GetResult represents the result of a get operation. type GetResult struct { commonResult diff --git a/vendor/vendor.json b/vendor/vendor.json index 6f0791b98..1186706c5 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -1835,16 +1835,16 @@ "revisionTime": "2017-03-10T01:59:53Z" }, { - "checksumSHA1": "FKwSMrpQf7b3TcCOQfh+ovoBShA=", + "checksumSHA1": "qabBGU1tfT99h1YXyxO9nGxMghE=", "path": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups", - "revision": "0f64da0e36de86a0ca1a8f2fc1b0570a0d3f7504", - "revisionTime": "2017-03-10T01:59:53Z" + "revision": "3027adb1ce72bc52b87b2decccc7852574b90031", + "revisionTime": "2017-05-24T13:09:59Z" }, { "checksumSHA1": "E/5q7DTCoOD15K1KGFXSwFCGDE4=", "path": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules", - "revision": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11", - "revisionTime": "2017-05-08T02:10:49Z" + "revision": "3027adb1ce72bc52b87b2decccc7852574b90031", + "revisionTime": "2017-05-24T13:09:59Z" }, { "checksumSHA1": "zKOhFTL5BDZPMC58ZzZkryjskno=", diff --git a/website/source/docs/providers/openstack/r/networking_secgroup_v2.html.markdown b/website/source/docs/providers/openstack/r/networking_secgroup_v2.html.markdown index e3f2a30e5..7271c4c11 100644 --- a/website/source/docs/providers/openstack/r/networking_secgroup_v2.html.markdown +++ b/website/source/docs/providers/openstack/r/networking_secgroup_v2.html.markdown @@ -30,11 +30,9 @@ The following arguments are supported: `OS_REGION_NAME` environment variable is used. Changing this creates a new security group. -* `name` - (Required) A unique name for the security group. Changing this - creates a new security group. +* `name` - (Required) A unique name for the security group. -* `description` - (Optional) A unique name for the security group. Changing this - creates a new security group. +* `description` - (Optional) A unique name for the security group. * `tenant_id` - (Optional) The owner of the security group. Required if admin wants to create a port for another tenant. Changing this creates a new