Skip to content

Commit

Permalink
Merge pull request #3712 from jtopjian/openstack-networking-statechange
Browse files Browse the repository at this point in the history
provider/openstack: State Changes for Networking Resources
  • Loading branch information
jtopjian committed Nov 3, 2015
2 parents 21eb546 + cc54d9e commit 6a791d1
Show file tree
Hide file tree
Showing 6 changed files with 450 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ package openstack
import (
"fmt"
"log"
"time"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"

"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
"github.com/rackspace/gophercloud/pagination"
Expand Down Expand Up @@ -45,7 +49,7 @@ func resourceNetworkingFloatingIPV2() *schema.Resource {

func resourceNetworkFloatingIPV2Create(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
networkClient, err := config.networkingV2Client(d.Get("region").(string))
networkingClient, err := config.networkingV2Client(d.Get("region").(string))
if err != nil {
return fmt.Errorf("Error creating OpenStack network client: %s", err)
}
Expand All @@ -62,24 +66,36 @@ func resourceNetworkFloatingIPV2Create(d *schema.ResourceData, meta interface{})
PortID: d.Get("port_id").(string),
}
log.Printf("[DEBUG] Create Options: %#v", createOpts)
floatingIP, err := floatingips.Create(networkClient, createOpts).Extract()
floatingIP, err := floatingips.Create(networkingClient, createOpts).Extract()
if err != nil {
return fmt.Errorf("Error allocating floating IP: %s", err)
}

log.Printf("[DEBUG] Waiting for OpenStack Neutron Floating IP (%s) to become available.", floatingIP.ID)

stateConf := &resource.StateChangeConf{
Target: "ACTIVE",
Refresh: waitForFloatingIPActive(networkingClient, floatingIP.ID),
Timeout: 2 * time.Minute,
Delay: 5 * time.Second,
MinTimeout: 3 * time.Second,
}

_, err = stateConf.WaitForState()

d.SetId(floatingIP.ID)

return resourceNetworkFloatingIPV2Read(d, meta)
}

func resourceNetworkFloatingIPV2Read(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
networkClient, err := config.networkingV2Client(d.Get("region").(string))
networkingClient, err := config.networkingV2Client(d.Get("region").(string))
if err != nil {
return fmt.Errorf("Error creating OpenStack network client: %s", err)
}

floatingIP, err := floatingips.Get(networkClient, d.Id()).Extract()
floatingIP, err := floatingips.Get(networkingClient, d.Id()).Extract()
if err != nil {
return CheckDeleted(d, err, "floating IP")
}
Expand All @@ -97,7 +113,7 @@ func resourceNetworkFloatingIPV2Read(d *schema.ResourceData, meta interface{}) e

func resourceNetworkFloatingIPV2Update(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
networkClient, err := config.networkingV2Client(d.Get("region").(string))
networkingClient, err := config.networkingV2Client(d.Get("region").(string))
if err != nil {
return fmt.Errorf("Error creating OpenStack network client: %s", err)
}
Expand All @@ -110,7 +126,7 @@ func resourceNetworkFloatingIPV2Update(d *schema.ResourceData, meta interface{})

log.Printf("[DEBUG] Update Options: %#v", updateOpts)

_, err = floatingips.Update(networkClient, d.Id(), updateOpts).Extract()
_, err = floatingips.Update(networkingClient, d.Id(), updateOpts).Extract()
if err != nil {
return fmt.Errorf("Error updating floating IP: %s", err)
}
Expand All @@ -120,28 +136,38 @@ func resourceNetworkFloatingIPV2Update(d *schema.ResourceData, meta interface{})

func resourceNetworkFloatingIPV2Delete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
networkClient, err := config.networkingV2Client(d.Get("region").(string))
networkingClient, err := config.networkingV2Client(d.Get("region").(string))
if err != nil {
return fmt.Errorf("Error creating OpenStack network client: %s", err)
}

err = floatingips.Delete(networkClient, d.Id()).ExtractErr()
stateConf := &resource.StateChangeConf{
Pending: []string{"ACTIVE"},
Target: "DELETED",
Refresh: waitForFloatingIPDelete(networkingClient, d.Id()),
Timeout: 2 * time.Minute,
Delay: 5 * time.Second,
MinTimeout: 3 * time.Second,
}

_, err = stateConf.WaitForState()
if err != nil {
return fmt.Errorf("Error deleting floating IP: %s", err)
return fmt.Errorf("Error deleting OpenStack Neutron Floating IP: %s", err)
}

d.SetId("")
return nil
}

func getNetworkID(d *schema.ResourceData, meta interface{}, networkName string) (string, error) {
config := meta.(*Config)
networkClient, err := config.networkingV2Client(d.Get("region").(string))
networkingClient, err := config.networkingV2Client(d.Get("region").(string))
if err != nil {
return "", fmt.Errorf("Error creating OpenStack network client: %s", err)
}

opts := networks.ListOpts{Name: networkName}
pager := networks.List(networkClient, opts)
pager := networks.List(networkingClient, opts)
networkID := ""

err = pager.EachPage(func(page pagination.Page) (bool, error) {
Expand All @@ -165,13 +191,13 @@ func getNetworkID(d *schema.ResourceData, meta interface{}, networkName string)

func getNetworkName(d *schema.ResourceData, meta interface{}, networkID string) (string, error) {
config := meta.(*Config)
networkClient, err := config.networkingV2Client(d.Get("region").(string))
networkingClient, err := config.networkingV2Client(d.Get("region").(string))
if err != nil {
return "", fmt.Errorf("Error creating OpenStack network client: %s", err)
}

opts := networks.ListOpts{ID: networkID}
pager := networks.List(networkClient, opts)
pager := networks.List(networkingClient, opts)
networkName := ""

err = pager.EachPage(func(page pagination.Page) (bool, error) {
Expand All @@ -192,3 +218,52 @@ func getNetworkName(d *schema.ResourceData, meta interface{}, networkID string)

return networkName, err
}

func waitForFloatingIPActive(networkingClient *gophercloud.ServiceClient, fId string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
f, err := floatingips.Get(networkingClient, fId).Extract()
if err != nil {
return nil, "", err
}

log.Printf("[DEBUG] OpenStack Neutron Floating IP: %+v", f)
if f.Status == "DOWN" || f.Status == "ACTIVE" {
return f, "ACTIVE", nil
}

return f, "", nil
}
}

func waitForFloatingIPDelete(networkingClient *gophercloud.ServiceClient, fId string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
log.Printf("[DEBUG] Attempting to delete OpenStack Floating IP %s.\n", fId)

f, err := floatingips.Get(networkingClient, fId).Extract()
if err != nil {
errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError)
if !ok {
return f, "ACTIVE", err
}
if errCode.Actual == 404 {
log.Printf("[DEBUG] Successfully deleted OpenStack Floating IP %s", fId)
return f, "DELETED", nil
}
}

err = floatingips.Delete(networkingClient, fId).ExtractErr()
if err != nil {
errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError)
if !ok {
return f, "ACTIVE", err
}
if errCode.Actual == 404 {
log.Printf("[DEBUG] Successfully deleted OpenStack Floating IP %s", fId)
return f, "DELETED", nil
}
}

log.Printf("[DEBUG] OpenStack Floating IP %s still active.\n", fId)
return f, "ACTIVE", nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ import (
"fmt"
"log"
"strconv"
"time"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"

"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
)

Expand Down Expand Up @@ -87,6 +91,19 @@ func resourceNetworkingNetworkV2Create(d *schema.ResourceData, meta interface{})
}
log.Printf("[INFO] Network ID: %s", n.ID)

log.Printf("[DEBUG] Waiting for Network (%s) to become available", n.ID)

stateConf := &resource.StateChangeConf{
Pending: []string{"BUILD"},
Target: "ACTIVE",
Refresh: waitForNetworkActive(networkingClient, n.ID),
Timeout: 2 * time.Minute,
Delay: 5 * time.Second,
MinTimeout: 3 * time.Second,
}

_, err = stateConf.WaitForState()

d.SetId(n.ID)

return resourceNetworkingNetworkV2Read(d, meta)
Expand Down Expand Up @@ -163,11 +180,69 @@ func resourceNetworkingNetworkV2Delete(d *schema.ResourceData, meta interface{})
return fmt.Errorf("Error creating OpenStack networking client: %s", err)
}

err = networks.Delete(networkingClient, d.Id()).ExtractErr()
stateConf := &resource.StateChangeConf{
Pending: []string{"ACTIVE"},
Target: "DELETED",
Refresh: waitForNetworkDelete(networkingClient, d.Id()),
Timeout: 2 * time.Minute,
Delay: 5 * time.Second,
MinTimeout: 3 * time.Second,
}

_, err = stateConf.WaitForState()
if err != nil {
return fmt.Errorf("Error deleting OpenStack Neutron Network: %s", err)
}

d.SetId("")
return nil
}

func waitForNetworkActive(networkingClient *gophercloud.ServiceClient, networkId string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
n, err := networks.Get(networkingClient, networkId).Extract()
if err != nil {
return nil, "", err
}

log.Printf("[DEBUG] OpenStack Neutron Network: %+v", n)
if n.Status == "DOWN" || n.Status == "ACTIVE" {
return n, "ACTIVE", nil
}

return n, n.Status, nil
}
}

func waitForNetworkDelete(networkingClient *gophercloud.ServiceClient, networkId string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
log.Printf("[DEBUG] Attempting to delete OpenStack Network %s.\n", networkId)

n, err := networks.Get(networkingClient, networkId).Extract()
if err != nil {
errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError)
if !ok {
return n, "ACTIVE", err
}
if errCode.Actual == 404 {
log.Printf("[DEBUG] Successfully deleted OpenStack Network %s", networkId)
return n, "DELETED", nil
}
}

err = networks.Delete(networkingClient, networkId).ExtractErr()
if err != nil {
errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError)
if !ok {
return n, "ACTIVE", err
}
if errCode.Actual == 404 {
log.Printf("[DEBUG] Successfully deleted OpenStack Network %s", networkId)
return n, "DELETED", nil
}
}

