provider/google: Support static private IP addresses (#6310)

* provider/google: Support static private IP addresses

The private address of an instance's network interface may now be specified.
If no value is provided, an address will be chosen by Google Compute Engine
and that value will be read into Terraform state.

* docs: GCE private static IP address information
This commit is contained in:
Evan Brown 2016-08-07 18:01:31 -07:00 committed by Paul Stack
parent 25b49dfd51
commit 3ac3516371
3 changed files with 131 additions and 2 deletions

View File

@ -153,6 +153,8 @@ func resourceComputeInstance() *schema.Resource {
"address": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Computed: true,
},
@ -467,9 +469,10 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
networkInterfaces = make([]*compute.NetworkInterface, 0, networkInterfacesCount)
for i := 0; i < networkInterfacesCount; i++ {
prefix := fmt.Sprintf("network_interface.%d", i)
// Load up the name of this network_interfac
// Load up the name of this network_interface
networkName := d.Get(prefix + ".network").(string)
subnetworkName := d.Get(prefix + ".subnetwork").(string)
address := d.Get(prefix + ".address").(string)
var networkLink, subnetworkLink string
if networkName != "" && subnetworkName != "" {
@ -499,6 +502,7 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
var iface compute.NetworkInterface
iface.Network = networkLink
iface.Subnetwork = subnetworkLink
iface.NetworkIP = address
// Handle access_config structs
accessConfigsCount := d.Get(prefix + ".access_config.#").(int)

View File

@ -371,6 +371,47 @@ func TestAccComputeInstance_subnet_custom(t *testing.T) {
})
}
func TestAccComputeInstance_address_auto(t *testing.T) {
var instance compute.Instance
var instanceName = fmt.Sprintf("instance-test-%s", acctest.RandString(10))
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeInstance_address_auto(instanceName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeInstanceExists(
"google_compute_instance.foobar", &instance),
testAccCheckComputeInstanceHasAnyAddress(&instance),
),
},
},
})
}
func TestAccComputeInstance_address_custom(t *testing.T) {
var instance compute.Instance
var instanceName = fmt.Sprintf("instance-test-%s", acctest.RandString(10))
var address = "10.0.200.200"
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeInstance_address_custom(instanceName, address),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeInstanceExists(
"google_compute_instance.foobar", &instance),
testAccCheckComputeInstanceHasAddress(&instance, address),
),
},
},
})
}
func testAccCheckComputeInstanceDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
@ -528,6 +569,30 @@ func testAccCheckComputeInstanceHasSubnet(instance *compute.Instance) resource.T
}
}
func testAccCheckComputeInstanceHasAnyAddress(instance *compute.Instance) resource.TestCheckFunc {
return func(s *terraform.State) error {
for _, i := range instance.NetworkInterfaces {
if i.NetworkIP == "" {
return fmt.Errorf("no address")
}
}
return nil
}
}
func testAccCheckComputeInstanceHasAddress(instance *compute.Instance, address string) resource.TestCheckFunc {
return func(s *terraform.State) error {
for _, i := range instance.NetworkInterfaces {
if i.NetworkIP != address {
return fmt.Errorf("Wrong address found: expected %v, got %v", address, i.NetworkIP)
}
}
return nil
}
}
func testAccComputeInstance_basic_deprecated_network(instance string) string {
return fmt.Sprintf(`
resource "google_compute_instance" "foobar" {
@ -880,3 +945,60 @@ func testAccComputeInstance_subnet_custom(instance string) string {
}`, acctest.RandString(10), acctest.RandString(10), instance)
}
func testAccComputeInstance_address_auto(instance string) string {
return fmt.Sprintf(`
resource "google_compute_network" "inst-test-network" {
name = "inst-test-network-%s"
}
resource "google_compute_subnetwork" "inst-test-subnetwork" {
name = "inst-test-subnetwork-%s"
ip_cidr_range = "10.0.0.0/16"
region = "us-central1"
network = "${google_compute_network.inst-test-network.self_link}"
}
resource "google_compute_instance" "foobar" {
name = "%s"
machine_type = "n1-standard-1"
zone = "us-central1-a"
disk {
image = "debian-7-wheezy-v20160301"
}
network_interface {
subnetwork = "${google_compute_subnetwork.inst-test-subnetwork.name}"
access_config { }
}
}`, acctest.RandString(10), acctest.RandString(10), instance)
}
func testAccComputeInstance_address_custom(instance, address string) string {
return fmt.Sprintf(`
resource "google_compute_network" "inst-test-network" {
name = "inst-test-network-%s"
}
resource "google_compute_subnetwork" "inst-test-subnetwork" {
name = "inst-test-subnetwork-%s"
ip_cidr_range = "10.0.0.0/16"
region = "us-central1"
network = "${google_compute_network.inst-test-network.self_link}"
}
resource "google_compute_instance" "foobar" {
name = "%s"
machine_type = "n1-standard-1"
zone = "us-central1-a"
disk {
image = "debian-7-wheezy-v20160301"
}
network_interface {
subnetwork = "${google_compute_subnetwork.inst-test-subnetwork.name}"
address = "%s"
access_config { }
}
}`, acctest.RandString(10), acctest.RandString(10), instance, address)
}

View File

@ -139,6 +139,9 @@ The `network_interface` block supports:
to. The subnetwork must exist in the same region this instance will be
created in. Either `network` or `subnetwork` must be provided.
* `address` - (Optional) The private IP address to assign to the instance. If
empty, the address will be automatically assigned.
* `access_config` - (Optional) Access configurations, i.e. IPs via which this
instance can be accessed via the Internet. Omit to ensure that the instance
is not accessible from the Internet (this means that ssh provisioners will
@ -189,7 +192,7 @@ exported:
* `tags_fingerprint` - The unique fingerprint of the tags.
* `network_interface.0.address` - The internal ip address of the instance (usually on the 10.x.x.x range).
* `network_interface.0.address` - The internal ip address of the instance, either manually or dynamically assigned.
* `network_interface.0.access_config.0.assigned_nat_ip` - If the instance has an access config, either the given external ip (in the `nat_ip` field) or the ephemeral (generated) ip (if you didn't provide one).