diff --git a/builder/xenserver/common/ssh.go b/builder/xenserver/common/ssh.go index 0e4e31c..329b8a5 100644 --- a/builder/xenserver/common/ssh.go +++ b/builder/xenserver/common/ssh.go @@ -2,14 +2,7 @@ package common import ( "bytes" - "encoding/pem" "fmt" - "github.com/hashicorp/packer-plugin-sdk/communicator" - "io" - "io/ioutil" - "log" - "net" - "os" "strings" "github.com/hashicorp/packer-plugin-sdk/multistep" @@ -22,47 +15,6 @@ func SSHAddress(state multistep.StateBag) (string, error) { return fmt.Sprintf("%s:%d", sshIP, sshHostPort), nil } -func SSHLocalAddress(state multistep.StateBag) (string, error) { - sshLocalPort, ok := state.Get("local_ssh_port").(uint) - if !ok { - return "", fmt.Errorf("SSH port forwarding hasn't been set up yet") - } - conn_str := fmt.Sprintf("%s:%d", "127.0.0.1", sshLocalPort) - return conn_str, nil -} - -func SSHPort(state multistep.StateBag) (int, error) { - sshHostPort := state.Get("local_ssh_port").(uint) - return int(sshHostPort), nil -} - -func CommHost(state multistep.StateBag) (string, error) { - return "127.0.0.1", nil -} - -func SSHConfigFunc(commConfig communicator.Config) func(multistep.StateBag) (*gossh.ClientConfig, error) { - return func(state multistep.StateBag) (*gossh.ClientConfig, error) { - auth := []gossh.AuthMethod{ - gossh.Password(commConfig.SSHPassword), - } - - if commConfig.SSHPrivateKeyFile != "" { - signer, err := FileSigner(commConfig.SSHPrivateKeyFile) - if err != nil { - return nil, err - } - - auth = append(auth, gossh.PublicKeys(signer)) - } - - return &gossh.ClientConfig{ - User: commConfig.SSHUsername, - Auth: auth, - HostKeyCallback: gossh.InsecureIgnoreHostKey(), - }, nil - } -} - func doExecuteSSHCmd(cmd, target string, config *gossh.ClientConfig) (stdout string, err error) { client, err := gossh.Dial("tcp", target, config) if err != nil { @@ -99,119 +51,3 @@ func ExecuteHostSSHCmd(state multistep.StateBag, cmd string) (stdout string, err } return doExecuteSSHCmd(cmd, sshAddress, sshConfig) } - -func ExecuteGuestSSHCmd(state multistep.StateBag, cmd string) (stdout string, err error) { - config := state.Get("commonconfig").(CommonConfig) - localAddress, err := SSHLocalAddress(state) - if err != nil { - return - } - sshConfig, err := SSHConfigFunc(config.Comm)(state) - if err != nil { - return - } - - return doExecuteSSHCmd(cmd, localAddress, sshConfig) -} - -func forward(local_conn net.Conn, config *gossh.ClientConfig, server, remote_dest string, remote_port uint) error { - defer local_conn.Close() - - ssh_client_conn, err := gossh.Dial("tcp", server+":22", config) - if err != nil { - log.Printf("local ssh.Dial error: %s", err) - return err - } - defer ssh_client_conn.Close() - - remote_loc := fmt.Sprintf("%s:%d", remote_dest, remote_port) - ssh_conn, err := ssh_client_conn.Dial("tcp", remote_loc) - if err != nil { - log.Printf("ssh.Dial error: %s", err) - return err - } - defer ssh_conn.Close() - - txDone := make(chan struct{}) - rxDone := make(chan struct{}) - - go func() { - _, err = io.Copy(ssh_conn, local_conn) - if err != nil { - log.Printf("io.copy failed: %v", err) - } - close(txDone) - }() - - go func() { - _, err = io.Copy(local_conn, ssh_conn) - if err != nil { - log.Printf("io.copy failed: %v", err) - } - close(rxDone) - }() - - <-txDone - <-rxDone - - return nil -} - -func ssh_port_forward(local_listener net.Listener, remote_port int, remote_dest, host, username, password string) error { - - config := &gossh.ClientConfig{ - User: username, - Auth: []gossh.AuthMethod{ - gossh.Password(password), - }, - HostKeyCallback: gossh.InsecureIgnoreHostKey(), - } - - for { - local_connection, err := local_listener.Accept() - - if err != nil { - log.Printf("Local accept failed: %s", err) - return err - } - - // Forward to a remote port - go forward(local_connection, config, host, remote_dest, uint(remote_port)) - } - - return nil -} - -// FileSigner returns an gossh.Signer for a key file. -func FileSigner(path string) (gossh.Signer, error) { - f, err := os.Open(path) - if err != nil { - return nil, err - } - defer f.Close() - - keyBytes, err := ioutil.ReadAll(f) - if err != nil { - return nil, err - } - - // We parse the private key on our own first so that we can - // show a nicer error if the private key has a password. - block, _ := pem.Decode(keyBytes) - if block == nil { - return nil, fmt.Errorf( - "Failed to read key '%s': no key found", path) - } - if block.Headers["Proc-Type"] == "4,ENCRYPTED" { - return nil, fmt.Errorf( - "Failed to read key '%s': password protected keys are\n"+ - "not supported. Please decrypt the key prior to use.", path) - } - - signer, err := gossh.ParsePrivateKey(keyBytes) - if err != nil { - return nil, fmt.Errorf("Error setting up SSH config: %s", err) - } - - return signer, nil -} diff --git a/builder/xenserver/common/step_forward_port_over_ssh.go b/builder/xenserver/common/step_forward_port_over_ssh.go deleted file mode 100644 index 84cb948..0000000 --- a/builder/xenserver/common/step_forward_port_over_ssh.go +++ /dev/null @@ -1,50 +0,0 @@ -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepForwardPortOverSSH struct { - RemotePort func(state multistep.StateBag) (int, error) - RemoteDest func(state multistep.StateBag) (string, error) - - HostPortMin int - HostPortMax int - - ResultKey string -} - -func (self *StepForwardPortOverSSH) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - - config := state.Get("commonconfig").(CommonConfig) - ui := state.Get("ui").(packer.Ui) - - // Find a free local port: - - l, sshHostPort := FindPort(self.HostPortMin, self.HostPortMax) - - if l == nil || sshHostPort == 0 { - ui.Error("Error: unable to find free host port. Try providing a larger range [host_port_min, host_port_max]") - return multistep.ActionHalt - } - - ui.Say(fmt.Sprintf("Creating a local port forward over SSH on local port %d", sshHostPort)) - - hostAddress, _ := state.Get("ssh_address").(string) - remotePort, _ := self.RemotePort(state) - remoteDest, _ := self.RemoteDest(state) - - go ssh_port_forward(l, remotePort, remoteDest, hostAddress, config.Username, config.Password) - ui.Say(fmt.Sprintf("Port forward setup. %d ---> %s:%d on %s", sshHostPort, remoteDest, remotePort, hostAddress)) - - // Provide the local port to future steps. - state.Put(self.ResultKey, sshHostPort) - - return multistep.ActionContinue -} - -func (self *StepForwardPortOverSSH) Cleanup(state multistep.StateBag) {} diff --git a/builder/xenserver/common/step_shutdown.go b/builder/xenserver/common/step_shutdown.go index 2cafad3..c246bca 100644 --- a/builder/xenserver/common/step_shutdown.go +++ b/builder/xenserver/common/step_shutdown.go @@ -3,6 +3,7 @@ package common import ( "context" "fmt" + "log" "time" "github.com/hashicorp/packer-plugin-sdk/multistep" @@ -29,11 +30,13 @@ func (StepShutdown) Run(ctx context.Context, state multistep.StateBag) multistep // Shutdown the VM success := func() bool { if config.ShutdownCommand != "" { - ui.Message("Executing shutdown command...") + comm := state.Get("communicator").(packer.Communicator) + ui.Say("Gracefully halting virtual machine...") + log.Printf("Executing shutdown command: %s", config.ShutdownCommand) - _, err := ExecuteGuestSSHCmd(state, config.ShutdownCommand) - if err != nil { - ui.Error(fmt.Sprintf("Shutdown command failed: %s", err.Error())) + cmd := &packer.RemoteCmd{Command: config.ShutdownCommand} + if err := cmd.RunWithUi(ctx, comm, ui); err != nil { + ui.Error(fmt.Sprintf("Failed to send shutdown command: %s", err.Error())) return false } diff --git a/builder/xenserver/iso/builder.go b/builder/xenserver/iso/builder.go index e1efc11..052e2e0 100644 --- a/builder/xenserver/iso/builder.go +++ b/builder/xenserver/iso/builder.go @@ -267,13 +267,6 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p Chan: httpReqChan, Timeout: self.config.InstallTimeout, // @todo change this }, - &xscommon.StepForwardPortOverSSH{ - RemotePort: xscommon.InstanceSSHPort, - RemoteDest: xscommon.InstanceSSHIP, - HostPortMin: self.config.HostPortMin, - HostPortMax: self.config.HostPortMax, - ResultKey: "local_ssh_port", - }, &communicator.StepConnect{ Config: &self.config.Comm, Host: xscommon.InstanceSSHIP, diff --git a/builder/xenserver/xva/builder.go b/builder/xenserver/xva/builder.go index bc901e9..959f81a 100644 --- a/builder/xenserver/xva/builder.go +++ b/builder/xenserver/xva/builder.go @@ -156,9 +156,9 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p }, &communicator.StepConnect{ Config: &self.config.Comm, - Host: xscommon.CommHost, - SSHConfig: xscommon.SSHConfigFunc(self.config.CommonConfig.Comm), - SSHPort: xscommon.SSHPort, + Host: xscommon.InstanceSSHIP, + SSHConfig: self.config.Comm.SSHConfigFunc(), + SSHPort: xscommon.InstanceSSHPort, }, new(commonsteps.StepProvision), new(xscommon.StepShutdown),