mirror of https://github.com/docker/compose.git
Removed NAME from `volume ls` output, allow `volume delete <ID>` using IDs from `volume ls`.
Signed-off-by: Guillaume Tardif <guillaume.tardif@docker.com>
This commit is contained in:
parent
38a8f5310b
commit
80d23a6097
|
@ -19,6 +19,7 @@ package aci
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/compose-cli/progress"
|
||||
|
||||
|
@ -80,17 +81,10 @@ type VolumeCreateOptions struct {
|
|||
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) {
|
||||
opts, ok := options.(VolumeCreateOptions)
|
||||
if !ok {
|
||||
return volumes.Volume{}, errors.New("Could not read azure LoginParams struct from generic parameter")
|
||||
return volumes.Volume{}, errors.New("Could not read azure VolumeCreateOptions struct from generic parameter")
|
||||
}
|
||||
w := progress.ContextWriter(ctx)
|
||||
w.Event(event(opts.Account, progress.Working, "Validating"))
|
||||
|
@ -105,7 +99,6 @@ func (cs *aciVolumeService) Create(ctx context.Context, options interface{}) (vo
|
|||
if account.StatusCode != 404 {
|
||||
return volumes.Volume{}, err
|
||||
}
|
||||
//TODO confirm storage account creation
|
||||
result, err := accountClient.CheckNameAvailability(ctx, storage.AccountCheckNameAvailabilityParameters{
|
||||
Name: to.StringPtr(opts.Account),
|
||||
Type: to.StringPtr("Microsoft.Storage/storageAccounts"),
|
||||
|
@ -177,49 +170,62 @@ func errorEvent(resource string) progress.Event {
|
|||
}
|
||||
}
|
||||
|
||||
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 fileshares on this account
|
||||
storageAccountsClient, err := login.NewStorageAccountsClient(cs.aciContext.SubscriptionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := storageAccountsClient.Delete(ctx, cs.aciContext.ResourceGroup, opts.Account)
|
||||
if result.StatusCode == 204 {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "storage account %s does not exist", opts.Account)
|
||||
}
|
||||
|
||||
return err
|
||||
func (cs *aciVolumeService) Delete(ctx context.Context, id string, options interface{}) error {
|
||||
tokens := strings.Split(id, "@")
|
||||
if len(tokens) != 2 {
|
||||
return errors.New("wrong format for volume ID : should be storageaccount@fileshare")
|
||||
}
|
||||
storageAccount := tokens[0]
|
||||
fileshare := tokens[1]
|
||||
|
||||
fileShareClient, err := login.NewFileShareClient(cs.aciContext.SubscriptionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := fileShareClient.Delete(ctx, cs.aciContext.ResourceGroup, opts.Account, opts.Fileshare)
|
||||
if result.StatusCode == 204 {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "fileshare %s does not exist", opts.Fileshare)
|
||||
fileShareItemsPage, err := fileShareClient.List(ctx, cs.aciContext.ResourceGroup, storageAccount, "", "", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result.StatusCode == 404 {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "storage account %s does not exist", opts.Account)
|
||||
fileshares := fileShareItemsPage.Values()
|
||||
if len(fileshares) == 1 && *fileshares[0].Name == fileshare {
|
||||
storageAccountsClient, err := login.NewStorageAccountsClient(cs.aciContext.SubscriptionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
account, err := storageAccountsClient.GetProperties(ctx, cs.aciContext.ResourceGroup, storageAccount, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err == nil {
|
||||
if _, ok := account.Tags[dockerVolumeTag]; ok {
|
||||
result, err := storageAccountsClient.Delete(ctx, cs.aciContext.ResourceGroup, storageAccount)
|
||||
if result.StatusCode == 204 {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "storage account %s does not exist", storageAccount)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result, err := fileShareClient.Delete(ctx, cs.aciContext.ResourceGroup, storageAccount, fileshare)
|
||||
if result.StatusCode == 204 {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "fileshare %s does not exist", fileshare)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func toVolume(account storage.Account, fileShareName string) volumes.Volume {
|
||||
return volumes.Volume{
|
||||
ID: fmt.Sprintf("%s@%s", *account.Name, fileShareName),
|
||||
Name: fileShareName,
|
||||
ID: VolumeID(*account.Name, fileShareName),
|
||||
Description: fmt.Sprintf("Fileshare %s in %s storage account", fileShareName, *account.Name),
|
||||
}
|
||||
}
|
||||
|
||||
// VolumeID generate volume ID from azure storage accoun & fileshare
|
||||
func VolumeID(storageAccount string, fileShareName string) string {
|
||||
return fmt.Sprintf("%s@%s", storageAccount, fileShareName)
|
||||
}
|
||||
|
||||
func defaultStorageAccountParams(aciContext store.AciContext) storage.AccountCreateParameters {
|
||||
tags := map[string]*string{dockerVolumeTag: to.StringPtr(dockerVolumeTag)}
|
||||
return storage.AccountCreateParameters{
|
||||
|
|
|
@ -34,6 +34,6 @@ func (c *volumeService) Create(ctx context.Context, options interface{}) (volume
|
|||
return volumes.Volume{}, errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (c *volumeService) Delete(ctx context.Context, options interface{}) error {
|
||||
func (c *volumeService) Delete(ctx context.Context, id string, options interface{}) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ import (
|
|||
// Volume volume info
|
||||
type Volume struct {
|
||||
ID string
|
||||
Name string
|
||||
Description string
|
||||
}
|
||||
|
||||
|
@ -34,5 +33,5 @@ type Service interface {
|
|||
// Create creates a new volume
|
||||
Create(ctx context.Context, options interface{}) (Volume, error)
|
||||
// Delete deletes an existing volume
|
||||
Delete(ctx context.Context, options interface{}) error
|
||||
Delete(ctx context.Context, volumeID string, options interface{}) error
|
||||
}
|
||||
|
|
|
@ -53,9 +53,9 @@ func listVolume() *cobra.Command {
|
|||
func printList(out io.Writer, volumes []volumes.Volume) {
|
||||
printSection(out, func(w io.Writer) {
|
||||
for _, vol := range volumes {
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\n", vol.ID, vol.Name, vol.Description) // nolint:errcheck
|
||||
fmt.Fprintf(w, "%s\t%s\n", vol.ID, vol.Description) // nolint:errcheck
|
||||
}
|
||||
}, "ID", "NAME", "DESCRIPTION")
|
||||
}, "ID", "DESCRIPTION")
|
||||
}
|
||||
|
||||
func printSection(out io.Writer, printer func(io.Writer), headers ...string) {
|
||||
|
|
|
@ -29,7 +29,6 @@ func TestPrintList(t *testing.T) {
|
|||
secrets := []volumes.Volume{
|
||||
{
|
||||
ID: "volume@123",
|
||||
Name: "123",
|
||||
Description: "volume 123",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -19,6 +19,9 @@ package volume
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
|
@ -64,8 +67,8 @@ func createVolume() *cobra.Command {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("volume successfully created\n")
|
||||
return err
|
||||
fmt.Println(aci.VolumeID(aciOpts.Account, aciOpts.Fileshare))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -75,22 +78,37 @@ func createVolume() *cobra.Command {
|
|||
}
|
||||
|
||||
func rmVolume() *cobra.Command {
|
||||
aciOpts := aci.VolumeDeleteOptions{}
|
||||
cmd := &cobra.Command{
|
||||
Use: "rm",
|
||||
Short: "Deletes an Azure file share and/or the Azure storage account.",
|
||||
Args: cobra.ExactArgs(0),
|
||||
Use: "rm [OPTIONS] VOLUME [VOLUME...]",
|
||||
Short: "Remove one or more volumes.",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
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(), aciOpts)
|
||||
var errs *multierror.Error
|
||||
for _, id := range args {
|
||||
err = c.VolumeService().Delete(cmd.Context(), id, nil)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
continue
|
||||
}
|
||||
fmt.Println(id)
|
||||
}
|
||||
if errs != nil {
|
||||
errs.ErrorFormat = formatErrors
|
||||
}
|
||||
return errs.ErrorOrNil()
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVar(&aciOpts.Account, "storage-account", "", "Storage account name")
|
||||
cmd.Flags().StringVar(&aciOpts.Fileshare, "fileshare", "", "Fileshare name")
|
||||
cmd.Flags().BoolVar(&aciOpts.DeleteAccount, "delete-storage-account", false, "Also delete storage account")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func formatErrors(errs []error) string {
|
||||
messages := make([]string, len(errs))
|
||||
for i, err := range errs {
|
||||
messages[i] = "Error: " + err.Error()
|
||||
}
|
||||
return strings.Join(messages, "\n")
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
ID NAME DESCRIPTION
|
||||
volume@123 123 volume 123
|
||||
ID DESCRIPTION
|
||||
volume@123 volume 123
|
||||
|
|
|
@ -162,9 +162,10 @@ func TestContainerRunVolume(t *testing.T) {
|
|||
t.Run("create volumes", func(t *testing.T) {
|
||||
c.RunDockerCmd("volume", "create", "--storage-account", accountName, "--fileshare", fileshareName)
|
||||
})
|
||||
volumeID = accountName + "@" + fileshareName
|
||||
|
||||
t.Cleanup(func() {
|
||||
c.RunDockerCmd("volume", "rm", "--storage-account", accountName, "--delete-storage-account")
|
||||
c.RunDockerCmd("volume", "rm", volumeID)
|
||||
res := c.RunDockerCmd("volume", "ls")
|
||||
lines := lines(res.Stdout())
|
||||
assert.Equal(t, len(lines), 1)
|
||||
|
@ -173,6 +174,7 @@ func TestContainerRunVolume(t *testing.T) {
|
|||
t.Run("create second fileshare", func(t *testing.T) {
|
||||
c.RunDockerCmd("volume", "create", "--storage-account", accountName, "--fileshare", "dockertestshare2")
|
||||
})
|
||||
volumeID2 := accountName + "@dockertestshare2"
|
||||
|
||||
t.Run("list volumes", func(t *testing.T) {
|
||||
res := c.RunDockerCmd("volume", "ls")
|
||||
|
@ -180,18 +182,14 @@ func TestContainerRunVolume(t *testing.T) {
|
|||
assert.Equal(t, len(lines), 3)
|
||||
firstAccount := lines[1]
|
||||
fields := strings.Fields(firstAccount)
|
||||
volumeID = accountName + "@" + fileshareName
|
||||
assert.Equal(t, fields[0], volumeID)
|
||||
assert.Equal(t, fields[1], fileshareName)
|
||||
secondAccount := lines[2]
|
||||
fields = strings.Fields(secondAccount)
|
||||
assert.Equal(t, fields[0], accountName+"@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.Equal(t, fields[0], volumeID2)
|
||||
})
|
||||
|
||||
t.Run("delete only fileshare", func(t *testing.T) {
|
||||
c.RunDockerCmd("volume", "rm", "--storage-account", accountName, "--fileshare", "dockertestshare2")
|
||||
c.RunDockerCmd("volume", "rm", volumeID2)
|
||||
res := c.RunDockerCmd("volume", "ls")
|
||||
lines := lines(res.Stdout())
|
||||
assert.Equal(t, len(lines), 2)
|
||||
|
|
Loading…
Reference in New Issue