Added volume delete, can delete juste a file share or the storage account if confirmed

Signed-off-by: Guillaume Tardif <guillaume.tardif@docker.com>
This commit is contained in:
Guillaume Tardif 2020-09-08 15:27:56 +02:00
parent 2f672f6c4c
commit 96d785a5bd
14 changed files with 156 additions and 84 deletions

View File

@ -40,6 +40,7 @@ const (
backendType = store.AciContextType backendType = store.AciContextType
singleContainerTag = "docker-single-container" singleContainerTag = "docker-single-container"
composeContainerTag = "docker-compose-application" composeContainerTag = "docker-compose-application"
dockerVolumeTag = "docker-volume"
composeContainerSeparator = "_" composeContainerSeparator = "_"
) )
@ -149,7 +150,6 @@ func addTag(groupDefinition *containerinstance.ContainerGroup, tagName string) {
groupDefinition.Tags[tagName] = to.StringPtr(tagName) groupDefinition.Tags[tagName] = to.StringPtr(tagName)
} }
func getGroupAndContainerName(containerID string) (string, string) { func getGroupAndContainerName(containerID string) (string, string) {
tokens := strings.Split(containerID, composeContainerSeparator) tokens := strings.Split(containerID, composeContainerSeparator)
groupName := tokens[0] groupName := tokens[0]
@ -160,4 +160,3 @@ func getGroupAndContainerName(containerID string) (string, string) {
} }
return groupName, containerName return groupName, containerName
} }

View File

@ -18,7 +18,9 @@ package aci
import ( import (
"context" "context"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/docker/compose-cli/aci/login" "github.com/docker/compose-cli/aci/login"
) )

View File

