mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-07-01 07:42:40 +00:00
add new compute_instance_from_template resource (#1652)
This was done as its own resource as suggested in slack, since we don't have the option of making all fields Computed in google_compute_instance. There's precedent in the aws provider for this sort of thing (see ami_copy, ami_from_instance). When I started working on this I assumed I could do it in the compute_instance resource and so I went ahead and reordered the schema to make it easier to work with in the future. Now it's not quite relevant, but I left it in as its own commit that can be looked at separately from the other changes. Fixes #1582.
This commit is contained in:
parent
cf4451177e
commit
7e04cee958
|
@ -62,6 +62,10 @@ func ParseInstanceGroupFieldValue(instanceGroup string, d TerraformResourceData,
|
|||
return parseZonalFieldValue("instanceGroups", instanceGroup, "project", "zone", d, config, false)
|
||||
}
|
||||
|
||||
func ParseInstanceTemplateFieldValue(instanceTemplate string, d TerraformResourceData, config *Config) (*GlobalFieldValue, error) {
|
||||
return parseGlobalFieldValue("instanceTemplates", instanceTemplate, "project", d, config, false)
|
||||
}
|
||||
|
||||
func ParseSecurityPolicyFieldValue(securityPolicy string, d TerraformResourceData, config *Config) (*GlobalFieldValue, error) {
|
||||
return parseGlobalFieldValue("securityPolicies", securityPolicy, "project", d, config, true)
|
||||
}
|
||||
|
|
|
@ -120,6 +120,7 @@ func Provider() terraform.ResourceProvider {
|
|||
"google_compute_health_check": resourceComputeHealthCheck(),
|
||||
"google_compute_image": resourceComputeImage(),
|
||||
"google_compute_instance": resourceComputeInstance(),
|
||||
"google_compute_instance_from_template": resourceComputeInstanceFromTemplate(),
|
||||
"google_compute_instance_group": resourceComputeInstanceGroup(),
|
||||
"google_compute_instance_group_manager": resourceComputeInstanceGroupManager(),
|
||||
"google_compute_instance_template": resourceComputeInstanceTemplate(),
|
||||
|
|
|
@ -122,126 +122,6 @@ func resourceComputeInstance() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"scratch_disk": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"interface": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Default: "SCSI",
|
||||
ValidateFunc: validation.StringInSlice([]string{"SCSI", "NVME"}, false),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"disk": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Removed: "Use boot_disk, scratch_disk, and attached_disk instead",
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
// TODO(mitchellh): one of image or disk is required
|
||||
|
||||
"disk": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"image": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"scratch": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"auto_delete": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"size": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"device_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"disk_encryption_key_raw": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Sensitive: true,
|
||||
},
|
||||
|
||||
"disk_encryption_key_sha256": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"attached_disk": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"source": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
DiffSuppressFunc: linkDiffSuppress,
|
||||
},
|
||||
|
||||
"device_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"mode": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Default: "READ_WRITE",
|
||||
ValidateFunc: validation.StringInSlice([]string{"READ_WRITE", "READ_ONLY"}, false),
|
||||
},
|
||||
|
||||
"disk_encryption_key_raw": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Sensitive: true,
|
||||
},
|
||||
|
||||
"disk_encryption_key_sha256": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"machine_type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
|
@ -253,48 +133,6 @@ func resourceComputeInstance() *schema.Resource {
|
|||
ForceNew: true,
|
||||
},
|
||||
|
||||
"instance_id": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"zone": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"can_ip_forward": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"description": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"metadata": &schema.Schema{
|
||||
Type: schema.TypeMap,
|
||||
Optional: true,
|
||||
Elem: schema.TypeString,
|
||||
},
|
||||
|
||||
"metadata_startup_script": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"metadata_fingerprint": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"network_interface": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Required: true,
|
||||
|
@ -400,6 +238,187 @@ func resourceComputeInstance() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"allow_stopping_for_update": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"attached_disk": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"source": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
DiffSuppressFunc: linkDiffSuppress,
|
||||
},
|
||||
|
||||
"device_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"mode": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Default: "READ_WRITE",
|
||||
ValidateFunc: validation.StringInSlice([]string{"READ_WRITE", "READ_ONLY"}, false),
|
||||
},
|
||||
|
||||
"disk_encryption_key_raw": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Sensitive: true,
|
||||
},
|
||||
|
||||
"disk_encryption_key_sha256": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"can_ip_forward": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"create_timeout": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 4,
|
||||
Deprecated: "Use timeouts block instead.",
|
||||
},
|
||||
|
||||
"description": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"deletion_protection": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
|
||||
"disk": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Removed: "Use boot_disk, scratch_disk, and attached_disk instead",
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
// TODO(mitchellh): one of image or disk is required
|
||||
|
||||
"disk": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"image": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"scratch": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"auto_delete": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"size": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"device_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"disk_encryption_key_raw": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Sensitive: true,
|
||||
},
|
||||
|
||||
"disk_encryption_key_sha256": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"guest_accelerator": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"count": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
DiffSuppressFunc: linkDiffSuppress,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"labels": &schema.Schema{
|
||||
Type: schema.TypeMap,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
Set: schema.HashString,
|
||||
},
|
||||
|
||||
"metadata": &schema.Schema{
|
||||
Type: schema.TypeMap,
|
||||
Optional: true,
|
||||
Elem: schema.TypeString,
|
||||
},
|
||||
|
||||
"metadata_startup_script": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"min_cpu_platform": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"network": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
|
@ -444,11 +463,6 @@ func resourceComputeInstance() *schema.Resource {
|
|||
ForceNew: true,
|
||||
},
|
||||
|
||||
"self_link": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"scheduling": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
MaxItems: 1,
|
||||
|
@ -478,6 +492,22 @@ func resourceComputeInstance() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"scratch_disk": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"interface": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Default: "SCSI",
|
||||
ValidateFunc: validation.StringInSlice([]string{"SCSI", "NVME"}, false),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"service_account": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
MaxItems: 1,
|
||||
|
@ -505,38 +535,6 @@ func resourceComputeInstance() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"guest_accelerator": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"count": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
DiffSuppressFunc: linkDiffSuppress,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"cpu_platform": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"min_cpu_platform": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"tags": &schema.Schema{
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
|
@ -544,27 +542,21 @@ func resourceComputeInstance() *schema.Resource {
|
|||
Set: schema.HashString,
|
||||
},
|
||||
|
||||
"tags_fingerprint": &schema.Schema{
|
||||
"zone": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"cpu_platform": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"labels": &schema.Schema{
|
||||
Type: schema.TypeMap,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
Set: schema.HashString,
|
||||
},
|
||||
|
||||
"allow_stopping_for_update": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"deletion_protection": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
"instance_id": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"label_fingerprint": &schema.Schema{
|
||||
|
@ -572,11 +564,19 @@ func resourceComputeInstance() *schema.Resource {
|
|||
Computed: true,
|
||||
},
|
||||
|
||||
"create_timeout": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 4,
|
||||
Deprecated: "Use timeouts block instead.",
|
||||
"metadata_fingerprint": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"self_link": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"tags_fingerprint": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
CustomizeDiff: customdiff.All(
|
||||
|
@ -620,50 +620,36 @@ func getDisk(diskUri string, d *schema.ResourceData, config *Config) (*compute.D
|
|||
return disk, err
|
||||
}
|
||||
|
||||
func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the zone
|
||||
z, err := getZone(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("[DEBUG] Loading zone: %s", z)
|
||||
zone, err := config.clientCompute.Zones.Get(
|
||||
project, z).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error loading zone '%s': %s", z, err)
|
||||
}
|
||||
|
||||
func expandComputeInstance(project string, zone *compute.Zone, d *schema.ResourceData, config *Config) (*computeBeta.Instance, error) {
|
||||
// Get the machine type
|
||||
log.Printf("[DEBUG] Loading machine type: %s", d.Get("machine_type").(string))
|
||||
machineType, err := config.clientCompute.MachineTypes.Get(
|
||||
project, zone.Name, d.Get("machine_type").(string)).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error loading machine type: %s",
|
||||
err)
|
||||
var machineTypeUrl string
|
||||
if mt, ok := d.GetOk("machine_type"); ok {
|
||||
log.Printf("[DEBUG] Loading machine type: %s", mt.(string))
|
||||
machineType, err := config.clientCompute.MachineTypes.Get(
|
||||
project, zone.Name, mt.(string)).Do()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error loading machine type: %s",
|
||||
err)
|
||||
}
|
||||
machineTypeUrl = machineType.SelfLink
|
||||
}
|
||||
|
||||
// Build up the list of disks
|
||||
|
||||
disks := []*computeBeta.AttachedDisk{}
|
||||
bootDisk, err := expandBootDisk(d, config, zone, project)
|
||||
if err != nil {
|
||||
return err
|
||||
if _, hasBootDisk := d.GetOk("boot_disk"); hasBootDisk {
|
||||
bootDisk, err := expandBootDisk(d, config, zone, project)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
disks = append(disks, bootDisk)
|
||||
}
|
||||
disks = append(disks, bootDisk)
|
||||
|
||||
if _, hasScratchDisk := d.GetOk("scratch_disk"); hasScratchDisk {
|
||||
scratchDisks, err := expandScratchDisks(d, config, zone, project)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
disks = append(disks, scratchDisks...)
|
||||
}
|
||||
|
@ -674,7 +660,7 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
|
|||
diskConfig := d.Get(fmt.Sprintf("attached_disk.%d", i)).(map[string]interface{})
|
||||
disk, err := expandAttachedDisk(diskConfig, d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
disks = append(disks, disk)
|
||||
|
@ -696,34 +682,27 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
|
|||
}
|
||||
scheduling.ForceSendFields = []string{"AutomaticRestart", "Preemptible"}
|
||||
|
||||
// Read create timeout
|
||||
// Until "create_timeout" is removed, use that timeout if set.
|
||||
createTimeout := int(d.Timeout(schema.TimeoutCreate).Minutes())
|
||||
if v, ok := d.GetOk("create_timeout"); ok && v != 4 {
|
||||
createTimeout = v.(int)
|
||||
}
|
||||
|
||||
metadata, err := resourceInstanceMetadata(d)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating metadata: %s", err)
|
||||
return nil, fmt.Errorf("Error creating metadata: %s", err)
|
||||
}
|
||||
|
||||
networkInterfaces, err := expandNetworkInterfaces(d, config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating network interfaces: %s", err)
|
||||
return nil, fmt.Errorf("Error creating network interfaces: %s", err)
|
||||
}
|
||||
|
||||
accels, err := expandInstanceGuestAccelerators(d, config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating guest accelerators: %s", err)
|
||||
return nil, fmt.Errorf("Error creating guest accelerators: %s", err)
|
||||
}
|
||||
|
||||
// Create the instance information
|
||||
instance := &computeBeta.Instance{
|
||||
return &computeBeta.Instance{
|
||||
CanIpForward: d.Get("can_ip_forward").(bool),
|
||||
Description: d.Get("description").(string),
|
||||
Disks: disks,
|
||||
MachineType: machineType.SelfLink,
|
||||
MachineType: machineTypeUrl,
|
||||
Metadata: metadata,
|
||||
Name: d.Get("name").(string),
|
||||
NetworkInterfaces: networkInterfaces,
|
||||
|
@ -734,6 +713,40 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
|
|||
MinCpuPlatform: d.Get("min_cpu_platform").(string),
|
||||
Scheduling: scheduling,
|
||||
DeletionProtection: d.Get("deletion_protection").(bool),
|
||||
ForceSendFields: []string{"CanIpForward", "DeletionProtection"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the zone
|
||||
z, err := getZone(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("[DEBUG] Loading zone: %s", z)
|
||||
zone, err := config.clientCompute.Zones.Get(
|
||||
project, z).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error loading zone '%s': %s", z, err)
|
||||
}
|
||||
|
||||
instance, err := expandComputeInstance(project, zone, d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read create timeout
|
||||
// Until "create_timeout" is removed, use that timeout if set.
|
||||
createTimeout := int(d.Timeout(schema.TimeoutCreate).Minutes())
|
||||
if v, ok := d.GetOk("create_timeout"); ok && v != 4 {
|
||||
createTimeout = v.(int)
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Requesting instance creation")
|
||||
|
@ -804,7 +817,9 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Set("network_interface", networkInterfaces)
|
||||
if err := d.Set("network_interface", networkInterfaces); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Fall back on internal ip if there is no external ip. This makes sense in the situation where
|
||||
// terraform is being used on a cloud instance and can therefore access the instances it creates
|
||||
|
@ -831,8 +846,8 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error
|
|||
d.Set("tags", convertStringArrToInterface(instance.Tags.Items))
|
||||
}
|
||||
|
||||
if len(instance.Labels) > 0 {
|
||||
d.Set("labels", instance.Labels)
|
||||
if err := d.Set("labels", instance.Labels); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if instance.LabelFingerprint != "" {
|
||||
|
|
139
google/resource_compute_instance_from_template.go
Normal file
139
google/resource_compute_instance_from_template.go
Normal file
|
@ -0,0 +1,139 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
strcase "github.com/stoewer/go-strcase"
|
||||
)
|
||||
|
||||
func resourceComputeInstanceFromTemplate() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceComputeInstanceFromTemplateCreate,
|
||||
Read: resourceComputeInstanceRead,
|
||||
Update: resourceComputeInstanceUpdate,
|
||||
Delete: resourceComputeInstanceDelete,
|
||||
|
||||
// Import doesn't really make sense, because you could just import
|
||||
// as a google_compute_instance.
|
||||
|
||||
Timeouts: resourceComputeInstance().Timeouts,
|
||||
|
||||
Schema: computeInstanceFromTemplateSchema(),
|
||||
CustomizeDiff: resourceComputeInstance().CustomizeDiff,
|
||||
}
|
||||
}
|
||||
|
||||
func computeInstanceFromTemplateSchema() map[string]*schema.Schema {
|
||||
s := resourceComputeInstance().Schema
|
||||
|
||||
for _, field := range []string{"boot_disk", "machine_type", "network_interface"} {
|
||||
s[field].Required = false
|
||||
}
|
||||
|
||||
// Remove deprecated/removed fields that are never d.Set. We can't
|
||||
// programatically remove all of them, because some of them still have d.Set
|
||||
// calls.
|
||||
for _, field := range []string{"create_timeout", "disk", "network"} {
|
||||
delete(s, field)
|
||||
}
|
||||
|
||||
recurseOnSchema(s, func(field *schema.Schema) {
|
||||
// We don't want to accidentally use default values to override the instance
|
||||
// template, so remove defaults.
|
||||
field.Default = nil
|
||||
|
||||
// Make non-required fields computed since they'll be set by the template.
|
||||
// Leave deprecated and removed fields alone because we don't set them.
|
||||
if !field.Required && !(field.Deprecated != "" || field.Removed != "") {
|
||||
field.Computed = true
|
||||
}
|
||||
})
|
||||
|
||||
s["source_instance_template"] = &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func recurseOnSchema(s map[string]*schema.Schema, f func(*schema.Schema)) {
|
||||
for _, field := range s {
|
||||
f(field)
|
||||
if e := field.Elem; e != nil {
|
||||
if r, ok := e.(*schema.Resource); ok {
|
||||
recurseOnSchema(r.Schema, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func resourceComputeInstanceFromTemplateCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the zone
|
||||
z, err := getZone(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("[DEBUG] Loading zone: %s", z)
|
||||
zone, err := config.clientCompute.Zones.Get(project, z).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error loading zone '%s': %s", z, err)
|
||||
}
|
||||
|
||||
instance, err := expandComputeInstance(project, zone, d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Force send all top-level fields in case they're overridden to zero values.
|
||||
// TODO: consider doing so for nested fields as well.
|
||||
for f, s := range computeInstanceFromTemplateSchema() {
|
||||
// It seems that GetOkExists always returns true for sets.
|
||||
// TODO: confirm this and file issue against Terraform core.
|
||||
// In the meantime, don't force send sets.
|
||||
if s.Type == schema.TypeSet {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, exists := d.GetOkExists(f); exists {
|
||||
// Assume for now that all fields are exact snake_case versions of the API fields.
|
||||
// This won't necessarily always be true, but it serves as a good approximation and
|
||||
// can be adjusted later as we discover issues.
|
||||
instance.ForceSendFields = append(instance.ForceSendFields, strcase.UpperCamelCase(f))
|
||||
}
|
||||
}
|
||||
|
||||
tpl, err := ParseInstanceTemplateFieldValue(d.Get("source_instance_template").(string), d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Requesting instance creation")
|
||||
op, err := config.clientComputeBeta.Instances.Insert(project, zone.Name, instance).SourceInstanceTemplate(tpl.RelativeLink()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating instance: %s", err)
|
||||
}
|
||||
|
||||
// Store the ID now
|
||||
d.SetId(instance.Name)
|
||||
|
||||
// Wait for the operation to complete
|
||||
waitErr := computeSharedOperationWaitTime(config.clientCompute, op, project, int(d.Timeout(schema.TimeoutCreate).Minutes()), "instance to create")
|
||||
if waitErr != nil {
|
||||
// The resource didn't actually create
|
||||
d.SetId("")
|
||||
return waitErr
|
||||
}
|
||||
|
||||
return resourceComputeInstanceRead(d, meta)
|
||||
}
|
109
google/resource_compute_instance_from_template_test.go
Normal file
109
google/resource_compute_instance_from_template_test.go
Normal file
|
@ -0,0 +1,109 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
compute "google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
func TestAccComputeInstanceFromTemplate_basic(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var instance compute.Instance
|
||||
instanceName := fmt.Sprintf("terraform-test-%s", acctest.RandString(10))
|
||||
templateName := fmt.Sprintf("terraform-test-%s", acctest.RandString(10))
|
||||
resourceName := "google_compute_instance_from_template.foobar"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckComputeInstanceFromTemplateDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccComputeInstanceFromTemplate_basic(instanceName, templateName),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckComputeInstanceExists(resourceName, &instance),
|
||||
|
||||
// Check that fields were set based on the template
|
||||
resource.TestCheckResourceAttr(resourceName, "machine_type", "n1-standard-1"),
|
||||
resource.TestCheckResourceAttr(resourceName, "attached_disk.#", "1"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckComputeInstanceFromTemplateDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_compute_instance_from_template" {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err := config.clientCompute.Instances.Get(
|
||||
config.Project, rs.Primary.Attributes["zone"], rs.Primary.ID).Do()
|
||||
if err == nil {
|
||||
return fmt.Errorf("Instance still exists")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccComputeInstanceFromTemplate_basic(instance, template string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_compute_disk" "foobar" {
|
||||
name = "%s"
|
||||
image = "debian-8-jessie-v20160803"
|
||||
size = 10
|
||||
type = "pd-ssd"
|
||||
zone = "us-central1-a"
|
||||
}
|
||||
|
||||
resource "google_compute_instance_template" "foobar" {
|
||||
name = "%s"
|
||||
machine_type = "n1-standard-1"
|
||||
|
||||
disk {
|
||||
source_image = "debian-cloud/debian-8"
|
||||
auto_delete = true
|
||||
disk_size_gb = 100
|
||||
boot = true
|
||||
}
|
||||
|
||||
disk {
|
||||
source = "${google_compute_disk.foobar.name}"
|
||||
auto_delete = false
|
||||
boot = false
|
||||
}
|
||||
|
||||
network_interface {
|
||||
network = "default"
|
||||
}
|
||||
|
||||
metadata {
|
||||
foo = "bar"
|
||||
}
|
||||
|
||||
can_ip_forward = true
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "foobar" {
|
||||
name = "%s"
|
||||
zone = "us-central1-a"
|
||||
|
||||
source_instance_template = "${google_compute_instance_template.foobar.self_link}"
|
||||
|
||||
// Overrides
|
||||
can_ip_forward = false
|
||||
labels {
|
||||
my_key = "my_value"
|
||||
}
|
||||
}
|
||||
`, template, template, instance)
|
||||
}
|
21
vendor/github.com/stoewer/go-strcase/LICENSE
generated
vendored
Normal file
21
vendor/github.com/stoewer/go-strcase/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017, Adrian Stoewer <adrian.stoewer@rz.ifi.lmu.de>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
30
vendor/github.com/stoewer/go-strcase/README.md
generated
vendored
Normal file
30
vendor/github.com/stoewer/go-strcase/README.md
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
[![Build Status](https://travis-ci.org/stoewer/go-strcase.svg?branch=master)](https://travis-ci.org/stoewer/go-strcase)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/stoewer/go-strcase/badge.svg?branch=master)](https://coveralls.io/github/stoewer/go-strcase?branch=master)
|
||||
[![GoDoc](https://godoc.org/github.com/stoewer/go-strcase?status.svg)](https://godoc.org/github.com/stoewer/go-strcase)
|
||||
---
|
||||
|
||||
# Go strcase
|
||||
|
||||
The package `strcase` converts between different kinds of naming formats such as camel case
|
||||
(`CamelCase`), snake case (`snake_case`) or kebab case (`kebab-case`).
|
||||
The package is designed to work only with strings consisting of standard ASCII letters.
|
||||
Unicode is currently not supported.
|
||||
|
||||
## Versioning and stability
|
||||
|
||||
Although the master branch is supposed to remain always backward compatible, the repository
|
||||
contains version tags in order to support vendoring tools such as `glide`.
|
||||
The tag names follow semantic versioning conventions and have the following format `v1.0.0`.
|
||||
|
||||
|
||||
## Install and use
|
||||
|
||||
```sh
|
||||
go get -u github.com/stoewer/go-strcase
|
||||
```
|
||||
|
||||
```go
|
||||
import "github.com/stoewer/go-strcase"
|
||||
|
||||
var snake = strcase.SnakeCase("CamelCase")
|
||||
```
|
37
vendor/github.com/stoewer/go-strcase/camel.go
generated
vendored
Normal file
37
vendor/github.com/stoewer/go-strcase/camel.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2017, A. Stoewer <adrian.stoewer@rz.ifi.lmu.de>
|
||||
// All rights reserved.
|
||||
|
||||
package strcase
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// UpperCamelCase converts a string into camel case starting with a upper case letter.
|
||||
func UpperCamelCase(s string) string {
|
||||
return camelCase(s, true)
|
||||
}
|
||||
|
||||
// LowerCamelCase converts a string into camel case starting with a lower case letter.
|
||||
func LowerCamelCase(s string) string {
|
||||
return camelCase(s, false)
|
||||
}
|
||||
|
||||
func camelCase(s string, upper bool) string {
|
||||
s = strings.TrimSpace(s)
|
||||
buffer := make([]rune, 0, len(s))
|
||||
|
||||
var prev rune
|
||||
for _, curr := range s {
|
||||
if !isDelimiter(curr) {
|
||||
if isDelimiter(prev) || (upper && prev == 0) {
|
||||
buffer = append(buffer, toUpper(curr))
|
||||
} else {
|
||||
buffer = append(buffer, toLower(curr))
|
||||
}
|
||||
}
|
||||
prev = curr
|
||||
}
|
||||
|
||||
return string(buffer)
|
||||
}
|
8
vendor/github.com/stoewer/go-strcase/doc.go
generated
vendored
Normal file
8
vendor/github.com/stoewer/go-strcase/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
// Copyright (c) 2017, A. Stoewer <adrian.stoewer@rz.ifi.lmu.de>
|
||||
// All rights reserved.
|
||||
|
||||
// Package strcase converts between different kinds of naming formats such as camel case
|
||||
// (CamelCase), snake case (snake_case) or kebab case (`kebab-case`). The package is designed
|
||||
// to work only with strings consisting of standard ASCII letters. Unicode is currently not
|
||||
// supported.
|
||||
package strcase
|
44
vendor/github.com/stoewer/go-strcase/helper.go
generated
vendored
Normal file
44
vendor/github.com/stoewer/go-strcase/helper.go
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) 2017, A. Stoewer <adrian.stoewer@rz.ifi.lmu.de>
|
||||
// All rights reserved.
|
||||
|
||||
package strcase
|
||||
|
||||
// isLower checks if a character is lower case. More precisely it evaluates if it is
|
||||
// in the range of ASCII character 'a' to 'z'.
|
||||
func isLower(ch rune) bool {
|
||||
return ch >= 'a' && ch <= 'z'
|
||||
}
|
||||
|
||||
// toLower converts a character in the range of ASCII characters 'A' to 'Z' to its lower
|
||||
// case counterpart. Other characters remain the same.
|
||||
func toLower(ch rune) rune {
|
||||
if ch >= 'A' && ch <= 'Z' {
|
||||
return ch + 32
|
||||
}
|
||||
return ch
|
||||
}
|
||||
|
||||
// isLower checks if a character is upper case. More precisely it evaluates if it is
|
||||
// in the range of ASCII characters 'A' to 'Z'.
|
||||
func isUpper(ch rune) bool {
|
||||
return ch >= 'A' && ch <= 'Z'
|
||||
}
|
||||
|
||||
// toLower converts a character in the range of ASCII characters 'a' to 'z' to its lower
|
||||
// case counterpart. Other characters remain the same.
|
||||
func toUpper(ch rune) rune {
|
||||
if ch >= 'a' && ch <= 'z' {
|
||||
return ch - 32
|
||||
}
|
||||
return ch
|
||||
}
|
||||
|
||||
// isSpace checks if a character is some kind of whitespace.
|
||||
func isSpace(ch rune) bool {
|
||||
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'
|
||||
}
|
||||
|
||||
// isDelimiter checks if a character is some kind of whitespace or '_' or '-'.
|
||||
func isDelimiter(ch rune) bool {
|
||||
return ch == '-' || ch == '_' || isSpace(ch)
|
||||
}
|
9
vendor/github.com/stoewer/go-strcase/kebab.go
generated
vendored
Normal file
9
vendor/github.com/stoewer/go-strcase/kebab.go
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) 2017, A. Stoewer <adrian.stoewer@rz.ifi.lmu.de>
|
||||
// All rights reserved.
|
||||
|
||||
package strcase
|
||||
|
||||
// KebabCase converts a string into kebab case.
|
||||
func KebabCase(s string) string {
|
||||
return lowerDelimiterCase(s, '-')
|
||||
}
|
48
vendor/github.com/stoewer/go-strcase/snake.go
generated
vendored
Normal file
48
vendor/github.com/stoewer/go-strcase/snake.go
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) 2017, A. Stoewer <adrian.stoewer@rz.ifi.lmu.de>
|
||||
// All rights reserved.
|
||||
|
||||
package strcase
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SnakeCase converts a string into snake case.
|
||||
func SnakeCase(s string) string {
|
||||
return lowerDelimiterCase(s, '_')
|
||||
}
|
||||
|
||||
// lowerDelimiterCase converts a string into snake_case or kebab-case depending on
|
||||
// the delimiter passed in as second argument.
|
||||
func lowerDelimiterCase(s string, delimiter rune) string {
|
||||
s = strings.TrimSpace(s)
|
||||
buffer := make([]rune, 0, len(s)+3)
|
||||
|
||||
var prev rune
|
||||
var curr rune
|
||||
for _, next := range s {
|
||||
if isDelimiter(curr) {
|
||||
if !isDelimiter(prev) {
|
||||
buffer = append(buffer, delimiter)
|
||||
}
|
||||
} else if isUpper(curr) {
|
||||
if isLower(prev) || (isUpper(prev) && isLower(next)) {
|
||||
buffer = append(buffer, delimiter)
|
||||
}
|
||||
buffer = append(buffer, toLower(curr))
|
||||
} else if curr != 0 {
|
||||
buffer = append(buffer, curr)
|
||||
}
|
||||
prev = curr
|
||||
curr = next
|
||||
}
|
||||
|
||||
if len(s) > 0 {
|
||||
if isUpper(curr) && isLower(prev) && prev != 0 {
|
||||
buffer = append(buffer, delimiter)
|
||||
}
|
||||
buffer = append(buffer, toLower(curr))
|
||||
}
|
||||
|
||||
return string(buffer)
|
||||
}
|
6
vendor/vendor.json
vendored
6
vendor/vendor.json
vendored
|
@ -974,6 +974,12 @@
|
|||
"revision": "b061729afc07e77a8aa4fad0a2fd840958f1942a",
|
||||
"revisionTime": "2016-09-27T10:08:44Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "t/Hcc8jNXkH58QfnotLNtpLh+qc=",
|
||||
"path": "github.com/stoewer/go-strcase",
|
||||
"revision": "c8136b55823dc6af966d084a06056c5575f6400f",
|
||||
"revisionTime": "2017-04-24T18:08:47Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "qgMa75aMGbkFY0jIqqqgVnCUoNA=",
|
||||
"path": "github.com/ulikunitz/xz",
|
||||
|
|
88
website/docs/r/compute_instance_from_template.html.markdown
Normal file
88
website/docs/r/compute_instance_from_template.html.markdown
Normal file
|
@ -0,0 +1,88 @@
|
|||
---
|
||||
layout: "google"
|
||||
page_title: "Google: google_compute_instance_from_template"
|
||||
sidebar_current: "docs-google-compute-instance-from-template"
|
||||
description: |-
|
||||
Manages a VM instance resource within GCE.
|
||||
---
|
||||
|
||||
# google\_compute\_instance\_from\_template
|
||||
|
||||
Manages a VM instance resource within GCE. For more information see
|
||||
[the official documentation](https://cloud.google.com/compute/docs/instances)
|
||||
and
|
||||
[API](https://cloud.google.com/compute/docs/reference/latest/instances).
|
||||
|
||||
This resource is specifically to create a compute instance from a given
|
||||
`source_instance_template`. To create an instance without a template, use the
|
||||
`google_compute_instance` resource.
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
```hcl
|
||||
resource "google_compute_instance_template" "tpl" {
|
||||
name = "template"
|
||||
machine_type = "n1-standard-1"
|
||||
|
||||
disk {
|
||||
source_image = "debian-cloud/debian-8"
|
||||
auto_delete = true
|
||||
disk_size_gb = 100
|
||||
boot = true
|
||||
}
|
||||
|
||||
network_interface {
|
||||
network = "default"
|
||||
}
|
||||
|
||||
metadata {
|
||||
foo = "bar"
|
||||
}
|
||||
|
||||
can_ip_forward = true
|
||||
}
|
||||
|
||||
resource "google_compute_instance_from_template" "tpl" {
|
||||
name = "instance-from-template"
|
||||
zone = "us-central1-a"
|
||||
|
||||
source_instance_template = "${google_compute_instance_template.tpl.self_link}"
|
||||
|
||||
// Override fields from instance template
|
||||
can_ip_forward = false
|
||||
labels {
|
||||
my_key = "my_value"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) A unique name for the resource, required by GCE.
|
||||
Changing this forces a new resource to be created.
|
||||
|
||||
* `source_instance_template` - (Required) Name or self link of an instance
|
||||
template to create the instance based on.
|
||||
|
||||
- - -
|
||||
|
||||
* `zone` - (Optional) The zone that the machine should be created in. If not
|
||||
set, the provider zone is used.
|
||||
|
||||
In addition to these, all arguments from `google_compute_instance` are supported
|
||||
as a way to override the properties in the template. All exported attributes
|
||||
from `google_compute_instance` are likewise exported here.
|
||||
|
||||
|
||||
## Timeouts
|
||||
|
||||
This resource provides the following
|
||||
[Timeouts](/docs/configuration/resources.html#timeouts) configuration options:
|
||||
|
||||
- `create` - Default is 6 minutes.
|
||||
- `update` - Default is 6 minutes.
|
||||
- `delete` - Default is 6 minutes.
|
||||
|
|
@ -299,6 +299,10 @@
|
|||
<a href="/docs/providers/google/r/compute_instance.html">google_compute_instance</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-google-compute-instance-from-template") %>>
|
||||
<a href="/docs/providers/google/r/compute_instance_from_template.html">google_compute_instance_from_template</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-google-compute-instance-group-x") %>>
|
||||
<a href="/docs/providers/google/r/compute_instance_group.html">google_compute_instance_group</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue
Block a user