QEMU: Initial QMP support

This commit is contained in:
Jayson Cofell 2019-07-03 18:33:59 -06:00
parent ba66d5d857
commit afe9ba2869
5 changed files with 98 additions and 0 deletions

View File

@ -117,6 +117,8 @@ type Config struct {
OutputDir string `mapstructure:"output_directory"`
QemuArgs [][]string `mapstructure:"qemuargs"`
QemuBinary string `mapstructure:"qemu_binary"`
QMPEnable bool `mapstructure:"qmp_enable"`
QMPSocketPath string `mapstructure:"qmp_socket_path"`
ShutdownCommand string `mapstructure:"shutdown_command"`
SSHHostPortMin int `mapstructure:"ssh_host_port_min"`
SSHHostPortMax int `mapstructure:"ssh_host_port_max"`
@ -344,6 +346,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
errs = packer.MultiErrorAppend(
errs, errors.New("ssh_host_port_min must be less than ssh_host_port_max"))
}
if b.config.SSHHostPortMin < 0 {
errs = packer.MultiErrorAppend(
errs, errors.New("ssh_host_port_min must be positive"))
@ -354,6 +357,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
errs, fmt.Errorf("vnc_port_min must be less than vnc_port_max"))
}
if b.config.QMPEnable && b.config.QMPSocketPath == "" {
socketName := fmt.Sprintf("%s.monitor", b.config.VMName)
b.config.QMPSocketPath = filepath.Join(b.config.OutputDir, socketName)
}
if b.config.QemuArgs == nil {
b.config.QemuArgs = make([][]string, 0)
}
@ -425,6 +433,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
steps = append(steps,
new(stepConfigureVNC),
steprun,
new(stepConfigureQMP),
&stepTypeBootCommand{},
)

View File

@ -598,3 +598,25 @@ func TestBuilderPrepare_QemuArgs(t *testing.T) {
t.Fatalf("bad: %#v", b.config.QemuArgs)
}
}
func TestBuilderPrepare_QMP(t *testing.T) {
var b Builder
config := testConfig()
// QMP Defaults
config["qmp_enable"] = true
config["output_directory"] = "not-a-real-directory"
b = Builder{}
warns, err := b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
expected := "not-a-real-directory/packer-foo.monitor"
if !reflect.DeepEqual(b.config.QMPSocketPath, expected) {
t.Fatalf("Bad QMP socket Path: %s", b.config.QMPSocketPath)
}
}

View File

@ -0,0 +1,56 @@
package qemu
import (
"context"
"fmt"
"log"
"time"
"github.com/digitalocean/go-qemu/qmp"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
// This step configures the VM to enable the QMP listener.
//
// Uses:
// config *config
// ui packer.Ui
//
// Produces:
type stepConfigureQMP struct {
monitor *qmp.SocketMonitor
}
func (s *stepConfigureQMP) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
ui := state.Get("ui").(packer.Ui)
if !config.QMPEnable {
return multistep.ActionContinue
}
msg := fmt.Sprintf("Opening QMP socket at: %s", config.QMPSocketPath)
ui.Say(msg)
log.Print(msg)
// Open QMP socket
var err error
s.monitor, err = qmp.NewSocketMonitor("unix", config.QMPSocketPath, 2*time.Second)
if err != nil {
err := fmt.Errorf("Error opening QMP socket: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
QMPMonitor := s.monitor
log.Printf("QMP socket open SUCCESS")
state.Put("qmp_monitor", QMPMonitor)
return multistep.ActionContinue
}
func (s *stepConfigureQMP) Cleanup(multistep.StateBag) {
}

View File

@ -85,6 +85,10 @@ func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error
defaultArgs["-netdev"] = fmt.Sprintf("user,id=user.0")
}
if config.QMPEnable {
defaultArgs["-qmp"] = fmt.Sprintf("unix:%s,server,nowait", config.QMPSocketPath)
}
rawVersion, err := driver.Version()
if err != nil {
return nil, err

View File

@ -282,6 +282,13 @@ Linux server and have not enabled X11 forwarding (`ssh -X`).
switch/value pairs. Any value specified as an empty string is ignored. All
values after the switch are concatenated with no separator.
- `qmp_enable` (bool) - Enable QMP socket. Location is specified by
`qmp_socket_path`.
Defaults to false.
- `qmp_socket_path` (string) - QMP Socket Path when `qmp_enable` is true.
Defaults to `output_directory`/`vm_name`.monitor.
~&gt; **Warning:** The qemu command line allows extreme flexibility, so beware
of conflicting arguments causing failures of your run. For instance, using
--no-acpi could break the ability to send power signal type commands (e.g.,