From 2dcd1a5826282d56bd6b10182afb6e06c635de98 Mon Sep 17 00:00:00 2001 From: aiordache Date: Mon, 26 Oct 2020 22:01:54 +0100 Subject: [PATCH] refactor ecs context creation Signed-off-by: aiordache --- cli/cmd/context/create_ecs.go | 1 + ecs/backend.go | 1 + ecs/context.go | 155 +++++++++++++++++++++++++++++----- 3 files changed, 135 insertions(+), 22 deletions(-) diff --git a/cli/cmd/context/create_ecs.go b/cli/cmd/context/create_ecs.go index 8dde7b049..fa5837954 100644 --- a/cli/cmd/context/create_ecs.go +++ b/cli/cmd/context/create_ecs.go @@ -45,6 +45,7 @@ func createEcsCommand() *cobra.Command { Short: "Create a context for Amazon ECS", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { + opts.Name = args[0] if localSimulation { return runCreateLocalSimulation(cmd.Context(), args[0], opts) } diff --git a/ecs/backend.go b/ecs/backend.go index 5d18bbc80..faa4da4ee 100644 --- a/ecs/backend.go +++ b/ecs/backend.go @@ -38,6 +38,7 @@ const backendType = store.EcsContextType // ContextParams options for creating AWS context type ContextParams struct { + Name string Description string Region string Profile string diff --git a/ecs/context.go b/ecs/context.go index ce91a853d..aa8e83b07 100644 --- a/ecs/context.go +++ b/ecs/context.go @@ -26,7 +26,6 @@ import ( "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/defaults" - "github.com/pkg/errors" "gopkg.in/ini.v1" "github.com/docker/compose-cli/context/store" @@ -34,6 +33,21 @@ import ( "github.com/docker/compose-cli/prompt" ) +type contextElements struct { + AccessKey string + SecretKey string + SessionToken string + Profile string + Region string +} + +func (c contextElements) HaveRequiredProps() bool { + if c.AccessKey != "" && c.SecretKey != "" { //} && c.Region != "" { + return true + } + return false +} + type contextCreateAWSHelper struct { user prompt.UI } @@ -44,7 +58,21 @@ func newContextCreateHelper() contextCreateAWSHelper { } } -func (h contextCreateAWSHelper) createProfile(name string) error { +func (h contextCreateAWSHelper) createProfile(name string, c *contextElements) error { + if c != nil { + if c.AccessKey != "" && c.SecretKey != "" { + return h.saveCredentials(name, c.AccessKey, c.SecretKey) + } + accessKey, secretKey, err := h.askCredentials() + + if err != nil { + return err + } + c.AccessKey = accessKey + c.SecretKey = secretKey + return h.saveCredentials(name, c.AccessKey, c.SecretKey) + } + accessKey, secretKey, err := h.askCredentials() if err != nil { return err @@ -67,33 +95,114 @@ func (h contextCreateAWSHelper) createContext(profile, region, description strin }, description } -func (h contextCreateAWSHelper) createContextData(_ context.Context, opts ContextParams) (interface{}, string, error) { - profile := opts.Profile - region := opts.Region +func (h contextCreateAWSHelper) ParseEnvVars(c *contextElements) { + profile := os.Getenv("AWS_PROFILE") + if profile != "" { + c.Profile = profile + } + region := os.Getenv("AWS_REGION") + if region != "" { + c.Region = region + } - profilesList, err := h.getProfiles() + p := credentials.EnvProvider{} + creds, err := p.Retrieve() if err != nil { + return + } + c.AccessKey = creds.AccessKeyID + c.SecretKey = creds.SecretAccessKey + c.SessionToken = creds.SessionToken +} + +func (h contextCreateAWSHelper) createContextData(_ context.Context, opts ContextParams) (interface{}, string, error) { + creds := contextElements{} + + h.ParseEnvVars(&creds) + + options := []string{} + if creds.HaveRequiredProps() { + options = append(options, "existing AWS environment variables (detected credentials)") + } + options = append(options, "enter AWS credentials", "use an AWS profile or create a new profile (advanced)") + selected, err := h.user.Select("Would you like to create your context based on", options) + if err != nil { + if err == terminal.InterruptErr { + return nil, "", errdefs.ErrCanceled + } return nil, "", err } - if profile != "" { - // validate profile - if profile != "default" && !contains(profilesList, profile) { - return nil, "", errors.Wrapf(errdefs.ErrNotFound, "profile %q", profile) + + if len(options) == 2 { + selected = selected + 1 + } + if selected != 0 { + creds = contextElements{} + } + + if creds.Region == "" { + creds.Region = opts.Region + } + if creds.Profile == "" { + creds.Profile = opts.Profile + } + + switch selected { + case 0: + if creds.Region == "" { + // prompt for the region to use with this context + creds.Region, err = h.chooseRegion(creds.Region, creds.Profile) + if err != nil { + return nil, "", err + } + } + if creds.Profile == "" { + creds.Profile = opts.Name + + } + fmt.Printf("Saving credentials under profile %s\n", creds.Profile) + h.createProfile(creds.Profile, &creds) + case 1: + accessKey, secretKey, err := h.askCredentials() + if err != nil { + return nil, "", err + } + creds.AccessKey = accessKey + creds.SecretKey = secretKey + // we need a region set -- either read it from profile or prompt user + + // prompt for the region to use with this context + creds.Region, err = h.chooseRegion(creds.Region, creds.Profile) + if err != nil { + return nil, "", err + } + // save as a profile + if creds.Profile == "" { + creds.Profile = opts.Name + } + fmt.Printf("Saving credentials under profile %s\n", creds.Profile) + h.createProfile(creds.Profile, &creds) + + case 2: + profilesList, err := h.getProfiles() + if err != nil { + return nil, "", err } - } else { // choose profile - profile, err = h.chooseProfile(profilesList) + creds.Profile, err = h.chooseProfile(profilesList) if err != nil { return nil, "", err } - } - if region == "" { - region, err = h.chooseRegion(region, profile) - if err != nil { - return nil, "", err + if creds.Region == "" { + creds.Region, err = h.chooseRegion(creds.Region, creds.Profile) + if err != nil { + return nil, "", err + } } } - ecsCtx, descr := h.createContext(profile, region, opts.Description) + + os.Exit(0) + ecsCtx, descr := h.createContext(creds.Profile, creds.Region, opts.Description) return ecsCtx, descr, nil } @@ -178,14 +287,16 @@ func (h contextCreateAWSHelper) chooseProfile(profiles []string) (string, error) if name == "" { return "", fmt.Errorf("profile name cannot be empty") } - return name, h.createProfile(name) + return name, h.createProfile(name, nil) } return profile, nil } func (h contextCreateAWSHelper) chooseRegion(region string, profile string) (string, error) { suggestion := region - + if profile == "" { + profile = "default" + } // only load ~/.aws/config awsConfig := defaults.SharedConfigFilename() configIni, err := ini.Load(awsConfig) @@ -230,13 +341,13 @@ func (h contextCreateAWSHelper) chooseRegion(region string, profile string) (str } func (h contextCreateAWSHelper) askCredentials() (string, string, error) { - confirm, err := h.user.Confirm("Enter AWS credentials", false) + /*confirm, err := h.user.Confirm("Enter AWS credentials", false) if err != nil { return "", "", err } if !confirm { return "", "", nil - } + }*/ accessKeyID, err := h.user.Input("AWS Access Key ID", "") if err != nil {