diff --git a/internal/controller/vm/mocks/mock_lcow_vm.go b/internal/controller/vm/mocks/mock_lcow_vm.go new file mode 100644 index 0000000000..da4391222e --- /dev/null +++ b/internal/controller/vm/mocks/mock_lcow_vm.go @@ -0,0 +1,591 @@ +//go:build windows && lcow + +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/Microsoft/hcsshim/internal/controller/vm (interfaces: vmLifetime,guestManager) +// +// Generated by this command: +// +// mockgen -build_flags=-tags=windows,lcow -build_constraint=windows && lcow -package mocks -destination internal/controller/vm/mocks/mock_lcow_vm.go github.com/Microsoft/hcsshim/internal/controller/vm vmLifetime,guestManager +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + time "time" + + guid "github.com/Microsoft/go-winio/pkg/guid" + cmd "github.com/Microsoft/hcsshim/internal/cmd" + gcs "github.com/Microsoft/hcsshim/internal/gcs" + schema2 "github.com/Microsoft/hcsshim/internal/hcs/schema2" + guestresource "github.com/Microsoft/hcsshim/internal/protocol/guestresource" + guestmanager "github.com/Microsoft/hcsshim/internal/vm/guestmanager" + gomock "go.uber.org/mock/gomock" +) + +// MockvmLifetime is a mock of vmLifetime interface. +type MockvmLifetime struct { + ctrl *gomock.Controller + recorder *MockvmLifetimeMockRecorder + isgomock struct{} +} + +// MockvmLifetimeMockRecorder is the mock recorder for MockvmLifetime. +type MockvmLifetimeMockRecorder struct { + mock *MockvmLifetime +} + +// NewMockvmLifetime creates a new mock instance. +func NewMockvmLifetime(ctrl *gomock.Controller) *MockvmLifetime { + mock := &MockvmLifetime{ctrl: ctrl} + mock.recorder = &MockvmLifetimeMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockvmLifetime) EXPECT() *MockvmLifetimeMockRecorder { + return m.recorder +} + +// AddDevice mocks base method. +func (m *MockvmLifetime) AddDevice(ctx context.Context, vmbusGUID guid.GUID, settings schema2.VirtualPciDevice) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddDevice", ctx, vmbusGUID, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddDevice indicates an expected call of AddDevice. +func (mr *MockvmLifetimeMockRecorder) AddDevice(ctx, vmbusGUID, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddDevice", reflect.TypeOf((*MockvmLifetime)(nil).AddDevice), ctx, vmbusGUID, settings) +} + +// AddNIC mocks base method. +func (m *MockvmLifetime) AddNIC(ctx context.Context, nicID string, settings *schema2.NetworkAdapter) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddNIC", ctx, nicID, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddNIC indicates an expected call of AddNIC. +func (mr *MockvmLifetimeMockRecorder) AddNIC(ctx, nicID, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNIC", reflect.TypeOf((*MockvmLifetime)(nil).AddNIC), ctx, nicID, settings) +} + +// AddPlan9 mocks base method. +func (m *MockvmLifetime) AddPlan9(ctx context.Context, settings schema2.Plan9Share) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddPlan9", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddPlan9 indicates an expected call of AddPlan9. +func (mr *MockvmLifetimeMockRecorder) AddPlan9(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddPlan9", reflect.TypeOf((*MockvmLifetime)(nil).AddPlan9), ctx, settings) +} + +// AddSCSIDisk mocks base method. +func (m *MockvmLifetime) AddSCSIDisk(ctx context.Context, disk schema2.Attachment, controller, lun uint) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddSCSIDisk", ctx, disk, controller, lun) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddSCSIDisk indicates an expected call of AddSCSIDisk. +func (mr *MockvmLifetimeMockRecorder) AddSCSIDisk(ctx, disk, controller, lun any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddSCSIDisk", reflect.TypeOf((*MockvmLifetime)(nil).AddSCSIDisk), ctx, disk, controller, lun) +} + +// Close mocks base method. +func (m *MockvmLifetime) Close(ctx context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close", ctx) + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockvmLifetimeMockRecorder) Close(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockvmLifetime)(nil).Close), ctx) +} + +// ExitError mocks base method. +func (m *MockvmLifetime) ExitError() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExitError") + ret0, _ := ret[0].(error) + return ret0 +} + +// ExitError indicates an expected call of ExitError. +func (mr *MockvmLifetimeMockRecorder) ExitError() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExitError", reflect.TypeOf((*MockvmLifetime)(nil).ExitError)) +} + +// ID mocks base method. +func (m *MockvmLifetime) ID() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ID") + ret0, _ := ret[0].(string) + return ret0 +} + +// ID indicates an expected call of ID. +func (mr *MockvmLifetimeMockRecorder) ID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockvmLifetime)(nil).ID)) +} + +// PropertiesV2 mocks base method. +func (m *MockvmLifetime) PropertiesV2(ctx context.Context, types ...schema2.PropertyType) (*schema2.Properties, error) { + m.ctrl.T.Helper() + varargs := []any{ctx} + for _, a := range types { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "PropertiesV2", varargs...) + ret0, _ := ret[0].(*schema2.Properties) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PropertiesV2 indicates an expected call of PropertiesV2. +func (mr *MockvmLifetimeMockRecorder) PropertiesV2(ctx any, types ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx}, types...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PropertiesV2", reflect.TypeOf((*MockvmLifetime)(nil).PropertiesV2), varargs...) +} + +// RemoveDevice mocks base method. +func (m *MockvmLifetime) RemoveDevice(ctx context.Context, vmbusGUID guid.GUID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveDevice", ctx, vmbusGUID) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveDevice indicates an expected call of RemoveDevice. +func (mr *MockvmLifetimeMockRecorder) RemoveDevice(ctx, vmbusGUID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveDevice", reflect.TypeOf((*MockvmLifetime)(nil).RemoveDevice), ctx, vmbusGUID) +} + +// RemoveNIC mocks base method. +func (m *MockvmLifetime) RemoveNIC(ctx context.Context, nicID string, settings *schema2.NetworkAdapter) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveNIC", ctx, nicID, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveNIC indicates an expected call of RemoveNIC. +func (mr *MockvmLifetimeMockRecorder) RemoveNIC(ctx, nicID, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveNIC", reflect.TypeOf((*MockvmLifetime)(nil).RemoveNIC), ctx, nicID, settings) +} + +// RemovePlan9 mocks base method. +func (m *MockvmLifetime) RemovePlan9(ctx context.Context, settings schema2.Plan9Share) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemovePlan9", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemovePlan9 indicates an expected call of RemovePlan9. +func (mr *MockvmLifetimeMockRecorder) RemovePlan9(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemovePlan9", reflect.TypeOf((*MockvmLifetime)(nil).RemovePlan9), ctx, settings) +} + +// RemoveSCSIDisk mocks base method. +func (m *MockvmLifetime) RemoveSCSIDisk(ctx context.Context, controller, lun uint) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveSCSIDisk", ctx, controller, lun) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveSCSIDisk indicates an expected call of RemoveSCSIDisk. +func (mr *MockvmLifetimeMockRecorder) RemoveSCSIDisk(ctx, controller, lun any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveSCSIDisk", reflect.TypeOf((*MockvmLifetime)(nil).RemoveSCSIDisk), ctx, controller, lun) +} + +// RuntimeID mocks base method. +func (m *MockvmLifetime) RuntimeID() guid.GUID { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RuntimeID") + ret0, _ := ret[0].(guid.GUID) + return ret0 +} + +// RuntimeID indicates an expected call of RuntimeID. +func (mr *MockvmLifetimeMockRecorder) RuntimeID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RuntimeID", reflect.TypeOf((*MockvmLifetime)(nil).RuntimeID)) +} + +// SetCPUGroup mocks base method. +func (m *MockvmLifetime) SetCPUGroup(ctx context.Context, settings *schema2.CpuGroup) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetCPUGroup", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetCPUGroup indicates an expected call of SetCPUGroup. +func (mr *MockvmLifetimeMockRecorder) SetCPUGroup(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetCPUGroup", reflect.TypeOf((*MockvmLifetime)(nil).SetCPUGroup), ctx, settings) +} + +// Start mocks base method. +func (m *MockvmLifetime) Start(ctx context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Start", ctx) + ret0, _ := ret[0].(error) + return ret0 +} + +// Start indicates an expected call of Start. +func (mr *MockvmLifetimeMockRecorder) Start(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockvmLifetime)(nil).Start), ctx) +} + +// StartedTime mocks base method. +func (m *MockvmLifetime) StartedTime() time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StartedTime") + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// StartedTime indicates an expected call of StartedTime. +func (mr *MockvmLifetimeMockRecorder) StartedTime() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartedTime", reflect.TypeOf((*MockvmLifetime)(nil).StartedTime)) +} + +// StoppedTime mocks base method. +func (m *MockvmLifetime) StoppedTime() time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StoppedTime") + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// StoppedTime indicates an expected call of StoppedTime. +func (mr *MockvmLifetimeMockRecorder) StoppedTime() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoppedTime", reflect.TypeOf((*MockvmLifetime)(nil).StoppedTime)) +} + +// Terminate mocks base method. +func (m *MockvmLifetime) Terminate(ctx context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Terminate", ctx) + ret0, _ := ret[0].(error) + return ret0 +} + +// Terminate indicates an expected call of Terminate. +func (mr *MockvmLifetimeMockRecorder) Terminate(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Terminate", reflect.TypeOf((*MockvmLifetime)(nil).Terminate), ctx) +} + +// UpdateCPULimits mocks base method. +func (m *MockvmLifetime) UpdateCPULimits(ctx context.Context, settings *schema2.ProcessorLimits) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateCPULimits", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateCPULimits indicates an expected call of UpdateCPULimits. +func (mr *MockvmLifetimeMockRecorder) UpdateCPULimits(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateCPULimits", reflect.TypeOf((*MockvmLifetime)(nil).UpdateCPULimits), ctx, settings) +} + +// UpdateMemory mocks base method. +func (m *MockvmLifetime) UpdateMemory(ctx context.Context, memory uint64) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateMemory", ctx, memory) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateMemory indicates an expected call of UpdateMemory. +func (mr *MockvmLifetimeMockRecorder) UpdateMemory(ctx, memory any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateMemory", reflect.TypeOf((*MockvmLifetime)(nil).UpdateMemory), ctx, memory) +} + +// Wait mocks base method. +func (m *MockvmLifetime) Wait(ctx context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Wait", ctx) + ret0, _ := ret[0].(error) + return ret0 +} + +// Wait indicates an expected call of Wait. +func (mr *MockvmLifetimeMockRecorder) Wait(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Wait", reflect.TypeOf((*MockvmLifetime)(nil).Wait), ctx) +} + +// MockguestManager is a mock of guestManager interface. +type MockguestManager struct { + ctrl *gomock.Controller + recorder *MockguestManagerMockRecorder + isgomock struct{} +} + +// MockguestManagerMockRecorder is the mock recorder for MockguestManager. +type MockguestManagerMockRecorder struct { + mock *MockguestManager +} + +// NewMockguestManager creates a new mock instance. +func NewMockguestManager(ctrl *gomock.Controller) *MockguestManager { + mock := &MockguestManager{ctrl: ctrl} + mock.recorder = &MockguestManagerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockguestManager) EXPECT() *MockguestManagerMockRecorder { + return m.recorder +} + +// AddMappedDirectory mocks base method. +func (m *MockguestManager) AddMappedDirectory(ctx context.Context, settings guestresource.LCOWMappedDirectory) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddMappedDirectory", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddMappedDirectory indicates an expected call of AddMappedDirectory. +func (mr *MockguestManagerMockRecorder) AddMappedDirectory(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddMappedDirectory", reflect.TypeOf((*MockguestManager)(nil).AddMappedDirectory), ctx, settings) +} + +// AddMappedVirtualDisk mocks base method. +func (m *MockguestManager) AddMappedVirtualDisk(ctx context.Context, settings guestresource.LCOWMappedVirtualDisk) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddMappedVirtualDisk", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddMappedVirtualDisk indicates an expected call of AddMappedVirtualDisk. +func (mr *MockguestManagerMockRecorder) AddMappedVirtualDisk(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddMappedVirtualDisk", reflect.TypeOf((*MockguestManager)(nil).AddMappedVirtualDisk), ctx, settings) +} + +// AddNetworkInterface mocks base method. +func (m *MockguestManager) AddNetworkInterface(ctx context.Context, settings *guestresource.LCOWNetworkAdapter) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddNetworkInterface", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddNetworkInterface indicates an expected call of AddNetworkInterface. +func (mr *MockguestManagerMockRecorder) AddNetworkInterface(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNetworkInterface", reflect.TypeOf((*MockguestManager)(nil).AddNetworkInterface), ctx, settings) +} + +// AddSecurityPolicy mocks base method. +func (m *MockguestManager) AddSecurityPolicy(ctx context.Context, opts guestresource.ConfidentialOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddSecurityPolicy", ctx, opts) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddSecurityPolicy indicates an expected call of AddSecurityPolicy. +func (mr *MockguestManagerMockRecorder) AddSecurityPolicy(ctx, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddSecurityPolicy", reflect.TypeOf((*MockguestManager)(nil).AddSecurityPolicy), ctx, opts) +} + +// AddVPCIDevice mocks base method. +func (m *MockguestManager) AddVPCIDevice(ctx context.Context, settings guestresource.LCOWMappedVPCIDevice) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddVPCIDevice", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddVPCIDevice indicates an expected call of AddVPCIDevice. +func (mr *MockguestManagerMockRecorder) AddVPCIDevice(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddVPCIDevice", reflect.TypeOf((*MockguestManager)(nil).AddVPCIDevice), ctx, settings) +} + +// Capabilities mocks base method. +func (m *MockguestManager) Capabilities() gcs.GuestDefinedCapabilities { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Capabilities") + ret0, _ := ret[0].(gcs.GuestDefinedCapabilities) + return ret0 +} + +// Capabilities indicates an expected call of Capabilities. +func (mr *MockguestManagerMockRecorder) Capabilities() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Capabilities", reflect.TypeOf((*MockguestManager)(nil).Capabilities)) +} + +// CloseConnection mocks base method. +func (m *MockguestManager) CloseConnection() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CloseConnection") + ret0, _ := ret[0].(error) + return ret0 +} + +// CloseConnection indicates an expected call of CloseConnection. +func (mr *MockguestManagerMockRecorder) CloseConnection() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseConnection", reflect.TypeOf((*MockguestManager)(nil).CloseConnection)) +} + +// CreateConnection mocks base method. +func (m *MockguestManager) CreateConnection(ctx context.Context, gcsServiceID guid.GUID, opts ...guestmanager.ConfigOption) error { + m.ctrl.T.Helper() + varargs := []any{ctx, gcsServiceID} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CreateConnection", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// CreateConnection indicates an expected call of CreateConnection. +func (mr *MockguestManagerMockRecorder) CreateConnection(ctx, gcsServiceID any, opts ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, gcsServiceID}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateConnection", reflect.TypeOf((*MockguestManager)(nil).CreateConnection), varargs...) +} + +// DumpStacks mocks base method. +func (m *MockguestManager) DumpStacks(ctx context.Context) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DumpStacks", ctx) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DumpStacks indicates an expected call of DumpStacks. +func (mr *MockguestManagerMockRecorder) DumpStacks(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DumpStacks", reflect.TypeOf((*MockguestManager)(nil).DumpStacks), ctx) +} + +// ExecIntoUVM mocks base method. +func (m *MockguestManager) ExecIntoUVM(ctx context.Context, request *cmd.CmdProcessRequest) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExecIntoUVM", ctx, request) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ExecIntoUVM indicates an expected call of ExecIntoUVM. +func (mr *MockguestManagerMockRecorder) ExecIntoUVM(ctx, request any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecIntoUVM", reflect.TypeOf((*MockguestManager)(nil).ExecIntoUVM), ctx, request) +} + +// InjectPolicyFragment mocks base method. +func (m *MockguestManager) InjectPolicyFragment(ctx context.Context, fragment guestresource.SecurityPolicyFragment) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InjectPolicyFragment", ctx, fragment) + ret0, _ := ret[0].(error) + return ret0 +} + +// InjectPolicyFragment indicates an expected call of InjectPolicyFragment. +func (mr *MockguestManagerMockRecorder) InjectPolicyFragment(ctx, fragment any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InjectPolicyFragment", reflect.TypeOf((*MockguestManager)(nil).InjectPolicyFragment), ctx, fragment) +} + +// RemoveMappedDirectory mocks base method. +func (m *MockguestManager) RemoveMappedDirectory(ctx context.Context, settings guestresource.LCOWMappedDirectory) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveMappedDirectory", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveMappedDirectory indicates an expected call of RemoveMappedDirectory. +func (mr *MockguestManagerMockRecorder) RemoveMappedDirectory(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveMappedDirectory", reflect.TypeOf((*MockguestManager)(nil).RemoveMappedDirectory), ctx, settings) +} + +// RemoveMappedVirtualDisk mocks base method. +func (m *MockguestManager) RemoveMappedVirtualDisk(ctx context.Context, settings guestresource.LCOWMappedVirtualDisk) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveMappedVirtualDisk", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveMappedVirtualDisk indicates an expected call of RemoveMappedVirtualDisk. +func (mr *MockguestManagerMockRecorder) RemoveMappedVirtualDisk(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveMappedVirtualDisk", reflect.TypeOf((*MockguestManager)(nil).RemoveMappedVirtualDisk), ctx, settings) +} + +// RemoveNetworkInterface mocks base method. +func (m *MockguestManager) RemoveNetworkInterface(ctx context.Context, settings *guestresource.LCOWNetworkAdapter) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveNetworkInterface", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveNetworkInterface indicates an expected call of RemoveNetworkInterface. +func (mr *MockguestManagerMockRecorder) RemoveNetworkInterface(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveNetworkInterface", reflect.TypeOf((*MockguestManager)(nil).RemoveNetworkInterface), ctx, settings) +} + +// RemoveSCSIDevice mocks base method. +func (m *MockguestManager) RemoveSCSIDevice(ctx context.Context, settings guestresource.SCSIDevice) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveSCSIDevice", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveSCSIDevice indicates an expected call of RemoveSCSIDevice. +func (mr *MockguestManagerMockRecorder) RemoveSCSIDevice(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveSCSIDevice", reflect.TypeOf((*MockguestManager)(nil).RemoveSCSIDevice), ctx, settings) +} diff --git a/internal/controller/vm/mocks/mock_wcow_vm.go b/internal/controller/vm/mocks/mock_wcow_vm.go new file mode 100644 index 0000000000..f8e9775a96 --- /dev/null +++ b/internal/controller/vm/mocks/mock_wcow_vm.go @@ -0,0 +1,565 @@ +//go:build windows && wcow + +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/Microsoft/hcsshim/internal/controller/vm (interfaces: vmLifetime,guestManager) +// +// Generated by this command: +// +// mockgen -build_flags=-tags=windows,wcow -build_constraint=windows && wcow -package mocks -destination internal/controller/vm/mocks/mock_wcow_vm.go github.com/Microsoft/hcsshim/internal/controller/vm vmLifetime,guestManager +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + time "time" + + guid "github.com/Microsoft/go-winio/pkg/guid" + hcn "github.com/Microsoft/hcsshim/hcn" + cmd "github.com/Microsoft/hcsshim/internal/cmd" + gcs "github.com/Microsoft/hcsshim/internal/gcs" + schema2 "github.com/Microsoft/hcsshim/internal/hcs/schema2" + guestrequest "github.com/Microsoft/hcsshim/internal/protocol/guestrequest" + guestresource "github.com/Microsoft/hcsshim/internal/protocol/guestresource" + guestmanager "github.com/Microsoft/hcsshim/internal/vm/guestmanager" + gomock "go.uber.org/mock/gomock" +) + +// MockvmLifetime is a mock of vmLifetime interface. +type MockvmLifetime struct { + ctrl *gomock.Controller + recorder *MockvmLifetimeMockRecorder + isgomock struct{} +} + +// MockvmLifetimeMockRecorder is the mock recorder for MockvmLifetime. +type MockvmLifetimeMockRecorder struct { + mock *MockvmLifetime +} + +// NewMockvmLifetime creates a new mock instance. +func NewMockvmLifetime(ctrl *gomock.Controller) *MockvmLifetime { + mock := &MockvmLifetime{ctrl: ctrl} + mock.recorder = &MockvmLifetimeMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockvmLifetime) EXPECT() *MockvmLifetimeMockRecorder { + return m.recorder +} + +// AddDevice mocks base method. +func (m *MockvmLifetime) AddDevice(ctx context.Context, vmbusGUID guid.GUID, settings schema2.VirtualPciDevice) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddDevice", ctx, vmbusGUID, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddDevice indicates an expected call of AddDevice. +func (mr *MockvmLifetimeMockRecorder) AddDevice(ctx, vmbusGUID, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddDevice", reflect.TypeOf((*MockvmLifetime)(nil).AddDevice), ctx, vmbusGUID, settings) +} + +// AddNIC mocks base method. +func (m *MockvmLifetime) AddNIC(ctx context.Context, nicID string, settings *schema2.NetworkAdapter) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddNIC", ctx, nicID, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddNIC indicates an expected call of AddNIC. +func (mr *MockvmLifetimeMockRecorder) AddNIC(ctx, nicID, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNIC", reflect.TypeOf((*MockvmLifetime)(nil).AddNIC), ctx, nicID, settings) +} + +// AddSCSIDisk mocks base method. +func (m *MockvmLifetime) AddSCSIDisk(ctx context.Context, disk schema2.Attachment, controller, lun uint) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddSCSIDisk", ctx, disk, controller, lun) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddSCSIDisk indicates an expected call of AddSCSIDisk. +func (mr *MockvmLifetimeMockRecorder) AddSCSIDisk(ctx, disk, controller, lun any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddSCSIDisk", reflect.TypeOf((*MockvmLifetime)(nil).AddSCSIDisk), ctx, disk, controller, lun) +} + +// Close mocks base method. +func (m *MockvmLifetime) Close(ctx context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close", ctx) + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockvmLifetimeMockRecorder) Close(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockvmLifetime)(nil).Close), ctx) +} + +// ExitError mocks base method. +func (m *MockvmLifetime) ExitError() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExitError") + ret0, _ := ret[0].(error) + return ret0 +} + +// ExitError indicates an expected call of ExitError. +func (mr *MockvmLifetimeMockRecorder) ExitError() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExitError", reflect.TypeOf((*MockvmLifetime)(nil).ExitError)) +} + +// ID mocks base method. +func (m *MockvmLifetime) ID() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ID") + ret0, _ := ret[0].(string) + return ret0 +} + +// ID indicates an expected call of ID. +func (mr *MockvmLifetimeMockRecorder) ID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockvmLifetime)(nil).ID)) +} + +// PropertiesV2 mocks base method. +func (m *MockvmLifetime) PropertiesV2(ctx context.Context, types ...schema2.PropertyType) (*schema2.Properties, error) { + m.ctrl.T.Helper() + varargs := []any{ctx} + for _, a := range types { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "PropertiesV2", varargs...) + ret0, _ := ret[0].(*schema2.Properties) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PropertiesV2 indicates an expected call of PropertiesV2. +func (mr *MockvmLifetimeMockRecorder) PropertiesV2(ctx any, types ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx}, types...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PropertiesV2", reflect.TypeOf((*MockvmLifetime)(nil).PropertiesV2), varargs...) +} + +// RemoveDevice mocks base method. +func (m *MockvmLifetime) RemoveDevice(ctx context.Context, vmbusGUID guid.GUID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveDevice", ctx, vmbusGUID) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveDevice indicates an expected call of RemoveDevice. +func (mr *MockvmLifetimeMockRecorder) RemoveDevice(ctx, vmbusGUID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveDevice", reflect.TypeOf((*MockvmLifetime)(nil).RemoveDevice), ctx, vmbusGUID) +} + +// RemoveNIC mocks base method. +func (m *MockvmLifetime) RemoveNIC(ctx context.Context, nicID string, settings *schema2.NetworkAdapter) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveNIC", ctx, nicID, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveNIC indicates an expected call of RemoveNIC. +func (mr *MockvmLifetimeMockRecorder) RemoveNIC(ctx, nicID, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveNIC", reflect.TypeOf((*MockvmLifetime)(nil).RemoveNIC), ctx, nicID, settings) +} + +// RemoveSCSIDisk mocks base method. +func (m *MockvmLifetime) RemoveSCSIDisk(ctx context.Context, controller, lun uint) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveSCSIDisk", ctx, controller, lun) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveSCSIDisk indicates an expected call of RemoveSCSIDisk. +func (mr *MockvmLifetimeMockRecorder) RemoveSCSIDisk(ctx, controller, lun any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveSCSIDisk", reflect.TypeOf((*MockvmLifetime)(nil).RemoveSCSIDisk), ctx, controller, lun) +} + +// RuntimeID mocks base method. +func (m *MockvmLifetime) RuntimeID() guid.GUID { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RuntimeID") + ret0, _ := ret[0].(guid.GUID) + return ret0 +} + +// RuntimeID indicates an expected call of RuntimeID. +func (mr *MockvmLifetimeMockRecorder) RuntimeID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RuntimeID", reflect.TypeOf((*MockvmLifetime)(nil).RuntimeID)) +} + +// SetCPUGroup mocks base method. +func (m *MockvmLifetime) SetCPUGroup(ctx context.Context, settings *schema2.CpuGroup) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetCPUGroup", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetCPUGroup indicates an expected call of SetCPUGroup. +func (mr *MockvmLifetimeMockRecorder) SetCPUGroup(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetCPUGroup", reflect.TypeOf((*MockvmLifetime)(nil).SetCPUGroup), ctx, settings) +} + +// Start mocks base method. +func (m *MockvmLifetime) Start(ctx context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Start", ctx) + ret0, _ := ret[0].(error) + return ret0 +} + +// Start indicates an expected call of Start. +func (mr *MockvmLifetimeMockRecorder) Start(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockvmLifetime)(nil).Start), ctx) +} + +// StartedTime mocks base method. +func (m *MockvmLifetime) StartedTime() time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StartedTime") + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// StartedTime indicates an expected call of StartedTime. +func (mr *MockvmLifetimeMockRecorder) StartedTime() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartedTime", reflect.TypeOf((*MockvmLifetime)(nil).StartedTime)) +} + +// StoppedTime mocks base method. +func (m *MockvmLifetime) StoppedTime() time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StoppedTime") + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// StoppedTime indicates an expected call of StoppedTime. +func (mr *MockvmLifetimeMockRecorder) StoppedTime() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoppedTime", reflect.TypeOf((*MockvmLifetime)(nil).StoppedTime)) +} + +// Terminate mocks base method. +func (m *MockvmLifetime) Terminate(ctx context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Terminate", ctx) + ret0, _ := ret[0].(error) + return ret0 +} + +// Terminate indicates an expected call of Terminate. +func (mr *MockvmLifetimeMockRecorder) Terminate(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Terminate", reflect.TypeOf((*MockvmLifetime)(nil).Terminate), ctx) +} + +// UpdateCPULimits mocks base method. +func (m *MockvmLifetime) UpdateCPULimits(ctx context.Context, settings *schema2.ProcessorLimits) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateCPULimits", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateCPULimits indicates an expected call of UpdateCPULimits. +func (mr *MockvmLifetimeMockRecorder) UpdateCPULimits(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateCPULimits", reflect.TypeOf((*MockvmLifetime)(nil).UpdateCPULimits), ctx, settings) +} + +// UpdateMemory mocks base method. +func (m *MockvmLifetime) UpdateMemory(ctx context.Context, memory uint64) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateMemory", ctx, memory) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateMemory indicates an expected call of UpdateMemory. +func (mr *MockvmLifetimeMockRecorder) UpdateMemory(ctx, memory any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateMemory", reflect.TypeOf((*MockvmLifetime)(nil).UpdateMemory), ctx, memory) +} + +// Wait mocks base method. +func (m *MockvmLifetime) Wait(ctx context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Wait", ctx) + ret0, _ := ret[0].(error) + return ret0 +} + +// Wait indicates an expected call of Wait. +func (mr *MockvmLifetimeMockRecorder) Wait(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Wait", reflect.TypeOf((*MockvmLifetime)(nil).Wait), ctx) +} + +// MockguestManager is a mock of guestManager interface. +type MockguestManager struct { + ctrl *gomock.Controller + recorder *MockguestManagerMockRecorder + isgomock struct{} +} + +// MockguestManagerMockRecorder is the mock recorder for MockguestManager. +type MockguestManagerMockRecorder struct { + mock *MockguestManager +} + +// NewMockguestManager creates a new mock instance. +func NewMockguestManager(ctrl *gomock.Controller) *MockguestManager { + mock := &MockguestManager{ctrl: ctrl} + mock.recorder = &MockguestManagerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockguestManager) EXPECT() *MockguestManagerMockRecorder { + return m.recorder +} + +// AddMappedVirtualDisk mocks base method. +func (m *MockguestManager) AddMappedVirtualDisk(ctx context.Context, settings guestresource.WCOWMappedVirtualDisk) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddMappedVirtualDisk", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddMappedVirtualDisk indicates an expected call of AddMappedVirtualDisk. +func (mr *MockguestManagerMockRecorder) AddMappedVirtualDisk(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddMappedVirtualDisk", reflect.TypeOf((*MockguestManager)(nil).AddMappedVirtualDisk), ctx, settings) +} + +// AddMappedVirtualDiskForContainerScratch mocks base method. +func (m *MockguestManager) AddMappedVirtualDiskForContainerScratch(ctx context.Context, settings guestresource.WCOWMappedVirtualDisk) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddMappedVirtualDiskForContainerScratch", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddMappedVirtualDiskForContainerScratch indicates an expected call of AddMappedVirtualDiskForContainerScratch. +func (mr *MockguestManagerMockRecorder) AddMappedVirtualDiskForContainerScratch(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddMappedVirtualDiskForContainerScratch", reflect.TypeOf((*MockguestManager)(nil).AddMappedVirtualDiskForContainerScratch), ctx, settings) +} + +// AddNetworkInterface mocks base method. +func (m *MockguestManager) AddNetworkInterface(ctx context.Context, adapterID string, requestType guestrequest.RequestType, settings *hcn.HostComputeEndpoint) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddNetworkInterface", ctx, adapterID, requestType, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddNetworkInterface indicates an expected call of AddNetworkInterface. +func (mr *MockguestManagerMockRecorder) AddNetworkInterface(ctx, adapterID, requestType, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNetworkInterface", reflect.TypeOf((*MockguestManager)(nil).AddNetworkInterface), ctx, adapterID, requestType, settings) +} + +// AddNetworkNamespace mocks base method. +func (m *MockguestManager) AddNetworkNamespace(ctx context.Context, settings *hcn.HostComputeNamespace) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddNetworkNamespace", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddNetworkNamespace indicates an expected call of AddNetworkNamespace. +func (mr *MockguestManagerMockRecorder) AddNetworkNamespace(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNetworkNamespace", reflect.TypeOf((*MockguestManager)(nil).AddNetworkNamespace), ctx, settings) +} + +// AddSecurityPolicy mocks base method. +func (m *MockguestManager) AddSecurityPolicy(ctx context.Context, opts guestresource.ConfidentialOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddSecurityPolicy", ctx, opts) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddSecurityPolicy indicates an expected call of AddSecurityPolicy. +func (mr *MockguestManagerMockRecorder) AddSecurityPolicy(ctx, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddSecurityPolicy", reflect.TypeOf((*MockguestManager)(nil).AddSecurityPolicy), ctx, opts) +} + +// Capabilities mocks base method. +func (m *MockguestManager) Capabilities() gcs.GuestDefinedCapabilities { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Capabilities") + ret0, _ := ret[0].(gcs.GuestDefinedCapabilities) + return ret0 +} + +// Capabilities indicates an expected call of Capabilities. +func (mr *MockguestManagerMockRecorder) Capabilities() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Capabilities", reflect.TypeOf((*MockguestManager)(nil).Capabilities)) +} + +// CloseConnection mocks base method. +func (m *MockguestManager) CloseConnection() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CloseConnection") + ret0, _ := ret[0].(error) + return ret0 +} + +// CloseConnection indicates an expected call of CloseConnection. +func (mr *MockguestManagerMockRecorder) CloseConnection() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseConnection", reflect.TypeOf((*MockguestManager)(nil).CloseConnection)) +} + +// CreateConnection mocks base method. +func (m *MockguestManager) CreateConnection(ctx context.Context, gcsServiceID guid.GUID, opts ...guestmanager.ConfigOption) error { + m.ctrl.T.Helper() + varargs := []any{ctx, gcsServiceID} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CreateConnection", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// CreateConnection indicates an expected call of CreateConnection. +func (mr *MockguestManagerMockRecorder) CreateConnection(ctx, gcsServiceID any, opts ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, gcsServiceID}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateConnection", reflect.TypeOf((*MockguestManager)(nil).CreateConnection), varargs...) +} + +// DumpStacks mocks base method. +func (m *MockguestManager) DumpStacks(ctx context.Context) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DumpStacks", ctx) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DumpStacks indicates an expected call of DumpStacks. +func (mr *MockguestManagerMockRecorder) DumpStacks(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DumpStacks", reflect.TypeOf((*MockguestManager)(nil).DumpStacks), ctx) +} + +// ExecIntoUVM mocks base method. +func (m *MockguestManager) ExecIntoUVM(ctx context.Context, request *cmd.CmdProcessRequest) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExecIntoUVM", ctx, request) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ExecIntoUVM indicates an expected call of ExecIntoUVM. +func (mr *MockguestManagerMockRecorder) ExecIntoUVM(ctx, request any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecIntoUVM", reflect.TypeOf((*MockguestManager)(nil).ExecIntoUVM), ctx, request) +} + +// InjectPolicyFragment mocks base method. +func (m *MockguestManager) InjectPolicyFragment(ctx context.Context, fragment guestresource.SecurityPolicyFragment) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InjectPolicyFragment", ctx, fragment) + ret0, _ := ret[0].(error) + return ret0 +} + +// InjectPolicyFragment indicates an expected call of InjectPolicyFragment. +func (mr *MockguestManagerMockRecorder) InjectPolicyFragment(ctx, fragment any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InjectPolicyFragment", reflect.TypeOf((*MockguestManager)(nil).InjectPolicyFragment), ctx, fragment) +} + +// RemoveMappedVirtualDisk mocks base method. +func (m *MockguestManager) RemoveMappedVirtualDisk(ctx context.Context, settings guestresource.WCOWMappedVirtualDisk) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveMappedVirtualDisk", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveMappedVirtualDisk indicates an expected call of RemoveMappedVirtualDisk. +func (mr *MockguestManagerMockRecorder) RemoveMappedVirtualDisk(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveMappedVirtualDisk", reflect.TypeOf((*MockguestManager)(nil).RemoveMappedVirtualDisk), ctx, settings) +} + +// RemoveNetworkInterface mocks base method. +func (m *MockguestManager) RemoveNetworkInterface(ctx context.Context, adapterID string, requestType guestrequest.RequestType, settings *hcn.HostComputeEndpoint) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveNetworkInterface", ctx, adapterID, requestType, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveNetworkInterface indicates an expected call of RemoveNetworkInterface. +func (mr *MockguestManagerMockRecorder) RemoveNetworkInterface(ctx, adapterID, requestType, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveNetworkInterface", reflect.TypeOf((*MockguestManager)(nil).RemoveNetworkInterface), ctx, adapterID, requestType, settings) +} + +// RemoveNetworkNamespace mocks base method. +func (m *MockguestManager) RemoveNetworkNamespace(ctx context.Context, settings *hcn.HostComputeNamespace) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveNetworkNamespace", ctx, settings) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveNetworkNamespace indicates an expected call of RemoveNetworkNamespace. +func (mr *MockguestManagerMockRecorder) RemoveNetworkNamespace(ctx, settings any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveNetworkNamespace", reflect.TypeOf((*MockguestManager)(nil).RemoveNetworkNamespace), ctx, settings) +} + +// UpdateHvSocketAddress mocks base method. +func (m *MockguestManager) UpdateHvSocketAddress(ctx context.Context, address *schema2.HvSocketAddress) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateHvSocketAddress", ctx, address) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateHvSocketAddress indicates an expected call of UpdateHvSocketAddress. +func (mr *MockguestManagerMockRecorder) UpdateHvSocketAddress(ctx, address any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateHvSocketAddress", reflect.TypeOf((*MockguestManager)(nil).UpdateHvSocketAddress), ctx, address) +} diff --git a/internal/controller/vm/types.go b/internal/controller/vm/types.go index 9312bedaae..c2aea1d1ac 100644 --- a/internal/controller/vm/types.go +++ b/internal/controller/vm/types.go @@ -12,6 +12,11 @@ import ( "github.com/Microsoft/go-winio/pkg/guid" ) +// vmLifetime and guestManager are defined per-platform in vm_lcow.go and +// vm_wcow.go because LCOW and WCOW expose different host- and guest-side +// method shapes (Plan9 is LCOW-only on the host; vPCI guest, Plan9 guest, +// network namespace, and HvSocket methods diverge across platforms). + // CreateOptions contains the configuration needed to create a new VM. type CreateOptions struct { // ID specifies the unique identifier for the VM. diff --git a/internal/controller/vm/vm.go b/internal/controller/vm/vm.go index b335249d1b..4d42b52931 100644 --- a/internal/controller/vm/vm.go +++ b/internal/controller/vm/vm.go @@ -36,8 +36,8 @@ import ( // and its associated resources. type Controller struct { vmID string - uvm *vmmanager.UtilityVM - guest *guestmanager.Guest + uvm vmLifetime + guest guestManager // vmState tracks the current state of the VM lifecycle. // Access must be guarded by mu. @@ -80,7 +80,8 @@ func New() *Controller { // Guest returns the guest manager instance for this VM. // The guest manager provides access to guest-host communication. func (c *Controller) Guest() *guestmanager.Guest { - return c.guest + g, _ := c.guest.(*guestmanager.Guest) + return g } // State returns the current VM state. diff --git a/internal/controller/vm/vm_lcow.go b/internal/controller/vm/vm_lcow.go index 72b8edbf87..9d62db888c 100644 --- a/internal/controller/vm/vm_lcow.go +++ b/internal/controller/vm/vm_lcow.go @@ -7,19 +7,74 @@ import ( "crypto/rand" "fmt" "io" + "time" "github.com/Microsoft/hcsshim/internal/builder/vm/lcow" + "github.com/Microsoft/hcsshim/internal/cmd" "github.com/Microsoft/hcsshim/internal/controller/device/plan9" "github.com/Microsoft/hcsshim/internal/controller/network" + "github.com/Microsoft/hcsshim/internal/gcs" 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/hcsshim/internal/vm/vmmanager" "github.com/Microsoft/hcsshim/internal/vm/vmutils" "github.com/Microsoft/go-winio" + "github.com/Microsoft/go-winio/pkg/guid" "golang.org/x/sync/errgroup" ) +// vmLifetime is the LCOW-flavoured seam over [*vmmanager.UtilityVM]. +// AddPlan9 / RemovePlan9 are LCOW-only on the host side, hence the per-platform split. +type vmLifetime interface { + ID() string + RuntimeID() guid.GUID + Start(ctx context.Context) error + Wait(ctx context.Context) error + Terminate(ctx context.Context) error + Close(ctx context.Context) error + SetCPUGroup(ctx context.Context, settings *hcsschema.CpuGroup) error + UpdateCPULimits(ctx context.Context, settings *hcsschema.ProcessorLimits) error + UpdateMemory(ctx context.Context, memory uint64) error + PropertiesV2(ctx context.Context, types ...hcsschema.PropertyType) (*hcsschema.Properties, error) + StartedTime() time.Time + StoppedTime() time.Time + ExitError() error + + AddDevice(ctx context.Context, vmbusGUID guid.GUID, settings hcsschema.VirtualPciDevice) error + RemoveDevice(ctx context.Context, vmbusGUID guid.GUID) error + + AddNIC(ctx context.Context, nicID string, settings *hcsschema.NetworkAdapter) error + RemoveNIC(ctx context.Context, nicID string, settings *hcsschema.NetworkAdapter) error + + AddPlan9(ctx context.Context, settings hcsschema.Plan9Share) error + RemovePlan9(ctx context.Context, settings hcsschema.Plan9Share) error + + AddSCSIDisk(ctx context.Context, disk hcsschema.Attachment, controller uint, lun uint) error + RemoveSCSIDisk(ctx context.Context, controller uint, lun uint) error +} + +// guestManager is the LCOW-flavoured seam over [*guestmanager.Guest]. +type guestManager interface { + CreateConnection(ctx context.Context, gcsServiceID guid.GUID, opts ...guestmanager.ConfigOption) error + CloseConnection() error + AddSecurityPolicy(ctx context.Context, opts guestresource.ConfidentialOptions) error + InjectPolicyFragment(ctx context.Context, fragment guestresource.SecurityPolicyFragment) error + Capabilities() gcs.GuestDefinedCapabilities + DumpStacks(ctx context.Context) (string, error) + ExecIntoUVM(ctx context.Context, request *cmd.CmdProcessRequest) (int, error) + + AddVPCIDevice(ctx context.Context, settings guestresource.LCOWMappedVPCIDevice) error + AddNetworkInterface(ctx context.Context, settings *guestresource.LCOWNetworkAdapter) error + RemoveNetworkInterface(ctx context.Context, settings *guestresource.LCOWNetworkAdapter) error + AddMappedDirectory(ctx context.Context, settings guestresource.LCOWMappedDirectory) error + RemoveMappedDirectory(ctx context.Context, settings guestresource.LCOWMappedDirectory) error + AddMappedVirtualDisk(ctx context.Context, settings guestresource.LCOWMappedVirtualDisk) error + RemoveMappedVirtualDisk(ctx context.Context, settings guestresource.LCOWMappedVirtualDisk) error + RemoveSCSIDevice(ctx context.Context, settings guestresource.SCSIDevice) error +} + // platformControllers holds platform-specific sub-controllers embedded in [Controller]. // For LCOW, this includes the Plan9 file share controller. type platformControllers struct { diff --git a/internal/controller/vm/vm_test.go b/internal/controller/vm/vm_test.go new file mode 100644 index 0000000000..f3d2dc9bc1 --- /dev/null +++ b/internal/controller/vm/vm_test.go @@ -0,0 +1,450 @@ +//go:build windows && (lcow || wcow) + +package vm + +import ( + "context" + "errors" + "testing" + "time" + + "go.uber.org/mock/gomock" + + "github.com/Microsoft/hcsshim/internal/controller/vm/mocks" + "github.com/Microsoft/hcsshim/internal/gcs" + "github.com/Microsoft/hcsshim/internal/protocol/guestresource" + "github.com/Microsoft/hcsshim/internal/shimdiag" +) + +var ( + errUVMTerminate = errors.New("uvm terminate failed") + errUVMClose = errors.New("uvm close failed") + errGuestClose = errors.New("guest close failed") + errGuestExec = errors.New("guest exec failed") + errGuestDump = errors.New("guest dump failed") + errGuestPolicy = errors.New("guest policy failed") +) + +type stubCaps struct { + dumpStacks bool +} + +func (s stubCaps) IsSignalProcessSupported() bool { return false } +func (s stubCaps) IsDeleteContainerStateSupported() bool { return false } +func (s stubCaps) IsDumpStacksSupported() bool { return s.dumpStacks } +func (s stubCaps) IsNamespaceAddRequestSupported() bool { return false } + +var _ gcs.GuestDefinedCapabilities = stubCaps{} + +func newControllerWithState(t *testing.T, state State) (*Controller, *mocks.MockvmLifetime, *mocks.MockguestManager) { + t.Helper() + ctrl := gomock.NewController(t) + uvm := mocks.NewMockvmLifetime(ctrl) + guest := mocks.NewMockguestManager(ctrl) + c := &Controller{ + uvm: uvm, + guest: guest, + vmState: state, + logOutputDone: make(chan struct{}), + } + return c, uvm, guest +} + +// ───────────────────────────────────────────────────────────────────────────── +// Idempotency +// ───────────────────────────────────────────────────────────────────────────── + +func TestStartVM_AlreadyRunning_NoOp(t *testing.T) { + c, _, _ := newControllerWithState(t, StateRunning) + + if err := c.StartVM(context.Background(), &StartOptions{}); err != nil { + t.Fatalf("expected nil error, got %v", err) + } + if got := c.State(); got != StateRunning { + t.Errorf("expected state to remain Running, got %s", got) + } +} + +func TestTerminateVM_FromTerminated_NoOp(t *testing.T) { + c, _, _ := newControllerWithState(t, StateTerminated) + + if err := c.TerminateVM(context.Background()); err != nil { + t.Fatalf("expected nil error, got %v", err) + } +} + +func TestTerminateVM_FromNotCreated_NoOp(t *testing.T) { + c, _, _ := newControllerWithState(t, StateNotCreated) + + if err := c.TerminateVM(context.Background()); err != nil { + t.Fatalf("expected nil error, got %v", err) + } +} + +// ───────────────────────────────────────────────────────────────────────────── +// State guards +// ───────────────────────────────────────────────────────────────────────────── + +func TestStartVM_RejectsWrongState(t *testing.T) { + for _, tt := range []struct { + name string + state State + }{ + {"NotCreated", StateNotCreated}, + {"Terminated", StateTerminated}, + {"Invalid", StateInvalid}, + } { + t.Run("reject/"+tt.name, func(t *testing.T) { + c, _, _ := newControllerWithState(t, tt.state) + if err := c.StartVM(context.Background(), &StartOptions{}); err == nil { + t.Fatalf("expected error for StartVM on %s, got nil", tt.state) + } + }) + } +} + +func TestExecIntoHost_RejectsTerminated(t *testing.T) { + c, _, _ := newControllerWithState(t, StateTerminated) + + code, err := c.ExecIntoHost(context.Background(), &shimdiag.ExecProcessRequest{Args: []string{"true"}}) + if err == nil { + t.Fatal("expected error for exec on terminated VM, got nil") + } + if code != -1 { + t.Errorf("expected exit code -1, got %d", code) + } +} + +func TestExecIntoHost_TerminalAndStderr_RejectsConfig(t *testing.T) { + c, _, _ := newControllerWithState(t, StateRunning) + + code, err := c.ExecIntoHost(context.Background(), &shimdiag.ExecProcessRequest{ + Terminal: true, + Stderr: "stderr.log", + }) + if err == nil { + t.Fatal("expected error for terminal+stderr, got nil") + } + if code != -1 { + t.Errorf("expected exit code -1, got %d", code) + } +} + +func TestUpdateMethods_RejectNonRunning(t *testing.T) { + for _, tt := range []struct { + name string + call func(c *Controller) error + }{ + {"UpdateCPU", func(c *Controller) error { return c.UpdateCPU(context.Background(), nil) }}, + {"UpdateMemory", func(c *Controller) error { return c.UpdateMemory(context.Background(), 1024) }}, + {"UpdateCPUGroup", func(c *Controller) error { return c.UpdateCPUGroup(context.Background(), "id") }}, + {"UpdatePolicyFragment", func(c *Controller) error { + return c.UpdatePolicyFragment(context.Background(), guestresource.SecurityPolicyFragment{}) + }}, + } { + t.Run("reject/"+tt.name, func(t *testing.T) { + c, _, _ := newControllerWithState(t, StateCreated) + if err := tt.call(c); err == nil { + t.Fatal("expected error for update on non-Running VM, got nil") + } + }) + } +} + +func TestStats_RejectsTerminated(t *testing.T) { + c, _, _ := newControllerWithState(t, StateTerminated) + + if _, err := c.Stats(context.Background()); err == nil { + t.Fatal("expected error for Stats on terminated VM, got nil") + } +} + +func TestWait_RejectsNotCreated(t *testing.T) { + c, _, _ := newControllerWithState(t, StateNotCreated) + + if err := c.Wait(context.Background()); err == nil { + t.Fatal("expected error for Wait on NotCreated VM, got nil") + } +} + +func TestDumpStacks_RejectsTerminated(t *testing.T) { + c, _, _ := newControllerWithState(t, StateTerminated) + + if _, err := c.DumpStacks(context.Background()); err == nil { + t.Fatal("expected error for DumpStacks on terminated VM, got nil") + } +} + +func TestUpdateCPUGroup_EmptyID_RejectsBeforeUVM(t *testing.T) { + c, _, _ := newControllerWithState(t, StateRunning) + + if err := c.UpdateCPUGroup(context.Background(), ""); err == nil { + t.Fatal("expected error for empty cpuGroupID, got nil") + } +} + +// ───────────────────────────────────────────────────────────────────────────── +// TerminateVM cleanup chain +// ───────────────────────────────────────────────────────────────────────────── + +func TestTerminateVM_FromCreated_DrivesFullCleanup(t *testing.T) { + c, uvm, guest := newControllerWithState(t, StateCreated) + gomock.InOrder( + uvm.EXPECT().Terminate(gomock.Any()).Return(nil), + guest.EXPECT().CloseConnection().Return(nil), + uvm.EXPECT().Close(gomock.Any()).Return(nil), + ) + + if err := c.TerminateVM(context.Background()); err != nil { + t.Fatalf("unexpected error: %v", err) + } + if got := c.State(); got != StateTerminated { + t.Errorf("expected Terminated, got %s", got) + } +} + +func TestTerminateVM_GuestCloseFails_StillCallsUVMClose(t *testing.T) { + c, uvm, guest := newControllerWithState(t, StateRunning) + gomock.InOrder( + uvm.EXPECT().Terminate(gomock.Any()).Return(nil), + guest.EXPECT().CloseConnection().Return(errGuestClose), + uvm.EXPECT().Close(gomock.Any()).Return(nil), + ) + + if err := c.TerminateVM(context.Background()); err != nil { + t.Fatalf("guest close failure must be swallowed, got %v", err) + } +} + +func TestTerminateVM_UVMTerminateFails_StillCallsCloseConnectionAndClose(t *testing.T) { + c, uvm, guest := newControllerWithState(t, StateRunning) + gomock.InOrder( + uvm.EXPECT().Terminate(gomock.Any()).Return(errUVMTerminate), + guest.EXPECT().CloseConnection().Return(nil), + uvm.EXPECT().Close(gomock.Any()).Return(nil), + ) + + if err := c.TerminateVM(context.Background()); err != nil { + t.Fatalf("uvm.Terminate failure must be swallowed, got %v", err) + } +} + +func TestTerminateVM_UVMCloseFails_TransitionsToInvalid(t *testing.T) { + c, uvm, guest := newControllerWithState(t, StateRunning) + gomock.InOrder( + uvm.EXPECT().Terminate(gomock.Any()).Return(nil), + guest.EXPECT().CloseConnection().Return(nil), + uvm.EXPECT().Close(gomock.Any()).Return(errUVMClose), + ) + + err := c.TerminateVM(context.Background()) + if !errors.Is(err, errUVMClose) { + t.Errorf("expected wrapped errUVMClose, got %v", err) + } + if got := c.State(); got != StateInvalid { + t.Errorf("expected Invalid, got %s", got) + } +} + +func TestTerminateVM_FromInvalid_RecoversToTerminated(t *testing.T) { + c, uvm, guest := newControllerWithState(t, StateInvalid) + gomock.InOrder( + uvm.EXPECT().Terminate(gomock.Any()).Return(nil), + guest.EXPECT().CloseConnection().Return(nil), + uvm.EXPECT().Close(gomock.Any()).Return(nil), + ) + + if err := c.TerminateVM(context.Background()); err != nil { + t.Fatalf("unexpected error: %v", err) + } + if got := c.State(); got != StateTerminated { + t.Errorf("expected Terminated, got %s", got) + } +} + +func TestTerminateVM_FromInvalid_StaysInvalidOnRetryFailure(t *testing.T) { + c, uvm, guest := newControllerWithState(t, StateInvalid) + uvm.EXPECT().Terminate(gomock.Any()).Return(nil) + guest.EXPECT().CloseConnection().Return(nil) + uvm.EXPECT().Close(gomock.Any()).Return(errUVMClose) + + err := c.TerminateVM(context.Background()) + if !errors.Is(err, errUVMClose) { + t.Fatalf("expected errUVMClose, got %v", err) + } + if got := c.State(); got != StateInvalid { + t.Errorf("expected Invalid preserved, got %s", got) + } +} + +// ───────────────────────────────────────────────────────────────────────────── +// ExitStatus +// ───────────────────────────────────────────────────────────────────────────── + +func TestExitStatus_NotTerminated_ReturnsError(t *testing.T) { + c, _, _ := newControllerWithState(t, StateRunning) + + if _, err := c.ExitStatus(); err == nil { + t.Fatal("expected error for non-Terminated VM, got nil") + } +} + +func TestExitStatus_Terminated_ReturnsValue(t *testing.T) { + c, uvm, _ := newControllerWithState(t, StateTerminated) + wantErr := errors.New("vm crashed") + uvm.EXPECT().StoppedTime().Return(time.Now()) + uvm.EXPECT().ExitError().Return(wantErr) + + st, err := c.ExitStatus() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !errors.Is(st.Err, wantErr) { + t.Errorf("expected ExitError %v, got %v", wantErr, st.Err) + } +} + +// ───────────────────────────────────────────────────────────────────────────── +// ExecIntoHost delegation +// ───────────────────────────────────────────────────────────────────────────── + +func TestExecIntoHost_Running_DelegatesToGuest(t *testing.T) { + c, _, guest := newControllerWithState(t, StateRunning) + guest.EXPECT().ExecIntoUVM(gomock.Any(), gomock.Any()).Return(42, nil) + + code, err := c.ExecIntoHost(context.Background(), &shimdiag.ExecProcessRequest{Args: []string{"true"}}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if code != 42 { + t.Errorf("expected exit code 42, got %d", code) + } +} + +func TestExecIntoHost_GuestError_PropagatesUnchanged(t *testing.T) { + c, _, guest := newControllerWithState(t, StateRunning) + guest.EXPECT().ExecIntoUVM(gomock.Any(), gomock.Any()).Return(-1, errGuestExec) + + code, err := c.ExecIntoHost(context.Background(), &shimdiag.ExecProcessRequest{Args: []string{"false"}}) + if !errors.Is(err, errGuestExec) { + t.Fatalf("expected errGuestExec, got %v", err) + } + if code != -1 { + t.Errorf("expected exit code -1, got %d", code) + } +} + +// ───────────────────────────────────────────────────────────────────────────── +// DumpStacks +// ───────────────────────────────────────────────────────────────────────────── + +func TestDumpStacks_NoCapability_ReturnsEmpty(t *testing.T) { + c, _, guest := newControllerWithState(t, StateRunning) + guest.EXPECT().Capabilities().Return(stubCaps{dumpStacks: false}) + + out, err := c.DumpStacks(context.Background()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if out != "" { + t.Errorf("expected empty output, got %q", out) + } +} + +func TestDumpStacks_HasCapability_DelegatesToGuest(t *testing.T) { + c, _, guest := newControllerWithState(t, StateRunning) + guest.EXPECT().Capabilities().Return(stubCaps{dumpStacks: true}) + guest.EXPECT().DumpStacks(gomock.Any()).Return("goroutine 1 [running]:\n", nil) + + out, err := c.DumpStacks(context.Background()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if out == "" { + t.Error("expected non-empty output") + } +} + +func TestDumpStacks_GuestError_PropagatesUnchanged(t *testing.T) { + c, _, guest := newControllerWithState(t, StateRunning) + guest.EXPECT().Capabilities().Return(stubCaps{dumpStacks: true}) + guest.EXPECT().DumpStacks(gomock.Any()).Return("", errGuestDump) + + _, err := c.DumpStacks(context.Background()) + if !errors.Is(err, errGuestDump) { + t.Fatalf("expected errGuestDump, got %v", err) + } +} + +// ───────────────────────────────────────────────────────────────────────────── +// UpdatePolicyFragment +// ───────────────────────────────────────────────────────────────────────────── + +func TestUpdatePolicyFragment_Running_DelegatesToGuest(t *testing.T) { + c, _, guest := newControllerWithState(t, StateRunning) + guest.EXPECT().InjectPolicyFragment(gomock.Any(), gomock.Any()).Return(errGuestPolicy) + + err := c.UpdatePolicyFragment(context.Background(), guestresource.SecurityPolicyFragment{}) + if !errors.Is(err, errGuestPolicy) { + t.Errorf("expected errGuestPolicy, got %v", err) + } +} + +// ───────────────────────────────────────────────────────────────────────────── +// Wait + background goroutine +// ───────────────────────────────────────────────────────────────────────────── + +func TestWait_Terminated_ReturnsAfterDrainingLogOutput(t *testing.T) { + c, uvm, _ := newControllerWithState(t, StateTerminated) + uvm.EXPECT().Wait(gomock.Any()).Return(nil) + close(c.logOutputDone) + + if err := c.Wait(context.Background()); err != nil { + t.Errorf("unexpected error: %v", err) + } +} + +func TestWait_ContextCancelledDuringLogDrain(t *testing.T) { + c, uvm, _ := newControllerWithState(t, StateRunning) + uvm.EXPECT().Wait(gomock.Any()).Return(nil) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + err := c.Wait(ctx) + if !errors.Is(err, context.Canceled) { + t.Errorf("expected wrapped context.Canceled, got %v", err) + } +} + +func TestWait_Running_HappyPath(t *testing.T) { + c, uvm, _ := newControllerWithState(t, StateRunning) + uvm.EXPECT().Wait(gomock.Any()).Return(nil) + close(c.logOutputDone) + + if err := c.Wait(context.Background()); err != nil { + t.Errorf("unexpected error: %v", err) + } +} + +func TestWaitForVMExit_TransitionsRunningToTerminated(t *testing.T) { + c, uvm, _ := newControllerWithState(t, StateRunning) + uvm.EXPECT().Wait(gomock.Any()).Return(nil) + + c.waitForVMExit(context.Background()) + + if got := c.State(); got != StateTerminated { + t.Errorf("expected Terminated, got %s", got) + } +} + +func TestWaitForVMExit_OverwritesInvalidToTerminated(t *testing.T) { + c, uvm, _ := newControllerWithState(t, StateInvalid) + uvm.EXPECT().Wait(gomock.Any()).Return(nil) + + c.waitForVMExit(context.Background()) + + if got := c.State(); got != StateTerminated { + t.Errorf("expected Terminated (current behaviour overwrites Invalid), got %s", got) + } +} diff --git a/internal/controller/vm/vm_wcow.go b/internal/controller/vm/vm_wcow.go index 80d8fa8c0d..1b0b28403e 100644 --- a/internal/controller/vm/vm_wcow.go +++ b/internal/controller/vm/vm_wcow.go @@ -6,11 +6,18 @@ import ( "context" "fmt" "sync" + "time" "github.com/Microsoft/go-winio" + "github.com/Microsoft/go-winio/pkg/guid" + "github.com/Microsoft/hcsshim/hcn" + "github.com/Microsoft/hcsshim/internal/cmd" + "github.com/Microsoft/hcsshim/internal/gcs" "github.com/Microsoft/hcsshim/internal/gcs/prot" hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" + "github.com/Microsoft/hcsshim/internal/protocol/guestrequest" "github.com/Microsoft/hcsshim/internal/protocol/guestresource" + "github.com/Microsoft/hcsshim/internal/vm/guestmanager" "github.com/Microsoft/hcsshim/internal/vm/vmmanager" "github.com/Microsoft/hcsshim/internal/vm/vmutils" @@ -19,6 +26,55 @@ import ( "golang.org/x/sync/errgroup" ) +// vmLifetime is the WCOW-flavoured seam over [*vmmanager.UtilityVM]. +// WCOW has no host-side Plan9, hence the per-platform split. +type vmLifetime interface { + ID() string + RuntimeID() guid.GUID + Start(ctx context.Context) error + Wait(ctx context.Context) error + Terminate(ctx context.Context) error + Close(ctx context.Context) error + SetCPUGroup(ctx context.Context, settings *hcsschema.CpuGroup) error + UpdateCPULimits(ctx context.Context, settings *hcsschema.ProcessorLimits) error + UpdateMemory(ctx context.Context, memory uint64) error + PropertiesV2(ctx context.Context, types ...hcsschema.PropertyType) (*hcsschema.Properties, error) + StartedTime() time.Time + StoppedTime() time.Time + ExitError() error + + AddDevice(ctx context.Context, vmbusGUID guid.GUID, settings hcsschema.VirtualPciDevice) error + RemoveDevice(ctx context.Context, vmbusGUID guid.GUID) error + + AddNIC(ctx context.Context, nicID string, settings *hcsschema.NetworkAdapter) error + RemoveNIC(ctx context.Context, nicID string, settings *hcsschema.NetworkAdapter) error + + AddSCSIDisk(ctx context.Context, disk hcsschema.Attachment, controller uint, lun uint) error + RemoveSCSIDisk(ctx context.Context, controller uint, lun uint) error +} + +// guestManager is the WCOW-flavoured seam over [*guestmanager.Guest]. +type guestManager interface { + CreateConnection(ctx context.Context, gcsServiceID guid.GUID, opts ...guestmanager.ConfigOption) error + CloseConnection() error + AddSecurityPolicy(ctx context.Context, opts guestresource.ConfidentialOptions) error + InjectPolicyFragment(ctx context.Context, fragment guestresource.SecurityPolicyFragment) error + Capabilities() gcs.GuestDefinedCapabilities + DumpStacks(ctx context.Context) (string, error) + ExecIntoUVM(ctx context.Context, request *cmd.CmdProcessRequest) (int, error) + + // UpdateHvSocketAddress is WCOW-only. + UpdateHvSocketAddress(ctx context.Context, address *hcsschema.HvSocketAddress) error + + AddNetworkInterface(ctx context.Context, adapterID string, requestType guestrequest.RequestType, settings *hcn.HostComputeEndpoint) error + RemoveNetworkInterface(ctx context.Context, adapterID string, requestType guestrequest.RequestType, settings *hcn.HostComputeEndpoint) error + AddNetworkNamespace(ctx context.Context, settings *hcn.HostComputeNamespace) error + RemoveNetworkNamespace(ctx context.Context, settings *hcn.HostComputeNamespace) error + AddMappedVirtualDisk(ctx context.Context, settings guestresource.WCOWMappedVirtualDisk) error + AddMappedVirtualDiskForContainerScratch(ctx context.Context, settings guestresource.WCOWMappedVirtualDisk) error + RemoveMappedVirtualDisk(ctx context.Context, settings guestresource.WCOWMappedVirtualDisk) error +} + // 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{} //nolint:unused // embedded in Controller for cross-platform compatibility with LCOW