From d70e7834555a7830d2497e8884651715bcb49cb0 Mon Sep 17 00:00:00 2001 From: Lars Wander Date: Wed, 2 Nov 2016 16:24:48 -0400 Subject: [PATCH 1/3] builder/googlecompute: Use ssh_private_key_file if provided This seemed to be missing from the googlecompute provider. Now if the ssh_private_key_file is provided, that will be used in place of a temporary key. I didn't update the googlecompute specific docs under `./website/`, since this parameter is already documented under the communicators templates page. --- builder/googlecompute/builder.go | 5 +++-- builder/googlecompute/step_create_instance.go | 22 +++++++++++++------ builder/googlecompute/step_create_ssh_key.go | 20 +++++++++++++++-- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/builder/googlecompute/builder.go b/builder/googlecompute/builder.go index 7be284b50..b39b92b4b 100644 --- a/builder/googlecompute/builder.go +++ b/builder/googlecompute/builder.go @@ -52,8 +52,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe steps := []multistep.Step{ new(StepCheckExistingImage), &StepCreateSSHKey{ - Debug: b.config.PackerDebug, - DebugKeyPath: fmt.Sprintf("gce_%s.pem", b.config.PackerBuildName), + Debug: b.config.PackerDebug, + DebugKeyPath: fmt.Sprintf("gce_%s.pem", b.config.PackerBuildName), + PrivateKeyFile: b.config.Comm.SSHPrivateKey, }, &StepCreateInstance{ Debug: b.config.PackerDebug, diff --git a/builder/googlecompute/step_create_instance.go b/builder/googlecompute/step_create_instance.go index ab70fd450..813295f30 100644 --- a/builder/googlecompute/step_create_instance.go +++ b/builder/googlecompute/step_create_instance.go @@ -24,13 +24,17 @@ func (c *Config) createInstanceMetadata(sourceImage *Image, sshPublicKey string) instanceMetadata[k] = v } - // Merge any existing ssh keys with our public key. - sshMetaKey := "sshKeys" - sshKeys := fmt.Sprintf("%s:%s", c.Comm.SSHUsername, sshPublicKey) - if confSshKeys, exists := instanceMetadata[sshMetaKey]; exists { - sshKeys = fmt.Sprintf("%s\n%s", sshKeys, confSshKeys) + // Merge any existing ssh keys with our public key, unless there is no + // supplied public key. This is possible if a private_key_file was + // specified. + if sshPublicKey != "" { + sshMetaKey := "sshKeys" + sshKeys := fmt.Sprintf("%s:%s", c.Comm.SSHUsername, sshPublicKey) + if confSshKeys, exists := instanceMetadata[sshMetaKey]; exists { + sshKeys = fmt.Sprintf("%s\n%s", sshKeys, confSshKeys) + } + instanceMetadata[sshMetaKey] = sshKeys } - instanceMetadata[sshMetaKey] = sshKeys // Wrap any startup script with our own startup script. if c.StartupScriptFile != "" { @@ -65,9 +69,13 @@ func getImage(c *Config, d Driver) (*Image, error) { func (s *StepCreateInstance) Run(state multistep.StateBag) multistep.StepAction { c := state.Get("config").(*Config) d := state.Get("driver").(Driver) - sshPublicKey := state.Get("ssh_public_key").(string) ui := state.Get("ui").(packer.Ui) + sshPublicKey := "" + if sshPublicKeyRaw, ok := state.GetOk("ssh_public_key"); ok { + sshPublicKey = sshPublicKeyRaw.(string) + } + sourceImage, err := getImage(c, d) if err != nil { err := fmt.Errorf("Error getting source image for instance creation: %s", err) diff --git a/builder/googlecompute/step_create_ssh_key.go b/builder/googlecompute/step_create_ssh_key.go index 4c4894fba..7d6c27622 100644 --- a/builder/googlecompute/step_create_ssh_key.go +++ b/builder/googlecompute/step_create_ssh_key.go @@ -6,6 +6,7 @@ import ( "crypto/x509" "encoding/pem" "fmt" + "io/ioutil" "os" "github.com/mitchellh/multistep" @@ -15,8 +16,9 @@ import ( // StepCreateSSHKey represents a Packer build step that generates SSH key pairs. type StepCreateSSHKey struct { - Debug bool - DebugKeyPath string + Debug bool + DebugKeyPath string + PrivateKeyFile string } // Run executes the Packer build step that generates SSH key pairs. @@ -25,6 +27,20 @@ type StepCreateSSHKey struct { func (s *StepCreateSSHKey) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) + if s.PrivateKeyFile != "" { + ui.Say("Using existing SSH private key") + privateKeyBytes, err := ioutil.ReadFile(s.PrivateKeyFile) + if err != nil { + state.Put("error", fmt.Errorf( + "Error loading configured private key file: %s", err)) + return multistep.ActionHalt + } + + state.Put("ssh_private_key", string(privateKeyBytes)) + + return multistep.ActionContinue + } + ui.Say("Creating temporary SSH key for instance...") priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { From 7f474d8f788b5eec291725b7581849aa41ecbf97 Mon Sep 17 00:00:00 2001 From: Lars Wander Date: Thu, 3 Nov 2016 12:45:52 -0400 Subject: [PATCH 2/3] builder/googlecompute: Tests added --- .../step_create_instance_test.go | 31 +++++++++++++++++++ .../googlecompute/step_create_ssh_key_test.go | 17 ++++++++++ builder/googlecompute/test-fixtures/fake-key | 27 ++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 builder/googlecompute/test-fixtures/fake-key diff --git a/builder/googlecompute/step_create_instance_test.go b/builder/googlecompute/step_create_instance_test.go index 8c567479b..c0122584a 100644 --- a/builder/googlecompute/step_create_instance_test.go +++ b/builder/googlecompute/step_create_instance_test.go @@ -2,6 +2,7 @@ package googlecompute import ( "errors" + "strings" "testing" "time" @@ -210,3 +211,33 @@ func TestStepCreateInstance_errorTimeout(t *testing.T) { _, ok = state.GetOk("instance_name") assert.False(t, ok, "State should not have an instance name.") } + +func TestCreateInstanceMetadata(t *testing.T) { + state := testState(t) + c := state.Get("config").(*Config) + image := StubImage("test-image", "test-project", []string{}, 100) + key := "abcdefgh12345678" + + // create our metadata + metadata, err := c.createInstanceMetadata(image, key) + + assert.True(t, err == nil, "Metadata creation should have succeeded.") + + // ensure our key is listed + assert.True(t, strings.Contains(metadata["sshKeys"], key), "Instance metadata should contain provided key") +} + +func TestCreateInstanceMetadata_noPublicKey(t *testing.T) { + state := testState(t) + c := state.Get("config").(*Config) + image := StubImage("test-image", "test-project", []string{}, 100) + sshKeys := c.Metadata["sshKeys"] + + // create our metadata + metadata, err := c.createInstanceMetadata(image, "") + + assert.True(t, err == nil, "Metadata creation should have succeeded.") + + // ensure the ssh metadata hasn't changed + assert.Equal(t, metadata["sshKeys"], sshKeys, "Instance metadata should not have been modified") +} diff --git a/builder/googlecompute/step_create_ssh_key_test.go b/builder/googlecompute/step_create_ssh_key_test.go index 304d6f1fb..94504ac7f 100644 --- a/builder/googlecompute/step_create_ssh_key_test.go +++ b/builder/googlecompute/step_create_ssh_key_test.go @@ -12,6 +12,23 @@ func TestStepCreateSSHKey_impl(t *testing.T) { var _ multistep.Step = new(StepCreateSSHKey) } +func TestStepCreateSSHKey_privateKey(t *testing.T) { + state := testState(t) + step := new(StepCreateSSHKey) + step.PrivateKeyFile = "test-fixtures/fake-key" + defer step.Cleanup(state) + + // run the step + if action := step.Run(state); action != multistep.ActionContinue { + t.Fatalf("bad action: %#v", action) + } + + // Verify that we have a public/private key + if _, ok := state.GetOk("ssh_private_key"); !ok { + t.Fatal("should have key") + } +} + func TestStepCreateSSHKey(t *testing.T) { state := testState(t) step := new(StepCreateSSHKey) diff --git a/builder/googlecompute/test-fixtures/fake-key b/builder/googlecompute/test-fixtures/fake-key new file mode 100644 index 000000000..e2f2e87e0 --- /dev/null +++ b/builder/googlecompute/test-fixtures/fake-key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= +-----END RSA PRIVATE KEY----- From 583e341ae78e7b2bcb84090d16c2717f03db5345 Mon Sep 17 00:00:00 2001 From: Lars Wander Date: Thu, 3 Nov 2016 12:49:09 -0400 Subject: [PATCH 3/3] builder/googlecompute: Store empty public_key --- builder/googlecompute/step_create_instance.go | 6 +----- builder/googlecompute/step_create_ssh_key.go | 1 + 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/builder/googlecompute/step_create_instance.go b/builder/googlecompute/step_create_instance.go index 813295f30..1707ef654 100644 --- a/builder/googlecompute/step_create_instance.go +++ b/builder/googlecompute/step_create_instance.go @@ -69,13 +69,9 @@ func getImage(c *Config, d Driver) (*Image, error) { func (s *StepCreateInstance) Run(state multistep.StateBag) multistep.StepAction { c := state.Get("config").(*Config) d := state.Get("driver").(Driver) + sshPublicKey := state.Get("ssh_public_key").(string) ui := state.Get("ui").(packer.Ui) - sshPublicKey := "" - if sshPublicKeyRaw, ok := state.GetOk("ssh_public_key"); ok { - sshPublicKey = sshPublicKeyRaw.(string) - } - sourceImage, err := getImage(c, d) if err != nil { err := fmt.Errorf("Error getting source image for instance creation: %s", err) diff --git a/builder/googlecompute/step_create_ssh_key.go b/builder/googlecompute/step_create_ssh_key.go index 7d6c27622..1012867b6 100644 --- a/builder/googlecompute/step_create_ssh_key.go +++ b/builder/googlecompute/step_create_ssh_key.go @@ -37,6 +37,7 @@ func (s *StepCreateSSHKey) Run(state multistep.StateBag) multistep.StepAction { } state.Put("ssh_private_key", string(privateKeyBytes)) + state.Put("ssh_public_key", "") return multistep.ActionContinue }