From b13c25532c8282c95fbe7cd6c1341f3ec5aad68f Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Sun, 3 Nov 2013 17:35:58 +0100 Subject: [PATCH] builder/digitalocean: add a droplet_name configuration value Practically, this lets you set the hostname of the droplet used for provisioning. --- builder/digitalocean/builder.go | 8 +++ builder/digitalocean/builder_test.go | 52 +++++++++++++++++++ builder/digitalocean/step_create_droplet.go | 7 +-- .../docs/builders/digitalocean.html.markdown | 3 ++ 4 files changed, 65 insertions(+), 5 deletions(-) diff --git a/builder/digitalocean/builder.go b/builder/digitalocean/builder.go index ae6564eb9..83e5e79d5 100644 --- a/builder/digitalocean/builder.go +++ b/builder/digitalocean/builder.go @@ -8,6 +8,7 @@ import ( "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/common" + "github.com/mitchellh/packer/common/uuid" "github.com/mitchellh/packer/packer" "log" "os" @@ -30,6 +31,7 @@ type config struct { ImageID uint `mapstructure:"image_id"` SnapshotName string `mapstructure:"snapshot_name"` + DropletName string `mapstructure:"droplet_name"` SSHUsername string `mapstructure:"ssh_username"` SSHPort uint `mapstructure:"ssh_port"` @@ -95,6 +97,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { b.config.SnapshotName = "packer-{{timestamp}}" } + if b.config.DropletName == "" { + // Default to packer-[time-ordered-uuid] + b.config.DropletName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) + } + if b.config.SSHUsername == "" { // Default to "root". You can override this if your // SourceImage has a different user account then the DO default @@ -121,6 +128,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { "client_id": &b.config.ClientID, "api_key": &b.config.APIKey, "snapshot_name": &b.config.SnapshotName, + "droplet_name": &b.config.DropletName, "ssh_username": &b.config.SSHUsername, "ssh_timeout": &b.config.RawSSHTimeout, "state_timeout": &b.config.RawStateTimeout, diff --git a/builder/digitalocean/builder_test.go b/builder/digitalocean/builder_test.go index 1d5deea00..2ccf20df4 100644 --- a/builder/digitalocean/builder_test.go +++ b/builder/digitalocean/builder_test.go @@ -401,3 +401,55 @@ func TestBuilderPrepare_SnapshotName(t *testing.T) { } } + +func TestBuilderPrepare_DropletName(t *testing.T) { + var b Builder + config := testConfig() + + // Test default + warnings, err := b.Prepare(config) + if len(warnings) > 0 { + t.Fatalf("bad: %#v", warnings) + } + if err != nil { + t.Fatalf("should not have error: %s", err) + } + + if b.config.DropletName == "" { + t.Errorf("invalid: %s", b.config.DropletName) + } + + // Test normal set + config["droplet_name"] = "foobar" + b = Builder{} + warnings, err = b.Prepare(config) + if len(warnings) > 0 { + t.Fatalf("bad: %#v", warnings) + } + if err != nil { + t.Fatalf("should not have error: %s", err) + } + + // Test with template + config["droplet_name"] = "foobar-{{timestamp}}" + b = Builder{} + warnings, err = b.Prepare(config) + if len(warnings) > 0 { + t.Fatalf("bad: %#v", warnings) + } + if err != nil { + t.Fatalf("should not have error: %s", err) + } + + // Test with bad template + config["droplet_name"] = "foobar-{{" + b = Builder{} + warnings, err = b.Prepare(config) + if len(warnings) > 0 { + t.Fatalf("bad: %#v", warnings) + } + if err == nil { + t.Fatal("should have error") + } + +} diff --git a/builder/digitalocean/step_create_droplet.go b/builder/digitalocean/step_create_droplet.go index cdf32db3e..73e025f86 100644 --- a/builder/digitalocean/step_create_droplet.go +++ b/builder/digitalocean/step_create_droplet.go @@ -3,7 +3,6 @@ package digitalocean import ( "fmt" "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/common/uuid" "github.com/mitchellh/packer/packer" ) @@ -19,11 +18,9 @@ func (s *stepCreateDroplet) Run(state multistep.StateBag) multistep.StepAction { ui.Say("Creating droplet...") - // Some random droplet name as it's temporary - name := fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) - // Create the droplet based on configuration - dropletId, err := client.CreateDroplet(name, c.SizeID, c.ImageID, c.RegionID, sshKeyId) + dropletId, err := client.CreateDroplet(c.DropletName, c.SizeID, c.ImageID, c.RegionID, sshKeyId) + if err != nil { err := fmt.Errorf("Error creating droplet: %s", err) state.Put("error", err) diff --git a/website/source/docs/builders/digitalocean.html.markdown b/website/source/docs/builders/digitalocean.html.markdown index b4793a8dd..10eed2c4e 100644 --- a/website/source/docs/builders/digitalocean.html.markdown +++ b/website/source/docs/builders/digitalocean.html.markdown @@ -51,6 +51,9 @@ Optional: To help make this unique, use a function like `timestamp` (see [configuration templates](/docs/templates/configuration-templates.html) for more info) +* `droplet_name` (string) - The name assigned to the droplet. DigitalOcean + sets the hostname of the machine to this value. + * `ssh_port` (int) - The port that SSH will be available on. Defaults to port 22.