hyperv

package
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: May 2, 2026 License: MPL-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package hyperv is the typed Go wrapper over the connection layer. It concatenates the embedded preamble to each script body, marshals Go DTOs into PowerShell input JSON, and unmarshals PowerShell output JSON back into typed structs. Errors from the structured envelope (Write-HypervError) are mapped to the typed errors in errors.go.

Resources never touch connection.Runner directly — they go through this Client.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNotFound          = errors.New("hyperv: resource not found")
	ErrUnavailable       = errors.New("hyperv: resource temporarily unavailable")
	ErrUnauthorized      = errors.New("hyperv: permission denied")
	ErrInvalidParentPath = errors.New("hyperv: invalid parent path")
	ErrChecksumMismatch  = errors.New("hyperv: image file checksum mismatch")
	ErrPSExecution       = errors.New("hyperv: powershell execution failed")
)

Sentinel errors. Resources match against these with `errors.Is(err, X)` to decide how to surface to the user (RemoveResource for ErrNotFound, AddAttributeError for ErrInvalidParentPath, etc.).

ErrNotFound vs ErrUnavailable is load-bearing: ErrNotFound means the object genuinely does not exist (PS ObjectNotFound) and a resource Read should RemoveResource so Terraform plans a recreate; ErrUnavailable means the object is known but temporarily inaccessible (PS ResourceUnavailable — vmms stopped, cluster node fenced, transport blip) and the resource MUST surface a transient error rather than dropping the resource from state.

Functions

This section is empty.

Types

type AttachDvdDriveInput

type AttachDvdDriveInput struct {
	Name               string  `json:"name"`
	ControllerType     string  `json:"controller_type"`
	ControllerNumber   int     `json:"controller_number"`
	ControllerLocation int     `json:"controller_location"`
	IsoPath            *string `json:"iso_path,omitempty"`
}

