Unwrapp API errors to get user-friendly error message

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2020-07-06 14:40:41 +02:00
parent f892ee1004
commit 4700fed836
No known key found for this signature in database
GPG Key ID: 9858809D6F8F6E7E
8 changed files with 53 additions and 92 deletions

View File

@ -8,7 +8,6 @@ import (
"strings" "strings"
"github.com/compose-spec/compose-go/cli" "github.com/compose-spec/compose-go/cli"
"github.com/compose-spec/compose-go/types"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
amazon "github.com/docker/ecs-plugin/pkg/amazon/backend" amazon "github.com/docker/ecs-plugin/pkg/amazon/backend"
"github.com/docker/ecs-plugin/pkg/docker" "github.com/docker/ecs-plugin/pkg/docker"
@ -43,15 +42,11 @@ func (o upOptions) LoadBalancerArn() *string {
return &o.loadBalancerArn 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{ cmd := &cobra.Command{
Use: "convert", Use: "convert",
RunE: WithProject(projectOpts, func(project *types.Project, args []string) error { RunE: docker.WithAwsContext(dockerCli, func(ctx docker.AwsContext, backend *amazon.Backend, args []string) error {
clusteropts, err := docker.GetAwsContext(dockerCli) project, err := cli.ProjectFromOptions(options)
if err != nil {
return err
}
backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region)
if err != nil { if err != nil {
return err return err
} }
@ -72,36 +67,24 @@ func ConvertCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cob
return cmd return cmd
} }
func UpCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cobra.Command { func UpCommand(dockerCli command.Cli, options *cli.ProjectOptions) *cobra.Command {
opts := upOptions{} opts := upOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "up", Use: "up",
RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, args []string) error { RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, backend *amazon.Backend, args []string) error {
backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region) return backend.Up(context.Background(), *options)
if err != nil {
return err
}
return backend.Up(context.Background(), *projectOpts)
}), }),
} }
cmd.Flags().StringVar(&opts.loadBalancerArn, "load-balancer", "", "") cmd.Flags().StringVar(&opts.loadBalancerArn, "load-balancer", "", "")
return cmd return cmd
} }
func PsCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cobra.Command { func PsCommand(dockerCli command.Cli, options *cli.ProjectOptions) *cobra.Command {
opts := upOptions{} opts := upOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "ps", Use: "ps",
RunE: WithProject(projectOpts, func(project *types.Project, args []string) error { RunE: docker.WithAwsContext(dockerCli, func(ctx docker.AwsContext, backend *amazon.Backend, args []string) error {
clusteropts, err := docker.GetAwsContext(dockerCli) status, err := backend.Ps(context.Background(), *options)
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)
if err != nil { if err != nil {
return err return err
} }
@ -125,11 +108,7 @@ func DownCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cobra.
opts := downOptions{} opts := downOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "down", Use: "down",
RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, args []string) error { RunE: docker.WithAwsContext(dockerCli, func(ctx docker.AwsContext, backend *amazon.Backend, args []string) error {
backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region)
if err != nil {
return err
}
return backend.Down(context.Background(), *projectOpts) 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 { func LogsCommand(dockerCli command.Cli, projectOpts *cli.ProjectOptions) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "logs [PROJECT NAME]", Use: "logs [PROJECT NAME]",
RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, args []string) error { RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, backend *amazon.Backend, args []string) error {
backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region) return backend.Logs(context.Background(), *projectOpts)
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)
}), }),
} }
return cmd return cmd

View File

@ -2,8 +2,6 @@ package commands
import ( import (
"github.com/compose-spec/compose-go/cli" "github.com/compose-spec/compose-go/cli"
"github.com/compose-spec/compose-go/types"
"github.com/spf13/cobra"
"github.com/spf13/pflag" "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.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)") 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)
}
}

View File

