github.com/recobe182/terraform@v0.8.5-0.20170117231232-49ab22a935b7/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 *[]byte `mapstructure:"ca_cert"` 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 }