diff --git a/virtcontainers/clh.go b/virtcontainers/clh.go index 1668bd3e30..fa44feac1a 100644 --- a/virtcontainers/clh.go +++ b/virtcontainers/clh.go @@ -89,6 +89,8 @@ type clhClient interface { VmAddDevicePut(ctx context.Context, vmAddDevice chclient.VmAddDevice) (chclient.PciDeviceInfo, *http.Response, error) // Add a new disk device to the VM VmAddDiskPut(ctx context.Context, diskConfig chclient.DiskConfig) (chclient.PciDeviceInfo, *http.Response, error) + // Remove a device from the VM + VmRemoveDevicePut(ctx context.Context, vmRemoveDevice chclient.VmRemoveDevice) (*http.Response, error) } type CloudHypervisorVersion struct { @@ -478,9 +480,39 @@ func (clh *cloudHypervisor) hotplugAddDevice(devInfo interface{}, devType device } +func (clh *cloudHypervisor) hotplugRemoveBlockDevice(drive *config.BlockDrive) error { + cl := clh.client() + ctx, cancel := context.WithTimeout(context.Background(), clhHotPlugAPITimeout*time.Second) + defer cancel() + + driveID := clhDriveIndexToID(drive.Index) + + if drive.Pmem { + return fmt.Errorf("pmem device hotplug remove not supported") + } + + _, err := cl.VmRemoveDevicePut(ctx, chclient.VmRemoveDevice{Id: driveID}) + + if err != nil { + err = fmt.Errorf("failed to hotplug remove block device %+v %s", drive, openAPIClientError(err)) + } + + return err +} + func (clh *cloudHypervisor) hotplugRemoveDevice(devInfo interface{}, devType deviceType) (interface{}, error) { - clh.Logger().WithField("function", "hotplugRemoveDevice").Warn("hotplug remove device not supported") - return nil, nil + span, _ := clh.trace("hotplugRemoveDevice") + defer span.Finish() + + switch devType { + case blockDev: + return nil, clh.hotplugRemoveBlockDevice(devInfo.(*config.BlockDrive)) + default: + clh.Logger().WithFields(log.Fields{"devInfo": devInfo, + "deviceType": devType}).Error("hotplugRemoveDevice: unsupported device") + return nil, fmt.Errorf("Could not hot remove device: unsupported device: %v, type: %v", + devInfo, devType) + } } func (clh *cloudHypervisor) hypervisorConfig() HypervisorConfig { diff --git a/virtcontainers/clh_test.go b/virtcontainers/clh_test.go index 9b76884fb5..5be13e6d27 100644 --- a/virtcontainers/clh_test.go +++ b/virtcontainers/clh_test.go @@ -104,6 +104,11 @@ func (c *clhClientMock) VmAddDiskPut(ctx context.Context, diskConfig chclient.Di return chclient.PciDeviceInfo{}, nil, nil } +//nolint:golint +func (c *clhClientMock) VmRemoveDevicePut(ctx context.Context, vmRemoveDevice chclient.VmRemoveDevice) (*http.Response, error) { + return nil, nil +} + func TestCloudHypervisorAddVSock(t *testing.T) { assert := assert.New(t) clh := cloudHypervisor{} @@ -363,7 +368,7 @@ func TestCheckVersion(t *testing.T) { } } -func TestCloudHypervisorHotplugBlockDevice(t *testing.T) { +func TestCloudHypervisorHotplugAddBlockDevice(t *testing.T) { assert := assert.New(t) clhConfig, err := newClhConfig() @@ -374,13 +379,31 @@ func TestCloudHypervisorHotplugBlockDevice(t *testing.T) { clh.APIClient = &clhClientMock{} clh.config.BlockDeviceDriver = config.VirtioBlock - err = clh.hotplugBlockDevice(&config.BlockDrive{Pmem: false}) + err = clh.hotplugAddBlockDevice(&config.BlockDrive{Pmem: false}) assert.NoError(err, "Hotplug disk block device expected no error") - err = clh.hotplugBlockDevice(&config.BlockDrive{Pmem: true}) + err = clh.hotplugAddBlockDevice(&config.BlockDrive{Pmem: true}) assert.Error(err, "Hotplug pmem block device expected error") clh.config.BlockDeviceDriver = config.VirtioSCSI - err = clh.hotplugBlockDevice(&config.BlockDrive{Pmem: false}) + err = clh.hotplugAddBlockDevice(&config.BlockDrive{Pmem: false}) assert.Error(err, "Hotplug block device not using 'virtio-blk' expected error") } + +func TestCloudHypervisorHotplugRemoveBlockDevice(t *testing.T) { + assert := assert.New(t) + + clhConfig, err := newClhConfig() + assert.NoError(err) + + clh := &cloudHypervisor{} + clh.config = clhConfig + clh.APIClient = &clhClientMock{} + + clh.config.BlockDeviceDriver = config.VirtioBlock + err = clh.hotplugRemoveBlockDevice(&config.BlockDrive{Pmem: false}) + assert.NoError(err, "Hotplug remove disk block device expected no error") + + err = clh.hotplugRemoveBlockDevice(&config.BlockDrive{Pmem: true}) + assert.Error(err, "Hotplug remove pmem block device expected error") +}