@ -47,11 +47,7 @@ func CreateSecret(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "create NAME", Use: "create NAME",
Short: "Creates a secret.", Short: "Creates a secret.",
RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, args []string) error { RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, backend *amazon.Backend, args []string) error {
backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region)
if err != nil {
return err
}
if len(args) == 0 { if len(args) == 0 {
return errors.New("Missing mandatory parameter: NAME") return errors.New("Missing mandatory parameter: NAME")
} }
@ -73,11 +69,7 @@ func InspectSecret(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "inspect ID", Use: "inspect ID",
Short: "Displays secret details", Short: "Displays secret details",
RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, args []string) error { RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, backend *amazon.Backend, args []string) error {
backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region)
if err != nil {
return err
}
if len(args) == 0 { if len(args) == 0 {
return errors.New("Missing mandatory parameter: ID") return errors.New("Missing mandatory parameter: ID")
} }
@ -102,11 +94,7 @@ func ListSecrets(dockerCli command.Cli) *cobra.Command {
Use: "list", Use: "list",
Aliases: []string{"ls"}, Aliases: []string{"ls"},
Short: "List secrets stored for the existing account.", Short: "List secrets stored for the existing account.",
RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, args []string) error { RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, backend *amazon.Backend, args []string) error {
backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region)
if err != nil {
return err
}
secrets, err := backend.ListSecrets(context.Background()) secrets, err := backend.ListSecrets(context.Background())
if err != nil { if err != nil {
return err return err
@ -125,11 +113,7 @@ func DeleteSecret(dockerCli command.Cli) *cobra.Command {
Use: "delete NAME", Use: "delete NAME",
Aliases: []string{"rm", "remove"}, Aliases: []string{"rm", "remove"},
Short: "Removes a secret.", Short: "Removes a secret.",
RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, args []string) error { RunE: docker.WithAwsContext(dockerCli, func(clusteropts docker.AwsContext, backend *amazon.Backend, args []string) error {
backend, err := amazon.NewBackend(clusteropts.Profile, clusteropts.Cluster, clusteropts.Region)
if err != nil {
return err
}
if len(args) == 0 { if len(args) == 0 {
return errors.New("Missing mandatory parameter: [NAME]") return errors.New("Missing mandatory parameter: [NAME]")
} }

View File

@ -4,11 +4,16 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/compose-spec/compose-go/types" "github.com/compose-spec/compose-go/cli"
"github.com/docker/ecs-plugin/pkg/compose" "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 cluster := b.Cluster
if cluster == "" { if cluster == "" {
cluster = project.Name cluster = project.Name

View File

@ -8,11 +8,22 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/compose-spec/compose-go/cli"
"github.com/docker/ecs-plugin/pkg/console" "github.com/docker/ecs-plugin/pkg/console"
) )
func (b *Backend) Logs(ctx context.Context, projectName string) error { func (b *Backend) Logs(ctx context.Context, options cli.ProjectOptions) error {
err := b.api.GetLogs(ctx, projectName, &logConsumer{ 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{}, colors: map[string]console.ColorFunc{},
width: 0, width: 0,
}) })

View File

@ -143,7 +143,9 @@ func (s sdk) StackExists(ctx context.Context, name string) (bool, error) {
StackName: aws.String(name), StackName: aws.String(name),
}) })
if err != nil { 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 false, nil
} }
return len(stacks.Stacks) > 0, nil return len(stacks.Stacks) > 0, nil

View File

@ -13,8 +13,8 @@ type API interface {
Down(ctx context.Context, options cli.ProjectOptions) error Down(ctx context.Context, options cli.ProjectOptions) error
Convert(project *types.Project) (*cloudformation.Template, error) Convert(project *types.Project) (*cloudformation.Template, error)
Logs(ctx context.Context, projectName string) error Logs(ctx context.Context, projectName cli.ProjectOptions) error
Ps(background context.Context, project *types.Project) ([]ServiceStatus, error) Ps(background context.Context, options cli.ProjectOptions) ([]ServiceStatus, error)
CreateSecret(ctx context.Context, secret Secret) (string, error) CreateSecret(ctx context.Context, secret Secret) (string, error)
InspectSecret(ctx context.Context, id string) (Secret, error) InspectSecret(ctx context.Context, id string) (Secret, error)

View File

@ -3,9 +3,11 @@ package docker
import ( import (
"fmt" "fmt"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
cliconfig "github.com/docker/cli/cli/config" cliconfig "github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/context/store" "github.com/docker/cli/cli/context/store"
amazon "github.com/docker/ecs-plugin/pkg/amazon/backend"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -72,7 +74,7 @@ func checkAwsContextExists(contextName string) (*AwsContext, error) {
return &awsContext, nil 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 { func WithAwsContext(dockerCli command.Cli, f ContextFunc) func(cmd *cobra.Command, args []string) error {
return 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 { if err != nil {
return err 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
} }
} }