Documentation
¶
Overview ¶
Package connection defines the transport abstraction the typed Hyper-V client (internal/hyperv) uses to ship PowerShell scripts to a Windows host and read their results back. Three backends are implemented: local (exec pwsh.exe directly), ssh (golang.org/x/crypto/ssh), and winrm (github.com/masterzen/winrm).
Contract highlights: script body via -EncodedCommand, stdin for data, stderr has CLIXML progress noise stripped before reaching the Result. Per-call cost is dominated by PowerShell startup, not transport.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrUnreachable means the transport could not reach the host (DNS, // TCP, TLS handshake, auth failure). Resource code typically retries. ErrUnreachable = errors.New("transport unreachable") // ErrTimeout means the call exceeded its context deadline. Distinct // from ErrUnreachable so callers can decide whether to retry vs. // surface as `timeouts.Diagnostics`. ErrTimeout = errors.New("transport timeout") // ErrSessionDropped means the remote session ended without signaling // an exit status (SSH/WinRM channel torn down mid-command), typically // because the cmdlet succeeded but the response got stranded. An // idempotent typed-client method can verify post-drop with a // follow-up Get instead of surfacing a false failure. ErrSessionDropped = errors.New("transport session dropped before exit status") // ErrUnsupportedBackend is returned by the backend selector when the // requested backend identifier is not yet implemented. Removed once // SSH/WinRM backends ship. ErrUnsupportedBackend = errors.New("backend not implemented") )
Functions ¶
This section is empty.
Types ¶
type Connection ¶
type Connection interface {
Runner
// Open establishes any persistent state the backend needs (an SSH
// client, a pooled HTTP transport, etc.). Local is stateless and
// returns nil.
Open(ctx context.Context) error
// Close releases the backend's persistent state. Idempotent. Local
// is a no-op.
Close() error
// Healthcheck returns nil if the backend can reach the host and run
// a trivial command. Used at provider Configure time to fail fast on
// misconfiguration.
Healthcheck(ctx context.Context) error
// Backend returns the lowercase identifier of the implementation —
// "local" | "ssh" | "winrm". Used for tflog field decoration; the
// schema's `backend` attribute is the user-facing form.
Backend() string
}
Connection is the abstract transport. Each provider instance holds a single Connection per (backend, host, user) tuple. Resources never reach for a new one; they share the configured Connection via the typed client in internal/hyperv.
func NewLocal ¶
func NewLocal(opts LocalOptions) (Connection, error)
NewLocal returns a Connection backed by a local pwsh / powershell.exe process per call. Opens nothing — the local backend is stateless.
func NewSSH ¶
func NewSSH(opts SSHOptions) (Connection, error)
NewSSH builds a Connection backed by ssh.Client. It resolves authentication methods and the known_hosts callback up-front so misconfiguration surfaces before Open dials. The client itself is established lazily by Open.
func NewWinRM ¶ added in v0.2.0
func NewWinRM(opts WinRMOptions) (Connection, error)
NewWinRM builds a Connection backed by masterzen/winrm, validating required fields and applying defaults; the HTTP client itself is built lazily by Open, so a unit test exercising only NewWinRM doesn't pay that cost. Auth supports ntlm (default), basic, and kerberos; kerberos uses jcmturner/gokrb5 (pure-Go, no GSSAPI on the runner) in either password mode (inline AS-REQ) or ccache mode (reuse an existing TGT), picked by setting Password or KrbCCachePath; setting both, or neither, is rejected.
type LocalOptions ¶
type LocalOptions struct {
// PwshPath, if non-empty, is used as-is. Set via the provider's
// `local.pwsh_path` attribute or the HYPERV_PWSH_PATH env var.
PwshPath string
}
LocalOptions configures the local backend. Empty values mean "discover from PATH": prefer pwsh (faster cold start), fall back to powershell.exe.
type Result ¶
Result is what every script invocation returns; the typed Hyper-V client maps its four fields into typed Go errors. Stderr has CLIXML progress noise stripped before reaching this struct; a real PS error arrives as a JSON envelope on Stderr per the Write-HypervError contract. RunScript's error return is reserved for transport failures (connection refused, auth failed, ctx canceled); PS-level failures come back via ExitCode != 0 plus that envelope.
type Runner ¶
type Runner interface {
RunScript(ctx context.Context, script string, stdinJSON []byte) (Result, error)
// StreamFile copies localPath's bytes to remotePath (both absolute),
// creating or truncating the destination. No SHA-256 verification
// happens here: callers hash before and after for a pure bytes-copy
// that lets each backend pick its own transport. ctx cancellation
// interrupts the stream, leaving a partial file at remotePath.
StreamFile(ctx context.Context, localPath, remotePath string) error
}
Runner is the narrowest useful interface: run a script, get a result. script is the full PowerShell body with the preamble already concatenated, sent as UTF-16LE base64 via -EncodedCommand, not stdin or an argument, which mis-parses a multi-line script; stdinJSON is piped to the process's stdin. The error return is transport-level only; a non-zero Result.ExitCode carries the application result.
type SSHOptions ¶
type SSHOptions struct {
Host string // required
Port int // default 22
Username string // required
// Auth priority: PrivateKey (raw contents, wins over PrivateKeyPath)
// beats PrivateKeyPath (read at Open time) beats Password (fallback).
// Passphrase decrypts the key. All three use []byte so Close() can
// zero the provider's copy; golang.org/x/crypto/ssh makes its own.
PrivateKey []byte
PrivateKeyPath string
Passphrase []byte
Password []byte
// KnownHostsPath is the file used for host key verification. Default:
// ~/.ssh/known_hosts. Empty path falls back to the default. A missing
// file is a hard error -- silently disabling host-key checking would be
// a security regression.
KnownHostsPath string
// Timeout is the dial timeout. Default 30s.
Timeout time.Duration
// CommandTimeout bounds an individual RunScript call. Default
// 5m. A wedged remote cmdlet surfaces as ErrTimeout instead of
// blocking the whole apply. Set to 0 to disable.
CommandTimeout time.Duration
// KeepaliveInterval is how often the backend sends an SSH
// keepalive request while the persistent client is open.
// Default 30s. Prevents NAT/firewall mid-apply drops. Set to
// 0 to disable.
KeepaliveInterval time.Duration
// PwshPath is the binary the remote shell invokes per call. Default:
// "powershell.exe" -- universally available on Windows. Set to "pwsh"
// or "pwsh.exe" to prefer PS 7+ if installed.
PwshPath string
// MaxConcurrentSessions caps in-flight RunScript calls against the
// persistent ssh.Client. OpenSSH's per-connection MaxSessions limit
// (default 10, often 4-6 on hardened Windows builds) rejects late
// session opens once exceeded; the default of 4 stays under typical
// caps. 0 uses the default; negative disables the cap (not recommended).
MaxConcurrentSessions int
}
SSHOptions configures the SSH backend. The provider's Configure pass resolves env vars + provider attributes into this struct (see internal/provider/backend_select.go).
type WinRMOptions ¶ added in v0.2.0
type WinRMOptions struct {
Host string // required
Port int // default 5986 (HTTPS) or 5985 (HTTP)
Username string // required
// Password is []byte so Close() can zero the long-lived copy held
// by the backend. masterzen/winrm copies the value into its own
// EndpointParams when we construct the client; that copy is outside
// our reach, but our state stays clean across the connection's life.
Password []byte // required for ntlm/basic; for kerberos, mutually exclusive with KrbCCachePath
UseHTTPS bool // default true; flip to false only for diagnosing TLS-only failures
Insecure bool // skip TLS certificate verification (default false)
Auth string // "ntlm" | "basic" | "kerberos"; default "ntlm"
CACert string // path to a CA bundle PEM; empty = system roots
// Kerberos fields, meaningful only when Auth=="kerberos" (the
// provider-config layer catches a misconfigured Auth at plan time).
// KrbRealm is required; KrbSpn defaults to "HTTP/<Host>";
// KrbConfigPath defaults to the first existing of $KRB5_CONFIG,
// ~/.config/krb5.conf, /etc/krb5.conf. Setting KrbCCachePath
// switches from password-mode (inline AS-REQ) to ccache-mode
// (reuse an existing TGT) and Password is then ignored.
KrbRealm string
KrbSpn string
KrbConfigPath string
KrbCCachePath string
// Timeout sets `http.Client.Timeout` for every WSMan request.
// Default 0 (no wall-clock cap) -- file transfers can run for
// arbitrarily long. The initial TCP dial is bounded by the OS;
// a connection that stalls mid-transfer (host freezes, packets
// silently dropped) holds the apply until ctx cancellation
// (operator Ctrl+C).
Timeout time.Duration
// CommandTimeout bounds a single RunScript call. Default 5m. A wedged
// remote cmdlet surfaces as ErrTimeout instead of blocking the whole
// apply. Set to 0 to disable.
CommandTimeout time.Duration
// PwshPath is the binary the remote shell invokes per call. Default:
// "powershell.exe" -- universally available on Windows. Set to "pwsh"
// or "pwsh.exe" to prefer PS 7+ if installed.
PwshPath string
// MaxShells caps the number of concurrent WinRM shells this backend
// will open. Windows' default MaxShellsPerUser is 5; with Terraform's
// default -parallelism=10 the provider can easily exceed that and
// receive HTTP 400. Default: 3.
MaxShells int
}
WinRMOptions configures the WinRM backend. The provider's Configure pass resolves env vars + provider attributes into this struct (see internal/provider/backend_select.go).