From 2f8f2d5ad1f01dd548636f82fe3462cff55dc56e Mon Sep 17 00:00:00 2001 From: Tom Hite Date: Mon, 7 Oct 2013 20:58:08 -0500 Subject: [PATCH] Fixes #1 and Fixes #2 by allowing qemuargs to operate and override defaults. --- builder/qemu/builder.go | 29 +++-- builder/qemu/step_run.go | 107 +++++++++++++----- .../source/docs/builders/qemu.html.markdown | 33 +++++- 3 files changed, 132 insertions(+), 37 deletions(-) diff --git a/builder/qemu/builder.go b/builder/qemu/builder.go index 1568843ae..64b921906 100644 --- a/builder/qemu/builder.go +++ b/builder/qemu/builder.go @@ -17,14 +17,27 @@ import ( const BuilderId = "transcend.qemu" var netDevice = map[string]bool{ - "ne2k_pci": true, - "i82551": true, - "i82557b": true, - "i82559er": true, - "rtl8139": true, - "e1000": true, - "pcnet": true, - "virtio": true, + "ne2k_pci": true, + "i82551": true, + "i82557b": true, + "i82559er": true, + "rtl8139": true, + "e1000": true, + "pcnet": true, + "virtio": true, + "virtio-net": true, + "usb-net": true, + "i82559a": true, + "i82559b": true, + "i82559c": true, + "i82550": true, + "i82562": true, + "i82557a": true, + "i82557c": true, + "i82801": true, + "vmxnet3": true, + "i82558a": true, + "i82558b": true, } var diskInterface = map[string]bool{ diff --git a/builder/qemu/step_run.go b/builder/qemu/step_run.go index f70c8a109..f79590f03 100644 --- a/builder/qemu/step_run.go +++ b/builder/qemu/step_run.go @@ -35,6 +35,84 @@ func cancelCallback(state multistep.StateBag) bool { return cancel } +func (s *stepRun) getCommandArgs( + bootDrive string, + state multistep.StateBag) []string { + + ui := state.Get("ui").(packer.Ui) + config := state.Get("config").(*config) + vmName := config.VMName + imgPath := filepath.Join(config.OutputDir, + fmt.Sprintf("%s.%s", vmName, strings.ToLower(config.Format))) + isoPath := state.Get("iso_path").(string) + vncPort := state.Get("vnc_port").(uint) + guiArgument := "sdl" + sshHostPort := state.Get("sshHostPort").(uint) + vnc := fmt.Sprintf("0.0.0.0:%d", vncPort-5900) + + 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.") + guiArgument = "none" + } + + defaultArgs := make(map[string]string) + defaultArgs["-name"] = vmName + defaultArgs["-machine"] = fmt.Sprintf("type=pc-1.0,accel=%s", config.Accelerator) + defaultArgs["-display"] = guiArgument + defaultArgs["-netdev"] = "user,id=user.0" + defaultArgs["-device"] = fmt.Sprintf("%s,netdev=user.0", config.NetDevice) + defaultArgs["-drive"] = fmt.Sprintf("file=%s,if=%s", imgPath, config.DiskInterface) + defaultArgs["-cdrom"] = isoPath + defaultArgs["-boot"] = bootDrive + defaultArgs["-m"] = "512m" + defaultArgs["-redir"] = fmt.Sprintf("tcp:%v::22", sshHostPort) + defaultArgs["-vnc"] = vnc + + inArgs := make(map[string][]string) + if len(config.QemuArgs) > 0 { + ui.Say("Overriding defaults Qemu arguments with QemuArgs...") + + // becuase qemu supports multiple appearances of the same + // switch, just different values, each key in the args hash + // will have an array of string values + for _, qemuArgs := range config.QemuArgs { + key := qemuArgs[0] + val := strings.Join(qemuArgs[1:], "") + if _, ok := inArgs[key]; !ok { + inArgs[key] = make([]string, 0) + } + if len(val) > 0 { + inArgs[key] = append(inArgs[key], val) + } + } + } + + // get any remaining missing default args from the default settings + for key := range defaultArgs { + if _, ok := inArgs[key]; !ok { + arg := make([]string, 1) + arg[0] = defaultArgs[key] + inArgs[key] = arg + } + } + + // Flatten to array of strings + outArgs := make([]string, 0) + for key, values := range inArgs { + if len(values) > 0 { + for idx := range values { + outArgs = append(outArgs, key, values[idx]) + } + } else { + outArgs = append(outArgs, key) + } + } + + return outArgs +} + func (s *stepRun) runVM( sendBootCommands bool, bootDrive string, @@ -45,35 +123,8 @@ func (s *stepRun) runVM( ui := state.Get("ui").(packer.Ui) vmName := config.VMName - imgPath := filepath.Join(config.OutputDir, - fmt.Sprintf("%s.%s", vmName, strings.ToLower(config.Format))) - isoPath := state.Get("iso_path").(string) - vncPort := state.Get("vnc_port").(uint) - guiArgument := "sdl" - sshHostPort := state.Get("sshHostPort").(uint) - vnc := fmt.Sprintf("0.0.0.0:%d", vncPort-5900) - ui.Say("Starting the virtual machine for OS Install...") - 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.") - guiArgument = "none" - } - - command := []string{ - "-name", vmName, - "-machine", fmt.Sprintf("type=pc-1.0,accel=%s", config.Accelerator), - "-display", guiArgument, - "-net", fmt.Sprintf("nic,model=%s", config.NetDevice), - "-net", "user", - "-drive", fmt.Sprintf("file=%s,if=%s", imgPath, config.DiskInterface), - "-cdrom", isoPath, - "-boot", bootDrive, - "-m", "512m", - "-redir", fmt.Sprintf("tcp:%v::22", sshHostPort), - "-vnc", vnc, - } + command := s.getCommandArgs(bootDrive, state) if err := driver.Qemu(vmName, command...); err != nil { err := fmt.Errorf("Error launching VM: %s", err) ui.Error(err.Error()) diff --git a/website/source/docs/builders/qemu.html.markdown b/website/source/docs/builders/qemu.html.markdown index 4b6dc80b3..69062752a 100644 --- a/website/source/docs/builders/qemu.html.markdown +++ b/website/source/docs/builders/qemu.html.markdown @@ -223,7 +223,38 @@ Optional: values "ne2k_pci," "i82551," "i82557b," "i82559er," "rtl8139," "e1000," "pcnet" or "virtio." The Qemu builder uses "virtio" by default. -* `qemuargs` (array of strings reserved for future use). +* `qemuargs` (array of array of strings) - Allows complete control over + the qemu command line (though not, at this time, qemu-img). Each array + of strings makes up a command line switch that overrides matching default + switch/value pairs. Any value specified as an empty string is ignored. + All values after the switch are concatenated with no separater. For instance: + +
+  . . .
+  "qemuargs": [
+    [ "-m", "1024m" ],
+    [ "--no-acpi", "" ],
+    [
+       "-netdev",
+      "user,id=mynet0,",
+      "hostfwd=hostip:hostport-guestip:guestport",
+      ""
+    ],
+    [ "-device", "virtio-net,netdev=mynet0" ]
+  ]
+  . . .
+
+ + would produce the following (not including other defaults supplied by the builder and not otherwise conflicting with the qemuargs): + +
+    qemu-system-x86 -m 1024m --no-acpi -netdev user,id=mynet0,hostfwd=hostip:hostport-guestip:guestport -device virtio-net,netdev=mynet0"
+
+ + Note that the qemu command line allows extreme flexibility, so beware of + conflicting arguments causing failures of your run. To see the defaults, + look in the packer.log file and search for the qemu-system-x86 command. The + arguments are all printed for review. * `output_directory` (string) - This is the path to the directory where the resulting virtual machine will be created. This may be relative or absolute.