@ -124,5 +124,3 @@ func (cs *aciComposeService) Logs(ctx context.Context, project string, w io.Writ
func (cs *aciComposeService) Convert(ctx context.Context, project *types.Project) ([]byte, error) { func (cs *aciComposeService) Convert(ctx context.Context, project *types.Project) ([]byte, error) {
return nil, errdefs.ErrNotImplemented return nil, errdefs.ErrNotImplemented
} }

View File

@ -62,7 +62,6 @@ func (cs *aciContainerService) List(ctx context.Context, all bool) ([]containers
return res, nil return res, nil
} }
func (cs *aciContainerService) Run(ctx context.Context, r containers.ContainerConfig) error { func (cs *aciContainerService) Run(ctx context.Context, r containers.ContainerConfig) error {
if strings.Contains(r.ID, composeContainerSeparator) { if strings.Contains(r.ID, composeContainerSeparator) {
return errors.New(fmt.Sprintf("invalid container name. ACI container name cannot include %q", composeContainerSeparator)) return errors.New(fmt.Sprintf("invalid container name. ACI container name cannot include %q", composeContainerSeparator))

View File

@ -46,4 +46,4 @@ func (helper StorageLogin) GetAzureStorageAccountKey(ctx context.Context, accoun
key := (*result.Keys)[0] key := (*result.Keys)[0]
return *key.Value, nil return *key.Value, nil
} }

View File

@ -19,7 +19,9 @@ package aci
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/Azure/go-autorest/autorest/to" "github.com/Azure/go-autorest/autorest/to"
"github.com/docker/compose-cli/aci/login" "github.com/docker/compose-cli/aci/login"
"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage" "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage"
@ -76,6 +78,13 @@ type VolumeCreateOptions struct {
Fileshare string Fileshare string
} }
//VolumeDeleteOptions options to create a new ACI volume
type VolumeDeleteOptions struct {
Account string
Fileshare string
DeleteAccount bool
}
func (cs *aciVolumeService) Create(ctx context.Context, options interface{}) (volumes.Volume, error) { func (cs *aciVolumeService) Create(ctx context.Context, options interface{}) (volumes.Volume, error) {
opts, ok := options.(VolumeCreateOptions) opts, ok := options.(VolumeCreateOptions)
if !ok { if !ok {
@ -91,6 +100,16 @@ func (cs *aciVolumeService) Create(ctx context.Context, options interface{}) (vo
return volumes.Volume{}, err return volumes.Volume{}, err
} }
//TODO confirm storage account creation //TODO confirm storage account creation
result, err := accountClient.CheckNameAvailability(ctx, storage.AccountCheckNameAvailabilityParameters{
Name: to.StringPtr(opts.Account),
Type: to.StringPtr("Microsoft.Storage/storageAccounts"),
})
if err != nil {
return volumes.Volume{}, err
}
if !*result.NameAvailable {
return volumes.Volume{}, errors.New("error: " + *result.Message)
}
parameters := defaultStorageAccountParams(cs.aciContext) parameters := defaultStorageAccountParams(cs.aciContext)
// TODO progress account creation // TODO progress account creation
future, err := accountClient.Create(ctx, cs.aciContext.ResourceGroup, opts.Account, parameters) future, err := accountClient.Create(ctx, cs.aciContext.ResourceGroup, opts.Account, parameters)
@ -125,6 +144,32 @@ func (cs *aciVolumeService) Create(ctx context.Context, options interface{}) (vo
return toVolume(account, *fileShare.Name), nil return toVolume(account, *fileShare.Name), nil
} }
func (cs *aciVolumeService) Delete(ctx context.Context, options interface{}) error {
opts, ok := options.(VolumeDeleteOptions)
if !ok {
return errors.New("Could not read azure VolumeDeleteOptions struct from generic parameter")
}
if opts.DeleteAccount {
//TODO check if there are other shares on this account
//TODO flag account and only delete ours
storageAccountsClient, err := login.NewStorageAccountsClient(cs.aciContext.SubscriptionID)
if err != nil {
return err
}
_, err = storageAccountsClient.Delete(ctx, cs.aciContext.ResourceGroup, opts.Account)
return err
}
fileShareClient, err := login.NewFileShareClient(cs.aciContext.SubscriptionID)
if err != nil {
return err
}
_, err = fileShareClient.Delete(ctx, cs.aciContext.ResourceGroup, opts.Account, opts.Fileshare)
return err
}
func toVolume(account storage.Account, fileShareName string) volumes.Volume { func toVolume(account storage.Account, fileShareName string) volumes.Volume {
return volumes.Volume{ return volumes.Volume{
ID: fmt.Sprintf("%s@%s", *account.Name, fileShareName), ID: fmt.Sprintf("%s@%s", *account.Name, fileShareName),
@ -134,12 +179,12 @@ func toVolume(account storage.Account, fileShareName string) volumes.Volume {
} }
func defaultStorageAccountParams(aciContext store.AciContext) storage.AccountCreateParameters { func defaultStorageAccountParams(aciContext store.AciContext) storage.AccountCreateParameters {
tags := map[string]*string{dockerVolumeTag: to.StringPtr(dockerVolumeTag)}
return storage.AccountCreateParameters{ return storage.AccountCreateParameters{
Location: to.StringPtr(aciContext.Location), Location: to.StringPtr(aciContext.Location),
Sku: &storage.Sku{ Sku: &storage.Sku{
Name: storage.StandardLRS, Name: storage.StandardLRS,
}, },
Kind:storage.StorageV2, Tags: tags,
AccountPropertiesCreateParameters: &storage.AccountPropertiesCreateParameters{},
} }
} }

View File

@ -26,12 +26,14 @@ import (
type volumeService struct { type volumeService struct {
} }
// List list volumes
func (c *volumeService) List(ctx context.Context) ([]volumes.Volume, error) { func (c *volumeService) List(ctx context.Context) ([]volumes.Volume, error) {
return nil, errdefs.ErrNotImplemented return nil, errdefs.ErrNotImplemented
} }
// Create creates a volume
func (c *volumeService) Create(ctx context.Context, options interface{}) (volumes.Volume, error) { func (c *volumeService) Create(ctx context.Context, options interface{}) (volumes.Volume, error) {
return volumes.Volume{}, errdefs.ErrNotImplemented return volumes.Volume{}, errdefs.ErrNotImplemented
} }
func (c *volumeService) Delete(ctx context.Context, options interface{}) error {
return errdefs.ErrNotImplemented
}

View File

@ -31,5 +31,8 @@ type Volume struct {
type Service interface { type Service interface {
// List returns all available volumes // List returns all available volumes
List(ctx context.Context) ([]Volume, error) List(ctx context.Context) ([]Volume, error)
// Create creates a new volume
Create(ctx context.Context, options interface{}) (Volume, error) Create(ctx context.Context, options interface{}) (Volume, error)
// Delete deletes an existing volume
Delete(ctx context.Context, options interface{}) error
} }

View File

@ -35,5 +35,5 @@ func TestPrintList(t *testing.T) {
} }
out := &bytes.Buffer{} out := &bytes.Buffer{}
printList(out, secrets) printList(out, secrets)
golden.Assert(t, out.String(), "volumes-out.golden") golden.Assert(t, out.String(), "secrets-out.golden")
} }

View File

@ -1,5 +1,3 @@
package volume
/* /*
Copyright 2020 Docker, Inc. Copyright 2020 Docker, Inc.
@ -16,13 +14,17 @@ package volume
limitations under the License. limitations under the License.
*/ */
package volume
import ( import (
"fmt" "fmt"
"io" "io"
"os" "os"
"strings" "strings"
"text/tabwriter" "text/tabwriter"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/docker/compose-cli/api/client" "github.com/docker/compose-cli/api/client"
"github.com/docker/compose-cli/api/volumes" "github.com/docker/compose-cli/api/volumes"
) )

View File

@ -1,10 +1,28 @@
/*
Copyright 2020 Docker, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package volume package volume
import ( import (
"bytes" "bytes"
"github.com/docker/compose-cli/api/volumes"
"gotest.tools/v3/golden"
"testing" "testing"
"gotest.tools/v3/golden"
"github.com/docker/compose-cli/api/volumes"
) )
func TestPrintList(t *testing.T) { func TestPrintList(t *testing.T) {
@ -19,4 +37,3 @@ func TestPrintList(t *testing.T) {
printList(out, secrets) printList(out, secrets)
golden.Assert(t, out.String(), "volumes-out.golden") golden.Assert(t, out.String(), "volumes-out.golden")
} }

View File

@ -1,5 +1,3 @@
package volume
/* /*
Copyright 2020 Docker, Inc. Copyright 2020 Docker, Inc.
@ -16,9 +14,13 @@ package volume
limitations under the License. limitations under the License.
*/ */
package volume
import ( import (
"fmt" "fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/docker/compose-cli/aci" "github.com/docker/compose-cli/aci"
"github.com/docker/compose-cli/api/client" "github.com/docker/compose-cli/api/client"
) )
@ -33,6 +35,7 @@ func Command() *cobra.Command {
cmd.AddCommand( cmd.AddCommand(
createVolume(), createVolume(),
listVolume(), listVolume(),
rmVolume(),
) )
return cmd return cmd
} }
@ -60,4 +63,25 @@ func createVolume() *cobra.Command {
cmd.Flags().StringVar(&opts.Account, "storage-account", "", "Storage account name") cmd.Flags().StringVar(&opts.Account, "storage-account", "", "Storage account name")
cmd.Flags().StringVar(&opts.Fileshare, "fileshare", "", "Fileshare name") cmd.Flags().StringVar(&opts.Fileshare, "fileshare", "", "Fileshare name")
return cmd return cmd
} }
func rmVolume() *cobra.Command {
opts := aci.VolumeDeleteOptions{}
cmd := &cobra.Command{
Use: "rm",
Short: "Deletes an Azure file share and/or the Azure storage account.",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
c, err := client.New(cmd.Context())
if err != nil {
return err
}
return c.VolumeService().Delete(cmd.Context(), opts)
},
}
cmd.Flags().StringVar(&opts.Account, "storage-account", "", "Storage account name")
cmd.Flags().StringVar(&opts.Fileshare, "fileshare", "", "Fileshare name")
cmd.Flags().BoolVar(&opts.DeleteAccount, "delete-storage-account", false, "Also delete storage account")
return cmd
}

View File

@ -47,7 +47,6 @@ import (
"github.com/docker/compose-cli/api/containers" "github.com/docker/compose-cli/api/containers"
"github.com/docker/compose-cli/context/store" "github.com/docker/compose-cli/context/store"
"github.com/docker/compose-cli/errdefs" "github.com/docker/compose-cli/errdefs"
"github.com/docker/compose-cli/tests/aci-e2e/storage"
. "github.com/docker/compose-cli/tests/framework" . "github.com/docker/compose-cli/tests/framework"
) )
@ -151,30 +150,54 @@ func TestContainerRunVolume(t *testing.T) {
accountName = "e2e" + strconv.Itoa(int(time.Now().UnixNano())) accountName = "e2e" + strconv.Itoa(int(time.Now().UnixNano()))
) )
t.Run("Create volumes", func(t *testing.T) { t.Run("check volume name validity", func(t *testing.T) {
invalidName := "some-storage-123"
res := c.RunDockerOrExitError("volume", "create", "--storage-account", invalidName, "--fileshare", fileshareName)
res.Assert(t, icmd.Expected{
ExitCode: 1,
Err: "some-storage-123 is not a valid storage account name. Storage account name must be between 3 and 24 characters in length and use numbers and lower-case letters only.",
})
})
t.Run("create volumes", func(t *testing.T) {
c.RunDockerCmd("volume", "create", "--storage-account", accountName, "--fileshare", fileshareName) c.RunDockerCmd("volume", "create", "--storage-account", accountName, "--fileshare", fileshareName)
}) })
t.Cleanup(func() { deleteStorageAccount(t, aciContext, accountName) })
t.Run("Create second fileshare", func(t *testing.T) { t.Cleanup(func() {
c.RunDockerCmd("volume", "rm", "--storage-account", accountName, "--delete-storage-account")
res := c.RunDockerCmd("volume", "ls")
lines := lines(res.Stdout())
assert.Equal(t, len(lines), 1)
})
t.Run("create second fileshare", func(t *testing.T) {
c.RunDockerCmd("volume", "create", "--storage-account", accountName, "--fileshare", "dockertestshare2") c.RunDockerCmd("volume", "create", "--storage-account", accountName, "--fileshare", "dockertestshare2")
}) })
t.Run("list volumes", func(t *testing.T) { t.Run("list volumes", func(t *testing.T) {
res := c.RunDockerCmd("volume", "ls") res := c.RunDockerCmd("volume", "ls")
out := strings.Split(strings.TrimSpace(res.Stdout()), "\n") lines := lines(res.Stdout())
firstAccount := out[1] assert.Equal(t, len(lines), 3)
firstAccount := lines[1]
fields := strings.Fields(firstAccount) fields := strings.Fields(firstAccount)
volumeID = accountName + "@" + fileshareName volumeID = accountName + "@" + fileshareName
assert.Equal(t, fields[0], volumeID) assert.Equal(t, fields[0], volumeID)
assert.Equal(t, fields[1], fileshareName) assert.Equal(t, fields[1], fileshareName)
secondAccount := out[2] secondAccount := lines[2]
fields = strings.Fields(secondAccount) fields = strings.Fields(secondAccount)
assert.Equal(t, fields[0], accountName + "@dockertestshare2") assert.Equal(t, fields[0], accountName+"@dockertestshare2")
assert.Equal(t, fields[1], "dockertestshare2") assert.Equal(t, fields[1], "dockertestshare2")
//assert.Assert(t, fields[2], strings.Contains(firstAccount, fmt.Sprintf("Fileshare %s in %s storage account", fileshareName, accountName))) //assert.Assert(t, fields[2], strings.Contains(firstAccount, fmt.Sprintf("Fileshare %s in %s storage account", fileshareName, accountName)))
}) })
t.Run("delete only fileshare", func(t *testing.T) {
c.RunDockerCmd("volume", "rm", "--storage-account", accountName, "--fileshare", "dockertestshare2")
res := c.RunDockerCmd("volume", "ls")
lines := lines(res.Stdout())
assert.Equal(t, len(lines), 2)
assert.Assert(t, !strings.Contains(res.Stdout(), "dockertestshare2"), "second fileshare still visible after rm")
})
t.Run("upload file", func(t *testing.T) { t.Run("upload file", func(t *testing.T) {
storageLogin := login.StorageLogin{AciContext: aciContext} storageLogin := login.StorageLogin{AciContext: aciContext}
@ -213,7 +236,7 @@ func TestContainerRunVolume(t *testing.T) {
t.Run("ps", func(t *testing.T) { t.Run("ps", func(t *testing.T) {
res := c.RunDockerCmd("ps") res := c.RunDockerCmd("ps")
out := strings.Split(strings.TrimSpace(res.Stdout()), "\n") out := lines(res.Stdout())
l := out[len(out)-1] l := out[len(out)-1]
assert.Assert(t, strings.Contains(l, container), "Looking for %q in line: %s", container, l) assert.Assert(t, strings.Contains(l, container), "Looking for %q in line: %s", container, l)
assert.Assert(t, strings.Contains(l, "nginx")) assert.Assert(t, strings.Contains(l, "nginx"))
@ -308,6 +331,10 @@ func TestContainerRunVolume(t *testing.T) {
}) })
} }
func lines(output string) []string {
return strings.Split(strings.TrimSpace(output), "\n")
}
func TestContainerRunAttached(t *testing.T) { func TestContainerRunAttached(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelE2eCLI(t, binDir)
_, _ = setupTestResourceGroup(t, c) _, _ = setupTestResourceGroup(t, c)
@ -398,11 +425,11 @@ func TestContainerRunAttached(t *testing.T) {
t.Run("ps stopped container with --all", func(t *testing.T) { t.Run("ps stopped container with --all", func(t *testing.T) {
res := c.RunDockerCmd("ps", container) res := c.RunDockerCmd("ps", container)
out := strings.Split(strings.TrimSpace(res.Stdout()), "\n") out := lines(res.Stdout())
assert.Assert(t, is.Len(out, 1)) assert.Assert(t, is.Len(out, 1))
res = c.RunDockerCmd("ps", "--all", container) res = c.RunDockerCmd("ps", "--all", container)
out = strings.Split(strings.TrimSpace(res.Stdout()), "\n") out = lines(res.Stdout())
assert.Assert(t, is.Len(out, 2)) assert.Assert(t, is.Len(out, 2))
}) })
@ -439,7 +466,7 @@ func TestComposeUpUpdate(t *testing.T) {
// Name of Compose project is taken from current folder "acie2e" // Name of Compose project is taken from current folder "acie2e"
c.RunDockerCmd("compose", "up", "-f", composeFile) c.RunDockerCmd("compose", "up", "-f", composeFile)
res := c.RunDockerCmd("ps") res := c.RunDockerCmd("ps")
out := strings.Split(strings.TrimSpace(res.Stdout()), "\n") out := lines(res.Stdout())
// Check three containers are running // Check three containers are running
assert.Assert(t, is.Len(out, 4)) assert.Assert(t, is.Len(out, 4))
webRunning := false webRunning := false
@ -468,7 +495,7 @@ func TestComposeUpUpdate(t *testing.T) {
t.Run("compose ps", func(t *testing.T) { t.Run("compose ps", func(t *testing.T) {
res := c.RunDockerCmd("compose", "ps", "--project-name", composeProjectName) res := c.RunDockerCmd("compose", "ps", "--project-name", composeProjectName)
lines := strings.Split(strings.TrimSpace(res.Stdout()), "\n") lines := lines(res.Stdout())
assert.Assert(t, is.Len(lines, 4)) assert.Assert(t, is.Len(lines, 4))
var wordsDisplayed, webDisplayed, dbDisplayed bool var wordsDisplayed, webDisplayed, dbDisplayed bool
for _, line := range lines { for _, line := range lines {
@ -492,7 +519,7 @@ func TestComposeUpUpdate(t *testing.T) {
t.Run("compose ls", func(t *testing.T) { t.Run("compose ls", func(t *testing.T) {
res := c.RunDockerCmd("compose", "ls") res := c.RunDockerCmd("compose", "ls")
lines := strings.Split(strings.TrimSpace(res.Stdout()), "\n") lines := lines(res.Stdout())
assert.Equal(t, 2, len(lines)) assert.Equal(t, 2, len(lines))
fields := strings.Fields(lines[1]) fields := strings.Fields(lines[1])
@ -509,7 +536,7 @@ func TestComposeUpUpdate(t *testing.T) {
t.Run("update", func(t *testing.T) { t.Run("update", func(t *testing.T) {
c.RunDockerCmd("compose", "up", "-f", composeFileMultiplePorts, "--project-name", composeProjectName) c.RunDockerCmd("compose", "up", "-f", composeFileMultiplePorts, "--project-name", composeProjectName)
res := c.RunDockerCmd("ps") res := c.RunDockerCmd("ps")
out := strings.Split(strings.TrimSpace(res.Stdout()), "\n") out := lines(res.Stdout())
// Check three containers are running // Check three containers are running
assert.Assert(t, is.Len(out, 4)) assert.Assert(t, is.Len(out, 4))
@ -551,7 +578,7 @@ func TestComposeUpUpdate(t *testing.T) {
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
c.RunDockerCmd("compose", "down", "--project-name", composeProjectName) c.RunDockerCmd("compose", "down", "--project-name", composeProjectName)
res := c.RunDockerCmd("ps") res := c.RunDockerCmd("ps")
out := strings.Split(strings.TrimSpace(res.Stdout()), "\n") out := lines(res.Stdout())
assert.Equal(t, len(out), 1) assert.Equal(t, len(out), 1)
}) })
} }
@ -572,7 +599,7 @@ func TestRunEnvVars(t *testing.T) {
cmd.Env = append(cmd.Env, "MYSQL_USER=user1") cmd.Env = append(cmd.Env, "MYSQL_USER=user1")
res := icmd.RunCmd(cmd) res := icmd.RunCmd(cmd)
res.Assert(t, icmd.Success) res.Assert(t, icmd.Success)
out := strings.Split(strings.TrimSpace(res.Stdout()), "\n") out := lines(res.Stdout())
container := strings.TrimSpace(out[len(out)-1]) container := strings.TrimSpace(out[len(out)-1])
res = c.RunDockerCmd("inspect", container) res = c.RunDockerCmd("inspect", container)
@ -607,7 +634,7 @@ func setupTestResourceGroup(t *testing.T, c *E2eCLI) (string, string) {
createAciContextAndUseIt(t, c, sID, rg) createAciContextAndUseIt(t, c, sID, rg)
// Check nothing is running // Check nothing is running
res := c.RunDockerCmd("ps") res := c.RunDockerCmd("ps")
assert.Assert(t, is.Len(strings.Split(strings.TrimSpace(res.Stdout()), "\n"), 1)) assert.Assert(t, is.Len(lines(res.Stdout()), 1))
return sID, rg return sID, rg
} }
@ -661,14 +688,6 @@ func createAciContextAndUseIt(t *testing.T, c *E2eCLI, sID, rgName string) {
res.Assert(t, icmd.Expected{Out: contextName + " *"}) res.Assert(t, icmd.Expected{Out: contextName + " *"})
} }
func deleteStorageAccount(t *testing.T, aciContext store.AciContext, name string) {
fmt.Printf(" [%s] deleting storage account %s\n", t.Name(), name)
_, err := storage.DeleteStorageAccount(context.TODO(), aciContext, name)
if err != nil {
t.Error(err)
}
}
func uploadFile(t *testing.T, cred azfile.SharedKeyCredential, baseURL, fileName, content string) { func uploadFile(t *testing.T, cred azfile.SharedKeyCredential, baseURL, fileName, content string) {
fURL, err := url.Parse(baseURL + "/" + fileName) fURL, err := url.Parse(baseURL + "/" + fileName)
assert.NilError(t, err) assert.NilError(t, err)
@ -678,7 +697,7 @@ func uploadFile(t *testing.T, cred azfile.SharedKeyCredential, baseURL, fileName
} }
func getContainerName(stdout string) string { func getContainerName(stdout string) string {
out := strings.Split(strings.TrimSpace(stdout), "\n") out := lines(stdout)
return strings.TrimSpace(out[len(out)-1]) return strings.TrimSpace(out[len(out)-1])
} }

View File

@ -1,38 +0,0 @@
/*
Copyright 2020 Docker, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package storage
import (
"context"
"github.com/Azure/go-autorest/autorest"
"github.com/docker/compose-cli/aci/login"
"github.com/docker/compose-cli/context/store"
)
// DeleteStorageAccount deletes a given storage account
func DeleteStorageAccount(ctx context.Context, aciContext store.AciContext, accountName string) (autorest.Response, error) {
storageAccountsClient, err := login.NewStorageAccountsClient(aciContext.SubscriptionID)
if err != nil {
return autorest.Response{}, err
}
response, err := storageAccountsClient.Delete(ctx, aciContext.ResourceGroup, accountName)
if err != nil {
return autorest.Response{}, err
}
return response, err
}