Skip to content

Commit

Permalink
builder: add option to no block on transfers
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewsomething committed Feb 12, 2024
1 parent 477c366 commit d8643f0
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 18 deletions.
3 changes: 2 additions & 1 deletion builder/digitalocean/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
new(stepShutdown),
new(stepPowerOff),
&stepSnapshot{
snapshotTimeout: b.config.SnapshotTimeout,
snapshotTimeout: b.config.SnapshotTimeout,
waitForSnapshotTransfer: *b.config.WaitSnapshotTransfer,
},
}

Expand Down
59 changes: 54 additions & 5 deletions builder/digitalocean/builder_acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package digitalocean
import (
"context"
"fmt"
"io"
"os"
"os/exec"
"regexp"
"testing"

"github.com/digitalocean/godo"
Expand Down Expand Up @@ -68,6 +70,43 @@ func TestBuilderAcc_multiRegion(t *testing.T) {
})
}

func TestBuilderAcc_multiRegionNoWait(t *testing.T) {
if skip := testAccPreCheck(t); skip == true {
return
}
acctest.TestPlugin(t, &acctest.PluginTestCase{
Name: "test-digitalocean-builder-multi-region",
Template: fmt.Sprintf(testBuilderAccMultiRegionNoWait, "ubuntu-20-04-x64"),
Check: func(buildCommand *exec.Cmd, logfile string) error {
if buildCommand.ProcessState != nil {
if buildCommand.ProcessState.ExitCode() != 0 {
return fmt.Errorf("Bad exit code. Logfile: %s", logfile)
}
}

logs, err := os.Open(logfile)
if err != nil {
return fmt.Errorf("Unable find %s", logfile)
}
defer logs.Close()

logsBytes, err := io.ReadAll(logs)
if err != nil {
return fmt.Errorf("Unable to read %s", logfile)
}
logsString := string(logsBytes)

notExpected := regexp.MustCompile(`Transfer to .* is complete.`)
matches := notExpected.FindStringSubmatch(logsString)
if len(matches) > 0 {
return fmt.Errorf("logs contains unexpected value: %v", matches)
}

return nil
},
})
}

func testAccPreCheck(t *testing.T) bool {
if os.Getenv(acctest.TestEnvVar) == "" {
t.Skipf("Acceptance tests skipped unless env '%s' set", acctest.TestEnvVar)
Expand Down Expand Up @@ -127,9 +166,7 @@ const (
"region": "nyc2",
"size": "s-1vcpu-1gb",
"image": "%v",
"ssh_username": "root",
"user_data": "",
"user_data_file": ""
"ssh_username": "root"
}]
}
`
Expand All @@ -142,10 +179,22 @@ const (
"size": "s-1vcpu-1gb",
"image": "%v",
"ssh_username": "root",
"user_data": "",
"user_data_file": "",
"snapshot_regions": ["nyc1", "nyc2", "nyc3"]
}]
}
`

testBuilderAccMultiRegionNoWait = `
{
"builders": [{
"type": "digitalocean",
"region": "nyc2",
"size": "s-1vcpu-1gb",
"image": "%v",
"ssh_username": "root",
"snapshot_regions": ["nyc2", "nyc3"],
"wait_snapshot_transfer": false
}]
}
`
)
11 changes: 9 additions & 2 deletions builder/digitalocean/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,12 @@ type Config struct {
// appear in your account. Defaults to `packer-{{timestamp}}` (see
// configuration templates for more info).
SnapshotName string `mapstructure:"snapshot_name" required:"false"`
// The regions of the resulting
// snapshot that will appear in your account.
// Additional regions that resulting snapshot should be distributed to.
SnapshotRegions []string `mapstructure:"snapshot_regions" required:"false"`
// When true, Packer will block until all snapshot transfers have been completed
// and report errors. When false, Packer will initiate the snapshot transfers
// and exit successfully without waiting for completion. Defaults to true.
WaitSnapshotTransfer *bool `mapstructure:"wait_snapshot_transfer" required:"false"`
// The time to wait, as a duration string, for a
// droplet to enter a desired state (such as "active") before timing out. The
// default state timeout is "6m".
Expand Down Expand Up @@ -212,6 +215,10 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
c.SnapshotTimeout = 60 * time.Minute
}

if c.WaitSnapshotTransfer == nil {
c.WaitSnapshotTransfer = godo.PtrTo(true)
}

if es := c.Comm.Prepare(&c.ctx); len(es) > 0 {
errs = packersdk.MultiErrorAppend(errs, es...)
}
Expand Down
2 changes: 2 additions & 0 deletions builder/digitalocean/config.hcl2spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 11 additions & 8 deletions builder/digitalocean/step_snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import (
)

type stepSnapshot struct {
snapshotTimeout time.Duration
snapshotTimeout time.Duration
waitForSnapshotTransfer bool
}

func (s *stepSnapshot) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
Expand Down Expand Up @@ -108,14 +109,16 @@ func (s *stepSnapshot) Run(ctx context.Context, state multistep.StateBag) multis
return fmt.Errorf("Error transferring snapshot: %s", err)
}

if err := WaitForImageState(
godo.ActionCompleted,
imageId,
imageTransfer.ID,
client, 20*time.Minute); err != nil {
return fmt.Errorf("Error waiting for snapshot transfer: %s", err)
if s.waitForSnapshotTransfer {
if err := WaitForImageState(
godo.ActionCompleted,
imageId,
imageTransfer.ID,
client, 20*time.Minute); err != nil {
return fmt.Errorf("Error waiting for snapshot transfer: %s", err)
}
ui.Say(fmt.Sprintf("Transfer to %s is complete.", region))
}
ui.Say(fmt.Sprintf("Transfer to %s is complete.", region))

return nil
})
Expand Down
7 changes: 5 additions & 2 deletions docs-partials/builder/digitalocean/Config-not-required.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@
appear in your account. Defaults to `packer-{{timestamp}}` (see
configuration templates for more info).

- `snapshot_regions` ([]string) - The regions of the resulting
snapshot that will appear in your account.
- `snapshot_regions` ([]string) - Additional regions that resulting snapshot should be distributed to.

- `wait_snapshot_transfer` (\*bool) - When true, Packer will block until all snapshot transfers have been completed
and report errors. When false, Packer will initiate the snapshot transfers
and exit successfully without waiting for completion. Defaults to true.

- `state_timeout` (duration string | ex: "1h5m2s") - The time to wait, as a duration string, for a
droplet to enter a desired state (such as "active") before timing out. The
Expand Down

0 comments on commit d8643f0

Please sign in to comment.