From 94b76036fcb8d3650d810fc6b8a7281f65fa1325 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 31 Aug 2013 12:25:08 -0700 Subject: [PATCH] builder/digitalocean: new multistep API --- builder/digitalocean/builder.go | 18 ++++++++-------- builder/digitalocean/ssh.go | 13 +++++------ builder/digitalocean/step_create_droplet.go | 22 +++++++++---------- builder/digitalocean/step_create_ssh_key.go | 20 ++++++++--------- builder/digitalocean/step_droplet_info.go | 18 ++++++++-------- builder/digitalocean/step_power_off.go | 14 ++++++------ builder/digitalocean/step_shutdown.go | 16 +++++++------- builder/digitalocean/step_snapshot.go | 24 ++++++++++----------- 8 files changed, 73 insertions(+), 72 deletions(-) diff --git a/builder/digitalocean/builder.go b/builder/digitalocean/builder.go index cce9d7292..25129e01a 100644 --- a/builder/digitalocean/builder.go +++ b/builder/digitalocean/builder.go @@ -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, } diff --git a/builder/digitalocean/ssh.go b/builder/digitalocean/ssh.go index bc35407c2..90de48400 100644 --- a/builder/digitalocean/ssh.go +++ b/builder/digitalocean/ssh.go @@ -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 { diff --git a/builder/digitalocean/step_create_droplet.go b/builder/digitalocean/step_create_droplet.go index 1cbf16724..484d516eb 100644 --- a/builder/digitalocean/step_create_droplet.go +++ b/builder/digitalocean/step_create_droplet.go @@ -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...") diff --git a/builder/digitalocean/step_create_ssh_key.go b/builder/digitalocean/step_create_ssh_key.go index ecadd92ef..f33a368e8 100644 --- a/builder/digitalocean/step_create_ssh_key.go +++ b/builder/digitalocean/step_create_ssh_key.go @@ -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) diff --git a/builder/digitalocean/step_droplet_info.go b/builder/digitalocean/step_droplet_info.go index 54daeebc4..6adfe0cd4 100644 --- a/builder/digitalocean/step_droplet_info.go +++ b/builder/digitalocean/step_droplet_info.go @@ -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 } diff --git a/builder/digitalocean/step_power_off.go b/builder/digitalocean/step_power_off.go index a0650a254..553436f01 100644 --- a/builder/digitalocean/step_power_off.go +++ b/builder/digitalocean/step_power_off.go @@ -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 } diff --git a/builder/digitalocean/step_shutdown.go b/builder/digitalocean/step_shutdown.go index 9c516ef28..31c9ae8ea 100644 --- a/builder/digitalocean/step_shutdown.go +++ b/builder/digitalocean/step_shutdown.go @@ -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 } diff --git a/builder/digitalocean/step_snapshot.go b/builder/digitalocean/step_snapshot.go index a032dfcc0..c9072116d 100644 --- a/builder/digitalocean/step_snapshot.go +++ b/builder/digitalocean/step_snapshot.go @@ -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 }