Skip to content

Commit

Permalink
Add a compute datasource.
Browse files Browse the repository at this point in the history
  • Loading branch information
rileykarson committed Sep 6, 2018
1 parent 3f906b3 commit b84ed5f
Show file tree
Hide file tree
Showing 3 changed files with 462 additions and 0 deletions.
140 changes: 140 additions & 0 deletions google/data_source_google_compute_instance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package google

import (
"fmt"
"github.com/hashicorp/terraform/helper/schema"
)

func dataSourceGoogleComputeInstance() *schema.Resource {
// Generate datasource schema from resource
dsSchema := datasourceSchemaFromResourceSchema(resourceComputeInstance().Schema)

// Set 'Required' schema elements
addRequiredFieldsToSchema(dsSchema, "name")

// Set 'Optional' schema elements
addOptionalFieldsToSchema(dsSchema, "project", "zone")

return &schema.Resource{
Read: dataSourceGoogleComputeInstanceRead,
Schema: dsSchema,
}
}

func dataSourceGoogleComputeInstanceRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)

project, err := getProject(d, config)
if err != nil {
return err
}

zone, err := getZone(d, config)
if err != nil {
return err
}

name := d.Get("name").(string)

instance, err := config.clientComputeBeta.Instances.Get(project, zone, name).Do()
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("Instance %s", name))
}

md := flattenMetadataBeta(instance.Metadata)
if err = d.Set("metadata", md); err != nil {
return fmt.Errorf("error setting metadata: %s", err)
}

d.Set("can_ip_forward", instance.CanIpForward)
d.Set("machine_type", GetResourceNameFromSelfLink(instance.MachineType))

// Set the networks
// Use the first external IP found for the default connection info.
networkInterfaces, _, internalIP, externalIP, err := flattenNetworkInterfaces(d, config, instance.NetworkInterfaces)
if err != nil {
return err
}
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
// via their internal ips.
sshIP := externalIP
if sshIP == "" {
sshIP = internalIP
}

// Initialize the connection info
d.SetConnInfo(map[string]string{
"type": "ssh",
"host": sshIP,
})

// Set the metadata fingerprint if there is one.
if instance.Metadata != nil {
d.Set("metadata_fingerprint", instance.Metadata.Fingerprint)
}

// Set the tags fingerprint if there is one.
if instance.Tags != nil {
d.Set("tags_fingerprint", instance.Tags.Fingerprint)
d.Set("tags", convertStringArrToInterface(instance.Tags.Items))
}

if err := d.Set("labels", instance.Labels); err != nil {
return err
}

if instance.LabelFingerprint != "" {
d.Set("label_fingerprint", instance.LabelFingerprint)
}

attachedDisks := []map[string]interface{}{}
scratchDisks := []map[string]interface{}{}
for _, disk := range instance.Disks {
if disk.Boot {
d.Set("boot_disk", flattenBootDisk(d, disk, config))
} else if disk.Type == "SCRATCH" {
scratchDisks = append(scratchDisks, flattenScratchDisk(disk))
} else {
di := map[string]interface{}{
"source": ConvertSelfLinkToV1(disk.Source),
"device_name": disk.DeviceName,
"mode": disk.Mode,
}
if key := disk.DiskEncryptionKey; key != nil {
di["disk_encryption_key_sha256"] = key.Sha256
}
attachedDisks = append(attachedDisks, di)
}
}
// Remove nils from map in case there were disks in the config that were not present on read;
// i.e. a disk was detached out of band
ads := []map[string]interface{}{}
for _, d := range attachedDisks {
if d != nil {
ads = append(ads, d)
}
}

d.Set("service_account", flattenServiceAccounts(instance.ServiceAccounts))
d.Set("attached_disk", ads)
d.Set("scratch_disk", scratchDisks)
d.Set("scheduling", flattenScheduling(instance.Scheduling))
d.Set("guest_accelerator", flattenGuestAccelerators(instance.GuestAccelerators))
d.Set("cpu_platform", instance.CpuPlatform)
d.Set("min_cpu_platform", instance.MinCpuPlatform)
d.Set("deletion_protection", instance.DeletionProtection)
d.Set("self_link", ConvertSelfLinkToV1(instance.SelfLink))
d.Set("instance_id", fmt.Sprintf("%d", instance.Id))
d.Set("project", project)
d.Set("zone", GetResourceNameFromSelfLink(instance.Zone))
d.Set("name", instance.Name)

d.SetId(instance.Name)

return nil
}
135 changes: 135 additions & 0 deletions google/data_source_google_compute_instance_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package google

import (
"fmt"
"testing"

"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func TestAccDataSourceComputeInstance_basic(t *testing.T) {
t.Parallel()

instanceName := fmt.Sprintf("data-instance-test-%s", acctest.RandString(10))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDataSourceComputeInstanceConfig(instanceName),
Check: resource.ComposeTestCheckFunc(
testAccDataSourceComputeInstanceCheck("data.google_compute_instance.bar", "google_compute_instance.foo"),
resource.TestCheckResourceAttr("data.google_compute_instance.bar", "network_interface.#", "1"),
resource.TestCheckResourceAttr("data.google_compute_instance.bar", "boot_disk.0.initialize_params.0.size", "10"),
resource.TestCheckResourceAttr("data.google_compute_instance.bar", "boot_disk.0.initialize_params.0.type", "pd-standard"),
resource.TestCheckResourceAttr("data.google_compute_instance.bar", "scratch_disk.0.interface", "SCSI"),
resource.TestCheckResourceAttr("data.google_compute_instance.bar", "network_interface.0.access_config.0.network_tier", "PREMIUM"),
),
},
},
})
}

func testAccDataSourceComputeInstanceCheck(datasourceName string, resourceName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
ds, ok := s.RootModule().Resources[datasourceName]
if !ok {
return fmt.Errorf("root module has no resource called %s", datasourceName)
}

rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return fmt.Errorf("can't find %s in state", resourceName)
}

datasourceAttributes := ds.Primary.Attributes
resourceAttributes := rs.Primary.Attributes

instanceAttrsToTest := []string{
"name",
"machine_type",
"can_ip_forward",
"description",
"deletion_protection",
"labels",
"metadata",
"min_cpu_platform",
"project",
"tags",
"zone",
"cpu_platform",
"instance_id",
"label_fingerprint",
"metadata_fingerprint",
"self_link",
"tags_fingerprint",
}

for _, attrToCheck := range instanceAttrsToTest {
if datasourceAttributes[attrToCheck] != resourceAttributes[attrToCheck] {
return fmt.Errorf(
"%s is %s; want %s",
attrToCheck,
datasourceAttributes[attrToCheck],
resourceAttributes[attrToCheck],
)
}
}

return nil
}
}

func testAccDataSourceComputeInstanceConfig(instanceName string) string {
return fmt.Sprintf(`
resource "google_compute_instance" "foo" {
name = "%s"
machine_type = "n1-standard-1"
zone = "us-central1-a"
can_ip_forward = false
tags = ["foo", "bar"]
boot_disk {
initialize_params{
image = "debian-8-jessie-v20160803"
}
}
scratch_disk {
}
network_interface {
network = "default"
access_config {
// Ephemeral IP
}
}
metadata {
foo = "bar"
baz = "qux"
}
create_timeout = 5
metadata {
startup-script = "echo Hello"
}
labels {
my_key = "my_value"
my_other_key = "my_other_value"
}
}
data "google_compute_instance" "bar" {
name = "${google_compute_instance.foo.name}"
zone = "us-central1-a"
}
`, instanceName)
}
Loading

0 comments on commit b84ed5f

Please sign in to comment.