// Copyright 2015-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). You may // not use this file except in compliance with the License. A copy of the // License is located at // // http://aws.amazon.com/apache2.0/ // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either // express or implied. See the License for the specific language governing // permissions and limitations under the License. package config import ( "flag" "io/ioutil" "os" "testing" "github.com/aws/amazon-ecs-cli/ecs-cli/modules/commands/flags" "github.com/stretchr/testify/assert" "github.com/urfave/cli" ) const ( composeServiceNamePrefix = "ecs-service-" composeProjectNamePrefix = "ecs-project-" cfnStackName = "cfn-stack-ecs" cfnStackNamePrefix = "cfn-stack-" awsAccess = "ecs-access" awsSecret = "ecs-secret" awsAccessAWSProfile = "aws-access" awsSecretAWSProfile = "aws-secret" awsProfileName = "awsprofile" ) // mockReadWriter implements ReadWriter interface // field whenperforming read. type mockReadWriter struct { isKeyPresentValue bool fargate bool version int } func (rdwr *mockReadWriter) Get(clusterConfig string, profileConfig string) (*LocalConfig, error) { config := NewLocalConfig(clusterName) if rdwr.isKeyPresentValue && rdwr.version == iniConfigVersion { config.ComposeServiceNamePrefix = composeServiceNamePrefix config.CFNStackNamePrefix = cfnStackNamePrefix config.ComposeProjectNamePrefix = composeProjectNamePrefix } if rdwr.isKeyPresentValue && rdwr.version == yamlConfigVersion { config.ComposeServiceNamePrefix = composeServiceNamePrefix config.CFNStackName = cfnStackName config.DefaultLaunchType = LaunchTypeEC2 if rdwr.fargate { config.DefaultLaunchType = LaunchTypeFargate } } config.Version = rdwr.version return config, nil } func (rdwr *mockReadWriter) SaveProfile(configName string, profile *Profile) error { return nil } func (rdwr *mockReadWriter) SaveCluster(configName string, cluster *Cluster) error { return nil } func (rdwr *mockReadWriter) SetDefaultProfile(configName string) error { return nil } func (rdwr *mockReadWriter) SetDefaultCluster(configName string) error { return nil } func TestNewCommandConfigFromEnvVarsWithRegionNotSpecified(t *testing.T) { context, rdwr := setupTest(t) _, err := NewCommandConfig(context, rdwr) assert.Error(t, err, "Expected error when region is not specified") } func TestNewCommandConfigFromEnvVarsWithRegionSpecifiedAsEnvVariable(t *testing.T) { region := "us-west-1" context, rdwr := setupTest(t) os.Setenv("AWS_REGION", region) os.Setenv("AWS_ACCESS_KEY", "AKIDEXAMPLE") os.Setenv("AWS_SECRET_KEY", "SECRET") defer os.Clearenv() config, err := NewCommandConfig(context, rdwr) assert.NoError(t, err, "Unexpected error when region is specified using environment variable AWS_REGION") configRegion := config.Region() assert.Equal(t, region, configRegion, "Region should match") } func TestNewCommandConfigFromEnvVarsWithRegionSpecifiedinAwsDefaultEnvVariable(t *testing.T) { region := "us-west-2" context, rdwr := setupTest(t) os.Setenv("AWS_DEFAULT_REGION", region) os.Setenv("AWS_ACCESS_KEY", "AKIDEXAMPLE") os.Setenv("AWS_SECRET_KEY", "SECRET") defer os.Clearenv() config, err := NewCommandConfig(context, rdwr) assert.NoError(t, err, "Unexpected error when region is specified using environment variable AWS_DEFAULT_REGION") configRegion := config.Region() assert.Equal(t, region, configRegion, "Region should match") } func TestNewCommandConfigFromConfig(t *testing.T) { region := "us-east-1" globalSet := flag.NewFlagSet("ecs-cli", 0) globalContext := cli.NewContext(nil, globalSet, nil) flagSet := flag.NewFlagSet("ecs-cli-up", 0) flagSet.String("region", region, "") context := cli.NewContext(nil, flagSet, globalContext) rdwr := &mockReadWriter{} os.Setenv("AWS_ACCESS_KEY", "AKIDEXAMPLE") os.Setenv("AWS_SECRET_KEY", "SECRET") defer os.Clearenv() config, err := NewCommandConfig(context, rdwr) assert.NoError(t, err, "Unexpected error when region is specified") configRegion := config.Region() assert.Equal(t, region, configRegion, "Region should match") } func TestNewCommandConfigWhenPrefixesPresentINIVersion(t *testing.T) { os.Setenv("AWS_ACCESS_KEY", "AKIDEXAMPLE") os.Setenv("AWS_SECRET_KEY", "SECRET") defer os.Clearenv() context := defaultConfig() // Prefixes are present, and values are defaulted to empty rdwr := &mockReadWriter{isKeyPresentValue: true, version: iniConfigVersion} config, err := NewCommandConfig(context, rdwr) assert.NoError(t, err, "Unexpected error when getting new cli config") assert.Equal(t, composeProjectNamePrefix, config.ComposeProjectNamePrefix, "Expected ComposeProjectNamePrefix to be set") assert.Equal(t, composeServiceNamePrefix, config.ComposeServiceNamePrefix, "Expected ComposeServiceNamePrefix to be set") assert.Equal(t, cfnStackNamePrefix+clusterName, config.CFNStackName, "Expected CFNStackName to be default") assert.Empty(t, config.LaunchType, "Expected Launch Type to be empty") } func TestNewCommandConfigWhenPrefixKeysAreNotPresentINIVersion(t *testing.T) { os.Setenv("AWS_ACCESS_KEY", "AKIDEXAMPLE") os.Setenv("AWS_SECRET_KEY", "SECRET") defer func() { os.Unsetenv("AWS_ACCESS_KEY") os.Unsetenv("AWS_SECRET_KEY") }() context := defaultConfig() // Prefixes are present, and values should be set to defaults rdwr := &mockReadWriter{isKeyPresentValue: false, version: iniConfigVersion} config, err := NewCommandConfig(context, rdwr) assert.NoError(t, err, "Unexpected error when getting new CLI config") assert.Empty(t, config.ComposeProjectNamePrefix, "Expected ComposeProjectNamePrefix to be empty") assert.Empty(t, config.ComposeServiceNamePrefix, "Expected ComposeServiceNamePrefix to be empty") assert.Equal(t, clusterName, config.CFNStackName, "Expected CFNStackName to equal cluster name") assert.Empty(t, config.LaunchType, "Expected Launch Type to be empty") } func TestNewCommandConfigINIVersionLaunchTypeFlagEC2(t *testing.T) { os.Setenv("AWS_ACCESS_KEY", "AKIDEXAMPLE") os.Setenv("AWS_SECRET_KEY", "SECRET") defer func() { os.Unsetenv("AWS_ACCESS_KEY") os.Unsetenv("AWS_SECRET_KEY") }() context := configWithLaunchType(LaunchTypeEC2) // Prefixes are present, and values should be set to defaults rdwr := &mockReadWriter{isKeyPresentValue: false, version: iniConfigVersion} config, err := NewCommandConfig(context, rdwr) assert.NoError(t, err, "Unexpected error when getting new CLI config") assert.Empty(t, config.ComposeProjectNamePrefix, "Expected ComposeProjectNamePrefix to be empty") assert.Empty(t, config.ComposeServiceNamePrefix, "Expected ComposeServiceNamePrefix to be empty") assert.Equal(t, clusterName, config.CFNStackName, "Expected CFNStackName to equal cluster name") assert.Equal(t, LaunchTypeEC2, config.LaunchType) } func TestNewCommandConfigINIVersionLaunchTypeFlagFargate(t *testing.T) { os.Setenv("AWS_ACCESS_KEY", "AKIDEXAMPLE") os.Setenv("AWS_SECRET_KEY", "SECRET") defer func() { os.Unsetenv("AWS_ACCESS_KEY") os.Unsetenv("AWS_SECRET_KEY") }() context := configWithLaunchType(LaunchTypeFargate) // Prefixes are present, and values should be set to defaults rdwr := &mockReadWriter{isKeyPresentValue: false, version: iniConfigVersion} config, err := NewCommandConfig(context, rdwr) assert.NoError(t, err, "Unexpected error when getting new CLI config") assert.Empty(t, config.ComposeProjectNamePrefix, "Expected ComposeProjectNamePrefix to be empty") assert.Empty(t, config.ComposeServiceNamePrefix, "Expected ComposeServiceNamePrefix to be empty") assert.Equal(t, clusterName, config.CFNStackName, "Expected CFNStackName to equal cluster name") assert.Equal(t, LaunchTypeFargate, config.LaunchType) } func TestNewCommandConfigWhenPrefixesPresentYAMLVersion(t *testing.T) { os.Setenv("AWS_ACCESS_KEY", "AKIDEXAMPLE") os.Setenv("AWS_SECRET_KEY", "SECRET") defer os.Clearenv() context := defaultConfig() // Prefixes are present, and values are defaulted to empty rdwr := &mockReadWriter{isKeyPresentValue: true, version: yamlConfigVersion} config, err := NewCommandConfig(context, rdwr) assert.NoError(t, err, "Unexpected error when getting new cli config") assert.Empty(t, config.ComposeProjectNamePrefix, "Expected ComposeProjectNamePrefix to be empty") assert.Equal(t, composeServiceNamePrefix, config.ComposeServiceNamePrefix, "Expected ComposeServiceNamePrefix to be set") assert.Equal(t, cfnStackName, config.CFNStackName, "Expected CFNStackName to be set") assert.Equal(t, LaunchTypeEC2, config.LaunchType) } func TestNewCommandConfigWhenPrefixKeysAreNotPresentYAMLVersion(t *testing.T) { os.Setenv("AWS_ACCESS_KEY", "AKIDEXAMPLE") os.Setenv("AWS_SECRET_KEY", "SECRET") defer func() { os.Unsetenv("AWS_ACCESS_KEY") os.Unsetenv("AWS_SECRET_KEY") }() context := defaultConfig() // Prefixes are present, and values should be set to defaults rdwr := &mockReadWriter{isKeyPresentValue: false, version: yamlConfigVersion} config, err := NewCommandConfig(context, rdwr) assert.NoError(t, err, "Unexpected error when getting new cli config") assert.Empty(t, config.ComposeProjectNamePrefix, "Expected ComposProjectNamePrefix to be empty") assert.Empty(t, config.ComposeServiceNamePrefix, "Expected ComposeServiceNamePrefix to be empty") assert.Equal(t, flags.CFNStackNamePrefixDefaultValue+clusterName, config.CFNStackName, "Expected CFNStackName to be default") assert.Empty(t, config.LaunchType, "Expected Launch Type to be empty") } func TestNewCommandConfigYAMLVersionLaunchTypeEC2(t *testing.T) { os.Setenv("AWS_ACCESS_KEY", "AKIDEXAMPLE") os.Setenv("AWS_SECRET_KEY", "SECRET") defer os.Clearenv() context := defaultConfig() // Prefixes are present, and values are defaulted to empty rdwr := &mockReadWriter{isKeyPresentValue: true, version: yamlConfigVersion, fargate: false} config, err := NewCommandConfig(context, rdwr) assert.NoError(t, err, "Unexpected error when getting new cli config") assert.Empty(t, config.ComposeProjectNamePrefix, "Expected ComposeProjectNamePrefix to be empty") assert.Equal(t, composeServiceNamePrefix, config.ComposeServiceNamePrefix, "Expected ComposeServiceNamePrefix to be set") assert.Equal(t, cfnStackName, config.CFNStackName, "Expected CFNStackName to be set") assert.Equal(t, LaunchTypeEC2, config.LaunchType) } func TestNewCommandConfigYAMLVersionLaunchTypeFargate(t *testing.T) { os.Setenv("AWS_ACCESS_KEY", "AKIDEXAMPLE") os.Setenv("AWS_SECRET_KEY", "SECRET") defer os.Clearenv() context := defaultConfig() // Prefixes are present, and values are defaulted to empty rdwr := &mockReadWriter{isKeyPresentValue: true, version: yamlConfigVersion, fargate: true} config, err := NewCommandConfig(context, rdwr) assert.NoError(t, err, "Unexpected error when getting new cli config") assert.Empty(t, config.ComposeProjectNamePrefix, "Expected ComposeProjectNamePrefix to be empty") assert.Equal(t, composeServiceNamePrefix, config.ComposeServiceNamePrefix, "Expected ComposeServiceNamePrefix to be set") assert.Equal(t, cfnStackName, config.CFNStackName, "Expected CFNStackName to be set") assert.Equal(t, LaunchTypeFargate, config.LaunchType) } func TestNewCommandConfigYAMLVersionLaunchTypeOverriddenFargate(t *testing.T) { os.Setenv("AWS_ACCESS_KEY", "AKIDEXAMPLE") os.Setenv("AWS_SECRET_KEY", "SECRET") defer os.Clearenv() context := configWithLaunchType(LaunchTypeFargate) // Prefixes are present, and values are defaulted to empty rdwr := &mockReadWriter{isKeyPresentValue: true, version: yamlConfigVersion, fargate: false} config, err := NewCommandConfig(context, rdwr) assert.NoError(t, err, "Unexpected error when getting new cli config") assert.Empty(t, config.ComposeProjectNamePrefix, "Expected ComposeProjectNamePrefix to be empty") assert.Equal(t, composeServiceNamePrefix, config.ComposeServiceNamePrefix, "Expected ComposeServiceNamePrefix to be set") assert.Equal(t, cfnStackName, config.CFNStackName, "Expected CFNStackName to be set") assert.Equal(t, LaunchTypeFargate, config.LaunchType) } func TestNewCommandConfigYAMLVersionLaunchTypeOverriddenEC2(t *testing.T) { os.Setenv("AWS_ACCESS_KEY", "AKIDEXAMPLE") os.Setenv("AWS_SECRET_KEY", "SECRET") defer os.Clearenv() context := configWithLaunchType(LaunchTypeEC2) // Prefixes are present, and values are defaulted to empty rdwr := &mockReadWriter{isKeyPresentValue: true, version: yamlConfigVersion, fargate: true} config, err := NewCommandConfig(context, rdwr) assert.NoError(t, err, "Unexpected error when getting new cli config") assert.Empty(t, config.ComposeProjectNamePrefix, "Expected ComposeProjectNamePrefix to be empty") assert.Equal(t, composeServiceNamePrefix, config.ComposeServiceNamePrefix, "Expected ComposeServiceNamePrefix to be set") assert.Equal(t, cfnStackName, config.CFNStackName, "Expected CFNStackName to be set") assert.Equal(t, LaunchTypeEC2, config.LaunchType) } func TestNewCommandConfigWithAWSProfile(t *testing.T) { // Keys in env vars take highest precedence; ensure they are not set os.Unsetenv("AWS_ACCESS_KEY") os.Unsetenv("AWS_SECRET_KEY") configContents := `[awsprofile] aws_access_key_id = aws-access aws_secret_access_key = aws-secret ` // Create a temporary directory for the dummy aws config tempDirName, err := ioutil.TempDir("", "test") if err != nil { t.Fatal("Error while creating the dummy ecs config directory") } os.Setenv("HOME", tempDirName) os.Setenv("AWS_DEFAULT_REGION", region) defer os.Clearenv() defer os.RemoveAll(tempDirName) // save the aws config fileInfo, err := os.Stat(tempDirName) assert.NoError(t, err) mode := fileInfo.Mode() err = os.MkdirAll(tempDirName+"/.aws", mode) assert.NoError(t, err, "Could not create aws config directory") err = ioutil.WriteFile(tempDirName+"/.aws/credentials", []byte(configContents), mode) assert.NoError(t, err) globalSet := flag.NewFlagSet("ecs-cli", 0) globalContext := cli.NewContext(nil, globalSet, nil) flagSet := flag.NewFlagSet("ecs-cli-up", 0) flagSet.String("aws-profile", awsProfileName, "") context := cli.NewContext(nil, flagSet, globalContext) rdwr := &mockReadWriter{} config, err := NewCommandConfig(context, rdwr) assert.NoError(t, err) creds, err := config.Session.Config.Credentials.Get() assert.NoError(t, err) assert.Equal(t, awsAccessAWSProfile, creds.AccessKeyID, "Expected AWS Access Key to be read from the AWS Profile") assert.Equal(t, awsSecretAWSProfile, creds.SecretAccessKey, "Expected AWS Secret Access Key to be read from the AWS Profile") } func defaultConfig() *cli.Context { globalSet := flag.NewFlagSet("ecs-cli", 0) globalContext := cli.NewContext(nil, globalSet, nil) flagSet := flag.NewFlagSet("ecs-cli-up", 0) flagSet.String("region", "us-east-1", "") return cli.NewContext(nil, flagSet, globalContext) } func configWithLaunchType(launchType string) *cli.Context { globalSet := flag.NewFlagSet("ecs-cli", 0) globalContext := cli.NewContext(nil, globalSet, nil) flagSet := flag.NewFlagSet("ecs-cli-up", 0) flagSet.String("region", "us-east-1", "") flagSet.String(flags.LaunchTypeFlag, launchType, "") return cli.NewContext(nil, flagSet, globalContext) } func setupTest(t *testing.T) (*cli.Context, *mockReadWriter) { globalSet := flag.NewFlagSet("ecs-cli", 0) globalContext := cli.NewContext(nil, globalSet, nil) flagSet := flag.NewFlagSet("ecs-cli-up", 0) context := cli.NewContext(nil, flagSet, globalContext) rdwr := &mockReadWriter{} return context, rdwr }