Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added databricks_recipient resource for Delta Sharing #1571

Merged
merged 7 commits into from
Sep 2, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions catalog/resource_recipient.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package catalog

import (
"context"
"github.com/databricks/terraform-provider-databricks/common"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

type RecipientsAPI struct {
client *common.DatabricksClient
context context.Context
}

func NewRecipientsAPI(ctx context.Context, m interface{}) RecipientsAPI {
return RecipientsAPI{m.(*common.DatabricksClient), ctx}
}

type Token struct {
Id string `json:"id,omitempty" tf:"computed"`
CreatedAt int64 `json:"created_at,omitempty" tf:"computed"`
CreatedBy string `json:"created_by,omitempty" tf:"computed"`
ActivationUrl string `json:"activation_url,omitempty" tf:"computed"`
ExpirationTime int64 `json:"expiration_time,omitempty" tf:"computed"`
UpdatedAt int64 `json:"updated_at,omitempty" tf:"computed"`
UpdatedBy string `json:"updated_by,omitempty" tf:"computed"`
}

type IpAccessList struct {
AllowedIpAddresses []string `json:"allowed_ip_addresses"`
}

type RecipientInfo struct {
Name string `json:"name" tf:"force_new"`
Comment string `json:"comment,omitempty"`
SharingCode string `json:"sharing_code,omitempty" tf:"sensitive,force_new,suppress_diff"`
AuthenticationType string `json:"authentication_type" tf:"force_new"`
Tokens []Token `json:"tokens,omitempty" tf:"computed"`
DataRecipientGlobalMetastoreId string `json:"data_recipient_global_metastore_id,omitempty" tf:"force_new,conflicts:ip_access_list"`
IpAccessList *IpAccessList `json:"ip_access_list,omitempty"`
}

type Recipients struct {
Recipients []RecipientInfo `json:"recipients"`
}

//func (a RecipientsAPI) list() (recipients Recipients, err error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove commented code. we have a generated SDK for that already.

// err = a.client.Get(a.context, "/unity-catalog/recipients", nil, &recipients)
// return
//}

func (a RecipientsAPI) createRecipient(ci *RecipientInfo) error {
return a.client.Post(a.context, "/unity-catalog/recipients", ci, ci)
}

func (a RecipientsAPI) getRecipient(name string) (ci RecipientInfo, err error) {
err = a.client.Get(a.context, "/unity-catalog/recipients/"+name, nil, &ci)
return
}

func (a RecipientsAPI) deleteRecipient(name string) error {
return a.client.Delete(a.context, "/unity-catalog/recipients/"+name, nil)
}

func (a RecipientsAPI) updateRecipient(ci *RecipientInfo) error {
patch := map[string]interface{}{"comment": ci.Comment, "ip_access_list": ci.IpAccessList}

return a.client.Patch(a.context, "/unity-catalog/recipients/"+ci.Name, patch)
}

func ResourceRecipient() *schema.Resource {
recipientSchema := common.StructToSchema(RecipientInfo{}, func(m map[string]*schema.Schema) map[string]*schema.Schema {
m["authentication_type"].ValidateFunc = validation.StringInSlice([]string{"TOKEN", "DATABRICKS"}, false)
return m
})
return common.Resource{
Schema: recipientSchema,
Create: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
var ri RecipientInfo
common.DataToStructPointer(d, recipientSchema, &ri)
if err := NewRecipientsAPI(ctx, c).createRecipient(&ri); err != nil {
return err
}
d.SetId(ri.Name)
return nil
},
Read: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
ri, err := NewRecipientsAPI(ctx, c).getRecipient(d.Id())
if err != nil {
return err
}
return common.StructToData(ri, recipientSchema, d)
},
Update: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
var ri RecipientInfo
common.DataToStructPointer(d, recipientSchema, &ri)
return NewRecipientsAPI(ctx, c).updateRecipient(&ri)
},
Delete: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
return NewRecipientsAPI(ctx, c).deleteRecipient(d.Id())
},
}.ToResource()
}
80 changes: 80 additions & 0 deletions catalog/resource_recipient_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package catalog

import (
"testing"

"github.com/databricks/terraform-provider-databricks/qa"
)

func TestRecipientCornerCases(t *testing.T) {
qa.ResourceCornerCases(t, ResourceRecipient())
}

