From fe5d7d1c63a3dbd4608d76c15c6e0de02b50a404 Mon Sep 17 00:00:00 2001 From: Noah Webb Date: Wed, 3 Aug 2016 16:58:35 -0400 Subject: [PATCH] provider/google: Support Import of 'google_compute_instance_template' --- .../import_compute_instance_template_test.go | 114 ++++++++++++++++ .../resource_compute_instance_template.go | 129 +++++++++++++++++- .../r/compute_instance_template.html.markdown | 3 +- 3 files changed, 244 insertions(+), 2 deletions(-) create mode 100644 builtin/providers/google/import_compute_instance_template_test.go diff --git a/builtin/providers/google/import_compute_instance_template_test.go b/builtin/providers/google/import_compute_instance_template_test.go new file mode 100644 index 000000000..fc414cd53 --- /dev/null +++ b/builtin/providers/google/import_compute_instance_template_test.go @@ -0,0 +1,114 @@ +package google + +import ( + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccComputeInstanceTemplate_importBasic(t *testing.T) { + resourceName := "google_compute_instance_template.foobar" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeInstanceTemplateDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeInstanceTemplate_basic, + }, + + resource.TestStep{ + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComputeInstanceTemplate_importIp(t *testing.T) { + resourceName := "google_compute_instance_template.foobar" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeInstanceTemplateDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeInstanceTemplate_ip, + }, + + resource.TestStep{ + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComputeInstanceTemplate_importDisks(t *testing.T) { + resourceName := "google_compute_instance_template.foobar" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeInstanceTemplateDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeInstanceTemplate_disks, + }, + + resource.TestStep{ + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComputeInstanceTemplate_importSubnetAuto(t *testing.T) { + resourceName := "google_compute_instance_template.foobar" + network := "network-" + acctest.RandString(10) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeInstanceTemplateDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeInstanceTemplate_subnet_auto(network), + }, + + resource.TestStep{ + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComputeInstanceTemplate_importSubnetCustom(t *testing.T) { + resourceName := "google_compute_instance_template.foobar" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeInstanceTemplateDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeInstanceTemplate_subnet_custom, + }, + + resource.TestStep{ + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} diff --git a/builtin/providers/google/resource_compute_instance_template.go b/builtin/providers/google/resource_compute_instance_template.go index 4add7124d..9b448f1a9 100644 --- a/builtin/providers/google/resource_compute_instance_template.go +++ b/builtin/providers/google/resource_compute_instance_template.go @@ -3,6 +3,7 @@ package google import ( "fmt" "log" + "strings" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" @@ -15,6 +16,9 @@ func resourceComputeInstanceTemplate() *schema.Resource { Create: resourceComputeInstanceTemplateCreate, Read: resourceComputeInstanceTemplateRead, Delete: resourceComputeInstanceTemplateDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "name": &schema.Schema{ @@ -66,6 +70,7 @@ func resourceComputeInstanceTemplate() *schema.Resource { Type: schema.TypeBool, Optional: true, ForceNew: true, + Computed: true, }, "device_name": &schema.Schema{ @@ -90,6 +95,7 @@ func resourceComputeInstanceTemplate() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, + Computed: true, }, "source_image": &schema.Schema{ @@ -102,12 +108,14 @@ func resourceComputeInstanceTemplate() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, + Computed: true, }, "mode": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, + Computed: true, }, "source": &schema.Schema{ @@ -120,6 +128,7 @@ func resourceComputeInstanceTemplate() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, + Computed: true, }, }, }, @@ -179,6 +188,7 @@ func resourceComputeInstanceTemplate() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, + Computed: true, }, "subnetwork": &schema.Schema{ @@ -215,6 +225,7 @@ func resourceComputeInstanceTemplate() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, + Computed: true, }, "region": &schema.Schema{ @@ -226,12 +237,14 @@ func resourceComputeInstanceTemplate() *schema.Resource { "scheduling": &schema.Schema{ Type: schema.TypeList, Optional: true, + Computed: true, ForceNew: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "preemptible": &schema.Schema{ Type: schema.TypeBool, Optional: true, + Default: false, ForceNew: true, }, @@ -245,6 +258,7 @@ func resourceComputeInstanceTemplate() *schema.Resource { "on_host_maintenance": &schema.Schema{ Type: schema.TypeString, Optional: true, + Computed: true, ForceNew: true, }, }, @@ -476,6 +490,7 @@ func resourceComputeInstanceTemplateCreate(d *schema.ResourceData, meta interfac instanceProperties.Scheduling = &compute.Scheduling{} instanceProperties.Scheduling.OnHostMaintenance = "MIGRATE" + // Depreciated fields if v, ok := d.GetOk("automatic_restart"); ok { instanceProperties.Scheduling.AutomaticRestart = v.(bool) } @@ -570,9 +585,91 @@ func resourceComputeInstanceTemplateCreate(d *schema.ResourceData, meta interfac return resourceComputeInstanceTemplateRead(d, meta) } +func flattenDisks(disks []*compute.AttachedDisk) []map[string]interface{} { + result := make([]map[string]interface{}, 0, len(disks)) + for _, disk := range disks { + diskMap := make(map[string]interface{}) + if disk.InitializeParams != nil { + sourceImageUrl := strings.Split(disk.InitializeParams.SourceImage, "/") + diskMap["source_image"] = sourceImageUrl[len(sourceImageUrl)-1] + diskMap["disk_type"] = disk.InitializeParams.DiskType + diskMap["disk_name"] = disk.InitializeParams.DiskName + diskMap["disk_size_gb"] = disk.InitializeParams.DiskSizeGb + } + diskMap["auto_delete"] = disk.AutoDelete + diskMap["boot"] = disk.Boot + diskMap["device_name"] = disk.DeviceName + diskMap["interface"] = disk.Interface + diskMap["source"] = disk.Source + diskMap["mode"] = disk.Mode + diskMap["type"] = disk.Type + result = append(result, diskMap) + } + return result +} + +func flattenNetworkInterfaces(networkInterfaces []*compute.NetworkInterface) ([]map[string]interface{}, string) { + result := make([]map[string]interface{}, 0, len(networkInterfaces)) + region := "" + for _, networkInterface := range networkInterfaces { + networkInterfaceMap := make(map[string]interface{}) + if networkInterface.Network != "" { + networkUrl := strings.Split(networkInterface.Network, "/") + networkInterfaceMap["network"] = networkUrl[len(networkUrl)-1] + } + if networkInterface.Subnetwork != "" { + subnetworkUrl := strings.Split(networkInterface.Subnetwork, "/") + networkInterfaceMap["subnetwork"] = subnetworkUrl[len(subnetworkUrl)-1] + region = subnetworkUrl[len(subnetworkUrl)-3] + } + + if networkInterface.AccessConfigs != nil { + accessConfigsMap := make([]map[string]interface{}, 0, len(networkInterface.AccessConfigs)) + for _, accessConfig := range networkInterface.AccessConfigs { + accessConfigMap := make(map[string]interface{}) + accessConfigMap["nat_ip"] = accessConfig.NatIP + + accessConfigsMap = append(accessConfigsMap, accessConfigMap) + } + networkInterfaceMap["access_config"] = accessConfigsMap + } + result = append(result, networkInterfaceMap) + } + return result, region +} + +func flattenScheduling(scheduling *compute.Scheduling) ([]map[string]interface{}, bool) { + result := make([]map[string]interface{}, 0, 1) + schedulingMap := make(map[string]interface{}) + schedulingMap["automatic_restart"] = scheduling.AutomaticRestart + schedulingMap["on_host_maintenance"] = scheduling.OnHostMaintenance + schedulingMap["preemptible"] = scheduling.Preemptible + result = append(result, schedulingMap) + return result, scheduling.AutomaticRestart +} + +func flattenServiceAccounts(serviceAccounts []*compute.ServiceAccount) []map[string]interface{} { + result := make([]map[string]interface{}, 0, len(serviceAccounts)) + for _, serviceAccount := range serviceAccounts { + serviceAccountMap := make(map[string]interface{}) + serviceAccountMap["email"] = serviceAccount.Email + serviceAccountMap["scopes"] = serviceAccount.Scopes + + result = append(result, serviceAccountMap) + } + return result +} + +func flattenMetadata(metadata *compute.Metadata) map[string]string { + metadataMap := make(map[string]string) + for _, item := range metadata.Items { + metadataMap[item.Key] = *item.Value + } + return metadataMap +} + func resourceComputeInstanceTemplateRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - project, err := getProject(d, config) if err != nil { return err @@ -603,6 +700,36 @@ func resourceComputeInstanceTemplateRead(d *schema.ResourceData, meta interface{ } d.Set("self_link", instanceTemplate.SelfLink) d.Set("name", instanceTemplate.Name) + if instanceTemplate.Properties.Disks != nil { + d.Set("disk", flattenDisks(instanceTemplate.Properties.Disks)) + } + d.Set("description", instanceTemplate.Description) + d.Set("machine_type", instanceTemplate.Properties.MachineType) + d.Set("can_ip_forward", instanceTemplate.Properties.CanIpForward) + if instanceTemplate.Properties.Metadata != nil { + d.Set("metadata", flattenMetadata(instanceTemplate.Properties.Metadata)) + } + d.Set("instance_description", instanceTemplate.Properties.Description) + d.Set("project", project) + if instanceTemplate.Properties.NetworkInterfaces != nil { + networkInterfaces, region := flattenNetworkInterfaces(instanceTemplate.Properties.NetworkInterfaces) + d.Set("network_interface", networkInterfaces) + // region is where to look up the subnetwork if there is one attached to the instance template + if region != "" { + d.Set("region", region) + } + } + if instanceTemplate.Properties.Scheduling != nil { + scheduling, autoRestart := flattenScheduling(instanceTemplate.Properties.Scheduling) + d.Set("scheduling", scheduling) + d.Set("automatic_restart", autoRestart) + } + if instanceTemplate.Properties.Tags != nil { + d.Set("tags", instanceTemplate.Properties.Tags.Items) + } + if instanceTemplate.Properties.ServiceAccounts != nil { + d.Set("service_account", flattenServiceAccounts(instanceTemplate.Properties.ServiceAccounts)) + } return nil } diff --git a/website/source/docs/providers/google/r/compute_instance_template.html.markdown b/website/source/docs/providers/google/r/compute_instance_template.html.markdown index be56da80e..2ce38389e 100644 --- a/website/source/docs/providers/google/r/compute_instance_template.html.markdown +++ b/website/source/docs/providers/google/r/compute_instance_template.html.markdown @@ -226,7 +226,8 @@ The `scheduling` block supports: * `on_host_maintenance` - (Optional) Defines the maintenance behavior for this instance. -* `preemptible` - (Optional) Allows instance to be preempted. Read more on this +* `preemptible` - (Optional) Allows instance to be preempted. This defaults to + false. Read more on this [here](https://cloud.google.com/compute/docs/instances/preemptible). ## Attributes Reference