Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Error: failed to resolve service-principal: TIDALDBServAccount - usdev, err: ServicePrincipal named 'TIDALDBServAccount - usdev' does not exist
Error: failed to resolve service-principal: TIDALDBServAccount - usdev, err: service principal named "TIDALDBServAccount - usdev" does not exist

Name: issue-3039
Target: personal
Expand Down
10 changes: 10 additions & 0 deletions acceptance/bundle/variables/lookup/databricks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
bundle:
name: test-bundle

variables:
sp:
lookup:
service_principal: "deco-test-spn"

result:
default: ${var.sp}
5 changes: 5 additions & 0 deletions acceptance/bundle/variables/lookup/out.test.toml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions acceptance/bundle/variables/lookup/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

>>> [CLI] bundle validate -o json
{
"result": {
"default": "[UUID]",
"value": "[UUID]"
},
"sp": {
"lookup": {
"service_principal": "deco-test-spn"
},
"value": "[UUID]"
}
}
1 change: 1 addition & 0 deletions acceptance/bundle/variables/lookup/script
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
trace $CLI bundle validate -o json | jq '.variables'
13 changes: 13 additions & 0 deletions acceptance/bundle/variables/lookup/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Local = true
Cloud = true

[[Server]]
Pattern = "GET /api/2.0/preview/scim/v2/ServicePrincipals"
Response.Body = '''{
"Resources": [
{
"displayName": "deco-test-spn",
"applicationId": "123e4567-e89b-12d3-a456-426614174000"
}
]
}'''
19 changes: 14 additions & 5 deletions bundle/config/mutator/resolve_lookup_variables_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package mutator

import (
"fmt"
"testing"

"github.com/databricks/cli/bundle"
Expand All @@ -11,6 +12,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/databricks/databricks-sdk-go/experimental/mocks"
"github.com/databricks/databricks-sdk-go/listing"
"github.com/databricks/databricks-sdk-go/service/compute"
"github.com/databricks/databricks-sdk-go/service/iam"
)
Expand Down Expand Up @@ -131,11 +133,18 @@ func TestResolveServicePrincipal(t *testing.T) {

m := mocks.NewMockWorkspaceClient(t)
b.SetWorkpaceClient(m.WorkspaceClient)
spApi := m.GetMockServicePrincipalsAPI()
spApi.EXPECT().GetByDisplayName(mock.Anything, spName).Return(&iam.ServicePrincipal{
Id: "1234",
ApplicationId: "app-1234",
}, nil)

api := m.GetMockServicePrincipalsV2API()
iterator := listing.SliceIterator[iam.ServicePrincipal]([]iam.ServicePrincipal{
{
ApplicationId: "app-1234",
},
})
api.EXPECT().
List(mock.Anything, iam.ListServicePrincipalsRequest{
Filter: fmt.Sprintf("displayName eq '%s'", spName),
}).
Return(&iterator)

diags := bundle.Apply(t.Context(), b, ResolveLookupVariables())
require.NoError(t, diags.Error())
Expand Down
19 changes: 17 additions & 2 deletions bundle/config/variable/resolve_service_principal.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package variable

import (
"context"
"fmt"

"github.com/databricks/databricks-sdk-go"
"github.com/databricks/databricks-sdk-go/listing"
"github.com/databricks/databricks-sdk-go/service/iam"
)

type resolveServicePrincipal struct {
Expand All @@ -12,11 +15,23 @@ type resolveServicePrincipal struct {

func (l resolveServicePrincipal) Resolve(ctx context.Context, w *databricks.WorkspaceClient) (string, error) {
//nolint:staticcheck // this API is deprecated but we still need use it as there is no replacement yet.
entity, err := w.ServicePrincipals.GetByDisplayName(ctx, l.name)
it := w.ServicePrincipalsV2.List(ctx, iam.ListServicePrincipalsRequest{
Filter: fmt.Sprintf("displayName eq '%s'", l.name),
})

servicePrincipals, err := listing.ToSliceN(ctx, it, 1)
if err != nil {
return "", err
}
return entity.ApplicationId, nil
if len(servicePrincipals) == 0 {
return "", fmt.Errorf("service principal named %q does not exist", l.name)
}

if len(servicePrincipals) > 1 {
return "", fmt.Errorf("multiple service principals found with display name %q", l.name)
}

return servicePrincipals[0].ApplicationId, nil
}

func (l resolveServicePrincipal) String() string {
Expand Down
28 changes: 18 additions & 10 deletions bundle/config/variable/resolve_service_principal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package variable
import (
"testing"

"github.com/databricks/databricks-sdk-go/apierr"
"github.com/databricks/databricks-sdk-go/experimental/mocks"
"github.com/databricks/databricks-sdk-go/listing"
"github.com/databricks/databricks-sdk-go/service/iam"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
Expand All @@ -14,12 +14,17 @@ import (
func TestResolveServicePrincipal_ResolveSuccess(t *testing.T) {
m := mocks.NewMockWorkspaceClient(t)

api := m.GetMockServicePrincipalsAPI()
api.EXPECT().
GetByDisplayName(mock.Anything, "service-principal").
Return(&iam.ServicePrincipal{
api := m.GetMockServicePrincipalsV2API()
iterator := listing.SliceIterator[iam.ServicePrincipal]([]iam.ServicePrincipal{
{
ApplicationId: "5678",
}, nil)
},
})
api.EXPECT().
List(mock.Anything, iam.ListServicePrincipalsRequest{
Filter: "displayName eq 'service-principal'",
}).
Return(&iterator)

ctx := t.Context()
l := resolveServicePrincipal{name: "service-principal"}
Expand All @@ -31,15 +36,18 @@ func TestResolveServicePrincipal_ResolveSuccess(t *testing.T) {
func TestResolveServicePrincipal_ResolveNotFound(t *testing.T) {
m := mocks.NewMockWorkspaceClient(t)

api := m.GetMockServicePrincipalsAPI()
api := m.GetMockServicePrincipalsV2API()
iterator := listing.SliceIterator[iam.ServicePrincipal]([]iam.ServicePrincipal{})
api.EXPECT().
GetByDisplayName(mock.Anything, "service-principal").
Return(nil, &apierr.APIError{StatusCode: 404})
List(mock.Anything, iam.ListServicePrincipalsRequest{
Filter: "displayName eq 'service-principal'",
}).
Return(&iterator)

ctx := t.Context()
l := resolveServicePrincipal{name: "service-principal"}
_, err := l.Resolve(ctx, m.WorkspaceClient)
require.ErrorIs(t, err, apierr.ErrNotFound)
require.ErrorContains(t, err, "service principal named \"service-principal\" does not exist")
}

func TestResolveServicePrincipal_String(t *testing.T) {
Expand Down
Loading