Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
869637d
Add a textual bundle summary command
lennartkats-db Aug 24, 2024
462ee2e
Merge remote-tracking branch 'databricks/main' into cp-summary-with-urls
lennartkats-db Aug 29, 2024
1325fd8
Fix typo
lennartkats-db Aug 29, 2024
44110d1
Merge branch 'main' into cp-summary-with-urls
pietern Sep 13, 2024
189d40b
Address reviewer comments
lennartkats-db Oct 5, 2024
8cd03d1
Merge branch 'cp-summary-with-urls' of github.com:lennartkats-db/cli …
lennartkats-db Oct 5, 2024
7911c67
Merge remote-tracking branch 'databricks/main' into cp-summary-with-urls
lennartkats-db Oct 5, 2024
65bad56
Fix test failure based on code from main
lennartkats-db Oct 5, 2024
ef2400f
Merge remote-tracking branch 'databricks/main' into cp-summary-with-urls
lennartkats-db Oct 11, 2024
d54f641
Fix test name
lennartkats-db Oct 11, 2024
6218539
Merge remote-tracking branch 'databricks/main' into cp-summary-with-urls
lennartkats-db Oct 11, 2024
aea4a6e
Styling fix
lennartkats-db Oct 17, 2024
2765a41
Merge remote-tracking branch 'databricks/main' into cp-summary-with-urls
lennartkats-db Oct 17, 2024
13049a5
Remove unused name field
pietern Oct 17, 2024
2c8bb75
Add singular/plural titles to config.SupportedResources()
pietern Oct 17, 2024
85bc79f
Use plural title resource header
pietern Oct 17, 2024
dccd70b
require -> assert
pietern Oct 17, 2024
b1dd60c
Include test case for clusters
pietern Oct 17, 2024
7bf2ec3
Always use ID to synthesize URLs
pietern Oct 17, 2024
7658dbd
Use net/url to build resource URLs such that proper escaping is done
pietern Oct 17, 2024
530a819
Merge branch 'main' into cp-summary-with-urls
lennartkats-db Oct 17, 2024
0cd3fcd
Update bundle/config/resources.go
pietern Oct 18, 2024
c45b058
Update bundle/config/mutator/initialize_urls_test.go
pietern Oct 18, 2024
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
31 changes: 19 additions & 12 deletions bundle/config/mutator/initialize_urls.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package mutator

import (
"context"
"fmt"
"net/url"
"strconv"
"strings"

Expand All @@ -11,7 +11,6 @@ import (
)

type initializeURLs struct {
name string
}

// InitializeURLs makes sure the URL field of each resource is configured.
Expand All @@ -23,7 +22,7 @@ func InitializeURLs() bundle.Mutator {
}
Comment thread
lennartkats-db marked this conversation as resolved.

func (m *initializeURLs) Name() string {
return fmt.Sprintf("InitializeURLs(%s)", m.name)
return "InitializeURLs"
}

func (m *initializeURLs) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics {
Expand All @@ -32,27 +31,35 @@ func (m *initializeURLs) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagn
return diag.FromErr(err)
}
orgId := strconv.FormatInt(workspaceId, 10)
urlPrefix := b.WorkspaceClient().Config.CanonicalHostName() + "/"
initializeForWorkspace(b, orgId, urlPrefix)
host := b.WorkspaceClient().Config.CanonicalHostName()
initializeForWorkspace(b, orgId, host)
return nil
}

