refactor ecs context creation

Signed-off-by: aiordache <anca.iordache@docker.com>
This commit is contained in:
aiordache 2020-10-26 22:01:54 +01:00
parent 5450791ba7
commit 2dcd1a5826
3 changed files with 135 additions and 22 deletions

View File

@ -45,6 +45,7 @@ func createEcsCommand() *cobra.Command {
Short: "Create a context for Amazon ECS", Short: "Create a context for Amazon ECS",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
opts.Name = args[0]
if localSimulation { if localSimulation {
return runCreateLocalSimulation(cmd.Context(), args[0], opts) return runCreateLocalSimulation(cmd.Context(), args[0], opts)
} }

View File

@ -38,6 +38,7 @@ const backendType = store.EcsContextType
// ContextParams options for creating AWS context // ContextParams options for creating AWS context
type ContextParams struct { type ContextParams struct {
Name string
Description string Description string
Region string Region string
Profile string Profile string

View File

@ -26,7 +26,6 @@ import (
"github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/defaults" "github.com/aws/aws-sdk-go/aws/defaults"
"github.com/pkg/errors"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
"github.com/docker/compose-cli/context/store" "github.com/docker/compose-cli/context/store"
@ -34,6 +33,21 @@ import (
"github.com/docker/compose-cli/prompt" "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 { type contextCreateAWSHelper struct {
user prompt.UI 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() accessKey, secretKey, err := h.askCredentials()
if err != nil { if err != nil {
return err return err
@ -67,33 +95,114 @@ func (h contextCreateAWSHelper) createContext(profile, region, description strin
}, description }, description
} }
func (h contextCreateAWSHelper) createContextData(_ context.Context, opts ContextParams) (interface{}, string, error) { func (h contextCreateAWSHelper) ParseEnvVars(c *contextElements) {
profile := opts.Profile profile := os.Getenv("AWS_PROFILE")
region := opts.Region 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 { 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 return nil, "", err
} }
if profile != "" {
// validate profile if len(options) == 2 {
if profile != "default" && !contains(profilesList, profile) { selected = selected + 1
return nil, "", errors.Wrapf(errdefs.ErrNotFound, "profile %q", profile) }
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 // choose profile
profile, err = h.chooseProfile(profilesList) creds.Profile, err = h.chooseProfile(profilesList)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
} if creds.Region == "" {
if region == "" { creds.Region, err = h.chooseRegion(creds.Region, creds.Profile)
region, err = h.chooseRegion(region, profile) if err != nil {
if err != nil { return nil, "", err
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 return ecsCtx, descr, nil
} }
@ -178,14 +287,16 @@ func (h contextCreateAWSHelper) chooseProfile(profiles []string) (string, error)
if name == "" { if name == "" {
return "", fmt.Errorf("profile name cannot be empty") return "", fmt.Errorf("profile name cannot be empty")
} }
return name, h.createProfile(name) return name, h.createProfile(name, nil)
} }
return profile, nil return profile, nil
} }
func (h contextCreateAWSHelper) chooseRegion(region string, profile string) (string, error) { func (h contextCreateAWSHelper) chooseRegion(region string, profile string) (string, error) {
suggestion := region suggestion := region
if profile == "" {
profile = "default"
}
// only load ~/.aws/config // only load ~/.aws/config
awsConfig := defaults.SharedConfigFilename() awsConfig := defaults.SharedConfigFilename()
configIni, err := ini.Load(awsConfig) 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) { 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 { if err != nil {
return "", "", err return "", "", err
} }
if !confirm { if !confirm {
return "", "", nil return "", "", nil
} }*/
accessKeyID, err := h.user.Input("AWS Access Key ID", "") accessKeyID, err := h.user.Input("AWS Access Key ID", "")
if err != nil { if err != nil {