mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-25 16:31:10 -06:00
ec85fb1960
This is part of a general effort to move all of Terraform's non-library package surface under internal in order to reinforce that these are for internal use within Terraform only. If you were previously importing packages under this prefix into an external codebase, you could pin to an earlier release tag as an interim solution until you've make a plan to achieve the same functionality some other way.
170 lines
4.3 KiB
Go
170 lines
4.3 KiB
Go
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
|
|
}
|