diff --git a/aci/backend.go b/aci/backend.go index a5e084253..a5890f33f 100644 --- a/aci/backend.go +++ b/aci/backend.go @@ -44,14 +44,6 @@ const ( composeContainerSeparator = "_" ) -// ContextParams options for creating ACI context -type ContextParams struct { - Description string - Location string - SubscriptionID string - ResourceGroup string -} - // LoginParams azure login options type LoginParams struct { TenantID string diff --git a/aci/context.go b/aci/context.go index 21784f2fc..512cd848a 100644 --- a/aci/context.go +++ b/aci/context.go @@ -31,6 +31,22 @@ import ( "github.com/docker/compose-cli/prompt" ) +// ContextParams options for creating ACI context +type ContextParams struct { + Description string + Location string + SubscriptionID string + ResourceGroup string +} + +// ErrSubscriptionNotFound is returned when a required subscription is not found +var ErrSubscriptionNotFound = errors.New("subscription not found") + +// IsSubscriptionNotFoundError returns true if the unwrapped error is IsSubscriptionNotFoundError +func IsSubscriptionNotFoundError(err error) bool { + return errors.Is(err, ErrSubscriptionNotFound) +} + type contextCreateACIHelper struct { selector prompt.UI resourceGroupHelper ResourceGroupHelper @@ -44,14 +60,21 @@ func newContextCreateHelper() contextCreateACIHelper { } func (helper contextCreateACIHelper) createContextData(ctx context.Context, opts ContextParams) (interface{}, string, error) { - var subscriptionID string + subs, err := helper.resourceGroupHelper.GetSubscriptionIDs(ctx) + if err != nil { + return nil, "", err + } + subscriptionID := "" if opts.SubscriptionID != "" { - subscriptionID = opts.SubscriptionID - } else { - subs, err := helper.resourceGroupHelper.GetSubscriptionIDs(ctx) - if err != nil { - return nil, "", err + for _, sub := range subs { + if *sub.SubscriptionID == opts.SubscriptionID { + subscriptionID = opts.SubscriptionID + } } + if subscriptionID == "" { + return nil, "", ErrSubscriptionNotFound + } + } else { subscriptionID, err = helper.chooseSub(subs) if err != nil { return nil, "", err @@ -59,8 +82,6 @@ func (helper contextCreateACIHelper) createContextData(ctx context.Context, opts } var group resources.Group - var err error - if opts.ResourceGroup != "" { group, err = helper.resourceGroupHelper.GetGroup(ctx, subscriptionID, opts.ResourceGroup) if err != nil { diff --git a/aci/context_test.go b/aci/context_test.go index d5b50a8f3..0453158cb 100644 --- a/aci/context_test.go +++ b/aci/context_test.go @@ -51,6 +51,7 @@ func TestCreateSpecifiedSubscriptionAndGroup(t *testing.T) { ctx := context.TODO() opts := options("1234", "myResourceGroup") m := testContextMocks() + m.resourceGroupHelper.On("GetSubscriptionIDs", ctx).Return([]subscription.Model{subModel("1234", "Subscription1")}, nil) m.resourceGroupHelper.On("GetGroup", ctx, "1234", "myResourceGroup").Return(group("myResourceGroup", "eastus"), nil) data, description, err := m.contextCreateHelper.createContextData(ctx, opts) @@ -64,6 +65,7 @@ func TestErrorOnNonExistentResourceGroup(t *testing.T) { opts := options("1234", "myResourceGroup") notFoundError := errors.New(`Not Found: "myResourceGroup"`) m := testContextMocks() + m.resourceGroupHelper.On("GetSubscriptionIDs", ctx).Return([]subscription.Model{subModel("1234", "Subscription1")}, nil) m.resourceGroupHelper.On("GetGroup", ctx, "1234", "myResourceGroup").Return(resources.Group{}, notFoundError) data, description, err := m.contextCreateHelper.createContextData(ctx, opts) @@ -72,10 +74,23 @@ func TestErrorOnNonExistentResourceGroup(t *testing.T) { assert.Error(t, err, "Could not find resource group \"myResourceGroup\": Not Found: \"myResourceGroup\"") } +func TestErrorOnNonExistentSubscriptionID(t *testing.T) { + ctx := context.TODO() + opts := options("otherSubscription", "myResourceGroup") + m := testContextMocks() + m.resourceGroupHelper.On("GetSubscriptionIDs", ctx).Return([]subscription.Model{subModel("1234", "Subscription1")}, nil) + + data, description, err := m.contextCreateHelper.createContextData(ctx, opts) + assert.Assert(t, cmp.Nil(data)) + assert.Equal(t, description, "") + assert.Assert(t, err == ErrSubscriptionNotFound) +} + func TestCreateNewResourceGroup(t *testing.T) { ctx := context.TODO() opts := options("1234", "") m := testContextMocks() + m.resourceGroupHelper.On("GetSubscriptionIDs", ctx).Return([]subscription.Model{subModel("1234", "Subscription1")}, nil) m.resourceGroupHelper.On("GetGroup", ctx, "1234", "myResourceGroup").Return(group("myResourceGroup", "eastus"), nil) selectOptions := []string{"create a new resource group", "group1 (eastus)", "group2 (westeurope)"} @@ -97,6 +112,7 @@ func TestSelectExistingResourceGroup(t *testing.T) { opts := options("1234", "") selectOptions := []string{"create a new resource group", "group1 (eastus)", "group2 (westeurope)"} m := testContextMocks() + m.resourceGroupHelper.On("GetSubscriptionIDs", ctx).Return([]subscription.Model{subModel("1234", "Subscription1")}, nil) m.userPrompt.On("Select", "Select a resource group", selectOptions).Return(2, nil) m.resourceGroupHelper.On("ListGroups", ctx, "1234").Return([]resources.Group{ group("group1", "eastus"), diff --git a/cli/cmd/context/create_aci.go b/cli/cmd/context/create_aci.go index ac07f8e4c..aeef3e2ff 100644 --- a/cli/cmd/context/create_aci.go +++ b/cli/cmd/context/create_aci.go @@ -62,6 +62,9 @@ func runCreateAci(ctx context.Context, contextName string, opts aci.ContextParam } contextData, description, err := getAciContextData(ctx, opts) if err != nil { + if aci.IsSubscriptionNotFoundError(err) { + return errors.New("could not find the requested subscription from your Azure login. You might need to specify a tenant ID with docker login azure --tenant-id xxx") + } return err } return createDockerContext(ctx, contextName, store.AciContextType, description, contextData)