Skip to content
Open
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
9 changes: 4 additions & 5 deletions bundle/direct/dresources/all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,20 +405,19 @@ var testDeps = map[string]prepareWorkspace{
},

"postgres_projects.permissions": func(ctx context.Context, client *databricks.WorkspaceClient) (any, error) {
const projectID = "permissions-project"
waiter, err := client.Postgres.CreateProject(ctx, postgres.CreateProjectRequest{
ProjectId: "permissions-project",
ProjectId: projectID,
})
if err != nil {
return nil, err
}
result, err := waiter.Wait(ctx)
if err != nil {
if _, err := waiter.Wait(ctx); err != nil {
return nil, err
}

components, _ := ParsePostgresName(result.Name)
return &PermissionsState{
ObjectID: "/database-projects/" + components.ProjectID,
ObjectID: "/database-projects/" + projectID,
EmbeddedSlice: []StatePermission{{
Level: "CAN_MANAGE",
UserName: "user@example.com",
Expand Down
9 changes: 5 additions & 4 deletions bundle/direct/dresources/postgres_branch.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,17 @@ func (*ResourcePostgresBranch) RemapState(remote *PostgresBranchRemote) *Postgre
// stay at their zero values, and resources.yml suppresses phantom drift via
// ignore_remote_changes with reason spec:input_only.
func makePostgresBranchRemote(branch *postgres.Branch) *PostgresBranchRemote {
// Extract branch_id from hierarchical name: "projects/{project_id}/branches/{branch_id}"
// TODO: log error when we have access to the context
components, _ := ParsePostgresName(branch.Name)
var spec postgres.BranchSpec
if branch.Spec != nil {
spec = *branch.Spec
}
var branchID string
if branch.Status != nil {
branchID = branch.Status.BranchId
}
return &PostgresBranchRemote{
BranchSpec: spec,
BranchId: components.BranchID,
BranchId: branchID,
Parent: branch.Parent,
Name: branch.Name,
Status: branch.Status,
Expand Down
9 changes: 5 additions & 4 deletions bundle/direct/dresources/postgres_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,17 @@ func (*ResourcePostgresEndpoint) RemapState(remote *PostgresEndpointRemote) *Pos
// stay at their zero values, and resources.yml suppresses phantom drift via
// ignore_remote_changes with reason spec:input_only.
func makePostgresEndpointRemote(endpoint *postgres.Endpoint) *PostgresEndpointRemote {
// Extract endpoint_id from hierarchical name: "projects/{project_id}/branches/{branch_id}/endpoints/{endpoint_id}"
// TODO: log error when we have access to the context
components, _ := ParsePostgresName(endpoint.Name)
var spec postgres.EndpointSpec
if endpoint.Spec != nil {
spec = *endpoint.Spec
}
var endpointID string
if endpoint.Status != nil {
endpointID = endpoint.Status.EndpointId
}
return &PostgresEndpointRemote{
EndpointSpec: spec,
EndpointId: components.EndpointID,
EndpointId: endpointID,
Parent: endpoint.Parent,
Name: endpoint.Name,
Status: endpoint.Status,
Expand Down
9 changes: 5 additions & 4 deletions bundle/direct/dresources/postgres_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,17 @@ func (*ResourcePostgresProject) RemapState(remote *PostgresProjectRemote) *Postg
// stay at their zero values, and resources.yml suppresses phantom drift via
// ignore_remote_changes with reason spec:input_only.
func makePostgresProjectRemote(project *postgres.Project) *PostgresProjectRemote {
// Extract project_id from hierarchical name: "projects/{project_id}"
// TODO: log error when we have access to the context
components, _ := ParsePostgresName(project.Name)
var spec postgres.ProjectSpec
if project.Spec != nil {
spec = *project.Spec
}
var projectID string
if project.Status != nil {
projectID = project.Status.ProjectId
}
return &PostgresProjectRemote{
ProjectSpec: spec,
ProjectId: components.ProjectID,
ProjectId: projectID,
InitialEndpointSpec: project.InitialEndpointSpec,
Name: project.Name,
Status: project.Status,
Expand Down
30 changes: 0 additions & 30 deletions bundle/direct/dresources/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,12 @@ package dresources

import (
"errors"
"fmt"
"regexp"

"github.com/databricks/cli/bundle/deployplan"
"github.com/databricks/cli/libs/structs/structpath"
"github.com/databricks/databricks-sdk-go/retries"
)

// postgresNamePattern matches hierarchical Postgres resource names:
// - projects/{project_id}
// - projects/{project_id}/branches/{branch_id}
// - projects/{project_id}/branches/{branch_id}/endpoints/{endpoint_id}
var postgresNamePattern = regexp.MustCompile(`^projects/([^/]+)(?:/branches/([^/]+)(?:/endpoints/([^/]+))?)?$`)

// PostgresNameComponents holds the extracted components from a Postgres resource name.
type PostgresNameComponents struct {
ProjectID string
BranchID string
EndpointID string
}

// ParsePostgresName extracts project, branch, and endpoint IDs from a hierarchical Postgres resource name.
// Returns an error if the name doesn't match the expected format.
func ParsePostgresName(name string) (PostgresNameComponents, error) {
matches := postgresNamePattern.FindStringSubmatch(name)
if matches == nil {
return PostgresNameComponents{}, fmt.Errorf("invalid postgres resource name format: %q", name)
}

return PostgresNameComponents{
ProjectID: matches[1],
BranchID: matches[2],
EndpointID: matches[3],
}, nil
}

// This is copied from the retries package of the databricks-sdk-go. It should be made public,
// but for now, I'm copying it here.
func shouldRetry(err error) bool {
Expand Down
92 changes: 0 additions & 92 deletions bundle/direct/dresources/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// assertFieldsCovered asserts that all fields in sdkType (except those in skip)
Expand All @@ -29,94 +28,3 @@ func assertFieldsCovered(t *testing.T, sdkType, remoteType reflect.Type, skip ma
assert.Contains(t, remoteFields, field.Name, "field %s from %s is missing in %s", field.Name, sdkType.Name(), remoteType.Name())
}
}

func TestParsePostgresName(t *testing.T) {
tests := []struct {
name string
input string
projectID string
branchID string
endpointID string
expectErr bool
}{
{
name: "project",
input: "projects/my-project",
projectID: "my-project",
},
{
name: "branch",
input: "projects/my-project/branches/my-branch",
projectID: "my-project",
branchID: "my-branch",
},
{
name: "endpoint",
input: "projects/my-project/branches/my-branch/endpoints/my-endpoint",
projectID: "my-project",
branchID: "my-branch",
endpointID: "my-endpoint",
},
{
name: "with hyphens and numbers",
input: "projects/my-app-123/branches/dev-branch/endpoints/primary-1",
projectID: "my-app-123",
branchID: "dev-branch",
endpointID: "primary-1",
},
{
name: "empty",
input: "",
expectErr: true,
},
{
name: "no prefix",
input: "my-project",
expectErr: true,
},
{
name: "wrong prefix",
input: "project/my-project",
expectErr: true,
},
{
name: "missing branch id",
input: "projects/my-project/branches/",
expectErr: true,
},
{
name: "missing endpoint id",
input: "projects/my-project/branches/my-branch/endpoints/",
expectErr: true,
},
{
name: "extra segments",
input: "projects/my-project/branches/my-branch/endpoints/my-endpoint/extra",
expectErr: true,
},
{
name: "branches without branch",
input: "projects/my-project/branches",
expectErr: true,
},
{
name: "endpoints without endpoint",
input: "projects/my-project/branches/my-branch/endpoints",
expectErr: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
components, err := ParsePostgresName(tt.input)
if tt.expectErr {
assert.ErrorContains(t, err, "invalid postgres resource name format")
return
}
require.NoError(t, err)
assert.Equal(t, tt.projectID, components.ProjectID)
assert.Equal(t, tt.branchID, components.BranchID)
assert.Equal(t, tt.endpointID, components.EndpointID)
})
}
}
Loading