AttachDvdDriveInput is the stdin JSON shape for vm/add-dvd-drive.ps1. IsoPath is *string so the wire JSON drops it cleanly when the user wants an empty drive (script's "if not empty" guard then omits -Path from the cmdlet call).

type AttachHardDiskInput

type AttachHardDiskInput struct {
	Name               string `json:"name"`
	ControllerType     string `json:"controller_type"`
	ControllerNumber   int    `json:"controller_number"`
	ControllerLocation int    `json:"controller_location"`
	Path               string `json:"path"`
}

AttachHardDiskInput is the stdin JSON shape for vm/add-hard-disk-drive.ps1. All fields are required; the script's ValidateSet on ControllerType is the second line of defense against typos that the resource-layer schema validator should catch first.

type AttachNetworkAdapterInput

type AttachNetworkAdapterInput struct {
	Name       string `json:"name"`
	VMName     string `json:"vm_name"`
	SwitchName string `json:"switch_name"`
}

AttachNetworkAdapterInput is the stdin JSON shape for vm/add-network-adapter.ps1. All three fields are required; uniqueness of Name within a VM is enforced by the resource-layer schema validator (Hyper-V itself doesn't enforce it).

type BootOrderEntry

type BootOrderEntry struct {
	Type               string `json:"Type"`
	ControllerType     string `json:"ControllerType"`
	ControllerNumber   int    `json:"ControllerNumber"`
	ControllerLocation int    `json:"ControllerLocation"`
	Name               string `json:"Name"`
}

BootOrderEntry is the per-entry shape vm/get.ps1 emits inside VM.BootOrder. Type discriminates between hard_disk_drive / dvd_drive (which carry the ControllerType + ControllerNumber + ControllerLocation slot tuple) and network_adapter (which carries Name). Unused fields for a given Type are zero values; consumers branch on Type.

Gen 1 VMs always emit []BootOrderEntry{} (the script doesn't fetch firmware for them; gen 1 BIOS StartupOrder is a separate, deferred schema slice).

type Client

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

Client is the typed wrapper resources use to invoke Hyper-V cmdlets. One instance per provider configuration; passed via the framework's resp.ResourceData / resp.DataSourceData.

func NewClient

func NewClient(r connection.Runner) *Client

NewClient wraps a connection.Runner. The Runner abstraction is what lets unit tests substitute a fake without standing up a real PowerShell host.

func (*Client) AttachDvdDrive

func (c *Client) AttachDvdDrive(ctx context.Context, in AttachDvdDriveInput) error

AttachDvdDrive adds a DVD drive to a VM at a specific controller slot via Add-VMDvdDrive, optionally loading an ISO. IsoPath=nil produces an empty drive (the medium tray exists but no ISO is loaded); IsoPath=&"path" loads the ISO at attach time.

func (*Client) AttachHardDisk

func (c *Client) AttachHardDisk(ctx context.Context, in AttachHardDiskInput) error

AttachHardDisk wires an existing VHD to a VM at a specific controller slot via Add-VMHardDiskDrive. Slot semantics:

  • (ControllerType, ControllerNumber, ControllerLocation) identifies the slot uniquely. Two attachments at the same slot is an error (Hyper-V's InvalidArgument -> ErrPSExecution).
  • The Path argument is the existing VHD's location -- this method does NOT create the VHD; pair with hyperv_vhd or hyperv_image_file for that.
  • ControllerType=IDE on a gen 2 VM errors at the cmdlet layer with a clear "cannot attach IDE devices to a generation 2 virtual machine" -- the resource-layer schema validator should catch this at plan time, but the script-side ValidateSet is defense in depth.

Returns ErrNotFound if the VM is missing (resource Read should have reconciled before this is reachable, but the path exists for safety). Other errors map to ErrPSExecution and surface verbatim.

func (*Client) AttachNetworkAdapter

func (c *Client) AttachNetworkAdapter(ctx context.Context, in AttachNetworkAdapterInput) error

AttachNetworkAdapter adds a new NIC to a VM and binds it to the named virtual switch via Add-VMNetworkAdapter. The display name is the slot key used by the resource-layer Update reconciliation.

Returns ErrNotFound if the VM is missing. Switch-not-found surfaces as ErrPSExecution (Hyper-V's InvalidArgument category isn't routed to a typed sentinel for this cmdlet).

func (*Client) DetachDvdDrive

func (c *Client) DetachDvdDrive(ctx context.Context, in DetachDvdDriveInput) error

DetachDvdDrive removes a DVD drive from a VM at a specific controller slot via Remove-VMDvdDrive. Same slot-keyed semantics as DetachHardDisk -- whatever ISO (if any) was loaded gets implicitly ejected.

func (*Client) DetachHardDisk

func (c *Client) DetachHardDisk(ctx context.Context, in DetachHardDiskInput) error

DetachHardDisk removes a VHD attachment from a VM at a specific controller slot via Remove-VMHardDiskDrive. The slot tuple alone identifies the attachment (Path is not part of the wire payload).

"Slot already empty" surfaces as ObjectNotFound from the cmdlet -> ErrNotFound on the Go side. The resource-layer reconciliation in Update treats ErrNotFound as a no-op (desired state is "empty", already met). Other errors map to ErrPSExecution.

func (*Client) DetachNetworkAdapter

func (c *Client) DetachNetworkAdapter(ctx context.Context, in DetachNetworkAdapterInput) error

DetachNetworkAdapter removes a NIC from a VM by display name via Remove-VMNetworkAdapter. Missing VM and "no NIC by that name" both surface as ObjectNotFound -> ErrNotFound; the resource-layer Update reconciliation treats ErrNotFound as a no-op (desired state is "no NIC by that name", already met).

func (*Client) GetImageFile

func (c *Client) GetImageFile(ctx context.Context, path string) (*ImageFile, error)

GetImageFile reads metadata + SHA-256 for a file on the host. Returns ErrNotFound when the file is absent (resource Read should call RemoveResource), or ErrUnauthorized for permission errors. SHA-256 is recomputed on every call -- intentional drift detection per PLAN.md S7.

func (*Client) GetVHD

func (c *Client) GetVHD(ctx context.Context, path string) (*VHD, error)

GetVHD reads a VHD's metadata + parent/format/attached flags. Returns ErrNotFound when the file is absent (resource Read should call RemoveResource), or ErrUnauthorized for permission errors.

func (*Client) GetVM

func (c *Client) GetVM(ctx context.Context, name string) (*VM, error)

GetVM fetches a VM by name. Returns ErrNotFound when the VM doesn't exist (resource Read should call RemoveResource), or ErrUnauthorized for permission errors. SecureBootEnabled in the returned VM is *bool because gen 1 VMs report null (no Secure Boot concept).

func (*Client) GetVMHost

func (c *Client) GetVMHost(ctx context.Context) (*VMHost, error)

GetVMHost returns the Hyper-V host info. The cmdlet stays inline; when M1c lands the vswitch scripts they'll move to internal/scripts/<resource>/<verb>.ps1 with Pester coverage.

func (*Client) GetVMSwitch

func (c *Client) GetVMSwitch(ctx context.Context, name string) (*VMSwitch, error)

GetVMSwitch fetches a virtual switch by name. Returns ErrNotFound when the switch doesn't exist (resource Read should call RemoveResource), or ErrUnavailable when vmms is stopped / cluster node fenced (transient).

func (*Client) NewImageFileFromHostPath

func (c *Client) NewImageFileFromHostPath(ctx context.Context, destinationPath string) (*ImageFile, error)

NewImageFileFromHostPath verifies a file the user attests already exists at destinationPath and returns its metadata. No copy, no fetch. Returns ErrNotFound if the file is absent. For host_path-mode resources, Delete is a no-op on the Go side -- the user did not ask the provider to put the file there, so removing it on destroy would surprise them.

func (*Client) NewImageFileFromURL

func (c *Client) NewImageFileFromURL(ctx context.Context, in NewImageFileFromURLInput) (*ImageFile, error)

NewImageFileFromURL downloads via Start-BitsTransfer to a sibling .part file in the destination directory, verifies the SHA-256 against in.ExpectedSha256, and atomic-renames into place. Returns ErrChecksumMismatch when the downloaded bytes don't hash to the expected value (the .part is cleaned up; no half-baked file lingers at the canonical destination).

func (*Client) NewVHDDifferencing

func (c *Client) NewVHDDifferencing(ctx context.Context, in NewVHDDifferencingInput) (*VHD, error)

NewVHDDifferencing creates a child that reads from in.ParentPath and writes new blocks locally. Returns ErrInvalidParentPath when the parent path is missing or invalid -- spike #3 documented the mapping from New-VHD's "InvalidParameter,Microsoft.Vhd.*" envelope to this sentinel.

func (*Client) NewVHDDynamic

func (c *Client) NewVHDDynamic(ctx context.Context, in NewVHDDynamicInput) (*VHD, error)

NewVHDDynamic creates a sparse VHD/VHDX. Initial on-disk size is minimal; the file grows as the guest writes blocks, up to SizeBytes.

func (*Client) NewVHDFixed

func (c *Client) NewVHDFixed(ctx context.Context, in NewVHDFixedInput) (*VHD, error)

NewVHDFixed creates a pre-allocated (full-sized on disk) VHD/VHDX. Slow create, no runtime expansion. Returns the post-create read shape.

func (*Client) NewVM

func (c *Client) NewVM(ctx context.Context, in NewVMInput) (*VM, error)

NewVM creates a VM and returns the canonical read shape. The script-side sequence is New-VM (with -NoVHD -BootDevice None -- no auto-attach of storage or boot device) followed by Set-VMMemory (static, with DynamicMemoryEnabled=$false in the same call), Set-VMProcessor, and the optional Set-VMFirmware (gen 2 + SecureBoot) and Set-VM (Notes) tail.

func (*Client) NewVMSwitch

func (c *Client) NewVMSwitch(ctx context.Context, in NewVMSwitchInput) (*VMSwitch, error)

NewVMSwitch creates a virtual switch and returns the canonical read shape. The script-side guard rejects Private + AllowManagementOS with a clear error before invoking the cmdlet (see new.ps1).

func (*Client) RemoveImageFile

func (c *Client) RemoveImageFile(ctx context.Context, path string) error

RemoveImageFile deletes a file from the host. Resource Delete should treat ErrNotFound as success (the file is already gone). Should NOT be called for host_path-mode resources -- the Go-side resource gates this based on the source_mode tracked in state.

func (*Client) RemoveVHD

func (c *Client) RemoveVHD(ctx context.Context, path string) error

RemoveVHD deletes the VHD file. Resource Delete should treat ErrNotFound as success (already gone). The cmdlet errors loudly when the file is attached to a running VM (open file handle); that surfaces as ErrPSExecution rather than being swallowed.

func (*Client) RemoveVM

func (c *Client) RemoveVM(ctx context.Context, name string) error

RemoveVM deletes a VM. Resource Delete should treat ErrNotFound as success (the VM is already gone). The script stops the VM first if it's running (Remove-VM errors on a running VM); this is the one place the PS layer drives a power transition, justified because destroy is destructive by definition.

func (*Client) RemoveVMSwitch

func (c *Client) RemoveVMSwitch(ctx context.Context, name string) error

RemoveVMSwitch deletes a virtual switch by name. Resource Delete should treat ErrNotFound as success (the switch is already gone).

func (*Client) ResizeVHD

func (c *Client) ResizeVHD(ctx context.Context, path string, sizeBytes int64) (*VHD, error)

ResizeVHD changes the declared size of an existing VHD. The cmdlet errors on shrink-without-compaction (run Optimize-VHD first) and on fixed-format resize while the disk is attached to a running VM; both surface as ErrPSExecution to the resource layer.

func (*Client) SetBootOrder

func (c *Client) SetBootOrder(ctx context.Context, in SetBootOrderInput) error

SetBootOrder replaces the boot device sequence on a gen 2 VM via Set-VMFirmware -BootOrder. Wholesale replacement: each call sets the full order; the script resolves each entry's slot/name to the underlying device handle the cmdlet expects. Gen 1 isn't supported in this slice -- the resource-layer schema validator should reject boot_order on gen 1 at plan time.

func (*Client) SetVM

func (c *Client) SetVM(ctx context.Context, in SetVMInput) (*VM, error)

SetVM applies a partial update and returns the post-mutation read shape (set.ps1 follows the Set-* sequence with a Get-VM read-back so the emitted shape matches GetVM exactly).

Callers should populate in.Generation from prior state so set.ps1's gen-2-only SecureBoot guard fires at the script layer; the Go-side Update should never let SecureBoot through for a gen 1 VM (the ConfigValidator catches it at plan time), but the script-layer guard is defense in depth.

Mutations on a running VM may error: vcpu, memory_bytes, and secure_boot generally require the VM to be Off. The script surfaces those errors verbatim -- the operator drives power transitions via hyperv_vm_state.

func (*Client) SetVMState

func (c *Client) SetVMState(ctx context.Context, in SetVMStateInput) (*VM, error)

SetVMState transitions the VM's power state via Start-VM (Desired= 'Running') or Stop-VM -TurnOff -Force (Desired='Off'). Returns the post-transition VM read so callers can refresh state without a separate GetVM round-trip. Idempotent at the cmdlet level: setting Desired='Running' on an already-Running VM is a no-op.

func (*Client) SetVMSwitch

func (c *Client) SetVMSwitch(ctx context.Context, in SetVMSwitchInput) (*VMSwitch, error)

SetVMSwitch applies a partial update and returns the post-mutation read shape (set.ps1 follows Set-VMSwitch with a Get-VMSwitch read-back so the emitted shape matches GetVMSwitch exactly).

Callers should populate in.SwitchType from prior state so set.ps1's Private + AllowManagementOS guard can fire at the script layer; without it, the cmdlet's opaque "parameter is not applicable" error surfaces instead.

type DetachDvdDriveInput

type DetachDvdDriveInput struct {
	Name               string `json:"name"`
	ControllerType     string `json:"controller_type"`
	ControllerNumber   int    `json:"controller_number"`
	ControllerLocation int    `json:"controller_location"`
}

DetachDvdDriveInput mirrors DetachHardDiskInput -- slot tuple identifies the DVD to remove, no Path needed.

type DetachHardDiskInput

type DetachHardDiskInput struct {
	Name               string `json:"name"`
	ControllerType     string `json:"controller_type"`
	ControllerNumber   int    `json:"controller_number"`
	ControllerLocation int    `json:"controller_location"`
}

DetachHardDiskInput is the stdin JSON shape for vm/remove-hard-disk-drive.ps1. Path is intentionally omitted -- the slot tuple identifies the attachment, not the underlying VHD.

type DetachNetworkAdapterInput

type DetachNetworkAdapterInput struct {
	Name   string `json:"name"`
	VMName string `json:"vm_name"`
}

DetachNetworkAdapterInput is the stdin JSON shape for vm/remove-network-adapter.ps1. Name + VMName identify the NIC to detach; the cmdlet would happily remove ALL NICs sharing the same Name, but the schema-level uniqueness validator means there's only ever one match in our state.

type DvdDrive

type DvdDrive struct {
	Path               string `json:"Path"`
	ControllerType     string `json:"ControllerType"`
	ControllerNumber   int    `json:"ControllerNumber"`
	ControllerLocation int    `json:"ControllerLocation"`
}

DvdDrive is the per-attachment shape vm/get.ps1 emits inside VM.DvdDrives. Same slot-tuple identity as HardDiskDrive (ControllerType + ControllerNumber + ControllerLocation), but Path may be empty -- a DVD drive without an ISO loaded is a legitimate state (the drive exists, the medium tray is empty).

type HardDiskDrive

type HardDiskDrive struct {
	Path               string `json:"Path"`
	ControllerType     string `json:"ControllerType"`
	ControllerNumber   int    `json:"ControllerNumber"`
	ControllerLocation int    `json:"ControllerLocation"`
}

HardDiskDrive is the per-attachment shape vm/get.ps1 emits inside VM.HardDiskDrives. The (ControllerType, ControllerNumber, ControllerLocation) tuple identifies the slot uniquely on a given VM; Path identifies the underlying VHD/VHDX. The same VHD attached at two different slots produces two HardDiskDrive entries.

type ImageFile

type ImageFile struct {
	Path      string `json:"Path"`
	SizeBytes int64  `json:"SizeBytes"`
	Sha256    string `json:"Sha256"`
}

ImageFile is the canonical read shape emitted by image_file/{get,new}.ps1. Sha256 is lowercase hex (the wire contract); SizeBytes is int64 because VHDX/ISO files routinely exceed 2^31 bytes.

type NetworkAdapter

type NetworkAdapter struct {
	Name        string   `json:"Name"`
	SwitchName  string   `json:"SwitchName"`
	IPAddresses []string `json:"IPAddresses"`
}

NetworkAdapter is the per-NIC shape vm/get.ps1 emits inside VM.NetworkAdapters. Display Name is the slot key the resource-layer reconciliation uses to diff plan vs state. SwitchName identifies which hyperv_virtual_switch the NIC is bound to (or empty when unbound -- Hyper-V allows that, though it's rare).

IPAddresses is populated by Hyper-V's integration services running in the guest -- empty when the VM is Off, when integration services haven't loaded yet, or when the guest doesn't ship them. The resource layer flattens IPAddresses across all NICs into a top- level ip_addresses Computed attribute.

type NewImageFileFromURLInput

type NewImageFileFromURLInput struct {
	DestinationPath string `json:"destination_path"`
	URL             string `json:"url"`
	ExpectedSha256  string `json:"expected_sha256"`
}

NewImageFileFromURLInput is the public input shape for the URL source mode of image_file/new.ps1. The discriminator field (source_mode) is not on the public struct -- the typed-client method sets it internally so callers can't pass the wrong value for the method they invoke.

type NewVHDDifferencingInput

type NewVHDDifferencingInput struct {
	Path       string `json:"path"`
	ParentPath string `json:"parent_path"`
}

NewVHDDifferencingInput is the public input shape for the Differencing creation mode. SizeBytes and BlockSizeBytes are inherited from the parent and rejected by Hyper-V if supplied; the typed-client method omits them from the wire payload.

type NewVHDDynamicInput

type NewVHDDynamicInput struct {
	Path           string `json:"path"`
	SizeBytes      int64  `json:"size_bytes"`
	BlockSizeBytes *int64 `json:"block_size_bytes,omitempty"`
}

NewVHDDynamicInput is the public input shape for the Dynamic creation mode. Same field set as fixed -- the discriminator is what differs.

type NewVHDFixedInput

type NewVHDFixedInput struct {
	Path           string `json:"path"`
	SizeBytes      int64  `json:"size_bytes"`
	BlockSizeBytes *int64 `json:"block_size_bytes,omitempty"`
}

NewVHDFixedInput is the public input shape for the Fixed creation mode. BlockSizeBytes is *int64 + omitempty so absent leaves the cmdlet default. The discriminator (vhd_type) is set internally by the typed client method, not on the public struct.

type NewVMInput

type NewVMInput struct {
	Name           string  `json:"name"`
	Generation     int     `json:"generation"`
	Vcpu           int     `json:"vcpu"`
	MemoryBytes    int64   `json:"memory_bytes"`
	DynamicMemory  *bool   `json:"dynamic_memory,omitempty"`
	MinMemoryBytes *int64  `json:"min_memory_bytes,omitempty"`
	MaxMemoryBytes *int64  `json:"max_memory_bytes,omitempty"`
	SecureBoot     *bool   `json:"secure_boot,omitempty"`
	Notes          *string `json:"notes,omitempty"`
}

NewVMInput is the stdin JSON shape for vm/new.ps1.

Required fields: Name, Generation, Vcpu, MemoryBytes (startup). Optionals use pointer types so missing-vs-explicit-false round-trips correctly through the wire contract: the entry block in new.ps1 treats absent keys and explicit null as equivalent (both skip the corresponding Set-*), so omitempty + nil pointer yields the "use cmdlet default" behavior.

Dynamic memory: DynamicMemory opts in to Hyper-V's dynamic memory mode. MinMemoryBytes / MaxMemoryBytes are the minimum and maximum bounds and are only meaningful when DynamicMemory is true (the script gates forwarding accordingly). When DynamicMemory is nil, the script defaults to static memory (DynamicMemoryEnabled=$false), preserving the v2-and- prior behavior for callers that don't manage dynamic memory.

type NewVMSwitchInput

type NewVMSwitchInput struct {
	Name              string   `json:"name"`
	SwitchType        string   `json:"switch_type"`
	NetAdapterNames   []string `json:"net_adapter_names,omitempty"`
	AllowManagementOS *bool    `json:"allow_management_os,omitempty"`
	Notes             *string  `json:"notes,omitempty"`
}

NewVMSwitchInput is the stdin JSON shape for vswitch/new.ps1.

Required fields: Name, SwitchType. Optional fields use pointer types so missing-vs-explicit-false round-trips correctly through the wire contract: the entry block in new.ps1 treats absent keys and explicit null as equivalent (both skip the splat), so omitempty + nil pointer yields the "use cmdlet default" behavior.

type SetBootOrderEntryInput

type SetBootOrderEntryInput struct {
	Type               string `json:"type"`
	ControllerType     string `json:"controller_type"`
	ControllerNumber   int    `json:"controller_number"`
	ControllerLocation int    `json:"controller_location"`
	Name               string `json:"name"`
}

SetBootOrderEntryInput is the per-entry shape inside SetBootOrderInput.BootOrder. Same discriminator pattern as BootOrderEntry: Type drives which subset of fields the script reads.

All fields are emitted unconditionally (no omitempty). Reason: PowerShell's Set-StrictMode 3.0 throws on access of an absent property on a PSCustomObject. The script reads $entry.controller_* for HDD/DVD entries and $entry.name for NIC entries; whichever fields are unused for a given Type still need to be present on the wire (zero values are fine -- the script's switch ignores them). Specifically, omitempty on `int` would drop controller_number=0, which is the most common slot index and would break the resolver.

type SetBootOrderInput

type SetBootOrderInput struct {
	Name      string                   `json:"name"`
	BootOrder []SetBootOrderEntryInput `json:"boot_order"`
}

SetBootOrderInput is the stdin JSON shape for vm/set-boot-order.ps1. BootOrder is the new desired sequence; the script replaces the VM's current order wholesale (Set-VMFirmware -BootOrder is not additive). Per-entry shape mirrors BootOrderEntry above with snake_case keys.

type SetVMInput

type SetVMInput struct {
	Name           string  `json:"name"`
	Generation     int     `json:"generation"`
	Vcpu           *int    `json:"vcpu,omitempty"`
	MemoryBytes    *int64  `json:"memory_bytes,omitempty"`
	DynamicMemory  *bool   `json:"dynamic_memory,omitempty"`
	MinMemoryBytes *int64  `json:"min_memory_bytes,omitempty"`
	MaxMemoryBytes *int64  `json:"max_memory_bytes,omitempty"`
	SecureBoot     *bool   `json:"secure_boot,omitempty"`
	Notes          *string `json:"notes,omitempty"`
}

SetVMInput is the stdin JSON shape for vm/set.ps1.

Same pattern as NewVMInput, with two differences:

  • Vcpu and MemoryBytes are *int / *int64 because Set is a partial update -- only changed fields are forwarded; nil drops them from the JSON (omitempty) so the script's "key present?" check skips the corresponding Set-* cmdlet.
  • Generation is OPTIONAL on the schema but ALWAYS forwarded by the Update path; it's a validation hint for set.ps1's gen-2-only SecureBoot guard, not a mutation.

type SetVMStateInput

type SetVMStateInput struct {
	Name         string `json:"name"`
	Desired      string `json:"desired"`
	ShutdownMode string `json:"shutdown_mode,omitempty"`
}

SetVMStateInput is the stdin JSON shape for vm/set-state.ps1.

Desired is the primary mutation: 'Off' invokes Stop-VM, 'Running' invokes Start-VM. Other Hyper-V states (Saved, Paused) are out of scope for this slice -- the script's ValidateSet on Desired rejects them.

ShutdownMode is optional and only governs the Stop dispatch:

  • "" or "turn_off" (default): Stop-VM -TurnOff -Force (hard power-off, matches destroy semantics, no integration-services dependency).
  • "graceful": Stop-VM -Force without -TurnOff (ACPI shutdown via integration services; hangs on guests without them).

`omitempty` keeps the wire shape stable for callers that don't care about the mode -- the script defaults to turn_off when the field is absent or empty.

type SetVMSwitchInput

type SetVMSwitchInput struct {
	Name              string   `json:"name"`
	SwitchType        string   `json:"switch_type,omitempty"`
	NetAdapterNames   []string `json:"net_adapter_names,omitempty"`
	AllowManagementOS *bool    `json:"allow_management_os,omitempty"`
	Notes             *string  `json:"notes,omitempty"`
}

SetVMSwitchInput is the stdin JSON shape for vswitch/set.ps1.

Same pattern as NewVMSwitchInput, with two differences:

  • SwitchType is OPTIONAL here -- it's a validation hint, not a mutation. The Update path should populate it from prior state so set.ps1's Private + AllowManagementOS guard fires with a clear error.
  • Only keys present in the input get forwarded to Set-VMSwitch (see set.ps1's wire contract). Sending nil/null for an attribute means "leave it alone"; sending a value means "set it to this".

type VHD

type VHD struct {
	Path           string `json:"Path"`
	VhdType        string `json:"VhdType"`
	SizeBytes      int64  `json:"SizeBytes"`
	FileSizeBytes  int64  `json:"FileSizeBytes"`
	BlockSizeBytes int64  `json:"BlockSizeBytes"`
	ParentPath     string `json:"ParentPath"`
	Format         string `json:"Format"`
	Attached       bool   `json:"Attached"`
}

VHD is the canonical read shape emitted by vhd/{get,new,set}.ps1. SizeBytes is the declared logical size; FileSizeBytes is the actual on-disk size (smaller than SizeBytes for dynamic and differencing). ParentPath is empty unless VhdType is "Differencing".

type VM

type VM struct {
	Name                 string           `json:"Name"`
	ID                   string           `json:"Id"`
	Generation           int              `json:"Generation"`
	ProcessorCount       int              `json:"ProcessorCount"`
	MemoryStartupBytes   int64            `json:"MemoryStartupBytes"`
	MemoryAssignedBytes  int64            `json:"MemoryAssignedBytes"`
	MemoryDynamicEnabled bool             `json:"MemoryDynamicEnabled"`
	MemoryMinimumBytes   *int64           `json:"MemoryMinimumBytes"`
	MemoryMaximumBytes   *int64           `json:"MemoryMaximumBytes"`
	State                string           `json:"State"`
	Notes                string           `json:"Notes"`
	Path                 string           `json:"Path"`
	SecureBootEnabled    *bool            `json:"SecureBootEnabled"`
	HardDiskDrives       []HardDiskDrive  `json:"HardDiskDrives"`
	NetworkAdapters      []NetworkAdapter `json:"NetworkAdapters"`
	DvdDrives            []DvdDrive       `json:"DvdDrives"`
	BootOrder            []BootOrderEntry `json:"BootOrder"`
}

VM is the canonical read shape emitted by vm/{get,new,set}.ps1. SecureBootEnabled is *bool because gen 1 VMs return null (BIOS-based, no Secure Boot concept); gen 2 always returns a real bool.

HardDiskDrives, NetworkAdapters, and DvdDrives are always (possibly empty) slices -- the script-side @() wrapper guarantees JSON array shape even when nothing is attached, so a freshly-created VM with no attachments round-trips as "[]" rather than null.

type VMHost

type VMHost struct {
	ComputerName          string `json:"ComputerName"`
	LogicalProcessorCount int64  `json:"LogicalProcessorCount"`
	MemoryCapacity        int64  `json:"MemoryCapacity"`
	VirtualMachinePath    string `json:"VirtualMachinePath"`
	VirtualHardDiskPath   string `json:"VirtualHardDiskPath"`
}

VMHost mirrors the subset of Get-VMHost output the provider exposes. Field tags match the PowerShell property names captured by spike #2.

type VMSwitch

type VMSwitch struct {
	Name                           string `json:"Name"`
	SwitchType                     string `json:"SwitchType"`
	AllowManagementOS              bool   `json:"AllowManagementOS"`
	NetAdapterInterfaceDescription string `json:"NetAdapterInterfaceDescription"`
	Notes                          string `json:"Notes"`
	ID                             string `json:"Id"`
}

VMSwitch is the canonical read shape emitted by vswitch/{get,new,set}.ps1. Field tags use PascalCase to match Get-VMSwitch's native output (the stdin convention is snake_case per the wire contract; stdout is the raw cmdlet shape consumed by the typed client).

Jump to

Keyboard shortcuts

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