mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-07-05 17:52:38 +00:00
Add subnetwork secondary ip ranges beta feature (#310)
This commit is contained in:
parent
f49e29411c
commit
52daf4097a
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
|
||||
computeBeta "google.golang.org/api/compute/v0.beta"
|
||||
"google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
|
@ -91,3 +92,13 @@ func computeOperationWaitTime(config *Config, op *compute.Operation, project, ac
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func computeBetaOperationWaitTime(config *Config, op *computeBeta.Operation, project, activity string, timeoutMin int) error {
|
||||
opV1 := &compute.Operation{}
|
||||
err := Convert(op, opV1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return computeOperationWaitTime(config, opV1, project, activity, 4)
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ func computeSharedOperationWaitTime(config *Config, op interface{}, project stri
|
|||
case *compute.Operation:
|
||||
return computeOperationWaitTime(config, op.(*compute.Operation), project, activity, minutes)
|
||||
case *computeBeta.Operation:
|
||||
return computeBetaOperationWaitGlobalTime(config, op.(*computeBeta.Operation), project, activity, minutes)
|
||||
return computeBetaOperationWaitTime(config, op.(*computeBeta.Operation), project, activity, minutes)
|
||||
default:
|
||||
panic("Attempted to wait on an Operation of unknown type.")
|
||||
}
|
||||
|
|
|
@ -7,9 +7,18 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
computeBeta "google.golang.org/api/compute/v0.beta"
|
||||
"google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
var SubnetworkBaseApiVersion = v1
|
||||
var SubnetworkVersionedFeatures = []Feature{
|
||||
{
|
||||
Version: v0beta,
|
||||
Item: "secondary_ip_range",
|
||||
},
|
||||
}
|
||||
|
||||
func resourceComputeSubnetwork() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceComputeSubnetworkCreate,
|
||||
|
@ -37,7 +46,7 @@ func resourceComputeSubnetwork() *schema.Resource {
|
|||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
DiffSuppressFunc: linkDiffSuppress,
|
||||
DiffSuppressFunc: compareGlobalSelfLinkOrResourceName,
|
||||
},
|
||||
|
||||
"description": &schema.Schema{
|
||||
|
@ -68,6 +77,27 @@ func resourceComputeSubnetwork() *schema.Resource {
|
|||
Optional: true,
|
||||
},
|
||||
|
||||
"secondary_ip_range": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"range_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateGCPName,
|
||||
},
|
||||
"ip_cidr_range": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"self_link": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
|
@ -76,18 +106,8 @@ func resourceComputeSubnetwork() *schema.Resource {
|
|||
}
|
||||
}
|
||||
|
||||
func createSubnetID(s *compute.Subnetwork) string {
|
||||
return fmt.Sprintf("%s/%s", s.Region, s.Name)
|
||||
}
|
||||
|
||||
func splitSubnetID(id string) (region string, name string) {
|
||||
parts := strings.Split(id, "/")
|
||||
region = parts[0]
|
||||
name = parts[1]
|
||||
return
|
||||
}
|
||||
|
||||
func resourceComputeSubnetworkCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, SubnetworkBaseApiVersion, SubnetworkVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
region, err := getRegion(d, config)
|
||||
|
@ -106,17 +126,32 @@ func resourceComputeSubnetworkCreate(d *schema.ResourceData, meta interface{}) e
|
|||
}
|
||||
|
||||
// Build the subnetwork parameters
|
||||
subnetwork := &compute.Subnetwork{
|
||||
subnetwork := &computeBeta.Subnetwork{
|
||||
Name: d.Get("name").(string),
|
||||
Description: d.Get("description").(string),
|
||||
IpCidrRange: d.Get("ip_cidr_range").(string),
|
||||
PrivateIpGoogleAccess: d.Get("private_ip_google_access").(bool),
|
||||
SecondaryIpRanges: expandSecondaryRanges(d.Get("secondary_ip_range").([]interface{})),
|
||||
Network: network,
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Subnetwork insert request: %#v", subnetwork)
|
||||
op, err := config.clientCompute.Subnetworks.Insert(
|
||||
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
subnetworkV1 := &compute.Subnetwork{}
|
||||
err := Convert(subnetwork, subnetworkV1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientCompute.Subnetworks.Insert(
|
||||
project, region, subnetworkV1).Do()
|
||||
case v0beta:
|
||||
op, err = config.clientComputeBeta.Subnetworks.Insert(
|
||||
project, region, subnetwork).Do()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating subnetwork: %s", err)
|
||||
|
@ -128,9 +163,9 @@ func resourceComputeSubnetworkCreate(d *schema.ResourceData, meta interface{}) e
|
|||
// The same name can appear twice in a project, as long as each one is in a different region."
|
||||
// https://cloud.google.com/compute/docs/subnetworks
|
||||
subnetwork.Region = region
|
||||
d.SetId(createSubnetID(subnetwork))
|
||||
d.SetId(createBetaSubnetID(subnetwork))
|
||||
|
||||
err = computeOperationWait(config, op, project, "Creating Subnetwork")
|
||||
err = computeSharedOperationWait(config, op, project, "Creating Subnetwork")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -139,6 +174,7 @@ func resourceComputeSubnetworkCreate(d *schema.ResourceData, meta interface{}) e
|
|||
}
|
||||
|
||||
func resourceComputeSubnetworkRead(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, SubnetworkBaseApiVersion, SubnetworkVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
region, err := getRegion(d, config)
|
||||
|
@ -153,24 +189,41 @@ func resourceComputeSubnetworkRead(d *schema.ResourceData, meta interface{}) err
|
|||
|
||||
name := d.Get("name").(string)
|
||||
|
||||
subnetwork, err := config.clientCompute.Subnetworks.Get(
|
||||
subnetwork := &computeBeta.Subnetwork{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
subnetworkV1, err := config.clientCompute.Subnetworks.Get(
|
||||
project, region, name).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Subnetwork %q", name))
|
||||
}
|
||||
|
||||
err = Convert(subnetworkV1, subnetwork)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case v0beta:
|
||||
var err error
|
||||
subnetwork, err = config.clientComputeBeta.Subnetworks.Get(project, region, name).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Subnetwork %q", name))
|
||||
}
|
||||
}
|
||||
|
||||
d.Set("name", subnetwork.Name)
|
||||
d.Set("ip_cidr_range", subnetwork.IpCidrRange)
|
||||
d.Set("network", subnetwork.Network)
|
||||
d.Set("description", subnetwork.Description)
|
||||
d.Set("private_ip_google_access", subnetwork.PrivateIpGoogleAccess)
|
||||
d.Set("gateway_address", subnetwork.GatewayAddress)
|
||||
d.Set("self_link", subnetwork.SelfLink)
|
||||
d.Set("secondary_ip_range", flattenSecondaryRanges(subnetwork.SecondaryIpRanges))
|
||||
d.Set("self_link", ConvertSelfLinkToV1(subnetwork.SelfLink))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceComputeSubnetworkUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersionUpdate(d, SubnetworkBaseApiVersion, SubnetworkVersionedFeatures, []Feature{})
|
||||
config := meta.(*Config)
|
||||
|
||||
region, err := getRegion(d, config)
|
||||
|
@ -186,18 +239,34 @@ func resourceComputeSubnetworkUpdate(d *schema.ResourceData, meta interface{}) e
|
|||
d.Partial(true)
|
||||
|
||||
if d.HasChange("private_ip_google_access") {
|
||||
subnetworksSetPrivateIpGoogleAccessRequest := &compute.SubnetworksSetPrivateIpGoogleAccessRequest{
|
||||
subnetworksSetPrivateIpGoogleAccessRequest := &computeBeta.SubnetworksSetPrivateIpGoogleAccessRequest{
|
||||
PrivateIpGoogleAccess: d.Get("private_ip_google_access").(bool),
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Updating Subnetwork PrivateIpGoogleAccess %q: %#v", d.Id(), subnetworksSetPrivateIpGoogleAccessRequest)
|
||||
op, err := config.clientCompute.Subnetworks.SetPrivateIpGoogleAccess(
|
||||
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
subnetworksSetPrivateIpGoogleAccessRequestV1 := &compute.SubnetworksSetPrivateIpGoogleAccessRequest{}
|
||||
err := Convert(subnetworksSetPrivateIpGoogleAccessRequest, subnetworksSetPrivateIpGoogleAccessRequestV1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err = config.clientCompute.Subnetworks.SetPrivateIpGoogleAccess(
|
||||
project, region, d.Get("name").(string), subnetworksSetPrivateIpGoogleAccessRequestV1).Do()
|
||||
case v0beta:
|
||||
op, err = config.clientComputeBeta.Subnetworks.SetPrivateIpGoogleAccess(
|
||||
project, region, d.Get("name").(string), subnetworksSetPrivateIpGoogleAccessRequest).Do()
|
||||
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating subnetwork PrivateIpGoogleAccess: %s", err)
|
||||
}
|
||||
|
||||
err = computeOperationWait(config, op, project, "Updating Subnetwork PrivateIpGoogleAccess")
|
||||
err = computeSharedOperationWait(config, op, project, "Updating Subnetwork PrivateIpGoogleAccess")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -211,6 +280,7 @@ func resourceComputeSubnetworkUpdate(d *schema.ResourceData, meta interface{}) e
|
|||
}
|
||||
|
||||
func resourceComputeSubnetworkDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
computeApiVersion := getComputeApiVersion(d, SubnetworkBaseApiVersion, SubnetworkVersionedFeatures)
|
||||
config := meta.(*Config)
|
||||
|
||||
region, err := getRegion(d, config)
|
||||
|
@ -224,13 +294,20 @@ func resourceComputeSubnetworkDelete(d *schema.ResourceData, meta interface{}) e
|
|||
}
|
||||
|
||||
// Delete the subnetwork
|
||||
op, err := config.clientCompute.Subnetworks.Delete(
|
||||
var op interface{}
|
||||
switch computeApiVersion {
|
||||
case v1:
|
||||
op, err = config.clientCompute.Subnetworks.Delete(
|
||||
project, region, d.Get("name").(string)).Do()
|
||||
case v0beta:
|
||||
op, err = config.clientComputeBeta.Subnetworks.Delete(
|
||||
project, region, d.Get("name").(string)).Do()
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting subnetwork: %s", err)
|
||||
}
|
||||
|
||||
err = computeOperationWait(config, op, project, "Deleting Subnetwork")
|
||||
err = computeSharedOperationWait(config, op, project, "Deleting Subnetwork")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -256,3 +333,45 @@ func resourceComputeSubnetworkImportState(d *schema.ResourceData, meta interface
|
|||
|
||||
return []*schema.ResourceData{d}, nil
|
||||
}
|
||||
|
||||
func createBetaSubnetID(s *computeBeta.Subnetwork) string {
|
||||
return fmt.Sprintf("%s/%s", s.Region, s.Name)
|
||||
}
|
||||
|
||||
func createSubnetID(s *compute.Subnetwork) string {
|
||||
return fmt.Sprintf("%s/%s", s.Region, s.Name)
|
||||
}
|
||||
|
||||
func splitSubnetID(id string) (region string, name string) {
|
||||
parts := strings.Split(id, "/")
|
||||
region = parts[0]
|
||||
name = parts[1]
|
||||
return
|
||||
}
|
||||
|
||||
func expandSecondaryRanges(configured []interface{}) []*computeBeta.SubnetworkSecondaryRange {
|
||||
secondaryRanges := make([]*computeBeta.SubnetworkSecondaryRange, 0, len(configured))
|
||||
for _, raw := range configured {
|
||||
data := raw.(map[string]interface{})
|
||||
secondaryRange := computeBeta.SubnetworkSecondaryRange{
|
||||
RangeName: data["range_name"].(string),
|
||||
IpCidrRange: data["ip_cidr_range"].(string),
|
||||
}
|
||||
|
||||
secondaryRanges = append(secondaryRanges, &secondaryRange)
|
||||
}
|
||||
return secondaryRanges
|
||||
}
|
||||
|
||||
func flattenSecondaryRanges(secondaryRanges []*computeBeta.SubnetworkSecondaryRange) []map[string]interface{} {
|
||||
secondaryRangesSchema := make([]map[string]interface{}, 0, len(secondaryRanges))
|
||||
for _, secondaryRange := range secondaryRanges {
|
||||
data := map[string]interface{}{
|
||||
"range_name": secondaryRange.RangeName,
|
||||
"ip_cidr_range": secondaryRange.IpCidrRange,
|
||||
}
|
||||
|
||||
secondaryRangesSchema = append(secondaryRangesSchema, data)
|
||||
}
|
||||
return secondaryRangesSchema
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import (
|
|||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"google.golang.org/api/compute/v1"
|
||||
|
||||
computeBeta "google.golang.org/api/compute/v0.beta"
|
||||
)
|
||||
|
||||
func TestAccComputeSubnetwork_basic(t *testing.T) {
|
||||
|
@ -70,6 +72,28 @@ func TestAccComputeSubnetwork_update(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAccComputeSubnetwork_secondaryIpRanges(t *testing.T) {
|
||||
var subnetwork computeBeta.Subnetwork
|
||||
|
||||
cnName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
|
||||
subnetworkName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckComputeSubnetworkDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccComputeSubnetwork_secondaryIpRanges(cnName, subnetworkName),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckComputeBetaSubnetworkExists("google_compute_subnetwork.network-with-private-secondary-ip-range", &subnetwork),
|
||||
testAccCheckComputeSubnetworkHasSecondaryIpRange(&subnetwork, "tf-test-secondary-range", "192.168.1.0/24"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckComputeSubnetworkDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
|
@ -119,6 +143,51 @@ func testAccCheckComputeSubnetworkExists(n string, subnetwork *compute.Subnetwor
|
|||
}
|
||||
}
|
||||
|
||||
func testAccCheckComputeBetaSubnetworkExists(n string, subnetwork *computeBeta.Subnetwork) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No ID is set")
|
||||
}
|
||||
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
region, subnet_name := splitSubnetID(rs.Primary.ID)
|
||||
found, err := config.clientComputeBeta.Subnetworks.Get(
|
||||
config.Project, region, subnet_name).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if found.Name != subnet_name {
|
||||
return fmt.Errorf("Subnetwork not found")
|
||||
}
|
||||
|
||||
*subnetwork = *found
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckComputeSubnetworkHasSecondaryIpRange(subnetwork *computeBeta.Subnetwork, rangeName, ipCidrRange string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
for _, secondaryRange := range subnetwork.SecondaryIpRanges {
|
||||
if secondaryRange.RangeName == rangeName {
|
||||
if secondaryRange.IpCidrRange == ipCidrRange {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Secondary range %s has the wrong ip_cidr_range. Expected %s, got %s", rangeName, ipCidrRange, secondaryRange.IpCidrRange)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("Secondary range %s not found", rangeName)
|
||||
}
|
||||
}
|
||||
|
||||
func testAccComputeSubnetwork_basic(cnName, subnetwork1Name, subnetwork2Name, subnetwork3Name string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_compute_network" "custom-test" {
|
||||
|
@ -183,3 +252,23 @@ resource "google_compute_subnetwork" "network-with-private-google-access" {
|
|||
}
|
||||
`, cnName, subnetworkName)
|
||||
}
|
||||
|
||||
func testAccComputeSubnetwork_secondaryIpRanges(cnName, subnetworkName string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_compute_network" "custom-test" {
|
||||
name = "%s"
|
||||
auto_create_subnetworks = false
|
||||
}
|
||||
|
||||
resource "google_compute_subnetwork" "network-with-private-secondary-ip-range" {
|
||||
name = "%s"
|
||||
ip_cidr_range = "10.2.0.0/16"
|
||||
region = "us-central1"
|
||||
network = "${google_compute_network.custom-test.self_link}"
|
||||
secondary_ip_range {
|
||||
range_name = "tf-test-secondary-range"
|
||||
ip_cidr_range = "192.168.1.0/24"
|
||||
}
|
||||
}
|
||||
`, cnName, subnetworkName)
|
||||
}
|
||||
|
|
|
@ -28,6 +28,17 @@ func compareSelfLinkRelativePaths(k, old, new string, d *schema.ResourceData) bo
|
|||
return false
|
||||
}
|
||||
|
||||
// Use this method when the field accepts either a name or a self_link referencing a global resource.
|
||||
func compareGlobalSelfLinkOrResourceName(k, old, new string, d *schema.ResourceData) bool {
|
||||
oldParts := strings.Split(old, "/")
|
||||
newParts := strings.Split(new, "/")
|
||||
|
||||
if oldParts[len(oldParts)-1] == newParts[len(newParts)-1] {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Hash the relative path of a self link.
|
||||
func selfLinkRelativePathHash(selfLink interface{}) int {
|
||||
path, _ := getRelativePath(selfLink.(string))
|
||||
|
|
|
@ -56,6 +56,16 @@ The following arguments are supported:
|
|||
can access Google services without assigned external IP
|
||||
addresses.
|
||||
|
||||
- - -
|
||||
|
||||
* `secondary_ip_range` - (Optional, Beta) An array of configurations for secondary IP ranges for VM instances contained in this subnetwork. Structure is documented below.
|
||||
|
||||
The `secondary_ip_range` block supports:
|
||||
|
||||
* `range_name` - (Required) The name associated with this subnetwork secondary range, used when adding an alias IP range to a VM instance.
|
||||
|
||||
* `ip_cidr_range` - (Required) The range of IP addresses belonging to this subnetwork secondary range. Ranges must be unique and non-overlapping with all primary and secondary IP ranges within a network.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
In addition to the arguments listed above, the following computed attributes are
|
||||
|
|
Loading…
Reference in New Issue
Block a user