diff --git a/google/data_source_google_compute_image.go b/google/data_source_google_compute_image.go new file mode 100644 index 00000000..2f9657d6 --- /dev/null +++ b/google/data_source_google_compute_image.go @@ -0,0 +1,167 @@ +package google + +import ( + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform/helper/schema" + compute "google.golang.org/api/compute/v1" +) + +func dataSourceGoogleComputeImage() *schema.Resource { + return &schema.Resource{ + Read: dataSourceGoogleComputeImageRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + ConflictsWith: []string{"family"}, + }, + "family": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + ConflictsWith: []string{"name"}, + }, + "archive_size_bytes": { + Type: schema.TypeInt, + Computed: true, + }, + "creation_timestamp": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "disk_size_gb": { + Type: schema.TypeInt, + Computed: true, + }, + "image_id": { + Type: schema.TypeString, + Computed: true, + }, + "image_encryption_key_sha256": { + Type: schema.TypeString, + Computed: true, + }, + "label_fingerprint": { + Type: schema.TypeString, + Computed: true, + }, + "labels": { + Type: schema.TypeMap, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Computed: true, + }, + "licenses": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Computed: true, + }, + "source_disk": { + Type: schema.TypeString, + Computed: true, + }, + "source_disk_encryption_key_sha256": { + Type: schema.TypeString, + Computed: true, + }, + "source_disk_id": { + Type: schema.TypeString, + Computed: true, + }, + "source_image_id": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "self_link": { + Type: schema.TypeString, + Computed: true, + }, + "project": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + }, + } +} + +func dataSourceGoogleComputeImageRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + params := []string{project} + var image *compute.Image + if v, ok := d.GetOk("name"); ok { + params = append(params, v.(string)) + log.Printf("[DEBUG] Fetching image %s", v.(string)) + image, err = config.clientCompute.Images.Get(project, v.(string)).Do() + log.Printf("[DEBUG] Fetched image %s", v.(string)) + } else if v, ok := d.GetOk("family"); ok { + params = append(params, "family", v.(string)) + log.Printf("[DEBUG] Fetching latest non-deprecated image from family %s", v.(string)) + image, err = config.clientCompute.Images.GetFromFamily(project, v.(string)).Do() + log.Printf("[DEBUG] Fetched latest non-deprecated image from family %s", v.(string)) + } else { + return fmt.Errorf("one of name or family must be set") + } + + if err != nil { + return fmt.Errorf("error retrieving image information: %s", err) + } + + var ieks256, sdeks256 string + + if image.SourceDiskEncryptionKey != nil { + sdeks256 = image.SourceDiskEncryptionKey.Sha256 + } + + if image.ImageEncryptionKey != nil { + ieks256 = image.ImageEncryptionKey.Sha256 + } + + d.Set("project", project) + d.Set("name", image.Name) + d.Set("family", image.Family) + d.Set("archive_size_bytes", image.ArchiveSizeBytes) + d.Set("creation_timestamp", image.CreationTimestamp) + d.Set("description", image.Description) + d.Set("disk_size_gb", image.DiskSizeGb) + d.Set("image_id", image.Id) + d.Set("image_encryption_key_sha256", ieks256) + d.Set("label_fingerprint", image.LabelFingerprint) + d.Set("labels", image.Labels) + d.Set("licenses", image.Licenses) + d.Set("self_link", image.SelfLink) + d.Set("source_disk", image.SourceDisk) + d.Set("source_disk_encryption_key_sha256", sdeks256) + d.Set("source_disk_id", image.SourceDiskId) + d.Set("source_image_id", image.SourceImageId) + d.Set("status", image.Status) + + d.SetId(strings.Join(params, "/")) + + return nil +} diff --git a/google/data_source_google_compute_image_test.go b/google/data_source_google_compute_image_test.go new file mode 100644 index 00000000..83a866fc --- /dev/null +++ b/google/data_source_google_compute_image_test.go @@ -0,0 +1,100 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccDataSourceComputeImage(t *testing.T) { + t.Parallel() + + family := acctest.RandomWithPrefix("tf-test") + name := acctest.RandomWithPrefix("tf-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeImageDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDataSourcePublicImageConfig, + Check: resource.ComposeTestCheckFunc( + testAccDataSourceCheckPublicImage(), + ), + }, + { + Config: testAccDataSourceCustomImageConfig(family, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.google_compute_image.from_name", + "name", name), + resource.TestCheckResourceAttr("data.google_compute_image.from_name", + "family", family), + resource.TestCheckResourceAttrSet("data.google_compute_image.from_name", + "self_link"), + ), + }, + }, + }) +} + +func testAccDataSourceCheckPublicImage() resource.TestCheckFunc { + return func(s *terraform.State) error { + data_source_name := "data.google_compute_image.debian" + ds, ok := s.RootModule().Resources[data_source_name] + if !ok { + return fmt.Errorf("root module has no resource called %s", data_source_name) + } + + ds_attr := ds.Primary.Attributes + attrs_to_test := map[string]string{ + "self_link": "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-9-stretch-v20171129", + "family": "debian-9", + } + + for attr, expect_value := range attrs_to_test { + if ds_attr[attr] != expect_value { + return fmt.Errorf( + "%s is %s; want %s", + attr, + ds_attr[attr], + expect_value, + ) + } + } + + return nil + } +} + +var testAccDataSourcePublicImageConfig = ` +data "google_compute_image" "debian" { + project = "debian-cloud" + name = "debian-9-stretch-v20171129" +} +` + +func testAccDataSourceCustomImageConfig(family, name string) string { + return fmt.Sprintf(` +resource "google_compute_image" "image" { + family = "%s" + name = "%s" + source_disk = "${google_compute_disk.disk.self_link}" +} +resource "google_compute_disk" "disk" { + name = "%s-disk" + zone = "us-central1-b" +} +data "google_compute_image" "from_name" { + project = "${google_compute_image.image.project}" + name = "${google_compute_image.image.name}" +} +data "google_compute_image" "from_family" { + project = "${google_compute_image.image.project}" + family = "${google_compute_image.image.family}" +} +`, family, name, name) +} diff --git a/google/provider.go b/google/provider.go index 0af0ff5a..4c95317d 100644 --- a/google/provider.go +++ b/google/provider.go @@ -62,6 +62,7 @@ func Provider() terraform.ResourceProvider { "google_dns_managed_zone": dataSourceDnsManagedZone(), "google_client_config": dataSourceGoogleClientConfig(), "google_compute_address": dataSourceGoogleComputeAddress(), + "google_compute_image": dataSourceGoogleComputeImage(), "google_compute_global_address": dataSourceGoogleComputeGlobalAddress(), "google_compute_lb_ip_ranges": dataSourceGoogleComputeLbIpRanges(), "google_compute_network": dataSourceGoogleComputeNetwork(), diff --git a/website/docs/d/datasource_compute_image.html.markdown b/website/docs/d/datasource_compute_image.html.markdown new file mode 100644 index 00000000..6731869f --- /dev/null +++ b/website/docs/d/datasource_compute_image.html.markdown @@ -0,0 +1,82 @@ +--- +layout: "google" +page_title: "Google: google_compute_image" +sidebar_current: "docs-google-datasource-compute-image" +description: |- + Get information about a Google Compute Image. +--- + +# google\_compute\_image + +Get information about a Google Compute Image. Check that your service account has the `compute.imageUser` role if you want to share [custom images](https://cloud.google.com/compute/docs/images/sharing-images-across-projects) from another project. If you want to use [public images](https://cloud.google.com/compute/docs/images#os-compute-support), do not forget to specify the dedicated project. For more information see +[the official documentation](https://cloud.google.com/compute/docs/images) and its [API](https://cloud.google.com/compute/docs/reference/latest/images). + +## Example Usage + +```hcl +data "google_compute_image" "my_image" { + name = "image" + # could also use family = "family-name" +} + +resource "google_compute_instance" "default" { + name = "test" + machine_type = "n1-standard-1" + zone = "us-central1-a" + + boot_disk { + initialize_params { + image = "${data.google_compute_image.my_image.self_link}" + } + } + + network_interface { + network = "default" + + access_config { + // Ephemeral IP + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` or `family` - (Required) The name of a specific image or a family. +Exactly one of `name` of `family` must be specified. If `name` is specified, it will fetch +the corresponding image. If `family` is specified, it will returns the latest image +that is part of an image family and is not deprecated. + +- - - + +* `project` - (Optional) The project in which the resource belongs. If it + is not provided, the provider project is used. + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are +exported: + +* `self_link` - The URI of the image. +* `name` - The name of the image. +* `family` - The family name of the image. +* `disk_size_gb` - The size of the image when restored onto a persistent disk in gigabytes. +* `archive_size_bytes` - The size of the image tar.gz archive stored in Google Cloud Storage in bytes. +* `image_id` - The unique identifier for the image. +* `image_encryption_key_sha256` - The [RFC 4648 base64](https://tools.ietf.org/html/rfc4648#section-4) + encoded SHA-256 hash of the [customer-supplied encryption key](https://cloud.google.com/compute/docs/disks/customer-supplied-encryption) + that protects this image. +* `source_image_id` - The ID value of the image used to create this image. +* `source_disk` - The URL of the source disk used to create this image. +* `source_disk_encryption_key_sha256` - The [RFC 4648 base64](https://tools.ietf.org/html/rfc4648#section-4) + encoded SHA-256 hash of the [customer-supplied encryption key](https://cloud.google.com/compute/docs/disks/customer-supplied-encryption) + that protects this image. +* `source_disk_id` - The ID value of the disk used to create this image. +* `creation_timestamp` - The creation timestamp in RFC3339 text format. +* `description` - An optional description of this image. +* `labels` - A map of labels applied to this image. +* `label_fingerprint` - A fingerprint for the labels being applied to this image. +* `licenses` - A list of applicable license URI. +* `status` - The status of the image. Possible values are **FAILED**, **PENDING**, or **READY**. diff --git a/website/google.erb b/website/google.erb index 4adad97b..01b11f11 100644 --- a/website/google.erb +++ b/website/google.erb @@ -19,6 +19,9 @@ > google_compute_address + > + google_compute_image + > google_compute_global_address