Skip to content

Commit

Permalink
Guest attributes data source (GoogleCloudPlatform#12081)
Browse files Browse the repository at this point in the history
  • Loading branch information
karolgorc authored and BBBmau committed Nov 5, 2024
1 parent 935267a commit 5a88c56
Show file tree
Hide file tree
Showing 4 changed files with 367 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ var handwrittenDatasources = map[string]*schema.Resource{
"google_compute_instance_group_manager": compute.DataSourceGoogleComputeInstanceGroupManager(),
"google_compute_instance_serial_port": compute.DataSourceGoogleComputeInstanceSerialPort(),
"google_compute_instance_template": compute.DataSourceGoogleComputeInstanceTemplate(),
"google_compute_instance_guest_attributes": compute.DataSourceGoogleComputeInstanceGuestAttributes(),
"google_compute_lb_ip_ranges": compute.DataSourceGoogleComputeLbIpRanges(),
"google_compute_machine_types": compute.DataSourceGoogleComputeMachineTypes(),
"google_compute_network": compute.DataSourceGoogleComputeNetwork(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package compute

import (
"fmt"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-google/google/tpgresource"
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
{{- if ne $.TargetVersionName "ga" }}
compute "google.golang.org/api/compute/v0.beta"
{{- else }}
compute "google.golang.org/api/compute/v1"
{{- end }}
)

func DataSourceGoogleComputeInstanceGuestAttributes() *schema.Resource {
return &schema.Resource{
Read: dataSourceGoogleComputeInstanceGuestAttributesRead,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},

"project": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},

"region": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},

"zone": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},

"query_path": {
Type: schema.TypeString,
Optional: true,
ConflictsWith: []string{"variable_key"},
},

"variable_key": {
Type: schema.TypeString,
Optional: true,
ConflictsWith: []string{"query_path"},
},

"variable_value": {
Type: schema.TypeString,
Computed: true,
},

"query_value": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"key": {
Type: schema.TypeString,
Computed: true,
},
"namespace": {
Type: schema.TypeString,
Computed: true,
},
"value": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
},
}
}

func dataSourceGoogleComputeInstanceGuestAttributesRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*transport_tpg.Config)
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
if err != nil {
return err
}
project, zone, name, err := tpgresource.GetZonalResourcePropertiesFromSelfLinkOrSchema(d, config)
if err != nil {
return err
}

id := fmt.Sprintf("projects/%s/zones/%s/instances/%s", project, zone, name)
instanceGuestAttributes := &compute.GuestAttributes{}

// You can either query based on variable_key, query_path or just get the first value
if d.Get("query_path").(string) != "" {
instanceGuestAttributes, err = config.NewComputeClient(userAgent).Instances.GetGuestAttributes(project, zone, name).QueryPath(d.Get("query_path").(string)).Do()
} else if d.Get("variable_key").(string) != "" {
instanceGuestAttributes, err = config.NewComputeClient(userAgent).Instances.GetGuestAttributes(project, zone, name).VariableKey(d.Get("variable_key").(string)).Do()
} else {
instanceGuestAttributes, err = config.NewComputeClient(userAgent).Instances.GetGuestAttributes(project, zone, name).Do()
}
if err != nil {
return transport_tpg.HandleDataSourceNotFoundError(err, d, fmt.Sprintf("Instance's Guest Attributes %s", name), id)
}

// Set query results
if err := d.Set("variable_value", instanceGuestAttributes.VariableValue); err != nil {
return fmt.Errorf("Error variable_value: %s", err)
}
if err := d.Set("query_value", flattenQueryValues(instanceGuestAttributes.QueryValue)); err != nil {
return fmt.Errorf("Error query_value: %s", err)
}

d.SetId(fmt.Sprintf(instanceGuestAttributes.SelfLink))
return nil
}

func flattenQueryValues(queryValue *compute.GuestAttributesValue) []map[string]interface{} {
if queryValue == nil {
return nil
}
queryValueItems := make([]map[string]interface{}, 0)
for _, item := range queryValue.Items {
queryValueItems = append(queryValueItems, map[string]interface{}{
"key": item.Key,
"namespace": item.Namespace,
"value": item.Value,
})
}
return queryValueItems
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package compute_test

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-provider-google/google/acctest"
{{- if ne $.TargetVersionName "ga" }}
compute "google.golang.org/api/compute/v0.beta"
{{- else }}
compute "google.golang.org/api/compute/v1"
{{- end }}
)

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

var instance compute.Instance
instanceName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10))

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckComputeInstanceDestroyProducer(t),
Steps: []resource.TestStep{
{
//need to create the guest_attributes metadata from startup script first
Config: testAccDataSourceComputeInstanceGuestAttributesInitialConfig(instanceName),
Check: testAccCheckComputeInstanceExists(t, "google_compute_instance.foo", &instance),
},
{
Config: testAccDataSourceComputeInstanceGuestAttributesConfig_variableKey(instanceName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.google_compute_instance_guest_attributes.bar", "variable_key", "testing/key2"),
resource.TestCheckResourceAttr("data.google_compute_instance_guest_attributes.bar", "variable_value", "test2"),
),
},
{
Config: testAccDataSourceComputeInstanceGuestAttributesConfig_queryPath(instanceName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.google_compute_instance_guest_attributes.bar", "query_path", "testing/"),
resource.TestCheckResourceAttr("data.google_compute_instance_guest_attributes.bar", "query_value.0.value", "test1"),
resource.TestCheckResourceAttr("data.google_compute_instance_guest_attributes.bar", "query_value.1.value", "test2"),
),
},
},
})
}

