hyperv

package
v0.1.53 Latest Latest
Warning

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

Go to latest
Published: Aug 28, 2026 License: AGPL-3.0 Imports: 23 Imported by: 0

Documentation

Overview

Package hyperv provides a providersdk.Driver for Microsoft Hyper-V. The agent must run on the Hyper-V host with Administrator privileges; no remote connection config is needed.

Index

Constants

View Source
const DefaultHostReserveMB int64 = 512
View Source
const ProviderType = "hyperv"

ProviderType is the registry key for Hyper-V providers.

Variables

View Source
var ErrVMBusy = errors.New("hyperv: vm did not reach a terminal power state in time")

ErrVMBusy indicates a VM is stuck transitioning between power states and did not settle within the wait window. Callers should treat this as a signal to back off and retry later rather than forcing removal, which can leave a stale vmwp.exe worker and destabilize the host's Virtual Machine Management service (see #118).

Functions

func Registration

func Registration() providersdk.Registration

Registration returns the providersdk.Registration for the Hyper-V provider.

Types

type CapacityError added in v0.1.37

type CapacityError = providersdk.CapacityError

CapacityError is providersdk.CapacityError under this package's existing name — see #185's design spec for why the type moved.

type Config

type Config struct {
	// HostReserveMB is the memory headroom kept available for the host OS and
	// other processes. nil uses the safe 512 MB default; a pointer preserves
	// the explicit zero value, which disables the reserve.
	HostReserveMB *int64 `json:"host_reserve_mb,omitempty" yaml:"host_reserve_mb,omitempty"`

	// DataDir is the directory where this Hyper-V provider's restart-safe
	// state is persisted — currently just the range-based IP allocation
	// ledger (see NetworkConfig.Range, ADR-0012). Relative paths resolve
	// against the boxy config file's own directory when one is known (see
	// ResolveRelativePaths); against the process's working directory
	// otherwise. Empty defaults to ".boxy-agent/hyperv" via the same
	// resolution.
	DataDir string `json:"data_dir,omitempty" yaml:"data_dir,omitempty"`
}

Config holds provider-level settings. These settings apply to the entire Hyper-V host, not to an individual pool or VM.

func (*Config) ResolveRelativePaths added in v0.1.45

func (c *Config) ResolveRelativePaths(baseDir string)

ResolveRelativePaths implements providersdk.RelativePathResolver.

Unlike devfactory's ResolveRelativePaths — which leaves an empty DataDir alone, since devfactory falls back to a throwaway temp directory instead — an empty DataDir here is defaulted to ".boxy-agent/hyperv" *before* anchoring against baseDir. A lost ledger directly reproduces the address collision #222 exists to fix, so an installed agent service (which persists ProviderConfigsBaseDir) and an interactive `boxy agent serve` sharing the same --config must resolve to the same ledger file even though their process working directories differ. See ADR-0012.

type CreateConfig

type CreateConfig struct {
	// TemplateVHD is the path to the parent VHD/VHDX used for differencing disks.
	// Required.
	TemplateVHD string `json:"template_vhd" yaml:"template_vhd"`

	// VHDDir is the directory where differencing VHDs are created.
	// Defaults to the directory containing TemplateVHD.
	VHDDir string `json:"vhd_dir" yaml:"vhd_dir"`

	// Generation is the Hyper-V VM generation (1 or 2). Default: 2.
	Generation int `json:"generation" yaml:"generation"`

	// CPUCount is the number of virtual processors. Default: 2.
	CPUCount int `json:"cpu_count" yaml:"cpu_count"`

	// MemoryMB is startup memory in megabytes. Default: 2048.
	MemoryMB int `json:"memory_mb" yaml:"memory_mb"`

	// Switch is the name of the virtual switch to connect to. Optional.
	Switch string `json:"switch" yaml:"switch"`

	// Network holds optional static IP configuration to apply inside the guest
	// during personalization. When omitted the guest relies on DHCP or a
	// pre-configured address. Use this on Windows Server hosts where Hyper-V
	// does not issue DHCP leases automatically.
	Network *NetworkConfig `json:"network,omitempty" yaml:"network,omitempty"`

	// GuestOS is the guest operating system: "windows" or "linux". Default: "windows".
	// Windows guests use PowerShell Direct (psdirect); Linux guests use SSH.
	GuestOS string `json:"guest_os" yaml:"guest_os"`

	// GuestUser is the guest OS username for exec operations.
	// Windows guests: used for PSRP authentication. Default: "Administrator".
	// Linux guests: used as the SSH username. Default: "admin".
	GuestUser string `json:"guest_user" yaml:"guest_user"`

	// GuestPasswordRef is an opaque lookup handle for the guest OS password.
	// Windows guests: PSRP password. Linux guests: SSH password.
	//
	// Supported built-in forms:
	//   - env:NAME
	GuestPasswordRef string `json:"guest_password_ref" yaml:"guest_password_ref"`

	// GuestPassword is deprecated and no longer used for bootstrap guest access.
	// Use GuestPasswordRef instead so the raw secret does not have to be persisted.
	GuestPassword string `json:"guest_password" yaml:"guest_password"`
}

CreateConfig holds pool-level settings for creating a Hyper-V VM.

type Driver

type Driver struct {
	// contains filtered or unexported fields
}

Driver implements providersdk.Driver for local Hyper-V. VM lifecycle (New-VM, Start-VM, etc.) uses powershell.exe on the host. Guest exec uses PowerShell Direct via go-psrp (Windows) or SSH (Linux).

