diff --git a/builder/qemu/builder.go b/builder/qemu/builder.go index 4ac22b59b..016515617 100644 --- a/builder/qemu/builder.go +++ b/builder/qemu/builder.go @@ -54,9 +54,10 @@ var netDevice = map[string]bool{ } var diskInterface = map[string]bool{ - "ide": true, - "scsi": true, - "virtio": true, + "ide": true, + "scsi": true, + "virtio": true, + "virtio-scsi": true, } var diskCache = map[string]bool{ diff --git a/builder/qemu/driver.go b/builder/qemu/driver.go index e93c87836..77c68737d 100644 --- a/builder/qemu/driver.go +++ b/builder/qemu/driver.go @@ -189,7 +189,7 @@ func (d *QemuDriver) Version() (string, error) { versionOutput := strings.TrimSpace(stdout.String()) log.Printf("Qemu --version output: %s", versionOutput) - versionRe := regexp.MustCompile("[0-9]\\.[0-9]\\.[0-9]") + versionRe := regexp.MustCompile("[\\.[0-9]+]*") matches := versionRe.FindStringSubmatch(versionOutput) if len(matches) == 0 { return "", fmt.Errorf("No version found: %s", versionOutput) diff --git a/builder/qemu/step_run.go b/builder/qemu/step_run.go index 8226b8651..74db88a15 100644 --- a/builder/qemu/step_run.go +++ b/builder/qemu/step_run.go @@ -69,30 +69,51 @@ func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error vmName := config.VMName imgPath := filepath.Join(config.OutputDir, vmName) - defaultArgs := make(map[string]string) + defaultArgs := make(map[string]interface{}) + var deviceArgs []string + var driveArgs []string + + defaultArgs["-name"] = vmName + defaultArgs["-machine"] = fmt.Sprintf("type=%s", config.MachineType) + defaultArgs["-netdev"] = fmt.Sprintf("user,id=user.0,hostfwd=tcp::%v-:%d", sshHostPort, config.Comm.Port()) + + qemuVersion, err := driver.Version() + if err != nil { + return nil, err + } + parts := strings.Split(qemuVersion, ".") + qemuMajor, err := strconv.Atoi(parts[0]) + if err != nil { + return nil, err + } + if qemuMajor >= 2 { + if config.DiskInterface == "virtio-scsi" { + deviceArgs = append(deviceArgs, "virtio-scsi-pci,id=scsi0", "scsi-hd,bus=scsi0.0,drive=drive0") + driveArgs = append(driveArgs, fmt.Sprintf("if=none,file=%s,id=drive0,cache=%s,discard=%s", imgPath, config.DiskCache, config.DiskDiscard)) + } else { + driveArgs = append(driveArgs, fmt.Sprintf("file=%s,if=%s,cache=%s,discard=%s", imgPath, config.DiskInterface, config.DiskCache, config.DiskDiscard)) + } + } else { + defaultArgs["-drive"] = fmt.Sprintf("file=%s,if=%s,cache=%s", imgPath, config.DiskInterface, config.DiskCache) + } + deviceArgs = append(deviceArgs, fmt.Sprintf("%s,netdev=user.0", config.NetDevice)) if config.Headless == true { ui.Message("WARNING: The VM will be started in headless mode, as configured.\n" + "In headless mode, errors during the boot sequence or OS setup\n" + "won't be easily visible. Use at your own discretion.") } else { - defaultArgs["-display"] = "sdl" + if qemuMajor >= 2 { + defaultArgs["-display"] = "sdl" + } else { + ui.Message("WARNING: The version of qemu on your host doesn't support display mode.\n" + + "The display parameter will be ignored.") + } } - defaultArgs["-name"] = vmName - defaultArgs["-machine"] = fmt.Sprintf("type=%s", config.MachineType) - defaultArgs["-netdev"] = fmt.Sprintf( - "user,id=user.0,hostfwd=tcp::%v-:%d", sshHostPort, config.Comm.Port()) - defaultArgs["-device"] = fmt.Sprintf("%s,netdev=user.0", config.NetDevice) - qemuVersion, err := driver.Version() - if err == nil { - parts := strings.Split(qemuVersion, ".") - if strconv.Atoi(parts[0]) >= 2 { - defaultArgs["-drive"] = fmt.Sprintf("file=%s,if=%s,cache=%s,discard=%s", imgPath, config.DiskInterface, config.DiskCache, config.DiskDiscard) - } - } else { - defaultArgs["-drive"] = fmt.Sprintf("file=%s,if=%s,cache=%s", imgPath, config.DiskInterface, config.DiskCache) - } + defaultArgs["-device"] = deviceArgs + defaultArgs["-drive"] = driveArgs + if !config.DiskImage { defaultArgs["-cdrom"] = isoPath } @@ -102,7 +123,7 @@ func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error // Append the accelerator to the machine type if it is specified if config.Accelerator != "none" { - defaultArgs["-machine"] += fmt.Sprintf(",accel=%s", config.Accelerator) + defaultArgs["-machine"] = fmt.Sprintf("%s,accel=%s", defaultArgs["-machine"], config.Accelerator) } else { ui.Message("WARNING: The VM will be started with no hardware acceleration.\n" + "The installation may take considerably longer to finish.\n") @@ -152,7 +173,12 @@ func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error for key := range defaultArgs { if _, ok := inArgs[key]; !ok { arg := make([]string, 1) - arg[0] = defaultArgs[key] + switch defaultArgs[key].(type) { + case string: + arg[0] = defaultArgs[key].(string) + case []string: + arg = defaultArgs[key].([]string) + } inArgs[key] = arg } }