post-processor/vagrant-cloud: try upload once
* fixes multiple uploads mentioned in #4973 * removed unused token code
This commit is contained in:
parent
6c9d07f9c0
commit
94d7a4ce8d
|
@ -105,7 +105,7 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
ReportTags(ui, snapshotTags)
|
ReportTags(ui, snapshotTags)
|
||||||
|
|
||||||
// Retry creating tags for about 2.5 minutes
|
// 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
|
// Tag images and snapshots
|
||||||
_, err := regionconn.CreateTags(&ec2.CreateTagsInput{
|
_, err := regionconn.CreateTags(&ec2.CreateTagsInput{
|
||||||
Resources: resourceIds,
|
Resources: resourceIds,
|
||||||
|
|
|
@ -294,7 +294,7 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi
|
||||||
ReportTags(ui, ec2Tags)
|
ReportTags(ui, ec2Tags)
|
||||||
|
|
||||||
// Retry creating tags for about 2.5 minutes
|
// 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{
|
_, err := ec2conn.CreateTags(&ec2.CreateTagsInput{
|
||||||
Tags: ec2Tags,
|
Tags: ec2Tags,
|
||||||
Resources: []*string{instance.InstanceId},
|
Resources: []*string{instance.InstanceId},
|
||||||
|
|
|
@ -582,7 +582,7 @@ type stateRefreshFunc func() (string, error)
|
||||||
// waitForState will spin in a loop forever waiting for state to
|
// waitForState will spin in a loop forever waiting for state to
|
||||||
// reach a certain target.
|
// reach a certain target.
|
||||||
func waitForState(errCh chan<- error, target string, refresh stateRefreshFunc) error {
|
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()
|
state, err := refresh()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
|
|
@ -22,7 +22,7 @@ func (s *StepWaitStartupScript) Run(state multistep.StateBag) multistep.StepActi
|
||||||
ui.Say("Waiting for any running startup script to finish...")
|
ui.Say("Waiting for any running startup script to finish...")
|
||||||
|
|
||||||
// Keep checking the serial port output to see if the startup script is done.
|
// 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,
|
status, err := driver.GetInstanceMetadata(config.Zone,
|
||||||
instanceName, StartupScriptStatusKey)
|
instanceName, StartupScriptStatusKey)
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ func (s *StepRemoveDevices) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
var vboxErr error
|
var vboxErr error
|
||||||
// Retry for 10 minutes to remove the floppy controller.
|
// Retry for 10 minutes to remove the floppy controller.
|
||||||
log.Printf("Trying for 10 minutes to remove 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
|
// Don't forget to remove the floppy controller as well
|
||||||
command = []string{
|
command = []string{
|
||||||
"storagectl", vmName,
|
"storagectl", vmName,
|
||||||
|
|
|
@ -8,7 +8,11 @@ import (
|
||||||
|
|
||||||
var RetryExhaustedError error = fmt.Errorf("Function never succeeded in Retry")
|
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.
|
// 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
|
// 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
|
done := false
|
||||||
interval := initialInterval
|
interval := initialInterval
|
||||||
for i := uint(0); !done && (numTries == 0 || i < numTries); i++ {
|
for i := uint(0); !done && (numTries == 0 || i < numTries); i++ {
|
||||||
done, err = function()
|
done, err = function(i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
func TestRetry(t *testing.T) {
|
func TestRetry(t *testing.T) {
|
||||||
numTries := uint(0)
|
numTries := uint(0)
|
||||||
// Test that a passing function only gets called once.
|
// 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++
|
numTries++
|
||||||
return true, nil
|
return true, nil
|
||||||
})
|
})
|
||||||
|
@ -22,7 +22,7 @@ func TestRetry(t *testing.T) {
|
||||||
// Test that a failing function gets retried (once in this example).
|
// Test that a failing function gets retried (once in this example).
|
||||||
numTries = 0
|
numTries = 0
|
||||||
results := []bool{false, true}
|
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]
|
result := results[numTries]
|
||||||
numTries++
|
numTries++
|
||||||
return result, nil
|
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.
|
// Test that a function error gets returned, and the function does not get called again.
|
||||||
numTries = 0
|
numTries = 0
|
||||||
funcErr := fmt.Errorf("This function had an error!")
|
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++
|
numTries++
|
||||||
return false, funcErr
|
return false, funcErr
|
||||||
})
|
})
|
||||||
|
@ -51,7 +51,7 @@ func TestRetry(t *testing.T) {
|
||||||
// Test when a function exhausts its retries.
|
// Test when a function exhausts its retries.
|
||||||
numTries = 0
|
numTries = 0
|
||||||
expectedTries := uint(3)
|
expectedTries := uint(3)
|
||||||
err = Retry(0, 0, expectedTries, func() (bool, error) {
|
err = Retry(0, 0, expectedTries, func(i uint) (bool, error) {
|
||||||
numTries++
|
numTries++
|
||||||
return false, nil
|
return false, nil
|
||||||
})
|
})
|
||||||
|
|
|
@ -152,7 +152,6 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac
|
||||||
new(stepCreateProvider),
|
new(stepCreateProvider),
|
||||||
new(stepPrepareUpload),
|
new(stepPrepareUpload),
|
||||||
new(stepUpload),
|
new(stepUpload),
|
||||||
new(stepVerifyUpload),
|
|
||||||
new(stepReleaseVersion),
|
new(stepReleaseVersion),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,12 +2,12 @@ package vagrantcloud
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/hashicorp/packer/packer"
|
"github.com/hashicorp/packer/packer"
|
||||||
"github.com/mitchellh/multistep"
|
"github.com/mitchellh/multistep"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Upload struct {
|
type Upload struct {
|
||||||
Token string `json:"token"`
|
|
||||||
UploadPath string `json:"upload_path"`
|
UploadPath string `json:"upload_path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,8 +41,6 @@ func (s *stepPrepareUpload) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.Message(fmt.Sprintf("Box upload prepared with token %s", upload.Token))
|
|
||||||
|
|
||||||
// Save the upload details to the state
|
// Save the upload details to the state
|
||||||
state.Put("upload", upload)
|
state.Put("upload", upload)
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,9 @@ package vagrantcloud
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"log"
|
||||||
|
|
||||||
|
"github.com/hashicorp/packer/common"
|
||||||
"github.com/hashicorp/packer/packer"
|
"github.com/hashicorp/packer/packer"
|
||||||
"github.com/mitchellh/multistep"
|
"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" +
|
"Depending on your internet connection and the size of the box,\n" +
|
||||||
"this may take some time")
|
"this may take some time")
|
||||||
|
|
||||||
var finalErr error
|
err := common.Retry(10, 10, 3, func(i uint) (bool, error) {
|
||||||
for i := 0; i < 3; i++ {
|
ui.Message(fmt.Sprintf("Uploading box, attempt %d", i+1))
|
||||||
if i > 0 {
|
|
||||||
ui.Message(fmt.Sprintf("Uploading box, attempt %d", i+1))
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := client.Upload(artifactFilePath, url)
|
resp, err := client.Upload(artifactFilePath, url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
finalErr = err
|
|
||||||
ui.Message(fmt.Sprintf(
|
ui.Message(fmt.Sprintf(
|
||||||
"Error uploading box! Will retry in 10 seconds. Error: %s", err))
|
"Error uploading box! Will retry in 10 seconds. Error: %s", err))
|
||||||
time.Sleep(10 * time.Second)
|
return false, nil
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
if resp.StatusCode != 200 {
|
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(
|
ui.Message(fmt.Sprintf(
|
||||||
"Error uploading box! Will retry in 10 seconds. Status: %d",
|
"Error uploading box! Will retry in 10 seconds. Status: %d",
|
||||||
resp.StatusCode))
|
resp.StatusCode))
|
||||||
time.Sleep(10 * time.Second)
|
return false, nil
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
finalErr = nil
|
if err != nil {
|
||||||
}
|
state.Put("error", err)
|
||||||
|
|
||||||
if finalErr != nil {
|
|
||||||
state.Put("error", finalErr)
|
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
Loading…
Reference in New Issue