Compare commits
97 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 974a2fe96f | |||
| 9f6b6a0267 | |||
| e5474e52d0 | |||
| ea4a7802d9 | |||
| e38b3508d3 | |||
| 4731f480e3 | |||
| a8d0211edd | |||
| 7866d7df14 | |||
| 6169a7c07f | |||
| a129d539d4 | |||
| 8a214a9dbe | |||
| b2775b0ca3 | |||
| 1ea6b439e9 | |||
| f91f24f164 | |||
| 27b5b276b0 | |||
| 9131c8cea8 | |||
| 793c42d6a2 | |||
| 9962fd486b | |||
| 1392f4dd09 | |||
| 81472bdbab | |||
| 9b8ab21c15 | |||
| 5781c27fef | |||
| bb153b519e | |||
| f985522e7c | |||
| 1f30646cab | |||
| 6bebcd89f5 | |||
| f1b5a78737 | |||
| b1b95fbf3a | |||
| 30792f5638 | |||
| 36608e5f9b | |||
| 8a80a735e7 | |||
| 6d884c171f | |||
| 06d5fbadc4 | |||
| 8b30c230ac | |||
| a8e864ac25 | |||
| d4d655503d | |||
| 05cb1cf012 | |||
| e42127d305 | |||
| 4c351d0ad9 | |||
| a05546e93c | |||
| 5807847cc4 | |||
| 3e9cf70fc9 | |||
| 0fb55177e4 | |||
| 7e98343b8f | |||
| 77d20776a9 | |||
| 67a81afac4 | |||
| 669dcae766 | |||
| 09a32d4793 | |||
| fcc53d3639 | |||
| 816eebe516 | |||
| 20a6ad651a | |||
| de3e2312c8 | |||
| 01ae8c728d | |||
| af3163d6cb | |||
| d14004eaf2 | |||
| 85b5b00b9a | |||
| 648590ba25 | |||
| eeeb09579f | |||
| da145b960b | |||
| 0216debe72 | |||
| e0eecb6829 | |||
| e6c8c547b2 | |||
| 43dec47de8 | |||
| 080a296e3a | |||
| 3a75f04c12 | |||
| e264c8aebb | |||
| ace3f2c04a | |||
| c4d8cfc090 | |||
| be324ac0d9 | |||
| 2f936cd6b7 | |||
| 22cdc76644 | |||
| b8429a2e58 | |||
| b2356bfe7a | |||
| e67994b174 | |||
| 7f608fd0d7 | |||
| 2c1740ab3c | |||
| f851475df8 | |||
| 7f679001c8 | |||
| 6fcf5a3223 | |||
| 1d4e3228f8 | |||
| a8dec623a1 | |||
| 876df8ed0f | |||
| 8cea6b69d9 | |||
| a819b04140 | |||
| 5d797565c1 | |||
| dbe08e5f18 | |||
| b5a27c23fe | |||
| 2a7eef5737 | |||
| 7ce2b7cf9f | |||
| 1ea024a38e | |||
| b6d0f08162 | |||
| c243b9a713 | |||
| 9d872dda56 | |||
| 408a15fe13 | |||
| 3767fe41f1 | |||
| edc3f8f39b | |||
| 116b7c738e |
+47
-3
@@ -1,7 +1,53 @@
|
||||
## (Unreleased)
|
||||
## 1.0.0-rc3 (March 30, 2017)
|
||||
|
||||
### BUG FIXES:
|
||||
* core: fix version number
|
||||
* communicator/ssh: don't return error if we can't close connection. #4741
|
||||
|
||||
## 1.0.0-rc2 (March 29, 2017)
|
||||
|
||||
### BUG FIXES:
|
||||
|
||||
* core: Invoking packer `--help` or `--version` now exits with status 0.
|
||||
[GH-4723]
|
||||
* core: show correct step name when debugging. [GH-4672]
|
||||
* builder/virtualbox: fix `none` communicator by allowing skipping upload of
|
||||
version file. [GH-4678]
|
||||
* communicator/ssh: fix nil pointer error. [GH-4690]
|
||||
* builder/hyper-v: Don't wait for shutdown_command to return. [GH-4691]
|
||||
* builder/amazon: Fix b/c issue by reporting again the tags we create.
|
||||
[GH-4704]
|
||||
* builder/virtualbox: retry removing floppy controller. [GH-4705]
|
||||
|
||||
### IMRPOVEMENTS:
|
||||
|
||||
* builder/ansible: Clearer error message when we have problems getting the
|
||||
ansible version. [GH-4694]
|
||||
* builder/amazon-chroot: Ability to give an empty list in `copy_files` to
|
||||
prevent the default `/etc/resolv.conf` file from being copied. If `copy_files`
|
||||
isn't given at all, the default behavior remains. [GH-4708]
|
||||
|
||||
|
||||
## 1.0.0-rc1 (March 16, 2017)
|
||||
|
||||
### BUG FIXES:
|
||||
|
||||
* builder/googlecompute: Correct values for `on_host_maintenance`. [GH-4643]
|
||||
* builder/amazon: Fix crash in `step_region_copy`. [GH-4642]
|
||||
|
||||
### IMRPOVEMENTS:
|
||||
|
||||
* builder/amazon: validate ssh key name/file. [GH-4665]
|
||||
* builder/amazon: set force_deregister to true on -force. [GH-4649]
|
||||
* builder/hyper-v: validate output dir in step, not in config. [GH-4645]
|
||||
* website: fix display on ios devices. [GH-4618]
|
||||
|
||||
## 0.12.3 (March 1, 2017)
|
||||
|
||||
### BACKWARDS INCOMPATIBILITIES:
|
||||
|
||||
* provisioner/ansible: by default, the staging dir will be randomized. [GH-4472]
|
||||
|
||||
### FEATURES:
|
||||
|
||||
* **New builder:** `ebs-surrogate` for building AMIs from EBS volumes. [GH-4351]
|
||||
@@ -18,7 +64,6 @@
|
||||
* communicator/winrm: support ProxyFromEnvironment. [GH-4463]
|
||||
* core: make VNC links clickable in terminal. [GH-4497] [GH-4498]
|
||||
* post-processor/amazon-import: support AMI attributes on import [GH-4216]
|
||||
* provisioner/ansible: use randomized staging dir [GH-4472]
|
||||
* communicator/ssh: Use SSH agent when enabled for bastion step. [GH-4598]
|
||||
* builder/amazon: enable ena when `enhanced_networking` is set. [GH-4578]
|
||||
* builder/vmware-esxi: try for longer to connect to vnc port. [GH-4480]
|
||||
@@ -32,7 +77,6 @@
|
||||
* builder/azure:: add two new config variables for temp_compute_name and
|
||||
temp_resource_group_name. [GH-4468]
|
||||
|
||||
|
||||
### BUG FIXES:
|
||||
|
||||
* builder/amazon: Fix ssh agent authentication. [GH-4597]
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
[report-badge]: https://goreportcard.com/badge/github.com/mitchellh/packer
|
||||
[report]: https://goreportcard.com/report/github.com/mitchellh/packer
|
||||
|
||||
* Website: http://www.packer.io
|
||||
* Website: https://www.packer.io
|
||||
* IRC: `#packer-tool` on Freenode
|
||||
* Mailing list: [Google Groups](http://groups.google.com/group/packer-tool)
|
||||
|
||||
@@ -27,14 +27,19 @@ comes out of the box with support for the following platforms:
|
||||
|
||||
* Amazon EC2 (AMI). Both EBS-backed and instance-store AMIs
|
||||
* Azure
|
||||
* CloudStack
|
||||
* DigitalOcean
|
||||
* Docker
|
||||
* Google Compute Engine
|
||||
* Hyper-V
|
||||
* 1&1
|
||||
* OpenStack
|
||||
* Parallels
|
||||
* ProfitBricks
|
||||
* QEMU. Both KVM and Xen images.
|
||||
* VirtualBox
|
||||
* Triton (Joyent Public Cloud)
|
||||
* VMware
|
||||
* VirtualBox
|
||||
|
||||
Support for other platforms can be added via plugins.
|
||||
|
||||
|
||||
@@ -78,15 +78,15 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if b.config.PackerConfig.PackerForce {
|
||||
b.config.AMIForceDeregister = true
|
||||
}
|
||||
|
||||
// Defaults
|
||||
if b.config.ChrootMounts == nil {
|
||||
b.config.ChrootMounts = make([][]string, 0)
|
||||
}
|
||||
|
||||
if b.config.CopyFiles == nil {
|
||||
b.config.CopyFiles = make([]string, 0)
|
||||
}
|
||||
|
||||
if len(b.config.ChrootMounts) == 0 {
|
||||
b.config.ChrootMounts = [][]string{
|
||||
{"proc", "proc", "/proc"},
|
||||
@@ -97,8 +97,12 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if len(b.config.CopyFiles) == 0 && !b.config.FromScratch {
|
||||
b.config.CopyFiles = []string{"/etc/resolv.conf"}
|
||||
// set default copy file if we're not giving our own
|
||||
if b.config.CopyFiles == nil {
|
||||
b.config.CopyFiles = make([]string, 0)
|
||||
if !b.config.FromScratch {
|
||||
b.config.CopyFiles = []string{"/etc/resolv.conf"}
|
||||
}
|
||||
}
|
||||
|
||||
if b.config.CommandWrapper == "" {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package chroot
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"testing"
|
||||
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
func testConfig() map[string]interface{} {
|
||||
@@ -117,3 +118,33 @@ func TestBuilderPrepare_CommandWrapper(t *testing.T) {
|
||||
t.Errorf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_CopyFiles(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config := testConfig()
|
||||
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("err: %s", err)
|
||||
}
|
||||
|
||||
if len(b.config.CopyFiles) != 1 && b.config.CopyFiles[0] != "/etc/resolv.conf" {
|
||||
t.Errorf("Was expecting default value for copy_files.")
|
||||
}
|
||||
|
||||
config["copy_files"] = []string{}
|
||||
warnings, err = b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
t.Fatalf("bad: %#v", warnings)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("err: %s", err)
|
||||
}
|
||||
|
||||
if len(b.config.CopyFiles) > 0 {
|
||||
t.Errorf("Was expecting no default value for copy_files.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,10 @@ func (c *Communicator) Upload(dst string, r io.Reader, fi *os.FileInfo) error {
|
||||
return fmt.Errorf("Error preparing shell script: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
io.Copy(tf, r)
|
||||
|
||||
if _, err := io.Copy(tf, r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cpCmd, err := c.CmdWrapper(fmt.Sprintf("cp %s %s", tf.Name(), dst))
|
||||
if err != nil {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package chroot
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
)
|
||||
|
||||
// StepChrootProvision provisions the instance within a chroot.
|
||||
type StepChrootProvision struct {
|
||||
mounts []string
|
||||
}
|
||||
|
||||
func (s *StepChrootProvision) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
@@ -82,7 +82,7 @@ func (s *StepMountDevice) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui.Say("Mounting the root device...")
|
||||
stderr := new(bytes.Buffer)
|
||||
|
||||
// build mount options from mount_options config, usefull for nouuid options
|
||||
// build mount options from mount_options config, useful for nouuid options
|
||||
// or other specific device type settings for mount
|
||||
opts := ""
|
||||
if len(s.MountOptions) > 0 {
|
||||
|
||||
@@ -2,15 +2,15 @@ package chroot
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
// StepPrepareDevice finds an available device and sets it.
|
||||
type StepPrepareDevice struct {
|
||||
mounts []string
|
||||
}
|
||||
|
||||
func (s *StepPrepareDevice) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
@@ -66,7 +66,7 @@ func (c *AccessConfig) Config() (*aws.Config, error) {
|
||||
func (c *AccessConfig) Region() (string, error) {
|
||||
if c.RawRegion != "" {
|
||||
if !c.SkipValidation {
|
||||
if valid := ValidateRegion(c.RawRegion); valid == false {
|
||||
if valid := ValidateRegion(c.RawRegion); !valid {
|
||||
return "", fmt.Errorf("Not a valid region: %s", c.RawRegion)
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@ func (c *AccessConfig) Region() (string, error) {
|
||||
func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
var errs []error
|
||||
if c.RawRegion != "" && !c.SkipValidation {
|
||||
if valid := ValidateRegion(c.RawRegion); valid == false {
|
||||
if valid := ValidateRegion(c.RawRegion); !valid {
|
||||
errs = append(errs, fmt.Errorf("Unknown region: %s", c.RawRegion))
|
||||
}
|
||||
}
|
||||
@@ -115,5 +115,5 @@ func GetInstanceMetaData(path string) (contents []byte, err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return []byte(body), err
|
||||
return body, err
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ func (c *AMIConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
|
||||
if !c.AMISkipRegionValidation {
|
||||
// Verify the region is real
|
||||
if valid := ValidateRegion(region); valid == false {
|
||||
if valid := ValidateRegion(region); !valid {
|
||||
errs = append(errs, fmt.Errorf("Unknown region: %s", region))
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -90,10 +90,7 @@ func (c *CLIConfig) Prepare(name string) error {
|
||||
c.SourceProfile = c.ProfileName
|
||||
}
|
||||
c.profileCred, err = credsFromName(c.SourceProfile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *CLIConfig) getSessionName(rawName string) (string, error) {
|
||||
|
||||
@@ -75,6 +75,14 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
|
||||
// Validation
|
||||
errs := c.Comm.Prepare(ctx)
|
||||
if c.SSHKeyPairName != "" {
|
||||
if c.Comm.Type == "winrm" && c.Comm.WinRMPassword == "" && c.Comm.SSHPrivateKey == "" {
|
||||
errs = append(errs, errors.New("A private_key_file must be provided to retrieve the winrm password when using ssh_keypair_name."))
|
||||
} else if c.Comm.SSHPrivateKey == "" && !c.Comm.SSHAgentAuth {
|
||||
errs = append(errs, errors.New("A private_key_file must be provided or ssh_agent_auth enabled when ssh_keypair_name is specified."))
|
||||
}
|
||||
}
|
||||
|
||||
if c.SourceAmi == "" && c.SourceAmiFilter.Empty() {
|
||||
errs = append(errs, errors.New("A source_ami or source_ami_filter must be specified"))
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ func WaitForState(conf *StateChangeConf) (i interface{}, err error) {
|
||||
log.Printf("Waiting for state to become: %s", conf.Target)
|
||||
|
||||
sleepSeconds := SleepSeconds()
|
||||
maxTicks := int(TimeoutSeconds()/sleepSeconds) + 1
|
||||
maxTicks := TimeoutSeconds()/sleepSeconds + 1
|
||||
notfoundTick := 0
|
||||
|
||||
for {
|
||||
|
||||
@@ -2,7 +2,6 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sync"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
@@ -128,7 +127,7 @@ func amiRegionCopy(state multistep.StateBag, config *AccessConfig, name string,
|
||||
}
|
||||
|
||||
for _, blockDeviceMapping := range describeImageResp.Images[0].BlockDeviceMappings {
|
||||
if blockDeviceMapping.Ebs != nil {
|
||||
if blockDeviceMapping.Ebs != nil && blockDeviceMapping.Ebs.SnapshotId != nil {
|
||||
snapshotIds = append(snapshotIds, *blockDeviceMapping.Ebs.SnapshotId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
@@ -94,6 +93,7 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
ReportTags(ui, amiTags)
|
||||
|
||||
ui.Say("Creating snapshot tags")
|
||||
snapshotTags, err := ConvertToEC2Tags(s.SnapshotTags, *ec2conn.Config.Region, sourceAMI, s.Ctx)
|
||||
@@ -102,6 +102,7 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
ReportTags(ui, snapshotTags)
|
||||
|
||||
// Retry creating tags for about 2.5 minutes
|
||||
err = retry.Retry(0.2, 30, 11, func() (bool, error) {
|
||||
@@ -150,6 +151,13 @@ func (s *StepCreateTags) Cleanup(state multistep.StateBag) {
|
||||
// No cleanup...
|
||||
}
|
||||
|
||||
func ReportTags(ui packer.Ui, tags []*ec2.Tag) {
|
||||
for _, tag := range tags {
|
||||
ui.Message(fmt.Sprintf("Adding tag: \"%s\": \"%s\"",
|
||||
aws.StringValue(tag.Key), aws.StringValue(tag.Value)))
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertToEC2Tags(tags map[string]string, region, sourceAmiId string, ctx interpolate.Context) ([]*ec2.Tag, error) {
|
||||
var ec2Tags []*ec2.Tag
|
||||
for key, value := range tags {
|
||||
@@ -163,7 +171,6 @@ func ConvertToEC2Tags(tags map[string]string, region, sourceAmiId string, ctx in
|
||||
return ec2Tags, fmt.Errorf("Error processing tag: %s:%s - %s", key, value, err)
|
||||
}
|
||||
|
||||
log.Printf("Adding tag: \"%s\": \"%s\"", key, interpolatedValue)
|
||||
ec2Tags = append(ec2Tags, &ec2.Tag{
|
||||
Key: aws.String(key),
|
||||
Value: aws.String(interpolatedValue),
|
||||
|
||||
@@ -25,7 +25,7 @@ func (s *StepCreateEncryptedAMICopy) Run(state multistep.StateBag) multistep.Ste
|
||||
// Encrypt boot not set, so skip step
|
||||
if !s.EncryptBootVolume {
|
||||
if kmsKeyId != "" {
|
||||
log.Printf(fmt.Sprintf("Ignoring KMS Key ID: %s, encrypted=false", kmsKeyId))
|
||||
log.Printf("Ignoring KMS Key ID: %s, encrypted=false", kmsKeyId)
|
||||
}
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
@@ -289,6 +289,8 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
ReportTags(ui, ec2Tags)
|
||||
|
||||
_, err = ec2conn.CreateTags(&ec2.CreateTagsInput{
|
||||
Tags: ec2Tags,
|
||||
Resources: []*string{instance.InstanceId},
|
||||
@@ -340,7 +342,10 @@ func (s *StepRunSourceInstance) Cleanup(state multistep.StateBag) {
|
||||
Target: "cancelled",
|
||||
}
|
||||
|
||||
WaitForState(&stateChange)
|
||||
_, err := WaitForState(&stateChange)
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -357,6 +362,9 @@ func (s *StepRunSourceInstance) Cleanup(state multistep.StateBag) {
|
||||
Target: "terminated",
|
||||
}
|
||||
|
||||
WaitForState(&stateChange)
|
||||
_, err := WaitForState(&stateChange)
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ func (s *StepSecurityGroup) Run(state multistep.StateBag) multistep.StepAction {
|
||||
}
|
||||
|
||||
// We loop and retry this a few times because sometimes the security
|
||||
// group isn't available immediately because AWS resources are eventaully
|
||||
// group isn't available immediately because AWS resources are eventually
|
||||
// consistent.
|
||||
ui.Say(fmt.Sprintf(
|
||||
"Authorizing access to port %d the temporary security group...",
|
||||
|
||||
@@ -85,7 +85,7 @@ func (s *StepSourceAMIInfo) Run(state multistep.StateBag) multistep.StepAction {
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if len(imageResp.Images) > 1 && s.AmiFilters.MostRecent == false {
|
||||
if len(imageResp.Images) > 1 && !s.AmiFilters.MostRecent {
|
||||
err := fmt.Errorf("Your query returned more than one result. Please try a more specific search, or set most_recent to true.")
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
|
||||
@@ -44,6 +44,8 @@ func (s *StepTagEBSVolumes) Run(state multistep.StateBag) multistep.StepAction {
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
ReportTags(ui, tags)
|
||||
|
||||
_, err = ec2conn.CreateTags(&ec2.CreateTagsInput{
|
||||
Resources: volumeIds,
|
||||
Tags: tags,
|
||||
|
||||
@@ -58,6 +58,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if b.config.PackerConfig.PackerForce {
|
||||
b.config.AMIForceDeregister = true
|
||||
}
|
||||
|
||||
// Accumulate any errors
|
||||
var errs *packer.MultiError
|
||||
errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(&b.config.ctx)...)
|
||||
|
||||
@@ -84,11 +84,11 @@ func checkTags() builderT.TestCheckFunc {
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error retreiving Snapshots for AMI Artifcat (%#v) in Tags Test: %s", artifact, err)
|
||||
return fmt.Errorf("Error retrieving Snapshots for AMI Artifact (%#v) in Tags Test: %s", artifact, err)
|
||||
}
|
||||
|
||||
if len(resp.Snapshots) == 0 {
|
||||
return fmt.Errorf("No Snapshots found for AMI Artifcat (%#v) in Tags Test", artifact)
|
||||
return fmt.Errorf("No Snapshots found for AMI Artifact (%#v) in Tags Test", artifact)
|
||||
}
|
||||
|
||||
// Grab the snapshots, check the tags
|
||||
|
||||
@@ -58,6 +58,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if b.config.PackerConfig.PackerForce {
|
||||
b.config.AMIForceDeregister = true
|
||||
}
|
||||
|
||||
// Accumulate any errors
|
||||
var errs *packer.MultiError
|
||||
errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(&b.config.ctx)...)
|
||||
|
||||
@@ -50,6 +50,7 @@ func (s *stepTagEBSVolumes) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
awscommon.ReportTags(ui, tags)
|
||||
|
||||
for _, v := range instance.BlockDeviceMappings {
|
||||
if *v.DeviceName == mapping.DeviceName {
|
||||
|
||||
@@ -77,6 +77,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if b.config.PackerConfig.PackerForce {
|
||||
b.config.AMIForceDeregister = true
|
||||
}
|
||||
|
||||
if b.config.BundleDestination == "" {
|
||||
b.config.BundleDestination = "/tmp"
|
||||
}
|
||||
|
||||
@@ -13,12 +13,11 @@ import (
|
||||
)
|
||||
|
||||
type StepGetCertificate struct {
|
||||
client *AzureClient
|
||||
template string
|
||||
get func(keyVaultName string, secretName string) (string, error)
|
||||
say func(message string)
|
||||
error func(e error)
|
||||
pause func()
|
||||
client *AzureClient
|
||||
get func(keyVaultName string, secretName string) (string, error)
|
||||
say func(message string)
|
||||
error func(e error)
|
||||
pause func()
|
||||
}
|
||||
|
||||
func NewStepGetCertificate(client *AzureClient, ui packer.Ui) *StepGetCertificate {
|
||||
|
||||
@@ -18,5 +18,5 @@ func GlueStrings(a, b string) string {
|
||||
shift++
|
||||
}
|
||||
|
||||
return string(a[:shift]) + b
|
||||
return a[:shift] + b
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestBMPStringDecode(t *testing.T) {
|
||||
|
||||
func TestBMPString(t *testing.T) {
|
||||
str, err := bmpString("")
|
||||
if bytes.Compare(str, []byte{0, 0}) != 0 {
|
||||
if !bytes.Equal(str, []byte{0, 0}) {
|
||||
t.Errorf("expected empty string to return double 0, but found: % x", str)
|
||||
}
|
||||
if err != nil {
|
||||
@@ -44,7 +44,7 @@ func TestBMPString(t *testing.T) {
|
||||
|
||||
// Example from https://tools.ietf.org/html/rfc7292#appendix-B
|
||||
str, err = bmpString("Beavis")
|
||||
if bytes.Compare(str, []byte{0x00, 0x42, 0x00, 0x65, 0x00, 0x61, 0x00, 0x0076, 0x00, 0x69, 0x00, 0x73, 0x00, 0x00}) != 0 {
|
||||
if !bytes.Equal(str, []byte{0x00, 0x42, 0x00, 0x65, 0x00, 0x61, 0x00, 0x0076, 0x00, 0x69, 0x00, 0x73, 0x00, 0x00}) {
|
||||
t.Errorf("expected 'Beavis' to return 0x00 0x42 0x00 0x65 0x00 0x61 0x00 0x76 0x00 0x69 0x00 0x73 0x00 0x00, but found: % x", str)
|
||||
}
|
||||
if err != nil {
|
||||
@@ -54,7 +54,7 @@ func TestBMPString(t *testing.T) {
|
||||
// some characters from the "Letterlike Symbols Unicode block"
|
||||
tst := "\u2115 - Double-struck N"
|
||||
str, err = bmpString(tst)
|
||||
if bytes.Compare(str, []byte{0x21, 0x15, 0x00, 0x20, 0x00, 0x2d, 0x00, 0x20, 0x00, 0x44, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x2d, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x75, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x20, 0x00, 0x4e, 0x00, 0x00}) != 0 {
|
||||
if !bytes.Equal(str, []byte{0x21, 0x15, 0x00, 0x20, 0x00, 0x2d, 0x00, 0x20, 0x00, 0x44, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x2d, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x75, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x20, 0x00, 0x4e, 0x00, 0x00}) {
|
||||
t.Errorf("expected '%s' to return 0x21 0x15 0x00 0x20 0x00 0x2d 0x00 0x20 0x00 0x44 0x00 0x6f 0x00 0x75 0x00 0x62 0x00 0x6c 0x00 0x65 0x00 0x2d 0x00 0x73 0x00 0x74 0x00 0x72 0x00 0x75 0x00 0x63 0x00 0x6b 0x00 0x20 0x00 0x4e 0x00 0x00, but found: % x", tst, str)
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
@@ -47,7 +47,7 @@ func pbDecrypt(info decryptable, password []byte) (decrypted []byte, err error)
|
||||
if psLen := int(decrypted[len(decrypted)-1]); psLen > 0 && psLen <= cbc.BlockSize() {
|
||||
m := decrypted[:len(decrypted)-psLen]
|
||||
ps := decrypted[len(decrypted)-psLen:]
|
||||
if bytes.Compare(ps, bytes.Repeat([]byte{byte(psLen)}, psLen)) != 0 {
|
||||
if !bytes.Equal(ps, bytes.Repeat([]byte{byte(psLen)}, psLen)) {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
decrypted = m
|
||||
@@ -87,7 +87,7 @@ func TestPbDecrypterFor(t *testing.T) {
|
||||
expectedM := []byte{185, 73, 135, 249, 137, 1, 122, 247}
|
||||
cbc.CryptBlocks(M, M)
|
||||
|
||||
if bytes.Compare(M, expectedM) != 0 {
|
||||
if !bytes.Equal(M, expectedM) {
|
||||
t.Errorf("expected M to be '%d', but found '%d", expectedM, M)
|
||||
}
|
||||
}
|
||||
@@ -127,7 +127,7 @@ func TestPbDecrypt(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("error decrypting C=%x: %v", c, err)
|
||||
}
|
||||
if bytes.Compare(m, e) != 0 {
|
||||
if !bytes.Equal(m, e) {
|
||||
t.Errorf("expected C=%x to be decoded to M=%x, but found %x", c, e, m)
|
||||
}
|
||||
case error:
|
||||
|
||||
@@ -12,7 +12,7 @@ func TestThatPBKDFWorksCorrectlyForLongKeys(t *testing.T) {
|
||||
password, _ := bmpString("sesame")
|
||||
key := pbkdf(salt, password, 2048)
|
||||
|
||||
if expected := []byte("\x7c\xd9\xfd\x3e\x2b\x3b\xe7\x69\x1a\x44\xe3\xbe\xf0\xf9\xea\x0f\xb9\xb8\x97\xd4\xe3\x25\xd9\xd1"); bytes.Compare(key, expected) != 0 {
|
||||
if expected := []byte("\x7c\xd9\xfd\x3e\x2b\x3b\xe7\x69\x1a\x44\xe3\xbe\xf0\xf9\xea\x0f\xb9\xb8\x97\xd4\xe3\x25\xd9\xd1"); !bytes.Equal(key, expected) {
|
||||
t.Fatalf("expected key '% x', but found '% x'", key, expected)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,23 +30,6 @@ type contentInfo struct {
|
||||
Content asn1.RawValue `asn1:"tag:0,explicit,optional"`
|
||||
}
|
||||
|
||||
type encryptedData struct {
|
||||
Version int
|
||||
EncryptedContentInfo encryptedContentInfo
|
||||
}
|
||||
|
||||
type encryptedContentInfo struct {
|
||||
ContentType asn1.ObjectIdentifier
|
||||
ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
|
||||
EncryptedContent []byte `asn1:"tag:0,optional"`
|
||||
}
|
||||
|
||||
func (i encryptedContentInfo) GetAlgorithm() pkix.AlgorithmIdentifier {
|
||||
return i.ContentEncryptionAlgorithm
|
||||
}
|
||||
|
||||
func (i encryptedContentInfo) GetData() []byte { return i.EncryptedContent }
|
||||
|
||||
type safeBag struct {
|
||||
Id asn1.ObjectIdentifier
|
||||
Value asn1.RawValue `asn1:"tag:0,explicit"`
|
||||
|
||||
@@ -44,7 +44,7 @@ func sshConfig(state multistep.StateBag) (*ssh.ClientConfig, error) {
|
||||
return nil, fmt.Errorf("Error loading configured private key file: %s", err)
|
||||
}
|
||||
|
||||
signer, err := ssh.ParsePrivateKey([]byte(privateKey))
|
||||
signer, err := ssh.ParsePrivateKey(privateKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error setting up SSH config: %s", err)
|
||||
}
|
||||
|
||||
@@ -3,10 +3,11 @@ package digitalocean
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/digitalocean/godo"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type stepCreateDroplet struct {
|
||||
@@ -41,7 +42,7 @@ func (s *stepCreateDroplet) Run(state multistep.StateBag) multistep.StepAction {
|
||||
Slug: c.Image,
|
||||
},
|
||||
SSHKeys: []godo.DropletCreateSSHKey{
|
||||
{ID: int(sshKeyId)},
|
||||
{ID: sshKeyId},
|
||||
},
|
||||
PrivateNetworking: c.PrivateNetworking,
|
||||
UserData: userData,
|
||||
|
||||
@@ -99,7 +99,7 @@ func TestUploadDownload(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLargeDownload verifies that files are the apporpriate size after being
|
||||
// TestLargeDownload verifies that files are the appropriate size after being
|
||||
// downloaded. This is to identify and fix the race condition in #2793. You may
|
||||
// need to use github.com/cbednarski/rerun to verify since this problem occurs
|
||||
// only intermittently.
|
||||
|
||||
@@ -50,7 +50,7 @@ func (c *AwsAccessConfig) config(region string) (*aws.Config, error) {
|
||||
// or an error.
|
||||
func (c *AwsAccessConfig) EcrGetLogin(ecrUrl string) (string, string, error) {
|
||||
|
||||
exp := regexp.MustCompile("(?:http://|https://|)([0-9]*)\\.dkr\\.ecr\\.(.*)\\.amazonaws\\.com.*")
|
||||
exp := regexp.MustCompile(`(?:http://|https://|)([0-9]*)\.dkr\.ecr\.(.*)\.amazonaws\.com.*`)
|
||||
splitUrl := exp.FindStringSubmatch(ecrUrl)
|
||||
if len(splitUrl) != 3 {
|
||||
return "", "", fmt.Errorf("Failed to parse the ECR URL: %s it should be on the form <account number>.dkr.ecr.<region>.amazonaws.com", ecrUrl)
|
||||
|
||||
@@ -54,7 +54,6 @@ type Config struct {
|
||||
Zone string `mapstructure:"zone"`
|
||||
|
||||
Account AccountFile
|
||||
privateKeyBytes []byte
|
||||
stateTimeout time.Duration
|
||||
imageAlreadyExists bool
|
||||
ctx interpolate.Context
|
||||
@@ -93,15 +92,20 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||
if c.ImageDescription == "" {
|
||||
c.ImageDescription = "Created by Packer"
|
||||
}
|
||||
// Setting OnHostMaintenance Correct Defaults
|
||||
// "MIGRATE" : Possible if Preemptible is false
|
||||
// "TERMINATE": Posssible if Preemptible is true
|
||||
if c.OnHostMaintenance == "" && c.Preemptible {
|
||||
c.OnHostMaintenance = "MIGRATE"
|
||||
}
|
||||
|
||||
if c.OnHostMaintenance == "" && !c.Preemptible {
|
||||
if c.OnHostMaintenance == "MIGRATE" && c.Preemptible {
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
errors.New("on_host_maintenance must be TERMINATE when using preemptible instances."))
|
||||
}
|
||||
// Setting OnHostMaintenance Correct Defaults
|
||||
// "MIGRATE" : Possible and default if Preemptible is false
|
||||
// "TERMINATE": Required if Preemptible is true
|
||||
if c.Preemptible {
|
||||
c.OnHostMaintenance = "TERMINATE"
|
||||
} else {
|
||||
if c.OnHostMaintenance == "" {
|
||||
c.OnHostMaintenance = "MIGRATE"
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure user sets a valid value for on_host_maintenance option
|
||||
|
||||
@@ -12,8 +12,6 @@ import (
|
||||
// stepInstanceInfo represents a Packer build step that gathers GCE instance info.
|
||||
type StepInstanceInfo struct {
|
||||
Debug bool
|
||||
|
||||
info int
|
||||
}
|
||||
|
||||
// Run executes the Packer build step that gathers GCE instance info.
|
||||
|
||||
@@ -64,7 +64,7 @@ func (d *HypervPS4Driver) Verify() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := d.verifyElevatedMode(); err != nil {
|
||||
if err := d.verifyHypervPermissions(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ func (d *HypervPS4Driver) verifyPSVersion() error {
|
||||
return err
|
||||
}
|
||||
|
||||
versionOutput := strings.TrimSpace(string(cmdOut))
|
||||
versionOutput := strings.TrimSpace(cmdOut)
|
||||
log.Printf("%s output: %s", versionCmd, versionOutput)
|
||||
|
||||
ver, err := strconv.ParseInt(versionOutput, 10, 32)
|
||||
@@ -283,7 +283,7 @@ func (d *HypervPS4Driver) verifyPSHypervModule() error {
|
||||
return err
|
||||
}
|
||||
|
||||
res := strings.TrimSpace(string(cmdOut))
|
||||
res := strings.TrimSpace(cmdOut)
|
||||
|
||||
if res == "False" {
|
||||
err := fmt.Errorf("%s", "PS Hyper-V module is not loaded. Make sure Hyper-V feature is on.")
|
||||
@@ -293,16 +293,28 @@ func (d *HypervPS4Driver) verifyPSHypervModule() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *HypervPS4Driver) verifyElevatedMode() error {
|
||||
func (d *HypervPS4Driver) verifyHypervPermissions() error {
|
||||
|
||||
log.Printf("Enter method: %s", "verifyElevatedMode")
|
||||
log.Printf("Enter method: %s", "verifyHypervPermissions")
|
||||
|
||||
isAdmin, _ := powershell.IsCurrentUserAnAdministrator()
|
||||
hypervAdminCmd := "([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole('Hyper-V Administrators')"
|
||||
|
||||
if !isAdmin {
|
||||
err := fmt.Errorf("%s", "Please restart your shell in elevated mode")
|
||||
var ps powershell.PowerShellCmd
|
||||
cmdOut, err := ps.Output(hypervAdminCmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res := strings.TrimSpace(cmdOut)
|
||||
|
||||
if res == "False" {
|
||||
isAdmin, _ := powershell.IsCurrentUserAnAdministrator()
|
||||
|
||||
if !isAdmin {
|
||||
err := fmt.Errorf("%s", "Current user is not a member of 'Hyper-V Administrators' or 'Administrators' group")
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/template/interpolate"
|
||||
"os"
|
||||
)
|
||||
|
||||
type OutputConfig struct {
|
||||
@@ -16,13 +16,5 @@ func (c *OutputConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig
|
||||
c.OutputDir = fmt.Sprintf("output-%s", pc.PackerBuildName)
|
||||
}
|
||||
|
||||
var errs []error
|
||||
if !pc.PackerForce {
|
||||
if _, err := os.Stat(c.OutputDir); err == nil {
|
||||
errs = append(errs, fmt.Errorf(
|
||||
"Output directory '%s' already exists. It must not exist.", c.OutputDir))
|
||||
}
|
||||
}
|
||||
|
||||
return errs
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/packer/common"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/mitchellh/packer/common"
|
||||
)
|
||||
|
||||
func TestOutputConfigPrepare(t *testing.T) {
|
||||
@@ -39,7 +40,7 @@ func TestOutputConfigPrepare_exists(t *testing.T) {
|
||||
PackerForce: false,
|
||||
}
|
||||
errs := c.Prepare(testConfigTemplate(t), pc)
|
||||
if len(errs) == 0 {
|
||||
t.Fatal("should have errors")
|
||||
if len(errs) != 0 {
|
||||
t.Fatal("should not have errors")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
type StepConfigureIp struct {
|
||||
@@ -35,7 +36,7 @@ func (s *StepConfigureIp) Run(state multistep.StateBag) multistep.StepAction {
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
ip = strings.TrimSpace(string(cmdOut))
|
||||
ip = strings.TrimSpace(cmdOut)
|
||||
|
||||
if ip != "False" {
|
||||
break
|
||||
|
||||
@@ -17,16 +17,30 @@ import (
|
||||
type StepOutputDir struct {
|
||||
Force bool
|
||||
Path string
|
||||
|
||||
cleanup bool
|
||||
}
|
||||
|
||||
func (s *StepOutputDir) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
if _, err := os.Stat(s.Path); err == nil && s.Force {
|
||||
if _, err := os.Stat(s.Path); err == nil {
|
||||
if !s.Force {
|
||||
err := fmt.Errorf(
|
||||
"Output directory exists: %s\n\n"+
|
||||
"Use the force flag to delete it prior to building.",
|
||||
s.Path)
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
ui.Say("Deleting previous output directory...")
|
||||
os.RemoveAll(s.Path)
|
||||
}
|
||||
|
||||
// Enable cleanup
|
||||
s.cleanup = true
|
||||
|
||||
// Create the directory
|
||||
if err := os.MkdirAll(s.Path, 0755); err != nil {
|
||||
state.Put("error", err)
|
||||
@@ -47,6 +61,10 @@ func (s *StepOutputDir) Run(state multistep.StateBag) multistep.StepAction {
|
||||
}
|
||||
|
||||
func (s *StepOutputDir) Cleanup(state multistep.StateBag) {
|
||||
if !s.cleanup {
|
||||
return
|
||||
}
|
||||
|
||||
_, cancelled := state.GetOk(multistep.StateCancelled)
|
||||
_, halted := state.GetOk(multistep.StateHalted)
|
||||
|
||||
|
||||
@@ -3,18 +3,18 @@ package common
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
const port string = "13000"
|
||||
|
||||
type StepPollingInstalation struct {
|
||||
step int
|
||||
}
|
||||
|
||||
func (s *StepPollingInstalation) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
@@ -4,10 +4,11 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
// This step shuts down the machine. It first attempts to do so gracefully,
|
||||
@@ -51,14 +52,6 @@ func (s *StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Wait for the command to run so we can print std{err,out}
|
||||
// We don't care if the command errored, since we'll notice
|
||||
// if the vm didn't shut down.
|
||||
cmd.Wait()
|
||||
|
||||
log.Printf("Shutdown stdout: %s", stdout.String())
|
||||
log.Printf("Shutdown stderr: %s", stderr.String())
|
||||
|
||||
// Wait for the machine to actually shut down
|
||||
log.Printf("Waiting max %s for shutdown to complete", s.Timeout)
|
||||
shutdownTimer := time.After(s.Timeout)
|
||||
@@ -70,12 +63,14 @@ func (s *StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
select {
|
||||
case <-shutdownTimer:
|
||||
log.Printf("Shutdown stdout: %s", stdout.String())
|
||||
log.Printf("Shutdown stderr: %s", stderr.String())
|
||||
err := errors.New("Timeout while waiting for machine to shut down.")
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
default:
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -2,10 +2,11 @@ package openstack
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
var ber_encoded_key = `
|
||||
@@ -71,7 +72,7 @@ mKMH6Gf6COfSIbLuejdzSOUAmjkFpm+nwBkka1eHdAy4ALn9wNQz3w==
|
||||
func TestBerToDer(t *testing.T) {
|
||||
_, err := exec.LookPath("openssl")
|
||||
if err != nil {
|
||||
t.Skipf("OpenSSL not availible skippint test.")
|
||||
t.Skipf("OpenSSL not available skipping test.")
|
||||
}
|
||||
|
||||
msg := new(bytes.Buffer)
|
||||
|
||||
@@ -36,7 +36,7 @@ func (s *StepAttachParallelsTools) Run(state multistep.StateBag) multistep.StepA
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
// Get the Paralells Tools path on the host machine
|
||||
// Get the Parallels Tools path on the host machine
|
||||
parallelsToolsPath := state.Get("parallels_tools_path").(string)
|
||||
|
||||
// Attach the guest additions to the computer
|
||||
|
||||
@@ -47,7 +47,7 @@ func (s *StepUploadParallelsTools) Run(state multistep.StateBag) multistep.StepA
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
// Get the Paralells Tools path on the host machine
|
||||
// Get the Parallels Tools path on the host machine
|
||||
parallelsToolsPath := state.Get("parallels_tools_path").(string)
|
||||
|
||||
f, err := os.Open(parallelsToolsPath)
|
||||
|
||||
@@ -90,7 +90,7 @@ func TestBuilderPrepare_InvalidFloppies(t *testing.T) {
|
||||
b = Builder{}
|
||||
_, errs := b.Prepare(config)
|
||||
if errs == nil {
|
||||
t.Fatalf("Non existant floppies should trigger multierror")
|
||||
t.Fatalf("Nonexistent floppies should trigger multierror")
|
||||
}
|
||||
|
||||
if len(errs.(*packer.MultiError).Errors) != 2 {
|
||||
|
||||
@@ -36,7 +36,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
// Create the driver that we'll use to communicate with Parallels
|
||||
driver, err := parallelscommon.NewDriver()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed creating Paralles driver: %s", err)
|
||||
return nil, fmt.Errorf("Failed creating Parallels driver: %s", err)
|
||||
}
|
||||
|
||||
// Set up the state.
|
||||
|
||||
@@ -87,7 +87,7 @@ func TestNewConfig_InvalidFloppies(t *testing.T) {
|
||||
c["floppy_files"] = []string{"nonexistant.bat", "nonexistant.ps1"}
|
||||
_, _, errs := NewConfig(c)
|
||||
if errs == nil {
|
||||
t.Fatalf("Non existant floppies should trigger multierror")
|
||||
t.Fatalf("Nonexistent floppies should trigger multierror")
|
||||
}
|
||||
|
||||
if len(errs.(*packer.MultiError).Errors) != 2 {
|
||||
|
||||
@@ -4,12 +4,13 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/profitbricks/profitbricks-sdk-go"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/profitbricks/profitbricks-sdk-go"
|
||||
)
|
||||
|
||||
type stepCreateServer struct{}
|
||||
@@ -71,7 +72,11 @@ func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction {
|
||||
if datacenter.StatusCode > 299 {
|
||||
if datacenter.StatusCode > 299 {
|
||||
var restError RestError
|
||||
json.Unmarshal([]byte(datacenter.Response), &restError)
|
||||
err := json.Unmarshal([]byte(datacenter.Response), &restError)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error decoding json response: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
if len(restError.Messages) > 0 {
|
||||
ui.Error(restError.Messages[0].Message)
|
||||
} else {
|
||||
@@ -83,7 +88,7 @@ func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
err := s.waitTillProvisioned(datacenter.Headers.Get("Location"), *c)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error occured while creating a datacenter %s", err.Error()))
|
||||
ui.Error(fmt.Sprintf("Error occurred while creating a datacenter %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -97,13 +102,13 @@ func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction {
|
||||
})
|
||||
|
||||
if lan.StatusCode > 299 {
|
||||
ui.Error(fmt.Sprintf("Error occured %s", parseErrorMessage(lan.Response)))
|
||||
ui.Error(fmt.Sprintf("Error occurred %s", parseErrorMessage(lan.Response)))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = s.waitTillProvisioned(lan.Headers.Get("Location"), *c)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error occured while creating a LAN %s", err.Error()))
|
||||
ui.Error(fmt.Sprintf("Error occurred while creating a LAN %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -117,13 +122,13 @@ func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction {
|
||||
})
|
||||
|
||||
if lan.StatusCode > 299 {
|
||||
ui.Error(fmt.Sprintf("Error occured %s", parseErrorMessage(nic.Response)))
|
||||
ui.Error(fmt.Sprintf("Error occurred %s", parseErrorMessage(nic.Response)))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = s.waitTillProvisioned(nic.Headers.Get("Location"), *c)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error occured while creating a NIC %s", err.Error()))
|
||||
ui.Error(fmt.Sprintf("Error occurred while creating a NIC %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -146,9 +151,11 @@ func (s *stepCreateServer) Cleanup(state multistep.StateBag) {
|
||||
|
||||
if dcId, ok := state.GetOk("datacenter_id"); ok {
|
||||
resp := profitbricks.DeleteDatacenter(dcId.(string))
|
||||
s.checkForErrors(resp)
|
||||
err := s.waitTillProvisioned(resp.Headers.Get("Location"), *c)
|
||||
if err != nil {
|
||||
if err := s.checkForErrors(resp); err != nil {
|
||||
ui.Error(fmt.Sprintf(
|
||||
"Error deleting Virtual Data Center. Please destroy it manually: %s", err))
|
||||
}
|
||||
if err := s.waitTillProvisioned(resp.Headers.Get("Location"), *c); err != nil {
|
||||
ui.Error(fmt.Sprintf(
|
||||
"Error deleting Virtual Data Center. Please destroy it manually: %s", err))
|
||||
}
|
||||
@@ -182,7 +189,7 @@ func (d *stepCreateServer) setPB(username string, password string, url string) {
|
||||
|
||||
func (d *stepCreateServer) checkForErrors(instance profitbricks.Resp) error {
|
||||
if instance.StatusCode > 299 {
|
||||
return errors.New(fmt.Sprintf("Error occured %s", string(instance.Body)))
|
||||
return errors.New(fmt.Sprintf("Error occurred %s", string(instance.Body)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,12 +2,11 @@ package profitbricks
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/profitbricks/profitbricks-sdk-go"
|
||||
"time"
|
||||
)
|
||||
|
||||
type stepTakeSnapshot struct{}
|
||||
@@ -29,7 +28,10 @@ func (s *stepTakeSnapshot) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
if snapshot.StatusCode > 299 {
|
||||
var restError RestError
|
||||
json.Unmarshal([]byte(snapshot.Response), &restError)
|
||||
if err := json.Unmarshal([]byte(snapshot.Response), &restError); err != nil {
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
if len(restError.Messages) > 0 {
|
||||
ui.Error(restError.Messages[0].Message)
|
||||
} else {
|
||||
@@ -47,13 +49,6 @@ func (s *stepTakeSnapshot) Run(state multistep.StateBag) multistep.StepAction {
|
||||
func (s *stepTakeSnapshot) Cleanup(state multistep.StateBag) {
|
||||
}
|
||||
|
||||
func (d *stepTakeSnapshot) checkForErrors(instance profitbricks.Resp) error {
|
||||
if instance.StatusCode > 299 {
|
||||
return errors.New(fmt.Sprintf("Error occured %s", string(instance.Body)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *stepTakeSnapshot) waitTillProvisioned(path string, config Config) {
|
||||
d.setPB(config.PBUsername, config.PBPassword, config.PBUrl)
|
||||
waitCount := 50
|
||||
|
||||
@@ -301,11 +301,11 @@ func TestBuilderPrepare_FloppyFiles(t *testing.T) {
|
||||
func TestBuilderPrepare_InvalidFloppies(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
config["floppy_files"] = []string{"nonexistant.bat", "nonexistant.ps1"}
|
||||
config["floppy_files"] = []string{"nonexistent.bat", "nonexistent.ps1"}
|
||||
b = Builder{}
|
||||
_, errs := b.Prepare(config)
|
||||
if errs == nil {
|
||||
t.Fatalf("Non existant floppies should trigger multierror")
|
||||
t.Fatalf("Nonexistent floppies should trigger multierror")
|
||||
}
|
||||
|
||||
if len(errs.(*packer.MultiError).Errors) != 2 {
|
||||
|
||||
@@ -2,11 +2,12 @@ package qemu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
// This step configures the VM to enable the VNC server.
|
||||
@@ -28,7 +29,7 @@ func (stepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction {
|
||||
// best.
|
||||
msg := fmt.Sprintf("Looking for available port between %d and %d on %s", config.VNCPortMin, config.VNCPortMax, config.VNCBindAddress)
|
||||
ui.Say(msg)
|
||||
log.Printf(msg)
|
||||
log.Print(msg)
|
||||
var vncPort uint
|
||||
portRange := int(config.VNCPortMax - config.VNCPortMin)
|
||||
for {
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
package qemu
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"time"
|
||||
)
|
||||
|
||||
// stepWaitForShutdown waits for the shutdown of the currently running
|
||||
// qemu VM.
|
||||
type stepWaitForShutdown struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (s *stepWaitForShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
defer close(stopCh)
|
||||
|
||||
cancelCh := make(chan struct{})
|
||||
go func() {
|
||||
for {
|
||||
if _, ok := state.GetOk(multistep.StateCancelled); ok {
|
||||
close(cancelCh)
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case <-stopCh:
|
||||
return
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
ui.Say(s.Message)
|
||||
driver.WaitForShutdown(cancelCh)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepWaitForShutdown) Cleanup(state multistep.StateBag) {}
|
||||
@@ -59,7 +59,7 @@ func (c *AccessConfig) CreateTritonClient() (*cloudapi.Client, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userauth, err := auth.NewAuth(c.Account, string(keyData), "rsa-sha256")
|
||||
userauth, err := auth.NewAuth(c.Account, keyData, "rsa-sha256")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ func CommHost(host string) func(multistep.StateBag) (string, error) {
|
||||
|
||||
func SSHPort(state multistep.StateBag) (int, error) {
|
||||
sshHostPort := state.Get("sshHostPort").(int)
|
||||
return int(sshHostPort), nil
|
||||
return sshHostPort, nil
|
||||
}
|
||||
|
||||
func SSHConfigFunc(config SSHConfig) func(multistep.StateBag) (*gossh.ClientConfig, error) {
|
||||
|
||||
@@ -2,7 +2,10 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
@@ -39,14 +42,25 @@ func (s *StepRemoveDevices) Run(state multistep.StateBag) multistep.StepAction {
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Don't forget to remove the floppy controller as well
|
||||
command = []string{
|
||||
"storagectl", vmName,
|
||||
"--name", "Floppy Controller",
|
||||
"--remove",
|
||||
}
|
||||
if err := driver.VBoxManage(command...); err != nil {
|
||||
err := fmt.Errorf("Error removing floppy controller: %s", err)
|
||||
var vboxErr error
|
||||
// Retry for 10 minutes to remove the floppy controller.
|
||||
log.Printf("Trying for 10 minutes to remove floppy controller.")
|
||||
err := common.Retry(15, 15, 40, func() (bool, error) {
|
||||
// Don't forget to remove the floppy controller as well
|
||||
command = []string{
|
||||
"storagectl", vmName,
|
||||
"--name", "Floppy Controller",
|
||||
"--remove",
|
||||
}
|
||||
vboxErr = driver.VBoxManage(command...)
|
||||
if vboxErr != nil {
|
||||
log.Printf("Error removing floppy controller. Retrying.")
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
if err == common.RetryExhaustedError {
|
||||
err := fmt.Errorf("Error removing floppy controller: %s", vboxErr)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
|
||||
@@ -2,9 +2,10 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"time"
|
||||
)
|
||||
|
||||
// This step starts the virtual machine.
|
||||
@@ -29,7 +30,7 @@ func (s *StepRun) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
ui.Say("Starting the virtual machine...")
|
||||
guiArgument := "gui"
|
||||
if s.Headless == true {
|
||||
if s.Headless {
|
||||
vrdpIpRaw, vrdpIpOk := state.GetOk("vrdpIp")
|
||||
vrdpPortRaw, vrdpPortOk := state.GetOk("vrdpPort")
|
||||
|
||||
|
||||
@@ -5,12 +5,13 @@ import (
|
||||
)
|
||||
|
||||
type VBoxVersionConfig struct {
|
||||
VBoxVersionFile string `mapstructure:"virtualbox_version_file"`
|
||||
VBoxVersionFile *string `mapstructure:"virtualbox_version_file"`
|
||||
}
|
||||
|
||||
func (c *VBoxVersionConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
if c.VBoxVersionFile == "" {
|
||||
c.VBoxVersionFile = ".vbox_version"
|
||||
if c.VBoxVersionFile == nil {
|
||||
default_file := ".vbox_version"
|
||||
c.VBoxVersionFile = &default_file
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -15,19 +15,50 @@ func TestVBoxVersionConfigPrepare_BootWait(t *testing.T) {
|
||||
t.Fatalf("should not have error: %s", errs)
|
||||
}
|
||||
|
||||
if c.VBoxVersionFile != ".vbox_version" {
|
||||
t.Fatalf("bad value: %s", c.VBoxVersionFile)
|
||||
if *c.VBoxVersionFile != ".vbox_version" {
|
||||
t.Fatalf("bad value: %s", *c.VBoxVersionFile)
|
||||
}
|
||||
|
||||
// Test with a good one
|
||||
c = new(VBoxVersionConfig)
|
||||
c.VBoxVersionFile = "foo"
|
||||
filename := "foo"
|
||||
c.VBoxVersionFile = &filename
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %s", errs)
|
||||
}
|
||||
|
||||
if c.VBoxVersionFile != "foo" {
|
||||
t.Fatalf("bad value: %s", c.VBoxVersionFile)
|
||||
if *c.VBoxVersionFile != "foo" {
|
||||
t.Fatalf("bad value: %s", *c.VBoxVersionFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVBoxVersionConfigPrepare_empty(t *testing.T) {
|
||||
var c *VBoxVersionConfig
|
||||
var errs []error
|
||||
|
||||
// Test with nil value
|
||||
c = new(VBoxVersionConfig)
|
||||
c.VBoxVersionFile = nil
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %s", errs)
|
||||
}
|
||||
|
||||
if *c.VBoxVersionFile != ".vbox_version" {
|
||||
t.Fatalf("bad value: %s", *c.VBoxVersionFile)
|
||||
}
|
||||
|
||||
// Test with empty name
|
||||
c = new(VBoxVersionConfig)
|
||||
filename := ""
|
||||
c.VBoxVersionFile = &filename
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %s", errs)
|
||||
}
|
||||
|
||||
if *c.VBoxVersionFile != "" {
|
||||
t.Fatalf("bad value: %s", *c.VBoxVersionFile)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
WinRMPort: vboxcommon.SSHPort,
|
||||
},
|
||||
&vboxcommon.StepUploadVersion{
|
||||
Path: b.config.VBoxVersionFile,
|
||||
Path: *b.config.VBoxVersionFile,
|
||||
},
|
||||
&vboxcommon.StepUploadGuestAdditions{
|
||||
GuestAdditionsMode: b.config.GuestAdditionsMode,
|
||||
|
||||
@@ -126,11 +126,11 @@ func TestBuilderPrepare_FloppyFiles(t *testing.T) {
|
||||
func TestBuilderPrepare_InvalidFloppies(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
config["floppy_files"] = []string{"nonexistant.bat", "nonexistant.ps1"}
|
||||
config["floppy_files"] = []string{"nonexistent.bat", "nonexistent.ps1"}
|
||||
b = Builder{}
|
||||
_, errs := b.Prepare(config)
|
||||
if errs == nil {
|
||||
t.Fatalf("Non existant floppies should trigger multierror")
|
||||
t.Fatalf("Nonexistent floppies should trigger multierror")
|
||||
}
|
||||
|
||||
if len(errs.(*packer.MultiError).Errors) != 2 {
|
||||
|
||||
@@ -119,7 +119,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
WinRMPort: vboxcommon.SSHPort,
|
||||
},
|
||||
&vboxcommon.StepUploadVersion{
|
||||
Path: b.config.VBoxVersionFile,
|
||||
Path: *b.config.VBoxVersionFile,
|
||||
},
|
||||
&vboxcommon.StepUploadGuestAdditions{
|
||||
GuestAdditionsMode: b.config.GuestAdditionsMode,
|
||||
|
||||
@@ -42,10 +42,10 @@ func TestNewConfig_FloppyFiles(t *testing.T) {
|
||||
|
||||
func TestNewConfig_InvalidFloppies(t *testing.T) {
|
||||
c := testConfig(t)
|
||||
c["floppy_files"] = []string{"nonexistant.bat", "nonexistant.ps1"}
|
||||
c["floppy_files"] = []string{"nonexistent.bat", "nonexistent.ps1"}
|
||||
_, _, errs := NewConfig(c)
|
||||
if errs == nil {
|
||||
t.Fatalf("Non existant floppies should trigger multierror")
|
||||
t.Fatalf("Nonexistent floppies should trigger multierror")
|
||||
}
|
||||
|
||||
if len(errs.(*packer.MultiError).Errors) != 2 {
|
||||
|
||||
@@ -127,11 +127,11 @@ func TestBuilderPrepare_FloppyFiles(t *testing.T) {
|
||||
func TestBuilderPrepare_InvalidFloppies(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
config["floppy_files"] = []string{"nonexistant.bat", "nonexistant.ps1"}
|
||||
config["floppy_files"] = []string{"nonexistent.bat", "nonexistent.ps1"}
|
||||
b = Builder{}
|
||||
_, errs := b.Prepare(config)
|
||||
if errs == nil {
|
||||
t.Fatalf("Non existant floppies should trigger multierror")
|
||||
t.Fatalf("Nonexistent floppies should trigger multierror")
|
||||
}
|
||||
|
||||
if len(errs.(*packer.MultiError).Errors) != 2 {
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
package iso
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// OutputDir is an interface type that abstracts the creation and handling
|
||||
// of the output directory for VMware-based products. The abstraction is made
|
||||
// so that the output directory can be properly made on remote (ESXi) based
|
||||
@@ -17,50 +12,3 @@ type OutputDir interface {
|
||||
RemoveAll() error
|
||||
SetOutputDir(string)
|
||||
}
|
||||
|
||||
// localOutputDir is an OutputDir implementation where the directory
|
||||
// is on the local machine.
|
||||
type localOutputDir struct {
|
||||
dir string
|
||||
}
|
||||
|
||||
func (d *localOutputDir) DirExists() (bool, error) {
|
||||
_, err := os.Stat(d.dir)
|
||||
return err == nil, nil
|
||||
}
|
||||
|
||||
func (d *localOutputDir) ListFiles() ([]string, error) {
|
||||
files := make([]string, 0, 10)
|
||||
|
||||
visit := func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
files = append(files, path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return files, filepath.Walk(d.dir, visit)
|
||||
}
|
||||
|
||||
func (d *localOutputDir) MkdirAll() error {
|
||||
return os.MkdirAll(d.dir, 0755)
|
||||
}
|
||||
|
||||
func (d *localOutputDir) Remove(path string) error {
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
func (d *localOutputDir) RemoveAll() error {
|
||||
return os.RemoveAll(d.dir)
|
||||
}
|
||||
|
||||
func (d *localOutputDir) SetOutputDir(path string) {
|
||||
d.dir = path
|
||||
}
|
||||
|
||||
func (d *localOutputDir) String() string {
|
||||
return d.dir
|
||||
}
|
||||
|
||||
@@ -56,11 +56,11 @@ func TestBuilderPrepare_FloppyFiles(t *testing.T) {
|
||||
func TestBuilderPrepare_InvalidFloppies(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig(t)
|
||||
config["floppy_files"] = []string{"nonexistant.bat", "nonexistant.ps1"}
|
||||
config["floppy_files"] = []string{"nonexistent.bat", "nonexistent.ps1"}
|
||||
b = Builder{}
|
||||
_, errs := b.Prepare(config)
|
||||
if errs == nil {
|
||||
t.Fatalf("Non existant floppies should trigger multierror")
|
||||
t.Fatalf("Nonexistent floppies should trigger multierror")
|
||||
}
|
||||
|
||||
if len(errs.(*packer.MultiError).Errors) != 2 {
|
||||
|
||||
+4
-4
@@ -211,8 +211,8 @@ func (c BuildCommand) Run(args []string) int {
|
||||
|
||||
c.Ui.Error("\n==> Some builds didn't complete successfully and had errors:")
|
||||
for name, err := range errors {
|
||||
// Create a UI for the machine readable stuff to be targetted
|
||||
ui := &packer.TargettedUi{
|
||||
// Create a UI for the machine readable stuff to be targeted
|
||||
ui := &packer.TargetedUI{
|
||||
Target: name,
|
||||
Ui: c.Ui,
|
||||
}
|
||||
@@ -226,8 +226,8 @@ func (c BuildCommand) Run(args []string) int {
|
||||
if len(artifacts.m) > 0 {
|
||||
c.Ui.Say("\n==> Builds finished. The artifacts of successful builds are:")
|
||||
for name, buildArtifacts := range artifacts.m {
|
||||
// Create a UI for the machine readable stuff to be targetted
|
||||
ui := &packer.TargettedUi{
|
||||
// Create a UI for the machine readable stuff to be targeted
|
||||
ui := &packer.TargetedUI{
|
||||
Target: name,
|
||||
Ui: c.Ui,
|
||||
}
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ func (c *VersionCommand) Run(args []string) int {
|
||||
var versionString bytes.Buffer
|
||||
fmt.Fprintf(&versionString, "Packer v%s", c.Version)
|
||||
if c.VersionPrerelease != "" {
|
||||
fmt.Fprintf(&versionString, ".%s", c.VersionPrerelease)
|
||||
fmt.Fprintf(&versionString, "-%s", c.VersionPrerelease)
|
||||
|
||||
if c.Revision != "" {
|
||||
fmt.Fprintf(&versionString, " (%s)", c.Revision)
|
||||
|
||||
-20
@@ -1,9 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/mitchellh/packer/command"
|
||||
"github.com/mitchellh/packer/version"
|
||||
@@ -68,20 +65,3 @@ func init() {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// makeShutdownCh creates an interrupt listener and returns a channel.
|
||||
// A message will be sent on the channel for every interrupt received.
|
||||
func makeShutdownCh() <-chan struct{} {
|
||||
resultCh := make(chan struct{})
|
||||
|
||||
signalCh := make(chan os.Signal, 4)
|
||||
signal.Notify(signalCh, os.Interrupt)
|
||||
go func() {
|
||||
for {
|
||||
<-signalCh
|
||||
resultCh <- struct{}{}
|
||||
}
|
||||
}()
|
||||
|
||||
return resultCh
|
||||
}
|
||||
|
||||
+1
-1
@@ -205,7 +205,7 @@ func (d *DownloadClient) VerifyChecksum(path string) (bool, error) {
|
||||
log.Printf("Verifying checksum of %s", path)
|
||||
d.config.Hash.Reset()
|
||||
io.Copy(d.config.Hash, f)
|
||||
return bytes.Compare(d.config.Hash.Sum(nil), d.config.Checksum) == 0, nil
|
||||
return bytes.Equal(d.config.Hash.Sum(nil), d.config.Checksum), nil
|
||||
}
|
||||
|
||||
// HTTPDownloader is an implementation of Downloader that downloads
|
||||
|
||||
@@ -23,7 +23,7 @@ func (c *FloppyConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
}
|
||||
|
||||
for _, path := range c.FloppyFiles {
|
||||
if strings.IndexAny(path, "*?[") >= 0 {
|
||||
if strings.ContainsAny(path, "*?[") {
|
||||
_, err = filepath.Glob(path)
|
||||
} else {
|
||||
_, err = os.Stat(path)
|
||||
@@ -38,7 +38,7 @@ func (c *FloppyConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
}
|
||||
|
||||
for _, path := range c.FloppyDirectories {
|
||||
if strings.IndexAny(path, "*?[") >= 0 {
|
||||
if strings.ContainsAny(path, "*?[") {
|
||||
_, err = filepath.Glob(path)
|
||||
} else {
|
||||
_, err = os.Stat(path)
|
||||
|
||||
@@ -61,6 +61,10 @@ type abortStep struct {
|
||||
ui packer.Ui
|
||||
}
|
||||
|
||||
func (s abortStep) InnerStepName() string {
|
||||
return typeName(s.step)
|
||||
}
|
||||
|
||||
func (s abortStep) Run(state multistep.StateBag) multistep.StepAction {
|
||||
return s.step.Run(state)
|
||||
}
|
||||
@@ -82,6 +86,10 @@ type askStep struct {
|
||||
ui packer.Ui
|
||||
}
|
||||
|
||||
func (s askStep) InnerStepName() string {
|
||||
return typeName(s.step)
|
||||
}
|
||||
|
||||
func (s askStep) Run(state multistep.StateBag) (action multistep.StepAction) {
|
||||
for {
|
||||
action = s.step.Run(state)
|
||||
|
||||
@@ -575,7 +575,7 @@ func GetExternalOnlineVirtualSwitch() (string, error) {
|
||||
|
||||
var script = `
|
||||
$adapters = Get-NetAdapter -Physical -ErrorAction SilentlyContinue | Where-Object { $_.Status -eq 'Up' } | Sort-Object -Descending -Property Speed
|
||||
foreach ($adapter in $adapters) {
|
||||
foreach ($adapter in $adapters) {
|
||||
$switch = Get-VMSwitch -SwitchType External | Where-Object { $_.NetAdapterInterfaceDescription -eq $adapter.InterfaceDescription }
|
||||
|
||||
if ($switch -ne $null) {
|
||||
@@ -605,10 +605,10 @@ $adapters = foreach ($name in $names) {
|
||||
Get-NetAdapter -Physical -Name $name -ErrorAction SilentlyContinue | where status -eq 'up'
|
||||
}
|
||||
|
||||
foreach ($adapter in $adapters) {
|
||||
foreach ($adapter in $adapters) {
|
||||
$switch = Get-VMSwitch -SwitchType External | where { $_.NetAdapterInterfaceDescription -eq $adapter.InterfaceDescription }
|
||||
|
||||
if ($switch -eq $null) {
|
||||
if ($switch -eq $null) {
|
||||
$switch = New-VMSwitch -Name $switchName -NetAdapterName $adapter.Name -AllowManagementOS $true -Notes 'Parent OS, VMs, WiFi'
|
||||
}
|
||||
|
||||
@@ -617,9 +617,9 @@ foreach ($adapter in $adapters) {
|
||||
}
|
||||
}
|
||||
|
||||
if($switch -ne $null) {
|
||||
Get-VMNetworkAdapter -VMName $vmName | Connect-VMNetworkAdapter -VMSwitch $switch
|
||||
} else {
|
||||
if($switch -ne $null) {
|
||||
Get-VMNetworkAdapter -VMName $vmName | Connect-VMNetworkAdapter -VMSwitch $switch
|
||||
} else {
|
||||
Write-Error 'No internet adapters found'
|
||||
}
|
||||
`
|
||||
@@ -721,7 +721,7 @@ $vm.Uptime.TotalSeconds
|
||||
return 0, err
|
||||
}
|
||||
|
||||
uptime, err := strconv.ParseUint(strings.TrimSpace(string(cmdOut)), 10, 64)
|
||||
uptime, err := strconv.ParseUint(strings.TrimSpace(cmdOut), 10, 64)
|
||||
|
||||
return uptime, err
|
||||
}
|
||||
@@ -752,7 +752,7 @@ func IpAddress(mac string) (string, error) {
|
||||
param([string]$mac, [int]$addressIndex)
|
||||
try {
|
||||
$ip = Get-Vm | %{$_.NetworkAdapters} | ?{$_.MacAddress -eq $mac} | %{$_.IpAddresses[$addressIndex]}
|
||||
|
||||
|
||||
if($ip -eq $null) {
|
||||
return ""
|
||||
}
|
||||
@@ -807,7 +807,7 @@ func TypeScanCodes(vmName string, scanCodes string) error {
|
||||
param([string]$vmName, [string]$scanCodes)
|
||||
#Requires -Version 3
|
||||
#Requires -RunAsAdministrator
|
||||
|
||||
|
||||
function Get-VMConsole
|
||||
{
|
||||
[CmdletBinding()]
|
||||
@@ -815,16 +815,16 @@ param([string]$vmName, [string]$scanCodes)
|
||||
[Parameter(Mandatory)]
|
||||
[string] $VMName
|
||||
)
|
||||
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
|
||||
$vm = Get-CimInstance -Namespace "root\virtualization\v2" -ClassName Msvm_ComputerSystem -ErrorAction Ignore -Verbose:$false | where ElementName -eq $VMName | select -first 1
|
||||
if ($vm -eq $null){
|
||||
Write-Error ("VirtualMachine({0}) is not found!" -f $VMName)
|
||||
}
|
||||
|
||||
|
||||
$vmKeyboard = $vm | Get-CimAssociatedInstance -ResultClassName "Msvm_Keyboard" -ErrorAction Ignore -Verbose:$false
|
||||
|
||||
|
||||
if ($vmKeyboard -eq $null) {
|
||||
$vmKeyboard = Get-CimInstance -Namespace "root\virtualization\v2" -ClassName Msvm_Keyboard -ErrorAction Ignore -Verbose:$false | where SystemName -eq $vm.Name | select -first 1
|
||||
}
|
||||
@@ -832,22 +832,22 @@ param([string]$vmName, [string]$scanCodes)
|
||||
if ($vmKeyboard -eq $null) {
|
||||
$vmKeyboard = Get-CimInstance -Namespace "root\virtualization" -ClassName Msvm_Keyboard -ErrorAction Ignore -Verbose:$false | where SystemName -eq $vm.Name | select -first 1
|
||||
}
|
||||
|
||||
|
||||
if ($vmKeyboard -eq $null){
|
||||
Write-Error ("VirtualMachine({0}) keyboard class is not found!" -f $VMName)
|
||||
}
|
||||
|
||||
|
||||
#TODO: It may be better using New-Module -AsCustomObject to return console object?
|
||||
|
||||
|
||||
#Console object to return
|
||||
$console = [pscustomobject] @{
|
||||
Msvm_ComputerSystem = $vm
|
||||
Msvm_Keyboard = $vmKeyboard
|
||||
}
|
||||
|
||||
|
||||
#Need to import assembly to use System.Windows.Input.Key
|
||||
Add-Type -AssemblyName WindowsBase
|
||||
|
||||
|
||||
#region Add Console Members
|
||||
$console | Add-Member -MemberType ScriptMethod -Name TypeText -Value {
|
||||
[OutputType([bool])]
|
||||
@@ -859,13 +859,13 @@ param([string]$vmName, [string]$scanCodes)
|
||||
$result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeText" -Arguments @{ asciiText = $AsciiText }
|
||||
return (0 -eq $result.ReturnValue)
|
||||
}
|
||||
|
||||
|
||||
#Define method:TypeCtrlAltDel
|
||||
$console | Add-Member -MemberType ScriptMethod -Name TypeCtrlAltDel -Value {
|
||||
$result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeCtrlAltDel"
|
||||
return (0 -eq $result.ReturnValue)
|
||||
}
|
||||
|
||||
|
||||
#Define method:TypeKey
|
||||
$console | Add-Member -MemberType ScriptMethod -Name TypeKey -Value {
|
||||
[OutputType([bool])]
|
||||
@@ -874,9 +874,9 @@ param([string]$vmName, [string]$scanCodes)
|
||||
[Windows.Input.Key] $Key,
|
||||
[Windows.Input.ModifierKeys] $ModifierKey = [Windows.Input.ModifierKeys]::None
|
||||
)
|
||||
|
||||
|
||||
$keyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey($Key)
|
||||
|
||||
|
||||
switch ($ModifierKey)
|
||||
{
|
||||
([Windows.Input.ModifierKeys]::Control){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftCtrl)}
|
||||
@@ -884,7 +884,7 @@ param([string]$vmName, [string]$scanCodes)
|
||||
([Windows.Input.ModifierKeys]::Shift){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftShift)}
|
||||
([Windows.Input.ModifierKeys]::Windows){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LWin)}
|
||||
}
|
||||
|
||||
|
||||
if ($ModifierKey -eq [Windows.Input.ModifierKeys]::None)
|
||||
{
|
||||
$result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeKey" -Arguments @{ keyCode = $keyCode }
|
||||
@@ -897,7 +897,7 @@ param([string]$vmName, [string]$scanCodes)
|
||||
}
|
||||
$result = return (0 -eq $result.ReturnValue)
|
||||
}
|
||||
|
||||
|
||||
#Define method:Scancodes
|
||||
$console | Add-Member -MemberType ScriptMethod -Name TypeScancodes -Value {
|
||||
[OutputType([bool])]
|
||||
@@ -908,7 +908,7 @@ param([string]$vmName, [string]$scanCodes)
|
||||
$result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeScancodes" -Arguments @{ ScanCodes = $ScanCodes }
|
||||
return (0 -eq $result.ReturnValue)
|
||||
}
|
||||
|
||||
|
||||
#Define method:ExecCommand
|
||||
$console | Add-Member -MemberType ScriptMethod -Name ExecCommand -Value {
|
||||
param (
|
||||
@@ -918,46 +918,46 @@ param([string]$vmName, [string]$scanCodes)
|
||||
if ([String]::IsNullOrEmpty($Command)){
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
$console.TypeText($Command) > $null
|
||||
$console.TypeKey([Windows.Input.Key]::Enter) > $null
|
||||
#sleep -Milliseconds 100
|
||||
}
|
||||
|
||||
|
||||
#Define method:Dispose
|
||||
$console | Add-Member -MemberType ScriptMethod -Name Dispose -Value {
|
||||
$this.Msvm_ComputerSystem.Dispose()
|
||||
$this.Msvm_Keyboard.Dispose()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
return $console
|
||||
}
|
||||
|
||||
|
||||
$vmConsole = Get-VMConsole -VMName $vmName
|
||||
$scanCodesToSend = ''
|
||||
$scanCodes.Split(' ') | %{
|
||||
$scanCode = $_
|
||||
|
||||
|
||||
if ($scanCode.StartsWith('wait')){
|
||||
$timeToWait = $scanCode.Substring(4)
|
||||
if (!$timeToWait){
|
||||
$timeToWait = "1"
|
||||
}
|
||||
|
||||
|
||||
if ($scanCodesToSend){
|
||||
$scanCodesToSendByteArray = [byte[]]@($scanCodesToSend.Split(' ') | %{"0x$_"})
|
||||
|
||||
|
||||
$scanCodesToSendByteArray | %{
|
||||
$vmConsole.TypeScancodes($_)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
write-host "Special code <wait> found, will sleep $timeToWait second(s) at this point."
|
||||
Start-Sleep -s $timeToWait
|
||||
|
||||
|
||||
$scanCodesToSend = ''
|
||||
} else {
|
||||
if ($scanCodesToSend){
|
||||
@@ -971,7 +971,7 @@ param([string]$vmName, [string]$scanCodes)
|
||||
}
|
||||
if ($scanCodesToSend){
|
||||
$scanCodesToSendByteArray = [byte[]]@($scanCodesToSend.Split(' ') | %{"0x$_"})
|
||||
|
||||
|
||||
$scanCodesToSendByteArray | %{
|
||||
$vmConsole.TypeScancodes($_)
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@ param([string]$moduleName)
|
||||
return false, err
|
||||
}
|
||||
|
||||
res := strings.TrimSpace(string(cmdOut))
|
||||
res := strings.TrimSpace(cmdOut)
|
||||
|
||||
if res == powerShellFalse {
|
||||
err := fmt.Errorf("PowerShell %s module is not loaded. Make sure %s feature is on.", moduleName, moduleName)
|
||||
|
||||
+3
-1
@@ -8,13 +8,15 @@ import (
|
||||
|
||||
var RetryExhaustedError error = fmt.Errorf("Function never succeeded in Retry")
|
||||
|
||||
type RetryableFunc func() (bool, error)
|
||||
|
||||
// Retry retries a function up to numTries times with exponential backoff.
|
||||
// If numTries == 0, retry indefinitely. If interval == 0, Retry will not delay retrying and there will be
|
||||
// no exponential backoff. If maxInterval == 0, maxInterval is set to +Infinity.
|
||||
// Intervals are in seconds.
|
||||
// Returns an error if initial > max intervals, if retries are exhausted, or if the passed function returns
|
||||
// an error.
|
||||
func Retry(initialInterval float64, maxInterval float64, numTries uint, function func() (bool, error)) error {
|
||||
func Retry(initialInterval float64, maxInterval float64, numTries uint, function RetryableFunc) error {
|
||||
if maxInterval == 0 {
|
||||
maxInterval = math.Inf(1)
|
||||
} else if initialInterval < 0 || initialInterval > maxInterval {
|
||||
|
||||
@@ -56,7 +56,7 @@ func TestRetry(t *testing.T) {
|
||||
return false, nil
|
||||
})
|
||||
if numTries != expectedTries {
|
||||
t.Fatalf("Unsuccessul retry function should have been called %d times. Only called %d times.", expectedTries, numTries)
|
||||
t.Fatalf("Unsuccessful retry function should have been called %d times. Only called %d times.", expectedTries, numTries)
|
||||
}
|
||||
if err != RetryExhaustedError {
|
||||
t.Fatalf("Unsuccessful retry function should have returned a retry exhausted error. Actual error: %s", err)
|
||||
|
||||
@@ -2,10 +2,6 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/go-fs"
|
||||
"github.com/mitchellh/go-fs/fat"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
@@ -13,6 +9,11 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/mitchellh/go-fs"
|
||||
"github.com/mitchellh/go-fs/fat"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
// StepCreateFloppy will create a floppy disk with the given files.
|
||||
@@ -96,7 +97,7 @@ func (s *StepCreateFloppy) Run(state multistep.StateBag) multistep.StepAction {
|
||||
// Utility functions for walking through a directory grabbing all files flatly
|
||||
globFiles := func(files []string, list chan string) {
|
||||
for _, filename := range files {
|
||||
if strings.IndexAny(filename, "*?[") >= 0 {
|
||||
if strings.ContainsAny(filename, "*?[") {
|
||||
matches, _ := filepath.Glob(filename)
|
||||
if err != nil {
|
||||
continue
|
||||
@@ -173,7 +174,7 @@ func (s *StepCreateFloppy) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui.Message("Collecting paths from floppy_dirs")
|
||||
var pathqueue []string
|
||||
for _, filename := range s.Directories {
|
||||
if strings.IndexAny(filename, "*?[") >= 0 {
|
||||
if strings.ContainsAny(filename, "*?[") {
|
||||
matches, err := filepath.Glob(filename)
|
||||
if err != nil {
|
||||
state.Put("error", fmt.Errorf("Error adding path %s to floppy: %s", filename, err))
|
||||
|
||||
@@ -239,9 +239,9 @@ func (c *comm) newSession() (session *ssh.Session, err error) {
|
||||
}
|
||||
|
||||
if c.client == nil {
|
||||
err = errors.New("client not available")
|
||||
return nil, errors.New("client not available")
|
||||
} else {
|
||||
session, err = c.client.NewSession()
|
||||
return c.client.NewSession()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,6 +250,7 @@ func (c *comm) newSession() (session *ssh.Session, err error) {
|
||||
|
||||
func (c *comm) reconnect() (err error) {
|
||||
if c.conn != nil {
|
||||
// Ignore errors here because we don't care if it fails
|
||||
c.conn.Close()
|
||||
}
|
||||
|
||||
@@ -620,14 +621,10 @@ func (c *comm) scpDownloadSession(path string, output io.Writer) error {
|
||||
|
||||
fmt.Fprint(w, "\x00")
|
||||
|
||||
if err := checkSCPStatus(stdoutR); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return checkSCPStatus(stdoutR)
|
||||
}
|
||||
|
||||
if strings.Index(path, " ") == -1 {
|
||||
if !strings.Contains(path, " ") {
|
||||
return c.scpSession("scp -vf "+path, scpFunc)
|
||||
}
|
||||
return c.scpSession("scp -vf "+strconv.Quote(path), scpFunc)
|
||||
@@ -805,11 +802,7 @@ func scpUploadFile(dst string, src io.Reader, w io.Writer, r *bufio.Reader, fi *
|
||||
}
|
||||
|
||||
fmt.Fprint(w, "\x00")
|
||||
if err := checkSCPStatus(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return checkSCPStatus(r)
|
||||
}
|
||||
|
||||
func scpUploadDirProtocol(name string, w io.Writer, r *bufio.Reader, f func() error, fi os.FileInfo) error {
|
||||
@@ -830,11 +823,7 @@ func scpUploadDirProtocol(name string, w io.Writer, r *bufio.Reader, f func() er
|
||||
}
|
||||
|
||||
fmt.Fprintln(w, "E")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func scpUploadDir(root string, fs []os.FileInfo, w io.Writer, r *bufio.Reader) error {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"golang.org/x/crypto/ssh"
|
||||
"log"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// An implementation of ssh.KeyboardInteractiveChallenge that simply sends
|
||||
@@ -19,7 +20,7 @@ func PasswordKeyboardInteractive(password string) ssh.KeyboardInteractiveChallen
|
||||
// Just send the password back for all questions
|
||||
answers := make([]string, len(questions))
|
||||
for i := range answers {
|
||||
answers[i] = string(password)
|
||||
answers[i] = password
|
||||
}
|
||||
|
||||
return answers, nil
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/masterzen/winrm"
|
||||
@@ -129,6 +131,9 @@ func (c *Communicator) Upload(path string, input io.Reader, _ *os.FileInfo) erro
|
||||
|
||||
// UploadDir implementation of communicator.Communicator interface
|
||||
func (c *Communicator) UploadDir(dst string, src string, exclude []string) error {
|
||||
if !strings.HasSuffix(src, "/") {
|
||||
dst = fmt.Sprintf("%s\\%s", dst, filepath.Base(src))
|
||||
}
|
||||
log.Printf("Uploading dir '%s' to '%s'", src, dst)
|
||||
wcp, err := c.newCopyClient()
|
||||
if err != nil {
|
||||
|
||||
@@ -155,13 +155,8 @@ func (c *config) discover(path string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.discoverSingle(
|
||||
return c.discoverSingle(
|
||||
filepath.Join(path, "packer-provisioner-*"), &c.Provisioners)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *config) discoverSingle(glob string, m *map[string]string) error {
|
||||
|
||||
@@ -187,8 +187,6 @@ func wrappedMain() int {
|
||||
Ui: ui,
|
||||
}
|
||||
|
||||
//setupSignalHandlers(env)
|
||||
|
||||
cli := &cli.CLI{
|
||||
Args: args,
|
||||
Commands: Commands,
|
||||
|
||||
+4
-4
@@ -56,7 +56,7 @@ type Build interface {
|
||||
Run(Ui, Cache) ([]Artifact, error)
|
||||
|
||||
// Cancel will cancel a running build. This will block until the build
|
||||
// is actually completely cancelled.
|
||||
// is actually completely canceled.
|
||||
Cancel()
|
||||
|
||||
// SetDebug will enable/disable debug mode. Debug mode is always
|
||||
@@ -210,8 +210,8 @@ func (b *coreBuild) Run(originalUi Ui, cache Cache) ([]Artifact, error) {
|
||||
hook := &DispatchHook{Mapping: hooks}
|
||||
artifacts := make([]Artifact, 0, 1)
|
||||
|
||||
// The builder just has a normal Ui, but targetted
|
||||
builderUi := &TargettedUi{
|
||||
// The builder just has a normal Ui, but targeted
|
||||
builderUi := &TargetedUI{
|
||||
Target: b.Name(),
|
||||
Ui: originalUi,
|
||||
}
|
||||
@@ -236,7 +236,7 @@ PostProcessorRunSeqLoop:
|
||||
for _, ppSeq := range b.postProcessors {
|
||||
priorArtifact := builderArtifact
|
||||
for i, corePP := range ppSeq {
|
||||
ppUi := &TargettedUi{
|
||||
ppUi := &TargetedUI{
|
||||
Target: fmt.Sprintf("%s (%s)", b.Name(), corePP.processorType),
|
||||
Ui: originalUi,
|
||||
}
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@ type Builder interface {
|
||||
// Prepare is responsible for configuring the builder and validating
|
||||
// that configuration. Any setup should be done in this method. Note that
|
||||
// NO side effects should take place in prepare, it is meant as a state
|
||||
// setup only. Calling Prepare is not necessarilly followed by a Run.
|
||||
// setup only. Calling Prepare is not necessarily followed by a Run.
|
||||
//
|
||||
// The parameters to Prepare are a set of interface{} values of the
|
||||
// configuration. These are almost always `map[string]interface{}`
|
||||
@@ -24,7 +24,7 @@ type Builder interface {
|
||||
// configuration.
|
||||
//
|
||||
// Prepare should return a list of warnings along with any errors
|
||||
// that occured while preparing.
|
||||
// that occurred while preparing.
|
||||
Prepare(...interface{}) ([]string, error)
|
||||
|
||||
// Run is where the actual build should take place. It takes a Build and a Ui.
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/rpc"
|
||||
)
|
||||
|
||||
// rpcDial makes a TCP connection to a remote RPC server and returns
|
||||
// the client. This will set the connection up properly so that keep-alives
|
||||
// are set and so on and should be used to make all RPC connections within
|
||||
// this package.
|
||||
func rpcDial(address string) (*rpc.Client, error) {
|
||||
tcpConn, err := tcpDial(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create an RPC client around our connection
|
||||
return rpc.NewClient(tcpConn), nil
|
||||
}
|
||||
|
||||
// tcpDial connects via TCP to the designated address.
|
||||
func tcpDial(address string) (*net.TCPConn, error) {
|
||||
conn, err := net.Dial("tcp", address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set a keep-alive so that the connection stays alive even when idle
|
||||
tcpConn := conn.(*net.TCPConn)
|
||||
tcpConn.SetKeepAlive(true)
|
||||
return tcpConn, nil
|
||||
}
|
||||
@@ -183,9 +183,7 @@ func (m *muxBroker) timeoutWait(id uint32, p *muxBrokerPending) {
|
||||
// If we timed out, then check if we have a channel in the buffer,
|
||||
// and if so, close it.
|
||||
if timeout {
|
||||
select {
|
||||
case s := <-p.ch:
|
||||
s.Close()
|
||||
}
|
||||
s := <-p.ch
|
||||
s.Close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"net/rpc"
|
||||
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
// An implementation of packer.PostProcessor where the PostProcessor is actually
|
||||
@@ -15,9 +16,8 @@ type postProcessor struct {
|
||||
// PostProcessorServer wraps a packer.PostProcessor implementation and makes it
|
||||
// exportable as part of a Golang RPC server.
|
||||
type PostProcessorServer struct {
|
||||
client *rpc.Client
|
||||
mux *muxBroker
|
||||
p packer.PostProcessor
|
||||
mux *muxBroker
|
||||
p packer.PostProcessor
|
||||
}
|
||||
|
||||
type PostProcessorConfigureArgs struct {
|
||||
|
||||
@@ -4,14 +4,11 @@ import (
|
||||
"io"
|
||||
"log"
|
||||
"net/rpc"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/ugorji/go/codec"
|
||||
)
|
||||
|
||||
var endpointId uint64
|
||||
|
||||
const (
|
||||
DefaultArtifactEndpoint string = "Artifact"
|
||||
DefaultBuildEndpoint = "Build"
|
||||
@@ -140,18 +137,3 @@ func (s *Server) Serve() {
|
||||
rpcCodec := codec.GoRpc.ServerCodec(stream, h)
|
||||
s.server.ServeCodec(rpcCodec)
|
||||
}
|
||||
|
||||
// registerComponent registers a single Packer RPC component onto
|
||||
// the RPC server. If id is true, then a unique ID number will be appended
|
||||
// onto the end of the endpoint.
|
||||
//
|
||||
// The endpoint name is returned.
|
||||
func registerComponent(server *rpc.Server, name string, rcvr interface{}, id bool) string {
|
||||
endpoint := name
|
||||
if id {
|
||||
log.Printf("%s.%d", endpoint, atomic.AddUint64(&endpointId, 1))
|
||||
}
|
||||
|
||||
server.RegisterName(endpoint, rcvr)
|
||||
return endpoint
|
||||
}
|
||||
|
||||
+8
-8
@@ -46,12 +46,12 @@ type ColoredUi struct {
|
||||
Ui Ui
|
||||
}
|
||||
|
||||
// TargettedUi is a UI that wraps another UI implementation and modifies
|
||||
// TargetedUI is a UI that wraps another UI implementation and modifies
|
||||
// the output to indicate a specific target. Specifically, all Say output
|
||||
// is prefixed with the target name. Message output is not prefixed but
|
||||
// is offset by the length of the target so that output is lined up properly
|
||||
// with Say output. Machine-readable output has the proper target set.
|
||||
type TargettedUi struct {
|
||||
type TargetedUI struct {
|
||||
Target string
|
||||
Ui Ui
|
||||
}
|
||||
@@ -132,28 +132,28 @@ func (u *ColoredUi) supportsColors() bool {
|
||||
return cygwin
|
||||
}
|
||||
|
||||
func (u *TargettedUi) Ask(query string) (string, error) {
|
||||
func (u *TargetedUI) Ask(query string) (string, error) {
|
||||
return u.Ui.Ask(u.prefixLines(true, query))
|
||||
}
|
||||
|
||||
func (u *TargettedUi) Say(message string) {
|
||||
func (u *TargetedUI) Say(message string) {
|
||||
u.Ui.Say(u.prefixLines(true, message))
|
||||
}
|
||||
|
||||
func (u *TargettedUi) Message(message string) {
|
||||
func (u *TargetedUI) Message(message string) {
|
||||
u.Ui.Message(u.prefixLines(false, message))
|
||||
}
|
||||
|
||||
func (u *TargettedUi) Error(message string) {
|
||||
func (u *TargetedUI) Error(message string) {
|
||||
u.Ui.Error(u.prefixLines(true, message))
|
||||
}
|
||||
|
||||
func (u *TargettedUi) Machine(t string, args ...string) {
|
||||
func (u *TargetedUI) Machine(t string, args ...string) {
|
||||
// Prefix in the target, then pass through
|
||||
u.Ui.Machine(fmt.Sprintf("%s,%s", u.Target, t), args...)
|
||||
}
|
||||
|
||||
func (u *TargettedUi) prefixLines(arrow bool, message string) string {
|
||||
func (u *TargetedUI) prefixLines(arrow bool, message string) string {
|
||||
arrowText := "==>"
|
||||
if !arrow {
|
||||
arrowText = strings.Repeat(" ", len(arrowText))
|
||||
|
||||
+5
-5
@@ -97,9 +97,9 @@ func TestColoredUi_noColorEnv(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTargettedUi(t *testing.T) {
|
||||
func TestTargetedUI(t *testing.T) {
|
||||
bufferUi := testUi()
|
||||
targettedUi := &TargettedUi{
|
||||
targettedUi := &TargetedUI{
|
||||
Target: "foo",
|
||||
Ui: bufferUi,
|
||||
}
|
||||
@@ -142,11 +142,11 @@ func TestColoredUi_ImplUi(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTargettedUi_ImplUi(t *testing.T) {
|
||||
func TestTargetedUI_ImplUi(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = &TargettedUi{}
|
||||
raw = &TargetedUI{}
|
||||
if _, ok := raw.(Ui); !ok {
|
||||
t.Fatalf("TargettedUi must implement Ui")
|
||||
t.Fatalf("TargetedUI must implement Ui")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ type Config struct {
|
||||
Name string `mapstructure:"ami_name"`
|
||||
Description string `mapstructure:"ami_description"`
|
||||
Users []string `mapstructure:"ami_users"`
|
||||
Groups []string `mapstrcuture:"ami_groups"`
|
||||
Groups []string `mapstructure:"ami_groups"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
@@ -42,7 +42,7 @@ type PostProcessor struct {
|
||||
config Config
|
||||
}
|
||||
|
||||
// Entry point for configuration parisng when we've defined
|
||||
// Entry point for configuration parsing when we've defined
|
||||
func (p *PostProcessor) Configure(raws ...interface{}) error {
|
||||
p.config.ctx.Funcs = awscommon.TemplateFuncs
|
||||
err := config.Decode(&p.config, &config.DecodeOpts{
|
||||
@@ -74,7 +74,7 @@ func (p *PostProcessor) Configure(raws ...interface{}) error {
|
||||
// Check we have AWS access variables defined somewhere
|
||||
errs = packer.MultiErrorAppend(errs, p.config.AccessConfig.Prepare(&p.config.ctx)...)
|
||||
|
||||
// define all our required paramaters
|
||||
// define all our required parameters
|
||||
templates := map[string]*string{
|
||||
"s3_bucket_name": &p.config.S3Bucket,
|
||||
}
|
||||
@@ -178,7 +178,7 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac
|
||||
|
||||
ui.Message(fmt.Sprintf("Started import of s3://%s/%s, task id %s", p.config.S3Bucket, p.config.S3Key, *import_start.ImportTaskId))
|
||||
|
||||
// Wait for import process to complete, this takess a while
|
||||
// Wait for import process to complete, this takes a while
|
||||
ui.Message(fmt.Sprintf("Waiting for task %s to complete (may take a while)", *import_start.ImportTaskId))
|
||||
|
||||
stateChange := awscommon.StateChangeConf{
|
||||
@@ -239,7 +239,7 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac
|
||||
return nil, false, fmt.Errorf("Error waiting for AMI (%s): %s", *resp.ImageId, err)
|
||||
}
|
||||
|
||||
ec2conn.DeregisterImage(&ec2.DeregisterImageInput{
|
||||
_, err = ec2conn.DeregisterImage(&ec2.DeregisterImageInput{
|
||||
ImageId: &createdami,
|
||||
})
|
||||
|
||||
@@ -307,7 +307,7 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac
|
||||
|
||||
}
|
||||
|
||||
// Apply atttributes for AMI specified in config
|
||||
// Apply attributes for AMI specified in config
|
||||
// (duped from builder/amazon/common/step_modify_ami_attributes.go)
|
||||
options := make(map[string]*ec2.ModifyImageAttributeInput)
|
||||
if p.config.Description != "" {
|
||||
|
||||
@@ -8,8 +8,7 @@ import (
|
||||
const BuilderId = "packer.post-processor.compress"
|
||||
|
||||
type Artifact struct {
|
||||
Path string
|
||||
files []string
|
||||
Path string
|
||||
}
|
||||
|
||||
func (a *Artifact) BuilderId() string {
|
||||
|
||||
@@ -54,7 +54,7 @@ func (s *stepUpload) Run(state multistep.StateBag) multistep.StepAction {
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
ui.Message("Box succesfully uploaded")
|
||||
ui.Message("Box successfully uploaded")
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
@@ -2,10 +2,11 @@ package vagrantcloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
type stepVerifyUpload struct {
|
||||
@@ -88,8 +89,8 @@ func (s *stepVerifyUpload) Run(state multistep.StateBag) multistep.StepAction {
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
ui.Message(fmt.Sprintf("Upload succesfully verified with token %s", providerCheck.HostedToken))
|
||||
log.Printf("Box succesfully verified %s == %s", upload.Token, providerCheck.HostedToken)
|
||||
ui.Message(fmt.Sprintf("Upload successfully verified with token %s", providerCheck.HostedToken))
|
||||
log.Printf("Box successfully verified %s == %s", upload.Token, providerCheck.HostedToken)
|
||||
|
||||
return multistep.ActionContinue
|
||||
case <-time.After(600 * time.Second):
|
||||
|
||||
@@ -31,7 +31,7 @@ func TestAWSProvider_ArtifactId(t *testing.T) {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
result := `aws.region_config "us-east-1", ami: "ami-1234"`
|
||||
if strings.Index(vagrantfile, result) == -1 {
|
||||
if !strings.Contains(vagrantfile, result) {
|
||||
t.Fatalf("wrong substitution: %s", vagrantfile)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ func TestDigitalOceanProvider_ArtifactId(t *testing.T) {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
image := `digital_ocean.image = "42"`
|
||||
if strings.Index(vagrantfile, image) == -1 {
|
||||
if !strings.Contains(vagrantfile, image) {
|
||||
t.Fatalf("wrong image substitution: %s", vagrantfile)
|
||||
}
|
||||
region := `digital_ocean.region = "San Francisco"`
|
||||
if strings.Index(vagrantfile, region) == -1 {
|
||||
if !strings.Contains(vagrantfile, region) {
|
||||
t.Fatalf("wrong region substitution: %s", vagrantfile)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,8 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||
func (p *Provisioner) getVersion() error {
|
||||
out, err := exec.Command(p.config.Command, "--version").Output()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf(
|
||||
"Error running \"%s --version\": %s", p.config.Command, err.Error())
|
||||
}
|
||||
|
||||
versionRe := regexp.MustCompile(`\w (\d+\.\d+[.\d+]*)`)
|
||||
@@ -354,7 +355,9 @@ func (p *Provisioner) executeAnsible(ui packer.Ui, comm packer.Communicator, pri
|
||||
go repeat(stderr)
|
||||
|
||||
log.Printf("Executing Ansible: %s", strings.Join(cmd.Args, " "))
|
||||
cmd.Start()
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
wg.Wait()
|
||||
err = cmd.Wait()
|
||||
if err != nil {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/mitchellh/packer/packer"
|
||||
@@ -258,6 +259,18 @@ func TestAnsibleGetVersion(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnsibleGetVersionError(t *testing.T) {
|
||||
var p Provisioner
|
||||
p.config.Command = "./test-fixtures/exit1"
|
||||
err := p.getVersion()
|
||||
if err == nil {
|
||||
t.Fatal("Should return error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "./test-fixtures/exit1 --version") {
|
||||
t.Fatal("Error message should include command name")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnsibleLongMessages(t *testing.T) {
|
||||
if os.Getenv("PACKER_ACC") == "" {
|
||||
t.Skip("This test is only run with PACKER_ACC=1 and it requires Ansible to be installed")
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user