mirror of https://github.com/databricks/cli.git
Add permissions block to each resource (#264)
Example: ```yaml resources: jobs: my_job: name: "[${bundle.environment}] My job" permissions: - level: CAN_VIEW group_name: users ```
This commit is contained in:
parent
58563b1ea9
commit
66ca9ec266
|
@ -3,7 +3,8 @@ package resources
|
|||
import "github.com/databricks/databricks-sdk-go/service/jobs"
|
||||
|
||||
type Job struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Permissions []Permission `json:"permissions,omitempty"`
|
||||
|
||||
*jobs.JobSettings
|
||||
}
|
||||
|
|
|
@ -3,5 +3,7 @@ package resources
|
|||
import "github.com/databricks/databricks-sdk-go/service/mlflow"
|
||||
|
||||
type MlflowExperiment struct {
|
||||
Permissions []Permission `json:"permissions,omitempty"`
|
||||
|
||||
*mlflow.Experiment
|
||||
}
|
||||
|
|
|
@ -3,5 +3,7 @@ package resources
|
|||
import "github.com/databricks/databricks-sdk-go/service/mlflow"
|
||||
|
||||
type MlflowModel struct {
|
||||
Permissions []Permission `json:"permissions,omitempty"`
|
||||
|
||||
*mlflow.RegisteredModel
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package resources
|
||||
|
||||
// Permission holds the permission level setting for a single principal.
|
||||
// Multiple of these can be defined on any resource.
|
||||
type Permission struct {
|
||||
Level string `json:"level"`
|
||||
|
||||
UserName string `json:"user_name,omitempty"`
|
||||
ServicePrincipalName string `json:"service_principal_name,omitempty"`
|
||||
GroupName string `json:"group_name,omitempty"`
|
||||
}
|
|
@ -3,7 +3,8 @@ package resources
|
|||
import "github.com/databricks/databricks-sdk-go/service/pipelines"
|
||||
|
||||
type Pipeline struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Permissions []Permission `json:"permissions,omitempty"`
|
||||
|
||||
*pipelines.PipelineSpec
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/databricks/bricks/bundle/config"
|
||||
"github.com/databricks/bricks/bundle/config/resources"
|
||||
"github.com/databricks/bricks/bundle/internal/tf/schema"
|
||||
tfjson "github.com/hashicorp/terraform-json"
|
||||
)
|
||||
|
@ -14,6 +15,35 @@ func conv(from any, to any) {
|
|||
json.Unmarshal(buf, &to)
|
||||
}
|
||||
|
||||
func convPermissions(acl []resources.Permission) *schema.ResourcePermissions {
|
||||
if len(acl) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
resource := schema.ResourcePermissions{}
|
||||
for _, ac := range acl {
|
||||
resource.AccessControl = append(resource.AccessControl, convPermission(ac))
|
||||
}
|
||||
|
||||
return &resource
|
||||
}
|
||||
|
||||
func convPermission(ac resources.Permission) schema.ResourcePermissionsAccessControl {
|
||||
dst := schema.ResourcePermissionsAccessControl{
|
||||
PermissionLevel: ac.Level,
|
||||
}
|
||||
if ac.UserName != "" {
|
||||
dst.UserName = ac.UserName
|
||||
}
|
||||
if ac.GroupName != "" {
|
||||
dst.GroupName = ac.GroupName
|
||||
}
|
||||
if ac.ServicePrincipalName != "" {
|
||||
dst.ServicePrincipalName = ac.ServicePrincipalName
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// BundleToTerraform converts resources in a bundle configuration
|
||||
// to the equivalent Terraform JSON representation.
|
||||
//
|
||||
|
@ -29,68 +59,96 @@ func BundleToTerraform(config *config.Root) *schema.Root {
|
|||
var dst schema.ResourceJob
|
||||
conv(src, &dst)
|
||||
|
||||
for _, v := range src.Tasks {
|
||||
var t schema.ResourceJobTask
|
||||
conv(v, &t)
|
||||
if src.JobSettings != nil {
|
||||
for _, v := range src.Tasks {
|
||||
var t schema.ResourceJobTask
|
||||
conv(v, &t)
|
||||
|
||||
for _, v_ := range v.Libraries {
|
||||
var l schema.ResourceJobTaskLibrary
|
||||
conv(v_, &l)
|
||||
t.Library = append(t.Library, l)
|
||||
for _, v_ := range v.Libraries {
|
||||
var l schema.ResourceJobTaskLibrary
|
||||
conv(v_, &l)
|
||||
t.Library = append(t.Library, l)
|
||||
}
|
||||
|
||||
dst.Task = append(dst.Task, t)
|
||||
}
|
||||
|
||||
dst.Task = append(dst.Task, t)
|
||||
}
|
||||
for _, v := range src.JobClusters {
|
||||
var t schema.ResourceJobJobCluster
|
||||
conv(v, &t)
|
||||
dst.JobCluster = append(dst.JobCluster, t)
|
||||
}
|
||||
|
||||
for _, v := range src.JobClusters {
|
||||
var t schema.ResourceJobJobCluster
|
||||
conv(v, &t)
|
||||
dst.JobCluster = append(dst.JobCluster, t)
|
||||
}
|
||||
|
||||
// Unblock downstream work. To be addressed more generally later.
|
||||
if git := src.GitSource; git != nil {
|
||||
dst.GitSource = &schema.ResourceJobGitSource{
|
||||
Url: git.GitUrl,
|
||||
Branch: git.GitBranch,
|
||||
Commit: git.GitCommit,
|
||||
Provider: string(git.GitProvider),
|
||||
Tag: git.GitTag,
|
||||
// Unblock downstream work. To be addressed more generally later.
|
||||
if git := src.GitSource; git != nil {
|
||||
dst.GitSource = &schema.ResourceJobGitSource{
|
||||
Url: git.GitUrl,
|
||||
Branch: git.GitBranch,
|
||||
Commit: git.GitCommit,
|
||||
Provider: string(git.GitProvider),
|
||||
Tag: git.GitTag,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tfroot.Resource.Job[k] = &dst
|
||||
|
||||
// Configure permissions for this resource.
|
||||
if rp := convPermissions(src.Permissions); rp != nil {
|
||||
rp.JobId = fmt.Sprintf("${databricks_job.%s.id}", k)
|
||||
tfroot.Resource.Permissions["job_"+k] = rp
|
||||
}
|
||||
}
|
||||
|
||||
for k, src := range config.Resources.Pipelines {
|
||||
var dst schema.ResourcePipeline
|
||||
conv(src, &dst)
|
||||
|
||||
for _, v := range src.Libraries {
|
||||
var l schema.ResourcePipelineLibrary
|
||||
conv(v, &l)
|
||||
dst.Library = append(dst.Library, l)
|
||||
}
|
||||
if src.PipelineSpec != nil {
|
||||
for _, v := range src.Libraries {
|
||||
var l schema.ResourcePipelineLibrary
|
||||
conv(v, &l)
|
||||
dst.Library = append(dst.Library, l)
|
||||
}
|
||||
|
||||
for _, v := range src.Clusters {
|
||||
var l schema.ResourcePipelineCluster
|
||||
conv(v, &l)
|
||||
dst.Cluster = append(dst.Cluster, l)
|
||||
for _, v := range src.Clusters {
|
||||
var l schema.ResourcePipelineCluster
|
||||
conv(v, &l)
|
||||
dst.Cluster = append(dst.Cluster, l)
|
||||
}
|
||||
}
|
||||
|
||||
tfroot.Resource.Pipeline[k] = &dst
|
||||
|
||||
// Configure permissions for this resource.
|
||||
if rp := convPermissions(src.Permissions); rp != nil {
|
||||
rp.PipelineId = fmt.Sprintf("${databricks_pipeline.%s.id}", k)
|
||||
tfroot.Resource.Permissions["pipeline_"+k] = rp
|
||||
}
|
||||
}
|
||||
|
||||
for k, src := range config.Resources.Models {
|
||||
var dst schema.ResourceMlflowModel
|
||||
conv(src, &dst)
|
||||
tfroot.Resource.MlflowModel[k] = &dst
|
||||
|
||||
// Configure permissions for this resource.
|
||||
if rp := convPermissions(src.Permissions); rp != nil {
|
||||
rp.RegisteredModelId = fmt.Sprintf("${databricks_mlflow_model.%s.registered_model_id}", k)
|
||||
tfroot.Resource.Permissions["mlflow_model_"+k] = rp
|
||||
}
|
||||
}
|
||||
|
||||
for k, src := range config.Resources.Experiments {
|
||||
var dst schema.ResourceMlflowExperiment
|
||||
conv(src, &dst)
|
||||
tfroot.Resource.MlflowExperiment[k] = &dst
|
||||
|
||||
// Configure permissions for this resource.
|
||||
if rp := convPermissions(src.Permissions); rp != nil {
|
||||
rp.ExperimentId = fmt.Sprintf("${databricks_mlflow_experiment.%s.id}", k)
|
||||
tfroot.Resource.Permissions["mlflow_experiment_"+k] = rp
|
||||
}
|
||||
}
|
||||
|
||||
return tfroot
|
||||
|
|
|
@ -47,6 +47,33 @@ func TestConvertJob(t *testing.T) {
|
|||
assert.Nil(t, out.Data)
|
||||
}
|
||||
|
||||
func TestConvertJobPermissions(t *testing.T) {
|
||||
var src = resources.Job{
|
||||
Permissions: []resources.Permission{
|
||||
{
|
||||
Level: "CAN_VIEW",
|
||||
UserName: "jane@doe.com",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var config = config.Root{
|
||||
Resources: config.Resources{
|
||||
Jobs: map[string]*resources.Job{
|
||||
"my_job": &src,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
out := BundleToTerraform(&config)
|
||||
assert.NotEmpty(t, out.Resource.Permissions["job_my_job"].JobId)
|
||||
assert.Len(t, out.Resource.Permissions["job_my_job"].AccessControl, 1)
|
||||
|
||||
p := out.Resource.Permissions["job_my_job"].AccessControl[0]
|
||||
assert.Equal(t, "jane@doe.com", p.UserName)
|
||||
assert.Equal(t, "CAN_VIEW", p.PermissionLevel)
|
||||
}
|
||||
|
||||
func TestConvertJobTaskLibraries(t *testing.T) {
|
||||
var src = resources.Job{
|
||||
JobSettings: &jobs.JobSettings{
|
||||
|
@ -81,6 +108,33 @@ func TestConvertJobTaskLibraries(t *testing.T) {
|
|||
assert.Equal(t, "mlflow", out.Resource.Job["my_job"].Task[0].Library[0].Pypi.Package)
|
||||
}
|
||||
|
||||
func TestConvertPipelinePermissions(t *testing.T) {
|
||||
var src = resources.Pipeline{
|
||||
Permissions: []resources.Permission{
|
||||
{
|
||||
Level: "CAN_VIEW",
|
||||
UserName: "jane@doe.com",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var config = config.Root{
|
||||
Resources: config.Resources{
|
||||
Pipelines: map[string]*resources.Pipeline{
|
||||
"my_pipeline": &src,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
out := BundleToTerraform(&config)
|
||||
assert.NotEmpty(t, out.Resource.Permissions["pipeline_my_pipeline"].PipelineId)
|
||||
assert.Len(t, out.Resource.Permissions["pipeline_my_pipeline"].AccessControl, 1)
|
||||
|
||||
p := out.Resource.Permissions["pipeline_my_pipeline"].AccessControl[0]
|
||||
assert.Equal(t, "jane@doe.com", p.UserName)
|
||||
assert.Equal(t, "CAN_VIEW", p.PermissionLevel)
|
||||
}
|
||||
|
||||
func TestConvertModel(t *testing.T) {
|
||||
var src = resources.MlflowModel{
|
||||
RegisteredModel: &mlflow.RegisteredModel{
|
||||
|
@ -118,6 +172,33 @@ func TestConvertModel(t *testing.T) {
|
|||
assert.Nil(t, out.Data)
|
||||
}
|
||||
|
||||
func TestConvertModelPermissions(t *testing.T) {
|
||||
var src = resources.MlflowModel{
|
||||
Permissions: []resources.Permission{
|
||||
{
|
||||
Level: "CAN_READ",
|
||||
UserName: "jane@doe.com",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var config = config.Root{
|
||||
Resources: config.Resources{
|
||||
Models: map[string]*resources.MlflowModel{
|
||||
"my_model": &src,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
out := BundleToTerraform(&config)
|
||||
assert.NotEmpty(t, out.Resource.Permissions["mlflow_model_my_model"].RegisteredModelId)
|
||||
assert.Len(t, out.Resource.Permissions["mlflow_model_my_model"].AccessControl, 1)
|
||||
|
||||
p := out.Resource.Permissions["mlflow_model_my_model"].AccessControl[0]
|
||||
assert.Equal(t, "jane@doe.com", p.UserName)
|
||||
assert.Equal(t, "CAN_READ", p.PermissionLevel)
|
||||
}
|
||||
|
||||
func TestConvertExperiment(t *testing.T) {
|
||||
var src = resources.MlflowExperiment{
|
||||
Experiment: &mlflow.Experiment{
|
||||
|
@ -137,3 +218,31 @@ func TestConvertExperiment(t *testing.T) {
|
|||
assert.Equal(t, "name", out.Resource.MlflowExperiment["my_experiment"].Name)
|
||||
assert.Nil(t, out.Data)
|
||||
}
|
||||
|
||||
func TestConvertExperimentPermissions(t *testing.T) {
|
||||
var src = resources.MlflowExperiment{
|
||||
Permissions: []resources.Permission{
|
||||
{
|
||||
Level: "CAN_READ",
|
||||
UserName: "jane@doe.com",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var config = config.Root{
|
||||
Resources: config.Resources{
|
||||
Experiments: map[string]*resources.MlflowExperiment{
|
||||
"my_experiment": &src,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
out := BundleToTerraform(&config)
|
||||
assert.NotEmpty(t, out.Resource.Permissions["mlflow_experiment_my_experiment"].ExperimentId)
|
||||
assert.Len(t, out.Resource.Permissions["mlflow_experiment_my_experiment"].AccessControl, 1)
|
||||
|
||||
p := out.Resource.Permissions["mlflow_experiment_my_experiment"].AccessControl[0]
|
||||
assert.Equal(t, "jane@doe.com", p.UserName)
|
||||
assert.Equal(t, "CAN_READ", p.PermissionLevel)
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue