diff --git a/products/storage/ansible.yaml b/products/storage/ansible.yaml index b451eea1b415..2621b32e9ea1 100644 --- a/products/storage/ansible.yaml +++ b/products/storage/ansible.yaml @@ -31,6 +31,8 @@ overrides: !ruby/object:Overrides::ResourceOverrides exclude: true Object: !ruby/object:Overrides::Ansible::ResourceOverride exclude: true + HmacKey: !ruby/object:Overrides::Ansible::ResourceOverride + exclude: true files: !ruby/object:Provider::Config::Files resource: <%= lines(indent(compile('provider/ansible/resource~compile.yaml'), 4)) -%> diff --git a/products/storage/api.yaml b/products/storage/api.yaml index 39cab56414f1..41843ed822b3 100644 --- a/products/storage/api.yaml +++ b/products/storage/api.yaml @@ -780,4 +780,63 @@ objects: name: timeUpdated api_name: updated description: The modification time of the object metadata. - + - !ruby/object:Api::Resource + name: 'HmacKey' + kind: 'storage#hmacKey' + base_url: projects/{{project}}/hmacKeys + create_url: projects/{{project}}/hmacKeys?serviceAccountEmail={{serviceAccountEmail}} + self_link: projects/{{project}}/hmacKeys/{{accessId}} + # technically updatable, but implemented as custom update for new fingerprint support + input: true + references: !ruby/object:Api::Resource::ReferenceLinks + guides: + 'Official Documentation': 'https://cloud.google.com/storage/docs/authentication/managing-hmackeys' + api: 'https://cloud.google.com/storage/docs/json_api/v1/projects/hmacKeys' + description: | + The hmacKeys resource represents an HMAC key within Cloud Storage. The resource + consists of a secret and HMAC key metadata. HMAC keys can be used as credentials + for service accounts. + properties: + - !ruby/object:Api::Type::String + name: 'serviceAccountEmail' + description: | + The email address of the key's associated service account. + required: true + - !ruby/object:Api::Type::Enum + name: 'state' + description: | + The state of the key. Can be set to one of ACTIVE, INACTIVE. + default_value: :ACTIVE + values: + - :ACTIVE + - :INACTIVE + # - :DELETED (not directly settable) + update_verb: :PUT + update_url: projects/{{project}}/hmacKeys/{{accessId}} + update_id: 'state' + fingerprint_name: 'etag' + - !ruby/object:Api::Type::String + name: 'secret' + output: true + description: | + HMAC secret key material. + - !ruby/object:Api::Type::String + name: 'accessId' + output: true + description: | + The access ID of the HMAC Key. + - !ruby/object:Api::Type::String + name: 'id' + output: true + description: | + The ID of the HMAC key, including the Project ID and the Access ID. + - !ruby/object:Api::Type::Time + name: 'timeCreated' + output: true + description: | + 'The creation time of the HMAC key in RFC 3339 format. ' + - !ruby/object:Api::Type::Time + name: 'updated' + output: true + description: | + 'The last modification time of the HMAC key metadata in RFC 3339 format.' diff --git a/products/storage/inspec.yaml b/products/storage/inspec.yaml index 7afffda68508..6ab54d42bebf 100644 --- a/products/storage/inspec.yaml +++ b/products/storage/inspec.yaml @@ -60,4 +60,6 @@ overrides: !ruby/object:Overrides::ResourceOverrides timeCreated: !ruby/object:Overrides::Inspec::PropertyOverride override_name: object_created_times bucket: !ruby/object:Overrides::Inspec::PropertyOverride - override_name: object_bucket \ No newline at end of file + override_name: object_bucket + HmacKey: !ruby/object:Overrides::Inspec::ResourceOverride + exclude: true \ No newline at end of file diff --git a/products/storage/terraform.yaml b/products/storage/terraform.yaml index 1d1eec976ee9..28d4d940e8c5 100644 --- a/products/storage/terraform.yaml +++ b/products/storage/terraform.yaml @@ -102,6 +102,37 @@ overrides: !ruby/object:Overrides::ResourceOverrides ignore_read: true Object: !ruby/object:Overrides::Terraform::ResourceOverride exclude: true + HmacKey: !ruby/object:Overrides::Terraform::ResourceOverride + create_url: projects/{{project}}/hmacKeys?serviceAccountEmail={{service_account_email}} + self_link: projects/{{project}}/hmacKeys/{{access_id}} + id_format: "projects/{{project}}/hmacKeys/{{access_id}}" + import_format: ['projects/{{project}}/hmacKeys/{{access_id}}'] + # This resource does not have a name field + skip_sweeper: true + examples: + - !ruby/object:Provider::Terraform::Examples + name: "storage_hmac_key" + primary_resource_id: "key" + vars: + account_id: "my-svc-acc" + docs: !ruby/object:Provider::Terraform::Docs + warning: | + All arguments including the `secret` value will be stored in the raw + state as plain-text. [Read more about sensitive data in state](/docs/state/sensitive-data.html). + On import, the `secret` value will not be retrieved. + properties: + id: !ruby/object:Overrides::Terraform::PropertyOverride + exclude: true + secret: !ruby/object:Overrides::Terraform::PropertyOverride + ignore_read: true + sensitive: true + state: !ruby/object:Overrides::Terraform::PropertyOverride + update_url: projects/{{project}}/hmacKeys/{{access_id}} + custom_code: !ruby/object:Provider::Terraform::CustomCode + decoder: templates/terraform/decoders/storage_hmac_key.go.erb + pre_delete: templates/terraform/pre_delete/storage_hmac_key.go.erb + post_create: templates/terraform/post_create/storage_hmac_key.go.erb + test_check_destroy: templates/terraform/custom_check_destroy/storage_hmac_key.go.erb # This is for copying files over files: !ruby/object:Provider::Config::Files # These files have templating (ERB) code that will be run. diff --git a/templates/terraform/custom_check_destroy/storage_hmac_key.go.erb b/templates/terraform/custom_check_destroy/storage_hmac_key.go.erb new file mode 100644 index 000000000000..c7208fbdd1fc --- /dev/null +++ b/templates/terraform/custom_check_destroy/storage_hmac_key.go.erb @@ -0,0 +1,17 @@ +config := testAccProvider.Meta().(*Config) + +url, err := replaceVarsForTest(config, rs, "{{StorageBasePath}}projects/{{project}}/hmacKeys/{{access_id}}") +if err != nil { + return err +} + +res, err := sendRequest(config, "GET", "", url, nil) +if err != nil { + return nil +} + +if v := res["state"]; v == "DELETED" { + return nil +} + +return fmt.Errorf("StorageHmacKey still exists at %s", url) diff --git a/templates/terraform/decoders/storage_hmac_key.go.erb b/templates/terraform/decoders/storage_hmac_key.go.erb new file mode 100644 index 000000000000..85855239db2d --- /dev/null +++ b/templates/terraform/decoders/storage_hmac_key.go.erb @@ -0,0 +1,5 @@ +if v := res["state"]; v == "DELETED" { + return nil, nil +} + +return res, nil diff --git a/templates/terraform/examples/storage_hmac_key.tf.erb b/templates/terraform/examples/storage_hmac_key.tf.erb new file mode 100644 index 000000000000..243ad9ce2ac5 --- /dev/null +++ b/templates/terraform/examples/storage_hmac_key.tf.erb @@ -0,0 +1,7 @@ +resource "google_service_account" "service_account" { + account_id = "<%= ctx[:vars]['account_id'] %>" +} + +resource "google_storage_hmac_key" "<%= ctx[:primary_resource_id] %>" { + service_account_email = google_service_account.service_account.email +} diff --git a/templates/terraform/post_create/storage_hmac_key.go.erb b/templates/terraform/post_create/storage_hmac_key.go.erb new file mode 100644 index 000000000000..1304036f6636 --- /dev/null +++ b/templates/terraform/post_create/storage_hmac_key.go.erb @@ -0,0 +1,23 @@ +// `secret` and `access_id` are generated by the API upon successful CREATE. The following +// ensures terraform has the correct values based on the Projects.hmacKeys response object. +secret, ok := res["secret"].(string) +if !ok { + return fmt.Errorf("The response to CREATE was missing an expected field. Your create did not work.") +} + +d.Set("secret", secret) + +metadata := res["metadata"].(map[string]interface{}) +accessId, ok := metadata["accessId"].(string) +if !ok { + return fmt.Errorf("The response to CREATE was missing an expected field. Your create did not work.") +} + +d.Set("access_id", accessId) + +id, err = replaceVars(d, config, "projects/{{project}}/hmacKeys/{{access_id}}") +if err != nil { + return fmt.Errorf("Error constructing id: %s", err) +} + +d.SetId(id) diff --git a/templates/terraform/pre_delete/storage_hmac_key.go.erb b/templates/terraform/pre_delete/storage_hmac_key.go.erb new file mode 100644 index 000000000000..a8a299a116f5 --- /dev/null +++ b/templates/terraform/pre_delete/storage_hmac_key.go.erb @@ -0,0 +1,26 @@ +getUrl, err := replaceVars(d, config, "{{StorageBasePath}}projects/{{project}}/hmacKeys/{{access_id}}") +if err != nil { + return err +} + +getRes, err := sendRequest(config, "GET", project, getUrl, nil) +if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("StorageHmacKey %q", d.Id())) +} + +// HmacKeys need to be INACTIVE to be deleted and the API doesn't accept noop +// updates +if v := getRes["state"]; v == "ACTIVE" { + getRes["state"] = "INACTIVE" + updateUrl, err := replaceVars(d, config, "{{StorageBasePath}}projects/{{project}}/hmacKeys/{{access_id}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Deactivating HmacKey %q: %#v", d.Id(), getRes) + _, err = sendRequestWithTimeout(config, "PUT", project, updateUrl, getRes, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return fmt.Errorf("Error deactivating HmacKey %q: %s", d.Id(), err) + } +} + diff --git a/third_party/terraform/tests/resource_storage_hmac_key_test.go b/third_party/terraform/tests/resource_storage_hmac_key_test.go new file mode 100644 index 000000000000..7e28c8965797 --- /dev/null +++ b/third_party/terraform/tests/resource_storage_hmac_key_test.go @@ -0,0 +1,53 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccStorageHmacKey_update(t *testing.T) { + t.Parallel() + + saName := fmt.Sprintf("%v%v", "service-account", acctest.RandString(10)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckStorageHmacKeyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccGoogleStorageHmacKeyBasic(saName, "ACTIVE"), + }, + { + ResourceName: "google_storage_hmac_key.key", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"secret"}, + }, + { + Config: testAccGoogleStorageHmacKeyBasic(saName, "INACTIVE"), + }, + { + ResourceName: "google_storage_hmac_key.key", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"secret"}, + }, + }, + }) +} + +func testAccGoogleStorageHmacKeyBasic(saName, state string) string { + return fmt.Sprintf(` +resource "google_service_account" "service_account" { + account_id = "%s" +} + +resource "google_storage_hmac_key" "key" { + service_account_email = google_service_account.service_account.email + state = "%s" +} +`, saName, state) +} diff --git a/third_party/terraform/website-compiled/google.erb b/third_party/terraform/website-compiled/google.erb index 70e8a39dd62b..9df1613ad30f 100644 --- a/third_party/terraform/website-compiled/google.erb +++ b/third_party/terraform/website-compiled/google.erb @@ -1477,6 +1477,10 @@ google_storage_default_object_acl + > + google_storage_hmac_key + + > google_storage_notification