From 6c92cb586f7d393fbdcde1bbcb8f9ad1fc80969c Mon Sep 17 00:00:00 2001 From: Nir Soffer Date: Sun, 18 Aug 2024 02:58:37 +0300 Subject: [PATCH 1/3] Add readonly option for storage devices The virtio-blk, nvme, and usb-mass-storage devices can use now `readonly` option to create a read only device. This exposes the exiting StorageConfig.ReadOnly field. Because this option is mostly useful to cdrom images, document the option only for usb-mass-storage. --- doc/usage.md | 5 +++-- pkg/config/virtio.go | 11 ++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/doc/usage.md b/doc/usage.md index a867dc16..f38f6655 100644 --- a/doc/usage.md +++ b/doc/usage.md @@ -183,12 +183,13 @@ The `--device usb-mass-storage` option adds a USB mass storage device to the vir #### Arguments - `path`: the absolute path to the disk image file. +- `readonly`: if specified the device will be read only. #### Example -This adds a USB mass storage device to the VM which will be backed by the ISO image at `/Users/virtuser/distro.iso`: +This adds a read only USB mass storage device to the VM which will be backed by the ISO image at `/Users/virtuser/distro.iso`: ``` ---device usb-mass-storage,path=/Users/virtuser/distro.iso +--device usb-mass-storage,path=/Users/virtuser/distro.iso,readonly ``` diff --git a/pkg/config/virtio.go b/pkg/config/virtio.go index 5523cf9a..f3b1af51 100644 --- a/pkg/config/virtio.go +++ b/pkg/config/virtio.go @@ -685,7 +685,11 @@ func (config *StorageConfig) ToCmdLine() ([]string, error) { if config.ImagePath == "" { return nil, fmt.Errorf("%s devices need the path to a disk image", config.DevName) } - return []string{"--device", fmt.Sprintf("%s,path=%s", config.DevName, config.ImagePath)}, nil + value := fmt.Sprintf("%s,path=%s", config.DevName, config.ImagePath) + if config.ReadOnly { + value += ",readonly" + } + return []string{"--device", value}, nil } func (config *StorageConfig) FromOptions(options []option) error { @@ -693,6 +697,11 @@ func (config *StorageConfig) FromOptions(options []option) error { switch option.key { case "path": config.ImagePath = option.value + case "readonly": + if option.value != "" { + return fmt.Errorf("unexpected value for virtio-blk 'readonly' option: %s", option.value) + } + config.ReadOnly = true default: return fmt.Errorf("unknown option for %s devices: %s", config.DevName, option.key) } From 2ab835d7af7f46acbcf77f3365ccae6a4324a308 Mon Sep 17 00:00:00 2001 From: Nir Soffer Date: Sun, 18 Aug 2024 04:17:40 +0300 Subject: [PATCH 2/3] Allow creating a read only USBMassStorage We can create a read only device using the command line option, this change adds USBMassStorage.SetReadOnly() setting to allow crating a device programmatically. --- pkg/config/virtio.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/config/virtio.go b/pkg/config/virtio.go index f3b1af51..0fd18fb7 100644 --- a/pkg/config/virtio.go +++ b/pkg/config/virtio.go @@ -667,13 +667,17 @@ func usbMassStorageNewEmpty() *USBMassStorage { // USBMassStorageNew creates a new USB disk to use in the virtual machine. It will use // the file at imagePath as the disk image. This image must be in raw or ISO format. -func USBMassStorageNew(imagePath string) (VMComponent, error) { +func USBMassStorageNew(imagePath string) (*USBMassStorage, error) { usbMassStorage := usbMassStorageNewEmpty() usbMassStorage.ImagePath = imagePath return usbMassStorage, nil } +func (dev *USBMassStorage) SetReadOnly(readOnly bool) { + dev.StorageConfig.ReadOnly = readOnly +} + // StorageConfig configures a disk device. type StorageConfig struct { DevName string `json:"devName"` From 0826af0c102490a4191bd1c6cb88fc8a6f021774 Mon Sep 17 00:00:00 2001 From: Nir Soffer Date: Sun, 18 Aug 2024 04:21:47 +0300 Subject: [PATCH 3/3] Test read only usb-mass-storage Add test for converting command line options and formatting JSON. --- pkg/config/json_test.go | 3 ++- pkg/config/virtio_test.go | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/pkg/config/json_test.go b/pkg/config/json_test.go index 72763f1f..11049db2 100644 --- a/pkg/config/json_test.go +++ b/pkg/config/json_test.go @@ -156,6 +156,7 @@ var jsonTests = map[string]jsonTest{ // USB mass storage usb, err := USBMassStorageNew("/usbmassstorage") require.NoError(t, err) + usb.SetReadOnly(true) // rosetta rosetta, err := RosettaShareNew("vz-rosetta") require.NoError(t, err) @@ -164,7 +165,7 @@ var jsonTests = map[string]jsonTest{ return vm }, - expectedJSON: `{"vcpus":3,"memoryBytes":4194304000,"bootloader":{"kind":"linuxBootloader","vmlinuzPath":"/vmlinuz","initrdPath":"/initrd","kernelCmdLine":"console=hvc0"},"devices":[{"kind":"virtioserial","logFile":"/virtioserial"},{"kind":"virtioinput","inputType":"keyboard"},{"kind":"virtiogpu","usesGUI":false,"width":800,"height":600},{"kind":"virtionet","nat":true,"macAddress":"00:11:22:33:44:55"},{"kind":"virtiorng"},{"kind":"virtioblk","devName":"virtio-blk","imagePath":"/virtioblk"},{"kind":"virtiosock","port":1234,"socketURL":"/virtiovsock"},{"kind":"virtiofs","mountTag":"tag","sharedDir":"/virtiofs"},{"kind":"usbmassstorage","devName":"usb-mass-storage","imagePath":"/usbmassstorage"},{"kind":"rosetta","mountTag":"vz-rosetta","installRosetta":false}]}`, + expectedJSON: `{"vcpus":3,"memoryBytes":4194304000,"bootloader":{"kind":"linuxBootloader","vmlinuzPath":"/vmlinuz","initrdPath":"/initrd","kernelCmdLine":"console=hvc0"},"devices":[{"kind":"virtioserial","logFile":"/virtioserial"},{"kind":"virtioinput","inputType":"keyboard"},{"kind":"virtiogpu","usesGUI":false,"width":800,"height":600},{"kind":"virtionet","nat":true,"macAddress":"00:11:22:33:44:55"},{"kind":"virtiorng"},{"kind":"virtioblk","devName":"virtio-blk","imagePath":"/virtioblk"},{"kind":"virtiosock","port":1234,"socketURL":"/virtiovsock"},{"kind":"virtiofs","mountTag":"tag","sharedDir":"/virtiofs"},{"kind":"usbmassstorage","devName":"usb-mass-storage","imagePath":"/usbmassstorage","readOnly":true},{"kind":"rosetta","mountTag":"vz-rosetta","installRosetta":false}]}`, }, } diff --git a/pkg/config/virtio_test.go b/pkg/config/virtio_test.go index 371c1875..d592edd5 100644 --- a/pkg/config/virtio_test.go +++ b/pkg/config/virtio_test.go @@ -161,6 +161,24 @@ var virtioDevTests = map[string]virtioDevTest{ }, expectedCmdLine: []string{"--device", "usb-mass-storage,path=/foo/bar"}, }, + "NewUSBMassStorageReadOnly": { + newDev: func() (VirtioDevice, error) { + dev, err := USBMassStorageNew("/foo/bar") + if err != nil { + return nil, err + } + dev.SetReadOnly(true) + return dev, err + }, + expectedDev: &USBMassStorage{ + StorageConfig: StorageConfig{ + DevName: "usb-mass-storage", + ImagePath: "/foo/bar", + ReadOnly: true, + }, + }, + expectedCmdLine: []string{"--device", "usb-mass-storage,path=/foo/bar,readonly"}, + }, "NewVirtioInputWithPointingDevice": { newDev: func() (VirtioDevice, error) { return VirtioInputNew("pointing") }, expectedDev: &VirtioInput{