mirror of https://github.com/hashicorp/packer
commit
75f574bd4b
@ -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
|
||||
}
|
||||
@ -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())
|
||||
}
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
}
|
||||
@ -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) {
|
||||
}
|
||||
@ -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"))
|
||||
}
|
||||
}
|
||||
@ -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.
|
||||
Loading…
Reference in new issue