From 74a139227c347a650cecab6ee885ea5ec8b849be Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Wed, 25 May 2022 18:14:25 +0000 Subject: [PATCH] Add Dataplex Lake to tpg built from their DCL resources (#6055) * Only add Dataplex lake resources * run make serialize * Moved samples to the correct location * Use lake instead of lake_name as variable placeholder * migrate to DCL version 1.8 * Updated DCL to 1.8.1 * Updated DCL to 1.8.2 Signed-off-by: Modular Magician --- .changelog/6055.txt | 3 + go.mod | 2 +- go.sum | 12 + google/config.go | 1 + google/provider.go | 3 + google/provider_dcl_client_creation.go | 24 + google/provider_dcl_endpoints.go | 12 + google/resource_container_aws_cluster.go | 2 - google/resource_container_aws_node_pool.go | 2 - google/resource_dataplex_lake.go | 514 ++++++++++++++++++ .../resource_dataplex_lake_generated_test.go | 139 +++++ google/resource_dataplex_lake_sweeper_test.go | 71 +++ website/docs/r/dataplex_lake.html.markdown | 138 +++++ website/google.erb | 16 + 14 files changed, 934 insertions(+), 5 deletions(-) create mode 100644 .changelog/6055.txt create mode 100644 google/resource_dataplex_lake.go create mode 100644 google/resource_dataplex_lake_generated_test.go create mode 100644 google/resource_dataplex_lake_sweeper_test.go create mode 100644 website/docs/r/dataplex_lake.html.markdown diff --git a/.changelog/6055.txt b/.changelog/6055.txt new file mode 100644 index 00000000000..d0ea8a6175a --- /dev/null +++ b/.changelog/6055.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +`google_dataplex_lake` +``` diff --git a/go.mod b/go.mod index a38f2f4ae48..e197ecdca93 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/hashicorp/terraform-provider-google require ( cloud.google.com/go/bigtable v1.13.0 cloud.google.com/go/iam v0.1.1 // indirect - github.com/GoogleCloudPlatform/declarative-resource-client-library v1.5.2 + github.com/GoogleCloudPlatform/declarative-resource-client-library v1.8.2 github.com/apparentlymart/go-cidr v1.1.0 github.com/client9/misspell v0.3.4 github.com/davecgh/go-spew v1.1.1 diff --git a/go.sum b/go.sum index c449eef40c7..7f48b46e734 100644 --- a/go.sum +++ b/go.sum @@ -1598,3 +1598,15 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.7.0 h1:yeTuK0eMUI8FDPR4+NK0LS6rIogHkNGF3/sjws49CVk= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.7.0/go.mod h1:UJoDYx6t3+xCOd+dZX8+NrEB+Y/eW1pQlvxh2Gt7y5E= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.7.0 h1:yeTuK0eMUI8FDPR4+NK0LS6rIogHkNGF3/sjws49CVk= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.7.0/go.mod h1:UJoDYx6t3+xCOd+dZX8+NrEB+Y/eW1pQlvxh2Gt7y5E= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.7.0 h1:yeTuK0eMUI8FDPR4+NK0LS6rIogHkNGF3/sjws49CVk= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.7.0/go.mod h1:UJoDYx6t3+xCOd+dZX8+NrEB+Y/eW1pQlvxh2Gt7y5E= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.8.0 h1:ztgQd50fYLjEspg/PmO1how0Oo4asx1uN+EkV7st5X8= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.8.0/go.mod h1:UJoDYx6t3+xCOd+dZX8+NrEB+Y/eW1pQlvxh2Gt7y5E= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.8.1 h1:tOK2JMa0ioqsuG3sbe8AMzVwUTo/xM1bvUj1U0aPVXM= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.8.1/go.mod h1:UJoDYx6t3+xCOd+dZX8+NrEB+Y/eW1pQlvxh2Gt7y5E= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.8.2 h1:V2EzqYSMPUkyKTtSevKTFU0Dw7nK6uVpg40U31Y0x/8= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.8.2/go.mod h1:UJoDYx6t3+xCOd+dZX8+NrEB+Y/eW1pQlvxh2Gt7y5E= diff --git a/google/config.go b/google/config.go index efae8f6bebc..2461dbabb33 100644 --- a/google/config.go +++ b/google/config.go @@ -251,6 +251,7 @@ type Config struct { CloudResourceManagerBasePath string ContainerAwsBasePath string ContainerAzureBasePath string + DataplexBasePath string EventarcBasePath string FirebaserulesBasePath string GkeHubBasePath string diff --git a/google/provider.go b/google/provider.go index f95bccdb238..1448b353b14 100644 --- a/google/provider.go +++ b/google/provider.go @@ -711,6 +711,7 @@ func Provider() *schema.Provider { AssuredWorkloadsEndpointEntryKey: AssuredWorkloadsEndpointEntry, ClouddeployEndpointEntryKey: ClouddeployEndpointEntry, CloudResourceManagerEndpointEntryKey: CloudResourceManagerEndpointEntry, + DataplexEndpointEntryKey: DataplexEndpointEntry, EventarcEndpointEntryKey: EventarcEndpointEntry, FirebaserulesEndpointEntryKey: FirebaserulesEndpointEntry, GkeHubFeatureCustomEndpointEntryKey: GkeHubFeatureCustomEndpointEntry, @@ -1272,6 +1273,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_container_azure_client": resourceContainerAzureClient(), "google_container_azure_cluster": resourceContainerAzureCluster(), "google_container_azure_node_pool": resourceContainerAzureNodePool(), + "google_dataplex_lake": resourceDataplexLake(), "google_dataproc_workflow_template": resourceDataprocWorkflowTemplate(), "google_eventarc_trigger": resourceEventarcTrigger(), "google_firebaserules_release": resourceFirebaserulesRelease(), @@ -1520,6 +1522,7 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData, p *schema.Pr config.AssuredWorkloadsBasePath = d.Get(AssuredWorkloadsEndpointEntryKey).(string) config.ClouddeployBasePath = d.Get(ClouddeployEndpointEntryKey).(string) config.CloudResourceManagerBasePath = d.Get(CloudResourceManagerEndpointEntryKey).(string) + config.DataplexBasePath = d.Get(DataplexEndpointEntryKey).(string) config.EventarcBasePath = d.Get(EventarcEndpointEntryKey).(string) config.FirebaserulesBasePath = d.Get(FirebaserulesEndpointEntryKey).(string) config.GkeHubBasePath = d.Get(GkeHubFeatureCustomEndpointEntryKey).(string) diff --git a/google/provider_dcl_client_creation.go b/google/provider_dcl_client_creation.go index 8c1e4f05ea7..261e1fe0b67 100644 --- a/google/provider_dcl_client_creation.go +++ b/google/provider_dcl_client_creation.go @@ -28,6 +28,7 @@ import ( compute "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/compute" containeraws "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/containeraws" containerazure "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/containerazure" + dataplex "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/dataplex" dataproc "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/dataproc" eventarc "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/eventarc" firebaserules "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/firebaserules" @@ -246,6 +247,29 @@ func NewDCLContainerAzureClient(config *Config, userAgent, billingProject string return containerazure.NewClient(dclConfig) } +func NewDCLDataplexClient(config *Config, userAgent, billingProject string, timeout time.Duration) *dataplex.Client { + configOptions := []dcl.ConfigOption{ + dcl.WithHTTPClient(config.client), + dcl.WithUserAgent(userAgent), + dcl.WithLogger(dclLogger{}), + dcl.WithBasePath(config.DataplexBasePath), + } + + if timeout != 0 { + configOptions = append(configOptions, dcl.WithTimeout(timeout)) + } + + if config.UserProjectOverride { + configOptions = append(configOptions, dcl.WithUserProjectOverride()) + if billingProject != "" { + configOptions = append(configOptions, dcl.WithBillingProject(billingProject)) + } + } + + dclConfig := dcl.NewConfig(configOptions...) + return dataplex.NewClient(dclConfig) +} + func NewDCLDataprocClient(config *Config, userAgent, billingProject string, timeout time.Duration) *dataproc.Client { configOptions := []dcl.ConfigOption{ dcl.WithHTTPClient(config.client), diff --git a/google/provider_dcl_endpoints.go b/google/provider_dcl_endpoints.go index 6c3b2c1d589..d78c6528798 100644 --- a/google/provider_dcl_endpoints.go +++ b/google/provider_dcl_endpoints.go @@ -94,6 +94,15 @@ var ContainerAzureEndpointEntry = &schema.Schema{ }, ""), } +var DataplexEndpointEntryKey = "dataplex_custom_endpoint" +var DataplexEndpointEntry = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DefaultFunc: schema.MultiEnvDefaultFunc([]string{ + "GOOGLE_DATAPLEX_CUSTOM_ENDPOINT", + }, ""), +} + var EventarcEndpointEntryKey = "eventarc_custom_endpoint" var EventarcEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -175,6 +184,7 @@ var RecaptchaEnterpriseEndpointEntry = &schema.Schema{ //ComputeBasePath string //ContainerAwsBasePath string //ContainerAzureBasePath string +//DataplexBasePath string //EventarcBasePath string //FirebaserulesBasePath string //LoggingBasePath string @@ -193,6 +203,7 @@ var RecaptchaEnterpriseEndpointEntry = &schema.Schema{ // ComputeEndpointEntryKey: ComputeEndpointEntry, // ContainerAwsEndpointEntryKey: ContainerAwsEndpointEntry, // ContainerAzureEndpointEntryKey: ContainerAzureEndpointEntry, +// DataplexEndpointEntryKey: DataplexEndpointEntry, // EventarcEndpointEntryKey: EventarcEndpointEntry, // FirebaserulesEndpointEntryKey: FirebaserulesEndpointEntry, // LoggingEndpointEntryKey: LoggingEndpointEntry, @@ -211,6 +222,7 @@ var RecaptchaEnterpriseEndpointEntry = &schema.Schema{ // config.ComputeBasePath = d.Get(ComputeEndpointEntryKey).(string) // config.ContainerAwsBasePath = d.Get(ContainerAwsEndpointEntryKey).(string) // config.ContainerAzureBasePath = d.Get(ContainerAzureEndpointEntryKey).(string) +// config.DataplexBasePath = d.Get(DataplexEndpointEntryKey).(string) // config.EventarcBasePath = d.Get(EventarcEndpointEntryKey).(string) // config.FirebaserulesBasePath = d.Get(FirebaserulesEndpointEntryKey).(string) // config.LoggingBasePath = d.Get(LoggingEndpointEntryKey).(string) diff --git a/google/resource_container_aws_cluster.go b/google/resource_container_aws_cluster.go index 024a75b7ba9..82900e94472 100644 --- a/google/resource_container_aws_cluster.go +++ b/google/resource_container_aws_cluster.go @@ -292,7 +292,6 @@ func ContainerAwsClusterControlPlaneSchema() *schema.Resource { "ssh_config": { Type: schema.TypeList, Optional: true, - ForceNew: true, Description: "Optional. SSH configuration for how to access the underlying control plane machines.", MaxItems: 1, Elem: ContainerAwsClusterControlPlaneSshConfigSchema(), @@ -447,7 +446,6 @@ func ContainerAwsClusterControlPlaneSshConfigSchema() *schema.Resource { "ec2_key_pair": { Type: schema.TypeString, Required: true, - ForceNew: true, Description: "The name of the EC2 key pair used to login into cluster machines.", }, }, diff --git a/google/resource_container_aws_node_pool.go b/google/resource_container_aws_node_pool.go index 4addcef6dac..a294b6d3687 100644 --- a/google/resource_container_aws_node_pool.go +++ b/google/resource_container_aws_node_pool.go @@ -239,7 +239,6 @@ func ContainerAwsNodePoolConfigSchema() *schema.Resource { "ssh_config": { Type: schema.TypeList, Optional: true, - ForceNew: true, Description: "Optional. The SSH configuration.", MaxItems: 1, Elem: ContainerAwsNodePoolConfigSshConfigSchema(), @@ -333,7 +332,6 @@ func ContainerAwsNodePoolConfigSshConfigSchema() *schema.Resource { "ec2_key_pair": { Type: schema.TypeString, Required: true, - ForceNew: true, Description: "The name of the EC2 key pair used to login into cluster machines.", }, }, diff --git a/google/resource_dataplex_lake.go b/google/resource_dataplex_lake.go new file mode 100644 index 00000000000..2b212d92e72 --- /dev/null +++ b/google/resource_dataplex_lake.go @@ -0,0 +1,514 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: DCL *** +// +// ---------------------------------------------------------------------------- +// +// This file is managed by Magic Modules (https://github.com/GoogleCloudPlatform/magic-modules) +// and is based on the DCL (https://github.com/GoogleCloudPlatform/declarative-resource-client-library). +// Changes will need to be made to the DCL or Magic Modules instead of here. +// +// We are not currently able to accept contributions to this file. If changes +// are required, please file an issue at https://github.com/hashicorp/terraform-provider-google/issues/new/choose +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + dcl "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" + dataplex "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/dataplex" +) + +func resourceDataplexLake() *schema.Resource { + return &schema.Resource{ + Create: resourceDataplexLakeCreate, + Read: resourceDataplexLakeRead, + Update: resourceDataplexLakeUpdate, + Delete: resourceDataplexLakeDelete, + + Importer: &schema.ResourceImporter{ + State: resourceDataplexLakeImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(20 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "location": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The location for the resource", + }, + + "name": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + Description: "The name of the lake.", + }, + + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Optional. Description of the lake.", + }, + + "display_name": { + Type: schema.TypeString, + Optional: true, + Description: "Optional. User friendly display name.", + }, + + "labels": { + Type: schema.TypeMap, + Optional: true, + Description: "Optional. User-defined labels for the lake.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "metastore": { + Type: schema.TypeList, + Optional: true, + Description: "Optional. Settings to manage lake and Dataproc Metastore service instance association.", + MaxItems: 1, + Elem: DataplexLakeMetastoreSchema(), + }, + + "project": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + Description: "The project for the resource", + }, + + "asset_status": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. Aggregated status of the underlying assets of the lake.", + Elem: DataplexLakeAssetStatusSchema(), + }, + + "create_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time when the lake was created.", + }, + + "metastore_status": { + Type: schema.TypeList, + Computed: true, + Description: "Output only. Metastore status of the lake.", + Elem: DataplexLakeMetastoreStatusSchema(), + }, + + "service_account": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. Service account associated with this lake. This service account must be authorized to access or operate on resources managed by the lake.", + }, + + "state": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. Current state of the lake. Possible values: STATE_UNSPECIFIED, ACTIVE, CREATING, DELETING, ACTION_REQUIRED", + }, + + "uid": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. System generated globally unique ID for the lake. This ID will be different if the lake is deleted and re-created with the same name.", + }, + + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: "Output only. The time when the lake was last updated.", + }, + }, + } +} + +func DataplexLakeMetastoreSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service": { + Type: schema.TypeString, + Optional: true, + Description: "Optional. A relative reference to the Dataproc Metastore (https://cloud.google.com/dataproc-metastore/docs) service associated with the lake: `projects/{project_id}/locations/{location_id}/services/{service_id}`", + }, + }, + } +} + +func DataplexLakeAssetStatusSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "active_assets": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of active assets.", + }, + + "security_policy_applying_assets": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of assets that are in process of updating the security policy on attached resources.", + }, + + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: "Last update time of the status.", + }, + }, + } +} + +func DataplexLakeMetastoreStatusSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "endpoint": { + Type: schema.TypeString, + Computed: true, + Description: "The URI of the endpoint used to access the Metastore service.", + }, + + "message": { + Type: schema.TypeString, + Computed: true, + Description: "Additional information about the current status.", + }, + + "state": { + Type: schema.TypeString, + Computed: true, + Description: "Current state of association. Possible values: STATE_UNSPECIFIED, NONE, READY, UPDATING, ERROR", + }, + + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: "Last update time of the metastore status of the lake.", + }, + }, + } +} + +func resourceDataplexLakeCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + project, err := getProject(d, config) + if err != nil { + return err + } + + obj := &dataplex.Lake{ + Location: dcl.String(d.Get("location").(string)), + Name: dcl.String(d.Get("name").(string)), + Description: dcl.String(d.Get("description").(string)), + DisplayName: dcl.String(d.Get("display_name").(string)), + Labels: checkStringMap(d.Get("labels")), + Metastore: expandDataplexLakeMetastore(d.Get("metastore")), + Project: dcl.String(project), + } + + id, err := replaceVarsForId(d, config, "projects/{{project}}/locations/{{location}}/lakes/{{name}}") + if err != nil { + return fmt.Errorf("error constructing id: %s", err) + } + d.SetId(id) + createDirective := CreateDirective + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + billingProject := project + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + client := NewDCLDataplexClient(config, userAgent, billingProject, d.Timeout(schema.TimeoutCreate)) + if bp, err := replaceVars(d, config, client.Config.BasePath); err != nil { + d.SetId("") + return fmt.Errorf("Could not format %q: %w", client.Config.BasePath, err) + } else { + client.Config.BasePath = bp + } + res, err := client.ApplyLake(context.Background(), obj, createDirective...) + + if _, ok := err.(dcl.DiffAfterApplyError); ok { + log.Printf("[DEBUG] Diff after apply returned from the DCL: %s", err) + } else if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error creating Lake: %s", err) + } + + log.Printf("[DEBUG] Finished creating Lake %q: %#v", d.Id(), res) + + return resourceDataplexLakeRead(d, meta) +} + +func resourceDataplexLakeRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + project, err := getProject(d, config) + if err != nil { + return err + } + + obj := &dataplex.Lake{ + Location: dcl.String(d.Get("location").(string)), + Name: dcl.String(d.Get("name").(string)), + Description: dcl.String(d.Get("description").(string)), + DisplayName: dcl.String(d.Get("display_name").(string)), + Labels: checkStringMap(d.Get("labels")), + Metastore: expandDataplexLakeMetastore(d.Get("metastore")), + Project: dcl.String(project), + } + + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + billingProject := project + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + client := NewDCLDataplexClient(config, userAgent, billingProject, d.Timeout(schema.TimeoutRead)) + if bp, err := replaceVars(d, config, client.Config.BasePath); err != nil { + d.SetId("") + return fmt.Errorf("Could not format %q: %w", client.Config.BasePath, err) + } else { + client.Config.BasePath = bp + } + res, err := client.GetLake(context.Background(), obj) + if err != nil { + resourceName := fmt.Sprintf("DataplexLake %q", d.Id()) + return handleNotFoundDCLError(err, d, resourceName) + } + + if err = d.Set("location", res.Location); err != nil { + return fmt.Errorf("error setting location in state: %s", err) + } + if err = d.Set("name", res.Name); err != nil { + return fmt.Errorf("error setting name in state: %s", err) + } + if err = d.Set("description", res.Description); err != nil { + return fmt.Errorf("error setting description in state: %s", err) + } + if err = d.Set("display_name", res.DisplayName); err != nil { + return fmt.Errorf("error setting display_name in state: %s", err) + } + if err = d.Set("labels", res.Labels); err != nil { + return fmt.Errorf("error setting labels in state: %s", err) + } + if err = d.Set("metastore", flattenDataplexLakeMetastore(res.Metastore)); err != nil { + return fmt.Errorf("error setting metastore in state: %s", err) + } + if err = d.Set("project", res.Project); err != nil { + return fmt.Errorf("error setting project in state: %s", err) + } + if err = d.Set("asset_status", flattenDataplexLakeAssetStatus(res.AssetStatus)); err != nil { + return fmt.Errorf("error setting asset_status in state: %s", err) + } + if err = d.Set("create_time", res.CreateTime); err != nil { + return fmt.Errorf("error setting create_time in state: %s", err) + } + if err = d.Set("metastore_status", flattenDataplexLakeMetastoreStatus(res.MetastoreStatus)); err != nil { + return fmt.Errorf("error setting metastore_status in state: %s", err) + } + if err = d.Set("service_account", res.ServiceAccount); err != nil { + return fmt.Errorf("error setting service_account in state: %s", err) + } + if err = d.Set("state", res.State); err != nil { + return fmt.Errorf("error setting state in state: %s", err) + } + if err = d.Set("uid", res.Uid); err != nil { + return fmt.Errorf("error setting uid in state: %s", err) + } + if err = d.Set("update_time", res.UpdateTime); err != nil { + return fmt.Errorf("error setting update_time in state: %s", err) + } + + return nil +} +func resourceDataplexLakeUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + project, err := getProject(d, config) + if err != nil { + return err + } + + obj := &dataplex.Lake{ + Location: dcl.String(d.Get("location").(string)), + Name: dcl.String(d.Get("name").(string)), + Description: dcl.String(d.Get("description").(string)), + DisplayName: dcl.String(d.Get("display_name").(string)), + Labels: checkStringMap(d.Get("labels")), + Metastore: expandDataplexLakeMetastore(d.Get("metastore")), + Project: dcl.String(project), + } + directive := UpdateDirective + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + billingProject := "" + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + client := NewDCLDataplexClient(config, userAgent, billingProject, d.Timeout(schema.TimeoutUpdate)) + if bp, err := replaceVars(d, config, client.Config.BasePath); err != nil { + d.SetId("") + return fmt.Errorf("Could not format %q: %w", client.Config.BasePath, err) + } else { + client.Config.BasePath = bp + } + res, err := client.ApplyLake(context.Background(), obj, directive...) + + if _, ok := err.(dcl.DiffAfterApplyError); ok { + log.Printf("[DEBUG] Diff after apply returned from the DCL: %s", err) + } else if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error updating Lake: %s", err) + } + + log.Printf("[DEBUG] Finished creating Lake %q: %#v", d.Id(), res) + + return resourceDataplexLakeRead(d, meta) +} + +func resourceDataplexLakeDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + project, err := getProject(d, config) + if err != nil { + return err + } + + obj := &dataplex.Lake{ + Location: dcl.String(d.Get("location").(string)), + Name: dcl.String(d.Get("name").(string)), + Description: dcl.String(d.Get("description").(string)), + DisplayName: dcl.String(d.Get("display_name").(string)), + Labels: checkStringMap(d.Get("labels")), + Metastore: expandDataplexLakeMetastore(d.Get("metastore")), + Project: dcl.String(project), + } + + log.Printf("[DEBUG] Deleting Lake %q", d.Id()) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + billingProject := project + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + client := NewDCLDataplexClient(config, userAgent, billingProject, d.Timeout(schema.TimeoutDelete)) + if bp, err := replaceVars(d, config, client.Config.BasePath); err != nil { + d.SetId("") + return fmt.Errorf("Could not format %q: %w", client.Config.BasePath, err) + } else { + client.Config.BasePath = bp + } + if err := client.DeleteLake(context.Background(), obj); err != nil { + return fmt.Errorf("Error deleting Lake: %s", err) + } + + log.Printf("[DEBUG] Finished deleting Lake %q", d.Id()) + return nil +} + +func resourceDataplexLakeImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + + if err := parseImportId([]string{ + "projects/(?P[^/]+)/locations/(?P[^/]+)/lakes/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := replaceVarsForId(d, config, "projects/{{project}}/locations/{{location}}/lakes/{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func expandDataplexLakeMetastore(o interface{}) *dataplex.LakeMetastore { + if o == nil { + return dataplex.EmptyLakeMetastore + } + objArr := o.([]interface{}) + if len(objArr) == 0 || objArr[0] == nil { + return dataplex.EmptyLakeMetastore + } + obj := objArr[0].(map[string]interface{}) + return &dataplex.LakeMetastore{ + Service: dcl.String(obj["service"].(string)), + } +} + +func flattenDataplexLakeMetastore(obj *dataplex.LakeMetastore) interface{} { + if obj == nil || obj.Empty() { + return nil + } + transformed := map[string]interface{}{ + "service": obj.Service, + } + + return []interface{}{transformed} + +} + +func flattenDataplexLakeAssetStatus(obj *dataplex.LakeAssetStatus) interface{} { + if obj == nil || obj.Empty() { + return nil + } + transformed := map[string]interface{}{ + "active_assets": obj.ActiveAssets, + "security_policy_applying_assets": obj.SecurityPolicyApplyingAssets, + "update_time": obj.UpdateTime, + } + + return []interface{}{transformed} + +} + +func flattenDataplexLakeMetastoreStatus(obj *dataplex.LakeMetastoreStatus) interface{} { + if obj == nil || obj.Empty() { + return nil + } + transformed := map[string]interface{}{ + "endpoint": obj.Endpoint, + "message": obj.Message, + "state": obj.State, + "update_time": obj.UpdateTime, + } + + return []interface{}{transformed} + +} diff --git a/google/resource_dataplex_lake_generated_test.go b/google/resource_dataplex_lake_generated_test.go new file mode 100644 index 00000000000..85dc3d13538 --- /dev/null +++ b/google/resource_dataplex_lake_generated_test.go @@ -0,0 +1,139 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: DCL *** +// +// ---------------------------------------------------------------------------- +// +// This file is managed by Magic Modules (https://github.com/GoogleCloudPlatform/magic-modules) +// and is based on the DCL (https://github.com/GoogleCloudPlatform/declarative-resource-client-library). +// Changes will need to be made to the DCL or Magic Modules instead of here. +// +// We are not currently able to accept contributions to this file. If changes +// are required, please file an issue at https://github.com/hashicorp/terraform-provider-google/issues/new/choose +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "context" + "fmt" + dcl "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" + dataplex "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/dataplex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "strings" + "testing" +) + +func TestAccDataplexLake_BasicLake(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project_name": getTestProjectFromEnv(), + "region": getTestRegionFromEnv(), + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckDataplexLakeDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccDataplexLake_BasicLake(context), + }, + { + ResourceName: "google_dataplex_lake.primary", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccDataplexLake_BasicLakeUpdate0(context), + }, + { + ResourceName: "google_dataplex_lake.primary", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccDataplexLake_BasicLake(context map[string]interface{}) string { + return Nprintf(` +resource "google_dataplex_lake" "primary" { + location = "%{region}" + name = "tf-test-lake%{random_suffix}" + description = "Lake for DCL" + display_name = "Lake for DCL" + + labels = { + my-lake = "exists" + } + + project = "%{project_name}" +} + + +`, context) +} + +func testAccDataplexLake_BasicLakeUpdate0(context map[string]interface{}) string { + return Nprintf(` +resource "google_dataplex_lake" "primary" { + location = "%{region}" + name = "tf-test-lake%{random_suffix}" + description = "Updated description for lake" + display_name = "Lake for DCL" + + labels = { + my-lake = "exists" + } + + project = "%{project_name}" +} + + +`, context) +} + +func testAccCheckDataplexLakeDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "rs.google_dataplex_lake" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := googleProviderConfig(t) + + billingProject := "" + if config.BillingProject != "" { + billingProject = config.BillingProject + } + + obj := &dataplex.Lake{ + Location: dcl.String(rs.Primary.Attributes["location"]), + Name: dcl.String(rs.Primary.Attributes["name"]), + Description: dcl.String(rs.Primary.Attributes["description"]), + DisplayName: dcl.String(rs.Primary.Attributes["display_name"]), + Project: dcl.StringOrNil(rs.Primary.Attributes["project"]), + CreateTime: dcl.StringOrNil(rs.Primary.Attributes["create_time"]), + ServiceAccount: dcl.StringOrNil(rs.Primary.Attributes["service_account"]), + State: dataplex.LakeStateEnumRef(rs.Primary.Attributes["state"]), + Uid: dcl.StringOrNil(rs.Primary.Attributes["uid"]), + UpdateTime: dcl.StringOrNil(rs.Primary.Attributes["update_time"]), + } + + client := NewDCLDataplexClient(config, config.userAgent, billingProject, 0) + _, err := client.GetLake(context.Background(), obj) + if err == nil { + return fmt.Errorf("google_dataplex_lake still exists %v", obj) + } + } + return nil + } +} diff --git a/google/resource_dataplex_lake_sweeper_test.go b/google/resource_dataplex_lake_sweeper_test.go new file mode 100644 index 00000000000..12f11c8a33b --- /dev/null +++ b/google/resource_dataplex_lake_sweeper_test.go @@ -0,0 +1,71 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: DCL *** +// +// ---------------------------------------------------------------------------- +// +// This file is managed by Magic Modules (https://github.com/GoogleCloudPlatform/magic-modules) +// and is based on the DCL (https://github.com/GoogleCloudPlatform/declarative-resource-client-library). +// Changes will need to be made to the DCL or Magic Modules instead of here. +// +// We are not currently able to accept contributions to this file. If changes +// are required, please file an issue at https://github.com/hashicorp/terraform-provider-google/issues/new/choose +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "context" + "log" + "testing" + + dataplex "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/dataplex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func init() { + resource.AddTestSweepers("DataplexLake", &resource.Sweeper{ + Name: "DataplexLake", + F: testSweepDataplexLake, + }) +} + +func testSweepDataplexLake(region string) error { + log.Print("[INFO][SWEEPER_LOG] Starting sweeper for DataplexLake") + + config, err := sharedConfigForRegion(region) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err) + return err + } + + err = config.LoadAndValidate(context.Background()) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err) + return err + } + + t := &testing.T{} + billingId := getTestBillingAccountFromEnv(t) + + // Setup variables to be used for Delete arguments. + d := map[string]string{ + "project": config.Project, + "region": region, + "location": region, + "zone": "-", + "billing_account": billingId, + } + + client := NewDCLDataplexClient(config, config.userAgent, "", 0) + err = client.DeleteAllLake(context.Background(), d["project"], d["location"], isDeletableDataplexLake) + if err != nil { + return err + } + return nil +} + +func isDeletableDataplexLake(r *dataplex.Lake) bool { + return isSweepableTestResource(*r.Name) +} diff --git a/website/docs/r/dataplex_lake.html.markdown b/website/docs/r/dataplex_lake.html.markdown new file mode 100644 index 00000000000..39a95dc744d --- /dev/null +++ b/website/docs/r/dataplex_lake.html.markdown @@ -0,0 +1,138 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: DCL *** +# +# ---------------------------------------------------------------------------- +# +# This file is managed by Magic Modules (https:#github.com/GoogleCloudPlatform/magic-modules) +# and is based on the DCL (https:#github.com/GoogleCloudPlatform/declarative-resource-client-library). +# Changes will need to be made to the DCL or Magic Modules instead of here. +# +# We are not currently able to accept contributions to this file. If changes +# are required, please file an issue at https:#github.com/hashicorp/terraform-provider-google/issues/new/choose +# +# ---------------------------------------------------------------------------- +subcategory: "Dataplex" +layout: "google" +page_title: "Google: google_dataplex_lake" +sidebar_current: "docs-google-dataplex-lake" +description: |- + The Dataplex Lake resource +--- + +# google_dataplex_lake + +The Dataplex Lake resource + +## Example Usage - basic_lake +A basic example of a dataplex lake +```hcl +resource "google_dataplex_lake" "primary" { + location = "us-west1" + name = "lake" + description = "Lake for DCL" + display_name = "Lake for DCL" + + labels = { + my-lake = "exists" + } + + project = "my-project-name" +} + + +``` + +## Argument Reference + +The following arguments are supported: + +* `location` - + (Required) + The location for the resource + +* `name` - + (Required) + The name of the lake. + + + +- - - + +* `description` - + (Optional) + Optional. Description of the lake. + +* `display_name` - + (Optional) + Optional. User friendly display name. + +* `labels` - + (Optional) + Optional. User-defined labels for the lake. + +* `metastore` - + (Optional) + Optional. Settings to manage lake and Dataproc Metastore service instance association. + +* `project` - + (Optional) + The project for the resource + + + +The `metastore` block supports: + +* `service` - + (Optional) + Optional. A relative reference to the Dataproc Metastore (https://cloud.google.com/dataproc-metastore/docs) service associated with the lake: `projects/{project_id}/locations/{location_id}/services/{service_id}` + +## 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}}/lakes/{{name}}` + +* `asset_status` - + Output only. Aggregated status of the underlying assets of the lake. + +* `create_time` - + Output only. The time when the lake was created. + +* `metastore_status` - + Output only. Metastore status of the lake. + +* `service_account` - + Output only. Service account associated with this lake. This service account must be authorized to access or operate on resources managed by the lake. + +* `state` - + Output only. Current state of the lake. Possible values: STATE_UNSPECIFIED, ACTIVE, CREATING, DELETING, ACTION_REQUIRED + +* `uid` - + Output only. System generated globally unique ID for the lake. This ID will be different if the lake is deleted and re-created with the same name. + +* `update_time` - + Output only. The time when the lake was last updated. + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 20 minutes. +- `update` - Default is 20 minutes. +- `delete` - Default is 20 minutes. + +## Import + +Lake can be imported using any of these accepted formats: + +``` +$ terraform import google_dataplex_lake.default projects/{{project}}/locations/{{location}}/lakes/{{name}} +$ terraform import google_dataplex_lake.default {{project}}/{{location}}/{{name}} +$ terraform import google_dataplex_lake.default {{location}}/{{name}} +``` + + + diff --git a/website/google.erb b/website/google.erb index f0bedb8a310..3a6b69281c9 100644 --- a/website/google.erb +++ b/website/google.erb @@ -2474,6 +2474,22 @@ +
  • + Dataplex + +
  • +
  • Dataproc