From dd108412c36b37c5e1134ba03c8289fa411d48bb Mon Sep 17 00:00:00 2001 From: The Magician Date: Thu, 28 May 2020 17:11:56 -0700 Subject: [PATCH] Data Catalog tag template (#3555) (#6485) Signed-off-by: Modular Magician --- .changelog/3555.txt | 3 + google/provider.go | 5 +- google/resource_data_catalog_tag_template.go | 600 ++++++++++++++++++ ...ata_catalog_tag_template_generated_test.go | 124 ++++ .../r/data_catalog_tag_template.html.markdown | 215 +++++++ website/google.erb | 4 + 6 files changed, 949 insertions(+), 2 deletions(-) create mode 100644 .changelog/3555.txt create mode 100644 google/resource_data_catalog_tag_template.go create mode 100644 google/resource_data_catalog_tag_template_generated_test.go create mode 100644 website/docs/r/data_catalog_tag_template.html.markdown diff --git a/.changelog/3555.txt b/.changelog/3555.txt new file mode 100644 index 00000000000..4dd49f8e142 --- /dev/null +++ b/.changelog/3555.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +`data_catalog_tag_template` +``` diff --git a/google/provider.go b/google/provider.go index 6b138e9326c..2f1884760e8 100644 --- a/google/provider.go +++ b/google/provider.go @@ -563,9 +563,9 @@ func Provider() terraform.ResourceProvider { return provider } -// Generated resources: 133 +// Generated resources: 134 // Generated IAM resources: 57 -// Total generated resources: 190 +// Total generated resources: 191 func ResourceMap() map[string]*schema.Resource { resourceMap, _ := ResourceMapWithErrors() return resourceMap @@ -672,6 +672,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_data_catalog_entry_group_iam_member": ResourceIamMember(DataCatalogEntryGroupIamSchema, DataCatalogEntryGroupIamUpdaterProducer, DataCatalogEntryGroupIdParseFunc), "google_data_catalog_entry_group_iam_policy": ResourceIamPolicy(DataCatalogEntryGroupIamSchema, DataCatalogEntryGroupIamUpdaterProducer, DataCatalogEntryGroupIdParseFunc), "google_data_catalog_entry": resourceDataCatalogEntry(), + "google_data_catalog_tag_template": resourceDataCatalogTagTemplate(), "google_dataproc_autoscaling_policy": resourceDataprocAutoscalingPolicy(), "google_datastore_index": resourceDatastoreIndex(), "google_deployment_manager_deployment": resourceDeploymentManagerDeployment(), diff --git a/google/resource_data_catalog_tag_template.go b/google/resource_data_catalog_tag_template.go new file mode 100644 index 00000000000..2a2224aff35 --- /dev/null +++ b/google/resource_data_catalog_tag_template.go @@ -0,0 +1,600 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "fmt" + "log" + "reflect" + "regexp" + "strconv" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" +) + +func resourceDataCatalogTagTemplate() *schema.Resource { + return &schema.Resource{ + Create: resourceDataCatalogTagTemplateCreate, + Read: resourceDataCatalogTagTemplateRead, + Update: resourceDataCatalogTagTemplateUpdate, + Delete: resourceDataCatalogTagTemplateDelete, + + Importer: &schema.ResourceImporter{ + State: resourceDataCatalogTagTemplateImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(4 * time.Minute), + Update: schema.DefaultTimeout(4 * time.Minute), + Delete: schema.DefaultTimeout(4 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "fields": { + Type: schema.TypeSet, + Required: true, + ForceNew: true, + Description: `Set of tag template field IDs and the settings for the field. This set is an exhaustive list of the allowed fields. This set must contain at least one field and at most 500 fields.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "field_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "type": { + Type: schema.TypeList, + Required: true, + Description: `The type of value this tag field can contain.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enum_type": { + Type: schema.TypeList, + Optional: true, + Description: `Represents an enum type. + Exactly one of 'primitive_type' or 'enum_type' must be set`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allowed_values": { + Type: schema.TypeSet, + Required: true, + Description: `The set of allowed values for this enum. The display names of the +values must be case-insensitively unique within this set. Currently, +enum values can only be added to the list of allowed values. Deletion +and renaming of enum values are not supported. +Can have up to 500 allowed values.`, + Elem: datacatalogTagTemplateFieldsFieldsTypeEnumTypeAllowedValuesSchema(), + // Default schema.HashSchema is used. + }, + }, + }, + }, + "primitive_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"DOUBLE", "STRING", "BOOL", "TIMESTAMP", ""}, false), + Description: `Represents primitive types - string, bool etc. + Exactly one of 'primitive_type' or 'enum_type' must be set Possible values: ["DOUBLE", "STRING", "BOOL", "TIMESTAMP"]`, + }, + }, + }, + }, + "display_name": { + Type: schema.TypeString, + Optional: true, + Description: `The display name for this field.`, + }, + "is_required": { + Type: schema.TypeBool, + Optional: true, + Description: `Whether this is a required field. Defaults to false.`, + }, + "order": { + Type: schema.TypeInt, + Optional: true, + Description: `The order of this field with respect to other fields in this tag template. +A higher value indicates a more important field. The value can be negative. +Multiple fields can have the same order, and field orders within a tag do not have to be sequential.`, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The resource name of the tag template field in URL format. Example: projects/{project_id}/locations/{location}/tagTemplates/{tagTemplateId}/fields/{field}`, + }, + }, + }, + }, + "tag_template_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateRegexp(`^[a-z_][a-z0-9_]{0,63}$`), + Description: `The id of the tag template to create.`, + }, + "display_name": { + Type: schema.TypeString, + Optional: true, + Description: `The display name for this template.`, + }, + "force_delete": { + Type: schema.TypeBool, + Optional: true, + Description: `This confirms the deletion of any possible tags using this template. Must be set to true in order to delete the tag template.`, + }, + "region": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + Description: `Template location region.`, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The resource name of the tag template in URL format. Example: projects/{project_id}/locations/{location}/tagTemplates/{tagTemplateId}`, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + } +} + +func datacatalogTagTemplateFieldsFieldsTypeEnumTypeAllowedValuesSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "display_name": { + Type: schema.TypeString, + Required: true, + Description: `The display name of the enum value.`, + }, + }, + } +} + +func resourceDataCatalogTagTemplateCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + displayNameProp, err := expandDataCatalogTagTemplateDisplayName(d.Get("display_name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("display_name"); !isEmptyValue(reflect.ValueOf(displayNameProp)) && (ok || !reflect.DeepEqual(v, displayNameProp)) { + obj["displayName"] = displayNameProp + } + fieldsProp, err := expandDataCatalogTagTemplateFields(d.Get("fields"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("fields"); !isEmptyValue(reflect.ValueOf(fieldsProp)) && (ok || !reflect.DeepEqual(v, fieldsProp)) { + obj["fields"] = fieldsProp + } + + url, err := replaceVars(d, config, "{{DataCatalogBasePath}}projects/{{project}}/locations/{{region}}/tagTemplates?tagTemplateId={{tag_template_id}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new TagTemplate: %#v", obj) + project, err := getProject(d, config) + if err != nil { + return err + } + res, err := sendRequestWithTimeout(config, "POST", project, url, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating TagTemplate: %s", err) + } + if err := d.Set("name", flattenDataCatalogTagTemplateName(res["name"], d, config)); err != nil { + return fmt.Errorf(`Error setting computed identity field "name": %s`, err) + } + + // Store the ID now + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating TagTemplate %q: %#v", d.Id(), res) + + return resourceDataCatalogTagTemplateRead(d, meta) +} + +func resourceDataCatalogTagTemplateRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "{{DataCatalogBasePath}}{{name}}") + if err != nil { + return err + } + + project, err := getProject(d, config) + if err != nil { + return err + } + res, err := sendRequest(config, "GET", project, url, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("DataCatalogTagTemplate %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading TagTemplate: %s", err) + } + + region, err := getRegion(d, config) + if err != nil { + return err + } + if err := d.Set("region", region); err != nil { + return fmt.Errorf("Error reading TagTemplate: %s", err) + } + + if err := d.Set("name", flattenDataCatalogTagTemplateName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading TagTemplate: %s", err) + } + if err := d.Set("display_name", flattenDataCatalogTagTemplateDisplayName(res["displayName"], d, config)); err != nil { + return fmt.Errorf("Error reading TagTemplate: %s", err) + } + if err := d.Set("fields", flattenDataCatalogTagTemplateFields(res["fields"], d, config)); err != nil { + return fmt.Errorf("Error reading TagTemplate: %s", err) + } + + return nil +} + +func resourceDataCatalogTagTemplateUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + displayNameProp, err := expandDataCatalogTagTemplateDisplayName(d.Get("display_name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("display_name"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, displayNameProp)) { + obj["displayName"] = displayNameProp + } + + url, err := replaceVars(d, config, "{{DataCatalogBasePath}}{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating TagTemplate %q: %#v", d.Id(), obj) + updateMask := []string{} + + if d.HasChange("display_name") { + updateMask = append(updateMask, "displayName") + } + // updateMask is a URL parameter but not present in the schema, so replaceVars + // won't set it + url, err = addQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) + if err != nil { + return err + } + _, err = sendRequestWithTimeout(config, "PATCH", project, url, obj, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return fmt.Errorf("Error updating TagTemplate %q: %s", d.Id(), err) + } + + return resourceDataCatalogTagTemplateRead(d, meta) +} + +func resourceDataCatalogTagTemplateDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + url, err := replaceVars(d, config, "{{DataCatalogBasePath}}{{name}}?force={{force_delete}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting TagTemplate %q", d.Id()) + + res, err := sendRequestWithTimeout(config, "DELETE", project, url, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "TagTemplate") + } + + log.Printf("[DEBUG] Finished deleting TagTemplate %q: %#v", d.Id(), res) + return nil +} + +func resourceDataCatalogTagTemplateImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + + // current import_formats can't import fields with forward slashes in their value + if err := parseImportId([]string{"(?P.+)"}, d, config); err != nil { + return nil, err + } + + name := d.Get("name").(string) + egRegex := regexp.MustCompile("projects/(.+)/locations/(.+)/tagTemplates/(.+)") + + parts := egRegex.FindStringSubmatch(name) + if len(parts) != 4 { + return nil, fmt.Errorf("entry group name does not fit the format %s", egRegex) + } + d.Set("project", parts[1]) + d.Set("region", parts[2]) + d.Set("tag_template_id", parts[3]) + return []*schema.ResourceData{d}, nil +} + +func flattenDataCatalogTagTemplateName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenDataCatalogTagTemplateDisplayName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenDataCatalogTagTemplateFields(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return v + } + l := v.(map[string]interface{}) + transformed := make([]interface{}, 0, len(l)) + for k, raw := range l { + original := raw.(map[string]interface{}) + transformed = append(transformed, map[string]interface{}{ + "field_id": k, + "name": flattenDataCatalogTagTemplateFieldsName(original["name"], d, config), + "display_name": flattenDataCatalogTagTemplateFieldsDisplayName(original["displayName"], d, config), + "type": flattenDataCatalogTagTemplateFieldsType(original["type"], d, config), + "is_required": flattenDataCatalogTagTemplateFieldsIsRequired(original["isRequired"], d, config), + "order": flattenDataCatalogTagTemplateFieldsOrder(original["order"], d, config), + }) + } + return transformed +} +func flattenDataCatalogTagTemplateFieldsName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenDataCatalogTagTemplateFieldsDisplayName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenDataCatalogTagTemplateFieldsType(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["primitive_type"] = + flattenDataCatalogTagTemplateFieldsTypePrimitiveType(original["primitiveType"], d, config) + transformed["enum_type"] = + flattenDataCatalogTagTemplateFieldsTypeEnumType(original["enumType"], d, config) + return []interface{}{transformed} +} +func flattenDataCatalogTagTemplateFieldsTypePrimitiveType(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenDataCatalogTagTemplateFieldsTypeEnumType(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["allowed_values"] = + flattenDataCatalogTagTemplateFieldsTypeEnumTypeAllowedValues(original["allowedValues"], d, config) + return []interface{}{transformed} +} +func flattenDataCatalogTagTemplateFieldsTypeEnumTypeAllowedValues(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := schema.NewSet(schema.HashResource(datacatalogTagTemplateFieldsFieldsTypeEnumTypeAllowedValuesSchema()), []interface{}{}) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed.Add(map[string]interface{}{ + "display_name": flattenDataCatalogTagTemplateFieldsTypeEnumTypeAllowedValuesDisplayName(original["displayName"], d, config), + }) + } + return transformed +} +func flattenDataCatalogTagTemplateFieldsTypeEnumTypeAllowedValuesDisplayName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenDataCatalogTagTemplateFieldsIsRequired(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenDataCatalogTagTemplateFieldsOrder(v interface{}, d *schema.ResourceData, config *Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func expandDataCatalogTagTemplateDisplayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandDataCatalogTagTemplateFields(v interface{}, d TerraformResourceData, config *Config) (map[string]interface{}, error) { + if v == nil { + return map[string]interface{}{}, nil + } + m := make(map[string]interface{}) + for _, raw := range v.(*schema.Set).List() { + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedName, err := expandDataCatalogTagTemplateFieldsName(original["name"], d, config) + if err != nil { + return nil, err + } + transformed["name"] = transformedName + transformedDisplayName, err := expandDataCatalogTagTemplateFieldsDisplayName(original["display_name"], d, config) + if err != nil { + return nil, err + } + transformed["displayName"] = transformedDisplayName + transformedType, err := expandDataCatalogTagTemplateFieldsType(original["type"], d, config) + if err != nil { + return nil, err + } + transformed["type"] = transformedType + transformedIsRequired, err := expandDataCatalogTagTemplateFieldsIsRequired(original["is_required"], d, config) + if err != nil { + return nil, err + } + transformed["isRequired"] = transformedIsRequired + transformedOrder, err := expandDataCatalogTagTemplateFieldsOrder(original["order"], d, config) + if err != nil { + return nil, err + } + transformed["order"] = transformedOrder + + transformedFieldId, err := expandString(original["field_id"], d, config) + if err != nil { + return nil, err + } + m[transformedFieldId] = transformed + } + return m, nil +} + +func expandDataCatalogTagTemplateFieldsName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandDataCatalogTagTemplateFieldsDisplayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandDataCatalogTagTemplateFieldsType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedPrimitiveType, err := expandDataCatalogTagTemplateFieldsTypePrimitiveType(original["primitive_type"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPrimitiveType); val.IsValid() && !isEmptyValue(val) { + transformed["primitiveType"] = transformedPrimitiveType + } + + transformedEnumType, err := expandDataCatalogTagTemplateFieldsTypeEnumType(original["enum_type"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedEnumType); val.IsValid() && !isEmptyValue(val) { + transformed["enumType"] = transformedEnumType + } + + return transformed, nil +} + +func expandDataCatalogTagTemplateFieldsTypePrimitiveType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandDataCatalogTagTemplateFieldsTypeEnumType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedAllowedValues, err := expandDataCatalogTagTemplateFieldsTypeEnumTypeAllowedValues(original["allowed_values"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedAllowedValues); val.IsValid() && !isEmptyValue(val) { + transformed["allowedValues"] = transformedAllowedValues + } + + return transformed, nil +} + +func expandDataCatalogTagTemplateFieldsTypeEnumTypeAllowedValues(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + if raw == nil { + continue + } + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedDisplayName, err := expandDataCatalogTagTemplateFieldsTypeEnumTypeAllowedValuesDisplayName(original["display_name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDisplayName); val.IsValid() && !isEmptyValue(val) { + transformed["displayName"] = transformedDisplayName + } + + req = append(req, transformed) + } + return req, nil +} + +func expandDataCatalogTagTemplateFieldsTypeEnumTypeAllowedValuesDisplayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandDataCatalogTagTemplateFieldsIsRequired(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandDataCatalogTagTemplateFieldsOrder(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} diff --git a/google/resource_data_catalog_tag_template_generated_test.go b/google/resource_data_catalog_tag_template_generated_test.go new file mode 100644 index 00000000000..d0328a1cd38 --- /dev/null +++ b/google/resource_data_catalog_tag_template_generated_test.go @@ -0,0 +1,124 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccDataCatalogTagTemplate_dataCatalogTagTemplateBasicExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "force_delete": true, + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckDataCatalogTagTemplateDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccDataCatalogTagTemplate_dataCatalogTagTemplateBasicExample(context), + }, + { + ResourceName: "google_data_catalog_tag_template.basic_tag_template", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"region", "tag_template_id", "force_delete"}, + }, + }, + }) +} + +func testAccDataCatalogTagTemplate_dataCatalogTagTemplateBasicExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_data_catalog_tag_template" "basic_tag_template" { + tag_template_id = "tf_test_my_template%{random_suffix}" + region = "us-central1" + display_name = "Demo Tag Template" + + fields { + field_id = "source" + display_name = "Source of data asset" + type { + primitive_type = "STRING" + } + is_required = true + } + + fields { + field_id = "num_rows" + display_name = "Number of rows in the data asset" + type { + primitive_type = "DOUBLE" + } + } + + fields { + field_id = "pii_type" + display_name = "PII type" + type { + enum_type { + allowed_values { + display_name = "EMAIL" + } + allowed_values { + display_name = "SOCIAL SECURITY NUMBER" + } + allowed_values { + display_name = "NONE" + } + } + } + } + + force_delete = "%{force_delete}" +} +`, context) +} + +func testAccCheckDataCatalogTagTemplateDestroyProducer(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_data_catalog_tag_template" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := googleProviderConfig(t) + + url, err := replaceVarsForTest(config, rs, "{{DataCatalogBasePath}}{{name}}") + if err != nil { + return err + } + + _, err = sendRequest(config, "GET", "", url, nil) + if err == nil { + return fmt.Errorf("DataCatalogTagTemplate still exists at %s", url) + } + } + + return nil + } +} diff --git a/website/docs/r/data_catalog_tag_template.html.markdown b/website/docs/r/data_catalog_tag_template.html.markdown new file mode 100644 index 00000000000..4d02016193b --- /dev/null +++ b/website/docs/r/data_catalog_tag_template.html.markdown @@ -0,0 +1,215 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +subcategory: "Data catalog" +layout: "google" +page_title: "Google: google_data_catalog_tag_template" +sidebar_current: "docs-google-data-catalog-tag-template" +description: |- + A tag template defines a tag, which can have one or more typed fields. +--- + +# google\_data\_catalog\_tag\_template + +A tag template defines a tag, which can have one or more typed fields. +The template is used to create and attach the tag to GCP resources. + + +To get more information about TagTemplate, see: + +* [API documentation](https://cloud.google.com/data-catalog/docs/reference/rest/v1/projects.locations.tagTemplates) +* How-to Guides + * [Official Documentation](https://cloud.google.com/data-catalog/docs) + + +## Example Usage - Data Catalog Tag Template Basic + + +```hcl +resource "google_data_catalog_tag_template" "basic_tag_template" { + tag_template_id = "my_template" + region = "us-central1" + display_name = "Demo Tag Template" + + fields { + field_id = "source" + display_name = "Source of data asset" + type { + primitive_type = "STRING" + } + is_required = true + } + + fields { + field_id = "num_rows" + display_name = "Number of rows in the data asset" + type { + primitive_type = "DOUBLE" + } + } + + fields { + field_id = "pii_type" + display_name = "PII type" + type { + enum_type { + allowed_values { + display_name = "EMAIL" + } + allowed_values { + display_name = "SOCIAL SECURITY NUMBER" + } + allowed_values { + display_name = "NONE" + } + } + } + } + + force_delete = "false" +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `fields` - + (Required) + Set of tag template field IDs and the settings for the field. This set is an exhaustive list of the allowed fields. This set must contain at least one field and at most 500 fields. Structure is documented below. + +* `tag_template_id` - + (Required) + The id of the tag template to create. + + +The `fields` block supports: + +* `field_id` - (Required) The identifier for this object. Format specified above. + +* `name` - + The resource name of the tag template field in URL format. Example: projects/{project_id}/locations/{location}/tagTemplates/{tagTemplateId}/fields/{field} + +* `display_name` - + (Optional) + The display name for this field. + +* `type` - + (Required) + The type of value this tag field can contain. Structure is documented below. + +* `is_required` - + (Optional) + Whether this is a required field. Defaults to false. + +* `order` - + (Optional) + The order of this field with respect to other fields in this tag template. + A higher value indicates a more important field. The value can be negative. + Multiple fields can have the same order, and field orders within a tag do not have to be sequential. + + +The `type` block supports: + +* `primitive_type` - + (Optional) + Represents primitive types - string, bool etc. + Exactly one of `primitive_type` or `enum_type` must be set + + Possible values are: + * `DOUBLE` + * `STRING` + * `BOOL` + * `TIMESTAMP` + +* `enum_type` - + (Optional) + Represents an enum type. + Exactly one of `primitive_type` or `enum_type` must be set Structure is documented below. + + +The `enum_type` block supports: + +* `allowed_values` - + (Required) + The set of allowed values for this enum. The display names of the + values must be case-insensitively unique within this set. Currently, + enum values can only be added to the list of allowed values. Deletion + and renaming of enum values are not supported. + Can have up to 500 allowed values. Structure is documented below. + + +The `allowed_values` block supports: + +* `display_name` - + (Required) + The display name of the enum value. + +- - - + + +* `display_name` - + (Optional) + The display name for this template. + +* `region` - + (Optional) + Template location region. + +* `force_delete` - + (Optional) + This confirms the deletion of any possible tags using this template. Must be set to true in order to delete the tag template. + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `id` - an identifier for the resource with format `{{name}}` + +* `name` - + The resource name of the tag template in URL format. Example: projects/{project_id}/locations/{location}/tagTemplates/{tagTemplateId} + + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 4 minutes. +- `update` - Default is 4 minutes. +- `delete` - Default is 4 minutes. + +## Import + +TagTemplate can be imported using any of these accepted formats: + +``` +$ terraform import google_data_catalog_tag_template.default {{name}} +``` + +-> If you're importing a resource with beta features, make sure to include `-provider=google-beta` +as an argument so that Terraform uses the correct provider to import your resource. + +## User Project Overrides + +This resource supports [User Project Overrides](https://www.terraform.io/docs/providers/google/guides/provider_reference.html#user_project_override). diff --git a/website/google.erb b/website/google.erb index 2fd729c59a4..e1b1b1a45d1 100644 --- a/website/google.erb +++ b/website/google.erb @@ -1507,6 +1507,10 @@ google_data_catalog_entry_group_iam +
  • + google_data_catalog_tag_template +
  • +