Compare commits

...

106 Commits

Author SHA1 Message Date
Matthew Hooker e3d65a193e Cut version 1.0.0 2017-04-04 13:05:41 -07:00
Matthew Hooker 8ea8ff683d prepare for version 1.0.0 2017-04-04 12:42:25 -07:00
Matthew Hooker 41203ddc3d Merge pull request #4759 from mitchellh/comcore
call out community vs core plugins
2017-04-04 12:38:09 -07:00
Matthew Hooker 416330bd9e Merge pull request #4758 from mitchellh/fix4680
provisioner/ansible-local: document staging dir
2017-04-04 12:02:44 -07:00
Matthew Hooker 9209a60b30 Merge pull request #4757 from mitchellh/fix4756
link to other downloads, not necessarily older.
2017-04-04 11:23:55 -07:00
Matthew Hooker 21321d2695 update changelog 2017-04-04 10:36:55 -07:00
Matthew Hooker 2be5ce2f16 Merge pull request #4752 from mitchellh/fix-4007
add sleep and retry to azure setup script
2017-04-04 10:35:27 -07:00
Matthew Hooker fec5cb3b86 update changelog 2017-04-03 11:26:54 -07:00
Matthew Hooker a242014aa9 Merge pull request #4749 from rickard-von-essen/issue-4608
builder/googlecompute: Revert to using default service account
2017-04-03 11:24:50 -07:00
Matthew Hooker 974a2fe96f Cut version 1.0.0-rc3 2017-03-30 18:01:25 -07:00
Matthew Hooker 9f6b6a0267 better version numbers 2017-03-30 17:48:46 -07:00
Matthew Hooker e5474e52d0 v1.0.0rc3 changelog 2017-03-30 17:48:10 -07:00
Andy Bulford ea4a7802d9 Fix a couple of typos 2017-03-30 10:29:42 -07:00
Matthew Hooker e38b3508d3 next version is rc3 2017-03-30 02:22:49 -07:00
Matthew Hooker 4731f480e3 communicator/ssh: don't return error if we can't close connection. 2017-03-30 02:17:35 -07:00
Matthew Hooker a8d0211edd fix version 2017-03-30 01:30:32 -07:00
Matthew Hooker 7866d7df14 Cut version 1.0.0-rc2 2017-03-29 17:55:49 -07:00
Matthew Hooker 6169a7c07f prepare rc2 2017-03-29 17:51:35 -07:00
Matthew Hooker a129d539d4 update rc2 changelog 2017-03-29 17:48:43 -07:00
Matthew Hooker 8a214a9dbe update changelog for 1.0rc1 2017-03-29 17:34:42 -07:00
Matthew Hooker b2775b0ca3 more fixes from errcheck 2017-03-29 17:34:42 -07:00
Matthew Hooker 1ea6b439e9 s/TargettedUi/TargetedUI/ 2017-03-29 17:34:41 -07:00
Matthew Hooker f91f24f164 s/non existent/nonexistent/ 2017-03-29 17:34:41 -07:00
Matthew Hooker 27b5b276b0 simplify 2017-03-29 17:34:41 -07:00
Matthew Hooker 9131c8cea8 check for a couple errors 2017-03-29 17:34:40 -07:00
Matthew Hooker 793c42d6a2 remove unnecessary type conversions 2017-03-29 17:34:40 -07:00
Matthew Hooker 9962fd486b automagic simplification 2017-03-29 17:34:39 -07:00
Matthew Hooker 1392f4dd09 simplify some code 2017-03-29 17:34:39 -07:00
Matthew Hooker 81472bdbab Print instead of Printf with no dynamic first variable. 2017-03-29 17:34:38 -07:00
Matthew Hooker 9b8ab21c15 remove a bunch of dead code.
https://github.com/dominikh/go-tools/tree/master/cmd/unused
2017-03-29 17:34:38 -07:00
Matthew Hooker 5781c27fef spell fixes 2017-03-29 17:34:38 -07:00
Sean Malloy bb153b519e Fix link to GitHub project page on website 2017-03-29 17:34:37 -07:00
Howard Nguyen f985522e7c Removed merge conflict from Docker example web page 2017-03-29 17:34:37 -07:00
Matthew Hooker 1f30646cab fix typo 2017-03-29 17:34:36 -07:00
Seth Vargo 6bebcd89f5 Fix broken links 2017-03-29 17:34:36 -07:00
Seth Vargo f1b5a78737 Update config styles 2017-03-29 17:34:35 -07:00
Seth Vargo b1b95fbf3a Update styles 2017-03-29 17:34:35 -07:00
Jason Costello 30792f5638 $black headlines 2017-03-29 17:34:35 -07:00
Jason Costello 36608e5f9b Bring my changes over to this branch 2017-03-29 17:34:34 -07:00
Jason Costello 8a80a735e7 Update middleman-hashicorp to 3.22 2017-03-29 17:34:34 -07:00
Seth Vargo 6d884c171f New container 2017-03-29 17:34:33 -07:00
Seth Vargo 06d5fbadc4 Update CSS breakpoints 2017-03-29 17:34:33 -07:00
Seth Vargo 8b30c230ac Revamp pages and docs to fit HashiCorp brand 2017-03-29 17:34:30 -07:00
Rickard von Essen a8e864ac25 builder/googlecompute: Added Windows example to the docs.
Closes: #4713
2017-03-29 17:32:05 -07:00
Matthew Hooker d4d655503d update cli library 2017-03-29 17:32:04 -07:00
Matthew Hooker 05cb1cf012 remove windows smart quotes 2017-03-29 17:32:04 -07:00
Matthew Hooker e42127d305 website/docs: fix typo 2017-03-29 17:32:04 -07:00
Matthew Hooker 4c351d0ad9 website/docs: add note about systemd and amazon-chroot. 2017-03-29 17:32:03 -07:00
Matthew Hooker a05546e93c update changelog 2017-03-29 17:32:03 -07:00
Matthew Hooker 5807847cc4 document skipping copy_files 2017-03-29 17:32:02 -07:00
Matthew Hooker 3e9cf70fc9 builder/amazon-chroot: nullable copy_files
Allow users to specify that they don't want any
files copied into the chroot by setting an empty
copy_files list
2017-03-29 17:32:02 -07:00
Matthew Hooker 0fb55177e4 fix typo 2017-03-29 17:32:01 -07:00
Matthew Hooker 7e98343b8f update changelog 2017-03-29 17:32:01 -07:00
Matthew Hooker 77d20776a9 builder/virtualbox: retry removing floppy controller 2017-03-29 17:32:01 -07:00
Matthew Hooker 67a81afac4 update changelog 2017-03-29 17:32:00 -07:00
Matthew Hooker 669dcae766 builder/amazon: report tag creation 2017-03-29 17:32:00 -07:00
Matthew Hooker 09a32d4793 update readme with supported providers 2017-03-29 17:31:59 -07:00
Matthew Hooker fcc53d3639 update changelog 2017-03-29 17:31:59 -07:00
Andrey Chernih 816eebe516 More verbose error message when ansible-playbook fails
I've spent 1 hour today debugging why packer does not want to work with
ansible. It turns out `ansible-playbook` command was returning non-zero
exit status because of the file system permission problem.

