provider/openstack: Resolve issues with Port Fixed IPs (#13056)
* provider/openstack: Add all_fixed_ips computed attribute to port resource This commit adds the `all_fixed_ips` attribute to the openstack_networking_port_v2 resource. This contains all of the port's Fixed IPs returned by the Networking v2 API. * provider/openstack: Revert Port fixed_ip back to a List This commit reverts the changes made in a8c4e81a6e3f2. This re-enables the ability to reference IP addresses using the numerical-element notation. This commit also makes fixed_ip a non-computed field, meaning Terraform will no longer set fixed_ip with what was returned by the API. This resolves the original issue about ordering. The last use-case is for fixed_ips that received an IP address via DHCP. Because fixed_ip is no longer computed, the DHCP IP will not be set. The workaround for this use-case is to use the new all_fixed_ips attribute. In effect, users should use fixed_ip only as a way of inputting data into Terraform and use all_fixed_ips as the output returned by the API. If use-cases exist where fixed_ip can be used as an output, that's a bonus feature.
This commit is contained in:
parent
9848d14bc9
commit
77a41ca859
|
@ -85,10 +85,9 @@ func resourceNetworkingPortV2() *schema.Resource {
|
|||
Computed: true,
|
||||
},
|
||||
"fixed_ip": &schema.Schema{
|
||||
Type: schema.TypeSet,
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
ForceNew: false,
|
||||
Computed: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"subnet_id": &schema.Schema{
|
||||
|
@ -98,7 +97,6 @@ func resourceNetworkingPortV2() *schema.Resource {
|
|||
"ip_address": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -128,6 +126,11 @@ func resourceNetworkingPortV2() *schema.Resource {
|
|||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"all_fixed_ips": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -202,15 +205,14 @@ func resourceNetworkingPortV2Read(d *schema.ResourceData, meta interface{}) erro
|
|||
d.Set("security_group_ids", p.SecurityGroups)
|
||||
d.Set("device_id", p.DeviceID)
|
||||
|
||||
// Convert FixedIPs to list of map
|
||||
var ips []map[string]interface{}
|
||||
// Create a slice of all returned Fixed IPs.
|
||||
// This will be in the order returned by the API,
|
||||
// which is usually alpha-numeric.
|
||||
var ips []string
|
||||
for _, ipObject := range p.FixedIPs {
|
||||
ip := make(map[string]interface{})
|
||||
ip["subnet_id"] = ipObject.SubnetID
|
||||
ip["ip_address"] = ipObject.IPAddress
|
||||
ips = append(ips, ip)
|
||||
ips = append(ips, ipObject.IPAddress)
|
||||
}
|
||||
d.Set("fixed_ip", ips)
|
||||
d.Set("all_fixed_ips", ips)
|
||||
|
||||
// Convert AllowedAddressPairs to list of map
|
||||
var pairs []map[string]interface{}
|
||||
|
@ -309,7 +311,7 @@ func resourcePortSecurityGroupsV2(d *schema.ResourceData) []string {
|
|||
}
|
||||
|
||||
func resourcePortFixedIpsV2(d *schema.ResourceData) interface{} {
|
||||
rawIP := d.Get("fixed_ip").(*schema.Set).List()
|
||||
rawIP := d.Get("fixed_ip").([]interface{})
|
||||
|
||||
if len(rawIP) == 0 {
|
||||
return nil
|
||||
|
|
|
@ -50,6 +50,30 @@ func TestAccNetworkingV2Port_noip(t *testing.T) {
|
|||
testAccCheckNetworkingV2SubnetExists("openstack_networking_subnet_v2.subnet_1", &subnet),
|
||||
testAccCheckNetworkingV2NetworkExists("openstack_networking_network_v2.network_1", &network),
|
||||
testAccCheckNetworkingV2PortExists("openstack_networking_port_v2.port_1", &port),
|
||||
testAccCheckNetworkingV2PortCountFixedIPs(&port, 1),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccNetworkingV2Port_multipleNoIP(t *testing.T) {
|
||||
var network networks.Network
|
||||
var port ports.Port
|
||||
var subnet subnets.Subnet
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckNetworkingV2PortDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccNetworkingV2Port_multipleNoIP,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckNetworkingV2SubnetExists("openstack_networking_subnet_v2.subnet_1", &subnet),
|
||||
testAccCheckNetworkingV2NetworkExists("openstack_networking_network_v2.network_1", &network),
|
||||
testAccCheckNetworkingV2PortExists("openstack_networking_port_v2.port_1", &port),
|
||||
testAccCheckNetworkingV2PortCountFixedIPs(&port, 3),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -96,6 +120,7 @@ func TestAccNetworkingV2Port_multipleFixedIPs(t *testing.T) {
|
|||
testAccCheckNetworkingV2SubnetExists("openstack_networking_subnet_v2.subnet_1", &subnet),
|
||||
testAccCheckNetworkingV2NetworkExists("openstack_networking_network_v2.network_1", &network),
|
||||
testAccCheckNetworkingV2PortExists("openstack_networking_port_v2.port_1", &port),
|
||||
testAccCheckNetworkingV2PortCountFixedIPs(&port, 3),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -124,6 +149,25 @@ func TestAccNetworkingV2Port_timeout(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccNetworkingV2Port_fixedIPs(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckNetworkingV2PortDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccNetworkingV2Port_fixedIPs,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr(
|
||||
"openstack_networking_port_v2.port_1", "all_fixed_ips.0", "192.168.199.23"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"openstack_networking_port_v2.port_1", "all_fixed_ips.1", "192.168.199.24"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckNetworkingV2PortDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
networkingClient, err := config.networkingV2Client(OS_REGION_NAME)
|
||||
|
@ -177,6 +221,16 @@ func testAccCheckNetworkingV2PortExists(n string, port *ports.Port) resource.Tes
|
|||
}
|
||||
}
|
||||
|
||||
func testAccCheckNetworkingV2PortCountFixedIPs(port *ports.Port, expected int) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
if len(port.FixedIPs) != expected {
|
||||
return fmt.Errorf("Expected %d Fixed IPs, got %d", expected, len(port.FixedIPs))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testAccNetworkingV2Port_basic = `
|
||||
resource "openstack_networking_network_v2" "network_1" {
|
||||
name = "network_1"
|
||||
|
@ -226,6 +280,38 @@ resource "openstack_networking_port_v2" "port_1" {
|
|||
}
|
||||
`
|
||||
|
||||
const testAccNetworkingV2Port_multipleNoIP = `
|
||||
resource "openstack_networking_network_v2" "network_1" {
|
||||
name = "network_1"
|
||||
admin_state_up = "true"
|
||||
}
|
||||
|
||||
resource "openstack_networking_subnet_v2" "subnet_1" {
|
||||
name = "subnet_1"
|
||||
cidr = "192.168.199.0/24"
|
||||
ip_version = 4
|
||||
network_id = "${openstack_networking_network_v2.network_1.id}"
|
||||
}
|
||||
|
||||
resource "openstack_networking_port_v2" "port_1" {
|
||||
name = "port_1"
|
||||
admin_state_up = "true"
|
||||
network_id = "${openstack_networking_network_v2.network_1.id}"
|
||||
|
||||
fixed_ip {
|
||||
subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}"
|
||||
}
|
||||
|
||||
fixed_ip {
|
||||
subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}"
|
||||
}
|
||||
|
||||
fixed_ip {
|
||||
subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const testAccNetworkingV2Port_allowedAddressPairs = `
|
||||
resource "openstack_networking_network_v2" "vrrp_network" {
|
||||
name = "vrrp_network"
|
||||
|
@ -356,3 +442,33 @@ resource "openstack_networking_port_v2" "port_1" {
|
|||
}
|
||||
}
|
||||
`
|
||||
|
||||
const testAccNetworkingV2Port_fixedIPs = `
|
||||
resource "openstack_networking_network_v2" "network_1" {
|
||||
name = "network_1"
|
||||
admin_state_up = "true"
|
||||
}
|
||||
|
||||
resource "openstack_networking_subnet_v2" "subnet_1" {
|
||||
name = "subnet_1"
|
||||
cidr = "192.168.199.0/24"
|
||||
ip_version = 4
|
||||
network_id = "${openstack_networking_network_v2.network_1.id}"
|
||||
}
|
||||
|
||||
resource "openstack_networking_port_v2" "port_1" {
|
||||
name = "port_1"
|
||||
admin_state_up = "true"
|
||||
network_id = "${openstack_networking_network_v2.network_1.id}"
|
||||
|
||||
fixed_ip {
|
||||
subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}"
|
||||
ip_address = "192.168.199.24"
|
||||
}
|
||||
|
||||
fixed_ip {
|
||||
subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}"
|
||||
ip_address = "192.168.199.23"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
|
@ -95,7 +95,9 @@ The following attributes are exported:
|
|||
* `device_owner` - See Argument Reference above.
|
||||
* `security_group_ids` - See Argument Reference above.
|
||||
* `device_id` - See Argument Reference above.
|
||||
* `fixed_ip/ip_address` - See Argument Reference above.
|
||||
* `fixed_ip` - See Argument Reference above.
|
||||
* `all fixed_ips` - The collection of Fixed IP addresses on the port in the
|
||||
order returned by the Network v2 API.
|
||||
|
||||
## Import
|
||||
|
||||
|
|
Loading…
Reference in New Issue