diff --git a/products/compute/ansible.yaml b/products/compute/ansible.yaml index 72d3a77c6717..cde8f9e6e339 100644 --- a/products/compute/ansible.yaml +++ b/products/compute/ansible.yaml @@ -258,6 +258,10 @@ overrides: !ruby/object:Provider::ResourceOverrides timeoutSec: !ruby/object:Provider::Ansible::PropertyOverride aliases: - timeout_seconds + Image: !ruby/object:Provider::Ansible::ResourceOverride + properties: + labels: !ruby/object:Provider::Ansible::PropertyOverride + version_added: '2.8' InstanceGroup: !ruby/object:Provider::Ansible::ResourceOverride properties: instances: !ruby/object:Provider::Ansible::PropertyOverride diff --git a/products/compute/api.yaml b/products/compute/api.yaml index 04d7d1143803..d9faa0af328b 100644 --- a/products/compute/api.yaml +++ b/products/compute/api.yaml @@ -1639,9 +1639,17 @@ objects: name: 'Image' kind: 'compute#image' base_url: projects/{{project}}/global/images + input: true + exports: + - !ruby/object:Api::Type::SelfLink + name: 'selfLink' collection_url_response: !ruby/object:Api::Resource::ResponseList kind: 'compute#imageList' items: 'items' + references: !ruby/object:Api::Resource::ReferenceLinks + guides: + 'Official Documentation': 'https://cloud.google.com/compute/docs/images' + api: 'https://cloud.google.com/compute/docs/reference/latest/images' description: | Represents an Image resource. @@ -1795,6 +1803,18 @@ objects: min_version: beta description: | The name of the encryption key that is stored in Google Cloud KMS. + - !ruby/object:Api::Type::KeyValuePairs + name: 'labels' + description: Labels to apply to this Image. + update_verb: :POST + update_url: 'projects/{{project}}/global/images/{{name}}/setLabels' + - !ruby/object:Api::Type::Fingerprint + name: 'labelFingerprint' + description: | + The fingerprint used for optimistic locking of this resource. Used + internally during updates. + update_url: 'projects/{{project}}/global/images/{{name}}/setLabels' + update_verb: :POST # TODO(alexstephen): Change to ResourceRef with array support - !ruby/object:Api::Type::Array name: 'licenses' @@ -1832,6 +1852,7 @@ objects: # TODO(alexstephen): Figure out cross-module ResourceRefs - !ruby/object:Api::Type::String name: 'source' + required: true description: | The full Google Cloud Storage URL where disk storage is stored You must provide either this property or the sourceDisk property diff --git a/products/compute/terraform.yaml b/products/compute/terraform.yaml index 270b7fb17137..2c7aa8940a6d 100644 --- a/products/compute/terraform.yaml +++ b/products/compute/terraform.yaml @@ -392,26 +392,38 @@ overrides: !ruby/object:Provider::ResourceOverrides sslHealthCheck.port: !ruby/object:Provider::Terraform::PropertyOverride default_value: 443 Image: !ruby/object:Provider::Terraform::ResourceOverride - exclude: true + example: + - !ruby/object:Provider::Terraform::Examples + name: "image_basic" + primary_resource_id: "example" + version: <%= version_name %> + vars: + image_name: "example-image" properties: id: !ruby/object:Provider::Terraform::PropertyOverride exclude: true + diskSizeGb: !ruby/object:Provider::Terraform::PropertyOverride + default_from_api: true deprecated: !ruby/object:Provider::Terraform::PropertyOverride exclude: true guestOsFeatures: !ruby/object:Provider::Terraform::PropertyOverride exclude: true imageEncryptionKey: !ruby/object:Provider::Terraform::PropertyOverride exclude: true + licenses: !ruby/object:Provider::Terraform::PropertyOverride + default_from_api: true rawDisk.sha1Checksum: !ruby/object:Provider::Terraform::PropertyOverride name: 'sha1' + rawDisk.containerType: !ruby/object:Provider::Terraform::PropertyOverride + default_value: "TAR" + rawDisk: !ruby/object:Provider::Terraform::PropertyOverride + ignore_read: true sourceDiskEncryptionKey: !ruby/object:Provider::Terraform::PropertyOverride exclude: true sourceDiskId: !ruby/object:Provider::Terraform::PropertyOverride exclude: true sourceType: !ruby/object:Provider::Terraform::PropertyOverride exclude: true - licenses: !ruby/object:Provider::Terraform::PropertyOverride - exclude: true Instance: !ruby/object:Provider::Terraform::ResourceOverride exclude: true InstanceGroup: !ruby/object:Provider::Terraform::ResourceOverride diff --git a/templates/terraform/examples/base_configs/test_file.go.erb b/templates/terraform/examples/base_configs/test_file.go.erb index d383f4402108..849c1fec1bbf 100644 --- a/templates/terraform/examples/base_configs/test_file.go.erb +++ b/templates/terraform/examples/base_configs/test_file.go.erb @@ -53,10 +53,13 @@ func testAcc<%= test_slug -%>(val string) string { <%- end %> func testAccCheck<%= resource_name -%>Destroy(s *terraform.State) error { - for _, rs := range s.RootModule().Resources { + for name, rs := range s.RootModule().Resources { if rs.Type != "<%= terraform_name -%>" { continue } + if strings.HasPrefix(name, "data.") { + continue + } config := testAccProvider.Meta().(*Config) diff --git a/templates/terraform/examples/image_basic.tf.erb b/templates/terraform/examples/image_basic.tf.erb new file mode 100644 index 000000000000..c44174a97c2d --- /dev/null +++ b/templates/terraform/examples/image_basic.tf.erb @@ -0,0 +1,7 @@ +resource "google_compute_image" "example" { + name = "<%= ctx[:vars]['image_name'] %>" + + raw_disk { + source = "https://storage.googleapis.com/bosh-cpi-artifacts/bosh-stemcell-3262.4-google-kvm-ubuntu-trusty-go_agent-raw.tar.gz" + } +} diff --git a/third_party/terraform/resources/resource_compute_image.go b/third_party/terraform/resources/resource_compute_image.go deleted file mode 100644 index 25f6423dc722..000000000000 --- a/third_party/terraform/resources/resource_compute_image.go +++ /dev/null @@ -1,307 +0,0 @@ -package google - -import ( - "fmt" - "log" - "time" - - "github.com/hashicorp/terraform/helper/schema" - "google.golang.org/api/compute/v1" -) - -const computeImageCreateTimeoutDefault = 4 - -func resourceComputeImage() *schema.Resource { - return &schema.Resource{ - Create: resourceComputeImageCreate, - Read: resourceComputeImageRead, - Update: resourceComputeImageUpdate, - Delete: resourceComputeImageDelete, - Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, - }, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(computeImageCreateTimeoutDefault * time.Minute), - Update: schema.DefaultTimeout(computeImageCreateTimeoutDefault * time.Minute), - Delete: schema.DefaultTimeout(computeImageCreateTimeoutDefault * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - // TODO(cblecker): one of source_disk or raw_disk is required - - "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - - "description": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - }, - - "family": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - }, - - "project": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - }, - - "source_disk": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - }, - - "raw_disk": { - Type: schema.TypeList, - Optional: true, - ForceNew: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "source": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "sha1": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - }, - "container_type": { - Type: schema.TypeString, - Optional: true, - Default: "TAR", - ForceNew: true, - }, - }, - }, - }, - - "self_link": { - Type: schema.TypeString, - Computed: true, - }, - - "create_timeout": { - Type: schema.TypeInt, - Optional: true, - Removed: "Use timeouts block instead. See https://www.terraform.io/docs/configuration/resources.html#timeouts.", - }, - - "labels": { - Type: schema.TypeMap, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - - "licenses": { - Type: schema.TypeList, - Optional: true, - ForceNew: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Computed: true, - }, - - "label_fingerprint": { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func resourceComputeImageCreate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - project, err := getProject(d, config) - if err != nil { - return err - } - - // Build the image - image := &compute.Image{ - Name: d.Get("name").(string), - } - - if v, ok := d.GetOk("description"); ok { - image.Description = v.(string) - } - - if v, ok := d.GetOk("family"); ok { - image.Family = v.(string) - } - - // Load up the source_disk for this image if specified - if v, ok := d.GetOk("source_disk"); ok { - image.SourceDisk = v.(string) - } - - // Load up the raw_disk for this image if specified - if v, ok := d.GetOk("raw_disk"); ok { - rawDiskEle := v.([]interface{})[0].(map[string]interface{}) - imageRawDisk := &compute.ImageRawDisk{ - Source: rawDiskEle["source"].(string), - ContainerType: rawDiskEle["container_type"].(string), - } - if val, ok := rawDiskEle["sha1"]; ok { - imageRawDisk.Sha1Checksum = val.(string) - } - - image.RawDisk = imageRawDisk - } - - if _, ok := d.GetOk("labels"); ok { - image.Labels = expandLabels(d) - } - - // Load up the licenses for this image if specified - if _, ok := d.GetOk("licenses"); ok { - image.Licenses = licenses(d) - } - - // Read create timeout - createTimeout := int(d.Timeout(schema.TimeoutCreate).Minutes()) - - // Insert the image - op, err := config.clientCompute.Images.Insert( - project, image).Do() - if err != nil { - return fmt.Errorf("Error creating image: %s", err) - } - - // Store the ID - d.SetId(image.Name) - - err = computeOperationWaitTime(config.clientCompute, op, project, "Creating Image", createTimeout) - if err != nil { - return err - } - - return resourceComputeImageRead(d, meta) -} - -func resourceComputeImageRead(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - project, err := getProject(d, config) - if err != nil { - return err - } - - image, err := config.clientCompute.Images.Get( - project, d.Id()).Do() - if err != nil { - return handleNotFoundError(err, d, fmt.Sprintf("Image %q", d.Get("name").(string))) - } - - if image.SourceDisk != "" { - d.Set("source_disk", image.SourceDisk) - } else if image.RawDisk != nil { - // `raw_disk.*.source` is only used at image creation but is not returned when calling Get. - // `raw_disk.*.sha1` is not supported, the value is simply discarded by the server. - // Leaving `raw_disk` to current state value. - } else { - return fmt.Errorf("Either raw_disk or source_disk configuration is required.") - } - - d.Set("name", image.Name) - d.Set("description", image.Description) - d.Set("family", image.Family) - d.Set("self_link", image.SelfLink) - d.Set("labels", image.Labels) - d.Set("licenses", image.Licenses) - d.Set("label_fingerprint", image.LabelFingerprint) - d.Set("project", project) - - return nil -} - -func resourceComputeImageUpdate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - project, err := getProject(d, config) - if err != nil { - return err - } - - // Technically we are only updating one attribute, but setting d.Partial here makes it easier to add updates later - d.Partial(true) - - if d.HasChange("labels") { - labels := expandLabels(d) - labelFingerprint := d.Get("label_fingerprint").(string) - setLabelsRequest := compute.GlobalSetLabelsRequest{ - LabelFingerprint: labelFingerprint, - Labels: labels, - ForceSendFields: []string{"Labels"}, - } - - op, err := config.clientCompute.Images.SetLabels(project, d.Id(), &setLabelsRequest).Do() - if err != nil { - return err - } - - d.SetPartial("labels") - - err = computeOperationWaitTime(config.clientCompute, op, project, "Setting labels", int(d.Timeout(schema.TimeoutUpdate).Minutes())) - if err != nil { - return err - } - // Perform a read to see the new label_fingerprint value - image, err := config.clientCompute.Images.Get(project, d.Id()).Do() - if err != nil { - return err - } - d.Set("label_fingerprint", image.LabelFingerprint) - d.SetPartial("label_fingerprint") - } - - d.Partial(false) - return nil -} - -func resourceComputeImageDelete(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - project, err := getProject(d, config) - if err != nil { - return err - } - - // Delete the image - log.Printf("[DEBUG] image delete request") - op, err := config.clientCompute.Images.Delete( - project, d.Id()).Do() - if err != nil { - return fmt.Errorf("Error deleting image: %s", err) - } - - err = computeOperationWaitTime(config.clientCompute, op, project, "Deleting image", int(d.Timeout(schema.TimeoutDelete).Minutes())) - if err != nil { - return err - } - - d.SetId("") - return nil -} - -func licenses(d *schema.ResourceData) []string { - licensesCount := d.Get("licenses.#").(int) - data := make([]string, licensesCount) - for i := 0; i < licensesCount; i++ { - data[i] = d.Get(fmt.Sprintf("licenses.%d", i)).(string) - } - return data -} diff --git a/third_party/terraform/tests/resource_compute_image_test.go b/third_party/terraform/tests/resource_compute_image_test.go index b2ebf652f2ab..29b31a5be8f2 100644 --- a/third_party/terraform/tests/resource_compute_image_test.go +++ b/third_party/terraform/tests/resource_compute_image_test.go @@ -133,24 +133,6 @@ func TestAccComputeImage_basedondisk(t *testing.T) { }) } -func testAccCheckComputeImageDestroy(s *terraform.State) error { - config := testAccProvider.Meta().(*Config) - - for _, rs := range s.RootModule().Resources { - if rs.Type != "google_compute_image" { - continue - } - - _, err := config.clientCompute.Images.Get( - config.Project, rs.Primary.ID).Do() - if err == nil { - return fmt.Errorf("Image still exists") - } - } - - return nil -} - func testAccCheckComputeImageExists(n string, image *compute.Image) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -180,6 +162,99 @@ func testAccCheckComputeImageExists(n string, image *compute.Image) resource.Tes } } +func TestAccComputeImage_resolveImage(t *testing.T) { + t.Parallel() + + var image compute.Image + rand := acctest.RandString(10) + name := fmt.Sprintf("test-image-%s", rand) + fam := fmt.Sprintf("test-image-family-%s", rand) + + // You'll note that this test does not have a CheckDestroy. This is not + // a typo - the test "creates" an image from a disk which is created from + // a public image. The purpose of the test is to show that we do NOT, in + // fact, create a new image in this circumstance. So, the resources under + // test are "the latest public debian image" - which of course we do not + // destroy. + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeImageDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeImage_resolving(name, fam), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeImageExists( + "google_compute_image.foobar", &image), + testAccCheckComputeImageResolution("google_compute_image.foobar"), + ), + }, + }, + }) +} + +func testAccCheckComputeImageResolution(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + project := config.Project + + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Resource not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + if rs.Primary.Attributes["name"] == "" { + return fmt.Errorf("No image name is set") + } + if rs.Primary.Attributes["family"] == "" { + return fmt.Errorf("No image family is set") + } + if rs.Primary.Attributes["self_link"] == "" { + return fmt.Errorf("No self_link is set") + } + + name := rs.Primary.Attributes["name"] + family := rs.Primary.Attributes["family"] + link := rs.Primary.Attributes["self_link"] + + latestDebian, err := config.clientCompute.Images.GetFromFamily("debian-cloud", "debian-9").Do() + if err != nil { + return fmt.Errorf("Error retrieving latest debian: %s", err) + } + + images := map[string]string{ + "family/" + latestDebian.Family: "projects/debian-cloud/global/images/family/" + latestDebian.Family, + "projects/debian-cloud/global/images/" + latestDebian.Name: "projects/debian-cloud/global/images/" + latestDebian.Name, + latestDebian.Family: "projects/debian-cloud/global/images/family/" + latestDebian.Family, + latestDebian.Name: "projects/debian-cloud/global/images/" + latestDebian.Name, + latestDebian.SelfLink: latestDebian.SelfLink, + + "global/images/" + name: "global/images/" + name, + "global/images/family/" + family: "global/images/family/" + family, + name: "global/images/" + name, + family: "global/images/family/" + family, + "family/" + family: "global/images/family/" + family, + project + "/" + name: "projects/" + project + "/global/images/" + name, + project + "/" + family: "projects/" + project + "/global/images/family/" + family, + link: link, + } + + for input, expectation := range images { + result, err := resolveImage(config, project, input) + if err != nil { + return fmt.Errorf("Error resolving input %s to image: %+v\n", input, err) + } + if result != expectation { + return fmt.Errorf("Expected input '%s' to resolve to '%s', it resolved to '%s' instead.\n", input, expectation, result) + } + } + return nil + } +} + func testAccCheckComputeImageDescription(image *compute.Image, description string) resource.TestCheckFunc { return func(s *terraform.State) error { if image.Description != description { @@ -265,6 +340,26 @@ func testAccCheckComputeImageHasSourceDisk(image *compute.Image) resource.TestCh } } +func testAccComputeImage_resolving(name, family string) string { + return fmt.Sprintf(` +data "google_compute_image" "my_image" { + family = "debian-9" + project = "debian-cloud" +} + +resource "google_compute_disk" "foobar" { + name = "%s" + zone = "us-central1-a" + image = "${data.google_compute_image.my_image.self_link}" +} +resource "google_compute_image" "foobar" { + name = "%s" + family = "%s" + source_disk = "${google_compute_disk.foobar.self_link}" +} +`, name, name, family) +} + func testAccComputeImage_basic(name string) string { return fmt.Sprintf(` resource "google_compute_image" "foobar" { diff --git a/third_party/terraform/utils/image_test.go b/third_party/terraform/utils/image_test.go deleted file mode 100644 index 026d02e54c28..000000000000 --- a/third_party/terraform/utils/image_test.go +++ /dev/null @@ -1,119 +0,0 @@ -package google - -import ( - "fmt" - "testing" - - "google.golang.org/api/compute/v1" - - "github.com/hashicorp/terraform/helper/acctest" - "github.com/hashicorp/terraform/helper/resource" - "github.com/hashicorp/terraform/terraform" -) - -func TestAccComputeImage_resolveImage(t *testing.T) { - t.Parallel() - - var image compute.Image - rand := acctest.RandString(10) - name := fmt.Sprintf("test-image-%s", rand) - fam := fmt.Sprintf("test-image-family-%s", rand) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckComputeImageDestroy, - Steps: []resource.TestStep{ - { - Config: testAccComputeImage_resolving(name, fam), - Check: resource.ComposeTestCheckFunc( - testAccCheckComputeImageExists( - "google_compute_image.foobar", &image), - testAccCheckComputeImageResolution("google_compute_image.foobar"), - ), - }, - }, - }) -} - -func testAccCheckComputeImageResolution(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - config := testAccProvider.Meta().(*Config) - project := config.Project - - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Resource not found: %s", n) - } - - if rs.Primary.ID == "" { - return fmt.Errorf("No ID is set") - } - if rs.Primary.Attributes["name"] == "" { - return fmt.Errorf("No image name is set") - } - if rs.Primary.Attributes["family"] == "" { - return fmt.Errorf("No image family is set") - } - if rs.Primary.Attributes["self_link"] == "" { - return fmt.Errorf("No self_link is set") - } - - name := rs.Primary.Attributes["name"] - family := rs.Primary.Attributes["family"] - link := rs.Primary.Attributes["self_link"] - - latestDebian, err := config.clientCompute.Images.GetFromFamily("debian-cloud", "debian-9").Do() - if err != nil { - return fmt.Errorf("Error retrieving latest debian: %s", err) - } - - images := map[string]string{ - "family/" + latestDebian.Family: "projects/debian-cloud/global/images/family/" + latestDebian.Family, - "projects/debian-cloud/global/images/" + latestDebian.Name: "projects/debian-cloud/global/images/" + latestDebian.Name, - latestDebian.Family: "projects/debian-cloud/global/images/family/" + latestDebian.Family, - latestDebian.Name: "projects/debian-cloud/global/images/" + latestDebian.Name, - latestDebian.SelfLink: latestDebian.SelfLink, - - "global/images/" + name: "global/images/" + name, - "global/images/family/" + family: "global/images/family/" + family, - name: "global/images/" + name, - family: "global/images/family/" + family, - "family/" + family: "global/images/family/" + family, - project + "/" + name: "projects/" + project + "/global/images/" + name, - project + "/" + family: "projects/" + project + "/global/images/family/" + family, - link: link, - } - - for input, expectation := range images { - result, err := resolveImage(config, project, input) - if err != nil { - return fmt.Errorf("Error resolving input %s to image: %+v\n", input, err) - } - if result != expectation { - return fmt.Errorf("Expected input '%s' to resolve to '%s', it resolved to '%s' instead.\n", input, expectation, result) - } - } - return nil - } -} - -func testAccComputeImage_resolving(name, family string) string { - return fmt.Sprintf(` -data "google_compute_image" "my_image" { - family = "debian-9" - project = "debian-cloud" -} - -resource "google_compute_disk" "foobar" { - name = "%s" - zone = "us-central1-a" - image = "${data.google_compute_image.my_image.self_link}" -} -resource "google_compute_image" "foobar" { - name = "%s" - family = "%s" - source_disk = "${google_compute_disk.foobar.self_link}" -} -`, name, name, family) -} diff --git a/third_party/terraform/utils/provider.go.erb b/third_party/terraform/utils/provider.go.erb index 41011ac4e8a4..cc11023b5ff2 100644 --- a/third_party/terraform/utils/provider.go.erb +++ b/third_party/terraform/utils/provider.go.erb @@ -147,7 +147,6 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_compute_attached_disk": resourceComputeAttachedDisk(), "google_compute_backend_service": resourceComputeBackendService(), "google_compute_global_forwarding_rule": resourceComputeGlobalForwardingRule(), - "google_compute_image": resourceComputeImage(), "google_compute_instance": resourceComputeInstance(), "google_compute_instance_from_template": resourceComputeInstanceFromTemplate(), "google_compute_instance_group": resourceComputeInstanceGroup(), diff --git a/third_party/terraform/website/docs/r/compute_image.html.markdown b/third_party/terraform/website/docs/r/compute_image.html.markdown deleted file mode 100644 index 495b5c7583aa..000000000000 --- a/third_party/terraform/website/docs/r/compute_image.html.markdown +++ /dev/null @@ -1,112 +0,0 @@ ---- -layout: "google" -page_title: "Google: google_compute_image" -sidebar_current: "docs-google-compute-image" -description: |- - Creates a bootable VM image for Google Compute Engine from an existing tarball. ---- - -# google\_compute\_image - -Creates a bootable VM image resource for Google Compute Engine from an existing -tarball. For more information see [the official documentation](https://cloud.google.com/compute/docs/images) and -[API](https://cloud.google.com/compute/docs/reference/latest/images). - - -## Example Usage - -```hcl -resource "google_compute_image" "bootable-image" { - name = "my-custom-image" - - raw_disk { - source = "https://storage.googleapis.com/my-bucket/my-disk-image-tarball.tar.gz" - } - - licenses = [ - "https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx", - ] -} - -resource "google_compute_instance" "vm" { - name = "vm-from-custom-image" - machine_type = "n1-standard-1" - zone = "us-east1-c" - - boot_disk { - initialize_params { - image = "${google_compute_image.bootable-image.self_link}" - } - } - - network_interface { - network = "default" - } -} -``` - -## Argument Reference - -The following arguments are supported: (Note that one of either source_disk or - raw_disk is required) - -* `name` - (Required) A unique name for the resource, required by GCE. - Changing this forces a new resource to be created. - -- - - - -* `description` - (Optional) The description of the image to be created - -* `family` - (Optional) The name of the image family to which this image belongs. - -* `labels` - (Optional) A set of key/value label pairs to assign to the image. - -* `source_disk` - (Optional) The URL of a disk that will be used as the source of the - image. Changing this forces a new resource to be created. - -* `project` - (Optional) The ID of the project in which the resource belongs. If it - is not provided, the provider project is used. - -* `raw_disk` - (Optional) The raw disk that will be used as the source of the image. - Changing this forces a new resource to be created. Structure is documented - below. - -* `licenses` - (Optional) A list of license URIs to apply to this image. Changing this - forces a new resource to be created. - -The `raw_disk` block supports: - -* `source` - (Required) The full Google Cloud Storage URL where the disk - image is stored. - -* `sha1` - (Optional) SHA1 checksum of the source tarball that will be used - to verify the source before creating the image. - -* `container_type` - (Optional) The format used to encode and transmit the - block device. TAR is the only supported type and is the default. - -## Attributes Reference - -In addition to the arguments listed above, the following computed attributes are -exported: - -* `self_link` - The URI of the created resource. - -* `label_fingerprint` - The fingerprint of the assigned labels. - -## Timeouts - -`google_compute_image` provides the following -[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: - -- `create` - Default `4 minutes` -- `update` - Default `4 minutes` -- `delete` - Default `4 minutes` - -## Import - -VM image can be imported using the `name`, e.g. - -``` -$ terraform import google_compute_image.web-image my-custom-image -```