diff --git a/.changelog/11864.txt b/.changelog/11864.txt new file mode 100644 index 000000000..9ca1db038 --- /dev/null +++ b/.changelog/11864.txt @@ -0,0 +1,3 @@ +```release-note:improvement +qemu: Added option to configure `drive_interface` +``` diff --git a/drivers/qemu/driver.go b/drivers/qemu/driver.go index aaa8d0301..23c127ee5 100644 --- a/drivers/qemu/driver.go +++ b/drivers/qemu/driver.go @@ -95,6 +95,7 @@ var ( // a taskConfig within a job. It is returned in the TaskConfigSchema RPC taskConfigSpec = hclspec.NewObject(map[string]*hclspec.Spec{ "image_path": hclspec.NewAttr("image_path", "string", true), + "drive_interface": hclspec.NewAttr("drive_interface", "string", false), "accelerator": hclspec.NewAttr("accelerator", "string", false), "graceful_shutdown": hclspec.NewAttr("graceful_shutdown", "bool", false), "guest_agent": hclspec.NewAttr("guest_agent", "bool", false), @@ -125,6 +126,7 @@ type TaskConfig struct { Args []string `codec:"args"` // extra arguments to qemu executable PortMap hclutils.MapStrInt `codec:"port_map"` // A map of host port and the port name defined in the image manifest file GracefulShutdown bool `codec:"graceful_shutdown"` + DriveInterface string `codec:"drive_interface"` // Use interface for image GuestAgent bool `codec:"guest_agent"` } @@ -344,6 +346,19 @@ func isAllowedImagePath(allowedPaths []string, allocDir, imagePath string) bool return false } +// hardcoded list of drive interfaces, Qemu currently supports +var allowedDriveInterfaces = []string{"ide", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "none"} + +func isAllowedDriveInterface(driveInterface string) bool { + for _, ai := range allowedDriveInterfaces { + if driveInterface == ai { + return true + } + } + + return false +} + // validateArgs ensures that all QEMU command line params are in the // allowlist. This function must be called after all interpolation has // taken place. @@ -414,12 +429,20 @@ func (d *Driver) StartTask(cfg *drivers.TaskConfig) (*drivers.TaskHandle, *drive return nil, nil, err } + driveInterface := "ide" + if driverConfig.DriveInterface != "" { + driveInterface = driverConfig.DriveInterface + } + if !isAllowedDriveInterface(driveInterface) { + return nil, nil, fmt.Errorf("Unsupported drive_interface") + } + args := []string{ absPath, "-machine", "type=pc,accel=" + accelerator, "-name", vmID, "-m", mem, - "-drive", "file=" + vmPath, + "-drive", "file=" + vmPath + ",if=" + driveInterface, "-nographic", } diff --git a/drivers/qemu/driver_test.go b/drivers/qemu/driver_test.go index 5d2b71538..7bb27d1a7 100644 --- a/drivers/qemu/driver_test.go +++ b/drivers/qemu/driver_test.go @@ -390,6 +390,7 @@ func TestConfig_ParseAllHCL(t *testing.T) { cfgStr := ` config { image_path = "/tmp/image_path" + drive_interface = "virtio" accelerator = "kvm" args = ["arg1", "arg2"] port_map { @@ -400,9 +401,10 @@ config { }` expected := &TaskConfig{ - ImagePath: "/tmp/image_path", - Accelerator: "kvm", - Args: []string{"arg1", "arg2"}, + ImagePath: "/tmp/image_path", + DriveInterface: "virtio", + Accelerator: "kvm", + Args: []string{"arg1", "arg2"}, PortMap: map[string]int{ "http": 80, "https": 443, @@ -416,6 +418,19 @@ config { require.EqualValues(t, expected, tc) } +func TestIsAllowedDriveInterface(t *testing.T) { + validInterfaces := []string{"ide", "scsi", "sd", "mtd", "floppy", "pflash", "virtio", "none"} + invalidInterfaces := []string{"foo", "virtio-foo"} + + for _, i := range validInterfaces { + require.Truef(t, isAllowedDriveInterface(i), "drive_interface should be allowed: %v", i) + } + + for _, i := range invalidInterfaces { + require.Falsef(t, isAllowedDriveInterface(i), "drive_interface should be not allowed: %v", i) + } +} + func TestIsAllowedImagePath(t *testing.T) { ci.Parallel(t) diff --git a/website/content/docs/drivers/qemu.mdx b/website/content/docs/drivers/qemu.mdx index 30cb1bf0e..a5e874cee 100644 --- a/website/content/docs/drivers/qemu.mdx +++ b/website/content/docs/drivers/qemu.mdx @@ -42,6 +42,10 @@ The `qemu` driver supports the following configuration in the job spec: contains the image in a subfolder, the path will need to be the relative path (`subdir/from_archive/my.img`). +- `drive_interface` - (Optional) This option defines on which type of interface + the drive is connected. Available types are: `ide`, `scsi`, `sd`, `mtd`, + `floppy`, `pflash`, `virtio` and `none`. Default is `ide`. + - `accelerator` - (Optional) The type of accelerator to use in the invocation. If the host machine has `qemu` installed with KVM support, users can specify `kvm` for the `accelerator`. Default is `tcg`.