From d05db39bad072e97b8805fc59a23567693cc6aa7 Mon Sep 17 00:00:00 2001 From: vuong-nguyen <44292934+nkvuong@users.noreply.github.com> Date: Thu, 7 Dec 2023 11:46:01 +0000 Subject: [PATCH] refactor `databricks_mws_credentials` to Go SDK (#2962) * refactor `databricks_mws_credentials` to Go SDK * bottom left -> top right * feedback * clean up tests * nit --- docs/data-sources/aws_assume_role_policy.md | 4 +- docs/guides/aws-e2-firewall-hub-and-spoke.md | 2 +- docs/guides/aws-e2-firewall-workspace.md | 2 +- docs/guides/aws-private-link-workspace.md | 2 +- docs/guides/aws-workspace.md | 2 +- docs/guides/unity-catalog.md | 2 +- docs/index.md | 2 +- docs/resources/mws_credentials.md | 10 +- docs/resources/mws_customer_managed_keys.md | 10 +- docs/resources/mws_log_delivery.md | 4 +- docs/resources/mws_networks.md | 6 +- docs/resources/mws_permission_assignment.md | 2 +- docs/resources/mws_storage_configurations.md | 4 +- docs/resources/mws_workspaces.md | 8 +- mws/resource_mws_credentials.go | 119 +++++++---------- mws/resource_mws_credentials_test.go | 126 +++++++++++++----- .../modules/workspace-in-shared-vpc/main.tf | 2 +- 17 files changed, 172 insertions(+), 135 deletions(-) diff --git a/docs/data-sources/aws_assume_role_policy.md b/docs/data-sources/aws_assume_role_policy.md index 66530bdfbd..608b0205f1 100644 --- a/docs/data-sources/aws_assume_role_policy.md +++ b/docs/data-sources/aws_assume_role_policy.md @@ -12,7 +12,7 @@ End-to-end example of provisioning Cross-account IAM role with [databricks_mws_c ```hcl variable "databricks_account_id" { - description = "Account Id that could be found in the bottom left corner of https://accounts.cloud.databricks.com/" + description = "Account Id that could be found in the top right corner of https://accounts.cloud.databricks.com/" } data "databricks_aws_crossaccount_policy" "this" {} @@ -48,7 +48,7 @@ resource "databricks_mws_credentials" "this" { ## Argument Reference -* `external_id` (Required) Account Id that could be found in the bottom left corner of [Accounts Console](https://accounts.cloud.databricks.com/). +* `external_id` (Required) Account Id that could be found in the top right corner of [Accounts Console](https://accounts.cloud.databricks.com/). * `for_log_delivery` (Optional) Either or not this assume role policy should be created for usage log delivery. Defaults to false. ## Attribute Reference diff --git a/docs/guides/aws-e2-firewall-hub-and-spoke.md b/docs/guides/aws-e2-firewall-hub-and-spoke.md index db77624f28..83531fd5a9 100644 --- a/docs/guides/aws-e2-firewall-hub-and-spoke.md +++ b/docs/guides/aws-e2-firewall-hub-and-spoke.md @@ -10,7 +10,7 @@ You can provision multiple Databricks workspaces with Terraform, and where many ## Provider initialization for E2 workspaces -This guide assumes you have the `client_id`, which is the `application_id` of the [Service Principal](resources/service_principal.md), `client_secret`, which is its secret, and `databricks_account_id`, which can be found in the bottom left corner of the [Account Console](https://accounts.cloud.databricks.com). (see [instruction](https://docs.databricks.com/dev-tools/authentication-oauth.html#step-2-create-an-oauth-secret-for-a-service-principal)). This guide is provided as is and assumes you will use it as the basis for your setup. If you use AWS Firewall to block most traffic but allow the URLs to which Databricks needs to connect, please update the configuration based on your region. You can get the configuration details for your region from [Firewall Appliance](https://docs.databricks.com/administration-guide/cloud-configurations/aws/customer-managed-vpc.html#firewall-appliance-infrastructure) document. +This guide assumes you have the `client_id`, which is the `application_id` of the [Service Principal](resources/service_principal.md), `client_secret`, which is its secret, and `databricks_account_id`, which can be found in the top right corner of the [Account Console](https://accounts.cloud.databricks.com). (see [instruction](https://docs.databricks.com/dev-tools/authentication-oauth.html#step-2-create-an-oauth-secret-for-a-service-principal)). This guide is provided as is and assumes you will use it as the basis for your setup. If you use AWS Firewall to block most traffic but allow the URLs to which Databricks needs to connect, please update the configuration based on your region. You can get the configuration details for your region from [Firewall Appliance](https://docs.databricks.com/administration-guide/cloud-configurations/aws/customer-managed-vpc.html#firewall-appliance-infrastructure) document. ```hcl variable "client_id" {} diff --git a/docs/guides/aws-e2-firewall-workspace.md b/docs/guides/aws-e2-firewall-workspace.md index e5417eb19f..f627b3bdb9 100644 --- a/docs/guides/aws-e2-firewall-workspace.md +++ b/docs/guides/aws-e2-firewall-workspace.md @@ -12,7 +12,7 @@ For more information, please visit [Data Exfiltration Protection With Databricks ## Provider initialization for E2 workspaces -This guide assumes you have the `client_id`, which is the `application_id` of the [Service Principal](resources/service_principal.md), `client_secret`, which is its secret, and `databricks_account_id`, which can be found in the bottom left corner of the [Account Console](https://accounts.cloud.databricks.com). (see [instruction](https://docs.databricks.com/dev-tools/authentication-oauth.html#step-2-create-an-oauth-secret-for-a-service-principal)). This guide is provided as is and assumes you will use it as the basis for your setup. If you are using AWS Firewall to block most traffic but allow the URLs that Databricks needs to connect to, please update the configuration based on your region. You can get the configuration details for your region from [Firewall Appliance](https://docs.databricks.com/administration-guide/cloud-configurations/aws/customer-managed-vpc.html#firewall-appliance-infrastructure) document. +This guide assumes you have the `client_id`, which is the `application_id` of the [Service Principal](resources/service_principal.md), `client_secret`, which is its secret, and `databricks_account_id`, which can be found in the top right corner of the [Account Console](https://accounts.cloud.databricks.com). (see [instruction](https://docs.databricks.com/dev-tools/authentication-oauth.html#step-2-create-an-oauth-secret-for-a-service-principal)). This guide is provided as is and assumes you will use it as the basis for your setup. If you are using AWS Firewall to block most traffic but allow the URLs that Databricks needs to connect to, please update the configuration based on your region. You can get the configuration details for your region from [Firewall Appliance](https://docs.databricks.com/administration-guide/cloud-configurations/aws/customer-managed-vpc.html#firewall-appliance-infrastructure) document. ```hcl variable "client_id" {} diff --git a/docs/guides/aws-private-link-workspace.md b/docs/guides/aws-private-link-workspace.md index 4a011776ca..5120f233b8 100644 --- a/docs/guides/aws-private-link-workspace.md +++ b/docs/guides/aws-private-link-workspace.md @@ -12,7 +12,7 @@ This guide uses the following variables in configurations: - `client_id`: `application_id` of the service principal, see [instruction](https://docs.databricks.com/dev-tools/authentication-oauth.html#step-2-create-an-oauth-secret-for-a-service-principal) - `client_secret`: the secret of the service principal. -- `databricks_account_id`: The numeric ID for your Databricks account. When logged in, it appears in the bottom left corner of the page. +- `databricks_account_id`: The numeric ID for your Databricks account. When logged in, it appears in the top right corner of the page. - `vpc_id` - The ID for the AWS VPC. - `region` - AWS region. - `security_group_id` - Security groups set up for the existing VPC. diff --git a/docs/guides/aws-workspace.md b/docs/guides/aws-workspace.md index 36fc8d93f7..aadb41b7a4 100644 --- a/docs/guides/aws-workspace.md +++ b/docs/guides/aws-workspace.md @@ -10,7 +10,7 @@ You can provision multiple Databricks workspaces with Terraform. ## Provider initialization for E2 workspaces -This guide assumes you have the `client_id`, which is the `application_id` of the [Service Principal](resources/service_principal.md), `client_secret`, which is its secret, and `databricks_account_id`, which can be found in the bottom left corner of the [Account Console](https://accounts.cloud.databricks.com). (see [instruction](https://docs.databricks.com/dev-tools/authentication-oauth.html#step-2-create-an-oauth-secret-for-a-service-principal)). This guide is provided as is and assumes you will use it as the basis for your setup. +This guide assumes you have the `client_id`, which is the `application_id` of the [Service Principal](resources/service_principal.md), `client_secret`, which is its secret, and `databricks_account_id`, which can be found in the top right corner of the [Account Console](https://accounts.cloud.databricks.com). (see [instruction](https://docs.databricks.com/dev-tools/authentication-oauth.html#step-2-create-an-oauth-secret-for-a-service-principal)). This guide is provided as is and assumes you will use it as the basis for your setup. ```hcl variable "client_id" {} diff --git a/docs/guides/unity-catalog.md b/docs/guides/unity-catalog.md index dfd8afb5db..2c152f438e 100644 --- a/docs/guides/unity-catalog.md +++ b/docs/guides/unity-catalog.md @@ -18,7 +18,7 @@ This guide uses the following variables in configurations: - `databricks_client_id`: The `client_id` is the `application_id` of a [Service Principal](../resources/service_principal.md) that has account-level admin permission on [https://accounts.cloud.databricks.com](https://accounts.cloud.databricks.com). - `databricks_client_secret`: The secret of the above service principal. -- `databricks_account_id`: The numeric ID for your Databricks account. When you are logged in, it appears in the bottom left corner of the [Databricks Account Console](https://accounts.cloud.databricks.com/) or [Azure Databricks Account Console](https://accounts.azuredatabricks.net). +- `databricks_account_id`: The numeric ID for your Databricks account. When you are logged in, it appears in the top right corner of the [Databricks Account Console](https://accounts.cloud.databricks.com/) or [Azure Databricks Account Console](https://accounts.azuredatabricks.net). - `databricks_workspace_url`: Value of `workspace_url` attribute from [databricks_mws_workspaces](../resources/mws_workspaces.md#attribute-reference) resource. This guide is provided as-is and you can use this guide as the basis for your custom Terraform module. diff --git a/docs/index.md b/docs/index.md index 48aa0d6c82..445791287a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -205,7 +205,7 @@ Alternatively, you can provide this value as an environment variable `DATABRICKS * `config_file` - (optional) Location of the Databricks CLI credentials file created by `databricks configure --token` command (~/.databrickscfg by default). Check [Databricks CLI documentation](https://docs.databricks.com/dev-tools/cli/index.html#set-up-authentication) for more details. The provider uses configuration file credentials when you don't specify host/token/username/password/azure attributes. Alternatively, you can provide this value as an environment variable `DATABRICKS_CONFIG_FILE`. This field defaults to `~/.databrickscfg`. * `profile` - (optional) Connection profile specified within ~/.databrickscfg. Please check [connection profiles section](https://docs.databricks.com/dev-tools/cli/index.html#connection-profiles) for more details. This field defaults to `DEFAULT`. -* `account_id` - (optional) Account Id that could be found in the bottom left corner of [Accounts Console](https://accounts.cloud.databricks.com/). Alternatively, you can provide this value as an environment variable `DATABRICKS_ACCOUNT_ID`. Only has effect when `host = "https://accounts.cloud.databricks.com/"`, and is currently used to provision account admins via [databricks_user](resources/user.md). In the future releases of the provider this property will also be used specify account for `databricks_mws_*` resources as well. +* `account_id` - (optional) Account Id that could be found in the top right corner of [Accounts Console](https://accounts.cloud.databricks.com/). Alternatively, you can provide this value as an environment variable `DATABRICKS_ACCOUNT_ID`. Only has effect when `host = "https://accounts.cloud.databricks.com/"`, and is currently used to provision account admins via [databricks_user](resources/user.md). In the future releases of the provider this property will also be used specify account for `databricks_mws_*` resources as well. * `auth_type` - (optional) enforce specific auth type to be used in very rare cases, where a single Terraform state manages Databricks workspaces on more than one cloud and `more than one authorization method configured` error is a false positive. Valid values are `pat`, `basic`, `oauth-m2m`, `azure-client-secret`, `azure-msi`, `azure-cli`, `google-credentials`, and `google-id`. ## Special configurations for AWS diff --git a/docs/resources/mws_credentials.md b/docs/resources/mws_credentials.md index a3947b839d..9ddc027a6d 100644 --- a/docs/resources/mws_credentials.md +++ b/docs/resources/mws_credentials.md @@ -13,7 +13,7 @@ Please follow this [complete runnable example](../guides/aws-workspace.md) with ```hcl variable "databricks_account_id" { - description = "Account Id that could be found in the bottom left corner of https://accounts.cloud.databricks.com/" + description = "Account Id that could be found in the top right corner of https://accounts.cloud.databricks.com/" } data "databricks_aws_assume_role_policy" "this" { @@ -47,7 +47,7 @@ resource "databricks_mws_credentials" "this" { The following arguments are required: -* `account_id` - (Required) Account Id that could be found in the bottom left corner of [Accounts Console](https://accounts.cloud.databricks.com/) +* `account_id` - (Optional) Account Id that could be found in the top right corner of [Accounts Console](https://accounts.cloud.databricks.com/) * `credentials_name` - (Required) name of credentials to register * `role_arn` - (Required) ARN of cross-account role @@ -61,7 +61,11 @@ In addition to all arguments above, the following attributes are exported: ## Import --> **Note** Importing this resource is not currently supported. +This resource can be imported by the combination of its identifier and the account id: + +```bash +terraform import databricks_mws_credentials.this / +``` ## Related Resources diff --git a/docs/resources/mws_customer_managed_keys.md b/docs/resources/mws_customer_managed_keys.md index f739d06bb9..d27a2ff1c0 100644 --- a/docs/resources/mws_customer_managed_keys.md +++ b/docs/resources/mws_customer_managed_keys.md @@ -24,7 +24,7 @@ You must configure this during workspace creation ```hcl variable "databricks_account_id" { - description = "Account Id that could be found in the bottom left corner of https://accounts.cloud.databricks.com/" + description = "Account Id that could be found in the top right corner of https://accounts.cloud.databricks.com/" } data "aws_caller_identity" "current" {} @@ -80,7 +80,7 @@ resource "databricks_mws_customer_managed_keys" "managed_services" { ```hcl variable "databricks_account_id" { - description = "Account Id that could be found in the bottom left corner of https://accounts.gcp.databricks.com/" + description = "Account Id that could be found in the top right corner of https://accounts.gcp.databricks.com/" } variable "cmek_resource_id" { @@ -103,7 +103,7 @@ resource "databricks_mws_customer_managed_keys" "managed_services" { ```hcl variable "databricks_account_id" { - description = "Account Id that could be found in the bottom left corner of https://accounts.cloud.databricks.com/" + description = "Account Id that could be found in the top right corner of https://accounts.cloud.databricks.com/" } variable "databricks_cross_account_role" { @@ -203,7 +203,7 @@ resource "databricks_mws_customer_managed_keys" "storage" { ```hcl variable "databricks_account_id" { - description = "Account Id that could be found in the bottom left corner of https://accounts.gcp.databricks.com/" + description = "Account Id that could be found in the top right corner of https://accounts.gcp.databricks.com/" } variable "cmek_resource_id" { @@ -226,7 +226,7 @@ The following arguments are required: * `aws_key_info` - This field is a block and is documented below. This conflicts with `gcp_key_info` * `gcp_key_info` - This field is a block and is documented below. This conflicts with `aws_key_info` -* `account_id` - Account Id that could be found in the bottom left corner of [Accounts Console](https://accounts.cloud.databricks.com/) +* `account_id` - Account Id that could be found in the top right corner of [Accounts Console](https://accounts.cloud.databricks.com/) * `use_cases` - *(since v0.3.4)* List of use cases for which this key will be used. *If you've used the resource before, please add `use_cases = ["MANAGED_SERVICES"]` to keep the previous behaviour.* Possible values are: * `MANAGED_SERVICES` - for encryption of the workspace objects (notebooks, secrets) that are stored in the control plane * `STORAGE` - for encryption of the DBFS Storage & Cluster EBS Volumes diff --git a/docs/resources/mws_log_delivery.md b/docs/resources/mws_log_delivery.md index 964731ab51..948efb0a69 100644 --- a/docs/resources/mws_log_delivery.md +++ b/docs/resources/mws_log_delivery.md @@ -15,7 +15,7 @@ End-to-end example of usage and audit log delivery: ```hcl variable "databricks_account_id" { - description = "Account Id that could be found in the bottom left corner of https://accounts.cloud.databricks.com/" + description = "Account Id that could be found in the top right corner of https://accounts.cloud.databricks.com/" } resource "aws_s3_bucket" "logdelivery" { @@ -130,7 +130,7 @@ resource "databricks_mws_log_delivery" "audit_logs" { ## Argument reference -* `account_id` - Account Id that could be found in the bottom left corner of [Accounts Console](https://accounts.cloud.databricks.com/). +* `account_id` - Account Id that could be found in the top right corner of [Accounts Console](https://accounts.cloud.databricks.com/). * `config_name` - The optional human-readable name of the log delivery configuration. Defaults to empty. * `log_type` - The type of log delivery. `BILLABLE_USAGE` and `AUDIT_LOGS` are supported. * `output_format` - The file type of log delivery. Currently `CSV` (for `BILLABLE_USAGE`) and `JSON` (for `AUDIT_LOGS`) are supported. diff --git a/docs/resources/mws_networks.md b/docs/resources/mws_networks.md index d71ff1fcab..5caf2167f3 100644 --- a/docs/resources/mws_networks.md +++ b/docs/resources/mws_networks.md @@ -39,7 +39,7 @@ Please follow this [complete runnable example](../guides/gcp-workspace.md) with ```hcl variable "databricks_account_id" { - description = "Account Id that could be found in the bottom left corner of https://accounts.cloud.databricks.com/" + description = "Account Id that could be found in the top right corner of https://accounts.cloud.databricks.com/" } data "aws_availability_zones" "available" {} @@ -104,7 +104,7 @@ resource "databricks_mws_networks" "this" { ```hcl variable "databricks_account_id" { - description = "Account Id that could be found in the bottom left corner of https://accounts.cloud.databricks.com/" + description = "Account Id that could be found in the top right corner of https://accounts.cloud.databricks.com/" } resource "google_compute_network" "dbx_private_vpc" { @@ -190,7 +190,7 @@ Due to specifics of platform APIs, changing any attribute of network configurati The following arguments are available: -* `account_id` - Account Id that could be found in the bottom left corner of [Accounts Console](https://accounts.cloud.databricks.com/) +* `account_id` - Account Id that could be found in the top right corner of [Accounts Console](https://accounts.cloud.databricks.com/) * `network_name` - name under which this network is registered * `vpc_id` - (AWS only) [aws_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) id * `subnet_ids` - (AWS only) ids of [aws_subnet](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) diff --git a/docs/resources/mws_permission_assignment.md b/docs/resources/mws_permission_assignment.md index 2c65a9e8ac..acdb38bb7c 100644 --- a/docs/resources/mws_permission_assignment.md +++ b/docs/resources/mws_permission_assignment.md @@ -3,7 +3,7 @@ subcategory: "Security" --- # databricks_mws_permission_assignment Resource -These resources are invoked in the account context. Permission Assignment Account API endpoints are restricted to account admins. Provider must have `account_id` attribute configured. Account Id that could be found in the bottom left corner of Accounts Console +These resources are invoked in the account context. Permission Assignment Account API endpoints are restricted to account admins. Provider must have `account_id` attribute configured. Account Id that could be found in the top right corner of Accounts Console ## Example Usage diff --git a/docs/resources/mws_storage_configurations.md b/docs/resources/mws_storage_configurations.md index fe64b550e3..fd6f276955 100644 --- a/docs/resources/mws_storage_configurations.md +++ b/docs/resources/mws_storage_configurations.md @@ -15,7 +15,7 @@ Please follow this [complete runnable example](../guides/aws-workspace.md) with ```hcl variable "databricks_account_id" { - description = "Account Id that could be found in the bottom left corner of https://accounts.cloud.databricks.com/" + description = "Account Id that could be found in the top right corner of https://accounts.cloud.databricks.com/" } resource "aws_s3_bucket" "root_storage_bucket" { @@ -43,7 +43,7 @@ resource "databricks_mws_storage_configurations" "this" { The following arguments are required: * `bucket_name` - name of AWS S3 bucket -* `account_id` - Account Id that could be found in the bottom left corner of [Accounts Console](https://accounts.cloud.databricks.com/) +* `account_id` - Account Id that could be found in the top right corner of [Accounts Console](https://accounts.cloud.databricks.com/) * `storage_configuration_name` - name under which this storage configuration is stored ## Attribute Reference diff --git a/docs/resources/mws_workspaces.md b/docs/resources/mws_workspaces.md index d8bda94cb3..571bea02c1 100644 --- a/docs/resources/mws_workspaces.md +++ b/docs/resources/mws_workspaces.md @@ -93,7 +93,7 @@ By default, Databricks creates a VPC in your AWS account for each workspace. Dat ```hcl variable "databricks_account_id" { - description = "Account Id that could be found in the bottom left corner of https://accounts.cloud.databricks.com/" + description = "Account Id that could be found in the top right corner of https://accounts.cloud.databricks.com/" } resource "random_string" "naming" { @@ -210,7 +210,7 @@ To get workspace running, you have to configure a network object: ```hcl variable "databricks_account_id" { - description = "Account Id that could be found in the bottom left corner of https://accounts.cloud.databricks.com/" + description = "Account Id that could be found in the top right corner of https://accounts.cloud.databricks.com/" } variable "databricks_google_service_account" {} variable "google_project" {} @@ -271,7 +271,7 @@ By default, Databricks creates a VPC in your GCP project for each workspace. Dat ```hcl variable "databricks_account_id" { - description = "Account Id that could be found in the bottom left corner of https://accounts.cloud.databricks.com/" + description = "Account Id that could be found in the top right corner of https://accounts.cloud.databricks.com/" } data "google_client_openid_userinfo" "me" { @@ -312,7 +312,7 @@ output "databricks_token" { The following arguments are available: -* `account_id` - Account Id that could be found in the bottom left corner of [Accounts Console](https://accounts.cloud.databricks.com/). +* `account_id` - Account Id that could be found in the top right corner of [Accounts Console](https://accounts.cloud.databricks.com/). * `deployment_name` - (Optional) part of URL as in `https://-.cloud.databricks.com`. Deployment name cannot be used until a deployment name prefix is defined. Please contact your Databricks representative. Once a new deployment prefix is added/updated, it only will affect the new workspaces created. * `workspace_name` - name of the workspace, will appear on UI. * `network_id` - (Optional) `network_id` from [networks](mws_networks.md). diff --git a/mws/resource_mws_credentials.go b/mws/resource_mws_credentials.go index 7111804f34..2cb12619d6 100644 --- a/mws/resource_mws_credentials.go +++ b/mws/resource_mws_credentials.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/databricks/databricks-sdk-go/service/provisioning" "github.com/databricks/terraform-provider-databricks/common" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -20,37 +21,6 @@ type CredentialsAPI struct { context context.Context } -// TODO: move mwsAcctID into provider configuration... - -// Create creates a set of MWS Credentials for the cross account role -func (a CredentialsAPI) Create(mwsAcctID, credentialsName string, roleArn string) (Credentials, error) { - var mwsCreds Credentials - credentialsAPIPath := fmt.Sprintf("/accounts/%s/credentials", mwsAcctID) - err := a.client.Post(a.context, credentialsAPIPath, Credentials{ - CredentialsName: credentialsName, - AwsCredentials: &AwsCredentials{ - StsRole: &StsRole{ - RoleArn: roleArn, - }, - }, - }, &mwsCreds) - return mwsCreds, err -} - -// Read returns the credentials object along with metadata -func (a CredentialsAPI) Read(mwsAcctID, credentialsID string) (Credentials, error) { - var mwsCreds Credentials - credentialsAPIPath := fmt.Sprintf("/accounts/%s/credentials/%s", mwsAcctID, credentialsID) - err := a.client.Get(a.context, credentialsAPIPath, nil, &mwsCreds) - return mwsCreds, err -} - -// Delete deletes the credentials object given a credentials id -func (a CredentialsAPI) Delete(mwsAcctID, credentialsID string) error { - credentialsAPIPath := fmt.Sprintf("/accounts/%s/credentials/%s", mwsAcctID, credentialsID) - return a.client.Delete(a.context, credentialsAPIPath, nil) -} - // List lists all the available credentials object in the mws account func (a CredentialsAPI) List(mwsAcctID string) ([]Credentials, error) { var mwsCredsList []Credentials @@ -59,71 +29,82 @@ func (a CredentialsAPI) List(mwsAcctID string) ([]Credentials, error) { return mwsCredsList, err } +type CredentialInfo struct { + // The account id - this is for backwards compatiblity + AccountId string `json:"account_id,omitempty" tf:"force_new,suppress_diff"` + // The human-readable name of the credential configuration object. + CredentialsName string `json:"credentials_name" tf:"force_new"` + // The Amazon Resource Name (ARN) of the cross account role. + RoleArn string `json:"role_arn" tf:"force_new"` + // Time in epoch milliseconds when the credential was created. + CreationTime int64 `json:"creation_time,omitempty" tf:"computed"` + // Databricks credential configuration ID. + CredentialsId string `json:"credentials_id,omitempty" tf:"computed"` + // The external ID that needs to be trusted by the cross-account role. This + // is always your Databricks account ID. + ExternalId string `json:"external_id,omitempty" tf:"computed"` +} + func ResourceMwsCredentials() *schema.Resource { p := common.NewPairSeparatedID("account_id", "credentials_id", "/") return common.Resource{ Create: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error { - accountID := d.Get("account_id").(string) + acc, err := c.AccountClient() + if err != nil { + return err + } roleArn := d.Get("role_arn").(string) credentialsName := d.Get("credentials_name").(string) - credentials, err := NewCredentialsAPI(ctx, c).Create(accountID, credentialsName, roleArn) + + credentials, err := acc.Credentials.Create(ctx, provisioning.CreateCredentialRequest{ + CredentialsName: credentialsName, + AwsCredentials: provisioning.CreateCredentialAwsCredentials{ + StsRole: &provisioning.CreateCredentialStsRole{ + RoleArn: roleArn, + }, + }, + }) if err != nil { return err } - d.Set("credentials_id", credentials.CredentialsID) + d.Set("credentials_id", credentials.CredentialsId) + d.Set("account_id", c.Config.AccountID) p.Pack(d) return nil }, Read: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error { - accountID, credsID, err := p.Unpack(d) + acc, err := c.AccountClient() + if err != nil { + return err + } + _, credsId, err := p.Unpack(d) if err != nil { return err } - credentials, err := NewCredentialsAPI(ctx, c).Read(accountID, credsID) + credentials, err := acc.Credentials.GetByCredentialsId(ctx, credsId) if err != nil { return err } d.Set("credentials_name", credentials.CredentialsName) d.Set("role_arn", credentials.AwsCredentials.StsRole.RoleArn) d.Set("creation_time", credentials.CreationTime) - return d.Set("external_id", credentials.AwsCredentials.StsRole.ExternalID) + return d.Set("external_id", credentials.AwsCredentials.StsRole.ExternalId) + }, + // this resource cannot be updated, add this to prevent "doesn't support update" error from TF + Update: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error { + return nil }, Delete: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error { - accountID, credsID, err := p.Unpack(d) + acc, err := c.AccountClient() if err != nil { return err } - return NewCredentialsAPI(ctx, c).Delete(accountID, credsID) - }, - Schema: map[string]*schema.Schema{ - "account_id": { - Type: schema.TypeString, - Required: true, - Sensitive: true, - ForceNew: true, - }, - "credentials_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "role_arn": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "creation_time": { - Type: schema.TypeInt, - Computed: true, - }, - "external_id": { - Type: schema.TypeString, - Computed: true, - }, - "credentials_id": { - Type: schema.TypeString, - Computed: true, - }, + _, credsId, err := p.Unpack(d) + if err != nil { + return err + } + return acc.Credentials.DeleteByCredentialsId(ctx, credsId) }, + Schema: common.StructToSchema(CredentialInfo{}, common.NoCustomize), }.ToResource() } diff --git a/mws/resource_mws_credentials_test.go b/mws/resource_mws_credentials_test.go index de9c9eae09..4cc659e857 100644 --- a/mws/resource_mws_credentials_test.go +++ b/mws/resource_mws_credentials_test.go @@ -11,7 +11,7 @@ import ( ) func TestResourceCredentialsCreate(t *testing.T) { - d, err := qa.ResourceFixture{ + qa.ResourceFixture{ Fixtures: []qa.HTTPFixture{ { Method: "POST", @@ -30,7 +30,7 @@ func TestResourceCredentialsCreate(t *testing.T) { }, { Method: "GET", - Resource: "/api/2.0/accounts/abc/credentials/cid", + Resource: "/api/2.0/accounts/abc/credentials/cid?", Response: Credentials{ CredentialsID: "cid", CredentialsName: "Cross-account ARN", @@ -48,10 +48,57 @@ func TestResourceCredentialsCreate(t *testing.T) { "credentials_name": "Cross-account ARN", "role_arn": "arn:aws:iam::098765:role/cross-account", }, - Create: true, - }.Apply(t) - assert.NoError(t, err) - assert.Equal(t, "abc/cid", d.Id()) + Create: true, + AccountID: "abc", + }.ApplyAndExpectData(t, map[string]any{ + "id": "abc/cid", + "role_arn": "arn:aws:iam::098765:role/cross-account", + }) +} + +func TestResourceCredentialsCreateWithoutAccId(t *testing.T) { + qa.ResourceFixture{ + Fixtures: []qa.HTTPFixture{ + { + Method: "POST", + Resource: "/api/2.0/accounts/abc/credentials", + ExpectedRequest: Credentials{ + CredentialsName: "Cross-account ARN", + AwsCredentials: &AwsCredentials{ + StsRole: &StsRole{ + RoleArn: "arn:aws:iam::098765:role/cross-account", + }, + }, + }, + Response: Credentials{ + CredentialsID: "cid", + }, + }, + { + Method: "GET", + Resource: "/api/2.0/accounts/abc/credentials/cid?", + Response: Credentials{ + CredentialsID: "cid", + CredentialsName: "Cross-account ARN", + AwsCredentials: &AwsCredentials{ + StsRole: &StsRole{ + RoleArn: "arn:aws:iam::098765:role/cross-account", + }, + }, + }, + }, + }, + Resource: ResourceMwsCredentials(), + State: map[string]any{ + "credentials_name": "Cross-account ARN", + "role_arn": "arn:aws:iam::098765:role/cross-account", + }, + Create: true, + AccountID: "abc", + }.ApplyAndExpectData(t, map[string]any{ + "id": "abc/cid", + "role_arn": "arn:aws:iam::098765:role/cross-account", + }) } func TestResourceCredentialsCreate_Error(t *testing.T) { @@ -73,18 +120,19 @@ func TestResourceCredentialsCreate_Error(t *testing.T) { "credentials_name": "Cross-account ARN", "role_arn": "arn:aws:iam::098765:role/cross-account", }, - Create: true, + Create: true, + AccountID: "abc", }.Apply(t) qa.AssertErrorStartsWith(t, err, "Internal error happened") assert.Equal(t, "", d.Id(), "Id should be empty for error creates") } func TestResourceCredentialsRead(t *testing.T) { - d, err := qa.ResourceFixture{ + qa.ResourceFixture{ Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/accounts/abc/credentials/cid", + Resource: "/api/2.0/accounts/abc/credentials/cid?", Response: Credentials{ CredentialsID: "cid", CredentialsName: "Cross-account ARN", @@ -96,17 +144,17 @@ func TestResourceCredentialsRead(t *testing.T) { }, }, }, - Resource: ResourceMwsCredentials(), - Read: true, - ID: "abc/cid", - }.Apply(t) - assert.NoError(t, err) - assert.Equal(t, "abc/cid", d.Id(), "Id should not be empty") - assert.Equal(t, 0, d.Get("creation_time")) - assert.Equal(t, "cid", d.Get("credentials_id")) - assert.Equal(t, "Cross-account ARN", d.Get("credentials_name")) - assert.Equal(t, "", d.Get("external_id")) - assert.Equal(t, "arn:aws:iam::098765:role/cross-account", d.Get("role_arn")) + Resource: ResourceMwsCredentials(), + Read: true, + ID: "abc/cid", + AccountID: "abc", + }.ApplyAndExpectData(t, map[string]any{ + "id": "abc/cid", + "role_arn": "arn:aws:iam::098765:role/cross-account", + "creation_time": 0, + "credentials_name": "Cross-account ARN", + "external_id": "", + }) } func TestResourceCredentialsRead_NotFound(t *testing.T) { @@ -114,7 +162,7 @@ func TestResourceCredentialsRead_NotFound(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/accounts/abc/credentials/cid", + Resource: "/api/2.0/accounts/abc/credentials/cid?", Response: apierr.APIErrorBody{ ErrorCode: "NOT_FOUND", Message: "Item not found", @@ -122,10 +170,11 @@ func TestResourceCredentialsRead_NotFound(t *testing.T) { Status: 404, }, }, - Resource: ResourceMwsCredentials(), - Read: true, - Removed: true, - ID: "abc/cid", + Resource: ResourceMwsCredentials(), + Read: true, + Removed: true, + ID: "abc/cid", + AccountID: "abc", }.ApplyNoError(t) } @@ -134,7 +183,7 @@ func TestResourceCredentialsRead_Error(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "GET", - Resource: "/api/2.0/accounts/abc/credentials/cid", + Resource: "/api/2.0/accounts/abc/credentials/cid?", Response: apierr.APIErrorBody{ ErrorCode: "INVALID_REQUEST", Message: "Internal error happened", @@ -142,9 +191,10 @@ func TestResourceCredentialsRead_Error(t *testing.T) { Status: 400, }, }, - Resource: ResourceMwsCredentials(), - Read: true, - ID: "abc/cid", + Resource: ResourceMwsCredentials(), + Read: true, + ID: "abc/cid", + AccountID: "abc", }.Apply(t) qa.AssertErrorStartsWith(t, err, "Internal error happened") assert.Equal(t, "abc/cid", d.Id(), "Id should not be empty for error reads") @@ -155,12 +205,13 @@ func TestResourceCredentialsDelete(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "DELETE", - Resource: "/api/2.0/accounts/abc/credentials/cid", + Resource: "/api/2.0/accounts/abc/credentials/cid?", }, }, - Resource: ResourceMwsCredentials(), - Delete: true, - ID: "abc/cid", + Resource: ResourceMwsCredentials(), + Delete: true, + ID: "abc/cid", + AccountID: "abc", }.Apply(t) assert.NoError(t, err) assert.Equal(t, "abc/cid", d.Id()) @@ -171,7 +222,7 @@ func TestResourceCredentialsDelete_Error(t *testing.T) { Fixtures: []qa.HTTPFixture{ { Method: "DELETE", - Resource: "/api/2.0/accounts/abc/credentials/cid", + Resource: "/api/2.0/accounts/abc/credentials/cid?", Response: apierr.APIErrorBody{ ErrorCode: "INVALID_REQUEST", Message: "Internal error happened", @@ -179,9 +230,10 @@ func TestResourceCredentialsDelete_Error(t *testing.T) { Status: 400, }, }, - Resource: ResourceMwsCredentials(), - Delete: true, - ID: "abc/cid", + Resource: ResourceMwsCredentials(), + Delete: true, + ID: "abc/cid", + AccountID: "abc", }.Apply(t) qa.AssertErrorStartsWith(t, err, "Internal error happened") assert.Equal(t, "abc/cid", d.Id()) diff --git a/scripts/modules/workspace-in-shared-vpc/main.tf b/scripts/modules/workspace-in-shared-vpc/main.tf index d689c28e76..caf0cd8105 100644 --- a/scripts/modules/workspace-in-shared-vpc/main.tf +++ b/scripts/modules/workspace-in-shared-vpc/main.tf @@ -1,6 +1,6 @@ variable "account_id" { type = string - description = "Account Id that could be found in the bottom left corner of https://accounts.cloud.databricks.com/" + description = "Account Id that could be found in the top right corner of https://accounts.cloud.databricks.com/" } variable "username" {