Merge pull request #1347 from jtopjian/compute-network-refactor
provider/openstack Compute Network Refactor
This commit is contained in:
commit
e0cdadfc55
|
@ -63,4 +63,9 @@ func testAccPreCheck(t *testing.T) {
|
|||
if v1 == "" && v2 == "" {
|
||||
t.Fatal("OS_FLAVOR_ID or OS_FLAVOR_NAME must be set for acceptance tests")
|
||||
}
|
||||
|
||||
v = os.Getenv("OS_NETWORK_ID")
|
||||
if v == "" {
|
||||
t.Fatal("OS_NETWORK_ID must be set for acceptance tests")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,14 @@ package openstack
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
||||
)
|
||||
|
||||
func TestAccComputeV2FloatingIP_basic(t *testing.T) {
|
||||
|
@ -28,6 +30,40 @@ func TestAccComputeV2FloatingIP_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccComputeV2FloatingIP_attach(t *testing.T) {
|
||||
var instance servers.Server
|
||||
var fip floatingip.FloatingIP
|
||||
var testAccComputeV2FloatingIP_attach = fmt.Sprintf(`
|
||||
resource "openstack_compute_floatingip_v2" "myip" {
|
||||
}
|
||||
|
||||
resource "openstack_compute_instance_v2" "foo" {
|
||||
name = "terraform-test"
|
||||
floating_ip = "${openstack_compute_floatingip_v2.myip.address}"
|
||||
|
||||
network {
|
||||
uuid = "%s"
|
||||
}
|
||||
}`,
|
||||
os.Getenv("OS_NETWORK_ID"))
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckComputeV2FloatingIPDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccComputeV2FloatingIP_attach,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckComputeV2FloatingIPExists(t, "openstack_compute_floatingip_v2.myip", &fip),
|
||||
testAccCheckComputeV2InstanceExists(t, "openstack_compute_instance_v2.foo", &instance),
|
||||
testAccCheckComputeV2InstanceFloatingIPAttach(&instance, &fip),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckComputeV2FloatingIPDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
computeClient, err := config.computeV2Client(OS_REGION_NAME)
|
||||
|
@ -83,9 +119,4 @@ func testAccCheckComputeV2FloatingIPExists(t *testing.T, n string, kp *floatingi
|
|||
|
||||
var testAccComputeV2FloatingIP_basic = `
|
||||
resource "openstack_compute_floatingip_v2" "foo" {
|
||||
}
|
||||
|
||||
resource "openstack_compute_instance_v2" "bar" {
|
||||
name = "terraform-acc-floating-ip-test"
|
||||
floating_ip = "${openstack_compute_floatingip_v2.foo.address}"
|
||||
}`
|
||||
|
|
|
@ -13,14 +13,14 @@ import (
|
|||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/rackspace/gophercloud"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/volumeattach"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/flavors"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/images"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
|
||||
"github.com/rackspace/gophercloud/openstack/networking/v2/ports"
|
||||
"github.com/rackspace/gophercloud/pagination"
|
||||
)
|
||||
|
||||
|
@ -76,7 +76,7 @@ func resourceComputeInstanceV2() *schema.Resource {
|
|||
Optional: true,
|
||||
ForceNew: false,
|
||||
},
|
||||
"user_data": &schema.Schema{
|
||||
"user_data": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
|
@ -106,19 +106,37 @@ func resourceComputeInstanceV2() *schema.Resource {
|
|||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Computed: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"uuid": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
"port": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
"fixed_ip": &schema.Schema{
|
||||
"fixed_ip_v4": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
"fixed_ip_v6": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
"mac": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -230,13 +248,27 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e
|
|||
return err
|
||||
}
|
||||
|
||||
networkDetails, err := resourceInstanceNetworks(computeClient, d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
networks := make([]servers.Network, len(networkDetails))
|
||||
for i, net := range networkDetails {
|
||||
networks[i] = servers.Network{
|
||||
UUID: net["uuid"].(string),
|
||||
Port: net["port"].(string),
|
||||
FixedIP: net["fixed_ip_v4"].(string),
|
||||
}
|
||||
}
|
||||
|
||||
createOpts = &servers.CreateOpts{
|
||||
Name: d.Get("name").(string),
|
||||
ImageRef: imageId,
|
||||
FlavorRef: flavorId,
|
||||
SecurityGroups: resourceInstanceSecGroupsV2(d),
|
||||
AvailabilityZone: d.Get("availability_zone").(string),
|
||||
Networks: resourceInstanceNetworksV2(d),
|
||||
Networks: networks,
|
||||
Metadata: resourceInstanceMetadataV2(d),
|
||||
ConfigDrive: d.Get("config_drive").(bool),
|
||||
AdminPass: d.Get("admin_pass").(string),
|
||||
|
@ -291,18 +323,8 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e
|
|||
}
|
||||
floatingIP := d.Get("floating_ip").(string)
|
||||
if floatingIP != "" {
|
||||
networkingClient, err := config.networkingV2Client(d.Get("region").(string))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating OpenStack compute client: %s", err)
|
||||
}
|
||||
|
||||
allFloatingIPs, err := getFloatingIPs(networkingClient)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error listing OpenStack floating IPs: %s", err)
|
||||
}
|
||||
err = assignFloatingIP(networkingClient, extractFloatingIPFromIP(allFloatingIPs, floatingIP), server.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error assigning floating IP to OpenStack compute instance: %s", err)
|
||||
if err := floatingip.Associate(computeClient, server.ID, floatingIP).ExtractErr(); err != nil {
|
||||
return fmt.Errorf("Error associating floating IP: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,67 +360,85 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err
|
|||
log.Printf("[DEBUG] Retreived Server %s: %+v", d.Id(), server)
|
||||
|
||||
d.Set("name", server.Name)
|
||||
|
||||
// begin reading the network configuration
|
||||
d.Set("access_ip_v4", server.AccessIPv4)
|
||||
d.Set("access_ip_v6", server.AccessIPv6)
|
||||
|
||||
hostv4 := server.AccessIPv4
|
||||
if hostv4 == "" {
|
||||
if publicAddressesRaw, ok := server.Addresses["public"]; ok {
|
||||
publicAddresses := publicAddressesRaw.([]interface{})
|
||||
for _, paRaw := range publicAddresses {
|
||||
pa := paRaw.(map[string]interface{})
|
||||
if pa["version"].(float64) == 4 {
|
||||
hostv4 = pa["addr"].(string)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no host found, just get the first IPv4 we find
|
||||
if hostv4 == "" {
|
||||
for _, networkAddresses := range server.Addresses {
|
||||
for _, element := range networkAddresses.([]interface{}) {
|
||||
address := element.(map[string]interface{})
|
||||
if address["version"].(float64) == 4 {
|
||||
hostv4 = address["addr"].(string)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
d.Set("access_ip_v4", hostv4)
|
||||
log.Printf("hostv4: %s", hostv4)
|
||||
|
||||
hostv6 := server.AccessIPv6
|
||||
if hostv6 == "" {
|
||||
if publicAddressesRaw, ok := server.Addresses["public"]; ok {
|
||||
publicAddresses := publicAddressesRaw.([]interface{})
|
||||
for _, paRaw := range publicAddresses {
|
||||
pa := paRaw.(map[string]interface{})
|
||||
if pa["version"].(float64) == 6 {
|
||||
hostv6 = fmt.Sprintf("[%s]", pa["addr"].(string))
|
||||
break
|
||||
|
||||
networkDetails, err := resourceInstanceNetworks(computeClient, d)
|
||||
addresses := resourceInstanceAddresses(server.Addresses)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if there are no networkDetails, make networks at least a length of 1
|
||||
networkLength := 1
|
||||
if len(networkDetails) > 0 {
|
||||
networkLength = len(networkDetails)
|
||||
}
|
||||
networks := make([]map[string]interface{}, networkLength)
|
||||
|
||||
// Loop through all networks and addresses,
|
||||
// merge relevant address details.
|
||||
if len(networkDetails) == 0 {
|
||||
for netName, n := range addresses {
|
||||
if floatingIP, ok := n["floating_ip"]; ok {
|
||||
hostv4 = floatingIP.(string)
|
||||
} else {
|
||||
if hostv4 == "" && n["fixed_ip_v4"] != nil {
|
||||
hostv4 = n["fixed_ip_v4"].(string)
|
||||
}
|
||||
}
|
||||
|
||||
if hostv6 == "" && n["fixed_ip_v6"] != nil {
|
||||
hostv6 = n["fixed_ip_v6"].(string)
|
||||
}
|
||||
|
||||
networks[0] = map[string]interface{}{
|
||||
"name": netName,
|
||||
"fixed_ip_v4": n["fixed_ip_v4"],
|
||||
"fixed_ip_v6": n["fixed_ip_v6"],
|
||||
"mac": n["mac"],
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i, net := range networkDetails {
|
||||
n := addresses[net["name"].(string)]
|
||||
|
||||
if floatingIP, ok := n["floating_ip"]; ok {
|
||||
hostv4 = floatingIP.(string)
|
||||
} else {
|
||||
if hostv4 == "" && n["fixed_ip_v4"] != nil {
|
||||
hostv4 = n["fixed_ip_v4"].(string)
|
||||
}
|
||||
}
|
||||
|
||||
if hostv6 == "" && n["fixed_ip_v6"] != nil {
|
||||
hostv6 = n["fixed_ip_v6"].(string)
|
||||
}
|
||||
|
||||
networks[i] = map[string]interface{}{
|
||||
"uuid": networkDetails[i]["uuid"],
|
||||
"name": networkDetails[i]["name"],
|
||||
"port": networkDetails[i]["port"],
|
||||
"fixed_ip_v4": n["fixed_ip_v4"],
|
||||
"fixed_ip_v6": n["fixed_ip_v6"],
|
||||
"mac": n["mac"],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no hostv6 found, just get the first IPv6 we find
|
||||
if hostv6 == "" {
|
||||
for _, networkAddresses := range server.Addresses {
|
||||
for _, element := range networkAddresses.([]interface{}) {
|
||||
address := element.(map[string]interface{})
|
||||
if address["version"].(float64) == 6 {
|
||||
hostv6 = fmt.Sprintf("[%s]", address["addr"].(string))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Printf("[DEBUG] new networks: %+v", networks)
|
||||
|
||||
d.Set("network", networks)
|
||||
d.Set("access_ip_v4", hostv4)
|
||||
d.Set("access_ip_v6", hostv6)
|
||||
log.Printf("hostv4: %s", hostv4)
|
||||
log.Printf("hostv6: %s", hostv6)
|
||||
|
||||
// prefer the v6 address if no v4 address exists.
|
||||
preferredv := ""
|
||||
if hostv4 != "" {
|
||||
preferredv = hostv4
|
||||
|
@ -413,6 +453,7 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err
|
|||
"host": preferredv,
|
||||
})
|
||||
}
|
||||
// end network configuration
|
||||
|
||||
d.Set("metadata", server.Metadata)
|
||||
|
||||
|
@ -553,20 +594,20 @@ func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) e
|
|||
}
|
||||
|
||||
if d.HasChange("floating_ip") {
|
||||
floatingIP := d.Get("floating_ip").(string)
|
||||
if floatingIP != "" {
|
||||
networkingClient, err := config.networkingV2Client(d.Get("region").(string))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating OpenStack compute client: %s", err)
|
||||
oldFIP, newFIP := d.GetChange("floating_ip")
|
||||
log.Printf("[DEBUG] Old Floating IP: %v", oldFIP)
|
||||
log.Printf("[DEBUG] New Floating IP: %v", newFIP)
|
||||
if oldFIP.(string) != "" {
|
||||
log.Printf("[DEBUG] Attemping to disassociate %s from %s", oldFIP, d.Id())
|
||||
if err := floatingip.Disassociate(computeClient, d.Id(), oldFIP.(string)).ExtractErr(); err != nil {
|
||||
return fmt.Errorf("Error disassociating Floating IP during update: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
allFloatingIPs, err := getFloatingIPs(networkingClient)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error listing OpenStack floating IPs: %s", err)
|
||||
}
|
||||
err = assignFloatingIP(networkingClient, extractFloatingIPFromIP(allFloatingIPs, floatingIP), d.Id())
|
||||
if err != nil {
|
||||
fmt.Errorf("Error assigning floating IP to OpenStack compute instance: %s", err)
|
||||
if newFIP.(string) != "" {
|
||||
log.Printf("[DEBUG] Attemping to associate %s to %s", newFIP, d.Id())
|
||||
if err := floatingip.Associate(computeClient, d.Id(), newFIP.(string)).ExtractErr(); err != nil {
|
||||
return fmt.Errorf("Error associating Floating IP during update: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -722,18 +763,91 @@ func resourceInstanceSecGroupsV2(d *schema.ResourceData) []string {
|
|||
return secgroups
|
||||
}
|
||||
|
||||
func resourceInstanceNetworksV2(d *schema.ResourceData) []servers.Network {
|
||||
func resourceInstanceNetworks(computeClient *gophercloud.ServiceClient, d *schema.ResourceData) ([]map[string]interface{}, error) {
|
||||
rawNetworks := d.Get("network").([]interface{})
|
||||
networks := make([]servers.Network, len(rawNetworks))
|
||||
newNetworks := make([]map[string]interface{}, len(rawNetworks))
|
||||
var tenantnet tenantnetworks.Network
|
||||
|
||||
tenantNetworkExt := true
|
||||
for i, raw := range rawNetworks {
|
||||
rawMap := raw.(map[string]interface{})
|
||||
networks[i] = servers.Network{
|
||||
UUID: rawMap["uuid"].(string),
|
||||
Port: rawMap["port"].(string),
|
||||
FixedIP: rawMap["fixed_ip"].(string),
|
||||
|
||||
allPages, err := tenantnetworks.List(computeClient).AllPages()
|
||||
if err != nil {
|
||||
errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError)
|
||||
if !ok {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if errCode.Actual == 404 {
|
||||
tenantNetworkExt = false
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
networkID := ""
|
||||
networkName := ""
|
||||
if tenantNetworkExt {
|
||||
networkList, err := tenantnetworks.ExtractNetworks(allPages)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, network := range networkList {
|
||||
if network.Name == rawMap["name"] {
|
||||
tenantnet = network
|
||||
}
|
||||
if network.ID == rawMap["uuid"] {
|
||||
tenantnet = network
|
||||
}
|
||||
}
|
||||
|
||||
networkID = tenantnet.ID
|
||||
networkName = tenantnet.Name
|
||||
} else {
|
||||
networkID = rawMap["uuid"].(string)
|
||||
networkName = rawMap["name"].(string)
|
||||
}
|
||||
|
||||
newNetworks[i] = map[string]interface{}{
|
||||
"uuid": networkID,
|
||||
"name": networkName,
|
||||
"port": rawMap["port"].(string),
|
||||
"fixed_ip_v4": rawMap["fixed_ip_v4"].(string),
|
||||
}
|
||||
}
|
||||
return networks
|
||||
|
||||
log.Printf("[DEBUG] networks: %+v", newNetworks)
|
||||
|
||||
return newNetworks, nil
|
||||
}
|
||||
|
||||
func resourceInstanceAddresses(addresses map[string]interface{}) map[string]map[string]interface{} {
|
||||
|
||||
addrs := make(map[string]map[string]interface{})
|
||||
for n, networkAddresses := range addresses {
|
||||
addrs[n] = make(map[string]interface{})
|
||||
for _, element := range networkAddresses.([]interface{}) {
|
||||
address := element.(map[string]interface{})
|
||||
if address["OS-EXT-IPS:type"] == "floating" {
|
||||
addrs[n]["floating_ip"] = address["addr"]
|
||||
} else {
|
||||
if address["version"].(float64) == 4 {
|
||||
addrs[n]["fixed_ip_v4"] = address["addr"].(string)
|
||||
} else {
|
||||
addrs[n]["fixed_ip_v6"] = fmt.Sprintf("[%s]", address["addr"].(string))
|
||||
}
|
||||
}
|
||||
if mac, ok := address["OS-EXT-IPS-MAC:mac_addr"]; ok {
|
||||
addrs[n]["mac"] = mac.(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Addresses: %+v", addresses)
|
||||
|
||||
return addrs
|
||||
}
|
||||
|
||||
func resourceInstanceMetadataV2(d *schema.ResourceData) map[string]string {
|
||||
|
@ -759,75 +873,6 @@ func resourceInstanceBlockDeviceV2(d *schema.ResourceData, bd map[string]interfa
|
|||
return bfvOpts
|
||||
}
|
||||
|
||||
func extractFloatingIPFromIP(ips []floatingips.FloatingIP, IP string) *floatingips.FloatingIP {
|
||||
for _, floatingIP := range ips {
|
||||
if floatingIP.FloatingIP == IP {
|
||||
return &floatingIP
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func assignFloatingIP(networkingClient *gophercloud.ServiceClient, floatingIP *floatingips.FloatingIP, instanceID string) error {
|
||||
portID, err := getInstancePortID(networkingClient, instanceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return floatingips.Update(networkingClient, floatingIP.ID, floatingips.UpdateOpts{
|
||||
PortID: portID,
|
||||
}).Err
|
||||
}
|
||||
|
||||
func getInstancePortID(networkingClient *gophercloud.ServiceClient, instanceID string) (string, error) {
|
||||
pager := ports.List(networkingClient, ports.ListOpts{
|
||||
DeviceID: instanceID,
|
||||
})
|
||||
|
||||
var portID string
|
||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
||||
portList, err := ports.ExtractPorts(page)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, port := range portList {
|
||||
portID = port.ID
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if portID == "" {
|
||||
return "", fmt.Errorf("Cannot find port for instance %s", instanceID)
|
||||
}
|
||||
|
||||
return portID, nil
|
||||
}
|
||||
|
||||
func getFloatingIPs(networkingClient *gophercloud.ServiceClient) ([]floatingips.FloatingIP, error) {
|
||||
pager := floatingips.List(networkingClient, floatingips.ListOpts{})
|
||||
|
||||
ips := []floatingips.FloatingIP{}
|
||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
||||
floatingipList, err := floatingips.ExtractFloatingIPs(page)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, f := range floatingipList {
|
||||
ips = append(ips, f)
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
func getImageID(client *gophercloud.ServiceClient, d *schema.ResourceData) (string, error) {
|
||||
imageId := d.Get("image_id").(string)
|
||||
|
||||
|
|
|
@ -2,12 +2,14 @@ package openstack
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
|
||||
"github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/volumeattach"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
||||
"github.com/rackspace/gophercloud/pagination"
|
||||
|
@ -15,6 +17,17 @@ import (
|
|||
|
||||
func TestAccComputeV2Instance_basic(t *testing.T) {
|
||||
var instance servers.Server
|
||||
var testAccComputeV2Instance_basic = fmt.Sprintf(`
|
||||
resource "openstack_compute_instance_v2" "foo" {
|
||||
name = "terraform-test"
|
||||
network {
|
||||
uuid = "%s"
|
||||
}
|
||||
metadata {
|
||||
foo = "bar"
|
||||
}
|
||||
}`,
|
||||
os.Getenv("OS_NETWORK_ID"))
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
@ -53,6 +66,40 @@ func TestAccComputeV2Instance_volumeAttach(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccComputeV2Instance_floatingIPAttach(t *testing.T) {
|
||||
var instance servers.Server
|
||||
var fip floatingip.FloatingIP
|
||||
var testAccComputeV2Instance_floatingIPAttach = fmt.Sprintf(`
|
||||
resource "openstack_compute_floatingip_v2" "myip" {
|
||||
}
|
||||
|
||||
resource "openstack_compute_instance_v2" "foo" {
|
||||
name = "terraform-test"
|
||||
floating_ip = "${openstack_compute_floatingip_v2.myip.address}"
|
||||
|
||||
network {
|
||||
uuid = "%s"
|
||||
}
|
||||
}`,
|
||||
os.Getenv("OS_NETWORK_ID"))
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckComputeV2InstanceDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccComputeV2Instance_floatingIPAttach,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckComputeV2FloatingIPExists(t, "openstack_compute_floatingip_v2.myip", &fip),
|
||||
testAccCheckComputeV2InstanceExists(t, "openstack_compute_instance_v2.foo", &instance),
|
||||
testAccCheckComputeV2InstanceFloatingIPAttach(&instance, &fip),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckComputeV2InstanceDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
computeClient, err := config.computeV2Client(OS_REGION_NAME)
|
||||
|
@ -159,15 +206,17 @@ func testAccCheckComputeV2InstanceVolumeAttachment(
|
|||
}
|
||||
}
|
||||
|
||||
var testAccComputeV2Instance_basic = fmt.Sprintf(`
|
||||
resource "openstack_compute_instance_v2" "foo" {
|
||||
region = "%s"
|
||||
name = "terraform-test"
|
||||
metadata {
|
||||
foo = "bar"
|
||||
func testAccCheckComputeV2InstanceFloatingIPAttach(
|
||||
instance *servers.Server, fip *floatingip.FloatingIP) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
if fip.InstanceID == instance.ID {
|
||||
return nil
|
||||
}
|
||||
}`,
|
||||
OS_REGION_NAME)
|
||||
|
||||
return fmt.Errorf("Floating IP %s was not attached to instance %s", fip.ID, instance.ID)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var testAccComputeV2Instance_volumeAttach = fmt.Sprintf(`
|
||||
resource "openstack_blockstorage_volume_v1" "myvol" {
|
||||
|
|
|
@ -2,11 +2,13 @@ package openstack
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
|
||||
)
|
||||
|
||||
|
@ -28,6 +30,40 @@ func TestAccNetworkingV2FloatingIP_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccNetworkingV2FloatingIP_attach(t *testing.T) {
|
||||
var instance servers.Server
|
||||
var fip floatingips.FloatingIP
|
||||
var testAccNetworkV2FloatingIP_attach = fmt.Sprintf(`
|
||||
resource "openstack_networking_floatingip_v2" "myip" {
|
||||
}
|
||||
|
||||
resource "openstack_compute_instance_v2" "foo" {
|
||||
name = "terraform-test"
|
||||
floating_ip = "${openstack_networking_floatingip_v2.myip.address}"
|
||||
|
||||
network {
|
||||
uuid = "%s"
|
||||
}
|
||||
}`,
|
||||
os.Getenv("OS_NETWORK_ID"))
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckNetworkingV2FloatingIPDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccNetworkV2FloatingIP_attach,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckNetworkingV2FloatingIPExists(t, "openstack_networking_floatingip_v2.myip", &fip),
|
||||
testAccCheckComputeV2InstanceExists(t, "openstack_compute_instance_v2.foo", &instance),
|
||||
testAccCheckNetworkingV2InstanceFloatingIPAttach(&instance, &fip),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckNetworkingV2FloatingIPDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
networkClient, err := config.networkingV2Client(OS_REGION_NAME)
|
||||
|
@ -81,11 +117,28 @@ func testAccCheckNetworkingV2FloatingIPExists(t *testing.T, n string, kp *floati
|
|||
}
|
||||
}
|
||||
|
||||
func testAccCheckNetworkingV2InstanceFloatingIPAttach(
|
||||
instance *servers.Server, fip *floatingips.FloatingIP) resource.TestCheckFunc {
|
||||
|
||||
// When Neutron is used, the Instance sometimes does not know its floating IP until some time
|
||||
// after the attachment happened. This can be anywhere from 2-20 seconds. Because of that delay,
|
||||
// the test usually completes with failure.
|
||||
// However, the Fixed IP is known on both sides immediately, so that can be used as a bridge
|
||||
// to ensure the two are now related.
|
||||
// I think a better option is to introduce some state changing config in the actual resource.
|
||||
return func(s *terraform.State) error {
|
||||
for _, networkAddresses := range instance.Addresses {
|
||||
for _, element := range networkAddresses.([]interface{}) {
|
||||
address := element.(map[string]interface{})
|
||||
if address["OS-EXT-IPS:type"] == "fixed" && address["addr"] == fip.FixedIP {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("Floating IP %+v was not attached to instance %+v", fip, instance)
|
||||
}
|
||||
}
|
||||
|
||||
var testAccNetworkingV2FloatingIP_basic = `
|
||||
resource "openstack_networking_floatingip_v2" "foo" {
|
||||
}
|
||||
|
||||
resource "openstack_compute_instance_v2" "bar" {
|
||||
name = "terraform-acc-floating-ip-test"
|
||||
floating_ip = "${openstack_networking_floatingip_v2.foo.address}"
|
||||
}`
|
||||
|
|
Loading…
Reference in New Issue