diff --git a/mmv1/products/tags/api.yaml b/mmv1/products/tags/api.yaml index 9f5f4f3415dd..0a0cd095a08f 100644 --- a/mmv1/products/tags/api.yaml +++ b/mmv1/products/tags/api.yaml @@ -93,3 +93,59 @@ objects: A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z". output: true + - !ruby/object:Api::Resource + name: 'TagValue' + min_version: beta + base_url: tagValues + self_link: "tagValues/{{name}}" + update_verb: :PATCH + update_mask: true + description: A TagValue is a child of a particular TagKey. TagValues are used to group cloud resources for the purpose of controlling them using policies. + references: !ruby/object:Api::Resource::ReferenceLinks + guides: + 'Official Documentation': + 'https://cloud.google.com/resource-manager/docs/tags/tags-creating-and-managing' + api: 'https://cloud.google.com/resource-manager/reference/rest/v3/tagValues' + properties: + - !ruby/object:Api::Type::String + name: name + description: | + The generated numeric id for the TagValue. + output: true + - !ruby/object:Api::Type::String + name: parent + description: | + Input only. The resource name of the new TagValue's parent. Must be of the form tagKeys/{tag_key_id}. + input: true + required: true + - !ruby/object:Api::Type::String + name: shortName + description: | + Input only. User-assigned short name for TagValue. The short name should be unique for TagValues within the same parent TagKey. + + The short name must be 63 characters or less, beginning and ending with an alphanumeric character ([a-z0-9A-Z]) with dashes (-), underscores (_), dots (.), and alphanumerics between. + input: true + required: true + - !ruby/object:Api::Type::String + name: namespacedName + description: | + Output only. Namespaced name of the TagValue. Will be in the format {organizationId}/{tag_key_short_name}/{shortName}. + output: true + - !ruby/object:Api::Type::String + name: description + description: | + User-assigned description of the TagValue. Must not exceed 256 characters. + - !ruby/object:Api::Type::String + name: createTime + description: | + Output only. Creation time. + + A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z". + output: true + - !ruby/object:Api::Type::String + name: updateTime + description: | + Output only. Update time. + + A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z". + output: true diff --git a/mmv1/products/tags/terraform.yaml b/mmv1/products/tags/terraform.yaml index f1d81ce85cf3..b3b05cf6727b 100644 --- a/mmv1/products/tags/terraform.yaml +++ b/mmv1/products/tags/terraform.yaml @@ -21,14 +21,43 @@ overrides: !ruby/object:Overrides::ResourceOverrides properties: name: !ruby/object:Overrides::Terraform::PropertyOverride custom_flatten: 'templates/terraform/custom_flatten/name_from_self_link.erb' + shortName: !ruby/object:Overrides::Terraform::PropertyOverride + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.StringLenBetween(1, 63)' + description: !ruby/object:Overrides::Terraform::PropertyOverride + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.StringLenBetween(0, 256)' examples: - !ruby/object:Provider::Terraform::Examples name: "tag_key_basic" min_version: 'beta' - skip_vcr: true skip_test: true primary_resource_id: "key" vars: short_name: "foo" test_env_vars: org_id: :ORG_ID + TagValue: !ruby/object:Overrides::Terraform::ResourceOverride + autogen_async: true + mutex: tagValue/{{parent}} + id_format: "tagValues/{{name}}" + import_format: ["tagValues/{{name}}", "{{name}}"] + properties: + name: !ruby/object:Overrides::Terraform::PropertyOverride + custom_flatten: 'templates/terraform/custom_flatten/name_from_self_link.erb' + shortName: !ruby/object:Overrides::Terraform::PropertyOverride + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.StringLenBetween(1, 63)' + description: !ruby/object:Overrides::Terraform::PropertyOverride + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.StringLenBetween(0, 256)' + examples: + - !ruby/object:Provider::Terraform::Examples + name: "tag_value_basic" + min_version: 'beta' + skip_test: true + primary_resource_id: "value" + vars: + short_name: "foo" + test_env_vars: + org_id: :ORG_ID diff --git a/mmv1/templates/terraform/examples/tag_value_basic.tf.erb b/mmv1/templates/terraform/examples/tag_value_basic.tf.erb new file mode 100644 index 000000000000..c54968c406be --- /dev/null +++ b/mmv1/templates/terraform/examples/tag_value_basic.tf.erb @@ -0,0 +1,15 @@ +resource "google_tags_tag_key" "key" { + provider = google-beta + + parent = "organizations/<%= ctx[:test_env_vars]['org_id'] %>" + short_name = "keyname" + description = "For a certain set of resources." +} + +resource "google_tags_tag_value" "<%= ctx[:primary_resource_id] %>" { + provider = google-beta + + parent = "tagKeys/${google_tags_tag_key.key.name}" + short_name = "<%= ctx[:vars]['short_name'] %>" + description = "For <%= ctx[:vars]['short_name'] %> resources."" +} diff --git a/mmv1/third_party/terraform/tests/resource_tags_tag_key_test.go.erb b/mmv1/third_party/terraform/tests/resource_tags_tag_key_test.go.erb deleted file mode 100644 index d113ba9467c1..000000000000 --- a/mmv1/third_party/terraform/tests/resource_tags_tag_key_test.go.erb +++ /dev/null @@ -1,159 +0,0 @@ -<% autogen_exception -%> -package google - -<% unless version == "ga" -%> -import ( - "fmt" - "strings" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -// Tags tests cannot be run in parallel without running into Error Code 10: ABORTED -// See https://github.com/hashicorp/terraform-provider-google/issues/8637 - -func TestAccTags(t *testing.T) { - testCases := map[string]func(t *testing.T){ - "basic": testAccTagsTagKey_tagKeyBasic, - "update": testAccTagsTagKey_update, - } - - for name, tc := range testCases { - // shadow the tc variable into scope so that when - // the loop continues, if t.Run hasn't executed tc(t) - // yet, we don't have a race condition - // see https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables - tc := tc - t.Run(name, func(t *testing.T) { - tc(t) - }) - } -} - -func testAccTagsTagKey_tagKeyBasic(t *testing.T) { - context := map[string]interface{}{ - "org_id": getTestOrgFromEnv(t), - "random_suffix": randString(t, 10), - } - - vcrTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProvidersOiCS, - ExternalProviders: map[string]resource.ExternalProvider{ - "random": {}, - }, - CheckDestroy: testAccCheckTagsTagKeyDestroyProducer(t), - Steps: []resource.TestStep{ - { - Config: testAccTagsTagKey_tagKeyBasicExample(context), - }, - }, - }) -} - -func testAccTagsTagKey_tagKeyBasicExample(context map[string]interface{}) string { - return Nprintf(` -resource "google_tags_tag_key" "key" { - provider = google-beta - - parent = "organizations/%{org_id}" - short_name = "foo%{random_suffix}" - description = "For foo%{random_suffix} resources." -} -`, context) -} - -func testAccTagsTagKey_update(t *testing.T) { - context := map[string]interface{}{ - "org_id": getTestOrgFromEnv(t), - "random_suffix": randString(t, 10), - } - - vcrTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProvidersOiCS, - ExternalProviders: map[string]resource.ExternalProvider{ - "random": {}, - }, - CheckDestroy: testAccCheckTagsTagKeyDestroyProducer(t), - Steps: []resource.TestStep{ - { - Config: testAccTagsTagKey_basic(context), - }, - { - ResourceName: "google_tags_tag_key.key", - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccTagsTagKey_basicUpdated(context), - }, - { - ResourceName: "google_tags_tag_key.key", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func testAccTagsTagKey_basic(context map[string]interface{}) string { - return Nprintf(` -resource "google_tags_tag_key" "key" { - provider = google-beta - - parent = "organizations/%{org_id}" - short_name = "foo%{random_suffix}" - description = "For foo%{random_suffix} resources." -} -`, context) -} - -func testAccTagsTagKey_basicUpdated(context map[string]interface{}) string { - return Nprintf(` -resource "google_tags_tag_key" "key" { - provider = google-beta - - parent = "organizations/%{org_id}" - short_name = "foo%{random_suffix}" - description = "Anything related to foo%{random_suffix}" -} -`, context) -} - -func testAccCheckTagsTagKeyDestroyProducer(t *testing.T) func(s *terraform.State) error { - return func(s *terraform.State) error { - for name, rs := range s.RootModule().Resources { - if rs.Type != "google_tags_tag_key" { - continue - } - if strings.HasPrefix(name, "data.") { - continue - } - - config := googleProviderConfig(t) - - url, err := replaceVarsForTest(config, rs, "{{TagsBasePath}}tagKeys/{{name}}") - if err != nil { - return err - } - - billingProject := "" - - if config.BillingProject != "" { - billingProject = config.BillingProject - } - - _, err = sendRequest(config, "GET", billingProject, url, config.userAgent, nil) - if err == nil { - return fmt.Errorf("TagsTagKey still exists at %s", url) - } - } - - return nil - } -} - -<% end %> \ No newline at end of file diff --git a/mmv1/third_party/terraform/tests/resource_tags_test.go.erb b/mmv1/third_party/terraform/tests/resource_tags_test.go.erb new file mode 100644 index 000000000000..c7daee514227 --- /dev/null +++ b/mmv1/third_party/terraform/tests/resource_tags_test.go.erb @@ -0,0 +1,309 @@ +<% autogen_exception -%> +package google + +<% unless version == "ga" -%> +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +// Tags tests cannot be run in parallel without running into Error Code 10: ABORTED +// See https://github.com/hashicorp/terraform-provider-google/issues/8637 + +func TestAccTags(t *testing.T) { + testCases := map[string]func(t *testing.T){ + "tagKeyBasic": testAccTagsTagKey_tagKeyBasic, + "tagKeyUpdate": testAccTagsTagKey_tagKeyUpdate, + "tagValueBasic": testAccTagsTagValue_tagValueBasic, + "tagValueUpdate": testAccTagsTagValue_tagValueUpdate, + } + + for name, tc := range testCases { + // shadow the tc variable into scope so that when + // the loop continues, if t.Run hasn't executed tc(t) + // yet, we don't have a race condition + // see https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables + tc := tc + t.Run(name, func(t *testing.T) { + tc(t) + }) + } +} + +func testAccTagsTagKey_tagKeyBasic(t *testing.T) { + context := map[string]interface{}{ + "org_id": getTestOrgFromEnv(t), + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + }, + CheckDestroy: testAccCheckTagsTagKeyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccTagsTagKey_tagKeyBasicExample(context), + }, + }, + }) +} + +func testAccTagsTagKey_tagKeyBasicExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_tags_tag_key" "key" { + provider = google-beta + + parent = "organizations/%{org_id}" + short_name = "foo%{random_suffix}" + description = "For foo%{random_suffix} resources." +} +`, context) +} + +func testAccTagsTagKey_tagKeyUpdate(t *testing.T) { + context := map[string]interface{}{ + "org_id": getTestOrgFromEnv(t), + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + }, + CheckDestroy: testAccCheckTagsTagKeyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccTagsTagKey_basic(context), + }, + { + ResourceName: "google_tags_tag_key.key", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccTagsTagKey_basicUpdated(context), + }, + { + ResourceName: "google_tags_tag_key.key", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccTagsTagKey_basic(context map[string]interface{}) string { + return Nprintf(` +resource "google_tags_tag_key" "key" { + provider = google-beta + + parent = "organizations/%{org_id}" + short_name = "foo%{random_suffix}" + description = "For foo%{random_suffix} resources." +} +`, context) +} + +func testAccTagsTagKey_basicUpdated(context map[string]interface{}) string { + return Nprintf(` +resource "google_tags_tag_key" "key" { + provider = google-beta + + parent = "organizations/%{org_id}" + short_name = "foo%{random_suffix}" + description = "Anything related to foo%{random_suffix}" +} +`, context) +} + +func testAccCheckTagsTagKeyDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_tags_tag_key" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := googleProviderConfig(t) + + url, err := replaceVarsForTest(config, rs, "{{TagsBasePath}}tagKeys/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + if config.BillingProject != "" { + billingProject = config.BillingProject + } + + _, err = sendRequest(config, "GET", billingProject, url, config.userAgent, nil) + if err == nil { + return fmt.Errorf("TagsTagKey still exists at %s", url) + } + } + + return nil + } +} + +func testAccTagsTagValue_tagValueBasic(t *testing.T) { + context := map[string]interface{}{ + "org_id": getTestOrgFromEnv(t), + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + }, + CheckDestroy: testAccCheckTagsTagValueDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccTagsTagValue_tagValueBasicExample(context), + }, + }, + }) +} + +func testAccTagsTagValue_tagValueBasicExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_tags_tag_key" "key" { + provider = google-beta + + parent = "organizations/%{org_id}" + short_name = "foobarbaz%{random_suffix}" + description = "For foo/bar/baz resources." +} + +resource "google_tags_tag_value" "value" { + provider = google-beta + + parent = "tagKeys/${google_tags_tag_key.key.name}" + short_name = "foo%{random_suffix}" + description = "For foo resources." +} +`, context) +} + +func testAccTagsTagValue_tagValueUpdate(t *testing.T) { + context := map[string]interface{}{ + "org_id": getTestOrgFromEnv(t), + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + }, + CheckDestroy: testAccCheckTagsTagValueDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccTagsTagValue_basic(context), + }, + { + ResourceName: "google_tags_tag_key.key", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccTagsTagValue_basicUpdated(context), + }, + { + ResourceName: "google_tags_tag_key.key", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccTagsTagValue_basic(context map[string]interface{}) string { + return Nprintf(` +resource "google_tags_tag_key" "key" { + provider = google-beta + + parent = "organizations/%{org_id}" + short_name = "foobarbaz%{random_suffix}" + description = "For foo/bar/baz resources." +} + +resource "google_tags_tag_value" "value" { + provider = google-beta + + parent = "tagKeys/${google_tags_tag_key.key.name}" + short_name = "foo%{random_suffix}" + description = "For foo resources." +} +`, context) +} + +func testAccTagsTagValue_basicUpdated(context map[string]interface{}) string { + return Nprintf(` +resource "google_tags_tag_key" "key" { + provider = google-beta + + parent = "organizations/%{org_id}" + short_name = "foobarbaz%{random_suffix}" + description = "For foo/bar/baz resources." +} + +resource "google_tags_tag_value" "value" { + provider = google-beta + + parent = "tagKeys/${google_tags_tag_key.key.name}" + short_name = "foo%{random_suffix}" + description = "For any foo resources." +} +`, context) +} + +func testAccCheckTagsTagValueDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_tags_tag_key" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := googleProviderConfig(t) + + url, err := replaceVarsForTest(config, rs, "{{TagsBasePath}}tagValues/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + if config.BillingProject != "" { + billingProject = config.BillingProject + } + + _, err = sendRequest(config, "GET", billingProject, url, config.userAgent, nil) + if err == nil { + return fmt.Errorf("TagsTagValue still exists at %s", url) + } + } + + return nil + } +} + +<% end %> \ No newline at end of file