github.com/svenhamers/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 }