1- //go:build windows
1+ //go:build windows && (lcow || wcow)
22
33package vm
44
@@ -24,8 +24,6 @@ import (
2424 "github.com/Microsoft/hcsshim/internal/vm/vmmanager"
2525 "github.com/Microsoft/hcsshim/internal/vm/vmutils"
2626 iwin "github.com/Microsoft/hcsshim/internal/windows"
27- "github.com/Microsoft/hcsshim/pkg/annotations"
28- "github.com/Microsoft/hcsshim/pkg/ctrdtaskapi"
2927
3028 "github.com/Microsoft/go-winio/pkg/process"
3129 "github.com/containerd/errdefs"
@@ -236,41 +234,78 @@ func (c *Controller) StartVM(ctx context.Context, opts *StartOptions) (err error
236234 return nil
237235}
238236
239- // Update is used to update the VM configuration on-the-fly.
240- // It supports modifying resources like CPU and memory while the VM is running.
241- // It also supports injecting policy fragments or updating the CPU group id for the VM.
242- func (c * Controller ) Update (ctx context.Context , resources interface {}, annots map [string ]string ) error {
243- ctx , _ = log .WithContext (ctx , logrus .WithField (logfields .Operation , "Update" ))
237+ // UpdatePolicyFragment injects a security policy fragment into the running VM's guest.
238+ func (c * Controller ) UpdatePolicyFragment (ctx context.Context , fragment guestresource.SecurityPolicyFragment ) error {
239+ ctx , _ = log .WithContext (ctx , logrus .WithField (logfields .Operation , "UpdatePolicyFragment" ))
244240
245241 c .mu .Lock ()
246242 defer c .mu .Unlock ()
247243
248244 if c .vmState != StateRunning {
249- return fmt .Errorf ("cannot update VM : VM is in state %s" , c .vmState )
245+ return fmt .Errorf ("cannot update policy fragment : VM is in state %s" , c .vmState )
250246 }
251247
252- // If the resource is a policy fragment, inject it directly into the guest and return.
253- if policyFragment , ok := resources .(* ctrdtaskapi.PolicyFragment ); ok {
254- return c .guest .InjectPolicyFragment (ctx ,
255- guestresource.SecurityPolicyFragment {
256- Fragment : policyFragment .Fragment ,
257- },
258- )
248+ return c .guest .InjectPolicyFragment (ctx , fragment )
249+ }
250+
251+ // UpdateCPUGroup assigns the VM to the specified CPU group.
252+ func (c * Controller ) UpdateCPUGroup (ctx context.Context , cpuGroupID string ) error {
253+ ctx , _ = log .WithContext (ctx , logrus .WithField (logfields .Operation , "UpdateCPUGroup" ))
254+
255+ c .mu .Lock ()
256+ defer c .mu .Unlock ()
257+
258+ if c .vmState != StateRunning {
259+ return fmt .Errorf ("cannot update cpu group: VM is in state %s" , c .vmState )
259260 }
260261
261- // Apply generic VM resource updates (e.g., CPU count, memory).
262- if err := c .updateVMResources (ctx , resources ); err != nil {
263- return fmt .Errorf ("failed to update VM resources: %w" , err )
262+ if cpuGroupID == "" {
263+ return errors .New ("must specify an ID to use when configuring a VM's cpu group" )
264264 }
265265
266- // Update CPU group membership if the corresponding annotation is present.
267- if cpuGroupID , ok := annots [annotations .CPUGroupID ]; ok {
268- if cpuGroupID == "" {
269- return errors .New ("must specify an ID to use when configuring a VM's cpugroup" )
270- }
271- if err := c .uvm .SetCPUGroup (ctx , & hcsschema.CpuGroup {Id : cpuGroupID }); err != nil {
272- return fmt .Errorf ("failed to set CPU group: %w" , err )
273- }
266+ if err := c .uvm .SetCPUGroup (ctx , & hcsschema.CpuGroup {Id : cpuGroupID }); err != nil {
267+ return fmt .Errorf ("failed to set CPU group: %w" , err )
268+ }
269+
270+ return nil
271+ }
272+
273+ // UpdateCPU updates the CPU limits for the running VM.
274+ func (c * Controller ) UpdateCPU (ctx context.Context , limits * hcsschema.ProcessorLimits ) error {
275+ ctx , _ = log .WithContext (ctx , logrus .WithField (logfields .Operation , "UpdateCPU" ))
276+
277+ c .mu .Lock ()
278+ defer c .mu .Unlock ()
279+
280+ if c .vmState != StateRunning {
281+ return fmt .Errorf ("cannot update cpu limits: VM is in state %s" , c .vmState )
282+ }
283+
284+ if err := c .uvm .UpdateCPULimits (ctx , limits ); err != nil {
285+ return fmt .Errorf ("failed to update vm cpu limits: %w" , err )
286+ }
287+
288+ return nil
289+ }
290+
291+ // UpdateMemory updates the memory size for the running VM.
292+ // The requestedSizeInMB is normalized before being applied.
293+ func (c * Controller ) UpdateMemory (ctx context.Context , requestedSizeInMB uint64 ) error {
294+ ctx , _ = log .WithContext (ctx , logrus .WithField (logfields .Operation , "UpdateMemory" ))
295+
296+ c .mu .Lock ()
297+ defer c .mu .Unlock ()
298+
299+ if c .vmState != StateRunning {
300+ return fmt .Errorf ("cannot update memory: VM is in state %s" , c .vmState )
301+ }
302+
303+ // Normalize the requested memory size and apply it.
304+ // Internally, HCS will get the number of pages this corresponds to
305+ // and attempt to assign pages to numa nodes evenly.
306+ actual := vmutils .NormalizeMemorySize (ctx , c .vmID , requestedSizeInMB )
307+ if err := c .uvm .UpdateMemory (ctx , actual ); err != nil {
308+ return fmt .Errorf ("failed to update vm memory: %w" , err )
274309 }
275310
276311 return nil
0 commit comments