mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-07-03 08:42:39 +00:00
google_compute_instance can specified the subnetwork using a self_link (#290)
This commit is contained in:
parent
b95fb1b6f9
commit
3fde8cf24e
|
@ -13,6 +13,7 @@ import (
|
|||
computeBeta "google.golang.org/api/compute/v0.beta"
|
||||
"google.golang.org/api/compute/v1"
|
||||
"google.golang.org/api/googleapi"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// Global MutexKV
|
||||
|
@ -273,6 +274,46 @@ func getNetworkLink(d *schema.ResourceData, config *Config, field string) (strin
|
|||
}
|
||||
}
|
||||
|
||||
// Reads the "subnetwork" fields from the given resource data and if the value is:
|
||||
// - a resource URL, returns the string unchanged
|
||||
// - a subnetwork name, looks up the resource URL using the google client.
|
||||
//
|
||||
// If `subnetworkField` is a resource url, `subnetworkProjectField` cannot be set.
|
||||
// If `subnetworkField` is a subnetwork name, `subnetworkProjectField` will be used
|
||||
// as the project if set. If not, we fallback on the default project.
|
||||
func getSubnetworkLink(d *schema.ResourceData, config *Config, subnetworkField, subnetworkProjectField, zoneField string) (string, error) {
|
||||
if v, ok := d.GetOk(subnetworkField); ok {
|
||||
subnetwork := v.(string)
|
||||
r := regexp.MustCompile(SubnetworkLinkRegex)
|
||||
if r.MatchString(subnetwork) {
|
||||
return subnetwork, nil
|
||||
}
|
||||
|
||||
var project string
|
||||
if subnetworkProject, ok := d.GetOk(subnetworkProjectField); ok {
|
||||
project = subnetworkProject.(string)
|
||||
} else {
|
||||
var err error
|
||||
project, err = getProject(d, config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
region := getRegionFromZone(d.Get(zoneField).(string))
|
||||
|
||||
subnet, err := config.clientCompute.Subnetworks.Get(project, region, subnetwork).Do()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf(
|
||||
"Error referencing subnetwork '%s' in region '%s': %s",
|
||||
subnetwork, region, err)
|
||||
}
|
||||
|
||||
return subnet.SelfLink, nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// getNetworkName reads the "network" field from the given resource data and if the value:
|
||||
// - is a resource URL, extracts the network name from the URL and returns it
|
||||
// - is the network name only (i.e not prefixed with http://www.googleapis.com/compute/...), is returned unchanged
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/hashicorp/terraform/helper/validation"
|
||||
"google.golang.org/api/compute/v1"
|
||||
"google.golang.org/api/googleapi"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func stringScopeHashcode(v interface{}) int {
|
||||
|
@ -278,20 +279,26 @@ func resourceComputeInstance() *schema.Resource {
|
|||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"network": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
DiffSuppressFunc: linkDiffSuppress,
|
||||
ConflictsWith: []string{"network_interface.0.subnetwork", "network_interface.0.subnetwork_project"},
|
||||
},
|
||||
|
||||
"subnetwork": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
DiffSuppressFunc: linkDiffSuppress,
|
||||
},
|
||||
|
||||
"subnetwork_project": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
|
@ -704,34 +711,21 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
|
|||
prefix := fmt.Sprintf("network_interface.%d", i)
|
||||
// Load up the name of this network_interface
|
||||
networkName := d.Get(prefix + ".network").(string)
|
||||
subnetworkName := d.Get(prefix + ".subnetwork").(string)
|
||||
subnetworkProject := d.Get(prefix + ".subnetwork_project").(string)
|
||||
address := d.Get(prefix + ".address").(string)
|
||||
var networkLink, subnetworkLink string
|
||||
|
||||
if networkName != "" && subnetworkName != "" {
|
||||
return fmt.Errorf("Cannot specify both network and subnetwork values.")
|
||||
} else if networkName != "" {
|
||||
if networkName != "" {
|
||||
networkLink, err = getNetworkLink(d, config, prefix+".network")
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error referencing network '%s': %s",
|
||||
networkName, err)
|
||||
}
|
||||
|
||||
} else {
|
||||
region := getRegionFromZone(d.Get("zone").(string))
|
||||
if subnetworkProject == "" {
|
||||
subnetworkProject = project
|
||||
}
|
||||
subnetwork, err := config.clientCompute.Subnetworks.Get(
|
||||
subnetworkProject, region, subnetworkName).Do()
|
||||
subnetworkLink, err = getSubnetworkLink(d, config, prefix+".subnetwork", prefix+".subnetwork_project", "zone")
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error referencing subnetwork '%s' in region '%s': %s",
|
||||
subnetworkName, region, err)
|
||||
return err
|
||||
}
|
||||
subnetworkLink = subnetwork.SelfLink
|
||||
}
|
||||
|
||||
// Build the networkInterface
|
||||
|
@ -961,9 +955,9 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error
|
|||
networkInterfaces = append(networkInterfaces, map[string]interface{}{
|
||||
"name": iface.Name,
|
||||
"address": iface.NetworkIP,
|
||||
"network": d.Get(fmt.Sprintf("network_interface.%d.network", i)),
|
||||
"subnetwork": d.Get(fmt.Sprintf("network_interface.%d.subnetwork", i)),
|
||||
"subnetwork_project": d.Get(fmt.Sprintf("network_interface.%d.subnetwork_project", i)),
|
||||
"network": iface.Network,
|
||||
"subnetwork": iface.Subnetwork,
|
||||
"subnetwork_project": getProjectFromSubnetworkLink(iface.Subnetwork),
|
||||
"access_config": accessConfigs,
|
||||
})
|
||||
}
|
||||
|
@ -1452,3 +1446,12 @@ func flattenScratchDisk(disk *compute.AttachedDisk) map[string]interface{} {
|
|||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func getProjectFromSubnetworkLink(subnetwork string) string {
|
||||
r := regexp.MustCompile(SubnetworkLinkRegex)
|
||||
if !r.MatchString(subnetwork) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return r.FindStringSubmatch(subnetwork)[1]
|
||||
}
|
||||
|
|
|
@ -1609,7 +1609,7 @@ resource "google_compute_instance" "foobar" {
|
|||
}
|
||||
|
||||
network_interface {
|
||||
subnetwork = "${google_compute_subnetwork.inst-test-subnetwork.name}"
|
||||
subnetwork = "${google_compute_subnetwork.inst-test-subnetwork.self_link}"
|
||||
access_config { }
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,14 @@ import (
|
|||
"regexp"
|
||||
)
|
||||
|
||||
// Copied from the official Google Cloud auto-generated client.
|
||||
const ProjectRegex = "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))"
|
||||
const (
|
||||
// Copied from the official Google Cloud auto-generated client.
|
||||
ProjectRegex = "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))"
|
||||
RegionRegex = "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?"
|
||||
SubnetworkRegex = "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?"
|
||||
|
||||
SubnetworkLinkRegex = "projects/(" + ProjectRegex + ")/regions/(" + RegionRegex + ")/subnetworks/(" + SubnetworkRegex + ")$"
|
||||
)
|
||||
|
||||
func validateGCPName(v interface{}, k string) (ws []string, errors []error) {
|
||||
re := `^(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)$`
|
||||
|
|
|
@ -210,12 +210,14 @@ The `network_interface` block supports:
|
|||
* `network` - (Optional) The name or self_link of the network to attach this interface to.
|
||||
Either `network` or `subnetwork` must be provided.
|
||||
|
||||
* `subnetwork` - (Optional) The name of the subnetwork to attach this interface
|
||||
to. The subnetwork must exist in the same region this instance will be
|
||||
* `subnetwork` - (Optional) The name or self_link of the subnetwork to attach this
|
||||
interface to. The subnetwork must exist in the same region this instance will be
|
||||
created in. Either `network` or `subnetwork` must be provided.
|
||||
|
||||
* `subnetwork_project` - (Optional) The project in which the subnetwork belongs.
|
||||
If it is not provided, the provider project is used.
|
||||
If the `subnetwork` is a self_link, this field is ignored in favor of the project
|
||||
defined in the subnetwork self_link. If the `subnetwork` is a name and this
|
||||
field is not provided, the provider project is used.
|
||||
|
||||
* `address` - (Optional) The private IP address to assign to the instance. If
|
||||
empty, the address will be automatically assigned.
|
||||
|
|
Loading…
Reference in New Issue
Block a user