From 65641da68099454064cc5525c2a22b7062b921a3 Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Fri, 16 May 2025 21:46:07 +0000 Subject: [PATCH] Terraform support for Category and Term Resources (#13923) [upstream:fde094ff360a3ff3d46530e67cdc0f686d18d29c] Signed-off-by: Modular Magician --- .changelog/13923.txt | 7 + .../provider/provider_mmv1_resources.go | 6 +- .../dataplex/resource_dataplex_glossary.go | 6 +- .../resource_dataplex_glossary_category.go | 554 ++++++++++++++++++ ...plex_glossary_category_generated_meta.yaml | 25 + ...taplex_glossary_category_generated_test.go | 156 +++++ ...esource_dataplex_glossary_category_test.go | 85 +++ .../resource_dataplex_glossary_term.go | 554 ++++++++++++++++++ ...dataplex_glossary_term_generated_meta.yaml | 25 + ...e_dataplex_glossary_term_generated_test.go | 156 +++++ .../resource_dataplex_glossary_term_test.go | 85 +++ .../docs/r/dataplex_glossary.html.markdown | 6 +- .../dataplex_glossary_category.html.markdown | 183 ++++++ .../r/dataplex_glossary_term.html.markdown | 183 ++++++ 14 files changed, 2023 insertions(+), 8 deletions(-) create mode 100644 .changelog/13923.txt create mode 100644 google-beta/services/dataplex/resource_dataplex_glossary_category.go create mode 100644 google-beta/services/dataplex/resource_dataplex_glossary_category_generated_meta.yaml create mode 100644 google-beta/services/dataplex/resource_dataplex_glossary_category_generated_test.go create mode 100644 google-beta/services/dataplex/resource_dataplex_glossary_category_test.go create mode 100644 google-beta/services/dataplex/resource_dataplex_glossary_term.go create mode 100644 google-beta/services/dataplex/resource_dataplex_glossary_term_generated_meta.yaml create mode 100644 google-beta/services/dataplex/resource_dataplex_glossary_term_generated_test.go create mode 100644 google-beta/services/dataplex/resource_dataplex_glossary_term_test.go create mode 100644 website/docs/r/dataplex_glossary_category.html.markdown create mode 100644 website/docs/r/dataplex_glossary_term.html.markdown diff --git a/.changelog/13923.txt b/.changelog/13923.txt new file mode 100644 index 00000000000..5943b7b17a6 --- /dev/null +++ b/.changelog/13923.txt @@ -0,0 +1,7 @@ +```release-note:new-resource +`google_dataplex_glossary_category` +``` + +```release-note:new-resource +`google_dataplex_glossary_term` +``` \ No newline at end of file diff --git a/google-beta/provider/provider_mmv1_resources.go b/google-beta/provider/provider_mmv1_resources.go index 0293208eb22..f856060d0e4 100644 --- a/google-beta/provider/provider_mmv1_resources.go +++ b/google-beta/provider/provider_mmv1_resources.go @@ -567,9 +567,9 @@ var handwrittenIAMDatasources = map[string]*schema.Resource{ } // Resources -// Generated resources: 656 +// Generated resources: 658 // Generated IAM resources: 333 -// Total generated resources: 989 +// Total generated resources: 991 var generatedResources = map[string]*schema.Resource{ "google_folder_access_approval_settings": accessapproval.ResourceAccessApprovalFolderSettings(), "google_organization_access_approval_settings": accessapproval.ResourceAccessApprovalOrganizationSettings(), @@ -995,6 +995,8 @@ var generatedResources = map[string]*schema.Resource{ "google_dataplex_glossary_iam_binding": tpgiamresource.ResourceIamBinding(dataplex.DataplexGlossaryIamSchema, dataplex.DataplexGlossaryIamUpdaterProducer, dataplex.DataplexGlossaryIdParseFunc), "google_dataplex_glossary_iam_member": tpgiamresource.ResourceIamMember(dataplex.DataplexGlossaryIamSchema, dataplex.DataplexGlossaryIamUpdaterProducer, dataplex.DataplexGlossaryIdParseFunc), "google_dataplex_glossary_iam_policy": tpgiamresource.ResourceIamPolicy(dataplex.DataplexGlossaryIamSchema, dataplex.DataplexGlossaryIamUpdaterProducer, dataplex.DataplexGlossaryIdParseFunc), + "google_dataplex_glossary_category": dataplex.ResourceDataplexGlossaryCategory(), + "google_dataplex_glossary_term": dataplex.ResourceDataplexGlossaryTerm(), "google_dataplex_lake_iam_binding": tpgiamresource.ResourceIamBinding(dataplex.DataplexLakeIamSchema, dataplex.DataplexLakeIamUpdaterProducer, dataplex.DataplexLakeIdParseFunc), "google_dataplex_lake_iam_member": tpgiamresource.ResourceIamMember(dataplex.DataplexLakeIamSchema, dataplex.DataplexLakeIamUpdaterProducer, dataplex.DataplexLakeIdParseFunc), "google_dataplex_lake_iam_policy": tpgiamresource.ResourceIamPolicy(dataplex.DataplexLakeIamSchema, dataplex.DataplexLakeIamUpdaterProducer, dataplex.DataplexLakeIdParseFunc), diff --git a/google-beta/services/dataplex/resource_dataplex_glossary.go b/google-beta/services/dataplex/resource_dataplex_glossary.go index 6d1abb35dc1..72d6e386f10 100644 --- a/google-beta/services/dataplex/resource_dataplex_glossary.go +++ b/google-beta/services/dataplex/resource_dataplex_glossary.go @@ -46,9 +46,9 @@ func ResourceDataplexGlossary() *schema.Resource { }, Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(5 * time.Minute), - Update: schema.DefaultTimeout(5 * time.Minute), - Delete: schema.DefaultTimeout(5 * time.Minute), + Create: schema.DefaultTimeout(15 * time.Minute), + Update: schema.DefaultTimeout(15 * time.Minute), + Delete: schema.DefaultTimeout(15 * time.Minute), }, CustomizeDiff: customdiff.All( diff --git a/google-beta/services/dataplex/resource_dataplex_glossary_category.go b/google-beta/services/dataplex/resource_dataplex_glossary_category.go new file mode 100644 index 00000000000..378ab00bc29 --- /dev/null +++ b/google-beta/services/dataplex/resource_dataplex_glossary_category.go @@ -0,0 +1,554 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This code is generated by Magic Modules using the following: +// +// Configuration: https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/products/dataplex/GlossaryCategory.yaml +// Template: https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/templates/terraform/resource.go.tmpl +// +// DO NOT EDIT this file directly. Any changes made to this file will be +// overwritten during the next generation cycle. +// +// ---------------------------------------------------------------------------- + +package dataplex + +import ( + "fmt" + "log" + "net/http" + "reflect" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport" +) + +func ResourceDataplexGlossaryCategory() *schema.Resource { + return &schema.Resource{ + Create: resourceDataplexGlossaryCategoryCreate, + Read: resourceDataplexGlossaryCategoryRead, + Update: resourceDataplexGlossaryCategoryUpdate, + Delete: resourceDataplexGlossaryCategoryDelete, + + Importer: &schema.ResourceImporter{ + State: resourceDataplexGlossaryCategoryImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(15 * time.Minute), + Update: schema.DefaultTimeout(15 * time.Minute), + Delete: schema.DefaultTimeout(15 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + tpgresource.SetLabelsDiff, + tpgresource.DefaultProviderProject, + ), + + Schema: map[string]*schema.Schema{ + "location": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The location where the glossary category should reside.`, + }, + "parent": { + Type: schema.TypeString, + Required: true, + Description: `The immediate parent of the GlossaryCategory in the resource-hierarchy. It can either be a Glossary or a Category. Format: projects/{projectId}/locations/{locationId}/glossaries/{glossaryId} OR projects/{projectId}/locations/{locationId}/glossaries/{glossaryId}/categories/{categoryId}`, + }, + "category_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `The category id for creation.`, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: `The user-mutable description of the GlossaryCategory.`, + }, + "display_name": { + Type: schema.TypeString, + Optional: true, + Description: `User friendly display name of the GlossaryCategory. This is user-mutable. This will be same as the categoryId, if not specified.`, + }, + "glossary_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `The glossary id for creation.`, + }, + "labels": { + Type: schema.TypeMap, + Optional: true, + Description: `User-defined labels for the GlossaryCategory. + + +**Note**: This field is non-authoritative, and will only manage the labels present in your configuration. +Please refer to the field 'effective_labels' for all of the labels present on the resource.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + Description: `The time at which the GlossaryCategory was created.`, + }, + "effective_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The resource name of the GlossaryCategory. Format: projects/{projectId}/locations/{locationId}/glossaries/{glossaryId}/categories/{categoryId}`, + }, + "terraform_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `The combination of labels configured directly on the resource + and default labels configured on the provider.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "uid": { + Type: schema.TypeString, + Computed: true, + Description: `System generated unique id for the GlossaryCategory. This ID will be different if the GlossaryCategory is deleted and re-created with the same name.`, + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: `The time at which the GlossaryCategory was last updated.`, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + UseJSONNumber: true, + } +} + +func resourceDataplexGlossaryCategoryCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + displayNameProp, err := expandDataplexGlossaryCategoryDisplayName(d.Get("display_name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("display_name"); !tpgresource.IsEmptyValue(reflect.ValueOf(displayNameProp)) && (ok || !reflect.DeepEqual(v, displayNameProp)) { + obj["displayName"] = displayNameProp + } + descriptionProp, err := expandDataplexGlossaryCategoryDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !tpgresource.IsEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + parentProp, err := expandDataplexGlossaryCategoryParent(d.Get("parent"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("parent"); !tpgresource.IsEmptyValue(reflect.ValueOf(parentProp)) && (ok || !reflect.DeepEqual(v, parentProp)) { + obj["parent"] = parentProp + } + labelsProp, err := expandDataplexGlossaryCategoryEffectiveLabels(d.Get("effective_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("effective_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{DataplexBasePath}}projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/categories?category_id={{category_id}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new GlossaryCategory: %#v", obj) + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for GlossaryCategory: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutCreate), + Headers: headers, + }) + if err != nil { + return fmt.Errorf("Error creating GlossaryCategory: %s", err) + } + + // Store the ID now + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/categories/{{category_id}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating GlossaryCategory %q: %#v", d.Id(), res) + + return resourceDataplexGlossaryCategoryRead(d, meta) +} + +func resourceDataplexGlossaryCategoryRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + url, err := tpgresource.ReplaceVars(d, config, "{{DataplexBasePath}}projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/categories/{{category_id}}") + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for GlossaryCategory: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Headers: headers, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("DataplexGlossaryCategory %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading GlossaryCategory: %s", err) + } + + if err := d.Set("name", flattenDataplexGlossaryCategoryName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryCategory: %s", err) + } + if err := d.Set("display_name", flattenDataplexGlossaryCategoryDisplayName(res["displayName"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryCategory: %s", err) + } + if err := d.Set("description", flattenDataplexGlossaryCategoryDescription(res["description"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryCategory: %s", err) + } + if err := d.Set("labels", flattenDataplexGlossaryCategoryLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryCategory: %s", err) + } + if err := d.Set("uid", flattenDataplexGlossaryCategoryUid(res["uid"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryCategory: %s", err) + } + if err := d.Set("create_time", flattenDataplexGlossaryCategoryCreateTime(res["createTime"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryCategory: %s", err) + } + if err := d.Set("update_time", flattenDataplexGlossaryCategoryUpdateTime(res["updateTime"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryCategory: %s", err) + } + if err := d.Set("parent", flattenDataplexGlossaryCategoryParent(res["parent"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryCategory: %s", err) + } + if err := d.Set("terraform_labels", flattenDataplexGlossaryCategoryTerraformLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryCategory: %s", err) + } + if err := d.Set("effective_labels", flattenDataplexGlossaryCategoryEffectiveLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryCategory: %s", err) + } + + return nil +} + +func resourceDataplexGlossaryCategoryUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for GlossaryCategory: %s", err) + } + billingProject = project + + obj := make(map[string]interface{}) + displayNameProp, err := expandDataplexGlossaryCategoryDisplayName(d.Get("display_name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("display_name"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, displayNameProp)) { + obj["displayName"] = displayNameProp + } + descriptionProp, err := expandDataplexGlossaryCategoryDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + parentProp, err := expandDataplexGlossaryCategoryParent(d.Get("parent"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("parent"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, parentProp)) { + obj["parent"] = parentProp + } + labelsProp, err := expandDataplexGlossaryCategoryEffectiveLabels(d.Get("effective_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("effective_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{DataplexBasePath}}projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/categories/{{category_id}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating GlossaryCategory %q: %#v", d.Id(), obj) + headers := make(http.Header) + updateMask := []string{} + + if d.HasChange("display_name") { + updateMask = append(updateMask, "displayName") + } + + if d.HasChange("description") { + updateMask = append(updateMask, "description") + } + + if d.HasChange("parent") { + updateMask = append(updateMask, "parent") + } + + if d.HasChange("effective_labels") { + updateMask = append(updateMask, "labels") + } + // updateMask is a URL parameter but not present in the schema, so ReplaceVars + // won't set it + url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) + if err != nil { + return err + } + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + // if updateMask is empty we are not updating anything so skip the post + if len(updateMask) > 0 { + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "PATCH", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutUpdate), + Headers: headers, + }) + + if err != nil { + return fmt.Errorf("Error updating GlossaryCategory %q: %s", d.Id(), err) + } else { + log.Printf("[DEBUG] Finished updating GlossaryCategory %q: %#v", d.Id(), res) + } + + } + + return resourceDataplexGlossaryCategoryRead(d, meta) +} + +func resourceDataplexGlossaryCategoryDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for GlossaryCategory: %s", err) + } + billingProject = project + + url, err := tpgresource.ReplaceVars(d, config, "{{DataplexBasePath}}projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/categories/{{category_id}}") + if err != nil { + return err + } + + var obj map[string]interface{} + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + + log.Printf("[DEBUG] Deleting GlossaryCategory %q", d.Id()) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutDelete), + Headers: headers, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, "GlossaryCategory") + } + + log.Printf("[DEBUG] Finished deleting GlossaryCategory %q: %#v", d.Id(), res) + return nil +} + +func resourceDataplexGlossaryCategoryImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*transport_tpg.Config) + if err := tpgresource.ParseImportId([]string{ + "^projects/(?P[^/]+)/locations/(?P[^/]+)/glossaries/(?P[^/]+)/categories/(?P[^/]+)$", + "^(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)$", + "^(?P[^/]+)/(?P[^/]+)/(?P[^/]+)$", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/categories/{{category_id}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenDataplexGlossaryCategoryName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataplexGlossaryCategoryDisplayName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataplexGlossaryCategoryDescription(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataplexGlossaryCategoryLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed +} + +func flattenDataplexGlossaryCategoryUid(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataplexGlossaryCategoryCreateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataplexGlossaryCategoryUpdateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataplexGlossaryCategoryParent(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataplexGlossaryCategoryTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("terraform_labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed +} + +func flattenDataplexGlossaryCategoryEffectiveLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func expandDataplexGlossaryCategoryDisplayName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDataplexGlossaryCategoryDescription(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDataplexGlossaryCategoryParent(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDataplexGlossaryCategoryEffectiveLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { + if v == nil { + return map[string]string{}, nil + } + m := make(map[string]string) + for k, val := range v.(map[string]interface{}) { + m[k] = val.(string) + } + return m, nil +} diff --git a/google-beta/services/dataplex/resource_dataplex_glossary_category_generated_meta.yaml b/google-beta/services/dataplex/resource_dataplex_glossary_category_generated_meta.yaml new file mode 100644 index 00000000000..6313d860368 --- /dev/null +++ b/google-beta/services/dataplex/resource_dataplex_glossary_category_generated_meta.yaml @@ -0,0 +1,25 @@ +resource: 'google_dataplex_glossary_category' +generation_type: 'mmv1' +source_file: 'products/dataplex/GlossaryCategory.yaml' +api_service_name: 'dataplex.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'GlossaryCategory' +fields: + - field: 'category_id' + provider_only: true + - field: 'create_time' + - field: 'description' + - field: 'display_name' + - field: 'effective_labels' + provider_only: true + - field: 'glossary_id' + provider_only: true + - field: 'labels' + - field: 'location' + provider_only: true + - field: 'name' + - field: 'parent' + - field: 'terraform_labels' + provider_only: true + - field: 'uid' + - field: 'update_time' diff --git a/google-beta/services/dataplex/resource_dataplex_glossary_category_generated_test.go b/google-beta/services/dataplex/resource_dataplex_glossary_category_generated_test.go new file mode 100644 index 00000000000..ac94f9acfb8 --- /dev/null +++ b/google-beta/services/dataplex/resource_dataplex_glossary_category_generated_test.go @@ -0,0 +1,156 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// 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 dataplex_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + + "github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport" +) + +func TestAccDataplexGlossaryCategory_dataplexGlossaryCategoryBasicExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckDataplexGlossaryCategoryDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccDataplexGlossaryCategory_dataplexGlossaryCategoryBasicExample(context), + }, + { + ResourceName: "google_dataplex_glossary_category.category_test_id", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"category_id", "glossary_id", "labels", "location", "terraform_labels"}, + }, + }, + }) +} + +func testAccDataplexGlossaryCategory_dataplexGlossaryCategoryBasicExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_dataplex_glossary" "category_test_id" { + glossary_id = "tf-test-glossary%{random_suffix}" + location = "us-central1" +} + +resource "google_dataplex_glossary_category" "category_test_id" { + parent = "projects/${google_dataplex_glossary.category_test_id.project}/locations/us-central1/glossaries/${google_dataplex_glossary.category_test_id.glossary_id}" + glossary_id = google_dataplex_glossary.category_test_id.glossary_id + location = "us-central1" + category_id = "tf-test-category-basic%{random_suffix}" +} +`, context) +} + +func TestAccDataplexGlossaryCategory_dataplexGlossaryCategoryFullExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckDataplexGlossaryCategoryDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccDataplexGlossaryCategory_dataplexGlossaryCategoryFullExample(context), + }, + { + ResourceName: "google_dataplex_glossary_category.category_test_id_full", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"category_id", "glossary_id", "labels", "location", "terraform_labels"}, + }, + }, + }) +} + +func testAccDataplexGlossaryCategory_dataplexGlossaryCategoryFullExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_dataplex_glossary" "category_test_id_full" { + glossary_id = "tf-test-glossary%{random_suffix}" + location = "us-central1" +} + +resource "google_dataplex_glossary_category" "category_test_id_full" { + parent = "projects/${google_dataplex_glossary.category_test_id_full.project}/locations/us-central1/glossaries/${google_dataplex_glossary.category_test_id_full.glossary_id}" + glossary_id = google_dataplex_glossary.category_test_id_full.glossary_id + location = "us-central1" + category_id = "tf-test-category-full%{random_suffix}" + + labels = { "tag": "test-tf" } + display_name = "terraform category" + description = "category created by Terraform" +} +`, context) +} + +func testAccCheckDataplexGlossaryCategoryDestroyProducer(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_dataplex_glossary_category" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := acctest.GoogleProviderConfig(t) + + url, err := tpgresource.ReplaceVarsForTest(config, rs, "{{DataplexBasePath}}projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/categories/{{category_id}}") + if err != nil { + return err + } + + billingProject := "" + + if config.BillingProject != "" { + billingProject = config.BillingProject + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: config.UserAgent, + }) + if err == nil { + return fmt.Errorf("DataplexGlossaryCategory still exists at %s", url) + } + } + + return nil + } +} diff --git a/google-beta/services/dataplex/resource_dataplex_glossary_category_test.go b/google-beta/services/dataplex/resource_dataplex_glossary_category_test.go new file mode 100644 index 00000000000..66e364809a1 --- /dev/null +++ b/google-beta/services/dataplex/resource_dataplex_glossary_category_test.go @@ -0,0 +1,85 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package dataplex_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest" +) + +func TestAccDataplexGlossaryCategory_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccDataplexGlossaryCategory_dataplexGlossaryCategoryFull(context), + }, + { + ResourceName: "google_dataplex_glossary_category.category_test_id_full", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"category_id", "glossary_id", "labels", "location", "terraform_labels"}, + }, + { + Config: testAccDataplexGlossaryCategory_update(context), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_dataplex_glossary_category.category_test_id_full", plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: "google_dataplex_glossary_category.category_test_id_full", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"category_id", "glossary_id", "labels", "location", "terraform_labels"}, + }, + }, + }) +} + +func testAccDataplexGlossaryCategory_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_dataplex_glossary" "category_test_id_full" { + glossary_id = "tf-test-glossary%{random_suffix}" + location = "us-central1" +} +resource "google_dataplex_glossary_category" "category_test_id_full" { + parent = "projects/${google_dataplex_glossary.category_test_id_full.project}/locations/us-central1/glossaries/${google_dataplex_glossary.category_test_id_full.glossary_id}" + glossary_id = google_dataplex_glossary.category_test_id_full.glossary_id + location = "us-central1" + category_id = "tf-test-category-full%{random_suffix}" + display_name = "terraform category updated" + description = "category updated by Terraform" +} +`, context) +} + +func testAccDataplexGlossaryCategory_dataplexGlossaryCategoryFull(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_dataplex_glossary" "category_test_id_full" { + glossary_id = "tf-test-glossary%{random_suffix}" + location = "us-central1" +} +resource "google_dataplex_glossary_category" "category_test_id_full" { + parent = "projects/${google_dataplex_glossary.category_test_id_full.project}/locations/us-central1/glossaries/${google_dataplex_glossary.category_test_id_full.glossary_id}" + glossary_id = google_dataplex_glossary.category_test_id_full.glossary_id + location = "us-central1" + category_id = "tf-test-category-full%{random_suffix}" + labels = { "tag": "test-tf" } + display_name = "terraform category" + description = "category created by Terraform" +} +`, context) +} diff --git a/google-beta/services/dataplex/resource_dataplex_glossary_term.go b/google-beta/services/dataplex/resource_dataplex_glossary_term.go new file mode 100644 index 00000000000..4ac77c29709 --- /dev/null +++ b/google-beta/services/dataplex/resource_dataplex_glossary_term.go @@ -0,0 +1,554 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This code is generated by Magic Modules using the following: +// +// Configuration: https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/products/dataplex/GlossaryTerm.yaml +// Template: https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/templates/terraform/resource.go.tmpl +// +// DO NOT EDIT this file directly. Any changes made to this file will be +// overwritten during the next generation cycle. +// +// ---------------------------------------------------------------------------- + +package dataplex + +import ( + "fmt" + "log" + "net/http" + "reflect" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport" +) + +func ResourceDataplexGlossaryTerm() *schema.Resource { + return &schema.Resource{ + Create: resourceDataplexGlossaryTermCreate, + Read: resourceDataplexGlossaryTermRead, + Update: resourceDataplexGlossaryTermUpdate, + Delete: resourceDataplexGlossaryTermDelete, + + Importer: &schema.ResourceImporter{ + State: resourceDataplexGlossaryTermImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(15 * time.Minute), + Update: schema.DefaultTimeout(15 * time.Minute), + Delete: schema.DefaultTimeout(15 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + tpgresource.SetLabelsDiff, + tpgresource.DefaultProviderProject, + ), + + Schema: map[string]*schema.Schema{ + "location": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The location where the glossary term should reside.`, + }, + "parent": { + Type: schema.TypeString, + Required: true, + Description: `The immediate parent of the GlossaryTerm in the resource-hierarchy. It can either be a Glossary or a Term. Format: projects/{projectId}/locations/{locationId}/glossaries/{glossaryId} OR projects/{projectId}/locations/{locationId}/glossaries/{glossaryId}/terms/{termId}`, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: `The user-mutable description of the GlossaryTerm.`, + }, + "display_name": { + Type: schema.TypeString, + Optional: true, + Description: `User friendly display name of the GlossaryTerm. This is user-mutable. This will be same as the termId, if not specified.`, + }, + "glossary_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `The glossary id for creation.`, + }, + "labels": { + Type: schema.TypeMap, + Optional: true, + Description: `User-defined labels for the GlossaryTerm. + + +**Note**: This field is non-authoritative, and will only manage the labels present in your configuration. +Please refer to the field 'effective_labels' for all of the labels present on the resource.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "term_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `The term id for creation.`, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + Description: `The time at which the GlossaryTerm was created.`, + }, + "effective_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The resource name of the GlossaryTerm. Format: projects/{projectId}/locations/{locationId}/glossaries/{glossaryId}/categories/{termId}`, + }, + "terraform_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `The combination of labels configured directly on the resource + and default labels configured on the provider.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "uid": { + Type: schema.TypeString, + Computed: true, + Description: `System generated unique id for the GlossaryTerm. This ID will be different if the GlossaryTerm is deleted and re-created with the same name.`, + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: `The time at which the GlossaryTerm was last updated.`, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + UseJSONNumber: true, + } +} + +func resourceDataplexGlossaryTermCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + displayNameProp, err := expandDataplexGlossaryTermDisplayName(d.Get("display_name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("display_name"); !tpgresource.IsEmptyValue(reflect.ValueOf(displayNameProp)) && (ok || !reflect.DeepEqual(v, displayNameProp)) { + obj["displayName"] = displayNameProp + } + descriptionProp, err := expandDataplexGlossaryTermDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !tpgresource.IsEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + parentProp, err := expandDataplexGlossaryTermParent(d.Get("parent"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("parent"); !tpgresource.IsEmptyValue(reflect.ValueOf(parentProp)) && (ok || !reflect.DeepEqual(v, parentProp)) { + obj["parent"] = parentProp + } + labelsProp, err := expandDataplexGlossaryTermEffectiveLabels(d.Get("effective_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("effective_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{DataplexBasePath}}projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/terms?term_id={{term_id}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new GlossaryTerm: %#v", obj) + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for GlossaryTerm: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutCreate), + Headers: headers, + }) + if err != nil { + return fmt.Errorf("Error creating GlossaryTerm: %s", err) + } + + // Store the ID now + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/terms/{{term_id}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating GlossaryTerm %q: %#v", d.Id(), res) + + return resourceDataplexGlossaryTermRead(d, meta) +} + +func resourceDataplexGlossaryTermRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + url, err := tpgresource.ReplaceVars(d, config, "{{DataplexBasePath}}projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/terms/{{term_id}}") + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for GlossaryTerm: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Headers: headers, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("DataplexGlossaryTerm %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading GlossaryTerm: %s", err) + } + + if err := d.Set("name", flattenDataplexGlossaryTermName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryTerm: %s", err) + } + if err := d.Set("display_name", flattenDataplexGlossaryTermDisplayName(res["displayName"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryTerm: %s", err) + } + if err := d.Set("description", flattenDataplexGlossaryTermDescription(res["description"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryTerm: %s", err) + } + if err := d.Set("labels", flattenDataplexGlossaryTermLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryTerm: %s", err) + } + if err := d.Set("uid", flattenDataplexGlossaryTermUid(res["uid"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryTerm: %s", err) + } + if err := d.Set("create_time", flattenDataplexGlossaryTermCreateTime(res["createTime"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryTerm: %s", err) + } + if err := d.Set("update_time", flattenDataplexGlossaryTermUpdateTime(res["updateTime"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryTerm: %s", err) + } + if err := d.Set("parent", flattenDataplexGlossaryTermParent(res["parent"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryTerm: %s", err) + } + if err := d.Set("terraform_labels", flattenDataplexGlossaryTermTerraformLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryTerm: %s", err) + } + if err := d.Set("effective_labels", flattenDataplexGlossaryTermEffectiveLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading GlossaryTerm: %s", err) + } + + return nil +} + +func resourceDataplexGlossaryTermUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for GlossaryTerm: %s", err) + } + billingProject = project + + obj := make(map[string]interface{}) + displayNameProp, err := expandDataplexGlossaryTermDisplayName(d.Get("display_name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("display_name"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, displayNameProp)) { + obj["displayName"] = displayNameProp + } + descriptionProp, err := expandDataplexGlossaryTermDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + parentProp, err := expandDataplexGlossaryTermParent(d.Get("parent"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("parent"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, parentProp)) { + obj["parent"] = parentProp + } + labelsProp, err := expandDataplexGlossaryTermEffectiveLabels(d.Get("effective_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("effective_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{DataplexBasePath}}projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/terms/{{term_id}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating GlossaryTerm %q: %#v", d.Id(), obj) + headers := make(http.Header) + updateMask := []string{} + + if d.HasChange("display_name") { + updateMask = append(updateMask, "displayName") + } + + if d.HasChange("description") { + updateMask = append(updateMask, "description") + } + + if d.HasChange("parent") { + updateMask = append(updateMask, "parent") + } + + if d.HasChange("effective_labels") { + updateMask = append(updateMask, "labels") + } + // updateMask is a URL parameter but not present in the schema, so ReplaceVars + // won't set it + url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) + if err != nil { + return err + } + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + // if updateMask is empty we are not updating anything so skip the post + if len(updateMask) > 0 { + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "PATCH", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutUpdate), + Headers: headers, + }) + + if err != nil { + return fmt.Errorf("Error updating GlossaryTerm %q: %s", d.Id(), err) + } else { + log.Printf("[DEBUG] Finished updating GlossaryTerm %q: %#v", d.Id(), res) + } + + } + + return resourceDataplexGlossaryTermRead(d, meta) +} + +func resourceDataplexGlossaryTermDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for GlossaryTerm: %s", err) + } + billingProject = project + + url, err := tpgresource.ReplaceVars(d, config, "{{DataplexBasePath}}projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/terms/{{term_id}}") + if err != nil { + return err + } + + var obj map[string]interface{} + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + + log.Printf("[DEBUG] Deleting GlossaryTerm %q", d.Id()) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutDelete), + Headers: headers, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, "GlossaryTerm") + } + + log.Printf("[DEBUG] Finished deleting GlossaryTerm %q: %#v", d.Id(), res) + return nil +} + +func resourceDataplexGlossaryTermImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*transport_tpg.Config) + if err := tpgresource.ParseImportId([]string{ + "^projects/(?P[^/]+)/locations/(?P[^/]+)/glossaries/(?P[^/]+)/terms/(?P[^/]+)$", + "^(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)$", + "^(?P[^/]+)/(?P[^/]+)/(?P[^/]+)$", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/terms/{{term_id}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenDataplexGlossaryTermName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataplexGlossaryTermDisplayName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataplexGlossaryTermDescription(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataplexGlossaryTermLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed +} + +func flattenDataplexGlossaryTermUid(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataplexGlossaryTermCreateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataplexGlossaryTermUpdateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataplexGlossaryTermParent(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataplexGlossaryTermTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("terraform_labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed +} + +func flattenDataplexGlossaryTermEffectiveLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func expandDataplexGlossaryTermDisplayName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDataplexGlossaryTermDescription(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDataplexGlossaryTermParent(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandDataplexGlossaryTermEffectiveLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { + if v == nil { + return map[string]string{}, nil + } + m := make(map[string]string) + for k, val := range v.(map[string]interface{}) { + m[k] = val.(string) + } + return m, nil +} diff --git a/google-beta/services/dataplex/resource_dataplex_glossary_term_generated_meta.yaml b/google-beta/services/dataplex/resource_dataplex_glossary_term_generated_meta.yaml new file mode 100644 index 00000000000..9be6afdc7f5 --- /dev/null +++ b/google-beta/services/dataplex/resource_dataplex_glossary_term_generated_meta.yaml @@ -0,0 +1,25 @@ +resource: 'google_dataplex_glossary_term' +generation_type: 'mmv1' +source_file: 'products/dataplex/GlossaryTerm.yaml' +api_service_name: 'dataplex.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'GlossaryTerm' +fields: + - field: 'create_time' + - field: 'description' + - field: 'display_name' + - field: 'effective_labels' + provider_only: true + - field: 'glossary_id' + provider_only: true + - field: 'labels' + - field: 'location' + provider_only: true + - field: 'name' + - field: 'parent' + - field: 'term_id' + provider_only: true + - field: 'terraform_labels' + provider_only: true + - field: 'uid' + - field: 'update_time' diff --git a/google-beta/services/dataplex/resource_dataplex_glossary_term_generated_test.go b/google-beta/services/dataplex/resource_dataplex_glossary_term_generated_test.go new file mode 100644 index 00000000000..b03002fc96f --- /dev/null +++ b/google-beta/services/dataplex/resource_dataplex_glossary_term_generated_test.go @@ -0,0 +1,156 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// 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 dataplex_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + + "github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport" +) + +func TestAccDataplexGlossaryTerm_dataplexGlossaryTermBasicExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckDataplexGlossaryTermDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccDataplexGlossaryTerm_dataplexGlossaryTermBasicExample(context), + }, + { + ResourceName: "google_dataplex_glossary_term.term_test_id", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"glossary_id", "labels", "location", "term_id", "terraform_labels"}, + }, + }, + }) +} + +func testAccDataplexGlossaryTerm_dataplexGlossaryTermBasicExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_dataplex_glossary" "term_test_id" { + glossary_id = "tf-test-glossary%{random_suffix}" + location = "us-central1" +} + +resource "google_dataplex_glossary_term" "term_test_id" { + parent = "projects/${google_dataplex_glossary.term_test_id.project}/locations/us-central1/glossaries/${google_dataplex_glossary.term_test_id.glossary_id}" + glossary_id = google_dataplex_glossary.term_test_id.glossary_id + location = "us-central1" + term_id = "tf-test-term-basic%{random_suffix}" +} +`, context) +} + +func TestAccDataplexGlossaryTerm_dataplexGlossaryTermFullExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckDataplexGlossaryTermDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccDataplexGlossaryTerm_dataplexGlossaryTermFullExample(context), + }, + { + ResourceName: "google_dataplex_glossary_term.term_test_id_full", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"glossary_id", "labels", "location", "term_id", "terraform_labels"}, + }, + }, + }) +} + +func testAccDataplexGlossaryTerm_dataplexGlossaryTermFullExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_dataplex_glossary" "term_test_id_full" { + glossary_id = "tf-test-glossary%{random_suffix}" + location = "us-central1" +} + +resource "google_dataplex_glossary_term" "term_test_id_full" { + parent = "projects/${google_dataplex_glossary.term_test_id_full.project}/locations/us-central1/glossaries/${google_dataplex_glossary.term_test_id_full.glossary_id}" + glossary_id = google_dataplex_glossary.term_test_id_full.glossary_id + location = "us-central1" + term_id = "tf-test-term-full%{random_suffix}" + + labels = { "tag": "test-tf" } + display_name = "terraform term" + description = "term created by Terraform" +} +`, context) +} + +func testAccCheckDataplexGlossaryTermDestroyProducer(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_dataplex_glossary_term" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := acctest.GoogleProviderConfig(t) + + url, err := tpgresource.ReplaceVarsForTest(config, rs, "{{DataplexBasePath}}projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/terms/{{term_id}}") + if err != nil { + return err + } + + billingProject := "" + + if config.BillingProject != "" { + billingProject = config.BillingProject + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: config.UserAgent, + }) + if err == nil { + return fmt.Errorf("DataplexGlossaryTerm still exists at %s", url) + } + } + + return nil + } +} diff --git a/google-beta/services/dataplex/resource_dataplex_glossary_term_test.go b/google-beta/services/dataplex/resource_dataplex_glossary_term_test.go new file mode 100644 index 00000000000..3b6882a2c52 --- /dev/null +++ b/google-beta/services/dataplex/resource_dataplex_glossary_term_test.go @@ -0,0 +1,85 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package dataplex_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest" +) + +func TestAccDataplexGlossaryTerm_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccDataplexGlossaryTerm_dataplexGlossaryTermFull(context), + }, + { + ResourceName: "google_dataplex_glossary_term.term_test_id_full", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"glossary_id", "labels", "location", "term_id", "terraform_labels"}, + }, + { + Config: testAccDataplexGlossaryTerm_update(context), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_dataplex_glossary_term.term_test_id_full", plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: "google_dataplex_glossary_term.term_test_id_full", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"glossary_id", "labels", "location", "term_id", "terraform_labels"}, + }, + }, + }) +} + +func testAccDataplexGlossaryTerm_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_dataplex_glossary" "term_test_id_full" { + glossary_id = "tf-test-glossary%{random_suffix}" + location = "us-central1" +} +resource "google_dataplex_glossary_term" "term_test_id_full" { + parent = "projects/${google_dataplex_glossary.term_test_id_full.project}/locations/us-central1/glossaries/${google_dataplex_glossary.term_test_id_full.glossary_id}" + glossary_id = google_dataplex_glossary.term_test_id_full.glossary_id + location = "us-central1" + term_id = "tf-test-term-full%{random_suffix}" + display_name = "terraform term updated" + description = "term created by Terraform updated" +} +`, context) +} + +func testAccDataplexGlossaryTerm_dataplexGlossaryTermFull(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_dataplex_glossary" "term_test_id_full" { + glossary_id = "tf-test-glossary%{random_suffix}" + location = "us-central1" +} +resource "google_dataplex_glossary_term" "term_test_id_full" { + parent = "projects/${google_dataplex_glossary.term_test_id_full.project}/locations/us-central1/glossaries/${google_dataplex_glossary.term_test_id_full.glossary_id}" + glossary_id = google_dataplex_glossary.term_test_id_full.glossary_id + location = "us-central1" + term_id = "tf-test-term-full%{random_suffix}" + labels = { "tag": "test-tf" } + display_name = "terraform term" + description = "term created by Terraform" +} +`, context) +} diff --git a/website/docs/r/dataplex_glossary.html.markdown b/website/docs/r/dataplex_glossary.html.markdown index d8aa8c61649..5ed21367b08 100644 --- a/website/docs/r/dataplex_glossary.html.markdown +++ b/website/docs/r/dataplex_glossary.html.markdown @@ -131,9 +131,9 @@ In addition to the arguments listed above, the following computed attributes are This resource provides the following [Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: -- `create` - Default is 5 minutes. -- `update` - Default is 5 minutes. -- `delete` - Default is 5 minutes. +- `create` - Default is 15 minutes. +- `update` - Default is 15 minutes. +- `delete` - Default is 15 minutes. ## Import diff --git a/website/docs/r/dataplex_glossary_category.html.markdown b/website/docs/r/dataplex_glossary_category.html.markdown new file mode 100644 index 00000000000..682801d0599 --- /dev/null +++ b/website/docs/r/dataplex_glossary_category.html.markdown @@ -0,0 +1,183 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# This code is generated by Magic Modules using the following: +# +# Configuration: https:#github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/products/dataplex/GlossaryCategory.yaml +# Template: https:#github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/templates/terraform/resource.html.markdown.tmpl +# +# DO NOT EDIT this file directly. Any changes made to this file will be +# overwritten during the next generation cycle. +# +# ---------------------------------------------------------------------------- +subcategory: "Dataplex" +description: |- + Represents a collection of categories and terms within a Glossary that are related to each other. +--- + +# google_dataplex_glossary_category + +Represents a collection of categories and terms within a Glossary that are related to each other. + + + + +## Example Usage - Dataplex Glossary Category Basic + + +```hcl +resource "google_dataplex_glossary" "category_test_id" { + glossary_id = "tf-test-glossary%{random_suffix}" + location = "us-central1" +} + +resource "google_dataplex_glossary_category" "category_test_id" { + parent = "projects/${google_dataplex_glossary.category_test_id.project}/locations/us-central1/glossaries/${google_dataplex_glossary.category_test_id.glossary_id}" + glossary_id = google_dataplex_glossary.category_test_id.glossary_id + location = "us-central1" + category_id = "tf-test-category-basic%{random_suffix}" +} +``` + +## Example Usage - Dataplex Glossary Category Full + + +```hcl +resource "google_dataplex_glossary" "category_test_id_full" { + glossary_id = "tf-test-glossary%{random_suffix}" + location = "us-central1" +} + +resource "google_dataplex_glossary_category" "category_test_id_full" { + parent = "projects/${google_dataplex_glossary.category_test_id_full.project}/locations/us-central1/glossaries/${google_dataplex_glossary.category_test_id_full.glossary_id}" + glossary_id = google_dataplex_glossary.category_test_id_full.glossary_id + location = "us-central1" + category_id = "tf-test-category-full%{random_suffix}" + + labels = { "tag": "test-tf" } + display_name = "terraform category" + description = "category created by Terraform" +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `parent` - + (Required) + The immediate parent of the GlossaryCategory in the resource-hierarchy. It can either be a Glossary or a Category. Format: projects/{projectId}/locations/{locationId}/glossaries/{glossaryId} OR projects/{projectId}/locations/{locationId}/glossaries/{glossaryId}/categories/{categoryId} + +* `location` - + (Required) + The location where the glossary category should reside. + + +- - - + + +* `display_name` - + (Optional) + User friendly display name of the GlossaryCategory. This is user-mutable. This will be same as the categoryId, if not specified. + +* `description` - + (Optional) + The user-mutable description of the GlossaryCategory. + +* `labels` - + (Optional) + User-defined labels for the GlossaryCategory. + + **Note**: This field is non-authoritative, and will only manage the labels present in your configuration. + Please refer to the field `effective_labels` for all of the labels present on the resource. + +* `glossary_id` - + (Optional) + The glossary id for creation. + +* `category_id` - + (Optional) + The category id for creation. + +* `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 `projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/categories/{{category_id}}` + +* `name` - + The resource name of the GlossaryCategory. Format: projects/{projectId}/locations/{locationId}/glossaries/{glossaryId}/categories/{categoryId} + +* `uid` - + System generated unique id for the GlossaryCategory. This ID will be different if the GlossaryCategory is deleted and re-created with the same name. + +* `create_time` - + The time at which the GlossaryCategory was created. + +* `update_time` - + The time at which the GlossaryCategory was last updated. + +* `terraform_labels` - + The combination of labels configured directly on the resource + and default labels configured on the provider. + +* `effective_labels` - + All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services. + + +## Timeouts + +This resource provides the following +[Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: + +- `create` - Default is 15 minutes. +- `update` - Default is 15 minutes. +- `delete` - Default is 15 minutes. + +## Import + + +GlossaryCategory can be imported using any of these accepted formats: + +* `projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/categories/{{category_id}}` +* `{{project}}/{{location}}/{{glossary_id}}/{{category_id}}` +* `{{location}}/{{glossary_id}}/{{category_id}}` + + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import GlossaryCategory using one of the formats above. For example: + +```tf +import { + id = "projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/categories/{{category_id}}" + to = google_dataplex_glossary_category.default +} +``` + +When using the [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import), GlossaryCategory can be imported using one of the formats above. For example: + +``` +$ terraform import google_dataplex_glossary_category.default projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/categories/{{category_id}} +$ terraform import google_dataplex_glossary_category.default {{project}}/{{location}}/{{glossary_id}}/{{category_id}} +$ terraform import google_dataplex_glossary_category.default {{location}}/{{glossary_id}}/{{category_id}} +``` + +## User Project Overrides + +This resource supports [User Project Overrides](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#user_project_override). diff --git a/website/docs/r/dataplex_glossary_term.html.markdown b/website/docs/r/dataplex_glossary_term.html.markdown new file mode 100644 index 00000000000..d98ea62bad1 --- /dev/null +++ b/website/docs/r/dataplex_glossary_term.html.markdown @@ -0,0 +1,183 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# This code is generated by Magic Modules using the following: +# +# Configuration: https:#github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/products/dataplex/GlossaryTerm.yaml +# Template: https:#github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/templates/terraform/resource.html.markdown.tmpl +# +# DO NOT EDIT this file directly. Any changes made to this file will be +# overwritten during the next generation cycle. +# +# ---------------------------------------------------------------------------- +subcategory: "Dataplex" +description: |- + Represents a collection of terms within a Glossary that are related to each other. +--- + +# google_dataplex_glossary_term + +Represents a collection of terms within a Glossary that are related to each other. + + + + +## Example Usage - Dataplex Glossary Term Basic + + +```hcl +resource "google_dataplex_glossary" "term_test_id" { + glossary_id = "tf-test-glossary%{random_suffix}" + location = "us-central1" +} + +resource "google_dataplex_glossary_term" "term_test_id" { + parent = "projects/${google_dataplex_glossary.term_test_id.project}/locations/us-central1/glossaries/${google_dataplex_glossary.term_test_id.glossary_id}" + glossary_id = google_dataplex_glossary.term_test_id.glossary_id + location = "us-central1" + term_id = "tf-test-term-basic%{random_suffix}" +} +``` + +## Example Usage - Dataplex Glossary Term Full + + +```hcl +resource "google_dataplex_glossary" "term_test_id_full" { + glossary_id = "tf-test-glossary%{random_suffix}" + location = "us-central1" +} + +resource "google_dataplex_glossary_term" "term_test_id_full" { + parent = "projects/${google_dataplex_glossary.term_test_id_full.project}/locations/us-central1/glossaries/${google_dataplex_glossary.term_test_id_full.glossary_id}" + glossary_id = google_dataplex_glossary.term_test_id_full.glossary_id + location = "us-central1" + term_id = "tf-test-term-full%{random_suffix}" + + labels = { "tag": "test-tf" } + display_name = "terraform term" + description = "term created by Terraform" +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `parent` - + (Required) + The immediate parent of the GlossaryTerm in the resource-hierarchy. It can either be a Glossary or a Term. Format: projects/{projectId}/locations/{locationId}/glossaries/{glossaryId} OR projects/{projectId}/locations/{locationId}/glossaries/{glossaryId}/terms/{termId} + +* `location` - + (Required) + The location where the glossary term should reside. + + +- - - + + +* `display_name` - + (Optional) + User friendly display name of the GlossaryTerm. This is user-mutable. This will be same as the termId, if not specified. + +* `description` - + (Optional) + The user-mutable description of the GlossaryTerm. + +* `labels` - + (Optional) + User-defined labels for the GlossaryTerm. + + **Note**: This field is non-authoritative, and will only manage the labels present in your configuration. + Please refer to the field `effective_labels` for all of the labels present on the resource. + +* `glossary_id` - + (Optional) + The glossary id for creation. + +* `term_id` - + (Optional) + The term id for creation. + +* `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 `projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/terms/{{term_id}}` + +* `name` - + The resource name of the GlossaryTerm. Format: projects/{projectId}/locations/{locationId}/glossaries/{glossaryId}/categories/{termId} + +* `uid` - + System generated unique id for the GlossaryTerm. This ID will be different if the GlossaryTerm is deleted and re-created with the same name. + +* `create_time` - + The time at which the GlossaryTerm was created. + +* `update_time` - + The time at which the GlossaryTerm was last updated. + +* `terraform_labels` - + The combination of labels configured directly on the resource + and default labels configured on the provider. + +* `effective_labels` - + All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services. + + +## Timeouts + +This resource provides the following +[Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: + +- `create` - Default is 15 minutes. +- `update` - Default is 15 minutes. +- `delete` - Default is 15 minutes. + +## Import + + +GlossaryTerm can be imported using any of these accepted formats: + +* `projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/terms/{{term_id}}` +* `{{project}}/{{location}}/{{glossary_id}}/{{term_id}}` +* `{{location}}/{{glossary_id}}/{{term_id}}` + + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import GlossaryTerm using one of the formats above. For example: + +```tf +import { + id = "projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/terms/{{term_id}}" + to = google_dataplex_glossary_term.default +} +``` + +When using the [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import), GlossaryTerm can be imported using one of the formats above. For example: + +``` +$ terraform import google_dataplex_glossary_term.default projects/{{project}}/locations/{{location}}/glossaries/{{glossary_id}}/terms/{{term_id}} +$ terraform import google_dataplex_glossary_term.default {{project}}/{{location}}/{{glossary_id}}/{{term_id}} +$ terraform import google_dataplex_glossary_term.default {{location}}/{{glossary_id}}/{{term_id}} +``` + +## User Project Overrides + +This resource supports [User Project Overrides](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#user_project_override).