QEMU: Initial QMP support
This commit is contained in:
parent
ba66d5d857
commit
afe9ba2869
@ -117,6 +117,8 @@ type Config struct {
|
|||||||
OutputDir string `mapstructure:"output_directory"`
|
OutputDir string `mapstructure:"output_directory"`
|
||||||
QemuArgs [][]string `mapstructure:"qemuargs"`
|
QemuArgs [][]string `mapstructure:"qemuargs"`
|
||||||
QemuBinary string `mapstructure:"qemu_binary"`
|
QemuBinary string `mapstructure:"qemu_binary"`
|
||||||
|
QMPEnable bool `mapstructure:"qmp_enable"`
|
||||||
|
QMPSocketPath string `mapstructure:"qmp_socket_path"`
|
||||||
ShutdownCommand string `mapstructure:"shutdown_command"`
|
ShutdownCommand string `mapstructure:"shutdown_command"`
|
||||||
SSHHostPortMin int `mapstructure:"ssh_host_port_min"`
|
SSHHostPortMin int `mapstructure:"ssh_host_port_min"`
|
||||||
SSHHostPortMax int `mapstructure:"ssh_host_port_max"`
|
SSHHostPortMax int `mapstructure:"ssh_host_port_max"`
|
||||||
@ -344,6 +346,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||||||
errs = packer.MultiErrorAppend(
|
errs = packer.MultiErrorAppend(
|
||||||
errs, errors.New("ssh_host_port_min must be less than ssh_host_port_max"))
|
errs, errors.New("ssh_host_port_min must be less than ssh_host_port_max"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.config.SSHHostPortMin < 0 {
|
if b.config.SSHHostPortMin < 0 {
|
||||||
errs = packer.MultiErrorAppend(
|
errs = packer.MultiErrorAppend(
|
||||||
errs, errors.New("ssh_host_port_min must be positive"))
|
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"))
|
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 {
|
if b.config.QemuArgs == nil {
|
||||||
b.config.QemuArgs = make([][]string, 0)
|
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,
|
steps = append(steps,
|
||||||
new(stepConfigureVNC),
|
new(stepConfigureVNC),
|
||||||
steprun,
|
steprun,
|
||||||
|
new(stepConfigureQMP),
|
||||||
&stepTypeBootCommand{},
|
&stepTypeBootCommand{},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -598,3 +598,25 @@ func TestBuilderPrepare_QemuArgs(t *testing.T) {
|
|||||||
t.Fatalf("bad: %#v", b.config.QemuArgs)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
56
builder/qemu/step_configure_qmp.go
Normal file
56
builder/qemu/step_configure_qmp.go
Normal 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) {
|
||||||
|
}
|
@ -85,6 +85,10 @@ func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error
|
|||||||
defaultArgs["-netdev"] = fmt.Sprintf("user,id=user.0")
|
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()
|
rawVersion, err := driver.Version()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -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
|
switch/value pairs. Any value specified as an empty string is ignored. All
|
||||||
values after the switch are concatenated with no separator.
|
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.
|
||||||
|
|
||||||
~> **Warning:** The qemu command line allows extreme flexibility, so beware
|
~> **Warning:** The qemu command line allows extreme flexibility, so beware
|
||||||
of conflicting arguments causing failures of your run. For instance, using
|
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.,
|
--no-acpi could break the ability to send power signal type commands (e.g.,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user