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  }