diff --git a/models/nuke.go b/models/nuke.go index 7e324ff..0055ee0 100644 --- a/models/nuke.go +++ b/models/nuke.go @@ -19,14 +19,15 @@ package models // Config represents all the parameters supported by cfn-teardown type Config struct { - AWSProfile string `mapstructure:"AWS_PROFILE"` - AWSRegion string `mapstructure:"AWS_REGION"` - TargetAccountId string `mapstructure:"TARGET_ACCOUNT_ID"` - StackPattern string `mapstructure:"STACK_PATTERN"` - StackWaitTimeSeconds int16 `mapstructure:"STACK_WAIT_TIME_SECONDS"` - MaxDeleteRetryCount int16 `mapstructure:"MAX_DELETE_RETRY_COUNT"` - AbortWaitTimeMinutes int16 `mapstructure:"ABORT_WAIT_TIME_MINUTES"` - SlackWebhookURL string `mapstructure:"SLACK_WEBHOOK_URL"` - RoleARN string `mapstructure:"ROLE_ARN"` - DryRun string `mapstructure:"DRY_RUN"` + AWSProfile string `mapstructure:"AWS_PROFILE"` + AWSRegion string `mapstructure:"AWS_REGION"` + TargetAccountId string `mapstructure:"TARGET_ACCOUNT_ID"` + StackPattern string `mapstructure:"STACK_PATTERN"` + StackWaitTimeSeconds int16 `mapstructure:"STACK_WAIT_TIME_SECONDS"` + MaxDeleteRetryCount int16 `mapstructure:"MAX_DELETE_RETRY_COUNT"` + AbortWaitTimeMinutes int16 `mapstructure:"ABORT_WAIT_TIME_MINUTES"` + SlackWebhookURL string `mapstructure:"SLACK_WEBHOOK_URL"` + RoleARN string `mapstructure:"ROLE_ARN"` + DryRun string `mapstructure:"DRY_RUN"` + EndpointURL *string `mapstructure:"ENDPOINT_URL"` } diff --git a/utils/cloudformation.go b/utils/cloudformation.go index e4adb69..7bb94c8 100644 --- a/utils/cloudformation.go +++ b/utils/cloudformation.go @@ -38,6 +38,7 @@ type CFNManager struct { StackPattern string AWSProfile string AWSRegion string + EndpointURL *string } // DescribeStack returns description for particular stack. @@ -161,6 +162,7 @@ func (dm CFNManager) ListEnvironmentStacks() (map[string]models.StackDetails, er } } + // FIX: this condition is unreachable if err != nil { fmt.Printf("Failed listing stacks with pattern: '%v', Error: '%v'\n", dm.StackPattern, err) return envStacks, err @@ -196,10 +198,11 @@ func (dm CFNManager) ListEnvironmentStacks() (map[string]models.StackDetails, er } // ListEnvironmentExports finds all exported values for our matching stacks in this format: -// { -// "stack-1-name": ["export-1", "export-2"], -// "stack-2-name": [] -// } +// +// { +// "stack-1-name": ["export-1", "export-2"], +// "stack-2-name": [] +// } func (dm CFNManager) ListEnvironmentExports() (map[string][]string, error) { exports := map[string][]string{} @@ -257,7 +260,11 @@ func (dm CFNManager) RegexMatch(stackName string) bool { // It also has validation for target account id to ensure we are deleting in the correct aws account. func (dm CFNManager) Session() (*cloudformation.CloudFormation, error) { sess := session.Must(session.NewSessionWithOptions(session.Options{ - Config: aws.Config{Region: aws.String(dm.AWSRegion)}, + Config: aws.Config{ + Region: aws.String(dm.AWSRegion), + // localstack endpoint URL is passed during integration tests, otherwise it is nil + Endpoint: dm.EndpointURL, + }, SharedConfigState: session.SharedConfigEnable, Profile: dm.AWSProfile, })) diff --git a/utils/deleter.go b/utils/deleter.go index 3825d77..fa4240c 100644 --- a/utils/deleter.go +++ b/utils/deleter.go @@ -55,8 +55,8 @@ var ( // InitiateTearDown scans and deletes cloudformation stacks respecting the dependencies. // A stack is eligible for deletion when it's exports has not been imported by any other stacks. func InitiateTearDown(config models.Config) { - cfn := CFNManager{StackPattern: config.StackPattern, TargetAccountId: config.TargetAccountId, NukeRoleARN: config.RoleARN, AWSProfile: config.AWSProfile, AWSRegion: config.AWSRegion} - s3 := S3Manager{TargetAccountId: config.TargetAccountId, NukeRoleARN: config.RoleARN, AWSProfile: config.AWSProfile, AWSRegion: config.AWSRegion} + cfn := CFNManager{StackPattern: config.StackPattern, TargetAccountId: config.TargetAccountId, NukeRoleARN: config.RoleARN, AWSProfile: config.AWSProfile, AWSRegion: config.AWSRegion, EndpointURL: config.EndpointURL} + s3 := S3Manager{TargetAccountId: config.TargetAccountId, NukeRoleARN: config.RoleARN, AWSProfile: config.AWSProfile, AWSRegion: config.AWSRegion, EndpointURL: config.EndpointURL} notifier := NotificationManager{StackPattern: config.StackPattern, SlackWebHookURL: config.SlackWebhookURL, DryRun: config.DryRun} var dependencyTree = map[string]models.StackDetails{} diff --git a/utils/s3.go b/utils/s3.go index 296547f..e642531 100644 --- a/utils/s3.go +++ b/utils/s3.go @@ -34,6 +34,7 @@ type S3Manager struct { NukeRoleARN string AWSProfile string AWSRegion string + EndpointURL *string } // EmptyBucket deletes all objects from a particular S3 bucket. @@ -75,7 +76,11 @@ func (sm S3Manager) EmptyBucket(bucketName string) error { // It also has validation for target account id to ensure we are deleting in the correct aws account. func (sm S3Manager) Session() (*s3.S3, error) { sess := session.Must(session.NewSessionWithOptions(session.Options{ - Config: aws.Config{Region: aws.String(sm.AWSRegion)}, + Config: aws.Config{ + Region: aws.String(sm.AWSRegion), + // localstack endpoint URL is passed during integration tests, otherwise it is nil + Endpoint: sm.EndpointURL, + }, SharedConfigState: session.SharedConfigEnable, Profile: sm.AWSProfile, }))