github.com/tappoz/packer@v1.0.0-rc1/helper/communicator/config.go (about)

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