Skip to content

Commit

Permalink
move setup flags to setup package
Browse files Browse the repository at this point in the history
To separate command line flags parsing and using that data.
  • Loading branch information
ianic committed Oct 5, 2021
1 parent 74ac713 commit c99a5f2
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 122 deletions.
127 changes: 11 additions & 116 deletions cli/cmd/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ package cmd

import (
"fmt"
"os"

"github.com/mantil-io/mantil/aws"
"github.com/mantil-io/mantil/cli/cmd/setup"
"github.com/mantil-io/mantil/cli/log"
"github.com/mantil-io/mantil/cli/ui"
"github.com/mantil-io/mantil/workspace"
"github.com/spf13/cobra"
)

Expand All @@ -24,7 +21,7 @@ func newAwsCommand() *cobra.Command {
}

func newAwsInstallCommand() *cobra.Command {
var f awsFlags
f := &setup.Flags{}
cmd := &cobra.Command{
Use: "install [account-name]",
Short: "Install Mantil into AWS account",
Expand All @@ -38,28 +35,28 @@ If not provided default name %s will be used for the first account.
There is --dry-run flag which will show you what credentials will be used
and what account will be managed by command.
`, credentialsHelp(), workspace.DefaultAccountName),
`, credentialsHelp(), setup.DefaultAccountName()),
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
f.ParseArgs(args)
stp, err := newSetup(&f)
stp, err := setup.New(f)
if err != nil {
return log.Wrap(err)
}
if f.DryRun {
showAwsDryRunInfo(&f)
showAwsDryRunInfo(f)
return nil
}
return stp.Create()
},
}
bindAwsInstallFlags(cmd, &f)
bindAwsInstallFlags(cmd, f)
cmd.Flags().BoolVar(&f.Override, "override", false, "force override access tokens on already installed account")
return cmd
}

func newAwsUninstallCommand() *cobra.Command {
var f awsFlags
f := &setup.Flags{}
cmd := &cobra.Command{
Use: "uninstall [account-name]",
Short: "Uninstall Mantil from AWS account",
Expand All @@ -76,32 +73,21 @@ and what account will be managed by command.
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
f.ParseArgs(args)
stp, err := newSetup(&f)
stp, err := setup.New(f)
if err != nil {
return log.Wrap(err)
}
if f.DryRun {
showAwsDryRunInfo(&f)
showAwsDryRunInfo(f)
return nil
}
return stp.Destroy()
},
}
bindAwsInstallFlags(cmd, &f)
bindAwsInstallFlags(cmd, f)
return cmd
}

func newSetup(f *awsFlags) (*setup.Cmd, error) {
if err := f.Validate(); err != nil {
return nil, err
}
cli, err := f.awsConnect()
if err != nil {
return nil, log.WithUserMessage(err, "invalid AWS access credentials")
}
return setup.New(cli, f.AccountName, f.Override), nil
}

func credentialsHelp() string {
return `There are few ways to provide credentials:
Expand All @@ -123,7 +109,7 @@ reference: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profil
`
}

