From b77098fb6ae0a7e4bd134065a57724c6ea9f09d3 Mon Sep 17 00:00:00 2001 From: Harsh Rawat Date: Mon, 6 Apr 2026 11:36:03 +0530 Subject: [PATCH 1/5] [shimV2] remove all interfaces from vm manager and guest manager Following the shim V2 standard, we are declaring the interfaces at the place where the APIs are used. Therefore, we are deleting all the interfaces from the existing packages. Signed-off-by: Harsh Rawat --- internal/vm/guestmanager/block_cims.go | 10 ---- .../vm/guestmanager/combinedlayers_lcow.go | 10 ---- .../vm/guestmanager/combinedlayers_wcow.go | 14 ----- internal/vm/guestmanager/guest.go | 26 ++++++---- internal/vm/guestmanager/hvsocket.go | 7 --- internal/vm/guestmanager/manager.go | 25 --------- .../vm/guestmanager/mapped_directory_lcow.go | 10 ---- .../vm/guestmanager/mapped_directory_wcow.go | 8 --- internal/vm/guestmanager/security_policy.go | 10 ---- internal/vm/vmmanager/lifetime.go | 51 ------------------- internal/vm/vmmanager/pipe.go | 11 ---- internal/vm/vmmanager/resources.go | 17 ------- internal/vm/vmmanager/utils.go | 11 +++- internal/vm/vmmanager/vmsocket.go | 12 ----- internal/vm/vmmanager/vsmb.go | 11 ---- 15 files changed, 26 insertions(+), 207 deletions(-) diff --git a/internal/vm/guestmanager/block_cims.go b/internal/vm/guestmanager/block_cims.go index c84cd0b094..eb2c7f52e0 100644 --- a/internal/vm/guestmanager/block_cims.go +++ b/internal/vm/guestmanager/block_cims.go @@ -11,16 +11,6 @@ import ( "github.com/Microsoft/hcsshim/internal/protocol/guestresource" ) -// CIMsManager exposes guest WCOW block CIM operations. -type CIMsManager interface { - // AddWCOWBlockCIMs adds WCOW block CIM mounts in the guest. - AddWCOWBlockCIMs(ctx context.Context, settings *guestresource.CWCOWBlockCIMMounts) error - // RemoveWCOWBlockCIMs removes WCOW block CIM mounts from the guest. - RemoveWCOWBlockCIMs(ctx context.Context, settings *guestresource.CWCOWBlockCIMMounts) error -} - -var _ CIMsManager = (*Guest)(nil) - // AddWCOWBlockCIMs adds WCOW block CIM mounts in the guest. func (gm *Guest) AddWCOWBlockCIMs(ctx context.Context, settings *guestresource.CWCOWBlockCIMMounts) error { request := &hcsschema.ModifySettingRequest{ diff --git a/internal/vm/guestmanager/combinedlayers_lcow.go b/internal/vm/guestmanager/combinedlayers_lcow.go index f62f8a64cd..6d16a28d19 100644 --- a/internal/vm/guestmanager/combinedlayers_lcow.go +++ b/internal/vm/guestmanager/combinedlayers_lcow.go @@ -11,16 +11,6 @@ import ( "github.com/Microsoft/hcsshim/internal/protocol/guestresource" ) -// LCOWLayersManager exposes combined layer operations in the LCOW guest. -type LCOWLayersManager interface { - // AddLCOWCombinedLayers adds combined layers to the LCOW guest. - AddLCOWCombinedLayers(ctx context.Context, settings guestresource.LCOWCombinedLayers) error - // RemoveLCOWCombinedLayers removes combined layers from the LCOW guest. - RemoveLCOWCombinedLayers(ctx context.Context, settings guestresource.LCOWCombinedLayers) error -} - -var _ LCOWLayersManager = (*Guest)(nil) - // AddLCOWCombinedLayers adds LCOW combined layers in the guest. func (gm *Guest) AddLCOWCombinedLayers(ctx context.Context, settings guestresource.LCOWCombinedLayers) error { modifyRequest := &hcsschema.ModifySettingRequest{ diff --git a/internal/vm/guestmanager/combinedlayers_wcow.go b/internal/vm/guestmanager/combinedlayers_wcow.go index 4397f96fc1..ffa19aa438 100644 --- a/internal/vm/guestmanager/combinedlayers_wcow.go +++ b/internal/vm/guestmanager/combinedlayers_wcow.go @@ -11,20 +11,6 @@ import ( "github.com/Microsoft/hcsshim/internal/protocol/guestresource" ) -// WCOWLayersManager exposes combined layer operations in the WCOW guest. -type WCOWLayersManager interface { - // AddWCOWCombinedLayers adds combined layers to the WCOW guest. - AddWCOWCombinedLayers(ctx context.Context, settings guestresource.WCOWCombinedLayers) error - // AddCWCOWCombinedLayers adds combined layers to the CWCOW guest. - AddCWCOWCombinedLayers(ctx context.Context, settings guestresource.CWCOWCombinedLayers) error - // RemoveWCOWCombinedLayers removes combined layers from the WCOW guest. - RemoveWCOWCombinedLayers(ctx context.Context, settings guestresource.WCOWCombinedLayers) error - // RemoveCWCOWCombinedLayers removes combined layers from the CWCOW guest. - RemoveCWCOWCombinedLayers(ctx context.Context, settings guestresource.CWCOWCombinedLayers) error -} - -var _ WCOWLayersManager = (*Guest)(nil) - // AddWCOWCombinedLayers adds WCOW combined layers in the guest. func (gm *Guest) AddWCOWCombinedLayers(ctx context.Context, settings guestresource.WCOWCombinedLayers) error { modifyRequest := &hcsschema.ModifySettingRequest{ diff --git a/internal/vm/guestmanager/guest.go b/internal/vm/guestmanager/guest.go index 7f9b705376..b8ef0f11be 100644 --- a/internal/vm/guestmanager/guest.go +++ b/internal/vm/guestmanager/guest.go @@ -17,6 +17,19 @@ import ( "github.com/sirupsen/logrus" ) +// uvm exposes the subset of [vmmanager.UtilityVM] functionality that the +// guest manager needs. +type uvm interface { + // ID returns the user-visible identifier for the Utility VM. + ID() string + // RuntimeID returns the Hyper-V VM GUID. + RuntimeID() guid.GUID + // Wait blocks until the VM exits or ctx is cancelled. + Wait(ctx context.Context) error + // ExitError returns the error that caused the VM to exit, if any. + ExitError() error +} + // Guest manages the GCS connection and guest-side operations for a utility VM. type Guest struct { // mu serializes all operations that interact with the guest connection (gc). @@ -28,22 +41,15 @@ type Guest struct { log *logrus.Entry // uvm is the utility VM that this GuestManager is managing. - // We restrict access to just lifetime manager and VMSocket manager. - // Other APIs are outside the purview of this package. - uvm interface { - vmmanager.LifetimeManager - vmmanager.VMSocketManager - } + // We restrict access to just the methods actually needed by this package. + uvm uvm // gc is the active GCS connection to the guest. // It will be nil if no connection is active. gc *gcs.GuestConnection } // New creates a new Guest Manager. -func New(ctx context.Context, uvm interface { - vmmanager.LifetimeManager - vmmanager.VMSocketManager -}) *Guest { +func New(ctx context.Context, uvm uvm) *Guest { return &Guest{ log: log.G(ctx).WithField(logfields.UVMID, uvm.ID()), uvm: uvm, diff --git a/internal/vm/guestmanager/hvsocket.go b/internal/vm/guestmanager/hvsocket.go index 1108ec1cd6..8cb616fd0f 100644 --- a/internal/vm/guestmanager/hvsocket.go +++ b/internal/vm/guestmanager/hvsocket.go @@ -11,13 +11,6 @@ import ( "github.com/Microsoft/hcsshim/internal/protocol/guestresource" ) -// HVSocketManager exposes the hvSocket operations in the Guest. -type HVSocketManager interface { - UpdateHvSocketAddress(ctx context.Context, settings *hcsschema.HvSocketAddress) error -} - -var _ HVSocketManager = (*Guest)(nil) - // UpdateHvSocketAddress updates the Hyper-V socket address settings for the VM. // These address settings are applied by the GCS every time the VM starts or restores. func (gm *Guest) UpdateHvSocketAddress(ctx context.Context, settings *hcsschema.HvSocketAddress) error { diff --git a/internal/vm/guestmanager/manager.go b/internal/vm/guestmanager/manager.go index 2eeb705bbd..474e9ca63c 100644 --- a/internal/vm/guestmanager/manager.go +++ b/internal/vm/guestmanager/manager.go @@ -8,33 +8,8 @@ import ( "github.com/Microsoft/hcsshim/internal/cmd" "github.com/Microsoft/hcsshim/internal/gcs" - - "github.com/Microsoft/go-winio/pkg/guid" ) -// Manager provides access to guest operations over the GCS connection. -// Call CreateConnection before invoking other methods. -type Manager interface { - // CreateConnection accepts the GCS connection and performs initial setup. - CreateConnection(ctx context.Context, GCSServiceID guid.GUID, opts ...ConfigOption) error - // CloseConnection closes the GCS connection and listener. - CloseConnection() error - // Capabilities returns the guest's declared capabilities. - Capabilities() gcs.GuestDefinedCapabilities - // CreateContainer creates a container within guest using ID `cid` and `config`. - // Once the container is created, it can be managed using the returned `gcs.Container` interface. - // `gcs.Container` uses the underlying guest connection to issue commands to the guest. - CreateContainer(ctx context.Context, cid string, config interface{}) (*gcs.Container, error) - // DumpStacks requests a stack dump from the guest and returns it as a string. - DumpStacks(ctx context.Context) (string, error) - // DeleteContainerState removes persisted state for the container identified by `cid` from the guest. - DeleteContainerState(ctx context.Context, cid string) error - // ExecIntoUVM executes commands specified in the requests in the utility VM. - ExecIntoUVM(ctx context.Context, request *cmd.CmdProcessRequest) (int, error) -} - -var _ Manager = (*Guest)(nil) - // Capabilities returns the capabilities of the guest connection. func (gm *Guest) Capabilities() gcs.GuestDefinedCapabilities { gm.mu.RLock() diff --git a/internal/vm/guestmanager/mapped_directory_lcow.go b/internal/vm/guestmanager/mapped_directory_lcow.go index 8b6a1abe55..a401f7ff26 100644 --- a/internal/vm/guestmanager/mapped_directory_lcow.go +++ b/internal/vm/guestmanager/mapped_directory_lcow.go @@ -11,16 +11,6 @@ import ( "github.com/Microsoft/hcsshim/internal/protocol/guestresource" ) -// LCOWDirectoryManager exposes mapped directory operations in the LCOW guest. -type LCOWDirectoryManager interface { - // AddLCOWMappedDirectory maps a directory into the LCOW guest. - AddLCOWMappedDirectory(ctx context.Context, settings guestresource.LCOWMappedDirectory) error - // RemoveLCOWMappedDirectory unmaps a directory from the LCOW guest. - RemoveLCOWMappedDirectory(ctx context.Context, settings guestresource.LCOWMappedDirectory) error -} - -var _ LCOWDirectoryManager = (*Guest)(nil) - // AddLCOWMappedDirectory maps a directory into LCOW guest. func (gm *Guest) AddLCOWMappedDirectory(ctx context.Context, settings guestresource.LCOWMappedDirectory) error { request := &hcsschema.ModifySettingRequest{ diff --git a/internal/vm/guestmanager/mapped_directory_wcow.go b/internal/vm/guestmanager/mapped_directory_wcow.go index 19ea2e0c4a..a48083a4d7 100644 --- a/internal/vm/guestmanager/mapped_directory_wcow.go +++ b/internal/vm/guestmanager/mapped_directory_wcow.go @@ -11,14 +11,6 @@ import ( "github.com/Microsoft/hcsshim/internal/protocol/guestresource" ) -// WCOWDirectoryManager exposes mapped directory operations in the WCOW guest. -type WCOWDirectoryManager interface { - // AddMappedDirectory maps a directory into the WCOW guest. - AddMappedDirectory(ctx context.Context, settings *hcsschema.MappedDirectory) error -} - -var _ WCOWDirectoryManager = (*Guest)(nil) - // AddMappedDirectory maps a directory into the guest. func (gm *Guest) AddMappedDirectory(ctx context.Context, settings *hcsschema.MappedDirectory) error { request := &hcsschema.ModifySettingRequest{ diff --git a/internal/vm/guestmanager/security_policy.go b/internal/vm/guestmanager/security_policy.go index c91a4950b6..bb04749ced 100644 --- a/internal/vm/guestmanager/security_policy.go +++ b/internal/vm/guestmanager/security_policy.go @@ -11,16 +11,6 @@ import ( "github.com/Microsoft/hcsshim/internal/protocol/guestresource" ) -// SecurityPolicyManager exposes guest security policy operations. -type SecurityPolicyManager interface { - // AddSecurityPolicy adds a security policy to the guest. - AddSecurityPolicy(ctx context.Context, settings guestresource.ConfidentialOptions) error - // InjectPolicyFragment injects a policy fragment into the guest. - InjectPolicyFragment(ctx context.Context, settings guestresource.SecurityPolicyFragment) error -} - -var _ SecurityPolicyManager = (*Guest)(nil) - // AddSecurityPolicy adds a security policy to the guest. func (gm *Guest) AddSecurityPolicy(ctx context.Context, settings guestresource.ConfidentialOptions) error { request := &hcsschema.ModifySettingRequest{ diff --git a/internal/vm/vmmanager/lifetime.go b/internal/vm/vmmanager/lifetime.go index b2cc737b53..c98cba82a4 100644 --- a/internal/vm/vmmanager/lifetime.go +++ b/internal/vm/vmmanager/lifetime.go @@ -11,57 +11,6 @@ import ( hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" ) -type LifetimeManager interface { - // ID will return a string identifier for the Utility VM. - ID() string - - // RuntimeID will return the Hyper-V VM GUID for the Utility VM. - // - // Only valid after the utility VM has been created. - RuntimeID() guid.GUID - - // Start will power on the Utility VM and put it into a running state. This will boot the guest OS and start all of the - // devices configured on the machine. - Start(ctx context.Context) error - - // Terminate will forcefully power off the Utility VM. - // It waits for the UVM to exit and returns any encountered errors. - Terminate(ctx context.Context) error - - // Close terminates and releases resources associated with the utility VM. - Close(ctx context.Context) error - - // Pause will place the Utility VM into a paused state. The guest OS will be halted and any devices will have be in a - // a suspended state. Save can be used to snapshot the current state of the virtual machine, and Resume can be used to - // place the virtual machine back into a running state. - Pause(ctx context.Context) error - - // Resume will put a previously paused Utility VM back into a running state. The guest OS will resume operation from the point - // in time it was paused and all devices should be un-suspended. - Resume(ctx context.Context) error - - // Save will snapshot the state of the Utility VM at the point in time when the VM was paused. - Save(ctx context.Context, options hcsschema.SaveOptions) error - - // Wait synchronously waits for the Utility VM to terminate. - Wait(ctx context.Context) error - - // PropertiesV2 returns the properties of the Utility VM. - PropertiesV2(ctx context.Context, types ...hcsschema.PropertyType) (*hcsschema.Properties, error) - - // StartedTime returns the time when the Utility VM entered the running state. - StartedTime() time.Time - - // StoppedTime returns the time when the Utility VM entered the stopped state. - StoppedTime() time.Time - - // ExitError will return any error if the Utility VM exited unexpectedly, or if the Utility VM experienced an - // error after Wait returned, it will return the wait error. - ExitError() error -} - -var _ LifetimeManager = (*UtilityVM)(nil) - // ID returns the ID of the utility VM. func (uvm *UtilityVM) ID() string { return uvm.id diff --git a/internal/vm/vmmanager/pipe.go b/internal/vm/vmmanager/pipe.go index 6de649e5b2..f46904ae14 100644 --- a/internal/vm/vmmanager/pipe.go +++ b/internal/vm/vmmanager/pipe.go @@ -11,17 +11,6 @@ import ( "github.com/Microsoft/hcsshim/internal/protocol/guestrequest" ) -// PipeManager manages adding and removing named pipes for a Utility VM. -type PipeManager interface { - // AddPipe adds a named pipe to the Utility VM. - AddPipe(ctx context.Context, hostPath string) error - - // RemovePipe removes a named pipe from the Utility VM. - RemovePipe(ctx context.Context, hostPath string) error -} - -var _ PipeManager = (*UtilityVM)(nil) - func (uvm *UtilityVM) AddPipe(ctx context.Context, hostPath string) error { modification := &hcsschema.ModifySettingRequest{ RequestType: guestrequest.RequestTypeAdd, diff --git a/internal/vm/vmmanager/resources.go b/internal/vm/vmmanager/resources.go index 48f23a5fe1..c91ae3db07 100644 --- a/internal/vm/vmmanager/resources.go +++ b/internal/vm/vmmanager/resources.go @@ -10,23 +10,6 @@ import ( hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" ) -type ResourceManager interface { - // SetCPUGroup assigns the Utility VM to a cpu group. - SetCPUGroup(ctx context.Context, settings *hcsschema.CpuGroup) error - - // UpdateCPULimits updates the CPU limits for the Utility VM. - // `limit` is the percentage of CPU cycles that the Utility VM is allowed to use. - // `weight` is the relative weight of the Utility VM compared to other VMs when CPU cycles are contended. - // `reservation` is the percentage of CPU cycles that are reserved for the Utility VM. - // `maximumFrequencyMHz` is the maximum frequency in MHz that the Utility VM can use. - UpdateCPULimits(ctx context.Context, settings *hcsschema.ProcessorLimits) error - - // UpdateMemory makes a call to the VM's orchestrator to update the VM's size in MB - UpdateMemory(ctx context.Context, memory uint64) error -} - -var _ ResourceManager = (*UtilityVM)(nil) - func (uvm *UtilityVM) SetCPUGroup(ctx context.Context, settings *hcsschema.CpuGroup) error { modification := &hcsschema.ModifySettingRequest{ ResourcePath: resourcepaths.CPUGroupResourcePath, diff --git a/internal/vm/vmmanager/utils.go b/internal/vm/vmmanager/utils.go index ad247352c8..5790fd5b0d 100644 --- a/internal/vm/vmmanager/utils.go +++ b/internal/vm/vmmanager/utils.go @@ -7,9 +7,18 @@ import ( "net" ) +// vmWaiter exposes the subset of VM lifecycle needed by [AcceptConnection]: +// Implemented by [UtilityVM]. +type vmWaiter interface { + // Wait blocks until the VM exits or ctx is cancelled. + Wait(ctx context.Context) error + // ExitError returns the error that caused the VM to exit, if any. + ExitError() error +} + // AcceptConnection accepts a connection and then closes a listener. // It monitors ctx.Done() and uvm.Wait() for early termination. -func AcceptConnection(ctx context.Context, uvm LifetimeManager, l net.Listener, closeConnection bool) (net.Conn, error) { +func AcceptConnection(ctx context.Context, uvm vmWaiter, l net.Listener, closeConnection bool) (net.Conn, error) { // Channel to capture the accept result type acceptResult struct { conn net.Conn diff --git a/internal/vm/vmmanager/vmsocket.go b/internal/vm/vmmanager/vmsocket.go index 637850e931..c6fb7a0bfe 100644 --- a/internal/vm/vmmanager/vmsocket.go +++ b/internal/vm/vmmanager/vmsocket.go @@ -11,18 +11,6 @@ import ( "github.com/Microsoft/hcsshim/internal/protocol/guestrequest" ) -// VMSocketManager manages configuration for a hypervisor socket transport. This includes sockets such as -// HvSocket and Vsock. -type VMSocketManager interface { - // UpdateHvSocketService will update the configuration for the HvSocket service with the specified `serviceID`. - UpdateHvSocketService(ctx context.Context, serviceID string, config *hcsschema.HvSocketServiceConfig) error - - // RemoveHvSocketService will remove the HvSocket service with the specified `serviceID` from the Utility VM. - RemoveHvSocketService(ctx context.Context, serviceID string) error -} - -var _ VMSocketManager = (*UtilityVM)(nil) - // UpdateHvSocketService calls HCS to update/create the hvsocket service for // the UVM. Takes in a service ID and the hvsocket service configuration. If there is no // entry for the service ID already it will be created. The same call on HvSockets side diff --git a/internal/vm/vmmanager/vsmb.go b/internal/vm/vmmanager/vsmb.go index af7af6c2d7..b957f257a2 100644 --- a/internal/vm/vmmanager/vsmb.go +++ b/internal/vm/vmmanager/vsmb.go @@ -11,17 +11,6 @@ import ( "github.com/Microsoft/hcsshim/internal/protocol/guestrequest" ) -// VSMBManager manages adding virtual smb shares to a Utility VM. -type VSMBManager interface { - // AddVSMB adds a virtual smb share to a running Utility VM. - AddVSMB(ctx context.Context, settings hcsschema.VirtualSmbShare) error - - // RemoveVSMB removes a virtual smb share from a running Utility VM. - RemoveVSMB(ctx context.Context, settings hcsschema.VirtualSmbShare) error -} - -var _ VSMBManager = (*UtilityVM)(nil) - func (uvm *UtilityVM) AddVSMB(ctx context.Context, settings hcsschema.VirtualSmbShare) error { modification := &hcsschema.ModifySettingRequest{ RequestType: guestrequest.RequestTypeAdd, From e0b7ba6df5c1a6ba4e574a77f35468afe0e2d761 Mon Sep 17 00:00:00 2001 From: Harsh Rawat Date: Mon, 6 Apr 2026 16:47:51 +0530 Subject: [PATCH 2/5] [shimV2] refactor vm controller + add functionalities In this commit, we are refactoring the vm controller to bring it to the same standard as rest of the controllers. Additionally, we are adding- - Update functionality - RuntimeID API - APIs to obtain device controllers Signed-off-by: Harsh Rawat --- internal/controller/vm/doc.go | 8 +- internal/controller/vm/interface.go | 88 ---------------- internal/controller/vm/state.go | 2 +- internal/controller/vm/types.go | 52 +++++++++ internal/controller/vm/vm.go | 129 ++++++++++++++++++----- internal/controller/vm/vm_devices.go | 82 ++++++++++++++ internal/controller/vm/vm_lcow.go | 74 ++++++++++++- internal/controller/vm/vm_unsupported.go | 26 +++++ internal/controller/vm/vm_wcow.go | 57 +++++++++- 9 files changed, 390 insertions(+), 128 deletions(-) delete mode 100644 internal/controller/vm/interface.go create mode 100644 internal/controller/vm/types.go create mode 100644 internal/controller/vm/vm_devices.go create mode 100644 internal/controller/vm/vm_unsupported.go diff --git a/internal/controller/vm/doc.go b/internal/controller/vm/doc.go index 304e117157..389b705e04 100644 --- a/internal/controller/vm/doc.go +++ b/internal/controller/vm/doc.go @@ -4,8 +4,8 @@ // // A Utility VM is a lightweight virtual machine used to host Linux (LCOW) or // Windows (WCOW) containers. This package abstracts the VM lifecycle — -// creation, startup, stats collection, and termination — behind the [Controller] -// interface, with [Manager] as the primary implementation. +// creation, startup, stats collection, and termination — with the [Controller] +// as the primary implementation. // // # Lifecycle // @@ -33,7 +33,7 @@ // // State descriptions: // -// - [StateNotCreated]: initial state after [NewController] is called. +// - [StateNotCreated]: initial state after [New] is called. // - [StateCreated]: after [Controller.CreateVM] succeeds; the VM exists but has not started. // - [StateRunning]: after [Controller.StartVM] succeeds; the guest OS is up and the // Guest Compute Service (GCS) connection is established. @@ -51,7 +51,7 @@ // // # Usage // -// ctrl := vm.NewController() +// ctrl := vm.New() // // if err := ctrl.CreateVM(ctx, &vm.CreateOptions{ // ID: "my-uvm", diff --git a/internal/controller/vm/interface.go b/internal/controller/vm/interface.go deleted file mode 100644 index 3629e21e33..0000000000 --- a/internal/controller/vm/interface.go +++ /dev/null @@ -1,88 +0,0 @@ -//go:build windows - -package vm - -import ( - "context" - "time" - - "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/stats" - hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" - "github.com/Microsoft/hcsshim/internal/protocol/guestresource" - "github.com/Microsoft/hcsshim/internal/shimdiag" - "github.com/Microsoft/hcsshim/internal/vm/guestmanager" - - "github.com/Microsoft/go-winio/pkg/guid" -) - -type Controller interface { - // Guest returns the guest manager instance for this VM. - Guest() *guestmanager.Guest - - // State returns the current VM state. - State() State - - // CreateVM creates and initializes a new VM with the specified options. - // This prepares the VM but does not start it. - CreateVM(ctx context.Context, opts *CreateOptions) error - - // StartVM starts the created VM with the specified options. - // This establishes the guest connection, sets up necessary listeners for - // guest-host communication, and transitions the VM to StateRunning. - StartVM(context.Context, *StartOptions) error - - // ExecIntoHost executes a command in the running UVM. - ExecIntoHost(ctx context.Context, request *shimdiag.ExecProcessRequest) (int, error) - - // DumpStacks dumps the GCS stacks associated with the VM. - DumpStacks(ctx context.Context) (string, error) - - // Wait blocks until the VM exits or the context is cancelled. - // It also waits for log output processing to complete. - Wait(ctx context.Context) error - - Stats(ctx context.Context) (*stats.VirtualMachineStatistics, error) - - TerminateVM(context.Context) error - - // StartTime returns the timestamp when the VM was started. - // Returns zero value of time.time, if the VM is not in StateRunning or StateTerminated. - StartTime() time.Time - - // ExitStatus returns information about the stopped VM, including when it - // stopped and any exit error. Returns an error if the VM is not in StateTerminated. - ExitStatus() (*ExitStatus, error) -} - -// CreateOptions contains the configuration needed to create a new VM. -type CreateOptions struct { - // ID specifies the unique identifier for the VM. - ID string - - // HCSDocument specifies the HCS schema document used to create the VM. - HCSDocument *hcsschema.ComputeSystem -} - -// StartOptions contains the configuration needed to start a VM and establish -// the Guest Compute Service (GCS) connection. -type StartOptions struct { - // GCSServiceID specifies the GUID for the GCS vsock service. - GCSServiceID guid.GUID - - // ConfigOptions specifies additional configuration options for the guest config. - ConfigOptions []guestmanager.ConfigOption - - // ConfidentialOptions specifies security policy and confidential computing - // options for the VM. This is optional and only used for confidential VMs. - ConfidentialOptions *guestresource.ConfidentialOptions -} - -// ExitStatus contains information about a stopped VM's final state. -type ExitStatus struct { - // StoppedTime is the timestamp when the VM stopped. - StoppedTime time.Time - - // Err is the error that caused the VM to stop, if any. - // This will be nil if the VM exited cleanly. - Err error -} diff --git a/internal/controller/vm/state.go b/internal/controller/vm/state.go index 6e98eb4ae1..f9aedddc47 100644 --- a/internal/controller/vm/state.go +++ b/internal/controller/vm/state.go @@ -29,7 +29,7 @@ type State int32 const ( // StateNotCreated indicates the VM has not been created yet. - // This is the initial state when a Controller is first instantiated via [NewController]. + // This is the initial state when a Controller is first instantiated via [New]. // Valid transitions: StateNotCreated → StateCreated (via [Controller.CreateVM]) StateNotCreated State = iota diff --git a/internal/controller/vm/types.go b/internal/controller/vm/types.go new file mode 100644 index 0000000000..383afffe9c --- /dev/null +++ b/internal/controller/vm/types.go @@ -0,0 +1,52 @@ +//go:build windows + +package vm + +import ( + "time" + + hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" + "github.com/Microsoft/hcsshim/internal/protocol/guestresource" + "github.com/Microsoft/hcsshim/internal/vm/guestmanager" + + "github.com/Microsoft/go-winio/pkg/guid" +) + +// CreateOptions contains the configuration needed to create a new VM. +type CreateOptions struct { + // ID specifies the unique identifier for the VM. + ID string + + // HCSDocument specifies the HCS schema document used to create the VM. + HCSDocument *hcsschema.ComputeSystem + + // NoWritableFileShares disallows writable file shares to the UVM. + NoWritableFileShares bool + + // FullyPhysicallyBacked indicates all memory allocations are backed by physical memory. + FullyPhysicallyBacked bool +} + +// StartOptions contains the configuration needed to start a VM and establish +// the Guest Compute Service (GCS) connection. +type StartOptions struct { + // GCSServiceID specifies the GUID for the GCS vsock service. + GCSServiceID guid.GUID + + // ConfigOptions specifies additional configuration options for the guest config. + ConfigOptions []guestmanager.ConfigOption + + // ConfidentialOptions specifies security policy and confidential computing + // options for the VM. This is optional and only used for confidential VMs. + ConfidentialOptions *guestresource.ConfidentialOptions +} + +// ExitStatus contains information about a stopped VM's final state. +type ExitStatus struct { + // StoppedTime is the timestamp when the VM stopped. + StoppedTime time.Time + + // Err is the error that caused the VM to stop, if any. + // This will be nil if the VM exited cleanly. + Err error +} diff --git a/internal/controller/vm/vm.go b/internal/controller/vm/vm.go index e4c8c42736..fb7abffb3e 100644 --- a/internal/controller/vm/vm.go +++ b/internal/controller/vm/vm.go @@ -12,26 +12,32 @@ import ( "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/stats" "github.com/Microsoft/hcsshim/internal/cmd" + "github.com/Microsoft/hcsshim/internal/controller/device/plan9" + "github.com/Microsoft/hcsshim/internal/controller/device/scsi" + "github.com/Microsoft/hcsshim/internal/controller/device/vpci" hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" "github.com/Microsoft/hcsshim/internal/log" "github.com/Microsoft/hcsshim/internal/logfields" + "github.com/Microsoft/hcsshim/internal/protocol/guestresource" "github.com/Microsoft/hcsshim/internal/shimdiag" "github.com/Microsoft/hcsshim/internal/timeout" "github.com/Microsoft/hcsshim/internal/vm/guestmanager" "github.com/Microsoft/hcsshim/internal/vm/vmmanager" "github.com/Microsoft/hcsshim/internal/vm/vmutils" iwin "github.com/Microsoft/hcsshim/internal/windows" - "github.com/containerd/errdefs" + "github.com/Microsoft/hcsshim/pkg/annotations" + "github.com/Microsoft/hcsshim/pkg/ctrdtaskapi" "github.com/Microsoft/go-winio/pkg/process" + "github.com/containerd/errdefs" "github.com/sirupsen/logrus" "golang.org/x/sync/errgroup" "golang.org/x/sys/windows" ) -// Manager is the VM controller implementation that manages the lifecycle of a Utility VM +// Controller is the VM controller implementation that manages the lifecycle of a Utility VM // and its associated resources. -type Manager struct { +type Controller struct { vmID string uvm *vmmanager.UtilityVM guest *guestmanager.Guest @@ -40,7 +46,7 @@ type Manager struct { // Access must be guarded by mu. vmState State - // mu guards the concurrent access to the Manager's fields and operations. + // mu guards the concurrent access to the Controller's fields and operations. mu sync.RWMutex // logOutputDone is closed when the GCS log output processing goroutine completes. @@ -55,14 +61,23 @@ type Manager struct { // isPhysicallyBacked indicates whether the VM is using physical backing for its memory. isPhysicallyBacked bool -} -// Ensure both the Controller, and it's subset Handle are implemented by Manager. -var _ Controller = (*Manager)(nil) + // noWritableFileShares indicates whether writable file shares are disabled for this VM. + noWritableFileShares bool + + // scsiController manages SCSI devices for this VM. + scsiController *scsi.Controller + + // vpciController manages virtual PCI device assignments for this VM. + vpciController *vpci.Controller -// NewController creates a new Manager instance in the [StateNotCreated] state. -func NewController() *Manager { - return &Manager{ + // plan9Controller manages Plan9 file share mounts for this VM. + plan9Controller *plan9.Controller +} + +// New creates a new Controller instance in the [StateNotCreated] state. +func New() *Controller { + return &Controller{ logOutputDone: make(chan struct{}), vmState: StateNotCreated, } @@ -70,20 +85,32 @@ func NewController() *Manager { // Guest returns the guest manager instance for this VM. // The guest manager provides access to guest-host communication. -func (c *Manager) Guest() *guestmanager.Guest { +func (c *Controller) Guest() *guestmanager.Guest { return c.guest } // State returns the current VM state. -func (c *Manager) State() State { +func (c *Controller) State() State { c.mu.RLock() defer c.mu.RUnlock() return c.vmState } +// RuntimeID returns the UVM runtime identifier when the VM is created or running. +func (c *Controller) RuntimeID() string { + c.mu.RLock() + defer c.mu.RUnlock() + + if c.vmState != StateCreated && c.vmState != StateRunning { + return "" + } + + return c.uvm.RuntimeID().String() +} + // CreateVM creates the VM using the HCS document and initializes device state. -func (c *Manager) CreateVM(ctx context.Context, opts *CreateOptions) error { +func (c *Controller) CreateVM(ctx context.Context, opts *CreateOptions) error { ctx, _ = log.WithContext(ctx, logrus.WithField(logfields.Operation, "CreateVM")) c.mu.Lock() @@ -100,17 +127,25 @@ func (c *Manager) CreateVM(ctx context.Context, opts *CreateOptions) error { return fmt.Errorf("failed to create VM: %w", err) } - // Set the Manager parameters after successful creation. + // Set the Controller parameters after successful creation. c.vmID = opts.ID c.uvm = uvm - // Determine if the VM is physically backed based on the HCS document configuration. - // We need this while extracting memory metrics, as some of them are only relevant for physically backed VMs. - c.isPhysicallyBacked = !opts.HCSDocument.VirtualMachine.ComputeTopology.Memory.AllowOvercommit + // Determine if the VM is physically backed based on the create options. + c.isPhysicallyBacked = opts.FullyPhysicallyBacked + // + c.noWritableFileShares = opts.NoWritableFileShares // Initialize the GuestManager for managing guest interactions. // We will create the guest connection via GuestManager during StartVM. c.guest = guestmanager.New(ctx, uvm) + // Eager initialize the SCSI controller as opposed to all other controllers. + // This is because we always use SCSI for attaching scratch VHDs. + c.scsiController, err = newSCSIController(ctx, opts.HCSDocument, c.uvm, c.guest, c.guest) + if err != nil { + return fmt.Errorf("failed to initialize SCSI controller: %w", err) + } + c.vmState = StateCreated return nil } @@ -119,7 +154,7 @@ func (c *Manager) CreateVM(ctx context.Context, opts *CreateOptions) error { // It starts the underlying HCS VM, establishes the GCS connection, // and transitions the VM to [StateRunning]. // On any failure the VM is transitioned to [StateInvalid]. -func (c *Manager) StartVM(ctx context.Context, opts *StartOptions) (err error) { +func (c *Controller) StartVM(ctx context.Context, opts *StartOptions) (err error) { ctx, _ = log.WithContext(ctx, logrus.WithField(logfields.Operation, "StartVM")) c.mu.Lock() @@ -202,9 +237,49 @@ func (c *Manager) StartVM(ctx context.Context, opts *StartOptions) (err error) { return nil } +// Update is used to update the VM configuration on-the-fly. +// It supports modifying resources like CPU and memory while the VM is running. +// It also supports injecting policy fragments or updating the CPU group id for the VM. +func (c *Controller) Update(ctx context.Context, resources interface{}, annots map[string]string) error { + ctx, _ = log.WithContext(ctx, logrus.WithField(logfields.Operation, "Update")) + + c.mu.Lock() + defer c.mu.Unlock() + + if c.vmState != StateRunning { + return fmt.Errorf("cannot update VM: VM is in state %s", c.vmState) + } + + // If the resource is a policy fragment, inject it directly into the guest and return. + if policyFragment, ok := resources.(*ctrdtaskapi.PolicyFragment); ok { + return c.guest.InjectPolicyFragment(ctx, + guestresource.SecurityPolicyFragment{ + Fragment: policyFragment.Fragment, + }, + ) + } + + // Apply generic VM resource updates (e.g., CPU count, memory). + if err := c.updateVMResources(ctx, resources); err != nil { + return fmt.Errorf("failed to update VM resources: %w", err) + } + + // Update CPU group membership if the corresponding annotation is present. + if cpuGroupID, ok := annots[annotations.CPUGroupID]; ok { + if cpuGroupID == "" { + return errors.New("must specify an ID to use when configuring a VM's cpugroup") + } + if err := c.uvm.SetCPUGroup(ctx, &hcsschema.CpuGroup{Id: cpuGroupID}); err != nil { + return fmt.Errorf("failed to set CPU group: %w", err) + } + } + + return nil +} + // waitForVMExit blocks until the VM exits and then transitions the VM state to [StateTerminated]. // This is called in StartVM in a background goroutine. -func (c *Manager) waitForVMExit(ctx context.Context) { +func (c *Controller) waitForVMExit(ctx context.Context) { // The original context may have timeout or propagate a cancellation // copy the original to prevent it affecting the background wait go routine ctx = context.WithoutCancel(ctx) @@ -216,14 +291,12 @@ func (c *Manager) waitForVMExit(ctx context.Context) { c.mu.Lock() if c.vmState != StateTerminated { c.vmState = StateTerminated - } else { - log.G(ctx).WithField("currentState", c.vmState).Debug("waitForVMExit: state transition to Terminated was a no-op") } c.mu.Unlock() } // ExecIntoHost executes a command in the running UVM. -func (c *Manager) ExecIntoHost(ctx context.Context, request *shimdiag.ExecProcessRequest) (int, error) { +func (c *Controller) ExecIntoHost(ctx context.Context, request *shimdiag.ExecProcessRequest) (int, error) { ctx, _ = log.WithContext(ctx, logrus.WithField(logfields.Operation, "ExecIntoHost")) if request.Terminal && request.Stderr != "" { @@ -256,7 +329,7 @@ func (c *Manager) ExecIntoHost(ctx context.Context, request *shimdiag.ExecProces } // DumpStacks dumps the GCS stacks associated with the VM -func (c *Manager) DumpStacks(ctx context.Context) (string, error) { +func (c *Controller) DumpStacks(ctx context.Context) (string, error) { ctx, _ = log.WithContext(ctx, logrus.WithField(logfields.Operation, "DumpStacks")) // Take read lock at this place. @@ -278,7 +351,7 @@ func (c *Manager) DumpStacks(ctx context.Context) (string, error) { } // Wait blocks until the VM exits and all log output processing has completed. -func (c *Manager) Wait(ctx context.Context) error { +func (c *Controller) Wait(ctx context.Context) error { ctx, _ = log.WithContext(ctx, logrus.WithField(logfields.Operation, "Wait")) // Validate that the VM has been created and can be waited on. @@ -308,7 +381,7 @@ func (c *Manager) Wait(ctx context.Context) error { // Stats returns runtime statistics for the VM including processor runtime and // memory usage. The VM must be in [StateRunning]. -func (c *Manager) Stats(ctx context.Context) (*stats.VirtualMachineStatistics, error) { +func (c *Controller) Stats(ctx context.Context) (*stats.VirtualMachineStatistics, error) { ctx, _ = log.WithContext(ctx, logrus.WithField(logfields.Operation, "Stats")) // Take read lock at this place. @@ -376,7 +449,7 @@ func (c *Manager) Stats(ctx context.Context) (*stats.VirtualMachineStatistics, e // // The context is used for all operations, including waits, so timeouts/cancellations may prevent // proper UVM cleanup. -func (c *Manager) TerminateVM(ctx context.Context) (err error) { +func (c *Controller) TerminateVM(ctx context.Context) (err error) { ctx, _ = log.WithContext(ctx, logrus.WithField(logfields.Operation, "TerminateVM")) c.mu.Lock() @@ -413,7 +486,7 @@ func (c *Manager) TerminateVM(ctx context.Context) (err error) { // StartTime returns the timestamp when the VM was started. // Returns zero value of time.Time if the VM has not yet reached // [StateRunning] or [StateTerminated]. -func (c *Manager) StartTime() (startTime time.Time) { +func (c *Controller) StartTime() (startTime time.Time) { c.mu.RLock() defer c.mu.RUnlock() @@ -427,7 +500,7 @@ func (c *Manager) StartTime() (startTime time.Time) { // ExitStatus returns the final status of the VM once it has reached // [StateTerminated], including the time it stopped and any exit error. // Returns an error if the VM has not yet stopped. -func (c *Manager) ExitStatus() (*ExitStatus, error) { +func (c *Controller) ExitStatus() (*ExitStatus, error) { c.mu.RLock() defer c.mu.RUnlock() diff --git a/internal/controller/vm/vm_devices.go b/internal/controller/vm/vm_devices.go new file mode 100644 index 0000000000..873a5aa161 --- /dev/null +++ b/internal/controller/vm/vm_devices.go @@ -0,0 +1,82 @@ +//go:build windows + +package vm + +import ( + "context" + "fmt" + "strconv" + + "github.com/Microsoft/hcsshim/internal/controller/device/scsi" + "github.com/Microsoft/hcsshim/internal/controller/device/vpci" + "github.com/Microsoft/hcsshim/internal/controller/network" + hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" + "github.com/Microsoft/hcsshim/internal/protocol/guestrequest" +) + +// NetworkController returns a new controller for managing network devices on the VM. +// Since we have a namespace per pod, we create a new controller per call. +func (c *Controller) NetworkController() *network.Controller { + return network.New(c.uvm, c.guest, c.guest) +} + +// SCSIController returns the singleton SCSI device controller for this VM. +func (c *Controller) SCSIController() *scsi.Controller { + return c.scsiController +} + +// VPCIController returns the singleton vPCI device controller for this VM. +func (c *Controller) VPCIController() *vpci.Controller { + c.mu.Lock() + defer c.mu.Unlock() + + if c.vpciController == nil { + c.vpciController = vpci.New(c.uvm, c.guest) + } + + return c.vpciController +} + +// newSCSIController creates a [scsi.Controller] from the HCS document, +// pre-reserving every rootfs slot that already has an attachment in the document. +func newSCSIController( + ctx context.Context, + doc *hcsschema.ComputeSystem, + vm scsi.VMSCSIOps, + linuxGuest scsi.LinuxGuestSCSIOps, + windowsGuest scsi.WindowsGuestSCSIOps, +) (*scsi.Controller, error) { + // If there are no SCSI device controllers in the document, error out. + if doc.VirtualMachine == nil || + doc.VirtualMachine.Devices == nil || + len(doc.VirtualMachine.Devices.Scsi) == 0 { + return nil, fmt.Errorf("expected the VM to have at least one SCSI controller") + } + + // Create a VM SCSI controller. + scsiMap := doc.VirtualMachine.Devices.Scsi + ctrl := scsi.New(len(scsiMap), vm, linuxGuest, windowsGuest) + + // Iterate over the well-known controller GUIDs so the slice index gives us + // the correct controller number directly. + for ctrlIdx, guid := range guestrequest.ScsiControllerGuids { + c, ok := scsiMap[guid] + if !ok { + continue + } + + // Found the controller GUID in the document. + for lunStr := range c.Attachments { + lun, err := strconv.ParseUint(lunStr, 10, 32) + if err != nil { + continue + } + + if err := ctrl.ReserveForRootfs(ctx, uint(ctrlIdx), uint(lun)); err != nil { + return nil, fmt.Errorf("reserve SCSI slot (controller=%d, lun=%d): %w", ctrlIdx, lun, err) + } + } + } + + return ctrl, nil +} diff --git a/internal/controller/vm/vm_lcow.go b/internal/controller/vm/vm_lcow.go index e8c5b51194..52769cb6fb 100644 --- a/internal/controller/vm/vm_lcow.go +++ b/internal/controller/vm/vm_lcow.go @@ -1,4 +1,4 @@ -//go:build windows && !wcow +//go:build windows && lcow package vm @@ -8,19 +8,38 @@ import ( "fmt" "io" + "github.com/Microsoft/hcsshim/internal/controller/device/plan9" + hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" + "github.com/Microsoft/hcsshim/internal/memory" "github.com/Microsoft/hcsshim/internal/vm/vmmanager" "github.com/Microsoft/hcsshim/internal/vm/vmutils" + "github.com/Microsoft/hcsshim/osversion" "github.com/Microsoft/go-winio" + "github.com/containerd/errdefs" + "github.com/opencontainers/runtime-spec/specs-go" "golang.org/x/sync/errgroup" ) +// Plan9Controller returns the singleton controller which can be used +// to manage the Plan9 shares on the Linux UVM. +func (c *Controller) Plan9Controller() *plan9.Controller { + c.mu.Lock() + defer c.mu.Unlock() + + if c.plan9Controller == nil { + c.plan9Controller = plan9.New(c.uvm, c.guest, c.noWritableFileShares) + } + + return c.plan9Controller +} + // setupEntropyListener sets up entropy for LCOW UVMs. // // Linux VMs require entropy to initialize their random number generators during boot. // This method listens on a predefined vsock port and provides cryptographically secure // random data to the Linux init process when it connects. -func (c *Manager) setupEntropyListener(ctx context.Context, group *errgroup.Group) { +func (c *Controller) setupEntropyListener(ctx context.Context, group *errgroup.Group) { group.Go(func() error { // The Linux guest will connect to this port during init to receive entropy. entropyConn, err := winio.ListenHvsock(&winio.HvsockAddr{ @@ -58,7 +77,7 @@ func (c *Manager) setupEntropyListener(ctx context.Context, group *errgroup.Grou // This method establishes a vsock connection to receive log output from GCS // running inside the Linux VM. The logs are parsed and // forwarded to the host's logging system for monitoring and debugging. -func (c *Manager) setupLoggingListener(ctx context.Context, group *errgroup.Group) { +func (c *Controller) setupLoggingListener(ctx context.Context, group *errgroup.Group) { group.Go(func() error { // The GCS will connect to this port to stream log output. logConn, err := winio.ListenHvsock(&winio.HvsockAddr{ @@ -93,6 +112,53 @@ func (c *Manager) setupLoggingListener(ctx context.Context, group *errgroup.Grou // finalizeGCSConnection finalizes the GCS connection for LCOW VMs. // For LCOW, no additional finalization is needed. -func (c *Manager) finalizeGCSConnection(_ context.Context) error { +func (c *Controller) finalizeGCSConnection(_ context.Context) error { + return nil +} + +// updateVMResources applies Linux VM memory and CPU limits from OCI resources. +func (c *Controller) updateVMResources(ctx context.Context, data interface{}) error { + resources, ok := data.(*specs.LinuxResources) + if !ok { + return fmt.Errorf("invalid resource type %T, expected *specs.LinuxResources", data) + } + + if resources.Memory != nil { + if resources.Memory.Limit == nil { + return fmt.Errorf("invalid linux memory limit") + } + + sizeInBytes := uint64(*resources.Memory.Limit) + // Make a call to the VM's orchestrator to update the VM's size in MB + // Internally, HCS will get the number of pages this corresponds to and attempt to assign + // pages to numa nodes evenly + requestedSizeInMB := sizeInBytes / memory.MiB + actual := vmutils.NormalizeMemorySize(ctx, c.vmID, requestedSizeInMB) + + if err := c.uvm.UpdateMemory(ctx, actual); err != nil { + return fmt.Errorf("update vm memory: %w", err) + } + } + + // Translate OCI CPU knobs to HCS processor limits. + if resources.CPU != nil { + processorLimits := &hcsschema.ProcessorLimits{} + if resources.CPU.Quota != nil { + processorLimits.Limit = uint64(*resources.CPU.Quota) + } + if resources.CPU.Shares != nil { + processorLimits.Weight = uint64(*resources.CPU.Shares) + } + + // Support for updating CPU limits was not added until 20H2 build + if osversion.Get().Build < osversion.V20H2 { + return errdefs.ErrNotImplemented + } + + if err := c.uvm.UpdateCPULimits(ctx, processorLimits); err != nil { + return fmt.Errorf("update vm cpu limits: %w", err) + } + } + return nil } diff --git a/internal/controller/vm/vm_unsupported.go b/internal/controller/vm/vm_unsupported.go new file mode 100644 index 0000000000..957c428f1f --- /dev/null +++ b/internal/controller/vm/vm_unsupported.go @@ -0,0 +1,26 @@ +//go:build windows && !wcow && !lcow + +package vm + +import ( + "context" + "fmt" + + "golang.org/x/sync/errgroup" +) + +// setupEntropyListener is a no-op for unsupported guests. +func (c *Controller) setupEntropyListener(_ context.Context, _ *errgroup.Group) {} + +// setupLoggingListener is a no-op for unsupported guests. +func (c *Controller) setupLoggingListener(_ context.Context, _ *errgroup.Group) {} + +// finalizeGCSConnection is not supported for unsupported guests. +func (c *Controller) finalizeGCSConnection(_ context.Context) error { + return fmt.Errorf("unsupported guest") +} + +// updateVMResources is not supported for unsupported guests. +func (c *Controller) updateVMResources(_ context.Context, _ interface{}) error { + return fmt.Errorf("unsupported guest") +} diff --git a/internal/controller/vm/vm_wcow.go b/internal/controller/vm/vm_wcow.go index de6053be8e..50061b3b58 100644 --- a/internal/controller/vm/vm_wcow.go +++ b/internal/controller/vm/vm_wcow.go @@ -10,9 +10,13 @@ import ( "github.com/Microsoft/go-winio" "github.com/Microsoft/hcsshim/internal/gcs/prot" hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" + "github.com/Microsoft/hcsshim/internal/memory" "github.com/Microsoft/hcsshim/internal/vm/vmmanager" "github.com/Microsoft/hcsshim/internal/vm/vmutils" + "github.com/Microsoft/hcsshim/osversion" + "github.com/containerd/errdefs" + "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" "golang.org/x/net/netutil" "golang.org/x/sync/errgroup" @@ -25,7 +29,7 @@ import ( // This is a no-op implementation to satisfy the platform-specific interface. // // For comparison, LCOW VMs require entropy to be provided during boot. -func (c *Manager) setupEntropyListener(_ context.Context, _ *errgroup.Group) {} +func (c *Controller) setupEntropyListener(_ context.Context, _ *errgroup.Group) {} // setupLoggingListener sets up logging for WCOW UVMs. // @@ -37,7 +41,7 @@ func (c *Manager) setupEntropyListener(_ context.Context, _ *errgroup.Group) {} // The listener is configured to accept only one concurrent connection at a time // to prevent resource exhaustion, but will accept new connections if the current one is closed. // This supports scenarios where the logging service inside the VM needs to restart. -func (c *Manager) setupLoggingListener(ctx context.Context, _ *errgroup.Group) { +func (c *Controller) setupLoggingListener(ctx context.Context, _ *errgroup.Group) { // For Windows, the listener can receive a connection later (after VM starts), // so we start the output handler in a goroutine with a non-timeout context. // This allows the output handler to run independently of the VM creation lifecycle. @@ -96,7 +100,7 @@ func (c *Manager) setupLoggingListener(ctx context.Context, _ *errgroup.Group) { // finalizeGCSConnection finalizes the GCS connection for WCOW UVMs. // This is called after CreateConnection succeeds and before the VM is considered fully started. -func (c *Manager) finalizeGCSConnection(ctx context.Context) error { +func (c *Controller) finalizeGCSConnection(ctx context.Context) error { // Prepare the HvSocket address configuration for the external GCS connection. // The LocalAddress is the VM's runtime ID, and the ParentAddress is the // predefined host ID for Windows GCS communication. @@ -114,3 +118,50 @@ func (c *Manager) finalizeGCSConnection(ctx context.Context) error { return nil } + +// updateVMResources applies Windows VM memory and CPU limits from OCI resources. +func (c *Controller) updateVMResources(ctx context.Context, data interface{}) error { + resources, ok := data.(*specs.WindowsResources) + if !ok { + return fmt.Errorf("invalid resource type %T, expected *specs.WindowsResources", data) + } + + if resources.Memory != nil { + if resources.Memory.Limit == nil { + return fmt.Errorf("invalid windows memory limit: nil") + } + + sizeInBytes := *resources.Memory.Limit + // Make a call to the VM's orchestrator to update the VM's size in MB + // Internally, HCS will get the number of pages this corresponds to and attempt to assign + // pages to numa nodes evenly + requestedSizeInMB := sizeInBytes / memory.MiB + actual := vmutils.NormalizeMemorySize(ctx, c.vmID, requestedSizeInMB) + + if err := c.uvm.UpdateMemory(ctx, actual); err != nil { + return fmt.Errorf("update vm memory: %w", err) + } + } + + // Translate OCI CPU knobs to HCS processor limits. + if resources.CPU != nil { + processorLimits := &hcsschema.ProcessorLimits{} + if resources.CPU.Maximum != nil { + processorLimits.Limit = uint64(*resources.CPU.Maximum) + } + if resources.CPU.Shares != nil { + processorLimits.Weight = uint64(*resources.CPU.Shares) + } + + // Support for updating CPU limits was not added until 20H2 build + if osversion.Get().Build < osversion.V20H2 { + return errdefs.ErrNotImplemented + } + + if err := c.uvm.UpdateCPULimits(ctx, processorLimits); err != nil { + return fmt.Errorf("update vm cpu limits: %w", err) + } + } + + return nil +} From c8749869064bce37925099e08ab3e26b240b272e Mon Sep 17 00:00:00 2001 From: Harsh Rawat Date: Wed, 8 Apr 2026 07:38:08 +0530 Subject: [PATCH 3/5] review 1 Signed-off-by: Harsh Rawat --- internal/controller/vm/vm.go | 7 +++---- internal/controller/vm/vm_devices.go | 5 ++--- internal/controller/vm/vm_lcow.go | 7 +++++++ internal/controller/vm/vm_unsupported.go | 4 ++++ internal/controller/vm/vm_wcow.go | 4 ++++ 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/internal/controller/vm/vm.go b/internal/controller/vm/vm.go index fb7abffb3e..1884dee633 100644 --- a/internal/controller/vm/vm.go +++ b/internal/controller/vm/vm.go @@ -12,7 +12,6 @@ import ( "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/stats" "github.com/Microsoft/hcsshim/internal/cmd" - "github.com/Microsoft/hcsshim/internal/controller/device/plan9" "github.com/Microsoft/hcsshim/internal/controller/device/scsi" "github.com/Microsoft/hcsshim/internal/controller/device/vpci" hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" @@ -71,8 +70,8 @@ type Controller struct { // vpciController manages virtual PCI device assignments for this VM. vpciController *vpci.Controller - // plan9Controller manages Plan9 file share mounts for this VM. - plan9Controller *plan9.Controller + // platformControllers embeds platform-specific sub-controllers (e.g., Plan9 for LCOW). + platformControllers } // New creates a new Controller instance in the [StateNotCreated] state. @@ -141,7 +140,7 @@ func (c *Controller) CreateVM(ctx context.Context, opts *CreateOptions) error { // Eager initialize the SCSI controller as opposed to all other controllers. // This is because we always use SCSI for attaching scratch VHDs. - c.scsiController, err = newSCSIController(ctx, opts.HCSDocument, c.uvm, c.guest, c.guest) + c.scsiController, err = newSCSIController(ctx, opts.HCSDocument, c.uvm, c.guest) if err != nil { return fmt.Errorf("failed to initialize SCSI controller: %w", err) } diff --git a/internal/controller/vm/vm_devices.go b/internal/controller/vm/vm_devices.go index 873a5aa161..a39e8af560 100644 --- a/internal/controller/vm/vm_devices.go +++ b/internal/controller/vm/vm_devices.go @@ -43,8 +43,7 @@ func newSCSIController( ctx context.Context, doc *hcsschema.ComputeSystem, vm scsi.VMSCSIOps, - linuxGuest scsi.LinuxGuestSCSIOps, - windowsGuest scsi.WindowsGuestSCSIOps, + guest scsi.GuestSCSIOps, ) (*scsi.Controller, error) { // If there are no SCSI device controllers in the document, error out. if doc.VirtualMachine == nil || @@ -55,7 +54,7 @@ func newSCSIController( // Create a VM SCSI controller. scsiMap := doc.VirtualMachine.Devices.Scsi - ctrl := scsi.New(len(scsiMap), vm, linuxGuest, windowsGuest) + ctrl := scsi.New(len(scsiMap), vm, guest) // Iterate over the well-known controller GUIDs so the slice index gives us // the correct controller number directly. diff --git a/internal/controller/vm/vm_lcow.go b/internal/controller/vm/vm_lcow.go index 52769cb6fb..5c2448c5e8 100644 --- a/internal/controller/vm/vm_lcow.go +++ b/internal/controller/vm/vm_lcow.go @@ -21,6 +21,13 @@ import ( "golang.org/x/sync/errgroup" ) +// platformControllers holds platform-specific sub-controllers embedded in [Controller]. +// For LCOW, this includes the Plan9 file share controller. +type platformControllers struct { + // plan9Controller manages Plan9 file share mounts for this VM. + plan9Controller *plan9.Controller +} + // Plan9Controller returns the singleton controller which can be used // to manage the Plan9 shares on the Linux UVM. func (c *Controller) Plan9Controller() *plan9.Controller { diff --git a/internal/controller/vm/vm_unsupported.go b/internal/controller/vm/vm_unsupported.go index 957c428f1f..d14b3717e2 100644 --- a/internal/controller/vm/vm_unsupported.go +++ b/internal/controller/vm/vm_unsupported.go @@ -9,6 +9,10 @@ import ( "golang.org/x/sync/errgroup" ) +// platformControllers holds platform-specific sub-controllers embedded in [Controller]. +// For unsupported guests, no additional controllers are needed. +type platformControllers struct{} + // setupEntropyListener is a no-op for unsupported guests. func (c *Controller) setupEntropyListener(_ context.Context, _ *errgroup.Group) {} diff --git a/internal/controller/vm/vm_wcow.go b/internal/controller/vm/vm_wcow.go index 50061b3b58..5d7044d5ae 100644 --- a/internal/controller/vm/vm_wcow.go +++ b/internal/controller/vm/vm_wcow.go @@ -22,6 +22,10 @@ import ( "golang.org/x/sync/errgroup" ) +// platformControllers holds platform-specific sub-controllers embedded in [Controller]. +// For WCOW, no additional controllers are needed as of now (VSMB will be added later). +type platformControllers struct{} + // setupEntropyListener sets up entropy for WCOW (Windows Containers on Windows) VMs. // // For WCOW, entropy setup is not required. Windows VMs have their own internal From f660bd8a2eb9e6f8e22298a6d35797aaa112e476 Mon Sep 17 00:00:00 2001 From: Harsh Rawat Date: Wed, 15 Apr 2026 12:25:31 +0530 Subject: [PATCH 4/5] review 2 Signed-off-by: Harsh Rawat --- internal/controller/vm/doc.go | 2 +- internal/controller/vm/state.go | 2 +- internal/controller/vm/types.go | 2 +- internal/controller/vm/vm.go | 89 +++++++++++++++++------- internal/controller/vm/vm_devices.go | 2 +- internal/controller/vm/vm_lcow.go | 52 -------------- internal/controller/vm/vm_unsupported.go | 30 -------- internal/controller/vm/vm_wcow.go | 51 -------------- 8 files changed, 66 insertions(+), 164 deletions(-) delete mode 100644 internal/controller/vm/vm_unsupported.go diff --git a/internal/controller/vm/doc.go b/internal/controller/vm/doc.go index 389b705e04..b740cd7155 100644 --- a/internal/controller/vm/doc.go +++ b/internal/controller/vm/doc.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && (lcow || wcow) // Package vm provides a controller for managing the lifecycle of a Utility VM (UVM). // diff --git a/internal/controller/vm/state.go b/internal/controller/vm/state.go index f9aedddc47..5ea9360a3f 100644 --- a/internal/controller/vm/state.go +++ b/internal/controller/vm/state.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && (lcow || wcow) package vm diff --git a/internal/controller/vm/types.go b/internal/controller/vm/types.go index 383afffe9c..dbde987eae 100644 --- a/internal/controller/vm/types.go +++ b/internal/controller/vm/types.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && (lcow || wcow) package vm diff --git a/internal/controller/vm/vm.go b/internal/controller/vm/vm.go index 1884dee633..61ad4f72ce 100644 --- a/internal/controller/vm/vm.go +++ b/internal/controller/vm/vm.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && (lcow || wcow) package vm @@ -24,8 +24,6 @@ import ( "github.com/Microsoft/hcsshim/internal/vm/vmmanager" "github.com/Microsoft/hcsshim/internal/vm/vmutils" iwin "github.com/Microsoft/hcsshim/internal/windows" - "github.com/Microsoft/hcsshim/pkg/annotations" - "github.com/Microsoft/hcsshim/pkg/ctrdtaskapi" "github.com/Microsoft/go-winio/pkg/process" "github.com/containerd/errdefs" @@ -236,41 +234,78 @@ func (c *Controller) StartVM(ctx context.Context, opts *StartOptions) (err error return nil } -// Update is used to update the VM configuration on-the-fly. -// It supports modifying resources like CPU and memory while the VM is running. -// It also supports injecting policy fragments or updating the CPU group id for the VM. -func (c *Controller) Update(ctx context.Context, resources interface{}, annots map[string]string) error { - ctx, _ = log.WithContext(ctx, logrus.WithField(logfields.Operation, "Update")) +// UpdatePolicyFragment injects a security policy fragment into the running VM's guest. +func (c *Controller) UpdatePolicyFragment(ctx context.Context, fragment guestresource.SecurityPolicyFragment) error { + ctx, _ = log.WithContext(ctx, logrus.WithField(logfields.Operation, "UpdatePolicyFragment")) c.mu.Lock() defer c.mu.Unlock() if c.vmState != StateRunning { - return fmt.Errorf("cannot update VM: VM is in state %s", c.vmState) + return fmt.Errorf("cannot update policy fragment: VM is in state %s", c.vmState) } - // If the resource is a policy fragment, inject it directly into the guest and return. - if policyFragment, ok := resources.(*ctrdtaskapi.PolicyFragment); ok { - return c.guest.InjectPolicyFragment(ctx, - guestresource.SecurityPolicyFragment{ - Fragment: policyFragment.Fragment, - }, - ) + return c.guest.InjectPolicyFragment(ctx, fragment) +} + +// UpdateCPUGroup assigns the VM to the specified CPU group. +func (c *Controller) UpdateCPUGroup(ctx context.Context, cpuGroupID string) error { + ctx, _ = log.WithContext(ctx, logrus.WithField(logfields.Operation, "UpdateCPUGroup")) + + c.mu.Lock() + defer c.mu.Unlock() + + if c.vmState != StateRunning { + return fmt.Errorf("cannot update cpu group: VM is in state %s", c.vmState) } - // Apply generic VM resource updates (e.g., CPU count, memory). - if err := c.updateVMResources(ctx, resources); err != nil { - return fmt.Errorf("failed to update VM resources: %w", err) + if cpuGroupID == "" { + return errors.New("must specify an ID to use when configuring a VM's cpu group") } - // Update CPU group membership if the corresponding annotation is present. - if cpuGroupID, ok := annots[annotations.CPUGroupID]; ok { - if cpuGroupID == "" { - return errors.New("must specify an ID to use when configuring a VM's cpugroup") - } - if err := c.uvm.SetCPUGroup(ctx, &hcsschema.CpuGroup{Id: cpuGroupID}); err != nil { - return fmt.Errorf("failed to set CPU group: %w", err) - } + if err := c.uvm.SetCPUGroup(ctx, &hcsschema.CpuGroup{Id: cpuGroupID}); err != nil { + return fmt.Errorf("failed to set CPU group: %w", err) + } + + return nil +} + +// UpdateCPU updates the CPU limits for the running VM. +func (c *Controller) UpdateCPU(ctx context.Context, limits *hcsschema.ProcessorLimits) error { + ctx, _ = log.WithContext(ctx, logrus.WithField(logfields.Operation, "UpdateCPU")) + + c.mu.Lock() + defer c.mu.Unlock() + + if c.vmState != StateRunning { + return fmt.Errorf("cannot update cpu limits: VM is in state %s", c.vmState) + } + + if err := c.uvm.UpdateCPULimits(ctx, limits); err != nil { + return fmt.Errorf("failed to update vm cpu limits: %w", err) + } + + return nil +} + +// UpdateMemory updates the memory size for the running VM. +// The requestedSizeInMB is normalized before being applied. +func (c *Controller) UpdateMemory(ctx context.Context, requestedSizeInMB uint64) error { + ctx, _ = log.WithContext(ctx, logrus.WithField(logfields.Operation, "UpdateMemory")) + + c.mu.Lock() + defer c.mu.Unlock() + + if c.vmState != StateRunning { + return fmt.Errorf("cannot update memory: VM is in state %s", c.vmState) + } + + // Normalize the requested memory size and apply it. + // Internally, HCS will get the number of pages this corresponds to + // and attempt to assign pages to numa nodes evenly. + actual := vmutils.NormalizeMemorySize(ctx, c.vmID, requestedSizeInMB) + if err := c.uvm.UpdateMemory(ctx, actual); err != nil { + return fmt.Errorf("failed to update vm memory: %w", err) } return nil diff --git a/internal/controller/vm/vm_devices.go b/internal/controller/vm/vm_devices.go index a39e8af560..ec269e8190 100644 --- a/internal/controller/vm/vm_devices.go +++ b/internal/controller/vm/vm_devices.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && (lcow || wcow) package vm diff --git a/internal/controller/vm/vm_lcow.go b/internal/controller/vm/vm_lcow.go index 5c2448c5e8..70868d6d20 100644 --- a/internal/controller/vm/vm_lcow.go +++ b/internal/controller/vm/vm_lcow.go @@ -9,15 +9,10 @@ import ( "io" "github.com/Microsoft/hcsshim/internal/controller/device/plan9" - hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" - "github.com/Microsoft/hcsshim/internal/memory" "github.com/Microsoft/hcsshim/internal/vm/vmmanager" "github.com/Microsoft/hcsshim/internal/vm/vmutils" - "github.com/Microsoft/hcsshim/osversion" "github.com/Microsoft/go-winio" - "github.com/containerd/errdefs" - "github.com/opencontainers/runtime-spec/specs-go" "golang.org/x/sync/errgroup" ) @@ -122,50 +117,3 @@ func (c *Controller) setupLoggingListener(ctx context.Context, group *errgroup.G func (c *Controller) finalizeGCSConnection(_ context.Context) error { return nil } - -// updateVMResources applies Linux VM memory and CPU limits from OCI resources. -func (c *Controller) updateVMResources(ctx context.Context, data interface{}) error { - resources, ok := data.(*specs.LinuxResources) - if !ok { - return fmt.Errorf("invalid resource type %T, expected *specs.LinuxResources", data) - } - - if resources.Memory != nil { - if resources.Memory.Limit == nil { - return fmt.Errorf("invalid linux memory limit") - } - - sizeInBytes := uint64(*resources.Memory.Limit) - // Make a call to the VM's orchestrator to update the VM's size in MB - // Internally, HCS will get the number of pages this corresponds to and attempt to assign - // pages to numa nodes evenly - requestedSizeInMB := sizeInBytes / memory.MiB - actual := vmutils.NormalizeMemorySize(ctx, c.vmID, requestedSizeInMB) - - if err := c.uvm.UpdateMemory(ctx, actual); err != nil { - return fmt.Errorf("update vm memory: %w", err) - } - } - - // Translate OCI CPU knobs to HCS processor limits. - if resources.CPU != nil { - processorLimits := &hcsschema.ProcessorLimits{} - if resources.CPU.Quota != nil { - processorLimits.Limit = uint64(*resources.CPU.Quota) - } - if resources.CPU.Shares != nil { - processorLimits.Weight = uint64(*resources.CPU.Shares) - } - - // Support for updating CPU limits was not added until 20H2 build - if osversion.Get().Build < osversion.V20H2 { - return errdefs.ErrNotImplemented - } - - if err := c.uvm.UpdateCPULimits(ctx, processorLimits); err != nil { - return fmt.Errorf("update vm cpu limits: %w", err) - } - } - - return nil -} diff --git a/internal/controller/vm/vm_unsupported.go b/internal/controller/vm/vm_unsupported.go deleted file mode 100644 index d14b3717e2..0000000000 --- a/internal/controller/vm/vm_unsupported.go +++ /dev/null @@ -1,30 +0,0 @@ -//go:build windows && !wcow && !lcow - -package vm - -import ( - "context" - "fmt" - - "golang.org/x/sync/errgroup" -) - -// platformControllers holds platform-specific sub-controllers embedded in [Controller]. -// For unsupported guests, no additional controllers are needed. -type platformControllers struct{} - -// setupEntropyListener is a no-op for unsupported guests. -func (c *Controller) setupEntropyListener(_ context.Context, _ *errgroup.Group) {} - -// setupLoggingListener is a no-op for unsupported guests. -func (c *Controller) setupLoggingListener(_ context.Context, _ *errgroup.Group) {} - -// finalizeGCSConnection is not supported for unsupported guests. -func (c *Controller) finalizeGCSConnection(_ context.Context) error { - return fmt.Errorf("unsupported guest") -} - -// updateVMResources is not supported for unsupported guests. -func (c *Controller) updateVMResources(_ context.Context, _ interface{}) error { - return fmt.Errorf("unsupported guest") -} diff --git a/internal/controller/vm/vm_wcow.go b/internal/controller/vm/vm_wcow.go index 5d7044d5ae..2ef3ffec5a 100644 --- a/internal/controller/vm/vm_wcow.go +++ b/internal/controller/vm/vm_wcow.go @@ -10,13 +10,9 @@ import ( "github.com/Microsoft/go-winio" "github.com/Microsoft/hcsshim/internal/gcs/prot" hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" - "github.com/Microsoft/hcsshim/internal/memory" "github.com/Microsoft/hcsshim/internal/vm/vmmanager" "github.com/Microsoft/hcsshim/internal/vm/vmutils" - "github.com/Microsoft/hcsshim/osversion" - "github.com/containerd/errdefs" - "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" "golang.org/x/net/netutil" "golang.org/x/sync/errgroup" @@ -122,50 +118,3 @@ func (c *Controller) finalizeGCSConnection(ctx context.Context) error { return nil } - -// updateVMResources applies Windows VM memory and CPU limits from OCI resources. -func (c *Controller) updateVMResources(ctx context.Context, data interface{}) error { - resources, ok := data.(*specs.WindowsResources) - if !ok { - return fmt.Errorf("invalid resource type %T, expected *specs.WindowsResources", data) - } - - if resources.Memory != nil { - if resources.Memory.Limit == nil { - return fmt.Errorf("invalid windows memory limit: nil") - } - - sizeInBytes := *resources.Memory.Limit - // Make a call to the VM's orchestrator to update the VM's size in MB - // Internally, HCS will get the number of pages this corresponds to and attempt to assign - // pages to numa nodes evenly - requestedSizeInMB := sizeInBytes / memory.MiB - actual := vmutils.NormalizeMemorySize(ctx, c.vmID, requestedSizeInMB) - - if err := c.uvm.UpdateMemory(ctx, actual); err != nil { - return fmt.Errorf("update vm memory: %w", err) - } - } - - // Translate OCI CPU knobs to HCS processor limits. - if resources.CPU != nil { - processorLimits := &hcsschema.ProcessorLimits{} - if resources.CPU.Maximum != nil { - processorLimits.Limit = uint64(*resources.CPU.Maximum) - } - if resources.CPU.Shares != nil { - processorLimits.Weight = uint64(*resources.CPU.Shares) - } - - // Support for updating CPU limits was not added until 20H2 build - if osversion.Get().Build < osversion.V20H2 { - return errdefs.ErrNotImplemented - } - - if err := c.uvm.UpdateCPULimits(ctx, processorLimits); err != nil { - return fmt.Errorf("update vm cpu limits: %w", err) - } - } - - return nil -} From 00c98b19d911d6840740b724ecd1e5937e815068 Mon Sep 17 00:00:00 2001 From: Harsh Rawat Date: Thu, 16 Apr 2026 09:53:22 +0530 Subject: [PATCH 5/5] review 3 Signed-off-by: Harsh Rawat --- cmd/containerd-shim-lcow-v2/main.go | 2 +- cmd/containerd-shim-lcow-v2/manager.go | 2 +- cmd/containerd-shim-lcow-v2/manager_test.go | 2 +- cmd/containerd-shim-lcow-v2/service/plugin/plugin.go | 2 +- cmd/containerd-shim-lcow-v2/service/service.go | 6 +++--- cmd/containerd-shim-lcow-v2/service/service_sandbox.go | 2 +- .../service/service_sandbox_internal.go | 2 +- cmd/containerd-shim-lcow-v2/service/service_shimdiag.go | 2 +- .../service/service_shimdiag_internal.go | 2 +- cmd/containerd-shim-lcow-v2/service/service_task.go | 2 +- .../service/service_task_internal.go | 2 +- internal/controller/vm/vm.go | 2 +- internal/controller/vm/vm_wcow.go | 2 +- internal/vm/guestmanager/device_lcow.go | 2 +- 14 files changed, 16 insertions(+), 16 deletions(-) diff --git a/cmd/containerd-shim-lcow-v2/main.go b/cmd/containerd-shim-lcow-v2/main.go index 9951144a8a..c42c664c99 100644 --- a/cmd/containerd-shim-lcow-v2/main.go +++ b/cmd/containerd-shim-lcow-v2/main.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && lcow // containerd-shim-lcow-v2 is a containerd shim implementation for Linux Containers on Windows (LCOW). package main diff --git a/cmd/containerd-shim-lcow-v2/manager.go b/cmd/containerd-shim-lcow-v2/manager.go index e0a997dcc5..1f5c07c87f 100644 --- a/cmd/containerd-shim-lcow-v2/manager.go +++ b/cmd/containerd-shim-lcow-v2/manager.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && lcow package main diff --git a/cmd/containerd-shim-lcow-v2/manager_test.go b/cmd/containerd-shim-lcow-v2/manager_test.go index fd93692299..c080040233 100644 --- a/cmd/containerd-shim-lcow-v2/manager_test.go +++ b/cmd/containerd-shim-lcow-v2/manager_test.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && lcow package main diff --git a/cmd/containerd-shim-lcow-v2/service/plugin/plugin.go b/cmd/containerd-shim-lcow-v2/service/plugin/plugin.go index dd7c1124ae..ecc6544c0d 100644 --- a/cmd/containerd-shim-lcow-v2/service/plugin/plugin.go +++ b/cmd/containerd-shim-lcow-v2/service/plugin/plugin.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && lcow package plugin diff --git a/cmd/containerd-shim-lcow-v2/service/service.go b/cmd/containerd-shim-lcow-v2/service/service.go index 3c2968c53f..4dd54fe980 100644 --- a/cmd/containerd-shim-lcow-v2/service/service.go +++ b/cmd/containerd-shim-lcow-v2/service/service.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && lcow package service @@ -45,7 +45,7 @@ type Service struct { sandboxOptions *lcow.SandboxOptions // vmController is responsible for managing the lifecycle of the underlying utility VM and its associated resources. - vmController vm.Controller + vmController *vm.Controller // shutdown manages graceful shutdown operations and allows registration of cleanup callbacks. shutdown shutdown.Service @@ -58,7 +58,7 @@ func NewService(ctx context.Context, eventsPublisher shim.Publisher, sd shutdown svc := &Service{ publisher: eventsPublisher, events: make(chan interface{}, 128), // Buffered channel for events - vmController: vm.NewController(), + vmController: vm.New(), shutdown: sd, } diff --git a/cmd/containerd-shim-lcow-v2/service/service_sandbox.go b/cmd/containerd-shim-lcow-v2/service/service_sandbox.go index 3e2a3ea437..9e433cb3c0 100644 --- a/cmd/containerd-shim-lcow-v2/service/service_sandbox.go +++ b/cmd/containerd-shim-lcow-v2/service/service_sandbox.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && lcow package service diff --git a/cmd/containerd-shim-lcow-v2/service/service_sandbox_internal.go b/cmd/containerd-shim-lcow-v2/service/service_sandbox_internal.go index f8cd3dfd97..e265553870 100644 --- a/cmd/containerd-shim-lcow-v2/service/service_sandbox_internal.go +++ b/cmd/containerd-shim-lcow-v2/service/service_sandbox_internal.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && lcow package service diff --git a/cmd/containerd-shim-lcow-v2/service/service_shimdiag.go b/cmd/containerd-shim-lcow-v2/service/service_shimdiag.go index 503982d59e..6bbf4388ac 100644 --- a/cmd/containerd-shim-lcow-v2/service/service_shimdiag.go +++ b/cmd/containerd-shim-lcow-v2/service/service_shimdiag.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && lcow package service diff --git a/cmd/containerd-shim-lcow-v2/service/service_shimdiag_internal.go b/cmd/containerd-shim-lcow-v2/service/service_shimdiag_internal.go index a835ade320..2d49e1a621 100644 --- a/cmd/containerd-shim-lcow-v2/service/service_shimdiag_internal.go +++ b/cmd/containerd-shim-lcow-v2/service/service_shimdiag_internal.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && lcow package service diff --git a/cmd/containerd-shim-lcow-v2/service/service_task.go b/cmd/containerd-shim-lcow-v2/service/service_task.go index f7f7dda5af..bd452772f9 100644 --- a/cmd/containerd-shim-lcow-v2/service/service_task.go +++ b/cmd/containerd-shim-lcow-v2/service/service_task.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && lcow package service diff --git a/cmd/containerd-shim-lcow-v2/service/service_task_internal.go b/cmd/containerd-shim-lcow-v2/service/service_task_internal.go index 254199873b..6ffa2eeda9 100644 --- a/cmd/containerd-shim-lcow-v2/service/service_task_internal.go +++ b/cmd/containerd-shim-lcow-v2/service/service_task_internal.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && lcow package service diff --git a/internal/controller/vm/vm.go b/internal/controller/vm/vm.go index 61ad4f72ce..aa4efb8903 100644 --- a/internal/controller/vm/vm.go +++ b/internal/controller/vm/vm.go @@ -69,7 +69,7 @@ type Controller struct { vpciController *vpci.Controller // platformControllers embeds platform-specific sub-controllers (e.g., Plan9 for LCOW). - platformControllers + platformControllers //nolint:unused,nolintlint // embedded for cross-platform compatibility; empty on WCOW } // New creates a new Controller instance in the [StateNotCreated] state. diff --git a/internal/controller/vm/vm_wcow.go b/internal/controller/vm/vm_wcow.go index 2ef3ffec5a..b156656689 100644 --- a/internal/controller/vm/vm_wcow.go +++ b/internal/controller/vm/vm_wcow.go @@ -20,7 +20,7 @@ import ( // platformControllers holds platform-specific sub-controllers embedded in [Controller]. // For WCOW, no additional controllers are needed as of now (VSMB will be added later). -type platformControllers struct{} +type platformControllers struct{} //nolint:unused // embedded in Controller for cross-platform compatibility with LCOW // setupEntropyListener sets up entropy for WCOW (Windows Containers on Windows) VMs. // diff --git a/internal/vm/guestmanager/device_lcow.go b/internal/vm/guestmanager/device_lcow.go index a5650be72b..61524a0ccc 100644 --- a/internal/vm/guestmanager/device_lcow.go +++ b/internal/vm/guestmanager/device_lcow.go @@ -1,4 +1,4 @@ -//go:build windows && lcow +//go:build windows package guestmanager