diff --git a/aci/aci.go b/aci/aci.go index f1d1e76dd..c22994d75 100644 --- a/aci/aci.go +++ b/aci/aci.go @@ -24,8 +24,6 @@ import ( "strings" "time" - "github.com/docker/api/errdefs" - "github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance" "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/to" @@ -39,13 +37,12 @@ import ( "github.com/docker/api/aci/login" "github.com/docker/api/containers" "github.com/docker/api/context/store" + "github.com/docker/api/errdefs" "github.com/docker/api/progress" ) -const aciDockerUserAgent = "docker-cli" - func createACIContainers(ctx context.Context, aciContext store.AciContext, groupDefinition containerinstance.ContainerGroup) error { - containerGroupsClient, err := getContainerGroupsClient(aciContext.SubscriptionID) + containerGroupsClient, err := login.NewContainerGroupsClient(aciContext.SubscriptionID) if err != nil { return errors.Wrapf(err, "cannot get container group client") } @@ -69,7 +66,7 @@ func createACIContainers(ctx context.Context, aciContext store.AciContext, group func createOrUpdateACIContainers(ctx context.Context, aciContext store.AciContext, groupDefinition containerinstance.ContainerGroup) error { w := progress.ContextWriter(ctx) - containerGroupsClient, err := getContainerGroupsClient(aciContext.SubscriptionID) + containerGroupsClient, err := login.NewContainerGroupsClient(aciContext.SubscriptionID) if err != nil { return errors.Wrapf(err, "cannot get container group client") } @@ -124,7 +121,7 @@ func createOrUpdateACIContainers(ctx context.Context, aciContext store.AciContex } func getACIContainerGroup(ctx context.Context, aciContext store.AciContext, containerGroupName string) (containerinstance.ContainerGroup, error) { - containerGroupsClient, err := getContainerGroupsClient(aciContext.SubscriptionID) + containerGroupsClient, err := login.NewContainerGroupsClient(aciContext.SubscriptionID) if err != nil { return containerinstance.ContainerGroup{}, fmt.Errorf("cannot get container group client: %v", err) } @@ -133,7 +130,7 @@ func getACIContainerGroup(ctx context.Context, aciContext store.AciContext, cont } func deleteACIContainerGroup(ctx context.Context, aciContext store.AciContext, containerGroupName string) (containerinstance.ContainerGroup, error) { - containerGroupsClient, err := getContainerGroupsClient(aciContext.SubscriptionID) + containerGroupsClient, err := login.NewContainerGroupsClient(aciContext.SubscriptionID) if err != nil { return containerinstance.ContainerGroup{}, fmt.Errorf("cannot get container group client: %v", err) } @@ -142,7 +139,7 @@ func deleteACIContainerGroup(ctx context.Context, aciContext store.AciContext, c } func stopACIContainerGroup(ctx context.Context, aciContext store.AciContext, containerGroupName string) error { - containerGroupsClient, err := getContainerGroupsClient(aciContext.SubscriptionID) + containerGroupsClient, err := login.NewContainerGroupsClient(aciContext.SubscriptionID) if err != nil { return fmt.Errorf("cannot get container group client: %v", err) } @@ -155,7 +152,7 @@ func stopACIContainerGroup(ctx context.Context, aciContext store.AciContext, con } func execACIContainer(ctx context.Context, aciContext store.AciContext, command, containerGroup string, containerName string) (c containerinstance.ContainerExecResponse, err error) { - containerClient, err := getContainerClient(aciContext.SubscriptionID) + containerClient, err := login.NewContainerClient(aciContext.SubscriptionID) if err != nil { return c, errors.Wrapf(err, "cannot get container client") } @@ -248,7 +245,7 @@ func exec(ctx context.Context, address string, password string, request containe } func getACIContainerLogs(ctx context.Context, aciContext store.AciContext, containerGroupName, containerName string, tail *int32) (string, error) { - containerClient, err := getContainerClient(aciContext.SubscriptionID) + containerClient, err := login.NewContainerClient(aciContext.SubscriptionID) if err != nil { return "", errors.Wrapf(err, "cannot get container client") } @@ -311,34 +308,3 @@ func getBacktrackLines(lines []string, terminalWidth int) int { return numLines } - -func getContainerGroupsClient(subscriptionID string) (containerinstance.ContainerGroupsClient, error) { - containerGroupsClient := containerinstance.NewContainerGroupsClient(subscriptionID) - err := setupClient(&containerGroupsClient.Client) - if err != nil { - return containerinstance.ContainerGroupsClient{}, err - } - containerGroupsClient.PollingDelay = 5 * time.Second - containerGroupsClient.RetryAttempts = 30 - containerGroupsClient.RetryDuration = 1 * time.Second - return containerGroupsClient, nil -} - -func setupClient(aciClient *autorest.Client) error { - aciClient.UserAgent = aciDockerUserAgent - auth, err := login.NewAuthorizerFromLogin() - if err != nil { - return err - } - aciClient.Authorizer = auth - return nil -} - -func getContainerClient(subscriptionID string) (containerinstance.ContainerClient, error) { - containerClient := containerinstance.NewContainerClient(subscriptionID) - err := setupClient(&containerClient.Client) - if err != nil { - return containerinstance.ContainerClient{}, err - } - return containerClient, nil -} diff --git a/aci/backend.go b/aci/backend.go index feaebab66..71679a070 100644 --- a/aci/backend.go +++ b/aci/backend.go @@ -133,7 +133,7 @@ type aciContainerService struct { } func (cs *aciContainerService) List(ctx context.Context, all bool) ([]containers.Container, error) { - groupsClient, err := getContainerGroupsClient(cs.ctx.SubscriptionID) + groupsClient, err := login.NewContainerGroupsClient(cs.ctx.SubscriptionID) if err != nil { return nil, err } @@ -209,7 +209,7 @@ func (cs *aciContainerService) Run(ctx context.Context, r containers.ContainerCo } logrus.Debugf("Running container %q with name %q\n", r.Image, r.ID) - groupDefinition, err := convert.ToContainerGroup(cs.ctx, project) + groupDefinition, err := convert.ToContainerGroup(ctx, cs.ctx, project) if err != nil { return err } @@ -232,7 +232,7 @@ func (cs *aciContainerService) Start(ctx context.Context, containerID string) er return errors.New(fmt.Sprintf(msg, containerName, groupName, groupName)) } - containerGroupsClient, err := getContainerGroupsClient(cs.ctx.SubscriptionID) + containerGroupsClient, err := login.NewContainerGroupsClient(cs.ctx.SubscriptionID) if err != nil { return err } @@ -336,7 +336,7 @@ func (cs *aciContainerService) Delete(ctx context.Context, containerID string, r } if !request.Force { - containerGroupsClient, err := getContainerGroupsClient(cs.ctx.SubscriptionID) + containerGroupsClient, err := login.NewContainerGroupsClient(cs.ctx.SubscriptionID) if err != nil { return err } @@ -410,7 +410,7 @@ func (cs *aciComposeService) Up(ctx context.Context, opts cli.ProjectOptions) er return err } logrus.Debugf("Up on project with name %q\n", project.Name) - groupDefinition, err := convert.ToContainerGroup(cs.ctx, *project) + groupDefinition, err := convert.ToContainerGroup(ctx, cs.ctx, *project) addTag(&groupDefinition, composeContainerTag) if err != nil { diff --git a/aci/convert/convert.go b/aci/convert/convert.go index c8134b7c4..ae8528c22 100644 --- a/aci/convert/convert.go +++ b/aci/convert/convert.go @@ -17,8 +17,8 @@ package convert import ( + "context" "encoding/base64" - "errors" "fmt" "io/ioutil" "math" @@ -29,7 +29,9 @@ import ( "github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance" "github.com/Azure/go-autorest/autorest/to" "github.com/compose-spec/compose-go/types" + "github.com/pkg/errors" + "github.com/docker/api/aci/login" "github.com/docker/api/containers" "github.com/docker/api/context/store" ) @@ -42,15 +44,22 @@ const ( azureFileDriverName = "azure_file" volumeDriveroptsShareNameKey = "share_name" volumeDriveroptsAccountNameKey = "storage_account_name" - volumeDriveroptsAccountKeyKey = "storage_account_key" secretInlineMark = "inline:" ) // ToContainerGroup converts a compose project into a ACI container group -func ToContainerGroup(aciContext store.AciContext, p types.Project) (containerinstance.ContainerGroup, error) { +func ToContainerGroup(ctx context.Context, aciContext store.AciContext, p types.Project) (containerinstance.ContainerGroup, error) { project := projectAciHelper(p) containerGroupName := strings.ToLower(project.Name) - volumesCache, volumesSlice, err := project.getAciFileVolumes() + loginService, err := login.NewAzureLoginService() + if err != nil { + return containerinstance.ContainerGroup{}, err + } + storageHelper := login.StorageAccountHelper{ + LoginService: *loginService, + AciContext: aciContext, + } + volumesCache, volumesSlice, err := project.getAciFileVolumes(ctx, storageHelper) if err != nil { return containerinstance.ContainerGroup{}, err } @@ -191,7 +200,7 @@ func (p projectAciHelper) getAciSecretVolumes() ([]containerinstance.Volume, err return secretVolumes, nil } -func (p projectAciHelper) getAciFileVolumes() (map[string]bool, []containerinstance.Volume, error) { +func (p projectAciHelper) getAciFileVolumes(ctx context.Context, helper login.StorageAccountHelper) (map[string]bool, []containerinstance.Volume, error) { azureFileVolumesMap := make(map[string]bool, len(p.Volumes)) var azureFileVolumesSlice []containerinstance.Volume for name, v := range p.Volumes { @@ -204,9 +213,9 @@ func (p projectAciHelper) getAciFileVolumes() (map[string]bool, []containerinsta if !ok { return nil, nil, fmt.Errorf("cannot retrieve account name for Azurefile") } - accountKey, ok := v.DriverOpts[volumeDriveroptsAccountKeyKey] - if !ok { - return nil, nil, fmt.Errorf("cannot retrieve account key for Azurefile") + accountKey, err := helper.GetAzureStorageAccountKey(ctx, accountName) + if err != nil { + return nil, nil, err } aciVolume := containerinstance.Volume{ Name: to.StringPtr(name), diff --git a/aci/convert/convert_test.go b/aci/convert/convert_test.go index 2667e8756..60c6b1650 100644 --- a/aci/convert/convert_test.go +++ b/aci/convert/convert_test.go @@ -17,6 +17,7 @@ package convert import ( + "context" "os" "testing" @@ -40,7 +41,7 @@ func TestProjectName(t *testing.T) { project := types.Project{ Name: "TEST", } - containerGroup, err := ToContainerGroup(convertCtx, project) + containerGroup, err := ToContainerGroup(context.TODO(), convertCtx, project) assert.NilError(t, err) assert.Equal(t, *containerGroup.Name, "test") } @@ -117,7 +118,7 @@ func TestComposeContainerGroupToContainerWithDnsSideCarSide(t *testing.T) { }, } - group, err := ToContainerGroup(convertCtx, project) + group, err := ToContainerGroup(context.TODO(), convertCtx, project) assert.NilError(t, err) assert.Assert(t, is.Len(*group.Containers, 3)) @@ -142,7 +143,7 @@ func TestComposeSingleContainerGroupToContainerNoDnsSideCarSide(t *testing.T) { }, } - group, err := ToContainerGroup(convertCtx, project) + group, err := ToContainerGroup(context.TODO(), convertCtx, project) assert.NilError(t, err) assert.Assert(t, is.Len(*group.Containers, 1)) @@ -165,7 +166,7 @@ func TestComposeSingleContainerRestartPolicy(t *testing.T) { }, } - group, err := ToContainerGroup(convertCtx, project) + group, err := ToContainerGroup(context.TODO(), convertCtx, project) assert.NilError(t, err) assert.Assert(t, is.Len(*group.Containers, 1)) @@ -197,7 +198,7 @@ func TestComposeMultiContainerRestartPolicy(t *testing.T) { }, } - group, err := ToContainerGroup(convertCtx, project) + group, err := ToContainerGroup(context.TODO(), convertCtx, project) assert.NilError(t, err) assert.Assert(t, is.Len(*group.Containers, 3)) @@ -231,7 +232,7 @@ func TestComposeInconsistentMultiContainerRestartPolicy(t *testing.T) { }, } - _, err := ToContainerGroup(convertCtx, project) + _, err := ToContainerGroup(context.TODO(), convertCtx, project) assert.Error(t, err, "ACI integration does not support specifying different restart policies on containers in the same compose application") } @@ -248,7 +249,7 @@ func TestLabelsErrorMessage(t *testing.T) { }, } - _, err := ToContainerGroup(convertCtx, project) + _, err := ToContainerGroup(context.TODO(), convertCtx, project) assert.Error(t, err, "ACI integration does not support labels in compose applications") } @@ -262,7 +263,7 @@ func TestComposeSingleContainerGroupToContainerDefaultRestartPolicy(t *testing.T }, } - group, err := ToContainerGroup(convertCtx, project) + group, err := ToContainerGroup(context.TODO(), convertCtx, project) assert.NilError(t, err) assert.Assert(t, is.Len(*group.Containers, 1)) @@ -296,7 +297,7 @@ func TestComposeContainerGroupToContainerMultiplePorts(t *testing.T) { }, } - group, err := ToContainerGroup(convertCtx, project) + group, err := ToContainerGroup(context.TODO(), convertCtx, project) assert.NilError(t, err) assert.Assert(t, is.Len(*group.Containers, 3)) @@ -335,7 +336,7 @@ func TestComposeContainerGroupToContainerResourceLimits(t *testing.T) { }, } - group, err := ToContainerGroup(convertCtx, project) + group, err := ToContainerGroup(context.TODO(), convertCtx, project) assert.NilError(t, err) limits := *((*group.Containers)[0]).Resources.Limits @@ -361,7 +362,7 @@ func TestComposeContainerGroupToContainerResourceLimitsDefaults(t *testing.T) { }, } - group, err := ToContainerGroup(convertCtx, project) + group, err := ToContainerGroup(context.TODO(), convertCtx, project) assert.NilError(t, err) limits := *((*group.Containers)[0]).Resources.Limits @@ -385,7 +386,7 @@ func TestComposeContainerGroupToContainerenvVar(t *testing.T) { }, } - group, err := ToContainerGroup(convertCtx, project) + group, err := ToContainerGroup(context.TODO(), convertCtx, project) assert.NilError(t, err) envVars := *((*group.Containers)[0]).EnvironmentVariables diff --git a/aci/convert/volume.go b/aci/convert/volume.go index e3b37a83d..bdda13618 100644 --- a/aci/convert/volume.go +++ b/aci/convert/volume.go @@ -18,7 +18,6 @@ package convert import ( "fmt" - "net/url" "strings" "github.com/pkg/errors" @@ -44,7 +43,6 @@ func GetRunVolumes(volumes []string) (map[string]types.VolumeConfig, []types.Ser Driver: azureFileDriverName, DriverOpts: map[string]string{ volumeDriveroptsAccountNameKey: vi.username, - volumeDriveroptsAccountKeyKey: vi.key, volumeDriveroptsShareNameKey: vi.share, }, } @@ -62,73 +60,26 @@ func GetRunVolumes(volumes []string) (map[string]types.VolumeConfig, []types.Ser type volumeInput struct { name string username string - key string share string target string } -func escapeKeySlashes(rawURL string) (string, error) { - urlSplit := strings.Split(rawURL, "@") - if len(urlSplit) < 1 { - return "", fmt.Errorf("invalid URL format: %s", rawURL) - } - userPasswd := strings.ReplaceAll(urlSplit[0], "/", "_") - - atIndex := strings.Index(rawURL, "@") - if atIndex < 0 { - return "", fmt.Errorf("no share specified in: %s", rawURL) - } - - scaped := userPasswd + rawURL[atIndex:] - - return scaped, nil -} - -func unescapeKey(key string) string { - return strings.ReplaceAll(key, "_", "/") -} - -// Removes the second ':' that separates the source from target -func volumeURL(pathURL string) (*url.URL, error) { - scapedURL, err := escapeKeySlashes(pathURL) - if err != nil { - return nil, err - } - pathURL = "//" + scapedURL - - count := strings.Count(pathURL, ":") - if count > 2 { - return nil, fmt.Errorf("invalid path URL: %s", pathURL) - } - if count == 2 { - tokens := strings.Split(pathURL, ":") - pathURL = fmt.Sprintf("%s:%s%s", tokens[0], tokens[1], tokens[2]) - } - return url.Parse(pathURL) -} - func (v *volumeInput) parse(name string, s string) error { - volumeURL, err := volumeURL(s) - if err != nil { - return errors.Wrapf(errdefs.ErrParsingFailed, "unable to parse volume specification: %s", err.Error()) - } - v.username = volumeURL.User.Username() - if v.username == "" { - return errors.Wrapf(errdefs.ErrParsingFailed, "volume specification %q does not include a storage username", v) - } - key, ok := volumeURL.User.Password() - if !ok || key == "" { - return errors.Wrapf(errdefs.ErrParsingFailed, "volume specification %q does not include a storage key", v) - } - v.key = unescapeKey(key) - v.share = volumeURL.Host - if v.share == "" { - return errors.Wrapf(errdefs.ErrParsingFailed, "volume specification %q does not include a storage file share", v) - } v.name = name - v.target = volumeURL.Path - if v.target == "" { - // Do not use filepath.Join, on Windows it will replace / by \ + tokens := strings.Split(s, "@") + if len(tokens) < 2 || tokens[0] == "" { + return errors.Wrapf(errdefs.ErrParsingFailed, "volume specification %q does not include a storage account before '@'", v) + } + v.username = tokens[0] + remaining := tokens[1] + tokens = strings.Split(remaining, ":") + if tokens[0] == "" { + return errors.Wrapf(errdefs.ErrParsingFailed, "volume specification %q does not include a storage file share after '@'", v) + } + v.share = tokens[0] + if len(tokens) > 1 { + v.target = tokens[1] + } else { v.target = "/run/volumes/" + v.share } return nil diff --git a/aci/convert/volume_test.go b/aci/convert/volume_test.go index 6a9da4470..b3bdebcdd 100644 --- a/aci/convert/volume_test.go +++ b/aci/convert/volume_test.go @@ -21,21 +21,18 @@ import ( "github.com/compose-spec/compose-go/types" "gotest.tools/v3/assert" - - "github.com/docker/api/errdefs" ) const ( storageAccountNameKey = "storage_account_name" - storageAccountKeyKey = "storage_account_key" shareNameKey = "share_name" ) func TestGetRunVolumes(t *testing.T) { volumeStrings := []string{ - "myuser1:mykey1@myshare1/my/path/to/target1", - "myuser2:mykey2@myshare2/my/path/to/target2", - "myuser3:mykey3@mydefaultsharename", // Use default placement at '/run/volumes/' + "myuser1@myshare1:/my/path/to/target1", + "myuser2@myshare2:/my/path/to/target2", + "myuser3@mydefaultsharename", // Use default placement at '/run/volumes/' } var goldenVolumeConfigs = map[string]types.VolumeConfig{ "volume-0": { @@ -43,7 +40,6 @@ func TestGetRunVolumes(t *testing.T) { Driver: "azure_file", DriverOpts: map[string]string{ storageAccountNameKey: "myuser1", - storageAccountKeyKey: "mykey1", shareNameKey: "myshare1", }, }, @@ -52,7 +48,6 @@ func TestGetRunVolumes(t *testing.T) { Driver: "azure_file", DriverOpts: map[string]string{ storageAccountNameKey: "myuser2", - storageAccountKeyKey: "mykey2", shareNameKey: "myshare2", }, }, @@ -61,7 +56,6 @@ func TestGetRunVolumes(t *testing.T) { Driver: "azure_file", DriverOpts: map[string]string{ storageAccountNameKey: "myuser3", - storageAccountKeyKey: "mykey3", shareNameKey: "mydefaultsharename", }, }, @@ -95,29 +89,16 @@ func TestGetRunVolumes(t *testing.T) { } func TestGetRunVolumesMissingFileShare(t *testing.T) { - _, _, err := GetRunVolumes([]string{"myuser:mykey@"}) - assert.Assert(t, errdefs.IsErrParsingFailed(err)) - assert.ErrorContains(t, err, "does not include a storage file share") + _, _, err := GetRunVolumes([]string{"myaccount@"}) + assert.ErrorContains(t, err, "does not include a storage file share after '@'") } func TestGetRunVolumesMissingUser(t *testing.T) { - _, _, err := GetRunVolumes([]string{":mykey@myshare"}) - assert.Assert(t, errdefs.IsErrParsingFailed(err)) - assert.ErrorContains(t, err, "does not include a storage username") -} - -func TestGetRunVolumesMissingKey(t *testing.T) { - _, _, err := GetRunVolumes([]string{"userwithnokey:@myshare"}) - assert.Assert(t, errdefs.IsErrParsingFailed(err)) - assert.ErrorContains(t, err, "does not include a storage key") - - _, _, err = GetRunVolumes([]string{"userwithnokeytoo@myshare"}) - assert.Assert(t, errdefs.IsErrParsingFailed(err)) - assert.ErrorContains(t, err, "does not include a storage key") + _, _, err := GetRunVolumes([]string{"@myshare"}) + assert.ErrorContains(t, err, "does not include a storage account before '@'") } func TestGetRunVolumesNoShare(t *testing.T) { _, _, err := GetRunVolumes([]string{"noshare"}) - assert.Assert(t, errdefs.IsErrParsingFailed(err)) - assert.ErrorContains(t, err, "no share specified") + assert.ErrorContains(t, err, "does not include a storage account before '@'") } diff --git a/aci/login/client.go b/aci/login/client.go new file mode 100644 index 000000000..ad92441bb --- /dev/null +++ b/aci/login/client.go @@ -0,0 +1,82 @@ +package login + +import ( + "time" + + "github.com/Azure/azure-sdk-for-go/profiles/2019-03-01/resources/mgmt/resources" + "github.com/Azure/azure-sdk-for-go/profiles/preview/preview/subscription/mgmt/subscription" + "github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance" + "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage" + "github.com/Azure/go-autorest/autorest" + "github.com/pkg/errors" + + "github.com/docker/api/errdefs" +) + +const userAgent = "docker-cli" + +// NewContainerGroupsClient get client toi manipulate containerGrouos +func NewContainerGroupsClient(subscriptionID string) (containerinstance.ContainerGroupsClient, error) { + containerGroupsClient := containerinstance.NewContainerGroupsClient(subscriptionID) + err := setupClient(&containerGroupsClient.Client) + if err != nil { + return containerinstance.ContainerGroupsClient{}, err + } + containerGroupsClient.PollingDelay = 5 * time.Second + containerGroupsClient.RetryAttempts = 30 + containerGroupsClient.RetryDuration = 1 * time.Second + return containerGroupsClient, nil +} + +func setupClient(aciClient *autorest.Client) error { + aciClient.UserAgent = userAgent + auth, err := NewAuthorizerFromLogin() + if err != nil { + return err + } + aciClient.Authorizer = auth + return nil +} + +// NewStorageAccountsClient get client to manipulate storage accounts +func NewStorageAccountsClient(subscriptionID string) (storage.AccountsClient, error) { + containerGroupsClient := storage.NewAccountsClient(subscriptionID) + err := setupClient(&containerGroupsClient.Client) + if err != nil { + return storage.AccountsClient{}, err + } + containerGroupsClient.PollingDelay = 5 * time.Second + containerGroupsClient.RetryAttempts = 30 + containerGroupsClient.RetryDuration = 1 * time.Second + return containerGroupsClient, nil +} + +// NewSubscriptionsClient get subscription client +func NewSubscriptionsClient() (subscription.SubscriptionsClient, error) { + subc := subscription.NewSubscriptionsClient() + err := setupClient(&subc.Client) + if err != nil { + return subscription.SubscriptionsClient{}, errors.Wrap(errdefs.ErrLoginRequired, err.Error()) + } + return subc, nil +} + +// NewGroupsClient get client to manipulate groups +func NewGroupsClient(subscriptionID string) (resources.GroupsClient, error) { + groupsClient := resources.NewGroupsClient(subscriptionID) + err := setupClient(&groupsClient.Client) + if err != nil { + return resources.GroupsClient{}, err + } + return groupsClient, nil +} + +// NewContainerClient get client to manipulate containers +func NewContainerClient(subscriptionID string) (containerinstance.ContainerClient, error) { + containerClient := containerinstance.NewContainerClient(subscriptionID) + err := setupClient(&containerClient.Client) + if err != nil { + return containerinstance.ContainerClient{}, err + } + return containerClient, nil +} diff --git a/aci/login/storage_helper.go b/aci/login/storage_helper.go new file mode 100644 index 000000000..51d047462 --- /dev/null +++ b/aci/login/storage_helper.go @@ -0,0 +1,34 @@ +package login + +import ( + "context" + "fmt" + + "github.com/pkg/errors" + + "github.com/docker/api/context/store" +) + +// StorageAccountHelper helper for Azure Storage Account +type StorageAccountHelper struct { + LoginService AzureLoginService + AciContext store.AciContext +} + +// GetAzureStorageAccountKey retrieves the storage account ket from the current azure login +func (helper StorageAccountHelper) GetAzureStorageAccountKey(ctx context.Context, accountName string) (string, error) { + client, err := NewStorageAccountsClient(helper.AciContext.SubscriptionID) + if err != nil { + return "", err + } + result, err := client.ListKeys(ctx, helper.AciContext.ResourceGroup, accountName, "") + if err != nil { + return "", errors.Wrap(err, fmt.Sprintf("could not access storage account acountKeys for %s, using the azure login", accountName)) + } + if result.Keys != nil && len((*result.Keys)) < 1 { + return "", fmt.Errorf("no key could be obtained for storage account %s from your azure login", accountName) + } + + key := (*result.Keys)[0] + return *key.Value, nil +} diff --git a/aci/resource_group.go b/aci/resource_group.go index d461936c2..e5f623f5c 100644 --- a/aci/resource_group.go +++ b/aci/resource_group.go @@ -23,7 +23,7 @@ import ( "github.com/Azure/azure-sdk-for-go/profiles/preview/preview/subscription/mgmt/subscription" "github.com/pkg/errors" - "github.com/docker/api/errdefs" + "github.com/docker/api/aci/login" ) // ResourceGroupHelper interface to manage resource groups and subscription IDs @@ -45,7 +45,7 @@ func NewACIResourceGroupHelper() ResourceGroupHelper { // GetGroup get a resource group from its name func (mgt aciResourceGroupHelperImpl) GetGroup(ctx context.Context, subscriptionID string, groupName string) (resources.Group, error) { - gc, err := getGroupsClient(subscriptionID) + gc, err := login.NewGroupsClient(subscriptionID) if err != nil { return resources.Group{}, err } @@ -54,7 +54,7 @@ func (mgt aciResourceGroupHelperImpl) GetGroup(ctx context.Context, subscription // ListGroups list resource groups func (mgt aciResourceGroupHelperImpl) ListGroups(ctx context.Context, subscriptionID string) ([]resources.Group, error) { - gc, err := getGroupsClient(subscriptionID) + gc, err := login.NewGroupsClient(subscriptionID) if err != nil { return nil, err } @@ -80,7 +80,7 @@ func (mgt aciResourceGroupHelperImpl) ListGroups(ctx context.Context, subscripti // CreateOrUpdate create or update a resource group func (mgt aciResourceGroupHelperImpl) CreateOrUpdate(ctx context.Context, subscriptionID string, resourceGroupName string, parameters resources.Group) (result resources.Group, err error) { - gc, err := getGroupsClient(subscriptionID) + gc, err := login.NewGroupsClient(subscriptionID) if err != nil { return resources.Group{}, err } @@ -89,7 +89,7 @@ func (mgt aciResourceGroupHelperImpl) CreateOrUpdate(ctx context.Context, subscr // DeleteAsync deletes a resource group. Does not wait for full deletion to return (long operation) func (mgt aciResourceGroupHelperImpl) DeleteAsync(ctx context.Context, subscriptionID string, resourceGroupName string) (err error) { - gc, err := getGroupsClient(subscriptionID) + gc, err := login.NewGroupsClient(subscriptionID) if err != nil { return err } @@ -100,7 +100,7 @@ func (mgt aciResourceGroupHelperImpl) DeleteAsync(ctx context.Context, subscript // GetSubscriptionIDs Return available subscription IDs based on azure login func (mgt aciResourceGroupHelperImpl) GetSubscriptionIDs(ctx context.Context) ([]subscription.Model, error) { - c, err := getSubscriptionsClient() + c, err := login.NewSubscriptionsClient() if err != nil { return nil, err } @@ -122,21 +122,3 @@ func (mgt aciResourceGroupHelperImpl) GetSubscriptionIDs(ctx context.Context) ([ } return subs, nil } - -func getSubscriptionsClient() (subscription.SubscriptionsClient, error) { - subc := subscription.NewSubscriptionsClient() - err := setupClient(&subc.Client) - if err != nil { - return subscription.SubscriptionsClient{}, errors.Wrap(errdefs.ErrLoginRequired, err.Error()) - } - return subc, nil -} - -func getGroupsClient(subscriptionID string) (resources.GroupsClient, error) { - groupsClient := resources.NewGroupsClient(subscriptionID) - err := setupClient(&groupsClient.Client) - if err != nil { - return resources.GroupsClient{}, err - } - return groupsClient, nil -} diff --git a/tests/aci-e2e/e2e-aci_test.go b/tests/aci-e2e/e2e-aci_test.go index b51816470..cf2ea3183 100644 --- a/tests/aci-e2e/e2e-aci_test.go +++ b/tests/aci-e2e/e2e-aci_test.go @@ -165,7 +165,7 @@ func TestContainerRun(t *testing.T) { mountTarget := "/usr/share/nginx/html" res := c.RunDockerCmd( "run", "-d", - "-v", fmt.Sprintf("%s:%s@%s:%s", saName, k, testShareName, mountTarget), + "-v", fmt.Sprintf("%s@%s:%s", saName, testShareName, mountTarget), "-p", "80:80", "nginx", ) diff --git a/tests/composefiles/aci-demo/aci_demo_port_secrets_volumes.yaml b/tests/composefiles/aci-demo/aci_demo_port_secrets_volumes.yaml index 1469e65d8..eb4f1b25b 100644 --- a/tests/composefiles/aci-demo/aci_demo_port_secrets_volumes.yaml +++ b/tests/composefiles/aci-demo/aci_demo_port_secrets_volumes.yaml @@ -14,10 +14,6 @@ services: image: gtardif/sentences-web ports: - "80:80" - secrets: - - source: mysecret1 - target: mytarget1 - - mysecret2 volumes: - mydata:/mount/testvolumes @@ -25,12 +21,5 @@ volumes: mydata: driver: azure_file driver_opts: - share_name: gtashare1 - storage_account_name: gtastorageaccount1 - storage_account_key: UZyyUyZJA0LYrPrXqvB+HP+gGWD0K54LNmtfV+xwGQ18JufaAQ7vtUhcJoEcFUUrm40mehLKtvi4n58w0ivDtQ== - -secrets: - mysecret1: - file: ./my_secret1.txt - mysecret2: - file: ./my_secret2.txt + share_name: minecraft-volume + storage_account_name: minecraftdocker