func bindAwsInstallFlags(cmd *cobra.Command, f *awsFlags) {
func bindAwsInstallFlags(cmd *cobra.Command, f *setup.Flags) {
cmd.Flags().StringVar(&f.AccessKeyID, "aws-access-key-id", "", "access key ID for the AWS account, must be used with the aws-secret-access-key and aws-region flags")
cmd.Flags().StringVar(&f.SecretAccessKey, "aws-secret-access-key", "", "secret access key for the AWS account, must be used with the aws-access-key-id and aws-region flags")
cmd.Flags().StringVar(&f.Region, "aws-region", "", "region for the AWS account, must be used with and aws-access-key-id and aws-secret-access-key flags")
Expand All @@ -132,7 +118,7 @@ func bindAwsInstallFlags(cmd *cobra.Command, f *awsFlags) {
cmd.Flags().BoolVar(&f.DryRun, "dry-run", false, "don't start install/uninstall just show what credentials will be used")
}

func showAwsDryRunInfo(f *awsFlags) {
func showAwsDryRunInfo(f *setup.Flags) {
if f.Profile != "" {
ui.Info(`Command will use AWS profile %s defined in your AWS configuration file (~/.aws/config)`, f.Profile)
} else {
Expand All @@ -144,94 +130,3 @@ func showAwsDryRunInfo(f *awsFlags) {
ui.Info("To manage AWS account ID: %s in region %s", f.AccountID, f.Region)
ui.Info("Account name in Mantil is %s", f.AccountName)
}

type awsFlags struct {
AccessKeyID string
SecretAccessKey string
Region string
Profile string
UseEnv bool
AccountName string
DryRun bool
Override bool
AccountID string
}

func (f *awsFlags) ParseArgs(args []string) {
if len(args) == 0 {
f.AccountName = workspace.DefaultAccountName
return
}
f.AccountName = args[0]
}

func (f *awsFlags) Validate() error {
if f.AccessKeyID != "" || f.SecretAccessKey != "" {
return f.validateAccessKeys()
}
if f.UseEnv {
return f.readFromEnv()
}
if f.Profile != "" {
return nil
}
return fmt.Errorf("AWS credentials not provided")
}

func (f *awsFlags) validateAccessKeys() error {
if f.AccessKeyID == "" {
return fmt.Errorf("aws-access-key-id not provided, must be used with the aws-secret-access-key and aws-region")
}
if f.SecretAccessKey == "" {
return fmt.Errorf("aws-secret-access-key not provided, must be used with the aws-access-key-id and aws-region")
}
if f.Region == "" {
return fmt.Errorf("aws-region not provided, must be used with aws-access-key-id and aws-secret-access-key")
}
return nil
}

const (
accessKeyIDEnv = "AWS_ACCESS_KEY_ID"
secretAccessKeyEnv = "AWS_SECRET_ACCESS_KEY"
regionEnv = "AWS_DEFAULT_REGION"
)

func (f *awsFlags) readFromEnv() error {
errf := func(env string) error {
return fmt.Errorf("%s environment variable not provided", env)
}
f.AccessKeyID, _ = os.LookupEnv(accessKeyIDEnv)
if f.AccessKeyID == "" {
return errf(accessKeyIDEnv)
}
f.SecretAccessKey, _ = os.LookupEnv(secretAccessKeyEnv)
if f.SecretAccessKey == "" {
return errf(secretAccessKeyEnv)
}
f.Region, _ = os.LookupEnv(regionEnv)
if f.Region == "" {
return errf(regionEnv)
}
return nil
}

func (f *awsFlags) awsConnect() (*aws.AWS, error) {
cli, err := f.awsClient()
if err != nil {
return nil, err
}
f.AccountID, err = cli.AccountID()
if err != nil {
return nil, err
}
f.Region = cli.Region()
return cli, nil
}

func (f *awsFlags) awsClient() (*aws.AWS, error) {
if f.Profile != "" {
return aws.NewFromProfile(f.Profile)
}
return aws.NewWithCredentials(f.AccessKeyID, f.SecretAccessKey, "", f.Region)
}
102 changes: 102 additions & 0 deletions cli/cmd/setup/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package setup

import (
"fmt"
"os"

"github.com/mantil-io/mantil/aws"
"github.com/mantil-io/mantil/workspace"
)

type Flags struct {
AccessKeyID string
SecretAccessKey string
Region string
Profile string
UseEnv bool
AccountName string
DryRun bool
Override bool
AccountID string
}

func DefaultAccountName() string { return workspace.DefaultAccountName }

func (f *Flags) ParseArgs(args []string) {
if len(args) == 0 {
f.AccountName = DefaultAccountName()
return
}
f.AccountName = args[0]
}

func (f *Flags) validate() error {
if f.AccessKeyID != "" || f.SecretAccessKey != "" {
return f.validateAccessKeys()
}
if f.UseEnv {
return f.readFromEnv()
}
if f.Profile != "" {
return nil
}
return fmt.Errorf("AWS credentials not provided")
}

func (f *Flags) validateAccessKeys() error {
if f.AccessKeyID == "" {
return fmt.Errorf("aws-access-key-id not provided, must be used with the aws-secret-access-key and aws-region")
}
if f.SecretAccessKey == "" {
return fmt.Errorf("aws-secret-access-key not provided, must be used with the aws-access-key-id and aws-region")
}
if f.Region == "" {
return fmt.Errorf("aws-region not provided, must be used with aws-access-key-id and aws-secret-access-key")
}
return nil
}

const (
accessKeyIDEnv = "AWS_ACCESS_KEY_ID"
secretAccessKeyEnv = "AWS_SECRET_ACCESS_KEY"
regionEnv = "AWS_DEFAULT_REGION"
)

func (f *Flags) readFromEnv() error {
errf := func(env string) error {
return fmt.Errorf("%s environment variable not provided", env)
}
f.AccessKeyID, _ = os.LookupEnv(accessKeyIDEnv)
if f.AccessKeyID == "" {
return errf(accessKeyIDEnv)
}
f.SecretAccessKey, _ = os.LookupEnv(secretAccessKeyEnv)
if f.SecretAccessKey == "" {
return errf(secretAccessKeyEnv)
}
f.Region, _ = os.LookupEnv(regionEnv)
if f.Region == "" {
return errf(regionEnv)
}
return nil
}

func (f *Flags) awsConnect() (*aws.AWS, error) {
cli, err := f.awsClient()
if err != nil {
return nil, err
}
f.AccountID, err = cli.AccountID()
if err != nil {
return nil, err
}
f.Region = cli.Region()
return cli, nil
}

func (f *Flags) awsClient() (*aws.AWS, error) {
if f.Profile != "" {
return aws.NewFromProfile(f.Profile)
}
return aws.NewWithCredentials(f.AccessKeyID, f.SecretAccessKey, "", f.Region)
}
15 changes: 11 additions & 4 deletions cli/cmd/setup/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,22 @@ type Cmd struct {
override bool
}

func New(awsClient *aws.AWS, accountName string, override bool) *Cmd {
func New(f *Flags) (*Cmd, error) {
if err := f.validate(); err != nil {
return nil, err
}
awsClient, err := f.awsConnect()
if err != nil {
return nil, log.WithUserMessage(err, "invalid AWS access credentials")
}
v := build.Version()
return &Cmd{
awsClient: awsClient,
functionsBucket: v.FunctionsBucket(awsClient.Region()),
functionsPath: v.FunctionsPath(),
accountName: accountName,
override: override,
}
accountName: f.AccountName,
override: f.Override,
}, nil
}

func (c *Cmd) Create() error {
Expand Down
15 changes: 13 additions & 2 deletions cli/cmd/setup/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"

"github.com/mantil-io/mantil/aws"
"github.com/mantil-io/mantil/cli/build"
"github.com/sergi/go-diff/diffmatchpatch"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand All @@ -29,7 +30,7 @@ func TestCreateLambda(t *testing.T) {
if cli == nil {
t.Skip("skip: AWS client not initialized")
}
cmd := New(cli, "", false)
cmd := new(cli)
// empty at start
alreadyRun, err := cmd.isAlreadyRun()
require.NoError(t, err)
Expand Down Expand Up @@ -59,7 +60,7 @@ func TestCreateAndInvoke(t *testing.T) {
if cli == nil {
t.Skip("skip: AWS client not initialized")
}
cmd := New(cli, "dev", false)
cmd := new(cli)

// empty at start
alreadyRun, err := cmd.isAlreadyRun()
Expand Down Expand Up @@ -94,3 +95,13 @@ func equalStrings(t *testing.T, expected, actual string) {
t.Fatalf("failed")
}
}

func new(cli *aws.AWS) *Cmd {
v := build.Version()
return &Cmd{
awsClient: cli,
functionsBucket: v.FunctionsBucket(cli.Region()),
functionsPath: v.FunctionsPath(),
accountName: "dev",
}
}

0 comments on commit c99a5f2

Please sign in to comment.