From 5368697413c775ba85099b70c1dcbd8694585acf Mon Sep 17 00:00:00 2001 From: Rickard von Essen Date: Tue, 16 Feb 2016 11:06:22 +0100 Subject: [PATCH] Get admin password of booted instance when using WinRM Fixes #2663 --- builder/openstack/builder.go | 4 ++ builder/openstack/step_get_password.go | 81 ++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 builder/openstack/step_get_password.go diff --git a/builder/openstack/builder.go b/builder/openstack/builder.go index a97effa7c..94bf65579 100644 --- a/builder/openstack/builder.go +++ b/builder/openstack/builder.go @@ -91,6 +91,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe UserDataFile: b.config.UserDataFile, ConfigDrive: b.config.ConfigDrive, }, + &StepGetPassword{ + Debug: b.config.PackerDebug, + Comm: &b.config.RunConfig.Comm, + }, &StepWaitForRackConnect{ Wait: b.config.RackconnectWait, }, diff --git a/builder/openstack/step_get_password.go b/builder/openstack/step_get_password.go new file mode 100644 index 000000000..905838d5c --- /dev/null +++ b/builder/openstack/step_get_password.go @@ -0,0 +1,81 @@ +package openstack + +import ( + "crypto/rsa" + "fmt" + "log" + "time" + + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/helper/communicator" + "github.com/mitchellh/packer/packer" + "github.com/rackspace/gophercloud/openstack/compute/v2/servers" + "golang.org/x/crypto/ssh" +) + +// StepGetPassword reads the password from a booted OpenStack server and sets +// it on the WinRM config. +type StepGetPassword struct { + Debug bool + Comm *communicator.Config +} + +func (s *StepGetPassword) Run(state multistep.StateBag) multistep.StepAction { + config := state.Get("config").(Config) + ui := state.Get("ui").(packer.Ui) + + // Skip if we're not using winrm + if s.Comm.Type != "winrm" { + log.Printf("[INFO] Not using winrm communicator, skipping get password...") + return multistep.ActionContinue + } + + // If we already have a password, skip it + if s.Comm.WinRMPassword != "" { + ui.Say("Skipping waiting for password since WinRM password set...") + return multistep.ActionContinue + } + + // We need the v2 compute client + computeClient, err := config.computeV2Client() + if err != nil { + err = fmt.Errorf("Error initializing compute client: %s", err) + state.Put("error", err) + return multistep.ActionHalt + } + + ui.Say("Waiting for password since WinRM password is not set...") + server := state.Get("server").(*servers.Server) + var password string + + privateKey, err := ssh.ParseRawPrivateKey([]byte(state.Get("privateKey").(string))) + if err != nil { + err = fmt.Errorf("Error parsing private key: %s", err) + state.Put("error", err) + return multistep.ActionHalt + } + + for ; password == "" && err == nil; password, err = servers.GetPassword(computeClient, server.ID).ExtractPassword(privateKey.(*rsa.PrivateKey)) { + + // Check for an interrupt in between attempts. + if _, ok := state.GetOk(multistep.StateCancelled); ok { + return multistep.ActionHalt + } + + log.Printf("Retrying to get a administrator password evry 5 seconds.") + time.Sleep(5 * time.Second) + } + + ui.Message(fmt.Sprintf("Password retrieved!")) + s.Comm.WinRMPassword = password + + // In debug-mode, we output the password + if s.Debug { + ui.Message(fmt.Sprintf( + "Password (since debug is enabled) \"%s\"", s.Comm.WinRMPassword)) + } + + return multistep.ActionContinue +} + +func (s *StepGetPassword) Cleanup(multistep.StateBag) {}