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

Exporter: add support for databricks_artifact_allowlist #3083

Merged
merged 1 commit into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions docs/guides/experimental-exporter.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Services are just logical groups of resources used for filtering and organizatio
* `sql-endpoints` - **listing** [databricks_sql_endpoint](../resources/sql_endpoint.md) along with [databricks_sql_global_config](../resources/sql_global_config.md).
* `sql-queries` - **listing** [databricks_sql_query](../resources/sql_query.md).
* `storage` - only [databricks_dbfs_file](../resources/dbfs_file.md) referenced in other resources (libraries, init scripts, ...) will be downloaded locally and properly arranged into terraform state.
* `uc-artifact-allowlist` - exports [databricks_artifact_allowlist](../resources/artifact_allowlist.md) resources for Unity Catalog Allow Lists attached to the current metastore.
* `uc-system-schemas` - exports [databricks_system_schema](../resources/system_schema.md) resources for the UC metastore of the current workspace.
* `users` - [databricks_user](../resources/user.md) and [databricks_service_principal](../resources/service_principal.md) are written to their own file, simply because of their amount. If you use SCIM provisioning, migrating workspaces is the only use case for importing `users` service.
* `workspace` - [databricks_workspace_conf](../resources/workspace_conf.md) and [databricks_global_init_script](../resources/global_init_script.md)
Expand All @@ -101,6 +102,7 @@ Exporter aims to generate HCL code for most of the resources within the Databric
| Resource | Generated code | Incremental |
| --- | --- | --- |
| [databricks_access_control_rule_set](../resources/access_control_rule_set.md) | Yes | No |
| [databricks_artifact_allowlist](../resources/artifact_allowlist.md) | Yes | No |
| [databricks_cluster](../resources/cluster.md) | Yes | No |
| [databricks_cluster_policy](../resources/cluster_policy.md) | Yes | No |
| [databricks_dbfs_file](../resources/dbfs_file.md) | Yes | No |
Expand Down
10 changes: 10 additions & 0 deletions exporter/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"time"

"github.com/databricks/databricks-sdk-go"
"github.com/databricks/databricks-sdk-go/service/catalog"
"github.com/databricks/databricks-sdk-go/service/compute"

"github.com/databricks/terraform-provider-databricks/commands"
Expand Down Expand Up @@ -140,6 +141,9 @@ type importContext struct {

builtInPolicies map[string]compute.PolicyFamily
builtInPoliciesMutex sync.Mutex

// Workspace-level UC Metastore information
currentMetastore *catalog.GetMetastoreSummaryResponse
}

