post-processor/vagrant-cloud: try upload once

* fixes multiple uploads mentioned in #4973
* removed unused token code
This commit is contained in:
Matthew Hooker 2017-06-12 17:34:32 -07:00
parent 6c9d07f9c0
commit 94d7a4ce8d
No known key found for this signature in database
GPG Key ID: 7B5F933D9CE8C6A1
11 changed files with 27 additions and 136 deletions

View File

@ -105,7 +105,7 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
ReportTags(ui, snapshotTags)
// Retry creating tags for about 2.5 minutes
err = retry.Retry(0.2, 30, 11, func() (bool, error) {
err = retry.Retry(0.2, 30, 11, func(_ uint) (bool, error) {
// Tag images and snapshots
_, err := regionconn.CreateTags(&ec2.CreateTagsInput{
Resources: resourceIds,

View File

@ -294,7 +294,7 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi
ReportTags(ui, ec2Tags)
// Retry creating tags for about 2.5 minutes
err = retry.Retry(0.2, 30, 11, func() (bool, error) {
err = retry.Retry(0.2, 30, 11, func(_ uint) (bool, error) {
_, err := ec2conn.CreateTags(&ec2.CreateTagsInput{
Tags: ec2Tags,
Resources: []*string{instance.InstanceId},

View File

@ -582,7 +582,7 @@ type stateRefreshFunc func() (string, error)
// waitForState will spin in a loop forever waiting for state to
// reach a certain target.
func waitForState(errCh chan<- error, target string, refresh stateRefreshFunc) error {
err := common.Retry(2, 2, 0, func() (bool, error) {
err := common.Retry(2, 2, 0, func(_ uint) (bool, error) {
state, err := refresh()
if err != nil {
return false, err

View File

@ -22,7 +22,7 @@ func (s *StepWaitStartupScript) Run(state multistep.StateBag) multistep.StepActi
ui.Say("Waiting for any running startup script to finish...")
// Keep checking the serial port output to see if the startup script is done.
err := common.Retry(10, 60, 0, func() (bool, error) {
err := common.Retry(10, 60, 0, func(_ uint) (bool, error) {
status, err := driver.GetInstanceMetadata(config.Zone,
instanceName, StartupScriptStatusKey)

View File

@ -45,7 +45,7 @@ func (s *StepRemoveDevices) Run(state multistep.StateBag) multistep.StepAction {
var vboxErr error
// Retry for 10 minutes to remove the floppy controller.
log.Printf("Trying for 10 minutes to remove floppy controller.")
err := common.Retry(15, 15, 40, func() (bool, error) {
err := common.Retry(15, 15, 40, func(_ uint) (bool, error) {
// Don't forget to remove the floppy controller as well
command = []string{
"storagectl", vmName,

View File

@ -8,7 +8,11 @@ import (
var RetryExhaustedError error = fmt.Errorf("Function never succeeded in Retry")
type RetryableFunc func() (bool, error)
// RetryableFunc performs an action and returns a bool indicating whether the
// function is done, or if it should keep retrying, and an erorr which will
// abort the retry and be returned by the Retry function. The 0-indexed attempt
// is passed with each call.
type RetryableFunc func(uint) (bool, error)
// Retry retries a function up to numTries times with exponential backoff.
// If numTries == 0, retry indefinitely. If interval == 0, Retry will not delay retrying and there will be
@ -27,7 +31,7 @@ func Retry(initialInterval float64, maxInterval float64, numTries uint, function
done := false
interval := initialInterval
for i := uint(0); !done && (numTries == 0 || i < numTries); i++ {
done, err = function()
done, err = function(i)
if err != nil {
return err
}

View File

@ -8,7 +8,7 @@ import (
func TestRetry(t *testing.T) {
numTries := uint(0)
// Test that a passing function only gets called once.
err := Retry(0, 0, 0, func() (bool, error) {
err := Retry(0, 0, 0, func(i uint) (bool, error) {
numTries++
return true, nil
})
@ -22,7 +22,7 @@ func TestRetry(t *testing.T) {
// Test that a failing function gets retried (once in this example).
numTries = 0
results := []bool{false, true}
err = Retry(0, 0, 0, func() (bool, error) {
err = Retry(0, 0, 0, func(i uint) (bool, error) {
result := results[numTries]
numTries++
return result, nil
@ -37,7 +37,7 @@ func TestRetry(t *testing.T) {
// Test that a function error gets returned, and the function does not get called again.
numTries = 0
funcErr := fmt.Errorf("This function had an error!")
err = Retry(0, 0, 0, func() (bool, error) {
err = Retry(0, 0, 0, func(i uint) (bool, error) {
numTries++
return false, funcErr
})
@ -51,7 +51,7 @@ func TestRetry(t *testing.T) {
// Test when a function exhausts its retries.
numTries = 0
expectedTries := uint(3)
err = Retry(0, 0, expectedTries, func() (bool, error) {
err = Retry(0, 0, expectedTries, func(i uint) (bool, error) {
numTries++
return false, nil
})

View File

@ -152,7 +152,6 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac
new(stepCreateProvider),
new(stepPrepareUpload),
new(stepUpload),
new(stepVerifyUpload),
new(stepReleaseVersion),
}
} else {

View File

@ -2,12 +2,12 @@ package vagrantcloud
import (
"fmt"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type Upload struct {
Token string `json:"token"`
UploadPath string `json:"upload_path"`
}
@ -41,8 +41,6 @@ func (s *stepPrepareUpload) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionHalt
}
ui.Message(fmt.Sprintf("Box upload prepared with token %s", upload.Token))
// Save the upload details to the state
state.Put("upload", upload)

View File

@ -2,8 +2,9 @@ package vagrantcloud
import (
"fmt"
"time"
"log"
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
@ -23,34 +24,27 @@ func (s *stepUpload) Run(state multistep.StateBag) multistep.StepAction {
"Depending on your internet connection and the size of the box,\n" +
"this may take some time")
var finalErr error
for i := 0; i < 3; i++ {
if i > 0 {
ui.Message(fmt.Sprintf("Uploading box, attempt %d", i+1))
}
err := common.Retry(10, 10, 3, func(i uint) (bool, error) {
ui.Message(fmt.Sprintf("Uploading box, attempt %d", i+1))
resp, err := client.Upload(artifactFilePath, url)
if err != nil {
finalErr = err
ui.Message(fmt.Sprintf(
"Error uploading box! Will retry in 10 seconds. Error: %s", err))
time.Sleep(10 * time.Second)
continue
return false, nil
}
if resp.StatusCode != 200 {
finalErr = fmt.Errorf("bad HTTP status: %d", resp.StatusCode)
log.Printf("bad HTTP status: %d", resp.StatusCode)
ui.Message(fmt.Sprintf(
"Error uploading box! Will retry in 10 seconds. Status: %d",
resp.StatusCode))
time.Sleep(10 * time.Second)
continue
return false, nil
}
return true, nil
})
finalErr = nil
}
if finalErr != nil {
state.Put("error", finalErr)
if err != nil {
state.Put("error", err)
return multistep.ActionHalt
}

View File

@ -1,104 +0,0 @@
package vagrantcloud
import (
"fmt"
"log"
"time"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)
type stepVerifyUpload struct {
}
func (s *stepVerifyUpload) Run(state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*VagrantCloudClient)
ui := state.Get("ui").(packer.Ui)
box := state.Get("box").(*Box)
version := state.Get("version").(*Version)
upload := state.Get("upload").(*Upload)
provider := state.Get("provider").(*Provider)
path := fmt.Sprintf("box/%s/version/%v/provider/%s", box.Tag, version.Version, provider.Name)
providerCheck := &Provider{}
ui.Say(fmt.Sprintf("Verifying provider upload: %s", provider.Name))
done := make(chan struct{})
defer close(done)
result := make(chan error, 1)
go func() {
attempts := 0
for {
attempts += 1
log.Printf("Checking token match for provider.. (attempt: %d)", attempts)
resp, err := client.Get(path)
if err != nil || (resp.StatusCode != 200) {
cloudErrors := &VagrantCloudErrors{}
err = decodeBody(resp, cloudErrors)
err = fmt.Errorf("Error retrieving provider: %s", cloudErrors.FormatErrors())
result <- err
return
}
if err = decodeBody(resp, providerCheck); err != nil {
err = fmt.Errorf("Error parsing provider response: %s", err)
result <- err
return
}
if err != nil {
result <- err
return
}
if upload.Token == providerCheck.HostedToken {
// success!
result <- nil
return
}
// Wait 3 seconds in between
time.Sleep(3 * time.Second)
// Verify we shouldn't exit
select {
case <-done:
// We finished, so just exit the goroutine
return
default:
// Keep going
}
}
}()
ui.Message("Waiting for upload token match")
log.Printf("Waiting for up to 600 seconds for provider hosted token to match %s", upload.Token)
select {
case err := <-result:
if err != nil {
state.Put("error", err)
return multistep.ActionHalt
}
ui.Message(fmt.Sprintf("Upload successfully verified with token %s", providerCheck.HostedToken))
log.Printf("Box successfully verified %s == %s", upload.Token, providerCheck.HostedToken)
return multistep.ActionContinue
case <-time.After(600 * time.Second):
state.Put("error", fmt.Errorf("Timeout while waiting to for upload to verify token '%s'", upload.Token))
return multistep.ActionHalt
}
}
func (s *stepVerifyUpload) Cleanup(state multistep.StateBag) {
// No cleanup
}