func testAccDataSourceComputeInstanceGuestAttributesInitialConfig(instanceName string) string {
return fmt.Sprintf(`
resource "google_compute_instance" "foo" {
name = "%s"
machine_type = "n1-standard-1"
zone = "us-central1-a"

boot_disk {
initialize_params {
image = "debian-8-jessie-v20160803"
}
}

network_interface {
network = "default"
access_config {
// Ephemeral IP
}
}

metadata = {
enable-guest-attributes = "TRUE"
}

metadata_startup_script = <<-EOF
curl -X PUT --data "test1" http://metadata.google.internal/computeMetadata/v1/instance/guest-attributes/testing/key1 -H "Metadata-Flavor: Google"
curl -X PUT --data "test2" http://metadata.google.internal/computeMetadata/v1/instance/guest-attributes/testing/key2 -H "Metadata-Flavor: Google"
EOF
}
`, instanceName)
}

func testAccDataSourceComputeInstanceGuestAttributesConfig_queryPath(instanceName string) string {
return fmt.Sprintf(`
resource "google_compute_instance" "foo" {
name = "%s"
machine_type = "n1-standard-1"
zone = "us-central1-a"

boot_disk {
initialize_params {
image = "debian-8-jessie-v20160803"
}
}

network_interface {
network = "default"
access_config {
// Ephemeral IP
}
}

metadata = {
enable-guest-attributes = "TRUE"
}

metadata_startup_script = <<-EOF
curl -X PUT --data "test1" http://metadata.google.internal/computeMetadata/v1/instance/guest-attributes/testing/key1 -H "Metadata-Flavor: Google"
curl -X PUT --data "test2" http://metadata.google.internal/computeMetadata/v1/instance/guest-attributes/testing/key2 -H "Metadata-Flavor: Google"
EOF
}

data "google_compute_instance_guest_attributes" "bar" {
name = google_compute_instance.foo.name
zone = "us-central1-a"
query_path = "testing/"
}
`, instanceName)
}

func testAccDataSourceComputeInstanceGuestAttributesConfig_variableKey(instanceName string) string {
return fmt.Sprintf(`
resource "google_compute_instance" "foo" {
name = "%s"
machine_type = "n1-standard-1"
zone = "us-central1-a"

boot_disk {
initialize_params {
image = "debian-8-jessie-v20160803"
}
}

network_interface {
network = "default"
access_config {
// Ephemeral IP
}
}

metadata = {
enable-guest-attributes = "TRUE"
}

metadata_startup_script = <<-EOF
curl -X PUT --data "test1" http://metadata.google.internal/computeMetadata/v1/instance/guest-attributes/testing/key1 -H "Metadata-Flavor: Google"
curl -X PUT --data "test2" http://metadata.google.internal/computeMetadata/v1/instance/guest-attributes/testing/key2 -H "Metadata-Flavor: Google"
EOF
}

data "google_compute_instance_guest_attributes" "bar" {
name = google_compute_instance.foo.name
zone = "us-central1-a"
variable_key = "testing/key2"
}
`, instanceName)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
subcategory: "Compute Engine"
description: |-
Get GCE instance's guest attributes
---

# google_compute_instance_guest_attributes

Get information about 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).

Get information about VM's guest attrubutes. For more information see [the official documentation](https://cloud.google.com/compute/docs/metadata/manage-guest-attributes)
and
[API](https://cloud.google.com/compute/docs/reference/rest/v1/instances/getGuestAttributes).

## Example Usage - get all attributes from a single namespace

```hcl
data "google_compute_instance_guest_attributes" "appserver_ga" {
name = "primary-application-server"
zone = "us-central1-a"
query_path = "variables/"
}
```

## Example Usage - get a specific variable

```hcl
data "google_compute_instance_guest_attributes" "appserver_ga" {
name = "primary-application-server"
zone = "us-central1-a"
variable_key = "variables/key1"
}
```

## Argument Reference

The following arguments are supported:

* `name` - (Optional) The name or self_link of the instance.

---

* `project` - (Optional) The ID of the project in which the resource belongs.
If `self_link` is provided, this value is ignored. If neither `self_link`
nor `project` are provided, the provider project is used.

* `zone` - (Optional) The zone of the instance. If `self_link` is provided, this
value is ignored. If neither `self_link` nor `zone` are provided, the
provider zone is used.

* `query_path` - (Optional) Path to query for the guest attributes. Consists of
`namespace` name for the attributes followed with a `/`.

* `variable_key` - (Optional) Key of a variable to get the value of. Consists of
`namespace` name and `key` name for the variable separated by a `/`.

## Attributes Reference

* `query_value` - Structure is [documented below](#nested_query_value).

* `variable_value` - Value of the queried guest_attribute.

---

<a name="nested_query_value"></a>The `query_value` block supports:

* `key` - Key of the guest_attribute.

* `namespace` - Namespace of the guest_attribute.

* `value` - Value of the guest_attribute.

0 comments on commit 5a88c56

Please sign in to comment.