func New

func New(cfg *Config) (*Driver, error)

New creates a Hyper-V driver and validates its host-wide configuration.

func (*Driver) Allocate

func (d *Driver) Allocate(ctx context.Context, id string) (map[string]any, error)

func (*Driver) Availability added in v0.1.37

func (d *Driver) Availability(ctx context.Context) (*providersdk.ResourceAvailability, error)

Availability implements providersdk.AvailabilityReporter.

func (*Driver) Create

func (d *Driver) Create(ctx context.Context, cfg any) (*providersdk.Resource, error)

func (*Driver) Delete

func (d *Driver) Delete(ctx context.Context, id string) (err error)

func (*Driver) List added in v0.1.39

List satisfies providersdk.ResourceLister, enumerating every boxy-*-named VM this driver's host currently has — including ones the store has no record of, e.g. left behind by a crash between New-VM succeeding and Create's failure branch running (see #174). Prefix-filtered inside the PowerShell query itself, not client-side, so a host running unrelated VMs alongside Boxy's never returns them to a caller that doesn't expect it.

func (*Driver) NetworkRanges added in v0.1.46

func (d *Driver) NetworkRanges(ctx context.Context, switchName string) ([]providersdk.NetworkRange, error)

NetworkRanges implements providersdk.NetworkRangeReporter. It discovers switchName's real IPv4 range(s) from the host's own vEthernet adapter for that switch (Get-NetIPAddress) — not from Get-VMSwitch itself, which has no IP address of its own. Hyper-V creates a "vEthernet (<switch name>)" host network adapter for an Internal or Default switch, carrying the address that is that range's gateway; an External switch's host adapter instead carries the physical NIC's own LAN address, which callers should not treat as a per-VM range even though it's still reported here (see validateNetworkRange's containment check, which handles that the same way as any other non-matching discovered range).

Get-NetNat has no field naming which switch it backs, so its InternalIPInterfaceAddressPrefix values are cross-checked in Go against each discovered address's own network prefix instead — best-effort: a mismatch or Get-NetNat failure only affects NetworkRange.NATBacked, never CIDR/Gateway. See ADR-0013.

A switch with no discoverable IPv4 address (e.g. a Private switch, which has no host vNIC at all) is not an error: it returns (nil, nil). A non-nil error means the query itself could not be completed.

func (*Driver) PersonalizeGuest

func (d *Driver) PersonalizeGuest(ctx context.Context, id string) (*providersdk.GuestPersonalizationResult, error)

func (*Driver) Read

func (*Driver) SetGuestBootstrapResolver added in v0.1.40

func (d *Driver) SetGuestBootstrapResolver(resolver providersdk.GuestBootstrapResolver)

SetGuestBootstrapResolver injects the control-plane lookup used for new VMs. The callback is evaluated at personalization time so remote-agent reconnects always use their current gRPC connection and the server's current pool credential.

func (*Driver) Type

func (d *Driver) Type() providersdk.Type

func (*Driver) Update

func (*Driver) UpdateStream added in v0.1.34

func (d *Driver) UpdateStream(ctx context.Context, id string, op providersdk.Operation, sink eventstream.Sink) (*providersdk.Result, error)

UpdateStream forwards a guest's native streaming capability. Hyper-V providers that cannot stream return an explicit capability error rather than buffering unary output and presenting it as live data.

type ExecOp

type ExecOp = providersdk.ExecOperation

ExecOp is retained as a provider-specific spelling of the shared command operation for compatibility with existing callers.

type NetworkConfig added in v0.1.43

type NetworkConfig struct {
	// StaticIP is a single fixed IPv4 address (e.g. "203.0.113.50", an RFC
	// 5737 documentation address) assigned to every VM this pool creates.
	// Mutually exclusive with Range. Only safe for a pool that never has
	// more than one VM alive at once — a pool with min_ready > 1, or that
	// preheats multiple VMs before allocation, collides on the wire. Use
	// Range for those. See ADR-0012.
	StaticIP string `json:"static_ip,omitempty" yaml:"static_ip,omitempty"`

	// Range is an IPv4 CIDR (e.g. "203.0.113.0/24") that a per-agent,
	// restart-safe ledger allocates distinct addresses from at allocation
	// time — one per resource, released back to the range on delete.
	// Mutually exclusive with StaticIP. See ADR-0012.
	Range string `json:"range,omitempty" yaml:"range,omitempty"`

	// PrefixLength is the subnet prefix length (e.g. 24 for /24) applied
	// alongside StaticIP. Default: 24. Not used in Range mode — the prefix
	// there comes from Range's own CIDR bits, which is authoritative.
	PrefixLength int `json:"prefix_length" yaml:"prefix_length"`

	// DefaultGateway is the IPv4 default gateway (e.g. "203.0.113.1").
	// Optional in both modes; in Range mode it is also excluded from
	// allocation so no VM is ever assigned the gateway's own address.
	DefaultGateway string `json:"default_gateway,omitempty" yaml:"default_gateway,omitempty"`

	// DNSServers is a list of DNS server IPv4 addresses to assign. Optional.
	DNSServers []string `json:"dns_servers,omitempty" yaml:"dns_servers,omitempty"`
}

NetworkConfig describes how to assign an IPv4 address to a guest VM during personalization. Exactly one of StaticIP or Range must be set.

Jump to

Keyboard shortcuts

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