Compare commits
122 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b85913b9a7 | |||
| be9f245810 | |||
| fe0b1aa75b | |||
| d740015ef4 | |||
| dd6b5f0d85 | |||
| 8f50d2dd9a | |||
| 4f6f9e1639 | |||
| cb5f645c4c | |||
| 46cb972776 | |||
| 0d822745a1 | |||
| 4b76b8f0a7 | |||
| f40a6e21aa | |||
| 908678423e | |||
| e23411ad24 | |||
| f9747ad110 | |||
| 2d221c5947 | |||
| 58e8d9ac56 | |||
| af7b8d1e15 | |||
| a4077c9d8a | |||
| 623706676b | |||
| 833f80b282 | |||
| 4856300f62 | |||
| a5812670a8 | |||
| b3c2ee3a67 | |||
| 7abfed7a7a | |||
| 3a9ea41dca | |||
| fcbc2e7ff2 | |||
| 6dea765ba4 | |||
| d17605bd1f | |||
| 2964f27cc5 | |||
| 1d87e98c32 | |||
| fbfed8a0eb | |||
| 7fbd3f1ad4 | |||
| 83b96325aa | |||
| 88f8e4d079 | |||
| bdd4294a41 | |||
| d68e723a04 | |||
| d9aaf49234 | |||
| 8b7e258829 | |||
| 60bb158bf1 | |||
| 412d0d6607 | |||
| 9fa9cae9b3 | |||
| 402b38e779 | |||
| 8df4c991df | |||
| e0a96e968a | |||
| 19b1bdee98 | |||
| 5bc3150bb5 | |||
| d094cb7c5c | |||
| 831621ea8b | |||
| 73a638749a | |||
| 50f65ad2c2 | |||
| 07bd414ce5 | |||
| 15c4fb66e3 | |||
| c4515dbd56 | |||
| 39f532f611 | |||
| afe0b88fca | |||
| 5cf345f932 | |||
| 32737c255b | |||
| dfc553d36d | |||
| ee39f8e09e | |||
| e7886ff807 | |||
| 65169b4576 | |||
| a54e5e70da | |||
| 85bad26ec3 | |||
| 6d6b32924d | |||
| 9357c25991 | |||
| 9699c1bb37 | |||
| a6fecce367 | |||
| f7656aad9c | |||
| fa3e70ef75 | |||
| 5bb28e7ece | |||
| 45f4a1a914 | |||
| fae3b96658 | |||
| cfcdeadf53 | |||
| 640d2e9432 | |||
| 7d3987d840 | |||
| cf9dafd373 | |||
| 3fad717ba4 | |||
| ac64805a9e | |||
| 697c91b0b0 | |||
| 7b09e24ac3 | |||
| d3ab4d6b40 | |||
| f2c0aeacf5 | |||
| 4beec63845 | |||
| abe92ed739 | |||
| bd68f3c52b | |||
| 61ea7de66b | |||
| 111392ad43 | |||
| bfba541338 | |||
| e7414f334b | |||
| 93ab5c8f63 | |||
| 54e1f70a3c | |||
| eb2bcfe456 | |||
| e05cc3220f | |||
| df3d751b19 | |||
| 7ae1042696 | |||
| 739fbc8962 | |||
| aeb0e8bc06 | |||
| 4afe900535 | |||
| fcb83ced59 | |||
| 2c5f742fa3 | |||
| f0ebd2c61b | |||
| a91e6a9eed | |||
| 53b15e62cc | |||
| 50bc71e4a2 | |||
| 4c0ba7ff12 | |||
| 4f10ff2480 | |||
| c2ff4ded9c | |||
| 9b501b93d6 | |||
| 58899f3888 | |||
| 475b65cb3b | |||
| c897998ec9 | |||
| 2057ed1366 | |||
| 1fd165bb87 | |||
| 9ca3c82228 | |||
| 9afa4732dd | |||
| 32dd300b35 | |||
| f817b08bde | |||
| d437ecee2a | |||
| 0ec41b0d90 | |||
| f0d34f9897 | |||
| 7674513aaa |
@@ -1,3 +1,72 @@
|
||||
## 0.3.11 (November 4, 2013)
|
||||
|
||||
FEATURES:
|
||||
|
||||
* builder/amazon/ebs: Ability to specify which availability zone to create
|
||||
instance in. [GH-536]
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
* core: builders can now give warnings during validation. warnings won't
|
||||
fail the build but may hint at potential future problems.
|
||||
* builder/digitalocean: Can now specify a droplet name
|
||||
* builder/virtualbox: Can now disable guest addition download entirely
|
||||
by setting "guest_additions_mode" to "disable" [GH-580]
|
||||
* builder/virtualbox,vmware: ISO urls can now be https [GH-587]
|
||||
* builder/virtualbox,vmware: Warning if shutdown command is not specified,
|
||||
since it is a common case of data loss.
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* core: Won't panic when writing to a bad pipe. [GH-560]
|
||||
* builder/amazon/all: Properly scrub access key and secret key from logs.
|
||||
[GH-554]
|
||||
* builder/openstack: Properly scrub password from logs [GH-554]
|
||||
* builder/virtualbox: No panic if SSH host port min/max is the same. [GH-594]
|
||||
* builder/vmware: checks if `ifconfig` is in `/sbin` [GH-591]
|
||||
* builder/vmware: Host IP lookup works for non-C locales. [GH-592]
|
||||
* common/uuid: Use cryptographically secure PRNG when generating
|
||||
UUIDs. [GH-552]
|
||||
* communicator/ssh: File uploads that exceed the size of memory no longer
|
||||
cause crashes. [GH-561]
|
||||
|
||||
## 0.3.10 (October 20, 2013)
|
||||
|
||||
FEATURES:
|
||||
|
||||
* Ansible provisioner
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
* post-processor/vagrant: support instance-store AMIs built by Packer. [GH-502]
|
||||
* post-processor/vagrant: can now specify compression level to use
|
||||
when creating the box. [GH-506]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* builder/all: timeout waiting for SSH connection is a failure. [GH-491]
|
||||
* builder/amazon: Scrub sensitive data from the logs. [GH-521]
|
||||
* builder/amazon: Handle the situation where an EC2 instance might not
|
||||
be immediately available. [GH-522]
|
||||
* builder/amazon/chroot: Files copied into the chroot remove destination
|
||||
before copy, fixing issues with dangling symlinks. [GH-500]
|
||||
* builder/digitalocean: don't panic if erroneous API response doesn't
|
||||
contain error message. [GH-492]
|
||||
* builder/digitalocean: scrub API keys from config debug output [GH-516]
|
||||
* builder/virtualbox: error if VirtualBox version cant be detected. [GH-488]
|
||||
* builder/virtualbox: detect if vboxdrv isn't properly setup. [GH-488]
|
||||
* builder/virtualbox: sleep a bit before export to ensure the sesssion
|
||||
is unlocked. [GH-512]
|
||||
* builder/virtualbox: create SATA drives properly on VirtualBox 4.3 [GH-547]
|
||||
* builder/virtualbox: support user templates in SSH key path. [GH-539]
|
||||
* builder/vmware: support user templates in SSH key path. [GH-539]
|
||||
* communicator/ssh: Fix issue where a panic could arise from a nil
|
||||
dereference. [GH-525]
|
||||
* post-processor/vagrant: Fix issue with VirtualBox OVA. [GH-548]
|
||||
* provisioner/salt: Move salt states to correct remote directory. [GH-513]
|
||||
* provisioner/shell: Won't block on certain scripts on Windows anymore.
|
||||
[GH-507]
|
||||
|
||||
## 0.3.9 (October 2, 2013)
|
||||
|
||||
FEATURES:
|
||||
|
||||
@@ -18,6 +18,12 @@ it raises the chances we can quickly merge or address your contributions.
|
||||
* Make sure you test against the latest released version. It is possible
|
||||
we already fixed the bug you're experiencing.
|
||||
|
||||
* Run the command with debug ouput with the environment variable
|
||||
`PACKER_LOG`. For example: `PACKER_LOG=1 packer build template.json`. Take
|
||||
the *entire* output and create a [gist](https://gist.github.com) for linking
|
||||
to in your issue. Packer should strip sensitive keys from the output,
|
||||
but take a look through just in case.
|
||||
|
||||
* Provide a reproducible test case. If a contributor can't reproduce an
|
||||
issue, then it dramatically lowers the chances it'll get fixed. And in
|
||||
some cases, the issue will eventually be closed.
|
||||
|
||||
@@ -45,15 +45,15 @@ type Builder struct {
|
||||
runner multistep.Runner
|
||||
}
|
||||
|
||||
func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
md, err := common.DecodeConfig(&b.config, raws...)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.config.tpl, err = packer.NewConfigTemplate()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
b.config.tpl.UserVars = b.config.PackerUserVars
|
||||
b.config.tpl.Funcs(awscommon.TemplateFuncs)
|
||||
@@ -140,11 +140,11 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
}
|
||||
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return errs
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
log.Printf("Config: %+v", b.config)
|
||||
return nil
|
||||
log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
|
||||
@@ -26,7 +26,10 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
|
||||
|
||||
// Test good
|
||||
config["ami_name"] = "foo"
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -34,7 +37,10 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
|
||||
// Test bad
|
||||
config["ami_name"] = "foo {{"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -42,7 +48,10 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
|
||||
// Test bad
|
||||
delete(config, "ami_name")
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -53,7 +62,10 @@ func TestBuilderPrepare_ChrootMounts(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
config["chroot_mounts"] = nil
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("err: %s", err)
|
||||
}
|
||||
@@ -61,7 +73,10 @@ func TestBuilderPrepare_ChrootMounts(t *testing.T) {
|
||||
config["chroot_mounts"] = [][]string{
|
||||
[]string{"bad"},
|
||||
}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -71,13 +86,19 @@ func TestBuilderPrepare_SourceAmi(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
config["source_ami"] = ""
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
config["source_ami"] = "foo"
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("err: %s", err)
|
||||
}
|
||||
@@ -88,7 +109,10 @@ func TestBuilderPrepare_CommandWrapper(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
config["command_wrapper"] = "echo hi; {{.Command}}"
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("err: %s", err)
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func (s *StepCopyFiles) Run(state multistep.StateBag) multistep.StepAction {
|
||||
chrootPath := filepath.Join(mountPath, path)
|
||||
log.Printf("Copying '%s' to '%s'", path, chrootPath)
|
||||
|
||||
cmdText, err := wrappedCommand(fmt.Sprintf("cp %s %s", path, chrootPath))
|
||||
cmdText, err := wrappedCommand(fmt.Sprintf("cp --remove-destination %s %s", path, chrootPath))
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error building copy command: %s", err)
|
||||
state.Put("error", err)
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestArtifact_Impl(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
var actual packer.Artifact
|
||||
assert.Implementor(&Artifact{}, &actual, "should be an Artifact")
|
||||
var _ packer.Artifact = new(Artifact)
|
||||
}
|
||||
|
||||
func TestArtifactId(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
expected := `east:foo,west:bar`
|
||||
|
||||
amis := make(map[string]string)
|
||||
@@ -27,12 +21,12 @@ func TestArtifactId(t *testing.T) {
|
||||
}
|
||||
|
||||
result := a.Id()
|
||||
assert.Equal(result, expected, "should match output")
|
||||
if result != expected {
|
||||
t.Fatalf("bad: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestArtifactString(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
expected := `AMIs were created:
|
||||
|
||||
east: foo
|
||||
@@ -44,5 +38,7 @@ west: bar`
|
||||
|
||||
a := &Artifact{Amis: amis}
|
||||
result := a.String()
|
||||
assert.Equal(result, expected, "should match output")
|
||||
if result != expected {
|
||||
t.Fatalf("bad: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBlockDevice(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
ec2Mapping := []ec2.BlockDeviceMapping{
|
||||
ec2.BlockDeviceMapping{
|
||||
DeviceName: "/dev/sdb",
|
||||
@@ -36,6 +34,11 @@ func TestBlockDevice(t *testing.T) {
|
||||
LaunchMappings: []BlockDevice{blockDevice},
|
||||
}
|
||||
|
||||
assert.Equal(ec2Mapping, blockDevices.BuildAMIDevices(), "should match output")
|
||||
assert.Equal(ec2Mapping, blockDevices.BuildLaunchDevices(), "should match output")
|
||||
if !reflect.DeepEqual(ec2Mapping, blockDevices.BuildAMIDevices()) {
|
||||
t.Fatalf("bad: %#v", ec2Mapping)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(ec2Mapping, blockDevices.BuildLaunchDevices()) {
|
||||
t.Fatalf("bad: %#v", ec2Mapping)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ type RunConfig struct {
|
||||
SubnetId string `mapstructure:"subnet_id"`
|
||||
TemporaryKeyPairName string `mapstructure:"temporary_key_pair_name"`
|
||||
VpcId string `mapstructure:"vpc_id"`
|
||||
AvailabilityZone string `mapstructure:"availability_zone"`
|
||||
|
||||
// Unexported fields that are calculated from others
|
||||
sshTimeout time.Duration
|
||||
@@ -83,6 +84,7 @@ func (c *RunConfig) Prepare(t *packer.ConfigTemplate) []error {
|
||||
"subnet_id": &c.SubnetId,
|
||||
"temporary_key_pair_name": &c.TemporaryKeyPairName,
|
||||
"vpc_id": &c.VpcId,
|
||||
"availability_zone": &c.AvailabilityZone,
|
||||
}
|
||||
|
||||
for n, ptr := range templates {
|
||||
|
||||
@@ -62,11 +62,16 @@ func InstanceStateRefreshFunc(conn *ec2.EC2, i *ec2.Instance) StateRefreshFunc {
|
||||
return func() (interface{}, string, error) {
|
||||
resp, err := conn.Instances([]string{i.InstanceId}, ec2.NewFilter())
|
||||
if err != nil {
|
||||
log.Printf("Error on InstanceStateRefresh: %s", err)
|
||||
return nil, "", err
|
||||
if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
|
||||
// Set this to nil as if we didn't find anything.
|
||||
resp = nil
|
||||
} else {
|
||||
log.Printf("Error on InstanceStateRefresh: %s", err)
|
||||
return nil, "", err
|
||||
}
|
||||
}
|
||||
|
||||
if len(resp.Reservations) == 0 || len(resp.Reservations[0].Instances) == 0 {
|
||||
if resp == nil || len(resp.Reservations) == 0 || len(resp.Reservations[0].Instances) == 0 {
|
||||
// Sometimes AWS just has consistency issues and doesn't see
|
||||
// our instance yet. Return an empty state.
|
||||
return nil, "", nil
|
||||
|
||||
@@ -18,6 +18,7 @@ type StepRunSourceInstance struct {
|
||||
SourceAMI string
|
||||
IamInstanceProfile string
|
||||
SubnetId string
|
||||
AvailabilityZone string
|
||||
BlockDevices BlockDevices
|
||||
|
||||
instance *ec2.Instance
|
||||
@@ -51,6 +52,7 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi
|
||||
IamInstanceProfile: s.IamInstanceProfile,
|
||||
SubnetId: s.SubnetId,
|
||||
BlockDevices: s.BlockDevices.BuildLaunchDevices(),
|
||||
AvailZone: s.AvailabilityZone,
|
||||
}
|
||||
|
||||
ui.Say("Launching a source AWS instance...")
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/identifier"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/common/uuid"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"time"
|
||||
@@ -35,7 +34,7 @@ func (s *StepSecurityGroup) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
// Create the group
|
||||
ui.Say("Creating temporary security group for this instance...")
|
||||
groupName := fmt.Sprintf("packer %s", hex.EncodeToString(identifier.NewUUID().Raw()))
|
||||
groupName := fmt.Sprintf("packer %s", uuid.TimeOrderedUUID())
|
||||
log.Printf("Temporary group name: %s", groupName)
|
||||
group := ec2.SecurityGroup{
|
||||
Name: groupName,
|
||||
|
||||
@@ -33,15 +33,15 @@ type Builder struct {
|
||||
runner multistep.Runner
|
||||
}
|
||||
|
||||
func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
md, err := common.DecodeConfig(&b.config, raws...)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.config.tpl, err = packer.NewConfigTemplate()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
b.config.tpl.UserVars = b.config.PackerUserVars
|
||||
b.config.tpl.Funcs(awscommon.TemplateFuncs)
|
||||
@@ -53,11 +53,11 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(b.config.tpl)...)
|
||||
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return errs
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
log.Printf("Config: %+v", b.config)
|
||||
return nil
|
||||
log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
@@ -101,6 +101,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
SourceAMI: b.config.SourceAmi,
|
||||
IamInstanceProfile: b.config.IamInstanceProfile,
|
||||
SubnetId: b.config.SubnetId,
|
||||
AvailabilityZone: b.config.AvailabilityZone,
|
||||
BlockDevices: b.config.BlockDevices,
|
||||
},
|
||||
&common.StepConnectSSH{
|
||||
|
||||
@@ -31,7 +31,10 @@ func TestBuilder_Prepare_BadType(t *testing.T) {
|
||||
"access_key": []string{},
|
||||
}
|
||||
|
||||
err := b.Prepare(c)
|
||||
warnings, err := b.Prepare(c)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("prepare should fail")
|
||||
}
|
||||
@@ -43,7 +46,10 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
|
||||
|
||||
// Test good
|
||||
config["ami_name"] = "foo"
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -51,7 +57,10 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
|
||||
// Test bad
|
||||
config["ami_name"] = "foo {{"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -59,7 +68,10 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
|
||||
// Test bad
|
||||
delete(config, "ami_name")
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -71,7 +83,10 @@ func TestBuilderPrepare_InvalidKey(t *testing.T) {
|
||||
|
||||
// Add a random key
|
||||
config["i_should_not_be_valid"] = true
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
@@ -45,15 +45,15 @@ type Builder struct {
|
||||
runner multistep.Runner
|
||||
}
|
||||
|
||||
func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
md, err := common.DecodeConfig(&b.config, raws...)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.config.tpl, err = packer.NewConfigTemplate()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
b.config.tpl.UserVars = b.config.PackerUserVars
|
||||
b.config.tpl.Funcs(awscommon.TemplateFuncs)
|
||||
@@ -156,11 +156,11 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
}
|
||||
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return errs
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
log.Printf("Config: %+v", b.config)
|
||||
return nil
|
||||
log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
@@ -204,6 +204,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
UserDataFile: b.config.UserDataFile,
|
||||
SourceAMI: b.config.SourceAmi,
|
||||
SubnetId: b.config.SubnetId,
|
||||
AvailabilityZone: b.config.AvailabilityZone,
|
||||
BlockDevices: b.config.BlockDevices,
|
||||
},
|
||||
&common.StepConnectSSH{
|
||||
|
||||
@@ -40,19 +40,28 @@ func TestBuilderPrepare_AccountId(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
config["account_id"] = ""
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
config["account_id"] = "foo"
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("err: %s", err)
|
||||
}
|
||||
|
||||
config["account_id"] = "0123-0456-7890"
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -68,7 +77,10 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
|
||||
|
||||
// Test good
|
||||
config["ami_name"] = "foo"
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -76,7 +88,10 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
|
||||
// Test bad
|
||||
config["ami_name"] = "foo {{"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -84,7 +99,10 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
|
||||
// Test bad
|
||||
delete(config, "ami_name")
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -95,7 +113,10 @@ func TestBuilderPrepare_BundleDestination(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
config["bundle_destination"] = ""
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -110,7 +131,10 @@ func TestBuilderPrepare_BundlePrefix(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
config["bundle_prefix"] = ""
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -126,7 +150,10 @@ func TestBuilderPrepare_InvalidKey(t *testing.T) {
|
||||
|
||||
// Add a random key
|
||||
config["i_should_not_be_valid"] = true
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -137,13 +164,19 @@ func TestBuilderPrepare_S3Bucket(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
config["s3_bucket"] = ""
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
config["s3_bucket"] = "foo"
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("err: %s", err)
|
||||
}
|
||||
@@ -154,13 +187,19 @@ func TestBuilderPrepare_X509CertPath(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
config["x509_cert_path"] = ""
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
config["x509_cert_path"] = "i/am/a/file/that/doesnt/exist"
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Error("should have error")
|
||||
}
|
||||
@@ -172,7 +211,10 @@ func TestBuilderPrepare_X509CertPath(t *testing.T) {
|
||||
defer os.Remove(tf.Name())
|
||||
|
||||
config["x509_cert_path"] = tf.Name()
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -183,13 +225,19 @@ func TestBuilderPrepare_X509KeyPath(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
config["x509_key_path"] = ""
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
config["x509_key_path"] = "i/am/a/file/that/doesnt/exist"
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Error("should have error")
|
||||
}
|
||||
@@ -201,7 +249,10 @@ func TestBuilderPrepare_X509KeyPath(t *testing.T) {
|
||||
defer os.Remove(tf.Name())
|
||||
|
||||
config["x509_key_path"] = tf.Name()
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -212,7 +263,10 @@ func TestBuilderPrepare_X509UploadPath(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
config["x509_upload_path"] = ""
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
@@ -227,7 +227,13 @@ func NewRequest(d DigitalOceanClient, path string, params url.Values) (map[strin
|
||||
}
|
||||
|
||||
if status == "ERROR" {
|
||||
status = decodedResponse["message"].(string)
|
||||
statusRaw, ok := decodedResponse["message"]
|
||||
if ok {
|
||||
status = statusRaw.(string)
|
||||
} else {
|
||||
status = fmt.Sprintf(
|
||||
"Unknown error. Full response body: %s", body)
|
||||
}
|
||||
}
|
||||
|
||||
lastErr = errors.New(fmt.Sprintf("Received error from DigitalOcean (%d): %s",
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/common/uuid"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"os"
|
||||
@@ -30,6 +31,7 @@ type config struct {
|
||||
ImageID uint `mapstructure:"image_id"`
|
||||
|
||||
SnapshotName string `mapstructure:"snapshot_name"`
|
||||
DropletName string `mapstructure:"droplet_name"`
|
||||
SSHUsername string `mapstructure:"ssh_username"`
|
||||
SSHPort uint `mapstructure:"ssh_port"`
|
||||
|
||||
@@ -49,15 +51,15 @@ type Builder struct {
|
||||
runner multistep.Runner
|
||||
}
|
||||
|
||||
func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
md, err := common.DecodeConfig(&b.config, raws...)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.config.tpl, err = packer.NewConfigTemplate()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
b.config.tpl.UserVars = b.config.PackerUserVars
|
||||
|
||||
@@ -95,6 +97,11 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
b.config.SnapshotName = "packer-{{timestamp}}"
|
||||
}
|
||||
|
||||
if b.config.DropletName == "" {
|
||||
// Default to packer-[time-ordered-uuid]
|
||||
b.config.DropletName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
|
||||
}
|
||||
|
||||
if b.config.SSHUsername == "" {
|
||||
// Default to "root". You can override this if your
|
||||
// SourceImage has a different user account then the DO default
|
||||
@@ -121,6 +128,7 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
"client_id": &b.config.ClientID,
|
||||
"api_key": &b.config.APIKey,
|
||||
"snapshot_name": &b.config.SnapshotName,
|
||||
"droplet_name": &b.config.DropletName,
|
||||
"ssh_username": &b.config.SSHUsername,
|
||||
"ssh_timeout": &b.config.RawSSHTimeout,
|
||||
"state_timeout": &b.config.RawStateTimeout,
|
||||
@@ -161,11 +169,11 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
b.config.stateTimeout = stateTimeout
|
||||
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return errs
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
log.Printf("Config: %+v", b.config)
|
||||
return nil
|
||||
common.ScrubConfig(b.config, b.config.ClientID, b.config.APIKey)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
|
||||
@@ -34,7 +34,10 @@ func TestBuilder_Prepare_BadType(t *testing.T) {
|
||||
"api_key": []string{},
|
||||
}
|
||||
|
||||
err := b.Prepare(c)
|
||||
warnings, err := b.Prepare(c)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("prepare should fail")
|
||||
}
|
||||
@@ -46,7 +49,10 @@ func TestBuilderPrepare_APIKey(t *testing.T) {
|
||||
|
||||
// Test good
|
||||
config["api_key"] = "foo"
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -58,7 +64,10 @@ func TestBuilderPrepare_APIKey(t *testing.T) {
|
||||
// Test bad
|
||||
delete(config, "api_key")
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -67,7 +76,10 @@ func TestBuilderPrepare_APIKey(t *testing.T) {
|
||||
delete(config, "api_key")
|
||||
os.Setenv("DIGITALOCEAN_API_KEY", "foo")
|
||||
defer os.Setenv("DIGITALOCEAN_API_KEY", "")
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -79,7 +91,10 @@ func TestBuilderPrepare_ClientID(t *testing.T) {
|
||||
|
||||
// Test good
|
||||
config["client_id"] = "foo"
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -91,7 +106,10 @@ func TestBuilderPrepare_ClientID(t *testing.T) {
|
||||
// Test bad
|
||||
delete(config, "client_id")
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -100,7 +118,10 @@ func TestBuilderPrepare_ClientID(t *testing.T) {
|
||||
delete(config, "client_id")
|
||||
os.Setenv("DIGITALOCEAN_CLIENT_ID", "foo")
|
||||
defer os.Setenv("DIGITALOCEAN_CLIENT_ID", "")
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -112,7 +133,10 @@ func TestBuilderPrepare_InvalidKey(t *testing.T) {
|
||||
|
||||
// Add a random key
|
||||
config["i_should_not_be_valid"] = true
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -123,7 +147,10 @@ func TestBuilderPrepare_RegionID(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
// Test default
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -135,7 +162,10 @@ func TestBuilderPrepare_RegionID(t *testing.T) {
|
||||
// Test set
|
||||
config["region_id"] = 2
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -150,7 +180,10 @@ func TestBuilderPrepare_SizeID(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
// Test default
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -162,7 +195,10 @@ func TestBuilderPrepare_SizeID(t *testing.T) {
|
||||
// Test set
|
||||
config["size_id"] = 67
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -177,7 +213,10 @@ func TestBuilderPrepare_ImageID(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
// Test default
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -189,7 +228,10 @@ func TestBuilderPrepare_ImageID(t *testing.T) {
|
||||
// Test set
|
||||
config["size_id"] = 2
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -204,7 +246,10 @@ func TestBuilderPrepare_SSHUsername(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
// Test default
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -216,7 +261,10 @@ func TestBuilderPrepare_SSHUsername(t *testing.T) {
|
||||
// Test set
|
||||
config["ssh_username"] = "foo"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -231,7 +279,10 @@ func TestBuilderPrepare_SSHTimeout(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
// Test default
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -243,7 +294,10 @@ func TestBuilderPrepare_SSHTimeout(t *testing.T) {
|
||||
// Test set
|
||||
config["ssh_timeout"] = "30s"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -251,7 +305,10 @@ func TestBuilderPrepare_SSHTimeout(t *testing.T) {
|
||||
// Test bad
|
||||
config["ssh_timeout"] = "tubes"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -263,7 +320,10 @@ func TestBuilderPrepare_StateTimeout(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
// Test default
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -275,7 +335,10 @@ func TestBuilderPrepare_StateTimeout(t *testing.T) {
|
||||
// Test set
|
||||
config["state_timeout"] = "5m"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -283,7 +346,10 @@ func TestBuilderPrepare_StateTimeout(t *testing.T) {
|
||||
// Test bad
|
||||
config["state_timeout"] = "tubes"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -295,7 +361,10 @@ func TestBuilderPrepare_SnapshotName(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
// Test default
|
||||
err := b.Prepare(config)
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -307,7 +376,10 @@ func TestBuilderPrepare_SnapshotName(t *testing.T) {
|
||||
// Test set
|
||||
config["snapshot_name"] = "foobarbaz"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -315,7 +387,10 @@ func TestBuilderPrepare_SnapshotName(t *testing.T) {
|
||||
// Test set with template
|
||||
config["snapshot_name"] = "{{timestamp}}"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -326,3 +401,55 @@ func TestBuilderPrepare_SnapshotName(t *testing.T) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_DropletName(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// Test default
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
if b.config.DropletName == "" {
|
||||
t.Errorf("invalid: %s", b.config.DropletName)
|
||||
}
|
||||
|
||||
// Test normal set
|
||||
config["droplet_name"] = "foobar"
|
||||
b = Builder{}
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
// Test with template
|
||||
config["droplet_name"] = "foobar-{{timestamp}}"
|
||||
b = Builder{}
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
// Test with bad template
|
||||
config["droplet_name"] = "foobar-{{"
|
||||
b = Builder{}
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package digitalocean
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/identifier"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
@@ -20,11 +18,9 @@ func (s *stepCreateDroplet) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
ui.Say("Creating droplet...")
|
||||
|
||||
// Some random droplet name as it's temporary
|
||||
name := fmt.Sprintf("packer-%s", hex.EncodeToString(identifier.NewUUID().Raw()))
|
||||
|
||||
// Create the droplet based on configuration
|
||||
dropletId, err := client.CreateDroplet(name, c.SizeID, c.ImageID, c.RegionID, sshKeyId)
|
||||
dropletId, err := client.CreateDroplet(c.DropletName, c.SizeID, c.ImageID, c.RegionID, sshKeyId)
|
||||
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating droplet: %s", err)
|
||||
state.Put("error", err)
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package digitalocean
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/identifier"
|
||||
"code.google.com/p/go.crypto/ssh"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/common/uuid"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
)
|
||||
@@ -43,7 +42,7 @@ func (s *stepCreateSSHKey) Run(state multistep.StateBag) multistep.StepAction {
|
||||
pub_sshformat := string(ssh.MarshalAuthorizedKey(pub))
|
||||
|
||||
// The name of the public key on DO
|
||||
name := fmt.Sprintf("packer-%s", hex.EncodeToString(identifier.NewUUID().Raw()))
|
||||
name := fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
|
||||
|
||||
// Create the key!
|
||||
keyId, err := client.CreateKey(name, pub_sshformat)
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
package openstack
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestArtifact_Impl(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
var actual packer.Artifact
|
||||
assert.Implementor(&Artifact{}, &actual, "should be an Artifact")
|
||||
var _ packer.Artifact = new(Artifact)
|
||||
}
|
||||
|
||||
func TestArtifactId(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
expected := `b8cdf55b-c916-40bd-b190-389ec144c4ed`
|
||||
|
||||
a := &Artifact{
|
||||
@@ -23,17 +17,19 @@ func TestArtifactId(t *testing.T) {
|
||||
}
|
||||
|
||||
result := a.Id()
|
||||
assert.Equal(result, expected, "should match output")
|
||||
if result != expected {
|
||||
t.Fatalf("bad: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestArtifactString(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
expected := "An image was created: b8cdf55b-c916-40bd-b190-389ec144c4ed"
|
||||
|
||||
a := &Artifact{
|
||||
ImageId: "b8cdf55b-c916-40bd-b190-389ec144c4ed",
|
||||
}
|
||||
result := a.String()
|
||||
assert.Equal(result, expected, "should match output")
|
||||
if result != expected {
|
||||
t.Fatalf("bad: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,15 +29,15 @@ type Builder struct {
|
||||
runner multistep.Runner
|
||||
}
|
||||
|
||||
func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
md, err := common.DecodeConfig(&b.config, raws...)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.config.tpl, err = packer.NewConfigTemplate()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
b.config.tpl.UserVars = b.config.PackerUserVars
|
||||
|
||||
@@ -48,11 +48,11 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(b.config.tpl)...)
|
||||
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return errs
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
log.Printf("Config: %+v", b.config)
|
||||
return nil
|
||||
log.Println(common.ScrubConfig(b.config, b.config.Password))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
|
||||
@@ -32,7 +32,10 @@ func TestBuilder_Prepare_BadType(t *testing.T) {
|
||||
"password": []string{},
|
||||
}
|
||||
|
||||
err := b.Prepare(c)
|
||||
warns, err := b.Prepare(c)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("prepare should fail")
|
||||
}
|
||||
@@ -44,7 +47,10 @@ func TestBuilderPrepare_ImageName(t *testing.T) {
|
||||
|
||||
// Test good
|
||||
config["image_name"] = "foo"
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -52,7 +58,10 @@ func TestBuilderPrepare_ImageName(t *testing.T) {
|
||||
// Test bad
|
||||
config["image_name"] = "foo {{"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -60,7 +69,10 @@ func TestBuilderPrepare_ImageName(t *testing.T) {
|
||||
// Test bad
|
||||
delete(config, "image_name")
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -72,7 +84,10 @@ func TestBuilderPrepare_InvalidKey(t *testing.T) {
|
||||
|
||||
// Add a random key
|
||||
config["i_should_not_be_valid"] = true
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package openstack
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/identifier"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/common/uuid"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/rackspace/gophercloud"
|
||||
"log"
|
||||
@@ -19,7 +18,7 @@ func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Creating temporary keypair for this instance...")
|
||||
keyName := fmt.Sprintf("packer %s", hex.EncodeToString(identifier.NewUUID().Raw()))
|
||||
keyName := fmt.Sprintf("packer %s", uuid.TimeOrderedUUID())
|
||||
log.Printf("temporary keypair name: %s", keyName)
|
||||
keyResp, err := csp.CreateKeyPair(gophercloud.NewKeyPair{Name: keyName})
|
||||
if err != nil {
|
||||
|
||||
@@ -16,6 +16,14 @@ import (
|
||||
|
||||
const BuilderId = "mitchellh.virtualbox"
|
||||
|
||||
// These are the different valid mode values for "guest_additions_mode" which
|
||||
// determine how guest additions are delivered to the guest.
|
||||
const (
|
||||
GuestAdditionsModeDisable string = "disable"
|
||||
GuestAdditionsModeAttach = "attach"
|
||||
GuestAdditionsModeUpload = "upload"
|
||||
)
|
||||
|
||||
type Builder struct {
|
||||
config config
|
||||
runner multistep.Runner
|
||||
@@ -28,7 +36,7 @@ type config struct {
|
||||
DiskSize uint `mapstructure:"disk_size"`
|
||||
FloppyFiles []string `mapstructure:"floppy_files"`
|
||||
Format string `mapstructure:"format"`
|
||||
GuestAdditionsAttach bool `mapstructure:"guest_additions_attach"`
|
||||
GuestAdditionsMode string `mapstructure:"guest_additions_mode"`
|
||||
GuestAdditionsPath string `mapstructure:"guest_additions_path"`
|
||||
GuestAdditionsURL string `mapstructure:"guest_additions_url"`
|
||||
GuestAdditionsSHA256 string `mapstructure:"guest_additions_sha256"`
|
||||
@@ -64,20 +72,21 @@ type config struct {
|
||||
tpl *packer.ConfigTemplate
|
||||
}
|
||||
|
||||
func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
md, err := common.DecodeConfig(&b.config, raws...)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.config.tpl, err = packer.NewConfigTemplate()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
b.config.tpl.UserVars = b.config.PackerUserVars
|
||||
|
||||
// Accumulate any errors
|
||||
// Accumulate any errors and warnings
|
||||
errs := common.CheckUnusedConfig(md)
|
||||
warnings := make([]string, 0)
|
||||
|
||||
if b.config.DiskSize == 0 {
|
||||
b.config.DiskSize = 40000
|
||||
@@ -87,6 +96,10 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
b.config.FloppyFiles = make([]string, 0)
|
||||
}
|
||||
|
||||
if b.config.GuestAdditionsMode == "" {
|
||||
b.config.GuestAdditionsMode = "upload"
|
||||
}
|
||||
|
||||
if b.config.GuestAdditionsPath == "" {
|
||||
b.config.GuestAdditionsPath = "VBoxGuestAdditions.iso"
|
||||
}
|
||||
@@ -145,6 +158,7 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
|
||||
// Errors
|
||||
templates := map[string]*string{
|
||||
"guest_additions_mode": &b.config.GuestAdditionsMode,
|
||||
"guest_additions_sha256": &b.config.GuestAdditionsSHA256,
|
||||
"guest_os_type": &b.config.GuestOSType,
|
||||
"hard_drive_interface": &b.config.HardDriveInterface,
|
||||
@@ -154,6 +168,7 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
"iso_url": &b.config.RawSingleISOUrl,
|
||||
"output_directory": &b.config.OutputDir,
|
||||
"shutdown_command": &b.config.ShutdownCommand,
|
||||
"ssh_key_path": &b.config.SSHKeyPath,
|
||||
"ssh_password": &b.config.SSHPassword,
|
||||
"ssh_username": &b.config.SSHUser,
|
||||
"virtualbox_version_file": &b.config.VBoxVersionFile,
|
||||
@@ -263,6 +278,25 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
}
|
||||
}
|
||||
|
||||
validMode := false
|
||||
validModes := []string{
|
||||
GuestAdditionsModeDisable,
|
||||
GuestAdditionsModeAttach,
|
||||
GuestAdditionsModeUpload,
|
||||
}
|
||||
|
||||
for _, mode := range validModes {
|
||||
if b.config.GuestAdditionsMode == mode {
|
||||
validMode = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !validMode {
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
fmt.Errorf("guest_additions_mode is invalid. Must be one of: %v", validModes))
|
||||
}
|
||||
|
||||
if b.config.GuestAdditionsSHA256 != "" {
|
||||
b.config.GuestAdditionsSHA256 = strings.ToLower(b.config.GuestAdditionsSHA256)
|
||||
}
|
||||
@@ -330,11 +364,18 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
}
|
||||
}
|
||||
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return errs
|
||||
// Warnings
|
||||
if b.config.ShutdownCommand == "" {
|
||||
warnings = append(warnings,
|
||||
"A shutdown_command was not specified. Without a shutdown command, Packer\n"+
|
||||
"will forcibly halt the virtual machine, which may result in data loss.")
|
||||
}
|
||||
|
||||
return nil
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return warnings, errs
|
||||
}
|
||||
|
||||
return warnings, nil
|
||||
}
|
||||
|
||||
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
|
||||
@@ -43,6 +43,7 @@ func testConfig() map[string]interface{} {
|
||||
"iso_checksum": "foo",
|
||||
"iso_checksum_type": "md5",
|
||||
"iso_url": "http://www.google.com/",
|
||||
"shutdown_command": "yes",
|
||||
"ssh_username": "foo",
|
||||
|
||||
packer.BuildNameConfigKey: "foo",
|
||||
@@ -60,11 +61,18 @@ func TestBuilder_ImplementsBuilder(t *testing.T) {
|
||||
func TestBuilderPrepare_Defaults(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
if b.config.GuestAdditionsMode != GuestAdditionsModeUpload {
|
||||
t.Errorf("bad guest additions mode: %s", b.config.GuestAdditionsMode)
|
||||
}
|
||||
|
||||
if b.config.GuestOSType != "Other" {
|
||||
t.Errorf("bad guest OS type: %s", b.config.GuestOSType)
|
||||
}
|
||||
@@ -100,7 +108,10 @@ func TestBuilderPrepare_BootWait(t *testing.T) {
|
||||
|
||||
// Test a default boot_wait
|
||||
delete(config, "boot_wait")
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -111,7 +122,10 @@ func TestBuilderPrepare_BootWait(t *testing.T) {
|
||||
|
||||
// Test with a bad boot_wait
|
||||
config["boot_wait"] = "this is not good"
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -119,7 +133,10 @@ func TestBuilderPrepare_BootWait(t *testing.T) {
|
||||
// Test with a good one
|
||||
config["boot_wait"] = "5s"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -130,7 +147,10 @@ func TestBuilderPrepare_DiskSize(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
delete(config, "disk_size")
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("bad err: %s", err)
|
||||
}
|
||||
@@ -141,7 +161,10 @@ func TestBuilderPrepare_DiskSize(t *testing.T) {
|
||||
|
||||
config["disk_size"] = 60000
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -156,7 +179,10 @@ func TestBuilderPrepare_FloppyFiles(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
delete(config, "floppy_files")
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("bad err: %s", err)
|
||||
}
|
||||
@@ -167,7 +193,10 @@ func TestBuilderPrepare_FloppyFiles(t *testing.T) {
|
||||
|
||||
config["floppy_files"] = []string{"foo", "bar"}
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -178,12 +207,56 @@ func TestBuilderPrepare_FloppyFiles(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_GuestAdditionsMode(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// test default mode
|
||||
delete(config, "guest_additions_mode")
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("bad err: %s", err)
|
||||
}
|
||||
|
||||
// Test another mode
|
||||
config["guest_additions_mode"] = "attach"
|
||||
b = Builder{}
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
if b.config.GuestAdditionsMode != GuestAdditionsModeAttach {
|
||||
t.Fatalf("bad: %s", b.config.GuestAdditionsMode)
|
||||
}
|
||||
|
||||
// Test bad mode
|
||||
config["guest_additions_mode"] = "teleport"
|
||||
b = Builder{}
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_GuestAdditionsPath(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
delete(config, "guest_additions_path")
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("bad err: %s", err)
|
||||
}
|
||||
@@ -194,7 +267,10 @@ func TestBuilderPrepare_GuestAdditionsPath(t *testing.T) {
|
||||
|
||||
config["guest_additions_path"] = "foo"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -209,7 +285,10 @@ func TestBuilderPrepare_GuestAdditionsSHA256(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
delete(config, "guest_additions_sha256")
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("bad err: %s", err)
|
||||
}
|
||||
@@ -220,7 +299,10 @@ func TestBuilderPrepare_GuestAdditionsSHA256(t *testing.T) {
|
||||
|
||||
config["guest_additions_sha256"] = "FOO"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -235,7 +317,10 @@ func TestBuilderPrepare_GuestAdditionsURL(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
config["guest_additions_url"] = ""
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -246,7 +331,10 @@ func TestBuilderPrepare_GuestAdditionsURL(t *testing.T) {
|
||||
|
||||
config["guest_additions_url"] = "http://www.packer.io"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("should not have error: %s", err)
|
||||
}
|
||||
@@ -258,7 +346,10 @@ func TestBuilderPrepare_HardDriveInterface(t *testing.T) {
|
||||
|
||||
// Test a default boot_wait
|
||||
delete(config, "hard_drive_interface")
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -270,7 +361,10 @@ func TestBuilderPrepare_HardDriveInterface(t *testing.T) {
|
||||
// Test with a bad
|
||||
config["hard_drive_interface"] = "fake"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -278,7 +372,10 @@ func TestBuilderPrepare_HardDriveInterface(t *testing.T) {
|
||||
// Test with a good
|
||||
config["hard_drive_interface"] = "sata"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -291,7 +388,10 @@ func TestBuilderPrepare_HTTPPort(t *testing.T) {
|
||||
// Bad
|
||||
config["http_port_min"] = 1000
|
||||
config["http_port_max"] = 500
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -299,7 +399,10 @@ func TestBuilderPrepare_HTTPPort(t *testing.T) {
|
||||
// Bad
|
||||
config["http_port_min"] = -500
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -308,7 +411,10 @@ func TestBuilderPrepare_HTTPPort(t *testing.T) {
|
||||
config["http_port_min"] = 500
|
||||
config["http_port_max"] = 1000
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -320,7 +426,10 @@ func TestBuilderPrepare_Format(t *testing.T) {
|
||||
|
||||
// Bad
|
||||
config["format"] = "illegal value"
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -328,7 +437,10 @@ func TestBuilderPrepare_Format(t *testing.T) {
|
||||
// Good
|
||||
config["format"] = "ova"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -336,7 +448,10 @@ func TestBuilderPrepare_Format(t *testing.T) {
|
||||
// Good
|
||||
config["format"] = "ovf"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -348,7 +463,10 @@ func TestBuilderPrepare_InvalidKey(t *testing.T) {
|
||||
|
||||
// Add a random key
|
||||
config["i_should_not_be_valid"] = true
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -360,7 +478,10 @@ func TestBuilderPrepare_ISOChecksum(t *testing.T) {
|
||||
|
||||
// Test bad
|
||||
config["iso_checksum"] = ""
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -368,7 +489,10 @@ func TestBuilderPrepare_ISOChecksum(t *testing.T) {
|
||||
// Test good
|
||||
config["iso_checksum"] = "FOo"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -384,7 +508,10 @@ func TestBuilderPrepare_ISOChecksumType(t *testing.T) {
|
||||
|
||||
// Test bad
|
||||
config["iso_checksum_type"] = ""
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -392,7 +519,10 @@ func TestBuilderPrepare_ISOChecksumType(t *testing.T) {
|
||||
// Test good
|
||||
config["iso_checksum_type"] = "mD5"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -404,7 +534,10 @@ func TestBuilderPrepare_ISOChecksumType(t *testing.T) {
|
||||
// Test unknown
|
||||
config["iso_checksum_type"] = "fake"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -419,7 +552,10 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) {
|
||||
// Test both epty
|
||||
config["iso_url"] = ""
|
||||
b = Builder{}
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -427,7 +563,10 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) {
|
||||
// Test iso_url set
|
||||
config["iso_url"] = "http://www.packer.io"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("should not have error: %s", err)
|
||||
}
|
||||
@@ -441,7 +580,10 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) {
|
||||
config["iso_url"] = "http://www.packer.io"
|
||||
config["iso_urls"] = []string{"http://www.packer.io"}
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -454,7 +596,10 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) {
|
||||
}
|
||||
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("should not have error: %s", err)
|
||||
}
|
||||
@@ -481,7 +626,10 @@ func TestBuilderPrepare_OutputDir(t *testing.T) {
|
||||
|
||||
config["output_directory"] = dir
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -489,19 +637,40 @@ func TestBuilderPrepare_OutputDir(t *testing.T) {
|
||||
// Test with a good one
|
||||
config["output_directory"] = "i-hope-i-dont-exist"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_ShutdownCommand(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
delete(config, "shutdown_command")
|
||||
|
||||
warns, err := b.Prepare(config)
|
||||
if err != nil {
|
||||
t.Fatalf("bad: %s", err)
|
||||
}
|
||||
|
||||
if len(warns) != 1 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_ShutdownTimeout(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// Test with a bad value
|
||||
config["shutdown_timeout"] = "this is not good"
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -509,7 +678,10 @@ func TestBuilderPrepare_ShutdownTimeout(t *testing.T) {
|
||||
// Test with a good one
|
||||
config["shutdown_timeout"] = "5s"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -523,7 +695,10 @@ func TestBuilderPrepare_SSHHostPort(t *testing.T) {
|
||||
config["ssh_host_port_min"] = 1000
|
||||
config["ssh_host_port_max"] = 500
|
||||
b = Builder{}
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -531,7 +706,10 @@ func TestBuilderPrepare_SSHHostPort(t *testing.T) {
|
||||
// Bad
|
||||
config["ssh_host_port_min"] = -500
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -540,7 +718,10 @@ func TestBuilderPrepare_SSHHostPort(t *testing.T) {
|
||||
config["ssh_host_port_min"] = 500
|
||||
config["ssh_host_port_max"] = 1000
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -552,14 +733,20 @@ func TestBuilderPrepare_sshKeyPath(t *testing.T) {
|
||||
|
||||
config["ssh_key_path"] = ""
|
||||
b = Builder{}
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
config["ssh_key_path"] = "/i/dont/exist"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -578,7 +765,10 @@ func TestBuilderPrepare_sshKeyPath(t *testing.T) {
|
||||
|
||||
config["ssh_key_path"] = tf.Name()
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -589,7 +779,10 @@ func TestBuilderPrepare_sshKeyPath(t *testing.T) {
|
||||
tf.Write([]byte(testPem))
|
||||
config["ssh_key_path"] = tf.Name()
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -601,14 +794,20 @@ func TestBuilderPrepare_SSHUser(t *testing.T) {
|
||||
|
||||
config["ssh_username"] = ""
|
||||
b = Builder{}
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
config["ssh_username"] = "exists"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -620,7 +819,10 @@ func TestBuilderPrepare_SSHWaitTimeout(t *testing.T) {
|
||||
|
||||
// Test a default boot_wait
|
||||
delete(config, "ssh_wait_timeout")
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -632,7 +834,10 @@ func TestBuilderPrepare_SSHWaitTimeout(t *testing.T) {
|
||||
// Test with a bad value
|
||||
config["ssh_wait_timeout"] = "this is not good"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -640,7 +845,10 @@ func TestBuilderPrepare_SSHWaitTimeout(t *testing.T) {
|
||||
// Test with a good one
|
||||
config["ssh_wait_timeout"] = "5s"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -652,7 +860,10 @@ func TestBuilderPrepare_VBoxManage(t *testing.T) {
|
||||
|
||||
// Test with empty
|
||||
delete(config, "vboxmanage")
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -667,7 +878,10 @@ func TestBuilderPrepare_VBoxManage(t *testing.T) {
|
||||
}
|
||||
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -687,7 +901,10 @@ func TestBuilderPrepare_VBoxVersionFile(t *testing.T) {
|
||||
|
||||
// Test empty
|
||||
delete(config, "virtualbox_version_file")
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -699,7 +916,10 @@ func TestBuilderPrepare_VBoxVersionFile(t *testing.T) {
|
||||
// Test with a good one
|
||||
config["virtualbox_version_file"] = "foo"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
@@ -11,8 +11,15 @@ import (
|
||||
)
|
||||
|
||||
// A driver is able to talk to VirtualBox and perform certain
|
||||
// operations with it.
|
||||
// operations with it. Some of the operations on here may seem overly
|
||||
// specific, but they were built specifically in mind to handle features
|
||||
// of the VirtualBox builder for Packer, and to abstract differences in
|
||||
// versions out of the builder steps, so sometimes the methods are
|
||||
// extremely specific.
|
||||
type Driver interface {
|
||||
// Create a SATA controller.
|
||||
CreateSATAController(vm string, controller string) error
|
||||
|
||||
// Checks if the VM with the given name is running.
|
||||
IsRunning(string) (bool, error)
|
||||
|
||||
@@ -40,6 +47,27 @@ type VBox42Driver struct {
|
||||
VBoxManagePath string
|
||||
}
|
||||
|
||||
func (d *VBox42Driver) CreateSATAController(vmName string, name string) error {
|
||||
version, err := d.Version()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
portCountArg := "--sataportcount"
|
||||
if strings.HasPrefix(version, "4.3") {
|
||||
portCountArg = "--portcount"
|
||||
}
|
||||
|
||||
command := []string{
|
||||
"storagectl", vmName,
|
||||
"--name", name,
|
||||
"--add", "sata",
|
||||
portCountArg, "1",
|
||||
}
|
||||
|
||||
return d.VBoxManage(command...)
|
||||
}
|
||||
|
||||
func (d *VBox42Driver) IsRunning(name string) (bool, error) {
|
||||
var stdout bytes.Buffer
|
||||
|
||||
@@ -135,9 +163,17 @@ func (d *VBox42Driver) Version() (string, error) {
|
||||
|
||||
versionOutput := strings.TrimSpace(stdout.String())
|
||||
log.Printf("VBoxManage --version output: %s", versionOutput)
|
||||
|
||||
// If the "--version" output contains vboxdrv, then this is indicative
|
||||
// of problems with the VirtualBox setup and we shouldn't really continue,
|
||||
// whether or not we can read the version.
|
||||
if strings.Contains(versionOutput, "vboxdrv") {
|
||||
return "", fmt.Errorf("VirtualBox is not properly setup: %s", versionOutput)
|
||||
}
|
||||
|
||||
versionRe := regexp.MustCompile("[^.0-9]")
|
||||
matches := versionRe.Split(versionOutput, 2)
|
||||
if len(matches) == 0 {
|
||||
if len(matches) == 0 || matches[0] == "" {
|
||||
return "", fmt.Errorf("No version found: %s", versionOutput)
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ func (s *stepAttachGuestAdditions) Run(state multistep.StateBag) multistep.StepA
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
// If we're not attaching the guest additions then just return
|
||||
if !config.GuestAdditionsAttach {
|
||||
if config.GuestAdditionsMode != GuestAdditionsModeAttach {
|
||||
log.Println("Not attaching guest additions since we're uploading.")
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
@@ -56,13 +56,7 @@ func (s *stepCreateDisk) Run(state multistep.StateBag) multistep.StepAction {
|
||||
// that.
|
||||
if config.HardDriveInterface == "sata" {
|
||||
controllerName = "SATA Controller"
|
||||
command = []string{
|
||||
"storagectl", vmName,
|
||||
"--name", controllerName,
|
||||
"--add", "sata",
|
||||
"--sataportcount", "1",
|
||||
}
|
||||
if err := driver.VBoxManage(command...); err != nil {
|
||||
if err := driver.CreateSATAController(vmName, controllerName); err != nil {
|
||||
err := fmt.Errorf("Error creating disk controller: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
|
||||
@@ -43,7 +43,7 @@ func (s *stepCreateVM) Run(state multistep.StateBag) multistep.StepAction {
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Set the VM name propery on the first command
|
||||
// Set the VM name property on the first command
|
||||
if s.vmName == "" {
|
||||
s.vmName = name
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@ import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
// This step cleans up forwarded ports and exports the VM to an OVF.
|
||||
@@ -21,6 +23,10 @@ func (s *stepExport) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
// Wait a second to ensure VM is really shutdown.
|
||||
log.Println("1 second timeout to ensure VM is really shutdown")
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// Clear out the Packer-created forwarding rule
|
||||
ui.Say("Preparing to export machine...")
|
||||
ui.Message(fmt.Sprintf("Deleting forwarded port mapping for SSH (host port %d)", state.Get("sshHostPort")))
|
||||
|
||||
@@ -25,9 +25,16 @@ func (s *stepForwardSSH) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
log.Printf("Looking for available SSH port between %d and %d", config.SSHHostPortMin, config.SSHHostPortMax)
|
||||
var sshHostPort uint
|
||||
var offset uint = 0
|
||||
|
||||
portRange := int(config.SSHHostPortMax - config.SSHHostPortMin)
|
||||
if portRange > 0 {
|
||||
// Have to check if > 0 to avoid a panic
|
||||
offset = uint(rand.Intn(portRange))
|
||||
}
|
||||
|
||||
for {
|
||||
sshHostPort = uint(rand.Intn(portRange)) + config.SSHHostPortMin
|
||||
sshHostPort = offset + config.SSHHostPortMin
|
||||
log.Printf("Trying port: %d", sshHostPort)
|
||||
l, err := net.Listen("tcp", fmt.Sprintf(":%d", sshHostPort))
|
||||
if err == nil {
|
||||
|
||||
@@ -23,8 +23,8 @@ func (s *stepUploadGuestAdditions) Run(state multistep.StateBag) multistep.StepA
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
// If we're attaching then don't do this, since we attached.
|
||||
if config.GuestAdditionsAttach {
|
||||
log.Println("Not uploading guest additions since we're attaching.")
|
||||
if config.GuestAdditionsMode != GuestAdditionsModeUpload {
|
||||
log.Println("Not uploading guest additions since mode is not upload")
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
|
||||
@@ -66,20 +66,21 @@ type config struct {
|
||||
tpl *packer.ConfigTemplate
|
||||
}
|
||||
|
||||
func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
md, err := common.DecodeConfig(&b.config, raws...)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.config.tpl, err = packer.NewConfigTemplate()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
b.config.tpl.UserVars = b.config.PackerUserVars
|
||||
|
||||
// Accumulate any errors
|
||||
errs := common.CheckUnusedConfig(md)
|
||||
warnings := make([]string, 0)
|
||||
|
||||
if b.config.DiskName == "" {
|
||||
b.config.DiskName = "disk"
|
||||
@@ -148,6 +149,7 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
"iso_url": &b.config.RawSingleISOUrl,
|
||||
"output_directory": &b.config.OutputDir,
|
||||
"shutdown_command": &b.config.ShutdownCommand,
|
||||
"ssh_key_path": &b.config.SSHKeyPath,
|
||||
"ssh_password": &b.config.SSHPassword,
|
||||
"ssh_username": &b.config.SSHUser,
|
||||
"tools_upload_flavor": &b.config.ToolsUploadFlavor,
|
||||
@@ -325,11 +327,18 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||
errs, fmt.Errorf("vnc_port_min must be less than vnc_port_max"))
|
||||
}
|
||||
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return errs
|
||||
// Warnings
|
||||
if b.config.ShutdownCommand == "" {
|
||||
warnings = append(warnings,
|
||||
"A shutdown_command was not specified. Without a shutdown command, Packer\n"+
|
||||
"will forcibly halt the virtual machine, which may result in data loss.")
|
||||
}
|
||||
|
||||
return nil
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return warnings, errs
|
||||
}
|
||||
|
||||
return warnings, nil
|
||||
}
|
||||
|
||||
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
|
||||
+196
-45
@@ -44,6 +44,7 @@ func testConfig() map[string]interface{} {
|
||||
"iso_checksum": "foo",
|
||||
"iso_checksum_type": "md5",
|
||||
"iso_url": "http://www.packer.io",
|
||||
"shutdown_command": "foo",
|
||||
"ssh_username": "foo",
|
||||
|
||||
packer.BuildNameConfigKey: "foo",
|
||||
@@ -64,7 +65,10 @@ func TestBuilderPrepare_BootWait(t *testing.T) {
|
||||
|
||||
// Test a default boot_wait
|
||||
delete(config, "boot_wait")
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -75,7 +79,10 @@ func TestBuilderPrepare_BootWait(t *testing.T) {
|
||||
|
||||
// Test with a bad boot_wait
|
||||
config["boot_wait"] = "this is not good"
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -83,7 +90,10 @@ func TestBuilderPrepare_BootWait(t *testing.T) {
|
||||
// Test with a good one
|
||||
config["boot_wait"] = "5s"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -95,7 +105,10 @@ func TestBuilderPrepare_ISOChecksum(t *testing.T) {
|
||||
|
||||
// Test bad
|
||||
config["iso_checksum"] = ""
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -103,7 +116,10 @@ func TestBuilderPrepare_ISOChecksum(t *testing.T) {
|
||||
// Test good
|
||||
config["iso_checksum"] = "FOo"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -119,7 +135,10 @@ func TestBuilderPrepare_ISOChecksumType(t *testing.T) {
|
||||
|
||||
// Test bad
|
||||
config["iso_checksum_type"] = ""
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -127,7 +146,10 @@ func TestBuilderPrepare_ISOChecksumType(t *testing.T) {
|
||||
// Test good
|
||||
config["iso_checksum_type"] = "mD5"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -139,7 +161,10 @@ func TestBuilderPrepare_ISOChecksumType(t *testing.T) {
|
||||
// Test unknown
|
||||
config["iso_checksum_type"] = "fake"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -147,7 +172,10 @@ func TestBuilderPrepare_ISOChecksumType(t *testing.T) {
|
||||
func TestBuilderPrepare_Defaults(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -174,7 +202,10 @@ func TestBuilderPrepare_DiskSize(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
delete(config, "disk_size")
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("bad err: %s", err)
|
||||
}
|
||||
@@ -185,7 +216,10 @@ func TestBuilderPrepare_DiskSize(t *testing.T) {
|
||||
|
||||
config["disk_size"] = 60000
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -200,7 +234,10 @@ func TestBuilderPrepare_FloppyFiles(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
delete(config, "floppy_files")
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("bad err: %s", err)
|
||||
}
|
||||
@@ -211,7 +248,10 @@ func TestBuilderPrepare_FloppyFiles(t *testing.T) {
|
||||
|
||||
config["floppy_files"] = []string{"foo", "bar"}
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -229,7 +269,10 @@ func TestBuilderPrepare_HTTPPort(t *testing.T) {
|
||||
// Bad
|
||||
config["http_port_min"] = 1000
|
||||
config["http_port_max"] = 500
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -237,7 +280,10 @@ func TestBuilderPrepare_HTTPPort(t *testing.T) {
|
||||
// Bad
|
||||
config["http_port_min"] = -500
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -246,7 +292,10 @@ func TestBuilderPrepare_HTTPPort(t *testing.T) {
|
||||
config["http_port_min"] = 500
|
||||
config["http_port_max"] = 1000
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -258,7 +307,10 @@ func TestBuilderPrepare_InvalidKey(t *testing.T) {
|
||||
|
||||
// Add a random key
|
||||
config["i_should_not_be_valid"] = true
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -273,7 +325,10 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) {
|
||||
// Test both epty
|
||||
config["iso_url"] = ""
|
||||
b = Builder{}
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -281,7 +336,10 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) {
|
||||
// Test iso_url set
|
||||
config["iso_url"] = "http://www.packer.io"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("should not have error: %s", err)
|
||||
}
|
||||
@@ -295,7 +353,10 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) {
|
||||
config["iso_url"] = "http://www.packer.io"
|
||||
config["iso_urls"] = []string{"http://www.packer.io"}
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -308,7 +369,10 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) {
|
||||
}
|
||||
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("should not have error: %s", err)
|
||||
}
|
||||
@@ -335,7 +399,10 @@ func TestBuilderPrepare_OutputDir(t *testing.T) {
|
||||
|
||||
config["output_directory"] = dir
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -343,19 +410,40 @@ func TestBuilderPrepare_OutputDir(t *testing.T) {
|
||||
// Test with a good one
|
||||
config["output_directory"] = "i-hope-i-dont-exist"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_ShutdownCommand(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
delete(config, "shutdown_command")
|
||||
|
||||
warns, err := b.Prepare(config)
|
||||
if err != nil {
|
||||
t.Fatalf("bad: %s", err)
|
||||
}
|
||||
|
||||
if len(warns) != 1 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_ShutdownTimeout(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// Test with a bad value
|
||||
config["shutdown_timeout"] = "this is not good"
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -363,7 +451,10 @@ func TestBuilderPrepare_ShutdownTimeout(t *testing.T) {
|
||||
// Test with a good one
|
||||
config["shutdown_timeout"] = "5s"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -375,14 +466,20 @@ func TestBuilderPrepare_sshKeyPath(t *testing.T) {
|
||||
|
||||
config["ssh_key_path"] = ""
|
||||
b = Builder{}
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
config["ssh_key_path"] = "/i/dont/exist"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -401,7 +498,10 @@ func TestBuilderPrepare_sshKeyPath(t *testing.T) {
|
||||
|
||||
config["ssh_key_path"] = tf.Name()
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -412,7 +512,10 @@ func TestBuilderPrepare_sshKeyPath(t *testing.T) {
|
||||
tf.Write([]byte(testPem))
|
||||
config["ssh_key_path"] = tf.Name()
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -423,14 +526,20 @@ func TestBuilderPrepare_SSHUser(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
config["ssh_username"] = ""
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
config["ssh_username"] = "exists"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -442,7 +551,10 @@ func TestBuilderPrepare_SSHPort(t *testing.T) {
|
||||
|
||||
// Test with a bad value
|
||||
delete(config, "ssh_port")
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("bad err: %s", err)
|
||||
}
|
||||
@@ -454,7 +566,10 @@ func TestBuilderPrepare_SSHPort(t *testing.T) {
|
||||
// Test with a good one
|
||||
config["ssh_port"] = 44
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -470,7 +585,10 @@ func TestBuilderPrepare_SSHWaitTimeout(t *testing.T) {
|
||||
|
||||
// Test with a bad value
|
||||
config["ssh_wait_timeout"] = "this is not good"
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -478,7 +596,10 @@ func TestBuilderPrepare_SSHWaitTimeout(t *testing.T) {
|
||||
// Test with a good one
|
||||
config["ssh_wait_timeout"] = "5s"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -490,7 +611,10 @@ func TestBuilderPrepare_ToolsUploadPath(t *testing.T) {
|
||||
|
||||
// Test a default
|
||||
delete(config, "tools_upload_path")
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
@@ -502,7 +626,10 @@ func TestBuilderPrepare_ToolsUploadPath(t *testing.T) {
|
||||
// Test with a bad value
|
||||
config["tools_upload_path"] = "{{{nope}"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -510,7 +637,10 @@ func TestBuilderPrepare_ToolsUploadPath(t *testing.T) {
|
||||
// Test with a good one
|
||||
config["tools_upload_path"] = "hey"
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -522,7 +652,10 @@ func TestBuilderPrepare_VMXTemplatePath(t *testing.T) {
|
||||
|
||||
// Test bad
|
||||
config["vmx_template_path"] = "/i/dont/exist/forreal"
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -541,7 +674,10 @@ func TestBuilderPrepare_VMXTemplatePath(t *testing.T) {
|
||||
|
||||
config["vmx_template_path"] = tf.Name()
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -560,7 +696,10 @@ func TestBuilderPrepare_VMXTemplatePath(t *testing.T) {
|
||||
|
||||
config["vmx_template_path"] = tf2.Name()
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -573,7 +712,10 @@ func TestBuilderPrepare_VNCPort(t *testing.T) {
|
||||
// Bad
|
||||
config["vnc_port_min"] = 1000
|
||||
config["vnc_port_max"] = 500
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -581,7 +723,10 @@ func TestBuilderPrepare_VNCPort(t *testing.T) {
|
||||
// Bad
|
||||
config["vnc_port_min"] = -500
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
@@ -590,7 +735,10 @@ func TestBuilderPrepare_VNCPort(t *testing.T) {
|
||||
config["vnc_port_min"] = 500
|
||||
config["vnc_port_max"] = 1000
|
||||
b = Builder{}
|
||||
err = b.Prepare(config)
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
@@ -605,7 +753,10 @@ func TestBuilderPrepare_VMXData(t *testing.T) {
|
||||
"two": "bar",
|
||||
}
|
||||
|
||||
err := b.Prepare(config)
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package vmware
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
)
|
||||
@@ -13,14 +14,31 @@ type IfconfigIPFinder struct {
|
||||
}
|
||||
|
||||
func (f *IfconfigIPFinder) HostIP() (string, error) {
|
||||
ifconfigPath, err := exec.LookPath("ifconfig")
|
||||
if err != nil {
|
||||
return "", err
|
||||
var ifconfigPath string
|
||||
|
||||
// On some systems, ifconfig is in /sbin which is generally not
|
||||
// on the PATH for a standard user, so we just check that first.
|
||||
if _, err := os.Stat("/sbin/ifconfig"); err == nil {
|
||||
ifconfigPath = "/sbin/ifconfig"
|
||||
}
|
||||
|
||||
if ifconfigPath == "" {
|
||||
var err error
|
||||
ifconfigPath, err = exec.LookPath("ifconfig")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
stdout := new(bytes.Buffer)
|
||||
|
||||
cmd := exec.Command(ifconfigPath, f.Device)
|
||||
cmd.Env = append(cmd.Env, os.Environ()...)
|
||||
|
||||
// Force LANG=C so that the output is what we expect it to be
|
||||
// despite the locale.
|
||||
cmd.Env = append(cmd.Env, "LANG=C")
|
||||
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = new(bytes.Buffer)
|
||||
if err := cmd.Run(); err != nil {
|
||||
|
||||
@@ -113,11 +113,20 @@ func (c Command) Run(env packer.Environment, args []string) int {
|
||||
log.Printf("Preparing build: %s", b.Name())
|
||||
b.SetDebug(cfgDebug)
|
||||
b.SetForce(cfgForce)
|
||||
err := b.Prepare(userVars)
|
||||
|
||||
warnings, err := b.Prepare(userVars)
|
||||
if err != nil {
|
||||
env.Ui().Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
if len(warnings) > 0 {
|
||||
ui := buildUis[b.Name()]
|
||||
ui.Say(fmt.Sprintf("Warnings for build '%s':\n", b.Name()))
|
||||
for _, warning := range warnings {
|
||||
ui.Say(fmt.Sprintf("* %s", warning))
|
||||
}
|
||||
ui.Say("")
|
||||
}
|
||||
}
|
||||
|
||||
// Run all the builds in parallel and wait for them to complete
|
||||
|
||||
@@ -2,7 +2,6 @@ package build
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cgl.tideland.biz/asserts"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"testing"
|
||||
)
|
||||
@@ -23,33 +22,33 @@ func testEnvironment() packer.Environment {
|
||||
}
|
||||
|
||||
func TestCommand_Implements(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
var actual packer.Command
|
||||
assert.Implementor(new(Command), &actual, "should be a Command")
|
||||
var _ packer.Command = new(Command)
|
||||
}
|
||||
|
||||
func TestCommand_Run_NoArgs(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
command := new(Command)
|
||||
result := command.Run(testEnvironment(), make([]string, 0))
|
||||
assert.Equal(result, 1, "no args should error")
|
||||
if result != 1 {
|
||||
t.Fatalf("bad: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommand_Run_MoreThanOneArg(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
command := new(Command)
|
||||
|
||||
args := []string{"one", "two"}
|
||||
result := command.Run(testEnvironment(), args)
|
||||
assert.Equal(result, 1, "More than one arg should fail")
|
||||
if result != 1 {
|
||||
t.Fatalf("bad: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommand_Run_MissingFile(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
command := new(Command)
|
||||
|
||||
args := []string{"i-better-not-exist"}
|
||||
result := command.Run(testEnvironment(), args)
|
||||
assert.Equal(result, 1, "a non-existent file should error")
|
||||
if result != 1 {
|
||||
t.Fatalf("bad: %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ func (c Command) Run(env packer.Environment, args []string) int {
|
||||
fixers := []string{
|
||||
"iso-md5",
|
||||
"createtime",
|
||||
"virtualbox-gaattach",
|
||||
}
|
||||
|
||||
input := templateData
|
||||
|
||||
@@ -6,6 +6,10 @@ type Fixer interface {
|
||||
// in some way, and returns the new, transformed structure. The
|
||||
// Fix method is allowed to mutate the input.
|
||||
Fix(input map[string]interface{}) (map[string]interface{}, error)
|
||||
|
||||
// Synopsis returns a string description of what the fixer actually
|
||||
// does.
|
||||
Synopsis() string
|
||||
}
|
||||
|
||||
// Fixers is the map of all available fixers, by name.
|
||||
@@ -13,7 +17,8 @@ var Fixers map[string]Fixer
|
||||
|
||||
func init() {
|
||||
Fixers = map[string]Fixer{
|
||||
"iso-md5": new(FixerISOMD5),
|
||||
"createtime": new(FixerCreateTime),
|
||||
"iso-md5": new(FixerISOMD5),
|
||||
"createtime": new(FixerCreateTime),
|
||||
"virtualbox-gaattach": new(FixerVirtualBoxGAAttach),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,3 +49,7 @@ func (FixerCreateTime) Fix(input map[string]interface{}) (map[string]interface{}
|
||||
input["builders"] = tpl.Builders
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (FixerCreateTime) Synopsis() string {
|
||||
return `Replaces ".CreateTime" in builder configs with "{{timestamp}}"`
|
||||
}
|
||||
|
||||
@@ -41,3 +41,7 @@ func (FixerISOMD5) Fix(input map[string]interface{}) (map[string]interface{}, er
|
||||
input["builders"] = tpl.Builders
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (FixerISOMD5) Synopsis() string {
|
||||
return `Replaces "iso_md5" in builders with "iso_checksum"`
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package fix
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
// FixerVirtualBoxGAAttach changes the "guest_additions_attach" of a template
|
||||
// to "guest_additions_mode".
|
||||
type FixerVirtualBoxGAAttach struct{}
|
||||
|
||||
func (FixerVirtualBoxGAAttach) Fix(input map[string]interface{}) (map[string]interface{}, error) {
|
||||
// The type we'll decode into; we only care about builders
|
||||
type template struct {
|
||||
Builders []map[string]interface{}
|
||||
}
|
||||
|
||||
// Decode the input into our structure, if we can
|
||||
var tpl template
|
||||
if err := mapstructure.Decode(input, &tpl); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, builder := range tpl.Builders {
|
||||
builderTypeRaw, ok := builder["type"]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
builderType, ok := builderTypeRaw.(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if builderType != "virtualbox" {
|
||||
continue
|
||||
}
|
||||
|
||||
gaAttachRaw, ok := builder["guest_additions_attach"]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
gaAttach, ok := gaAttachRaw.(bool)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
gaMode := "upload"
|
||||
if gaAttach {
|
||||
gaMode = "attach"
|
||||
}
|
||||
|
||||
delete(builder, "guest_additions_attach")
|
||||
builder["guest_additions_mode"] = gaMode
|
||||
}
|
||||
|
||||
input["builders"] = tpl.Builders
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (FixerVirtualBoxGAAttach) Synopsis() string {
|
||||
return `Updates VirtualBox builders using "guest_additions_attach" to use "guest_additions_mode"`
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package fix
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFixerVirtualBoxGAAttach_Impl(t *testing.T) {
|
||||
var _ Fixer = new(FixerVirtualBoxGAAttach)
|
||||
}
|
||||
|
||||
func TestFixerVirtualBoxGAAttach_Fix(t *testing.T) {
|
||||
cases := []struct {
|
||||
Input map[string]interface{}
|
||||
Expected map[string]interface{}
|
||||
}{
|
||||
// No attach field
|
||||
{
|
||||
Input: map[string]interface{}{
|
||||
"type": "virtualbox",
|
||||
},
|
||||
|
||||
Expected: map[string]interface{}{
|
||||
"type": "virtualbox",
|
||||
},
|
||||
},
|
||||
|
||||
// Attach field == false
|
||||
{
|
||||
Input: map[string]interface{}{
|
||||
"type": "virtualbox",
|
||||
"guest_additions_attach": false,
|
||||
},
|
||||
|
||||
Expected: map[string]interface{}{
|
||||
"type": "virtualbox",
|
||||
"guest_additions_mode": "upload",
|
||||
},
|
||||
},
|
||||
|
||||
// Attach field == true
|
||||
{
|
||||
Input: map[string]interface{}{
|
||||
"type": "virtualbox",
|
||||
"guest_additions_attach": true,
|
||||
},
|
||||
|
||||
Expected: map[string]interface{}{
|
||||
"type": "virtualbox",
|
||||
"guest_additions_mode": "attach",
|
||||
},
|
||||
},
|
||||
|
||||
// Attach field is not a bool
|
||||
{
|
||||
Input: map[string]interface{}{
|
||||
"type": "virtualbox",
|
||||
"guest_additions_attach": "what",
|
||||
},
|
||||
|
||||
Expected: map[string]interface{}{
|
||||
"type": "virtualbox",
|
||||
"guest_additions_attach": "what",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
var f FixerVirtualBoxGAAttach
|
||||
|
||||
input := map[string]interface{}{
|
||||
"builders": []map[string]interface{}{tc.Input},
|
||||
}
|
||||
|
||||
expected := map[string]interface{}{
|
||||
"builders": []map[string]interface{}{tc.Expected},
|
||||
}
|
||||
|
||||
output, err := f.Fix(input)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(output, expected) {
|
||||
t.Fatalf("unexpected: %#v\nexpected: %#v\n", output, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,7 @@ func (c Command) Run(env packer.Environment, args []string) int {
|
||||
}
|
||||
|
||||
errs := make([]error, 0)
|
||||
warnings := make(map[string][]string)
|
||||
|
||||
// The component finder for our builds
|
||||
components := &packer.ComponentFinder{
|
||||
@@ -81,7 +82,10 @@ func (c Command) Run(env packer.Environment, args []string) int {
|
||||
// Check the configuration of all builds
|
||||
for _, b := range builds {
|
||||
log.Printf("Preparing build: %s", b.Name())
|
||||
err := b.Prepare(userVars)
|
||||
warns, err := b.Prepare(userVars)
|
||||
if len(warns) > 0 {
|
||||
warnings[b.Name()] = warns
|
||||
}
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("Errors validating build '%s'. %s", b.Name(), err))
|
||||
}
|
||||
@@ -100,6 +104,21 @@ func (c Command) Run(env packer.Environment, args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
if len(warnings) > 0 {
|
||||
env.Ui().Say("Template validation succeeded, but there were some warnings.")
|
||||
env.Ui().Say("These are ONLY WARNINGS, and Packer will attempt to build the")
|
||||
env.Ui().Say("template despite them, but they should be paid attention to.\n")
|
||||
|
||||
for build, warns := range warnings {
|
||||
env.Ui().Say(fmt.Sprintf("Warnings for build '%s':\n", build))
|
||||
for _, warning := range warns {
|
||||
env.Ui().Say(fmt.Sprintf("* %s", warning))
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
env.Ui().Say("Template validated successfully.")
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -12,6 +12,16 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ScrubConfig is a helper that returns a string representation of
|
||||
// any struct with the given values stripped out.
|
||||
func ScrubConfig(target interface{}, values ...string) string {
|
||||
conf := fmt.Sprintf("Config: %+v", target)
|
||||
for _, value := range values {
|
||||
conf = strings.Replace(conf, value, "<Filtered>", -1)
|
||||
}
|
||||
return conf
|
||||
}
|
||||
|
||||
// CheckUnusedConfig is a helper that makes sure that the there are no
|
||||
// unused configuration keys, properly ignoring keys that don't matter.
|
||||
func CheckUnusedConfig(md *mapstructure.Metadata) *packer.MultiError {
|
||||
|
||||
@@ -159,3 +159,20 @@ func TestDownloadableURL_FilePaths(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestScrubConfig(t *testing.T) {
|
||||
type Inner struct {
|
||||
Baz string
|
||||
}
|
||||
type Local struct {
|
||||
Foo string
|
||||
Bar string
|
||||
Inner
|
||||
}
|
||||
c := Local{"foo", "bar", Inner{"bar"}}
|
||||
expect := "Config: {Foo:foo Bar:<Filtered> Inner:{Baz:<Filtered>}}"
|
||||
conf := ScrubConfig(c, c.Bar)
|
||||
if conf != expect {
|
||||
t.Fatalf("got %s, expected %s", conf, expect)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -73,7 +73,8 @@ func HashForType(t string) hash.Hash {
|
||||
func NewDownloadClient(c *DownloadConfig) *DownloadClient {
|
||||
if c.DownloaderMap == nil {
|
||||
c.DownloaderMap = map[string]Downloader{
|
||||
"http": new(HTTPDownloader),
|
||||
"http": new(HTTPDownloader),
|
||||
"https": new(HTTPDownloader),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,9 @@ WaitLoop:
|
||||
state.Put("communicator", comm)
|
||||
break WaitLoop
|
||||
case <-timeout:
|
||||
ui.Error("Timeout waiting for SSH.")
|
||||
err := fmt.Errorf("Timeout waiting for SSH.")
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
close(cancel)
|
||||
return multistep.ActionHalt
|
||||
case <-time.After(1 * time.Second):
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Generates a time ordered UUID. Top 32 bits are a timestamp,
|
||||
// bottom 96 are random.
|
||||
func TimeOrderedUUID() string {
|
||||
unix := uint32(time.Now().UTC().Unix())
|
||||
|
||||
b := make([]byte, 12)
|
||||
n, err := rand.Read(b)
|
||||
if n != len(b) {
|
||||
err = fmt.Errorf("Not enough entropy available")
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return fmt.Sprintf("%08x-%04x-%04x-%04x-%04x%08x",
|
||||
unix, b[0:2], b[2:4], b[4:6], b[6:8], b[8:])
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTimeOrderedUuid(t *testing.T) {
|
||||
uuid := TimeOrderedUUID()
|
||||
if len(uuid) != 36 {
|
||||
t.Fatalf("bad: %s", uuid)
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
@@ -238,6 +239,14 @@ func (c *comm) reconnect() (err error) {
|
||||
log.Printf("reconnecting to TCP connection for SSH")
|
||||
c.conn, err = c.config.Connection()
|
||||
if err != nil {
|
||||
// Explicitly set this to the REAL nil. Connection() can return
|
||||
// a nil implementation of net.Conn which will make the
|
||||
// "if c.conn == nil" check fail above. Read here for more information
|
||||
// on this psychotic language feature:
|
||||
//
|
||||
// http://golang.org/doc/faq#nil_error
|
||||
c.conn = nil
|
||||
|
||||
log.Printf("reconnection error: %s", err)
|
||||
return
|
||||
}
|
||||
@@ -354,30 +363,49 @@ func checkSCPStatus(r *bufio.Reader) error {
|
||||
}
|
||||
|
||||
func scpUploadFile(dst string, src io.Reader, w io.Writer, r *bufio.Reader) error {
|
||||
// Determine the length of the upload content by copying it
|
||||
// into an in-memory buffer. Note that this means what we upload
|
||||
// must fit into memory.
|
||||
log.Println("Copying input data into in-memory buffer so we can get the length")
|
||||
inputBuf := new(bytes.Buffer)
|
||||
if _, err := io.Copy(inputBuf, src); err != nil {
|
||||
// Create a temporary file where we can copy the contents of the src
|
||||
// so that we can determine the length, since SCP is length-prefixed.
|
||||
tf, err := ioutil.TempFile("", "packer-upload")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating temporary file for upload: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
defer tf.Close()
|
||||
|
||||
log.Println("Copying input data into temporary file so we can read the length")
|
||||
if _, err := io.Copy(tf, src); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Sync the file so that the contents are definitely on disk, then
|
||||
// read the length of it.
|
||||
if err := tf.Sync(); err != nil {
|
||||
return fmt.Errorf("Error creating temporary file for upload: %s", err)
|
||||
}
|
||||
|
||||
// Seek the file to the beginning so we can re-read all of it
|
||||
if _, err := tf.Seek(0, 0); err != nil {
|
||||
return fmt.Errorf("Error creating temporary file for upload: %s", err)
|
||||
}
|
||||
|
||||
fi, err := tf.Stat()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating temporary file for upload: %s", err)
|
||||
}
|
||||
|
||||
// Start the protocol
|
||||
log.Println("Beginning file upload...")
|
||||
fmt.Fprintln(w, "C0644", inputBuf.Len(), dst)
|
||||
err := checkSCPStatus(r)
|
||||
if err != nil {
|
||||
fmt.Fprintln(w, "C0644", fi.Size(), dst)
|
||||
if err := checkSCPStatus(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := io.Copy(w, inputBuf); err != nil {
|
||||
if _, err := io.Copy(w, tf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprint(w, "\x00")
|
||||
err = checkSCPStatus(r)
|
||||
if err != nil {
|
||||
if err := checkSCPStatus(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ const defaultConfig = `
|
||||
},
|
||||
|
||||
"provisioners": {
|
||||
"ansible-local": "packer-provisioner-ansible-local",
|
||||
"chef-solo": "packer-provisioner-chef-solo",
|
||||
"file": "packer-provisioner-file",
|
||||
"puppet-masterless": "packer-provisioner-puppet-masterless",
|
||||
|
||||
+6
-5
@@ -38,8 +38,9 @@ type Build interface {
|
||||
Name() string
|
||||
|
||||
// Prepare configures the various components of this build and reports
|
||||
// any errors in doing so (such as syntax errors, validation errors, etc.)
|
||||
Prepare(v map[string]string) error
|
||||
// any errors in doing so (such as syntax errors, validation errors, etc.).
|
||||
// It also reports any warnings.
|
||||
Prepare(v map[string]string) ([]string, error)
|
||||
|
||||
// Run runs the actual builder, returning an artifact implementation
|
||||
// of what is built. If anything goes wrong, an error is returned.
|
||||
@@ -115,7 +116,7 @@ func (b *coreBuild) Name() string {
|
||||
// Prepare prepares the build by doing some initialization for the builder
|
||||
// and any hooks. This _must_ be called prior to Run. The parameter is the
|
||||
// overrides for the variables within the template (if any).
|
||||
func (b *coreBuild) Prepare(userVars map[string]string) (err error) {
|
||||
func (b *coreBuild) Prepare(userVars map[string]string) (warn []string, err error) {
|
||||
b.l.Lock()
|
||||
defer b.l.Unlock()
|
||||
|
||||
@@ -154,7 +155,7 @@ func (b *coreBuild) Prepare(userVars map[string]string) (err error) {
|
||||
// If there were any problem with variables, return an error right
|
||||
// away because we can't be certain anything else will actually work.
|
||||
if len(varErrs) > 0 {
|
||||
return &MultiError{
|
||||
return nil, &MultiError{
|
||||
Errors: varErrs,
|
||||
}
|
||||
}
|
||||
@@ -168,7 +169,7 @@ func (b *coreBuild) Prepare(userVars map[string]string) (err error) {
|
||||
}
|
||||
|
||||
// Prepare the builder
|
||||
err = b.builder.Prepare(b.builderConfig, packerConfig)
|
||||
warn, err = b.builder.Prepare(b.builderConfig, packerConfig)
|
||||
if err != nil {
|
||||
log.Printf("Build '%s' prepare failure: %s\n", b.name, err)
|
||||
return
|
||||
|
||||
+119
-57
@@ -1,7 +1,6 @@
|
||||
package packer
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
@@ -9,7 +8,7 @@ import (
|
||||
func testBuild() *coreBuild {
|
||||
return &coreBuild{
|
||||
name: "test",
|
||||
builder: &TestBuilder{artifactId: "b"},
|
||||
builder: &MockBuilder{ArtifactId: "b"},
|
||||
builderConfig: 42,
|
||||
builderType: "foo",
|
||||
hooks: map[string][]Hook{
|
||||
@@ -27,10 +26,6 @@ func testBuild() *coreBuild {
|
||||
}
|
||||
}
|
||||
|
||||
func testBuilder() *TestBuilder {
|
||||
return &TestBuilder{}
|
||||
}
|
||||
|
||||
func testDefaultPackerConfig() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
BuildNameConfigKey: "test",
|
||||
@@ -41,37 +36,52 @@ func testDefaultPackerConfig() map[string]interface{} {
|
||||
}
|
||||
}
|
||||
func TestBuild_Name(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
build := testBuild()
|
||||
assert.Equal(build.Name(), "test", "should have a name")
|
||||
if build.Name() != "test" {
|
||||
t.Fatalf("bad: %s", build.Name())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuild_Prepare(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
packerConfig := testDefaultPackerConfig()
|
||||
|
||||
build := testBuild()
|
||||
builder := build.builder.(*TestBuilder)
|
||||
builder := build.builder.(*MockBuilder)
|
||||
|
||||
build.Prepare(nil)
|
||||
assert.True(builder.prepareCalled, "prepare should be called")
|
||||
assert.Equal(builder.prepareConfig, []interface{}{42, packerConfig}, "prepare config should be 42")
|
||||
if !builder.PrepareCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
if !reflect.DeepEqual(builder.PrepareConfig, []interface{}{42, packerConfig}) {
|
||||
t.Fatalf("bad: %#v", builder.PrepareConfig)
|
||||
}
|
||||
|
||||
coreProv := build.provisioners[0]
|
||||
prov := coreProv.provisioner.(*MockProvisioner)
|
||||
assert.True(prov.PrepCalled, "prepare should be called")
|
||||
assert.Equal(prov.PrepConfigs, []interface{}{42, packerConfig}, "prepare should be called with proper config")
|
||||
if !prov.PrepCalled {
|
||||
t.Fatal("prep should be called")
|
||||
}
|
||||
if !reflect.DeepEqual(prov.PrepConfigs, []interface{}{42, packerConfig}) {
|
||||
t.Fatalf("bad: %#v", prov.PrepConfigs)
|
||||
}
|
||||
|
||||
corePP := build.postProcessors[0][0]
|
||||
pp := corePP.processor.(*TestPostProcessor)
|
||||
assert.True(pp.configCalled, "config should be called")
|
||||
assert.Equal(pp.configVal, []interface{}{make(map[string]interface{}), packerConfig}, "config should have right value")
|
||||
if !pp.configCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
if !reflect.DeepEqual(pp.configVal, []interface{}{make(map[string]interface{}), packerConfig}) {
|
||||
t.Fatalf("bad: %#v", pp.configVal)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuild_Prepare_Twice(t *testing.T) {
|
||||
build := testBuild()
|
||||
if err := build.Prepare(nil); err != nil {
|
||||
warn, err := build.Prepare(nil)
|
||||
if len(warn) > 0 {
|
||||
t.Fatalf("bad: %#v", warn)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("bad error: %s", err)
|
||||
}
|
||||
|
||||
@@ -89,24 +99,46 @@ func TestBuild_Prepare_Twice(t *testing.T) {
|
||||
build.Prepare(nil)
|
||||
}
|
||||
|
||||
func TestBuild_Prepare_Debug(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
func TestBuildPrepare_BuilderWarniings(t *testing.T) {
|
||||
expected := []string{"foo"}
|
||||
|
||||
build := testBuild()
|
||||
builder := build.builder.(*MockBuilder)
|
||||
builder.PrepareWarnings = expected
|
||||
|
||||
warn, err := build.Prepare(nil)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(warn, expected) {
|
||||
t.Fatalf("bad: %#v", warn)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuild_Prepare_Debug(t *testing.T) {
|
||||
packerConfig := testDefaultPackerConfig()
|
||||
packerConfig[DebugConfigKey] = true
|
||||
|
||||
build := testBuild()
|
||||
builder := build.builder.(*TestBuilder)
|
||||
builder := build.builder.(*MockBuilder)
|
||||
|
||||
build.SetDebug(true)
|
||||
build.Prepare(nil)
|
||||
assert.True(builder.prepareCalled, "prepare should be called")
|
||||
assert.Equal(builder.prepareConfig, []interface{}{42, packerConfig}, "prepare config should be 42")
|
||||
if !builder.PrepareCalled {
|
||||
t.Fatalf("should be called")
|
||||
}
|
||||
if !reflect.DeepEqual(builder.PrepareConfig, []interface{}{42, packerConfig}) {
|
||||
t.Fatalf("bad: %#v", builder.PrepareConfig)
|
||||
}
|
||||
|
||||
coreProv := build.provisioners[0]
|
||||
prov := coreProv.provisioner.(*MockProvisioner)
|
||||
assert.True(prov.PrepCalled, "prepare should be called")
|
||||
assert.Equal(prov.PrepConfigs, []interface{}{42, packerConfig}, "prepare should be called with proper config")
|
||||
if !prov.PrepCalled {
|
||||
t.Fatal("prepare should be called")
|
||||
}
|
||||
if !reflect.DeepEqual(prov.PrepConfigs, []interface{}{42, packerConfig}) {
|
||||
t.Fatalf("bad: %#v", prov.PrepConfigs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildPrepare_variables_default(t *testing.T) {
|
||||
@@ -117,19 +149,22 @@ func TestBuildPrepare_variables_default(t *testing.T) {
|
||||
|
||||
build := testBuild()
|
||||
build.variables["foo"] = coreBuildVariable{Default: "bar"}
|
||||
builder := build.builder.(*TestBuilder)
|
||||
builder := build.builder.(*MockBuilder)
|
||||
|
||||
err := build.Prepare(nil)
|
||||
warn, err := build.Prepare(nil)
|
||||
if len(warn) > 0 {
|
||||
t.Fatalf("bad: %#v", warn)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if !builder.prepareCalled {
|
||||
if !builder.PrepareCalled {
|
||||
t.Fatal("prepare should be called")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(builder.prepareConfig[1], packerConfig) {
|
||||
t.Fatalf("prepare bad: %#v", builder.prepareConfig[1])
|
||||
if !reflect.DeepEqual(builder.PrepareConfig[1], packerConfig) {
|
||||
t.Fatalf("prepare bad: %#v", builder.PrepareConfig[1])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +172,10 @@ func TestBuildPrepare_variables_nonexist(t *testing.T) {
|
||||
build := testBuild()
|
||||
build.variables["foo"] = coreBuildVariable{Default: "bar"}
|
||||
|
||||
err := build.Prepare(map[string]string{"bar": "baz"})
|
||||
warn, err := build.Prepare(map[string]string{"bar": "baz"})
|
||||
if len(warn) > 0 {
|
||||
t.Fatalf("bad: %#v", warn)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have had error")
|
||||
}
|
||||
@@ -151,19 +189,22 @@ func TestBuildPrepare_variables_override(t *testing.T) {
|
||||
|
||||
build := testBuild()
|
||||
build.variables["foo"] = coreBuildVariable{Default: "bar"}
|
||||
builder := build.builder.(*TestBuilder)
|
||||
builder := build.builder.(*MockBuilder)
|
||||
|
||||
err := build.Prepare(map[string]string{"foo": "baz"})
|
||||
warn, err := build.Prepare(map[string]string{"foo": "baz"})
|
||||
if len(warn) > 0 {
|
||||
t.Fatalf("bad: %#v", warn)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if !builder.prepareCalled {
|
||||
if !builder.PrepareCalled {
|
||||
t.Fatal("prepare should be called")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(builder.prepareConfig[1], packerConfig) {
|
||||
t.Fatalf("prepare bad: %#v", builder.prepareConfig[1])
|
||||
if !reflect.DeepEqual(builder.PrepareConfig[1], packerConfig) {
|
||||
t.Fatalf("prepare bad: %#v", builder.PrepareConfig[1])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +212,10 @@ func TestBuildPrepare_variablesRequired(t *testing.T) {
|
||||
build := testBuild()
|
||||
build.variables["foo"] = coreBuildVariable{Required: true}
|
||||
|
||||
err := build.Prepare(map[string]string{})
|
||||
warn, err := build.Prepare(map[string]string{})
|
||||
if len(warn) > 0 {
|
||||
t.Fatalf("bad: %#v", warn)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have had error")
|
||||
}
|
||||
@@ -179,44 +223,59 @@ func TestBuildPrepare_variablesRequired(t *testing.T) {
|
||||
// Test with setting the value
|
||||
build = testBuild()
|
||||
build.variables["foo"] = coreBuildVariable{Required: true}
|
||||
err = build.Prepare(map[string]string{"foo": ""})
|
||||
warn, err = build.Prepare(map[string]string{"foo": ""})
|
||||
if len(warn) > 0 {
|
||||
t.Fatalf("bad: %#v", warn)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuild_Run(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
cache := &TestCache{}
|
||||
ui := testUi()
|
||||
|
||||
build := testBuild()
|
||||
build.Prepare(nil)
|
||||
artifacts, err := build.Run(ui, cache)
|
||||
assert.Nil(err, "should not error")
|
||||
assert.Equal(len(artifacts), 2, "should have two artifacts")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if len(artifacts) != 2 {
|
||||
t.Fatalf("bad: %#v", artifacts)
|
||||
}
|
||||
|
||||
// Verify builder was run
|
||||
builder := build.builder.(*TestBuilder)
|
||||
assert.True(builder.runCalled, "run should be called")
|
||||
builder := build.builder.(*MockBuilder)
|
||||
if !builder.RunCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
|
||||
// Verify hooks are disapatchable
|
||||
dispatchHook := builder.runHook
|
||||
dispatchHook := builder.RunHook
|
||||
dispatchHook.Run("foo", nil, nil, 42)
|
||||
|
||||
hook := build.hooks["foo"][0].(*MockHook)
|
||||
assert.True(hook.RunCalled, "run should be called")
|
||||
assert.Equal(hook.RunData, 42, "should have correct data")
|
||||
if !hook.RunCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
if hook.RunData != 42 {
|
||||
t.Fatalf("bad: %#v", hook.RunData)
|
||||
}
|
||||
|
||||
// Verify provisioners run
|
||||
dispatchHook.Run(HookProvision, nil, nil, 42)
|
||||
prov := build.provisioners[0].provisioner.(*MockProvisioner)
|
||||
assert.True(prov.ProvCalled, "provision should be called")
|
||||
if !prov.ProvCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
|
||||
// Verify post-processor was run
|
||||
pp := build.postProcessors[0][0].processor.(*TestPostProcessor)
|
||||
assert.True(pp.ppCalled, "post processor should be called")
|
||||
if !pp.ppCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuild_Run_Artifacts(t *testing.T) {
|
||||
@@ -356,23 +415,26 @@ func TestBuild_Run_Artifacts(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBuild_RunBeforePrepare(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
defer func() {
|
||||
p := recover()
|
||||
assert.NotNil(p, "should panic")
|
||||
assert.Equal(p.(string), "Prepare must be called first", "right panic")
|
||||
if p == nil {
|
||||
t.Fatal("should panic")
|
||||
}
|
||||
|
||||
if p.(string) != "Prepare must be called first" {
|
||||
t.Fatalf("bad: %s", p.(string))
|
||||
}
|
||||
}()
|
||||
|
||||
testBuild().Run(testUi(), &TestCache{})
|
||||
}
|
||||
|
||||
func TestBuild_Cancel(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
build := testBuild()
|
||||
build.Cancel()
|
||||
|
||||
builder := build.builder.(*TestBuilder)
|
||||
assert.True(builder.cancelCalled, "cancel should be called")
|
||||
builder := build.builder.(*MockBuilder)
|
||||
if !builder.CancelCalled {
|
||||
t.Fatal("cancel should be called")
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -22,7 +22,10 @@ type Builder interface {
|
||||
//
|
||||
// Each of the configuration values should merge into the final
|
||||
// configuration.
|
||||
Prepare(...interface{}) error
|
||||
//
|
||||
// Prepare should return a list of warnings along with any errors
|
||||
// that occured while preparing.
|
||||
Prepare(...interface{}) ([]string, error)
|
||||
|
||||
// Run is where the actual build should take place. It takes a Build and a Ui.
|
||||
Run(ui Ui, hook Hook, cache Cache) (Artifact, error)
|
||||
|
||||
+19
-3
@@ -1,10 +1,17 @@
|
||||
package packer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// MockBuilder is an implementation of Builder that can be used for tests.
|
||||
// You can set some fake return values and you can keep track of what
|
||||
// methods were called on the builder. It is fairly basic.
|
||||
type MockBuilder struct {
|
||||
ArtifactId string
|
||||
ArtifactId string
|
||||
PrepareWarnings []string
|
||||
RunErrResult bool
|
||||
RunNilResult bool
|
||||
|
||||
PrepareCalled bool
|
||||
PrepareConfig []interface{}
|
||||
@@ -15,10 +22,10 @@ type MockBuilder struct {
|
||||
CancelCalled bool
|
||||
}
|
||||
|
||||
func (tb *MockBuilder) Prepare(config ...interface{}) error {
|
||||
func (tb *MockBuilder) Prepare(config ...interface{}) ([]string, error) {
|
||||
tb.PrepareCalled = true
|
||||
tb.PrepareConfig = config
|
||||
return nil
|
||||
return tb.PrepareWarnings, nil
|
||||
}
|
||||
|
||||
func (tb *MockBuilder) Run(ui Ui, h Hook, c Cache) (Artifact, error) {
|
||||
@@ -26,6 +33,15 @@ func (tb *MockBuilder) Run(ui Ui, h Hook, c Cache) (Artifact, error) {
|
||||
tb.RunHook = h
|
||||
tb.RunUi = ui
|
||||
tb.RunCache = c
|
||||
|
||||
if tb.RunErrResult {
|
||||
return nil, errors.New("foo")
|
||||
}
|
||||
|
||||
if tb.RunNilResult {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &MockArtifact{
|
||||
IdValue: tb.ArtifactId,
|
||||
}, nil
|
||||
|
||||
@@ -1,31 +1 @@
|
||||
package packer
|
||||
|
||||
type TestBuilder struct {
|
||||
artifactId string
|
||||
|
||||
prepareCalled bool
|
||||
prepareConfig []interface{}
|
||||
runCalled bool
|
||||
runCache Cache
|
||||
runHook Hook
|
||||
runUi Ui
|
||||
cancelCalled bool
|
||||
}
|
||||
|
||||
func (tb *TestBuilder) Prepare(config ...interface{}) error {
|
||||
tb.prepareCalled = true
|
||||
tb.prepareConfig = config
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tb *TestBuilder) Run(ui Ui, h Hook, c Cache) (Artifact, error) {
|
||||
tb.runCalled = true
|
||||
tb.runHook = h
|
||||
tb.runUi = ui
|
||||
tb.runCache = c
|
||||
return &TestArtifact{id: tb.artifactId}, nil
|
||||
}
|
||||
|
||||
func (tb *TestBuilder) Cancel() {
|
||||
tb.cancelCalled = true
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@ package packer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cgl.tideland.biz/identifier"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/mitchellh/packer/common/uuid"
|
||||
"strconv"
|
||||
"text/template"
|
||||
"time"
|
||||
@@ -94,5 +93,5 @@ func templateTimestamp() string {
|
||||
}
|
||||
|
||||
func templateUuid() string {
|
||||
return hex.EncodeToString(identifier.NewUUID().Raw())
|
||||
return uuid.TimeOrderedUUID()
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ func TestConfigTemplateProcess_uuid(t *testing.T) {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if len(result) != 32 {
|
||||
if len(result) != 36 {
|
||||
t.Fatalf("err: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
+156
-99
@@ -2,12 +2,11 @@ package packer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cgl.tideland.biz/asserts"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -18,7 +17,7 @@ func init() {
|
||||
}
|
||||
|
||||
func testComponentFinder() *ComponentFinder {
|
||||
builderFactory := func(n string) (Builder, error) { return testBuilder(), nil }
|
||||
builderFactory := func(n string) (Builder, error) { return new(MockBuilder), nil }
|
||||
ppFactory := func(n string) (PostProcessor, error) { return new(TestPostProcessor), nil }
|
||||
provFactory := func(n string) (Provisioner, error) { return new(MockProvisioner), nil }
|
||||
return &ComponentFinder{
|
||||
@@ -44,40 +43,48 @@ func testEnvironment() Environment {
|
||||
}
|
||||
|
||||
func TestEnvironment_DefaultConfig_Commands(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
assert.Empty(config.Commands, "should have no commands")
|
||||
if len(config.Commands) != 0 {
|
||||
t.Fatalf("bad: %#v", config.Commands)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_DefaultConfig_Ui(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
assert.NotNil(config.Ui, "default UI should not be nil")
|
||||
if config.Ui == nil {
|
||||
t.Fatal("config.Ui should not be nil")
|
||||
}
|
||||
|
||||
rwUi, ok := config.Ui.(*BasicUi)
|
||||
assert.True(ok, "default UI should be BasicUi")
|
||||
assert.Equal(rwUi.Writer, os.Stdout, "default UI should go to stdout")
|
||||
assert.Equal(rwUi.Reader, os.Stdin, "default UI should read from stdin")
|
||||
if !ok {
|
||||
t.Fatal("default UI should be BasicUi")
|
||||
}
|
||||
if rwUi.Writer != os.Stdout {
|
||||
t.Fatal("default UI should go to stdout")
|
||||
}
|
||||
if rwUi.Reader != os.Stdin {
|
||||
t.Fatal("default UI reader should go to stdin")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewEnvironment_NoConfig(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
env, err := NewEnvironment(nil)
|
||||
assert.Nil(env, "env should be nil")
|
||||
assert.NotNil(err, "should be an error")
|
||||
if env != nil {
|
||||
t.Fatal("env should be nil")
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_NilComponents(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.Components = *new(ComponentFinder)
|
||||
|
||||
env, err := NewEnvironment(config)
|
||||
assert.Nil(err, "should not have an error")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// All of these should not cause panics... so we don't assert
|
||||
// anything but if there is a panic in the test then yeah, something
|
||||
@@ -90,9 +97,7 @@ func TestEnvironment_NilComponents(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEnvironment_Builder(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
builder := &TestBuilder{}
|
||||
builder := &MockBuilder{}
|
||||
builders := make(map[string]Builder)
|
||||
builders["foo"] = builder
|
||||
|
||||
@@ -101,33 +106,43 @@ func TestEnvironment_Builder(t *testing.T) {
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returnedBuilder, err := env.Builder("foo")
|
||||
assert.Nil(err, "should be no error")
|
||||
assert.Equal(returnedBuilder, builder, "should return correct builder")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if returnedBuilder != builder {
|
||||
t.Fatalf("bad: %#v", returnedBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_Builder_NilError(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.Components.Builder = func(n string) (Builder, error) { return nil, nil }
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returnedBuilder, err := env.Builder("foo")
|
||||
assert.NotNil(err, "should be an error")
|
||||
assert.Nil(returnedBuilder, "should be no builder")
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if returnedBuilder != nil {
|
||||
t.Fatalf("bad: %#v", returnedBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_Builder_Error(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.Components.Builder = func(n string) (Builder, error) { return nil, errors.New("foo") }
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returnedBuilder, err := env.Builder("foo")
|
||||
assert.NotNil(err, "should be an error")
|
||||
assert.Equal(err.Error(), "foo", "should be correct error")
|
||||
assert.Nil(returnedBuilder, "should be no builder")
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if err.Error() != "foo" {
|
||||
t.Fatalf("bad err: %s", err)
|
||||
}
|
||||
if returnedBuilder != nil {
|
||||
t.Fatalf("should be nil: %#v", returnedBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_Cache(t *testing.T) {
|
||||
@@ -139,20 +154,20 @@ func TestEnvironment_Cache(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEnvironment_Cli_Error(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.Components.Command = func(n string) (Command, error) { return nil, errors.New("foo") }
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
_, err := env.Cli([]string{"foo"})
|
||||
assert.NotNil(err, "should be an error")
|
||||
assert.Equal(err.Error(), "foo", "should be correct error")
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if err.Error() != "foo" {
|
||||
t.Fatalf("bad: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_Cli_CallsRun(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
command := &TestCommand{}
|
||||
commands := make(map[string]Command)
|
||||
commands["foo"] = command
|
||||
@@ -163,25 +178,33 @@ func TestEnvironment_Cli_CallsRun(t *testing.T) {
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
exitCode, err := env.Cli([]string{"foo", "bar", "baz"})
|
||||
assert.Nil(err, "should be no error")
|
||||
assert.Equal(exitCode, 0, "runs foo command")
|
||||
assert.True(command.runCalled, "run should've been called")
|
||||
assert.Equal(command.runEnv, env, "should've ran with env")
|
||||
assert.Equal(command.runArgs, []string{"bar", "baz"}, "should have right args")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if exitCode != 0 {
|
||||
t.Fatalf("bad: %d", exitCode)
|
||||
}
|
||||
if !command.runCalled {
|
||||
t.Fatal("command should be run")
|
||||
}
|
||||
if command.runEnv != env {
|
||||
t.Fatalf("bad env: %#v", command.runEnv)
|
||||
}
|
||||
if !reflect.DeepEqual(command.runArgs, []string{"bar", "baz"}) {
|
||||
t.Fatalf("bad: %#v", command.runArgs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_DefaultCli_Empty(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
defaultEnv := testEnvironment()
|
||||
|
||||
exitCode, _ := defaultEnv.Cli([]string{})
|
||||
assert.Equal(exitCode, 1, "CLI with no args")
|
||||
if exitCode != 1 {
|
||||
t.Fatalf("bad: %d", exitCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_DefaultCli_Help(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
defaultEnv := testEnvironment()
|
||||
|
||||
// A little lambda to help us test the output actually contains help
|
||||
@@ -189,44 +212,52 @@ func TestEnvironment_DefaultCli_Help(t *testing.T) {
|
||||
buffer := defaultEnv.Ui().(*BasicUi).Writer.(*bytes.Buffer)
|
||||
output := buffer.String()
|
||||
buffer.Reset()
|
||||
assert.True(strings.Contains(output, "usage: packer"), "should print help")
|
||||
if !strings.Contains(output, "usage: packer") {
|
||||
t.Fatalf("should contain help: %#v", output)
|
||||
}
|
||||
}
|
||||
|
||||
// Test "--help"
|
||||
exitCode, _ := defaultEnv.Cli([]string{"--help"})
|
||||
assert.Equal(exitCode, 1, "--help should print")
|
||||
if exitCode != 1 {
|
||||
t.Fatalf("bad: %d", exitCode)
|
||||
}
|
||||
testOutput()
|
||||
|
||||
// Test "-h"
|
||||
exitCode, _ = defaultEnv.Cli([]string{"--help"})
|
||||
assert.Equal(exitCode, 1, "--help should print")
|
||||
if exitCode != 1 {
|
||||
t.Fatalf("bad: %d", exitCode)
|
||||
}
|
||||
testOutput()
|
||||
}
|
||||
|
||||
func TestEnvironment_DefaultCli_Version(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
defaultEnv := testEnvironment()
|
||||
|
||||
versionCommands := []string{"version", "--version", "-v"}
|
||||
for _, command := range versionCommands {
|
||||
exitCode, _ := defaultEnv.Cli([]string{command})
|
||||
assert.Equal(exitCode, 0, fmt.Sprintf("%s should work", command))
|
||||
if exitCode != 0 {
|
||||
t.Fatalf("bad: %d", exitCode)
|
||||
}
|
||||
|
||||
// Test the --version and -v can appear anywhere
|
||||
exitCode, _ = defaultEnv.Cli([]string{"bad", command})
|
||||
|
||||
if command != "version" {
|
||||
assert.Equal(exitCode, 0, fmt.Sprintf("%s should work anywhere", command))
|
||||
if exitCode != 0 {
|
||||
t.Fatalf("bad: %d", exitCode)
|
||||
}
|
||||
} else {
|
||||
assert.Equal(exitCode, 1, fmt.Sprintf("%s should NOT work anywhere", command))
|
||||
if exitCode != 1 {
|
||||
t.Fatalf("bad: %d", exitCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_Hook(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
hook := &MockHook{}
|
||||
hooks := make(map[string]Hook)
|
||||
hooks["foo"] = hook
|
||||
@@ -236,38 +267,46 @@ func TestEnvironment_Hook(t *testing.T) {
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returned, err := env.Hook("foo")
|
||||
assert.Nil(err, "should be no error")
|
||||
assert.Equal(returned, hook, "should return correct hook")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if returned != hook {
|
||||
t.Fatalf("bad: %#v", returned)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_Hook_NilError(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.Components.Hook = func(n string) (Hook, error) { return nil, nil }
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returned, err := env.Hook("foo")
|
||||
assert.NotNil(err, "should be an error")
|
||||
assert.Nil(returned, "should be no hook")
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if returned != nil {
|
||||
t.Fatalf("bad: %#v", returned)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_Hook_Error(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.Components.Hook = func(n string) (Hook, error) { return nil, errors.New("foo") }
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returned, err := env.Hook("foo")
|
||||
assert.NotNil(err, "should be an error")
|
||||
assert.Equal(err.Error(), "foo", "should be correct error")
|
||||
assert.Nil(returned, "should be no hook")
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if err.Error() != "foo" {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if returned != nil {
|
||||
t.Fatalf("bad: %#v", returned)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_PostProcessor(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
pp := &TestPostProcessor{}
|
||||
pps := make(map[string]PostProcessor)
|
||||
pps["foo"] = pp
|
||||
@@ -277,38 +316,46 @@ func TestEnvironment_PostProcessor(t *testing.T) {
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returned, err := env.PostProcessor("foo")
|
||||
assert.Nil(err, "should be no error")
|
||||
assert.Equal(returned, pp, "should return correct pp")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if returned != pp {
|
||||
t.Fatalf("bad: %#v", returned)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_PostProcessor_NilError(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.Components.PostProcessor = func(n string) (PostProcessor, error) { return nil, nil }
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returned, err := env.PostProcessor("foo")
|
||||
assert.NotNil(err, "should be an error")
|
||||
assert.Nil(returned, "should be no pp")
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if returned != nil {
|
||||
t.Fatalf("bad: %#v", returned)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_PostProcessor_Error(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.Components.PostProcessor = func(n string) (PostProcessor, error) { return nil, errors.New("foo") }
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returned, err := env.PostProcessor("foo")
|
||||
assert.NotNil(err, "should be an error")
|
||||
assert.Equal(err.Error(), "foo", "should be correct error")
|
||||
assert.Nil(returned, "should be no pp")
|
||||
if err == nil {
|
||||
t.Fatal("should be an error")
|
||||
}
|
||||
if err.Error() != "foo" {
|
||||
t.Fatalf("bad err: %s", err)
|
||||
}
|
||||
if returned != nil {
|
||||
t.Fatalf("bad: %#v", returned)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironmentProvisioner(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
p := &MockProvisioner{}
|
||||
ps := make(map[string]Provisioner)
|
||||
ps["foo"] = p
|
||||
@@ -318,25 +365,29 @@ func TestEnvironmentProvisioner(t *testing.T) {
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returned, err := env.Provisioner("foo")
|
||||
assert.Nil(err, "should be no error")
|
||||
assert.Equal(returned, p, "should return correct provisioner")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if returned != p {
|
||||
t.Fatalf("bad: %#v", returned)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironmentProvisioner_NilError(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.Components.Provisioner = func(n string) (Provisioner, error) { return nil, nil }
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returned, err := env.Provisioner("foo")
|
||||
assert.NotNil(err, "should be an error")
|
||||
assert.Nil(returned, "should be no provisioner")
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if returned != nil {
|
||||
t.Fatalf("bad: %#v", returned)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironmentProvisioner_Error(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
config := DefaultEnvironmentConfig()
|
||||
config.Components.Provisioner = func(n string) (Provisioner, error) {
|
||||
return nil, errors.New("foo")
|
||||
@@ -344,14 +395,18 @@ func TestEnvironmentProvisioner_Error(t *testing.T) {
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
returned, err := env.Provisioner("foo")
|
||||
assert.NotNil(err, "should be an error")
|
||||
assert.Equal(err.Error(), "foo", "should be correct error")
|
||||
assert.Nil(returned, "should be no provisioner")
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if err.Error() != "foo" {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if returned != nil {
|
||||
t.Fatalf("bad: %#v", returned)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_SettingUi(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
ui := &BasicUi{
|
||||
Reader: new(bytes.Buffer),
|
||||
Writer: new(bytes.Buffer),
|
||||
@@ -362,5 +417,7 @@ func TestEnvironment_SettingUi(t *testing.T) {
|
||||
|
||||
env, _ := NewEnvironment(config)
|
||||
|
||||
assert.Equal(env.Ui(), ui, "UIs should be equal")
|
||||
if env.Ui() != ui {
|
||||
t.Fatalf("UI should be equal: %#v", env.Ui())
|
||||
}
|
||||
}
|
||||
|
||||
+10
-12
@@ -1,7 +1,6 @@
|
||||
package packer
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -42,12 +41,7 @@ func (h *CancelHook) Cancel() {
|
||||
}
|
||||
|
||||
func TestDispatchHook_Implements(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
var r Hook
|
||||
c := &DispatchHook{}
|
||||
|
||||
assert.Implementor(c, &r, "should be a Hook")
|
||||
var _ Hook = new(DispatchHook)
|
||||
}
|
||||
|
||||
func TestDispatchHook_Run_NoHooks(t *testing.T) {
|
||||
@@ -57,8 +51,6 @@ func TestDispatchHook_Run_NoHooks(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDispatchHook_Run(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
hook := &MockHook{}
|
||||
|
||||
mapping := make(map[string][]Hook)
|
||||
@@ -66,9 +58,15 @@ func TestDispatchHook_Run(t *testing.T) {
|
||||
dh := &DispatchHook{Mapping: mapping}
|
||||
dh.Run("foo", nil, nil, 42)
|
||||
|
||||
assert.True(hook.RunCalled, "run should be called")
|
||||
assert.Equal(hook.RunName, "foo", "should be proper event")
|
||||
assert.Equal(hook.RunData, 42, "should be correct data")
|
||||
if !hook.RunCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
if hook.RunName != "foo" {
|
||||
t.Fatalf("bad: %s", hook.RunName)
|
||||
}
|
||||
if hook.RunData != 42 {
|
||||
t.Fatalf("bad: %#v", hook.RunData)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDispatchHook_cancel(t *testing.T) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package packer
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
@@ -15,8 +14,6 @@ func TestMultiError_Impl(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMultiErrorError(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
expected := `2 error(s) occurred:
|
||||
|
||||
* foo
|
||||
@@ -28,7 +25,9 @@ func TestMultiErrorError(t *testing.T) {
|
||||
}
|
||||
|
||||
multi := &MultiError{errors}
|
||||
assert.Equal(multi.Error(), expected, "should have proper error")
|
||||
if multi.Error() != expected {
|
||||
t.Fatalf("bad: %s", multi.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiErrorAppend_MultiError(t *testing.T) {
|
||||
|
||||
@@ -10,7 +10,7 @@ type cmdBuilder struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
func (b *cmdBuilder) Prepare(config ...interface{}) error {
|
||||
func (b *cmdBuilder) Prepare(config ...interface{}) ([]string, error) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
b.checkExit(r, nil)
|
||||
|
||||
@@ -1,23 +1,10 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"os/exec"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type helperBuilder byte
|
||||
|
||||
func (helperBuilder) Prepare(...interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (helperBuilder) Run(packer.Ui, packer.Hook, packer.Cache) (packer.Artifact, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (helperBuilder) Cancel() {}
|
||||
|
||||
func TestBuilder_NoExist(t *testing.T) {
|
||||
c := NewClient(&ClientConfig{Cmd: exec.Command("i-should-not-exist")})
|
||||
defer c.Kill()
|
||||
|
||||
@@ -54,7 +54,7 @@ func TestHelperProcess(*testing.T) {
|
||||
fmt.Printf("%s1|:1234\n", APIVersion)
|
||||
<-make(chan int)
|
||||
case "builder":
|
||||
ServeBuilder(new(helperBuilder))
|
||||
ServeBuilder(new(packer.MockBuilder))
|
||||
case "command":
|
||||
ServeCommand(new(helperCommand))
|
||||
case "hook":
|
||||
|
||||
+20
-14
@@ -1,9 +1,9 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"net/rpc"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -30,8 +30,6 @@ func (testArtifact) Destroy() error {
|
||||
}
|
||||
|
||||
func TestArtifactRPC(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
// Create the interface to test
|
||||
a := new(testArtifact)
|
||||
|
||||
@@ -42,21 +40,29 @@ func TestArtifactRPC(t *testing.T) {
|
||||
|
||||
// Create the client over RPC and run some methods to verify it works
|
||||
client, err := rpc.Dial("tcp", address)
|
||||
assert.Nil(err, "should be able to connect")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
aClient := Artifact(client)
|
||||
|
||||
// Test
|
||||
assert.Equal(aClient.BuilderId(), "bid", "should have correct builder ID")
|
||||
assert.Equal(aClient.Files(), []string{"a", "b"}, "should have correct builder ID")
|
||||
assert.Equal(aClient.Id(), "id", "should have correct builder ID")
|
||||
assert.Equal(aClient.String(), "string", "should have correct builder ID")
|
||||
if aClient.BuilderId() != "bid" {
|
||||
t.Fatalf("bad: %s", aClient.BuilderId())
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(aClient.Files(), []string{"a", "b"}) {
|
||||
t.Fatalf("bad: %#v", aClient.Files())
|
||||
}
|
||||
|
||||
if aClient.Id() != "id" {
|
||||
t.Fatalf("bad: %s", aClient.Id())
|
||||
}
|
||||
|
||||
if aClient.String() != "string" {
|
||||
t.Fatalf("bad: %s", aClient.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestArtifact_Implements(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
var r packer.Artifact
|
||||
a := Artifact(nil)
|
||||
|
||||
assert.Implementor(a, &r, "should be an Artifact")
|
||||
var _ packer.Artifact = Artifact(nil)
|
||||
}
|
||||
|
||||
+16
-6
@@ -21,6 +21,11 @@ type BuildRunArgs struct {
|
||||
UiRPCAddress string
|
||||
}
|
||||
|
||||
type BuildPrepareResponse struct {
|
||||
Warnings []string
|
||||
Error error
|
||||
}
|
||||
|
||||
func Build(client *rpc.Client) *build {
|
||||
return &build{client}
|
||||
}
|
||||
@@ -30,12 +35,13 @@ func (b *build) Name() (result string) {
|
||||
return
|
||||
}
|
||||
|
||||
func (b *build) Prepare(v map[string]string) (err error) {
|
||||
if cerr := b.client.Call("Build.Prepare", v, &err); cerr != nil {
|
||||
return cerr
|
||||
func (b *build) Prepare(v map[string]string) ([]string, error) {
|
||||
var resp BuildPrepareResponse
|
||||
if cerr := b.client.Call("Build.Prepare", v, &resp); cerr != nil {
|
||||
return nil, cerr
|
||||
}
|
||||
|
||||
return
|
||||
return resp.Warnings, resp.Error
|
||||
}
|
||||
|
||||
func (b *build) Run(ui packer.Ui, cache packer.Cache) ([]packer.Artifact, error) {
|
||||
@@ -86,8 +92,12 @@ func (b *BuildServer) Name(args *interface{}, reply *string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BuildServer) Prepare(v map[string]string, reply *error) error {
|
||||
*reply = b.build.Prepare(v)
|
||||
func (b *BuildServer) Prepare(v map[string]string, resp *BuildPrepareResponse) error {
|
||||
warnings, err := b.build.Prepare(v)
|
||||
*resp = BuildPrepareResponse{
|
||||
Warnings: warnings,
|
||||
Error: err,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+82
-36
@@ -1,25 +1,26 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"errors"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"net/rpc"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testBuildArtifact = &testArtifact{}
|
||||
|
||||
type testBuild struct {
|
||||
nameCalled bool
|
||||
prepareCalled bool
|
||||
prepareVars map[string]string
|
||||
runCalled bool
|
||||
runCache packer.Cache
|
||||
runUi packer.Ui
|
||||
setDebugCalled bool
|
||||
setForceCalled bool
|
||||
cancelCalled bool
|
||||
nameCalled bool
|
||||
prepareCalled bool
|
||||
prepareVars map[string]string
|
||||
prepareWarnings []string
|
||||
runCalled bool
|
||||
runCache packer.Cache
|
||||
runUi packer.Ui
|
||||
setDebugCalled bool
|
||||
setForceCalled bool
|
||||
cancelCalled bool
|
||||
|
||||
errRunResult bool
|
||||
}
|
||||
@@ -29,10 +30,10 @@ func (b *testBuild) Name() string {
|
||||
return "name"
|
||||
}
|
||||
|
||||
func (b *testBuild) Prepare(v map[string]string) error {
|
||||
func (b *testBuild) Prepare(v map[string]string) ([]string, error) {
|
||||
b.prepareCalled = true
|
||||
b.prepareVars = v
|
||||
return nil
|
||||
return b.prepareWarnings, nil
|
||||
}
|
||||
|
||||
func (b *testBuild) Run(ui packer.Ui, cache packer.Cache) ([]packer.Artifact, error) {
|
||||
@@ -59,9 +60,7 @@ func (b *testBuild) Cancel() {
|
||||
b.cancelCalled = true
|
||||
}
|
||||
|
||||
func TestBuildRPC(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
func buildRPCClient(t *testing.T) (*testBuild, packer.Build) {
|
||||
// Create the interface to test
|
||||
b := new(testBuild)
|
||||
|
||||
@@ -72,16 +71,27 @@ func TestBuildRPC(t *testing.T) {
|
||||
|
||||
// Create the client over RPC and run some methods to verify it works
|
||||
client, err := rpc.Dial("tcp", address)
|
||||
assert.Nil(err, "should be able to connect")
|
||||
bClient := Build(client)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
return b, Build(client)
|
||||
}
|
||||
|
||||
func TestBuild(t *testing.T) {
|
||||
b, bClient := buildRPCClient(t)
|
||||
|
||||
// Test Name
|
||||
bClient.Name()
|
||||
assert.True(b.nameCalled, "name should be called")
|
||||
if !b.nameCalled {
|
||||
t.Fatal("name should be called")
|
||||
}
|
||||
|
||||
// Test Prepare
|
||||
bClient.Prepare(map[string]string{"foo": "bar"})
|
||||
assert.True(b.prepareCalled, "prepare should be called")
|
||||
if !b.prepareCalled {
|
||||
t.Fatal("prepare should be called")
|
||||
}
|
||||
|
||||
if len(b.prepareVars) != 1 {
|
||||
t.Fatalf("bad vars: %#v", b.prepareVars)
|
||||
}
|
||||
@@ -94,44 +104,80 @@ func TestBuildRPC(t *testing.T) {
|
||||
cache := new(testCache)
|
||||
ui := new(testUi)
|
||||
artifacts, err := bClient.Run(ui, cache)
|
||||
assert.True(b.runCalled, "run should be called")
|
||||
assert.Nil(err, "should not error")
|
||||
assert.Equal(len(artifacts), 1, "should have one artifact")
|
||||
assert.Equal(artifacts[0].BuilderId(), "bid", "should have proper builder id")
|
||||
if !b.runCalled {
|
||||
t.Fatal("run should be called")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if len(artifacts) != 1 {
|
||||
t.Fatalf("bad: %#v", artifacts)
|
||||
}
|
||||
|
||||
if artifacts[0].BuilderId() != "bid" {
|
||||
t.Fatalf("bad: %#v", artifacts)
|
||||
}
|
||||
|
||||
// Test the UI given to run, which should be fully functional
|
||||
if b.runCalled {
|
||||
b.runCache.Lock("foo")
|
||||
assert.True(cache.lockCalled, "lock should be called")
|
||||
if !cache.lockCalled {
|
||||
t.Fatal("lock shuld be called")
|
||||
}
|
||||
|
||||
b.runUi.Say("format")
|
||||
assert.True(ui.sayCalled, "say should be called")
|
||||
assert.Equal(ui.sayMessage, "format", "message should be correct")
|
||||
if !ui.sayCalled {
|
||||
t.Fatal("say should be called")
|
||||
}
|
||||
|
||||
if ui.sayMessage != "format" {
|
||||
t.Fatalf("bad: %#v", ui.sayMessage)
|
||||
}
|
||||
}
|
||||
|
||||
// Test run with an error
|
||||
b.errRunResult = true
|
||||
_, err = bClient.Run(ui, cache)
|
||||
assert.NotNil(err, "should not nil")
|
||||
if err == nil {
|
||||
t.Fatal("should error")
|
||||
}
|
||||
|
||||
// Test SetDebug
|
||||
bClient.SetDebug(true)
|
||||
assert.True(b.setDebugCalled, "should be called")
|
||||
if !b.setDebugCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
|
||||
// Test SetForce
|
||||
bClient.SetForce(true)
|
||||
assert.True(b.setForceCalled, "should be called")
|
||||
if !b.setForceCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
|
||||
// Test Cancel
|
||||
bClient.Cancel()
|
||||
assert.True(b.cancelCalled, "cancel should be called")
|
||||
if !b.cancelCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildPrepare_Warnings(t *testing.T) {
|
||||
b, bClient := buildRPCClient(t)
|
||||
|
||||
expected := []string{"foo"}
|
||||
b.prepareWarnings = expected
|
||||
|
||||
warnings, err := bClient.Prepare(nil)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(warnings, expected) {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuild_ImplementsBuild(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
var realBuild packer.Build
|
||||
b := Build(nil)
|
||||
|
||||
assert.Implementor(b, &realBuild, "should be a Build")
|
||||
var _ packer.Build = Build(nil)
|
||||
}
|
||||
|
||||
+17
-7
@@ -29,6 +29,11 @@ type BuilderRunArgs struct {
|
||||
ResponseAddress string
|
||||
}
|
||||
|
||||
type BuilderPrepareResponse struct {
|
||||
Warnings []string
|
||||
Error error
|
||||
}
|
||||
|
||||
type BuilderRunResponse struct {
|
||||
Err error
|
||||
RPCAddress string
|
||||
@@ -38,13 +43,14 @@ func Builder(client *rpc.Client) *builder {
|
||||
return &builder{client}
|
||||
}
|
||||
|
||||
func (b *builder) Prepare(config ...interface{}) (err error) {
|
||||
cerr := b.client.Call("Builder.Prepare", &BuilderPrepareArgs{config}, &err)
|
||||
func (b *builder) Prepare(config ...interface{}) ([]string, error) {
|
||||
var resp BuilderPrepareResponse
|
||||
cerr := b.client.Call("Builder.Prepare", &BuilderPrepareArgs{config}, &resp)
|
||||
if cerr != nil {
|
||||
err = cerr
|
||||
return nil, cerr
|
||||
}
|
||||
|
||||
return
|
||||
return resp.Warnings, resp.Error
|
||||
}
|
||||
|
||||
func (b *builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
@@ -108,12 +114,16 @@ func (b *builder) Cancel() {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BuilderServer) Prepare(args *BuilderPrepareArgs, reply *error) error {
|
||||
err := b.builder.Prepare(args.Configs...)
|
||||
func (b *BuilderServer) Prepare(args *BuilderPrepareArgs, reply *BuilderPrepareResponse) error {
|
||||
warnings, err := b.builder.Prepare(args.Configs...)
|
||||
if err != nil {
|
||||
*reply = NewBasicError(err)
|
||||
err = NewBasicError(err)
|
||||
}
|
||||
|
||||
*reply = BuilderPrepareResponse{
|
||||
Warnings: warnings,
|
||||
Error: err,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+113
-84
@@ -1,58 +1,16 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"errors"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"net/rpc"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testBuilderArtifact = &testArtifact{}
|
||||
|
||||
type testBuilder struct {
|
||||
prepareCalled bool
|
||||
prepareConfig []interface{}
|
||||
runCalled bool
|
||||
runCache packer.Cache
|
||||
runHook packer.Hook
|
||||
runUi packer.Ui
|
||||
cancelCalled bool
|
||||
|
||||
errRunResult bool
|
||||
nilRunResult bool
|
||||
}
|
||||
|
||||
func (b *testBuilder) Prepare(config ...interface{}) error {
|
||||
b.prepareCalled = true
|
||||
b.prepareConfig = config
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *testBuilder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
b.runCache = cache
|
||||
b.runCalled = true
|
||||
b.runHook = hook
|
||||
b.runUi = ui
|
||||
|
||||
if b.errRunResult {
|
||||
return nil, errors.New("foo")
|
||||
} else if b.nilRunResult {
|
||||
return nil, nil
|
||||
} else {
|
||||
return testBuilderArtifact, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (b *testBuilder) Cancel() {
|
||||
b.cancelCalled = true
|
||||
}
|
||||
|
||||
func TestBuilderRPC(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
// Create the interface to test
|
||||
b := new(testBuilder)
|
||||
func builderRPCClient(t *testing.T) (*packer.MockBuilder, packer.Builder) {
|
||||
b := new(packer.MockBuilder)
|
||||
|
||||
// Start the server
|
||||
server := rpc.NewServer()
|
||||
@@ -61,60 +19,131 @@ func TestBuilderRPC(t *testing.T) {
|
||||
|
||||
// Create the client over RPC and run some methods to verify it works
|
||||
client, err := rpc.Dial("tcp", address)
|
||||
assert.Nil(err, "should be able to connect")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
return b, Builder(client)
|
||||
}
|
||||
|
||||
func TestBuilderPrepare(t *testing.T) {
|
||||
b, bClient := builderRPCClient(t)
|
||||
|
||||
// Test Prepare
|
||||
config := 42
|
||||
bClient := Builder(client)
|
||||
bClient.Prepare(config)
|
||||
assert.True(b.prepareCalled, "prepare should be called")
|
||||
assert.Equal(b.prepareConfig, []interface{}{42}, "prepare should be called with right arg")
|
||||
warnings, err := bClient.Prepare(config)
|
||||
if err != nil {
|
||||
t.Fatalf("bad: %s", err)
|
||||
}
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
|
||||
if !b.PrepareCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(b.PrepareConfig, []interface{}{42}) {
|
||||
t.Fatalf("bad: %#v", b.PrepareConfig)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_Warnings(t *testing.T) {
|
||||
b, bClient := builderRPCClient(t)
|
||||
|
||||
expected := []string{"foo"}
|
||||
b.PrepareWarnings = expected
|
||||
|
||||
// Test Prepare
|
||||
warnings, err := bClient.Prepare(nil)
|
||||
if err != nil {
|
||||
t.Fatalf("bad: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(warnings, expected) {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderRun(t *testing.T) {
|
||||
b, bClient := builderRPCClient(t)
|
||||
|
||||
// Test Run
|
||||
cache := new(testCache)
|
||||
hook := &packer.MockHook{}
|
||||
ui := &testUi{}
|
||||
artifact, err := bClient.Run(ui, hook, cache)
|
||||
assert.Nil(err, "should have no error")
|
||||
assert.True(b.runCalled, "runs hould be called")
|
||||
|
||||
if b.runCalled {
|
||||
b.runCache.Lock("foo")
|
||||
assert.True(cache.lockCalled, "lock should be called")
|
||||
|
||||
b.runHook.Run("foo", nil, nil, nil)
|
||||
assert.True(hook.RunCalled, "run should be called")
|
||||
|
||||
b.runUi.Say("format")
|
||||
assert.True(ui.sayCalled, "say should be called")
|
||||
assert.Equal(ui.sayMessage, "format", "message should be correct")
|
||||
|
||||
assert.Equal(artifact.Id(), testBuilderArtifact.Id(), "should have artifact Id")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Test run with nil result
|
||||
b.nilRunResult = true
|
||||
artifact, err = bClient.Run(ui, hook, cache)
|
||||
assert.Nil(artifact, "should be nil")
|
||||
assert.Nil(err, "should have no error")
|
||||
if !b.RunCalled {
|
||||
t.Fatal("run should be called")
|
||||
}
|
||||
|
||||
// Test with an error
|
||||
b.errRunResult = true
|
||||
b.nilRunResult = false
|
||||
artifact, err = bClient.Run(ui, hook, cache)
|
||||
assert.Nil(artifact, "should be nil")
|
||||
assert.NotNil(err, "should have error")
|
||||
b.RunCache.Lock("foo")
|
||||
if !cache.lockCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
|
||||
b.RunHook.Run("foo", nil, nil, nil)
|
||||
if !hook.RunCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
|
||||
b.RunUi.Say("format")
|
||||
if !ui.sayCalled {
|
||||
t.Fatal("say should be called")
|
||||
}
|
||||
|
||||
if ui.sayMessage != "format" {
|
||||
t.Fatalf("bad: %s", ui.sayMessage)
|
||||
}
|
||||
|
||||
if artifact.Id() != testBuilderArtifact.Id() {
|
||||
t.Fatalf("bad: %s", artifact.Id())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderRun_nilResult(t *testing.T) {
|
||||
b, bClient := builderRPCClient(t)
|
||||
b.RunNilResult = true
|
||||
|
||||
cache := new(testCache)
|
||||
hook := &packer.MockHook{}
|
||||
ui := &testUi{}
|
||||
artifact, err := bClient.Run(ui, hook, cache)
|
||||
if artifact != nil {
|
||||
t.Fatalf("bad: %#v", artifact)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("bad: %#v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderRun_ErrResult(t *testing.T) {
|
||||
b, bClient := builderRPCClient(t)
|
||||
b.RunErrResult = true
|
||||
|
||||
cache := new(testCache)
|
||||
hook := &packer.MockHook{}
|
||||
ui := &testUi{}
|
||||
artifact, err := bClient.Run(ui, hook, cache)
|
||||
if artifact != nil {
|
||||
t.Fatalf("bad: %#v", artifact)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderCancel(t *testing.T) {
|
||||
b, bClient := builderRPCClient(t)
|
||||
|
||||
// Test Cancel
|
||||
bClient.Cancel()
|
||||
assert.True(b.cancelCalled, "cancel should be called")
|
||||
if !b.CancelCalled {
|
||||
t.Fatal("cancel should be called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilder_ImplementsBuilder(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
var realBuilder packer.Builder
|
||||
b := Builder(nil)
|
||||
|
||||
assert.Implementor(b, &realBuilder, "should be a Builder")
|
||||
var _ packer.Builder = Builder(nil)
|
||||
}
|
||||
|
||||
+27
-12
@@ -1,7 +1,6 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"net/rpc"
|
||||
"testing"
|
||||
@@ -49,8 +48,6 @@ func TestCache_Implements(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCacheRPC(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
// Create the interface to test
|
||||
c := new(testCache)
|
||||
|
||||
@@ -61,26 +58,44 @@ func TestCacheRPC(t *testing.T) {
|
||||
|
||||
// Create the client over RPC and run some methods to verify it works
|
||||
rpcClient, err := rpc.Dial("tcp", address)
|
||||
assert.Nil(err, "should be able to connect")
|
||||
if err != nil {
|
||||
t.Fatalf("bad: %s", err)
|
||||
}
|
||||
client := Cache(rpcClient)
|
||||
|
||||
// Test Lock
|
||||
client.Lock("foo")
|
||||
assert.True(c.lockCalled, "should be called")
|
||||
assert.Equal(c.lockKey, "foo", "should have proper key")
|
||||
if !c.lockCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
if c.lockKey != "foo" {
|
||||
t.Fatalf("bad: %s", c.lockKey)
|
||||
}
|
||||
|
||||
// Test Unlock
|
||||
client.Unlock("foo")
|
||||
assert.True(c.unlockCalled, "should be called")
|
||||
assert.Equal(c.unlockKey, "foo", "should have proper key")
|
||||
if !c.unlockCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
if c.unlockKey != "foo" {
|
||||
t.Fatalf("bad: %s", c.unlockKey)
|
||||
}
|
||||
|
||||
// Test RLock
|
||||
client.RLock("foo")
|
||||
assert.True(c.rlockCalled, "should be called")
|
||||
assert.Equal(c.rlockKey, "foo", "should have proper key")
|
||||
if !c.rlockCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
if c.rlockKey != "foo" {
|
||||
t.Fatalf("bad: %s", c.rlockKey)
|
||||
}
|
||||
|
||||
// Test RUnlock
|
||||
client.RUnlock("foo")
|
||||
assert.True(c.runlockCalled, "should be called")
|
||||
assert.Equal(c.runlockKey, "foo", "should have proper key")
|
||||
if !c.runlockCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
if c.runlockKey != "foo" {
|
||||
t.Fatalf("bad: %s", c.runlockKey)
|
||||
}
|
||||
}
|
||||
|
||||
+24
-18
@@ -1,9 +1,9 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"net/rpc"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -29,8 +29,6 @@ func (tc *TestCommand) Synopsis() string {
|
||||
}
|
||||
|
||||
func TestRPCCommand(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
// Create the command
|
||||
command := new(TestCommand)
|
||||
|
||||
@@ -42,37 +40,45 @@ func TestRPCCommand(t *testing.T) {
|
||||
// Create the command client over RPC and run some methods to verify
|
||||
// we get the proper behavior.
|
||||
client, err := rpc.Dial("tcp", address)
|
||||
assert.Nil(err, "should be no error")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
clientComm := Command(client)
|
||||
|
||||
//Test Help
|
||||
help := clientComm.Help()
|
||||
assert.Equal(help, "bar", "helps hould be correct")
|
||||
if help != "bar" {
|
||||
t.Fatalf("bad: %s", help)
|
||||
}
|
||||
|
||||
// Test run
|
||||
runArgs := []string{"foo", "bar"}
|
||||
testEnv := &testEnvironment{}
|
||||
exitCode := clientComm.Run(testEnv, runArgs)
|
||||
assert.Equal(command.runArgs, runArgs, "Correct args should be sent")
|
||||
assert.Equal(exitCode, 0, "Exit code should be correct")
|
||||
if !reflect.DeepEqual(command.runArgs, runArgs) {
|
||||
t.Fatalf("bad: %#v", command.runArgs)
|
||||
}
|
||||
if exitCode != 0 {
|
||||
t.Fatalf("bad: %d", exitCode)
|
||||
}
|
||||
|
||||
assert.NotNil(command.runEnv, "should have an env")
|
||||
if command.runEnv != nil {
|
||||
command.runEnv.Ui()
|
||||
assert.True(testEnv.uiCalled, "UI should be called on env")
|
||||
if command.runEnv == nil {
|
||||
t.Fatal("runEnv should not be nil")
|
||||
}
|
||||
|
||||
command.runEnv.Ui()
|
||||
if !testEnv.uiCalled {
|
||||
t.Fatal("ui should be called")
|
||||
}
|
||||
|
||||
// Test Synopsis
|
||||
synopsis := clientComm.Synopsis()
|
||||
assert.Equal(synopsis, "foo", "Synopsis should be correct")
|
||||
if synopsis != "foo" {
|
||||
t.Fatalf("bad: %#v", synopsis)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommand_Implements(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
var r packer.Command
|
||||
c := Command(nil)
|
||||
|
||||
assert.Implementor(c, &r, "should be a Builder")
|
||||
var _ packer.Command = Command(nil)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"net/rpc"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testEnvBuilder = &testBuilder{}
|
||||
var testEnvBuilder = &packer.MockBuilder{}
|
||||
var testEnvCache = &testCache{}
|
||||
var testEnvUi = &testUi{}
|
||||
|
||||
@@ -65,8 +65,6 @@ func (e *testEnvironment) Ui() packer.Ui {
|
||||
}
|
||||
|
||||
func TestEnvironmentRPC(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
// Create the interface to test
|
||||
e := &testEnvironment{}
|
||||
|
||||
@@ -77,49 +75,70 @@ func TestEnvironmentRPC(t *testing.T) {
|
||||
|
||||
// Create the client over RPC and run some methods to verify it works
|
||||
client, err := rpc.Dial("tcp", address)
|
||||
assert.Nil(err, "should be able to connect")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
eClient := &Environment{client}
|
||||
|
||||
// Test Builder
|
||||
builder, _ := eClient.Builder("foo")
|
||||
assert.True(e.builderCalled, "Builder should be called")
|
||||
assert.Equal(e.builderName, "foo", "Correct name for Builder")
|
||||
if !e.builderCalled {
|
||||
t.Fatal("builder should be called")
|
||||
}
|
||||
if e.builderName != "foo" {
|
||||
t.Fatalf("bad: %#v", e.builderName)
|
||||
}
|
||||
|
||||
builder.Prepare(nil)
|
||||
assert.True(testEnvBuilder.prepareCalled, "Prepare should be called")
|
||||
if !testEnvBuilder.PrepareCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
|
||||
// Test Cache
|
||||
cache := eClient.Cache()
|
||||
cache.Lock("foo")
|
||||
assert.True(testEnvCache.lockCalled, "lock should be called")
|
||||
if !testEnvCache.lockCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
|
||||
// Test Cli
|
||||
cliArgs := []string{"foo", "bar"}
|
||||
result, _ := eClient.Cli(cliArgs)
|
||||
assert.True(e.cliCalled, "CLI should be called")
|
||||
assert.Equal(e.cliArgs, cliArgs, "args should match")
|
||||
assert.Equal(result, 42, "result shuld be 42")
|
||||
if !e.cliCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
if !reflect.DeepEqual(e.cliArgs, cliArgs) {
|
||||
t.Fatalf("bad: %#v", e.cliArgs)
|
||||
}
|
||||
if result != 42 {
|
||||
t.Fatalf("bad: %#v", result)
|
||||
}
|
||||
|
||||
// Test Provisioner
|
||||
_, _ = eClient.Provisioner("foo")
|
||||
assert.True(e.provCalled, "provisioner should be called")
|
||||
assert.Equal(e.provName, "foo", "should have proper name")
|
||||
if !e.provCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
if e.provName != "foo" {
|
||||
t.Fatalf("bad: %s", e.provName)
|
||||
}
|
||||
|
||||
// Test Ui
|
||||
ui := eClient.Ui()
|
||||
assert.True(e.uiCalled, "Ui should've been called")
|
||||
if !e.uiCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
|
||||
// Test calls on the Ui
|
||||
ui.Say("format")
|
||||
assert.True(testEnvUi.sayCalled, "Say should be called")
|
||||
assert.Equal(testEnvUi.sayMessage, "format", "message should match")
|
||||
if !testEnvUi.sayCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
if testEnvUi.sayMessage != "format" {
|
||||
t.Fatalf("bad: %#v", testEnvUi.sayMessage)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironment_ImplementsEnvironment(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
var realVar packer.Environment
|
||||
e := &Environment{nil}
|
||||
|
||||
assert.Implementor(e, &realVar, "should be an Environment")
|
||||
var _ packer.Environment = new(Environment)
|
||||
}
|
||||
|
||||
@@ -1,25 +1,19 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBasicError_ImplementsError(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
var r error
|
||||
e := &BasicError{""}
|
||||
|
||||
assert.Implementor(e, &r, "should be an error")
|
||||
var _ error = new(BasicError)
|
||||
}
|
||||
|
||||
func TestBasicError_MatchesMessage(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
err := errors.New("foo")
|
||||
wrapped := NewBasicError(err)
|
||||
|
||||
assert.Equal(wrapped.Error(), err.Error(), "should have the same error")
|
||||
if wrapped.Error() != err.Error() {
|
||||
t.Fatalf("bad: %#v", wrapped.Error())
|
||||
}
|
||||
}
|
||||
|
||||
+10
-12
@@ -1,7 +1,6 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"net/rpc"
|
||||
"reflect"
|
||||
@@ -11,8 +10,6 @@ import (
|
||||
)
|
||||
|
||||
func TestHookRPC(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
// Create the UI to test
|
||||
h := new(packer.MockHook)
|
||||
|
||||
@@ -23,27 +20,28 @@ func TestHookRPC(t *testing.T) {
|
||||
|
||||
// Create the client over RPC and run some methods to verify it works
|
||||
client, err := rpc.Dial("tcp", address)
|
||||
assert.Nil(err, "should be able to connect")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
hClient := Hook(client)
|
||||
|
||||
// Test Run
|
||||
ui := &testUi{}
|
||||
hClient.Run("foo", ui, nil, 42)
|
||||
assert.True(h.RunCalled, "run should be called")
|
||||
if !h.RunCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
|
||||
// Test Cancel
|
||||
hClient.Cancel()
|
||||
assert.True(h.CancelCalled, "cancel should be called")
|
||||
if !h.CancelCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHook_Implements(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
var r packer.Hook
|
||||
h := &hook{nil}
|
||||
|
||||
assert.Implementor(h, &r, "should be a Hook")
|
||||
var _ packer.Hook = new(hook)
|
||||
}
|
||||
|
||||
func TestHook_cancelWhileRun(t *testing.T) {
|
||||
|
||||
+12
-7
@@ -1,7 +1,6 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -13,21 +12,27 @@ func addrPort(address net.Addr) string {
|
||||
}
|
||||
|
||||
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")
|
||||
defer L1000.Close()
|
||||
assert.Nil(err, "should be able to bind to port 10000")
|
||||
if err != nil {
|
||||
t.Fatalf("bad: %s", err)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
// Verify it selects an open port
|
||||
L := netListenerInRange(11000, 11005)
|
||||
assert.NotNil(L, "should have a listener")
|
||||
assert.Equal(addrPort(L.Addr()), "11001", "should bind to open port")
|
||||
if L == nil {
|
||||
t.Fatal("L should not be nil")
|
||||
}
|
||||
if addrPort(L.Addr()) != "11001" {
|
||||
t.Fatalf("bad: %s", L.Addr())
|
||||
}
|
||||
|
||||
// Returns nil if there are no open ports
|
||||
L = netListenerInRange(11000, 11000)
|
||||
assert.Nil(L, "should not get a listener")
|
||||
if L != nil {
|
||||
t.Fatalf("bad: %#v", L)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"net/rpc"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestProvisionerRPC(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
// Create the interface to test
|
||||
p := new(packer.MockProvisioner)
|
||||
|
||||
@@ -20,23 +18,33 @@ func TestProvisionerRPC(t *testing.T) {
|
||||
|
||||
// Create the client over RPC and run some methods to verify it works
|
||||
client, err := rpc.Dial("tcp", address)
|
||||
assert.Nil(err, "should be able to connect")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Test Prepare
|
||||
config := 42
|
||||
pClient := Provisioner(client)
|
||||
pClient.Prepare(config)
|
||||
assert.True(p.PrepCalled, "prepare should be called")
|
||||
assert.Equal(p.PrepConfigs, []interface{}{42}, "prepare should be called with right arg")
|
||||
if !p.PrepCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
if !reflect.DeepEqual(p.PrepConfigs, []interface{}{42}) {
|
||||
t.Fatalf("bad: %#v", p.PrepConfigs)
|
||||
}
|
||||
|
||||
// Test Provision
|
||||
ui := &testUi{}
|
||||
comm := &packer.MockCommunicator{}
|
||||
pClient.Provision(ui, comm)
|
||||
assert.True(p.ProvCalled, "provision should be called")
|
||||
if !p.ProvCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
|
||||
p.ProvUi.Say("foo")
|
||||
assert.True(ui.sayCalled, "say should be called")
|
||||
if !ui.sayCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
|
||||
// Test Cancel
|
||||
pClient.Cancel()
|
||||
@@ -46,10 +54,5 @@ func TestProvisionerRPC(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProvisioner_Implements(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
var r packer.Provisioner
|
||||
p := Provisioner(nil)
|
||||
|
||||
assert.Implementor(p, &r, "should be a provisioner")
|
||||
var _ packer.Provisioner = Provisioner(nil)
|
||||
}
|
||||
|
||||
+21
-10
@@ -1,7 +1,6 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"net/rpc"
|
||||
"reflect"
|
||||
"testing"
|
||||
@@ -49,8 +48,6 @@ func (u *testUi) Say(message string) {
|
||||
}
|
||||
|
||||
func TestUiRPC(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
// Create the UI to test
|
||||
ui := new(testUi)
|
||||
|
||||
@@ -69,19 +66,33 @@ func TestUiRPC(t *testing.T) {
|
||||
|
||||
// Basic error and say tests
|
||||
result, err := uiClient.Ask("query")
|
||||
assert.Nil(err, "should not error")
|
||||
assert.True(ui.askCalled, "ask should be called")
|
||||
assert.Equal(ui.askQuery, "query", "should be correct")
|
||||
assert.Equal(result, "foo", "should have correct result")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if !ui.askCalled {
|
||||
t.Fatal("should be called")
|
||||
}
|
||||
if ui.askQuery != "query" {
|
||||
t.Fatalf("bad: %s", ui.askQuery)
|
||||
}
|
||||
if result != "foo" {
|
||||
t.Fatalf("bad: %#v", result)
|
||||
}
|
||||
|
||||
uiClient.Error("message")
|
||||
assert.Equal(ui.errorMessage, "message", "message should be correct")
|
||||
if ui.errorMessage != "message" {
|
||||
t.Fatalf("bad: %#v", ui.errorMessage)
|
||||
}
|
||||
|
||||
uiClient.Message("message")
|
||||
assert.Equal(ui.messageMessage, "message", "message should be correct")
|
||||
if ui.messageMessage != "message" {
|
||||
t.Fatalf("bad: %#v", ui.errorMessage)
|
||||
}
|
||||
|
||||
uiClient.Say("message")
|
||||
assert.Equal(ui.sayMessage, "message", "message should be correct")
|
||||
if ui.sayMessage != "message" {
|
||||
t.Fatalf("bad: %#v", ui.errorMessage)
|
||||
}
|
||||
|
||||
uiClient.Machine("foo", "bar", "baz")
|
||||
if !ui.machineCalled {
|
||||
|
||||
+189
-108
@@ -1,7 +1,6 @@
|
||||
package packer
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
@@ -10,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func testTemplateComponentFinder() *ComponentFinder {
|
||||
builder := testBuilder()
|
||||
builder := new(MockBuilder)
|
||||
pp := new(TestPostProcessor)
|
||||
provisioner := &MockProvisioner{}
|
||||
|
||||
@@ -94,8 +93,6 @@ func TestParseTemplateFile_stdin(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestParseTemplate_Basic(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [{"type": "something"}]
|
||||
@@ -103,14 +100,18 @@ func TestParseTemplate_Basic(t *testing.T) {
|
||||
`
|
||||
|
||||
result, err := ParseTemplate([]byte(data))
|
||||
assert.Nil(err, "should not error")
|
||||
assert.NotNil(result, "template should not be nil")
|
||||
assert.Length(result.Builders, 1, "one builder")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if result == nil {
|
||||
t.Fatal("should have result")
|
||||
}
|
||||
if len(result.Builders) != 1 {
|
||||
t.Fatalf("bad: %#v", result.Builders)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTemplate_Invalid(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
// Note there is an extra comma below for a purposeful
|
||||
// syntax error in the JSON.
|
||||
data := `
|
||||
@@ -120,13 +121,15 @@ func TestParseTemplate_Invalid(t *testing.T) {
|
||||
`
|
||||
|
||||
result, err := ParseTemplate([]byte(data))
|
||||
assert.NotNil(err, "should have an error")
|
||||
assert.Nil(result, "should have no result")
|
||||
if err == nil {
|
||||
t.Fatal("shold have error")
|
||||
}
|
||||
if result != nil {
|
||||
t.Fatal("should not have result")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTemplate_InvalidKeys(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
// Note there is an extra comma below for a purposeful
|
||||
// syntax error in the JSON.
|
||||
data := `
|
||||
@@ -137,13 +140,15 @@ func TestParseTemplate_InvalidKeys(t *testing.T) {
|
||||
`
|
||||
|
||||
result, err := ParseTemplate([]byte(data))
|
||||
assert.NotNil(err, "should have an error")
|
||||
assert.Nil(result, "should have no result")
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if result != nil {
|
||||
t.Fatal("should not have result")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTemplate_BuilderWithoutType(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [{}]
|
||||
@@ -151,12 +156,12 @@ func TestParseTemplate_BuilderWithoutType(t *testing.T) {
|
||||
`
|
||||
|
||||
_, err := ParseTemplate([]byte(data))
|
||||
assert.NotNil(err, "should have error")
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTemplate_BuilderWithNonStringType(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [{
|
||||
@@ -166,12 +171,12 @@ func TestParseTemplate_BuilderWithNonStringType(t *testing.T) {
|
||||
`
|
||||
|
||||
_, err := ParseTemplate([]byte(data))
|
||||
assert.NotNil(err, "should have error")
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTemplate_BuilderWithoutName(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [
|
||||
@@ -183,18 +188,26 @@ func TestParseTemplate_BuilderWithoutName(t *testing.T) {
|
||||
`
|
||||
|
||||
result, err := ParseTemplate([]byte(data))
|
||||
assert.Nil(err, "should not error")
|
||||
assert.NotNil(result, "template should not be nil")
|
||||
assert.Length(result.Builders, 1, "should have one builder")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if result == nil {
|
||||
t.Fatal("should have result")
|
||||
}
|
||||
if len(result.Builders) != 1 {
|
||||
t.Fatalf("bad: %#v", result.Builders)
|
||||
}
|
||||
|
||||
builder, ok := result.Builders["amazon-ebs"]
|
||||
assert.True(ok, "should have amazon-ebs builder")
|
||||
assert.Equal(builder.Type, "amazon-ebs", "builder should be amazon-ebs")
|
||||
if !ok {
|
||||
t.Fatal("should be ok")
|
||||
}
|
||||
if builder.Type != "amazon-ebs" {
|
||||
t.Fatalf("bad: %#v", builder.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTemplate_BuilderWithName(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [
|
||||
@@ -207,13 +220,23 @@ func TestParseTemplate_BuilderWithName(t *testing.T) {
|
||||
`
|
||||
|
||||
result, err := ParseTemplate([]byte(data))
|
||||
assert.Nil(err, "should not error")
|
||||
assert.NotNil(result, "template should not be nil")
|
||||
assert.Length(result.Builders, 1, "should have one builder")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if result == nil {
|
||||
t.Fatal("should have result")
|
||||
}
|
||||
if len(result.Builders) != 1 {
|
||||
t.Fatalf("bad: %#v", result.Builders)
|
||||
}
|
||||
|
||||
builder, ok := result.Builders["bob"]
|
||||
assert.True(ok, "should have bob builder")
|
||||
assert.Equal(builder.Type, "amazon-ebs", "builder should be amazon-ebs")
|
||||
if !ok {
|
||||
t.Fatal("should be ok")
|
||||
}
|
||||
if builder.Type != "amazon-ebs" {
|
||||
t.Fatalf("bad: %#v", builder.Type)
|
||||
}
|
||||
|
||||
RawConfig := builder.RawConfig
|
||||
if RawConfig == nil {
|
||||
@@ -230,8 +253,6 @@ func TestParseTemplate_BuilderWithName(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestParseTemplate_BuilderWithConflictingName(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [
|
||||
@@ -248,12 +269,12 @@ func TestParseTemplate_BuilderWithConflictingName(t *testing.T) {
|
||||
`
|
||||
|
||||
_, err := ParseTemplate([]byte(data))
|
||||
assert.NotNil(err, "should have error")
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTemplate_Hooks(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
|
||||
@@ -266,13 +287,23 @@ func TestParseTemplate_Hooks(t *testing.T) {
|
||||
`
|
||||
|
||||
result, err := ParseTemplate([]byte(data))
|
||||
assert.Nil(err, "should not error")
|
||||
assert.NotNil(result, "template should not be nil")
|
||||
assert.Length(result.Hooks, 1, "should have one hook")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if result == nil {
|
||||
t.Fatal("should have result")
|
||||
}
|
||||
if len(result.Hooks) != 1 {
|
||||
t.Fatalf("bad: %#v", result.Hooks)
|
||||
}
|
||||
|
||||
hooks, ok := result.Hooks["event"]
|
||||
assert.True(ok, "should have hook")
|
||||
assert.Equal(hooks, []string{"foo", "bar"}, "hooks should be correct")
|
||||
if !ok {
|
||||
t.Fatal("should be okay")
|
||||
}
|
||||
if !reflect.DeepEqual(hooks, []string{"foo", "bar"}) {
|
||||
t.Fatalf("bad: %#v", hooks)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTemplate_PostProcessors(t *testing.T) {
|
||||
@@ -332,8 +363,6 @@ func TestParseTemplate_PostProcessors(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestParseTemplate_ProvisionerWithoutType(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [{"type": "foo"}],
|
||||
@@ -343,12 +372,12 @@ func TestParseTemplate_ProvisionerWithoutType(t *testing.T) {
|
||||
`
|
||||
|
||||
_, err := ParseTemplate([]byte(data))
|
||||
assert.NotNil(err, "should have error")
|
||||
if err == nil {
|
||||
t.Fatal("err should not be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTemplate_ProvisionerWithNonStringType(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [{"type": "foo"}],
|
||||
@@ -360,12 +389,12 @@ func TestParseTemplate_ProvisionerWithNonStringType(t *testing.T) {
|
||||
`
|
||||
|
||||
_, err := ParseTemplate([]byte(data))
|
||||
assert.NotNil(err, "should have error")
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTemplate_Provisioners(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [{"type": "foo"}],
|
||||
@@ -379,11 +408,21 @@ func TestParseTemplate_Provisioners(t *testing.T) {
|
||||
`
|
||||
|
||||
result, err := ParseTemplate([]byte(data))
|
||||
assert.Nil(err, "should not error")
|
||||
assert.NotNil(result, "template should not be nil")
|
||||
assert.Length(result.Provisioners, 1, "should have one provisioner")
|
||||
assert.Equal(result.Provisioners[0].Type, "shell", "provisioner should be shell")
|
||||
assert.NotNil(result.Provisioners[0].RawConfig, "should have raw config")
|
||||
if err != nil {
|
||||
t.Fatal("err: %s", err)
|
||||
}
|
||||
if result == nil {
|
||||
t.Fatal("should have result")
|
||||
}
|
||||
if len(result.Provisioners) != 1 {
|
||||
t.Fatalf("bad: %#v", result.Provisioners)
|
||||
}
|
||||
if result.Provisioners[0].Type != "shell" {
|
||||
t.Fatalf("bad: %#v", result.Provisioners[0].Type)
|
||||
}
|
||||
if result.Provisioners[0].RawConfig == nil {
|
||||
t.Fatal("should have raw config")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTemplate_Variables(t *testing.T) {
|
||||
@@ -451,8 +490,6 @@ func TestParseTemplate_variablesBadDefault(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTemplate_BuildNames(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [
|
||||
@@ -469,16 +506,18 @@ func TestTemplate_BuildNames(t *testing.T) {
|
||||
`
|
||||
|
||||
result, err := ParseTemplate([]byte(data))
|
||||
assert.Nil(err, "should not error")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
buildNames := result.BuildNames()
|
||||
sort.Strings(buildNames)
|
||||
assert.Equal(buildNames, []string{"bob", "chris"}, "should have proper builds")
|
||||
if !reflect.DeepEqual(buildNames, []string{"bob", "chris"}) {
|
||||
t.Fatalf("bad: %#v", buildNames)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplate_BuildUnknown(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [
|
||||
@@ -491,16 +530,20 @@ func TestTemplate_BuildUnknown(t *testing.T) {
|
||||
`
|
||||
|
||||
template, err := ParseTemplate([]byte(data))
|
||||
assert.Nil(err, "should not error")
|
||||
if err != nil {
|
||||
t.Fatalf("bad: %s", err)
|
||||
}
|
||||
|
||||
build, err := template.Build("nope", nil)
|
||||
assert.Nil(build, "build should be nil")
|
||||
assert.NotNil(err, "should have error")
|
||||
if build != nil {
|
||||
t.Fatalf("build should be nil: %#v", build)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplate_BuildUnknownBuilder(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [
|
||||
@@ -513,18 +556,22 @@ func TestTemplate_BuildUnknownBuilder(t *testing.T) {
|
||||
`
|
||||
|
||||
template, err := ParseTemplate([]byte(data))
|
||||
assert.Nil(err, "should not error")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
builderFactory := func(string) (Builder, error) { return nil, nil }
|
||||
components := &ComponentFinder{Builder: builderFactory}
|
||||
build, err := template.Build("test1", components)
|
||||
assert.Nil(build, "build should be nil")
|
||||
assert.NotNil(err, "should have error")
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if build != nil {
|
||||
t.Fatalf("bad: %#v", build)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplate_Build_NilBuilderFunc(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [
|
||||
@@ -543,14 +590,18 @@ func TestTemplate_Build_NilBuilderFunc(t *testing.T) {
|
||||
`
|
||||
|
||||
template, err := ParseTemplate([]byte(data))
|
||||
assert.Nil(err, "should not error")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
p := recover()
|
||||
assert.NotNil(p, "should panic")
|
||||
if p == nil {
|
||||
t.Fatal("should panic")
|
||||
}
|
||||
|
||||
if p != nil {
|
||||
assert.Equal(p.(string), "no builder function", "right panic")
|
||||
if p.(string) != "no builder function" {
|
||||
t.Fatalf("bad panic: %s", p.(string))
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -558,8 +609,6 @@ func TestTemplate_Build_NilBuilderFunc(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTemplate_Build_NilProvisionerFunc(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [
|
||||
@@ -578,14 +627,18 @@ func TestTemplate_Build_NilProvisionerFunc(t *testing.T) {
|
||||
`
|
||||
|
||||
template, err := ParseTemplate([]byte(data))
|
||||
assert.Nil(err, "should not error")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
p := recover()
|
||||
assert.NotNil(p, "should panic")
|
||||
if p == nil {
|
||||
t.Fatal("should panic")
|
||||
}
|
||||
|
||||
if p != nil {
|
||||
assert.Equal(p.(string), "no provisioner function", "right panic")
|
||||
if p.(string) != "no provisioner function" {
|
||||
t.Fatalf("bad panic: %s", p.(string))
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -595,8 +648,6 @@ func TestTemplate_Build_NilProvisionerFunc(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTemplate_Build_NilProvisionerFunc_WithNoProvisioners(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [
|
||||
@@ -611,7 +662,9 @@ func TestTemplate_Build_NilProvisionerFunc_WithNoProvisioners(t *testing.T) {
|
||||
`
|
||||
|
||||
template, err := ParseTemplate([]byte(data))
|
||||
assert.Nil(err, "should not error")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
template.Build("test1", &ComponentFinder{
|
||||
Builder: func(string) (Builder, error) { return nil, nil },
|
||||
@@ -619,8 +672,6 @@ func TestTemplate_Build_NilProvisionerFunc_WithNoProvisioners(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTemplate_Build(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [
|
||||
@@ -651,9 +702,11 @@ func TestTemplate_Build(t *testing.T) {
|
||||
}
|
||||
|
||||
template, err := ParseTemplate([]byte(data))
|
||||
assert.Nil(err, "should not error")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
builder := testBuilder()
|
||||
builder := new(MockBuilder)
|
||||
builderMap := map[string]Builder{
|
||||
"test-builder": builder,
|
||||
}
|
||||
@@ -680,18 +733,40 @@ func TestTemplate_Build(t *testing.T) {
|
||||
// Get the build, verifying we can get it without issue, but also
|
||||
// that the proper builder was looked up and used for the build.
|
||||
build, err := template.Build("test1", components)
|
||||
assert.Nil(err, "should not error")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
coreBuild, ok := build.(*coreBuild)
|
||||
assert.True(ok, "should be a core build")
|
||||
assert.Equal(coreBuild.builder, builder, "should have the same builder")
|
||||
assert.Equal(coreBuild.builderConfig, expectedConfig, "should have proper config")
|
||||
assert.Equal(len(coreBuild.provisioners), 1, "should have one provisioner")
|
||||
assert.Equal(len(coreBuild.postProcessors), 2, "should have pps")
|
||||
assert.Equal(len(coreBuild.postProcessors[0]), 1, "should have correct number")
|
||||
assert.Equal(len(coreBuild.postProcessors[1]), 2, "should have correct number")
|
||||
assert.False(coreBuild.postProcessors[1][0].keepInputArtifact, "shoule be correct")
|
||||
assert.True(coreBuild.postProcessors[1][1].keepInputArtifact, "shoule be correct")
|
||||
if !ok {
|
||||
t.Fatal("should be ok")
|
||||
}
|
||||
if coreBuild.builder != builder {
|
||||
t.Fatalf("bad: %#v", coreBuild.builder)
|
||||
}
|
||||
if !reflect.DeepEqual(coreBuild.builderConfig, expectedConfig) {
|
||||
t.Fatalf("bad: %#v", coreBuild.builderConfig)
|
||||
}
|
||||
if len(coreBuild.provisioners) != 1 {
|
||||
t.Fatalf("bad: %#v", coreBuild.provisioners)
|
||||
}
|
||||
if len(coreBuild.postProcessors) != 2 {
|
||||
t.Fatalf("bad: %#v", coreBuild.postProcessors)
|
||||
}
|
||||
|
||||
if len(coreBuild.postProcessors[0]) != 1 {
|
||||
t.Fatalf("bad: %#v", coreBuild.postProcessors[0])
|
||||
}
|
||||
if len(coreBuild.postProcessors[1]) != 2 {
|
||||
t.Fatalf("bad: %#v", coreBuild.postProcessors[1])
|
||||
}
|
||||
|
||||
if coreBuild.postProcessors[1][0].keepInputArtifact {
|
||||
t.Fatal("postProcessors[1][0] should not keep input artifact")
|
||||
}
|
||||
if !coreBuild.postProcessors[1][1].keepInputArtifact {
|
||||
t.Fatal("postProcessors[1][1] should keep input artifact")
|
||||
}
|
||||
|
||||
config := coreBuild.postProcessors[1][1].config
|
||||
if _, ok := config["keep_input_artifact"]; ok {
|
||||
@@ -1080,8 +1155,6 @@ func TestTemplateBuild_onlyProv(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTemplate_Build_ProvisionerOverride(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
data := `
|
||||
{
|
||||
"builders": [
|
||||
@@ -1121,7 +1194,7 @@ func TestTemplate_Build_ProvisionerOverride(t *testing.T) {
|
||||
t.Fatalf("bad raw: %#v", RawConfig)
|
||||
}
|
||||
|
||||
builder := testBuilder()
|
||||
builder := new(MockBuilder)
|
||||
builderMap := map[string]Builder{
|
||||
"test-builder": builder,
|
||||
}
|
||||
@@ -1141,12 +1214,20 @@ func TestTemplate_Build_ProvisionerOverride(t *testing.T) {
|
||||
// Get the build, verifying we can get it without issue, but also
|
||||
// that the proper builder was looked up and used for the build.
|
||||
build, err := template.Build("test1", components)
|
||||
assert.Nil(err, "should not error")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
coreBuild, ok := build.(*coreBuild)
|
||||
assert.True(ok, "should be a core build")
|
||||
assert.Equal(len(coreBuild.provisioners), 1, "should have one provisioner")
|
||||
assert.Equal(len(coreBuild.provisioners[0].config), 2, "should have two configs on the provisioner")
|
||||
if !ok {
|
||||
t.Fatal("should be okay")
|
||||
}
|
||||
if len(coreBuild.provisioners) != 1 {
|
||||
t.Fatalf("bad: %#v", coreBuild.provisioners)
|
||||
}
|
||||
if len(coreBuild.provisioners[0].config) != 2 {
|
||||
t.Fatalf("bad: %#v", coreBuild.provisioners[0].config)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplate_Build_ProvisionerOverrideBad(t *testing.T) {
|
||||
|
||||
+3
-3
@@ -210,7 +210,7 @@ func (rw *BasicUi) Say(message string) {
|
||||
log.Printf("ui: %s", message)
|
||||
_, err := fmt.Fprint(rw.Writer, message+"\n")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Printf("[ERR] Failed to write to UI: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ func (rw *BasicUi) Message(message string) {
|
||||
log.Printf("ui: %s", message)
|
||||
_, err := fmt.Fprint(rw.Writer, message+"\n")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Printf("[ERR] Failed to write to UI: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ func (rw *BasicUi) Error(message string) {
|
||||
log.Printf("ui error: %s", message)
|
||||
_, err := fmt.Fprint(rw.Writer, message+"\n")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Printf("[ERR] Failed to write to UI: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+44
-15
@@ -2,7 +2,6 @@ package packer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cgl.tideland.biz/asserts"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -38,25 +37,40 @@ func TestColoredUi(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTargettedUi(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
bufferUi := testUi()
|
||||
targettedUi := &TargettedUi{
|
||||
Target: "foo",
|
||||
Ui: bufferUi,
|
||||
}
|
||||
|
||||
var actual, expected string
|
||||
targettedUi.Say("foo")
|
||||
assert.Equal(readWriter(bufferUi), "==> foo: foo\n", "should have prefix")
|
||||
actual = readWriter(bufferUi)
|
||||
expected = "==> foo: foo\n"
|
||||
if actual != expected {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
|
||||
targettedUi.Message("foo")
|
||||
assert.Equal(readWriter(bufferUi), " foo: foo\n", "should have prefix")
|
||||
actual = readWriter(bufferUi)
|
||||
expected = " foo: foo\n"
|
||||
if actual != expected {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
|
||||
targettedUi.Error("bar")
|
||||
assert.Equal(readWriter(bufferUi), "==> foo: bar\n", "should have prefix")
|
||||
actual = readWriter(bufferUi)
|
||||
expected = "==> foo: bar\n"
|
||||
if actual != expected {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
|
||||
targettedUi.Say("foo\nbar")
|
||||
assert.Equal(readWriter(bufferUi), "==> foo: foo\n==> foo: bar\n", "should multiline")
|
||||
actual = readWriter(bufferUi)
|
||||
expected = "==> foo: foo\n==> foo: bar\n"
|
||||
if actual != expected {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestColoredUi_ImplUi(t *testing.T) {
|
||||
@@ -84,27 +98,42 @@ func TestBasicUi_ImplUi(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBasicUi_Error(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
bufferUi := testUi()
|
||||
|
||||
var actual, expected string
|
||||
bufferUi.Error("foo")
|
||||
assert.Equal(readWriter(bufferUi), "foo\n", "basic output")
|
||||
actual = readWriter(bufferUi)
|
||||
expected = "foo\n"
|
||||
if actual != expected {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
|
||||
bufferUi.Error("5")
|
||||
assert.Equal(readWriter(bufferUi), "5\n", "formatting")
|
||||
actual = readWriter(bufferUi)
|
||||
expected = "5\n"
|
||||
if actual != expected {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBasicUi_Say(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
bufferUi := testUi()
|
||||
|
||||
var actual, expected string
|
||||
|
||||
bufferUi.Say("foo")
|
||||
assert.Equal(readWriter(bufferUi), "foo\n", "basic output")
|
||||
actual = readWriter(bufferUi)
|
||||
expected = "foo\n"
|
||||
if actual != expected {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
|
||||
bufferUi.Say("5")
|
||||
assert.Equal(readWriter(bufferUi), "5\n", "formatting")
|
||||
actual = readWriter(bufferUi)
|
||||
expected = "5\n"
|
||||
if actual != expected {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMachineReadableUi_ImplUi(t *testing.T) {
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import (
|
||||
var GitCommit string
|
||||
|
||||
// The version of packer.
|
||||
const Version = "0.3.9"
|
||||
const Version = "0.3.11"
|
||||
|
||||
// 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
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/packer/packer/plugin"
|
||||
"github.com/mitchellh/packer/provisioner/ansible-local"
|
||||
)
|
||||
|
||||
func main() {
|
||||
plugin.ServeProvisioner(new(ansiblelocal.Provisioner))
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package main
|
||||
@@ -1,6 +1,7 @@
|
||||
package vagrant
|
||||
|
||||
import (
|
||||
"compress/flate"
|
||||
"fmt"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
@@ -8,6 +9,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -16,6 +18,7 @@ type AWSBoxConfig struct {
|
||||
|
||||
OutputPath string `mapstructure:"output"`
|
||||
VagrantfileTemplate string `mapstructure:"vagrantfile_template"`
|
||||
CompressionLevel string `mapstructure:"compression_level"`
|
||||
|
||||
tpl *packer.ConfigTemplate
|
||||
}
|
||||
@@ -46,6 +49,7 @@ func (p *AWSBoxPostProcessor) Configure(raws ...interface{}) error {
|
||||
validates := map[string]*string{
|
||||
"output": &p.config.OutputPath,
|
||||
"vagrantfile_template": &p.config.VagrantfileTemplate,
|
||||
"compression_level": &p.config.CompressionLevel,
|
||||
}
|
||||
|
||||
for n, ptr := range validates {
|
||||
@@ -127,6 +131,14 @@ func (p *AWSBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact
|
||||
vf.Write([]byte(vagrantfileContents))
|
||||
vf.Close()
|
||||
|
||||
var level int = flate.DefaultCompression
|
||||
if p.config.CompressionLevel != "" {
|
||||
level, err = strconv.Atoi(p.config.CompressionLevel)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create the metadata
|
||||
metadata := map[string]string{"provider": "aws"}
|
||||
if err := WriteMetadata(dir, metadata); err != nil {
|
||||
@@ -134,7 +146,7 @@ func (p *AWSBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact
|
||||
}
|
||||
|
||||
// Compress the directory to the given output path
|
||||
if err := DirToBox(outputPath, dir, ui); err != nil {
|
||||
if err := DirToBox(outputPath, dir, ui, level); err != nil {
|
||||
err = fmt.Errorf("error creating box: %s", err)
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
@@ -12,9 +12,10 @@ import (
|
||||
)
|
||||
|
||||
var builtins = map[string]string{
|
||||
"mitchellh.amazonebs": "aws",
|
||||
"mitchellh.virtualbox": "virtualbox",
|
||||
"mitchellh.vmware": "vmware",
|
||||
"mitchellh.amazonebs": "aws",
|
||||
"mitchellh.amazon.instance": "aws",
|
||||
"mitchellh.virtualbox": "virtualbox",
|
||||
"mitchellh.vmware": "vmware",
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
|
||||
@@ -44,7 +44,7 @@ func CopyContents(dst, src string) error {
|
||||
// DirToBox takes the directory and compresses it into a Vagrant-compatible
|
||||
// box. This function does not perform checks to verify that dir is
|
||||
// actually a proper box. This is an expected precondition.
|
||||
func DirToBox(dst, dir string, ui packer.Ui) error {
|
||||
func DirToBox(dst, dir string, ui packer.Ui, level int) error {
|
||||
log.Printf("Turning dir into box: %s => %s", dir, dst)
|
||||
dstF, err := os.Create(dst)
|
||||
if err != nil {
|
||||
@@ -52,7 +52,10 @@ func DirToBox(dst, dir string, ui packer.Ui) error {
|
||||
}
|
||||
defer dstF.Close()
|
||||
|
||||
gzipWriter := gzip.NewWriter(dstF)
|
||||
gzipWriter, err := gzip.NewWriterLevel(dstF, level)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer gzipWriter.Close()
|
||||
|
||||
tarWriter := tar.NewWriter(gzipWriter)
|
||||
|
||||
@@ -2,6 +2,7 @@ package vagrant
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/flate"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mitchellh/packer/common"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type VBoxBoxConfig struct {
|
||||
@@ -19,6 +21,7 @@ type VBoxBoxConfig struct {
|
||||
|
||||
OutputPath string `mapstructure:"output"`
|
||||
VagrantfileTemplate string `mapstructure:"vagrantfile_template"`
|
||||
CompressionLevel string `mapstructure:"compression_level"`
|
||||
|
||||
tpl *packer.ConfigTemplate
|
||||
}
|
||||
@@ -49,6 +52,7 @@ func (p *VBoxBoxPostProcessor) Configure(raws ...interface{}) error {
|
||||
validates := map[string]*string{
|
||||
"output": &p.config.OutputPath,
|
||||
"vagrantfile_template": &p.config.VagrantfileTemplate,
|
||||
"compression_level": &p.config.CompressionLevel,
|
||||
}
|
||||
|
||||
for n, ptr := range validates {
|
||||
@@ -92,7 +96,7 @@ func (p *VBoxBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifac
|
||||
// directory so we can get the resulting disk and OVF.
|
||||
if extension := filepath.Ext(path); extension == ".ova" {
|
||||
ui.Message(fmt.Sprintf("Unpacking OVA: %s", path))
|
||||
if err := DecompressOva(dir, filepath.Base(path)); err != nil {
|
||||
if err := DecompressOva(dir, path); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
} else {
|
||||
@@ -141,6 +145,14 @@ func (p *VBoxBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifac
|
||||
vf.Write([]byte(vagrantfileContents))
|
||||
vf.Close()
|
||||
|
||||
var level int = flate.DefaultCompression
|
||||
if p.config.CompressionLevel != "" {
|
||||
level, err = strconv.Atoi(p.config.CompressionLevel)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create the metadata
|
||||
metadata := map[string]string{"provider": "virtualbox"}
|
||||
if err := WriteMetadata(dir, metadata); err != nil {
|
||||
@@ -155,7 +167,7 @@ func (p *VBoxBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifac
|
||||
|
||||
// Compress the directory to the given output path
|
||||
ui.Message(fmt.Sprintf("Compressing box..."))
|
||||
if err := DirToBox(outputPath, dir, ui); err != nil {
|
||||
if err := DirToBox(outputPath, dir, ui, level); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package vagrant
|
||||
|
||||
import (
|
||||
"compress/flate"
|
||||
"fmt"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type VMwareBoxConfig struct {
|
||||
@@ -14,6 +16,7 @@ type VMwareBoxConfig struct {
|
||||
|
||||
OutputPath string `mapstructure:"output"`
|
||||
VagrantfileTemplate string `mapstructure:"vagrantfile_template"`
|
||||
CompressionLevel string `mapstructure:"compression_level"`
|
||||
|
||||
tpl *packer.ConfigTemplate
|
||||
}
|
||||
@@ -40,6 +43,7 @@ func (p *VMwareBoxPostProcessor) Configure(raws ...interface{}) error {
|
||||
validates := map[string]*string{
|
||||
"output": &p.config.OutputPath,
|
||||
"vagrantfile_template": &p.config.VagrantfileTemplate,
|
||||
"compression_level": &p.config.CompressionLevel,
|
||||
}
|
||||
|
||||
for n, ptr := range validates {
|
||||
@@ -111,6 +115,14 @@ func (p *VMwareBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artif
|
||||
vf.Close()
|
||||
}
|
||||
|
||||
var level int = flate.DefaultCompression
|
||||
if p.config.CompressionLevel != "" {
|
||||
level, err = strconv.Atoi(p.config.CompressionLevel)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create the metadata
|
||||
metadata := map[string]string{"provider": "vmware_desktop"}
|
||||
if err := WriteMetadata(dir, metadata); err != nil {
|
||||
@@ -119,7 +131,7 @@ func (p *VMwareBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artif
|
||||
|
||||
// Compress the directory to the given output path
|
||||
ui.Message(fmt.Sprintf("Compressing box..."))
|
||||
if err := DirToBox(outputPath, dir, ui); err != nil {
|
||||
if err := DirToBox(outputPath, dir, ui, level); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
package ansiblelocal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const DefaultStagingDir = "/tmp/packer-provisioner-ansible-local"
|
||||
|
||||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
tpl *packer.ConfigTemplate
|
||||
|
||||
// The main playbook file to execute.
|
||||
PlaybookFile string `mapstructure:"playbook_file"`
|
||||
|
||||
// An array of local paths of playbook files to upload.
|
||||
PlaybookPaths []string `mapstructure:"playbook_paths"`
|
||||
|
||||
// An array of local paths of roles to upload.
|
||||
RolePaths []string `mapstructure:"role_paths"`
|
||||
|
||||
// The directory where files will be uploaded. Packer requires write
|
||||
// permissions in this directory.
|
||||
StagingDir string `mapstructure:"staging_directory"`
|
||||
}
|
||||
|
||||
type Provisioner struct {
|
||||
config Config
|
||||
}
|
||||
|
||||
func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||
md, err := common.DecodeConfig(&p.config, raws...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.config.tpl, err = packer.NewConfigTemplate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.config.tpl.UserVars = p.config.PackerUserVars
|
||||
|
||||
// Accumulate any errors
|
||||
errs := common.CheckUnusedConfig(md)
|
||||
|
||||
if p.config.StagingDir == "" {
|
||||
p.config.StagingDir = DefaultStagingDir
|
||||
}
|
||||
|
||||
// Templates
|
||||
templates := map[string]*string{
|
||||
"staging_dir": &p.config.StagingDir,
|
||||
}
|
||||
|
||||
for n, ptr := range templates {
|
||||
var err error
|
||||
*ptr, err = p.config.tpl.Process(*ptr, nil)
|
||||
if err != nil {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, fmt.Errorf("Error processing %s: %s", n, err))
|
||||
}
|
||||
}
|
||||
|
||||
// Validation
|
||||
err = validateFileConfig(p.config.PlaybookFile, "playbook_file", true)
|
||||
if err != nil {
|
||||
errs = packer.MultiErrorAppend(errs, err)
|
||||
}
|
||||
for _, path := range p.config.PlaybookPaths {
|
||||
err := validateFileConfig(path, "playbook_paths", false)
|
||||
if err != nil {
|
||||
errs = packer.MultiErrorAppend(errs, err)
|
||||
}
|
||||
}
|
||||
for _, path := range p.config.RolePaths {
|
||||
if err := validateDirConfig(path, "role_paths"); err != nil {
|
||||
errs = packer.MultiErrorAppend(errs, err)
|
||||
}
|
||||
}
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return errs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
|
||||
ui.Say("Provisioning with Ansible...")
|
||||
|
||||
ui.Message("Creating Ansible staging directory...")
|
||||
if err := p.createDir(ui, comm, p.config.StagingDir); err != nil {
|
||||
return fmt.Errorf("Error creating staging directory: %s", err)
|
||||
}
|
||||
|
||||
ui.Message("Uploading main Playbook file...")
|
||||
src := p.config.PlaybookFile
|
||||
dst := filepath.Join(p.config.StagingDir, filepath.Base(src))
|
||||
if err := p.uploadFile(ui, comm, dst, src); err != nil {
|
||||
return fmt.Errorf("Error uploading main playbook: %s", err)
|
||||
}
|
||||
|
||||
if len(p.config.RolePaths) > 0 {
|
||||
ui.Message("Uploading role directories...")
|
||||
for _, src := range p.config.RolePaths {
|
||||
dst := filepath.Join(p.config.StagingDir, "roles", filepath.Base(src))
|
||||
if err := p.uploadDir(ui, comm, dst, src); err != nil {
|
||||
return fmt.Errorf("Error uploading roles: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(p.config.PlaybookPaths) > 0 {
|
||||
ui.Message("Uploading additional Playbooks...")
|
||||
if err := p.createDir(ui, comm, filepath.Join(p.config.StagingDir, "playbooks")); err != nil {
|
||||
return fmt.Errorf("Error creating playbooks directory: %s", err)
|
||||
}
|
||||
for _, src := range p.config.PlaybookPaths {
|
||||
dst := filepath.Join(p.config.StagingDir, "playbooks", filepath.Base(src))
|
||||
if err := p.uploadFile(ui, comm, dst, src); err != nil {
|
||||
return fmt.Errorf("Error uploading playbooks: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := p.executeAnsible(ui, comm); err != nil {
|
||||
return fmt.Errorf("Error executing Ansible: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Provisioner) Cancel() {
|
||||
// Just hard quit. It isn't a big deal if what we're doing keeps
|
||||
// running on the other side.
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func (p *Provisioner) executeAnsible(ui packer.Ui, comm packer.Communicator) error {
|
||||
playbook := filepath.Join(p.config.StagingDir, filepath.Base(p.config.PlaybookFile))
|
||||
|
||||
// The inventory must be set to "127.0.0.1,". The comma is important
|
||||
// as its the only way to override the ansible inventory when dealing
|
||||
// with a single host.
|
||||
command := fmt.Sprintf("ansible-playbook %s -c local -i %s", playbook, `"127.0.0.1,"`)
|
||||
|
||||
ui.Message(fmt.Sprintf("Executing Ansible: %s", command))
|
||||
cmd := &packer.RemoteCmd{
|
||||
Command: command,
|
||||
}
|
||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
||||
return err
|
||||
}
|
||||
if cmd.ExitStatus != 0 {
|
||||
return fmt.Errorf("Non-zero exit status: %d", cmd.ExitStatus)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateDirConfig(path string, config string) error {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %s is invalid: %s", config, path, err)
|
||||
} else if !info.IsDir() {
|
||||
return fmt.Errorf("%s: %s must point to a directory", config, path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateFileConfig(name string, config string, req bool) error {
|
||||
if req {
|
||||
if name == "" {
|
||||
return fmt.Errorf("%s must be specified.", config)
|
||||
}
|
||||
}
|
||||
info, err := os.Stat(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %s is invalid: %s", config, name, err)
|
||||
} else if info.IsDir() {
|
||||
return fmt.Errorf("%s: %s must point to a file", config, name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Provisioner) uploadFile(ui packer.Ui, comm packer.Communicator, dst, src string) error {
|
||||
f, err := os.Open(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error opening: %s", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if err = comm.Upload(dst, f); err != nil {
|
||||
return fmt.Errorf("Error uploading %s: %s", src, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir string) error {
|
||||
ui.Message(fmt.Sprintf("Creating directory: %s", dir))
|
||||
cmd := &packer.RemoteCmd{
|
||||
Command: fmt.Sprintf("mkdir -p '%s'", dir),
|
||||
}
|
||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
||||
return err
|
||||
}
|
||||
if cmd.ExitStatus != 0 {
|
||||
return fmt.Errorf("Non-zero exit status.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Provisioner) uploadDir(ui packer.Ui, comm packer.Communicator, dst, src string) error {
|
||||
if err := p.createDir(ui, comm, dst); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make sure there is a trailing "/" so that the directory isn't
|
||||
// created on the other side.
|
||||
if src[len(src)-1] != '/' {
|
||||
src = src + "/"
|
||||
}
|
||||
return comm.UploadDir(dst, src, nil)
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package ansiblelocal
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testConfig() map[string]interface{} {
|
||||
m := make(map[string]interface{})
|
||||
return m
|
||||
}
|
||||
|
||||
func TestProvisioner_Impl(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = &Provisioner{}
|
||||
if _, ok := raw.(packer.Provisioner); !ok {
|
||||
t.Fatalf("must be a Provisioner")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvisionerPrepare_Defaults(t *testing.T) {
|
||||
var p Provisioner
|
||||
config := testConfig()
|
||||
|
||||
playbook_file, err := ioutil.TempFile("", "playbook")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.Remove(playbook_file.Name())
|
||||
|
||||
config["playbook_file"] = playbook_file.Name()
|
||||
err = p.Prepare(config)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if p.config.StagingDir != DefaultStagingDir {
|
||||
t.Fatalf("unexpected staging dir %s, expected %s",
|
||||
p.config.StagingDir, DefaultStagingDir)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvisionerPrepare_PlaybookFile(t *testing.T) {
|
||||
var p Provisioner
|
||||
config := testConfig()
|
||||
|
||||
err := p.Prepare(config)
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
config["playbook_file"] = ""
|
||||
err = p.Prepare(config)
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
playbook_file, err := ioutil.TempFile("", "playbook")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.Remove(playbook_file.Name())
|
||||
|
||||
config["playbook_file"] = playbook_file.Name()
|
||||
err = p.Prepare(config)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,6 @@ import (
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const DefaultTempConfigDir = "/tmp/salt"
|
||||
@@ -146,12 +144,13 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
|
||||
}
|
||||
|
||||
ui.Message(fmt.Sprintf("Uploading local state tree: %s", p.config.LocalStateTree))
|
||||
if err = UploadLocalDirectory(p.config.LocalStateTree, fmt.Sprintf("%s/states", p.config.TempConfigDir), comm, ui); err != nil {
|
||||
if err = comm.UploadDir(fmt.Sprintf("%s/states", p.config.TempConfigDir),
|
||||
p.config.LocalStateTree, []string{".git"}); err != nil {
|
||||
return fmt.Errorf("Error uploading local state tree to remote: %s", err)
|
||||
}
|
||||
|
||||
ui.Message(fmt.Sprintf("Moving %s to /srv/salt", p.config.TempConfigDir))
|
||||
cmd = &packer.RemoteCmd{Command: fmt.Sprintf("sudo mv %s/states /srv/salt/", p.config.TempConfigDir)}
|
||||
ui.Message(fmt.Sprintf("Moving %s/states to /srv/salt", p.config.TempConfigDir))
|
||||
cmd = &packer.RemoteCmd{Command: fmt.Sprintf("sudo mv %s/states /srv/salt", p.config.TempConfigDir)}
|
||||
if err = cmd.StartWithUi(comm, ui); err != nil || cmd.ExitStatus != 0 {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("Bad exit status: %d", cmd.ExitStatus)
|
||||
@@ -161,18 +160,9 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
|
||||
}
|
||||
|
||||
if p.config.LocalPillarRoots != "" {
|
||||
ui.Message(fmt.Sprintf("Creating remote pillar directory: %s/pillar", p.config.TempConfigDir))
|
||||
cmd := &packer.RemoteCmd{Command: fmt.Sprintf("mkdir -p %s/pillar", p.config.TempConfigDir)}
|
||||
if err = cmd.StartWithUi(comm, ui); err != nil || cmd.ExitStatus != 0 {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("Bad exit status: %d", cmd.ExitStatus)
|
||||
}
|
||||
|
||||
return fmt.Errorf("Error creating remote pillar directory: %s", err)
|
||||
}
|
||||
|
||||
ui.Message(fmt.Sprintf("Uploading local pillar roots: %s", p.config.LocalPillarRoots))
|
||||
if err = UploadLocalDirectory(p.config.LocalPillarRoots, fmt.Sprintf("%s/pillar", p.config.TempConfigDir), comm, ui); err != nil {
|
||||
if err = comm.UploadDir(fmt.Sprintf("%s/pillar", p.config.TempConfigDir),
|
||||
p.config.LocalPillarRoots, []string{".git"}); err != nil {
|
||||
return fmt.Errorf("Error uploading local pillar roots to remote: %s", err)
|
||||
}
|
||||
|
||||
@@ -206,44 +196,6 @@ func (p *Provisioner) Cancel() {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func UploadLocalDirectory(localDir string, remoteDir string, comm packer.Communicator, ui packer.Ui) (err error) {
|
||||
visitPath := func(localPath string, f os.FileInfo, err error) (err2 error) {
|
||||
localRelPath := strings.Replace(localPath, localDir, "", 1)
|
||||
localRelPath = strings.Replace(localRelPath, "\\", "/", -1)
|
||||
remotePath := filepath.Join(remoteDir, localRelPath)
|
||||
if f.IsDir() && f.Name() == ".git" {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if f.IsDir() {
|
||||
// Make remote directory
|
||||
cmd := &packer.RemoteCmd{Command: fmt.Sprintf("mkdir -p %s", remotePath)}
|
||||
if err = cmd.StartWithUi(comm, ui); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Upload file to existing directory
|
||||
file, err := os.Open(localPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error opening file: %s", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
ui.Message(fmt.Sprintf("Uploading file %s: %s", localPath, remotePath))
|
||||
if err = comm.Upload(remotePath, file); err != nil {
|
||||
return fmt.Errorf("Error uploading file: %s", err)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
err = filepath.Walk(localDir, visitPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error uploading local directory %s: %s", localDir, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func uploadMinionConfig(comm packer.Communicator, dst string, src string) error {
|
||||
f, err := os.Open(src)
|
||||
if err != nil {
|
||||
|
||||
@@ -54,5 +54,12 @@ func (r *UnixReader) Read(p []byte) (n int, err error) {
|
||||
// token returned will be "one\n".
|
||||
func scanUnixLine(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||
advance, token, err = bufio.ScanLines(data, atEOF)
|
||||
return advance, append(token, "\n"...), err
|
||||
if advance == 0 {
|
||||
// If we reached the end of a line without a newline, then
|
||||
// just return as it is. Otherwise the Scanner will keep trying
|
||||
// to scan, blocking forever.
|
||||
return
|
||||
}
|
||||
|
||||
return advance, append(token, '\n'), err
|
||||
}
|
||||
|
||||
@@ -15,27 +15,27 @@ func TestUnixReader_impl(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnixReader(t *testing.T) {
|
||||
input := "one\r\ntwo\nthree\r\n"
|
||||
expected := "one\ntwo\nthree\n"
|
||||
input := "one\r\ntwo\n\r\nthree\r\n"
|
||||
expected := "one\ntwo\n\nthree\n"
|
||||
|
||||
r := &UnixReader{
|
||||
Reader: bytes.NewReader([]byte(input)),
|
||||
}
|
||||
|
||||
result := new(bytes.Buffer)
|
||||
if _, err := io.Copy(result, r); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if result.String() != expected {
|
||||
t.Fatalf("bad: %#v", result.String())
|
||||
}
|
||||
unixReaderTest(t, input, expected)
|
||||
}
|
||||
|
||||
func TestUnixReader_unixOnly(t *testing.T) {
|
||||
input := "one\n\ntwo\nthree\n"
|
||||
expected := "one\n\ntwo\nthree\n"
|
||||
input := "\none\n\ntwo\nthree\n\n"
|
||||
expected := "\none\n\ntwo\nthree\n\n"
|
||||
|
||||
unixReaderTest(t, input, expected)
|
||||
}
|
||||
|
||||
func TestUnixReader_readsLastLine(t *testing.T) {
|
||||
input := "one\ntwo"
|
||||
expected := "one\ntwo\n"
|
||||
|
||||
unixReaderTest(t, input, expected)
|
||||
}
|
||||
|
||||
func unixReaderTest(t *testing.T, input string, expected string) {
|
||||
r := &UnixReader{
|
||||
Reader: bytes.NewReader([]byte(input)),
|
||||
}
|
||||
|
||||
@@ -72,6 +72,8 @@ go build \
|
||||
-ldflags "-X github.com/mitchellh/packer/packer.GitCommit ${GIT_COMMIT}${GIT_DIRTY}" \
|
||||
-v \
|
||||
-o bin/packer${EXTENSION} .
|
||||
|
||||
cp bin/packer${EXTENSION} ${GOPATH}/bin
|
||||
) &
|
||||
|
||||
waitSingle
|
||||
@@ -86,6 +88,8 @@ for PLUGIN in $(find ./plugin -mindepth 1 -maxdepth 1 -type d); do
|
||||
-ldflags "-X github.com/mitchellh/packer/packer.GitCommit ${GIT_COMMIT}${GIT_DIRTY}" \
|
||||
-v \
|
||||
-o bin/packer-${PLUGIN_NAME}${EXTENSION} ${PLUGIN}
|
||||
|
||||
cp bin/packer-${PLUGIN_NAME}${EXTENSION} ${GOPATH}/bin
|
||||
) &
|
||||
|
||||
waitSingle
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
ruby '1.9.3'
|
||||
|
||||
gem "middleman", "~> 3.1.5"
|
||||
gem "middleman-minify-html", "~> 3.1.1"
|
||||
gem "rack-contrib", "~> 1.1.0"
|
||||
|
||||
+15
-15
@@ -1,10 +1,10 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activesupport (3.2.14)
|
||||
activesupport (3.2.15)
|
||||
i18n (~> 0.6, >= 0.6.4)
|
||||
multi_json (~> 1.0)
|
||||
chunky_png (1.2.8)
|
||||
chunky_png (1.2.9)
|
||||
coffee-script (2.2.0)
|
||||
coffee-script-source
|
||||
execjs
|
||||
@@ -21,45 +21,45 @@ GEM
|
||||
fssm (0.2.10)
|
||||
haml (4.0.3)
|
||||
tilt
|
||||
highline (1.6.19)
|
||||
highline (1.6.20)
|
||||
hike (1.2.3)
|
||||
i18n (0.6.5)
|
||||
kramdown (1.1.0)
|
||||
kramdown (1.2.0)
|
||||
libv8 (3.16.14.3)
|
||||
listen (1.2.3)
|
||||
listen (1.3.1)
|
||||
rb-fsevent (>= 0.9.3)
|
||||
rb-inotify (>= 0.9)
|
||||
rb-kqueue (>= 0.2)
|
||||
middleman (3.1.5)
|
||||
middleman (3.1.6)
|
||||
coffee-script (~> 2.2.0)
|
||||
compass (>= 0.12.2)
|
||||
execjs (~> 1.4.0)
|
||||
haml (>= 3.1.6)
|
||||
kramdown (~> 1.1.0)
|
||||
middleman-core (= 3.1.5)
|
||||
middleman-more (= 3.1.5)
|
||||
kramdown (~> 1.2)
|
||||
middleman-core (= 3.1.6)
|
||||
middleman-more (= 3.1.6)
|
||||
middleman-sprockets (>= 3.1.2)
|
||||
sass (>= 3.1.20)
|
||||
uglifier (~> 2.1.0)
|
||||
middleman-core (3.1.5)
|
||||
middleman-core (3.1.6)
|
||||
activesupport (~> 3.2.6)
|
||||
bundler (~> 1.1)
|
||||
i18n (~> 0.6.1)
|
||||
listen (~> 1.2.2)
|
||||
listen (~> 1.1)
|
||||
rack (>= 1.4.5)
|
||||
rack-test (~> 0.6.1)
|
||||
thor (>= 0.15.2, < 2.0)
|
||||
tilt (~> 1.3.6)
|
||||
middleman-minify-html (3.1.1)
|
||||
middleman-core (~> 3.0)
|
||||
middleman-more (3.1.5)
|
||||
middleman-more (3.1.6)
|
||||
middleman-sprockets (3.1.4)
|
||||
middleman-core (>= 3.0.14)
|
||||
middleman-more (>= 3.0.14)
|
||||
sprockets (~> 2.1)
|
||||
sprockets-helpers (~> 1.0.0)
|
||||
sprockets-sass (~> 1.0.0)
|
||||
multi_json (1.8.0)
|
||||
multi_json (1.8.2)
|
||||
rack (1.5.2)
|
||||
rack-contrib (1.1.0)
|
||||
rack (>= 0.9.1)
|
||||
@@ -72,7 +72,7 @@ GEM
|
||||
ffi (>= 0.5.0)
|
||||
redcarpet (3.0.0)
|
||||
ref (1.0.5)
|
||||
sass (3.2.10)
|
||||
sass (3.2.12)
|
||||
sprockets (2.10.0)
|
||||
hike (~> 1.2)
|
||||
multi_json (~> 1.0)
|
||||
@@ -80,7 +80,7 @@ GEM
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
sprockets-helpers (1.0.1)
|
||||
sprockets (~> 2.0)
|
||||
sprockets-sass (1.0.1)
|
||||
sprockets-sass (1.0.2)
|
||||
sprockets (~> 2.0)
|
||||
tilt (~> 1.1)
|
||||
therubyracer (0.12.0)
|
||||
|
||||
@@ -217,3 +217,6 @@ The following policy document provides the minimal set permissions necessary for
|
||||
}]
|
||||
}
|
||||
</pre>
|
||||
|
||||
Depending on what setting you use the following Actions might have to be allowed as well:
|
||||
* `ec2:ModifyImageAttribute` when using `ami_description`
|
||||
|
||||
@@ -120,6 +120,9 @@ Optional:
|
||||
* `vpc_id` (string) - If launching into a VPC subnet, Packer needs the
|
||||
VPC ID in order to create a temporary security group within the VPC.
|
||||
|
||||
* `avail_zone` (string) - Destination availability zone to launch instance in.
|
||||
Leave this empty to allow Amazon to auto-assign.
|
||||
|
||||
## Basic Example
|
||||
|
||||
Here is a basic example. It is completely valid except for the access keys:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user