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  }