github.com/ttysteale/packer@v0.8.2-0.20150708160520-e5f8ea386ed8/communicator/winrm/communicator.go (about) 1 package winrm 2 3 import ( 4 "fmt" 5 "io" 6 "log" 7 "os" 8 9 "github.com/masterzen/winrm/winrm" 10 "github.com/mitchellh/packer/packer" 11 "github.com/packer-community/winrmcp/winrmcp" 12 13 // This import is a bit strange, but it's needed so `make updatedeps` 14 // can see and download it 15 _ "github.com/dylanmei/winrmtest" 16 ) 17 18 // Communicator represents the WinRM communicator 19 type Communicator struct { 20 config *Config 21 client *winrm.Client 22 endpoint *winrm.Endpoint 23 } 24 25 // New creates a new communicator implementation over WinRM. 26 func New(config *Config) (*Communicator, error) { 27 endpoint := &winrm.Endpoint{ 28 Host: config.Host, 29 Port: config.Port, 30 31 /* 32 TODO 33 HTTPS: connInfo.HTTPS, 34 Insecure: connInfo.Insecure, 35 CACert: connInfo.CACert, 36 */ 37 } 38 39 // Create the client 40 params := winrm.DefaultParameters() 41 params.Timeout = formatDuration(config.Timeout) 42 client, err := winrm.NewClientWithParameters( 43 endpoint, config.Username, config.Password, params) 44 if err != nil { 45 return nil, err 46 } 47 48 // Create the shell to verify the connection 49 log.Printf("[DEBUG] connecting to remote shell using WinRM") 50 shell, err := client.CreateShell() 51 if err != nil { 52 log.Printf("[ERROR] connection error: %s", err) 53 return nil, err 54 } 55 56 if err := shell.Close(); err != nil { 57 log.Printf("[ERROR] error closing connection: %s", err) 58 return nil, err 59 } 60 61 return &Communicator{ 62 config: config, 63 client: client, 64 endpoint: endpoint, 65 }, nil 66 } 67 68 // Start implementation of communicator.Communicator interface 69 func (c *Communicator) Start(rc *packer.RemoteCmd) error { 70 shell, err := c.client.CreateShell() 71 if err != nil { 72 return err 73 } 74 75 log.Printf("[INFO] starting remote command: %s", rc.Command) 76 cmd, err := shell.Execute(rc.Command) 77 if err != nil { 78 return err 79 } 80 81 go runCommand(shell, cmd, rc) 82 return nil 83 } 84 85 func runCommand(shell *winrm.Shell, cmd *winrm.Command, rc *packer.RemoteCmd) { 86 defer shell.Close() 87 88 go io.Copy(rc.Stdout, cmd.Stdout) 89 go io.Copy(rc.Stderr, cmd.Stderr) 90 91 cmd.Wait() 92 93 code := cmd.ExitCode() 94 log.Printf("[INFO] command '%s' exited with code: %d", rc.Command, code) 95 rc.SetExited(code) 96 } 97 98 // Upload implementation of communicator.Communicator interface 99 func (c *Communicator) Upload(path string, input io.Reader, _ *os.FileInfo) error { 100 wcp, err := c.newCopyClient() 101 if err != nil { 102 return err 103 } 104 log.Printf("Uploading file to '%s'", path) 105 return wcp.Write(path, input) 106 } 107 108 // UploadDir implementation of communicator.Communicator interface 109 func (c *Communicator) UploadDir(dst string, src string, exclude []string) error { 110 log.Printf("Uploading dir '%s' to '%s'", src, dst) 111 wcp, err := c.newCopyClient() 112 if err != nil { 113 return err 114 } 115 return wcp.Copy(src, dst) 116 } 117 118 func (c *Communicator) Download(src string, dst io.Writer) error { 119 return fmt.Errorf("WinRM doesn't support download.") 120 } 121 122 func (c *Communicator) newCopyClient() (*winrmcp.Winrmcp, error) { 123 addr := fmt.Sprintf("%s:%d", c.endpoint.Host, c.endpoint.Port) 124 return winrmcp.New(addr, &winrmcp.Config{ 125 Auth: winrmcp.Auth{ 126 User: c.config.Username, 127 Password: c.config.Password, 128 }, 129 OperationTimeout: c.config.Timeout, 130 MaxOperationsPerShell: 15, // lowest common denominator 131 }) 132 }