Output before change:

    % packer build rabbitmq.json
    amazon-ebs output will be in this color.

    1 error(s) occurred:

    * exit status 1

Output after change:

    amazon-ebs output will be in this color.

    1 error(s) occurred:

    * Error running "ansible-playbook --version": exit status 1
2017-03-29 17:31:59 -07:00
Matthew Hooker 20a6ad651a update changelog 2017-03-29 17:31:58 -07:00
Matthew Hooker de3e2312c8 builder/hyper-v don't wait for shutdown to return.
Mirrors work done in #4436
2017-03-29 17:31:58 -07:00
Matthew Hooker 01ae8c728d update changelog 2017-03-29 17:31:57 -07:00
Matthew Hooker af3163d6cb communicator/ssh: fix nil ptr error
fixes a case where we could return a nil error and nil ssh session.
2017-03-29 17:31:57 -07:00
Matthew Hooker d14004eaf2 fix example json 2017-03-29 17:31:56 -07:00
hfinucane 85b5b00b9a Fix example
`device_setup_commands` appears to no longer be a real name.
2017-03-29 17:31:56 -07:00
Matthew Hooker 648590ba25 correct 0.12.3 changelog
cf #4680
2017-03-29 17:31:56 -07:00
Matthew Hooker eeeb09579f update changelog 2017-03-29 17:31:55 -07:00
Matthew Hooker da145b960b builder/virtualbox: allow skipping upload of version file 2017-03-29 17:31:55 -07:00
Matthew Hooker 0216debe72 next version is 1.1.0 2017-03-29 17:31:54 -07:00
Matthew Hooker e0eecb6829 fix version 2017-03-29 17:31:54 -07:00
Matthew Hooker e6c8c547b2 display version correctly 2017-03-29 17:31:54 -07:00
Matthew Hooker 43dec47de8 update github.com/mitchellh/multistep 2017-03-29 17:31:53 -07:00
Matthew Hooker 080a296e3a WIP fix #4670 2017-03-29 17:31:53 -07:00
Matthew Hooker 3a75f04c12 update changelog for 1.1 2017-03-29 17:31:52 -07:00
Matthew Hooker e264c8aebb fix indentation 2017-03-29 17:31:52 -07:00
Rickard von Essen ace3f2c04a amazon-chroot: Fixed indentation 2017-03-29 17:31:51 -07:00
Matthew Hooker c4d8cfc090 builder/amazon: validate ssh key name/file
When using ssh_key_name, ssh_private_key file must be given,
or ssh_agent_auth enabled.

