Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| caaf679f27 | |||
| 659383618f | |||
| 84b0bf6dba | |||
| 86c43a1bc9 | |||
| 6cd10286db | |||
| 4e87275f87 | |||
| 3001c16eee | |||
| 5f3ae970c0 | |||
| 5be22de623 | |||
| 15132a9f17 | |||
| ffaca0a226 | |||
| eea558d2a5 | |||
| 4370726ba7 | |||
| 73ac1fc82c | |||
| 375eb57077 | |||
| e6881cee6a | |||
| d4c4581885 | |||
| 0c11cf7c88 | |||
| 67887c11e4 | |||
| f1eae75389 | |||
| 7681d618d6 | |||
| 90b4dc7860 | |||
| b842e53028 | |||
| 3abacee131 | |||
| 4e2936d270 | |||
| 570be4d581 | |||
| ab99d424ef | |||
| a1b4887324 | |||
| 23b21ff4d0 | |||
| 8e7c2796fc | |||
| b5606af9e2 | |||
| 1b8646c963 | |||
| 36698d4b6d | |||
| 8d5f8dc423 | |||
| ea5361a9ac | |||
| a82f1c18ee | |||
| 98f3bc57a0 | |||
| 964546e050 | |||
| 1719cf8006 | |||
| 6e098d1aaf | |||
| 66f7f5aad5 | |||
| 84001c7c76 | |||
| 21171db836 | |||
| 2e90660afc | |||
| cd12c3e030 | |||
| 017d27d7eb | |||
| 27a6dac7fd | |||
| 98ddf043cc | |||
| dfb44a2abe | |||
| dbae49f0c8 | |||
| a03c66272f | |||
| 65eb05384f | |||
| c157da38c9 | |||
| 4c4020f723 | |||
| e4c22472bb | |||
| dc9a803efd | |||
| d1fff21045 | |||
| f97b88654f | |||
| e613b0cdcd | |||
| 7ed2498407 | |||
| 5d8a211774 | |||
| 1b91110a59 | |||
| 729232c7c7 | |||
| 293db31a0f | |||
| 9f55695964 | |||
| a1893b0bce | |||
| fc595de0fd | |||
| e21e980647 | |||
| 332d666180 | |||
| 87f47ba6de |
@@ -1,3 +1,33 @@
|
||||
## 0.3.6 (September 2, 2013)
|
||||
|
||||
FEATURES:
|
||||
|
||||
* User variables can now be specified as "required", meaning the user
|
||||
MUST specify a value. Just set the default value to "null". [GH-374]
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
* core: Much improved interrupt handling. For example, interrupts now
|
||||
cancel much more quickly within provisioners.
|
||||
* builder/amazon: In `-debug` mode, the keypair used will be saved to
|
||||
the current directory so you can access the machine. [GH-373]
|
||||
* builder/amazon: In `-debug` mode, the DNS is outputted.
|
||||
* builder/openstack: IPv6 addresses supported for SSH. [GH-379]
|
||||
* communicator/ssh: Support for private keys encrypted using PKCS8. [GH-376]
|
||||
* provisioner/chef-solo: You can now use user variables in the `json`
|
||||
configuration for Chef. [GH-362]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* core: Concurrent map access is completely gone, fixing rare issues
|
||||
with runtime memory corruption. [GH-307]
|
||||
* core: Fix possible panic when ctrl-C during provisioner run.
|
||||
* builder/digitalocean: Retry destroy a few times because DO sometimes
|
||||
gives false errors.
|
||||
* builder/openstack: Properly handle the case no image is made. [GH-375]
|
||||
* builder/openstack: Specifying a region is now required in a template.
|
||||
* provisioners/salt-masterless: Use filepath join to properly join paths.
|
||||
|
||||
## 0.3.5 (August 28, 2013)
|
||||
|
||||
FEATURES:
|
||||
|
||||
@@ -167,11 +167,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
ec2conn := ec2.New(auth, region)
|
||||
|
||||
// Setup the state bag and initial state for the steps
|
||||
state := make(map[string]interface{})
|
||||
state["config"] = &b.config
|
||||
state["ec2"] = ec2conn
|
||||
state["hook"] = hook
|
||||
state["ui"] = ui
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("config", &b.config)
|
||||
state.Put("ec2", ec2conn)
|
||||
state.Put("hook", hook)
|
||||
state.Put("ui", ui)
|
||||
|
||||
// Build the steps
|
||||
steps := []multistep.Step{
|
||||
@@ -216,18 +216,18 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
b.runner.Run(state)
|
||||
|
||||
// If there was an error, return that
|
||||
if rawErr, ok := state["error"]; ok {
|
||||
if rawErr, ok := state.GetOk("error"); ok {
|
||||
return nil, rawErr.(error)
|
||||
}
|
||||
|
||||
// If there are no AMIs, then just return
|
||||
if _, ok := state["amis"]; !ok {
|
||||
if _, ok := state.GetOk("amis"); !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Build the artifact and return it
|
||||
artifact := &awscommon.Artifact{
|
||||
Amis: state["amis"].(map[string]string),
|
||||
Amis: state.Get("amis").(map[string]string),
|
||||
BuilderIdValue: BuilderId,
|
||||
Conn: ec2conn,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package chroot
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/multistep"
|
||||
)
|
||||
|
||||
// Cleanup is an interface that some steps implement for early cleanup.
|
||||
type Cleanup interface {
|
||||
CleanupFunc(map[string]interface{}) error
|
||||
CleanupFunc(multistep.StateBag) error
|
||||
}
|
||||
|
||||
@@ -21,12 +21,12 @@ type StepAttachVolume struct {
|
||||
volumeId string
|
||||
}
|
||||
|
||||
func (s *StepAttachVolume) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
device := state["device"].(string)
|
||||
instance := state["instance"].(*ec2.Instance)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
volumeId := state["volume_id"].(string)
|
||||
func (s *StepAttachVolume) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
device := state.Get("device").(string)
|
||||
instance := state.Get("instance").(*ec2.Instance)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
volumeId := state.Get("volume_id").(string)
|
||||
|
||||
// For the API call, it expects "sd" prefixed devices.
|
||||
attachVolume := strings.Replace(device, "/xvd", "/sd", 1)
|
||||
@@ -35,7 +35,7 @@ func (s *StepAttachVolume) Run(state map[string]interface{}) multistep.StepActio
|
||||
_, err := ec2conn.AttachVolume(volumeId, instance.InstanceId, attachVolume)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error attaching volume: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -67,29 +67,29 @@ func (s *StepAttachVolume) Run(state map[string]interface{}) multistep.StepActio
|
||||
_, err = awscommon.WaitForState(&stateChange)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error waiting for volume: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state["attach_cleanup"] = s
|
||||
state.Put("attach_cleanup", s)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepAttachVolume) Cleanup(state map[string]interface{}) {
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepAttachVolume) Cleanup(state multistep.StateBag) {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
if err := s.CleanupFunc(state); err != nil {
|
||||
ui.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StepAttachVolume) CleanupFunc(state map[string]interface{}) error {
|
||||
func (s *StepAttachVolume) CleanupFunc(state multistep.StateBag) error {
|
||||
if !s.attached {
|
||||
return nil
|
||||
}
|
||||
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Detaching EBS volume...")
|
||||
_, err := ec2conn.DetachVolume(s.volumeId)
|
||||
|
||||
@@ -11,10 +11,10 @@ type StepChrootProvision struct {
|
||||
mounts []string
|
||||
}
|
||||
|
||||
func (s *StepChrootProvision) Run(state map[string]interface{}) multistep.StepAction {
|
||||
hook := state["hook"].(packer.Hook)
|
||||
mountPath := state["mount_path"].(string)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepChrootProvision) Run(state multistep.StateBag) multistep.StepAction {
|
||||
hook := state.Get("hook").(packer.Hook)
|
||||
mountPath := state.Get("mount_path").(string)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
// Create our communicator
|
||||
comm := &Communicator{
|
||||
@@ -24,11 +24,11 @@ func (s *StepChrootProvision) Run(state map[string]interface{}) multistep.StepAc
|
||||
// Provision
|
||||
log.Println("Running the provision hook")
|
||||
if err := hook.Run(packer.HookProvision, ui, comm, nil); err != nil {
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepChrootProvision) Cleanup(state map[string]interface{}) {}
|
||||
func (s *StepChrootProvision) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
@@ -19,10 +19,10 @@ type StepCopyFiles struct {
|
||||
files []string
|
||||
}
|
||||
|
||||
func (s *StepCopyFiles) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*Config)
|
||||
mountPath := state["mount_path"].(string)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepCopyFiles) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
mountPath := state.Get("mount_path").(string)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
s.files = make([]string, 0, len(config.CopyFiles))
|
||||
if len(config.CopyFiles) > 0 {
|
||||
@@ -34,7 +34,7 @@ func (s *StepCopyFiles) Run(state map[string]interface{}) multistep.StepAction {
|
||||
|
||||
if err := s.copySingle(chrootPath, path); err != nil {
|
||||
err := fmt.Errorf("Error copying file: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -43,18 +43,18 @@ func (s *StepCopyFiles) Run(state map[string]interface{}) multistep.StepAction {
|
||||
}
|
||||
}
|
||||
|
||||
state["copy_files_cleanup"] = s
|
||||
state.Put("copy_files_cleanup", s)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepCopyFiles) Cleanup(state map[string]interface{}) {
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepCopyFiles) Cleanup(state multistep.StateBag) {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
if err := s.CleanupFunc(state); err != nil {
|
||||
ui.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StepCopyFiles) CleanupFunc(map[string]interface{}) error {
|
||||
func (s *StepCopyFiles) CleanupFunc(multistep.StateBag) error {
|
||||
if s.files != nil {
|
||||
for _, file := range s.files {
|
||||
log.Printf("Removing: %s", file)
|
||||
|
||||
@@ -18,11 +18,11 @@ type StepCreateVolume struct {
|
||||
volumeId string
|
||||
}
|
||||
|
||||
func (s *StepCreateVolume) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
image := state["source_image"].(*ec2.Image)
|
||||
instance := state["instance"].(*ec2.Instance)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepCreateVolume) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
image := state.Get("source_image").(*ec2.Image)
|
||||
instance := state.Get("instance").(*ec2.Instance)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
// Determine the root device snapshot
|
||||
log.Printf("Searching for root device of the image (%s)", image.RootDeviceName)
|
||||
@@ -36,7 +36,7 @@ func (s *StepCreateVolume) Run(state map[string]interface{}) multistep.StepActio
|
||||
|
||||
if rootDevice == nil {
|
||||
err := fmt.Errorf("Couldn't find root device!")
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func (s *StepCreateVolume) Run(state map[string]interface{}) multistep.StepActio
|
||||
createVolumeResp, err := ec2conn.CreateVolume(createVolume)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating root volume: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -82,22 +82,22 @@ func (s *StepCreateVolume) Run(state map[string]interface{}) multistep.StepActio
|
||||
_, err = awscommon.WaitForState(&stateChange)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error waiting for volume: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state["volume_id"] = s.volumeId
|
||||
state.Put("volume_id", s.volumeId)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepCreateVolume) Cleanup(state map[string]interface{}) {
|
||||
func (s *StepCreateVolume) Cleanup(state multistep.StateBag) {
|
||||
if s.volumeId == "" {
|
||||
return
|
||||
}
|
||||
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Deleting the created EBS volume...")
|
||||
_, err := ec2conn.DeleteVolume(s.volumeId)
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
// prepare for snapshotting and creating an AMI.
|
||||
type StepEarlyCleanup struct{}
|
||||
|
||||
func (s *StepEarlyCleanup) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepEarlyCleanup) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
cleanupKeys := []string{
|
||||
"copy_files_cleanup",
|
||||
"mount_extra_cleanup",
|
||||
@@ -21,11 +21,11 @@ func (s *StepEarlyCleanup) Run(state map[string]interface{}) multistep.StepActio
|
||||
}
|
||||
|
||||
for _, key := range cleanupKeys {
|
||||
c := state[key].(Cleanup)
|
||||
c := state.Get(key).(Cleanup)
|
||||
log.Printf("Running cleanup func: %s", key)
|
||||
if err := c.CleanupFunc(state); err != nil {
|
||||
err := fmt.Errorf("Error cleaning up: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -34,4 +34,4 @@ func (s *StepEarlyCleanup) Run(state map[string]interface{}) multistep.StepActio
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepEarlyCleanup) Cleanup(state map[string]interface{}) {}
|
||||
func (s *StepEarlyCleanup) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
@@ -10,14 +10,14 @@ import (
|
||||
// StepEarlyUnflock unlocks the flock.
|
||||
type StepEarlyUnflock struct{}
|
||||
|
||||
func (s *StepEarlyUnflock) Run(state map[string]interface{}) multistep.StepAction {
|
||||
cleanup := state["flock_cleanup"].(Cleanup)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepEarlyUnflock) Run(state multistep.StateBag) multistep.StepAction {
|
||||
cleanup := state.Get("flock_cleanup").(Cleanup)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
log.Println("Unlocking file lock...")
|
||||
if err := cleanup.CleanupFunc(state); err != nil {
|
||||
err := fmt.Errorf("Error unlocking file lock: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -25,4 +25,4 @@ func (s *StepEarlyUnflock) Run(state map[string]interface{}) multistep.StepActio
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepEarlyUnflock) Cleanup(state map[string]interface{}) {}
|
||||
func (s *StepEarlyUnflock) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
@@ -17,13 +17,13 @@ type StepFlock struct {
|
||||
fh *os.File
|
||||
}
|
||||
|
||||
func (s *StepFlock) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepFlock) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
lockfile := "/var/lock/packer-chroot/lock"
|
||||
if err := os.MkdirAll(filepath.Dir(lockfile), 0755); err != nil {
|
||||
err := fmt.Errorf("Error creating lock: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -32,7 +32,7 @@ func (s *StepFlock) Run(state map[string]interface{}) multistep.StepAction {
|
||||
f, err := os.Create(lockfile)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating lock: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -40,7 +40,7 @@ func (s *StepFlock) Run(state map[string]interface{}) multistep.StepAction {
|
||||
// LOCK!
|
||||
if err := lockFile(f); err != nil {
|
||||
err := fmt.Errorf("Error creating lock: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -49,15 +49,15 @@ func (s *StepFlock) Run(state map[string]interface{}) multistep.StepAction {
|
||||
// the lock.
|
||||
s.fh = f
|
||||
|
||||
state["flock_cleanup"] = s
|
||||
state.Put("flock_cleanup", s)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepFlock) Cleanup(state map[string]interface{}) {
|
||||
func (s *StepFlock) Cleanup(state multistep.StateBag) {
|
||||
s.CleanupFunc(state)
|
||||
}
|
||||
|
||||
func (s *StepFlock) CleanupFunc(state map[string]interface{}) error {
|
||||
func (s *StepFlock) CleanupFunc(state multistep.StateBag) error {
|
||||
if s.fh == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ import (
|
||||
// StepInstanceInfo verifies that this builder is running on an EC2 instance.
|
||||
type StepInstanceInfo struct{}
|
||||
|
||||
func (s *StepInstanceInfo) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepInstanceInfo) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
// Get our own instance ID
|
||||
ui.Say("Gathering information about this EC2 instance...")
|
||||
@@ -24,7 +24,7 @@ func (s *StepInstanceInfo) Run(state map[string]interface{}) multistep.StepActio
|
||||
err := fmt.Errorf(
|
||||
"Error retrieving the ID of the instance Packer is running on.\n" +
|
||||
"Please verify Packer is running on a proper AWS EC2 instance.")
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -36,22 +36,22 @@ func (s *StepInstanceInfo) Run(state map[string]interface{}) multistep.StepActio
|
||||
instancesResp, err := ec2conn.Instances([]string{instanceId}, ec2.NewFilter())
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error getting instance data: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if len(instancesResp.Reservations) == 0 {
|
||||
err := fmt.Errorf("Error getting instance data: no instance found.")
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
instance := &instancesResp.Reservations[0].Instances[0]
|
||||
state["instance"] = instance
|
||||
state.Put("instance", instance)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepInstanceInfo) Cleanup(map[string]interface{}) {}
|
||||
func (s *StepInstanceInfo) Cleanup(multistep.StateBag) {}
|
||||
|
||||
@@ -24,10 +24,10 @@ type StepMountDevice struct {
|
||||
mountPath string
|
||||
}
|
||||
|
||||
func (s *StepMountDevice) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*Config)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
device := state["device"].(string)
|
||||
func (s *StepMountDevice) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
device := state.Get("device").(string)
|
||||
|
||||
mountPath, err := config.tpl.Process(config.MountPath, &mountPathData{
|
||||
Device: filepath.Base(device),
|
||||
@@ -35,7 +35,7 @@ func (s *StepMountDevice) Run(state map[string]interface{}) multistep.StepAction
|
||||
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error preparing mount directory: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -43,7 +43,7 @@ func (s *StepMountDevice) Run(state map[string]interface{}) multistep.StepAction
|
||||
mountPath, err = filepath.Abs(mountPath)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error preparing mount directory: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -52,7 +52,7 @@ func (s *StepMountDevice) Run(state map[string]interface{}) multistep.StepAction
|
||||
|
||||
if err := os.MkdirAll(mountPath, 0755); err != nil {
|
||||
err := fmt.Errorf("Error creating mount directory: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -65,33 +65,33 @@ func (s *StepMountDevice) Run(state map[string]interface{}) multistep.StepAction
|
||||
if err := cmd.Run(); err != nil {
|
||||
err := fmt.Errorf(
|
||||
"Error mounting root volume: %s\nStderr: %s", err, stderr.String())
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Set the mount path so we remember to unmount it later
|
||||
s.mountPath = mountPath
|
||||
state["mount_path"] = s.mountPath
|
||||
state["mount_device_cleanup"] = s
|
||||
state.Put("mount_path", s.mountPath)
|
||||
state.Put("mount_device_cleanup", s)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepMountDevice) Cleanup(state map[string]interface{}) {
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepMountDevice) Cleanup(state multistep.StateBag) {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
if err := s.CleanupFunc(state); err != nil {
|
||||
ui.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StepMountDevice) CleanupFunc(state map[string]interface{}) error {
|
||||
func (s *StepMountDevice) CleanupFunc(state multistep.StateBag) error {
|
||||
if s.mountPath == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
config := state["config"].(*Config)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
config := state.Get("config").(*Config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
ui.Say("Unmounting the root device...")
|
||||
|
||||
unmountCommand := fmt.Sprintf("%s %s", config.UnmountCommand, s.mountPath)
|
||||
|
||||
@@ -17,10 +17,10 @@ type StepMountExtra struct {
|
||||
mounts []string
|
||||
}
|
||||
|
||||
func (s *StepMountExtra) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*Config)
|
||||
mountPath := state["mount_path"].(string)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepMountExtra) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
mountPath := state.Get("mount_path").(string)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
s.mounts = make([]string, 0, len(config.ChrootMounts))
|
||||
|
||||
@@ -30,7 +30,7 @@ func (s *StepMountExtra) Run(state map[string]interface{}) multistep.StepAction
|
||||
|
||||
if err := os.MkdirAll(innerPath, 0755); err != nil {
|
||||
err := fmt.Errorf("Error creating mount directory: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func (s *StepMountExtra) Run(state map[string]interface{}) multistep.StepAction
|
||||
if err := cmd.Run(); err != nil {
|
||||
err := fmt.Errorf(
|
||||
"Error mounting: %s\nStderr: %s", err, stderr.String())
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -61,12 +61,12 @@ func (s *StepMountExtra) Run(state map[string]interface{}) multistep.StepAction
|
||||
s.mounts = append(s.mounts, innerPath)
|
||||
}
|
||||
|
||||
state["mount_extra_cleanup"] = s
|
||||
state.Put("mount_extra_cleanup", s)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepMountExtra) Cleanup(state map[string]interface{}) {
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepMountExtra) Cleanup(state multistep.StateBag) {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
if err := s.CleanupFunc(state); err != nil {
|
||||
ui.Error(err.Error())
|
||||
@@ -74,12 +74,12 @@ func (s *StepMountExtra) Cleanup(state map[string]interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StepMountExtra) CleanupFunc(state map[string]interface{}) error {
|
||||
func (s *StepMountExtra) CleanupFunc(state multistep.StateBag) error {
|
||||
if s.mounts == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
config := state["config"].(*Config)
|
||||
config := state.Get("config").(*Config)
|
||||
for len(s.mounts) > 0 {
|
||||
var path string
|
||||
lastIndex := len(s.mounts) - 1
|
||||
|
||||
@@ -13,9 +13,9 @@ type StepPrepareDevice struct {
|
||||
mounts []string
|
||||
}
|
||||
|
||||
func (s *StepPrepareDevice) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*Config)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepPrepareDevice) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
device := config.DevicePath
|
||||
if device == "" {
|
||||
@@ -24,7 +24,7 @@ func (s *StepPrepareDevice) Run(state map[string]interface{}) multistep.StepActi
|
||||
device, err = AvailableDevice()
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error finding available device: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -32,14 +32,14 @@ func (s *StepPrepareDevice) Run(state map[string]interface{}) multistep.StepActi
|
||||
|
||||
if _, err := os.Stat(device); err == nil {
|
||||
err := fmt.Errorf("Device is in use: %s", device)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
log.Printf("Device: %s", device)
|
||||
state["device"] = device
|
||||
state.Put("device", device)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepPrepareDevice) Cleanup(state map[string]interface{}) {}
|
||||
func (s *StepPrepareDevice) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
@@ -11,12 +11,12 @@ import (
|
||||
// StepRegisterAMI creates the AMI.
|
||||
type StepRegisterAMI struct{}
|
||||
|
||||
func (s *StepRegisterAMI) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*Config)
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
image := state["source_image"].(*ec2.Image)
|
||||
snapshotId := state["snapshot_id"].(string)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
image := state.Get("source_image").(*ec2.Image)
|
||||
snapshotId := state.Get("snapshot_id").(string)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Registering the AMI...")
|
||||
blockDevices := make([]ec2.BlockDeviceMapping, len(image.BlockDevices))
|
||||
@@ -40,8 +40,8 @@ func (s *StepRegisterAMI) Run(state map[string]interface{}) multistep.StepAction
|
||||
|
||||
registerResp, err := ec2conn.RegisterImage(registerOpts)
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error registering AMI: %s", err)
|
||||
ui.Error(state["error"].(error).Error())
|
||||
state.Put("error", fmt.Errorf("Error registering AMI: %s", err))
|
||||
ui.Error(state.Get("error").(error).Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -49,13 +49,13 @@ func (s *StepRegisterAMI) Run(state map[string]interface{}) multistep.StepAction
|
||||
ui.Say(fmt.Sprintf("AMI: %s", registerResp.ImageId))
|
||||
amis := make(map[string]string)
|
||||
amis[ec2conn.Region.Name] = registerResp.ImageId
|
||||
state["amis"] = amis
|
||||
state.Put("amis", amis)
|
||||
|
||||
// Wait for the image to become ready
|
||||
ui.Say("Waiting for AMI to become ready...")
|
||||
if err := awscommon.WaitForAMI(ec2conn, registerResp.ImageId); err != nil {
|
||||
err := fmt.Errorf("Error waiting for AMI: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -63,4 +63,4 @@ func (s *StepRegisterAMI) Run(state map[string]interface{}) multistep.StepAction
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepRegisterAMI) Cleanup(state map[string]interface{}) {}
|
||||
func (s *StepRegisterAMI) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
@@ -17,16 +17,16 @@ type StepSnapshot struct {
|
||||
snapshotId string
|
||||
}
|
||||
|
||||
func (s *StepSnapshot) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
volumeId := state["volume_id"].(string)
|
||||
func (s *StepSnapshot) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
volumeId := state.Get("volume_id").(string)
|
||||
|
||||
ui.Say("Creating snapshot...")
|
||||
createSnapResp, err := ec2conn.CreateSnapshot(volumeId, "")
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating snapshot: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -58,26 +58,26 @@ func (s *StepSnapshot) Run(state map[string]interface{}) multistep.StepAction {
|
||||
_, err = awscommon.WaitForState(&stateChange)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error waiting for snapshot: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state["snapshot_id"] = s.snapshotId
|
||||
state.Put("snapshot_id", s.snapshotId)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepSnapshot) Cleanup(state map[string]interface{}) {
|
||||
func (s *StepSnapshot) Cleanup(state multistep.StateBag) {
|
||||
if s.snapshotId == "" {
|
||||
return
|
||||
}
|
||||
|
||||
_, cancelled := state[multistep.StateCancelled]
|
||||
_, halted := state[multistep.StateHalted]
|
||||
_, cancelled := state.GetOk(multistep.StateCancelled)
|
||||
_, halted := state.GetOk(multistep.StateHalted)
|
||||
|
||||
if cancelled || halted {
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
ui.Say("Removing snapshot since we cancelled or halted...")
|
||||
_, err := ec2conn.DeleteSnapshots([]string{s.snapshotId})
|
||||
if err != nil {
|
||||
|
||||
@@ -14,23 +14,23 @@ import (
|
||||
// source_image *ec2.Image - the source AMI info
|
||||
type StepSourceAMIInfo struct{}
|
||||
|
||||
func (s *StepSourceAMIInfo) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*Config)
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepSourceAMIInfo) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Inspecting the source AMI...")
|
||||
imageResp, err := ec2conn.Images([]string{config.SourceAmi}, ec2.NewFilter())
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error querying AMI: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if len(imageResp.Images) == 0 {
|
||||
err := fmt.Errorf("Source AMI '%s' was not found!", config.SourceAmi)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -40,13 +40,13 @@ func (s *StepSourceAMIInfo) Run(state map[string]interface{}) multistep.StepActi
|
||||
// It must be EBS-backed otherwise the build won't work
|
||||
if image.RootDeviceType != "ebs" {
|
||||
err := fmt.Errorf("The root device of the source AMI must be EBS-backed.")
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state["source_image"] = image
|
||||
state.Put("source_image", image)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepSourceAMIInfo) Cleanup(map[string]interface{}) {}
|
||||
func (s *StepSourceAMIInfo) Cleanup(multistep.StateBag) {}
|
||||
|
||||
@@ -26,7 +26,7 @@ type StateChangeConf struct {
|
||||
Conn *ec2.EC2
|
||||
Pending []string
|
||||
Refresh StateRefreshFunc
|
||||
StepState map[string]interface{}
|
||||
StepState multistep.StateBag
|
||||
Target string
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ func WaitForState(conf *StateChangeConf) (i interface{}, err error) {
|
||||
}
|
||||
|
||||
if conf.StepState != nil {
|
||||
if _, ok := conf.StepState[multistep.StateCancelled]; ok {
|
||||
if _, ok := conf.StepState.GetOk(multistep.StateCancelled); ok {
|
||||
return nil, errors.New("interrupted")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,17 +5,18 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/communicator/ssh"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SSHAddress returns a function that can be given to the SSH communicator
|
||||
// for determining the SSH address based on the instance DNS name.
|
||||
func SSHAddress(e *ec2.EC2, port int) func(map[string]interface{}) (string, error) {
|
||||
return func(state map[string]interface{}) (string, error) {
|
||||
func SSHAddress(e *ec2.EC2, port int) func(multistep.StateBag) (string, error) {
|
||||
return func(state multistep.StateBag) (string, error) {
|
||||
for j := 0; j < 2; j++ {
|
||||
var host string
|
||||
i := state["instance"].(*ec2.Instance)
|
||||
i := state.Get("instance").(*ec2.Instance)
|
||||
if i.DNSName != "" {
|
||||
host = i.DNSName
|
||||
} else if i.VpcId != "" {
|
||||
@@ -35,7 +36,7 @@ func SSHAddress(e *ec2.EC2, port int) func(map[string]interface{}) (string, erro
|
||||
return "", fmt.Errorf("instance not found: %s", i.InstanceId)
|
||||
}
|
||||
|
||||
state["instance"] = &r.Reservations[0].Instances[0]
|
||||
state.Put("instance", &r.Reservations[0].Instances[0])
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
@@ -46,9 +47,9 @@ func SSHAddress(e *ec2.EC2, port int) func(map[string]interface{}) (string, erro
|
||||
// SSHConfig returns a function that can be used for the SSH communicator
|
||||
// config for connecting to the instance created over SSH using the generated
|
||||
// private key.
|
||||
func SSHConfig(username string) func(map[string]interface{}) (*gossh.ClientConfig, error) {
|
||||
return func(state map[string]interface{}) (*gossh.ClientConfig, error) {
|
||||
privateKey := state["privateKey"].(string)
|
||||
func SSHConfig(username string) func(multistep.StateBag) (*gossh.ClientConfig, error) {
|
||||
return func(state multistep.StateBag) (*gossh.ClientConfig, error) {
|
||||
privateKey := state.Get("privateKey").(string)
|
||||
|
||||
keyring := new(ssh.SimpleKeychain)
|
||||
if err := keyring.AddPEMKey(privateKey); err != nil {
|
||||
|
||||
@@ -13,10 +13,10 @@ type StepAMIRegionCopy struct {
|
||||
Tags map[string]string
|
||||
}
|
||||
|
||||
func (s *StepAMIRegionCopy) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
amis := state["amis"].(map[string]string)
|
||||
func (s *StepAMIRegionCopy) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
amis := state.Get("amis").(map[string]string)
|
||||
ami := amis[ec2conn.Region.Name]
|
||||
|
||||
if len(s.Regions) == 0 {
|
||||
@@ -36,7 +36,7 @@ func (s *StepAMIRegionCopy) Run(state map[string]interface{}) multistep.StepActi
|
||||
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error Copying AMI (%s) to region (%s): %s", ami, region, err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -44,7 +44,7 @@ func (s *StepAMIRegionCopy) Run(state map[string]interface{}) multistep.StepActi
|
||||
ui.Say(fmt.Sprintf("Waiting for AMI (%s) in region (%s) to become ready...", resp.ImageId, region))
|
||||
if err := WaitForAMI(regionconn, resp.ImageId); err != nil {
|
||||
err := fmt.Errorf("Error waiting for AMI (%s) in region (%s): %s", resp.ImageId, region, err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -62,7 +62,7 @@ func (s *StepAMIRegionCopy) Run(state map[string]interface{}) multistep.StepActi
|
||||
_, err := regionconn.CreateTags([]string{resp.ImageId}, ec2Tags)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error adding tags to AMI (%s): %s", resp.ImageId, err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -71,10 +71,10 @@ func (s *StepAMIRegionCopy) Run(state map[string]interface{}) multistep.StepActi
|
||||
amis[region] = resp.ImageId
|
||||
}
|
||||
|
||||
state["amis"] = amis
|
||||
state.Put("amis", amis)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepAMIRegionCopy) Cleanup(state map[string]interface{}) {
|
||||
func (s *StepAMIRegionCopy) Cleanup(state multistep.StateBag) {
|
||||
// No cleanup...
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ type StepCreateTags struct {
|
||||
Tags map[string]string
|
||||
}
|
||||
|
||||
func (s *StepCreateTags) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
amis := state["amis"].(map[string]string)
|
||||
func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
amis := state.Get("amis").(map[string]string)
|
||||
ami := amis[ec2conn.Region.Name]
|
||||
|
||||
if len(s.Tags) > 0 {
|
||||
@@ -29,7 +29,7 @@ func (s *StepCreateTags) Run(state map[string]interface{}) multistep.StepAction
|
||||
_, err := ec2conn.CreateTags([]string{ami}, ec2Tags)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error adding tags to AMI (%s): %s", ami, err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -38,6 +38,6 @@ func (s *StepCreateTags) Run(state map[string]interface{}) multistep.StepAction
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepCreateTags) Cleanup(state map[string]interface{}) {
|
||||
func (s *StepCreateTags) Cleanup(state multistep.StateBag) {
|
||||
// No cleanup...
|
||||
}
|
||||
|
||||
@@ -8,22 +8,27 @@ import (
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
type StepKeyPair struct {
|
||||
Debug bool
|
||||
DebugKeyPath string
|
||||
|
||||
keyName string
|
||||
}
|
||||
|
||||
func (s *StepKeyPair) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Creating temporary keypair for this instance...")
|
||||
keyName := fmt.Sprintf("packer %s", hex.EncodeToString(identifier.NewUUID().Raw()))
|
||||
log.Printf("temporary keypair name: %s", keyName)
|
||||
keyResp, err := ec2conn.CreateKeyPair(keyName)
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error creating temporary keypair: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error creating temporary keypair: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -31,20 +36,46 @@ func (s *StepKeyPair) Run(state map[string]interface{}) multistep.StepAction {
|
||||
s.keyName = keyName
|
||||
|
||||
// Set some state data for use in future steps
|
||||
state["keyPair"] = keyName
|
||||
state["privateKey"] = keyResp.KeyMaterial
|
||||
state.Put("keyPair", keyName)
|
||||
state.Put("privateKey", keyResp.KeyMaterial)
|
||||
|
||||
// If we're in debug mode, output the private key to the working
|
||||
// directory.
|
||||
if s.Debug {
|
||||
ui.Message(fmt.Sprintf("Saving key for debug purposes: %s", s.DebugKeyPath))
|
||||
f, err := os.Create(s.DebugKeyPath)
|
||||
if err != nil {
|
||||
state.Put("error", fmt.Errorf("Error saving debug key: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Write the key out
|
||||
if _, err := f.Write([]byte(keyResp.KeyMaterial)); err != nil {
|
||||
state.Put("error", fmt.Errorf("Error saving debug key: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Chmod it so that it is SSH ready
|
||||
if runtime.GOOS != "windows" {
|
||||
if err := f.Chmod(0600); err != nil {
|
||||
state.Put("error", fmt.Errorf("Error setting permissions of debug key: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepKeyPair) Cleanup(state map[string]interface{}) {
|
||||
func (s *StepKeyPair) Cleanup(state multistep.StateBag) {
|
||||
// If no key name is set, then we never created it, so just return
|
||||
if s.keyName == "" {
|
||||
return
|
||||
}
|
||||
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Deleting temporary keypair...")
|
||||
_, err := ec2conn.DeleteKeyPair(s.keyName)
|
||||
|
||||
@@ -14,10 +14,10 @@ type StepModifyAMIAttributes struct {
|
||||
Description string
|
||||
}
|
||||
|
||||
func (s *StepModifyAMIAttributes) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
amis := state["amis"].(map[string]string)
|
||||
func (s *StepModifyAMIAttributes) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
amis := state.Get("amis").(map[string]string)
|
||||
ami := amis[ec2conn.Region.Name]
|
||||
|
||||
// Determine if there is any work to do.
|
||||
@@ -65,7 +65,7 @@ func (s *StepModifyAMIAttributes) Run(state map[string]interface{}) multistep.St
|
||||
_, err := ec2conn.ModifyImageAttribute(ami, opts)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error modify AMI attributes: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -74,6 +74,6 @@ func (s *StepModifyAMIAttributes) Run(state map[string]interface{}) multistep.St
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepModifyAMIAttributes) Cleanup(state map[string]interface{}) {
|
||||
func (s *StepModifyAMIAttributes) Cleanup(state multistep.StateBag) {
|
||||
// No cleanup...
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
)
|
||||
|
||||
type StepRunSourceInstance struct {
|
||||
Debug bool
|
||||
ExpectedRootDevice string
|
||||
InstanceType string
|
||||
UserData string
|
||||
@@ -22,17 +23,17 @@ type StepRunSourceInstance struct {
|
||||
instance *ec2.Instance
|
||||
}
|
||||
|
||||
func (s *StepRunSourceInstance) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
keyName := state["keyPair"].(string)
|
||||
securityGroupId := state["securityGroupId"].(string)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
keyName := state.Get("keyPair").(string)
|
||||
securityGroupId := state.Get("securityGroupId").(string)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
userData := s.UserData
|
||||
if s.UserDataFile != "" {
|
||||
contents, err := ioutil.ReadFile(s.UserDataFile)
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Problem reading user data file: %s", err)
|
||||
state.Put("error", fmt.Errorf("Problem reading user data file: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -55,27 +56,27 @@ func (s *StepRunSourceInstance) Run(state map[string]interface{}) multistep.Step
|
||||
ui.Say("Launching a source AWS instance...")
|
||||
imageResp, err := ec2conn.Images([]string{s.SourceAMI}, ec2.NewFilter())
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("There was a problem with the source AMI: %s", err)
|
||||
state.Put("error", fmt.Errorf("There was a problem with the source AMI: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if len(imageResp.Images) != 1 {
|
||||
state["error"] = fmt.Errorf("The source AMI '%s' could not be found.", s.SourceAMI)
|
||||
state.Put("error", fmt.Errorf("The source AMI '%s' could not be found.", s.SourceAMI))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if s.ExpectedRootDevice != "" && imageResp.Images[0].RootDeviceType != s.ExpectedRootDevice {
|
||||
state["error"] = fmt.Errorf(
|
||||
state.Put("error", fmt.Errorf(
|
||||
"The provided source AMI has an invalid root device type.\n"+
|
||||
"Expected '%s', got '%s'.",
|
||||
s.ExpectedRootDevice, imageResp.Images[0].RootDeviceType)
|
||||
s.ExpectedRootDevice, imageResp.Images[0].RootDeviceType))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
runResp, err := ec2conn.RunInstances(runOpts)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error launching source instance: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -94,24 +95,35 @@ func (s *StepRunSourceInstance) Run(state map[string]interface{}) multistep.Step
|
||||
latestInstance, err := WaitForState(&stateChange)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error waiting for instance (%s) to become ready: %s", s.instance.InstanceId, err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
s.instance = latestInstance.(*ec2.Instance)
|
||||
state["instance"] = s.instance
|
||||
|
||||
if s.Debug {
|
||||
if s.instance.DNSName != "" {
|
||||
ui.Message(fmt.Sprintf("Public DNS: %s", s.instance.DNSName))
|
||||
}
|
||||
|
||||
if s.instance.PrivateIpAddress != "" {
|
||||
ui.Message(fmt.Sprintf("Private IP: %s", s.instance.PrivateIpAddress))
|
||||
}
|
||||
}
|
||||
|
||||
state.Put("instance", s.instance)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepRunSourceInstance) Cleanup(state map[string]interface{}) {
|
||||
func (s *StepRunSourceInstance) Cleanup(state multistep.StateBag) {
|
||||
if s.instance == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Terminating the source AWS instance...")
|
||||
if _, err := ec2conn.TerminateInstances([]string{s.instance.InstanceId}); err != nil {
|
||||
|
||||
@@ -19,13 +19,13 @@ type StepSecurityGroup struct {
|
||||
createdGroupId string
|
||||
}
|
||||
|
||||
func (s *StepSecurityGroup) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepSecurityGroup) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
if s.SecurityGroupId != "" {
|
||||
log.Printf("Using specified security group: %s", s.SecurityGroupId)
|
||||
state["securityGroupId"] = s.SecurityGroupId
|
||||
state.Put("securityGroupId", s.SecurityGroupId)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
@@ -64,24 +64,24 @@ func (s *StepSecurityGroup) Run(state map[string]interface{}) multistep.StepActi
|
||||
ui.Say("Authorizing SSH access on the temporary security group...")
|
||||
if _, err := ec2conn.AuthorizeSecurityGroup(groupResp.SecurityGroup, perms); err != nil {
|
||||
err := fmt.Errorf("Error creating temporary security group: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Set some state data for use in future steps
|
||||
state["securityGroupId"] = s.createdGroupId
|
||||
state.Put("securityGroupId", s.createdGroupId)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepSecurityGroup) Cleanup(state map[string]interface{}) {
|
||||
func (s *StepSecurityGroup) Cleanup(state multistep.StateBag) {
|
||||
if s.createdGroupId == "" {
|
||||
return
|
||||
}
|
||||
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Deleting temporary security group...")
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package ebs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/goamz/ec2"
|
||||
"github.com/mitchellh/multistep"
|
||||
awscommon "github.com/mitchellh/packer/builder/amazon/common"
|
||||
@@ -72,21 +73,25 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
ec2conn := ec2.New(auth, region)
|
||||
|
||||
// Setup the state bag and initial state for the steps
|
||||
state := make(map[string]interface{})
|
||||
state["config"] = b.config
|
||||
state["ec2"] = ec2conn
|
||||
state["hook"] = hook
|
||||
state["ui"] = ui
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("config", b.config)
|
||||
state.Put("ec2", ec2conn)
|
||||
state.Put("hook", hook)
|
||||
state.Put("ui", ui)
|
||||
|
||||
// Build the steps
|
||||
steps := []multistep.Step{
|
||||
&awscommon.StepKeyPair{},
|
||||
&awscommon.StepKeyPair{
|
||||
Debug: b.config.PackerDebug,
|
||||
DebugKeyPath: fmt.Sprintf("ec2_%s.pem", b.config.PackerBuildName),
|
||||
},
|
||||
&awscommon.StepSecurityGroup{
|
||||
SecurityGroupId: b.config.SecurityGroupId,
|
||||
SSHPort: b.config.SSHPort,
|
||||
VpcId: b.config.VpcId,
|
||||
},
|
||||
&awscommon.StepRunSourceInstance{
|
||||
Debug: b.config.PackerDebug,
|
||||
ExpectedRootDevice: "ebs",
|
||||
InstanceType: b.config.InstanceType,
|
||||
UserData: b.config.UserData,
|
||||
@@ -131,18 +136,18 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
b.runner.Run(state)
|
||||
|
||||
// If there was an error, return that
|
||||
if rawErr, ok := state["error"]; ok {
|
||||
if rawErr, ok := state.GetOk("error"); ok {
|
||||
return nil, rawErr.(error)
|
||||
}
|
||||
|
||||
// If there are no AMIs, then just return
|
||||
if _, ok := state["amis"]; !ok {
|
||||
if _, ok := state.GetOk("amis"); !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Build the artifact and return it
|
||||
artifact := &awscommon.Artifact{
|
||||
Amis: state["amis"].(map[string]string),
|
||||
Amis: state.Get("amis").(map[string]string),
|
||||
BuilderIdValue: BuilderId,
|
||||
Conn: ec2conn,
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ import (
|
||||
|
||||
type stepCreateAMI struct{}
|
||||
|
||||
func (s *stepCreateAMI) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(config)
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
instance := state["instance"].(*ec2.Instance)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *stepCreateAMI) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(config)
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
instance := state.Get("instance").(*ec2.Instance)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
// Create the image
|
||||
ui.Say(fmt.Sprintf("Creating the AMI: %s", config.AMIName))
|
||||
@@ -27,7 +27,7 @@ func (s *stepCreateAMI) Run(state map[string]interface{}) multistep.StepAction {
|
||||
createResp, err := ec2conn.CreateImage(createOpts)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating AMI: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -36,13 +36,13 @@ func (s *stepCreateAMI) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ui.Say(fmt.Sprintf("AMI: %s", createResp.ImageId))
|
||||
amis := make(map[string]string)
|
||||
amis[ec2conn.Region.Name] = createResp.ImageId
|
||||
state["amis"] = amis
|
||||
state.Put("amis", amis)
|
||||
|
||||
// Wait for the image to become ready
|
||||
ui.Say("Waiting for AMI to become ready...")
|
||||
if err := awscommon.WaitForAMI(ec2conn, createResp.ImageId); err != nil {
|
||||
err := fmt.Errorf("Error waiting for AMI: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -50,6 +50,6 @@ func (s *stepCreateAMI) Run(state map[string]interface{}) multistep.StepAction {
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepCreateAMI) Cleanup(map[string]interface{}) {
|
||||
func (s *stepCreateAMI) Cleanup(multistep.StateBag) {
|
||||
// No cleanup...
|
||||
}
|
||||
|
||||
@@ -10,17 +10,17 @@ import (
|
||||
|
||||
type stepStopInstance struct{}
|
||||
|
||||
func (s *stepStopInstance) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
instance := state["instance"].(*ec2.Instance)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *stepStopInstance) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
instance := state.Get("instance").(*ec2.Instance)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
// Stop the instance so we can create an AMI from it
|
||||
ui.Say("Stopping the source instance...")
|
||||
_, err := ec2conn.StopInstances(instance.InstanceId)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error stopping instance: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -37,7 +37,7 @@ func (s *stepStopInstance) Run(state map[string]interface{}) multistep.StepActio
|
||||
_, err = awscommon.WaitForState(&stateChange)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error waiting for instance to stop: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -45,6 +45,6 @@ func (s *stepStopInstance) Run(state map[string]interface{}) multistep.StepActio
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepStopInstance) Cleanup(map[string]interface{}) {
|
||||
func (s *stepStopInstance) Cleanup(multistep.StateBag) {
|
||||
// No cleanup...
|
||||
}
|
||||
|
||||
@@ -176,21 +176,25 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
ec2conn := ec2.New(auth, region)
|
||||
|
||||
// Setup the state bag and initial state for the steps
|
||||
state := make(map[string]interface{})
|
||||
state["config"] = &b.config
|
||||
state["ec2"] = ec2conn
|
||||
state["hook"] = hook
|
||||
state["ui"] = ui
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("config", &b.config)
|
||||
state.Put("ec2", ec2conn)
|
||||
state.Put("hook", hook)
|
||||
state.Put("ui", ui)
|
||||
|
||||
// Build the steps
|
||||
steps := []multistep.Step{
|
||||
&awscommon.StepKeyPair{},
|
||||
&awscommon.StepKeyPair{
|
||||
Debug: b.config.PackerDebug,
|
||||
DebugKeyPath: fmt.Sprintf("ec2_%s.pem", b.config.PackerBuildName),
|
||||
},
|
||||
&awscommon.StepSecurityGroup{
|
||||
SecurityGroupId: b.config.SecurityGroupId,
|
||||
SSHPort: b.config.SSHPort,
|
||||
VpcId: b.config.VpcId,
|
||||
},
|
||||
&awscommon.StepRunSourceInstance{
|
||||
Debug: b.config.PackerDebug,
|
||||
ExpectedRootDevice: "instance-store",
|
||||
InstanceType: b.config.InstanceType,
|
||||
IamInstanceProfile: b.config.IamInstanceProfile,
|
||||
@@ -238,18 +242,18 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
b.runner.Run(state)
|
||||
|
||||
// If there was an error, return that
|
||||
if rawErr, ok := state["error"]; ok {
|
||||
if rawErr, ok := state.GetOk("error"); ok {
|
||||
return nil, rawErr.(error)
|
||||
}
|
||||
|
||||
// If there are no AMIs, then just return
|
||||
if _, ok := state["amis"]; !ok {
|
||||
if _, ok := state.GetOk("amis"); !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Build the artifact and return it
|
||||
artifact := &awscommon.Artifact{
|
||||
Amis: state["amis"].(map[string]string),
|
||||
Amis: state.Get("amis").(map[string]string),
|
||||
BuilderIdValue: BuilderId,
|
||||
Conn: ec2conn,
|
||||
}
|
||||
|
||||
@@ -19,13 +19,13 @@ type bundleCmdData struct {
|
||||
|
||||
type StepBundleVolume struct{}
|
||||
|
||||
func (s *StepBundleVolume) Run(state map[string]interface{}) multistep.StepAction {
|
||||
comm := state["communicator"].(packer.Communicator)
|
||||
config := state["config"].(*Config)
|
||||
instance := state["instance"].(*ec2.Instance)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
x509RemoteCertPath := state["x509RemoteCertPath"].(string)
|
||||
x509RemoteKeyPath := state["x509RemoteKeyPath"].(string)
|
||||
func (s *StepBundleVolume) Run(state multistep.StateBag) multistep.StepAction {
|
||||
comm := state.Get("communicator").(packer.Communicator)
|
||||
config := state.Get("config").(*Config)
|
||||
instance := state.Get("instance").(*ec2.Instance)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
x509RemoteCertPath := state.Get("x509RemoteCertPath").(string)
|
||||
x509RemoteKeyPath := state.Get("x509RemoteKeyPath").(string)
|
||||
|
||||
// Bundle the volume
|
||||
var err error
|
||||
@@ -40,7 +40,7 @@ func (s *StepBundleVolume) Run(state map[string]interface{}) multistep.StepActio
|
||||
})
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error processing bundle volume command: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -49,26 +49,26 @@ func (s *StepBundleVolume) Run(state map[string]interface{}) multistep.StepActio
|
||||
cmd := new(packer.RemoteCmd)
|
||||
cmd.Command = config.BundleVolCommand
|
||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
||||
state["error"] = fmt.Errorf("Error bundling volume: %s", err)
|
||||
ui.Error(state["error"].(error).Error())
|
||||
state.Put("error", fmt.Errorf("Error bundling volume: %s", err))
|
||||
ui.Error(state.Get("error").(error).Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if cmd.ExitStatus != 0 {
|
||||
state["error"] = fmt.Errorf(
|
||||
"Volume bundling failed. Please see the output above for more\n" +
|
||||
"details on what went wrong.")
|
||||
ui.Error(state["error"].(error).Error())
|
||||
state.Put("error", fmt.Errorf(
|
||||
"Volume bundling failed. Please see the output above for more\n"+
|
||||
"details on what went wrong."))
|
||||
ui.Error(state.Get("error").(error).Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Store the manifest path
|
||||
manifestName := config.BundlePrefix + ".manifest.xml"
|
||||
state["manifest_name"] = manifestName
|
||||
state["manifest_path"] = fmt.Sprintf(
|
||||
"%s/%s", config.BundleDestination, manifestName)
|
||||
state.Put("manifest_name", manifestName)
|
||||
state.Put("manifest_path", fmt.Sprintf(
|
||||
"%s/%s", config.BundleDestination, manifestName))
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepBundleVolume) Cleanup(map[string]interface{}) {}
|
||||
func (s *StepBundleVolume) Cleanup(multistep.StateBag) {}
|
||||
|
||||
@@ -10,11 +10,11 @@ import (
|
||||
|
||||
type StepRegisterAMI struct{}
|
||||
|
||||
func (s *StepRegisterAMI) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*Config)
|
||||
ec2conn := state["ec2"].(*ec2.EC2)
|
||||
manifestPath := state["remote_manifest_path"].(string)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
manifestPath := state.Get("remote_manifest_path").(string)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Registering the AMI...")
|
||||
registerOpts := &ec2.RegisterImage{
|
||||
@@ -25,8 +25,8 @@ func (s *StepRegisterAMI) Run(state map[string]interface{}) multistep.StepAction
|
||||
|
||||
registerResp, err := ec2conn.RegisterImage(registerOpts)
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error registering AMI: %s", err)
|
||||
ui.Error(state["error"].(error).Error())
|
||||
state.Put("error", fmt.Errorf("Error registering AMI: %s", err))
|
||||
ui.Error(state.Get("error").(error).Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -34,13 +34,13 @@ func (s *StepRegisterAMI) Run(state map[string]interface{}) multistep.StepAction
|
||||
ui.Say(fmt.Sprintf("AMI: %s", registerResp.ImageId))
|
||||
amis := make(map[string]string)
|
||||
amis[ec2conn.Region.Name] = registerResp.ImageId
|
||||
state["amis"] = amis
|
||||
state.Put("amis", amis)
|
||||
|
||||
// Wait for the image to become ready
|
||||
ui.Say("Waiting for AMI to become ready...")
|
||||
if err := awscommon.WaitForAMI(ec2conn, registerResp.ImageId); err != nil {
|
||||
err := fmt.Errorf("Error waiting for AMI: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -48,4 +48,4 @@ func (s *StepRegisterAMI) Run(state map[string]interface{}) multistep.StepAction
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepRegisterAMI) Cleanup(map[string]interface{}) {}
|
||||
func (s *StepRegisterAMI) Cleanup(multistep.StateBag) {}
|
||||
|
||||
@@ -16,12 +16,12 @@ type uploadCmdData struct {
|
||||
|
||||
type StepUploadBundle struct{}
|
||||
|
||||
func (s *StepUploadBundle) Run(state map[string]interface{}) multistep.StepAction {
|
||||
comm := state["communicator"].(packer.Communicator)
|
||||
config := state["config"].(*Config)
|
||||
manifestName := state["manifest_name"].(string)
|
||||
manifestPath := state["manifest_path"].(string)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepUploadBundle) Run(state multistep.StateBag) multistep.StepAction {
|
||||
comm := state.Get("communicator").(packer.Communicator)
|
||||
config := state.Get("config").(*Config)
|
||||
manifestName := state.Get("manifest_name").(string)
|
||||
manifestPath := state.Get("manifest_path").(string)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
var err error
|
||||
config.BundleUploadCommand, err = config.tpl.Process(config.BundleUploadCommand, uploadCmdData{
|
||||
@@ -33,7 +33,7 @@ func (s *StepUploadBundle) Run(state map[string]interface{}) multistep.StepActio
|
||||
})
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error processing bundle upload command: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -41,23 +41,23 @@ func (s *StepUploadBundle) Run(state map[string]interface{}) multistep.StepActio
|
||||
ui.Say("Uploading the bundle...")
|
||||
cmd := &packer.RemoteCmd{Command: config.BundleUploadCommand}
|
||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
||||
state["error"] = fmt.Errorf("Error uploading volume: %s", err)
|
||||
ui.Error(state["error"].(error).Error())
|
||||
state.Put("error", fmt.Errorf("Error uploading volume: %s", err))
|
||||
ui.Error(state.Get("error").(error).Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if cmd.ExitStatus != 0 {
|
||||
state["error"] = fmt.Errorf(
|
||||
"Bundle upload failed. Please see the output above for more\n" +
|
||||
"details on what went wrong.")
|
||||
ui.Error(state["error"].(error).Error())
|
||||
state.Put("error", fmt.Errorf(
|
||||
"Bundle upload failed. Please see the output above for more\n"+
|
||||
"details on what went wrong."))
|
||||
ui.Error(state.Get("error").(error).Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state["remote_manifest_path"] = fmt.Sprintf(
|
||||
"%s/%s", config.S3Bucket, manifestName)
|
||||
state.Put("remote_manifest_path", fmt.Sprintf(
|
||||
"%s/%s", config.S3Bucket, manifestName))
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepUploadBundle) Cleanup(state map[string]interface{}) {}
|
||||
func (s *StepUploadBundle) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
@@ -9,34 +9,34 @@ import (
|
||||
|
||||
type StepUploadX509Cert struct{}
|
||||
|
||||
func (s *StepUploadX509Cert) Run(state map[string]interface{}) multistep.StepAction {
|
||||
comm := state["communicator"].(packer.Communicator)
|
||||
config := state["config"].(*Config)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepUploadX509Cert) Run(state multistep.StateBag) multistep.StepAction {
|
||||
comm := state.Get("communicator").(packer.Communicator)
|
||||
config := state.Get("config").(*Config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
x509RemoteCertPath := config.X509UploadPath + "/cert.pem"
|
||||
x509RemoteKeyPath := config.X509UploadPath + "/key.pem"
|
||||
|
||||
ui.Say("Uploading X509 Certificate...")
|
||||
if err := s.uploadSingle(comm, x509RemoteCertPath, config.X509CertPath); err != nil {
|
||||
state["error"] = fmt.Errorf("Error uploading X509 cert: %s", err)
|
||||
ui.Error(state["error"].(error).Error())
|
||||
state.Put("error", fmt.Errorf("Error uploading X509 cert: %s", err))
|
||||
ui.Error(state.Get("error").(error).Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if err := s.uploadSingle(comm, x509RemoteKeyPath, config.X509KeyPath); err != nil {
|
||||
state["error"] = fmt.Errorf("Error uploading X509 cert: %s", err)
|
||||
ui.Error(state["error"].(error).Error())
|
||||
state.Put("error", fmt.Errorf("Error uploading X509 cert: %s", err))
|
||||
ui.Error(state.Get("error").(error).Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state["x509RemoteCertPath"] = x509RemoteCertPath
|
||||
state["x509RemoteKeyPath"] = x509RemoteKeyPath
|
||||
state.Put("x509RemoteCertPath", x509RemoteCertPath)
|
||||
state.Put("x509RemoteKeyPath", x509RemoteKeyPath)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepUploadX509Cert) Cleanup(map[string]interface{}) {}
|
||||
func (s *StepUploadX509Cert) Cleanup(multistep.StateBag) {}
|
||||
|
||||
func (s *StepUploadX509Cert) uploadSingle(comm packer.Communicator, dst, src string) error {
|
||||
f, err := os.Open(src)
|
||||
|
||||
@@ -189,11 +189,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
client := DigitalOceanClient{}.New(b.config.ClientID, b.config.APIKey)
|
||||
|
||||
// Set up the state
|
||||
state := make(map[string]interface{})
|
||||
state["config"] = b.config
|
||||
state["client"] = client
|
||||
state["hook"] = hook
|
||||
state["ui"] = ui
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("config", b.config)
|
||||
state.Put("client", client)
|
||||
state.Put("hook", hook)
|
||||
state.Put("ui", ui)
|
||||
|
||||
// Build the steps
|
||||
steps := []multistep.Step{
|
||||
@@ -224,18 +224,18 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
b.runner.Run(state)
|
||||
|
||||
// If there was an error, return that
|
||||
if rawErr, ok := state["error"]; ok {
|
||||
if rawErr, ok := state.GetOk("error"); ok {
|
||||
return nil, rawErr.(error)
|
||||
}
|
||||
|
||||
if _, ok := state["snapshot_name"]; !ok {
|
||||
if _, ok := state.GetOk("snapshot_name"); !ok {
|
||||
log.Println("Failed to find snapshot_name in state. Bug?")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
artifact := &Artifact{
|
||||
snapshotName: state["snapshot_name"].(string),
|
||||
snapshotId: state["snapshot_image_id"].(uint),
|
||||
snapshotName: state.Get("snapshot_name").(string),
|
||||
snapshotId: state.Get("snapshot_image_id").(uint),
|
||||
client: client,
|
||||
}
|
||||
|
||||
|
||||
@@ -3,18 +3,19 @@ package digitalocean
|
||||
import (
|
||||
gossh "code.google.com/p/go.crypto/ssh"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/communicator/ssh"
|
||||
)
|
||||
|
||||
func sshAddress(state map[string]interface{}) (string, error) {
|
||||
config := state["config"].(config)
|
||||
ipAddress := state["droplet_ip"].(string)
|
||||
func sshAddress(state multistep.StateBag) (string, error) {
|
||||
config := state.Get("config").(config)
|
||||
ipAddress := state.Get("droplet_ip").(string)
|
||||
return fmt.Sprintf("%s:%d", ipAddress, config.SSHPort), nil
|
||||
}
|
||||
|
||||
func sshConfig(state map[string]interface{}) (*gossh.ClientConfig, error) {
|
||||
config := state["config"].(config)
|
||||
privateKey := state["privateKey"].(string)
|
||||
func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) {
|
||||
config := state.Get("config").(config)
|
||||
privateKey := state.Get("privateKey").(string)
|
||||
|
||||
keyring := new(ssh.SimpleKeychain)
|
||||
if err := keyring.AddPEMKey(privateKey); err != nil {
|
||||
|
||||
@@ -14,11 +14,11 @@ type stepCreateDroplet struct {
|
||||
dropletId uint
|
||||
}
|
||||
|
||||
func (s *stepCreateDroplet) Run(state map[string]interface{}) multistep.StepAction {
|
||||
client := state["client"].(*DigitalOceanClient)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
c := state["config"].(config)
|
||||
sshKeyId := state["ssh_key_id"].(uint)
|
||||
func (s *stepCreateDroplet) Run(state multistep.StateBag) multistep.StepAction {
|
||||
client := state.Get("client").(*DigitalOceanClient)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
c := state.Get("config").(config)
|
||||
sshKeyId := state.Get("ssh_key_id").(uint)
|
||||
|
||||
ui.Say("Creating droplet...")
|
||||
|
||||
@@ -29,7 +29,7 @@ func (s *stepCreateDroplet) Run(state map[string]interface{}) multistep.StepActi
|
||||
dropletId, err := client.CreateDroplet(name, c.SizeID, c.ImageID, c.RegionID, sshKeyId)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating droplet: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -38,20 +38,20 @@ func (s *stepCreateDroplet) Run(state map[string]interface{}) multistep.StepActi
|
||||
s.dropletId = dropletId
|
||||
|
||||
// Store the droplet id for later
|
||||
state["droplet_id"] = dropletId
|
||||
state.Put("droplet_id", dropletId)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepCreateDroplet) Cleanup(state map[string]interface{}) {
|
||||
func (s *stepCreateDroplet) Cleanup(state multistep.StateBag) {
|
||||
// If the dropletid isn't there, we probably never created it
|
||||
if s.dropletId == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
client := state["client"].(*DigitalOceanClient)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
c := state["config"].(config)
|
||||
client := state.Get("client").(*DigitalOceanClient)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
c := state.Get("config").(config)
|
||||
|
||||
// Destroy the droplet we just created
|
||||
ui.Say("Destroying droplet...")
|
||||
@@ -62,12 +62,20 @@ func (s *stepCreateDroplet) Cleanup(state map[string]interface{}) {
|
||||
log.Printf("Sleeping for %v, event_delay", c.RawEventDelay)
|
||||
time.Sleep(c.eventDelay)
|
||||
|
||||
err := client.DestroyDroplet(s.dropletId)
|
||||
var err error
|
||||
for i := 0; i < 5; i++ {
|
||||
err = client.DestroyDroplet(s.dropletId)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
curlstr := fmt.Sprintf("curl '%v/droplets/%v/destroy?client_id=%v&api_key=%v'",
|
||||
DIGITALOCEAN_API_URL, s.dropletId, c.ClientID, c.APIKey)
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
curlstr := fmt.Sprintf("curl '%v/droplets/%v/destroy?client_id=%v&api_key=%v'",
|
||||
DIGITALOCEAN_API_URL, s.dropletId, c.ClientID, c.APIKey)
|
||||
|
||||
ui.Error(fmt.Sprintf(
|
||||
"Error destroying droplet. Please destroy it manually: %v", curlstr))
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ type stepCreateSSHKey struct {
|
||||
keyId uint
|
||||
}
|
||||
|
||||
func (s *stepCreateSSHKey) Run(state map[string]interface{}) multistep.StepAction {
|
||||
client := state["client"].(*DigitalOceanClient)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *stepCreateSSHKey) Run(state multistep.StateBag) multistep.StepAction {
|
||||
client := state.Get("client").(*DigitalOceanClient)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Creating temporary ssh key for droplet...")
|
||||
|
||||
@@ -35,7 +35,7 @@ func (s *stepCreateSSHKey) Run(state map[string]interface{}) multistep.StepActio
|
||||
}
|
||||
|
||||
// Set the private key in the statebag for later
|
||||
state["privateKey"] = string(pem.EncodeToMemory(&priv_blk))
|
||||
state.Put("privateKey", string(pem.EncodeToMemory(&priv_blk)))
|
||||
|
||||
// Marshal the public key into SSH compatible format
|
||||
pub := priv.PublicKey
|
||||
@@ -48,7 +48,7 @@ func (s *stepCreateSSHKey) Run(state map[string]interface{}) multistep.StepActio
|
||||
keyId, err := client.CreateKey(name, pub_sshformat)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating temporary SSH key: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -59,20 +59,20 @@ func (s *stepCreateSSHKey) Run(state map[string]interface{}) multistep.StepActio
|
||||
log.Printf("temporary ssh key name: %s", name)
|
||||
|
||||
// Remember some state for the future
|
||||
state["ssh_key_id"] = keyId
|
||||
state.Put("ssh_key_id", keyId)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepCreateSSHKey) Cleanup(state map[string]interface{}) {
|
||||
func (s *stepCreateSSHKey) Cleanup(state multistep.StateBag) {
|
||||
// If no key name is set, then we never created it, so just return
|
||||
if s.keyId == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
client := state["client"].(*DigitalOceanClient)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
c := state["config"].(config)
|
||||
client := state.Get("client").(*DigitalOceanClient)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
c := state.Get("config").(config)
|
||||
|
||||
ui.Say("Deleting temporary ssh key...")
|
||||
err := client.DestroyKey(s.keyId)
|
||||
|
||||
@@ -8,18 +8,18 @@ import (
|
||||
|
||||
type stepDropletInfo struct{}
|
||||
|
||||
func (s *stepDropletInfo) Run(state map[string]interface{}) multistep.StepAction {
|
||||
client := state["client"].(*DigitalOceanClient)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
c := state["config"].(config)
|
||||
dropletId := state["droplet_id"].(uint)
|
||||
func (s *stepDropletInfo) Run(state multistep.StateBag) multistep.StepAction {
|
||||
client := state.Get("client").(*DigitalOceanClient)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
c := state.Get("config").(config)
|
||||
dropletId := state.Get("droplet_id").(uint)
|
||||
|
||||
ui.Say("Waiting for droplet to become active...")
|
||||
|
||||
err := waitForDropletState("active", dropletId, client, c)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error waiting for droplet to become active: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -28,16 +28,16 @@ func (s *stepDropletInfo) Run(state map[string]interface{}) multistep.StepAction
|
||||
ip, _, err := client.DropletStatus(dropletId)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error retrieving droplet ID: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state["droplet_ip"] = ip
|
||||
state.Put("droplet_ip", ip)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepDropletInfo) Cleanup(state map[string]interface{}) {
|
||||
func (s *stepDropletInfo) Cleanup(state multistep.StateBag) {
|
||||
// no cleanup
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ import (
|
||||
|
||||
type stepPowerOff struct{}
|
||||
|
||||
func (s *stepPowerOff) Run(state map[string]interface{}) multistep.StepAction {
|
||||
client := state["client"].(*DigitalOceanClient)
|
||||
c := state["config"].(config)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
dropletId := state["droplet_id"].(uint)
|
||||
func (s *stepPowerOff) Run(state multistep.StateBag) multistep.StepAction {
|
||||
client := state.Get("client").(*DigitalOceanClient)
|
||||
c := state.Get("config").(config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
dropletId := state.Get("droplet_id").(uint)
|
||||
|
||||
// Sleep arbitrarily before sending power off request
|
||||
// Otherwise we get "pending event" errors, even though there isn't
|
||||
@@ -27,7 +27,7 @@ func (s *stepPowerOff) Run(state map[string]interface{}) multistep.StepAction {
|
||||
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error powering off droplet: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -44,6 +44,6 @@ func (s *stepPowerOff) Run(state map[string]interface{}) multistep.StepAction {
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepPowerOff) Cleanup(state map[string]interface{}) {
|
||||
func (s *stepPowerOff) Cleanup(state multistep.StateBag) {
|
||||
// no cleanup
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ import (
|
||||
|
||||
type stepShutdown struct{}
|
||||
|
||||
func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||
client := state["client"].(*DigitalOceanClient)
|
||||
c := state["config"].(config)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
dropletId := state["droplet_id"].(uint)
|
||||
func (s *stepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
||||
client := state.Get("client").(*DigitalOceanClient)
|
||||
c := state.Get("config").(config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
dropletId := state.Get("droplet_id").(uint)
|
||||
|
||||
// Sleep arbitrarily before sending the request
|
||||
// Otherwise we get "pending event" errors, even though there isn't
|
||||
@@ -26,7 +26,7 @@ func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error shutting down droplet: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -36,7 +36,7 @@ func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||
err = waitForDropletState("off", dropletId, client, c)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error waiting for droplet to become 'off': %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -44,6 +44,6 @@ func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepShutdown) Cleanup(state map[string]interface{}) {
|
||||
func (s *stepShutdown) Cleanup(state multistep.StateBag) {
|
||||
// no cleanup
|
||||
}
|
||||
|
||||
@@ -10,17 +10,17 @@ import (
|
||||
|
||||
type stepSnapshot struct{}
|
||||
|
||||
func (s *stepSnapshot) Run(state map[string]interface{}) multistep.StepAction {
|
||||
client := state["client"].(*DigitalOceanClient)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
c := state["config"].(config)
|
||||
dropletId := state["droplet_id"].(uint)
|
||||
func (s *stepSnapshot) Run(state multistep.StateBag) multistep.StepAction {
|
||||
client := state.Get("client").(*DigitalOceanClient)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
c := state.Get("config").(config)
|
||||
dropletId := state.Get("droplet_id").(uint)
|
||||
|
||||
ui.Say(fmt.Sprintf("Creating snapshot: %v", c.SnapshotName))
|
||||
err := client.CreateSnapshot(dropletId, c.SnapshotName)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating snapshot: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -29,7 +29,7 @@ func (s *stepSnapshot) Run(state map[string]interface{}) multistep.StepAction {
|
||||
err = waitForDropletState("active", dropletId, client, c)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error waiting for snapshot to complete: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -38,7 +38,7 @@ func (s *stepSnapshot) Run(state map[string]interface{}) multistep.StepAction {
|
||||
images, err := client.Images()
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error looking up snapshot ID: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -53,19 +53,19 @@ func (s *stepSnapshot) Run(state map[string]interface{}) multistep.StepAction {
|
||||
|
||||
if imageId == 0 {
|
||||
err := errors.New("Couldn't find snapshot to get the image ID. Bug?")
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
log.Printf("Snapshot image ID: %d", imageId)
|
||||
|
||||
state["snapshot_image_id"] = imageId
|
||||
state["snapshot_name"] = c.SnapshotName
|
||||
state.Put("snapshot_image_id", imageId)
|
||||
state.Put("snapshot_name", c.SnapshotName)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepSnapshot) Cleanup(state map[string]interface{}) {
|
||||
func (s *stepSnapshot) Cleanup(state multistep.StateBag) {
|
||||
// no cleanup
|
||||
}
|
||||
|
||||
@@ -9,9 +9,10 @@ import (
|
||||
|
||||
// AccessConfig is for common configuration related to openstack access
|
||||
type AccessConfig struct {
|
||||
Username string `mapstructure:"username"`
|
||||
Password string `mapstructure:"password"`
|
||||
Provider string `mapstructure:"provider"`
|
||||
Username string `mapstructure:"username"`
|
||||
Password string `mapstructure:"password"`
|
||||
Provider string `mapstructure:"provider"`
|
||||
RawRegion string `mapstructure:"region"`
|
||||
}
|
||||
|
||||
// Auth returns a valid Auth object for access to openstack services, or
|
||||
@@ -40,6 +41,10 @@ func (c *AccessConfig) Auth() (gophercloud.AccessProvider, error) {
|
||||
return gophercloud.Authenticate(provider, authoptions)
|
||||
}
|
||||
|
||||
func (c *AccessConfig) Region() string {
|
||||
return c.RawRegion
|
||||
}
|
||||
|
||||
func (c *AccessConfig) Prepare(t *packer.ConfigTemplate) []error {
|
||||
if t == nil {
|
||||
var err error
|
||||
@@ -65,6 +70,10 @@ func (c *AccessConfig) Prepare(t *packer.ConfigTemplate) []error {
|
||||
}
|
||||
}
|
||||
|
||||
if c.RawRegion == "" {
|
||||
errs = append(errs, fmt.Errorf("region must be specified"))
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
@@ -8,9 +8,21 @@ func testAccessConfig() *AccessConfig {
|
||||
return &AccessConfig{}
|
||||
}
|
||||
|
||||
func TestAccessConfigPrepare_Region(t *testing.T) {
|
||||
func TestAccessConfigPrepare_NoRegion(t *testing.T) {
|
||||
c := testAccessConfig()
|
||||
if err := c.Prepare(nil); err != nil {
|
||||
if err := c.Prepare(nil); err == nil {
|
||||
t.Fatalf("shouldn't have err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccessConfigPrepare_Region(t *testing.T) {
|
||||
dfw := "DFW"
|
||||
c := testAccessConfig()
|
||||
c.RawRegion = dfw
|
||||
if err := c.Prepare(nil); err != nil {
|
||||
t.Fatalf("shouldn't have err: %s", err)
|
||||
}
|
||||
if dfw != c.Region() {
|
||||
t.Fatalf("Regions do not match: %s %s", dfw, c.Region())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,21 +62,22 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
}
|
||||
api := &gophercloud.ApiCriteria{
|
||||
Name: "cloudServersOpenStack",
|
||||
Region: "DFW",
|
||||
Region: b.config.AccessConfig.Region(),
|
||||
VersionId: "2",
|
||||
UrlChoice: gophercloud.PublicURL,
|
||||
}
|
||||
csp, err := gophercloud.ServersApi(auth, *api)
|
||||
if err != nil {
|
||||
log.Printf("Region: %s", b.config.AccessConfig.Region())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Setup the state bag and initial state for the steps
|
||||
state := make(map[string]interface{})
|
||||
state["config"] = b.config
|
||||
state["csp"] = csp
|
||||
state["hook"] = hook
|
||||
state["ui"] = ui
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("config", b.config)
|
||||
state.Put("csp", csp)
|
||||
state.Put("hook", hook)
|
||||
state.Put("ui", ui)
|
||||
|
||||
// Build the steps
|
||||
steps := []multistep.Step{
|
||||
@@ -108,13 +109,18 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
b.runner.Run(state)
|
||||
|
||||
// If there was an error, return that
|
||||
if rawErr, ok := state["error"]; ok {
|
||||
if rawErr, ok := state.GetOk("error"); ok {
|
||||
return nil, rawErr.(error)
|
||||
}
|
||||
|
||||
// If there are no images, then just return
|
||||
if _, ok := state.GetOk("image"); !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Build the artifact and return it
|
||||
artifact := &Artifact{
|
||||
ImageId: state["image"].(string),
|
||||
ImageId: state.Get("image").(string),
|
||||
BuilderIdValue: BuilderId,
|
||||
Conn: csp,
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ func testConfig() map[string]interface{} {
|
||||
"username": "foo",
|
||||
"password": "bar",
|
||||
"provider": "foo",
|
||||
"region": "DFW",
|
||||
"image_name": "foo",
|
||||
"source_image": "foo",
|
||||
"flavor": "foo",
|
||||
|
||||
@@ -39,7 +39,7 @@ func (c *RunConfig) Prepare(t *packer.ConfigTemplate) []error {
|
||||
}
|
||||
|
||||
if c.RawSSHTimeout == "" {
|
||||
c.RawSSHTimeout = "1m"
|
||||
c.RawSSHTimeout = "5m"
|
||||
}
|
||||
|
||||
// Validation
|
||||
|
||||
@@ -25,7 +25,7 @@ type StateRefreshFunc func() (result interface{}, state string, progress int, er
|
||||
type StateChangeConf struct {
|
||||
Pending []string
|
||||
Refresh StateRefreshFunc
|
||||
StepState map[string]interface{}
|
||||
StepState multistep.StateBag
|
||||
Target string
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ func WaitForState(conf *StateChangeConf) (i interface{}, err error) {
|
||||
}
|
||||
|
||||
if conf.StepState != nil {
|
||||
if _, ok := conf.StepState[multistep.StateCancelled]; ok {
|
||||
if _, ok := conf.StepState.GetOk(multistep.StateCancelled); ok {
|
||||
return nil, errors.New("interrupted")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
gossh "code.google.com/p/go.crypto/ssh"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/communicator/ssh"
|
||||
"github.com/rackspace/gophercloud"
|
||||
"time"
|
||||
@@ -11,20 +12,23 @@ import (
|
||||
|
||||
// SSHAddress returns a function that can be given to the SSH communicator
|
||||
// for determining the SSH address based on the server AccessIPv4 setting..
|
||||
func SSHAddress(csp gophercloud.CloudServersProvider, port int) func(map[string]interface{}) (string, error) {
|
||||
return func(state map[string]interface{}) (string, error) {
|
||||
func SSHAddress(csp gophercloud.CloudServersProvider, port int) func(multistep.StateBag) (string, error) {
|
||||
return func(state multistep.StateBag) (string, error) {
|
||||
for j := 0; j < 2; j++ {
|
||||
s := state["server"].(*gophercloud.Server)
|
||||
s := state.Get("server").(*gophercloud.Server)
|
||||
if s.AccessIPv4 != "" {
|
||||
return fmt.Sprintf("%s:%d", s.AccessIPv4, port), nil
|
||||
}
|
||||
if s.AccessIPv6 != "" {
|
||||
return fmt.Sprintf("[%s]:%d", s.AccessIPv6, port), nil
|
||||
}
|
||||
serverState, err := csp.ServerById(s.Id)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
state["server"] = serverState
|
||||
state.Put("server", serverState)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
@@ -35,9 +39,9 @@ func SSHAddress(csp gophercloud.CloudServersProvider, port int) func(map[string]
|
||||
// SSHConfig returns a function that can be used for the SSH communicator
|
||||
// config for connecting to the instance created over SSH using the generated
|
||||
// private key.
|
||||
func SSHConfig(username string) func(map[string]interface{}) (*gossh.ClientConfig, error) {
|
||||
return func(state map[string]interface{}) (*gossh.ClientConfig, error) {
|
||||
privateKey := state["privateKey"].(string)
|
||||
func SSHConfig(username string) func(multistep.StateBag) (*gossh.ClientConfig, error) {
|
||||
return func(state multistep.StateBag) (*gossh.ClientConfig, error) {
|
||||
privateKey := state.Get("privateKey").(string)
|
||||
|
||||
keyring := new(ssh.SimpleKeychain)
|
||||
if err := keyring.AddPEMKey(privateKey); err != nil {
|
||||
|
||||
@@ -11,11 +11,11 @@ import (
|
||||
|
||||
type stepCreateImage struct{}
|
||||
|
||||
func (s *stepCreateImage) Run(state map[string]interface{}) multistep.StepAction {
|
||||
csp := state["csp"].(gophercloud.CloudServersProvider)
|
||||
config := state["config"].(config)
|
||||
server := state["server"].(*gophercloud.Server)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *stepCreateImage) Run(state multistep.StateBag) multistep.StepAction {
|
||||
csp := state.Get("csp").(gophercloud.CloudServersProvider)
|
||||
config := state.Get("config").(config)
|
||||
server := state.Get("server").(*gophercloud.Server)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
// Create the image
|
||||
ui.Say(fmt.Sprintf("Creating the image: %s", config.ImageName))
|
||||
@@ -25,20 +25,20 @@ func (s *stepCreateImage) Run(state map[string]interface{}) multistep.StepAction
|
||||
imageId, err := csp.CreateImage(server.Id, createOpts)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating image: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Set the Image ID in the state
|
||||
ui.Say(fmt.Sprintf("Image: %s", imageId))
|
||||
state["image"] = imageId
|
||||
state.Put("image", imageId)
|
||||
|
||||
// Wait for the image to become ready
|
||||
ui.Say("Waiting for image to become ready...")
|
||||
if err := WaitForImage(csp, imageId); err != nil {
|
||||
err := fmt.Errorf("Error waiting for image: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -46,7 +46,7 @@ func (s *stepCreateImage) Run(state map[string]interface{}) multistep.StepAction
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepCreateImage) Cleanup(map[string]interface{}) {
|
||||
func (s *stepCreateImage) Cleanup(multistep.StateBag) {
|
||||
// No cleanup...
|
||||
}
|
||||
|
||||
|
||||
@@ -14,16 +14,16 @@ type StepKeyPair struct {
|
||||
keyName string
|
||||
}
|
||||
|
||||
func (s *StepKeyPair) Run(state map[string]interface{}) multistep.StepAction {
|
||||
csp := state["csp"].(gophercloud.CloudServersProvider)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction {
|
||||
csp := state.Get("csp").(gophercloud.CloudServersProvider)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Creating temporary keypair for this instance...")
|
||||
keyName := fmt.Sprintf("packer %s", hex.EncodeToString(identifier.NewUUID().Raw()))
|
||||
log.Printf("temporary keypair name: %s", keyName)
|
||||
keyResp, err := csp.CreateKeyPair(gophercloud.NewKeyPair{Name: keyName})
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error creating temporary keypair: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error creating temporary keypair: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -31,20 +31,20 @@ func (s *StepKeyPair) Run(state map[string]interface{}) multistep.StepAction {
|
||||
s.keyName = keyName
|
||||
|
||||
// Set some state data for use in future steps
|
||||
state["keyPair"] = keyName
|
||||
state["privateKey"] = keyResp.PrivateKey
|
||||
state.Put("keyPair", keyName)
|
||||
state.Put("privateKey", keyResp.PrivateKey)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepKeyPair) Cleanup(state map[string]interface{}) {
|
||||
func (s *StepKeyPair) Cleanup(state multistep.StateBag) {
|
||||
// If no key name is set, then we never created it, so just return
|
||||
if s.keyName == "" {
|
||||
return
|
||||
}
|
||||
|
||||
csp := state["csp"].(gophercloud.CloudServersProvider)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
csp := state.Get("csp").(gophercloud.CloudServersProvider)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Deleting temporary keypair...")
|
||||
err := csp.DeleteKeyPair(s.keyName)
|
||||
|
||||
@@ -16,10 +16,10 @@ type StepRunSourceServer struct {
|
||||
server *gophercloud.Server
|
||||
}
|
||||
|
||||
func (s *StepRunSourceServer) Run(state map[string]interface{}) multistep.StepAction {
|
||||
csp := state["csp"].(gophercloud.CloudServersProvider)
|
||||
keyName := state["keyPair"].(string)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepRunSourceServer) Run(state multistep.StateBag) multistep.StepAction {
|
||||
csp := state.Get("csp").(gophercloud.CloudServersProvider)
|
||||
keyName := state.Get("keyPair").(string)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
// XXX - validate image and flavor is available
|
||||
|
||||
@@ -33,7 +33,7 @@ func (s *StepRunSourceServer) Run(state map[string]interface{}) multistep.StepAc
|
||||
serverResp, err := csp.CreateServer(server)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error launching source server: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -51,24 +51,24 @@ func (s *StepRunSourceServer) Run(state map[string]interface{}) multistep.StepAc
|
||||
latestServer, err := WaitForState(&stateChange)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error waiting for server (%s) to become ready: %s", s.server.Id, err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
s.server = latestServer.(*gophercloud.Server)
|
||||
state["server"] = s.server
|
||||
state.Put("server", s.server)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepRunSourceServer) Cleanup(state map[string]interface{}) {
|
||||
func (s *StepRunSourceServer) Cleanup(state multistep.StateBag) {
|
||||
if s.server == nil {
|
||||
return
|
||||
}
|
||||
|
||||
csp := state["csp"].(gophercloud.CloudServersProvider)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
csp := state.Get("csp").(gophercloud.CloudServersProvider)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Terminating the source server...")
|
||||
if err := csp.DeleteServerById(s.server.Id); err != nil {
|
||||
|
||||
@@ -368,12 +368,12 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
}
|
||||
|
||||
// Setup the state bag
|
||||
state := make(map[string]interface{})
|
||||
state["cache"] = cache
|
||||
state["config"] = &b.config
|
||||
state["driver"] = driver
|
||||
state["hook"] = hook
|
||||
state["ui"] = ui
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("cache", cache)
|
||||
state.Put("config", &b.config)
|
||||
state.Put("driver", driver)
|
||||
state.Put("hook", hook)
|
||||
state.Put("ui", ui)
|
||||
|
||||
// Run
|
||||
if b.config.PackerDebug {
|
||||
@@ -388,16 +388,16 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
b.runner.Run(state)
|
||||
|
||||
// If there was an error, return that
|
||||
if rawErr, ok := state["error"]; ok {
|
||||
if rawErr, ok := state.GetOk("error"); ok {
|
||||
return nil, rawErr.(error)
|
||||
}
|
||||
|
||||
// If we were interrupted or cancelled, then just exit.
|
||||
if _, ok := state[multistep.StateCancelled]; ok {
|
||||
if _, ok := state.GetOk(multistep.StateCancelled); ok {
|
||||
return nil, errors.New("Build was cancelled.")
|
||||
}
|
||||
|
||||
if _, ok := state[multistep.StateHalted]; ok {
|
||||
if _, ok := state.GetOk(multistep.StateHalted); ok {
|
||||
return nil, errors.New("Build was halted.")
|
||||
}
|
||||
|
||||
|
||||
@@ -3,18 +3,19 @@ package virtualbox
|
||||
import (
|
||||
gossh "code.google.com/p/go.crypto/ssh"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/communicator/ssh"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
func sshAddress(state map[string]interface{}) (string, error) {
|
||||
sshHostPort := state["sshHostPort"].(uint)
|
||||
func sshAddress(state multistep.StateBag) (string, error) {
|
||||
sshHostPort := state.Get("sshHostPort").(uint)
|
||||
return fmt.Sprintf("127.0.0.1:%d", sshHostPort), nil
|
||||
}
|
||||
|
||||
func sshConfig(state map[string]interface{}) (*gossh.ClientConfig, error) {
|
||||
config := state["config"].(*config)
|
||||
func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) {
|
||||
config := state.Get("config").(*config)
|
||||
|
||||
auth := []gossh.ClientAuth{
|
||||
gossh.ClientAuthPassword(ssh.Password(config.SSHPassword)),
|
||||
|
||||
@@ -20,10 +20,10 @@ type stepAttachFloppy struct {
|
||||
floppyPath string
|
||||
}
|
||||
|
||||
func (s *stepAttachFloppy) Run(state map[string]interface{}) multistep.StepAction {
|
||||
func (s *stepAttachFloppy) Run(state multistep.StateBag) multistep.StepAction {
|
||||
// Determine if we even have a floppy disk to attach
|
||||
var floppyPath string
|
||||
if floppyPathRaw, ok := state["floppy_path"]; ok {
|
||||
if floppyPathRaw, ok := state.GetOk("floppy_path"); ok {
|
||||
floppyPath = floppyPathRaw.(string)
|
||||
} else {
|
||||
log.Println("No floppy disk, not attaching.")
|
||||
@@ -35,13 +35,13 @@ func (s *stepAttachFloppy) Run(state map[string]interface{}) multistep.StepActio
|
||||
// floppy.
|
||||
floppyPath, err := s.copyFloppy(floppyPath)
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error preparing floppy: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error preparing floppy: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
vmName := state["vmName"].(string)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
ui.Say("Attaching floppy disk...")
|
||||
|
||||
@@ -52,7 +52,7 @@ func (s *stepAttachFloppy) Run(state map[string]interface{}) multistep.StepActio
|
||||
"--add", "floppy",
|
||||
}
|
||||
if err := driver.VBoxManage(command...); err != nil {
|
||||
state["error"] = fmt.Errorf("Error creating floppy controller: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error creating floppy controller: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ func (s *stepAttachFloppy) Run(state map[string]interface{}) multistep.StepActio
|
||||
"--medium", floppyPath,
|
||||
}
|
||||
if err := driver.VBoxManage(command...); err != nil {
|
||||
state["error"] = fmt.Errorf("Error attaching floppy: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error attaching floppy: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func (s *stepAttachFloppy) Run(state map[string]interface{}) multistep.StepActio
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepAttachFloppy) Cleanup(state map[string]interface{}) {
|
||||
func (s *stepAttachFloppy) Cleanup(state multistep.StateBag) {
|
||||
if s.floppyPath == "" {
|
||||
return
|
||||
}
|
||||
@@ -84,8 +84,8 @@ func (s *stepAttachFloppy) Cleanup(state map[string]interface{}) {
|
||||
// Delete the floppy disk
|
||||
defer os.Remove(s.floppyPath)
|
||||
|
||||
driver := state["driver"].(Driver)
|
||||
vmName := state["vmName"].(string)
|
||||
driver := state.Get("driver").(Driver)
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
command := []string{
|
||||
"storageattach", vmName,
|
||||
|
||||
@@ -15,11 +15,11 @@ type stepAttachISO struct {
|
||||
diskPath string
|
||||
}
|
||||
|
||||
func (s *stepAttachISO) Run(state map[string]interface{}) multistep.StepAction {
|
||||
driver := state["driver"].(Driver)
|
||||
isoPath := state["iso_path"].(string)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
vmName := state["vmName"].(string)
|
||||
func (s *stepAttachISO) Run(state multistep.StateBag) multistep.StepAction {
|
||||
driver := state.Get("driver").(Driver)
|
||||
isoPath := state.Get("iso_path").(string)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
// Attach the disk to the controller
|
||||
command := []string{
|
||||
@@ -32,7 +32,7 @@ func (s *stepAttachISO) Run(state map[string]interface{}) multistep.StepAction {
|
||||
}
|
||||
if err := driver.VBoxManage(command...); err != nil {
|
||||
err := fmt.Errorf("Error attaching ISO: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -43,14 +43,14 @@ func (s *stepAttachISO) Run(state map[string]interface{}) multistep.StepAction {
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepAttachISO) Cleanup(state map[string]interface{}) {
|
||||
func (s *stepAttachISO) Cleanup(state multistep.StateBag) {
|
||||
if s.diskPath == "" {
|
||||
return
|
||||
}
|
||||
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
vmName := state["vmName"].(string)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
command := []string{
|
||||
"storageattach", vmName,
|
||||
|
||||
@@ -13,11 +13,11 @@ import (
|
||||
// hard drive for the virtual machine.
|
||||
type stepCreateDisk struct{}
|
||||
|
||||
func (s *stepCreateDisk) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
vmName := state["vmName"].(string)
|
||||
func (s *stepCreateDisk) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
format := "VDI"
|
||||
path := filepath.Join(config.OutputDir, fmt.Sprintf("%s.%s", config.VMName, strings.ToLower(format)))
|
||||
@@ -34,7 +34,7 @@ func (s *stepCreateDisk) Run(state map[string]interface{}) multistep.StepAction
|
||||
err := driver.VBoxManage(command...)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating hard drive: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -44,7 +44,7 @@ func (s *stepCreateDisk) Run(state map[string]interface{}) multistep.StepAction
|
||||
err = driver.VBoxManage("storagectl", vmName, "--name", controllerName, "--add", "ide")
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating disk controller: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -60,7 +60,7 @@ func (s *stepCreateDisk) Run(state map[string]interface{}) multistep.StepAction
|
||||
}
|
||||
if err := driver.VBoxManage(command...); err != nil {
|
||||
err := fmt.Errorf("Error attaching hard drive: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -68,4 +68,4 @@ func (s *stepCreateDisk) Run(state map[string]interface{}) multistep.StepAction
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepCreateDisk) Cleanup(state map[string]interface{}) {}
|
||||
func (s *stepCreateDisk) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
@@ -14,10 +14,10 @@ type stepCreateVM struct {
|
||||
vmName string
|
||||
}
|
||||
|
||||
func (s *stepCreateVM) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *stepCreateVM) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
name := config.VMName
|
||||
|
||||
@@ -38,7 +38,7 @@ func (s *stepCreateVM) Run(state map[string]interface{}) multistep.StepAction {
|
||||
err := driver.VBoxManage(command...)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating VM: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -50,18 +50,18 @@ func (s *stepCreateVM) Run(state map[string]interface{}) multistep.StepAction {
|
||||
}
|
||||
|
||||
// Set the final name in the state bag so others can use it
|
||||
state["vmName"] = s.vmName
|
||||
state.Put("vmName", s.vmName)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepCreateVM) Cleanup(state map[string]interface{}) {
|
||||
func (s *stepCreateVM) Cleanup(state multistep.StateBag) {
|
||||
if s.vmName == "" {
|
||||
return
|
||||
}
|
||||
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Unregistering and deleting virtual machine...")
|
||||
if err := driver.VBoxManage("unregistervm", s.vmName, "--delete"); err != nil {
|
||||
|
||||
@@ -29,16 +29,16 @@ type guestAdditionsUrlTemplate struct {
|
||||
// guest_additions_path string - Path to the guest additions.
|
||||
type stepDownloadGuestAdditions struct{}
|
||||
|
||||
func (s *stepDownloadGuestAdditions) Run(state map[string]interface{}) multistep.StepAction {
|
||||
func (s *stepDownloadGuestAdditions) Run(state multistep.StateBag) multistep.StepAction {
|
||||
var action multistep.StepAction
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
config := state["config"].(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
config := state.Get("config").(*config)
|
||||
|
||||
// Get VBox version
|
||||
version, err := driver.Version()
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error reading version for guest additions download: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error reading version for guest additions download: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ func (s *stepDownloadGuestAdditions) Run(state map[string]interface{}) multistep
|
||||
url, err = config.tpl.Process(url, tplData)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error preparing guest additions url: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -85,7 +85,7 @@ func (s *stepDownloadGuestAdditions) Run(state map[string]interface{}) multistep
|
||||
url, err = common.DownloadableURL(url)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error preparing guest additions url: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -103,9 +103,9 @@ func (s *stepDownloadGuestAdditions) Run(state map[string]interface{}) multistep
|
||||
return downStep.Run(state)
|
||||
}
|
||||
|
||||
func (s *stepDownloadGuestAdditions) Cleanup(state map[string]interface{}) {}
|
||||
func (s *stepDownloadGuestAdditions) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
func (s *stepDownloadGuestAdditions) downloadAdditionsSHA256(state map[string]interface{}, additionsVersion string, additionsName string) (string, multistep.StepAction) {
|
||||
func (s *stepDownloadGuestAdditions) downloadAdditionsSHA256(state multistep.StateBag, additionsVersion string, additionsName string) (string, multistep.StepAction) {
|
||||
// First things first, we get the list of checksums for the files available
|
||||
// for this version.
|
||||
checksumsUrl := fmt.Sprintf(
|
||||
@@ -114,9 +114,9 @@ func (s *stepDownloadGuestAdditions) downloadAdditionsSHA256(state map[string]in
|
||||
|
||||
checksumsFile, err := ioutil.TempFile("", "packer")
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf(
|
||||
state.Put("error", fmt.Errorf(
|
||||
"Failed creating temporary file to store guest addition checksums: %s",
|
||||
err)
|
||||
err))
|
||||
return "", multistep.ActionHalt
|
||||
}
|
||||
defer os.Remove(checksumsFile.Name())
|
||||
@@ -136,9 +136,9 @@ func (s *stepDownloadGuestAdditions) downloadAdditionsSHA256(state map[string]in
|
||||
|
||||
// Next, we find the checksum for the file we're looking to download.
|
||||
// It is an error if the checksum cannot be found.
|
||||
checksumsF, err := os.Open(state["guest_additions_checksums_path"].(string))
|
||||
checksumsF, err := os.Open(state.Get("guest_additions_checksums_path").(string))
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error opening guest addition checksums: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error opening guest addition checksums: %s", err))
|
||||
return "", multistep.ActionHalt
|
||||
}
|
||||
defer checksumsF.Close()
|
||||
@@ -166,8 +166,8 @@ func (s *stepDownloadGuestAdditions) downloadAdditionsSHA256(state map[string]in
|
||||
}
|
||||
|
||||
if checksum == "" {
|
||||
state["error"] = fmt.Errorf(
|
||||
"The checksum for the file '%s' could not be found.", additionsName)
|
||||
state.Put("error", fmt.Errorf(
|
||||
"The checksum for the file '%s' could not be found.", additionsName))
|
||||
return "", multistep.ActionHalt
|
||||
}
|
||||
|
||||
|
||||
@@ -15,25 +15,25 @@ import (
|
||||
// exportPath string - The path to the resulting export.
|
||||
type stepExport struct{}
|
||||
|
||||
func (s *stepExport) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
vmName := state["vmName"].(string)
|
||||
func (s *stepExport) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
// Clear out the Packer-created forwarding rule
|
||||
ui.Say("Preparing to export machine...")
|
||||
ui.Message(fmt.Sprintf("Deleting forwarded port mapping for SSH (host port %d)", state["sshHostPort"]))
|
||||
ui.Message(fmt.Sprintf("Deleting forwarded port mapping for SSH (host port %d)", state.Get("sshHostPort")))
|
||||
command := []string{"modifyvm", vmName, "--natpf1", "delete", "packerssh"}
|
||||
if err := driver.VBoxManage(command...); err != nil {
|
||||
err := fmt.Errorf("Error deleting port forwarding rule: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Remove the attached floppy disk, if it exists
|
||||
if _, ok := state["floppy_path"]; ok {
|
||||
if _, ok := state.GetOk("floppy_path"); ok {
|
||||
ui.Message("Removing floppy drive...")
|
||||
command := []string{
|
||||
"storageattach", vmName,
|
||||
@@ -43,7 +43,7 @@ func (s *stepExport) Run(state map[string]interface{}) multistep.StepAction {
|
||||
"--medium", "none",
|
||||
}
|
||||
if err := driver.VBoxManage(command...); err != nil {
|
||||
state["error"] = fmt.Errorf("Error removing floppy: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error removing floppy: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -63,14 +63,14 @@ func (s *stepExport) Run(state map[string]interface{}) multistep.StepAction {
|
||||
err := driver.VBoxManage(command...)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error exporting virtual machine: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state["exportPath"] = outputPath
|
||||
state.Put("exportPath", outputPath)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepExport) Cleanup(state map[string]interface{}) {}
|
||||
func (s *stepExport) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
@@ -17,11 +17,11 @@ import (
|
||||
// Produces:
|
||||
type stepForwardSSH struct{}
|
||||
|
||||
func (s *stepForwardSSH) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
vmName := state["vmName"].(string)
|
||||
func (s *stepForwardSSH) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
log.Printf("Looking for available SSH port between %d and %d", config.SSHHostPortMin, config.SSHHostPortMax)
|
||||
var sshHostPort uint
|
||||
@@ -45,15 +45,15 @@ func (s *stepForwardSSH) Run(state map[string]interface{}) multistep.StepAction
|
||||
}
|
||||
if err := driver.VBoxManage(command...); err != nil {
|
||||
err := fmt.Errorf("Error creating port forwarding rule: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Save the port we're using so that future steps can use it
|
||||
state["sshHostPort"] = sshHostPort
|
||||
state.Put("sshHostPort", sshHostPort)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepForwardSSH) Cleanup(state map[string]interface{}) {}
|
||||
func (s *stepForwardSSH) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
@@ -23,13 +23,13 @@ type stepHTTPServer struct {
|
||||
l net.Listener
|
||||
}
|
||||
|
||||
func (s *stepHTTPServer) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *stepHTTPServer) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
var httpPort uint = 0
|
||||
if config.HTTPDir == "" {
|
||||
state["http_port"] = httpPort
|
||||
state.Put("http_port", httpPort)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
@@ -62,12 +62,12 @@ func (s *stepHTTPServer) Run(state map[string]interface{}) multistep.StepAction
|
||||
go server.Serve(s.l)
|
||||
|
||||
// Save the address into the state so it can be accessed in the future
|
||||
state["http_port"] = httpPort
|
||||
state.Put("http_port", httpPort)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepHTTPServer) Cleanup(map[string]interface{}) {
|
||||
func (s *stepHTTPServer) Cleanup(multistep.StateBag) {
|
||||
if s.l != nil {
|
||||
// Close the listener so that the HTTP server stops
|
||||
s.l.Close()
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
|
||||
type stepPrepareOutputDir struct{}
|
||||
|
||||
func (stepPrepareOutputDir) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (stepPrepareOutputDir) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
if _, err := os.Stat(config.OutputDir); err == nil && config.PackerForce {
|
||||
ui.Say("Deleting previous output directory...")
|
||||
@@ -20,20 +20,20 @@ func (stepPrepareOutputDir) Run(state map[string]interface{}) multistep.StepActi
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(config.OutputDir, 0755); err != nil {
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (stepPrepareOutputDir) Cleanup(state map[string]interface{}) {
|
||||
_, cancelled := state[multistep.StateCancelled]
|
||||
_, halted := state[multistep.StateHalted]
|
||||
func (stepPrepareOutputDir) Cleanup(state multistep.StateBag) {
|
||||
_, cancelled := state.GetOk(multistep.StateCancelled)
|
||||
_, halted := state.GetOk(multistep.StateHalted)
|
||||
|
||||
if cancelled || halted {
|
||||
config := state["config"].(*config)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
config := state.Get("config").(*config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Deleting output directory...")
|
||||
for i := 0; i < 5; i++ {
|
||||
|
||||
@@ -16,11 +16,11 @@ type stepRun struct {
|
||||
vmName string
|
||||
}
|
||||
|
||||
func (s *stepRun) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
vmName := state["vmName"].(string)
|
||||
func (s *stepRun) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
ui.Say("Starting the virtual machine...")
|
||||
guiArgument := "gui"
|
||||
@@ -33,7 +33,7 @@ func (s *stepRun) Run(state map[string]interface{}) multistep.StepAction {
|
||||
command := []string{"startvm", vmName, "--type", guiArgument}
|
||||
if err := driver.VBoxManage(command...); err != nil {
|
||||
err := fmt.Errorf("Error starting VM: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -48,13 +48,13 @@ func (s *stepRun) Run(state map[string]interface{}) multistep.StepAction {
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepRun) Cleanup(state map[string]interface{}) {
|
||||
func (s *stepRun) Cleanup(state multistep.StateBag) {
|
||||
if s.vmName == "" {
|
||||
return
|
||||
}
|
||||
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
if running, _ := driver.IsRunning(s.vmName); running {
|
||||
if err := driver.VBoxManage("controlvm", s.vmName, "poweroff"); err != nil {
|
||||
|
||||
@@ -23,12 +23,12 @@ import (
|
||||
// <nothing>
|
||||
type stepShutdown struct{}
|
||||
|
||||
func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||
comm := state["communicator"].(packer.Communicator)
|
||||
config := state["config"].(*config)
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
vmName := state["vmName"].(string)
|
||||
func (s *stepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
||||
comm := state.Get("communicator").(packer.Communicator)
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
if config.ShutdownCommand != "" {
|
||||
ui.Say("Gracefully halting virtual machine...")
|
||||
@@ -36,7 +36,7 @@ func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||
cmd := &packer.RemoteCmd{Command: config.ShutdownCommand}
|
||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
||||
err := fmt.Errorf("Failed to send shutdown command: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||
select {
|
||||
case <-shutdownTimer:
|
||||
err := errors.New("Timeout while waiting for machine to shut down.")
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
default:
|
||||
@@ -64,7 +64,7 @@ func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ui.Say("Halting the virtual machine...")
|
||||
if err := driver.Stop(vmName); err != nil {
|
||||
err := fmt.Errorf("Error stopping VM: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -74,4 +74,4 @@ func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepShutdown) Cleanup(state map[string]interface{}) {}
|
||||
func (s *stepShutdown) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
@@ -11,14 +11,14 @@ import (
|
||||
// pop-up messages don't exist.
|
||||
type stepSuppressMessages struct{}
|
||||
|
||||
func (stepSuppressMessages) Run(state map[string]interface{}) multistep.StepAction {
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (stepSuppressMessages) Run(state multistep.StateBag) multistep.StepAction {
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
log.Println("Suppressing annoying messages in VirtualBox")
|
||||
if err := driver.SuppressMessages(); err != nil {
|
||||
err := fmt.Errorf("Error configuring VirtualBox to suppress messages: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -26,4 +26,4 @@ func (stepSuppressMessages) Run(state map[string]interface{}) multistep.StepActi
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (stepSuppressMessages) Cleanup(map[string]interface{}) {}
|
||||
func (stepSuppressMessages) Cleanup(multistep.StateBag) {}
|
||||
|
||||
@@ -32,12 +32,12 @@ type bootCommandTemplateData struct {
|
||||
// <nothing>
|
||||
type stepTypeBootCommand struct{}
|
||||
|
||||
func (s *stepTypeBootCommand) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
driver := state["driver"].(Driver)
|
||||
httpPort := state["http_port"].(uint)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
vmName := state["vmName"].(string)
|
||||
func (s *stepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
httpPort := state.Get("http_port").(uint)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
tplData := &bootCommandTemplateData{
|
||||
"10.0.2.2",
|
||||
@@ -50,7 +50,7 @@ func (s *stepTypeBootCommand) Run(state map[string]interface{}) multistep.StepAc
|
||||
command, err := config.tpl.Process(command, tplData)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error preparing boot command: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -73,13 +73,13 @@ func (s *stepTypeBootCommand) Run(state map[string]interface{}) multistep.StepAc
|
||||
|
||||
// Since typing is sometimes so slow, we check for an interrupt
|
||||
// in between each character.
|
||||
if _, ok := state[multistep.StateCancelled]; ok {
|
||||
if _, ok := state.GetOk(multistep.StateCancelled); ok {
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if err := driver.VBoxManage("controlvm", vmName, "keyboardputscancode", code); err != nil {
|
||||
err := fmt.Errorf("Error sending boot command: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -89,7 +89,7 @@ func (s *stepTypeBootCommand) Run(state map[string]interface{}) multistep.StepAc
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (*stepTypeBootCommand) Cleanup(map[string]interface{}) {}
|
||||
func (*stepTypeBootCommand) Cleanup(multistep.StateBag) {}
|
||||
|
||||
func scancodes(message string) []string {
|
||||
special := make(map[string][]string)
|
||||
|
||||
@@ -14,22 +14,22 @@ type guestAdditionsPathTemplate struct {
|
||||
// This step uploads the guest additions ISO to the VM.
|
||||
type stepUploadGuestAdditions struct{}
|
||||
|
||||
func (s *stepUploadGuestAdditions) Run(state map[string]interface{}) multistep.StepAction {
|
||||
comm := state["communicator"].(packer.Communicator)
|
||||
config := state["config"].(*config)
|
||||
driver := state["driver"].(Driver)
|
||||
guestAdditionsPath := state["guest_additions_path"].(string)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *stepUploadGuestAdditions) Run(state multistep.StateBag) multistep.StepAction {
|
||||
comm := state.Get("communicator").(packer.Communicator)
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
guestAdditionsPath := state.Get("guest_additions_path").(string)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
version, err := driver.Version()
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error reading version for guest additions upload: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error reading version for guest additions upload: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
f, err := os.Open(guestAdditionsPath)
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error opening guest additions ISO: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error opening guest additions ISO: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -40,18 +40,18 @@ func (s *stepUploadGuestAdditions) Run(state map[string]interface{}) multistep.S
|
||||
config.GuestAdditionsPath, err = config.tpl.Process(config.GuestAdditionsPath, tplData)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error preparing guest additions path: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
ui.Say("Uploading VirtualBox guest additions ISO...")
|
||||
if err := comm.Upload(config.GuestAdditionsPath, f); err != nil {
|
||||
state["error"] = fmt.Errorf("Error uploading guest additions: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error uploading guest additions: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepUploadGuestAdditions) Cleanup(state map[string]interface{}) {}
|
||||
func (s *stepUploadGuestAdditions) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
@@ -12,11 +12,11 @@ import (
|
||||
// can be useful for various provisioning reasons.
|
||||
type stepUploadVersion struct{}
|
||||
|
||||
func (s *stepUploadVersion) Run(state map[string]interface{}) multistep.StepAction {
|
||||
comm := state["communicator"].(packer.Communicator)
|
||||
config := state["config"].(*config)
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *stepUploadVersion) Run(state multistep.StateBag) multistep.StepAction {
|
||||
comm := state.Get("communicator").(packer.Communicator)
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
if config.VBoxVersionFile == "" {
|
||||
log.Println("VBoxVersionFile is empty. Not uploading.")
|
||||
@@ -25,7 +25,7 @@ func (s *stepUploadVersion) Run(state map[string]interface{}) multistep.StepActi
|
||||
|
||||
version, err := driver.Version()
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error reading version for metadata upload: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error reading version for metadata upload: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -33,11 +33,11 @@ func (s *stepUploadVersion) Run(state map[string]interface{}) multistep.StepActi
|
||||
var data bytes.Buffer
|
||||
data.WriteString(version)
|
||||
if err := comm.Upload(config.VBoxVersionFile, &data); err != nil {
|
||||
state["error"] = fmt.Errorf("Error uploading VirtualBox version: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error uploading VirtualBox version: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepUploadVersion) Cleanup(state map[string]interface{}) {}
|
||||
func (s *stepUploadVersion) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
@@ -19,11 +19,11 @@ type commandTemplate struct {
|
||||
// Produces:
|
||||
type stepVBoxManage struct{}
|
||||
|
||||
func (s *stepVBoxManage) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
vmName := state["vmName"].(string)
|
||||
func (s *stepVBoxManage) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
if len(config.VBoxManage) > 0 {
|
||||
ui.Say("Executing custom VBoxManage commands...")
|
||||
@@ -42,7 +42,7 @@ func (s *stepVBoxManage) Run(state map[string]interface{}) multistep.StepAction
|
||||
command[i], err = config.tpl.Process(arg, tplData)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error preparing vboxmanage command: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -51,7 +51,7 @@ func (s *stepVBoxManage) Run(state map[string]interface{}) multistep.StepAction
|
||||
ui.Message(fmt.Sprintf("Executing: %s", strings.Join(command, " ")))
|
||||
if err := driver.VBoxManage(command...); err != nil {
|
||||
err := fmt.Errorf("Error executing command: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -60,4 +60,4 @@ func (s *stepVBoxManage) Run(state map[string]interface{}) multistep.StepAction
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepVBoxManage) Cleanup(state map[string]interface{}) {}
|
||||
func (s *stepVBoxManage) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
@@ -376,12 +376,12 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
}
|
||||
|
||||
// Setup the state bag
|
||||
state := make(map[string]interface{})
|
||||
state["cache"] = cache
|
||||
state["config"] = &b.config
|
||||
state["driver"] = driver
|
||||
state["hook"] = hook
|
||||
state["ui"] = ui
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("cache", cache)
|
||||
state.Put("config", &b.config)
|
||||
state.Put("driver", driver)
|
||||
state.Put("hook", hook)
|
||||
state.Put("ui", ui)
|
||||
|
||||
// Run!
|
||||
if b.config.PackerDebug {
|
||||
@@ -396,16 +396,16 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
b.runner.Run(state)
|
||||
|
||||
// If there was an error, return that
|
||||
if rawErr, ok := state["error"]; ok {
|
||||
if rawErr, ok := state.GetOk("error"); ok {
|
||||
return nil, rawErr.(error)
|
||||
}
|
||||
|
||||
// If we were interrupted or cancelled, then just exit.
|
||||
if _, ok := state[multistep.StateCancelled]; ok {
|
||||
if _, ok := state.GetOk(multistep.StateCancelled); ok {
|
||||
return nil, errors.New("Build was cancelled.")
|
||||
}
|
||||
|
||||
if _, ok := state[multistep.StateHalted]; ok {
|
||||
if _, ok := state.GetOk(multistep.StateHalted); ok {
|
||||
return nil, errors.New("Build was halted.")
|
||||
}
|
||||
|
||||
|
||||
@@ -4,16 +4,17 @@ import (
|
||||
gossh "code.google.com/p/go.crypto/ssh"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/communicator/ssh"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func sshAddress(state map[string]interface{}) (string, error) {
|
||||
config := state["config"].(*config)
|
||||
driver := state["driver"].(Driver)
|
||||
vmxPath := state["vmx_path"].(string)
|
||||
func sshAddress(state multistep.StateBag) (string, error) {
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
vmxPath := state.Get("vmx_path").(string)
|
||||
|
||||
log.Println("Lookup up IP information...")
|
||||
f, err := os.Open(vmxPath)
|
||||
@@ -58,8 +59,8 @@ func sshAddress(state map[string]interface{}) (string, error) {
|
||||
return fmt.Sprintf("%s:%d", ipAddress, config.SSHPort), nil
|
||||
}
|
||||
|
||||
func sshConfig(state map[string]interface{}) (*gossh.ClientConfig, error) {
|
||||
config := state["config"].(*config)
|
||||
func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) {
|
||||
config := state.Get("config").(*config)
|
||||
|
||||
auth := []gossh.ClientAuth{
|
||||
gossh.ClientAuthPassword(ssh.Password(config.SSHPassword)),
|
||||
|
||||
@@ -23,9 +23,9 @@ var KeepFileExtensions = []string{".nvram", ".vmdk", ".vmsd", ".vmx", ".vmxf"}
|
||||
// <nothing>
|
||||
type stepCleanFiles struct{}
|
||||
|
||||
func (stepCleanFiles) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (stepCleanFiles) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Deleting unnecessary VMware files...")
|
||||
visit := func(path string, info os.FileInfo, err error) error {
|
||||
@@ -55,11 +55,11 @@ func (stepCleanFiles) Run(state map[string]interface{}) multistep.StepAction {
|
||||
}
|
||||
|
||||
if err := filepath.Walk(config.OutputDir, visit); err != nil {
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (stepCleanFiles) Cleanup(map[string]interface{}) {}
|
||||
func (stepCleanFiles) Cleanup(multistep.StateBag) {}
|
||||
|
||||
@@ -22,20 +22,20 @@ import (
|
||||
// <nothing>
|
||||
type stepCleanVMX struct{}
|
||||
|
||||
func (s stepCleanVMX) Run(state map[string]interface{}) multistep.StepAction {
|
||||
isoPath := state["iso_path"].(string)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
vmxPath := state["vmx_path"].(string)
|
||||
func (s stepCleanVMX) Run(state multistep.StateBag) multistep.StepAction {
|
||||
isoPath := state.Get("iso_path").(string)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmxPath := state.Get("vmx_path").(string)
|
||||
|
||||
ui.Say("Cleaning VMX prior to finishing up...")
|
||||
|
||||
vmxData, err := s.readVMX(vmxPath)
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error reading VMX: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error reading VMX: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if _, ok := state["floppy_path"]; ok {
|
||||
if _, ok := state.GetOk("floppy_path"); ok {
|
||||
// Delete the floppy0 entries so the floppy is no longer mounted
|
||||
ui.Message("Unmounting floppy from VMX...")
|
||||
for k, _ := range vmxData {
|
||||
@@ -47,7 +47,7 @@ func (s stepCleanVMX) Run(state map[string]interface{}) multistep.StepAction {
|
||||
vmxData["floppy0.present"] = "FALSE"
|
||||
}
|
||||
|
||||
ui.Message("Detatching ISO from CD-ROM device...")
|
||||
ui.Message("Detaching ISO from CD-ROM device...")
|
||||
devRe := regexp.MustCompile(`^ide\d:\d\.`)
|
||||
for k, _ := range vmxData {
|
||||
match := devRe.FindString(k)
|
||||
@@ -67,14 +67,14 @@ func (s stepCleanVMX) Run(state map[string]interface{}) multistep.StepAction {
|
||||
|
||||
// Rewrite the VMX
|
||||
if err := WriteVMX(vmxPath, vmxData); err != nil {
|
||||
state["error"] = fmt.Errorf("Error writing VMX: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error writing VMX: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (stepCleanVMX) Cleanup(map[string]interface{}) {}
|
||||
func (stepCleanVMX) Cleanup(multistep.StateBag) {}
|
||||
|
||||
func (stepCleanVMX) readVMX(vmxPath string) (map[string]string, error) {
|
||||
vmxF, err := os.Open(vmxPath)
|
||||
|
||||
@@ -20,11 +20,11 @@ import (
|
||||
// <nothing>
|
||||
type stepCompactDisk struct{}
|
||||
|
||||
func (stepCompactDisk) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
full_disk_path := state["full_disk_path"].(string)
|
||||
func (stepCompactDisk) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
full_disk_path := state.Get("full_disk_path").(string)
|
||||
|
||||
if config.SkipCompaction == true {
|
||||
log.Println("Skipping disk compaction step...")
|
||||
@@ -33,11 +33,11 @@ func (stepCompactDisk) Run(state map[string]interface{}) multistep.StepAction {
|
||||
|
||||
ui.Say("Compacting the disk image")
|
||||
if err := driver.CompactDisk(full_disk_path); err != nil {
|
||||
state["error"] = fmt.Errorf("Error compacting disk: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error compacting disk: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (stepCompactDisk) Cleanup(map[string]interface{}) {}
|
||||
func (stepCompactDisk) Cleanup(multistep.StateBag) {}
|
||||
|
||||
@@ -22,15 +22,15 @@ import (
|
||||
// vnc_port uint - The port that VNC is configured to listen on.
|
||||
type stepConfigureVNC struct{}
|
||||
|
||||
func (stepConfigureVNC) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
vmxPath := state["vmx_path"].(string)
|
||||
func (stepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmxPath := state.Get("vmx_path").(string)
|
||||
|
||||
f, err := os.Open(vmxPath)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error reading VMX data: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -38,7 +38,7 @@ func (stepConfigureVNC) Run(state map[string]interface{}) multistep.StepAction {
|
||||
vmxBytes, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error reading VMX data: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -67,15 +67,15 @@ func (stepConfigureVNC) Run(state map[string]interface{}) multistep.StepAction {
|
||||
|
||||
if err := WriteVMX(vmxPath, vmxData); err != nil {
|
||||
err := fmt.Errorf("Error writing VMX data: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state["vnc_port"] = vncPort
|
||||
state.Put("vnc_port", vncPort)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (stepConfigureVNC) Cleanup(map[string]interface{}) {
|
||||
func (stepConfigureVNC) Cleanup(multistep.StateBag) {
|
||||
}
|
||||
|
||||
@@ -18,23 +18,23 @@ import (
|
||||
// full_disk_path (string) - The full path to the created disk.
|
||||
type stepCreateDisk struct{}
|
||||
|
||||
func (stepCreateDisk) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (stepCreateDisk) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Creating virtual machine disk")
|
||||
full_disk_path := filepath.Join(config.OutputDir, config.DiskName+".vmdk")
|
||||
if err := driver.CreateDisk(full_disk_path, fmt.Sprintf("%dM", config.DiskSize), config.DiskTypeId); err != nil {
|
||||
err := fmt.Errorf("Error creating disk: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state["full_disk_path"] = full_disk_path
|
||||
state.Put("full_disk_path", full_disk_path)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (stepCreateDisk) Cleanup(map[string]interface{}) {}
|
||||
func (stepCreateDisk) Cleanup(multistep.StateBag) {}
|
||||
|
||||
@@ -28,10 +28,10 @@ type vmxTemplateData struct {
|
||||
// vmx_path string - The path to the VMX file.
|
||||
type stepCreateVMX struct{}
|
||||
|
||||
func (stepCreateVMX) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
isoPath := state["iso_path"].(string)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (stepCreateVMX) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
isoPath := state.Get("iso_path").(string)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Building and writing VMX file")
|
||||
|
||||
@@ -47,7 +47,7 @@ func (stepCreateVMX) Run(state map[string]interface{}) multistep.StepAction {
|
||||
f, err := os.Open(config.VMXTemplatePath)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error reading VMX template: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -56,7 +56,7 @@ func (stepCreateVMX) Run(state map[string]interface{}) multistep.StepAction {
|
||||
rawBytes, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error reading VMX template: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -67,7 +67,7 @@ func (stepCreateVMX) Run(state map[string]interface{}) multistep.StepAction {
|
||||
vmxContents, err := config.tpl.Process(vmxTemplate, tplData)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error procesing VMX template: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -81,7 +81,7 @@ func (stepCreateVMX) Run(state map[string]interface{}) multistep.StepAction {
|
||||
}
|
||||
}
|
||||
|
||||
if floppyPathRaw, ok := state["floppy_path"]; ok {
|
||||
if floppyPathRaw, ok := state.GetOk("floppy_path"); ok {
|
||||
log.Println("Floppy path present, setting in VMX")
|
||||
vmxData["floppy0.present"] = "TRUE"
|
||||
vmxData["floppy0.fileType"] = "file"
|
||||
@@ -91,17 +91,17 @@ func (stepCreateVMX) Run(state map[string]interface{}) multistep.StepAction {
|
||||
vmxPath := filepath.Join(config.OutputDir, config.VMName+".vmx")
|
||||
if err := WriteVMX(vmxPath, vmxData); err != nil {
|
||||
err := fmt.Errorf("Error creating VMX file: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state["vmx_path"] = vmxPath
|
||||
state.Put("vmx_path", vmxPath)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (stepCreateVMX) Cleanup(map[string]interface{}) {
|
||||
func (stepCreateVMX) Cleanup(multistep.StateBag) {
|
||||
}
|
||||
|
||||
// This is the default VMX template used if no other template is given.
|
||||
|
||||
@@ -23,13 +23,13 @@ type stepHTTPServer struct {
|
||||
l net.Listener
|
||||
}
|
||||
|
||||
func (s *stepHTTPServer) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *stepHTTPServer) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
var httpPort uint = 0
|
||||
if config.HTTPDir == "" {
|
||||
state["http_port"] = httpPort
|
||||
state.Put("http_port", httpPort)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
@@ -62,12 +62,12 @@ func (s *stepHTTPServer) Run(state map[string]interface{}) multistep.StepAction
|
||||
go server.Serve(s.l)
|
||||
|
||||
// Save the address into the state so it can be accessed in the future
|
||||
state["http_port"] = httpPort
|
||||
state.Put("http_port", httpPort)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepHTTPServer) Cleanup(map[string]interface{}) {
|
||||
func (s *stepHTTPServer) Cleanup(multistep.StateBag) {
|
||||
if s.l != nil {
|
||||
// Close the listener so that the HTTP server stops
|
||||
s.l.Close()
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
|
||||
type stepPrepareOutputDir struct{}
|
||||
|
||||
func (stepPrepareOutputDir) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (stepPrepareOutputDir) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
if _, err := os.Stat(config.OutputDir); err == nil && config.PackerForce {
|
||||
ui.Say("Deleting previous output directory...")
|
||||
@@ -20,20 +20,20 @@ func (stepPrepareOutputDir) Run(state map[string]interface{}) multistep.StepActi
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(config.OutputDir, 0755); err != nil {
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (stepPrepareOutputDir) Cleanup(state map[string]interface{}) {
|
||||
_, cancelled := state[multistep.StateCancelled]
|
||||
_, halted := state[multistep.StateHalted]
|
||||
func (stepPrepareOutputDir) Cleanup(state multistep.StateBag) {
|
||||
_, cancelled := state.GetOk(multistep.StateCancelled)
|
||||
_, halted := state.GetOk(multistep.StateHalted)
|
||||
|
||||
if cancelled || halted {
|
||||
config := state["config"].(*config)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
config := state.Get("config").(*config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Deleting output directory...")
|
||||
for i := 0; i < 5; i++ {
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
|
||||
type stepPrepareTools struct{}
|
||||
|
||||
func (*stepPrepareTools) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
driver := state["driver"].(Driver)
|
||||
func (*stepPrepareTools) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
|
||||
if config.ToolsUploadFlavor == "" {
|
||||
return multistep.ActionContinue
|
||||
@@ -18,16 +18,16 @@ func (*stepPrepareTools) Run(state map[string]interface{}) multistep.StepAction
|
||||
|
||||
path := driver.ToolsIsoPath(config.ToolsUploadFlavor)
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
state["error"] = fmt.Errorf(
|
||||
state.Put("error", fmt.Errorf(
|
||||
"Couldn't find VMware tools for '%s'! VMware often downloads these\n"+
|
||||
"tools on-demand. However, to do this, you need to create a fake VM\n"+
|
||||
"of the proper type then click the 'install tools' option in the\n"+
|
||||
"VMware GUI.", config.ToolsUploadFlavor)
|
||||
"VMware GUI.", config.ToolsUploadFlavor))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state["tools_upload_source"] = path
|
||||
state.Put("tools_upload_source", path)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (*stepPrepareTools) Cleanup(map[string]interface{}) {}
|
||||
func (*stepPrepareTools) Cleanup(multistep.StateBag) {}
|
||||
|
||||
+10
-10
@@ -22,12 +22,12 @@ type stepRun struct {
|
||||
vmxPath string
|
||||
}
|
||||
|
||||
func (s *stepRun) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
vmxPath := state["vmx_path"].(string)
|
||||
vncPort := state["vnc_port"].(uint)
|
||||
func (s *stepRun) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmxPath := state.Get("vmx_path").(string)
|
||||
vncPort := state.Get("vnc_port").(uint)
|
||||
|
||||
// Set the VMX path so that we know we started the machine
|
||||
s.bootTime = time.Now()
|
||||
@@ -43,7 +43,7 @@ func (s *stepRun) Run(state map[string]interface{}) multistep.StepAction {
|
||||
|
||||
if err := driver.Start(vmxPath, config.Headless); err != nil {
|
||||
err := fmt.Errorf("Error starting VM: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -57,9 +57,9 @@ func (s *stepRun) Run(state map[string]interface{}) multistep.StepAction {
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepRun) Cleanup(state map[string]interface{}) {
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *stepRun) Cleanup(state multistep.StateBag) {
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
// If we started the machine... stop it.
|
||||
if s.vmxPath != "" {
|
||||
|
||||
@@ -27,12 +27,12 @@ import (
|
||||
// <nothing>
|
||||
type stepShutdown struct{}
|
||||
|
||||
func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||
comm := state["communicator"].(packer.Communicator)
|
||||
config := state["config"].(*config)
|
||||
driver := state["driver"].(Driver)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
vmxPath := state["vmx_path"].(string)
|
||||
func (s *stepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
||||
comm := state.Get("communicator").(packer.Communicator)
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmxPath := state.Get("vmx_path").(string)
|
||||
|
||||
if config.ShutdownCommand != "" {
|
||||
ui.Say("Gracefully halting virtual machine...")
|
||||
@@ -46,7 +46,7 @@ func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||
}
|
||||
if err := comm.Start(cmd); err != nil {
|
||||
err := fmt.Errorf("Failed to send shutdown command: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -56,9 +56,9 @@ func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||
|
||||
// If the command failed to run, notify the user in some way.
|
||||
if cmd.ExitStatus != 0 {
|
||||
state["error"] = fmt.Errorf(
|
||||
state.Put("error", fmt.Errorf(
|
||||
"Shutdown command has non-zero exit status.\n\nStdout: %s\n\nStderr: %s",
|
||||
stdout.String(), stderr.String())
|
||||
stdout.String(), stderr.String()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||
select {
|
||||
case <-shutdownTimer:
|
||||
err := errors.New("Timeout while waiting for machine to shut down.")
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
default:
|
||||
@@ -87,7 +87,7 @@ func (s *stepShutdown) Run(state map[string]interface{}) multistep.StepAction {
|
||||
} else {
|
||||
if err := driver.Stop(vmxPath); err != nil {
|
||||
err := fmt.Errorf("Error stopping VM: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -132,4 +132,4 @@ LockWaitLoop:
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepShutdown) Cleanup(state map[string]interface{}) {}
|
||||
func (s *stepShutdown) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
@@ -34,18 +34,18 @@ type bootCommandTemplateData struct {
|
||||
// <nothing>
|
||||
type stepTypeBootCommand struct{}
|
||||
|
||||
func (s *stepTypeBootCommand) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
httpPort := state["http_port"].(uint)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
vncPort := state["vnc_port"].(uint)
|
||||
func (s *stepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
httpPort := state.Get("http_port").(uint)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vncPort := state.Get("vnc_port").(uint)
|
||||
|
||||
// Connect to VNC
|
||||
ui.Say("Connecting to VM via VNC")
|
||||
nc, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", vncPort))
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error connecting to VNC: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func (s *stepTypeBootCommand) Run(state map[string]interface{}) multistep.StepAc
|
||||
c, err := vnc.Client(nc, &vnc.ClientConfig{Exclusive: true})
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error handshaking with VNC: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -73,7 +73,7 @@ func (s *stepTypeBootCommand) Run(state map[string]interface{}) multistep.StepAc
|
||||
hostIp, err := ipFinder.HostIP()
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error detecting host IP: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
@@ -91,14 +91,14 @@ func (s *stepTypeBootCommand) Run(state map[string]interface{}) multistep.StepAc
|
||||
command, err := config.tpl.Process(command, tplData)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error preparing boot command: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Check for interrupts between typing things so we can cancel
|
||||
// since this isn't the fastest thing.
|
||||
if _, ok := state[multistep.StateCancelled]; ok {
|
||||
if _, ok := state.GetOk(multistep.StateCancelled); ok {
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ func (s *stepTypeBootCommand) Run(state map[string]interface{}) multistep.StepAc
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (*stepTypeBootCommand) Cleanup(map[string]interface{}) {}
|
||||
func (*stepTypeBootCommand) Cleanup(multistep.StateBag) {}
|
||||
|
||||
func vncSendString(c *vnc.ClientConn, original string) {
|
||||
special := make(map[string]uint32)
|
||||
|
||||
@@ -13,20 +13,20 @@ type toolsUploadPathTemplate struct {
|
||||
|
||||
type stepUploadTools struct{}
|
||||
|
||||
func (*stepUploadTools) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config := state["config"].(*config)
|
||||
func (*stepUploadTools) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*config)
|
||||
if config.ToolsUploadFlavor == "" {
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
comm := state["communicator"].(packer.Communicator)
|
||||
tools_source := state["tools_upload_source"].(string)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
comm := state.Get("communicator").(packer.Communicator)
|
||||
tools_source := state.Get("tools_upload_source").(string)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say(fmt.Sprintf("Uploading the '%s' VMware Tools", config.ToolsUploadFlavor))
|
||||
f, err := os.Open(tools_source)
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error opening VMware Tools ISO: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error opening VMware Tools ISO: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
defer f.Close()
|
||||
@@ -35,17 +35,17 @@ func (*stepUploadTools) Run(state map[string]interface{}) multistep.StepAction {
|
||||
config.ToolsUploadPath, err = config.tpl.Process(config.ToolsUploadPath, tplData)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error preparing upload path: %s", err)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if err := comm.Upload(config.ToolsUploadPath, f); err != nil {
|
||||
state["error"] = fmt.Errorf("Error uploading VMware Tools: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error uploading VMware Tools: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (*stepUploadTools) Cleanup(map[string]interface{}) {}
|
||||
func (*stepUploadTools) Cleanup(multistep.StateBag) {}
|
||||
|
||||
@@ -44,10 +44,28 @@ func (c Command) Run(env packer.Environment, args []string) int {
|
||||
ui := env.Ui()
|
||||
|
||||
// Variables
|
||||
ui.Say("Variables and their defaults:\n")
|
||||
if len(tpl.Variables) == 0 {
|
||||
ui.Say("Variables:\n")
|
||||
ui.Say(" <No variables>")
|
||||
} else {
|
||||
requiredHeader := false
|
||||
for k, v := range tpl.Variables {
|
||||
if v.Required {
|
||||
if !requiredHeader {
|
||||
requiredHeader = true
|
||||
ui.Say("Required variables:\n")
|
||||
}
|
||||
|
||||
ui.Machine("template-variable", k, v.Default, "1")
|
||||
ui.Say(" " + k)
|
||||
}
|
||||
}
|
||||
|
||||
if requiredHeader {
|
||||
ui.Say("")
|
||||
}
|
||||
|
||||
ui.Say("Optional variables and their defaults:\n")
|
||||
keys := make([]string, 0, len(tpl.Variables))
|
||||
max := 0
|
||||
for k, _ := range tpl.Variables {
|
||||
@@ -61,10 +79,14 @@ func (c Command) Run(env packer.Environment, args []string) int {
|
||||
|
||||
for _, k := range keys {
|
||||
v := tpl.Variables[k]
|
||||
if v.Required {
|
||||
continue
|
||||
}
|
||||
|
||||
padding := strings.Repeat(" ", max-len(k))
|
||||
output := fmt.Sprintf(" %s%s = %s", k, padding, v)
|
||||
|
||||
ui.Machine("template-variable", k, v)
|
||||
ui.Machine("template-variable", k, v.Default, "0")
|
||||
ui.Say(output)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
// MultistepDebugFn will return a proper multistep.DebugPauseFn to
|
||||
// use for debugging if you're using multistep in your builder.
|
||||
func MultistepDebugFn(ui packer.Ui) multistep.DebugPauseFn {
|
||||
return func(loc multistep.DebugLocation, name string, state map[string]interface{}) {
|
||||
return func(loc multistep.DebugLocation, name string, state multistep.StateBag) {
|
||||
var locationString string
|
||||
switch loc {
|
||||
case multistep.DebugLocationAfterRun:
|
||||
@@ -41,7 +41,7 @@ func MultistepDebugFn(ui packer.Ui) multistep.DebugPauseFn {
|
||||
case <-result:
|
||||
return
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
if _, ok := state[multistep.StateCancelled]; ok {
|
||||
if _, ok := state.GetOk(multistep.StateCancelled); ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,11 @@ type StepConnectSSH struct {
|
||||
// SSHAddress is a function that returns the TCP address to connect to
|
||||
// for SSH. This is a function so that you can query information
|
||||
// if necessary for this address.
|
||||
SSHAddress func(map[string]interface{}) (string, error)
|
||||
SSHAddress func(multistep.StateBag) (string, error)
|
||||
|
||||
// SSHConfig is a function that returns the proper client configuration
|
||||
// for SSH access.
|
||||
SSHConfig func(map[string]interface{}) (*gossh.ClientConfig, error)
|
||||
SSHConfig func(multistep.StateBag) (*gossh.ClientConfig, error)
|
||||
|
||||
// SSHWaitTimeout is the total timeout to wait for SSH to become available.
|
||||
SSHWaitTimeout time.Duration
|
||||
@@ -40,8 +40,8 @@ type StepConnectSSH struct {
|
||||
comm packer.Communicator
|
||||
}
|
||||
|
||||
func (s *StepConnectSSH) Run(state map[string]interface{}) multistep.StepAction {
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepConnectSSH) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
var comm packer.Communicator
|
||||
var err error
|
||||
@@ -69,14 +69,14 @@ WaitLoop:
|
||||
|
||||
ui.Say("Connected to SSH!")
|
||||
s.comm = comm
|
||||
state["communicator"] = comm
|
||||
state.Put("communicator", comm)
|
||||
break WaitLoop
|
||||
case <-timeout:
|
||||
ui.Error("Timeout waiting for SSH.")
|
||||
close(cancel)
|
||||
return multistep.ActionHalt
|
||||
case <-time.After(1 * time.Second):
|
||||
if _, ok := state[multistep.StateCancelled]; ok {
|
||||
if _, ok := state.GetOk(multistep.StateCancelled); ok {
|
||||
// The step sequence was cancelled, so cancel waiting for SSH
|
||||
// and just start the halting process.
|
||||
close(cancel)
|
||||
@@ -89,10 +89,10 @@ WaitLoop:
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepConnectSSH) Cleanup(map[string]interface{}) {
|
||||
func (s *StepConnectSSH) Cleanup(multistep.StateBag) {
|
||||
}
|
||||
|
||||
func (s *StepConnectSSH) waitForSSH(state map[string]interface{}, cancel <-chan struct{}) (packer.Communicator, error) {
|
||||
func (s *StepConnectSSH) waitForSSH(state multistep.StateBag, cancel <-chan struct{}) (packer.Communicator, error) {
|
||||
handshakeAttempts := 0
|
||||
|
||||
var comm packer.Communicator
|
||||
|
||||
@@ -22,19 +22,20 @@ type StepCreateFloppy struct {
|
||||
floppyPath string
|
||||
}
|
||||
|
||||
func (s *StepCreateFloppy) Run(state map[string]interface{}) multistep.StepAction {
|
||||
func (s *StepCreateFloppy) Run(state multistep.StateBag) multistep.StepAction {
|
||||
if len(s.Files) == 0 {
|
||||
log.Println("No floppy files specified. Floppy disk will not be made.")
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
ui := state["ui"].(packer.Ui)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
ui.Say("Creating floppy disk...")
|
||||
|
||||
// Create a temporary file to be our floppy drive
|
||||
floppyF, err := ioutil.TempFile("", "packer")
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error creating temporary file for floppy: %s", err)
|
||||
state.Put("error",
|
||||
fmt.Errorf("Error creating temporary file for floppy: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
defer floppyF.Close()
|
||||
@@ -46,7 +47,7 @@ func (s *StepCreateFloppy) Run(state map[string]interface{}) multistep.StepActio
|
||||
|
||||
// Set the size of the file to be a floppy sized
|
||||
if err := floppyF.Truncate(1440 * 1024); err != nil {
|
||||
state["error"] = fmt.Errorf("Error creating floppy: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error creating floppy: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -54,7 +55,7 @@ func (s *StepCreateFloppy) Run(state map[string]interface{}) multistep.StepActio
|
||||
log.Println("Initializing block device backed by temporary file")
|
||||
device, err := fs.NewFileDisk(floppyF)
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error creating floppy: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error creating floppy: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -66,7 +67,7 @@ func (s *StepCreateFloppy) Run(state map[string]interface{}) multistep.StepActio
|
||||
OEMName: "packer",
|
||||
}
|
||||
if fat.FormatSuperFloppy(device, formatConfig); err != nil {
|
||||
state["error"] = fmt.Errorf("Error creating floppy: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error creating floppy: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -74,7 +75,7 @@ func (s *StepCreateFloppy) Run(state map[string]interface{}) multistep.StepActio
|
||||
log.Println("Initializing FAT filesystem on block device")
|
||||
fatFs, err := fat.New(device)
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error creating floppy: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error creating floppy: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -82,7 +83,7 @@ func (s *StepCreateFloppy) Run(state map[string]interface{}) multistep.StepActio
|
||||
log.Println("Reading the root directory from the filesystem")
|
||||
rootDir, err := fatFs.RootDir()
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error creating floppy: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error creating floppy: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
@@ -90,18 +91,18 @@ func (s *StepCreateFloppy) Run(state map[string]interface{}) multistep.StepActio
|
||||
for _, filename := range s.Files {
|
||||
ui.Message(fmt.Sprintf("Copying: %s", filepath.Base(filename)))
|
||||
if s.addSingleFile(rootDir, filename); err != nil {
|
||||
state["error"] = fmt.Errorf("Error adding file to floppy: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error adding file to floppy: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
}
|
||||
|
||||
// Set the path to the floppy so it can be used later
|
||||
state["floppy_path"] = s.floppyPath
|
||||
state.Put("floppy_path", s.floppyPath)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepCreateFloppy) Cleanup(map[string]interface{}) {
|
||||
func (s *StepCreateFloppy) Cleanup(multistep.StateBag) {
|
||||
if s.floppyPath != "" {
|
||||
log.Printf("Deleting floppy disk: %s", s.floppyPath)
|
||||
os.Remove(s.floppyPath)
|
||||
|
||||
+10
-10
@@ -37,16 +37,16 @@ type StepDownload struct {
|
||||
Url []string
|
||||
}
|
||||
|
||||
func (s *StepDownload) Run(state map[string]interface{}) multistep.StepAction {
|
||||
cache := state["cache"].(packer.Cache)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (s *StepDownload) Run(state multistep.StateBag) multistep.StepAction {
|
||||
cache := state.Get("cache").(packer.Cache)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
var checksum []byte
|
||||
if s.Checksum != "" {
|
||||
var err error
|
||||
checksum, err = hex.DecodeString(s.Checksum)
|
||||
if err != nil {
|
||||
state["error"] = fmt.Errorf("Error parsing checksum: %s", err)
|
||||
state.Put("error", fmt.Errorf("Error parsing checksum: %s", err))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
}
|
||||
@@ -89,20 +89,20 @@ func (s *StepDownload) Run(state map[string]interface{}) multistep.StepAction {
|
||||
|
||||
if finalPath == "" {
|
||||
err := fmt.Errorf("%s download failed.", s.Description)
|
||||
state["error"] = err
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state[s.ResultKey] = finalPath
|
||||
state.Put(s.ResultKey, finalPath)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepDownload) Cleanup(map[string]interface{}) {}
|
||||
func (s *StepDownload) Cleanup(multistep.StateBag) {}
|
||||
|
||||
func (s *StepDownload) download(config *DownloadConfig, state map[string]interface{}) (string, error, bool) {
|
||||
func (s *StepDownload) download(config *DownloadConfig, state multistep.StateBag) (string, error, bool) {
|
||||
var path string
|
||||
ui := state["ui"].(packer.Ui)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
download := NewDownloadClient(config)
|
||||
|
||||
downloadCompleteCh := make(chan error, 1)
|
||||
@@ -129,7 +129,7 @@ func (s *StepDownload) download(config *DownloadConfig, state map[string]interfa
|
||||
ui.Message(fmt.Sprintf("Download progress: %d%%", progress))
|
||||
}
|
||||
case <-time.After(1 * time.Second):
|
||||
if _, ok := state[multistep.StateCancelled]; ok {
|
||||
if _, ok := state.GetOk(multistep.StateCancelled); ok {
|
||||
ui.Say("Interrupt received. Cancelling download...")
|
||||
return "", nil, false
|
||||
}
|
||||
|
||||
+29
-10
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
// StepProvision runs the provisioners.
|
||||
@@ -17,18 +18,36 @@ import (
|
||||
// <nothing>
|
||||
type StepProvision struct{}
|
||||
|
||||
func (*StepProvision) Run(state map[string]interface{}) multistep.StepAction {
|
||||
comm := state["communicator"].(packer.Communicator)
|
||||
hook := state["hook"].(packer.Hook)
|
||||
ui := state["ui"].(packer.Ui)
|
||||
func (*StepProvision) Run(state multistep.StateBag) multistep.StepAction {
|
||||
comm := state.Get("communicator").(packer.Communicator)
|
||||
hook := state.Get("hook").(packer.Hook)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
// Run the provisioner in a goroutine so we can continually check
|
||||
// for cancellations...
|
||||
log.Println("Running the provision hook")
|
||||
if err := hook.Run(packer.HookProvision, ui, comm, nil); err != nil {
|
||||
state["error"] = err
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
errCh <- hook.Run(packer.HookProvision, ui, comm, nil)
|
||||
}()
|
||||
|
||||
return multistep.ActionContinue
|
||||
for {
|
||||
select {
|
||||
case err := <-errCh:
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
case <-time.After(1 * time.Second):
|
||||
if _, ok := state.GetOk(multistep.StateCancelled); ok {
|
||||
log.Println("Cancelling provisioning due to interrupt...")
|
||||
hook.Cancel()
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (*StepProvision) Cleanup(map[string]interface{}) {}
|
||||
func (*StepProvision) Cleanup(multistep.StateBag) {}
|
||||
|
||||
@@ -24,7 +24,12 @@ func (k *SimpleKeychain) AddPEMKey(key string) (err error) {
|
||||
return errors.New("no block in key")
|
||||
}
|
||||
|
||||
rsakey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
var rsakey interface{}
|
||||
rsakey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
rsakey, err = x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
+28
-11
@@ -77,7 +77,7 @@ type coreBuild struct {
|
||||
hooks map[string][]Hook
|
||||
postProcessors [][]coreBuildPostProcessor
|
||||
provisioners []coreBuildProvisioner
|
||||
variables map[string]string
|
||||
variables map[string]coreBuildVariable
|
||||
|
||||
debug bool
|
||||
force bool
|
||||
@@ -101,6 +101,12 @@ type coreBuildProvisioner struct {
|
||||
config []interface{}
|
||||
}
|
||||
|
||||
// A user-variable that is part of a single build.
|
||||
type coreBuildVariable struct {
|
||||
Default string
|
||||
Required bool
|
||||
}
|
||||
|
||||
// Returns the name of the build.
|
||||
func (b *coreBuild) Name() string {
|
||||
return b.name
|
||||
@@ -120,27 +126,36 @@ func (b *coreBuild) Prepare(userVars map[string]string) (err error) {
|
||||
b.prepareCalled = true
|
||||
|
||||
// Compile the variables
|
||||
varErrs := make([]error, 0)
|
||||
variables := make(map[string]string)
|
||||
for k, v := range b.variables {
|
||||
variables[k] = v
|
||||
variables[k] = v.Default
|
||||
|
||||
if v.Required {
|
||||
if _, ok := userVars[k]; !ok {
|
||||
varErrs = append(varErrs,
|
||||
fmt.Errorf("Required user variable '%s' not set", k))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if userVars != nil {
|
||||
errs := make([]error, 0)
|
||||
for k, v := range userVars {
|
||||
if _, ok := variables[k]; !ok {
|
||||
errs = append(
|
||||
errs, fmt.Errorf("Unknown user variable: %s", k))
|
||||
varErrs = append(
|
||||
varErrs, fmt.Errorf("Unknown user variable: %s", k))
|
||||
continue
|
||||
}
|
||||
|
||||
variables[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return &MultiError{
|
||||
Errors: errs,
|
||||
}
|
||||
// If there were any problem with variables, return an error right
|
||||
// away because we can't be certain anything else will actually work.
|
||||
if len(varErrs) > 0 {
|
||||
return &MultiError{
|
||||
Errors: varErrs,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,10 +222,12 @@ func (b *coreBuild) Run(originalUi Ui, cache Cache) ([]Artifact, error) {
|
||||
hooks[HookProvision] = make([]Hook, 0, 1)
|
||||
}
|
||||
|
||||
hooks[HookProvision] = append(hooks[HookProvision], &ProvisionHook{provisioners})
|
||||
hooks[HookProvision] = append(hooks[HookProvision], &ProvisionHook{
|
||||
Provisioners: provisioners,
|
||||
})
|
||||
}
|
||||
|
||||
hook := &DispatchHook{hooks}
|
||||
hook := &DispatchHook{Mapping: hooks}
|
||||
artifacts := make([]Artifact, 0, 1)
|
||||
|
||||
// The builder just has a normal Ui, but targetted
|
||||
|
||||
+35
-17
@@ -13,17 +13,17 @@ func testBuild() *coreBuild {
|
||||
builderConfig: 42,
|
||||
builderType: "foo",
|
||||
hooks: map[string][]Hook{
|
||||
"foo": []Hook{&TestHook{}},
|
||||
"foo": []Hook{&MockHook{}},
|
||||
},
|
||||
provisioners: []coreBuildProvisioner{
|
||||
coreBuildProvisioner{&TestProvisioner{}, []interface{}{42}},
|
||||
coreBuildProvisioner{&MockProvisioner{}, []interface{}{42}},
|
||||
},
|
||||
postProcessors: [][]coreBuildPostProcessor{
|
||||
[]coreBuildPostProcessor{
|
||||
coreBuildPostProcessor{&TestPostProcessor{artifactId: "pp"}, "testPP", make(map[string]interface{}), true},
|
||||
},
|
||||
},
|
||||
variables: make(map[string]string),
|
||||
variables: make(map[string]coreBuildVariable),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,9 +59,9 @@ func TestBuild_Prepare(t *testing.T) {
|
||||
assert.Equal(builder.prepareConfig, []interface{}{42, packerConfig}, "prepare config should be 42")
|
||||
|
||||
coreProv := build.provisioners[0]
|
||||
prov := coreProv.provisioner.(*TestProvisioner)
|
||||
assert.True(prov.prepCalled, "prepare should be called")
|
||||
assert.Equal(prov.prepConfigs, []interface{}{42, packerConfig}, "prepare should be called with proper config")
|
||||
prov := coreProv.provisioner.(*MockProvisioner)
|
||||
assert.True(prov.PrepCalled, "prepare should be called")
|
||||
assert.Equal(prov.PrepConfigs, []interface{}{42, packerConfig}, "prepare should be called with proper config")
|
||||
|
||||
corePP := build.postProcessors[0][0]
|
||||
pp := corePP.processor.(*TestPostProcessor)
|
||||
@@ -104,9 +104,9 @@ func TestBuild_Prepare_Debug(t *testing.T) {
|
||||
assert.Equal(builder.prepareConfig, []interface{}{42, packerConfig}, "prepare config should be 42")
|
||||
|
||||
coreProv := build.provisioners[0]
|
||||
prov := coreProv.provisioner.(*TestProvisioner)
|
||||
assert.True(prov.prepCalled, "prepare should be called")
|
||||
assert.Equal(prov.prepConfigs, []interface{}{42, packerConfig}, "prepare should be called with proper config")
|
||||
prov := coreProv.provisioner.(*MockProvisioner)
|
||||
assert.True(prov.PrepCalled, "prepare should be called")
|
||||
assert.Equal(prov.PrepConfigs, []interface{}{42, packerConfig}, "prepare should be called with proper config")
|
||||
}
|
||||
|
||||
func TestBuildPrepare_variables_default(t *testing.T) {
|
||||
@@ -116,7 +116,7 @@ func TestBuildPrepare_variables_default(t *testing.T) {
|
||||
}
|
||||
|
||||
build := testBuild()
|
||||
build.variables["foo"] = "bar"
|
||||
build.variables["foo"] = coreBuildVariable{Default: "bar"}
|
||||
builder := build.builder.(*TestBuilder)
|
||||
|
||||
err := build.Prepare(nil)
|
||||
@@ -135,7 +135,7 @@ func TestBuildPrepare_variables_default(t *testing.T) {
|
||||
|
||||
func TestBuildPrepare_variables_nonexist(t *testing.T) {
|
||||
build := testBuild()
|
||||
build.variables["foo"] = "bar"
|
||||
build.variables["foo"] = coreBuildVariable{Default: "bar"}
|
||||
|
||||
err := build.Prepare(map[string]string{"bar": "baz"})
|
||||
if err == nil {
|
||||
@@ -150,7 +150,7 @@ func TestBuildPrepare_variables_override(t *testing.T) {
|
||||
}
|
||||
|
||||
build := testBuild()
|
||||
build.variables["foo"] = "bar"
|
||||
build.variables["foo"] = coreBuildVariable{Default: "bar"}
|
||||
builder := build.builder.(*TestBuilder)
|
||||
|
||||
err := build.Prepare(map[string]string{"foo": "baz"})
|
||||
@@ -167,6 +167,24 @@ func TestBuildPrepare_variables_override(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildPrepare_variablesRequired(t *testing.T) {
|
||||
build := testBuild()
|
||||
build.variables["foo"] = coreBuildVariable{Required: true}
|
||||
|
||||
err := build.Prepare(map[string]string{})
|
||||
if err == nil {
|
||||
t.Fatal("should have had error")
|
||||
}
|
||||
|
||||
// Test with setting the value
|
||||
build = testBuild()
|
||||
build.variables["foo"] = coreBuildVariable{Required: true}
|
||||
err = build.Prepare(map[string]string{"foo": ""})
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuild_Run(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
@@ -187,14 +205,14 @@ func TestBuild_Run(t *testing.T) {
|
||||
dispatchHook := builder.runHook
|
||||
dispatchHook.Run("foo", nil, nil, 42)
|
||||
|
||||
hook := build.hooks["foo"][0].(*TestHook)
|
||||
assert.True(hook.runCalled, "run should be called")
|
||||
assert.Equal(hook.runData, 42, "should have correct data")
|
||||
hook := build.hooks["foo"][0].(*MockHook)
|
||||
assert.True(hook.RunCalled, "run should be called")
|
||||
assert.Equal(hook.RunData, 42, "should have correct data")
|
||||
|
||||
// Verify provisioners run
|
||||
dispatchHook.Run(HookProvision, nil, nil, 42)
|
||||
prov := build.provisioners[0].provisioner.(*TestProvisioner)
|
||||
assert.True(prov.provCalled, "provision should be called")
|
||||
prov := build.provisioners[0].provisioner.(*MockProvisioner)
|
||||
assert.True(prov.ProvCalled, "provision should be called")
|
||||
|
||||
// Verify post-processor was run
|
||||
pp := build.postProcessors[0][0].processor.(*TestPostProcessor)
|
||||
|
||||
@@ -20,7 +20,7 @@ func init() {
|
||||
func testComponentFinder() *ComponentFinder {
|
||||
builderFactory := func(n string) (Builder, error) { return testBuilder(), nil }
|
||||
ppFactory := func(n string) (PostProcessor, error) { return new(TestPostProcessor), nil }
|
||||
provFactory := func(n string) (Provisioner, error) { return new(TestProvisioner), nil }
|
||||
provFactory := func(n string) (Provisioner, error) { return new(MockProvisioner), nil }
|
||||
return &ComponentFinder{
|
||||
Builder: builderFactory,
|
||||
PostProcessor: ppFactory,
|
||||
@@ -227,7 +227,7 @@ func TestEnvironment_DefaultCli_Version(t *testing.T) {
|
||||
func TestEnvironment_Hook(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
hook := &TestHook{}
|
||||
hook := &MockHook{}
|
||||
hooks := make(map[string]Hook)
|
||||
hooks["foo"] = hook
|
||||
|
||||
@@ -309,7 +309,7 @@ func TestEnvironment_PostProcessor_Error(t *testing.T) {
|
||||
func TestEnvironmentProvisioner(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
p := &TestProvisioner{}
|
||||
p := &MockProvisioner{}
|
||||
ps := make(map[string]Provisioner)
|
||||
ps["foo"] = p
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package packer
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// This is the hook that should be fired for provisioners to run.
|
||||
const HookProvision = "packer_provision"
|
||||
|
||||
@@ -11,19 +15,40 @@ const HookProvision = "packer_provision"
|
||||
// you must reference the documentation for the specific hook you're interested
|
||||
// in. In addition to that, the Hook is given access to a UI so that it can
|
||||
// output things to the user.
|
||||
//
|
||||
// Cancel is called when the hook needs to be cancelled. This will usually
|
||||
// be called when Run is still in progress so the mechanism that handles this
|
||||
// must be race-free. Cancel should attempt to cancel the hook in the
|
||||
// quickest, safest way possible.
|
||||
type Hook interface {
|
||||
Run(string, Ui, Communicator, interface{}) error
|
||||
Cancel()
|
||||
}
|
||||
|
||||
// A Hook implementation that dispatches based on an internal mapping.
|
||||
type DispatchHook struct {
|
||||
Mapping map[string][]Hook
|
||||
|
||||
l sync.Mutex
|
||||
cancelled bool
|
||||
runningHook Hook
|
||||
}
|
||||
|
||||
// Runs the hook with the given name by dispatching it to the proper
|
||||
// hooks if a mapping exists. If a mapping doesn't exist, then nothing
|
||||
// happens.
|
||||
func (h *DispatchHook) Run(name string, ui Ui, comm Communicator, data interface{}) error {
|
||||
h.l.Lock()
|
||||
h.cancelled = false
|
||||
h.l.Unlock()
|
||||
|
||||
// Make sure when we exit that we reset the running hook.
|
||||
defer func() {
|
||||
h.l.Lock()
|
||||
defer h.l.Unlock()
|
||||
h.runningHook = nil
|
||||
}()
|
||||
|
||||
hooks, ok := h.Mapping[name]
|
||||
if !ok {
|
||||
// No hooks for that name. No problem.
|
||||
@@ -31,6 +56,15 @@ func (h *DispatchHook) Run(name string, ui Ui, comm Communicator, data interface
|
||||
}
|
||||
|
||||
for _, hook := range hooks {
|
||||
h.l.Lock()
|
||||
if h.cancelled {
|
||||
h.l.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
h.runningHook = hook
|
||||
h.l.Unlock()
|
||||
|
||||
if err := hook.Run(name, ui, comm, data); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -38,3 +72,16 @@ func (h *DispatchHook) Run(name string, ui Ui, comm Communicator, data interface
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Cancels all the hooks that are currently in-flight, if any. This will
|
||||
// block until the hooks are all cancelled.
|
||||
func (h *DispatchHook) Cancel() {
|
||||
h.l.Lock()
|
||||
defer h.l.Unlock()
|
||||
|
||||
if h.runningHook != nil {
|
||||
h.runningHook.Cancel()
|
||||
}
|
||||
|
||||
h.cancelled = true
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package packer
|
||||
|
||||
// MockHook is an implementation of Hook that can be used for tests.
|
||||
type MockHook struct {
|
||||
RunFunc func() error
|
||||
|
||||
RunCalled bool
|
||||
RunComm Communicator
|
||||
RunData interface{}
|
||||
RunName string
|
||||
RunUi Ui
|
||||
CancelCalled bool
|
||||
}
|
||||
|
||||
func (t *MockHook) Run(name string, ui Ui, comm Communicator, data interface{}) error {
|
||||
t.RunCalled = true
|
||||
t.RunComm = comm
|
||||
t.RunData = data
|
||||
t.RunName = name
|
||||
t.RunUi = ui
|
||||
|
||||
if t.RunFunc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return t.RunFunc()
|
||||
}
|
||||
|
||||
func (t *MockHook) Cancel() {
|
||||
t.CancelCalled = true
|
||||
}
|
||||
+56
-19
@@ -2,52 +2,89 @@ package packer
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TestHook struct {
|
||||
runCalled bool
|
||||
runComm Communicator
|
||||
runData interface{}
|
||||
runName string
|
||||
runUi Ui
|
||||
// A helper Hook implementation for testing cancels.
|
||||
type CancelHook struct {
|
||||
sync.Mutex
|
||||
cancelCh chan struct{}
|
||||
doneCh chan struct{}
|
||||
|
||||
Cancelled bool
|
||||
}
|
||||
|
||||
func (t *TestHook) Run(name string, ui Ui, comm Communicator, data interface{}) error {
|
||||
t.runCalled = true
|
||||
t.runComm = comm
|
||||
t.runData = data
|
||||
t.runName = name
|
||||
t.runUi = ui
|
||||
func (h *CancelHook) Run(string, Ui, Communicator, interface{}) error {
|
||||
h.Lock()
|
||||
h.cancelCh = make(chan struct{})
|
||||
h.doneCh = make(chan struct{})
|
||||
h.Unlock()
|
||||
|
||||
defer close(h.doneCh)
|
||||
|
||||
select {
|
||||
case <-h.cancelCh:
|
||||
h.Cancelled = true
|
||||
case <-time.After(1 * time.Second):
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *CancelHook) Cancel() {
|
||||
h.Lock()
|
||||
close(h.cancelCh)
|
||||
h.Unlock()
|
||||
|
||||
<-h.doneCh
|
||||
}
|
||||
|
||||
func TestDispatchHook_Implements(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
var r Hook
|
||||
c := &DispatchHook{nil}
|
||||
c := &DispatchHook{}
|
||||
|
||||
assert.Implementor(c, &r, "should be a Hook")
|
||||
}
|
||||
|
||||
func TestDispatchHook_Run_NoHooks(t *testing.T) {
|
||||
// Just make sure nothing blows up
|
||||
dh := &DispatchHook{make(map[string][]Hook)}
|
||||
dh := &DispatchHook{}
|
||||
dh.Run("foo", nil, nil, nil)
|
||||
}
|
||||
|
||||
func TestDispatchHook_Run(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
hook := &TestHook{}
|
||||
hook := &MockHook{}
|
||||
|
||||
mapping := make(map[string][]Hook)
|
||||
mapping["foo"] = []Hook{hook}
|
||||
dh := &DispatchHook{mapping}
|
||||
dh := &DispatchHook{Mapping: mapping}
|
||||
dh.Run("foo", nil, nil, 42)
|
||||
|
||||
assert.True(hook.runCalled, "run should be called")
|
||||
assert.Equal(hook.runName, "foo", "should be proper event")
|
||||
assert.Equal(hook.runData, 42, "should be correct data")
|
||||
assert.True(hook.RunCalled, "run should be called")
|
||||
assert.Equal(hook.RunName, "foo", "should be proper event")
|
||||
assert.Equal(hook.RunData, 42, "should be correct data")
|
||||
}
|
||||
|
||||
func TestDispatchHook_cancel(t *testing.T) {
|
||||
hook := new(CancelHook)
|
||||
|
||||
dh := &DispatchHook{
|
||||
Mapping: map[string][]Hook{
|
||||
"foo": []Hook{hook},
|
||||
},
|
||||
}
|
||||
|
||||
go dh.Run("foo", nil, nil, 42)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
dh.Cancel()
|
||||
|
||||
if !hook.Cancelled {
|
||||
t.Fatal("hook should've cancelled")
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -19,8 +19,17 @@ func (c *cmdHook) Run(name string, ui packer.Ui, comm packer.Communicator, data
|
||||
return c.hook.Run(name, ui, comm, data)
|
||||
}
|
||||
|
||||
func (c *cmdHook) Cancel() {
|
||||
defer func() {
|
||||
r := recover()
|
||||
c.checkExit(r, nil)
|
||||
}()
|
||||
|
||||
c.hook.Cancel()
|
||||
}
|
||||
|
||||
func (c *cmdHook) checkExit(p interface{}, cb func()) {
|
||||
if c.client.Exited() {
|
||||
if c.client.Exited() && cb != nil {
|
||||
cb()
|
||||
} else if p != nil && !Killed {
|
||||
log.Panic(p)
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"os/exec"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type helperHook byte
|
||||
|
||||
func (helperHook) Run(string, packer.Ui, packer.Communicator, interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestHook_NoExist(t *testing.T) {
|
||||
c := NewClient(&ClientConfig{Cmd: exec.Command("i-should-not-exist")})
|
||||
defer c.Kill()
|
||||
|
||||
+20
-8
@@ -19,8 +19,14 @@ import (
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// This is a count of the number of interrupts the process has received.
|
||||
// This is updated with sync/atomic whenever a SIGINT is received and can
|
||||
// be checked by the plugin safely to take action.
|
||||
var Interrupts int32 = 0
|
||||
|
||||
const MagicCookieKey = "PACKER_PLUGIN_MAGIC_COOKIE"
|
||||
const MagicCookieValue = "d602bf8f470bc67ca7faa0386276bbdd4330efaf76d1a219cb4d6991ca9872b2"
|
||||
|
||||
@@ -86,17 +92,18 @@ func serve(server *rpc.Server) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Registers a signal handler to "swallow" interrupts so that the
|
||||
// Registers a signal handler to swallow and count interrupts so that the
|
||||
// plugin isn't killed. The main host Packer process is responsible
|
||||
// for killing the plugins when interrupted.
|
||||
func swallowInterrupts() {
|
||||
func countInterrupts() {
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, os.Interrupt)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
<-ch
|
||||
log.Println("Received interrupt signal. Ignoring.")
|
||||
newCount := atomic.AddInt32(&Interrupts, 1)
|
||||
log.Printf("Received interrupt signal (count: %d). Ignoring.", newCount)
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -108,7 +115,7 @@ func ServeBuilder(builder packer.Builder) {
|
||||
server := rpc.NewServer()
|
||||
packrpc.RegisterBuilder(server, builder)
|
||||
|
||||
swallowInterrupts()
|
||||
countInterrupts()
|
||||
if err := serve(server); err != nil {
|
||||
log.Printf("ERROR: %s", err)
|
||||
os.Exit(1)
|
||||
@@ -122,7 +129,7 @@ func ServeCommand(command packer.Command) {
|
||||
server := rpc.NewServer()
|
||||
packrpc.RegisterCommand(server, command)
|
||||
|
||||
swallowInterrupts()
|
||||
countInterrupts()
|
||||
if err := serve(server); err != nil {
|
||||
log.Printf("ERROR: %s", err)
|
||||
os.Exit(1)
|
||||
@@ -136,7 +143,7 @@ func ServeHook(hook packer.Hook) {
|
||||
server := rpc.NewServer()
|
||||
packrpc.RegisterHook(server, hook)
|
||||
|
||||
swallowInterrupts()
|
||||
countInterrupts()
|
||||
if err := serve(server); err != nil {
|
||||
log.Printf("ERROR: %s", err)
|
||||
os.Exit(1)
|
||||
@@ -150,7 +157,7 @@ func ServePostProcessor(p packer.PostProcessor) {
|
||||
server := rpc.NewServer()
|
||||
packrpc.RegisterPostProcessor(server, p)
|
||||
|
||||
swallowInterrupts()
|
||||
countInterrupts()
|
||||
if err := serve(server); err != nil {
|
||||
log.Printf("ERROR: %s", err)
|
||||
os.Exit(1)
|
||||
@@ -164,9 +171,14 @@ func ServeProvisioner(p packer.Provisioner) {
|
||||
server := rpc.NewServer()
|
||||
packrpc.RegisterProvisioner(server, p)
|
||||
|
||||
swallowInterrupts()
|
||||
countInterrupts()
|
||||
if err := serve(server); err != nil {
|
||||
log.Printf("ERROR: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests whether or not the plugin was interrupted or not.
|
||||
func Interrupted() bool {
|
||||
return atomic.LoadInt32(&Interrupts) > 0
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user