From 4700fed83660354cc63c804c4399d23c0eef2456 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Mon, 6 Jul 2020 14:40:41 +0200 Subject: [PATCH] Unwrapp API errors to get user-friendly error message Signed-off-by: Nicolas De Loof --- ecs/cmd/commands/compose.go | 60 +++++++--------------------------- ecs/cmd/commands/opts.go | 15 --------- ecs/cmd/commands/secret.go | 24 +++----------- ecs/pkg/amazon/backend/list.go | 9 +++-- ecs/pkg/amazon/backend/logs.go | 15 +++++++-- ecs/pkg/amazon/sdk/sdk.go | 4 ++- ecs/pkg/compose/api.go | 4 +-- ecs/pkg/docker/contextStore.go | 14 ++++++-- 8 files changed, 53 insertions(+), 92 deletions(-) diff --git a/ecs/cmd/commands/compose.go b/ecs/cmd/commands/compose.go index ed488a891..9f5a38418 100644 --- a/ecs/cmd/commands/compose.go +++ b/ecs/cmd/commands/compose.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/compose-spec/compose-go/cli" - "github.com/compose-spec/compose-go/types" "github.com/docker/cli/cli/command" amazon "github.com/docker/ecs-plugin/pkg/amazon/backend" "github.com/docker/ecs-plugin/pkg/docker" @@ -43,15 +42,11 @@ func (o upOptions) LoadBalancerArn() *string { return &o.loadBalancerArn } -func ConvertCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cobra.Command { +func ConvertCommand(dockerCli command.Cli, options *cli.ProjectOptions) *cobra.Command { cmd := &cobra.Command{ Use: "convert", - RunE: WithProject(projectOpts, func(project *types.Project, args []string) error { - clusteropts, err := docker.GetAwsContext(dockerCli) - if err != nil { - return err - } - backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region) + RunE: docker.WithAwsContext(dockerCli, func(ctx docker.AwsContext, backend *amazon.Backend, args []string) error { + project, err := cli.ProjectFromOptions(options) if err != nil { return err } @@ -72,36 +67,24 @@ func ConvertCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cob return cmd } -func UpCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cobra.Command { +func UpCommand(dockerCli command.Cli, options *cli.ProjectOptions) *cobra.Command { opts := upOptions{} cmd := &cobra.Command{ Use: "up", - RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, args []string) error { - backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region) - if err != nil { - return err - } - return backend.Up(context.Background(), *projectOpts) + RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, backend *amazon.Backend, args []string) error { + return backend.Up(context.Background(), *options) }), } cmd.Flags().StringVar(&opts.loadBalancerArn, "load-balancer", "", "") return cmd } -func PsCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cobra.Command { +func PsCommand(dockerCli command.Cli, options *cli.ProjectOptions) *cobra.Command { opts := upOptions{} cmd := &cobra.Command{ Use: "ps", - RunE: WithProject(projectOpts, func(project *types.Project, args []string) error { - clusteropts, err := docker.GetAwsContext(dockerCli) - if err != nil { - return err - } - backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region) - if err != nil { - return err - } - status, err := backend.Ps(context.Background(), project) + RunE: docker.WithAwsContext(dockerCli, func(ctx docker.AwsContext, backend *amazon.Backend, args []string) error { + status, err := backend.Ps(context.Background(), *options) if err != nil { return err } @@ -125,11 +108,7 @@ func DownCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cobra. opts := downOptions{} cmd := &cobra.Command{ Use: "down", - RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, args []string) error { - backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region) - if err != nil { - return err - } + RunE: docker.WithAwsContext(dockerCli, func(ctx docker.AwsContext, backend *amazon.Backend, args []string) error { return backend.Down(context.Background(), *projectOpts) }), } @@ -140,23 +119,8 @@ func DownCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cobra. func LogsCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cobra.Command { cmd := &cobra.Command{ Use: "logs [PROJECT NAME]", - RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, args []string) error { - backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region) - if err != nil { - return err - } - var name string - - if len(args) == 0 { - project, err := cli.ProjectFromOptions(projectOpts) - if err != nil { - return err - } - name = project.Name - } else { - name = args[0] - } - return backend.Logs(context.Background(), name) + RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, backend *amazon.Backend, args []string) error { + return backend.Logs(context.Background(), *projectOpts) }), } return cmd diff --git a/ecs/cmd/commands/opts.go b/ecs/cmd/commands/opts.go index 7d0856c86..bb63ec383 100644 --- a/ecs/cmd/commands/opts.go +++ b/ecs/cmd/commands/opts.go @@ -2,8 +2,6 @@ package commands import ( "github.com/compose-spec/compose-go/cli" - "github.com/compose-spec/compose-go/types" - "github.com/spf13/cobra" "github.com/spf13/pflag" ) @@ -11,16 +9,3 @@ func AddFlags(o *cli.ProjectOptions, flags *pflag.FlagSet) { flags.StringArrayVarP(&o.ConfigPaths, "file", "f", nil, "Specify an alternate compose file") flags.StringVarP(&o.Name, "project-name", "n", "", "Specify an alternate project name (default: directory name)") } - -type ProjectFunc func(project *types.Project, args []string) error - -// WithProject wrap a ProjectFunc into a cobra command -func WithProject(options *cli.ProjectOptions, f ProjectFunc) func(cmd *cobra.Command, args []string) error { - return func(cmd *cobra.Command, args []string) error { - project, err := cli.ProjectFromOptions(options) - if err != nil { - return err - } - return f(project, args) - } -} diff --git a/ecs/cmd/commands/secret.go b/ecs/cmd/commands/secret.go index b6a32c783..5bbefaa9b 100644 --- a/ecs/cmd/commands/secret.go +++ b/ecs/cmd/commands/secret.go @@ -47,11 +47,7 @@ func CreateSecret(dockerCli command.Cli) *cobra.Command { cmd := &cobra.Command{ Use: "create NAME", Short: "Creates a secret.", - RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, args []string) error { - backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region) - if err != nil { - return err - } + RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, backend *amazon.Backend, args []string) error { if len(args) == 0 { return errors.New("Missing mandatory parameter: NAME") } @@ -73,11 +69,7 @@ func InspectSecret(dockerCli command.Cli) *cobra.Command { cmd := &cobra.Command{ Use: "inspect ID", Short: "Displays secret details", - RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, args []string) error { - backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region) - if err != nil { - return err - } + RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, backend *amazon.Backend, args []string) error { if len(args) == 0 { return errors.New("Missing mandatory parameter: ID") } @@ -102,11 +94,7 @@ func ListSecrets(dockerCli command.Cli) *cobra.Command { Use: "list", Aliases: []string{"ls"}, Short: "List secrets stored for the existing account.", - RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, args []string) error { - backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region) - if err != nil { - return err - } + RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, backend *amazon.Backend, args []string) error { secrets, err := backend.ListSecrets(context.Background()) if err != nil { return err @@ -125,11 +113,7 @@ func DeleteSecret(dockerCli command.Cli) *cobra.Command { Use: "delete NAME", Aliases: []string{"rm", "remove"}, Short: "Removes a secret.", - RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, args []string) error { - backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region) - if err != nil { - return err - } + RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, backend *amazon.Backend, args []string) error { if len(args) == 0 { return errors.New("Missing mandatory parameter: [NAME]") } diff --git a/ecs/pkg/amazon/backend/list.go b/ecs/pkg/amazon/backend/list.go index 00b4adee3..232b2c816 100644 --- a/ecs/pkg/amazon/backend/list.go +++ b/ecs/pkg/amazon/backend/list.go @@ -4,11 +4,16 @@ import ( "context" "fmt" - "github.com/compose-spec/compose-go/types" + "github.com/compose-spec/compose-go/cli" "github.com/docker/ecs-plugin/pkg/compose" ) -func (b *Backend) Ps(ctx context.Context, project *types.Project) ([]compose.ServiceStatus, error) { +func (b *Backend) Ps(ctx context.Context, options cli.ProjectOptions) ([]compose.ServiceStatus, error) { + project, err := cli.ProjectFromOptions(&options) + if err != nil { + return nil, err + } + cluster := b.Cluster if cluster == "" { cluster = project.Name diff --git a/ecs/pkg/amazon/backend/logs.go b/ecs/pkg/amazon/backend/logs.go index a17158857..00b8b2d4f 100644 --- a/ecs/pkg/amazon/backend/logs.go +++ b/ecs/pkg/amazon/backend/logs.go @@ -8,11 +8,22 @@ import ( "strconv" "strings" + "github.com/compose-spec/compose-go/cli" + "github.com/docker/ecs-plugin/pkg/console" ) -func (b *Backend) Logs(ctx context.Context, projectName string) error { - err := b.api.GetLogs(ctx, projectName, &logConsumer{ +func (b *Backend) Logs(ctx context.Context, options cli.ProjectOptions) error { + name := options.Name + if name == "" { + project, err := cli.ProjectFromOptions(&options) + if err != nil { + return err + } + name = project.Name + } + + err := b.api.GetLogs(ctx, name, &logConsumer{ colors: map[string]console.ColorFunc{}, width: 0, }) diff --git a/ecs/pkg/amazon/sdk/sdk.go b/ecs/pkg/amazon/sdk/sdk.go index 5874a8009..3365b07f8 100644 --- a/ecs/pkg/amazon/sdk/sdk.go +++ b/ecs/pkg/amazon/sdk/sdk.go @@ -143,7 +143,9 @@ func (s sdk) StackExists(ctx context.Context, name string) (bool, error) { StackName: aws.String(name), }) if err != nil { - // FIXME doesn't work as expected + if strings.HasPrefix(err.Error(), fmt.Sprintf("ValidationError: Stack with id %s does not exist", name)) { + return false, nil + } return false, nil } return len(stacks.Stacks) > 0, nil diff --git a/ecs/pkg/compose/api.go b/ecs/pkg/compose/api.go index 64e7e5c87..5f8278c65 100644 --- a/ecs/pkg/compose/api.go +++ b/ecs/pkg/compose/api.go @@ -13,8 +13,8 @@ type API interface { Down(ctx context.Context, options cli.ProjectOptions) error Convert(project *types.Project) (*cloudformation.Template, error) - Logs(ctx context.Context, projectName string) error - Ps(background context.Context, project *types.Project) ([]ServiceStatus, error) + Logs(ctx context.Context, projectName cli.ProjectOptions) error + Ps(background context.Context, options cli.ProjectOptions) ([]ServiceStatus, error) CreateSecret(ctx context.Context, secret Secret) (string, error) InspectSecret(ctx context.Context, id string) (Secret, error) diff --git a/ecs/pkg/docker/contextStore.go b/ecs/pkg/docker/contextStore.go index b038eb924..83c055f68 100644 --- a/ecs/pkg/docker/contextStore.go +++ b/ecs/pkg/docker/contextStore.go @@ -3,9 +3,11 @@ package docker import ( "fmt" + "github.com/aws/aws-sdk-go/aws/awserr" "github.com/docker/cli/cli/command" cliconfig "github.com/docker/cli/cli/config" "github.com/docker/cli/cli/context/store" + amazon "github.com/docker/ecs-plugin/pkg/amazon/backend" "github.com/mitchellh/mapstructure" "github.com/spf13/cobra" ) @@ -72,7 +74,7 @@ func checkAwsContextExists(contextName string) (*AwsContext, error) { return &awsContext, nil } -type ContextFunc func(ctx AwsContext, args []string) error +type ContextFunc func(ctx AwsContext, backend *amazon.Backend, args []string) error func WithAwsContext(dockerCli command.Cli, f ContextFunc) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { @@ -80,7 +82,15 @@ func WithAwsContext(dockerCli command.Cli, f ContextFunc) func(cmd *cobra.Comman if err != nil { return err } - return f(*ctx, args) + backend, err := amazon.NewBackend(ctx.Profile, ctx.Cluster, ctx.Region) + if err != nil { + return err + } + err = f(*ctx, backend, args) + if e, ok := err.(awserr.Error); ok { + return fmt.Errorf(e.Message()) + } + return err } }