github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/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 37 // WinRM 38 WinRMUser string `mapstructure:"winrm_username"` 39 WinRMPassword string `mapstructure:"winrm_password"` 40 WinRMHost string `mapstructure:"winrm_host"` 41 WinRMPort int `mapstructure:"winrm_port"` 42 WinRMTimeout time.Duration `mapstructure:"winrm_timeout"` 43 WinRMUseSSL bool `mapstructure:"winrm_use_ssl"` 44 WinRMInsecure bool `mapstructure:"winrm_insecure"` 45 WinRMUseNTLM bool `mapstructure:"winrm_use_ntlm"` 46 WinRMTransportDecorator func() winrm.Transporter 47 } 48 49 // Port returns the port that will be used for access based on config. 50 func (c *Config) Port() int { 51 switch c.Type { 52 case "ssh": 53 return c.SSHPort 54 case "winrm": 55 return c.WinRMPort 56 default: 57 return 0 58 } 59 } 60 61 // Host returns the port that will be used for access based on config. 62 func (c *Config) Host() string { 63 switch c.Type { 64 case "ssh": 65 return c.SSHHost 66 case "winrm": 67 return c.WinRMHost 68 default: 69 return "" 70 } 71 } 72 73 // User returns the port that will be used for access based on config. 74 func (c *Config) User() string { 75 switch c.Type { 76 case "ssh": 77 return c.SSHUsername 78 case "winrm": 79 return c.WinRMUser 80 default: 81 return "" 82 } 83 } 84 85 // Password returns the port that will be used for access based on config. 86 func (c *Config) Password() string { 87 switch c.Type { 88 case "ssh": 89 return c.SSHPassword 90 case "winrm": 91 return c.WinRMPassword 92 default: 93 return "" 94 } 95 } 96 97 func (c *Config) Prepare(ctx *interpolate.Context) []error { 98 if c.Type == "" { 99 c.Type = "ssh" 100 } 101 102 var errs []error 103 switch c.Type { 104 case "ssh": 105 if es := c.prepareSSH(ctx); len(es) > 0 { 106 errs = append(errs, es...) 107 } 108 case "winrm": 109 if es := c.prepareWinRM(ctx); len(es) > 0 { 110 errs = append(errs, es...) 111 } 112 case "docker", "none": 113 break 114 default: 115 return []error{fmt.Errorf("Communicator type %s is invalid", c.Type)} 116 } 117 118 return errs 119 } 120 121 func (c *Config) prepareSSH(ctx *interpolate.Context) []error { 122 if c.SSHPort == 0 { 123 c.SSHPort = 22 124 } 125 126 if c.SSHTimeout == 0 { 127 c.SSHTimeout = 5 * time.Minute 128 } 129 130 if c.SSHHandshakeAttempts == 0 { 131 c.SSHHandshakeAttempts = 10 132 } 133 134 if c.SSHBastionHost != "" { 135 if c.SSHBastionPort == 0 { 136 c.SSHBastionPort = 22 137 } 138 139 if c.SSHBastionPrivateKey == "" && c.SSHPrivateKey != "" { 140 c.SSHBastionPrivateKey = c.SSHPrivateKey 141 } 142 } 143 144 if c.SSHFileTransferMethod == "" { 145 c.SSHFileTransferMethod = "scp" 146 } 147 148 // Validation 149 var errs []error 150 if c.SSHUsername == "" { 151 errs = append(errs, errors.New("An ssh_username must be specified\n Note: some builders used to default ssh_username to \"root\".")) 152 } 153 154 if c.SSHPrivateKey != "" { 155 if _, err := os.Stat(c.SSHPrivateKey); err != nil { 156 errs = append(errs, fmt.Errorf( 157 "ssh_private_key_file is invalid: %s", err)) 158 } else if _, err := SSHFileSigner(c.SSHPrivateKey); err != nil { 159 errs = append(errs, fmt.Errorf( 160 "ssh_private_key_file is invalid: %s", err)) 161 } 162 } 163 164 if c.SSHBastionHost != "" && !c.SSHBastionAgentAuth { 165 if c.SSHBastionPassword == "" && c.SSHBastionPrivateKey == "" { 166 errs = append(errs, errors.New( 167 "ssh_bastion_password or ssh_bastion_private_key_file must be specified")) 168 } 169 } 170 171 if c.SSHFileTransferMethod != "scp" && c.SSHFileTransferMethod != "sftp" { 172 errs = append(errs, fmt.Errorf( 173 "ssh_file_transfer_method ('%s') is invalid, valid methods: sftp, scp", 174 c.SSHFileTransferMethod)) 175 } 176 177 return errs 178 } 179 180 func (c *Config) prepareWinRM(ctx *interpolate.Context) []error { 181 if c.WinRMPort == 0 && c.WinRMUseSSL { 182 c.WinRMPort = 5986 183 } else if c.WinRMPort == 0 { 184 c.WinRMPort = 5985 185 } 186 187 if c.WinRMTimeout == 0 { 188 c.WinRMTimeout = 30 * time.Minute 189 } 190 191 if c.WinRMUseNTLM == true { 192 c.WinRMTransportDecorator = func() winrm.Transporter { return &winrm.ClientNTLM{} } 193 } 194 195 var errs []error 196 if c.WinRMUser == "" { 197 errs = append(errs, errors.New("winrm_username must be specified.")) 198 } 199 200 return errs 201 }