When automatically retrieving the winrm password, if ssh_key_name is
given, ssh_private_key_file must also be given.
2017-03-29 17:31:51 -07:00
Anton Kvashenkin be324ac0d9 README: update packer website url with HTTPS 2017-03-29 17:31:51 -07:00
Matthew Hooker 2f936cd6b7 communicator/winrm: make directory upload behave more like scp
changes behavior to be in-line with the docs.
Resolves #3562
2017-03-29 17:31:50 -07:00
Matthew Hooker 22cdc76644 website/docs: fix file upload tar script 2017-03-29 17:31:50 -07:00
Matthew Hooker b8429a2e58 website/docs: make file provisioner reqs clearer
Make extra clear the file provisioner needs destination directory to exist.
2017-03-29 17:31:49 -07:00
Matthew Hooker b2356bfe7a website/docs: note docker behavior in file provisioner 2017-03-29 17:31:49 -07:00
Matthew Hooker e67994b174 builder/amazon: set force_deregister to true on -force 2017-03-29 17:31:48 -07:00
Matthew Hooker 7f608fd0d7 website/docs: atlas token not required 2017-03-29 17:31:48 -07:00
Matthew Hooker 2c1740ab3c builder/hyper-v: validate output dir in step, not in config
essentially same work as #2233
2017-03-29 17:31:48 -07:00
Tadas Medisauskas f851475df8 Add support for Hyper-V admins security group 2017-03-29 17:31:47 -07:00
Jack Pearkes 7f679001c8 website: update middleman-hashicorp to 0.3.13 2017-03-29 17:31:47 -07:00
Seth Vargo 6fcf5a3223 Add bootstrap 2017-03-29 17:31:46 -07:00
Jason Costello 1d4e3228f8 Make containers non-fluid for header and footer 2017-03-29 17:31:46 -07:00
Jason Costello a8dec623a1 Remove "by hashicorp" 2017-03-29 17:31:45 -07:00
Jason Costello 876df8ed0f For real 2017-03-29 17:31:45 -07:00
Jason Costello 8cea6b69d9 Add meganav tag 2017-03-29 17:31:45 -07:00
Jason Costello a819b04140 Remove p img width: 100% 2017-03-29 17:31:44 -07:00
Jason Costello 5d797565c1 Add mega nav 2017-03-29 17:31:44 -07:00
Rickard von Essen dbe08e5f18 googlecompute: Added missing disk_name option to docs. 2017-03-29 17:31:43 -07:00
Rickard von Essen b5a27c23fe googlecompute: Correct values for on_host_maintenance
If preemptible is true then on_host_maintenance must be TERMINATE.

Also corrected order in docs.

