diff --git a/internal/guest/prot/protocol.go b/internal/guest/prot/protocol.go index 7cdeaaf34e..c371cef334 100644 --- a/internal/guest/prot/protocol.go +++ b/internal/guest/prot/protocol.go @@ -534,6 +534,12 @@ func UnmarshalContainerModifySettings(b []byte) (*ContainerModifySettings, error // Fill in the ResourceType-specific fields. switch msr.ResourceType { + case guestresource.ResourceTypeSCSIDevice: + msd := &guestresource.SCSIDevice{} + if err := commonutils.UnmarshalJSONWithHresult(msrRawSettings, msd); err != nil { + return &request, errors.Wrap(err, "failed to unmarshal settings as SCSIDevice") + } + msr.Settings = msd case guestresource.ResourceTypeMappedVirtualDisk: mvd := &guestresource.LCOWMappedVirtualDisk{} if err := commonutils.UnmarshalJSONWithHresult(msrRawSettings, mvd); err != nil { diff --git a/internal/guest/runtime/hcsv2/uvm.go b/internal/guest/runtime/hcsv2/uvm.go index 8770534dff..54e00f571f 100644 --- a/internal/guest/runtime/hcsv2/uvm.go +++ b/internal/guest/runtime/hcsv2/uvm.go @@ -540,6 +540,8 @@ func (h *Host) CreateContainer(ctx context.Context, id string, settings *prot.VM func (h *Host) modifyHostSettings(ctx context.Context, containerID string, req *guestrequest.ModificationRequest) (err error) { switch req.ResourceType { + case guestresource.ResourceTypeSCSIDevice: + return modifySCSIDevice(ctx, req.RequestType, req.Settings.(*guestresource.SCSIDevice)) case guestresource.ResourceTypeMappedVirtualDisk: mvd := req.Settings.(*guestresource.LCOWMappedVirtualDisk) // find the actual controller number on the bus and update the incoming request. @@ -939,6 +941,23 @@ func newInvalidRequestTypeError(rt guestrequest.RequestType) error { return errors.Errorf("the RequestType %q is not supported", rt) } +func modifySCSIDevice( + ctx context.Context, + rt guestrequest.RequestType, + msd *guestresource.SCSIDevice, +) error { + switch rt { + case guestrequest.RequestTypeRemove: + cNum, err := scsi.ActualControllerNumber(ctx, msd.Controller) + if err != nil { + return err + } + return scsi.UnplugDevice(ctx, cNum, msd.Lun) + default: + return newInvalidRequestTypeError(rt) + } +} + func modifyMappedVirtualDisk( ctx context.Context, rt guestrequest.RequestType, @@ -979,7 +998,7 @@ func modifyMappedVirtualDisk( return err } } - return scsi.UnplugDevice(ctx, mvd.Controller, mvd.Lun) + return nil default: return newInvalidRequestTypeError(rt) } diff --git a/internal/protocol/guestresource/resources.go b/internal/protocol/guestresource/resources.go index 00090a94ae..579c9d4687 100644 --- a/internal/protocol/guestresource/resources.go +++ b/internal/protocol/guestresource/resources.go @@ -18,6 +18,11 @@ const ( // ResourceTypeMappedDirectory is the modify resource type for mapped // directories ResourceTypeMappedDirectory guestrequest.ResourceType = "MappedDirectory" + // ResourceTypeSCSIDevice is the modify resources type for SCSI devices. + // Note this type is not related to mounting a device in the guest, only + // for operations on the SCSI device itself. + // Currently it only supports Remove, to cleanly remove a SCSI device. + ResourceTypeSCSIDevice guestrequest.ResourceType = "SCSIDevice" // ResourceTypeMappedVirtualDisk is the modify resource type for mapped // virtual disks ResourceTypeMappedVirtualDisk guestrequest.ResourceType = "MappedVirtualDisk" @@ -64,6 +69,12 @@ type WCOWCombinedLayers struct { // Defines the schema for hosted settings passed to GCS and/or OpenGCS +// SCSIDevice represents a SCSI device that is attached to the system. +type SCSIDevice struct { + Controller uint8 `json:"Controller,omitempty"` + Lun uint8 `json:"Lun,omitempty"` +} + // LCOWMappedVirtualDisk represents a disk on the host which is mapped into a // directory in the guest in the V2 schema. type LCOWMappedVirtualDisk struct {