github.com/scottwinkler/terraform@v0.11.6-0.20180329211809-05143987aea8/communicator/winrm/provisioner.go (about)

     1  package winrm
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"path/filepath"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/hashicorp/terraform/communicator/shared"
    11  	"github.com/hashicorp/terraform/terraform"
    12  	"github.com/mitchellh/mapstructure"
    13  )
    14  
    15  const (
    16  	// DefaultUser is used if there is no user given
    17  	DefaultUser = "Administrator"
    18  
    19  	// DefaultPort is used if there is no port given
    20  	DefaultPort = 5985
    21  
    22  	// DefaultScriptPath is used as the path to copy the file to
    23  	// for remote execution if not provided otherwise.
    24  	DefaultScriptPath = "C:/Temp/terraform_%RAND%.cmd"
    25  
    26  	// DefaultTimeout is used if there is no timeout given
    27  	DefaultTimeout = 5 * time.Minute
    28  )
    29  
    30  // connectionInfo is decoded from the ConnInfo of the resource. These are the
    31  // only keys we look at. If a KeyFile is given, that is used instead
    32  // of a password.
    33  type connectionInfo struct {
    34  	User       string
    35  	Password   string
    36  	Host       string
    37  	Port       int
    38  	HTTPS      bool
    39  	Insecure   bool
    40  	CACert     string `mapstructure:"cacert"`
    41  	Timeout    string
    42  	ScriptPath string        `mapstructure:"script_path"`
    43  	TimeoutVal time.Duration `mapstructure:"-"`
    44  }
    45  
    46  // parseConnectionInfo is used to convert the ConnInfo of the InstanceState into
    47  // a ConnectionInfo struct
    48  func parseConnectionInfo(s *terraform.InstanceState) (*connectionInfo, error) {
    49  	connInfo := &connectionInfo{}
    50  	decConf := &mapstructure.DecoderConfig{
    51  		WeaklyTypedInput: true,
    52  		Result:           connInfo,
    53  	}
    54  	dec, err := mapstructure.NewDecoder(decConf)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	if err := dec.Decode(s.Ephemeral.ConnInfo); err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	// Check on script paths which point to the default Windows TEMP folder because files
    63  	// which are put in there very early in the boot process could get cleaned/deleted
    64  	// before you had the change to execute them.
    65  	//
    66  	// TODO (SvH) Needs some more debugging to fully understand the exact sequence of events
    67  	// causing this...
    68  	if strings.HasPrefix(filepath.ToSlash(connInfo.ScriptPath), "C:/Windows/Temp") {
    69  		return nil, fmt.Errorf(
    70  			`Using the C:\Windows\Temp folder is not supported. Please use a different 'script_path'.`)
    71  	}
    72  
    73  	if connInfo.User == "" {
    74  		connInfo.User = DefaultUser
    75  	}
    76  
    77  	// Format the host if needed.
    78  	// Needed for IPv6 support.
    79  	connInfo.Host = shared.IpFormat(connInfo.Host)
    80  
    81  	if connInfo.Port == 0 {
    82  		connInfo.Port = DefaultPort
    83  	}
    84  	if connInfo.ScriptPath == "" {
    85  		connInfo.ScriptPath = DefaultScriptPath
    86  	}
    87  	if connInfo.Timeout != "" {
    88  		connInfo.TimeoutVal = safeDuration(connInfo.Timeout, DefaultTimeout)
    89  	} else {
    90  		connInfo.TimeoutVal = DefaultTimeout
    91  	}
    92  
    93  	return connInfo, nil
    94  }
    95  
    96  // safeDuration returns either the parsed duration or a default value
    97  func safeDuration(dur string, defaultDur time.Duration) time.Duration {
    98  	d, err := time.ParseDuration(dur)
    99  	if err != nil {
   100  		log.Printf("Invalid duration '%s', using default of %s", dur, defaultDur)
   101  		return defaultDur
   102  	}
   103  	return d
   104  }
   105  
   106  func formatDuration(duration time.Duration) string {
   107  	h := int(duration.Hours())
   108  	m := int(duration.Minutes()) - h*60
   109  	s := int(duration.Seconds()) - (h*3600 + m*60)
   110  
   111  	res := "PT"
   112  	if h > 0 {
   113  		res = fmt.Sprintf("%s%dH", res, h)
   114  	}
   115  	if m > 0 {
   116  		res = fmt.Sprintf("%s%dM", res, m)
   117  	}
   118  	if s > 0 {
   119  		res = fmt.Sprintf("%s%dS", res, s)
   120  	}
   121  
   122  	return res
   123  }