Compare commits

..

1 Commits

Author SHA1 Message Date
Mitchell Hashimoto 2d1cc53d45 v0.1.2 2013-06-29 14:03:15 -07:00
37 changed files with 141 additions and 383 deletions
-1
View File
@@ -1,6 +1,5 @@
/bin
/local
/pkg
/src
/website/.sass-cache
/website/build
-22
View File
@@ -1,25 +1,3 @@
## 0.1.3 (July 1, 2013)
FEATURES:
* The VMware builder can now upload the VMware tools for you into
the VM. This is opt-in, you must specify the `tools_upload_flavor`
option. See the website for more documentation.
IMPROVEMENTS:
* digitalocean: Errors contain human-friendly error messages. [GH-85]
BUG FIXES:
* core: More plugin server fixes that avoid hangs on OS X 10.7 [GH-87]
* vagrant: AWS boxes will keep the AMI artifact around [GH-55]
* virtualbox: More robust version parsing for uploading guest additions. [GH-69]
* virtualbox: Output dir and VM name defaults depend on build name,
avoiding collisions. [GH-91]
* vmware: Output dir and VM name defaults depend on build name,
avoiding collisions. [GH-91]
## 0.1.2 (June 29, 2013)
IMPROVEMENTS:
+4 -4
View File
@@ -1,7 +1,7 @@
NO_COLOR=\033[0m
OK_COLOR=\033[32;01m
ERROR_COLOR=\033[31;01m
WARN_COLOR=\033[33;01m
NO_COLOR=\x1b[0m
OK_COLOR=\x1b[32;01m
ERROR_COLOR=\x1b[31;01m
WARN_COLOR=\x1b[33;01m
all:
@mkdir -p bin/
+4 -11
View File
@@ -11,7 +11,7 @@ Packer is lightweight, runs on every major operating system, and is highly
performant, creating machine images for multiple platforms in parallel.
Packer comes out of the box with support for creating AMIs (EC2), VMware
images, and VirtualBox images. Support for more platforms can be added via
plugins.
plugins.
The images that Packer creates can easily be turned into
[Vagrant](http://www.vagrantup.com) boxes.
@@ -70,15 +70,8 @@ http://www.packer.io/docs
## Developing Packer
If you wish to work on Packer itself, you'll first need [Go](http://golang.org)
installed (version 1.1+ is _required_). Make sure you have Go properly installed,
including setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH).
For some additional dependencies, Go needs [Mercurial](http://mercurial.selenic.com/)
to be installed. Packer itself doesn't require this but a dependency of a
dependency does.
Next, clone this repository then just type `make`. In a few moments,
you'll have a working `packer` executable:
installed (version 1.1+ is _required_). Next, clone this repository then just type `make`.
In a few moments, you'll have a working `packer` executable:
```
$ make
@@ -87,6 +80,6 @@ $ bin/packer
...
```
You can run tests by typing `make test`.
You can run tests by typing `make test`.
This will run tests for Packer core along with all the core builders and commands and such that come with Packer.
+11 -8
View File
@@ -189,25 +189,28 @@ func NewRequest(d DigitalOceanClient, path string, params string) (map[string]in
return decodedResponse, err
}
log.Printf("response from digitalocean: %s", body)
err = json.Unmarshal(body, &decodedResponse)
// Check for bad JSON
if err != nil {
err = errors.New(fmt.Sprintf("Failed to decode JSON response (HTTP %v) from DigitalOcean: %s",
resp.StatusCode, body))
log.Printf("response from digitalocean: %v", decodedResponse)
// Catch all non-200 status and return an error
if resp.StatusCode != 200 {
err = errors.New(fmt.Sprintf("Received non-200 HTTP status from DigitalOcean: %v", resp.StatusCode))
return decodedResponse, err
}
// Check for errors sent by digitalocean
if err != nil {
return decodedResponse, err
}
// Catch all non-OK statuses from DO and return an error
status := decodedResponse["status"]
if status != "OK" {
// Get the actual error message if there is one
if status == "ERROR" {
status = decodedResponse["error_message"]
}
err = errors.New(fmt.Sprintf("Received bad response (HTTP %v) from DigitalOcean: %s", resp.StatusCode, status))
err = errors.New(fmt.Sprintf("Received bad status from DigitalOcean: %v", status))
return decodedResponse, err
}
+3 -4
View File
@@ -48,8 +48,7 @@ type config struct {
VBoxManage [][]string `mapstructure:"vboxmanage"`
VMName string `mapstructure:"vm_name"`
PackerBuildName string `mapstructure:"packer_build_name"`
PackerDebug bool `mapstructure:"packer_debug"`
PackerDebug bool `mapstructure:"packer_debug"`
RawBootWait string `mapstructure:"boot_wait"`
RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
@@ -87,7 +86,7 @@ func (b *Builder) Prepare(raws ...interface{}) error {
}
if b.config.OutputDir == "" {
b.config.OutputDir = fmt.Sprintf("output-%s", b.config.PackerBuildName)
b.config.OutputDir = "virtualbox"
}
if b.config.RawBootWait == "" {
@@ -115,7 +114,7 @@ func (b *Builder) Prepare(raws ...interface{}) error {
}
if b.config.VMName == "" {
b.config.VMName = fmt.Sprintf("packer-%s", b.config.PackerBuildName)
b.config.VMName = "packer"
}
errs := make([]error, 0)
+2 -4
View File
@@ -13,8 +13,6 @@ func testConfig() map[string]interface{} {
"iso_md5": "foo",
"iso_url": "http://www.google.com/",
"ssh_username": "foo",
packer.BuildNameConfigKey: "foo",
}
}
@@ -38,7 +36,7 @@ func TestBuilderPrepare_Defaults(t *testing.T) {
t.Errorf("bad guest OS type: %s", b.config.GuestOSType)
}
if b.config.OutputDir != "output-foo" {
if b.config.OutputDir != "virtualbox" {
t.Errorf("bad output dir: %s", b.config.OutputDir)
}
@@ -54,7 +52,7 @@ func TestBuilderPrepare_Defaults(t *testing.T) {
t.Errorf("bad ssh port: %d", b.config.SSHPort)
}
if b.config.VMName != "packer-foo" {
if b.config.VMName != "packer" {
t.Errorf("bad vm name: %s", b.config.VMName)
}
}
+3 -4
View File
@@ -124,12 +124,11 @@ func (d *VBox42Driver) Version() (string, error) {
return "", err
}
versionOutput := strings.TrimSpace(stdout.String())
log.Printf("VBoxManage --version output: %s", versionOutput)
log.Printf("VBoxManage --version output: %s", stdout.String())
versionRe := regexp.MustCompile("[^.0-9]")
matches := versionRe.Split(versionOutput, 2)
matches := versionRe.Split(stdout.String(), 2)
if len(matches) == 0 {
return "", fmt.Errorf("No version found: %s", versionOutput)
return "", fmt.Errorf("No version found: %s", stdout.String())
}
log.Printf("VirtualBox version: %s", matches[0])
+24 -38
View File
@@ -13,7 +13,6 @@ import (
"os"
"path/filepath"
"strings"
"text/template"
"time"
)
@@ -26,32 +25,29 @@ type Builder struct {
}
type config struct {
DiskName string `mapstructure:"vmdk_name"`
DiskSize uint `mapstructure:"disk_size"`
GuestOSType string `mapstructure:"guest_os_type"`
ISOMD5 string `mapstructure:"iso_md5"`
ISOUrl string `mapstructure:"iso_url"`
VMName string `mapstructure:"vm_name"`
OutputDir string `mapstructure:"output_directory"`
HTTPDir string `mapstructure:"http_directory"`
HTTPPortMin uint `mapstructure:"http_port_min"`
HTTPPortMax uint `mapstructure:"http_port_max"`
BootCommand []string `mapstructure:"boot_command"`
BootWait time.Duration ``
ShutdownCommand string `mapstructure:"shutdown_command"`
ShutdownTimeout time.Duration ``
SSHUser string `mapstructure:"ssh_username"`
SSHPassword string `mapstructure:"ssh_password"`
SSHPort uint `mapstructure:"ssh_port"`
SSHWaitTimeout time.Duration ``
ToolsUploadFlavor string `mapstructure:"tools_upload_flavor"`
ToolsUploadPath string `mapstructure:"tools_upload_path"`
VMXData map[string]string `mapstructure:"vmx_data"`
VNCPortMin uint `mapstructure:"vnc_port_min"`
VNCPortMax uint `mapstructure:"vnc_port_max"`
DiskName string `mapstructure:"vmdk_name"`
DiskSize uint `mapstructure:"disk_size"`
GuestOSType string `mapstructure:"guest_os_type"`
ISOMD5 string `mapstructure:"iso_md5"`
ISOUrl string `mapstructure:"iso_url"`
VMName string `mapstructure:"vm_name"`
OutputDir string `mapstructure:"output_directory"`
HTTPDir string `mapstructure:"http_directory"`
HTTPPortMin uint `mapstructure:"http_port_min"`
HTTPPortMax uint `mapstructure:"http_port_max"`
BootCommand []string `mapstructure:"boot_command"`
BootWait time.Duration ``
ShutdownCommand string `mapstructure:"shutdown_command"`
ShutdownTimeout time.Duration ``
SSHUser string `mapstructure:"ssh_username"`
SSHPassword string `mapstructure:"ssh_password"`
SSHPort uint `mapstructure:"ssh_port"`
SSHWaitTimeout time.Duration ``
VMXData map[string]string `mapstructure:"vmx_data"`
VNCPortMin uint `mapstructure:"vnc_port_min"`
VNCPortMax uint `mapstructure:"vnc_port_max"`
PackerBuildName string `mapstructure:"packer_build_name"`
PackerDebug bool `mapstructure:"packer_debug"`
PackerDebug bool `mapstructure:"packer_debug"`
RawBootWait string `mapstructure:"boot_wait"`
RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
@@ -79,7 +75,7 @@ func (b *Builder) Prepare(raws ...interface{}) error {
}
if b.config.VMName == "" {
b.config.VMName = fmt.Sprintf("packer-%s", b.config.PackerBuildName)
b.config.VMName = "packer"
}
if b.config.HTTPPortMin == 0 {
@@ -103,17 +99,13 @@ func (b *Builder) Prepare(raws ...interface{}) error {
}
if b.config.OutputDir == "" {
b.config.OutputDir = fmt.Sprintf("output-%s", b.config.PackerBuildName)
b.config.OutputDir = "vmware"
}
if b.config.SSHPort == 0 {
b.config.SSHPort = 22
}
if b.config.ToolsUploadPath == "" {
b.config.ToolsUploadPath = "{{ .Flavor }}.iso"
}
// Accumulate any errors
var err error
errs := make([]error, 0)
@@ -200,10 +192,6 @@ func (b *Builder) Prepare(raws ...interface{}) error {
errs = append(errs, fmt.Errorf("Failed parsing ssh_wait_timeout: %s", err))
}
if _, err := template.New("path").Parse(b.config.ToolsUploadPath); err != nil {
errs = append(errs, fmt.Errorf("tools_upload_path invalid: %s", err))
}
if b.config.VNCPortMin > b.config.VNCPortMax {
errs = append(errs, fmt.Errorf("vnc_port_min must be less than vnc_port_max"))
}
@@ -225,7 +213,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
rand.Seed(time.Now().UTC().UnixNano())
steps := []multistep.Step{
&stepPrepareTools{},
&stepDownloadISO{},
&stepPrepareOutputDir{},
&stepCreateDisk{},
@@ -235,7 +222,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
&stepRun{},
&stepTypeBootCommand{},
&stepWaitForSSH{},
&stepUploadTools{},
&stepProvision{},
&stepShutdown{},
&stepCleanFiles{},
+2 -34
View File
@@ -13,8 +13,6 @@ func testConfig() map[string]interface{} {
"iso_md5": "foo",
"iso_url": "http://www.packer.io",
"ssh_username": "foo",
packer.BuildNameConfigKey: "foo",
}
}
@@ -68,7 +66,7 @@ func TestBuilderPrepare_Defaults(t *testing.T) {
t.Errorf("bad disk name: %s", b.config.DiskName)
}
if b.config.OutputDir != "output-foo" {
if b.config.OutputDir != "vmware" {
t.Errorf("bad output dir: %s", b.config.OutputDir)
}
@@ -76,7 +74,7 @@ func TestBuilderPrepare_Defaults(t *testing.T) {
t.Errorf("bad wait timeout: %s", b.config.SSHWaitTimeout)
}
if b.config.VMName != "packer-foo" {
if b.config.VMName != "packer" {
t.Errorf("bad vm name: %s", b.config.VMName)
}
}
@@ -311,36 +309,6 @@ func TestBuilderPrepare_SSHWaitTimeout(t *testing.T) {
}
}
func TestBuilderPrepare_ToolsUploadPath(t *testing.T) {
var b Builder
config := testConfig()
// Test a default
delete(config, "tools_upload_path")
err := b.Prepare(config)
if err != nil {
t.Fatalf("err: %s", err)
}
if b.config.ToolsUploadPath == "" {
t.Fatalf("bad value: %s", b.config.ToolsUploadPath)
}
// Test with a bad value
config["tools_upload_path"] = "{{{nope}"
err = b.Prepare(config)
if err == nil {
t.Fatal("should have error")
}
// Test with a good one
config["tools_upload_path"] = "hey"
err = b.Prepare(config)
if err != nil {
t.Fatalf("should not have error: %s", err)
}
}
func TestBuilderPrepare_VNCPort(t *testing.T) {
var b Builder
config := testConfig()
-7
View File
@@ -24,9 +24,6 @@ type Driver interface {
// Stop stops a VM specified by the path to the VMX given.
Stop(string) error
// Get the path to the VMware ISO for the given flavor.
ToolsIsoPath(string) string
// Verify checks to make sure that this driver should function
// properly. This should check that all the files it will use
// appear to exist and so on. If everything is okay, this doesn't
@@ -124,10 +121,6 @@ func (d *Fusion5Driver) vmrunPath() string {
return filepath.Join(d.AppPath, "Contents", "Library", "vmrun")
}
func (d *Fusion5Driver) ToolsIsoPath(k string) string {
return filepath.Join(d.AppPath, "Contents", "Library", "isoimages", k+".iso")
}
func (d *Fusion5Driver) runAndLog(cmd *exec.Cmd) (string, string, error) {
var stdout, stderr bytes.Buffer
-33
View File
@@ -1,33 +0,0 @@
package vmware
import (
"fmt"
"github.com/mitchellh/multistep"
"os"
)
type stepPrepareTools struct{}
func (*stepPrepareTools) Run(state map[string]interface{}) multistep.StepAction {
config := state["config"].(*config)
driver := state["driver"].(Driver)
if config.ToolsUploadFlavor == "" {
return multistep.ActionContinue
}
path := driver.ToolsIsoPath(config.ToolsUploadFlavor)
if _, err := os.Stat(path); err != nil {
state["error"] = fmt.Errorf(
"Couldn't find VMware tools for '%s'! VMware often downloads these\n"+
"tools on-demand. However, to do this, you need to create a fake VM\n"+
"of the proper type then click the 'install tools' option in the\n"+
"VMware GUI.", config.ToolsUploadFlavor)
return multistep.ActionHalt
}
state["tools_upload_source"] = path
return multistep.ActionContinue
}
func (*stepPrepareTools) Cleanup(map[string]interface{}) {}
-49
View File
@@ -1,49 +0,0 @@
package vmware
import (
"bytes"
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"os"
"text/template"
)
type toolsUploadPathTemplate struct {
Flavor string
}
type stepUploadTools struct{}
func (*stepUploadTools) Run(state map[string]interface{}) multistep.StepAction {
config := state["config"].(*config)
if config.ToolsUploadFlavor == "" {
return multistep.ActionContinue
}
comm := state["communicator"].(packer.Communicator)
tools_source := state["tools_upload_source"].(string)
ui := state["ui"].(packer.Ui)
ui.Say(fmt.Sprintf("Uploading the '%s' VMware Tools", config.ToolsUploadFlavor))
f, err := os.Open(tools_source)
if err != nil {
state["error"] = fmt.Errorf("Error opening VMware Tools ISO: %s", err)
return multistep.ActionHalt
}
defer f.Close()
tplData := &toolsUploadPathTemplate{Flavor: config.ToolsUploadFlavor}
var processedPath bytes.Buffer
t := template.Must(template.New("path").Parse(config.ToolsUploadPath))
t.Execute(&processedPath, tplData)
if err := comm.Upload(processedPath.String(), f); err != nil {
state["error"] = fmt.Errorf("Error uploading VMware Tools: %s", err)
return multistep.ActionHalt
}
return multistep.ActionContinue
}
func (*stepUploadTools) Cleanup(map[string]interface{}) {}
-3
View File
@@ -27,9 +27,6 @@ func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
}
log.Printf("Packer Version: %s %s", packer.Version, packer.VersionPrerelease)
log.Printf("Packer Target OS/Arch: %s %s", runtime.GOOS, runtime.GOARCH)
config, err := loadConfig()
if err != nil {
fmt.Fprintf(os.Stderr, "Error loading configuration: \n\n%s\n", err)
+7 -13
View File
@@ -6,10 +6,6 @@ import (
"sync"
)
// This is the key in configurations that is set to the name of the
// build.
const BuildNameConfigKey = "packer_build_name"
// This is the key in configurations that is set to "true" when Packer
// debugging is enabled.
const DebugConfigKey = "packer_debug"
@@ -95,13 +91,12 @@ func (b *coreBuild) Prepare() (err error) {
b.prepareCalled = true
packerConfig := map[string]interface{}{
BuildNameConfigKey: b.name,
DebugConfigKey: b.debug,
debugConfig := map[string]interface{}{
DebugConfigKey: b.debug,
}
// Prepare the builder
err = b.builder.Prepare(b.builderConfig, packerConfig)
err = b.builder.Prepare(b.builderConfig, debugConfig)
if err != nil {
log.Printf("Build '%s' prepare failure: %s\n", b.name, err)
return
@@ -111,7 +106,7 @@ func (b *coreBuild) Prepare() (err error) {
for _, coreProv := range b.provisioners {
configs := make([]interface{}, len(coreProv.config), len(coreProv.config)+1)
copy(configs, coreProv.config)
configs = append(configs, packerConfig)
configs = append(configs, debugConfig)
if err = coreProv.provisioner.Prepare(configs...); err != nil {
return
@@ -194,7 +189,7 @@ PostProcessorRunSeqLoop:
}
builderUi.Say(fmt.Sprintf("Running post-processor: %s", corePP.processorType))
artifact, keep, err := corePP.processor.PostProcess(ppUi, priorArtifact)
artifact, err := corePP.processor.PostProcess(ppUi, priorArtifact)
if err != nil {
errors = append(errors, fmt.Errorf("Post-processor failed: %s", err))
continue PostProcessorRunSeqLoop
@@ -205,12 +200,11 @@ PostProcessorRunSeqLoop:
continue PostProcessorRunSeqLoop
}
keep = keep || corePP.keepInputArtifact
if i == 0 {
// This is the first post-processor. We handle deleting
// previous artifacts a bit different because multiple
// post-processors may be using the original and need it.
if !keepOriginalArtifact && keep {
if !keepOriginalArtifact && corePP.keepInputArtifact {
log.Printf(
"Flagging to keep original artifact from post-processor '%s'",
corePP.processorType)
@@ -219,7 +213,7 @@ PostProcessorRunSeqLoop:
} else {
// We have a prior artifact. If we want to keep it, we append
// it to the results list. Otherwise, we destroy it.
if keep {
if corePP.keepInputArtifact {
artifacts = append(artifacts, priorArtifact)
} else {
log.Printf("Deleting prior artifact from post-processor '%s'", corePP.processorType)
+6 -39
View File
@@ -39,22 +39,19 @@ func TestBuild_Name(t *testing.T) {
func TestBuild_Prepare(t *testing.T) {
assert := asserts.NewTestingAsserts(t, true)
packerConfig := map[string]interface{}{
BuildNameConfigKey: "test",
DebugConfigKey: false,
}
debugFalseConfig := map[string]interface{}{DebugConfigKey: false}
build := testBuild()
builder := build.builder.(*TestBuilder)
build.Prepare()
assert.True(builder.prepareCalled, "prepare should be called")
assert.Equal(builder.prepareConfig, []interface{}{42, packerConfig}, "prepare config should be 42")
assert.Equal(builder.prepareConfig, []interface{}{42, debugFalseConfig}, "prepare config should be 42")
coreProv := build.provisioners[0]
prov := coreProv.provisioner.(*TestProvisioner)
assert.True(prov.prepCalled, "prepare should be called")
assert.Equal(prov.prepConfigs, []interface{}{42, packerConfig}, "prepare should be called with proper config")
assert.Equal(prov.prepConfigs, []interface{}{42, debugFalseConfig}, "prepare should be called with proper config")
corePP := build.postProcessors[0][0]
pp := corePP.processor.(*TestPostProcessor)
@@ -85,10 +82,7 @@ func TestBuild_Prepare_Twice(t *testing.T) {
func TestBuild_Prepare_Debug(t *testing.T) {
assert := asserts.NewTestingAsserts(t, true)
packerConfig := map[string]interface{}{
BuildNameConfigKey: "test",
DebugConfigKey: true,
}
debugConfig := map[string]interface{}{DebugConfigKey: true}
build := testBuild()
builder := build.builder.(*TestBuilder)
@@ -96,12 +90,12 @@ func TestBuild_Prepare_Debug(t *testing.T) {
build.SetDebug(true)
build.Prepare()
assert.True(builder.prepareCalled, "prepare should be called")
assert.Equal(builder.prepareConfig, []interface{}{42, packerConfig}, "prepare config should be 42")
assert.Equal(builder.prepareConfig, []interface{}{42, debugConfig}, "prepare config should be 42")
coreProv := build.provisioners[0]
prov := coreProv.provisioner.(*TestProvisioner)
assert.True(prov.prepCalled, "prepare should be called")
assert.Equal(prov.prepConfigs, []interface{}{42, packerConfig}, "prepare should be called with proper config")
assert.Equal(prov.prepConfigs, []interface{}{42, debugConfig}, "prepare should be called with proper config")
}
func TestBuild_Run(t *testing.T) {
@@ -245,33 +239,6 @@ func TestBuild_Run_Artifacts(t *testing.T) {
if !reflect.DeepEqual(artifactIds, expectedIds) {
t.Fatalf("unexpected ids: %#v", artifactIds)
}
// Test case: Test that with a single post-processor that forcibly
// keeps inputs, that the artifacts are kept.
build = testBuild()
build.postProcessors = [][]coreBuildPostProcessor{
[]coreBuildPostProcessor{
coreBuildPostProcessor{
&TestPostProcessor{artifactId: "pp", keep: true}, "pp", 42, false,
},
},
}
build.Prepare()
artifacts, err = build.Run(ui, cache)
if err != nil {
t.Fatalf("err: %s", err)
}
expectedIds = []string{"b", "pp"}
artifactIds = make([]string, len(artifacts))
for i, artifact := range artifacts {
artifactIds[i] = artifact.Id()
}
if !reflect.DeepEqual(artifactIds, expectedIds) {
t.Fatalf("unexpected ids: %#v", artifactIds)
}
}
func TestBuild_RunBeforePrepare(t *testing.T) {
+1 -1
View File
@@ -252,7 +252,7 @@ func (c *Client) Start() (address string, err error) {
timeout := time.After(c.config.StartTimeout)
// Start looking for the address
log.Printf("Waiting for RPC address for: %s", cmd.Path)
log.Println("Waiting for RPC address for: %s", cmd.Path)
for done := false; !done; {
select {
case <-timeout:
+1 -1
View File
@@ -19,7 +19,7 @@ func (c *cmdPostProcessor) Configure(config interface{}) error {
return c.p.Configure(config)
}
func (c *cmdPostProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Artifact, bool, error) {
func (c *cmdPostProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Artifact, error) {
defer func() {
r := recover()
c.checkExit(r, nil)
+2 -2
View File
@@ -12,8 +12,8 @@ func (helperPostProcessor) Configure(interface{}) error {
return nil
}
func (helperPostProcessor) PostProcess(packer.Ui, packer.Artifact) (packer.Artifact, bool, error) {
return nil, false, nil
func (helperPostProcessor) PostProcess(packer.Ui, packer.Artifact) (packer.Artifact, error) {
return nil, nil
}
func TestPostProcessor_NoExist(t *testing.T) {
+2 -3
View File
@@ -12,7 +12,6 @@ type PostProcessor interface {
Configure(interface{}) error
// PostProcess takes a previously created Artifact and produces another
// Artifact. If an error occurs, it should return that error. If `keep`
// is to true, then the previous artifact is forcibly kept.
PostProcess(Ui, Artifact) (a Artifact, keep bool, err error)
// Artifact. If an error occurs, it should return that error.
PostProcess(Ui, Artifact) (Artifact, error)
}
+2 -3
View File
@@ -2,7 +2,6 @@ package packer
type TestPostProcessor struct {
artifactId string
keep bool
configCalled bool
configVal interface{}
ppCalled bool
@@ -16,9 +15,9 @@ func (pp *TestPostProcessor) Configure(v interface{}) error {
return nil
}
func (pp *TestPostProcessor) PostProcess(ui Ui, a Artifact) (Artifact, bool, error) {
func (pp *TestPostProcessor) PostProcess(ui Ui, a Artifact) (Artifact, error) {
pp.ppCalled = true
pp.ppArtifact = a
pp.ppUi = ui
return &TestArtifact{id: pp.artifactId}, pp.keep, nil
return &TestArtifact{id: pp.artifactId}, nil
}
+1 -1
View File
@@ -20,7 +20,7 @@ func PortRange(min, max int) {
// bound to that port.
func netListenerInRange(min, max int) net.Listener {
for port := min; port <= max; port++ {
l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
l, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err == nil {
return l
}
+1 -1
View File
@@ -16,7 +16,7 @@ func Test_netListenerInRange(t *testing.T) {
assert := asserts.NewTestingAsserts(t, true)
// Open up port 10000 so that we take up a port
L1000, err := net.Listen("tcp", "127.0.0.1:11000")
L1000, err := net.Listen("tcp", ":11000")
defer L1000.Close()
assert.Nil(err, "should be able to bind to port 10000")
+7 -9
View File
@@ -19,7 +19,6 @@ type PostProcessorServer struct {
type PostProcessorProcessResponse struct {
Err error
Keep bool
RPCAddress string
}
@@ -34,30 +33,30 @@ func (p *postProcessor) Configure(raw interface{}) (err error) {
return
}
func (p *postProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Artifact, bool, error) {
func (p *postProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Artifact, error) {
server := rpc.NewServer()
RegisterArtifact(server, a)
RegisterUi(server, ui)
var response PostProcessorProcessResponse
if err := p.client.Call("PostProcessor.PostProcess", serveSingleConn(server), &response); err != nil {
return nil, false, err
return nil, err
}
if response.Err != nil {
return nil, false, response.Err
return nil, response.Err
}
if response.RPCAddress == "" {
return nil, false, nil
return nil, nil
}
client, err := rpc.Dial("tcp", response.RPCAddress)
if err != nil {
return nil, false, err
return nil, err
}
return Artifact(client), response.Keep, nil
return Artifact(client), nil
}
func (p *PostProcessorServer) Configure(raw *interface{}, reply *error) error {
@@ -77,7 +76,7 @@ func (p *PostProcessorServer) PostProcess(address string, reply *PostProcessorPr
responseAddress := ""
artifact, keep, err := p.p.PostProcess(&Ui{client}, Artifact(client))
artifact, err := p.p.PostProcess(&Ui{client}, Artifact(client))
if err == nil && artifact != nil {
server := rpc.NewServer()
RegisterArtifact(server, artifact)
@@ -90,7 +89,6 @@ func (p *PostProcessorServer) PostProcess(address string, reply *PostProcessorPr
*reply = PostProcessorProcessResponse{
Err: err,
Keep: keep,
RPCAddress: responseAddress,
}
+3 -3
View File
@@ -22,11 +22,11 @@ func (pp *TestPostProcessor) Configure(v interface{}) error {
return nil
}
func (pp *TestPostProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Artifact, bool, error) {
func (pp *TestPostProcessor) PostProcess(ui packer.Ui, a packer.Artifact) (packer.Artifact, error) {
pp.ppCalled = true
pp.ppArtifact = a
pp.ppUi = ui
return testPostProcessorArtifact, false, nil
return testPostProcessorArtifact, nil
}
func TestPostProcessorRPC(t *testing.T) {
@@ -63,7 +63,7 @@ func TestPostProcessorRPC(t *testing.T) {
// Test PostProcess
a := new(testArtifact)
ui := new(testUi)
artifact, _, err := pClient.PostProcess(ui, a)
artifact, err := pClient.PostProcess(ui, a)
if err != nil {
t.Fatalf("err: %s", err)
}
+10 -10
View File
@@ -33,7 +33,7 @@ func (p *AWSBoxPostProcessor) Configure(raw interface{}) error {
return nil
}
func (p *AWSBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
func (p *AWSBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, error) {
// Determine the regions...
tplData := &AWSVagrantfileTemplate{
Images: make(map[string]string),
@@ -42,7 +42,7 @@ func (p *AWSBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact
for _, regions := range strings.Split(artifact.Id(), ",") {
parts := strings.Split(regions, ":")
if len(parts) != 2 {
return nil, false, fmt.Errorf("Poorly formatted artifact ID: %s", artifact.Id())
return nil, fmt.Errorf("Poorly formatted artifact ID: %s", artifact.Id())
}
tplData.Images[parts[0]] = parts[1]
@@ -51,20 +51,20 @@ func (p *AWSBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact
// Compile the output path
outputPath, err := ProcessOutputPath(p.config.OutputPath, "aws", artifact)
if err != nil {
return nil, false, err
return nil, err
}
// Create a temporary directory for us to build the contents of the box in
dir, err := ioutil.TempDir("", "packer")
if err != nil {
return nil, false, err
return nil, err
}
defer os.RemoveAll(dir)
// Create the Vagrantfile from the template
vf, err := os.Create(filepath.Join(dir, "Vagrantfile"))
if err != nil {
return nil, false, err
return nil, err
}
defer vf.Close()
@@ -72,13 +72,13 @@ func (p *AWSBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact
if p.config.VagrantfileTemplate != "" {
f, err := os.Open(p.config.VagrantfileTemplate)
if err != nil {
return nil, false, err
return nil, err
}
defer f.Close()
contents, err := ioutil.ReadAll(f)
if err != nil {
return nil, false, err
return nil, err
}
vagrantfileContents = string(contents)
@@ -91,15 +91,15 @@ func (p *AWSBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact
// Create the metadata
metadata := map[string]string{"provider": "aws"}
if err := WriteMetadata(dir, metadata); err != nil {
return nil, false, err
return nil, err
}
// Compress the directory to the given output path
if err := DirToBox(outputPath, dir); err != nil {
return nil, false, err
return nil, err
}
return NewArtifact("aws", outputPath), true, nil
return NewArtifact("aws", outputPath), nil
}
var defaultAWSVagrantfile = `
+4 -4
View File
@@ -68,10 +68,10 @@ func (p *PostProcessor) Configure(raw interface{}) error {
return nil
}
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, error) {
ppName, ok := builtins[artifact.BuilderId()]
if !ok {
return nil, false, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId())
return nil, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId())
}
// Use the premade PostProcessor if we have one. Otherwise, we
@@ -81,12 +81,12 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac
log.Printf("Premade post-processor for '%s' not found. Creating.", ppName)
pp = keyToPostProcessor(ppName)
if pp == nil {
return nil, false, fmt.Errorf("Vagrant box post-processor not found: %s", ppName)
return nil, fmt.Errorf("Vagrant box post-processor not found: %s", ppName)
}
config := map[string]string{"output": p.config.OutputPath}
if err := pp.Configure(config); err != nil {
return nil, false, err
return nil, err
}
}
+14 -14
View File
@@ -37,24 +37,24 @@ func (p *VBoxBoxPostProcessor) Configure(raw interface{}) error {
return nil
}
func (p *VBoxBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
func (p *VBoxBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, error) {
var err error
tplData := &VBoxVagrantfileTemplate{}
tplData.BaseMacAddress, err = p.findBaseMacAddress(artifact)
if err != nil {
return nil, false, err
return nil, err
}
// Compile the output path
outputPath, err := ProcessOutputPath(p.config.OutputPath, "virtualbox", artifact)
if err != nil {
return nil, false, err
return nil, err
}
// Create a temporary directory for us to build the contents of the box in
dir, err := ioutil.TempDir("", "packer")
if err != nil {
return nil, false, err
return nil, err
}
defer os.RemoveAll(dir)
@@ -63,25 +63,25 @@ func (p *VBoxBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifac
ui.Message(fmt.Sprintf("Copying: %s", path))
src, err := os.Open(path)
if err != nil {
return nil, false, err
return nil, err
}
defer src.Close()
dst, err := os.Create(filepath.Join(dir, filepath.Base(path)))
if err != nil {
return nil, false, err
return nil, err
}
defer dst.Close()
if _, err := io.Copy(dst, src); err != nil {
return nil, false, err
return nil, err
}
}
// Create the Vagrantfile from the template
vf, err := os.Create(filepath.Join(dir, "Vagrantfile"))
if err != nil {
return nil, false, err
return nil, err
}
defer vf.Close()
@@ -89,13 +89,13 @@ func (p *VBoxBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifac
if p.config.VagrantfileTemplate != "" {
f, err := os.Open(p.config.VagrantfileTemplate)
if err != nil {
return nil, false, err
return nil, err
}
defer f.Close()
contents, err := ioutil.ReadAll(f)
if err != nil {
return nil, false, err
return nil, err
}
vagrantfileContents = string(contents)
@@ -108,22 +108,22 @@ func (p *VBoxBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifac
// Create the metadata
metadata := map[string]string{"provider": "virtualbox"}
if err := WriteMetadata(dir, metadata); err != nil {
return nil, false, err
return nil, err
}
// Rename the OVF file to box.ovf, as required by Vagrant
ui.Message("Renaming the OVF to box.ovf...")
if err := p.renameOVF(dir); err != nil {
return nil, false, err
return nil, err
}
// Compress the directory to the given output path
ui.Message(fmt.Sprintf("Compressing box..."))
if err := DirToBox(outputPath, dir); err != nil {
return nil, false, err
return nil, err
}
return NewArtifact("virtualbox", outputPath), false, nil
return NewArtifact("virtualbox", outputPath), nil
}
func (p *VBoxBoxPostProcessor) findBaseMacAddress(a packer.Artifact) (string, error) {
+12 -12
View File
@@ -29,17 +29,17 @@ func (p *VMwareBoxPostProcessor) Configure(raw interface{}) error {
return nil
}
func (p *VMwareBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
func (p *VMwareBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, error) {
// Compile the output path
outputPath, err := ProcessOutputPath(p.config.OutputPath, "vmware", artifact)
if err != nil {
return nil, false, err
return nil, err
}
// Create a temporary directory for us to build the contents of the box in
dir, err := ioutil.TempDir("", "packer")
if err != nil {
return nil, false, err
return nil, err
}
defer os.RemoveAll(dir)
@@ -48,37 +48,37 @@ func (p *VMwareBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artif
ui.Message(fmt.Sprintf("Copying: %s", path))
src, err := os.Open(path)
if err != nil {
return nil, false, err
return nil, err
}
defer src.Close()
dst, err := os.Create(filepath.Join(dir, filepath.Base(path)))
if err != nil {
return nil, false, err
return nil, err
}
defer dst.Close()
if _, err := io.Copy(dst, src); err != nil {
return nil, false, err
return nil, err
}
}
if p.config.VagrantfileTemplate != "" {
f, err := os.Open(p.config.VagrantfileTemplate)
if err != nil {
return nil, false, err
return nil, err
}
defer f.Close()
contents, err := ioutil.ReadAll(f)
if err != nil {
return nil, false, err
return nil, err
}
// Create the Vagrantfile from the template
vf, err := os.Create(filepath.Join(dir, "Vagrantfile"))
if err != nil {
return nil, false, err
return nil, err
}
defer vf.Close()
@@ -90,14 +90,14 @@ func (p *VMwareBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artif
// Create the metadata
metadata := map[string]string{"provider": "vmware_desktop"}
if err := WriteMetadata(dir, metadata); err != nil {
return nil, false, err
return nil, err
}
// Compress the directory to the given output path
ui.Message(fmt.Sprintf("Compressing box..."))
if err := DirToBox(outputPath, dir); err != nil {
return nil, false, err
return nil, err
}
return NewArtifact("vmware", outputPath), false, nil
return NewArtifact("vmware", outputPath), nil
}
+3 -3
View File
@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
set -e
NO_COLOR="\x1b[0m"
@@ -15,12 +15,12 @@ DIR="$( cd -P "$( dirname "$SOURCE" )/.." && pwd )"
cd $DIR
# Compile the main Packer app
echo -e "${OK_COLOR}--> Compiling Packer${NO_COLOR}"
echo "${OK_COLOR}--> Compiling Packer${NO_COLOR}"
go build -v -o bin/packer .
# Go over each plugin and build it
for PLUGIN in $(find ./plugin -mindepth 1 -maxdepth 1 -type d); do
PLUGIN_NAME=$(basename ${PLUGIN})
echo -e "${OK_COLOR}--> Compiling Plugin: ${PLUGIN_NAME}${NO_COLOR}"
echo "${OK_COLOR}--> Compiling Plugin: ${PLUGIN_NAME}${NO_COLOR}"
go build -v -o bin/packer-${PLUGIN_NAME} ${PLUGIN}
done
+1 -1
View File
@@ -82,7 +82,7 @@ helpers do
end
def download_url(file)
"https://dl.bintray.com/mitchellh/packer/#{file}?direct"
"http://dl.bintray.com/mitchellh/packer/#{file}?direct"
end
def latest_version
@@ -66,9 +66,6 @@ Optional:
five seconds and one minute 30 seconds, respectively. If this isn't specified,
the default is 10 seconds.
* `disk_size` (int) - The size, in megabytes, of the hard disk to create
for the VM. By default, this is 40000 (40 GB).
* `guest_additions_path` (string) - The path on the guest virtual machine
where the VirtualBox guest additions ISO will be uploaded. By default this
is "VBoxGuestAdditions.iso" which should upload into the login directory
@@ -100,9 +97,8 @@ Optional:
* `output_directory` (string) - This is the path to the directory where the
resulting virtual machine will be created. This may be relative or absolute.
If relative, the path is relative to the working directory when `packer`
is executed. This directory must not exist or be empty prior to running the builder.
By default this is "output-BUILDNAME" where "BUILDNAME" is the name
of the build.
is executed. By default this is "virtualbox". This directory must not exist
or be empty prior to running the builder.
* `shutdown_command` (string) - The command to use to gracefully shut down
the machine once all the provisioning is done. By default this is an empty
@@ -146,8 +142,7 @@ Optional:
the home directory.
* `vm_name` (string) - This is the name of the VMX file for the new virtual
machine, without the file extension. By default this is "packer-BUILDNAME",
where "BUILDNAME" is the name of the build.
machine, without the file extension. By default this is "packer".
## Boot Command
@@ -95,9 +95,8 @@ Optional:
* `output_directory` (string) - This is the path to the directory where the
resulting virtual machine will be created. This may be relative or absolute.
If relative, the path is relative to the working directory when `packer`
is executed. This directory must not exist or be empty prior to running the builder.
By default this is "output-BUILDNAME" where "BUILDNAME" is the name
of the build.
is executed. By default this is "vmware". This directory must not exist
or be empty prior to running the builder.
* `shutdown_command` (string) - The command to use to gracefully shut down
the machine once all the provisioning is done. By default this is an empty
@@ -118,23 +117,11 @@ Optional:
available. By default this is "20m", or 20 minutes. Note that this should
be quite long since the timer begins as soon as virtual machine is booted.
* `tools_upload_flavor` (string) - The flavor of the VMware Tools ISO to
upload into the VM. Valid values are "darwin", "linux", and "windows".
By default, this is empty, which means VMware tools won't be uploaded.
* `tools_upload_path` (string) - The path in the VM to upload the VMware
tools. This only takes effect if `tools_upload_flavor` is non-empty.
This is a [configuration template](/docs/templates/configuration-templates.html)
that has a single valid variable: `Flavor`, which will be the value of
`tools_upload_flavor`. By default the upload path is set to
`{{.Flavor}}.iso`.
* `vm_name` (string) - This is the name of the VMX file for the new virtual
machine, without the file extension. By default this is "packer-BUILDNAME",
where "BUILDNAME" is the name of the build.
machine, without the file extension. By default this is "packer".
* `vmdk_name` (string) - The filename of the virtual disk that'll be created,
without the extension. This is a This defaults to "packer".
without the extension. This defaults to "packer".
* `vmx_data` (object, string keys and string values) - Arbitrary key/values
to enter into the virtual machine VMX file. This is for advanced users
@@ -38,7 +38,7 @@ what each method should do.
<pre class="prettyprint">
type PostProcessor interface {
Configure(interface{}) error
PostProcess(Ui, Artifact) (a Artifact, keep bool, err error)
PostProcess(Ui, Artifact) (Artifact, error)
}
</pre>
@@ -79,15 +79,3 @@ a "compress" post-processor that is responsible for compressing files,
the transformation would be taking the `Files()` from the original artifact,
compressing them, and creating a new artifact with a single file: the
compressed archive.
The result signature of this method is `(Artifact, bool, error)`. Each
return value is explained below:
* `Artifact` - The newly created artifact if no errors occurred.
* `bool` - If true, the input artifact will forcefully be kept. By default,
Packer typically deletes all input artifacts, since the user doesn't generally
want intermediary artifacts. However, some post-processors depend on the
previous artifact existing. If this is `true`, it forces packer to keep the
artifact around.
* `error` - Non-nil if there was an error in any way. If this is the case,
the other two return values are ignored.
@@ -47,6 +47,6 @@ Available commands are:
If you get an error that `packer` could not be found, then your PATH
environmental variable was not setup properly. Please go back and ensure
that your PATH variable contains the directory which has Packer installed.
that yoru PATH variable contains the directory which has Packer installed.
Otherwise, Packer is installed and you're ready to go!
@@ -22,7 +22,7 @@ $ gem install veewee-to-packer
...
```
Once installed, usage is easy! Just point `veewee-to-packer`
Once installed, usage is easy! Just point call `veewee-to-packer` pointed
at the `definition.rb` file of any template. The converter will output
any warnings or messages about the conversion. The example below converts
a CentOS template:
+1 -1
View File
@@ -17,7 +17,7 @@ page_title: "Downloads"
Below are all available downloads for the latest version of Packer
(<%= latest_version %>). Please download the proper package for your
operating system and architecture. You can find SHA256 checksums
for packages <a href="https://dl.bintray.com/mitchellh/packer/<%= latest_version %>_SHA256SUMS?direct">here</a>.
for packages <a href="http://dl.bintray.com/mitchellh/packer/<%= latest_version %>_SHA256SUMS?direct">here</a>.
</p>
</div>
</div>