diff --git a/cloudstack/resource_cloudstack_ipaddress.go b/cloudstack/resource_cloudstack_ipaddress.go index c7db4ac0..158176a3 100644 --- a/cloudstack/resource_cloudstack_ipaddress.go +++ b/cloudstack/resource_cloudstack_ipaddress.go @@ -69,7 +69,9 @@ func resourceCloudStackIPAddress() *schema.Resource { "ip_address": { Type: schema.TypeString, + Optional: true, Computed: true, + ForceNew: true, }, "is_source_nat": { @@ -125,6 +127,10 @@ func resourceCloudStackIPAddressCreate(d *schema.ResourceData, meta interface{}) return err } + if ipaddress, ok := d.GetOk("ip_address"); ok { + p.SetIpaddress(ipaddress.(string)) + } + // Associate a new IP address r, err := cs.Address.AssociateIpAddress(p) if err != nil { diff --git a/cloudstack/resource_cloudstack_ipaddress_test.go b/cloudstack/resource_cloudstack_ipaddress_test.go index 82b8ffce..37ec68f6 100644 --- a/cloudstack/resource_cloudstack_ipaddress_test.go +++ b/cloudstack/resource_cloudstack_ipaddress_test.go @@ -68,6 +68,27 @@ func TestAccCloudStackIPAddress_vpc(t *testing.T) { }) } +func TestAccCloudStackIPAddress_specificIP(t *testing.T) { + var ipaddr cloudstack.PublicIpAddress + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudStackIPAddressDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCloudStackIPAddress_specificIP, + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudStackIPAddressExists( + "cloudstack_ipaddress.foo", &ipaddr), + resource.TestCheckResourceAttr( + "cloudstack_ipaddress.foo", "ip_address", "10.2.2.11"), + ), + }, + }, + }) +} + func TestAccCloudStackIPAddress_vpcid_with_network_id(t *testing.T) { regex := regexp.MustCompile("set only network_id or vpc_id") @@ -164,6 +185,46 @@ resource "cloudstack_ipaddress" "foo" { zone = cloudstack_vpc.foo.zone }` +const testAccCloudStackIPAddress_specificIP = ` +data "cloudstack_zone" "zone" { + filter { + name = "name" + value = "Sandbox-simulator" + } +} + +data "cloudstack_physical_network" "pn" { + filter { + name = "zone_name" + value = "Sandbox-simulator" + } +} + +resource "cloudstack_vlan_ip_range" "foo" { + physical_network_id = data.cloudstack_physical_network.pn.id + zone_id = data.cloudstack_zone.zone.id + for_virtual_network = true + vlan = "vlan://456" + gateway = "10.2.2.1" + netmask = "255.255.255.0" + start_ip = "10.2.2.10" + end_ip = "10.2.2.11" +} + +resource "cloudstack_network" "foo" { + name = "terraform-network" + display_text = "terraform-network" + cidr = "10.1.1.0/24" + network_offering = "DefaultIsolatedNetworkOfferingWithSourceNatService" + source_nat_ip = true + zone = "Sandbox-simulator" +} + +resource "cloudstack_ipaddress" "foo" { + network_id = cloudstack_network.foo.id + ip_address = cloudstack_vlan_ip_range.foo.end_ip +}` + const testAccCloudStackIPAddress_vpcid_with_network_id = ` resource "cloudstack_vpc" "foo" { name = "terraform-vpc" diff --git a/website/docs/r/ipaddress.html.markdown b/website/docs/r/ipaddress.html.markdown index 27bcbd20..40c2cca1 100644 --- a/website/docs/r/ipaddress.html.markdown +++ b/website/docs/r/ipaddress.html.markdown @@ -37,6 +37,11 @@ The following arguments are supported: * `project` - (Optional) The name or ID of the project to deploy this instance to. Changing this forces a new resource to be created. +* `ip_address` - (Optional) A specific IP address to acquire from the available + pool (e.g. from a `cloudstack_vlan_ip_range` dedicated to an account). If + not set, CloudStack auto-selects the next free address. Changing this + forces a new resource to be created. + *NOTE: `network_id` and/or `zone` should have a value when `is_portable` is `false`!* *NOTE: Either `network_id` or `vpc_id` should have a value when `is_portable` is `true`!*