Help us shape the future of Go! Take the 2026 Go Developer Survey

connection

package
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 29, 2026 License: MPL-2.0 Imports: 29 Imported by: 0

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

View Source
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

type Result struct {
	Stdout   []byte
	Stderr   []byte
	ExitCode int
	Duration time.Duration
}

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).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL