diff --git a/builder/vagrant/artifact.go b/builder/vagrant/artifact.go
new file mode 100644
index 000000000..8a3c053b1
--- /dev/null
+++ b/builder/vagrant/artifact.go
@@ -0,0 +1,50 @@
+package vagrant
+
+import (
+ "fmt"
+ "path/filepath"
+
+ "github.com/hashicorp/packer/packer"
+)
+
+// This is the common builder ID to all of these artifacts.
+const BuilderId = "vagrant"
+
+// Artifact is the result of running the vagrant builder, namely a set
+// of files associated with the resulting machine.
+type artifact struct {
+ OutputDir string
+ BoxName string
+}
+
+// NewArtifact returns a vagrant artifact containing the .box file
+func NewArtifact(dir string) (packer.Artifact, error) {
+ return &artifact{
+ OutputDir: dir,
+ BoxName: "package.box",
+ }, nil
+}
+
+func (*artifact) BuilderId() string {
+ return BuilderId
+}
+
+func (a *artifact) Files() []string {
+ return []string{a.BoxName}
+}
+
+func (a *artifact) Id() string {
+ return filepath.Join(a.OutputDir, a.BoxName)
+}
+
+func (a *artifact) String() string {
+ return fmt.Sprintf("Vagrant box is %s", a.Id())
+}
+
+func (a *artifact) State(name string) interface{} {
+ return nil
+}
+
+func (a *artifact) Destroy() error {
+ return nil
+}
diff --git a/builder/vagrant/artifact_test.go b/builder/vagrant/artifact_test.go
new file mode 100644
index 000000000..63e1db1ec
--- /dev/null
+++ b/builder/vagrant/artifact_test.go
@@ -0,0 +1,47 @@
+package vagrant
+
+import (
+ "runtime"
+ "strings"
+ "testing"
+
+ "github.com/hashicorp/packer/packer"
+)
+
+func TestArtifact_Impl(t *testing.T) {
+ var raw interface{} = &artifact{}
+
+ if _, ok := raw.(packer.Artifact); !ok {
+ t.Fatalf("Artifact does not implement packer.Artifact")
+ }
+}
+
+func TestArtifactId(t *testing.T) {
+ a := &artifact{
+ OutputDir: "/my/dir",
+ BoxName: "package.box",
+ }
+
+ expected := "/my/dir/package.box"
+ if runtime.GOOS == "windows" {
+ expected = strings.Replace(expected, "/", "\\", -1)
+ }
+ if strings.Compare(a.Id(), expected) != 0 {
+ t.Fatalf("artifact ID should match: expected: %s received: %s", expected, a.Id())
+ }
+}
+
+func TestArtifactString(t *testing.T) {
+ a := &artifact{
+ OutputDir: "/my/dir",
+ BoxName: "package.box",
+ }
+ expected := "Vagrant box is /my/dir/package.box"
+ if runtime.GOOS == "windows" {
+ expected = strings.Replace(expected, "/", "\\", -1)
+ }
+
+ if strings.Compare(a.String(), expected) != 0 {
+ t.Fatalf("artifact string should match: expected: %s received: %s", expected, a.String())
+ }
+}
diff --git a/builder/vagrant/builder.go b/builder/vagrant/builder.go
new file mode 100644
index 000000000..a0cd3202a
--- /dev/null
+++ b/builder/vagrant/builder.go
@@ -0,0 +1,276 @@
+package vagrant
+
+import (
+ "errors"
+ "fmt"
+ "log"
+ "path/filepath"
+ "strings"
+ "time"
+
+ "github.com/hashicorp/packer/common"
+ "github.com/hashicorp/packer/common/bootcommand"
+ "github.com/hashicorp/packer/helper/communicator"
+ "github.com/hashicorp/packer/helper/config"
+ "github.com/hashicorp/packer/helper/multistep"
+ "github.com/hashicorp/packer/packer"
+ "github.com/hashicorp/packer/template/interpolate"
+)
+
+// Builder implements packer.Builder and builds the actual VirtualBox
+// images.
+type Builder struct {
+ config *Config
+ runner multistep.Runner
+}
+
+type SSHConfig struct {
+ Comm communicator.Config `mapstructure:",squash"`
+}
+
+type Config struct {
+ common.PackerConfig `mapstructure:",squash"`
+ common.HTTPConfig `mapstructure:",squash"`
+ common.ISOConfig `mapstructure:",squash"`
+ common.FloppyConfig `mapstructure:",squash"`
+ bootcommand.BootConfig `mapstructure:",squash"`
+ SSHConfig `mapstructure:",squash"`
+
+ // This is the name of the new virtual machine.
+ // By default this is "packer-BUILDNAME", where "BUILDNAME" is the name of the build.
+ OutputDir string `mapstructure:"output_dir"`
+ SourceBox string `mapstructure:"source_path"`
+ GlobalID string `mapstructure:"global_id"`
+ Checksum string `mapstructure:"checksum"`
+ ChecksumType string `mapstructure:"checksum_type"`
+ BoxName string `mapstructure:"box_name"`
+
+ Provider string `mapstructure:"provider"`
+
+ Communicator string `mapstructure:"communicator"`
+
+ // What vagrantfile to use
+ VagrantfileTpl string `mapstructure:"vagrantfile_template"`
+
+ // Whether to Halt, Suspend, or Destroy the box
+ TeardownMethod string `mapstructure:"teardown_method"`
+
+ // Options for the "vagrant init" command
+ BoxVersion string `mapstructure:"box_version"`
+ Template string `mapstructure:"template"`
+ SyncedFolder string `mapstructure:"synced_folder"`
+
+ // Options for the "vagrant box add" command
+ SkipAdd bool `mapstructure:"skip_add"`
+ AddCACert string `mapstructure:"add_cacert"`
+ AddCAPath string `mapstructure:"add_capath"`
+ AddCert string `mapstructure:"add_cert"`
+ AddClean bool `mapstructure:"add_clean"`
+ AddForce bool `mapstructure:"add_force"`
+ AddInsecure bool `mapstructure:"add_insecure"`
+
+ // Don't package the Vagrant box after build.
+ SkipPackage bool `mapstructure:"skip_package"`
+ OutputVagrantfile string `mapstructure:"output_vagrantfile"`
+ PackageInclude []string `mapstructure:"package_include"`
+
+ ctx interpolate.Context
+}
+
+// Prepare processes the build configuration parameters.
+func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
+ b.config = new(Config)
+ err := config.Decode(&b.config, &config.DecodeOpts{
+ Interpolate: true,
+ InterpolateContext: &b.config.ctx,
+ InterpolateFilter: &interpolate.RenderFilter{
+ Exclude: []string{
+ "boot_command",
+ },
+ },
+ }, raws...)
+ if err != nil {
+ return nil, err
+ }
+
+ // Accumulate any errors and warnings
+ var errs *packer.MultiError
+ warnings := make([]string, 0)
+
+ if b.config.OutputDir == "" {
+ b.config.OutputDir = fmt.Sprintf("output-%s", b.config.PackerBuildName)
+ }
+
+ if b.config.Comm.SSHTimeout == 0 {
+ b.config.Comm.SSHTimeout = 10 * time.Minute
+ }
+
+ if b.config.Comm.Type != "ssh" {
+ errs = packer.MultiErrorAppend(errs,
+ fmt.Errorf(`The Vagrant builder currently only supports the ssh communicator"`))
+ }
+ // The box isn't a namespace like you'd pull from vagrant cloud
+ if b.config.BoxName == "" {
+ b.config.BoxName = fmt.Sprintf("packer_%s", b.config.PackerBuildName)
+ }
+
+ if b.config.SourceBox == "" {
+ if b.config.GlobalID == "" {
+ errs = packer.MultiErrorAppend(errs, fmt.Errorf("source_path is required unless you have set global_id"))
+ }
+ } else {
+ if b.config.GlobalID != "" {
+ errs = packer.MultiErrorAppend(errs, fmt.Errorf("You may either set global_id or source_path but not both"))
+ }
+ if strings.HasSuffix(b.config.SourceBox, ".box") {
+ b.config.SourceBox, err = common.ValidatedURL(b.config.SourceBox)
+ if err != nil {
+ errs = packer.MultiErrorAppend(errs, fmt.Errorf("source_path is invalid: %s", err))
+ }
+ fileOK := common.FileExistsLocally(b.config.SourceBox)
+ if !fileOK {
+ errs = packer.MultiErrorAppend(errs,
+ fmt.Errorf("Source file '%s' needs to exist at time of config validation!", b.config.SourceBox))
+ }
+ }
+ }
+
+ if b.config.TeardownMethod == "" {
+ // If we're using a box that's already opened on the system, don't
+ // automatically destroy it. If we open the box ourselves, then go ahead
+ // and kill it by default.
+ if b.config.GlobalID != "" {
+ b.config.TeardownMethod = "halt"
+ } else {
+ b.config.TeardownMethod = "destroy"
+ }
+ } else {
+ matches := false
+ for _, name := range []string{"halt", "suspend", "destroy"} {
+ if strings.ToLower(b.config.TeardownMethod) == name {
+ matches = true
+ }
+ }
+ if !matches {
+ errs = packer.MultiErrorAppend(errs,
+ fmt.Errorf(`TeardownMethod must be "halt", "suspend", or "destroy"`))
+ }
+ }
+
+ if errs != nil && len(errs.Errors) > 0 {
+ return warnings, errs
+ }
+
+ return warnings, nil
+}
+
+// Run executes a Packer build and returns a packer.Artifact representing
+// a VirtualBox appliance.
+func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
+ // Create the driver that we'll use to communicate with VirtualBox
+ VagrantCWD, err := filepath.Abs(b.config.OutputDir)
+ if err != nil {
+ return nil, err
+ }
+ driver, err := NewDriver(VagrantCWD)
+ if err != nil {
+ return nil, fmt.Errorf("Failed creating VirtualBox driver: %s", err)
+ }
+
+ // Set up the state.
+ state := new(multistep.BasicStateBag)
+ state.Put("config", b.config)
+ state.Put("debug", b.config.PackerDebug)
+ state.Put("driver", driver)
+ state.Put("cache", cache)
+ state.Put("hook", hook)
+ state.Put("ui", ui)
+
+ // Build the steps.
+ steps := []multistep.Step{}
+ // Download if source box isn't from vagrant cloud.
+ if strings.HasSuffix(b.config.SourceBox, ".box") {
+ steps = append(steps, &common.StepDownload{
+ Checksum: b.config.Checksum,
+ ChecksumType: b.config.ChecksumType,
+ Description: "Box",
+ Extension: "box",
+ ResultKey: "box_path",
+ Url: []string{b.config.SourceBox},
+ })
+ }
+ steps = append(steps,
+ &common.StepOutputDir{
+ Force: b.config.PackerForce,
+ Path: b.config.OutputDir,
+ },
+ &StepCreateVagrantfile{
+ Template: b.config.Template,
+ SyncedFolder: b.config.SyncedFolder,
+ SourceBox: b.config.SourceBox,
+ OutputDir: b.config.OutputDir,
+ GlobalID: b.config.GlobalID,
+ },
+ &StepAddBox{
+ BoxVersion: b.config.BoxVersion,
+ CACert: b.config.AddCACert,
+ CAPath: b.config.AddCAPath,
+ DownloadCert: b.config.AddCert,
+ Clean: b.config.AddClean,
+ Force: b.config.AddForce,
+ Insecure: b.config.AddInsecure,
+ Provider: b.config.Provider,
+ SourceBox: b.config.SourceBox,
+ BoxName: b.config.BoxName,
+ GlobalID: b.config.GlobalID,
+ SkipAdd: b.config.SkipAdd,
+ },
+ &StepUp{
+ TeardownMethod: b.config.TeardownMethod,
+ Provider: b.config.Provider,
+ GlobalID: b.config.GlobalID,
+ },
+ &StepSSHConfig{
+ b.config.GlobalID,
+ },
+ &communicator.StepConnect{
+ Config: &b.config.SSHConfig.Comm,
+ Host: CommHost(),
+ SSHConfig: b.config.SSHConfig.Comm.SSHConfigFunc(),
+ },
+ new(common.StepProvision),
+ &StepPackage{
+ SkipPackage: b.config.SkipPackage,
+ Include: b.config.PackageInclude,
+ Vagrantfile: b.config.OutputVagrantfile,
+ GlobalID: b.config.GlobalID,
+ })
+
+ // Run the steps.
+ b.runner = common.NewRunnerWithPauseFn(steps, b.config.PackerConfig, ui, state)
+ b.runner.Run(state)
+
+ // Report any errors.
+ if rawErr, ok := state.GetOk("error"); ok {
+ return nil, rawErr.(error)
+ }
+
+ // If we were interrupted or cancelled, then just exit.
+ if _, ok := state.GetOk(multistep.StateCancelled); ok {
+ return nil, errors.New("Build was cancelled.")
+ }
+
+ if _, ok := state.GetOk(multistep.StateHalted); ok {
+ return nil, errors.New("Build was halted.")
+ }
+
+ return NewArtifact(b.config.OutputDir)
+}
+
+// Cancel.
+func (b *Builder) Cancel() {
+ if b.runner != nil {
+ log.Println("Cancelling the step runner...")
+ b.runner.Cancel()
+ }
+}
diff --git a/builder/vagrant/builder_test.go b/builder/vagrant/builder_test.go
new file mode 100644
index 000000000..65c2e5e9f
--- /dev/null
+++ b/builder/vagrant/builder_test.go
@@ -0,0 +1,91 @@
+package vagrant
+
+import (
+ "testing"
+
+ "github.com/hashicorp/packer/packer"
+)
+
+func TestBuilder_ImplementsBuilder(t *testing.T) {
+ var raw interface{}
+ raw = &Builder{}
+ if _, ok := raw.(packer.Builder); !ok {
+ t.Fatalf("Builder should be a builder")
+ }
+}
+
+func TestBuilder_Prepare_ValidateSource(t *testing.T) {
+ b := &Builder{}
+ type testCase struct {
+ config map[string]interface{}
+ errExpected bool
+ reason string
+ }
+
+ cases := []testCase{
+ {
+ config: map[string]interface{}{
+ "global_id": "a3559ec",
+ },
+ errExpected: true,
+ reason: "Need to set SSH communicator.",
+ },
+ {
+ config: map[string]interface{}{
+ "global_id": "a3559ec",
+ "communicator": "ssh",
+ },
+ errExpected: false,
+ reason: "Shouldn't fail because we've set global_id",
+ },
+ {
+ config: map[string]interface{}{
+ "communicator": "ssh",
+ },
+ errExpected: true,
+ reason: "Should fail because we must set source_path or global_id",
+ },
+ {
+ config: map[string]interface{}{
+ "source_path": "./mybox",
+ "communicator": "ssh",
+ },
+ errExpected: false,
+ reason: "Source path is set; we should be fine",
+ },
+ {
+ config: map[string]interface{}{
+ "source_path": "./mybox",
+ "communicator": "ssh",
+ "global_id": "a3559ec",
+ },
+ errExpected: true,
+ reason: "Both source path and global are set: we should error.",
+ },
+ {
+ config: map[string]interface{}{
+ "communicator": "ssh",
+ "global_id": "a3559ec",
+ "teardown_method": "suspend",
+ },
+ errExpected: false,
+ reason: "Valid argument for teardown method",
+ },
+ {
+ config: map[string]interface{}{
+ "communicator": "ssh",
+ "global_id": "a3559ec",
+ "teardown_method": "surspernd",
+ },
+ errExpected: true,
+ reason: "Inalid argument for teardown method",
+ },
+ }
+
+ for _, tc := range cases {
+ _, err := b.Prepare(tc.config)
+ if (err != nil) != tc.errExpected {
+ t.Fatalf("Unexpected behavior from test case %#v; %s.", tc.config, tc.reason)
+ }
+ }
+}
diff --git a/builder/vagrant/driver.go b/builder/vagrant/driver.go
new file mode 100644
index 000000000..56f7e8f68
--- /dev/null
+++ b/builder/vagrant/driver.go
@@ -0,0 +1,67 @@
+package vagrant
+
+import (
+ "fmt"
+ "os/exec"
+ "runtime"
+)
+
+// A driver is able to talk to Vagrant and perform certain
+// operations with it.
+
+type VagrantDriver interface {
+ // Calls "vagrant init"
+ Init([]string) error
+
+ // Calls "vagrant add"
+ Add([]string) error
+
+ // Calls "vagrant up"
+ Up([]string) (string, string, error)
+
+ // Calls "vagrant halt"
+ Halt(string) error
+
+ // Calls "vagrant suspend"
+ Suspend(string) error
+
+ SSHConfig(string) (*VagrantSSHConfig, error)
+
+ // Calls "vagrant destroy"
+ Destroy(string) error
+
+ // Calls "vagrant package"[
+ Package([]string) error
+
+ // Verify checks to make sure that this driver should function
+ // properly. If there is any indication the driver can't function,
+ // this will return an error.
+ Verify() error
+
+ // Version reads the version of VirtualBox that is installed.
+ Version() (string, error)
+}
+
+func NewDriver(outputDir string) (VagrantDriver, error) {
+ // Hardcode path for now while I'm developing. Obviously this path needs
+ // to be discovered based on OS.
+ vagrantBinary := "vagrant"
+ if runtime.GOOS == "windows" {
+ vagrantBinary = "vagrant.exe"
+ }
+
+ if _, err := exec.LookPath(vagrantBinary); err != nil {
+ return nil, fmt.Errorf("Error: Packer cannot find Vagrant in the path: %s", err.Error())
+ }
+
+ driver := &Vagrant_2_2_Driver{
+ vagrantBinary: vagrantBinary,
+ VagrantCWD: outputDir,
+ }
+
+ if err := driver.Verify(); err != nil {
+ return nil, err
+ }
+
+ return driver, nil
+}
diff --git a/builder/vagrant/driver_2_2.go b/builder/vagrant/driver_2_2.go
new file mode 100644
index 000000000..01652f5c3
--- /dev/null
+++ b/builder/vagrant/driver_2_2.go
@@ -0,0 +1,199 @@
+package vagrant
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "strings"
+
+ "github.com/hashicorp/go-version"
+)
+
+const VAGRANT_MIN_VERSION = ">= 2.0.2"
+
+type Vagrant_2_2_Driver struct {
+ vagrantBinary string
+ VagrantCWD string
+}
+
+// Calls "vagrant init"
+func (d *Vagrant_2_2_Driver) Init(args []string) error {
+ _, _, err := d.vagrantCmd(append([]string{"init"}, args...)...)
+ return err
+}
+
+// Calls "vagrant add"
+func (d *Vagrant_2_2_Driver) Add(args []string) error {
+ // vagrant box add partyvm ubuntu-14.04.vmware.box
+ _, _, err := d.vagrantCmd(append([]string{"box", "add"}, args...)...)
+ return err
+}
+
+// Calls "vagrant up"
+func (d *Vagrant_2_2_Driver) Up(args []string) (string, string, error) {
+ stdout, stderr, err := d.vagrantCmd(append([]string{"up"}, args...)...)
+ return stdout, stderr, err
+}
+
+// Calls "vagrant halt"
+func (d *Vagrant_2_2_Driver) Halt(id string) error {
+ args := []string{"halt"}
+ if id != "" {
+ args = append(args, id)
+ }
+ _, _, err := d.vagrantCmd(args...)
+ return err
+}
+
+// Calls "vagrant suspend"
+func (d *Vagrant_2_2_Driver) Suspend(id string) error {
+ args := []string{"suspend"}
+ if id != "" {
+ args = append(args, id)
+ }
+ _, _, err := d.vagrantCmd(args...)
+ return err
+}
+
+// Calls "vagrant destroy"
+func (d *Vagrant_2_2_Driver) Destroy(id string) error {
+ args := []string{"destroy", "-f"}
+ if id != "" {
+ args = append(args, id)
+ }
+ _, _, err := d.vagrantCmd(args...)
+ return err
+}
+
+// Calls "vagrant package"
+func (d *Vagrant_2_2_Driver) Package(args []string) error {
+ args = append(args, "--output", filepath.Join(d.VagrantCWD, "package.box"))
+ _, _, err := d.vagrantCmd(append([]string{"package"}, args...)...)
+ return err
+}
+
+// Verify makes sure that Vagrant exists at the given path
+func (d *Vagrant_2_2_Driver) Verify() error {
+ vagrantPath, err := exec.LookPath(d.vagrantBinary)
+ if err != nil {
+ return fmt.Errorf("Can't find Vagrant binary!")
+ }
+ _, err = os.Stat(vagrantPath)
+ if err != nil {
+ return fmt.Errorf("Can't find Vagrant binary.")
+ }
+
+ constraints, err := version.NewConstraint(VAGRANT_MIN_VERSION)
+ vers, err := d.Version()
+ v, err := version.NewVersion(vers)
+ if err != nil {
+ return fmt.Errorf("Error figuring out Vagrant version.")
+ }
+
+ if !constraints.Check(v) {
+ return fmt.Errorf("installed Vagrant version must be >=2.0.2")
+ }
+
+ return nil
+}
+
+type VagrantSSHConfig struct {
+ Hostname string
+ User string
+ Port string
+ UserKnownHostsFile string
+ StrictHostKeyChecking bool
+ PasswordAuthentication bool
+ IdentityFile string
+ IdentitiesOnly bool
+ LogLevel string
+}
+
+func parseSSHConfig(lines []string, value string) string {
+ out := ""
+ for _, line := range lines {
+ if index := strings.Index(line, value); index != -1 {
+ out = line[index+len(value):]
+ }
+ }
+ return out
+}
+
+func yesno(yn string) bool {
+ if yn == "no" {
+ return false
+ }
+ return true
+}
+
+func (d *Vagrant_2_2_Driver) SSHConfig(id string) (*VagrantSSHConfig, error) {
+ // vagrant ssh-config --host 8df7860
+ args := []string{"ssh-config"}
+ if id != "" {
+ args = append(args, id)
+ }
+ stdout, _, err := d.vagrantCmd(args...)
+ sshConf := &VagrantSSHConfig{}
+
+ lines := strings.Split(stdout, "\n")
+ sshConf.Hostname = parseSSHConfig(lines, "HostName ")
+ sshConf.User = parseSSHConfig(lines, "User ")
+ sshConf.Port = parseSSHConfig(lines, "Port ")
+ sshConf.UserKnownHostsFile = parseSSHConfig(lines, "UserKnownHostsFile ")
+ sshConf.IdentityFile = parseSSHConfig(lines, "IdentityFile ")
+ sshConf.LogLevel = parseSSHConfig(lines, "LogLevel ")
+
+ // handle the booleans
+ sshConf.StrictHostKeyChecking = yesno(parseSSHConfig(lines, "StrictHostKeyChecking "))
+ sshConf.PasswordAuthentication = yesno(parseSSHConfig(lines, "PasswordAuthentication "))
+ sshConf.IdentitiesOnly = yesno((parseSSHConfig(lines, "IdentitiesOnly ")))
+
+ return sshConf, err
+}
+
+// Version reads the version of VirtualBox that is installed.
+func (d *Vagrant_2_2_Driver) Version() (string, error) {
+ stdoutString, _, err := d.vagrantCmd([]string{"--version"}...)
+ // Example stdout:
+
+ // Installed Version: 2.2.3
+ //
+ // Vagrant was unable to check for the latest version of Vagrant.
+ // Please check manually at https://www.vagrantup.com
+
+ // Use regex to find version
+ reg := regexp.MustCompile(`(\d+\.)?(\d+\.)?(\*|\d+)`)
+ version := reg.FindString(stdoutString)
+ if version == "" {
+ return "", err
+ }
+
+ return version, nil
+}
+
+func (d *Vagrant_2_2_Driver) vagrantCmd(args ...string) (string, string, error) {
+ var stdout, stderr bytes.Buffer
+
+ log.Printf("Calling Vagrant CLI: %#v", args)
+ cmd := exec.Command(d.vagrantBinary, args...)
+ cmd.Env = append(os.Environ(), fmt.Sprintf("VAGRANT_CWD=%s", d.VagrantCWD))
+ cmd.Stdout = &stdout
+ cmd.Stderr = &stderr
+ err := cmd.Run()
+
+ stdoutString := strings.TrimSpace(stdout.String())
+ stderrString := strings.TrimSpace(stderr.String())
+
+ if _, ok := err.(*exec.ExitError); ok {
+ err = fmt.Errorf("Vagrant error: %s", stderrString)
+ }
+
+ log.Printf("[vagrant driver] stdout: %s", stdoutString)
+ log.Printf("[vagrant driver] stderr: %s", stderrString)
+
+ return stdoutString, stderrString, err
+}
diff --git a/builder/vagrant/ssh.go b/builder/vagrant/ssh.go
new file mode 100644
index 000000000..d4a56cb17
--- /dev/null
+++ b/builder/vagrant/ssh.go
@@ -0,0 +1,19 @@
+package vagrant
+
+import (
+ "github.com/hashicorp/packer/helper/multistep"
+)
+
+func CommHost() func(multistep.StateBag) (string, error) {
+ return func(state multistep.StateBag) (string, error) {
+ config := state.Get("config").(*Config)
+ return config.Comm.SSHHost, nil
+ }
+}
+
+func SSHPort() func(multistep.StateBag) (int, error) {
+ return func(state multistep.StateBag) (int, error) {
+ config := state.Get("config").(*Config)
+ return config.Comm.SSHPort, nil
+ }
+}
diff --git a/builder/vagrant/step_add_box.go b/builder/vagrant/step_add_box.go
new file mode 100644
index 000000000..9c1e23eb6
--- /dev/null
+++ b/builder/vagrant/step_add_box.go
@@ -0,0 +1,100 @@
+package vagrant
+
+import (
+ "context"
+ "log"
+ "strings"
+
+ "github.com/hashicorp/packer/helper/multistep"
+ "github.com/hashicorp/packer/packer"
+)
+
+type StepAddBox struct {
+ BoxVersion string
+ CACert string
+ CAPath string
+ DownloadCert string
+ Clean bool
+ Force bool
+ Insecure bool
+ Provider string
+ SourceBox string
+ BoxName string
+ GlobalID string
+ SkipAdd bool
+}
+
+func (s *StepAddBox) generateAddArgs() []string {
+ addArgs := []string{}
+
+ if strings.HasSuffix(s.SourceBox, ".box") {
+ addArgs = append(addArgs, s.BoxName)
+ }
+
+ addArgs = append(addArgs, s.SourceBox)
+
+ if s.BoxVersion != "" {
+ addArgs = append(addArgs, "--box-version", s.BoxVersion)
+ }
+
+ if s.CACert != "" {
+ addArgs = append(addArgs, "--cacert", s.CACert)
+ }
+
+ if s.CAPath != "" {
+ addArgs = append(addArgs, "--capath", s.CAPath)
+ }
+
+ if s.DownloadCert != "" {
+ addArgs = append(addArgs, "--cert", s.DownloadCert)
+ }
+
+ if s.Clean {
+ addArgs = append(addArgs, "--clean")
+ }
+
+ if s.Force {
+ addArgs = append(addArgs, "--force")
+ }
+
+ if s.Insecure {
+ addArgs = append(addArgs, "--insecure")
+ }
+
+ if s.Provider != "" {
+ addArgs = append(addArgs, "--provider", s.Provider)
+ }
+
+ return addArgs
+}
+
+func (s *StepAddBox) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
+ driver := state.Get("driver").(VagrantDriver)
+ ui := state.Get("ui").(packer.Ui)
+
+ if s.SkipAdd {
+ ui.Say("skip_add was set so we assume the box is already in Vagrant...")
+ return multistep.ActionContinue
+ }
+
+ if s.GlobalID != "" {
+ ui.Say("Using a global-id; skipping Vagrant add command...")
+ return multistep.ActionContinue
+ }
+
+ ui.Say("Adding box using vagrant box add..")
+ addArgs := s.generateAddArgs()
+
+ log.Printf("[vagrant] Calling box add with following args %s", strings.Join(addArgs, " "))
+ // Call vagrant using prepared arguments
+ err := driver.Add(addArgs)
+ if err != nil {
+ state.Put("error", err)
+ return multistep.ActionHalt
+ }
+
+ return multistep.ActionContinue
+}
+
+func (s *StepAddBox) Cleanup(state multistep.StateBag) {
+}
diff --git a/builder/vagrant/step_add_box_test.go b/builder/vagrant/step_add_box_test.go
new file mode 100644
index 000000000..29feca5d1
--- /dev/null
+++ b/builder/vagrant/step_add_box_test.go
@@ -0,0 +1,62 @@
+package vagrant
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/hashicorp/packer/helper/multistep"
+)
+
+func TestStepAdd_Impl(t *testing.T) {
+ var raw interface{}
+ raw = new(StepAddBox)
+ if _, ok := raw.(multistep.Step); !ok {
+ t.Fatalf("initialize should be a step")
+ }
+}
+
+func TestPrepAddArgs(t *testing.T) {
+ type testArgs struct {
+ Step StepAddBox
+ Expected []string
+ }
+ addTests := []testArgs{
+ {
+ Step: StepAddBox{
+ SourceBox: "my_source_box.box",
+ BoxName: "AWESOME BOX",
+ },
+ Expected: []string{"AWESOME BOX", "my_source_box.box"},
+ },
+ {
+ Step: StepAddBox{
+ SourceBox: "my_source_box",
+ BoxName: "AWESOME BOX",
+ },
+ Expected: []string{"my_source_box"},
+ },
+ {
+ Step: StepAddBox{
+ BoxVersion: "eleventyone",
+ CACert: "adfasdf",
+ CAPath: "adfasdf",
+ DownloadCert: "adfasdf",
+ Clean: true,
+ Force: true,
+ Insecure: true,
+ Provider: "virtualbox",
+ SourceBox: "bananabox.box",
+ BoxName: "bananas",
+ },
+ Expected: []string{"bananas", "bananabox.box", "--box-version", "eleventyone", "--cacert", "adfasdf", "--capath", "adfasdf", "--cert", "adfasdf", "--clean", "--force", "--insecure", "--provider", "virtualbox"},
+ },
+ }
+ for _, addTest := range addTests {
+ addArgs := addTest.Step.generateAddArgs()
+ for i, val := range addTest.Expected {
+ if strings.Compare(addArgs[i], val) != 0 {
+ t.Fatalf("expected %#v but received %#v", addTest.Expected, addArgs)
+ }
+ }
+ }
+}
diff --git a/builder/vagrant/step_create_vagrantfile.go b/builder/vagrant/step_create_vagrantfile.go
new file mode 100644
index 000000000..40ead21dd
--- /dev/null
+++ b/builder/vagrant/step_create_vagrantfile.go
@@ -0,0 +1,96 @@
+package vagrant
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+ "text/template"
+
+ "github.com/hashicorp/packer/helper/multistep"
+ "github.com/hashicorp/packer/packer"
+)
+
+type StepCreateVagrantfile struct {
+ Template string
+ SourceBox string
+ OutputDir string
+ SyncedFolder string
+ GlobalID string
+}
+
+var DEFAULT_TEMPLATE = `Vagrant.configure("2") do |config|
+ config.vm.box = "{{.BoxName}}"
+ {{ if ne .SyncedFolder "" -}}
+ config.vm.synced_folder "{{.SyncedFolder}}", "/vagrant"
+ {{- else -}}
+ config.vm.synced_folder ".", "/vagrant", disabled: true
+ {{- end}}
+end`
+
+type VagrantfileOptions struct {
+ SyncedFolder string
+ BoxName string
+}
+
+func (s *StepCreateVagrantfile) createVagrantfile() (string, error) {
+ tplPath := filepath.Join(s.OutputDir, "Vagrantfile")
+ templateFile, err := os.Create(tplPath)
+ if err != nil {
+ retErr := fmt.Errorf("Error creating vagrantfile %s", err.Error())
+ return "", retErr
+ }
+
+ var tpl *template.Template
+ if s.Template == "" {
+ // Generate vagrantfile template based on our default
+ tpl = template.Must(template.New("VagrantTpl").Parse(DEFAULT_TEMPLATE))
+ } else {
+ // Read in the template from provided file.
+ tpl, err = template.ParseFiles(s.Template)
+ if err != nil {
+ return "", err
+ }
+ }
+
+ opts := &VagrantfileOptions{
+ SyncedFolder: s.SyncedFolder,
+ BoxName: s.SourceBox,
+ }
+
+ err = tpl.Execute(templateFile, opts)
+ if err != nil {
+ return "", err
+ }
+
+ abspath, err := filepath.Abs(tplPath)
+ if err != nil {
+ return "", err
+ }
+
+ return abspath, nil
+}
+
+func (s *StepCreateVagrantfile) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
+ ui := state.Get("ui").(packer.Ui)
+
+ // Skip the initialize step if we're trying to launch from a global ID.
+ if s.GlobalID != "" {
+ ui.Say("Using a global-id; skipping Vagrant init in this directory...")
+ return multistep.ActionContinue
+ }
+
+ ui.Say("Creating a Vagrantfile in the build directory...")
+ vagrantfilePath, err := s.createVagrantfile()
+ if err != nil {
+ state.Put("error", err)
+ return multistep.ActionHalt
+ }
+ log.Printf("Created vagrantfile at %s", vagrantfilePath)
+
+ return multistep.ActionContinue
+}
+
+func (s *StepCreateVagrantfile) Cleanup(state multistep.StateBag) {
+}
diff --git a/builder/vagrant/step_create_vagrantfile_test.go b/builder/vagrant/step_create_vagrantfile_test.go
new file mode 100644
index 000000000..d3bcf21b9
--- /dev/null
+++ b/builder/vagrant/step_create_vagrantfile_test.go
@@ -0,0 +1,60 @@
+package vagrant
+
+import (
+ "io/ioutil"
+ "os"
+ "strings"
+ "testing"
+
+ "github.com/hashicorp/packer/helper/multistep"
+)
+
+func TestStepCreateVagrantfile_Impl(t *testing.T) {
+ var raw interface{}
+ raw = new(StepCreateVagrantfile)
+ if _, ok := raw.(multistep.Step); !ok {
+ t.Fatalf("initialize should be a step")
+ }
+}
+
+func TestCreateFile(t *testing.T) {
+ testy := StepCreateVagrantfile{
+ OutputDir: "./",
+ SourceBox: "bananas",
+ }
+ templatePath, err := testy.createVagrantfile()
+ if err != nil {
+ t.Fatalf(err.Error())
+ }
+ defer os.Remove(templatePath)
+ contents, err := ioutil.ReadFile(templatePath)
+ actual := string(contents)
+ expected := `Vagrant.configure("2") do |config|
+ config.vm.box = "bananas"
+ config.vm.synced_folder ".", "/vagrant", disabled: true
+end`
+ if ok := strings.Compare(actual, expected); ok != 0 {
+ t.Fatalf("EXPECTED: \n%s\n\n RECEIVED: \n%s\n\n", expected, actual)
+ }
+}
+
+func TestCreateFile_customSync(t *testing.T) {
+ testy := StepCreateVagrantfile{
+ OutputDir: "./",
+ SyncedFolder: "myfolder/foldertimes",
+ }
+ templatePath, err := testy.createVagrantfile()
+ if err != nil {
+ t.Fatalf(err.Error())
+ }
+ defer os.Remove(templatePath)
+ contents, err := ioutil.ReadFile(templatePath)
+ actual := string(contents)
+ expected := `Vagrant.configure("2") do |config|
+ config.vm.box = ""
+ config.vm.synced_folder "myfolder/foldertimes", "/vagrant"
+end`
+ if ok := strings.Compare(actual, expected); ok != 0 {
+ t.Fatalf("EXPECTED: \n%s\n\n RECEIVED: \n%s\n\n", expected, actual)
+ }
+}
diff --git a/builder/vagrant/step_package.go b/builder/vagrant/step_package.go
new file mode 100644
index 000000000..8200296b4
--- /dev/null
+++ b/builder/vagrant/step_package.go
@@ -0,0 +1,49 @@
+package vagrant
+
+import (
+ "context"
+ "strings"
+
+ "github.com/hashicorp/packer/helper/multistep"
+ "github.com/hashicorp/packer/packer"
+)
+
+type StepPackage struct {
+ SkipPackage bool
+ Include []string
+ Vagrantfile string
+ GlobalID string
+}
+
+func (s *StepPackage) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
+ driver := state.Get("driver").(VagrantDriver)
+ ui := state.Get("ui").(packer.Ui)
+
+ if s.SkipPackage {
+ ui.Say("skip_package flag set; not going to call Vagrant package on this box.")
+ return multistep.ActionContinue
+ }
+ ui.Say("Packaging box...")
+ packageArgs := []string{}
+ if s.GlobalID != "" {
+ packageArgs = append(packageArgs, s.GlobalID)
+ }
+
+ if len(s.Include) > 0 {
+ packageArgs = append(packageArgs, "--include", strings.Join(s.Include, ","))
+ }
+ if s.Vagrantfile != "" {
+ packageArgs = append(packageArgs, "--vagrantfile", s.Vagrantfile)
+ }
+
+ err := driver.Package(packageArgs)
+ if err != nil {
+ state.Put("error", err)
+ return multistep.ActionHalt
+ }
+
+ return multistep.ActionContinue
+}
+
+func (s *StepPackage) Cleanup(state multistep.StateBag) {
+}
diff --git a/builder/vagrant/step_ssh_config.go b/builder/vagrant/step_ssh_config.go
new file mode 100644
index 000000000..68fc13aa3
--- /dev/null
+++ b/builder/vagrant/step_ssh_config.go
@@ -0,0 +1,53 @@
+package vagrant
+
+import (
+ "context"
+ "strconv"
+
+ "github.com/hashicorp/packer/helper/multistep"
+)
+
+// Vagrant already sets up ssh on the guests; our job is to find out what
+// it did. We can do that with the ssh-config command. Example output:
+
+// $ vagrant ssh-config
+// Host default
+// HostName 172.16.41.194
+// User vagrant
+// Port 22
+// UserKnownHostsFile /dev/null
+// StrictHostKeyChecking no
+// PasswordAuthentication no
+// IdentityFile /Users/mmarsh/Projects/vagrant-boxes/ubuntu/.vagrant/machines/default/vmware_fusion/private_key
+// IdentitiesOnly yes
+// LogLevel FATAL
+
+type StepSSHConfig struct {
+ GlobalID string
+}
+
+func (s *StepSSHConfig) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
+ driver := state.Get("driver").(VagrantDriver)
+ config := state.Get("config").(*Config)
+
+ sshConfig, err := driver.SSHConfig(s.GlobalID)
+ if err != nil {
+ state.Put("error", err)
+ return multistep.ActionHalt
+ }
+
+ config.Comm.SSHPrivateKeyFile = sshConfig.IdentityFile
+ config.Comm.SSHUsername = sshConfig.User
+ config.Comm.SSHHost = sshConfig.Hostname
+ port, err := strconv.Atoi(sshConfig.Port)
+ if err != nil {
+ state.Put("error", err)
+ return multistep.ActionHalt
+ }
+ config.Comm.SSHPort = port
+
+ return multistep.ActionContinue
+}
+
+func (s *StepSSHConfig) Cleanup(state multistep.StateBag) {
+}
diff --git a/builder/vagrant/step_up.go b/builder/vagrant/step_up.go
new file mode 100644
index 000000000..6f2584c5f
--- /dev/null
+++ b/builder/vagrant/step_up.go
@@ -0,0 +1,62 @@
+package vagrant
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/hashicorp/packer/helper/multistep"
+ "github.com/hashicorp/packer/packer"
+)
+
+type StepUp struct {
+ TeardownMethod string
+ Provider string
+ GlobalID string
+}
+
+func (s *StepUp) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
+ driver := state.Get("driver").(VagrantDriver)
+ ui := state.Get("ui").(packer.Ui)
+
+ ui.Say("Calling Vagrant Up...")
+
+ var args []string
+ if s.GlobalID != "" {
+ args = append(args, s.GlobalID)
+ }
+
+ if s.Provider != "" {
+ args = append(args, fmt.Sprintf("--provider=%s", s.Provider))
+ }
+
+ _, _, err := driver.Up(args)
+
+ if err != nil {
+ state.Put("error", err)
+ return multistep.ActionHalt
+ }
+
+ return multistep.ActionContinue
+}
+
+func (s *StepUp) Cleanup(state multistep.StateBag) {
+ driver := state.Get("driver").(VagrantDriver)
+ ui := state.Get("ui").(packer.Ui)
+
+ ui.Say(fmt.Sprintf("%sing Vagrant box...", s.TeardownMethod))
+
+ var err error
+ if s.TeardownMethod == "halt" {
+ err = driver.Halt(s.GlobalID)
+ } else if s.TeardownMethod == "suspend" {
+ err = driver.Suspend(s.GlobalID)
+ } else if s.TeardownMethod == "destroy" {
+ err = driver.Destroy(s.GlobalID)
+ } else {
+ // Should never get here because of template validation
+ state.Put("error", fmt.Errorf("Invalid teardown method selected; must be either halt, suspend, or destory."))
+ }
+ if err != nil {
+ state.Put("error", fmt.Errorf("Error halting Vagrant machine; please try to do this manually"))
+ }
+}
diff --git a/command/plugin.go b/command/plugin.go
index c17396e35..9e014018a 100644
--- a/command/plugin.go
+++ b/command/plugin.go
@@ -43,6 +43,7 @@ import (
scalewaybuilder "github.com/hashicorp/packer/builder/scaleway"
tencentcloudcvmbuilder "github.com/hashicorp/packer/builder/tencentcloud/cvm"
tritonbuilder "github.com/hashicorp/packer/builder/triton"
+ vagrantbuilder "github.com/hashicorp/packer/builder/vagrant"
virtualboxisobuilder "github.com/hashicorp/packer/builder/virtualbox/iso"
virtualboxovfbuilder "github.com/hashicorp/packer/builder/virtualbox/ovf"
vmwareisobuilder "github.com/hashicorp/packer/builder/vmware/iso"
@@ -118,6 +119,7 @@ var Builders = map[string]packer.Builder{
"scaleway": new(scalewaybuilder.Builder),
"tencentcloud-cvm": new(tencentcloudcvmbuilder.Builder),
"triton": new(tritonbuilder.Builder),
+ "vagrant": new(vagrantbuilder.Builder),
"virtualbox-iso": new(virtualboxisobuilder.Builder),
"virtualbox-ovf": new(virtualboxovfbuilder.Builder),
"vmware-iso": new(vmwareisobuilder.Builder),
diff --git a/website/source/docs/builders/alicloud-ecs.html.md b/website/source/docs/builders/alicloud-ecs.html.md
index 8585cee65..945b95090 100644
--- a/website/source/docs/builders/alicloud-ecs.html.md
+++ b/website/source/docs/builders/alicloud-ecs.html.md
@@ -147,28 +147,30 @@ builder.
Snapshots from on or before July 15, 2013 cannot be used to create a
disk.
-
-- `image_ignore_data_disks`(boolean) - If this value is true, the image created
- will not include any snapshot of data disks. This option would be useful for
- any circumstance that default data disks with instance types are not concerned.
- The default value is false.
-- `wait_snapshot_ready_timeout`(number) - Timeout of creating snapshot(s). The
- default timeout is 3600 seconds if this option is not set or is set to 0. For
- those disks containing lots of data, it may require a higher timeout value.
+- `image_ignore_data_disks`(boolean) - If this value is true, the image
+ created will not include any snapshot of data disks. This option would be
+ useful for any circumstance that default data disks with instance types are
+ not concerned. The default value is false.
+
+- `wait_snapshot_ready_timeout`(number) - Timeout of creating snapshot(s).
+ The default timeout is 3600 seconds if this option is not set or is set
+ to 0. For those disks containing lots of data, it may require a higher
+ timeout value.
- `image_force_delete` (boolean) - If this value is true, when the target
- image names including those copied are duplicated with existing images,
- it will delete the existing images and then create the target images,
- otherwise, the creation will fail. The default value is false. Check
- `image_name` and `image_copy_names` options for names of target images.
- If [-force](https://packer.io/docs/commands/build.html#force) option is provided
- in `build` command, this option can be omitted and taken as true.
+ image names including those copied are duplicated with existing images, it
+ will delete the existing images and then create the target images,
+ otherwise, the creation will fail. The default value is false. Check
+ `image_name` and `image_copy_names` options for names of target images. If
+ [-force](https://packer.io/docs/commands/build.html#force) option is
+ provided in `build` command, this option can be omitted and taken as true.
- `image_force_delete_snapshots` (boolean) - If this value is true, when
delete the duplicated existing images, the source snapshots of those images
- will be delete either. If [-force](https://packer.io/docs/commands/build.html#force)
- option is provided in `build` command, this option can be omitted and taken as true.
+ will be delete either. If
+ [-force](https://packer.io/docs/commands/build.html#force) option is
+ provided in `build` command, this option can be omitted and taken as true.
- `image_share_account` (array of string) - The IDs of to-be-added Aliyun
accounts to which the image is shared. The number of accounts is 1 to 10.
@@ -299,10 +301,13 @@ Here is a basic example for Alicloud.
\~> Note: Images can become deprecated after a while; run
`aliyun ecs DescribeImages` to find one that exists.
-\~> Note: Since WinRM is closed by default in the system image. If you are planning
-to use Windows as the base image, you need enable it by userdata in order to connect to
-the instance, check [alicloud_windows.json](https://github.com/hashicorp/packer/tree/master/examples/alicloud/basic/alicloud_windows.json)
-and [winrm_enable_userdata.ps1](https://github.com/hashicorp/packer/tree/master/examples/alicloud/basic/winrm_enable_userdata.ps1) for details.
+\~> Note: Since WinRM is closed by default in the system image. If you are
+planning to use Windows as the base image, you need enable it by userdata in
+order to connect to the instance, check
+[alicloud\_windows.json](https://github.com/hashicorp/packer/tree/master/examples/alicloud/basic/alicloud_windows.json)
+and
+[winrm\_enable\_userdata.ps1](https://github.com/hashicorp/packer/tree/master/examples/alicloud/basic/winrm_enable_userdata.ps1)
+for details.
See the
[examples/alicloud](https://github.com/hashicorp/packer/tree/master/examples/alicloud)
diff --git a/website/source/docs/builders/amazon.html.md b/website/source/docs/builders/amazon.html.md
index 931ff86ae..9e3fb1ba9 100644
--- a/website/source/docs/builders/amazon.html.md
+++ b/website/source/docs/builders/amazon.html.md
@@ -218,9 +218,9 @@ fail. If that's the case, you might see an error like this:
==> amazon-ebs: Error querying AMI: AuthFailure: AWS was not able to validate the provided access credentials
If you suspect your system's date is wrong, you can compare it against
-. On Linux/OS X, you can run the `date` command to get
-the current time. If you're on Linux, you can try setting the time with ntp by
-running `sudo ntpd -q`.
+. On
+Linux/OS X, you can run the `date` command to get the current time. If you're
+on Linux, you can try setting the time with ntp by running `sudo ntpd -q`.
### `exceeded wait attempts` while waiting for tasks to complete
diff --git a/website/source/docs/builders/azure.html.md b/website/source/docs/builders/azure.html.md
index 8caf44848..a4b86d2c7 100644
--- a/website/source/docs/builders/azure.html.md
+++ b/website/source/docs/builders/azure.html.md
@@ -206,8 +206,8 @@ Providing `temp_resource_group_name` or `location` in combination with
- `os_disk_size_gb` (number) Specify the size of the OS disk in GB
(gigabytes). Values of zero or less than zero are ignored.
-- `disk_caching_type` (string) Specify the disk caching type. Valid values are None, ReadOnly,
- and ReadWrite. The default value is ReadWrite.
+- `disk_caching_type` (string) Specify the disk caching type. Valid values
+ are None, ReadOnly, and ReadWrite. The default value is ReadWrite.
- `disk_additional_size` (array of integers) - The size(s) of any additional
hard disks for the VM in gigabytes. If this is not specified then the VM
@@ -325,13 +325,14 @@ Providing `temp_resource_group_name` or `location` in combination with
value and defaults to false. **Important** Setting this true means that
your builds are faster, however any failed deletes are not reported.
-- `managed_image_os_disk_snapshot_name` (string) If managed\_image\_os\_disk\_snapshot\_name
- is set, a snapshot of the OS disk is created with the same name as this value before the
- VM is captured.
+- `managed_image_os_disk_snapshot_name` (string) If
+ managed\_image\_os\_disk\_snapshot\_name is set, a snapshot of the OS disk
+ is created with the same name as this value before the VM is captured.
-- `managed_image_data_disk_snapshot_prefix` (string) If managed\_image\_data\_disk\_snapshot\_prefix
- is set, snapshot of the data disk(s) is created with the same prefix as this value before the VM
- is captured.
+- `managed_image_data_disk_snapshot_prefix` (string) If
+ managed\_image\_data\_disk\_snapshot\_prefix is set, snapshot of the data
+ disk(s) is created with the same prefix as this value before the VM is
+ captured.
## Basic Example
@@ -403,14 +404,14 @@ here](https://technet.microsoft.com/en-us/library/hh824815.aspx)
}
```
-The Windows Guest Agent participates in the Sysprep process. The
-agent must be fully installed before the VM can be sysprep'ed. To
-ensure this is true all agent services must be running before
-executing sysprep.exe. The above JSON snippet shows one way to do this
-in the PowerShell provisioner. This snippet is **only** required if
-the VM is configured to install the agent, which is the default. To
-learn more about disabling the Windows Guest Agent please see [Install the VM Agent](https://docs.microsoft.com/en-us/azure/virtual-machines/extensions/agent-windows#install-the-vm-agent).
-
+The Windows Guest Agent participates in the Sysprep process. The agent must be
+fully installed before the VM can be sysprep'ed. To ensure this is true all
+agent services must be running before executing sysprep.exe. The above JSON
+snippet shows one way to do this in the PowerShell provisioner. This snippet is
+**only** required if the VM is configured to install the agent, which is the
+default. To learn more about disabling the Windows Guest Agent please see
+[Install the VM
+Agent](https://docs.microsoft.com/en-us/azure/virtual-machines/extensions/agent-windows#install-the-vm-agent).
### Linux
diff --git a/website/source/docs/builders/docker.html.md b/website/source/docs/builders/docker.html.md
index 6612bb464..a0dddfc78 100644
--- a/website/source/docs/builders/docker.html.md
+++ b/website/source/docs/builders/docker.html.md
@@ -184,8 +184,8 @@ You must specify (only) one of `commit`, `discard`, or `export_path`.
`login_username`, and `login_password` will be ignored. For more
information see the [section on ECR](#amazon-ec2-container-registry).
-- `exec_user` (string) - Username or UID (format:
- <name\\\|uid>\[:<group\\\|gid>\]) to run remote commands with.
+- `exec_user` (string) - Username (UID) to run remote commands with. You can
+ also set the group name/ID if you want: (UID or UID:GID).
You may need this if you get permission errors trying to run the `shell` or
other provisioners.
@@ -380,8 +380,8 @@ portable provisioning scripts.
## Overriding the host directory
-By default, Packer creates a temporary folder under your home directory, and
-uses that to stage files for uploading into the container. If you would like to
+By default, Packer creates a temporary folder under your home directory, and
+uses that to stage files for uploading into the container. If you would like to
change the path to this temporary folder, you can set the `PACKER_TMP_DIR`.
This can be useful, for example, if you have your home directory permissions
set up to disallow access from the docker daemon.
diff --git a/website/source/docs/builders/googlecompute.html.md b/website/source/docs/builders/googlecompute.html.md
index f1d672adb..681fad15e 100644
--- a/website/source/docs/builders/googlecompute.html.md
+++ b/website/source/docs/builders/googlecompute.html.md
@@ -18,9 +18,8 @@ based on existing images.
It is possible to build images from scratch, but not with the `googlecompute`
Packer builder. The process is recommended only for advanced users, please see
-\[Building GCE Images from Scratch\]
-() and the
-[Google Compute Import
+[Building GCE Images from Scratch](https://cloud.google.com/compute/docs/tutorials/building-images)
+and the [Google Compute Import
Post-Processor](/docs/post-processors/googlecompute-import.html) for more
information.
@@ -139,7 +138,7 @@ using the gcloud command.
gcloud compute firewall-rules create allow-winrm --allow tcp:5986
Or alternatively by navigating to
-.
+https://console.cloud.google.com/networking/firewalls/list.
Once this is set up, the following is a complete working packer config after
setting a valid `account_file` and `project_id`:
diff --git a/website/source/docs/builders/hetzner-cloud.html.md b/website/source/docs/builders/hetzner-cloud.html.md
index 9f35cac84..71b710b1b 100644
--- a/website/source/docs/builders/hetzner-cloud.html.md
+++ b/website/source/docs/builders/hetzner-cloud.html.md
@@ -75,7 +75,9 @@ builder.
- `ssh_keys` (array of strings) - List of SSH keys by name or id to be added
to image on launch.
-- `rescue` (string) - Enable and boot in to the specified rescue system. This enables simple installation of custom operating systems. `linux64` `linux32` or `freebsd64`
+- `rescue` (string) - Enable and boot in to the specified rescue system. This
+ enables simple installation of custom operating systems. `linux64`
+ `linux32` or `freebsd64`
## Basic Example
diff --git a/website/source/docs/builders/lxc.html.md b/website/source/docs/builders/lxc.html.md
index f17b20e5f..c94042856 100644
--- a/website/source/docs/builders/lxc.html.md
+++ b/website/source/docs/builders/lxc.html.md
@@ -19,7 +19,7 @@ as a tar.gz of the root file system.
The LXC builder requires a modern linux kernel and the `lxc` or `lxc1` package.
This builder does not work with LXD.
-~> Note: to build Centos images on a Debian family host, you will need the
+\~> Note: to build Centos images on a Debian family host, you will need the
`yum` package installed.
Some provisioners such as `ansible-local` get
confused when running in a container of a different family. E.G. it will
attempt to use `apt-get` to install packages, when running in a Centos
diff --git a/website/source/docs/builders/lxd.html.md b/website/source/docs/builders/lxd.html.md
index 2523f1541..45a2937a9 100644
--- a/website/source/docs/builders/lxd.html.md
+++ b/website/source/docs/builders/lxd.html.md
@@ -47,7 +47,7 @@ Below is a fully functioning example.
container. This can be a (local or remote) image (name or fingerprint).
E.G. `my-base-image`, `ubuntu-daily:x`, `08fababf6f27`, ...
- ~> Note: The builder may appear to pause if required to download a
+ \~> Note: The builder may appear to pause if required to download a
remote image, as they are usually 100-200MB. `/var/log/lxd/lxd.log` will
mention starting such downloads.
@@ -68,8 +68,8 @@ Below is a fully functioning example.
- `publish_properties` (map\[string\]string) - Pass key values to the publish
step to be set as properties on the output image. This is most helpful to
set the description, but can be used to set anything needed. See
- for more
- properties.
+ https://stgraber.org/2016/03/30/lxd-2-0-image-management-512/
+ for more properties.
- `launch_config` (map\[string\]string) - List of key/value pairs you wish to
pass to `lxc launch` via `--config`. Defaults to empty.
diff --git a/website/source/docs/builders/ncloud.html.md b/website/source/docs/builders/ncloud.html.md
index 1aacf633f..ddc91b257 100644
--- a/website/source/docs/builders/ncloud.html.md
+++ b/website/source/docs/builders/ncloud.html.md
@@ -90,7 +90,6 @@ Here is a basic example for windows server.
]
}
-
Here is a basic example for linux server.
{
diff --git a/website/source/docs/builders/openstack.html.md b/website/source/docs/builders/openstack.html.md
index c67460b4c..837409e9f 100644
--- a/website/source/docs/builders/openstack.html.md
+++ b/website/source/docs/builders/openstack.html.md
@@ -278,8 +278,8 @@ builder.
isn't specified, the default enforced by your OpenStack cluster will be
used.
-- `volume_size` (int) - Size of the Block Storage service volume in GB. If this
- isn't specified, it is set to source image min disk value (if set) or
+- `volume_size` (int) - Size of the Block Storage service volume in GB. If
+ this isn't specified, it is set to source image min disk value (if set) or
calculated from the source image bytes size. Note that in some cases this
needs to be specified, if `use_blockstorage_volume` is true.
diff --git a/website/source/docs/builders/oracle-classic.html.md b/website/source/docs/builders/oracle-classic.html.md
index e917abeda..1fef81830 100644
--- a/website/source/docs/builders/oracle-classic.html.md
+++ b/website/source/docs/builders/oracle-classic.html.md
@@ -141,9 +141,10 @@ If this is set, a few more options become available.
- `builder_communicator` (communicator) - This represents an
[`ssh communicator`](/docs/templates/communicator.html#ssh-communicator),
and can be configured as such. If you use a different builder image, you
- may need to change the `ssh_username`, for example. That might look like this:
+ may need to change the `ssh_username`, for example. That might look like
+ this:
- ```json
+ ``` json
{
"builders": [
{
@@ -170,7 +171,7 @@ If this is set, a few more options become available.
amount of memory, and other resources allocated to the builder instance.
Default: `oc3`.
-* `builder_upload_image_command` (string) - The command to run to upload the
+- `builder_upload_image_command` (string) - The command to run to upload the
image to Object Storage Classic. This is for advanced users only, and you
should consult the default in code to decide on the changes to make. For
most users the default should suffice.
@@ -272,7 +273,7 @@ attributes file:
Here is an example using a persistent volume. Note the `persistent_volume_size`
setting.
-```json
+``` json
{
"variables": {
"opc_username": "{{ env `OPC_USERNAME`}}",
diff --git a/website/source/docs/builders/scaleway.html.md b/website/source/docs/builders/scaleway.html.md
index e2ce32676..4678b4222 100644
--- a/website/source/docs/builders/scaleway.html.md
+++ b/website/source/docs/builders/scaleway.html.md
@@ -48,8 +48,8 @@ builder.
- `image` (string) - The UUID of the base image to use. This is the image
that will be used to launch a new server and provision it. See
- get the complete list of the
- accepted image UUID.
+ [the images list](https://api-marketplace.scaleway.com/images)
+ get the complete list of the accepted image UUID.
- `region` (string) - The name of the region to launch the server in (`par1`
or `ams1`). Consequently, this is the region where the snapshot will be
diff --git a/website/source/docs/builders/triton.html.md b/website/source/docs/builders/triton.html.md
index df5173022..e3b003190 100644
--- a/website/source/docs/builders/triton.html.md
+++ b/website/source/docs/builders/triton.html.md
@@ -30,7 +30,7 @@ This reusable image can then be used to launch new machines.
The builder does *not* manage images. Once it creates an image, it is up to you
to use it or delete it.
-~> **Private installations of Triton must have custom images enabled!** To
+\~> **Private installations of Triton must have custom images enabled!** To
use the Triton builder with a private/on-prem installation of Joyent's Triton
software, you'll need an operator to manually [enable custom
images](https://docs.joyent.com/private-cloud/install/image-management) after
diff --git a/website/source/docs/builders/vagrant.html.md b/website/source/docs/builders/vagrant.html.md
new file mode 100644
index 000000000..fc93d00c9
--- /dev/null
+++ b/website/source/docs/builders/vagrant.html.md
@@ -0,0 +1,101 @@
+The Vagrant builder is intended for building new boxes from already-existing
+boxes. Your source should be a URL or path to a .box file or a Vagrant Cloud
+box name such as `hashicorp/precise64`.
+
+Packer will not install vagrant, nor will it install the underlying
+virtualization platforms or extra providers; We expect when you run this
+builder that you have already installed what you need.
+
+By default, this builder will initialize a new Vagrant workspace, launch your
+box from that workspace, provision it, call `vagrant package` to package it
+into a new box, and then destroy the original box. Please note that vagrant
+will _not_ remove the box file from your system (we don't call
+`vagrant box remove`).
+
+You can change the behavior so that the builder doesn't destroy the box by
+setting the `teardown_method` option. You can change the behavior so the builder
+doesn't package it (not all provisioners support the `vagrant package` command)
+by setting the `skip package` option. You can also change the behavior so that
+rather than inititalizing a new Vagrant workspace, you use an already defined
+one, by using `global_id` instead of `source_box`.
+
+Required:
+
+- `source_path` (string) - URL of the vagrant box to use, or the name of the
+ vagrant box. `hashicorp/precise64`, `./mylocalbox.box` and
+ `https://example.com/my-box.box` are all valid source boxes. If your
+ source is a .box file, whether locally or from a URL like the latter example
+ above, you will also need to provide a `box_name`. This option is required,
+ unless you set `global_id`. You may only set one or the other, not both.
+
+ or
+
+- `global_id` (string) - the global id of a Vagrant box already added to Vagrant
+ on your system. You can find the global id of your Vagrant boxes using the
+ command `vagrant global-status`; your global_id will be a 7-digit number and
+ letter comination that you'll find in the leftmost column of the
+ global-status output. If you choose to use `global_id` instead of
+ `source_box`, Packer will skip the Vagrant initialize and add steps, and
+ simply launch the box directly using the global id.
+
+Optional:
+
+- `output_dir` (string) - The directory to create that will contain
+ your output box. We always create this directory and run from inside of it to
+ prevent Vagrant init collisions. If unset, it will be set to `packer-` plus
+ your buildname.
+
+- `box_name` (string) - if your source\_box is a boxfile that we need to add
+ to Vagrant, this is the name to give it. If left blank, will default to
+ "packer_" plus your buildname.
+
+- `checksum` (string) - The checksum for the .box file. The type of the
+ checksum is specified with `checksum_type`, documented below.
+
+- `checksum_type` (string) - The type of the checksum specified in `checksum`.
+ Valid values are `none`, `md5`, `sha1`, `sha256`, or `sha512`. Although the
+ checksum will not be verified when `checksum_type` is set to "none", this is
+ not recommended since OVA files can be very large and corruption does happen
+ from time to time.
+
+- `vagrantfile_template` (string) - a path to a golang template for a
+ vagrantfile. Our default template can be found
+ [here](https://github.com/hashicorp/packer/tree/master/builder/vagrant/step_initialize_vagrant.go#L23-L30). So far the only template variables available to you are {{ .BoxName }} and
+ {{ .SyncedFolder }}, which correspond to the Packer options `box_name` and
+ `synced_folder`
+
+- `skip_add` (string) - Don't call "vagrant add" to add the box to your local
+ environment; this is necesasry if you want to launch a box that is already
+ added to your vagrant environment.
+
+- `teardown_method` (string) - Whether to halt, suspend, or destroy the box when
+ the build has completed. Defaults to "halt"
+
+- `box_version` (string) - What box version to use when initializing Vagrant.
+
+- `add_cacert` (string) - Equivalent to setting the
+ [`--cacert`](https://www.vagrantup.com/docs/cli/box.html#cacert-certfile)
+ option in `vagrant add`; defaults to unset.
+
+- `add_capath` (string) - Equivalent to setting the
+ [`--capath`](https://www.vagrantup.com/docs/cli/box.html#capath-certdir) option
+ in `vagrant add`; defaults to unset.
+
+- `add_cert` (string) - Equivalent to setting the
+ [`--cert`](https://www.vagrantup.com/docs/cli/box.html#cert-certfile) option in
+ `vagrant add`; defaults to unset.
+
+- `add_clean` (bool) - Equivalent to setting the
+ [`--clean`](https://www.vagrantup.com/docs/cli/box.html#clean) flag in
+ `vagrant add`; defaults to unset.
+
+- `add_force` (bool) - Equivalent to setting the
+ [`--force`](https://www.vagrantup.com/docs/cli/box.html#force) flag in
+ `vagrant add`; defaults to unset.
+
+- `add_insecure` (bool) - Equivalent to setting the
+ [`--force`](https://www.vagrantup.com/docs/cli/box.html#insecure) flag in
+ `vagrant add`; defaults to unset.
+
+- `skip_package` (bool) - if true, Packer will not call `vagrant package` to
+ package your base box into its own standalone .box file.
diff --git a/website/source/docs/commands/index.html.md b/website/source/docs/commands/index.html.md
index 8f71e386c..2aeecde6f 100644
--- a/website/source/docs/commands/index.html.md
+++ b/website/source/docs/commands/index.html.md
@@ -58,7 +58,7 @@ The format will be covered in more detail later. But as you can see, the output
immediately becomes machine-friendly. Try some other commands with the
`-machine-readable` flag to see!
-~> The `-machine-readable` flag is designed for automated environments and
+\~> The `-machine-readable` flag is designed for automated environments and
is mutually-exclusive with the `-debug` flag, which is designed for interactive
environments.
diff --git a/website/source/docs/extending/custom-builders.html.md b/website/source/docs/extending/custom-builders.html.md
index 6d1cbe03a..302401533 100644
--- a/website/source/docs/extending/custom-builders.html.md
+++ b/website/source/docs/extending/custom-builders.html.md
@@ -19,7 +19,7 @@ plugin interface, and this page documents how to do that.
Prior to reading this page, it is assumed you have read the page on [plugin
development basics](/docs/extending/plugins.html).
-~> **Warning!** This is an advanced topic. If you're new to Packer, we
+\~> **Warning!** This is an advanced topic. If you're new to Packer, we
recommend getting a bit more comfortable before you dive into writing plugins.
## The Interface
diff --git a/website/source/docs/extending/custom-post-processors.html.md b/website/source/docs/extending/custom-post-processors.html.md
index b177cf0a3..0ec5f71a5 100644
--- a/website/source/docs/extending/custom-post-processors.html.md
+++ b/website/source/docs/extending/custom-post-processors.html.md
@@ -24,7 +24,7 @@ development basics](/docs/extending/plugins.html).
Post-processor plugins implement the `packer.PostProcessor` interface and are
served using the `plugin.ServePostProcessor` function.
-~> **Warning!** This is an advanced topic. If you're new to Packer, we
+\~> **Warning!** This is an advanced topic. If you're new to Packer, we
recommend getting a bit more comfortable before you dive into writing plugins.
## The Interface
diff --git a/website/source/docs/extending/custom-provisioners.html.md b/website/source/docs/extending/custom-provisioners.html.md
index 75f412e4f..3d3a1721d 100644
--- a/website/source/docs/extending/custom-provisioners.html.md
+++ b/website/source/docs/extending/custom-provisioners.html.md
@@ -23,7 +23,7 @@ development basics](/docs/extending/plugins.html).
Provisioner plugins implement the `packer.Provisioner` interface and are served
using the `plugin.ServeProvisioner` function.
-~> **Warning!** This is an advanced topic. If you're new to Packer, we
+\~> **Warning!** This is an advanced topic. If you're new to Packer, we
recommend getting a bit more comfortable before you dive into writing plugins.
## The Interface
diff --git a/website/source/docs/extending/plugins.html.md b/website/source/docs/extending/plugins.html.md
index 1a027c4b4..901bfc91b 100644
--- a/website/source/docs/extending/plugins.html.md
+++ b/website/source/docs/extending/plugins.html.md
@@ -56,7 +56,8 @@ later, it will take precedence over one found earlier.
3. The `%APPDATA%/packer.d/plugins` if `%APPDATA%` is defined (windows)
-4. The `%USERPROFILE%/packer.d/plugins` if `%USERPROFILE%` is defined (windows)
+4. The `%USERPROFILE%/packer.d/plugins` if `%USERPROFILE%` is defined
+ (windows)
5. The current working directory.
@@ -83,7 +84,7 @@ assumed that you're familiar with the language. This page will not be a Go
language tutorial. Thankfully, if you are familiar with Go, the Go toolchain
provides many conveniences to help to develop Packer plugins.
-~> **Warning!** This is an advanced topic. If you're new to Packer, we
+\~> **Warning!** This is an advanced topic. If you're new to Packer, we
recommend getting a bit more comfortable before you dive into writing plugins.
### Plugin System Architecture
@@ -159,7 +160,7 @@ using standard installation procedures.
The specifics of how to implement each type of interface are covered in the
relevant subsections available in the navigation to the left.
-~> **Lock your dependencies!** Using `govendor` is highly recommended since
+\~> **Lock your dependencies!** Using `govendor` is highly recommended since
the Packer codebase will continue to improve, potentially breaking APIs along
the way until there is a stable release. By locking your dependencies, your
plugins will continue to work with the version of Packer you lock to.
diff --git a/website/source/docs/post-processors/alicloud-import.html.md b/website/source/docs/post-processors/alicloud-import.html.md
index c421883d7..7f26c42d7 100644
--- a/website/source/docs/post-processors/alicloud-import.html.md
+++ b/website/source/docs/post-processors/alicloud-import.html.md
@@ -42,7 +42,7 @@ are two categories: required and optional parameters.
- `image_name` (string) - The name of the user-defined image, \[2, 128\]
English or Chinese characters. It must begin with an uppercase/lowercase
letter or a Chinese character, and may contain numbers, `_` or `-`. It
- cannot begin with or .
+ cannot begin with `http://` or `https://`
- `oss_bucket_name` (string) - The name of the OSS bucket where the RAW or
VHD file will be copied to for import. If the Bucket isn't exist,
@@ -52,8 +52,8 @@ are two categories: required and optional parameters.
- `image_platform` (string) - platform such `CentOS`
-- `image_architecture` (string) - Platform type of the image system:i386 \|
- x86\_64
+- `image_architecture` (string) - Platform type of the image system: `i386` or
+ `x86_64`
- `format` (string) - The format of the image for import, now alicloud only
support RAW and VHD.
@@ -70,7 +70,7 @@ are two categories: required and optional parameters.
- `image_description` (string) - The description of the image, with a length
limit of 0 to 256 characters. Leaving it blank means null, which is the
- default value. It cannot begin with or .
+ default value. It cannot begin with `http://` or `https://`.
- `image_force_delete` (boolean) - If this value is true, when the target
image name is duplicated with an existing image, it will delete the
@@ -79,9 +79,9 @@ are two categories: required and optional parameters.
- `image_system_size` (number) - Size of the system disk, in GB, values
range:
- - cloud - 5 ~ 2000
- - cloud\_efficiency - 20 ~ 2048
- - cloud\_ssd - 20 ~ 2048
+ - cloud - 5 \~ 2000
+ - cloud\_efficiency - 20 \~ 2048
+ - cloud\_ssd - 20 \~ 2048
## Basic Example
diff --git a/website/source/docs/post-processors/amazon-import.html.md b/website/source/docs/post-processors/amazon-import.html.md
index 2fd9c9b65..34b6c01a7 100644
--- a/website/source/docs/post-processors/amazon-import.html.md
+++ b/website/source/docs/post-processors/amazon-import.html.md
@@ -14,7 +14,7 @@ Type: `amazon-import`
The Packer Amazon Import post-processor takes an OVA artifact from various
builders and imports it to an AMI available to Amazon Web Services EC2.
-~> This post-processor is for advanced users. It depends on specific IAM
+\~> This post-processor is for advanced users. It depends on specific IAM
roles inside AWS and is best used with images that operate with the EC2
configuration model (eg, cloud-init for Linux systems). Please ensure you read
the [prerequisites for
@@ -85,12 +85,13 @@ Optional:
provider whose API is compatible with aws EC2. Specify another endpoint
like this `https://ec2.custom.endpoint.com`.
-- `format` (string) - One of: `ova`, `raw`, `vhd`, `vhdx`, or `vmdk`. This specifies
- the format of the source virtual machine image. The resulting artifact from the builder
- is assumed to have a file extension matching the format. This defaults to `ova`.
+- `format` (string) - One of: `ova`, `raw`, `vhd`, `vhdx`, or `vmdk`. This
+ specifies the format of the source virtual machine image. The resulting
+ artifact from the builder is assumed to have a file extension matching the
+ format. This defaults to `ova`.
-- `insecure_skip_tls_verify` (boolean) - This allows skipping TLS verification of
- the AWS EC2 endpoint. The default is `false`.
+- `insecure_skip_tls_verify` (boolean) - This allows skipping TLS
+ verification of the AWS EC2 endpoint. The default is `false`.
- `license_type` (string) - The license type to be used for the Amazon
Machine Image (AMI) after importing. Valid values: `AWS` or `BYOL`
diff --git a/website/source/docs/post-processors/docker-import.html.md b/website/source/docs/post-processors/docker-import.html.md
index 8802a18e7..4fb3b0fe3 100644
--- a/website/source/docs/post-processors/docker-import.html.md
+++ b/website/source/docs/post-processors/docker-import.html.md
@@ -38,7 +38,6 @@ is optional.
commit. Example of instructions are `CMD`, `ENTRYPOINT`, `ENV`, and
`EXPOSE`. Example: `[ "USER ubuntu", "WORKDIR /app", "EXPOSE 8080" ]`
-
## Example
An example is shown below, showing only the post-processor configuration:
@@ -61,9 +60,9 @@ to a registry, if you want.
## Changing Metadata
Below is an example using the changes argument of the post-processor. This
-feature allows the tarball metadata to be changed when imported into the
-Docker environment. It is derived from the `docker import --change` command
-line [option to
+feature allows the tarball metadata to be changed when imported into the Docker
+environment. It is derived from the `docker import --change` command line
+[option to
Docker](https://docs.docker.com/engine/reference/commandline/import/).
Example uses of all of the options, assuming one is building an NGINX image
diff --git a/website/source/docs/post-processors/googlecompute-import.html.md b/website/source/docs/post-processors/googlecompute-import.html.md
index 4676dfd3c..c7ff21f09 100644
--- a/website/source/docs/post-processors/googlecompute-import.html.md
+++ b/website/source/docs/post-processors/googlecompute-import.html.md
@@ -14,7 +14,7 @@ Type: `googlecompute-import`
The Google Compute Image Import post-processor takes a compressed raw disk
image and imports it to a GCE image available to Google Compute Engine.
-~> This post-processor is for advanced users. Please ensure you read the
+\~> This post-processor is for advanced users. Please ensure you read the
[GCE import
documentation](https://cloud.google.com/compute/docs/images/import-existing-image)
before using this post-processor.
diff --git a/website/source/docs/post-processors/shell-local.html.md b/website/source/docs/post-processors/shell-local.html.md
index 279548b10..7599febf2 100644
--- a/website/source/docs/post-processors/shell-local.html.md
+++ b/website/source/docs/post-processors/shell-local.html.md
@@ -60,14 +60,13 @@ Optional parameters:
Packer injects some environmental variables by default into the
environment, as well, which are covered in the section below.
-- `env_var_format` (string) - When we parse the environment_vars that you
+- `env_var_format` (string) - When we parse the environment\_vars that you
provide, this gives us a string template to use in order to make sure that
we are setting the environment vars correctly. By default on Windows hosts
- this format is `set %s=%s && ` and on Unix, it is `%s='%s' `. You probably
+ this format is `set %s=%s && ` and on Unix, it is `%s='%s' `. You probably
won't need to change this format, but you can see usage examples for where
it is necessary below.
-
- `execute_command` (array of strings) - The command used to execute the
script. By default this is `["/bin/sh", "-c", "{{.Vars}}", "{{.Script}}"]`
on unix and `["cmd", "/c", "{{.Vars}}", "{{.Script}}"]` on windows. This is
@@ -250,10 +249,10 @@ are cleaned up.
For a shell script, that means the script **must** exit with a zero code. You
*must* be extra careful to `exit 0` when necessary.
-
## Usage Examples:
### Windows Host
+
Example of running a .cmd file on windows:
{
@@ -295,7 +294,6 @@ Contents of "example\_bash.sh":
Example of running a powershell script on windows: Required customizations:
env\_var\_format and execute\_command
-
{
"type": "shell-local",
"environment_vars": ["SHELLLOCALTEST=ShellTest4"],
@@ -317,6 +315,7 @@ customizations: env\_var\_format, tempfile\_extension, and execute\_command
}
### Unix Host
+
Example of running a bash script on unix:
{
@@ -336,19 +335,15 @@ Example of running a bash "inline" on unix:
Example of running a python script on unix:
-```
- {
- "type": "shell-local",
- "script": "hello.py",
- "environment_vars": ["HELLO_USER=packeruser"],
- "execute_command": ["/bin/sh", "-c", "{{.Vars}} /usr/local/bin/python {{.Script}}"]
- }
-```
+ {
+ "type": "shell-local",
+ "script": "hello.py",
+ "environment_vars": ["HELLO_USER=packeruser"],
+ "execute_command": ["/bin/sh", "-c", "{{.Vars}} /usr/local/bin/python {{.Script}}"]
+ }
Where "hello.py" contains:
-```
-import os
+ import os
-print('Hello, %s!' % os.getenv("HELLO_USER"))
-```
\ No newline at end of file
+ print('Hello, %s!' % os.getenv("HELLO_USER"))
diff --git a/website/source/docs/post-processors/vagrant.html.md b/website/source/docs/post-processors/vagrant.html.md
index c0ccf6241..253472ed3 100644
--- a/website/source/docs/post-processors/vagrant.html.md
+++ b/website/source/docs/post-processors/vagrant.html.md
@@ -144,5 +144,5 @@ The following Docker input artifacts are supported:
### QEMU/libvirt
-The `libvirt` provider supports QEMU artifacts built using any these accelerators: none,
-kvm, tcg, or hvf.
+The `libvirt` provider supports QEMU artifacts built using any these
+accelerators: none, kvm, tcg, or hvf.
diff --git a/website/source/docs/post-processors/vsphere-template.html.md b/website/source/docs/post-processors/vsphere-template.html.md
index 9057aca14..08fbf46c9 100644
--- a/website/source/docs/post-processors/vsphere-template.html.md
+++ b/website/source/docs/post-processors/vsphere-template.html.md
@@ -60,16 +60,16 @@ Optional:
- `insecure` (boolean) - If it's true skip verification of server
certificate. Default is false
-
-- `snapshot_enable` (boolean) - Create a snapshot before marking as a
+
+- `snapshot_enable` (boolean) - Create a snapshot before marking as a
template. Default is false
-
-- `snapshot_name` (string) - Name for the snapshot.
- Required when `snapshot_enable` is `true`
-
-- `snapshot_description` (string) - Description for the snapshot.
- Required when `snapshot_enable` is `true`
-
+
+- `snapshot_name` (string) - Name for the snapshot. Required when
+ `snapshot_enable` is `true`
+
+- `snapshot_description` (string) - Description for the snapshot. Required
+ when `snapshot_enable` is `true`
+
## Using the vSphere Template with local builders
Once the [vSphere](/docs/post-processors/vsphere.html) takes an artifact from
diff --git a/website/source/docs/provisioners/ansible-local.html.md b/website/source/docs/provisioners/ansible-local.html.md
index 5972cff1d..63cd15125 100644
--- a/website/source/docs/provisioners/ansible-local.html.md
+++ b/website/source/docs/provisioners/ansible-local.html.md
@@ -68,6 +68,7 @@ Optional:
example:
+
"extra_arguments": [ "--extra-vars \"Region={{user `Region`}} Stage={{user `Stage`}}\"" ]
- `inventory_groups` (string) - A comma-separated list of groups to which
diff --git a/website/source/docs/provisioners/breakpoint.html.md b/website/source/docs/provisioners/breakpoint.html.md
index edcc48405..d251e534b 100644
--- a/website/source/docs/provisioners/breakpoint.html.md
+++ b/website/source/docs/provisioners/breakpoint.html.md
@@ -1,8 +1,8 @@
---
description: |
- The breakpoint provisioner will pause until the user presses "enter" to
- resume the build. This is intended for debugging purposes, and allows you
- to halt at a particular part of the provisioning process.
+ The breakpoint provisioner will pause until the user presses "enter" to resume
+ the build. This is intended for debugging purposes, and allows you to halt at a
+ particular part of the provisioning process.
layout: docs
page_title: 'breakpoint - Provisioners'
sidebar_current: 'docs-provisioners-breakpoint'
@@ -12,9 +12,9 @@ sidebar_current: 'docs-provisioners-breakpoint'
Type: `breakpoint`
-The breakpoint provisioner will pause until the user presses "enter" to
-resume the build. This is intended for debugging purposes, and allows you
-to halt at a particular part of the provisioning process.
+The breakpoint provisioner will pause until the user presses "enter" to resume
+the build. This is intended for debugging purposes, and allows you to halt at a
+particular part of the provisioning process.
This is independent of the `-debug` flag, which will instead halt at every step
and between every provisioner.
@@ -33,8 +33,8 @@ and between every provisioner.
### Optional
- `disable` (boolean) - If `true`, skip the breakpoint. Useful for when you
- have set multiple breakpoints and want to toggle them off or on.
- Default: `false`
+ have set multiple breakpoints and want to toggle them off or on. Default:
+ `false`
- `note` (string) - a string to include explaining the purpose or location of
the breakpoint. For example, you may find it useful to number your
@@ -48,10 +48,8 @@ output prompting you to press "enter" to continue the build when you are ready.
For example:
-```
-==> docker: Pausing at breakpoint provisioner with note "foo bar baz".
-==> docker: Press enter to continue.
-```
+ ==> docker: Pausing at breakpoint provisioner with note "foo bar baz".
+ ==> docker: Press enter to continue.
Once you press enter, the build will resume and run normally until it either
-completes or errors.
\ No newline at end of file
+completes or errors.
diff --git a/website/source/docs/provisioners/puppet-masterless.html.md b/website/source/docs/provisioners/puppet-masterless.html.md
index e28a10e7d..41ced3fde 100644
--- a/website/source/docs/provisioners/puppet-masterless.html.md
+++ b/website/source/docs/provisioners/puppet-masterless.html.md
@@ -73,7 +73,8 @@ Optional parameters:
]
- `facter` (object of key:value strings) - Additional
- [facts](https://docs.puppet.com/facter/) to make available to the Puppet run.
+ [facts](https://docs.puppet.com/facter/) to make available to the Puppet
+ run.
- `guest_os_type` (string) - The remote host's OS type ('windows' or 'unix')
to tailor command-line and path separators. (default: unix).
@@ -88,9 +89,9 @@ Optional parameters:
This is useful if your main manifest uses imports, but the directory might
not contain the `manifest_file` itself.
-~> `manifest_dir` is passed to Puppet as `--manifestdir` option. This option
-was deprecated in puppet 3.6, and removed in puppet 4.0. If you have multiple
-manifests you should use `manifest_file` instead.
+\~> `manifest_dir` is passed to Puppet as `--manifestdir` option. This
+option was deprecated in puppet 3.6, and removed in puppet 4.0. If you have
+multiple manifests you should use `manifest_file` instead.
- `module_paths` (array of strings) - Array of local module directories to be
uploaded.
diff --git a/website/source/docs/provisioners/shell-local.html.md b/website/source/docs/provisioners/shell-local.html.md
index cf9b6cc60..3dc81fe66 100644
--- a/website/source/docs/provisioners/shell-local.html.md
+++ b/website/source/docs/provisioners/shell-local.html.md
@@ -74,10 +74,10 @@ Optional parameters:
this as an environment variable. For example:
`"environment_vars": "WINRMPASS={{.WinRMPassword}}"`
-- `env_var_format` (string) - When we parse the environment_vars that you
+- `env_var_format` (string) - When we parse the environment\_vars that you
provide, this gives us a string template to use in order to make sure that
we are setting the environment vars correctly. By default on Windows hosts
- this format is `set %s=%s && ` and on Unix, it is `%s='%s' `. You probably
+ this format is `set %s=%s && ` and on Unix, it is `%s='%s' `. You probably
won't need to change this format, but you can see usage examples for where
it is necessary below.
@@ -230,6 +230,7 @@ For a shell script, that means the script **must** exit with a zero code. You
## Usage Examples:
### Windows Host
+
Example of running a .cmd file on windows:
{
@@ -271,7 +272,6 @@ Contents of "example\_bash.sh":
Example of running a powershell script on windows: Required customizations:
env\_var\_format and execute\_command
-
{
"type": "shell-local",
"environment_vars": ["SHELLLOCALTEST=ShellTest4"],
@@ -293,6 +293,7 @@ customizations: env\_var\_format, tempfile\_extension, and execute\_command
}
### Unix Host
+
Example of running a bash script on unix:
{
@@ -312,19 +313,15 @@ Example of running a bash "inline" on unix:
Example of running a python script on unix:
-```
- {
- "type": "shell-local",
- "script": "hello.py",
- "environment_vars": ["HELLO_USER=packeruser"],
- "execute_command": ["/bin/sh", "-c", "{{.Vars}} /usr/local/bin/python {{.Script}}"]
- }
-```
+ {
+ "type": "shell-local",
+ "script": "hello.py",
+ "environment_vars": ["HELLO_USER=packeruser"],
+ "execute_command": ["/bin/sh", "-c", "{{.Vars}} /usr/local/bin/python {{.Script}}"]
+ }
Where "hello.py" contains:
-```
-import os
+ import os
-print('Hello, %s!' % os.getenv("HELLO_USER"))
-```
\ No newline at end of file
+ print('Hello, %s!' % os.getenv("HELLO_USER"))
diff --git a/website/source/docs/provisioners/windows-restart.html.md b/website/source/docs/provisioners/windows-restart.html.md
index b9ee04567..bb340efc8 100644
--- a/website/source/docs/provisioners/windows-restart.html.md
+++ b/website/source/docs/provisioners/windows-restart.html.md
@@ -41,10 +41,10 @@ Optional parameters:
- `check_registry` (bool) - if `true`, checks for several registry keys that
indicate that the system is going to reboot. This is useful if an
installation kicks off a reboot and you want the provisioner to wait for
- that reboot to complete before reconnecting. Please note that this option is
- a beta feature, and we generally recommend that you finish installs that
- auto-reboot (like windows updates) during your autounattend phase before our
- winrm provisioner connects.
+ that reboot to complete before reconnecting. Please note that this option
+ is a beta feature, and we generally recommend that you finish installs that
+ auto-reboot (like windows updates) during your autounattend phase before
+ our winrm provisioner connects.
- `registry_keys` (array of strings) - if `check-registry` is `true`,
windows-restart will not reconnect until after all of the listed keys are
@@ -52,13 +52,11 @@ Optional parameters:
default:
- ```
- var DefaultRegistryKeys = []string{
- "HKLM:SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootPending",
- "HKLM:SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\PackagesPending",
- "HKLM:Software\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootInProgress",
- }
- ```
+ var DefaultRegistryKeys = []string{
+ "HKLM:SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootPending",
+ "HKLM:SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\PackagesPending",
+ "HKLM:Software\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootInProgress",
+ }
- `restart_command` (string) - The command to execute to initiate the
restart. By default this is `shutdown /r /f /t 0 /c "packer restart"`.
diff --git a/website/source/docs/templates/communicator.html.md b/website/source/docs/templates/communicator.html.md
index b2133f825..c8054f623 100644
--- a/website/source/docs/templates/communicator.html.md
+++ b/website/source/docs/templates/communicator.html.md
@@ -75,9 +75,9 @@ The SSH communicator has the following options:
- `ssh_bastion_port` (number) - The port of the bastion host. Defaults to
`22`.
-- `ssh_bastion_private_key_file` (string) - Path to a PEM encoded private
- key file to use to authenticate with the bastion host. The `~` can be used
- in path and will be expanded to the home directory of current user.
+- `ssh_bastion_private_key_file` (string) - Path to a PEM encoded private key
+ file to use to authenticate with the bastion host. The `~` can be used in
+ path and will be expanded to the home directory of current user.
- `ssh_bastion_username` (string) - The username to connect to the bastion
host.
@@ -155,23 +155,25 @@ Packer supports the following ciphers:
- arcfour128
- arcfour256
- arcfour
--
--
+- `es128-gcm@openssh.com`
+- `acha20-poly1305@openssh.com`
And the following MACs:
- hmac-sha1
- hmac-sha1-96
- hmac-sha2-256
--
+- `hmac-sha2-256-etm@openssh.com`
## WinRM Communicator
The WinRM communicator has the following options.
- `winrm_host` (string) - The address for WinRM to connect to.
-
- NOTE: If using an Amazon EBS builder, you can specify the interface WinRM connects to via [`ssh_interface`](https://www.packer.io/docs/builders/amazon-ebs.html#ssh_interface)
+
+ NOTE: If using an Amazon EBS builder, you can specify the interface WinRM
+ connects to via
+ [`ssh_interface`](https://www.packer.io/docs/builders/amazon-ebs.html#ssh_interface)
- `winrm_insecure` (boolean) - If `true`, do not check server certificate
chain and host name.
diff --git a/website/source/docs/templates/engine.html.md b/website/source/docs/templates/engine.html.md
index aae419098..1cebe5fc5 100644
--- a/website/source/docs/templates/engine.html.md
+++ b/website/source/docs/templates/engine.html.md
@@ -44,7 +44,8 @@ Here is a full list of the available functions for reference.
reference](/docs/templates/engine.html#isotime-function-format-reference).
- `lower` - Lowercases the string.
- `pwd` - The working directory while executing Packer.
-- `sed` - Use [a golang implementation of sed](https://github.com/rwtodd/Go.Sed) to parse an input string.
+- `sed` - Use [a golang implementation of
+ sed](https://github.com/rwtodd/Go.Sed) to parse an input string.
- `split` - Split an input string using separator and return the requested
substring.
- `template_dir` - The directory to the template for the build.
@@ -227,6 +228,7 @@ Formatting for the function `isotime` uses the magic reference date **Mon Jan 2
+
*The values in parentheses are the abbreviated, or 24-hour clock values*
Note that "-0700" is always formatted into "+0000" because `isotime` is always
@@ -272,10 +274,10 @@ builder in this example.
The function `split` takes an input string, a seperator string, and a numeric
component value and returns the requested substring.
-Please note that you cannot use the `split` function on user variables,
-because we can't nest the functions currently. This function is indended to
-be used on builder variables like build_name. If you need a split user
-variable, the best way to do it is to create a separate variable.
+Please note that you cannot use the `split` function on user variables, because
+we can't nest the functions currently. This function is indended to be used on
+builder variables like build\_name. If you need a split user variable, the best
+way to do it is to create a separate variable.
Here are some examples using the above options:
@@ -310,16 +312,15 @@ this case, on the `fixed-string` value):
# sed Function Format Reference
-See the library documentation https://github.com/rwtodd/Go.Sed for notes about
-the difference between this golang implementation of sed and the regexes you may
-be used to. A very simple example of this functionality:
+See the library documentation
+https://github.com/rwtodd/Go.Sed
+for notes about the difference between this golang implementation of sed and
+the regexes you may be used to. A very simple example of this functionality:
-```
- "provisioners": [
- {
- "type": "shell-local",
- "environment_vars": ["EXAMPLE={{ sed \"s/null/awesome/\" build_type}}"],
- "inline": ["echo build_type is $EXAMPLE\n"]
- }
- ]
-```
+ "provisioners": [
+ {
+ "type": "shell-local",
+ "environment_vars": ["EXAMPLE={{ sed \"s/null/awesome/\" build_type}}"],
+ "inline": ["echo build_type is $EXAMPLE\n"]
+ }
+ ]