github.com/partitio/terraform@v0.11.12-beta1/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  	NTLM       bool   `mapstructure:"use_ntlm"`
    41  	CACert     string `mapstructure:"cacert"`
    42  	Timeout    string
    43  	ScriptPath string        `mapstructure:"script_path"`
    44  	TimeoutVal time.Duration `mapstructure:"-"`
    45  }
    46  
    47  // parseConnectionInfo is used to convert the ConnInfo of the InstanceState into
    48  // a ConnectionInfo struct
    49  func parseConnectionInfo(s *terraform.InstanceState) (*connectionInfo, error) {
    50  	connInfo := &connectionInfo{}
    51  	decConf := &mapstructure.DecoderConfig{
    52  		WeaklyTypedInput: true,
    53  		Result:           connInfo,
    54  	}
    55  	dec, err := mapstructure.NewDecoder(decConf)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  	if err := dec.Decode(s.Ephemeral.ConnInfo); err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	// Check on script paths which point to the default Windows TEMP folder because files
    64  	// which are put in there very early in the boot process could get cleaned/deleted
    65  	// before you had the change to execute them.
    66  	//
    67  	// TODO (SvH) Needs some more debugging to fully understand the exact sequence of events
    68  	// causing this...
    69  	if strings.HasPrefix(filepath.ToSlash(connInfo.ScriptPath), "C:/Windows/Temp") {
    70  		return nil, fmt.Errorf(
    71  			`Using the C:\Windows\Temp folder is not supported. Please use a different 'script_path'.`)
    72  	}
    73  
    74  	if connInfo.User == "" {
    75  		connInfo.User = DefaultUser
    76  	}
    77  
    78  	// Format the host if needed.
    79  	// Needed for IPv6 support.
    80  	connInfo.Host = shared.IpFormat(connInfo.Host)
    81  
    82  	if connInfo.Port == 0 {
    83  		connInfo.Port = DefaultPort
    84  	}
    85  	if connInfo.ScriptPath == "" {
    86  		connInfo.ScriptPath = DefaultScriptPath
    87  	}
    88  	if connInfo.Timeout != "" {
    89  		connInfo.TimeoutVal = safeDuration(connInfo.Timeout, DefaultTimeout)
    90  	} else {
    91  		connInfo.TimeoutVal = DefaultTimeout
    92  	}
    93  
    94  	return connInfo, nil
    95  }
    96  
    97  // safeDuration returns either the parsed duration or a default value
    98  func safeDuration(dur string, defaultDur time.Duration) time.Duration {
    99  	d, err := time.ParseDuration(dur)
   100  	if err != nil {
   101  		log.Printf("Invalid duration '%s', using default of %s", dur, defaultDur)
   102  		return defaultDur
   103  	}
   104  	return d
   105  }
   106  
   107  func formatDuration(duration time.Duration) string {
   108  	h := int(duration.Hours())
   109  	m := int(duration.Minutes()) - h*60
   110  	s := int(duration.Seconds()) - (h*3600 + m*60)
   111  
   112  	res := "PT"
   113  	if h > 0 {
   114  		res = fmt.Sprintf("%s%dH", res, h)
   115  	}
   116  	if m > 0 {
   117  		res = fmt.Sprintf("%s%dM", res, m)
   118  	}
   119  	if s > 0 {
   120  		res = fmt.Sprintf("%s%dS", res, s)
   121  	}
   122  
   123  	return res
   124  }