diff --git a/builder/amazon/common/state.go b/builder/amazon/common/state.go index 741b5c651..73280afaa 100644 --- a/builder/amazon/common/state.go +++ b/builder/amazon/common/state.go @@ -242,38 +242,77 @@ func WaitForImageToBeImported(c *ec2.EC2, ctx aws.Context, input *ec2.DescribeIm // if AWS_MAX_ATTEMPTS is set but AWS_POLL_DELAY_SECONDS is not, then we will // use waiter-specific defaults. +type envInfo struct { + envKey string + Val int + overridden bool +} + +type overridableWaitVars struct { + awsPollDelaySeconds envInfo + awsMaxAttempts envInfo + awsTimeoutSeconds envInfo +} + func getWaiterOptions() []request.WaiterOption { + envOverrides := getEnvOverrides() + waitOpts := applyEnvOverrides(envOverrides) + return waitOpts +} + +func getEnvOverrides() overridableWaitVars { + // Load env vars from environment, and use them to override defaults + envValues := overridableWaitVars{ + envInfo{"AWS_POLL_DELAY_SECONDS", 2, false}, + envInfo{"AWS_MAX_ATTEMPTS", 0, false}, + envInfo{"AWS_TIMEOUT_SECONDS", 300, false}, + } + + for _, varInfo := range []envInfo{envValues.awsPollDelaySeconds, envValues.awsMaxAttempts, envValues.awsTimeoutSeconds} { + override := os.Getenv(varInfo.envKey) + if override != "" { + n, err := strconv.Atoi(override) + if err != nil { + log.Printf("Invalid %s '%s', using default", varInfo.envKey, override) + } else { + varInfo.overridden = true + varInfo.Val = n + } + } + } + + return envValues +} + +func applyEnvOverrides(envOverrides overridableWaitVars) []request.WaiterOption { waitOpts := make([]request.WaiterOption, 0) // If user has set poll delay seconds, overwrite it. If user has NOT, // default to a poll delay of 2 seconds - delayOverridden, delay := getEnvOverrides(2, "AWS_POLL_DELAY_SECONDS") - if delayOverridden { - delaySeconds := request.ConstantWaiterDelay(time.Duration(delay) * time.Second) + if envOverrides.awsPollDelaySeconds.overridden { + delaySeconds := request.ConstantWaiterDelay(time.Duration(envOverrides.awsPollDelaySeconds.Val) * time.Second) waitOpts = append(waitOpts, request.WithWaiterDelay(delaySeconds)) } // If user has set max attempts, overwrite it. If user hasn't set max // attempts, default to whatever the waiter has set as a default. - maxAttemptsOverridden, maxAttempts := getEnvOverrides(0, "AWS_MAX_ATTEMPTS") - if maxAttemptsOverridden { - waitOpts = append(waitOpts, request.WithWaiterMaxAttempts(maxAttempts)) + if envOverrides.awsMaxAttempts.overridden { + waitOpts = append(waitOpts, request.WithWaiterMaxAttempts(envOverrides.awsMaxAttempts.Val)) } - timeoutOverridden, timeoutSeconds := getEnvOverrides(300, "AWS_TIMEOUT_SECONDS") - if maxAttemptsOverridden { + if envOverrides.awsMaxAttempts.overridden && envOverrides.awsTimeoutSeconds.overridden { log.Printf("WARNING: AWS_MAX_ATTEMPTS and AWS_TIMEOUT_SECONDS are" + " both set. Packer will be using AWS_MAX_ATTEMPTS and discarding " + "AWS_TIMEOUT_SECONDS. If you have not set AWS_POLL_DELAY_SECONDS, " + "Packer will default to a 2 second poll delay.") - } else if timeoutOverridden { + } else if envOverrides.awsTimeoutSeconds.overridden { log.Printf("DEPRECATION WARNING: env var AWS_TIMEOUT_SECONDS is " + "deprecated in favor of AWS_MAX_ATTEMPTS. If you have not " + "explicitly set AWS_POLL_DELAY_SECONDS, we are defaulting to a " + "poll delay of 2 seconds, regardless of the AWS waiter's default.") - maxAttempts := timeoutSeconds / delay + maxAttempts := envOverrides.awsTimeoutSeconds.Val / envOverrides.awsPollDelaySeconds.Val // override the delay so we can get the timeout right - if !delayOverridden { - delaySeconds := request.ConstantWaiterDelay(time.Duration(delay) * time.Second) + if !envOverrides.awsPollDelaySeconds.overridden { + delaySeconds := request.ConstantWaiterDelay(time.Duration(envOverrides.awsPollDelaySeconds.Val) * time.Second) waitOpts = append(waitOpts, request.WithWaiterDelay(delaySeconds)) } waitOpts = append(waitOpts, request.WithWaiterMaxAttempts(maxAttempts)) @@ -289,22 +328,3 @@ func getWaiterOptions() []request.WaiterOption { return waitOpts } - -func getEnvOverrides(defaultValue int, envVarName string) (bool, int) { - // "AWS_POLL_DELAY_SECONDS" - retVal := defaultValue - overridden := false - override := os.Getenv(envVarName) - if override != "" { - n, err := strconv.Atoi(override) - if err != nil { - log.Printf("Invalid %s '%s', using default", envVarName, override) - } else { - overridden = true - retVal = n - } - } - - log.Printf("Using %ds for %s", retVal, envVarName) - return overridden, retVal -} diff --git a/builder/amazon/common/state_test.go b/builder/amazon/common/state_test.go index 638a41ae9..2ef7ae5aa 100644 --- a/builder/amazon/common/state_test.go +++ b/builder/amazon/common/state_test.go @@ -1,7 +1,6 @@ package common import ( - "os" "reflect" "testing" "time" @@ -9,26 +8,25 @@ import ( "github.com/aws/aws-sdk-go/aws/request" ) -func clearEnvVars() { - os.Unsetenv("AWS_POLL_DELAY_SECONDS") - os.Unsetenv("AWS_MAX_ATTEMPTS") - os.Unsetenv("AWS_TIMEOUT_SECONDS") -} - func testGetWaiterOptions(t *testing.T) { - clearEnvVars() - // no vars are set - options := getWaiterOptions() + envValues := overridableWaitVars{ + envInfo{"AWS_POLL_DELAY_SECONDS", 2, false}, + envInfo{"AWS_MAX_ATTEMPTS", 0, false}, + envInfo{"AWS_TIMEOUT_SECONDS", 300, false}, + } + options := applyEnvOverrides(envValues) if len(options) > 0 { t.Fatalf("Did not expect any waiter options to be generated; actual: %#v", options) } // all vars are set - os.Setenv("AWS_MAX_ATTEMPTS", "800") - os.Setenv("AWS_TIMEOUT_SECONDS", "20") - os.Setenv("AWS_POLL_DELAY_SECONDS", "1") - options = getWaiterOptions() + envValues = overridableWaitVars{ + envInfo{"AWS_POLL_DELAY_SECONDS", 1, true}, + envInfo{"AWS_MAX_ATTEMPTS", 800, true}, + envInfo{"AWS_TIMEOUT_SECONDS", 20, true}, + } + options = applyEnvOverrides(envValues) expected := []request.WaiterOption{ request.WithWaiterDelay(request.ConstantWaiterDelay(time.Duration(1) * time.Second)), request.WithWaiterMaxAttempts(800), @@ -36,22 +34,28 @@ func testGetWaiterOptions(t *testing.T) { if !reflect.DeepEqual(options, expected) { t.Fatalf("expected != actual!! Expected: %#v; Actual: %#v.", expected, options) } - clearEnvVars() // poll delay is not set - os.Setenv("AWS_MAX_ATTEMPTS", "800") - options = getWaiterOptions() + envValues = overridableWaitVars{ + envInfo{"AWS_POLL_DELAY_SECONDS", 2, false}, + envInfo{"AWS_MAX_ATTEMPTS", 800, true}, + envInfo{"AWS_TIMEOUT_SECONDS", 300, false}, + } + options = applyEnvOverrides(envValues) expected = []request.WaiterOption{ request.WithWaiterMaxAttempts(800), } if !reflect.DeepEqual(options, expected) { t.Fatalf("expected != actual!! Expected: %#v; Actual: %#v.", expected, options) } - clearEnvVars() // poll delay is not set but timeout seconds is - os.Setenv("AWS_TIMEOUT_SECONDS", "20") - options = getWaiterOptions() + envValues = overridableWaitVars{ + envInfo{"AWS_POLL_DELAY_SECONDS", 2, false}, + envInfo{"AWS_MAX_ATTEMPTS", 0, false}, + envInfo{"AWS_TIMEOUT_SECONDS", 20, true}, + } + options = applyEnvOverrides(envValues) expected = []request.WaiterOption{ request.WithWaiterDelay(request.ConstantWaiterDelay(time.Duration(2) * time.Second)), request.WithWaiterMaxAttempts(10), @@ -59,5 +63,4 @@ func testGetWaiterOptions(t *testing.T) { if !reflect.DeepEqual(options, expected) { t.Fatalf("expected != actual!! Expected: %#v; Actual: %#v.", expected, options) } - clearEnvVars() } diff --git a/post-processor/amazon-import/post-processor.go b/post-processor/amazon-import/post-processor.go index 812f6a4d4..e42fb1ae7 100644 --- a/post-processor/amazon-import/post-processor.go +++ b/post-processor/amazon-import/post-processor.go @@ -203,7 +203,6 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac } // Check it was actually completed - log.Printf("MEGAN result was %s", *import_result.ImportImageTasks[0].Status) if *import_result.ImportImageTasks[0].Status != "completed" { // The most useful error message is from the job itself return nil, false, fmt.Errorf("Import task %s failed: %s", *import_start.ImportTaskId, *import_result.ImportImageTasks[0].StatusMessage)