Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

provider/openstack: State Changes for Networking Resources #3712

Merged
merged 1 commit into from
Nov 3, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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