Skip to content

Commit

Permalink
compute_snapshot datasource added (#6527) (#12671)
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <magic-modules@google.com>

Signed-off-by: Modular Magician <magic-modules@google.com>
  • Loading branch information
modular-magician committed Sep 28, 2022
1 parent c5278cf commit 1e3c865
Show file tree
Hide file tree
Showing 5 changed files with 372 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/6527.txt
@@ -0,0 +1,3 @@
```release-note:new-datasource
`google_compute_snapshot'
```
113 changes: 113 additions & 0 deletions google/data_source_google_compute_snapshot.go
@@ -0,0 +1,113 @@
package google

import (
"fmt"
"sort"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"google.golang.org/api/compute/v1"
)

func dataSourceGoogleComputeSnapshot() *schema.Resource {

// Generate datasource schema from resource
dsSchema := datasourceSchemaFromResourceSchema(resourceComputeSnapshot().Schema)

dsSchema["filter"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
}
dsSchema["most_recent"] = &schema.Schema{
Type: schema.TypeBool,
Optional: true,
}

// Set 'Optional' schema elements
addOptionalFieldsToSchema(dsSchema, "name", "filter", "most_recent", "project")

dsSchema["name"].ExactlyOneOf = []string{"name", "filter"}
dsSchema["filter"].ExactlyOneOf = []string{"name", "filter"}

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

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

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

if v, ok := d.GetOk("name"); ok {
return retrieveSnapshot(d, meta, project, v.(string))
}

if v, ok := d.GetOk("filter"); ok {
userAgent, err := generateUserAgentString(d, config.userAgent)
if err != nil {
return err
}

projectGetCall := config.NewResourceManagerClient(userAgent).Projects.Get(project)

if config.UserProjectOverride {
billingProject := project

// err == nil indicates that the billing_project value was found
if bp, err := getBillingProject(d, config); err == nil {
billingProject = bp
}
projectGetCall.Header().Add("X-Goog-User-Project", billingProject)
}

//handling the pagination locally
allSnapshots := make([]*compute.Snapshot, 0)
token := ""
for paginate := true; paginate; {
snapshots, err := config.NewComputeClient(userAgent).Snapshots.List(project).Filter(v.(string)).PageToken(token).Do()
if err != nil {
return fmt.Errorf("error retrieving list of snapshots: %s", err)

}
allSnapshots = append(allSnapshots, snapshots.Items...)

token = snapshots.NextPageToken
paginate = token != ""
}

mostRecent := d.Get("most_recent").(bool)
if mostRecent {
sort.Sort(ByCreationTimestampOfSnapshot(allSnapshots))
}

count := len(allSnapshots)
if count == 1 || count > 1 && mostRecent {
return retrieveSnapshot(d, meta, project, allSnapshots[0].Name)
}

return fmt.Errorf("your filter has returned %d snapshot(s). Please refine your filter or set most_recent to return exactly one snapshot", len(allSnapshots))

}

return fmt.Errorf("one of name or filter must be set")
}

func retrieveSnapshot(d *schema.ResourceData, meta interface{}, project, name string) error {
d.SetId("projects/" + project + "/global/snapshots/" + name)
d.Set("name", name)
return resourceComputeSnapshotRead(d, meta)
}

// ByCreationTimestamp implements sort.Interface for []*Snapshot based on
// the CreationTimestamp field.
type ByCreationTimestampOfSnapshot []*compute.Snapshot

func (a ByCreationTimestampOfSnapshot) Len() int { return len(a) }
func (a ByCreationTimestampOfSnapshot) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByCreationTimestampOfSnapshot) Less(i, j int) bool {
return a[i].CreationTimestamp > a[j].CreationTimestamp
}
205 changes: 205 additions & 0 deletions google/data_source_google_compute_snapshot_test.go
@@ -0,0 +1,205 @@
package google

import (
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

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

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccSnapshot_name(getTestProjectFromEnv(), randString(t, 10)),
Check: resource.ComposeTestCheckFunc(
checkDataSourceStateMatchesResourceStateWithIgnores(
"data.google_compute_snapshot.default",
"google_compute_snapshot.default",
map[string]struct{}{"zone": {}},
),
),
},
},
})
}

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

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccSnapshot_filter(getTestProjectFromEnv(), randString(t, 10)),
Check: resource.ComposeTestCheckFunc(
checkDataSourceStateMatchesResourceStateWithIgnores(
"data.google_compute_snapshot.default",
"google_compute_snapshot.c",
map[string]struct{}{"zone": {}},
),
),
},
},
})
}

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

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccSnapshot_filter_mostRecent(getTestProjectFromEnv(), randString(t, 10)),
Check: resource.ComposeTestCheckFunc(
checkDataSourceStateMatchesResourceStateWithIgnores(
"data.google_compute_snapshot.default",
"google_compute_snapshot.c",
map[string]struct{}{"zone": {}},
),
),
},
},
})
}

func testAccSnapshot_name(project, suffix string) string {
return Nprintf(`
data "google_compute_image" "tf-test-image" {
family = "debian-11"
project = "debian-cloud"
}
resource "google_compute_disk" "tf-test-disk" {
name = "debian-disk-%{suffix}"
image = data.google_compute_image.tf-test-image.self_link
size = 10
type = "pd-ssd"
zone = "us-central1-a"
}
resource "google_compute_snapshot" "default" {
name = "tf-test-snapshot-%{suffix}"
description = "Example snapshot."
source_disk = google_compute_disk.tf-test-disk.id
zone = "us-central1-a"
labels = {
my_label = "value"
}
storage_locations = ["us-central1"]
}
data "google_compute_snapshot" "default" {
project = "%{project}"
name = google_compute_snapshot.default.name
}
`, map[string]interface{}{"project": project, "suffix": suffix})
}

func testAccSnapshot_filter(project, suffix string) string {
return Nprintf(`
data "google_compute_image" "tf-test-image" {
family = "debian-11"
project = "debian-cloud"
}
resource "google_compute_disk" "tf-test-disk" {
name = "debian-disk-%{suffix}"
image = data.google_compute_image.tf-test-image.self_link
size = 10
type = "pd-ssd"
zone = "us-central1-a"
}
resource "google_compute_snapshot" "a" {
name = "tf-test-snapshot-a-%{suffix}"
description = "Example snapshot."
source_disk = google_compute_disk.tf-test-disk.id
zone = "us-central1-a"
labels = {
my_label = "a"
}
storage_locations = ["us-central1"]
}
resource "google_compute_snapshot" "b" {
name = "tf-test-snapshot-b-%{suffix}"
description = "Example snapshot."
source_disk = google_compute_disk.tf-test-disk.id
zone = "us-central1-a"
labels = {
my_label = "b"
}
storage_locations = ["us-central1"]
}
resource "google_compute_snapshot" "c" {
name = "tf-test-snapshot-c-%{suffix}"
description = "Example snapshot."
source_disk = google_compute_disk.tf-test-disk.id
zone = "us-central1-a"
labels = {
my_label = "c"
}
storage_locations = ["us-central1"]
}
data "google_compute_snapshot" "default" {
project = "%{project}"
filter = "name = tf-test-snapshot-c-%{suffix}"
depends_on = [google_compute_snapshot.c]
}
`, map[string]interface{}{"project": project, "suffix": suffix})
}

func testAccSnapshot_filter_mostRecent(project, suffix string) string {
return Nprintf(`
data "google_compute_image" "tf-test-image" {
family = "debian-11"
project = "debian-cloud"
}
resource "google_compute_disk" "tf-test-disk" {
name = "debian-disk-%{suffix}"
image = data.google_compute_image.tf-test-image.self_link
size = 10
type = "pd-ssd"
zone = "us-central1-a"
}
resource "google_compute_snapshot" "a" {
name = "tf-test-snapshot-a-%{suffix}"
description = "Example snapshot."
source_disk = google_compute_disk.tf-test-disk.id
zone = "us-central1-a"
labels = {
my_label = "a"
}
storage_locations = ["us-central1"]
}
resource "google_compute_snapshot" "b" {
name = "tf-test-snapshot-b-%{suffix}"
description = "Example snapshot."
source_disk = google_compute_disk.tf-test-disk.id
zone = "us-central1-a"
labels = {
my_label = "b"
}
storage_locations = ["us-central1"]
}
resource "google_compute_snapshot" "c" {
name = "tf-test-snapshot-c-%{suffix}"
description = "Example snapshot."
source_disk = google_compute_disk.tf-test-disk.id
zone = "us-central1-a"
labels = {
my_label = "c"
}
storage_locations = ["us-central1"]
}
data "google_compute_snapshot" "default" {
project = "%{project}"
most_recent = true
filter = "name = tf-test-snapshot-c-%{suffix}"
depends_on = [google_compute_snapshot.c]
}
`, map[string]interface{}{"project": project, "suffix": suffix})
}
1 change: 1 addition & 0 deletions google/provider.go
Expand Up @@ -811,6 +811,7 @@ func Provider() *schema.Provider {
"google_compute_resource_policy": dataSourceGoogleComputeResourcePolicy(),
"google_compute_router": dataSourceGoogleComputeRouter(),
"google_compute_router_status": dataSourceGoogleComputeRouterStatus(),
"google_compute_snapshot": dataSourceGoogleComputeSnapshot(),
"google_compute_ssl_certificate": dataSourceGoogleComputeSslCertificate(),
"google_compute_ssl_policy": dataSourceGoogleComputeSslPolicy(),
"google_compute_subnetwork": dataSourceGoogleComputeSubnetwork(),
Expand Down
50 changes: 50 additions & 0 deletions website/docs/d/compute_snapshot.html.markdown
@@ -0,0 +1,50 @@
---
subcategory: "Compute Engine"
page_title: "Google: google_compute_snapshot"
description: |-
Get information about a Google Compute Snapshot.
---

# google\_compute\_snapshot

To get more information about Snapshot, see:

* [API documentation](https://cloud.google.com/compute/docs/reference/rest/v1/snapshots)
* How-to Guides
* [Official Documentation](https://cloud.google.com/compute/docs/disks/create-snapshots)

## Example Usage

```hcl
#by name
data "google_compute_snapshot" "snapshot" {
name = "my-snapshot"
}
# using a filter
data "google_compute_snapshot" "latest-snapshot" {
filter = "name != my-snapshot"
most_recent = true
}
```

## Argument Reference

The following arguments are supported:

* `name` - (Optional) The name of the compute snapshot. One of `name` or `filter` must be provided.

* `filter` - (Optional) A filter to retrieve the compute snapshot.
See [gcloud topic filters](https://cloud.google.com/sdk/gcloud/reference/topic/filters) for reference.
If multiple compute snapshot match, either adjust the filter or specify `most_recent`. One of `name` or `filter` must be provided.

* `most_recent` - (Optional) If `filter` is provided, ensures the most recent snapshot is returned when multiple compute snapshot match.

- - -

* `project` - (Optional) The ID of the project in which the resource belongs.
If it is not provided, the provider project is used.

## Attributes Reference

See [google_compute_snapshot](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_snapshot) resource for details of the available attributes.

0 comments on commit 1e3c865

Please sign in to comment.