Skip to content

Commit 6fbe7ff

Browse files
authored
Added MLflow permissions (#1013)
## MLflow Experiment usage Valid [permission levels](https://docs.databricks.com/security/access-control/workspace-acl.html#mlflow-experiment-permissions-1) for [databricks_mlflow_experiment](mlflow_experiment.md) are: `CAN_READ`, `CAN_EDIT`, and `CAN_MANAGE`. ```hcl data "databricks_current_user" "me" {} resource "databricks_mlflow_experiment" "this" { name = "${data.databricks_current_user.me.home}/Sample" artifact_location = "dbfs:/tmp/my-experiment" description = "My MLflow experiment description" } resource "databricks_group" "auto" { display_name = "Automation" } resource "databricks_group" "eng" { display_name = "Engineering" } resource "databricks_permissions" "experiment_usage" { experiment_id = databricks_mlflow_experiment.this.id access_control { group_name = "users" permission_level = "CAN_READ" } access_control { group_name = databricks_group.auto.display_name permission_level = "CAN_MANAGE" } access_control { group_name = databricks_group.eng.display_name permission_level = "CAN_EDIT" } } ``` ## MLflow Model usage Valid [permission levels](https://docs.databricks.com/security/access-control/workspace-acl.html#mlflow-model-permissions-1) for [databricks_mlflow_model](mlflow_model.md) are: `CAN_READ`, `CAN_EDIT`, `CAN_MANAGE_STAGING_VERSIONS`, `CAN_MANAGE_PRODUCTION_VERSIONS`, and `CAN_MANAGE`. ```hcl resource "databricks_mlflow_model" "this" { name = "SomePredictions" } resource "databricks_group" "auto" { display_name = "Automation" } resource "databricks_group" "eng" { display_name = "Engineering" } resource "databricks_permissions" "model_usage" { registered_model_id = databricks_mlflow_model.this.registered_model_id access_control { group_name = "users" permission_level = "CAN_READ" } access_control { group_name = databricks_group.auto.display_name permission_level = "CAN_MANAGE_PRODUCTION_VERSIONS" } access_control { group_name = databricks_group.eng.display_name permission_level = "CAN_MANAGE_STAGING_VERSIONS" } } ``` Fixes #1012
1 parent e86931a commit 6fbe7ff

File tree

7 files changed

+117
-29
lines changed

7 files changed

+117
-29
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## 0.4.3
44

5+
* Added support for `databricks_permissions` for `databricks_mlflow_experiment` and `databricks_mlflow_model` ([#1013](https://github.com/databrickslabs/terraform-provider-databricks/pull/1013)).
56
* Added `Using XXX auth` explanation to HTTP 403 errors, which should help troubleshooting misconfigured authentication or provider aliasing. Example error message now looks like: *cannot create group: /2.0/preview/scim/v2/Groups is only accessible by admins. Using databricks-cli auth: host=https://XXX.cloud.databricks.com/, token=`***REDACTED***`, profile=demo.* All sensitive configuration parameters (`token`, `password`, and `azure_client_secret`) are redacted and replaced with `***REDACTED***` ([#821](https://github.com/databrickslabs/terraform-provider-databricks/issues/821)).
67
* Improved documentation with regards to public subnets in AWS quick start ([#1005](https://github.com/databrickslabs/terraform-provider-databricks/pull/1005)).
78
* Added `databricks_mount` code genration for [exporter](https://registry.terraform.io/providers/databrickslabs/databricks/latest/docs/guides/experimental-exporter) tooling ([#1006](https://github.com/databrickslabs/terraform-provider-databricks/pull/1006)).

docs/resources/mlflow_experiment.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ This resource allows you to create MLflow experiments in Databricks.
88
## Example Usage
99

1010
```hcl
11-
resource "databricks_mlflow_experiment" "test" {
12-
name = "/Users/myuserid/my-experiment"
11+
data "databricks_current_user" "me" {}
12+
13+
resource "databricks_mlflow_experiment" "this" {
14+
name = "${data.databricks_current_user.me.home}/Sample"
1315
artifact_location = "dbfs:/tmp/my-experiment"
1416
description = "My MLflow experiment description"
1517
}
@@ -22,3 +24,7 @@ The following arguments are supported:
2224
* `name` - (Required) Name of MLflow experiment. It must be an absolute path within the Databricks workspace, e.g. `/Users/<some-username>/my-experiment`. For more information about changes to experiment naming conventions, see [mlflow docs](https://docs.databricks.com/applications/mlflow/experiments.html#experiment-migration).
2325
* `artifact_location` - Path to dbfs:/ or s3:// artifact location of the MLflow experiment.
2426
* `description` - The description of the MLflow experiment.
27+
28+
## Access Control
29+
30+
* [databricks_permissions](permissions.md#MLflow-Experiment-usage) can control which groups or individual users can *Read*, *Edit*, or *Manage* individual experiments.

docs/resources/mlflow_model.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ resource "databricks_mlflow_model" "test" {
2828

2929
The following arguments are supported:
3030

31-
* `name` - (Required) Name of MLflow model.
31+
* `name` - (Required) Name of MLflow model. Change of name triggers new resource.
3232
* `description` - The description of the MLflow model.
3333
* `tags` - Tags for the MLflow model.
34+
35+
## Access Control
36+
37+
* [databricks_permissions](permissions.md#MLflow-Model-usage) can control which groups or individual users can *Read*, *Edit*, *Manage Staging Versions*, *Manage Production Versions*, and *Manage* individual models.

docs/resources/permissions.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,84 @@ resource "databricks_permissions" "repo_usage" {
330330
}
331331
```
332332

333+
## MLflow Experiment usage
334+
335+
Valid [permission levels](https://docs.databricks.com/security/access-control/workspace-acl.html#mlflow-experiment-permissions-1) for [databricks_mlflow_experiment](mlflow_experiment.md) are: `CAN_READ`, `CAN_EDIT`, and `CAN_MANAGE`.
336+
337+
```hcl
338+
data "databricks_current_user" "me" {}
339+
340+
resource "databricks_mlflow_experiment" "this" {
341+
name = "${data.databricks_current_user.me.home}/Sample"
342+
artifact_location = "dbfs:/tmp/my-experiment"
343+
description = "My MLflow experiment description"
344+
}
345+
346+
resource "databricks_group" "auto" {
347+
display_name = "Automation"
348+
}
349+
350+
resource "databricks_group" "eng" {
351+
display_name = "Engineering"
352+
}
353+
354+
resource "databricks_permissions" "experiment_usage" {
355+
experiment_id = databricks_mlflow_experiment.this.id
356+
357+
access_control {
358+
group_name = "users"
359+
permission_level = "CAN_READ"
360+
}
361+
362+
access_control {
363+
group_name = databricks_group.auto.display_name
364+
permission_level = "CAN_MANAGE"
365+
}
366+
367+
access_control {
368+
group_name = databricks_group.eng.display_name
369+
permission_level = "CAN_EDIT"
370+
}
371+
}
372+
```
373+
374+
## MLflow Model usage
375+
376+
Valid [permission levels](https://docs.databricks.com/security/access-control/workspace-acl.html#mlflow-model-permissions-1) for [databricks_mlflow_model](mlflow_model.md) are: `CAN_READ`, `CAN_EDIT`, `CAN_MANAGE_STAGING_VERSIONS`, `CAN_MANAGE_PRODUCTION_VERSIONS`, and `CAN_MANAGE`.
377+
378+
```hcl
379+
resource "databricks_mlflow_model" "this" {
380+
name = "SomePredictions"
381+
}
382+
383+
resource "databricks_group" "auto" {
384+
display_name = "Automation"
385+
}
386+
387+
resource "databricks_group" "eng" {
388+
display_name = "Engineering"
389+
}
390+
391+
resource "databricks_permissions" "model_usage" {
392+
registered_model_id = databricks_mlflow_model.this.registered_model_id
393+
394+
access_control {
395+
group_name = "users"
396+
permission_level = "CAN_READ"
397+
}
398+
399+
access_control {
400+
group_name = databricks_group.auto.display_name
401+
permission_level = "CAN_MANAGE_PRODUCTION_VERSIONS"
402+
}
403+
404+
access_control {
405+
group_name = databricks_group.eng.display_name
406+
permission_level = "CAN_MANAGE_STAGING_VERSIONS"
407+
}
408+
}
409+
```
410+
333411
## Passwords usage
334412

335413
By default on AWS deployments, all admin users can sign in to Databricks using either SSO or their username and password, and all API users can authenticate to the Databricks REST APIs using their username and password. As an admin, you [can limit](https://docs.databricks.com/administration-guide/users-groups/single-sign-on/index.html#optional-configure-password-access-control) admin users’ and API users’ ability to authenticate with their username and password by configuring `CAN_USE` permissions using password access control.

mlflow/resource_model.go

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ import (
77
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
88
)
99

10-
// Tag ...
1110
type Tag struct {
12-
Key string `json:"key" tf:"force_new"`
13-
Value string `json:"value" tf:"force_new"`
11+
Key string `json:"key"`
12+
Value string `json:"value"`
1413
}
1514

1615
// Model defines the response object from the API
@@ -21,50 +20,49 @@ type Model struct {
2120
UserID string `json:"user_id,omitempty" tf:"computed"`
2221
LatestVersions []string `json:"latest_versions,omitempty" tf:"computed"`
2322
Description string `json:"description,omitempty"`
24-
Tags []Tag `json:"tags,omitempty" tf:"force_new"`
23+
Tags []Tag `json:"tags,omitempty"`
24+
RegisteredModelID string `json:"id,omitempty" tf:"computed,alias:registered_model_id"`
2525
}
2626

2727
// registeredModel defines response from GET API op
2828
type registeredModel struct {
29-
RegisteredModel Model `json:"registered_model"`
29+
RegisteredModelDatabricks Model `json:"registered_model_databricks"`
3030
}
3131

32-
// ModelsAPI ...
3332
type ModelsAPI struct {
3433
client *common.DatabricksClient
3534
context context.Context
3635
}
3736

38-
// NewModelsAPI ...
3937
func NewModelsAPI(ctx context.Context, m interface{}) ModelsAPI {
4038
return ModelsAPI{m.(*common.DatabricksClient), ctx}
4139
}
4240

43-
// Create ...
4441
func (a ModelsAPI) Create(m *Model) error {
4542
return a.client.Post(a.context, "/mlflow/registered-models/create", m, m)
4643
}
4744

48-
// Read ...
4945
func (a ModelsAPI) Read(name string) (*Model, error) {
5046
var m registeredModel
51-
err := a.client.Get(a.context, "/mlflow/registered-models/get", map[string]string{
47+
err := a.client.Get(a.context, "/mlflow/databricks/registered-models/get", map[string]string{
5248
"name": name,
5349
}, &m)
5450
if err != nil {
5551
return nil, err
5652
}
57-
return &m.RegisteredModel, nil
53+
return &m.RegisteredModelDatabricks, nil
5854
}
5955

60-
// Update ...
56+
// Update the model entity
6157
func (a ModelsAPI) Update(m *Model) error {
6258
return a.client.Patch(a.context, "/mlflow/registered-models/update", m)
6359
}
6460

65-
// Delete ...
66-
func (a ModelsAPI) Delete(m *Model) error {
67-
return a.client.Delete(a.context, "/mlflow/registered-models/delete", m)
61+
// Delete removes the model by it's name
62+
func (a ModelsAPI) Delete(name string) error {
63+
return a.client.Delete(a.context, "/mlflow/registered-models/delete", map[string]string{
64+
"name": name,
65+
})
6866
}
6967

7068
func ResourceMLFlowModel() *schema.Resource {
@@ -98,9 +96,7 @@ func ResourceMLFlowModel() *schema.Resource {
9896
return NewModelsAPI(ctx, c).Update(&m)
9997
},
10098
Delete: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
101-
var m Model
102-
common.DataToStructPointer(d, s, &m)
103-
return NewModelsAPI(ctx, c).Delete(&m)
99+
return NewModelsAPI(ctx, c).Delete(d.Id())
104100
},
105101
Schema: s,
106102
}.ToResource()

mlflow/resource_model_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ func TestModelCreate(t *testing.T) {
2828
},
2929
{
3030
Method: "GET",
31-
Resource: "/api/2.0/mlflow/registered-models/get?name=xyz",
31+
Resource: "/api/2.0/mlflow/databricks/registered-models/get?name=xyz",
3232
Response: registeredModel{
33-
RegisteredModel: m(),
33+
RegisteredModelDatabricks: m(),
3434
},
3535
},
3636
},
@@ -89,9 +89,9 @@ func TestModelRead(t *testing.T) {
8989
Fixtures: []qa.HTTPFixture{
9090
{
9191
Method: "GET",
92-
Resource: "/api/2.0/mlflow/registered-models/get?name=xyz",
92+
Resource: "/api/2.0/mlflow/databricks/registered-models/get?name=xyz",
9393
Response: registeredModel{
94-
RegisteredModel: m(),
94+
RegisteredModelDatabricks: m(),
9595
},
9696
},
9797
},
@@ -109,9 +109,9 @@ func TestModelReadGetError(t *testing.T) {
109109
Fixtures: []qa.HTTPFixture{
110110
{
111111
Method: "GET",
112-
Resource: "/api/2.0/mlflow/registered-models/get?name=xyz",
112+
Resource: "/api/2.0/mlflow/databricks/registered-models/get?name=xyz",
113113
Response: registeredModel{
114-
RegisteredModel: m(),
114+
RegisteredModelDatabricks: m(),
115115
},
116116
Status: 400,
117117
},
@@ -138,9 +138,9 @@ func TestModelUpdate(t *testing.T) {
138138
},
139139
{
140140
Method: "GET",
141-
Resource: "/api/2.0/mlflow/registered-models/get?name=xyz",
141+
Resource: "/api/2.0/mlflow/databricks/registered-models/get?name=xyz",
142142
Response: registeredModel{
143-
RegisteredModel: gm,
143+
RegisteredModelDatabricks: gm,
144144
},
145145
},
146146
},

permissions/resource_permissions.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ func permissionsResourceIDFields() []permissionsIDFieldMapping {
246246
{"sql_dashboard_id", "dashboard", "sql/dashboards", []string{"CAN_EDIT", "CAN_RUN", "CAN_MANAGE"}, SIMPLE},
247247
{"sql_alert_id", "alert", "sql/alerts", []string{"CAN_EDIT", "CAN_RUN", "CAN_MANAGE"}, SIMPLE},
248248
{"sql_query_id", "query", "sql/queries", []string{"CAN_EDIT", "CAN_RUN", "CAN_MANAGE"}, SIMPLE},
249+
{"experiment_id", "mlflowExperiment", "experiments", []string{"CAN_READ", "CAN_EDIT", "CAN_MANAGE"}, SIMPLE},
250+
{"registered_model_id", "registered-model", "registered-models", []string{
251+
"CAN_READ", "CAN_EDIT", "CAN_MANAGE_STAGING_VERSIONS", "CAN_MANAGE_PRODUCTION_VERSIONS", "CAN_MANAGE"}, SIMPLE},
249252
}
250253
}
251254

0 commit comments

Comments
 (0)