func TestCreateRecipient(t *testing.T) {
qa.ResourceFixture{
Fixtures: []qa.HTTPFixture{
{
Method: "POST",
Resource: "/api/2.0/unity-catalog/recipients",
ExpectedRequest: RecipientInfo{
Name: "a",
Comment: "b",
SharingCode: "c",
AuthenticationType: "TOKEN",
Tokens: nil,
IpAccessList: &IpAccessList{
AllowedIpAddresses: []string{"0.0.0.0/0"},
},
},
Response: RecipientInfo{
Name: "a",
},
},
{
Method: "GET",
Resource: "/api/2.0/unity-catalog/recipients/a",
Response: RecipientInfo{
Name: "a",
Comment: "b",
SharingCode: "c",
AuthenticationType: "TOKEN",
Tokens: nil,
IpAccessList: &IpAccessList{
AllowedIpAddresses: []string{"0.0.0.0/0"},
},
},
},
},
Resource: ResourceRecipient(),
Create: true,
HCL: `
name = "a"
comment = "b"
authentication_type = "TOKEN"
sharing_code = "c"
ip_access_list {
allowed_ip_addresses = ["0.0.0.0/0"]
}
`,
}.ApplyNoError(t)
}

func TestCreateRecipient_InvalidAuthType(t *testing.T) {
qa.ResourceFixture{
Fixtures: []qa.HTTPFixture{},
Resource: ResourceRecipient(),
Create: true,
HCL: `
name = "a"
comment = "b"
authentication_type = "temp"
sharing_code = "c"
ip_access_list {
allowed_ip_addresses = ["0.0.0.0/0"]
}
`,
}.ExpectError(t, "invalid config supplied. "+
"[authentication_type] expected authentication_type "+
"to be one of [TOKEN DATABRICKS], got temp")

}
66 changes: 66 additions & 0 deletions docs/resources/recipient.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
subcategory: "Unity Catalog"
---
# databricks_recipient Resource

Within a metastore, Unity Catalog provides the ability to create a recipient to attach delta shares to.

A `databricks_recipient` is contained within [databricks_metastore](metastore.md) and can contain a list of shares.

## Example Usage

```hcl
resource "databricks_recipient" "db2open" {
nfx marked this conversation as resolved.
Show resolved Hide resolved
name = "db2open-recipient"
comment = "made by terraform"
authentication_type = "TOKEN"
sharing_code = "my code "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add tune this example with random_password resource

ip_access_list {
allowed_ip_addresses = ["0.0.0.0/0"]
}
}

resource "databricks_recipient" "db2db" {
name = "sri-terraform-test-db2db-recipient"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. make two separate examples (db2open & db2db) explaining what they do in one sentence.
  2. please use databricks_current_user resource instead of names.

comment = "made by terraform"
authentication_type = "DATABRICKS"
data_recipient_global_metastore_id = "<cloud>:<region>:<guid>"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you expand the example with databricks_metastore resource to refer the ID from it?

}
```

## Argument Reference

The following arguments are required:

* `name` - Name of recipient. Change forces creation of a new resource.
* `comment` - (Optional) Description about the recipient.
* `sharing_code` - (Optional) The one-time sharing code provided by the data recipient.
* `authentication_type` - (Optional) The delta sharing authentication type. Valid values are `TOKEN` and `DATABRICKS`.
* `data_recipient_global_metastore_id` - Required when authentication_type is DATABRICKS.
* `ip_access_list` - (Optional) The one-time sharing code provided by the data recipient.

### Ip Access List Argument
Only one `ip_access_list` blocks is allowed in a recipient. It conflicts with authentication type DATABRICKS.

```hcl
ip_access_list {
allowed_ip_addresses = ["0.0.0.0/0"]
}
```

Arguments for the `ip_access_list` block are:

Exactly one of the below arguments is required:
* `allowed_ip_addresses` - Allowed IP Addresses in CIDR notation. Limit of 100.

## Attribute Reference:

* `tokens` - (Optional) List of Recipient Tokens.

## Related Resources

The following resources are used in the same context:

* [databricks_table](../data-sources/tables.md) data to list tables within Unity Catalog.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add those in the later PRs? :)

* [databricks_schema](../data-sources/schemas.md) data to list schemas within Unity Catalog.
* [databricks_catalog](../data-sources/catalogs.md) data to list catalogs within Unity Catalog.
1 change: 1 addition & 0 deletions provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ func DatabricksProvider() *schema.Provider {
"databricks_permission_assignment": access.ResourcePermissionAssignment(),
"databricks_permissions": permissions.ResourcePermissions(),
"databricks_pipeline": pipelines.ResourcePipeline(),
"databricks_recipient": catalog.ResourceRecipient(),
"databricks_repo": repos.ResourceRepo(),
"databricks_schema": catalog.ResourceSchema(),
"databricks_secret": secrets.ResourceSecret(),
Expand Down