provider/openstack: LoadBalancer Security Groups (#11074)

* provider/openstack: LoadBalancer Security Groups

This commit adds the ability to specify security groups on a loadbalancer
resource.

* provider/openstack: LoadBalancer Security Groups Refactor

Moving common security group code into a dedicated function.
This commit is contained in:
Joe Topjian 2017-01-12 07:00:32 -07:00 committed by Paul Stack
parent a0c2d3ceb2
commit 91147fe11c
3 changed files with 243 additions and 6 deletions

View File

@ -10,6 +10,7 @@ import (
"github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers"
"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
) )
func resourceLoadBalancerV2() *schema.Resource { func resourceLoadBalancerV2() *schema.Resource {
@ -80,6 +81,13 @@ func resourceLoadBalancerV2() *schema.Resource {
Computed: true, Computed: true,
ForceNew: true, ForceNew: true,
}, },
"security_group_ids": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
}, },
} }
} }
@ -126,6 +134,13 @@ func resourceLoadBalancerV2Create(d *schema.ResourceData, meta interface{}) erro
return err return err
} }
// Once the loadbalancer has been created, apply any requested security groups
// to the port that was created behind the scenes.
if err := resourceLoadBalancerV2SecurityGroups(networkingClient, lb.VipPortID, d); err != nil {
return err
}
// If all has been successful, set the ID on the resource
d.SetId(lb.ID) d.SetId(lb.ID)
return resourceLoadBalancerV2Read(d, meta) return resourceLoadBalancerV2Read(d, meta)
@ -155,6 +170,16 @@ func resourceLoadBalancerV2Read(d *schema.ResourceData, meta interface{}) error
d.Set("flavor", lb.Flavor) d.Set("flavor", lb.Flavor)
d.Set("provider", lb.Provider) d.Set("provider", lb.Provider)
// Get any security groups on the VIP Port
if lb.VipPortID != "" {
port, err := ports.Get(networkingClient, lb.VipPortID).Extract()
if err != nil {
return err
}
d.Set("security_group_ids", port.SecurityGroups)
}
return nil return nil
} }
@ -184,6 +209,14 @@ func resourceLoadBalancerV2Update(d *schema.ResourceData, meta interface{}) erro
return fmt.Errorf("Error updating OpenStack LBaaSV2 LoadBalancer: %s", err) return fmt.Errorf("Error updating OpenStack LBaaSV2 LoadBalancer: %s", err)
} }
// Security Groups get updated separately
if d.HasChange("security_group_ids") {
vipPortID := d.Get("vip_port_id").(string)
if err := resourceLoadBalancerV2SecurityGroups(networkingClient, vipPortID, d); err != nil {
return err
}
}
return resourceLoadBalancerV2Read(d, meta) return resourceLoadBalancerV2Read(d, meta)
} }
@ -212,6 +245,26 @@ func resourceLoadBalancerV2Delete(d *schema.ResourceData, meta interface{}) erro
return nil return nil
} }
func resourceLoadBalancerV2SecurityGroups(networkingClient *gophercloud.ServiceClient, vipPortID string, d *schema.ResourceData) error {
if vipPortID != "" {
if _, ok := d.GetOk("security_group_ids"); ok {
updateOpts := ports.UpdateOpts{
SecurityGroups: resourcePortSecurityGroupsV2(d),
}
log.Printf("[DEBUG] Adding security groups to OpenStack LoadBalancer "+
"VIP Port (%s): %#v", vipPortID, updateOpts)
_, err := ports.Update(networkingClient, vipPortID, updateOpts).Extract()
if err != nil {
return err
}
}
}
return nil
}
func waitForLoadBalancerActive(networkingClient *gophercloud.ServiceClient, lbID string) resource.StateRefreshFunc { func waitForLoadBalancerActive(networkingClient *gophercloud.ServiceClient, lbID string) resource.StateRefreshFunc {
return func() (interface{}, string, error) { return func() (interface{}, string, error) {
lb, err := loadbalancers.Get(networkingClient, lbID).Extract() lb, err := loadbalancers.Get(networkingClient, lbID).Extract()

View File

@ -5,9 +5,12 @@ import (
"regexp" "regexp"
"testing" "testing"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers"
"github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups"
"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
) )
func TestAccLBV2LoadBalancer_basic(t *testing.T) { func TestAccLBV2LoadBalancer_basic(t *testing.T) {
@ -19,13 +22,13 @@ func TestAccLBV2LoadBalancer_basic(t *testing.T) {
CheckDestroy: testAccCheckLBV2LoadBalancerDestroy, CheckDestroy: testAccCheckLBV2LoadBalancerDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ resource.TestStep{
Config: TestAccLBV2LoadBalancerConfig_basic, Config: testAccLBV2LoadBalancerConfig_basic,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckLBV2LoadBalancerExists("openstack_lb_loadbalancer_v2.loadbalancer_1", &lb), testAccCheckLBV2LoadBalancerExists("openstack_lb_loadbalancer_v2.loadbalancer_1", &lb),
), ),
}, },
resource.TestStep{ resource.TestStep{
Config: TestAccLBV2LoadBalancerConfig_update, Config: testAccLBV2LoadBalancerConfig_update,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr( resource.TestCheckResourceAttr(
"openstack_lb_loadbalancer_v2.loadbalancer_1", "name", "loadbalancer_1_updated"), "openstack_lb_loadbalancer_v2.loadbalancer_1", "name", "loadbalancer_1_updated"),
@ -38,6 +41,62 @@ func TestAccLBV2LoadBalancer_basic(t *testing.T) {
}) })
} }
func TestAccLBV2LoadBalancer_secGroup(t *testing.T) {
var lb loadbalancers.LoadBalancer
var sg_1, sg_2 groups.SecGroup
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLBV2LoadBalancerDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccLBV2LoadBalancer_secGroup,
Check: resource.ComposeTestCheckFunc(
testAccCheckLBV2LoadBalancerExists(
"openstack_lb_loadbalancer_v2.loadbalancer_1", &lb),
testAccCheckNetworkingV2SecGroupExists(
"openstack_networking_secgroup_v2.secgroup_1", &sg_1),
testAccCheckNetworkingV2SecGroupExists(
"openstack_networking_secgroup_v2.secgroup_1", &sg_2),
resource.TestCheckResourceAttr(
"openstack_lb_loadbalancer_v2.loadbalancer_1", "security_group_ids.#", "1"),
testAccCheckLBV2LoadBalancerHasSecGroup(&lb, &sg_1),
),
},
resource.TestStep{
Config: testAccLBV2LoadBalancer_secGroup_update1,
Check: resource.ComposeTestCheckFunc(
testAccCheckLBV2LoadBalancerExists(
"openstack_lb_loadbalancer_v2.loadbalancer_1", &lb),
testAccCheckNetworkingV2SecGroupExists(
"openstack_networking_secgroup_v2.secgroup_2", &sg_1),
testAccCheckNetworkingV2SecGroupExists(
"openstack_networking_secgroup_v2.secgroup_2", &sg_2),
resource.TestCheckResourceAttr(
"openstack_lb_loadbalancer_v2.loadbalancer_1", "security_group_ids.#", "2"),
testAccCheckLBV2LoadBalancerHasSecGroup(&lb, &sg_1),
testAccCheckLBV2LoadBalancerHasSecGroup(&lb, &sg_2),
),
},
resource.TestStep{
Config: testAccLBV2LoadBalancer_secGroup_update2,
Check: resource.ComposeTestCheckFunc(
testAccCheckLBV2LoadBalancerExists(
"openstack_lb_loadbalancer_v2.loadbalancer_1", &lb),
testAccCheckNetworkingV2SecGroupExists(
"openstack_networking_secgroup_v2.secgroup_2", &sg_1),
testAccCheckNetworkingV2SecGroupExists(
"openstack_networking_secgroup_v2.secgroup_2", &sg_2),
resource.TestCheckResourceAttr(
"openstack_lb_loadbalancer_v2.loadbalancer_1", "security_group_ids.#", "1"),
testAccCheckLBV2LoadBalancerHasSecGroup(&lb, &sg_2),
),
},
},
})
}
func testAccCheckLBV2LoadBalancerDestroy(s *terraform.State) error { func testAccCheckLBV2LoadBalancerDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config) config := testAccProvider.Meta().(*Config)
networkingClient, err := config.networkingV2Client(OS_REGION_NAME) networkingClient, err := config.networkingV2Client(OS_REGION_NAME)
@ -59,7 +118,8 @@ func testAccCheckLBV2LoadBalancerDestroy(s *terraform.State) error {
return nil return nil
} }
func testAccCheckLBV2LoadBalancerExists(n string, lb *loadbalancers.LoadBalancer) resource.TestCheckFunc { func testAccCheckLBV2LoadBalancerExists(
n string, lb *loadbalancers.LoadBalancer) resource.TestCheckFunc {
return func(s *terraform.State) error { return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n] rs, ok := s.RootModule().Resources[n]
if !ok { if !ok {
@ -91,7 +151,31 @@ func testAccCheckLBV2LoadBalancerExists(n string, lb *loadbalancers.LoadBalancer
} }
} }
const TestAccLBV2LoadBalancerConfig_basic = ` func testAccCheckLBV2LoadBalancerHasSecGroup(
lb *loadbalancers.LoadBalancer, sg *groups.SecGroup) resource.TestCheckFunc {
return func(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
networkingClient, err := config.networkingV2Client(OS_REGION_NAME)
if err != nil {
return fmt.Errorf("Error creating OpenStack networking client: %s", err)
}
port, err := ports.Get(networkingClient, lb.VipPortID).Extract()
if err != nil {
return err
}
for _, p := range port.SecurityGroups {
if p == sg.ID {
return nil
}
}
return fmt.Errorf("LoadBalancer does not have the security group")
}
}
const testAccLBV2LoadBalancerConfig_basic = `
resource "openstack_networking_network_v2" "network_1" { resource "openstack_networking_network_v2" "network_1" {
name = "network_1" name = "network_1"
admin_state_up = "true" admin_state_up = "true"
@ -110,7 +194,7 @@ resource "openstack_lb_loadbalancer_v2" "loadbalancer_1" {
} }
` `
const TestAccLBV2LoadBalancerConfig_update = ` const testAccLBV2LoadBalancerConfig_update = `
resource "openstack_networking_network_v2" "network_1" { resource "openstack_networking_network_v2" "network_1" {
name = "network_1" name = "network_1"
admin_state_up = "true" admin_state_up = "true"
@ -129,3 +213,98 @@ resource "openstack_lb_loadbalancer_v2" "loadbalancer_1" {
vip_subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}" vip_subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}"
} }
` `
const testAccLBV2LoadBalancer_secGroup = `
resource "openstack_networking_secgroup_v2" "secgroup_1" {
name = "secgroup_1"
description = "secgroup_1"
}
resource "openstack_networking_secgroup_v2" "secgroup_2" {
name = "secgroup_2"
description = "secgroup_2"
}
resource "openstack_networking_network_v2" "network_1" {
name = "network_1"
admin_state_up = "true"
}
resource "openstack_networking_subnet_v2" "subnet_1" {
name = "subnet_1"
network_id = "${openstack_networking_network_v2.network_1.id}"
cidr = "192.168.199.0/24"
}
resource "openstack_lb_loadbalancer_v2" "loadbalancer_1" {
name = "loadbalancer_1"
vip_subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}"
security_group_ids = [
"${openstack_networking_secgroup_v2.secgroup_1.id}"
]
}
`
const testAccLBV2LoadBalancer_secGroup_update1 = `
resource "openstack_networking_secgroup_v2" "secgroup_1" {
name = "secgroup_1"
description = "secgroup_1"
}
resource "openstack_networking_secgroup_v2" "secgroup_2" {
name = "secgroup_2"
description = "secgroup_2"
}
resource "openstack_networking_network_v2" "network_1" {
name = "network_1"
admin_state_up = "true"
}
resource "openstack_networking_subnet_v2" "subnet_1" {
name = "subnet_1"
network_id = "${openstack_networking_network_v2.network_1.id}"
cidr = "192.168.199.0/24"
}
resource "openstack_lb_loadbalancer_v2" "loadbalancer_1" {
name = "loadbalancer_1"
vip_subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}"
security_group_ids = [
"${openstack_networking_secgroup_v2.secgroup_1.id}",
"${openstack_networking_secgroup_v2.secgroup_2.id}"
]
}
`
const testAccLBV2LoadBalancer_secGroup_update2 = `
resource "openstack_networking_secgroup_v2" "secgroup_1" {
name = "secgroup_1"
description = "secgroup_1"
}
resource "openstack_networking_secgroup_v2" "secgroup_2" {
name = "secgroup_2"
description = "secgroup_2"
}
resource "openstack_networking_network_v2" "network_1" {
name = "network_1"
admin_state_up = "true"
}
resource "openstack_networking_subnet_v2" "subnet_1" {
name = "subnet_1"
network_id = "${openstack_networking_network_v2.network_1.id}"
cidr = "192.168.199.0/24"
}
resource "openstack_lb_loadbalancer_v2" "loadbalancer_1" {
name = "loadbalancer_1"
vip_subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}"
security_group_ids = [
"${openstack_networking_secgroup_v2.secgroup_2.id}"
]
depends_on = ["openstack_networking_secgroup_v2.secgroup_1"]
}
`

View File

@ -53,6 +53,10 @@ The following arguments are supported:
* `provider` - (Optional) The name of the provider. Changing this creates a new * `provider` - (Optional) The name of the provider. Changing this creates a new
loadbalancer. loadbalancer.
* `security_group_ids` - (Optional) A list of security group IDs to apply to the
loadbalancer. The security groups must be specified by ID and not name (as
opposed to how they are configured with the Compute Instance).
## Attributes Reference ## Attributes Reference
The following attributes are exported: The following attributes are exported:
@ -66,4 +70,5 @@ The following attributes are exported:
* `admin_state_up` - See Argument Reference above. * `admin_state_up` - See Argument Reference above.
* `flavor` - See Argument Reference above. * `flavor` - See Argument Reference above.
* `provider` - See Argument Reference above. * `provider` - See Argument Reference above.
* `security_group_ids` - See Argument Reference above.
* `vip_port_id` - The Port ID of the Load Balancer IP. * `vip_port_id` - The Port ID of the Load Balancer IP.