mirror of https://github.com/databricks/cli.git
Refactor
This commit is contained in:
parent
7fff4bcb39
commit
c222ba344f
|
@ -3,7 +3,6 @@ package permissions
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/databricks/cli/bundle"
|
||||
|
@ -142,38 +141,3 @@ func ReportPermissionDenied(ctx context.Context, b *bundle.Bundle, path string)
|
|||
ID: diag.CannotChangePathPermissions,
|
||||
}}
|
||||
}
|
||||
|
||||
func TryExtendTerraformPermissionError(ctx context.Context, b *bundle.Bundle, err error) diag.Diagnostics {
|
||||
_, assistance := analyzeBundlePermissions(b)
|
||||
|
||||
// In a best-effort attempt to provide actionable error messages, we match
|
||||
// against a few specific error messages that come from the Jobs and Pipelines API.
|
||||
// For matching errors we provide a more specific error message that includes
|
||||
// details on how to resolve the issue.
|
||||
if !strings.Contains(err.Error(), "cannot update permissions") &&
|
||||
!strings.Contains(err.Error(), "permissions on pipeline") &&
|
||||
!strings.Contains(err.Error(), "cannot read permissions") &&
|
||||
!strings.Contains(err.Error(), "annot set run_as to user") {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Errorf(ctx, "Terraform error during deployment: %v", err.Error())
|
||||
|
||||
// Best-effort attempt to extract the resource name from the error message.
|
||||
re := regexp.MustCompile(`databricks_(\w*)\.(\w*)`)
|
||||
match := re.FindStringSubmatch(err.Error())
|
||||
resource := "resource"
|
||||
if len(match) > 1 {
|
||||
resource = match[2]
|
||||
}
|
||||
|
||||
return diag.Diagnostics{{
|
||||
Summary: fmt.Sprintf("permission denied creating or updating %s.\n"+
|
||||
"%s\n"+
|
||||
"They can redeploy the project to apply the latest set of permissions.\n"+
|
||||
"Please refer to https://docs.databricks.com/dev-tools/bundles/permissions.html for more on managing permissions.",
|
||||
resource, assistance),
|
||||
Severity: diag.Error,
|
||||
ID: diag.ResourcePermissionDenied,
|
||||
}}
|
||||
}
|
||||
|
|
|
@ -1,145 +1,81 @@
|
|||
package permissions
|
||||
package permissions_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/databricks/cli/bundle"
|
||||
"github.com/databricks/cli/bundle/config"
|
||||
"github.com/databricks/cli/bundle/config/resources"
|
||||
"github.com/databricks/cli/bundle/permissions"
|
||||
"github.com/databricks/cli/libs/diag"
|
||||
"github.com/databricks/databricks-sdk-go/service/iam"
|
||||
"github.com/databricks/databricks-sdk-go/service/jobs"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestApplySuccess(t *testing.T) {
|
||||
func TestPermissionDiagnosticsApplySuccess(t *testing.T) {
|
||||
b := mockBundle([]resources.Permission{
|
||||
{Level: "CAN_MANAGE", UserName: "testuser@databricks.com"},
|
||||
})
|
||||
|
||||
diags := PermissionDiagnostics().Apply(context.Background(), b)
|
||||
diags := permissions.PermissionDiagnostics().Apply(context.Background(), b)
|
||||
require.NoError(t, diags.Error())
|
||||
}
|
||||
|
||||
func TestApplyFail(t *testing.T) {
|
||||
func TestPermissionDiagnosticsApplyFail(t *testing.T) {
|
||||
b := mockBundle([]resources.Permission{
|
||||
{Level: "CAN_VIEW", UserName: "testuser@databricks.com"},
|
||||
})
|
||||
|
||||
diags := PermissionDiagnostics().Apply(context.Background(), b)
|
||||
diags := permissions.PermissionDiagnostics().Apply(context.Background(), b)
|
||||
require.Equal(t, diags[0].Severity, diag.Warning)
|
||||
require.Contains(t, diags[0].Summary, "testuser@databricks.com")
|
||||
}
|
||||
|
||||
func TestApplySuccessWithOwner(t *testing.T) {
|
||||
func TestPermissionDiagnosticsApplySuccessWithOwner(t *testing.T) {
|
||||
b := mockBundle([]resources.Permission{
|
||||
{Level: "IS_OWNER", UserName: "testuser@databricks.com"},
|
||||
})
|
||||
|
||||
diags := PermissionDiagnostics().Apply(context.Background(), b)
|
||||
diags := permissions.PermissionDiagnostics().Apply(context.Background(), b)
|
||||
require.Empty(t, diags)
|
||||
}
|
||||
|
||||
func TestPermissionDeniedWithPermission(t *testing.T) {
|
||||
func TestPermissionDiagnosticsPermissionDeniedWithPermission(t *testing.T) {
|
||||
b := mockBundle([]resources.Permission{
|
||||
{Level: "CAN_MANAGE", GroupName: "testgroup"},
|
||||
})
|
||||
|
||||
diags := ReportPermissionDenied(context.Background(), b, "testpath")
|
||||
diags := permissions.ReportPermissionDenied(context.Background(), b, "testpath")
|
||||
require.ErrorContains(t, diags.Error(), string(diag.CannotChangePathPermissions))
|
||||
}
|
||||
|
||||
func TestPermissionDeniedWithoutPermission(t *testing.T) {
|
||||
func TestPermissionDiagnosticsPermissionDeniedWithoutPermission(t *testing.T) {
|
||||
b := mockBundle([]resources.Permission{
|
||||
{Level: "CAN_VIEW", UserName: "testuser@databricks.com"},
|
||||
})
|
||||
|
||||
diags := ReportPermissionDenied(context.Background(), b, "testpath")
|
||||
diags := permissions.ReportPermissionDenied(context.Background(), b, "testpath")
|
||||
require.ErrorContains(t, diags.Error(), string(diag.PathPermissionDenied))
|
||||
}
|
||||
|
||||
func TestPermissionDeniedNilPermission(t *testing.T) {
|
||||
func TestPermissionDiagnosticsPermissionDeniedNilPermission(t *testing.T) {
|
||||
b := mockBundle(nil)
|
||||
|
||||
diags := ReportPermissionDenied(context.Background(), b, "testpath")
|
||||
diags := permissions.ReportPermissionDenied(context.Background(), b, "testpath")
|
||||
require.ErrorContains(t, diags.Error(), string(diag.PathPermissionDenied))
|
||||
}
|
||||
|
||||
func TestFindOtherOwners(t *testing.T) {
|
||||
func TestPermissionDiagnosticsFindOtherOwners(t *testing.T) {
|
||||
b := mockBundle([]resources.Permission{
|
||||
{Level: "CAN_MANAGE", GroupName: "testgroup"},
|
||||
{Level: "CAN_MANAGE", UserName: "alice@databricks.com"},
|
||||
})
|
||||
|
||||
diags := ReportPermissionDenied(context.Background(), b, "testpath")
|
||||
diags := permissions.ReportPermissionDenied(context.Background(), b, "testpath")
|
||||
require.ErrorContains(t, diags.Error(), "include: alice@databricks.com")
|
||||
}
|
||||
|
||||
func TestReportTerraformError1(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
b := mockBundle([]resources.Permission{
|
||||
{Level: "CAN_MANAGE", UserName: "alice@databricks.com"},
|
||||
})
|
||||
err := TryExtendTerraformPermissionError(ctx, b, errors.New(`Error: terraform apply: exit status 1
|
||||
|
||||
Error: cannot update permissions: ...
|
||||
|
||||
with databricks_pipeline.my_project_pipeline,
|
||||
on bundle.tf.json line 39, in resource.databricks_pipeline.my_project_pipeline:
|
||||
39: }`)).Error()
|
||||
require.ErrorContains(t, err, string(diag.ResourcePermissionDenied))
|
||||
}
|
||||
|
||||
func TestReportTerraformError2(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
b := mockBundle([]resources.Permission{
|
||||
{Level: "CAN_MANAGE", UserName: "alice@databricks.com"},
|
||||
})
|
||||
err := TryExtendTerraformPermissionError(ctx, b, errors.New(`Error: terraform apply: exit status 1
|
||||
|
||||
Error: cannot read pipeline: User xyz does not have View permissions on pipeline 4521dbb6-42aa-418c-b94d-b5f4859a3454.
|
||||
|
||||
with databricks_pipeline.my_project_pipeline,
|
||||
on bundle.tf.json line 39, in resource.databricks_pipeline.my_project_pipeline:
|
||||
39: }`)).Error()
|
||||
require.ErrorContains(t, err, string(diag.ResourcePermissionDenied))
|
||||
}
|
||||
|
||||
func TestReportTerraformError3(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
b := mockBundle([]resources.Permission{
|
||||
{Level: "CAN_MANAGE", UserName: "alice@databricks.com"},
|
||||
})
|
||||
err := TryExtendTerraformPermissionError(ctx, b, errors.New(`Error: terraform apply: exit status 1
|
||||
|
||||
Error: cannot read permissions: 1706906c-c0a2-4c25-9f57-3a7aa3cb8b90 does not have Owner permissions on Job with ID: ElasticJobId(28263044278868). Please contact the owner or an administrator for access.
|
||||
|
||||
with databricks_pipeline.my_project_pipeline,
|
||||
on bundle.tf.json line 39, in resource.databricks_pipeline.my_project_pipeline:
|
||||
39: }`)).Error()
|
||||
require.ErrorContains(t, err, string(diag.ResourcePermissionDenied))
|
||||
}
|
||||
|
||||
func TestReportTerraformErrorNotOwner(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
b := mockBundle([]resources.Permission{
|
||||
{Level: "CAN_MANAGE", UserName: "alice@databricks.com"},
|
||||
})
|
||||
b.Config.RunAs = &jobs.JobRunAs{
|
||||
UserName: "testuser@databricks.com",
|
||||
}
|
||||
err := TryExtendTerraformPermissionError(ctx, b, errors.New(`Error: terraform apply: exit status 1
|
||||
|
||||
Error: cannot read pipeline: User xyz does not have View permissions on pipeline 4521dbb6-42aa-418c-b94d-b5f4859a3454.
|
||||
|
||||
with databricks_pipeline.my_project_pipeline,
|
||||
on bundle.tf.json line 39, in resource.databricks_pipeline.my_project_pipeline:
|
||||
39: }`)).Error()
|
||||
require.ErrorContains(t, err, string(diag.ResourcePermissionDenied))
|
||||
}
|
||||
|
||||
func mockBundle(permissions []resources.Permission) *bundle.Bundle {
|
||||
return &bundle.Bundle{
|
||||
Config: config.Root{
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package permissions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/databricks/cli/bundle"
|
||||
"github.com/databricks/cli/libs/diag"
|
||||
"github.com/databricks/cli/libs/log"
|
||||
)
|
||||
|
||||
func TryExtendTerraformPermissionError(ctx context.Context, b *bundle.Bundle, err error) diag.Diagnostics {
|
||||
_, assistance := analyzeBundlePermissions(b)
|
||||
|
||||
// In a best-effort attempt to provide actionable error messages, we match
|
||||
// against a few specific error messages that come from the Jobs and Pipelines API.
|
||||
// For matching errors we provide a more specific error message that includes
|
||||
// details on how to resolve the issue.
|
||||
if !strings.Contains(err.Error(), "cannot update permissions") &&
|
||||
!strings.Contains(err.Error(), "permissions on pipeline") &&
|
||||
!strings.Contains(err.Error(), "cannot read permissions") &&
|
||||
!strings.Contains(err.Error(), "annot set run_as to user") {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Errorf(ctx, "Terraform error during deployment: %v", err.Error())
|
||||
|
||||
// Best-effort attempt to extract the resource name from the error message.
|
||||
re := regexp.MustCompile(`databricks_(\w*)\.(\w*)`)
|
||||
match := re.FindStringSubmatch(err.Error())
|
||||
resource := "resource"
|
||||
if len(match) > 1 {
|
||||
resource = match[2]
|
||||
}
|
||||
|
||||
return diag.Diagnostics{{
|
||||
Summary: fmt.Sprintf("permission denied creating or updating %s.\n"+
|
||||
"%s\n"+
|
||||
"They can redeploy the project to apply the latest set of permissions.\n"+
|
||||
"Please refer to https://docs.databricks.com/dev-tools/bundles/permissions.html for more on managing permissions.",
|
||||
resource, assistance),
|
||||
Severity: diag.Error,
|
||||
ID: diag.ResourcePermissionDenied,
|
||||
}}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package permissions_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/databricks/cli/bundle/config/resources"
|
||||
"github.com/databricks/cli/bundle/permissions"
|
||||
"github.com/databricks/cli/libs/diag"
|
||||
"github.com/databricks/databricks-sdk-go/service/jobs"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestTryExtendTerraformPermissionError1(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
b := mockBundle([]resources.Permission{
|
||||
{Level: "CAN_MANAGE", UserName: "alice@databricks.com"},
|
||||
})
|
||||
err := permissions.TryExtendTerraformPermissionError(ctx, b, errors.New(`Error: terraform apply: exit status 1
|
||||
|
||||
Error: cannot update permissions: ...
|
||||
|
||||
with databricks_pipeline.my_project_pipeline,
|
||||
on bundle.tf.json line 39, in resource.databricks_pipeline.my_project_pipeline:
|
||||
39: }`)).Error()
|
||||
require.ErrorContains(t, err, string(diag.ResourcePermissionDenied))
|
||||
}
|
||||
|
||||
func TestTryExtendTerraformPermissionError2(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
b := mockBundle([]resources.Permission{
|
||||
{Level: "CAN_MANAGE", UserName: "alice@databricks.com"},
|
||||
})
|
||||
err := permissions.TryExtendTerraformPermissionError(ctx, b, errors.New(`Error: terraform apply: exit status 1
|
||||
|
||||
Error: cannot read pipeline: User xyz does not have View permissions on pipeline 4521dbb6-42aa-418c-b94d-b5f4859a3454.
|
||||
|
||||
with databricks_pipeline.my_project_pipeline,
|
||||
on bundle.tf.json line 39, in resource.databricks_pipeline.my_project_pipeline:
|
||||
39: }`)).Error()
|
||||
require.ErrorContains(t, err, string(diag.ResourcePermissionDenied))
|
||||
}
|
||||
|
||||
func TestTryExtendTerraformPermissionError3(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
b := mockBundle([]resources.Permission{
|
||||
{Level: "CAN_MANAGE", UserName: "alice@databricks.com"},
|
||||
})
|
||||
err := permissions.TryExtendTerraformPermissionError(ctx, b, errors.New(`Error: terraform apply: exit status 1
|
||||
|
||||
Error: cannot read permissions: 1706906c-c0a2-4c25-9f57-3a7aa3cb8b90 does not have Owner permissions on Job with ID: ElasticJobId(28263044278868). Please contact the owner or an administrator for access.
|
||||
|
||||
with databricks_pipeline.my_project_pipeline,
|
||||
on bundle.tf.json line 39, in resource.databricks_pipeline.my_project_pipeline:
|
||||
39: }`)).Error()
|
||||
require.ErrorContains(t, err, string(diag.ResourcePermissionDenied))
|
||||
}
|
||||
|
||||
func TestTryExtendTerraformPermissionErrorNotOwner(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
b := mockBundle([]resources.Permission{
|
||||
{Level: "CAN_MANAGE", UserName: "alice@databricks.com"},
|
||||
})
|
||||
b.Config.RunAs = &jobs.JobRunAs{
|
||||
UserName: "testuser@databricks.com",
|
||||
}
|
||||
err := permissions.TryExtendTerraformPermissionError(ctx, b, errors.New(`Error: terraform apply: exit status 1
|
||||
|
||||
Error: cannot read pipeline: User xyz does not have View permissions on pipeline 4521dbb6-42aa-418c-b94d-b5f4859a3454.
|
||||
|
||||
with databricks_pipeline.my_project_pipeline,
|
||||
on bundle.tf.json line 39, in resource.databricks_pipeline.my_project_pipeline:
|
||||
39: }`)).Error()
|
||||
require.ErrorContains(t, err, string(diag.ResourcePermissionDenied))
|
||||
}
|
Loading…
Reference in New Issue