Merge pull request #4812 from jtopjian/openstack-per-network-floating-ip
provider/openstack: Per-network Floating IPs
This commit is contained in:
commit
1ccd0491ff
|
@ -136,10 +136,20 @@ func resourceComputeInstanceV2() *schema.Resource {
|
|||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
"floating_ip": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
"mac": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"access_network": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -320,11 +330,6 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e
|
|||
return err
|
||||
}
|
||||
|
||||
networkDetails, err := resourceInstanceNetworks(computeClient, d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// determine if volume/block_device configuration is correct
|
||||
// this includes ensuring volume_ids are set
|
||||
// and if only one block_device was specified.
|
||||
|
@ -332,6 +337,18 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e
|
|||
return err
|
||||
}
|
||||
|
||||
// check if floating IP configuration is correct
|
||||
if err := checkInstanceFloatingIPs(d); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Build a list of networks with the information given upon creation.
|
||||
// Error out if an invalid network configuration was used.
|
||||
networkDetails, err := getInstanceNetworks(computeClient, d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
networks := make([]servers.Network, len(networkDetails))
|
||||
for i, net := range networkDetails {
|
||||
networks[i] = servers.Network{
|
||||
|
@ -424,11 +441,15 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e
|
|||
"Error waiting for instance (%s) to become ready: %s",
|
||||
server.ID, err)
|
||||
}
|
||||
floatingIP := d.Get("floating_ip").(string)
|
||||
if floatingIP != "" {
|
||||
if err := floatingip.Associate(computeClient, server.ID, floatingIP).ExtractErr(); err != nil {
|
||||
return fmt.Errorf("Error associating floating IP: %s", err)
|
||||
}
|
||||
|
||||
// Now that the instance has been created, we need to do an early read on the
|
||||
// networks in order to associate floating IPs
|
||||
_, err = getInstanceNetworksAndAddresses(computeClient, d)
|
||||
|
||||
// If floating IPs were specified, associate them after the instance has launched.
|
||||
err = associateFloatingIPsToInstance(computeClient, d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if volumes were specified, attach them after the instance has launched.
|
||||
|
@ -462,99 +483,35 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err
|
|||
|
||||
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
|
||||
hostv6 := server.AccessIPv6
|
||||
|
||||
networkDetails, err := resourceInstanceNetworks(computeClient, d)
|
||||
addresses := resourceInstanceAddresses(server.Addresses)
|
||||
// Get the instance network and address information
|
||||
networks, err := getInstanceNetworksAndAddresses(computeClient, d)
|
||||
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"],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] new networks: %+v", networks)
|
||||
// Determine the best IPv4 and IPv6 addresses to access the instance with
|
||||
hostv4, hostv6 := getInstanceAccessAddresses(d, 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 := ""
|
||||
// Determine the best IP address to use for SSH connectivity.
|
||||
// Prefer IPv4 over IPv6.
|
||||
preferredSSHAddress := ""
|
||||
if hostv4 != "" {
|
||||
preferredv = hostv4
|
||||
preferredSSHAddress = hostv4
|
||||
} else if hostv6 != "" {
|
||||
preferredv = hostv6
|
||||
preferredSSHAddress = hostv6
|
||||
}
|
||||
|
||||
if preferredv != "" {
|
||||
if preferredSSHAddress != "" {
|
||||
// Initialize the connection info
|
||||
d.SetConnInfo(map[string]string{
|
||||
"type": "ssh",
|
||||
"host": preferredv,
|
||||
"host": preferredSSHAddress,
|
||||
})
|
||||
}
|
||||
// end network configuration
|
||||
|
||||
d.Set("metadata", server.Metadata)
|
||||
|
||||
|
@ -600,12 +557,6 @@ func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) e
|
|||
if d.HasChange("name") {
|
||||
updateOpts.Name = d.Get("name").(string)
|
||||
}
|
||||
if d.HasChange("access_ip_v4") {
|
||||
updateOpts.AccessIPv4 = d.Get("access_ip_v4").(string)
|
||||
}
|
||||
if d.HasChange("access_ip_v6") {
|
||||
updateOpts.AccessIPv4 = d.Get("access_ip_v6").(string)
|
||||
}
|
||||
|
||||
if updateOpts != (servers.UpdateOpts{}) {
|
||||
_, err := servers.Update(computeClient, d.Id(), updateOpts).Extract()
|
||||
|
@ -679,20 +630,48 @@ func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) e
|
|||
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 {
|
||||
log.Printf("[DEBUG] Attempting to disassociate %s from %s", oldFIP, d.Id())
|
||||
if err := disassociateFloatingIPFromInstance(computeClient, oldFIP.(string), d.Id(), ""); err != nil {
|
||||
return fmt.Errorf("Error disassociating Floating IP during update: %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 {
|
||||
log.Printf("[DEBUG] Attempting to associate %s to %s", newFIP, d.Id())
|
||||
if err := associateFloatingIPToInstance(computeClient, newFIP.(string), d.Id(), ""); err != nil {
|
||||
return fmt.Errorf("Error associating Floating IP during update: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange("network") {
|
||||
oldNetworks, newNetworks := d.GetChange("network")
|
||||
oldNetworkList := oldNetworks.([]interface{})
|
||||
newNetworkList := newNetworks.([]interface{})
|
||||
for i, oldNet := range oldNetworkList {
|
||||
oldNetRaw := oldNet.(map[string]interface{})
|
||||
oldFIP := oldNetRaw["floating_ip"].(string)
|
||||
oldFixedIP := oldNetRaw["fixed_ip_v4"].(string)
|
||||
|
||||
newNetRaw := newNetworkList[i].(map[string]interface{})
|
||||
newFIP := newNetRaw["floating_ip"].(string)
|
||||
newFixedIP := newNetRaw["fixed_ip_v4"].(string)
|
||||
|
||||
// Only changes to the floating IP are supported
|
||||
if oldFIP != newFIP {
|
||||
log.Printf("[DEBUG] Attempting to disassociate %s from %s", oldFIP, d.Id())
|
||||
if err := disassociateFloatingIPFromInstance(computeClient, oldFIP, d.Id(), oldFixedIP); err != nil {
|
||||
return fmt.Errorf("Error disassociating Floating IP during update: %s", err)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Attempting to associate %s to %s", newFIP, d.Id())
|
||||
if err := associateFloatingIPToInstance(computeClient, newFIP, d.Id(), newFixedIP); err != nil {
|
||||
return fmt.Errorf("Error associating Floating IP during update: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange("volume") {
|
||||
// ensure the volume configuration is correct
|
||||
if err := checkVolumeConfig(d); err != nil {
|
||||
|
@ -845,7 +824,62 @@ func resourceInstanceSecGroupsV2(d *schema.ResourceData) []string {
|
|||
return secgroups
|
||||
}
|
||||
|
||||
func resourceInstanceNetworks(computeClient *gophercloud.ServiceClient, d *schema.ResourceData) ([]map[string]interface{}, error) {
|
||||
// getInstanceNetworks collects instance network information from different sources
|
||||
// and aggregates it all together.
|
||||
func getInstanceNetworksAndAddresses(computeClient *gophercloud.ServiceClient, d *schema.ResourceData) ([]map[string]interface{}, error) {
|
||||
server, err := servers.Get(computeClient, d.Id()).Extract()
|
||||
if err != nil {
|
||||
return nil, CheckDeleted(d, err, "server")
|
||||
}
|
||||
|
||||
networkDetails, err := getInstanceNetworks(computeClient, d)
|
||||
addresses := getInstanceAddresses(server.Addresses)
|
||||
if err != nil {
|
||||
return nil, 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 {
|
||||
networks[0] = map[string]interface{}{
|
||||
"name": netName,
|
||||
"fixed_ip_v4": n["fixed_ip_v4"],
|
||||
"fixed_ip_v6": n["fixed_ip_v6"],
|
||||
"floating_ip": n["floating_ip"],
|
||||
"mac": n["mac"],
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i, net := range networkDetails {
|
||||
n := addresses[net["name"].(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"],
|
||||
"floating_ip": n["floating_ip"],
|
||||
"mac": n["mac"],
|
||||
"access_network": networkDetails[i]["access_network"],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] networks: %+v", networks)
|
||||
|
||||
return networks, nil
|
||||
}
|
||||
|
||||
func getInstanceNetworks(computeClient *gophercloud.ServiceClient, d *schema.ResourceData) ([]map[string]interface{}, error) {
|
||||
rawNetworks := d.Get("network").([]interface{})
|
||||
newNetworks := make([]map[string]interface{}, 0, len(rawNetworks))
|
||||
var tenantnet tenantnetworks.Network
|
||||
|
@ -860,6 +894,7 @@ func resourceInstanceNetworks(computeClient *gophercloud.ServiceClient, d *schem
|
|||
}
|
||||
|
||||
rawMap := raw.(map[string]interface{})
|
||||
|
||||
allPages, err := tenantnetworks.List(computeClient).AllPages()
|
||||
if err != nil {
|
||||
errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError)
|
||||
|
@ -903,6 +938,7 @@ func resourceInstanceNetworks(computeClient *gophercloud.ServiceClient, d *schem
|
|||
"name": networkName,
|
||||
"port": rawMap["port"].(string),
|
||||
"fixed_ip_v4": rawMap["fixed_ip_v4"].(string),
|
||||
"access_network": rawMap["access_network"].(bool),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -910,8 +946,7 @@ func resourceInstanceNetworks(computeClient *gophercloud.ServiceClient, d *schem
|
|||
return newNetworks, nil
|
||||
}
|
||||
|
||||
func resourceInstanceAddresses(addresses map[string]interface{}) map[string]map[string]interface{} {
|
||||
|
||||
func getInstanceAddresses(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{})
|
||||
|
@ -937,6 +972,117 @@ func resourceInstanceAddresses(addresses map[string]interface{}) map[string]map[
|
|||
return addrs
|
||||
}
|
||||
|
||||
func getInstanceAccessAddresses(d *schema.ResourceData, networks []map[string]interface{}) (string, string) {
|
||||
var hostv4, hostv6 string
|
||||
|
||||
// Start with a global floating IP
|
||||
floatingIP := d.Get("floating_ip").(string)
|
||||
if floatingIP != "" {
|
||||
hostv4 = floatingIP
|
||||
}
|
||||
|
||||
// Loop through all networks and check for the following:
|
||||
// * If the network is set as an access network.
|
||||
// * If the network has a floating IP.
|
||||
// * If the network has a v4/v6 fixed IP.
|
||||
for _, n := range networks {
|
||||
if n["floating_ip"] != nil {
|
||||
hostv4 = n["floating_ip"].(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)
|
||||
}
|
||||
|
||||
if n["access_network"].(bool) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] OpenStack Instance Network Access Addresses: %s, %s", hostv4, hostv6)
|
||||
|
||||
return hostv4, hostv6
|
||||
}
|
||||
|
||||
func checkInstanceFloatingIPs(d *schema.ResourceData) error {
|
||||
rawNetworks := d.Get("network").([]interface{})
|
||||
floatingIP := d.Get("floating_ip").(string)
|
||||
|
||||
for _, raw := range rawNetworks {
|
||||
if raw == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
rawMap := raw.(map[string]interface{})
|
||||
|
||||
// Error if a floating IP was specified both globally and in the network block.
|
||||
if floatingIP != "" && rawMap["floating_ip"] != "" {
|
||||
return fmt.Errorf("Cannot specify a floating IP both globally and in a network block.")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func associateFloatingIPsToInstance(computeClient *gophercloud.ServiceClient, d *schema.ResourceData) error {
|
||||
floatingIP := d.Get("floating_ip").(string)
|
||||
rawNetworks := d.Get("network").([]interface{})
|
||||
instanceID := d.Id()
|
||||
|
||||
if floatingIP != "" {
|
||||
if err := associateFloatingIPToInstance(computeClient, floatingIP, instanceID, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
for _, raw := range rawNetworks {
|
||||
if raw == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
rawMap := raw.(map[string]interface{})
|
||||
if rawMap["floating_ip"].(string) != "" {
|
||||
floatingIP := rawMap["floating_ip"].(string)
|
||||
fixedIP := rawMap["fixed_ip_v4"].(string)
|
||||
if err := associateFloatingIPToInstance(computeClient, floatingIP, instanceID, fixedIP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func associateFloatingIPToInstance(computeClient *gophercloud.ServiceClient, floatingIP string, instanceID string, fixedIP string) error {
|
||||
associateOpts := floatingip.AssociateOpts{
|
||||
ServerID: instanceID,
|
||||
FloatingIP: floatingIP,
|
||||
FixedIP: fixedIP,
|
||||
}
|
||||
|
||||
if err := floatingip.AssociateInstance(computeClient, associateOpts).ExtractErr(); err != nil {
|
||||
return fmt.Errorf("Error associating floating IP: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func disassociateFloatingIPFromInstance(computeClient *gophercloud.ServiceClient, floatingIP string, instanceID string, fixedIP string) error {
|
||||
associateOpts := floatingip.AssociateOpts{
|
||||
ServerID: instanceID,
|
||||
FloatingIP: floatingIP,
|
||||
FixedIP: fixedIP,
|
||||
}
|
||||
|
||||
if err := floatingip.DisassociateInstance(computeClient, associateOpts).ExtractErr(); err != nil {
|
||||
return fmt.Errorf("Error disassociating floating IP: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceInstanceMetadataV2(d *schema.ResourceData) map[string]string {
|
||||
m := make(map[string]string)
|
||||
for key, val := range d.Get("metadata").(map[string]interface{}) {
|
||||
|
|
|
@ -178,10 +178,10 @@ func TestAccComputeV2Instance_volumeDetachPostCreation(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccComputeV2Instance_floatingIPAttach(t *testing.T) {
|
||||
func TestAccComputeV2Instance_floatingIPAttachGlobally(t *testing.T) {
|
||||
var instance servers.Server
|
||||
var fip floatingip.FloatingIP
|
||||
var testAccComputeV2Instance_floatingIPAttach = fmt.Sprintf(`
|
||||
var testAccComputeV2Instance_floatingIPAttachGlobally = fmt.Sprintf(`
|
||||
resource "openstack_compute_floatingip_v2" "myip" {
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,7 @@ func TestAccComputeV2Instance_floatingIPAttach(t *testing.T) {
|
|||
CheckDestroy: testAccCheckComputeV2InstanceDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccComputeV2Instance_floatingIPAttach,
|
||||
Config: testAccComputeV2Instance_floatingIPAttachGlobally,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckComputeV2FloatingIPExists(t, "openstack_compute_floatingip_v2.myip", &fip),
|
||||
testAccCheckComputeV2InstanceExists(t, "openstack_compute_instance_v2.foo", &instance),
|
||||
|
@ -213,6 +213,108 @@ func TestAccComputeV2Instance_floatingIPAttach(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccComputeV2Instance_floatingIPAttachToNetwork(t *testing.T) {
|
||||
var instance servers.Server
|
||||
var fip floatingip.FloatingIP
|
||||
var testAccComputeV2Instance_floatingIPAttachToNetwork = fmt.Sprintf(`
|
||||
resource "openstack_compute_floatingip_v2" "myip" {
|
||||
}
|
||||
|
||||
resource "openstack_compute_instance_v2" "foo" {
|
||||
name = "terraform-test"
|
||||
security_groups = ["default"]
|
||||
|
||||
network {
|
||||
uuid = "%s"
|
||||
floating_ip = "${openstack_compute_floatingip_v2.myip.address}"
|
||||
access_network = true
|
||||
}
|
||||
}`,
|
||||
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_floatingIPAttachToNetwork,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckComputeV2FloatingIPExists(t, "openstack_compute_floatingip_v2.myip", &fip),
|
||||
testAccCheckComputeV2InstanceExists(t, "openstack_compute_instance_v2.foo", &instance),
|
||||
testAccCheckComputeV2InstanceFloatingIPAttach(&instance, &fip),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccComputeV2Instance_floatingIPAttachAndChange(t *testing.T) {
|
||||
var instance servers.Server
|
||||
var fip floatingip.FloatingIP
|
||||
var testAccComputeV2Instance_floatingIPAttachToNetwork_1 = fmt.Sprintf(`
|
||||
resource "openstack_compute_floatingip_v2" "myip_1" {
|
||||
}
|
||||
|
||||
resource "openstack_compute_floatingip_v2" "myip_2" {
|
||||
}
|
||||
|
||||
resource "openstack_compute_instance_v2" "foo" {
|
||||
name = "terraform-test"
|
||||
security_groups = ["default"]
|
||||
|
||||
network {
|
||||
uuid = "%s"
|
||||
floating_ip = "${openstack_compute_floatingip_v2.myip_1.address}"
|
||||
access_network = true
|
||||
}
|
||||
}`,
|
||||
os.Getenv("OS_NETWORK_ID"))
|
||||
|
||||
var testAccComputeV2Instance_floatingIPAttachToNetwork_2 = fmt.Sprintf(`
|
||||
resource "openstack_compute_floatingip_v2" "myip_1" {
|
||||
}
|
||||
|
||||
resource "openstack_compute_floatingip_v2" "myip_2" {
|
||||
}
|
||||
|
||||
resource "openstack_compute_instance_v2" "foo" {
|
||||
name = "terraform-test"
|
||||
security_groups = ["default"]
|
||||
|
||||
network {
|
||||
uuid = "%s"
|
||||
floating_ip = "${openstack_compute_floatingip_v2.myip_2.address}"
|
||||
access_network = true
|
||||
}
|
||||
}`,
|
||||
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_floatingIPAttachToNetwork_1,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckComputeV2FloatingIPExists(t, "openstack_compute_floatingip_v2.myip_1", &fip),
|
||||
testAccCheckComputeV2InstanceExists(t, "openstack_compute_instance_v2.foo", &instance),
|
||||
testAccCheckComputeV2InstanceFloatingIPAttach(&instance, &fip),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
Config: testAccComputeV2Instance_floatingIPAttachToNetwork_2,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckComputeV2FloatingIPExists(t, "openstack_compute_floatingip_v2.myip_2", &fip),
|
||||
testAccCheckComputeV2InstanceExists(t, "openstack_compute_instance_v2.foo", &instance),
|
||||
testAccCheckComputeV2InstanceFloatingIPAttach(&instance, &fip),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccComputeV2Instance_multi_secgroups(t *testing.T) {
|
||||
var instance servers.Server
|
||||
var secgroup secgroups.SecurityGroup
|
||||
|
|
|
@ -50,7 +50,8 @@ The following arguments are supported:
|
|||
desired flavor for the server. Changing this resizes the existing server.
|
||||
|
||||
* `floating_ip` - (Optional) A *Compute* Floating IP that will be associated
|
||||
with the Instance. The Floating IP must be provisioned already.
|
||||
with the Instance. The Floating IP must be provisioned already. See *Notes*
|
||||
for more information about Floating IPs.
|
||||
|
||||
* `user_data` - (Optional) The user data to provide when launching the instance.
|
||||
Changing this creates a new server.
|
||||
|
@ -106,6 +107,13 @@ The `network` block supports:
|
|||
* `fixed_ip_v4` - (Optional) Specifies a fixed IPv4 address to be used on this
|
||||
network.
|
||||
|
||||
* `floating_ip` - (Optional) Specifies a floating IP address to be associated
|
||||
with this network. Cannot be combined with a top-level floating IP. See
|
||||
*Notes* for more information about Floating IPs.
|
||||
|
||||
* `access_network` - (Optional) Specifies if this network should be used for
|
||||
provisioning access. Accepts true or false. Defaults to false.
|
||||
|
||||
The `block_device` block supports:
|
||||
|
||||
* `uuid` - (Required) The UUID of the image, volume, or snapshot.
|
||||
|
@ -173,11 +181,21 @@ The following attributes are exported:
|
|||
network.
|
||||
* `network/fixed_ip_v6` - The Fixed IPv6 address of the Instance on that
|
||||
network.
|
||||
* `network/floating_ip` - The Floating IP address of the Instance on that
|
||||
network.
|
||||
* `network/mac` - The MAC address of the NIC on that network.
|
||||
|
||||
## Notes
|
||||
|
||||
If you configure the instance to have multiple networks, be aware that only
|
||||
the first network can be associated with a Floating IP. So the first network
|
||||
in the instance resource _must_ be the network that you have configured to
|
||||
communicate with your floating IP / public network via a Neutron Router.
|
||||
Floating IPs can be associated in one of two ways:
|
||||
|
||||
* You can specify a Floating IP address by using the top-level `floating_ip`
|
||||
attribute. This floating IP will be associated with either the network defined
|
||||
in the first `network` block or the default network if no `network` blocks are
|
||||
defined.
|
||||
|
||||
* You can specify a Floating IP address by using the `floating_ip` attribute
|
||||
defined in the `network` block. Each `network` block can have its own floating
|
||||
IP address.
|
||||
|
||||
Only one of the above methods can be used.
|
||||
|
|
Loading…
Reference in New Issue