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] Allow to match resource names by regular expression #4177

Merged
merged 4 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -61,6 +61,8 @@ All arguments are optional, and they tune what code is being generated.
* `-listing` - Comma-separated list of services to be listed and further passed on for importing. For each service specified, the exporter performs a listing of available resources using the `List` function and emits them for importing together with their dependencies. The `-services` parameter could be used to control which transitive dependencies will be also imported.
* `-services` - Comma-separated list of services to import. By default, all services are imported.
* `-match` - Match resource names during listing operation. This filter applies to all resources that are getting listed, so if you want to import all dependencies of just one cluster, specify `-match=autoscaling -listing=compute`. By default, it is empty, which matches everything.
* `-matchRegex` - Match resource names against a given regex during listing operation. Applicable to all resources selected for listing.
* `-excludeRegex` - Exclude resource names matching a given regex. Applied during the listing operation and has higher priority than `-match` and `-matchRegex`. Applicable to all resources selected for listing. Could be used to exclude things like `databricks_automl` notebooks, etc.
* `-mounts` - List DBFS mount points, an extremely slow operation that would not trigger unless explicitly specified.
* `-generateProviderDeclaration` - the flag that toggles the generation of `databricks.tf` file with the declaration of the Databricks Terraform provider that is necessary for Terraform versions since Terraform 0.13 (disabled by default).
* `-prefix` - optional prefix that will be added to the name of all exported resources - that's useful for exporting resources from multiple workspaces for merging into a single one.
Expand Down
6 changes: 6 additions & 0 deletions exporter/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@ func Run(args ...string) error {
flags.StringVar(&ic.match, "match", "", "Match resource names during listing operation. "+
"This filter applies to all resources that are getting listed, so if you want to import "+
"all dependencies of just one cluster, specify -listing=compute")
flags.StringVar(&ic.matchRegexStr, "matchRegex", "", "Match resource names during listing operation against a regex. "+
"This filter applies to all resources that are getting listed, so if you want to import "+
"all dependencies of just one cluster, specify -listing=compute")
flags.StringVar(&ic.excludeRegexStr, "excludeRegex", "", "Exclude resource names matching regex during listing operation. "+
"This filter applies to all resources that are getting listed, so if you want to import "+
"all dependencies of just one cluster, specify -listing=compute")
prefix := ""
flags.StringVar(&prefix, "prefix", "", "Prefix that will be added to the name of all exported resources")
newArgs := args
Expand Down
22 changes: 22 additions & 0 deletions exporter/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ type importContext struct {
services map[string]struct{}
listing map[string]struct{}
match string
matchRegexStr string
matchRegex *regexp.Regexp
excludeRegexStr string
excludeRegex *regexp.Regexp
lastActiveDays int64
lastActiveMs int64
generateDeclaration bool
Expand Down Expand Up @@ -297,6 +301,24 @@ func (ic *importContext) Run() error {
return fmt.Errorf("no services to import")
}

if ic.matchRegexStr != "" {
log.Printf("[DEBUG] Using regex '%s' to filter resources", ic.matchRegexStr)
re, err := regexp.Compile(ic.matchRegexStr)
if err != nil {
log.Printf("[ERROR] can't compile regex '%s': %v", ic.matchRegexStr, err)
return err
}
ic.matchRegex = re
}
if ic.excludeRegexStr != "" {
log.Printf("[DEBUG] Using regex '%s' to filter resources", ic.excludeRegexStr)
re, err := regexp.Compile(ic.excludeRegexStr)
if err != nil {
log.Printf("[ERROR] can't compile regex '%s': %v", ic.excludeRegexStr, err)
return err
}
ic.excludeRegex = re
}
if ic.incremental {
if ic.updatedSinceStr == "" {
ic.updatedSinceStr = getLastRunString(statsFileName)
Expand Down
42 changes: 40 additions & 2 deletions exporter/exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2371,10 +2371,32 @@ func TestImportingNotebooksWorkspaceFiles(t *testing.T) {
Method: "GET",
Resource: "/api/2.0/workspace/list?path=%2F",
Response: workspace.ObjectList{
Objects: []workspace.ObjectStatus{notebookStatus, fileStatus},
Objects: []workspace.ObjectStatus{notebookStatus, fileStatus,
workspace.ObjectStatus{
ObjectID: 4567,
ObjectType: workspace.Notebook,
Path: "/UnmatchedNotebook",
Language: "PYTHON",
},
workspace.ObjectStatus{
ObjectID: 1234,
ObjectType: workspace.File,
Path: "/UnmatchedFile",
},
workspace.ObjectStatus{
ObjectID: 456,
ObjectType: workspace.Directory,
Path: "/databricks_automl",
},
},
},
ReuseRequest: true,
},
{
Method: "GET",
Resource: "/api/2.0/workspace/list?path=%2Fdatabricks_automl",
Response: workspace.ObjectList{},
},
{
Method: "GET",
Resource: "/api/2.0/workspace/get-status?path=%2FNotebook",
Expand Down Expand Up @@ -2410,10 +2432,26 @@ func TestImportingNotebooksWorkspaceFiles(t *testing.T) {

ic := newImportContext(client)
ic.Directory = tmpDir
ic.enableListing("notebooks")
ic.enableListing("notebooks,wsfiles")
ic.excludeRegexStr = "databricks_automl"
ic.matchRegexStr = "^/[FN].*$"

err := ic.Run()
assert.NoError(t, err)
// check generated code for notebooks
content, err := os.ReadFile(tmpDir + "/notebooks.tf")
assert.NoError(t, err)
contentStr := string(content)
assert.True(t, strings.Contains(contentStr, `resource "databricks_notebook" "notebook_456"`))
assert.True(t, strings.Contains(contentStr, `path = "/Notebook"`))
assert.False(t, strings.Contains(contentStr, `/UnmatchedNotebook`))
// check generated code for workspace files
content, err = os.ReadFile(tmpDir + "/wsfiles.tf")
assert.NoError(t, err)
contentStr = string(content)
assert.True(t, strings.Contains(contentStr, `resource "databricks_workspace_file" "file_123"`))
assert.True(t, strings.Contains(contentStr, `path = "/File"`))
assert.False(t, strings.Contains(contentStr, `/UnmatchedFile`))
})
}

Expand Down
8 changes: 7 additions & 1 deletion exporter/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,15 @@ func (ic *importContext) isServiceInListing(service string) bool {
}

func (ic *importContext) MatchesName(n string) bool {
if ic.match == "" {
if ic.match == "" && ic.matchRegex == nil && ic.excludeRegex == nil {
return true
}
if ic.excludeRegex != nil && ic.excludeRegex.MatchString(n) {
return false
}
if ic.matchRegex != nil {
return ic.matchRegex.MatchString(n)
}
return strings.Contains(strings.ToLower(n), strings.ToLower(ic.match))
}

Expand Down
Loading