func initializeForWorkspace(b *bundle.Bundle, orgId string, urlPrefix string) {
func initializeForWorkspace(b *bundle.Bundle, orgId string, host string) error {
baseURL, err := url.Parse(host)
if err != nil {
return err
}

// Add ?o=<workspace id> only if <workspace id> wasn't in the subdomain already.
// The ?o= is needed when vanity URLs / legacy workspace URLs are used.
// If it's not needed we prefer to leave it out since these URLs are rather
// long for most terminals.
Comment thread
pietern marked this conversation as resolved.
//
// See https://docs.databricks.com/en/workspace/workspace-details.html for
// further reading about the '?o=' suffix.
urlSuffix := ""
if !strings.Contains(urlPrefix, orgId) {
urlSuffix = "?o=" + orgId
if !strings.Contains(baseURL.Hostname(), orgId) {
values := baseURL.Query()
values.Add("o", orgId)
baseURL.RawQuery = values.Encode()
}

for _, rs := range b.Config.Resources.AllResources() {
for _, r := range rs {
r.InitializeURL(urlPrefix, urlSuffix)
for _, group := range b.Config.Resources.AllResources() {
for _, r := range group.Resources {
r.InitializeURL(*baseURL)
}
}

return nil
}
20 changes: 15 additions & 5 deletions bundle/config/mutator/initialize_urls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/databricks/cli/bundle/config"
"github.com/databricks/cli/bundle/config/resources"
"github.com/databricks/databricks-sdk-go/service/catalog"
"github.com/databricks/databricks-sdk-go/service/compute"
"github.com/databricks/databricks-sdk-go/service/jobs"
"github.com/databricks/databricks-sdk-go/service/ml"
"github.com/databricks/databricks-sdk-go/service/pipelines"
Expand Down Expand Up @@ -41,13 +42,13 @@ func TestInitializeURLs(t *testing.T) {
},
Models: map[string]*resources.MlflowModel{
"model1": {
ID: "6",
ID: "a model uses its name for identifier",
Model: &ml.Model{Name: "model1"},
Comment thread
pietern marked this conversation as resolved.
Outdated
},
},
ModelServingEndpoints: map[string]*resources.ModelServingEndpoint{
"servingendpoint1": {
ID: "7",
ID: "my_serving_endpoint",
CreateServingEndpoint: &serving.CreateServingEndpoint{
Name: "my_serving_endpoint",
},
Expand Down Expand Up @@ -76,6 +77,14 @@ func TestInitializeURLs(t *testing.T) {
},
},
},
Clusters: map[string]*resources.Cluster{
"cluster1": {
ID: "1017-103929-vlr7jzcf",
ClusterSpec: &compute.ClusterSpec{
ClusterName: "cluster1",
},
},
},
},
},
}
Expand All @@ -84,17 +93,18 @@ func TestInitializeURLs(t *testing.T) {
"job1": "https://mycompany.databricks.com/jobs/1?o=123456",
"pipeline1": "https://mycompany.databricks.com/pipelines/3?o=123456",
"experiment1": "https://mycompany.databricks.com/ml/experiments/4?o=123456",
"model1": "https://mycompany.databricks.com/ml/models/model1?o=123456",
"model1": "https://mycompany.databricks.com/ml/models/a%20model%20uses%20its%20name%20for%20identifier?o=123456",
Comment thread
pietern marked this conversation as resolved.
"servingendpoint1": "https://mycompany.databricks.com/ml/endpoints/my_serving_endpoint?o=123456",
"registeredmodel1": "https://mycompany.databricks.com/explore/data/models/8?o=123456",
"qualityMonitor1": "https://mycompany.databricks.com/explore/data/catalog/schema/qualityMonitor1?o=123456",
"schema1": "https://mycompany.databricks.com/explore/data/catalog/schema?o=123456",
Comment thread
lennartkats-db marked this conversation as resolved.
"cluster1": "https://mycompany.databricks.com/compute/clusters/1017-103929-vlr7jzcf?o=123456",
}

initializeForWorkspace(b, "123456", "https://mycompany.databricks.com/")

for _, rs := range b.Config.Resources.AllResources() {
for key, r := range rs {
for _, group := range b.Config.Resources.AllResources() {
for key, r := range group.Resources {
require.Equal(t, expectedURLs[key], r.GetURL(), "Unexpected URL for "+key)
}
}
Expand Down
156 changes: 93 additions & 63 deletions bundle/config/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package config
import (
"context"
"fmt"
"net/url"

"github.com/databricks/cli/bundle/config/resources"
"github.com/databricks/databricks-sdk-go"
Expand Down Expand Up @@ -38,67 +39,45 @@ type ConfigResource interface {
GetURL() string

// InitializeURL initializes the URL field of the resource.
InitializeURL(urlPrefix string, urlSuffix string)
InitializeURL(url.URL)
Comment thread
pietern marked this conversation as resolved.
Outdated
}

func (r *Resources) AllResources() map[string]map[string]ConfigResource {
result := make(map[string]map[string]ConfigResource)

jobResources := make(map[string]ConfigResource)
for key, job := range r.Jobs {
jobResources[key] = job
}
result["jobs"] = jobResources

pipelineResources := make(map[string]ConfigResource)
for key, pipeline := range r.Pipelines {
pipelineResources[key] = pipeline
}
result["pipelines"] = pipelineResources

modelResources := make(map[string]ConfigResource)
for key, model := range r.Models {
modelResources[key] = model
}
result["models"] = modelResources

experimentResources := make(map[string]ConfigResource)
for key, experiment := range r.Experiments {
experimentResources[key] = experiment
}
result["experiments"] = experimentResources

modelServingEndpointResources := make(map[string]ConfigResource)
for key, endpoint := range r.ModelServingEndpoints {
modelServingEndpointResources[key] = endpoint
}
result["model_serving_endpoints"] = modelServingEndpointResources

registeredModelResources := make(map[string]ConfigResource)
for key, registeredModel := range r.RegisteredModels {
registeredModelResources[key] = registeredModel
}
result["registered_models"] = registeredModelResources
// ResourceGroup represents a group of resources of the same type.
// It includes a description of the resource type and a map of resources.
type ResourceGroup struct {
Description ResourceDescription
Resources map[string]ConfigResource
}

qualityMonitorResources := make(map[string]ConfigResource)
for key, qualityMonitor := range r.QualityMonitors {
qualityMonitorResources[key] = qualityMonitor
// collectResourceMap collects resources of a specific type into a ResourceGroup.
func collectResourceMap[T ConfigResource](
description ResourceDescription,
input map[string]T,
) ResourceGroup {
resources := make(map[string]ConfigResource)
for key, resource := range input {
resources[key] = resource
}
result["quality_monitors"] = qualityMonitorResources

schemaResources := make(map[string]ConfigResource)
for key, schema := range r.Schemas {
schemaResources[key] = schema
return ResourceGroup{
Description: description,
Resources: resources,
}
result["schemas"] = schemaResources
}

clusterResources := make(map[string]ConfigResource)
for key, schema := range r.Clusters {
clusterResources[key] = schema
// AllResources returns all resources in the bundle grouped by their resource type.
func (r *Resources) AllResources() []ResourceGroup {
descriptions := SupportedResources()
return []ResourceGroup{
collectResourceMap(descriptions["jobs"], r.Jobs),
collectResourceMap(descriptions["pipelines"], r.Pipelines),
collectResourceMap(descriptions["models"], r.Models),
collectResourceMap(descriptions["experiments"], r.Experiments),
collectResourceMap(descriptions["model_serving_endpoints"], r.ModelServingEndpoints),
collectResourceMap(descriptions["registered_models"], r.RegisteredModels),
collectResourceMap(descriptions["quality_monitors"], r.QualityMonitors),
collectResourceMap(descriptions["schemas"], r.Schemas),
collectResourceMap(descriptions["clusters"], r.Clusters),
}
result["clusters"] = clusterResources

return result
}

func (r *Resources) FindResourceByConfigKey(key string) (ConfigResource, error) {
Expand Down Expand Up @@ -130,20 +109,71 @@ func (r *Resources) FindResourceByConfigKey(key string) (ConfigResource, error)
}

type ResourceDescription struct {
// Singular and plural name when used to refer to the configuration.
SingularName string
PluralName string

// Singular and plural title when used in summaries / terminal UI.
SingularTitle string
PluralTitle string
}

// The keys of the map corresponds to the resource key in the bundle configuration.
func SupportedResources() map[string]ResourceDescription {
return map[string]ResourceDescription{
"jobs": {SingularName: "job"},
"pipelines": {SingularName: "pipeline"},
"models": {SingularName: "model"},
"experiments": {SingularName: "experiment"},
"model_serving_endpoints": {SingularName: "model_serving_endpoint"},
"registered_models": {SingularName: "registered_model"},
"quality_monitors": {SingularName: "quality_monitor"},
"schemas": {SingularName: "schema"},
"clusters": {SingularName: "cluster"},
"jobs": {
SingularName: "job",
PluralName: "jobs",
SingularTitle: "Job",
PluralTitle: "Jobs",
},
"pipelines": {
SingularName: "pipeline",
PluralName: "pipelines",
SingularTitle: "Pipeline",
PluralTitle: "Pipelines",
},
"models": {
SingularName: "model",
PluralName: "models",
SingularTitle: "Model",
PluralTitle: "Models",
},
"experiments": {
SingularName: "experiment",
PluralName: "experiments",
SingularTitle: "Experiment",
PluralTitle: "Experiments",
},
"model_serving_endpoints": {
SingularName: "model_serving_endpoint",
PluralName: "model_serving_endpoints",
SingularTitle: "Model Serving Endpoint",
PluralTitle: "Model Serving Endpoints",
},
"registered_models": {
SingularName: "registered_model",
PluralName: "registered_models",
SingularTitle: "Registered Model",
PluralTitle: "Registered Models",
},
"quality_monitors": {
SingularName: "quality_monitor",
PluralName: "quality_monitors",
SingularTitle: "Quality Monitor",
PluralTitle: "Quality Monitors",
},
"schemas": {
SingularName: "schema",
PluralName: "schemas",
SingularTitle: "Schema",
PluralTitle: "Schemas",
},
"clusters": {
SingularName: "cluster",
PluralName: "clusters",
SingularTitle: "Cluster",
PluralTitle: "Clusters",
},
}
}
7 changes: 5 additions & 2 deletions bundle/config/resources/clusters.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package resources

import (
"context"
"fmt"
"net/url"

"github.com/databricks/cli/libs/log"
"github.com/databricks/databricks-sdk-go"
Expand Down Expand Up @@ -39,11 +41,12 @@ func (s *Cluster) TerraformResourceName() string {
return "databricks_cluster"
}

func (s *Cluster) InitializeURL(urlPrefix string, urlSuffix string) {
func (s *Cluster) InitializeURL(baseURL url.URL) {
if s.ID == "" {
return
}
s.URL = urlPrefix + "compute/clusters/" + s.ID + urlSuffix
baseURL.Path = fmt.Sprintf("compute/clusters/%s", s.ID)
s.URL = baseURL.String()
}

func (s *Cluster) GetName() string {
Expand Down
7 changes: 5 additions & 2 deletions bundle/config/resources/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package resources

import (
"context"
"fmt"
"net/url"
"strconv"

"github.com/databricks/cli/libs/log"
Expand Down Expand Up @@ -46,11 +48,12 @@ func (j *Job) TerraformResourceName() string {
return "databricks_job"
}

func (j *Job) InitializeURL(urlPrefix string, urlSuffix string) {
func (j *Job) InitializeURL(baseURL url.URL) {
if j.ID == "" {
return
}
j.URL = urlPrefix + "jobs/" + j.ID + urlSuffix
baseURL.Path = fmt.Sprintf("jobs/%s", j.ID)
j.URL = baseURL.String()
}

func (j *Job) GetName() string {
Expand Down
7 changes: 5 additions & 2 deletions bundle/config/resources/mlflow_experiment.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package resources

import (
"context"
"fmt"
"net/url"

"github.com/databricks/cli/libs/log"
"github.com/databricks/databricks-sdk-go"
Expand Down Expand Up @@ -41,11 +43,12 @@ func (s *MlflowExperiment) TerraformResourceName() string {
return "databricks_mlflow_experiment"
}

func (s *MlflowExperiment) InitializeURL(urlPrefix string, urlSuffix string) {
func (s *MlflowExperiment) InitializeURL(baseURL url.URL) {
if s.ID == "" {
return
}
s.URL = urlPrefix + "ml/experiments/" + s.ID + urlSuffix
baseURL.Path = fmt.Sprintf("ml/experiments/%s", s.ID)
s.URL = baseURL.String()
}

func (s *MlflowExperiment) GetName() string {
Expand Down
Loading