-
Notifications
You must be signed in to change notification settings - Fork 9.5k
/
provisioner.go
169 lines (148 loc) · 4.25 KB
/
provisioner.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package winrm
import (
"fmt"
"log"
"path/filepath"
"strings"
"time"
"github.com/hashicorp/terraform/internal/communicator/shared"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/gocty"
)
const (
// DefaultUser is used if there is no user given
DefaultUser = "Administrator"
// DefaultPort is used if there is no port given
DefaultPort = 5985
// DefaultHTTPSPort is used if there is no port given and HTTPS is true
DefaultHTTPSPort = 5986
// DefaultScriptPath is used as the path to copy the file to
// for remote execution if not provided otherwise.
DefaultScriptPath = "C:/Temp/terraform_%RAND%.cmd"
// DefaultTimeout is used if there is no timeout given
DefaultTimeout = 5 * time.Minute
)
// connectionInfo is decoded from the ConnInfo of the resource. These are the
// only keys we look at. If a KeyFile is given, that is used instead
// of a password.
type connectionInfo struct {
User string
Password string
Host string
Port uint16
HTTPS bool
Insecure bool
NTLM bool `mapstructure:"use_ntlm"`
CACert string `mapstructure:"cacert"`
Timeout string
ScriptPath string `mapstructure:"script_path"`
TimeoutVal time.Duration `mapstructure:"-"`
}
// decodeConnInfo decodes the given cty.Value using the same behavior as the
// lgeacy mapstructure decoder in order to preserve as much of the existing
// logic as possible for compatibility.
func decodeConnInfo(v cty.Value) (*connectionInfo, error) {
connInfo := &connectionInfo{}
if v.IsNull() {
return connInfo, nil
}
for k, v := range v.AsValueMap() {
if v.IsNull() {
continue
}
switch k {
case "user":
connInfo.User = v.AsString()
case "password":
connInfo.Password = v.AsString()
case "host":
connInfo.Host = v.AsString()
case "port":
if err := gocty.FromCtyValue(v, &connInfo.Port); err != nil {
return nil, err
}
case "https":
connInfo.HTTPS = v.True()
case "insecure":
connInfo.Insecure = v.True()
case "use_ntlm":
connInfo.NTLM = v.True()
case "cacert":
connInfo.CACert = v.AsString()
case "script_path":
connInfo.ScriptPath = v.AsString()
case "timeout":
connInfo.Timeout = v.AsString()
}
}
return connInfo, nil
}
// parseConnectionInfo is used to convert the ConnInfo of the InstanceState into
// a ConnectionInfo struct
func parseConnectionInfo(v cty.Value) (*connectionInfo, error) {
v, err := shared.ConnectionBlockSupersetSchema.CoerceValue(v)
if err != nil {
return nil, err
}
connInfo, err := decodeConnInfo(v)
if err != nil {
return nil, err
}
// Check on script paths which point to the default Windows TEMP folder because files
// which are put in there very early in the boot process could get cleaned/deleted
// before you had the change to execute them.
//
// TODO (SvH) Needs some more debugging to fully understand the exact sequence of events
// causing this...
if strings.HasPrefix(filepath.ToSlash(connInfo.ScriptPath), "C:/Windows/Temp") {
return nil, fmt.Errorf(
`Using the C:\Windows\Temp folder is not supported. Please use a different 'script_path'.`)
}
if connInfo.User == "" {
connInfo.User = DefaultUser
}
// Format the host if needed.
// Needed for IPv6 support.
connInfo.Host = shared.IpFormat(connInfo.Host)
if connInfo.Port == 0 {
if connInfo.HTTPS {
connInfo.Port = DefaultHTTPSPort
} else {
connInfo.Port = DefaultPort
}
}
if connInfo.ScriptPath == "" {
connInfo.ScriptPath = DefaultScriptPath
}
if connInfo.Timeout != "" {
connInfo.TimeoutVal = safeDuration(connInfo.Timeout, DefaultTimeout)
} else {
connInfo.TimeoutVal = DefaultTimeout
}
return connInfo, nil
}
// safeDuration returns either the parsed duration or a default value
func safeDuration(dur string, defaultDur time.Duration) time.Duration {
d, err := time.ParseDuration(dur)
if err != nil {
log.Printf("Invalid duration '%s', using default of %s", dur, defaultDur)
return defaultDur
}
return d
}
func formatDuration(duration time.Duration) string {
h := int(duration.Hours())
m := int(duration.Minutes()) - h*60
s := int(duration.Seconds()) - (h*3600 + m*60)
res := "PT"
if h > 0 {
res = fmt.Sprintf("%s%dH", res, h)
}
if m > 0 {
res = fmt.Sprintf("%s%dM", res, m)
}
if s > 0 {
res = fmt.Sprintf("%s%dS", res, s)
}
return res
}