- Startup scripts can be provided through the instance creation metadata field 'startup-script'. - Script log can be copied to a GCS location by setting the metadata field 'startup-script-log-dest'. Added Retry method to googlecompute package. Added GetSerialPortOutput to googlecompute Drivers. Added StepWaitInstanceStartup (and associated test) which waits for an instance startup-script to finish. Changed the instance service account to use the same service account as the one provided in the Packer config template. It was the project default service account. Tested googlecompute package with 'go test' and also performed builds with a startup script and without a startup script.
74 lines
2.0 KiB
Go
74 lines
2.0 KiB
Go
package googlecompute
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/mitchellh/multistep"
|
|
"github.com/mitchellh/packer/packer"
|
|
"golang.org/x/crypto/ssh"
|
|
)
|
|
|
|
// StepCreateSSHKey represents a Packer build step that generates SSH key pairs.
|
|
type StepCreateSSHKey struct {
|
|
Debug bool
|
|
DebugKeyPath string
|
|
}
|
|
|
|
// Run executes the Packer build step that generates SSH key pairs.
|
|
// The key pairs are added to the multistep state as "ssh_private_key" and
|
|
// "ssh_public_key".
|
|
func (s *StepCreateSSHKey) Run(state multistep.StateBag) multistep.StepAction {
|
|
ui := state.Get("ui").(packer.Ui)
|
|
|
|
ui.Say("Creating temporary SSH key for instance...")
|
|
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
if err != nil {
|
|
err := fmt.Errorf("Error creating temporary ssh key: %s", err)
|
|
state.Put("error", err)
|
|
ui.Error(err.Error())
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
priv_blk := pem.Block{
|
|
Type: "RSA PRIVATE KEY",
|
|
Headers: nil,
|
|
Bytes: x509.MarshalPKCS1PrivateKey(priv),
|
|
}
|
|
|
|
pub, err := ssh.NewPublicKey(&priv.PublicKey)
|
|
if err != nil {
|
|
err := fmt.Errorf("Error creating temporary ssh key: %s", err)
|
|
state.Put("error", err)
|
|
ui.Error(err.Error())
|
|
return multistep.ActionHalt
|
|
}
|
|
state.Put("ssh_private_key", string(pem.EncodeToMemory(&priv_blk)))
|
|
state.Put("ssh_public_key", string(ssh.MarshalAuthorizedKey(pub)))
|
|
|
|
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
|
|
}
|
|
|
|
// Write out the key
|
|
err = pem.Encode(f, &priv_blk)
|
|
f.Close()
|
|
if err != nil {
|
|
state.Put("error", fmt.Errorf("Error saving debug key: %s", err))
|
|
return multistep.ActionHalt
|
|
}
|
|
}
|
|
return multistep.ActionContinue
|
|
}
|
|
|
|
// Nothing to clean up. SSH keys are associated with a single GCE instance.
|
|
func (s *StepCreateSSHKey) Cleanup(state multistep.StateBag) {}
|