log.Printf("[DEBUG] OpenStack Network %s still active.\n", networkId)
return n, "ACTIVE", nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,36 @@ package openstack

import (
"fmt"
"os"
"testing"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"

"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/routers"
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
"github.com/rackspace/gophercloud/openstack/networking/v2/subnets"
)

func TestAccNetworkingV2Network_basic(t *testing.T) {
region := os.Getenv(OS_REGION_NAME)

var network networks.Network

var testAccNetworkingV2Network_basic = fmt.Sprintf(`
resource "openstack_networking_network_v2" "foo" {
region = "%s"
name = "network_1"
admin_state_up = "true"
}`, region)

var testAccNetworkingV2Network_update = fmt.Sprintf(`
resource "openstack_networking_network_v2" "foo" {
region = "%s"
name = "network_2"
admin_state_up = "true"
}`, region)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Expand All @@ -34,6 +53,57 @@ func TestAccNetworkingV2Network_basic(t *testing.T) {
})
}

func TestAccNetworkingV2Network_netstack(t *testing.T) {
region := os.Getenv(OS_REGION_NAME)

var network networks.Network
var subnet subnets.Subnet
var router routers.Router

var testAccNetworkingV2Network_netstack = fmt.Sprintf(`
resource "openstack_networking_network_v2" "foo" {
region = "%s"
name = "network_1"
admin_state_up = "true"
}
resource "openstack_networking_subnet_v2" "foo" {
region = "%s"
name = "subnet_1"
network_id = "${openstack_networking_network_v2.foo.id}"
cidr = "192.168.10.0/24"
ip_version = 4
}
resource "openstack_networking_router_v2" "foo" {
region = "%s"
name = "router_1"
}
resource "openstack_networking_router_interface_v2" "foo" {
region = "%s"
router_id = "${openstack_networking_router_v2.foo.id}"
subnet_id = "${openstack_networking_subnet_v2.foo.id}"
}`, region, region, region, region)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckNetworkingV2NetworkDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccNetworkingV2Network_netstack,
Check: resource.ComposeTestCheckFunc(
testAccCheckNetworkingV2NetworkExists(t, "openstack_networking_network_v2.foo", &network),
testAccCheckNetworkingV2SubnetExists(t, "openstack_networking_subnet_v2.foo", &subnet),
testAccCheckNetworkingV2RouterExists(t, "openstack_networking_router_v2.foo", &router),
testAccCheckNetworkingV2RouterInterfaceExists(t, "openstack_networking_router_interface_v2.foo"),
),
},
},
})
}

func testAccCheckNetworkingV2NetworkDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
networkingClient, err := config.networkingV2Client(OS_REGION_NAME)
Expand Down
Loading

0 comments on commit 6a791d1

Please sign in to comment.