type mount struct {
Expand Down Expand Up @@ -321,6 +325,12 @@ func (ic *importContext) Run() error {
break
}
}
currentMetastore, err := ic.workspaceClient.Metastores.Summary(ic.Context)
if err == nil {
ic.currentMetastore = currentMetastore
} else {
log.Printf("[WARN] can't get current UC metastore: %v", err)
}
}
// Concurrent execution part
if ic.waitGroup == nil {
Expand Down
27 changes: 27 additions & 0 deletions exporter/exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"time"

"github.com/databricks/databricks-sdk-go/apierr"
"github.com/databricks/databricks-sdk-go/service/catalog"
"github.com/databricks/databricks-sdk-go/service/compute"
"github.com/databricks/databricks-sdk-go/service/iam"
sdk_jobs "github.com/databricks/databricks-sdk-go/service/jobs"
Expand Down Expand Up @@ -382,6 +383,18 @@ var noCurrentMetastoreAttached = qa.HTTPFixture{
ReuseRequest: true,
}

var currentMetastoreResponse = &catalog.GetMetastoreSummaryResponse{
MetastoreId: "12345678-1234",
Name: "test",
}

var currentMetastoreSuccess = qa.HTTPFixture{
Method: "GET",
Resource: "/api/2.1/unity-catalog/metastore_summary",
Response: currentMetastoreResponse,
ReuseRequest: true,
}

func TestImportingUsersGroupsSecretScopes(t *testing.T) {
listSpFixtures := qa.ListServicePrincipalsFixtures([]iam.ServicePrincipal{
{
Expand Down Expand Up @@ -723,6 +736,7 @@ func TestImportingClusters(t *testing.T) {
qa.HTTPFixturesApply(t,
[]qa.HTTPFixture{
meAdminFixture,
noCurrentMetastoreAttached,
emptyRepos,
{
Method: "GET",
Expand Down Expand Up @@ -1402,6 +1416,7 @@ func TestImportingSecrets(t *testing.T) {
qa.HTTPFixturesApply(t,
[]qa.HTTPFixture{
meAdminFixture,
noCurrentMetastoreAttached,
emptyRepos,
{
Method: "GET",
Expand Down Expand Up @@ -1485,6 +1500,7 @@ func TestImportingGlobalInitScripts(t *testing.T) {
qa.HTTPFixturesApply(t,
[]qa.HTTPFixture{
meAdminFixture,
noCurrentMetastoreAttached,
emptyRepos,
emptyWorkspaceConf,
dummyWorkspaceConf,
Expand Down Expand Up @@ -1587,6 +1603,7 @@ func TestImportingRepos(t *testing.T) {
qa.HTTPFixturesApply(t,
[]qa.HTTPFixture{
meAdminFixture,
noCurrentMetastoreAttached,
userListIdUsernameFixture,
userListIdUsernameFixture2,
userListFixture,
Expand Down Expand Up @@ -1641,6 +1658,7 @@ func TestImportingIPAccessLists(t *testing.T) {
qa.HTTPFixturesApply(t,
[]qa.HTTPFixture{
meAdminFixture,
noCurrentMetastoreAttached,
emptyRepos,
emptyWorkspaceConf,
dummyWorkspaceConf,
Expand Down Expand Up @@ -1700,6 +1718,7 @@ func TestImportingSqlObjects(t *testing.T) {
qa.HTTPFixturesApply(t,
[]qa.HTTPFixture{
meAdminFixture,
noCurrentMetastoreAttached,
emptyRepos,
emptyIpAccessLIst,
emptyGlobalSQLConfig,
Expand Down Expand Up @@ -1838,6 +1857,7 @@ func TestImportingDLTPipelines(t *testing.T) {
qa.HTTPFixturesApply(t,
[]qa.HTTPFixture{
meAdminFixture,
noCurrentMetastoreAttached,
emptyRepos,
emptyWorkspace,
emptyIpAccessLIst,
Expand Down Expand Up @@ -2013,6 +2033,7 @@ func TestImportingDLTPipelinesMatchingOnly(t *testing.T) {
qa.HTTPFixturesApply(t,
[]qa.HTTPFixture{
meAdminFixture,
noCurrentMetastoreAttached,
emptyRepos,
emptyIpAccessLIst,
userListIdUsernameFixture,
Expand Down Expand Up @@ -2070,6 +2091,7 @@ func TestImportingGlobalSqlConfig(t *testing.T) {
qa.HTTPFixturesApply(t,
[]qa.HTTPFixture{
meAdminFixture,
noCurrentMetastoreAttached,
{
Method: "GET",
Resource: "/api/2.0/sql/warehouses",
Expand Down Expand Up @@ -2113,6 +2135,7 @@ func TestImportingNotebooksWorkspaceFiles(t *testing.T) {
qa.HTTPFixturesApply(t,
[]qa.HTTPFixture{
meAdminFixture,
noCurrentMetastoreAttached,
emptyRepos,
emptyIpAccessLIst,
{
Expand Down Expand Up @@ -2165,6 +2188,7 @@ func TestImportingModelServing(t *testing.T) {
qa.HTTPFixturesApply(t,
[]qa.HTTPFixture{
meAdminFixture,
noCurrentMetastoreAttached,
emptyRepos,
emptyIpAccessLIst,
emptyWorkspace,
Expand Down Expand Up @@ -2215,6 +2239,7 @@ func TestImportingMlfloweWebhooks(t *testing.T) {
qa.HTTPFixturesApply(t,
[]qa.HTTPFixture{
meAdminFixture,
noCurrentMetastoreAttached,
emptyRepos,
emptyIpAccessLIst,
emptyWorkspace,
Expand Down Expand Up @@ -2308,6 +2333,7 @@ func TestIncrementalDLTAndMLflowWebhooks(t *testing.T) {
qa.HTTPFixturesApply(t,
[]qa.HTTPFixture{
meAdminFixture,
noCurrentMetastoreAttached,
emptyRepos,
emptyIpAccessLIst,
emptyWorkspace,
Expand Down Expand Up @@ -2418,6 +2444,7 @@ func TestImportingRunJobTask(t *testing.T) {
qa.HTTPFixturesApply(t,
[]qa.HTTPFixture{
meAdminFixture,
noCurrentMetastoreAttached,
emptyRepos,
emptyIpAccessLIst,
emptyWorkspace,
Expand Down
28 changes: 24 additions & 4 deletions exporter/importables.go
Original file line number Diff line number Diff line change
Expand Up @@ -2165,11 +2165,10 @@ var resourcesMap map[string]importable = map[string]importable{
WorkspaceLevel: true,
Service: "uc-system-schemas",
List: func(ic *importContext) error {
summary, err := ic.workspaceClient.Metastores.Summary(ic.Context)
if err != nil {
return err
if ic.currentMetastore == nil {
return fmt.Errorf("there is no UC metastore information")
}
currentMetastore := summary.MetastoreId
currentMetastore := ic.currentMetastore.MetastoreId
systemSchemas, err := ic.workspaceClient.SystemSchemas.ListAll(ic.Context,
catalog.ListSystemSchemasRequest{MetastoreId: currentMetastore})
if err != nil {
Expand Down Expand Up @@ -2199,4 +2198,25 @@ var resourcesMap map[string]importable = map[string]importable{
return nil
},
},
"databricks_artifact_allowlist": {
WorkspaceLevel: true,
Service: "uc-artifact-allowlist",
List: func(ic *importContext) error {
if ic.currentMetastore == nil {
return fmt.Errorf("there is no UC metastore information")
}
artifactTypes := []string{"INIT_SCRIPT", "LIBRARY_JAR", "LIBRARY_MAVEN"}
for _, v := range artifactTypes {
id := fmt.Sprintf("%s|%s", ic.currentMetastore.MetastoreId, v)
name := fmt.Sprintf("%s_%s_%s", v, ic.currentMetastore.Name, ic.currentMetastore.MetastoreId[:8])
ic.Emit(&resource{
Resource: "databricks_artifact_allowlist",
ID: id,
Name: nameNormalizationRegex.ReplaceAllString(name, "_"),
})
}
return nil
},
// TODO: add Depends & Import to emit corresponding UC Volumes when support for them is added
},
}
40 changes: 21 additions & 19 deletions exporter/importables_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1297,21 +1297,12 @@ func TestIncrementalListDLT(t *testing.T) {
})
}

var currentMetastoreSuccess = qa.HTTPFixture{
Method: "GET",
Resource: "/api/2.1/unity-catalog/metastore_summary",
Response: catalog.GetMetastoreSummaryResponse{
MetastoreId: "1234",
},
ReuseRequest: true,
}

func TestListSystemSchemasSuccess(t *testing.T) {
qa.HTTPFixturesApply(t, []qa.HTTPFixture{
currentMetastoreSuccess,
{
Method: "GET",
Resource: "/api/2.1/unity-catalog/metastores/1234/systemschemas?",
Resource: fmt.Sprintf("/api/2.1/unity-catalog/metastores/%s/systemschemas?", currentMetastoreResponse.MetastoreId),
Response: catalog.ListSystemSchemasResponse{
Schemas: []catalog.SystemSchemaInfo{
{
Expand All @@ -1327,34 +1318,45 @@ func TestListSystemSchemasSuccess(t *testing.T) {
},
}, func(ctx context.Context, client *common.DatabricksClient) {
ic := importContextForTestWithClient(ctx, client)
ic.currentMetastore = currentMetastoreResponse
err := resourcesMap["databricks_system_schema"].List(ic)
assert.NoError(t, err)
assert.Equal(t, len(ic.testEmits), 1)
})
}

func TestListSystemSchemasErrorGetMetastore(t *testing.T) {
qa.HTTPFixturesApply(t, []qa.HTTPFixture{
noCurrentMetastoreAttached,
}, func(ctx context.Context, client *common.DatabricksClient) {
ic := importContextForTestWithClient(ctx, client)
err := resourcesMap["databricks_system_schema"].List(ic)
assert.EqualError(t, err, "nope")
})
ic := importContextForTest()
err := resourcesMap["databricks_system_schema"].List(ic)
assert.EqualError(t, err, "there is no UC metastore information")
}

func TestListSystemSchemasErrorListing(t *testing.T) {
qa.HTTPFixturesApply(t, []qa.HTTPFixture{
currentMetastoreSuccess,
{
Method: "GET",
Resource: "/api/2.1/unity-catalog/metastores/1234/systemschemas?",
Resource: fmt.Sprintf("/api/2.1/unity-catalog/metastores/%s/systemschemas?", currentMetastoreResponse.MetastoreId),
Status: 404,
Response: apierr.NotFound("nope"),
},
}, func(ctx context.Context, client *common.DatabricksClient) {
ic := importContextForTestWithClient(ctx, client)
ic.currentMetastore = currentMetastoreResponse
err := resourcesMap["databricks_system_schema"].List(ic)
assert.EqualError(t, err, "nope")
})
}

func TestListUcAllowListError(t *testing.T) {
ic := importContextForTest()
err := resourcesMap["databricks_artifact_allowlist"].List(ic)
assert.EqualError(t, err, "there is no UC metastore information")
}

func TestListUcAllowListSuccess(t *testing.T) {
ic := importContextForTest()
ic.currentMetastore = currentMetastoreResponse
err := resourcesMap["databricks_artifact_allowlist"].List(ic)
assert.NoError(t, err)
assert.Equal(t, len(ic.testEmits), 3)
}
Loading