Closes #4620
2017-03-29 17:31:43 -07:00
Seth Vargo 2a7eef5737 Update license 2017-03-29 17:31:43 -07:00
Seth Vargo 7ce2b7cf9f Update license 2017-03-29 17:31:42 -07:00
Seth Vargo 1ea024a38e Add website license 2017-03-29 17:31:42 -07:00
Seth Vargo b6d0f08162 Update website 2017-03-29 17:31:41 -07:00
Seth Vargo c243b9a713 Delete config.ru 2017-03-29 17:31:41 -07:00
Seth Vargo 9d872dda56 Update middleman-hashicorp 2017-03-29 17:31:40 -07:00
Rickard von Essen 408a15fe13 amazon: Step Region Copy crashing on device mapping
Closes #4635
2017-03-29 17:31:40 -07:00
Matthew Hooker 3767fe41f1 the digitalocean ubuntu user is root 2017-03-29 17:31:40 -07:00
Matthew Hooker edc3f8f39b docs/qemu: reformat 2017-03-29 17:31:39 -07:00
Michael Ledin 116b7c738e Add floppy size limitation notice.
Should help people dealing with #4570 and #3328 because packer copies
`floppy_files` to floppy without any error even if they exceed 1.44 MB
limit. `floppy_dirs`throws error about FAT size limit exceeded but
without mentioning that real issue is the floppy size limit:
```
Build 'qemu' errored: Error adding path virtio_iso to floppy: FAT FULL
```
2017-03-29 17:31:39 -07:00
341 changed files with 6933 additions and 7810 deletions
+56 -3
View File
@@ -1,7 +1,62 @@
## (Unreleased)
## 1.0.0 (April 4, 2017)
### BUG FIXES:
* builder/googlecompute: Use "default" service account. [GH-4749]
### IMPROVEMENTS:
* More diligently try to complete azure-setup.sh. [GH-4752]
## 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 +73,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 +86,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]
+7 -2
View File
@@ -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.
+10 -6
View File
@@ -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 == "" {
+32 -1
View File
@@ -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.")
}
}
+4 -1
View File
@@ -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 {
+1 -1
View File
@@ -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 {
+3 -3
View File
@@ -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 {
+3 -3
View File
@@ -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
}
+1 -1
View File
@@ -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
}
+1 -4
View File
@@ -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) {
+8
View File
@@ -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"))
}
+1 -1
View File
@@ -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)
}
}
+9 -2
View File
@@ -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),
+1 -1
View File
@@ -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())
}
}
}
+1 -1
View File
@@ -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,
+4
View File
@@ -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)...)
+2 -2
View File
@@ -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
+4
View File
@@ -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 {
+4
View File
@@ -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"
}
+5 -6
View File
@@ -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 {
+1 -1
View File
@@ -18,5 +18,5 @@ func GlueStrings(a, b string) string {
shift++
}
return string(a[:shift]) + b
return a[:shift] + b
}
+3 -3
View File
@@ -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 {
+3 -3
View File
@@ -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:
+1 -1
View File
@@ -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)
}
}
-17
View File
@@ -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"`
+1 -1
View File
@@ -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 -2
View File
@@ -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,
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -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)
+12 -8
View File
@@ -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
+18 -19
View File
@@ -58,25 +58,24 @@ type Driver interface {
}
type InstanceConfig struct {
Address string
Description string
DiskSizeGb int64
DiskType string
Image *Image
MachineType string
Metadata map[string]string
Name string
Network string
NetworkProjectId string
OmitExternalIP bool
OnHostMaintenance string
Preemptible bool
Region string
Scopes []string
ServiceAccountEmail string
Subnetwork string
Tags []string
Zone string
Address string
Description string
DiskSizeGb int64
DiskType string
Image *Image
MachineType string
Metadata map[string]string
Name string
Network string
NetworkProjectId string
OmitExternalIP bool
OnHostMaintenance string
Preemptible bool
Region string
Scopes []string
Subnetwork string
Tags []string
Zone string
}
// WindowsPasswordConfig is the data structue that GCE needs to encrypt the created
+1 -1
View File
@@ -391,7 +391,7 @@ func (d *driverGCE) RunInstance(c *InstanceConfig) (<-chan error, error) {
},
ServiceAccounts: []*compute.ServiceAccount{
{
Email: c.ServiceAccountEmail,
Email: "default",
Scopes: c.Scopes,
},
},
+18 -19
View File
@@ -99,25 +99,24 @@ func (s *StepCreateInstance) Run(state multistep.StateBag) multistep.StepAction
var metadata map[string]string
metadata, err = c.createInstanceMetadata(sourceImage, sshPublicKey)
errCh, err = d.RunInstance(&InstanceConfig{
Address: c.Address,
Description: "New instance created by Packer",
DiskSizeGb: c.DiskSizeGb,
DiskType: c.DiskType,
Image: sourceImage,
MachineType: c.MachineType,
Metadata: metadata,
Name: name,
Network: c.Network,
NetworkProjectId: c.NetworkProjectId,
OmitExternalIP: c.OmitExternalIP,
OnHostMaintenance: c.OnHostMaintenance,
Preemptible: c.Preemptible,
Region: c.Region,
ServiceAccountEmail: c.Account.ClientEmail,
Scopes: c.Scopes,
Subnetwork: c.Subnetwork,
Tags: c.Tags,
Zone: c.Zone,
Address: c.Address,
Description: "New instance created by Packer",
DiskSizeGb: c.DiskSizeGb,
DiskType: c.DiskType,
Image: sourceImage,
MachineType: c.MachineType,
Metadata: metadata,
Name: name,
Network: c.Network,
NetworkProjectId: c.NetworkProjectId,
OmitExternalIP: c.OmitExternalIP,
OnHostMaintenance: c.OnHostMaintenance,
Preemptible: c.Preemptible,
Region: c.Region,
Scopes: c.Scopes,
Subnetwork: c.Subnetwork,
Tags: c.Tags,
Zone: c.Zone,
})
if err == nil {
@@ -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.
+20 -8
View File
@@ -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 -10
View File
@@ -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
}
+4 -3
View File
@@ -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")
}
}
+4 -3
View File
@@ -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
+19 -1
View File
@@ -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 {
+6 -11
View File
@@ -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 {
+4 -3
View File
@@ -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)
+1 -1
View File
@@ -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 {
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -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 {
+20 -13
View File
@@ -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
}
+6 -11
View File
@@ -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
+2 -2
View File
@@ -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 {
+4 -3
View File
@@ -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 {
-43
View File
@@ -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) {}
+1 -1
View File
@@ -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
}
+1 -1
View File
@@ -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
+3 -2
View File
@@ -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)
}
}
+1 -1
View File
@@ -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,
+2 -2
View File
@@ -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 {
+1 -1
View File
@@ -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,
+2 -2
View File
@@ -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 {
+2 -2
View File
@@ -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 {
-52
View File
@@ -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
}
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+2 -2
View File
@@ -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)
+8
View File
@@ -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)
+37 -37
View File
@@ -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($_)
}
+1 -1
View File
@@ -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
View File
@@ -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 {
+1 -1
View File
@@ -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)
+7 -6
View File
@@ -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))
+7 -18
View File
@@ -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 {
+3 -2
View File
@@ -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
View File
@@ -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 {
+1 -6
View File
@@ -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 {
+201 -179
View File
@@ -12,234 +12,256 @@ azure_tenant_id= # Derived from the account after login
location=
azure_object_id=
azureversion=
create_sleep=10
showhelp() {
echo "azure-setup"
echo ""
echo " azure-setup helps you generate packer credentials for Azure"
echo ""
echo " The script creates a resource group, storage account, application"
echo " (client), service principal, and permissions and displays a snippet"
echo " for use in your packer templates."
echo ""
echo " For simplicity we make a lot of assumptions and choose reasonable"
echo " defaults. If you want more control over what happens, please use"
echo " the azure-cli directly."
echo ""
echo " Note that you must already have an Azure account, username,"
echo " password, and subscription. You can create those here:"
echo ""
echo " - https://account.windowsazure.com/"
echo ""
echo "REQUIREMENTS"
echo ""
echo " - azure-cli"
echo " - jq"
echo ""
echo " Use the requirements command (below) for more info."
echo ""
echo "USAGE"
echo ""
echo " ./azure-setup.sh requirements"
echo " ./azure-setup.sh setup"
echo ""
echo "azure-setup"
echo ""
echo " azure-setup helps you generate packer credentials for Azure"
echo ""
echo " The script creates a resource group, storage account, application"
echo " (client), service principal, and permissions and displays a snippet"
echo " for use in your packer templates."
echo ""
echo " For simplicity we make a lot of assumptions and choose reasonable"
echo " defaults. If you want more control over what happens, please use"
echo " the azure-cli directly."
echo ""
echo " Note that you must already have an Azure account, username,"
echo " password, and subscription. You can create those here:"
echo ""
echo " - https://account.windowsazure.com/"
echo ""
echo "REQUIREMENTS"
echo ""
echo " - azure-cli"
echo " - jq"
echo ""
echo " Use the requirements command (below) for more info."
echo ""
echo "USAGE"
echo ""
echo " ./azure-setup.sh requirements"
echo " ./azure-setup.sh setup"
echo ""
}
requirements() {
found=0
found=0
azureversion=$(azure -v)
if [ $? -eq 0 ]; then
found=$((found + 1))
echo "Found azure-cli version: $azureversion"
else
echo "azure-cli is missing. Please install azure-cli from"
echo "https://azure.microsoft.com/en-us/documentation/articles/xplat-cli-install/"
fi
azureversion=$(azure -v)
if [ $? -eq 0 ]; then
found=$((found + 1))
echo "Found azure-cli version: $azureversion"
else
echo "azure-cli is missing. Please install azure-cli from"
echo "https://azure.microsoft.com/en-us/documentation/articles/xplat-cli-install/"
fi
jqversion=$(jq --version)
if [ $? -eq 0 ]; then
found=$((found + 1))
echo "Found jq version: $jqversion"
else
echo "jq is missing. Please install jq from"
echo "https://stedolan.github.io/jq/"
fi
jqversion=$(jq --version)
if [ $? -eq 0 ]; then
found=$((found + 1))
echo "Found jq version: $jqversion"
else
echo "jq is missing. Please install jq from"
echo "https://stedolan.github.io/jq/"
fi
if [ $found -lt 2 ]; then
exit 1
fi
if [ $found -lt 2 ]; then
exit 1
fi
}
askSubscription() {
azure account list
echo ""
echo "Please enter the Id of the account you wish to use. If you do not see"
echo "a valid account in the list press Ctrl+C to abort and create one."
echo "If you leave this blank we will use the Current account."
echo -n "> "
read azure_subscription_id
if [ "$azure_subscription_id" != "" ]; then
azure account set $azure_subscription_id
else
azure_subscription_id=$(azure account show --json | jq -r .[].id)
fi
azure_tenant_id=$(azure account show --json | jq -r .[].tenantId)
echo "Using subscription_id: $azure_subscription_id"
echo "Using tenant_id: $azure_tenant_id"
azure account list
echo ""
echo "Please enter the Id of the account you wish to use. If you do not see"
echo "a valid account in the list press Ctrl+C to abort and create one."
echo "If you leave this blank we will use the Current account."
echo -n "> "
read azure_subscription_id
if [ "$azure_subscription_id" != "" ]; then
azure account set $azure_subscription_id
else
azure_subscription_id=$(azure account show --json | jq -r .[].id)
fi
azure_tenant_id=$(azure account show --json | jq -r .[].tenantId)
echo "Using subscription_id: $azure_subscription_id"
echo "Using tenant_id: $azure_tenant_id"
}
askName() {
echo ""
echo "Choose a name for your resource group, storage account and client"
echo "client. This is arbitrary, but it must not already be in use by"
echo "any of those resources. ALPHANUMERIC ONLY. Ex: mypackerbuild"
echo -n "> "
read meta_name
echo ""
echo "Choose a name for your resource group, storage account and client"
echo "client. This is arbitrary, but it must not already be in use by"
echo "any of those resources. ALPHANUMERIC ONLY. Ex: mypackerbuild"
echo -n "> "
read meta_name
}
askSecret() {
echo ""
echo "Enter a secret for your application. We recommend generating one with"
echo "openssl rand -base64 24. If you leave this blank we will attempt to"
echo "generate one for you using openssl. THIS WILL BE SHOWN IN PLAINTEXT."
echo "Ex: mypackersecret8734"
echo -n "> "
read azure_client_secret
if [ "$azure_client_secret" = "" ]; then
azure_client_secret=$(openssl rand -base64 24)
if [ $? -ne 0 ]; then
echo "Error generating secret"
exit 1
fi
echo "Generated client_secret: $azure_client_secret"
fi
echo ""
echo "Enter a secret for your application. We recommend generating one with"
echo "openssl rand -base64 24. If you leave this blank we will attempt to"
echo "generate one for you using openssl. THIS WILL BE SHOWN IN PLAINTEXT."
echo "Ex: mypackersecret8734"
echo -n "> "
read azure_client_secret
if [ "$azure_client_secret" = "" ]; then
azure_client_secret=$(openssl rand -base64 24)
if [ $? -ne 0 ]; then
echo "Error generating secret"
exit 1
fi
echo "Generated client_secret: $azure_client_secret"
fi
}
askLocation() {
azure location list
echo ""
echo "Choose which region your resource group and storage account will be created."
echo -n "> "
read location
azure location list
echo ""
echo "Choose which region your resource group and storage account will be created."
echo -n "> "
read location
}
createResourceGroup() {
echo "==> Creating resource group"
azure group create -n $meta_name -l $location
if [ $? -eq 0 ]; then
azure_group_name=$meta_name
else
echo "Error creating resource group: $meta_name"
exit 1
fi
echo "==> Creating resource group"
azure group create -n $meta_name -l $location
if [ $? -eq 0 ]; then
azure_group_name=$meta_name
else
echo "Error creating resource group: $meta_name"
return 1
fi
}
createStorageAccount() {
echo "==> Creating storage account"
azure storage account create -g $meta_name -l $location --sku-name LRS --kind Storage $meta_name
if [ $? -eq 0 ]; then
azure_storage_name=$meta_name
else
echo "Error creating storage account: $meta_name"
exit 1
fi
echo "==> Creating storage account"
azure storage account create -g $meta_name -l $location --sku-name LRS --kind Storage $meta_name
if [ $? -eq 0 ]; then
azure_storage_name=$meta_name
else
echo "Error creating storage account: $meta_name"
return 1
fi
}
createApplication() {
echo "==> Creating application"
azure_client_id=$(azure ad app create -n $meta_name -i http://$meta_name --home-page http://$meta_name -p $azure_client_secret --json | jq -r .appId)
if [ $? -ne 0 ]; then
echo "Error creating application: $meta_name @ http://$meta_name"
exit 1
fi
echo "==> Creating application"
azure_client_id=$(azure ad app create -n $meta_name -i http://$meta_name --home-page http://$meta_name -p $azure_client_secret --json | jq -r .appId)
if [ $? -ne 0 ]; then
echo "Error creating application: $meta_name @ http://$meta_name"
return 1
fi
}
createServicePrincipal() {
echo "==> Creating service principal"
# Azure CLI 0.10.2 introduced a breaking change, where appId must be supplied with the -a switch
# prior version accepted appId as the only parameter without a switch
newer_syntax=false
IFS='.' read -ra azureversionsemver <<< "$azureversion"
if [ ${azureversionsemver[0]} -ge 0 ] && [ ${azureversionsemver[1]} -ge 10 ] && [ ${azureversionsemver[2]} -ge 2 ]; then
newer_syntax=true
fi
echo "==> Creating service principal"
# Azure CLI 0.10.2 introduced a breaking change, where appId must be supplied with the -a switch
# prior version accepted appId as the only parameter without a switch
newer_syntax=false
IFS='.' read -ra azureversionsemver <<< "$azureversion"
if [ ${azureversionsemver[0]} -ge 0 ] && [ ${azureversionsemver[1]} -ge 10 ] && [ ${azureversionsemver[2]} -ge 2 ]; then
newer_syntax=true
fi
if [ "${newer_syntax}" = true ]; then
azure_object_id=$(azure ad sp create -a $azure_client_id --json | jq -r .objectId)
else
azure_object_id=$(azure ad sp create $azure_client_id --json | jq -r .objectId)
fi
if [ "${newer_syntax}" = true ]; then
azure_object_id=$(azure ad sp create -a $azure_client_id --json | jq -r .objectId)
else
azure_object_id=$(azure ad sp create $azure_client_id --json | jq -r .objectId)
fi
if [ $? -ne 0 ]; then
echo "Error creating service principal: $azure_client_id"
exit 1
fi
if [ $? -ne 0 ]; then
echo "Error creating service principal: $azure_client_id"
return 1
fi
}
createPermissions() {
echo "==> Creating permissions"
azure role assignment create --objectId $azure_object_id -o "Owner" -c /subscriptions/$azure_subscription_id
# We want to use this more conservative scope but it does not work with the
# current implementation which uses temporary resource groups
# azure role assignment create --spn http://$meta_name -g $azure_group_name -o "API Management Service Contributor"
if [ $? -ne 0 ]; then
echo "Error creating permissions for: http://$meta_name"
exit 1
fi
echo "==> Creating permissions"
azure role assignment create --objectId $azure_object_id -o "Owner" -c /subscriptions/$azure_subscription_id
# We want to use this more conservative scope but it does not work with the
# current implementation which uses temporary resource groups
# azure role assignment create --spn http://$meta_name -g $azure_group_name -o "API Management Service Contributor"
if [ $? -ne 0 ]; then
echo "Error creating permissions for: http://$meta_name"
return 1
fi
}
showConfigs() {
echo ""
echo "Use the following configuration for your packer template:"
echo ""
echo "{"
echo " \"client_id\": \"$azure_client_id\","
echo " \"client_secret\": \"$azure_client_secret\","
echo " \"object_id\": \"$azure_object_id\","
echo " \"subscription_id\": \"$azure_subscription_id\","
echo " \"tenant_id\": \"$azure_tenant_id\","
echo " \"resource_group_name\": \"$azure_group_name\","
echo " \"storage_account\": \"$azure_storage_name\","
echo "}"
echo ""
echo ""
echo "Use the following configuration for your packer template:"
echo ""
echo "{"
echo " \"client_id\": \"$azure_client_id\","
echo " \"client_secret\": \"$azure_client_secret\","
echo " \"object_id\": \"$azure_object_id\","
echo " \"subscription_id\": \"$azure_subscription_id\","
echo " \"tenant_id\": \"$azure_tenant_id\","
echo " \"resource_group_name\": \"$azure_group_name\","
echo " \"storage_account\": \"$azure_storage_name\","
echo "}"
echo ""
}
doSleep() {
local sleep_time=${PACKER_SLEEP_TIME-$create_sleep}
echo ""
echo "Sleeping for ${sleep_time} seconds to wait for resources to be "
echo "created. If you get an error about a resource not existing, you can "
echo "try increasing the amount of time we wait after creating resources "
echo "by setting PACKER_SLEEP_TIME to something higher than the default."
echo ""
sleep $sleep_time
}
retryable() {
n=0
until [ $n -ge $1 ]
do
$2 && return 0
echo "$2 failed. Retrying..."
n=$[$n+1]
doSleep
done
echo "$2 failed after $1 tries. Exiting."
exit 1
}
setup() {
requirements
requirements
azure config mode arm
azure login
azure config mode arm
azure login
askSubscription
askName
askSecret
askLocation
askSubscription
askName
askSecret
askLocation
# Some of the resources take a while to converge in the API. To make the
# script more reliable we'll add a sleep after we create each resource.
# Some of the resources take a while to converge in the API. To make the
# script more reliable we'll add a sleep after we create each resource.
createResourceGroup
sleep 5
createStorageAccount
sleep 5
createApplication
sleep 5
createServicePrincipal
sleep 5
createPermissions
retryable 3 createResourceGroup
retryable 3 createStorageAccount
retryable 3 createApplication
retryable 3 createServicePrincipal
retryable 3 createPermissions
showConfigs
showConfigs
}
case "$1" in
requirements)
requirements
;;
setup)
setup
;;
*)
showhelp
;;
requirements)
requirements
;;
setup)
setup
;;
*)
showhelp
;;
esac
-2
View File
@@ -187,8 +187,6 @@ func wrappedMain() int {
Ui: ui,
}
//setupSignalHandlers(env)
cli := &cli.CLI{
Args: args,
Commands: Commands,
+4 -4
View File
@@ -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
View File
@@ -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.
-33
View File
@@ -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
}
+2 -4
View File
@@ -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()
}
}
+4 -4
View File
@@ -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 {
-18
View File
@@ -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
View File
@@ -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
View File
@@ -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 != "" {
+1 -2
View File
@@ -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 {
+1 -1
View File
@@ -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):

Some files were not shown because too many files have changed in this diff Show More