Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2d1cc53d45 | |||
| 377f7ba3cd | |||
| 57c53ea2d7 | |||
| 5ad40dd184 | |||
| a35cbfc4da | |||
| 86df78a7be | |||
| 958502bbdc | |||
| 014ed0e507 | |||
| 45f6f6f297 | |||
| 7c7a8a7f27 | |||
| 1beec2b713 | |||
| 42d0980228 | |||
| a45f843ccb | |||
| f3bcdbdf34 | |||
| bb1aae39b0 | |||
| 2e1032a36b | |||
| f3ece7ceae | |||
| 0543d238dd | |||
| c420dc6e19 | |||
| 15206f53e8 | |||
| b4cca743cf | |||
| c3bbb82c5c | |||
| 32f6dd17a3 | |||
| c3363e48ed | |||
| 7db468f55e | |||
| e4ad595c90 | |||
| 1ffae8ad93 | |||
| 0691bf7657 | |||
| dfc88064a7 | |||
| 0c20949ed9 | |||
| b34c95af04 | |||
| a1c0ff0c90 | |||
| 6ed3f77951 | |||
| 686e418bbc | |||
| 17f2ea4c5d | |||
| 5d4abf8280 | |||
| 68d9d4be7c | |||
| 9163c25ef7 | |||
| df352702b5 | |||
| 0faa87b311 | |||
| 6903d11800 | |||
| 5786f6ad5a | |||
| e920c49e8f | |||
| b69e983474 | |||
| 69883d1abe | |||
| e8535e7f6a | |||
| 43bb20d05f | |||
| 871785ddfd | |||
| da8648114a | |||
| 8201b7f6e1 | |||
| adae75402f | |||
| 848f324515 | |||
| 02d67fd34d | |||
| 3682b30ee0 | |||
| 84e8dd806d | |||
| 7fff56657e | |||
| 9202878107 | |||
| 33635caf8c | |||
| 90829dcc19 |
@@ -1,3 +1,36 @@
|
||||
## 0.1.2 (June 29, 2013)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
* core: Template doesn't validate if there are no builders.
|
||||
* vmware: Delete any VMware files in the VM that aren't necessary for
|
||||
it to function.
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* core: Plugin servers consider a port in use if there is any
|
||||
error listening to it. This fixes I18n issues and Windows. [GH-58]
|
||||
* amazon-ebs: Sleep between checking instance state to avoid
|
||||
RequestLimitExceeded [GH-50]
|
||||
* vagrant: Rename VirtualBox ovf to "box.ovf" [GH-64]
|
||||
* vagrant: VMware boxes have the correct provider type.
|
||||
* vmware: Properly populate files in artifact so that the Vagrant
|
||||
post-processor works. [GH-63]
|
||||
|
||||
## 0.1.1 (June 28, 2013)
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* core: plugins listen explicitly on 127.0.0.1, fixing odd hangs. [GH-37]
|
||||
* core: fix race condition on verifying checksum of large ISOs which
|
||||
could cause panics [GH-52]
|
||||
* virtualbox: `boot_wait` defaults to "10s" rather than 0. [GH-44]
|
||||
* virtualbox: if `http_port_min` and max are the same, it will no longer
|
||||
panic [GH-53]
|
||||
* vmware: `boot_wait` defaults to "10s" rather than 0. [GH-44]
|
||||
* vmware: if `http_port_min` and max are the same, it will no longer
|
||||
panic [GH-53]
|
||||
|
||||
## 0.1.0 (June 28, 2013)
|
||||
|
||||
* Initial release
|
||||
|
||||
@@ -11,18 +11,20 @@ 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. The images that Packer creates an easily be turned into
|
||||
plugins.
|
||||
|
||||
The images that Packer creates can easily be turned into
|
||||
[Vagrant](http://www.vagrantup.com) boxes.
|
||||
|
||||
## Quick Start
|
||||
|
||||
**Note:** There is a great
|
||||
[introduction and getting started guide](http://localhost:4567/intro)
|
||||
[introduction and getting started guide](http://www.packer.io/intro)
|
||||
for those with a bit more patience. Otherwise, the quick start below
|
||||
will get you up and running quickly, at the sacrifice of not explaining some
|
||||
key points.
|
||||
|
||||
First, [downloada pre-built Packer binary](http://localhost:4567/downloads.html)
|
||||
First, [download a pre-built Packer binary](http://www.packer.io/downloads.html)
|
||||
for your operating system or [compile Packer yourself](#developing-packer).
|
||||
|
||||
After Packer is installed, create your first template, which tells Packer
|
||||
@@ -78,5 +80,6 @@ $ bin/packer
|
||||
...
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
@@ -48,7 +48,7 @@ func (a *artifact) Destroy() error {
|
||||
errors := make([]error, 0)
|
||||
|
||||
for _, imageId := range a.amis {
|
||||
log.Printf("Degistering image ID: %s", imageId)
|
||||
log.Printf("Deregistering image ID: %s", imageId)
|
||||
if _, err := a.conn.DeregisterImage(imageId); err != nil {
|
||||
errors = append(errors, err)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"strconv"
|
||||
"text/template"
|
||||
"time"
|
||||
@@ -68,6 +69,11 @@ func (s *stepCreateAMI) Run(state map[string]interface{}) multistep.StepAction {
|
||||
if imageResp.Images[0].State == "available" {
|
||||
break
|
||||
}
|
||||
|
||||
log.Printf("Image in state %s, sleeping 2s before checking again",
|
||||
imageResp.Images[0].State)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -73,6 +74,7 @@ func (d *DownloadClient) Cancel() {
|
||||
func (d *DownloadClient) Get() (string, error) {
|
||||
// If we already have the file and it matches, then just return the target path.
|
||||
if verify, _ := d.VerifyChecksum(d.config.TargetPath); verify {
|
||||
log.Println("Initial checksum matched, no download needed.")
|
||||
return d.config.TargetPath, nil
|
||||
}
|
||||
|
||||
@@ -81,6 +83,8 @@ func (d *DownloadClient) Get() (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
log.Printf("Parsed URL: %#v", url)
|
||||
|
||||
// Files when we don't copy the file are special cased.
|
||||
var finalPath string
|
||||
if url.Scheme == "file" && !d.config.CopyFile {
|
||||
@@ -101,6 +105,7 @@ func (d *DownloadClient) Get() (string, error) {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
log.Printf("Downloading: %s", url.String())
|
||||
err = d.downloader.Download(f, url)
|
||||
}
|
||||
|
||||
@@ -117,6 +122,10 @@ func (d *DownloadClient) Get() (string, error) {
|
||||
|
||||
// PercentProgress returns the download progress as a percentage.
|
||||
func (d *DownloadClient) PercentProgress() uint {
|
||||
if d.downloader == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return uint((float64(d.downloader.Progress()) / float64(d.downloader.Total())) * 100)
|
||||
}
|
||||
|
||||
@@ -133,6 +142,7 @@ func (d *DownloadClient) VerifyChecksum(path string) (bool, error) {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
log.Printf("Verifying checksum of %s", path)
|
||||
d.config.Hash.Reset()
|
||||
io.Copy(d.config.Hash, f)
|
||||
return bytes.Compare(d.config.Hash.Sum(nil), d.config.Checksum) == 0, nil
|
||||
|
||||
@@ -89,6 +89,10 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
b.config.OutputDir = "virtualbox"
|
||||
}
|
||||
|
||||
if b.config.RawBootWait == "" {
|
||||
b.config.RawBootWait = "10s"
|
||||
}
|
||||
|
||||
if b.config.SSHHostPortMin == 0 {
|
||||
b.config.SSHHostPortMin = 2222
|
||||
}
|
||||
@@ -168,17 +172,19 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
errs = append(errs, errors.New("Output directory already exists. It must not exist."))
|
||||
}
|
||||
|
||||
if b.config.RawBootWait != "" {
|
||||
b.config.BootWait, err = time.ParseDuration(b.config.RawBootWait)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("Failed parsing boot_wait: %s", err))
|
||||
}
|
||||
b.config.BootWait, err = time.ParseDuration(b.config.RawBootWait)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("Failed parsing boot_wait: %s", err))
|
||||
}
|
||||
|
||||
if b.config.RawShutdownTimeout == "" {
|
||||
b.config.RawShutdownTimeout = "5m"
|
||||
}
|
||||
|
||||
if b.config.RawSSHWaitTimeout == "" {
|
||||
b.config.RawSSHWaitTimeout = "20m"
|
||||
}
|
||||
|
||||
b.config.ShutdownTimeout, err = time.ParseDuration(b.config.RawShutdownTimeout)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("Failed parsing shutdown_timeout: %s", err))
|
||||
@@ -192,10 +198,6 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
errs = append(errs, errors.New("An ssh_username must be specified."))
|
||||
}
|
||||
|
||||
if b.config.RawSSHWaitTimeout == "" {
|
||||
b.config.RawSSHWaitTimeout = "20m"
|
||||
}
|
||||
|
||||
b.config.SSHWaitTimeout, err = time.ParseDuration(b.config.RawSSHWaitTimeout)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("Failed parsing ssh_wait_timeout: %s", err))
|
||||
|
||||
@@ -61,9 +61,20 @@ func TestBuilderPrepare_BootWait(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// Test a default boot_wait
|
||||
delete(config, "boot_wait")
|
||||
err := b.Prepare(config)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if b.config.RawBootWait != "10s" {
|
||||
t.Fatalf("bad value: %s", b.config.RawBootWait)
|
||||
}
|
||||
|
||||
// Test with a bad boot_wait
|
||||
config["boot_wait"] = "this is not good"
|
||||
err := b.Prepare(config)
|
||||
err = b.Prepare(config)
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -317,9 +328,20 @@ func TestBuilderPrepare_SSHWaitTimeout(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// Test a default boot_wait
|
||||
delete(config, "ssh_wait_timeout")
|
||||
err := b.Prepare(config)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if b.config.RawSSHWaitTimeout != "20m" {
|
||||
t.Fatalf("bad value: %s", b.config.RawSSHWaitTimeout)
|
||||
}
|
||||
|
||||
// Test with a bad value
|
||||
config["ssh_wait_timeout"] = "this is not good"
|
||||
err := b.Prepare(config)
|
||||
err = b.Prepare(config)
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
@@ -124,11 +124,13 @@ func (d *VBox42Driver) Version() (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
log.Printf("VBoxManage --version output: %s", stdout.String())
|
||||
versionRe := regexp.MustCompile("[^.0-9]")
|
||||
matches := versionRe.Split(stdout.String(), 2)
|
||||
if len(matches) == 0 {
|
||||
return "", fmt.Errorf("No version found: %s", stdout.String())
|
||||
}
|
||||
|
||||
log.Printf("VirtualBox version: %s", matches[0])
|
||||
return matches[0], nil
|
||||
}
|
||||
|
||||
@@ -35,9 +35,7 @@ func (s *stepDownloadISO) Run(state map[string]interface{}) multistep.StepAction
|
||||
|
||||
checksum, err := hex.DecodeString(config.ISOMD5)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error parsing checksum: %s", err)
|
||||
state["error"] = err
|
||||
ui.Error(err.Error())
|
||||
state["error"] = fmt.Errorf("Error parsing checksum: %s", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -111,6 +109,7 @@ DownloadWaitLoop:
|
||||
}
|
||||
defer sourceF.Close()
|
||||
|
||||
log.Printf("Copying ISO to temp location: %s", tempdir)
|
||||
if _, err := io.Copy(f, sourceF); err != nil {
|
||||
state["error"] = fmt.Errorf("Error copying ISO: %s", err)
|
||||
return multistep.ActionHalt
|
||||
|
||||
@@ -38,7 +38,14 @@ func (s *stepHTTPServer) Run(state map[string]interface{}) multistep.StepAction
|
||||
portRange := int(config.HTTPPortMax - config.HTTPPortMin)
|
||||
for {
|
||||
var err error
|
||||
httpPort = uint(rand.Intn(portRange)) + config.HTTPPortMin
|
||||
var offset uint = 0
|
||||
|
||||
if portRange > 0 {
|
||||
// Intn will panic if portRange == 0, so we do a check.
|
||||
offset = uint(rand.Intn(portRange))
|
||||
}
|
||||
|
||||
httpPort = offset + config.HTTPPortMin
|
||||
httpAddr = fmt.Sprintf(":%d", httpPort)
|
||||
log.Printf("Trying port: %d", httpPort)
|
||||
s.l, err = net.Listen("tcp", httpAddr)
|
||||
|
||||
@@ -86,6 +86,10 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
b.config.HTTPPortMax = 9000
|
||||
}
|
||||
|
||||
if b.config.RawBootWait == "" {
|
||||
b.config.RawBootWait = "10s"
|
||||
}
|
||||
|
||||
if b.config.VNCPortMin == 0 {
|
||||
b.config.VNCPortMin = 5900
|
||||
}
|
||||
@@ -220,6 +224,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
&stepWaitForSSH{},
|
||||
&stepProvision{},
|
||||
&stepShutdown{},
|
||||
&stepCleanFiles{},
|
||||
}
|
||||
|
||||
// Setup the state bag
|
||||
@@ -259,8 +264,15 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
// Compile the artifact list
|
||||
files := make([]string, 0, 10)
|
||||
visit := func(path string, info os.FileInfo, err error) error {
|
||||
files = append(files, path)
|
||||
return err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !info.IsDir() {
|
||||
files = append(files, path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := filepath.Walk(b.config.OutputDir, visit); err != nil {
|
||||
|
||||
@@ -28,9 +28,20 @@ func TestBuilderPrepare_BootWait(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// Test a default boot_wait
|
||||
delete(config, "boot_wait")
|
||||
err := b.Prepare(config)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if b.config.RawBootWait != "10s" {
|
||||
t.Fatalf("bad value: %s", b.config.RawBootWait)
|
||||
}
|
||||
|
||||
// Test with a bad boot_wait
|
||||
config["boot_wait"] = "this is not good"
|
||||
err := b.Prepare(config)
|
||||
err = b.Prepare(config)
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package vmware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// These are the extensions of files that are important for the function
|
||||
// of a VMware virtual machine. Any other file is discarded as part of the
|
||||
// build.
|
||||
var KeepFileExtensions = []string{".nvram", ".vmdk", ".vmsd", ".vmx", ".vmxf"}
|
||||
|
||||
// This step removes unnecessary files from the final result.
|
||||
//
|
||||
// Uses:
|
||||
// config *config
|
||||
// ui packer.Ui
|
||||
//
|
||||
// Produces:
|
||||
// <nothing>
|
||||
type stepCleanFiles struct{}
|
||||
|
||||
func (stepCleanFiles) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
|
||||
ui.Say("Deleting unnecessary VMware files...")
|
||||
visit := func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !info.IsDir() {
|
||||
// If the file isn't critical to the function of the
|
||||
// virtual machine, we get rid of it.
|
||||
keep := false
|
||||
ext := filepath.Ext(path)
|
||||
for _, goodExt := range KeepFileExtensions {
|
||||
if goodExt == ext {
|
||||
keep = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !keep {
|
||||
ui.Message(fmt.Sprintf("Deleting: %s", path))
|
||||
return os.Remove(path)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := filepath.Walk(config.OutputDir, visit); err != nil {
|
||||
state["error"] = err
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (stepCleanFiles) Cleanup(map[string]interface{}) {}
|
||||
@@ -38,7 +38,14 @@ func (s *stepHTTPServer) Run(state map[string]interface{}) multistep.StepAction
|
||||
portRange := int(config.HTTPPortMax - config.HTTPPortMin)
|
||||
for {
|
||||
var err error
|
||||
httpPort = uint(rand.Intn(portRange)) + config.HTTPPortMin
|
||||
var offset uint = 0
|
||||
|
||||
if portRange > 0 {
|
||||
// Intn will panic if portRange == 0, so we do a check.
|
||||
offset = uint(rand.Intn(portRange))
|
||||
}
|
||||
|
||||
httpPort = offset + config.HTTPPortMin
|
||||
httpAddr = fmt.Sprintf(":%d", httpPort)
|
||||
log.Printf("Trying port: %d", httpPort)
|
||||
s.l, err = net.Listen("tcp", httpAddr)
|
||||
|
||||
@@ -218,6 +218,8 @@ func (c *Client) Start() (address string, err error) {
|
||||
cmd.Env = append(cmd.Env, env...)
|
||||
cmd.Stderr = stderr
|
||||
cmd.Stdout = stdout
|
||||
|
||||
log.Printf("Starting plugin: %s %#v", cmd.Path, cmd.Args)
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
return
|
||||
@@ -250,6 +252,7 @@ func (c *Client) Start() (address string, err error) {
|
||||
timeout := time.After(c.config.StartTimeout)
|
||||
|
||||
// Start looking for the address
|
||||
log.Println("Waiting for RPC address for: %s", cmd.Path)
|
||||
for done := false; !done; {
|
||||
select {
|
||||
case <-timeout:
|
||||
|
||||
+3
-10
@@ -19,7 +19,6 @@ import (
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const MagicCookieKey = "PACKER_PLUGIN_MAGIC_COOKIE"
|
||||
@@ -56,17 +55,11 @@ func serve(server *rpc.Server) (err error) {
|
||||
var address string
|
||||
var listener net.Listener
|
||||
for port := minPort; port <= maxPort; port++ {
|
||||
address = fmt.Sprintf(":%d", port)
|
||||
address = fmt.Sprintf("127.0.0.1:%d", port)
|
||||
listener, err = net.Listen("tcp", address)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "address already in use") {
|
||||
// Not an address already in use error, return.
|
||||
return
|
||||
} else {
|
||||
// Address is in use, just try another
|
||||
err = nil
|
||||
continue
|
||||
}
|
||||
err = nil
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
@@ -172,6 +172,10 @@ func ParseTemplate(data []byte) (t *Template, err error) {
|
||||
raw.rawConfig = v
|
||||
}
|
||||
|
||||
if len(t.Builders) == 0 {
|
||||
errors = append(errors, fmt.Errorf("No builders are defined in the template."))
|
||||
}
|
||||
|
||||
// If there were errors, we put it into a MultiError and return
|
||||
if len(errors) > 0 {
|
||||
err = &MultiError{errors}
|
||||
|
||||
+12
-2
@@ -11,14 +11,14 @@ func TestParseTemplate_Basic(t *testing.T) {
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": []
|
||||
"builders": [{"type": "something"}]
|
||||
}
|
||||
`
|
||||
|
||||
result, err := ParseTemplate([]byte(data))
|
||||
assert.Nil(err, "should not error")
|
||||
assert.NotNil(result, "template should not be nil")
|
||||
assert.Length(result.Builders, 0, "no builders")
|
||||
assert.Length(result.Builders, 1, "one builder")
|
||||
}
|
||||
|
||||
func TestParseTemplate_Invalid(t *testing.T) {
|
||||
@@ -140,6 +140,8 @@ func TestParseTemplate_Hooks(t *testing.T) {
|
||||
data := `
|
||||
{
|
||||
|
||||
"builders": [{"type": "foo"}],
|
||||
|
||||
"hooks": {
|
||||
"event": ["foo", "bar"]
|
||||
}
|
||||
@@ -159,6 +161,8 @@ func TestParseTemplate_Hooks(t *testing.T) {
|
||||
func TestParseTemplate_PostProcessors(t *testing.T) {
|
||||
data := `
|
||||
{
|
||||
"builders": [{"type": "foo"}],
|
||||
|
||||
"post-processors": [
|
||||
"simple",
|
||||
|
||||
@@ -215,6 +219,8 @@ func TestParseTemplate_ProvisionerWithoutType(t *testing.T) {
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [{"type": "foo"}],
|
||||
|
||||
"provisioners": [{}]
|
||||
}
|
||||
`
|
||||
@@ -228,6 +234,8 @@ func TestParseTemplate_ProvisionerWithNonStringType(t *testing.T) {
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [{"type": "foo"}],
|
||||
|
||||
"provisioners": [{
|
||||
"type": 42
|
||||
}]
|
||||
@@ -243,6 +251,8 @@ func TestParseTemplate_Provisioners(t *testing.T) {
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [{"type": "foo"}],
|
||||
|
||||
"provisioners": [
|
||||
{
|
||||
"type": "shell"
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
// The version of packer.
|
||||
const Version = "0.1.0"
|
||||
const Version = "0.1.3"
|
||||
|
||||
// Any pre-release marker for the version. If this is "" (empty string),
|
||||
// then it means that it is a final release. Otherwise, this is the
|
||||
|
||||
@@ -111,6 +111,12 @@ func (p *VBoxBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifac
|
||||
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, err
|
||||
}
|
||||
|
||||
// Compress the directory to the given output path
|
||||
ui.Message(fmt.Sprintf("Compressing box..."))
|
||||
if err := DirToBox(outputPath, dir); err != nil {
|
||||
@@ -156,6 +162,21 @@ func (p *VBoxBoxPostProcessor) findBaseMacAddress(a packer.Artifact) (string, er
|
||||
return string(matches[1]), nil
|
||||
}
|
||||
|
||||
func (p *VBoxBoxPostProcessor) renameOVF(dir string) error {
|
||||
log.Println("Looking for OVF to rename...")
|
||||
matches, err := filepath.Glob(filepath.Join(dir, "*.ovf"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(matches) > 1 {
|
||||
return errors.New("More than one OVF file in VirtualBox artifact.")
|
||||
}
|
||||
|
||||
log.Printf("Renaming: '%s' => box.ovf", matches[0])
|
||||
return os.Rename(matches[0], filepath.Join(dir, "box.ovf"))
|
||||
}
|
||||
|
||||
var defaultVBoxVagrantfile = `
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.base_mac = "{{ .BaseMacAddress }}"
|
||||
|
||||
@@ -88,7 +88,7 @@ func (p *VMwareBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artif
|
||||
}
|
||||
|
||||
// Create the metadata
|
||||
metadata := map[string]string{"provider": "vmware"}
|
||||
metadata := map[string]string{"provider": "vmware_desktop"}
|
||||
if err := WriteMetadata(dir, metadata); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+11
-4
@@ -13,7 +13,7 @@ cd $DIR
|
||||
# of packer/version.go.
|
||||
VERSION=$(grep "const Version " packer/version.go | sed -E 's/.*"(.+)"$/\1/')
|
||||
VERSIONDIR="${VERSION}"
|
||||
PREVERSION=$(grep "const VersionPrerelease " packer/version.go | sed -E 's/.*"(.+)"$/\1/')
|
||||
PREVERSION=$(grep "const VersionPrerelease " packer/version.go | sed -E 's/.*"(.*)"$/\1/')
|
||||
if [ ! -z $PREVERSION ]; then
|
||||
PREVERSION="${PREVERSION}.$(date -u +%s)"
|
||||
VERSIONDIR="${VERSIONDIR}-${PREVERSION}"
|
||||
@@ -61,7 +61,14 @@ for PLUGIN in $(find ./plugin -mindepth 1 -maxdepth 1 -type d); do
|
||||
pushd ${PLUGIN}
|
||||
xc
|
||||
popd
|
||||
find ./pkg -type f -name ${PLUGIN_NAME} -execdir mv ${PLUGIN_NAME} packer-${PLUGIN_NAME} ';'
|
||||
find ./pkg \
|
||||
-type f \
|
||||
-name ${PLUGIN_NAME} \
|
||||
-execdir mv ${PLUGIN_NAME} packer-${PLUGIN_NAME} ';'
|
||||
find ./pkg \
|
||||
-type f \
|
||||
-name ${PLUGIN_NAME}.exe \
|
||||
-execdir mv ${PLUGIN_NAME}.exe packer-${PLUGIN_NAME}.exe ';'
|
||||
) &
|
||||
done
|
||||
|
||||
@@ -79,7 +86,7 @@ for PLATFORM in $(find ./pkg/${VERSIONDIR} -mindepth 1 -maxdepth 1 -type d); do
|
||||
|
||||
(
|
||||
pushd ${PLATFORM}
|
||||
zip -P hashipacker ${DIR}/pkg/${VERSIONDIR}/dist/${ARCHIVE_NAME}.zip ./*
|
||||
zip ${DIR}/pkg/${VERSIONDIR}/dist/${ARCHIVE_NAME}.zip ./*
|
||||
popd
|
||||
) &
|
||||
done
|
||||
@@ -88,7 +95,7 @@ waitAll
|
||||
|
||||
# Make the checksums
|
||||
pushd ./pkg/${VERSIONDIR}/dist
|
||||
shasum -a256 * > ./${VERSION}_SHA256SUMS
|
||||
shasum -a256 * > ./${VERSIONDIR}_SHA256SUMS
|
||||
popd
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Packer Website
|
||||
|
||||
This subdirectory contains the entire source for the [Packer website](http://www.packer.io).
|
||||
T
|
||||
This is a [Middleman](http://middlemanapp.com) project, which builds a static
|
||||
site from these source files.
|
||||
|
||||
|
||||
+5
-2
@@ -18,8 +18,9 @@ if !ENV["PACKER_DISABLE_DOWNLOAD_FETCH"]
|
||||
|
||||
response.body.split("\n").each do |line|
|
||||
next if line !~ /\/mitchellh\/packer\/(#{ENV["PACKER_VERSION"]}.+?)\?/
|
||||
filename = $1.to_s
|
||||
filename = $1.to_s
|
||||
os = filename.split("_")[1]
|
||||
next if os == "SHA256SUMS"
|
||||
|
||||
$packer_files[os] ||= []
|
||||
$packer_files[os] << filename
|
||||
@@ -59,7 +60,9 @@ end
|
||||
#-------------------------------------------------------------------------
|
||||
helpers do
|
||||
def download_arch(file)
|
||||
file.split("_")[2].split(".")[0]
|
||||
parts = file.split("_")
|
||||
return "" if parts.length != 3
|
||||
parts[2].split(".")[0]
|
||||
end
|
||||
|
||||
def download_os_human(os)
|
||||
|
||||
@@ -191,7 +191,7 @@ an Ubuntu 12.04 installer:
|
||||
"fb=false debconf/frontend=noninteractive ",
|
||||
"keyboard-configuration/modelcode=SKIP keyboard-configuration/layout=USA ",
|
||||
"keyboard-configuration/variant=USA console-setup/ask_detect=false ",
|
||||
"initrd=/install/initrd.gz -- <enter>"
|
||||
"initrd=/install/initrd.gz -- <enter>"
|
||||
]
|
||||
</pre>
|
||||
|
||||
|
||||
@@ -180,6 +180,6 @@ an Ubuntu 12.04 installer:
|
||||
"fb=false debconf/frontend=noninteractive ",
|
||||
"keyboard-configuration/modelcode=SKIP keyboard-configuration/layout=USA ",
|
||||
"keyboard-configuration/variant=USA console-setup/ask_detect=false ",
|
||||
"initrd=/install/initrd.gz -- <enter>"
|
||||
"initrd=/install/initrd.gz -- <enter>"
|
||||
]
|
||||
</pre>
|
||||
|
||||
@@ -39,7 +39,7 @@ the `type` key. This key specifies the name of the provisioner to use.
|
||||
Additional keys within the object are used to configure the provisioner,
|
||||
with the exception of a handful of special keys, covered later.
|
||||
|
||||
As an example, the "shell" provisioner requires at least the `path` key,
|
||||
As an example, the "shell" provisioner requires at least the `script` key,
|
||||
which specifies a path to a shell script to execute within the machines
|
||||
being created.
|
||||
|
||||
@@ -49,7 +49,7 @@ provisioner to run a local script within the machines:
|
||||
<pre class="prettyprint">
|
||||
{
|
||||
"type": "shell",
|
||||
"path": "script.sh"
|
||||
"script": "script.sh"
|
||||
}
|
||||
</pre>
|
||||
|
||||
@@ -73,7 +73,7 @@ This example is shown below:
|
||||
<pre class="prettyprint">
|
||||
{
|
||||
"type": "shell",
|
||||
"path": "script.sh",
|
||||
"script": "script.sh",
|
||||
|
||||
"override": {
|
||||
"vmware": {
|
||||
|
||||
@@ -14,7 +14,7 @@ of templates that can be readily used with Packer by simply converting them.
|
||||
|
||||
## Installation and Usage
|
||||
|
||||
Since Veewee itself is a Ruby project, so to is the veewee-to-packer
|
||||
Since Veewee itself is a Ruby project, so too is the veewee-to-packer
|
||||
application so that it can read the Veewee configurations. Install it using RubyGems:
|
||||
|
||||
```
|
||||
|
||||
@@ -16,7 +16,8 @@ page_title: "Downloads"
|
||||
<p>
|
||||
Below are all available downloads for the latest version of Packer
|
||||
(<%= latest_version %>). Please download the proper package for your
|
||||
operating system and architecture.
|
||||
operating system and architecture. You can find SHA256 checksums
|
||||
for packages <a href="http://dl.bintray.com/mitchellh/packer/<%= latest_version %>_SHA256SUMS?direct">here</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,14 +17,6 @@
|
||||
<div class="row download-row">
|
||||
<div class="download-container">
|
||||
<h2 class="uppercase"><a href="/downloads.html">Download v<%= latest_version %></a></h2>
|
||||
<div class="small">
|
||||
<small class="uppercase mono">
|
||||
<a href="#">
|
||||
Release Notes
|
||||
<!-- {{releasedate}} -->
|
||||
<span>06/17/13</span>
|
||||
</a>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -23,7 +23,7 @@ for your system and download it. Packer is packaged as a "zip" file.
|
||||
Next, unzip the downloaded package into a directory where Packer will be
|
||||
installed. On Unix systems, `~/packer` or `/usr/local/packer` is generally good,
|
||||
depending on whether you want to restrict the install to just your user
|
||||
or install it system-wide. On Windows systems, you can put it whereever you'd
|
||||
or install it system-wide. On Windows systems, you can put it wherever you'd
|
||||
like.
|
||||
|
||||
After unzipping the package, the directory should contain a set of binary
|
||||
@@ -49,7 +49,7 @@ 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 yoru PATH variable contains the directory which has Packer installed.
|
||||
environment variable was not setup properly. Please go back and ensure
|
||||
that your PATH variable contains the directory which has Packer installed.
|
||||
|
||||
Otherwise, Packer is installed and you're ready to go!
|
||||
|
||||
@@ -8,7 +8,7 @@ next_title: "Getting Started: Install Packer"
|
||||
|
||||
# Supported Platforms
|
||||
|
||||
Packer can creates machine images for any platform. Packer ships with
|
||||
Packer can create machine images for any platform. Packer ships with
|
||||
support for a set of platforms, but can be [extend through plugins](/docs/extend/builder.html)
|
||||
to support any platform. This page documents the list of supported image
|
||||
types that Packer supports creating.
|
||||
|
||||
@@ -10,7 +10,7 @@ next_title: "Packer Use Cases"
|
||||
|
||||
Pre-baked machine images have a lot of advantages, but most have been unable
|
||||
to benefit from them because images have been too tedious to create and manage.
|
||||
There were ether no existing tools to automate the creation of machine images or
|
||||
There were either no existing tools to automate the creation of machine images or
|
||||
they had too high of a learning curve. The result is that, prior to Packer,
|
||||
creating machine images threatened the agility of operations teams, and therefore
|
||||
aren't used, despite the massive benefits.
|
||||
|
||||
@@ -47,7 +47,7 @@ header .header {
|
||||
|
||||
h2 {
|
||||
font-family: $serif;
|
||||
font-size: 38px;
|
||||
font-size: 44px;
|
||||
color: #7bc6b1;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
|
||||
@@ -167,9 +167,11 @@ table {
|
||||
|
||||
::selection {
|
||||
background: #ffff00; /* Safari */
|
||||
color: $black;
|
||||
}
|
||||
::-moz-selection {
|
||||
background: #ffff00; /* Firefox */
|
||||
color: $black;
|
||||
}
|
||||
|
||||
input {
|
||||
|
||||
Reference in New Issue
Block a user