github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/helper/communicator/config.go (about) 1 package communicator 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "time" 8 9 "github.com/hashicorp/packer/template/interpolate" 10 "github.com/masterzen/winrm" 11 ) 12 13 // Config is the common configuration that communicators allow within 14 // a builder. 15 type Config struct { 16 Type string `mapstructure:"communicator"` 17 18 // SSH 19 SSHHost string `mapstructure:"ssh_host"` 20 SSHPort int `mapstructure:"ssh_port"` 21 SSHUsername string `mapstructure:"ssh_username"` 22 SSHPassword string `mapstructure:"ssh_password"` 23 SSHPrivateKey string `mapstructure:"ssh_private_key_file"` 24 SSHPty bool `mapstructure:"ssh_pty"` 25 SSHTimeout time.Duration `mapstructure:"ssh_timeout"` 26 SSHAgentAuth bool `mapstructure:"ssh_agent_auth"` 27 SSHDisableAgentForwarding bool `mapstructure:"ssh_disable_agent_forwarding"` 28 SSHHandshakeAttempts int `mapstructure:"ssh_handshake_attempts"` 29 SSHBastionHost string `mapstructure:"ssh_bastion_host"` 30 SSHBastionPort int `mapstructure:"ssh_bastion_port"` 31 SSHBastionAgentAuth bool `mapstructure:"ssh_bastion_agent_auth"` 32 SSHBastionUsername string `mapstructure:"ssh_bastion_username"` 33 SSHBastionPassword string `mapstructure:"ssh_bastion_password"` 34 SSHBastionPrivateKey string `mapstructure:"ssh_bastion_private_key_file"` 35 SSHFileTransferMethod string `mapstructure:"ssh_file_transfer_method"` 36 SSHProxyHost string `mapstructure:"ssh_proxy_host"` 37 SSHProxyPort int `mapstructure:"ssh_proxy_port"` 38 SSHProxyUsername string `mapstructure:"ssh_proxy_username"` 39 SSHProxyPassword string `mapstructure:"ssh_proxy_password"` 40 SSHKeepAliveInterval time.Duration `mapstructure:"ssh_keep_alive_interval"` 41 SSHReadWriteTimeout time.Duration `mapstructure:"ssh_read_write_timeout"` 42 43 // WinRM 44 WinRMUser string `mapstructure:"winrm_username"` 45 WinRMPassword string `mapstructure:"winrm_password"` 46 WinRMHost string `mapstructure:"winrm_host"` 47 WinRMPort int `mapstructure:"winrm_port"` 48 WinRMTimeout time.Duration `mapstructure:"winrm_timeout"` 49 WinRMUseSSL bool `mapstructure:"winrm_use_ssl"` 50 WinRMInsecure bool `mapstructure:"winrm_insecure"` 51 WinRMUseNTLM bool `mapstructure:"winrm_use_ntlm"` 52 WinRMTransportDecorator func() winrm.Transporter 53 } 54 55 // Port returns the port that will be used for access based on config. 56 func (c *Config) Port() int { 57 switch c.Type { 58 case "ssh": 59 return c.SSHPort 60 case "winrm": 61 return c.WinRMPort 62 default: 63 return 0 64 } 65 } 66 67 // Host returns the port that will be used for access based on config. 68 func (c *Config) Host() string { 69 switch c.Type { 70 case "ssh": 71 return c.SSHHost 72 case "winrm": 73 return c.WinRMHost 74 default: 75 return "" 76 } 77 } 78 79 // User returns the port that will be used for access based on config. 80 func (c *Config) User() string { 81 switch c.Type { 82 case "ssh": 83 return c.SSHUsername 84 case "winrm": 85 return c.WinRMUser 86 default: 87 return "" 88 } 89 } 90 91 // Password returns the port that will be used for access based on config. 92 func (c *Config) Password() string { 93 switch c.Type { 94 case "ssh": 95 return c.SSHPassword 96 case "winrm": 97 return c.WinRMPassword 98 default: 99 return "" 100 } 101 } 102 103 func (c *Config) Prepare(ctx *interpolate.Context) []error { 104 if c.Type == "" { 105 c.Type = "ssh" 106 } 107 108 var errs []error 109 switch c.Type { 110 case "ssh": 111 if es := c.prepareSSH(ctx); len(es) > 0 { 112 errs = append(errs, es...) 113 } 114 case "winrm": 115 if es := c.prepareWinRM(ctx); len(es) > 0 { 116 errs = append(errs, es...) 117 } 118 case "docker", "none": 119 break 120 default: 121 return []error{fmt.Errorf("Communicator type %s is invalid", c.Type)} 122 } 123 124 return errs 125 } 126 127 func (c *Config) prepareSSH(ctx *interpolate.Context) []error { 128 if c.SSHPort == 0 { 129 c.SSHPort = 22 130 } 131 132 if c.SSHTimeout == 0 { 133 c.SSHTimeout = 5 * time.Minute 134 } 135 136 if c.SSHKeepAliveInterval == 0 { 137 c.SSHKeepAliveInterval = 5 * time.Second 138 } 139 140 if c.SSHHandshakeAttempts == 0 { 141 c.SSHHandshakeAttempts = 10 142 } 143 144 if c.SSHBastionHost != "" { 145 if c.SSHBastionPort == 0 { 146 c.SSHBastionPort = 22 147 } 148 149 if c.SSHBastionPrivateKey == "" && c.SSHPrivateKey != "" { 150 c.SSHBastionPrivateKey = c.SSHPrivateKey 151 } 152 } 153 154 if c.SSHProxyHost != "" { 155 if c.SSHProxyPort == 0 { 156 c.SSHProxyPort = 1080 157 } 158 } 159 160 if c.SSHFileTransferMethod == "" { 161 c.SSHFileTransferMethod = "scp" 162 } 163 164 // Validation 165 var errs []error 166 if c.SSHUsername == "" { 167 errs = append(errs, errors.New("An ssh_username must be specified\n Note: some builders used to default ssh_username to \"root\".")) 168 } 169 170 if c.SSHPrivateKey != "" { 171 if _, err := os.Stat(c.SSHPrivateKey); err != nil { 172 errs = append(errs, fmt.Errorf( 173 "ssh_private_key_file is invalid: %s", err)) 174 } else if _, err := SSHFileSigner(c.SSHPrivateKey); err != nil { 175 errs = append(errs, fmt.Errorf( 176 "ssh_private_key_file is invalid: %s", err)) 177 } 178 } 179 180 if c.SSHBastionHost != "" && !c.SSHBastionAgentAuth { 181 if c.SSHBastionPassword == "" && c.SSHBastionPrivateKey == "" { 182 errs = append(errs, errors.New( 183 "ssh_bastion_password or ssh_bastion_private_key_file must be specified")) 184 } 185 } 186 187 if c.SSHFileTransferMethod != "scp" && c.SSHFileTransferMethod != "sftp" { 188 errs = append(errs, fmt.Errorf( 189 "ssh_file_transfer_method ('%s') is invalid, valid methods: sftp, scp", 190 c.SSHFileTransferMethod)) 191 } 192 193 if c.SSHBastionHost != "" && c.SSHProxyHost != "" { 194 errs = append(errs, errors.New("please specify either ssh_bastion_host or ssh_proxy_host, not both")) 195 } 196 197 return errs 198 } 199 200 func (c *Config) prepareWinRM(ctx *interpolate.Context) []error { 201 if c.WinRMPort == 0 && c.WinRMUseSSL { 202 c.WinRMPort = 5986 203 } else if c.WinRMPort == 0 { 204 c.WinRMPort = 5985 205 } 206 207 if c.WinRMTimeout == 0 { 208 c.WinRMTimeout = 30 * time.Minute 209 } 210 211 if c.WinRMUseNTLM == true { 212 c.WinRMTransportDecorator = func() winrm.Transporter { return &winrm.ClientNTLM{} } 213 } 214 215 var errs []error 216 if c.WinRMUser == "" { 217 errs = append(errs, errors.New("winrm_username must be specified.")) 218 } 219 220 return errs 221 }