Merge pull request #7221 from hashicorp/vagrant_builder
Vagrant builder
This commit is contained in:
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"))
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,6 +43,7 @@ import (
|
||||||
scalewaybuilder "github.com/hashicorp/packer/builder/scaleway"
|
scalewaybuilder "github.com/hashicorp/packer/builder/scaleway"
|
||||||
tencentcloudcvmbuilder "github.com/hashicorp/packer/builder/tencentcloud/cvm"
|
tencentcloudcvmbuilder "github.com/hashicorp/packer/builder/tencentcloud/cvm"
|
||||||
tritonbuilder "github.com/hashicorp/packer/builder/triton"
|
tritonbuilder "github.com/hashicorp/packer/builder/triton"
|
||||||
|
vagrantbuilder "github.com/hashicorp/packer/builder/vagrant"
|
||||||
virtualboxisobuilder "github.com/hashicorp/packer/builder/virtualbox/iso"
|
virtualboxisobuilder "github.com/hashicorp/packer/builder/virtualbox/iso"
|
||||||
virtualboxovfbuilder "github.com/hashicorp/packer/builder/virtualbox/ovf"
|
virtualboxovfbuilder "github.com/hashicorp/packer/builder/virtualbox/ovf"
|
||||||
vmwareisobuilder "github.com/hashicorp/packer/builder/vmware/iso"
|
vmwareisobuilder "github.com/hashicorp/packer/builder/vmware/iso"
|
||||||
|
@ -118,6 +119,7 @@ var Builders = map[string]packer.Builder{
|
||||||
"scaleway": new(scalewaybuilder.Builder),
|
"scaleway": new(scalewaybuilder.Builder),
|
||||||
"tencentcloud-cvm": new(tencentcloudcvmbuilder.Builder),
|
"tencentcloud-cvm": new(tencentcloudcvmbuilder.Builder),
|
||||||
"triton": new(tritonbuilder.Builder),
|
"triton": new(tritonbuilder.Builder),
|
||||||
|
"vagrant": new(vagrantbuilder.Builder),
|
||||||
"virtualbox-iso": new(virtualboxisobuilder.Builder),
|
"virtualbox-iso": new(virtualboxisobuilder.Builder),
|
||||||
"virtualbox-ovf": new(virtualboxovfbuilder.Builder),
|
"virtualbox-ovf": new(virtualboxovfbuilder.Builder),
|
||||||
"vmware-iso": new(vmwareisobuilder.Builder),
|
"vmware-iso": new(vmwareisobuilder.Builder),
|
||||||
|
|
|
@ -147,28 +147,30 @@ builder.
|
||||||
|
|
||||||
Snapshots from on or before July 15, 2013 cannot be used to create a
|
Snapshots from on or before July 15, 2013 cannot be used to create a
|
||||||
disk.
|
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
|
- `image_ignore_data_disks`(boolean) - If this value is true, the image
|
||||||
default timeout is 3600 seconds if this option is not set or is set to 0. For
|
created will not include any snapshot of data disks. This option would be
|
||||||
those disks containing lots of data, it may require a higher timeout value.
|
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_force_delete` (boolean) - If this value is true, when the target
|
||||||
image names including those copied are duplicated with existing images,
|
image names including those copied are duplicated with existing images, it
|
||||||
it will delete the existing images and then create the target images,
|
will delete the existing images and then create the target images,
|
||||||
otherwise, the creation will fail. The default value is false. Check
|
otherwise, the creation will fail. The default value is false. Check
|
||||||
`image_name` and `image_copy_names` options for names of target images.
|
`image_name` and `image_copy_names` options for names of target images. If
|
||||||
If [-force](https://packer.io/docs/commands/build.html#force) option is provided
|
[-force](https://packer.io/docs/commands/build.html#force) option is
|
||||||
in `build` command, this option can be omitted and taken as true.
|
provided in `build` command, this option can be omitted and taken as true.
|
||||||
|
|
||||||
- `image_force_delete_snapshots` (boolean) - If this value is true, when
|
- `image_force_delete_snapshots` (boolean) - If this value is true, when
|
||||||
delete the duplicated existing images, the source snapshots of those images
|
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)
|
will be delete either. If
|
||||||
option is provided in `build` command, this option can be omitted and taken as true.
|
[-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
|
- `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.
|
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
|
\~> Note: Images can become deprecated after a while; run
|
||||||
`aliyun ecs DescribeImages` to find one that exists.
|
`aliyun ecs DescribeImages` to find one that exists.
|
||||||
|
|
||||||
\~> Note: Since WinRM is closed by default in the system image. If you are planning
|
\~> Note: Since WinRM is closed by default in the system image. If you are
|
||||||
to use Windows as the base image, you need enable it by userdata in order to connect to
|
planning to use Windows as the base image, you need enable it by userdata in
|
||||||
the instance, check [alicloud_windows.json](https://github.com/hashicorp/packer/tree/master/examples/alicloud/basic/alicloud_windows.json)
|
order to connect to the instance, check
|
||||||
and [winrm_enable_userdata.ps1](https://github.com/hashicorp/packer/tree/master/examples/alicloud/basic/winrm_enable_userdata.ps1) for details.
|
[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
|
See the
|
||||||
[examples/alicloud](https://github.com/hashicorp/packer/tree/master/examples/alicloud)
|
[examples/alicloud](https://github.com/hashicorp/packer/tree/master/examples/alicloud)
|
||||||
|
|
|
@ -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
|
==> 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
|
If you suspect your system's date is wrong, you can compare it against
|
||||||
<http://www.time.gov/>. On Linux/OS X, you can run the `date` command to get
|
<http://www.time.gov/>. On
|
||||||
the current time. If you're on Linux, you can try setting the time with ntp by
|
Linux/OS X, you can run the `date` command to get the current time. If you're
|
||||||
running `sudo ntpd -q`.
|
on Linux, you can try setting the time with ntp by running `sudo ntpd -q`.
|
||||||
|
|
||||||
### `exceeded wait attempts` while waiting for tasks to complete
|
### `exceeded wait attempts` while waiting for tasks to complete
|
||||||
|
|
||||||
|
|
|
@ -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
|
- `os_disk_size_gb` (number) Specify the size of the OS disk in GB
|
||||||
(gigabytes). Values of zero or less than zero are ignored.
|
(gigabytes). Values of zero or less than zero are ignored.
|
||||||
|
|
||||||
- `disk_caching_type` (string) Specify the disk caching type. Valid values are None, ReadOnly,
|
- `disk_caching_type` (string) Specify the disk caching type. Valid values
|
||||||
and ReadWrite. The default value is ReadWrite.
|
are None, ReadOnly, and ReadWrite. The default value is ReadWrite.
|
||||||
|
|
||||||
- `disk_additional_size` (array of integers) - The size(s) of any additional
|
- `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
|
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
|
value and defaults to false. **Important** Setting this true means that
|
||||||
your builds are faster, however any failed deletes are not reported.
|
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
|
- `managed_image_os_disk_snapshot_name` (string) If
|
||||||
is set, a snapshot of the OS disk is created with the same name as this value before the
|
managed\_image\_os\_disk\_snapshot\_name is set, a snapshot of the OS disk
|
||||||
VM is captured.
|
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
|
- `managed_image_data_disk_snapshot_prefix` (string) If
|
||||||
is set, snapshot of the data disk(s) is created with the same prefix as this value before the VM
|
managed\_image\_data\_disk\_snapshot\_prefix is set, snapshot of the data
|
||||||
is captured.
|
disk(s) is created with the same prefix as this value before the VM is
|
||||||
|
captured.
|
||||||
|
|
||||||
## Basic Example
|
## 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
|
The Windows Guest Agent participates in the Sysprep process. The agent must be
|
||||||
agent must be fully installed before the VM can be sysprep'ed. To
|
fully installed before the VM can be sysprep'ed. To ensure this is true all
|
||||||
ensure this is true all agent services must be running before
|
agent services must be running before executing sysprep.exe. The above JSON
|
||||||
executing sysprep.exe. The above JSON snippet shows one way to do this
|
snippet shows one way to do this in the PowerShell provisioner. This snippet is
|
||||||
in the PowerShell provisioner. This snippet is **only** required if
|
**only** required if the VM is configured to install the agent, which is the
|
||||||
the VM is configured to install the agent, which is the default. To
|
default. To learn more about disabling the Windows Guest Agent please see
|
||||||
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).
|
[Install the VM
|
||||||
|
Agent](https://docs.microsoft.com/en-us/azure/virtual-machines/extensions/agent-windows#install-the-vm-agent).
|
||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
|
|
|
@ -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
|
`login_username`, and `login_password` will be ignored. For more
|
||||||
information see the [section on ECR](#amazon-ec2-container-registry).
|
information see the [section on ECR](#amazon-ec2-container-registry).
|
||||||
|
|
||||||
- `exec_user` (string) - Username or UID (format:
|
- `exec_user` (string) - Username (UID) to run remote commands with. You can
|
||||||
<name\\\|uid>\[:<group\\\|gid>\]) to run remote commands with.
|
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
|
You may need this if you get permission errors trying to run the `shell` or
|
||||||
other provisioners.
|
other provisioners.
|
||||||
|
|
||||||
|
@ -380,8 +380,8 @@ portable provisioning scripts.
|
||||||
|
|
||||||
## Overriding the host directory
|
## Overriding the host directory
|
||||||
|
|
||||||
By default, Packer creates a temporary folder under your home directory, and
|
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
|
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`.
|
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
|
This can be useful, for example, if you have your home directory permissions
|
||||||
set up to disallow access from the docker daemon.
|
set up to disallow access from the docker daemon.
|
||||||
|
|
|
@ -18,9 +18,8 @@ based on existing images.
|
||||||
|
|
||||||
It is possible to build images from scratch, but not with the `googlecompute`
|
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
|
Packer builder. The process is recommended only for advanced users, please see
|
||||||
\[Building GCE Images from Scratch\]
|
[Building GCE Images from Scratch](https://cloud.google.com/compute/docs/tutorials/building-images)
|
||||||
(<https://cloud.google.com/compute/docs/tutorials/building-images>) and the
|
and the [Google Compute Import
|
||||||
[Google Compute Import
|
|
||||||
Post-Processor](/docs/post-processors/googlecompute-import.html) for more
|
Post-Processor](/docs/post-processors/googlecompute-import.html) for more
|
||||||
information.
|
information.
|
||||||
|
|
||||||
|
@ -139,7 +138,7 @@ using the gcloud command.
|
||||||
gcloud compute firewall-rules create allow-winrm --allow tcp:5986
|
gcloud compute firewall-rules create allow-winrm --allow tcp:5986
|
||||||
|
|
||||||
Or alternatively by navigating to
|
Or alternatively by navigating to
|
||||||
<https://console.cloud.google.com/networking/firewalls/list>.
|
<a href="https://console.cloud.google.com/networking/firewalls/list" class="uri">https://console.cloud.google.com/networking/firewalls/list</a>.
|
||||||
|
|
||||||
Once this is set up, the following is a complete working packer config after
|
Once this is set up, the following is a complete working packer config after
|
||||||
setting a valid `account_file` and `project_id`:
|
setting a valid `account_file` and `project_id`:
|
||||||
|
|
|
@ -75,7 +75,9 @@ builder.
|
||||||
- `ssh_keys` (array of strings) - List of SSH keys by name or id to be added
|
- `ssh_keys` (array of strings) - List of SSH keys by name or id to be added
|
||||||
to image on launch.
|
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
|
## Basic Example
|
||||||
|
|
||||||
|
|
|
@ -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.
|
The LXC builder requires a modern linux kernel and the `lxc` or `lxc1` package.
|
||||||
This builder does not work with LXD.
|
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. <br>Some provisioners such as `ansible-local` get
|
`yum` package installed. <br>Some provisioners such as `ansible-local` get
|
||||||
confused when running in a container of a different family. E.G. it will
|
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
|
attempt to use `apt-get` to install packages, when running in a Centos
|
||||||
|
|
|
@ -47,7 +47,7 @@ Below is a fully functioning example.
|
||||||
container. This can be a (local or remote) image (name or fingerprint).
|
container. This can be a (local or remote) image (name or fingerprint).
|
||||||
E.G. `my-base-image`, `ubuntu-daily:x`, `08fababf6f27`, ...
|
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
|
remote image, as they are usually 100-200MB. `/var/log/lxd/lxd.log` will
|
||||||
mention starting such downloads.
|
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
|
- `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
|
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
|
set the description, but can be used to set anything needed. See
|
||||||
<https://stgraber.org/2016/03/30/lxd-2-0-image-management-512/> for more
|
<a href="https://stgraber.org/2016/03/30/lxd-2-0-image-management-512/" class="uri">https://stgraber.org/2016/03/30/lxd-2-0-image-management-512/</a>
|
||||||
properties.
|
for more properties.
|
||||||
|
|
||||||
- `launch_config` (map\[string\]string) - List of key/value pairs you wish to
|
- `launch_config` (map\[string\]string) - List of key/value pairs you wish to
|
||||||
pass to `lxc launch` via `--config`. Defaults to empty.
|
pass to `lxc launch` via `--config`. Defaults to empty.
|
||||||
|
|
|
@ -90,7 +90,6 @@ Here is a basic example for windows server.
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Here is a basic example for linux server.
|
Here is a basic example for linux server.
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -278,8 +278,8 @@ builder.
|
||||||
isn't specified, the default enforced by your OpenStack cluster will be
|
isn't specified, the default enforced by your OpenStack cluster will be
|
||||||
used.
|
used.
|
||||||
|
|
||||||
- `volume_size` (int) - Size of the Block Storage service volume in GB. If this
|
- `volume_size` (int) - Size of the Block Storage service volume in GB. If
|
||||||
isn't specified, it is set to source image min disk value (if set) or
|
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
|
calculated from the source image bytes size. Note that in some cases this
|
||||||
needs to be specified, if `use_blockstorage_volume` is true.
|
needs to be specified, if `use_blockstorage_volume` is true.
|
||||||
|
|
||||||
|
|
|
@ -141,9 +141,10 @@ If this is set, a few more options become available.
|
||||||
- `builder_communicator` (communicator) - This represents an
|
- `builder_communicator` (communicator) - This represents an
|
||||||
[`ssh communicator`](/docs/templates/communicator.html#ssh-communicator),
|
[`ssh communicator`](/docs/templates/communicator.html#ssh-communicator),
|
||||||
and can be configured as such. If you use a different builder image, you
|
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": [
|
"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.
|
amount of memory, and other resources allocated to the builder instance.
|
||||||
Default: `oc3`.
|
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
|
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
|
should consult the default in code to decide on the changes to make. For
|
||||||
most users the default should suffice.
|
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`
|
Here is an example using a persistent volume. Note the `persistent_volume_size`
|
||||||
setting.
|
setting.
|
||||||
|
|
||||||
```json
|
``` json
|
||||||
{
|
{
|
||||||
"variables": {
|
"variables": {
|
||||||
"opc_username": "{{ env `OPC_USERNAME`}}",
|
"opc_username": "{{ env `OPC_USERNAME`}}",
|
||||||
|
|
|
@ -48,8 +48,8 @@ builder.
|
||||||
|
|
||||||
- `image` (string) - The UUID of the base image to use. This is the image
|
- `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
|
that will be used to launch a new server and provision it. See
|
||||||
<https://api-marketplace.scaleway.com/images> get the complete list of the
|
[the images list](https://api-marketplace.scaleway.com/images)
|
||||||
accepted image UUID.
|
get the complete list of the accepted image UUID.
|
||||||
|
|
||||||
- `region` (string) - The name of the region to launch the server in (`par1`
|
- `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
|
or `ams1`). Consequently, this is the region where the snapshot will be
|
||||||
|
|
|
@ -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
|
The builder does *not* manage images. Once it creates an image, it is up to you
|
||||||
to use it or delete it.
|
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
|
use the Triton builder with a private/on-prem installation of Joyent's Triton
|
||||||
software, you'll need an operator to manually [enable custom
|
software, you'll need an operator to manually [enable custom
|
||||||
images](https://docs.joyent.com/private-cloud/install/image-management) after
|
images](https://docs.joyent.com/private-cloud/install/image-management) after
|
||||||
|
|
|
@ -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.
|
|
@ -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
|
immediately becomes machine-friendly. Try some other commands with the
|
||||||
`-machine-readable` flag to see!
|
`-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
|
is mutually-exclusive with the `-debug` flag, which is designed for interactive
|
||||||
environments.
|
environments.
|
||||||
|
|
||||||
|
|
|
@ -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
|
Prior to reading this page, it is assumed you have read the page on [plugin
|
||||||
development basics](/docs/extending/plugins.html).
|
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.
|
recommend getting a bit more comfortable before you dive into writing plugins.
|
||||||
|
|
||||||
## The Interface
|
## The Interface
|
||||||
|
|
|
@ -24,7 +24,7 @@ development basics](/docs/extending/plugins.html).
|
||||||
Post-processor plugins implement the `packer.PostProcessor` interface and are
|
Post-processor plugins implement the `packer.PostProcessor` interface and are
|
||||||
served using the `plugin.ServePostProcessor` function.
|
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.
|
recommend getting a bit more comfortable before you dive into writing plugins.
|
||||||
|
|
||||||
## The Interface
|
## The Interface
|
||||||
|
|
|
@ -23,7 +23,7 @@ development basics](/docs/extending/plugins.html).
|
||||||
Provisioner plugins implement the `packer.Provisioner` interface and are served
|
Provisioner plugins implement the `packer.Provisioner` interface and are served
|
||||||
using the `plugin.ServeProvisioner` function.
|
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.
|
recommend getting a bit more comfortable before you dive into writing plugins.
|
||||||
|
|
||||||
## The Interface
|
## The Interface
|
||||||
|
|
|
@ -56,7 +56,8 @@ later, it will take precedence over one found earlier.
|
||||||
|
|
||||||
3. The `%APPDATA%/packer.d/plugins` if `%APPDATA%` is defined (windows)
|
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.
|
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
|
language tutorial. Thankfully, if you are familiar with Go, the Go toolchain
|
||||||
provides many conveniences to help to develop Packer plugins.
|
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.
|
recommend getting a bit more comfortable before you dive into writing plugins.
|
||||||
|
|
||||||
### Plugin System Architecture
|
### 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
|
The specifics of how to implement each type of interface are covered in the
|
||||||
relevant subsections available in the navigation to the left.
|
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 Packer codebase will continue to improve, potentially breaking APIs along
|
||||||
the way until there is a stable release. By locking your dependencies, your
|
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.
|
plugins will continue to work with the version of Packer you lock to.
|
||||||
|
|
|
@ -42,7 +42,7 @@ are two categories: required and optional parameters.
|
||||||
- `image_name` (string) - The name of the user-defined image, \[2, 128\]
|
- `image_name` (string) - The name of the user-defined image, \[2, 128\]
|
||||||
English or Chinese characters. It must begin with an uppercase/lowercase
|
English or Chinese characters. It must begin with an uppercase/lowercase
|
||||||
letter or a Chinese character, and may contain numbers, `_` or `-`. It
|
letter or a Chinese character, and may contain numbers, `_` or `-`. It
|
||||||
cannot begin with <http://> or <https://>.
|
cannot begin with `http://` or `https://`
|
||||||
|
|
||||||
- `oss_bucket_name` (string) - The name of the OSS bucket where the RAW or
|
- `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,
|
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_platform` (string) - platform such `CentOS`
|
||||||
|
|
||||||
- `image_architecture` (string) - Platform type of the image system:i386 \|
|
- `image_architecture` (string) - Platform type of the image system: `i386` or
|
||||||
x86\_64
|
`x86_64`
|
||||||
|
|
||||||
- `format` (string) - The format of the image for import, now alicloud only
|
- `format` (string) - The format of the image for import, now alicloud only
|
||||||
support RAW and VHD.
|
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
|
- `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
|
limit of 0 to 256 characters. Leaving it blank means null, which is the
|
||||||
default value. It cannot begin with <http://> or <https://>.
|
default value. It cannot begin with `http://` or `https://`.
|
||||||
|
|
||||||
- `image_force_delete` (boolean) - If this value is true, when the target
|
- `image_force_delete` (boolean) - If this value is true, when the target
|
||||||
image name is duplicated with an existing image, it will delete the
|
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
|
- `image_system_size` (number) - Size of the system disk, in GB, values
|
||||||
range:
|
range:
|
||||||
- cloud - 5 ~ 2000
|
- cloud - 5 \~ 2000
|
||||||
- cloud\_efficiency - 20 ~ 2048
|
- cloud\_efficiency - 20 \~ 2048
|
||||||
- cloud\_ssd - 20 ~ 2048
|
- cloud\_ssd - 20 \~ 2048
|
||||||
|
|
||||||
## Basic Example
|
## Basic Example
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ Type: `amazon-import`
|
||||||
The Packer Amazon Import post-processor takes an OVA artifact from various
|
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.
|
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
|
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
|
configuration model (eg, cloud-init for Linux systems). Please ensure you read
|
||||||
the [prerequisites for
|
the [prerequisites for
|
||||||
|
@ -85,12 +85,13 @@ Optional:
|
||||||
provider whose API is compatible with aws EC2. Specify another endpoint
|
provider whose API is compatible with aws EC2. Specify another endpoint
|
||||||
like this `https://ec2.custom.endpoint.com`.
|
like this `https://ec2.custom.endpoint.com`.
|
||||||
|
|
||||||
- `format` (string) - One of: `ova`, `raw`, `vhd`, `vhdx`, or `vmdk`. This specifies
|
- `format` (string) - One of: `ova`, `raw`, `vhd`, `vhdx`, or `vmdk`. This
|
||||||
the format of the source virtual machine image. The resulting artifact from the builder
|
specifies the format of the source virtual machine image. The resulting
|
||||||
is assumed to have a file extension matching the format. This defaults to `ova`.
|
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
|
- `insecure_skip_tls_verify` (boolean) - This allows skipping TLS
|
||||||
the AWS EC2 endpoint. The default is `false`.
|
verification of the AWS EC2 endpoint. The default is `false`.
|
||||||
|
|
||||||
- `license_type` (string) - The license type to be used for the Amazon
|
- `license_type` (string) - The license type to be used for the Amazon
|
||||||
Machine Image (AMI) after importing. Valid values: `AWS` or `BYOL`
|
Machine Image (AMI) after importing. Valid values: `AWS` or `BYOL`
|
||||||
|
|
|
@ -38,7 +38,6 @@ is optional.
|
||||||
commit. Example of instructions are `CMD`, `ENTRYPOINT`, `ENV`, and
|
commit. Example of instructions are `CMD`, `ENTRYPOINT`, `ENV`, and
|
||||||
`EXPOSE`. Example: `[ "USER ubuntu", "WORKDIR /app", "EXPOSE 8080" ]`
|
`EXPOSE`. Example: `[ "USER ubuntu", "WORKDIR /app", "EXPOSE 8080" ]`
|
||||||
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
An example is shown below, showing only the post-processor configuration:
|
An example is shown below, showing only the post-processor configuration:
|
||||||
|
@ -61,9 +60,9 @@ to a registry, if you want.
|
||||||
## Changing Metadata
|
## Changing Metadata
|
||||||
|
|
||||||
Below is an example using the changes argument of the post-processor. This
|
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
|
feature allows the tarball metadata to be changed when imported into the Docker
|
||||||
Docker environment. It is derived from the `docker import --change` command
|
environment. It is derived from the `docker import --change` command line
|
||||||
line [option to
|
[option to
|
||||||
Docker](https://docs.docker.com/engine/reference/commandline/import/).
|
Docker](https://docs.docker.com/engine/reference/commandline/import/).
|
||||||
|
|
||||||
Example uses of all of the options, assuming one is building an NGINX image
|
Example uses of all of the options, assuming one is building an NGINX image
|
||||||
|
|
|
@ -14,7 +14,7 @@ Type: `googlecompute-import`
|
||||||
The Google Compute Image Import post-processor takes a compressed raw disk
|
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.
|
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
|
[GCE import
|
||||||
documentation](https://cloud.google.com/compute/docs/images/import-existing-image)
|
documentation](https://cloud.google.com/compute/docs/images/import-existing-image)
|
||||||
before using this post-processor.
|
before using this post-processor.
|
||||||
|
|
|
@ -60,14 +60,13 @@ Optional parameters:
|
||||||
Packer injects some environmental variables by default into the
|
Packer injects some environmental variables by default into the
|
||||||
environment, as well, which are covered in the section below.
|
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
|
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
|
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
|
won't need to change this format, but you can see usage examples for where
|
||||||
it is necessary below.
|
it is necessary below.
|
||||||
|
|
||||||
|
|
||||||
- `execute_command` (array of strings) - The command used to execute the
|
- `execute_command` (array of strings) - The command used to execute the
|
||||||
script. By default this is `["/bin/sh", "-c", "{{.Vars}}", "{{.Script}}"]`
|
script. By default this is `["/bin/sh", "-c", "{{.Vars}}", "{{.Script}}"]`
|
||||||
on unix and `["cmd", "/c", "{{.Vars}}", "{{.Script}}"]` on windows. This is
|
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
|
For a shell script, that means the script **must** exit with a zero code. You
|
||||||
*must* be extra careful to `exit 0` when necessary.
|
*must* be extra careful to `exit 0` when necessary.
|
||||||
|
|
||||||
|
|
||||||
## Usage Examples:
|
## Usage Examples:
|
||||||
|
|
||||||
### Windows Host
|
### Windows Host
|
||||||
|
|
||||||
Example of running a .cmd file on windows:
|
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:
|
Example of running a powershell script on windows: Required customizations:
|
||||||
env\_var\_format and execute\_command
|
env\_var\_format and execute\_command
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"type": "shell-local",
|
"type": "shell-local",
|
||||||
"environment_vars": ["SHELLLOCALTEST=ShellTest4"],
|
"environment_vars": ["SHELLLOCALTEST=ShellTest4"],
|
||||||
|
@ -317,6 +315,7 @@ customizations: env\_var\_format, tempfile\_extension, and execute\_command
|
||||||
}
|
}
|
||||||
|
|
||||||
### Unix Host
|
### Unix Host
|
||||||
|
|
||||||
Example of running a bash script on unix:
|
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:
|
Example of running a python script on unix:
|
||||||
|
|
||||||
```
|
{
|
||||||
{
|
"type": "shell-local",
|
||||||
"type": "shell-local",
|
"script": "hello.py",
|
||||||
"script": "hello.py",
|
"environment_vars": ["HELLO_USER=packeruser"],
|
||||||
"environment_vars": ["HELLO_USER=packeruser"],
|
"execute_command": ["/bin/sh", "-c", "{{.Vars}} /usr/local/bin/python {{.Script}}"]
|
||||||
"execute_command": ["/bin/sh", "-c", "{{.Vars}} /usr/local/bin/python {{.Script}}"]
|
}
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Where "hello.py" contains:
|
Where "hello.py" contains:
|
||||||
|
|
||||||
```
|
import os
|
||||||
import os
|
|
||||||
|
|
||||||
print('Hello, %s!' % os.getenv("HELLO_USER"))
|
print('Hello, %s!' % os.getenv("HELLO_USER"))
|
||||||
```
|
|
||||||
|
|
|
@ -144,5 +144,5 @@ The following Docker input artifacts are supported:
|
||||||
|
|
||||||
### QEMU/libvirt
|
### QEMU/libvirt
|
||||||
|
|
||||||
The `libvirt` provider supports QEMU artifacts built using any these accelerators: none,
|
The `libvirt` provider supports QEMU artifacts built using any these
|
||||||
kvm, tcg, or hvf.
|
accelerators: none, kvm, tcg, or hvf.
|
||||||
|
|
|
@ -60,16 +60,16 @@ Optional:
|
||||||
|
|
||||||
- `insecure` (boolean) - If it's true skip verification of server
|
- `insecure` (boolean) - If it's true skip verification of server
|
||||||
certificate. Default is false
|
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
|
template. Default is false
|
||||||
|
|
||||||
- `snapshot_name` (string) - Name for the snapshot.
|
- `snapshot_name` (string) - Name for the snapshot. Required when
|
||||||
Required when `snapshot_enable` is `true`
|
`snapshot_enable` is `true`
|
||||||
|
|
||||||
- `snapshot_description` (string) - Description for the snapshot.
|
- `snapshot_description` (string) - Description for the snapshot. Required
|
||||||
Required when `snapshot_enable` is `true`
|
when `snapshot_enable` is `true`
|
||||||
|
|
||||||
## Using the vSphere Template with local builders
|
## Using the vSphere Template with local builders
|
||||||
|
|
||||||
Once the [vSphere](/docs/post-processors/vsphere.html) takes an artifact from
|
Once the [vSphere](/docs/post-processors/vsphere.html) takes an artifact from
|
||||||
|
|
|
@ -68,6 +68,7 @@ Optional:
|
||||||
example:
|
example:
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
"extra_arguments": [ "--extra-vars \"Region={{user `Region`}} Stage={{user `Stage`}}\"" ]
|
"extra_arguments": [ "--extra-vars \"Region={{user `Region`}} Stage={{user `Stage`}}\"" ]
|
||||||
|
|
||||||
- `inventory_groups` (string) - A comma-separated list of groups to which
|
- `inventory_groups` (string) - A comma-separated list of groups to which
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
---
|
---
|
||||||
description: |
|
description: |
|
||||||
The breakpoint provisioner will pause until the user presses "enter" to
|
The breakpoint provisioner will pause until the user presses "enter" to resume
|
||||||
resume the build. This is intended for debugging purposes, and allows you
|
the build. This is intended for debugging purposes, and allows you to halt at a
|
||||||
to halt at a particular part of the provisioning process.
|
particular part of the provisioning process.
|
||||||
layout: docs
|
layout: docs
|
||||||
page_title: 'breakpoint - Provisioners'
|
page_title: 'breakpoint - Provisioners'
|
||||||
sidebar_current: 'docs-provisioners-breakpoint'
|
sidebar_current: 'docs-provisioners-breakpoint'
|
||||||
|
@ -12,9 +12,9 @@ sidebar_current: 'docs-provisioners-breakpoint'
|
||||||
|
|
||||||
Type: `breakpoint`
|
Type: `breakpoint`
|
||||||
|
|
||||||
The breakpoint provisioner will pause until the user presses "enter" to
|
The breakpoint provisioner will pause until the user presses "enter" to resume
|
||||||
resume the build. This is intended for debugging purposes, and allows you
|
the build. This is intended for debugging purposes, and allows you to halt at a
|
||||||
to halt at a particular part of the provisioning process.
|
particular part of the provisioning process.
|
||||||
|
|
||||||
This is independent of the `-debug` flag, which will instead halt at every step
|
This is independent of the `-debug` flag, which will instead halt at every step
|
||||||
and between every provisioner.
|
and between every provisioner.
|
||||||
|
@ -33,8 +33,8 @@ and between every provisioner.
|
||||||
### Optional
|
### Optional
|
||||||
|
|
||||||
- `disable` (boolean) - If `true`, skip the breakpoint. Useful for when you
|
- `disable` (boolean) - If `true`, skip the breakpoint. Useful for when you
|
||||||
have set multiple breakpoints and want to toggle them off or on.
|
have set multiple breakpoints and want to toggle them off or on. Default:
|
||||||
Default: `false`
|
`false`
|
||||||
|
|
||||||
- `note` (string) - a string to include explaining the purpose or location of
|
- `note` (string) - a string to include explaining the purpose or location of
|
||||||
the breakpoint. For example, you may find it useful to number your
|
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:
|
For example:
|
||||||
|
|
||||||
```
|
==> docker: Pausing at breakpoint provisioner with note "foo bar baz".
|
||||||
==> docker: Pausing at breakpoint provisioner with note "foo bar baz".
|
==> docker: Press enter to continue.
|
||||||
==> docker: Press enter to continue.
|
|
||||||
```
|
|
||||||
|
|
||||||
Once you press enter, the build will resume and run normally until it either
|
Once you press enter, the build will resume and run normally until it either
|
||||||
completes or errors.
|
completes or errors.
|
||||||
|
|
|
@ -73,7 +73,8 @@ Optional parameters:
|
||||||
]
|
]
|
||||||
|
|
||||||
- `facter` (object of key:value strings) - Additional
|
- `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')
|
- `guest_os_type` (string) - The remote host's OS type ('windows' or 'unix')
|
||||||
to tailor command-line and path separators. (default: 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
|
This is useful if your main manifest uses imports, but the directory might
|
||||||
not contain the `manifest_file` itself.
|
not contain the `manifest_file` itself.
|
||||||
|
|
||||||
~> `manifest_dir` is passed to Puppet as `--manifestdir` option. This option
|
\~> `manifest_dir` is passed to Puppet as `--manifestdir` option. This
|
||||||
was deprecated in puppet 3.6, and removed in puppet 4.0. If you have multiple
|
option was deprecated in puppet 3.6, and removed in puppet 4.0. If you have
|
||||||
manifests you should use `manifest_file` instead.
|
multiple manifests you should use `manifest_file` instead.
|
||||||
|
|
||||||
- `module_paths` (array of strings) - Array of local module directories to be
|
- `module_paths` (array of strings) - Array of local module directories to be
|
||||||
uploaded.
|
uploaded.
|
||||||
|
|
|
@ -74,10 +74,10 @@ Optional parameters:
|
||||||
this as an environment variable. For example:
|
this as an environment variable. For example:
|
||||||
`"environment_vars": "WINRMPASS={{.WinRMPassword}}"`
|
`"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
|
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
|
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
|
won't need to change this format, but you can see usage examples for where
|
||||||
it is necessary below.
|
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:
|
## Usage Examples:
|
||||||
|
|
||||||
### Windows Host
|
### Windows Host
|
||||||
|
|
||||||
Example of running a .cmd file on windows:
|
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:
|
Example of running a powershell script on windows: Required customizations:
|
||||||
env\_var\_format and execute\_command
|
env\_var\_format and execute\_command
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"type": "shell-local",
|
"type": "shell-local",
|
||||||
"environment_vars": ["SHELLLOCALTEST=ShellTest4"],
|
"environment_vars": ["SHELLLOCALTEST=ShellTest4"],
|
||||||
|
@ -293,6 +293,7 @@ customizations: env\_var\_format, tempfile\_extension, and execute\_command
|
||||||
}
|
}
|
||||||
|
|
||||||
### Unix Host
|
### Unix Host
|
||||||
|
|
||||||
Example of running a bash script on unix:
|
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:
|
Example of running a python script on unix:
|
||||||
|
|
||||||
```
|
{
|
||||||
{
|
"type": "shell-local",
|
||||||
"type": "shell-local",
|
"script": "hello.py",
|
||||||
"script": "hello.py",
|
"environment_vars": ["HELLO_USER=packeruser"],
|
||||||
"environment_vars": ["HELLO_USER=packeruser"],
|
"execute_command": ["/bin/sh", "-c", "{{.Vars}} /usr/local/bin/python {{.Script}}"]
|
||||||
"execute_command": ["/bin/sh", "-c", "{{.Vars}} /usr/local/bin/python {{.Script}}"]
|
}
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Where "hello.py" contains:
|
Where "hello.py" contains:
|
||||||
|
|
||||||
```
|
import os
|
||||||
import os
|
|
||||||
|
|
||||||
print('Hello, %s!' % os.getenv("HELLO_USER"))
|
print('Hello, %s!' % os.getenv("HELLO_USER"))
|
||||||
```
|
|
||||||
|
|
|
@ -41,10 +41,10 @@ Optional parameters:
|
||||||
- `check_registry` (bool) - if `true`, checks for several registry keys that
|
- `check_registry` (bool) - if `true`, checks for several registry keys that
|
||||||
indicate that the system is going to reboot. This is useful if an
|
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
|
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
|
that reboot to complete before reconnecting. Please note that this option
|
||||||
a beta feature, and we generally recommend that you finish installs that
|
is a beta feature, and we generally recommend that you finish installs that
|
||||||
auto-reboot (like windows updates) during your autounattend phase before our
|
auto-reboot (like windows updates) during your autounattend phase before
|
||||||
winrm provisioner connects.
|
our winrm provisioner connects.
|
||||||
|
|
||||||
- `registry_keys` (array of strings) - if `check-registry` is `true`,
|
- `registry_keys` (array of strings) - if `check-registry` is `true`,
|
||||||
windows-restart will not reconnect until after all of the listed keys are
|
windows-restart will not reconnect until after all of the listed keys are
|
||||||
|
@ -52,13 +52,11 @@ Optional parameters:
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
```
|
var DefaultRegistryKeys = []string{
|
||||||
var DefaultRegistryKeys = []string{
|
"HKLM:SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootPending",
|
||||||
"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\\PackagesPending",
|
"HKLM:Software\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootInProgress",
|
||||||
"HKLM:Software\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootInProgress",
|
}
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- `restart_command` (string) - The command to execute to initiate the
|
- `restart_command` (string) - The command to execute to initiate the
|
||||||
restart. By default this is `shutdown /r /f /t 0 /c "packer restart"`.
|
restart. By default this is `shutdown /r /f /t 0 /c "packer restart"`.
|
||||||
|
|
|
@ -75,9 +75,9 @@ The SSH communicator has the following options:
|
||||||
- `ssh_bastion_port` (number) - The port of the bastion host. Defaults to
|
- `ssh_bastion_port` (number) - The port of the bastion host. Defaults to
|
||||||
`22`.
|
`22`.
|
||||||
|
|
||||||
- `ssh_bastion_private_key_file` (string) - Path to a PEM encoded private
|
- `ssh_bastion_private_key_file` (string) - Path to a PEM encoded private key
|
||||||
key file to use to authenticate with the bastion host. The `~` can be used
|
file to use to authenticate with the bastion host. The `~` can be used in
|
||||||
in path and will be expanded to the home directory of current user.
|
path and will be expanded to the home directory of current user.
|
||||||
|
|
||||||
- `ssh_bastion_username` (string) - The username to connect to the bastion
|
- `ssh_bastion_username` (string) - The username to connect to the bastion
|
||||||
host.
|
host.
|
||||||
|
@ -155,23 +155,25 @@ Packer supports the following ciphers:
|
||||||
- arcfour128
|
- arcfour128
|
||||||
- arcfour256
|
- arcfour256
|
||||||
- arcfour
|
- arcfour
|
||||||
- <es128-gcm@openssh.com>
|
- `es128-gcm@openssh.com`
|
||||||
- <acha20-poly1305@openssh.com>
|
- `acha20-poly1305@openssh.com`
|
||||||
|
|
||||||
And the following MACs:
|
And the following MACs:
|
||||||
|
|
||||||
- hmac-sha1
|
- hmac-sha1
|
||||||
- hmac-sha1-96
|
- hmac-sha1-96
|
||||||
- hmac-sha2-256
|
- hmac-sha2-256
|
||||||
- <hmac-sha2-256-etm@openssh.com>
|
- `hmac-sha2-256-etm@openssh.com`
|
||||||
|
|
||||||
## WinRM Communicator
|
## WinRM Communicator
|
||||||
|
|
||||||
The WinRM communicator has the following options.
|
The WinRM communicator has the following options.
|
||||||
|
|
||||||
- `winrm_host` (string) - The address for WinRM to connect to.
|
- `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
|
- `winrm_insecure` (boolean) - If `true`, do not check server certificate
|
||||||
chain and host name.
|
chain and host name.
|
||||||
|
|
|
@ -44,7 +44,8 @@ Here is a full list of the available functions for reference.
|
||||||
reference](/docs/templates/engine.html#isotime-function-format-reference).
|
reference](/docs/templates/engine.html#isotime-function-format-reference).
|
||||||
- `lower` - Lowercases the string.
|
- `lower` - Lowercases the string.
|
||||||
- `pwd` - The working directory while executing Packer.
|
- `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
|
- `split` - Split an input string using separator and return the requested
|
||||||
substring.
|
substring.
|
||||||
- `template_dir` - The directory to the template for the build.
|
- `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
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
*The values in parentheses are the abbreviated, or 24-hour clock values*
|
*The values in parentheses are the abbreviated, or 24-hour clock values*
|
||||||
|
|
||||||
Note that "-0700" is always formatted into "+0000" because `isotime` is always
|
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
|
The function `split` takes an input string, a seperator string, and a numeric
|
||||||
component value and returns the requested substring.
|
component value and returns the requested substring.
|
||||||
|
|
||||||
Please note that you cannot use the `split` function on user variables,
|
Please note that you cannot use the `split` function on user variables, because
|
||||||
because we can't nest the functions currently. This function is indended to
|
we can't nest the functions currently. This function is indended to be used on
|
||||||
be used on builder variables like build_name. If you need a split user
|
builder variables like build\_name. If you need a split user variable, the best
|
||||||
variable, the best way to do it is to create a separate variable.
|
way to do it is to create a separate variable.
|
||||||
|
|
||||||
Here are some examples using the above options:
|
Here are some examples using the above options:
|
||||||
|
|
||||||
|
@ -310,16 +312,15 @@ this case, on the `fixed-string` value):
|
||||||
|
|
||||||
# sed Function Format Reference
|
# sed Function Format Reference
|
||||||
|
|
||||||
See the library documentation https://github.com/rwtodd/Go.Sed for notes about
|
See the library documentation
|
||||||
the difference between this golang implementation of sed and the regexes you may
|
<a href="https://github.com/rwtodd/Go.Sed" class="uri">https://github.com/rwtodd/Go.Sed</a>
|
||||||
be used to. A very simple example of this functionality:
|
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": [
|
||||||
"provisioners": [
|
{
|
||||||
{
|
"type": "shell-local",
|
||||||
"type": "shell-local",
|
"environment_vars": ["EXAMPLE={{ sed \"s/null/awesome/\" build_type}}"],
|
||||||
"environment_vars": ["EXAMPLE={{ sed \"s/null/awesome/\" build_type}}"],
|
"inline": ["echo build_type is $EXAMPLE\n"]
|
||||||
"inline": ["echo build_type is $EXAMPLE\n"]
|
}
|
||||||
}
|
]
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
Loading…
Reference in New Issue