Merge pull request #10929 from hashicorp/extract_qemu
Extract QEMU plugin
This commit is contained in:
commit
20faaef05c
|
@ -1,15 +0,0 @@
|
|||
package qemu
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func TestBuilder_ImplementsBuilder(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = &Builder{}
|
||||
if _, ok := raw.(packersdk.Builder); !ok {
|
||||
t.Error("Builder must implement builder.")
|
||||
}
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
package qemu
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/communicator"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
|
||||
)
|
||||
|
||||
func testCommConfig() *CommConfig {
|
||||
return &CommConfig{
|
||||
Comm: communicator.Config{
|
||||
SSH: communicator.SSH{
|
||||
SSHUsername: "foo",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommConfigPrepare(t *testing.T) {
|
||||
c := testCommConfig()
|
||||
warns, errs := c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
if len(warns) != 0 {
|
||||
t.Fatal("should not have any warnings")
|
||||
}
|
||||
|
||||
if c.HostPortMin != 2222 {
|
||||
t.Errorf("bad min communicator host port: %d", c.HostPortMin)
|
||||
}
|
||||
|
||||
if c.HostPortMax != 4444 {
|
||||
t.Errorf("bad max communicator host port: %d", c.HostPortMax)
|
||||
}
|
||||
|
||||
if c.Comm.SSHPort != 22 {
|
||||
t.Errorf("bad communicator port: %d", c.Comm.SSHPort)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommConfigPrepare_SSHHostPort(t *testing.T) {
|
||||
var c *CommConfig
|
||||
var errs []error
|
||||
var warns []string
|
||||
|
||||
// Bad
|
||||
c = testCommConfig()
|
||||
c.HostPortMin = 1000
|
||||
c.HostPortMax = 500
|
||||
warns, errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) == 0 {
|
||||
t.Fatalf("bad: %#v", errs)
|
||||
}
|
||||
if len(warns) != 0 {
|
||||
t.Fatal("should not have any warnings")
|
||||
}
|
||||
|
||||
// Good
|
||||
c = testCommConfig()
|
||||
c.HostPortMin = 50
|
||||
c.HostPortMax = 500
|
||||
warns, errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %s", errs)
|
||||
}
|
||||
if len(warns) != 0 {
|
||||
t.Fatal("should not have any warnings")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommConfigPrepare_SSHPrivateKey(t *testing.T) {
|
||||
var c *CommConfig
|
||||
var errs []error
|
||||
var warns []string
|
||||
|
||||
c = testCommConfig()
|
||||
c.Comm.SSHPrivateKeyFile = ""
|
||||
warns, errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %#v", errs)
|
||||
}
|
||||
if len(warns) != 0 {
|
||||
t.Fatal("should not have any warnings")
|
||||
}
|
||||
|
||||
c = testCommConfig()
|
||||
c.Comm.SSHPrivateKeyFile = "/i/dont/exist"
|
||||
warns, errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) == 0 {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if len(warns) != 0 {
|
||||
t.Fatal("should not have any warnings")
|
||||
}
|
||||
|
||||
// Test bad contents
|
||||
tf, err := ioutil.TempFile("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
defer tf.Close()
|
||||
|
||||
if _, err := tf.Write([]byte("HELLO!")); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
c = testCommConfig()
|
||||
c.Comm.SSHPrivateKeyFile = tf.Name()
|
||||
warns, errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) == 0 {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if len(warns) != 0 {
|
||||
t.Fatal("should not have any warnings")
|
||||
}
|
||||
|
||||
// Test good contents
|
||||
_, err = tf.Seek(0, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
err = tf.Truncate(0)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
_, err = tf.Write([]byte(testPem))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
c = testCommConfig()
|
||||
c.Comm.SSHPrivateKeyFile = tf.Name()
|
||||
warns, errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("should not have error: %#v", errs)
|
||||
}
|
||||
if len(warns) != 0 {
|
||||
t.Fatal("should not have any warnings")
|
||||
}
|
||||
}
|
|
@ -1,695 +0,0 @@
|
|||
package qemu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/common"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var testPem = `
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEAxd4iamvrwRJvtNDGQSIbNvvIQN8imXTRWlRY62EvKov60vqu
|
||||
hh+rDzFYAIIzlmrJopvOe0clqmi3mIP9dtkjPFrYflq52a2CF5q+BdwsJXuRHbJW
|
||||
LmStZUwW1khSz93DhvhmK50nIaczW63u4EO/jJb3xj+wxR1Nkk9bxi3DDsYFt8SN
|
||||
AzYx9kjlEYQ/+sI4/ATfmdV9h78SVotjScupd9KFzzi76gWq9gwyCBLRynTUWlyD
|
||||
2UOfJRkOvhN6/jKzvYfVVwjPSfA9IMuooHdScmC4F6KBKJl/zf/zETM0XyzIDNmH
|
||||
uOPbCiljq2WoRM+rY6ET84EO0kVXbfx8uxUsqQIDAQABAoIBAQCkPj9TF0IagbM3
|
||||
5BSs/CKbAWS4dH/D4bPlxx4IRCNirc8GUg+MRb04Xz0tLuajdQDqeWpr6iLZ0RKV
|
||||
BvreLF+TOdV7DNQ4XE4gSdJyCtCaTHeort/aordL3l0WgfI7mVk0L/yfN1PEG4YG
|
||||
E9q1TYcyrB3/8d5JwIkjabxERLglCcP+geOEJp+QijbvFIaZR/n2irlKW4gSy6ko
|
||||
9B0fgUnhkHysSg49ChHQBPQ+o5BbpuLrPDFMiTPTPhdfsvGGcyCGeqfBA56oHcSF
|
||||
K02Fg8OM+Bd1lb48LAN9nWWY4WbwV+9bkN3Ym8hO4c3a/Dxf2N7LtAQqWZzFjvM3
|
||||
/AaDvAgBAoGBAPLD+Xn1IYQPMB2XXCXfOuJewRY7RzoVWvMffJPDfm16O7wOiW5+
|
||||
2FmvxUDayk4PZy6wQMzGeGKnhcMMZTyaq2g/QtGfrvy7q1Lw2fB1VFlVblvqhoJa
|
||||
nMJojjC4zgjBkXMHsRLeTmgUKyGs+fdFbfI6uejBnnf+eMVUMIdJ+6I9AoGBANCn
|
||||
kWO9640dttyXURxNJ3lBr2H3dJOkmD6XS+u+LWqCSKQe691Y/fZ/ZL0Oc4Mhy7I6
|
||||
hsy3kDQ5k2V0fkaNODQIFJvUqXw2pMewUk8hHc9403f4fe9cPrL12rQ8WlQw4yoC
|
||||
v2B61vNczCCUDtGxlAaw8jzSRaSI5s6ax3K7enbdAoGBAJB1WYDfA2CoAQO6y9Sl
|
||||
b07A/7kQ8SN5DbPaqrDrBdJziBQxukoMJQXJeGFNUFD/DXFU5Fp2R7C86vXT7HIR
|
||||
v6m66zH+CYzOx/YE6EsUJms6UP9VIVF0Rg/RU7teXQwM01ZV32LQ8mswhTH20o/3
|
||||
uqMHmxUMEhZpUMhrfq0isyApAoGAe1UxGTXfj9AqkIVYylPIq2HqGww7+jFmVEj1
|
||||
9Wi6S6Sq72ffnzzFEPkIQL/UA4TsdHMnzsYKFPSbbXLIWUeMGyVTmTDA5c0e5XIR
|
||||
lPhMOKCAzv8w4VUzMnEkTzkFY5JqFCD/ojW57KvDdNZPVB+VEcdxyAW6aKELXMAc
|
||||
eHLc1nkCgYEApm/motCTPN32nINZ+Vvywbv64ZD+gtpeMNP3CLrbe1X9O+H52AXa
|
||||
1jCoOldWR8i2bs2NVPcKZgdo6fFULqE4dBX7Te/uYEIuuZhYLNzRO1IKU/YaqsXG
|
||||
3bfQ8hKYcSnTfE0gPtLDnqCIxTocaGLSHeG3TH9fTw+dA8FvWpUztI4=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`
|
||||
|
||||
func testConfig() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"iso_checksum": "md5:0B0F137F17AC10944716020B018F8126",
|
||||
"iso_url": "http://www.google.com/",
|
||||
"ssh_username": "foo",
|
||||
common.BuildNameConfigKey: "foo",
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_Defaults(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
if c.OutputDir != "output-foo" {
|
||||
t.Errorf("bad output dir: %s", c.OutputDir)
|
||||
}
|
||||
|
||||
if c.CommConfig.HostPortMin != 2222 {
|
||||
t.Errorf("bad min ssh host port: %d", c.CommConfig.HostPortMin)
|
||||
}
|
||||
|
||||
if c.CommConfig.HostPortMax != 4444 {
|
||||
t.Errorf("bad max ssh host port: %d", c.CommConfig.HostPortMax)
|
||||
}
|
||||
|
||||
if c.CommConfig.Comm.SSHPort != 22 {
|
||||
t.Errorf("bad ssh port: %d", c.CommConfig.Comm.SSHPort)
|
||||
}
|
||||
|
||||
if c.VMName != "packer-foo" {
|
||||
t.Errorf("bad vm name: %s", c.VMName)
|
||||
}
|
||||
|
||||
if c.Format != "qcow2" {
|
||||
t.Errorf("bad format: %s", c.Format)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_VNCBindAddress(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
|
||||
// Test a default boot_wait
|
||||
delete(config, "vnc_bind_address")
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if c.VNCBindAddress != "127.0.0.1" {
|
||||
t.Fatalf("bad value: %s", c.VNCBindAddress)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_DiskCompaction(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
|
||||
// Bad
|
||||
config["skip_compaction"] = false
|
||||
config["disk_compression"] = true
|
||||
config["format"] = "img"
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
if c.SkipCompaction != true {
|
||||
t.Fatalf("SkipCompaction should be true")
|
||||
}
|
||||
if c.DiskCompression != false {
|
||||
t.Fatalf("DiskCompression should be false")
|
||||
}
|
||||
|
||||
// Good
|
||||
config["skip_compaction"] = false
|
||||
config["disk_compression"] = true
|
||||
config["format"] = "qcow2"
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
if c.SkipCompaction != false {
|
||||
t.Fatalf("SkipCompaction should be false")
|
||||
}
|
||||
if c.DiskCompression != true {
|
||||
t.Fatalf("DiskCompression should be true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_DiskSize(t *testing.T) {
|
||||
type testcase struct {
|
||||
InputSize string
|
||||
OutputSize string
|
||||
ErrExpected bool
|
||||
}
|
||||
|
||||
testCases := []testcase{
|
||||
{"", "40960M", false}, // not provided
|
||||
{"12345", "12345M", false}, // no unit given, defaults to M
|
||||
{"12345x", "12345x", true}, // invalid unit
|
||||
{"12345T", "12345T", false}, // terabytes
|
||||
{"12345b", "12345b", false}, // bytes get preserved when set.
|
||||
{"60000M", "60000M", false}, // Original test case
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
// Set input disk size
|
||||
var c Config
|
||||
config := testConfig()
|
||||
delete(config, "disk_size")
|
||||
config["disk_size"] = tc.InputSize
|
||||
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if (err == nil) == tc.ErrExpected {
|
||||
t.Fatalf("bad: error when providing disk size %s; Err expected: %t; err recieved: %v", tc.InputSize, tc.ErrExpected, err)
|
||||
}
|
||||
|
||||
if c.DiskSize != tc.OutputSize {
|
||||
t.Fatalf("bad size: received: %s but expected %s", c.DiskSize, tc.OutputSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_AdditionalDiskSize(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
|
||||
config["disk_additional_size"] = []string{"1M"}
|
||||
config["disk_image"] = true
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error")
|
||||
}
|
||||
|
||||
delete(config, "disk_image")
|
||||
config["disk_additional_size"] = []string{"1M"}
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
if c.AdditionalDiskSize[0] != "1M" {
|
||||
t.Fatalf("bad size: %s", c.AdditionalDiskSize)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_Format(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
|
||||
// Bad
|
||||
config["format"] = "illegal value"
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
// Good
|
||||
config["format"] = "qcow2"
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
// Good
|
||||
config["format"] = "raw"
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_UseBackingFile(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
|
||||
config["use_backing_file"] = true
|
||||
|
||||
// Bad: iso_url is not a disk_image
|
||||
config["disk_image"] = false
|
||||
config["format"] = "qcow2"
|
||||
c = Config{}
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
// Bad: format is not 'qcow2'
|
||||
config["disk_image"] = true
|
||||
config["format"] = "raw"
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
// Good: iso_url is a disk image and format is 'qcow2'
|
||||
config["disk_image"] = true
|
||||
config["format"] = "qcow2"
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_SkipResizeDisk(t *testing.T) {
|
||||
config := testConfig()
|
||||
config["skip_resize_disk"] = true
|
||||
config["disk_image"] = false
|
||||
|
||||
var c Config
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Errorf("unexpected warns when calling prepare with skip_resize_disk set to true: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Errorf("setting skip_resize_disk to true when disk_image is false should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_FloppyFiles(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
|
||||
delete(config, "floppy_files")
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("bad err: %s", err)
|
||||
}
|
||||
|
||||
if len(c.FloppyFiles) != 0 {
|
||||
t.Fatalf("bad: %#v", c.FloppyFiles)
|
||||
}
|
||||
|
||||
floppies_path := "../test-fixtures/floppies"
|
||||
config["floppy_files"] = []string{fmt.Sprintf("%s/bar.bat", floppies_path), fmt.Sprintf("%s/foo.ps1", floppies_path)}
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
expected := []string{fmt.Sprintf("%s/bar.bat", floppies_path), fmt.Sprintf("%s/foo.ps1", floppies_path)}
|
||||
if !reflect.DeepEqual(c.FloppyFiles, expected) {
|
||||
t.Fatalf("bad: %#v", c.FloppyFiles)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_InvalidFloppies(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
config["floppy_files"] = []string{"nonexistent.bat", "nonexistent.ps1"}
|
||||
c = Config{}
|
||||
_, errs := c.Prepare(config)
|
||||
if errs == nil {
|
||||
t.Fatalf("Nonexistent floppies should trigger multierror")
|
||||
}
|
||||
|
||||
if len(errs.(*packersdk.MultiError).Errors) != 2 {
|
||||
t.Fatalf("Multierror should work and report 2 errors")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_InvalidKey(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
|
||||
// Add a random key
|
||||
config["i_should_not_be_valid"] = true
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_OutputDir(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
|
||||
// Test with existing dir
|
||||
dir, err := ioutil.TempDir("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
config["output_directory"] = dir
|
||||
c = Config{}
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
// Test with a good one
|
||||
config["output_directory"] = "i-hope-i-dont-exist"
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_ShutdownTimeout(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
|
||||
// Test with a bad value
|
||||
config["shutdown_timeout"] = "this is not good"
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
// Test with a good one
|
||||
config["shutdown_timeout"] = "5s"
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_SSHHostPort(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
|
||||
// Bad
|
||||
config["host_port_min"] = 1000
|
||||
config["host_port_max"] = 500
|
||||
c = Config{}
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
// Bad
|
||||
config["host_port_min"] = -500
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
// Good
|
||||
config["host_port_min"] = 500
|
||||
config["host_port_max"] = 1000
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_SSHPrivateKey(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
|
||||
config["ssh_private_key_file"] = ""
|
||||
c = Config{}
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
config["ssh_private_key_file"] = "/i/dont/exist"
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
// Test bad contents
|
||||
tf, err := ioutil.TempFile("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
defer tf.Close()
|
||||
|
||||
if _, err := tf.Write([]byte("HELLO!")); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
config["ssh_private_key_file"] = tf.Name()
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
// Test good contents
|
||||
if _, err := tf.Seek(0, 0); err != nil {
|
||||
t.Fatalf("errorf getting key")
|
||||
}
|
||||
if err := tf.Truncate(0); err != nil {
|
||||
t.Fatalf("errorf getting key")
|
||||
}
|
||||
if _, err := tf.Write([]byte(testPem)); err != nil {
|
||||
t.Fatalf("errorf getting key")
|
||||
}
|
||||
config["ssh_private_key_file"] = tf.Name()
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_SSHWaitTimeout(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
|
||||
// Test a default boot_wait
|
||||
delete(config, "ssh_timeout")
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Test with a bad value
|
||||
config["ssh_timeout"] = "this is not good"
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
|
||||
// Test with a good one
|
||||
config["ssh_timeout"] = "5s"
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_QemuArgs(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
|
||||
// Test with empty
|
||||
delete(config, "qemuargs")
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(c.QemuArgs, [][]string{}) {
|
||||
t.Fatalf("bad: %#v", c.QemuArgs)
|
||||
}
|
||||
|
||||
// Test with a good one
|
||||
config["qemuargs"] = [][]interface{}{
|
||||
{"foo", "bar", "baz"},
|
||||
}
|
||||
|
||||
c = Config{}
|
||||
warns, err = c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
expected := [][]string{
|
||||
{"foo", "bar", "baz"},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(c.QemuArgs, expected) {
|
||||
t.Fatalf("bad: %#v", c.QemuArgs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_VNCPassword(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
config["vnc_use_password"] = true
|
||||
config["output_directory"] = "not-a-real-directory"
|
||||
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
expected := filepath.Join("not-a-real-directory", "packer-foo.monitor")
|
||||
if !reflect.DeepEqual(c.QMPSocketPath, expected) {
|
||||
t.Fatalf("Bad QMP socket Path: %s", c.QMPSocketPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommConfigPrepare_BackwardsCompatibility(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
hostPortMin := 1234
|
||||
hostPortMax := 4321
|
||||
sshTimeout := 2 * time.Minute
|
||||
|
||||
config["ssh_wait_timeout"] = sshTimeout
|
||||
config["ssh_host_port_min"] = hostPortMin
|
||||
config["ssh_host_port_max"] = hostPortMax
|
||||
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) == 0 {
|
||||
t.Fatalf("should have deprecation warn")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
if c.CommConfig.Comm.SSHTimeout != sshTimeout {
|
||||
t.Fatalf("SSHTimeout should be %s for backwards compatibility, but it was %s", sshTimeout.String(), c.CommConfig.Comm.SSHTimeout.String())
|
||||
}
|
||||
|
||||
if c.CommConfig.HostPortMin != hostPortMin {
|
||||
t.Fatalf("HostPortMin should be %d for backwards compatibility, but it was %d", hostPortMin, c.CommConfig.HostPortMin)
|
||||
}
|
||||
|
||||
if c.CommConfig.HostPortMax != hostPortMax {
|
||||
t.Fatalf("HostPortMax should be %d for backwards compatibility, but it was %d", hostPortMax, c.CommConfig.HostPortMax)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_LoadQemuImgArgs(t *testing.T) {
|
||||
var c Config
|
||||
config := testConfig()
|
||||
config["qemu_img_args"] = map[string][]string{
|
||||
"convert": []string{"-o", "preallocation=full"},
|
||||
"resize": []string{"-foo", "bar"},
|
||||
"create": []string{"-baz", "bang"},
|
||||
}
|
||||
warns, err := c.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
assert.Equal(t, []string{"-o", "preallocation=full"},
|
||||
c.QemuImgArgs.Convert, "Convert args not loaded properly")
|
||||
assert.Equal(t, []string{"-foo", "bar"},
|
||||
c.QemuImgArgs.Resize, "Resize args not loaded properly")
|
||||
assert.Equal(t, []string{"-baz", "bang"},
|
||||
c.QemuImgArgs.Create, "Create args not loaded properly")
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
package qemu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_buildConvertCommand(t *testing.T) {
|
||||
type testCase struct {
|
||||
Step *stepConvertDisk
|
||||
Expected []string
|
||||
Reason string
|
||||
}
|
||||
testcases := []testCase{
|
||||
{
|
||||
&stepConvertDisk{
|
||||
Format: "qcow2",
|
||||
DiskCompression: false,
|
||||
},
|
||||
[]string{"convert", "-O", "qcow2", "source.qcow", "target.qcow2"},
|
||||
"Basic, happy path, no compression, no extra args",
|
||||
},
|
||||
{
|
||||
&stepConvertDisk{
|
||||
Format: "qcow2",
|
||||
DiskCompression: true,
|
||||
},
|
||||
[]string{"convert", "-c", "-O", "qcow2", "source.qcow", "target.qcow2"},
|
||||
"Basic, happy path, with compression, no extra args",
|
||||
},
|
||||
{
|
||||
&stepConvertDisk{
|
||||
Format: "qcow2",
|
||||
DiskCompression: true,
|
||||
QemuImgArgs: QemuImgArgs{
|
||||
Convert: []string{"-o", "preallocation=full"},
|
||||
},
|
||||
},
|
||||
[]string{"convert", "-c", "-o", "preallocation=full", "-O", "qcow2", "source.qcow", "target.qcow2"},
|
||||
"Basic, happy path, with compression, one set of extra args",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
command := tc.Step.buildConvertCommand("source.qcow", "target.qcow2")
|
||||
|
||||
assert.Equal(t, command, tc.Expected,
|
||||
fmt.Sprintf("%s. Expected %#v", tc.Reason, tc.Expected))
|
||||
}
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
package qemu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func copyTestState(t *testing.T, d *DriverMock) multistep.StateBag {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("ui", packersdk.TestUi(t))
|
||||
state.Put("driver", d)
|
||||
state.Put("iso_path", "example_source.qcow2")
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
func Test_StepCopySkip(t *testing.T) {
|
||||
testcases := []stepCopyDisk{
|
||||
stepCopyDisk{
|
||||
DiskImage: false,
|
||||
UseBackingFile: false,
|
||||
},
|
||||
stepCopyDisk{
|
||||
DiskImage: true,
|
||||
UseBackingFile: true,
|
||||
},
|
||||
stepCopyDisk{
|
||||
DiskImage: false,
|
||||
UseBackingFile: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
d := new(DriverMock)
|
||||
state := copyTestState(t, d)
|
||||
action := tc.Run(context.TODO(), state)
|
||||
if action != multistep.ActionContinue {
|
||||
t.Fatalf("Should have gotten an ActionContinue")
|
||||
}
|
||||
|
||||
if d.CopyCalled || d.QemuImgCalled {
|
||||
t.Fatalf("Should have skipped step since DiskImage and UseBackingFile are not set")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_StepCopyCalled(t *testing.T) {
|
||||
step := stepCopyDisk{
|
||||
DiskImage: true,
|
||||
Format: "qcow2",
|
||||
VMName: "output.qcow2",
|
||||
}
|
||||
|
||||
d := new(DriverMock)
|
||||
state := copyTestState(t, d)
|
||||
action := step.Run(context.TODO(), state)
|
||||
if action != multistep.ActionContinue {
|
||||
t.Fatalf("Should have gotten an ActionContinue")
|
||||
}
|
||||
|
||||
if !d.CopyCalled {
|
||||
t.Fatalf("Should have copied since all extensions are qcow2")
|
||||
}
|
||||
if d.QemuImgCalled {
|
||||
t.Fatalf("Should not have called qemu-img when formats match")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_StepQemuImgCalled(t *testing.T) {
|
||||
step := stepCopyDisk{
|
||||
DiskImage: true,
|
||||
Format: "raw",
|
||||
VMName: "output.qcow2",
|
||||
}
|
||||
|
||||
d := new(DriverMock)
|
||||
state := copyTestState(t, d)
|
||||
action := step.Run(context.TODO(), state)
|
||||
if action != multistep.ActionContinue {
|
||||
t.Fatalf("Should have gotten an ActionContinue")
|
||||
}
|
||||
if d.CopyCalled {
|
||||
t.Fatalf("Should not have copied since extensions don't match")
|
||||
}
|
||||
if !d.QemuImgCalled {
|
||||
t.Fatalf("Should have called qemu-img since extensions don't match")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_StepQemuImgCalledWithExtraArgs(t *testing.T) {
|
||||
step := &stepCopyDisk{
|
||||
DiskImage: true,
|
||||
Format: "raw",
|
||||
VMName: "output.qcow2",
|
||||
QemuImgArgs: QemuImgArgs{
|
||||
Convert: []string{"-o", "preallocation=full"},
|
||||
},
|
||||
}
|
||||
|
||||
d := new(DriverMock)
|
||||
state := copyTestState(t, d)
|
||||
action := step.Run(context.TODO(), state)
|
||||
if action != multistep.ActionContinue {
|
||||
t.Fatalf("Should have gotten an ActionContinue")
|
||||
}
|
||||
if d.CopyCalled {
|
||||
t.Fatalf("Should not have copied since extensions don't match")
|
||||
}
|
||||
if !d.QemuImgCalled {
|
||||
t.Fatalf("Should have called qemu-img since extensions don't match")
|
||||
}
|
||||
assert.Equal(
|
||||
t,
|
||||
d.QemuImgCalls,
|
||||
[]string{"convert", "-o", "preallocation=full", "-O", "raw",
|
||||
"example_source.qcow2", "output.qcow2"},
|
||||
"should have added user extra args")
|
||||
}
|
|
@ -1,176 +0,0 @@
|
|||
package qemu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_buildCreateCommand(t *testing.T) {
|
||||
type testCase struct {
|
||||
Step *stepCreateDisk
|
||||
I int
|
||||
Expected []string
|
||||
Reason string
|
||||
}
|
||||
testcases := []testCase{
|
||||
{
|
||||
&stepCreateDisk{
|
||||
Format: "qcow2",
|
||||
UseBackingFile: false,
|
||||
},
|
||||
0,
|
||||
[]string{"create", "-f", "qcow2", "target.qcow2", "1234M"},
|
||||
"Basic, happy path, no backing store, no extra args",
|
||||
},
|
||||
{
|
||||
&stepCreateDisk{
|
||||
Format: "qcow2",
|
||||
DiskImage: true,
|
||||
UseBackingFile: true,
|
||||
AdditionalDiskSize: []string{"1M", "2M"},
|
||||
},
|
||||
0,
|
||||
[]string{"create", "-f", "qcow2", "-b", "source.qcow2", "target.qcow2", "1234M"},
|
||||
"Basic, happy path, backing store, additional disks",
|
||||
},
|
||||
{
|
||||
&stepCreateDisk{
|
||||
Format: "qcow2",
|
||||
UseBackingFile: true,
|
||||
DiskImage: true,
|
||||
},
|
||||
1,
|
||||
[]string{"create", "-f", "qcow2", "target.qcow2", "1234M"},
|
||||
"Basic, happy path, backing store set but not at first index, no extra args",
|
||||
},
|
||||
{
|
||||
&stepCreateDisk{
|
||||
Format: "qcow2",
|
||||
UseBackingFile: true,
|
||||
DiskImage: true,
|
||||
QemuImgArgs: QemuImgArgs{
|
||||
Create: []string{"-foo", "bar"},
|
||||
},
|
||||
},
|
||||
0,
|
||||
[]string{"create", "-f", "qcow2", "-b", "source.qcow2", "-foo", "bar", "target.qcow2", "1234M"},
|
||||
"Basic, happy path, backing store set, extra args",
|
||||
},
|
||||
{
|
||||
&stepCreateDisk{
|
||||
Format: "qcow2",
|
||||
UseBackingFile: true,
|
||||
QemuImgArgs: QemuImgArgs{
|
||||
Create: []string{"-foo", "bar"},
|
||||
},
|
||||
},
|
||||
1,
|
||||
[]string{"create", "-f", "qcow2", "-foo", "bar", "target.qcow2", "1234M"},
|
||||
"Basic, happy path, backing store set but not at first index, extra args",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("iso_path", "source.qcow2")
|
||||
command := tc.Step.buildCreateCommand("target.qcow2", "1234M", tc.I, state)
|
||||
|
||||
assert.Equal(t, command, tc.Expected,
|
||||
fmt.Sprintf("%s. Expected %#v", tc.Reason, tc.Expected))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_StepCreateCalled(t *testing.T) {
|
||||
type testCase struct {
|
||||
Step *stepCreateDisk
|
||||
Expected []string
|
||||
Reason string
|
||||
}
|
||||
testcases := []testCase{
|
||||
{
|
||||
&stepCreateDisk{
|
||||
Format: "qcow2",
|
||||
DiskImage: true,
|
||||
DiskSize: "1M",
|
||||
VMName: "target",
|
||||
UseBackingFile: true,
|
||||
},
|
||||
[]string{
|
||||
"create", "-f", "qcow2", "-b", "source.qcow2", "target", "1M",
|
||||
},
|
||||
"Basic, happy path, backing store, no additional disks",
|
||||
},
|
||||
{
|
||||
&stepCreateDisk{
|
||||
Format: "raw",
|
||||
DiskImage: false,
|
||||
DiskSize: "4M",
|
||||
VMName: "target",
|
||||
UseBackingFile: false,
|
||||
},
|
||||
[]string{
|
||||
"create", "-f", "raw", "target", "4M",
|
||||
},
|
||||
"Basic, happy path, raw, no additional disks",
|
||||
},
|
||||
{
|
||||
&stepCreateDisk{
|
||||
Format: "qcow2",
|
||||
DiskImage: true,
|
||||
DiskSize: "4M",
|
||||
VMName: "target",
|
||||
UseBackingFile: false,
|
||||
AdditionalDiskSize: []string{"3M", "8M"},
|
||||
},
|
||||
[]string{
|
||||
"create", "-f", "qcow2", "target-1", "3M",
|
||||
"create", "-f", "qcow2", "target-2", "8M",
|
||||
},
|
||||
"Skips disk creation when disk can be copied",
|
||||
},
|
||||
{
|
||||
&stepCreateDisk{
|
||||
Format: "qcow2",
|
||||
DiskImage: true,
|
||||
DiskSize: "4M",
|
||||
VMName: "target",
|
||||
UseBackingFile: false,
|
||||
},
|
||||
nil,
|
||||
"Skips disk creation when disk can be copied",
|
||||
},
|
||||
{
|
||||
&stepCreateDisk{
|
||||
Format: "qcow2",
|
||||
DiskImage: true,
|
||||
DiskSize: "1M",
|
||||
VMName: "target",
|
||||
UseBackingFile: true,
|
||||
AdditionalDiskSize: []string{"3M", "8M"},
|
||||
},
|
||||
[]string{
|
||||
"create", "-f", "qcow2", "-b", "source.qcow2", "target", "1M",
|
||||
"create", "-f", "qcow2", "target-1", "3M",
|
||||
"create", "-f", "qcow2", "target-2", "8M",
|
||||
},
|
||||
"Basic, happy path, backing store, additional disks",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
d := new(DriverMock)
|
||||
state := copyTestState(t, d)
|
||||
state.Put("iso_path", "source.qcow2")
|
||||
action := tc.Step.Run(context.TODO(), state)
|
||||
if action != multistep.ActionContinue {
|
||||
t.Fatalf("Should have gotten an ActionContinue")
|
||||
}
|
||||
|
||||
assert.Equal(t, d.QemuImgCalls, tc.Expected,
|
||||
fmt.Sprintf("%s. Expected %#v", tc.Reason, tc.Expected))
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package qemu
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func TestStepHTTPIPDiscover_Run(t *testing.T) {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("ui", &packersdk.BasicUi{
|
||||
Reader: new(bytes.Buffer),
|
||||
Writer: new(bytes.Buffer),
|
||||
})
|
||||
config := &Config{}
|
||||
state.Put("config", config)
|
||||
step := new(stepHTTPIPDiscover)
|
||||
hostIp := "10.0.2.2"
|
||||
|
||||
// Test the run
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
if _, ok := state.GetOk("error"); ok {
|
||||
t.Fatal("should NOT have error")
|
||||
}
|
||||
httpIp := state.Get("http_ip").(string)
|
||||
if httpIp != hostIp {
|
||||
t.Fatalf("bad: Http ip is %s but was supposed to be %s", httpIp, hostIp)
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
package qemu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStepResizeDisk_Skips(t *testing.T) {
|
||||
testConfigs := []*Config{
|
||||
&Config{
|
||||
DiskImage: false,
|
||||
SkipResizeDisk: false,
|
||||
},
|
||||
&Config{
|
||||
DiskImage: false,
|
||||
SkipResizeDisk: true,
|
||||
},
|
||||
}
|
||||
for _, config := range testConfigs {
|
||||
state := testState(t)
|
||||
driver := state.Get("driver").(*DriverMock)
|
||||
|
||||
state.Put("config", config)
|
||||
step := new(stepResizeDisk)
|
||||
|
||||
// Test the run
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
if _, ok := state.GetOk("error"); ok {
|
||||
t.Fatal("should NOT have error")
|
||||
}
|
||||
if len(driver.QemuImgCalls) > 0 {
|
||||
t.Fatal("should NOT have called qemu-img")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_buildResizeCommand(t *testing.T) {
|
||||
type testCase struct {
|
||||
Step *stepResizeDisk
|
||||
Expected []string
|
||||
Reason string
|
||||
}
|
||||
testcases := []testCase{
|
||||
{
|
||||
&stepResizeDisk{
|
||||
Format: "qcow2",
|
||||
DiskSize: "1234M",
|
||||
},
|
||||
[]string{"resize", "-f", "qcow2", "source.qcow", "1234M"},
|
||||
"no extra args",
|
||||
},
|
||||
{
|
||||
&stepResizeDisk{
|
||||
Format: "qcow2",
|
||||
DiskSize: "1234M",
|
||||
QemuImgArgs: QemuImgArgs{
|
||||
Resize: []string{"-foo", "bar"},
|
||||
},
|
||||
},
|
||||
[]string{"resize", "-f", "qcow2", "-foo", "bar", "source.qcow", "1234M"},
|
||||
"one set of extra args",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
command := tc.Step.buildResizeCommand("source.qcow")
|
||||
|
||||
assert.Equal(t, command, tc.Expected,
|
||||
fmt.Sprintf("%s. Expected %#v", tc.Reason, tc.Expected))
|
||||
}
|
||||
}
|
|
@ -1,710 +0,0 @@
|
|||
package qemu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/communicator"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func runTestState(t *testing.T, config *Config) multistep.StateBag {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("config", config)
|
||||
|
||||
d := new(DriverMock)
|
||||
d.VersionResult = "3.0.0"
|
||||
state.Put("driver", d)
|
||||
|
||||
state.Put("commHostPort", 5000)
|
||||
state.Put("floppy_path", "fake_floppy_path")
|
||||
state.Put("http_ip", "127.0.0.1")
|
||||
state.Put("http_port", 1234)
|
||||
state.Put("iso_path", "/path/to/test.iso")
|
||||
state.Put("qemu_disk_paths", []string{})
|
||||
state.Put("vnc_port", 5905)
|
||||
state.Put("vnc_password", "fake_vnc_password")
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
func Test_UserOverrides(t *testing.T) {
|
||||
type testCase struct {
|
||||
Config *Config
|
||||
Expected []string
|
||||
Reason string
|
||||
}
|
||||
testcases := []testCase{
|
||||
{
|
||||
&Config{
|
||||
HTTPConfig: commonsteps.HTTPConfig{
|
||||
HTTPDir: "http/directory",
|
||||
},
|
||||
OutputDir: "output/directory",
|
||||
VMName: "myvm",
|
||||
QemuArgs: [][]string{
|
||||
{"-randomflag1", "{{.HTTPIP}}-{{.HTTPPort}}-{{.HTTPDir}}"},
|
||||
{"-randomflag2", "{{.OutputDir}}-{{.Name}}"},
|
||||
},
|
||||
},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-drive", "file=/path/to/test.iso,media=cdrom",
|
||||
"-randomflag1", "127.0.0.1-1234-http/directory",
|
||||
"-randomflag2", "output/directory-myvm",
|
||||
"-device", ",netdev=user.0",
|
||||
},
|
||||
"Test that interpolation overrides work.",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
VMName: "myvm",
|
||||
QemuArgs: [][]string{{"-display", "partydisplay"}},
|
||||
},
|
||||
[]string{
|
||||
"-display", "partydisplay",
|
||||
"-drive", "file=/path/to/test.iso,media=cdrom",
|
||||
"-device", ",netdev=user.0",
|
||||
},
|
||||
"User input overrides default, rest is populated as normal",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
VMName: "myvm",
|
||||
NetDevice: "mynetdevice",
|
||||
QemuArgs: [][]string{{"-device", "somerandomdevice"}},
|
||||
},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-device", "somerandomdevice",
|
||||
"-device", "mynetdevice,netdev=user.0",
|
||||
"-drive", "file=/path/to/test.iso,media=cdrom",
|
||||
},
|
||||
"Net device gets added",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
state := runTestState(t, tc.Config)
|
||||
|
||||
step := &stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packersdk.TestUi(t),
|
||||
}
|
||||
args, err := step.getCommandArgs(tc.Config, state)
|
||||
if err != nil {
|
||||
t.Fatalf("should not have an error getting args. Error: %s", err)
|
||||
}
|
||||
|
||||
expected := append([]string{
|
||||
"-m", "0M",
|
||||
"-boot", "once=d",
|
||||
"-fda", "fake_floppy_path",
|
||||
"-name", "myvm",
|
||||
"-netdev", "user,id=user.0,hostfwd=tcp::5000-:0",
|
||||
"-vnc", ":5",
|
||||
"-machine", "type=,accel="},
|
||||
tc.Expected...)
|
||||
|
||||
assert.ElementsMatch(t, args, expected,
|
||||
fmt.Sprintf("%s, \nRecieved: %#v", tc.Reason, args))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_DriveAndDeviceArgs(t *testing.T) {
|
||||
type testCase struct {
|
||||
Config *Config
|
||||
ExtraState map[string]interface{}
|
||||
Step *stepRun
|
||||
Expected []string
|
||||
Reason string
|
||||
}
|
||||
|
||||
testcases := []testCase{
|
||||
{
|
||||
&Config{},
|
||||
map[string]interface{}{},
|
||||
&stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packersdk.TestUi(t),
|
||||
},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "once=d",
|
||||
"-drive", "file=/path/to/test.iso,media=cdrom",
|
||||
},
|
||||
"Boot value should default to once=d when diskImage isn't set",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
DiskImage: true,
|
||||
DiskInterface: "virtio-scsi",
|
||||
|
||||
OutputDir: "path_to_output",
|
||||
DiskCache: "writeback",
|
||||
Format: "qcow2",
|
||||
DetectZeroes: "off",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"cd_path": "fake_cd_path.iso",
|
||||
"qemu_disk_paths": []string{"path_to_output"},
|
||||
},
|
||||
&stepRun{
|
||||
DiskImage: true,
|
||||
atLeastVersion2: true,
|
||||
ui: packersdk.TestUi(t),
|
||||
},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "c",
|
||||
"-device", "virtio-scsi-pci,id=scsi0",
|
||||
"-device", "scsi-hd,bus=scsi0.0,drive=drive0",
|
||||
"-drive", "if=none,file=path_to_output,id=drive0,cache=writeback,discard=,format=qcow2",
|
||||
"-drive", "file=fake_cd_path.iso,media=cdrom",
|
||||
},
|
||||
"virtio-scsi interface, DiskImage true, extra cdrom, detectZeroes off",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
DiskImage: true,
|
||||
DiskInterface: "virtio-scsi",
|
||||
|
||||
OutputDir: "path_to_output",
|
||||
DiskCache: "writeback",
|
||||
Format: "qcow2",
|
||||
DetectZeroes: "on",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"cd_path": "fake_cd_path.iso",
|
||||
"qemu_disk_paths": []string{"path_to_output"},
|
||||
},
|
||||
&stepRun{
|
||||
DiskImage: true,
|
||||
atLeastVersion2: true,
|
||||
ui: packersdk.TestUi(t),
|
||||
},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "c",
|
||||
"-device", "virtio-scsi-pci,id=scsi0",
|
||||
"-device", "scsi-hd,bus=scsi0.0,drive=drive0",
|
||||
"-drive", "if=none,file=path_to_output,id=drive0,cache=writeback,discard=,format=qcow2,detect-zeroes=on",
|
||||
"-drive", "file=fake_cd_path.iso,media=cdrom",
|
||||
},
|
||||
"virtio-scsi interface, DiskImage true, extra cdrom, detectZeroes on",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
DiskInterface: "virtio-scsi",
|
||||
|
||||
OutputDir: "path_to_output",
|
||||
DiskCache: "writeback",
|
||||
Format: "qcow2",
|
||||
DetectZeroes: "off",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"cd_path": "fake_cd_path.iso",
|
||||
// when disk image is false, we will always have at least one
|
||||
// disk path: the one we create to be the main disk.
|
||||
"qemu_disk_paths": []string{"qemupath1", "qemupath2"},
|
||||
},
|
||||
&stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packersdk.TestUi(t),
|
||||
},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "once=d",
|
||||
"-device", "virtio-scsi-pci,id=scsi0",
|
||||
"-device", "scsi-hd,bus=scsi0.0,drive=drive0",
|
||||
"-device", "scsi-hd,bus=scsi0.0,drive=drive1",
|
||||
"-drive", "if=none,file=qemupath1,id=drive0,cache=writeback,discard=,format=qcow2",
|
||||
"-drive", "if=none,file=qemupath2,id=drive1,cache=writeback,discard=,format=qcow2",
|
||||
"-drive", "file=/path/to/test.iso,media=cdrom",
|
||||
"-drive", "file=fake_cd_path.iso,media=cdrom",
|
||||
},
|
||||
"virtio-scsi interface, bootable iso, cdrom",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
DiskInterface: "virtio-scsi",
|
||||
|
||||
OutputDir: "path_to_output",
|
||||
DiskCache: "writeback",
|
||||
Format: "qcow2",
|
||||
DetectZeroes: "on",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"cd_path": "fake_cd_path.iso",
|
||||
// when disk image is false, we will always have at least one
|
||||
// disk path: the one we create to be the main disk.
|
||||
"qemu_disk_paths": []string{"qemupath1", "qemupath2"},
|
||||
},
|
||||
&stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packersdk.TestUi(t),
|
||||
},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "once=d",
|
||||
"-device", "virtio-scsi-pci,id=scsi0",
|
||||
"-device", "scsi-hd,bus=scsi0.0,drive=drive0",
|
||||
"-device", "scsi-hd,bus=scsi0.0,drive=drive1",
|
||||
"-drive", "if=none,file=qemupath1,id=drive0,cache=writeback,discard=,format=qcow2,detect-zeroes=on",
|
||||
"-drive", "if=none,file=qemupath2,id=drive1,cache=writeback,discard=,format=qcow2,detect-zeroes=on",
|
||||
"-drive", "file=/path/to/test.iso,media=cdrom",
|
||||
"-drive", "file=fake_cd_path.iso,media=cdrom",
|
||||
},
|
||||
"virtio-scsi interface, DiskImage false, extra cdrom, detect zeroes on",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
DiskInterface: "virtio-scsi",
|
||||
|
||||
OutputDir: "path_to_output",
|
||||
DiskCache: "writeback",
|
||||
Format: "qcow2",
|
||||
},
|
||||
map[string]interface{}{
|
||||
// when disk image is false, we will always have at least one
|
||||
// disk path: the one we create to be the main disk.
|
||||
"qemu_disk_paths": []string{"output/dir/path/mydisk.qcow2"},
|
||||
},
|
||||
&stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packersdk.TestUi(t),
|
||||
},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "once=d",
|
||||
"-device", "virtio-scsi-pci,id=scsi0",
|
||||
"-device", "scsi-hd,bus=scsi0.0,drive=drive0",
|
||||
"-drive", "if=none,file=output/dir/path/mydisk.qcow2,id=drive0,cache=writeback,discard=,format=qcow2,detect-zeroes=",
|
||||
"-drive", "file=/path/to/test.iso,media=cdrom",
|
||||
},
|
||||
"virtio-scsi interface, DiskImage false, no extra disks or cds",
|
||||
},
|
||||
{
|
||||
&Config{},
|
||||
map[string]interface{}{
|
||||
"cd_path": "fake_cd_path.iso",
|
||||
"qemu_disk_paths": []string{"output/dir/path/mydisk.qcow2"},
|
||||
},
|
||||
&stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packersdk.TestUi(t),
|
||||
},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "once=d",
|
||||
"-drive", "file=output/dir/path/mydisk.qcow2,if=,cache=,discard=,format=,detect-zeroes=",
|
||||
"-drive", "file=/path/to/test.iso,media=cdrom",
|
||||
"-drive", "file=fake_cd_path.iso,media=cdrom",
|
||||
},
|
||||
"cd_path is set and DiskImage is false",
|
||||
},
|
||||
{
|
||||
&Config{},
|
||||
map[string]interface{}{
|
||||
// when disk image is false, we will always have at least one
|
||||
// disk path: the one we create to be the main disk.
|
||||
"qemu_disk_paths": []string{"output/dir/path/mydisk.qcow2"},
|
||||
},
|
||||
&stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packersdk.TestUi(t),
|
||||
},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "once=d",
|
||||
"-drive", "file=output/dir/path/mydisk.qcow2,if=,cache=,discard=,format=,detect-zeroes=",
|
||||
"-drive", "file=/path/to/test.iso,media=cdrom",
|
||||
},
|
||||
"empty config",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
OutputDir: "path_to_output",
|
||||
DiskInterface: "virtio",
|
||||
DiskCache: "writeback",
|
||||
Format: "qcow2",
|
||||
},
|
||||
map[string]interface{}{
|
||||
// when disk image is false, we will always have at least one
|
||||
// disk path: the one we create to be the main disk.
|
||||
"qemu_disk_paths": []string{"output/dir/path/mydisk.qcow2"},
|
||||
},
|
||||
&stepRun{
|
||||
atLeastVersion2: false,
|
||||
ui: packersdk.TestUi(t),
|
||||
},
|
||||
[]string{
|
||||
"-boot", "once=d",
|
||||
"-drive", "file=path_to_output,if=virtio,cache=writeback,format=qcow2",
|
||||
"-drive", "file=/path/to/test.iso,media=cdrom",
|
||||
},
|
||||
"version less than 2",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
OutputDir: "path_to_output",
|
||||
DiskInterface: "virtio",
|
||||
DiskCache: "writeback",
|
||||
Format: "qcow2",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"cd_path": "fake_cd_path.iso",
|
||||
"qemu_disk_paths": []string{"qemupath1", "qemupath2"},
|
||||
},
|
||||
&stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packersdk.TestUi(t),
|
||||
},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "once=d",
|
||||
"-drive", "file=qemupath1,if=virtio,cache=writeback,discard=,format=qcow2,detect-zeroes=",
|
||||
"-drive", "file=qemupath2,if=virtio,cache=writeback,discard=,format=qcow2,detect-zeroes=",
|
||||
"-drive", "file=fake_cd_path.iso,media=cdrom",
|
||||
"-drive", "file=/path/to/test.iso,media=cdrom",
|
||||
},
|
||||
"virtio interface with extra disks",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
DiskImage: true,
|
||||
OutputDir: "path_to_output",
|
||||
DiskInterface: "virtio",
|
||||
DiskCache: "writeback",
|
||||
Format: "qcow2",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"cd_path": "fake_cd_path.iso",
|
||||
"qemu_disk_paths": []string{"path_to_output"},
|
||||
},
|
||||
&stepRun{
|
||||
DiskImage: true,
|
||||
atLeastVersion2: true,
|
||||
ui: packersdk.TestUi(t),
|
||||
},
|
||||
[]string{
|
||||
"-display", "gtk",
|
||||
"-boot", "c",
|
||||
"-drive", "file=path_to_output,if=virtio,cache=writeback,discard=,format=qcow2,detect-zeroes=",
|
||||
"-drive", "file=fake_cd_path.iso,media=cdrom",
|
||||
},
|
||||
"virtio interface with disk image",
|
||||
},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
state := runTestState(t, &Config{})
|
||||
for k, v := range tc.ExtraState {
|
||||
state.Put(k, v)
|
||||
}
|
||||
|
||||
args, err := tc.Step.getCommandArgs(tc.Config, state)
|
||||
if err != nil {
|
||||
t.Fatalf("should not have an error getting args. Error: %s", err)
|
||||
}
|
||||
|
||||
expected := append([]string{
|
||||
"-m", "0M",
|
||||
"-fda", "fake_floppy_path",
|
||||
"-name", "",
|
||||
"-netdev", "user,id=user.0,hostfwd=tcp::5000-:0",
|
||||
"-vnc", ":5",
|
||||
"-machine", "type=,accel=",
|
||||
"-device", ",netdev=user.0"},
|
||||
tc.Expected...)
|
||||
|
||||
assert.ElementsMatch(t, args, expected,
|
||||
fmt.Sprintf("%s, \nRecieved: %#v", tc.Reason, args))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_OptionalConfigOptionsGetSet(t *testing.T) {
|
||||
c := &Config{
|
||||
VNCUsePassword: true,
|
||||
QMPEnable: true,
|
||||
QMPSocketPath: "qmp_path",
|
||||
VMName: "MyFancyName",
|
||||
MachineType: "pc",
|
||||
Accelerator: "hvf",
|
||||
}
|
||||
|
||||
state := runTestState(t, c)
|
||||
step := &stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packersdk.TestUi(t),
|
||||
}
|
||||
args, err := step.getCommandArgs(c, state)
|
||||
if err != nil {
|
||||
t.Fatalf("should not have an error getting args. Error: %s", err)
|
||||
}
|
||||
|
||||
expected := []string{
|
||||
"-display", "gtk",
|
||||
"-m", "0M",
|
||||
"-boot", "once=d",
|
||||
"-fda", "fake_floppy_path",
|
||||
"-name", "MyFancyName",
|
||||
"-netdev", "user,id=user.0,hostfwd=tcp::5000-:0",
|
||||
"-vnc", ":5,password",
|
||||
"-machine", "type=pc,accel=hvf",
|
||||
"-device", ",netdev=user.0",
|
||||
"-drive", "file=/path/to/test.iso,media=cdrom",
|
||||
"-qmp", "unix:qmp_path,server,nowait",
|
||||
}
|
||||
|
||||
assert.ElementsMatch(t, args, expected, "password flag should be set, and d drive should be set: %s", args)
|
||||
}
|
||||
|
||||
// Tests for presence of Packer-generated arguments. Doesn't test that
|
||||
// arguments which shouldn't be there are absent.
|
||||
func Test_Defaults(t *testing.T) {
|
||||
type testCase struct {
|
||||
Config *Config
|
||||
ExtraState map[string]interface{}
|
||||
Step *stepRun
|
||||
Expected []string
|
||||
Reason string
|
||||
}
|
||||
|
||||
testcases := []testCase{
|
||||
{
|
||||
&Config{},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packersdk.TestUi(t)},
|
||||
[]string{"-boot", "once=d"},
|
||||
"Boot value should default to once=d",
|
||||
},
|
||||
{
|
||||
&Config{},
|
||||
map[string]interface{}{},
|
||||
&stepRun{
|
||||
DiskImage: true,
|
||||
ui: packersdk.TestUi(t),
|
||||
},
|
||||
[]string{"-boot", "c"},
|
||||
"Boot value should be set to c when DiskImage is set on step",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
QMPEnable: true,
|
||||
QMPSocketPath: "/path/to/socket",
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packersdk.TestUi(t)},
|
||||
[]string{"-qmp", "unix:/path/to/socket,server,nowait"},
|
||||
"Args should contain -qmp when qmp_enable is set",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
QMPEnable: true,
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packersdk.TestUi(t)},
|
||||
[]string{"-qmp", "unix:,server,nowait"},
|
||||
"Args contain -qmp even when socket path isn't set, if qmp enabled",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
VMName: "partyname",
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packersdk.TestUi(t)},
|
||||
[]string{"-name", "partyname"},
|
||||
"Name is set from config",
|
||||
},
|
||||
{
|
||||
&Config{},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packersdk.TestUi(t)},
|
||||
[]string{"-name", ""},
|
||||
"Name is set from config, even when name is blank (which won't " +
|
||||
"happen for real thanks to defaulting in build prepare)",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
Accelerator: "none",
|
||||
MachineType: "fancymachine",
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packersdk.TestUi(t)},
|
||||
[]string{"-machine", "type=fancymachine"},
|
||||
"Don't add accelerator tag when no accelerator is set.",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
Accelerator: "kvm",
|
||||
MachineType: "fancymachine",
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packersdk.TestUi(t)},
|
||||
[]string{"-machine", "type=fancymachine,accel=kvm"},
|
||||
"Add accelerator tag when accelerator is set.",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
NetBridge: "fakebridge",
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packersdk.TestUi(t)},
|
||||
[]string{"-netdev", "bridge,id=user.0,br=fakebridge"},
|
||||
"Add netbridge tag when netbridge is set.",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
CommConfig: CommConfig{
|
||||
Comm: communicator.Config{
|
||||
Type: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packersdk.TestUi(t)},
|
||||
[]string{"-netdev", "user,id=user.0"},
|
||||
"No host forwarding when no net bridge and no communicator",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
CommConfig: CommConfig{
|
||||
Comm: communicator.Config{
|
||||
Type: "ssh",
|
||||
SSH: communicator.SSH{
|
||||
SSHPort: 4567,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"commHostPort": 1111,
|
||||
},
|
||||
&stepRun{ui: packersdk.TestUi(t)},
|
||||
[]string{"-netdev", "user,id=user.0,hostfwd=tcp::1111-:4567"},
|
||||
"Host forwarding when a communicator is configured",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
VNCBindAddress: "1.1.1.1",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"vnc_port": 5959,
|
||||
},
|
||||
&stepRun{ui: packersdk.TestUi(t)},
|
||||
[]string{"-vnc", "1.1.1.1:59"},
|
||||
"no VNC password should be set",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
VNCBindAddress: "1.1.1.1",
|
||||
VNCUsePassword: true,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"vnc_port": 5959,
|
||||
},
|
||||
&stepRun{ui: packersdk.TestUi(t)},
|
||||
[]string{"-vnc", "1.1.1.1:59,password"},
|
||||
"VNC password should be set",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
MemorySize: 2345,
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packersdk.TestUi(t)},
|
||||
[]string{"-m", "2345M"},
|
||||
"Memory is set, with unit M",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
CpuCount: 2,
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packersdk.TestUi(t)},
|
||||
[]string{"-smp", "cpus=2,sockets=2"},
|
||||
"both cpus and sockets are set to config's CpuCount",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
CpuCount: 2,
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{ui: packersdk.TestUi(t)},
|
||||
[]string{"-smp", "cpus=2,sockets=2"},
|
||||
"both cpus and sockets are set to config's CpuCount",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
CpuCount: 2,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"floppy_path": "/path/to/floppy",
|
||||
},
|
||||
&stepRun{ui: packersdk.TestUi(t)},
|
||||
[]string{"-fda", "/path/to/floppy"},
|
||||
"floppy path should be set under fda flag, when it exists",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
Headless: false,
|
||||
Display: "fakedisplay",
|
||||
UseDefaultDisplay: false,
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packersdk.TestUi(t),
|
||||
},
|
||||
[]string{"-display", "fakedisplay"},
|
||||
"Display option should value config display",
|
||||
},
|
||||
{
|
||||
&Config{
|
||||
Headless: false,
|
||||
},
|
||||
map[string]interface{}{},
|
||||
&stepRun{
|
||||
atLeastVersion2: true,
|
||||
ui: packersdk.TestUi(t),
|
||||
},
|
||||
[]string{"-display", "gtk"},
|
||||
"Display option should default to gtk",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
state := runTestState(t, &Config{})
|
||||
for k, v := range tc.ExtraState {
|
||||
state.Put(k, v)
|
||||
}
|
||||
|
||||
args, err := tc.Step.getCommandArgs(tc.Config, state)
|
||||
if err != nil {
|
||||
t.Fatalf("should not have an error getting args. Error: %s", err)
|
||||
}
|
||||
if !matchArgument(args, tc.Expected) {
|
||||
t.Fatalf("Couldn't find %#v in result. Got: %#v, Reason: %s",
|
||||
tc.Expected, args, tc.Reason)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This test makes sure that arguments don't end up in the final boot command
|
||||
// if they aren't configured in the config.
|
||||
// func TestDefaultsAbsentValues(t *testing.T) {}
|
||||
func matchArgument(actual []string, expected []string) bool {
|
||||
key := expected[0]
|
||||
for i, k := range actual {
|
||||
if key == k {
|
||||
if expected[1] == actual[i+1] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
package qemu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/communicator"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func Test_Shutdown_Null_success(t *testing.T) {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("ui", packersdk.TestUi(t))
|
||||
driverMock := new(DriverMock)
|
||||
driverMock.WaitForShutdownState = true
|
||||
state.Put("driver", driverMock)
|
||||
|
||||
step := &stepShutdown{
|
||||
ShutdownCommand: "",
|
||||
ShutdownTimeout: 5 * time.Minute,
|
||||
Comm: &communicator.Config{
|
||||
Type: "none",
|
||||
},
|
||||
}
|
||||
action := step.Run(context.TODO(), state)
|
||||
if action != multistep.ActionContinue {
|
||||
t.Fatalf("Should have successfully shut down.")
|
||||
}
|
||||
err := state.Get("error")
|
||||
if err != nil {
|
||||
err = err.(error)
|
||||
t.Fatalf("Shutdown shouldn't have errored; err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Shutdown_Null_failure(t *testing.T) {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("ui", packersdk.TestUi(t))
|
||||
driverMock := new(DriverMock)
|
||||
driverMock.WaitForShutdownState = false
|
||||
state.Put("driver", driverMock)
|
||||
|
||||
step := &stepShutdown{
|
||||
ShutdownCommand: "",
|
||||
ShutdownTimeout: 5 * time.Minute,
|
||||
Comm: &communicator.Config{
|
||||
Type: "none",
|
||||
},
|
||||
}
|
||||
action := step.Run(context.TODO(), state)
|
||||
if action != multistep.ActionHalt {
|
||||
t.Fatalf("Shouldn't have successfully shut down.")
|
||||
}
|
||||
err := state.Get("error")
|
||||
if err == nil {
|
||||
t.Fatalf("Shutdown should have errored")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Shutdown_NoShutdownCommand(t *testing.T) {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("ui", packersdk.TestUi(t))
|
||||
driverMock := new(DriverMock)
|
||||
state.Put("driver", driverMock)
|
||||
|
||||
step := &stepShutdown{
|
||||
ShutdownCommand: "",
|
||||
ShutdownTimeout: 5 * time.Minute,
|
||||
Comm: &communicator.Config{
|
||||
Type: "ssh",
|
||||
},
|
||||
}
|
||||
action := step.Run(context.TODO(), state)
|
||||
if action != multistep.ActionContinue {
|
||||
t.Fatalf("Should have successfully shut down.")
|
||||
}
|
||||
|
||||
if !driverMock.StopCalled {
|
||||
t.Fatalf("should have called Stop through the driver.")
|
||||
}
|
||||
err := state.Get("error")
|
||||
if err != nil {
|
||||
err = err.(error)
|
||||
t.Fatalf("Shutdown shouldn't have errored; err: %v", err)
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package qemu
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func testState(t *testing.T) multistep.StateBag {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("driver", new(DriverMock))
|
||||
state.Put("ui", &packersdk.BasicUi{
|
||||
Reader: new(bytes.Buffer),
|
||||
Writer: new(bytes.Buffer),
|
||||
})
|
||||
return state
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package version
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/packer-plugin-sdk/version"
|
||||
packerVersion "github.com/hashicorp/packer/version"
|
||||
)
|
||||
|
||||
var QemuPluginVersion *version.PluginVersion
|
||||
|
||||
func init() {
|
||||
QemuPluginVersion = version.InitializePluginVersion(
|
||||
packerVersion.Version, packerVersion.VersionPrerelease)
|
||||
}
|
|
@ -44,7 +44,6 @@ import (
|
|||
proxmoxbuilder "github.com/hashicorp/packer/builder/proxmox"
|
||||
proxmoxclonebuilder "github.com/hashicorp/packer/builder/proxmox/clone"
|
||||
proxmoxisobuilder "github.com/hashicorp/packer/builder/proxmox/iso"
|
||||
qemubuilder "github.com/hashicorp/packer/builder/qemu"
|
||||
scalewaybuilder "github.com/hashicorp/packer/builder/scaleway"
|
||||
tencentcloudcvmbuilder "github.com/hashicorp/packer/builder/tencentcloud/cvm"
|
||||
tritonbuilder "github.com/hashicorp/packer/builder/triton"
|
||||
|
@ -117,7 +116,6 @@ var Builders = map[string]packersdk.Builder{
|
|||
"proxmox": new(proxmoxbuilder.Builder),
|
||||
"proxmox-clone": new(proxmoxclonebuilder.Builder),
|
||||
"proxmox-iso": new(proxmoxisobuilder.Builder),
|
||||
"qemu": new(qemubuilder.Builder),
|
||||
"scaleway": new(scalewaybuilder.Builder),
|
||||
"tencentcloud-cvm": new(tencentcloudcvmbuilder.Builder),
|
||||
"triton": new(tritonbuilder.Builder),
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
googlecomputebuilder "github.com/hashicorp/packer-plugin-googlecompute/builder/googlecompute"
|
||||
googlecomputeexportpostprocessor "github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-export"
|
||||
googlecomputeimportpostprocessor "github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-import"
|
||||
qemubuilder "github.com/hashicorp/packer-plugin-qemu/builder/qemu"
|
||||
virtualboxisobuilder "github.com/hashicorp/packer-plugin-virtualbox/builder/virtualbox/iso"
|
||||
virtualboxovfbuilder "github.com/hashicorp/packer-plugin-virtualbox/builder/virtualbox/ovf"
|
||||
virtualboxvmbuilder "github.com/hashicorp/packer-plugin-virtualbox/builder/virtualbox/vm"
|
||||
|
@ -53,6 +54,7 @@ var VendoredBuilders = map[string]packersdk.Builder{
|
|||
"amazon-instance": new(amazoninstancebuilder.Builder),
|
||||
"docker": new(dockerbuilder.Builder),
|
||||
"googlecompute": new(googlecomputebuilder.Builder),
|
||||
"qemu": new(qemubuilder.Builder),
|
||||
"vsphere-clone": new(vsphereclonebuilder.Builder),
|
||||
"vsphere-iso": new(vsphereisobuilder.Builder),
|
||||
"virtualbox-iso": new(virtualboxisobuilder.Builder),
|
||||
|
|
3
go.mod
3
go.mod
|
@ -22,7 +22,6 @@ require (
|
|||
github.com/cheggaaa/pb v1.0.27
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/digitalocean/go-qemu v0.0.0-20201211181942-d361e7b4965f
|
||||
github.com/digitalocean/godo v1.11.1
|
||||
github.com/dsnet/compress v0.0.1
|
||||
github.com/exoscale/packer-plugin-exoscale v0.1.1
|
||||
|
@ -50,6 +49,7 @@ require (
|
|||
github.com/hashicorp/packer-plugin-ansible v0.0.2
|
||||
github.com/hashicorp/packer-plugin-docker v0.0.7
|
||||
github.com/hashicorp/packer-plugin-googlecompute v0.0.1
|
||||
github.com/hashicorp/packer-plugin-qemu v0.0.1
|
||||
github.com/hashicorp/packer-plugin-sdk v0.2.0
|
||||
github.com/hashicorp/packer-plugin-virtualbox v0.0.1
|
||||
github.com/hashicorp/packer-plugin-vmware v0.0.1
|
||||
|
@ -64,7 +64,6 @@ require (
|
|||
github.com/mattn/go-tty v0.0.0-20191112051231-74040eebce08
|
||||
github.com/mitchellh/cli v1.1.0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed
|
||||
github.com/mitchellh/mapstructure v1.4.0
|
||||
github.com/mitchellh/panicwrap v1.0.0
|
||||
github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784
|
||||
|
|
9
go.sum
9
go.sum
|
@ -199,8 +199,9 @@ github.com/digitalocean/go-libvirt v0.0.0-20210108193637-3a8ae49ba8cd/go.mod h1:
|
|||
github.com/digitalocean/go-libvirt v0.0.0-20210112203132-25518eb2c840 h1:F3RVNV8SLLNhkNFcbDTgD3wAPMcrMJW6xjjI0JXy9z8=
|
||||
github.com/digitalocean/go-libvirt v0.0.0-20210112203132-25518eb2c840/go.mod h1:gtar3MgGsIO64GgphCHw1cbyxSI6qEuTIm9+izMmlfk=
|
||||
github.com/digitalocean/go-qemu v0.0.0-20181112162955-dd7bb9c771b8/go.mod h1:/YnlngP1PARC0SKAZx6kaAEMOp8bNTQGqS+Ka3MctNI=
|
||||
github.com/digitalocean/go-qemu v0.0.0-20201211181942-d361e7b4965f h1:BYkBJhHxUJJn27mhqfqWycWaEOWv9JQqLgQ2pOFJMqE=
|
||||
github.com/digitalocean/go-qemu v0.0.0-20201211181942-d361e7b4965f/go.mod h1:y4Eq3ZfZQFWQwVyW0qvgo5seXUIq2C7BlHsdE+xtXL4=
|
||||
github.com/digitalocean/go-qemu v0.0.0-20210326154740-ac9e0b687001 h1:WAg57gnaAWWjMAELcwHjc2xy0PoXQ5G+vn3+XS6s1jI=
|
||||
github.com/digitalocean/go-qemu v0.0.0-20210326154740-ac9e0b687001/go.mod h1:IetBE52JfFxK46p2n2Rqm+p5Gx1gpu2hRHsrbnPOWZQ=
|
||||
github.com/digitalocean/godo v1.11.1 h1:OsTh37YFKk+g6DnAOrkXJ9oDArTkRx5UTkBJ2EWAO38=
|
||||
github.com/digitalocean/godo v1.11.1/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU=
|
||||
github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4=
|
||||
|
@ -461,6 +462,10 @@ github.com/hashicorp/packer-plugin-docker v0.0.7 h1:hMTrH7vrkFIjphtbbtpuzffTzSjM
|
|||
github.com/hashicorp/packer-plugin-docker v0.0.7/go.mod h1:IpeKlwOSy2kdgQcysqd3gCsoqjME9jtmpFoKxn7RRNI=
|
||||
github.com/hashicorp/packer-plugin-googlecompute v0.0.1 h1:Shjio88MraB+ocj0VI5+M65r4UBKbYI4eCqLNyPXKEo=
|
||||
github.com/hashicorp/packer-plugin-googlecompute v0.0.1/go.mod h1:MfV898IrEMpKH6wVnvOI5Tkhxm2snf3QxwVqV4k3bNI=
|
||||
github.com/hashicorp/packer-plugin-qemu v0.0.0-20210419131938-9ec808d0c364 h1:9vTNg4xYdp+PzBFSi+G2Nfc8qw7X1ebrBFKt4wmvARk=
|
||||
github.com/hashicorp/packer-plugin-qemu v0.0.0-20210419131938-9ec808d0c364/go.mod h1:8Q/LCjO7oplLcLe1KLdEt7rq94h42Di6Lab2DTLNwVg=
|
||||
github.com/hashicorp/packer-plugin-qemu v0.0.1 h1:yGnmWf4Z+ZmOJXJF6w23V2KChtTCiPHsFnfg7+LRu74=
|
||||
github.com/hashicorp/packer-plugin-qemu v0.0.1/go.mod h1:8Q/LCjO7oplLcLe1KLdEt7rq94h42Di6Lab2DTLNwVg=
|
||||
github.com/hashicorp/packer-plugin-sdk v0.0.6/go.mod h1:Nvh28f+Jmpp2rcaN79bULTouNkGNDRfHckhHKTAXtyU=
|
||||
github.com/hashicorp/packer-plugin-sdk v0.0.7-0.20210111224258-fd30ebb797f0/go.mod h1:YdWTt5w6cYfaQG7IOi5iorL+3SXnz8hI0gJCi8Db/LI=
|
||||
github.com/hashicorp/packer-plugin-sdk v0.0.7-0.20210120105339-f6fd68d2570a/go.mod h1:exN0C+Pe+3zu18l4nxueNjX5cfmslxUX/m/xk4IVmZQ=
|
||||
|
@ -478,8 +483,6 @@ github.com/hashicorp/packer-plugin-sdk v0.2.0 h1:A4Dq7p4y1vscY4gMzp7GQaXyDJYYhP4
|
|||
github.com/hashicorp/packer-plugin-sdk v0.2.0/go.mod h1:0DiOMEBldmB0HEhp0npFSSygC8bIvW43pphEgWkp2WU=
|
||||
github.com/hashicorp/packer-plugin-virtualbox v0.0.1 h1:vTfy7a10RUVMdNnDLo0EQrCVbAG4rGWkaDTMC7MVBi4=
|
||||
github.com/hashicorp/packer-plugin-virtualbox v0.0.1/go.mod h1:OOGNMK8Y8zjsYngesZH5kCbH0Fj8PKvhqPp8w1ejM3Y=
|
||||
github.com/hashicorp/packer-plugin-vmware v0.0.0-20210416150724-592c0637562a h1:LpZ+8Y1vozsI4vuAjUpUOEzFl+jNSY4SL1kfGkVMmb8=
|
||||
github.com/hashicorp/packer-plugin-vmware v0.0.0-20210416150724-592c0637562a/go.mod h1:NsiT4IOeDKf/aszQNX+/B1xHrfBR3RdUM3sSqANgNec=
|
||||
github.com/hashicorp/packer-plugin-vmware v0.0.1 h1:jRQAdjHwg3zeCBb52KoZsuxugrHcQhjgQln72o9eGgM=
|
||||
github.com/hashicorp/packer-plugin-vmware v0.0.1/go.mod h1:NsiT4IOeDKf/aszQNX+/B1xHrfBR3RdUM3sSqANgNec=
|
||||
github.com/hashicorp/packer-plugin-vsphere v0.0.1 h1:4SUmRP+mGpBJHp6dLL4dmBCC+yDseTktb9YNLj11mVI=
|
||||
|
|
|
@ -18,8 +18,10 @@ import (
|
|||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
@ -34,6 +36,9 @@ type SocketMonitor struct {
|
|||
// QEMU version reported by a connected monitor socket.
|
||||
Version *Version
|
||||
|
||||
// QEMU QMP capabiltiies reported by a connected monitor socket.
|
||||
Capabilities []string
|
||||
|
||||
// Underlying connection
|
||||
c net.Conn
|
||||
|
||||
|
@ -119,6 +124,7 @@ func (mon *SocketMonitor) Connect() error {
|
|||
return err
|
||||
}
|
||||
mon.Version = &ban.QMP.Version
|
||||
mon.Capabilities = ban.QMP.Capabilities
|
||||
|
||||
// Issue capabilities handshake
|
||||
cmd := Command{Execute: qmpCapabilities}
|
||||
|
@ -194,14 +200,46 @@ func (mon *SocketMonitor) listen(r io.Reader, events chan<- Event, stream chan<-
|
|||
// For a list of available QAPI commands, see:
|
||||
// http://git.qemu.org/?p=qemu.git;a=blob;f=qapi-schema.json;hb=HEAD
|
||||
func (mon *SocketMonitor) Run(command []byte) ([]byte, error) {
|
||||
// Just call RunWithFile with no file
|
||||
return mon.RunWithFile(command, nil)
|
||||
}
|
||||
|
||||
// RunWithFile behaves like Run but allows for passing a file through out-of-band data.
|
||||
func (mon *SocketMonitor) RunWithFile(command []byte, file *os.File) ([]byte, error) {
|
||||
// Only allow a single command to be run at a time to ensure that responses
|
||||
// to a command cannot be mixed with responses from another command
|
||||
mon.mu.Lock()
|
||||
defer mon.mu.Unlock()
|
||||
|
||||
if file == nil {
|
||||
// Just send a normal command through.
|
||||
if _, err := mon.c.Write(command); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
unixConn, ok := mon.c.(*net.UnixConn)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("RunWithFile only works with unix monitor sockets")
|
||||
}
|
||||
|
||||
oobSupported := false
|
||||
for _, capability := range mon.Capabilities {
|
||||
if capability == "oob" {
|
||||
oobSupported = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !oobSupported {
|
||||
return nil, fmt.Errorf("The QEMU server doesn't support oob (needed for RunWithFile)")
|
||||
}
|
||||
|
||||
// Send the command along with the file descriptor.
|
||||
oob := getUnixRights(file)
|
||||
if _, _, err := unixConn.WriteMsgUnix(command, oob, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for a response or error to our command
|
||||
res := <-mon.stream
|
||||
|
@ -224,6 +262,7 @@ func (mon *SocketMonitor) Run(command []byte) ([]byte, error) {
|
|||
// banner is a wrapper type around a Version.
|
||||
type banner struct {
|
||||
QMP struct {
|
||||
Capabilities []string `json:"capabilities"`
|
||||
Version Version `json:"version"`
|
||||
} `json:"QMP"`
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2016 The go-qemu Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !windows
|
||||
|
||||
package qmp
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func getUnixRights(file *os.File) []byte {
|
||||
return unix.UnixRights(int(file.Fd()))
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2016 The go-qemu Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build windows
|
||||
|
||||
package qmp
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func getUnixRights(file *os.File) []byte {
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,373 @@
|
|||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
|
@ -281,8 +281,7 @@ github.com/digitalocean/go-libvirt
|
|||
github.com/digitalocean/go-libvirt/internal/constants
|
||||
github.com/digitalocean/go-libvirt/internal/event
|
||||
github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2
|
||||
# github.com/digitalocean/go-qemu v0.0.0-20201211181942-d361e7b4965f
|
||||
## explicit
|
||||
# github.com/digitalocean/go-qemu v0.0.0-20210326154740-ac9e0b687001
|
||||
github.com/digitalocean/go-qemu/qmp
|
||||
# github.com/digitalocean/godo v1.11.1
|
||||
## explicit
|
||||
|
@ -524,6 +523,9 @@ github.com/hashicorp/packer-plugin-googlecompute/builder/googlecompute
|
|||
github.com/hashicorp/packer-plugin-googlecompute/builder/googlecompute/version
|
||||
github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-export
|
||||
github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-import
|
||||
# github.com/hashicorp/packer-plugin-qemu v0.0.1
|
||||
## explicit
|
||||
github.com/hashicorp/packer-plugin-qemu/builder/qemu
|
||||
# github.com/hashicorp/packer-plugin-sdk v0.2.0
|
||||
## explicit
|
||||
github.com/hashicorp/packer-plugin-sdk/acctest
|
||||
|
@ -681,7 +683,6 @@ github.com/mitchellh/go-homedir
|
|||
# github.com/mitchellh/go-testing-interface v1.0.3
|
||||
github.com/mitchellh/go-testing-interface
|
||||
# github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed
|
||||
## explicit
|
||||
github.com/mitchellh/go-vnc
|
||||
# github.com/mitchellh/go-wordwrap v1.0.0
|
||||
github.com/mitchellh/go-wordwrap
|
||||
|
|
|
@ -1,219 +0,0 @@
|
|||
---
|
||||
modeline: |
|
||||
vim: set ft=pandoc:
|
||||
description: |
|
||||
The Qemu Packer builder is able to create KVM virtual machine images.
|
||||
page_title: QEMU - Builders
|
||||
---
|
||||
|
||||
# QEMU Builder
|
||||
|
||||
Type: `qemu`
|
||||
Artifact BuilderId: `transcend.qemu`
|
||||
|
||||
The Qemu Packer builder is able to create [KVM](http://www.linux-kvm.org) virtual
|
||||
machine images.
|
||||
|
||||
The builder builds a virtual machine by creating a new virtual machine from
|
||||
scratch, booting it, installing an OS, rebooting the machine with the boot media
|
||||
as the virtual hard drive, provisioning software within the OS, then shutting it
|
||||
down. The result of the Qemu builder is a directory containing the image file
|
||||
necessary to run the virtual machine on KVM.
|
||||
|
||||
## Basic Example
|
||||
|
||||
Here is a basic example. This example is functional so long as you fixup paths
|
||||
to files, URLS for ISOs and checksums.
|
||||
|
||||
<Tabs>
|
||||
<Tab heading="JSON">
|
||||
|
||||
```json
|
||||
{
|
||||
"builders": [
|
||||
{
|
||||
"type": "qemu",
|
||||
"iso_url": "http://mirror.raystedman.net/centos/6/isos/x86_64/CentOS-6.9-x86_64-minimal.iso",
|
||||
"iso_checksum": "md5:af4a1640c0c6f348c6c41f1ea9e192a2",
|
||||
"output_directory": "output_centos_tdhtest",
|
||||
"shutdown_command": "echo 'packer' | sudo -S shutdown -P now",
|
||||
"disk_size": "5000M",
|
||||
"format": "qcow2",
|
||||
"accelerator": "kvm",
|
||||
"http_directory": "path/to/httpdir",
|
||||
"ssh_username": "root",
|
||||
"ssh_password": "s0m3password",
|
||||
"ssh_timeout": "20m",
|
||||
"vm_name": "tdhtest",
|
||||
"net_device": "virtio-net",
|
||||
"disk_interface": "virtio",
|
||||
"boot_wait": "10s",
|
||||
"boot_command": [
|
||||
"<tab> text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/centos6-ks.cfg<enter><wait>"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab heading="HCL2">
|
||||
|
||||
```hcl
|
||||
source "qemu" "example" {
|
||||
iso_url = "http://mirror.raystedman.net/centos/6/isos/x86_64/CentOS-6.9-x86_64-minimal.iso"
|
||||
iso_checksum = "md5:af4a1640c0c6f348c6c41f1ea9e192a2"
|
||||
output_directory = "output_centos_tdhtest"
|
||||
shutdown_command = "echo 'packer' | sudo -S shutdown -P now"
|
||||
disk_size = "5000M"
|
||||
format = "qcow2"
|
||||
accelerator = "kvm"
|
||||
http_directory = "path/to/httpdir"
|
||||
ssh_username = "root"
|
||||
ssh_password = "s0m3password"
|
||||
ssh_timeout = "20m"
|
||||
vm_name = "tdhtest"
|
||||
net_device = "virtio-net"
|
||||
disk_interface = "virtio"
|
||||
boot_wait = "10s"
|
||||
boot_command = ["<tab> text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/centos6-ks.cfg<enter><wait>"]
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.qemu.example"]
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
This is an example only, and will time out waiting for SSH because we have not
|
||||
provided a kickstart file. You must add a valid kickstart file to the
|
||||
"http_directory" and then provide the file in the "boot_command" in order for
|
||||
this build to run. We recommend you check out the
|
||||
[Community Templates](/community-tools#templates)
|
||||
for a practical usage example.
|
||||
|
||||
Note that you will need to set `"headless": true` if you are running Packer
|
||||
on a Linux server without X11; or if you are connected via SSH to a remote
|
||||
Linux server and have not enabled X11 forwarding (`ssh -X`).
|
||||
|
||||
## Qemu Specific Configuration Reference
|
||||
|
||||
There are many configuration options available for the builder. In addition to
|
||||
the items listed here, you will want to look at the general configuration
|
||||
references for [ISO](#iso-configuration),
|
||||
[HTTP](#http-directory-configuration),
|
||||
[Floppy](#floppy-configuration),
|
||||
[Boot](#boot-configuration),
|
||||
[Shutdown](#shutdown-configuration),
|
||||
[Communicator](#communicator-configuration)
|
||||
configuration references, which are
|
||||
necessary for this build to succeed and can be found further down the page.
|
||||
|
||||
### Optional:
|
||||
|
||||
@include 'builder/qemu/Config-not-required.mdx'
|
||||
|
||||
## ISO Configuration
|
||||
|
||||
@include 'packer-plugin-sdk/multistep/commonsteps/ISOConfig.mdx'
|
||||
|
||||
### Required:
|
||||
|
||||
@include 'packer-plugin-sdk/multistep/commonsteps/ISOConfig-required.mdx'
|
||||
|
||||
### Optional:
|
||||
|
||||
@include 'packer-plugin-sdk/multistep/commonsteps/ISOConfig-not-required.mdx'
|
||||
|
||||
## Http directory configuration
|
||||
|
||||
@include 'packer-plugin-sdk/multistep/commonsteps/HTTPConfig.mdx'
|
||||
|
||||
### Optional:
|
||||
|
||||
@include 'packer-plugin-sdk/multistep/commonsteps/HTTPConfig-not-required.mdx'
|
||||
|
||||
## Floppy configuration
|
||||
|
||||
@include 'packer-plugin-sdk/multistep/commonsteps/FloppyConfig.mdx'
|
||||
|
||||
### Optional:
|
||||
|
||||
@include 'packer-plugin-sdk/multistep/commonsteps/FloppyConfig-not-required.mdx'
|
||||
|
||||
### CD configuration
|
||||
|
||||
@include 'packer-plugin-sdk/multistep/commonsteps/CDConfig.mdx'
|
||||
|
||||
#### Optional:
|
||||
|
||||
@include 'packer-plugin-sdk/multistep/commonsteps/CDConfig-not-required.mdx'
|
||||
|
||||
## Shutdown configuration
|
||||
|
||||
### Optional:
|
||||
|
||||
@include 'packer-plugin-sdk/shutdowncommand/ShutdownConfig-not-required.mdx'
|
||||
|
||||
## Communicator configuration
|
||||
|
||||
### Optional common fields:
|
||||
|
||||
@include 'packer-plugin-sdk/communicator/Config-not-required.mdx'
|
||||
|
||||
@include 'builder/qemu/CommConfig-not-required.mdx'
|
||||
|
||||
### Optional SSH fields:
|
||||
|
||||
@include 'packer-plugin-sdk/communicator/SSH-not-required.mdx'
|
||||
|
||||
@include 'packer-plugin-sdk/communicator/SSH-Private-Key-File-not-required.mdx'
|
||||
|
||||
### Optional WinRM fields:
|
||||
|
||||
@include 'packer-plugin-sdk/communicator/WinRM-not-required.mdx'
|
||||
|
||||
## Boot Configuration
|
||||
|
||||
@include 'packer-plugin-sdk/bootcommand/VNCConfig.mdx'
|
||||
|
||||
@include 'packer-plugin-sdk/bootcommand/BootConfig.mdx'
|
||||
|
||||
### Optional:
|
||||
|
||||
@include 'packer-plugin-sdk/bootcommand/VNCConfig-not-required.mdx'
|
||||
|
||||
@include 'packer-plugin-sdk/bootcommand/BootConfig-not-required.mdx'
|
||||
|
||||
### Communicator Configuration
|
||||
|
||||
#### Optional:
|
||||
|
||||
@include 'packer-plugin-sdk/communicator/Config-not-required.mdx'
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
#### Invalid Keymaps
|
||||
|
||||
Some users have experienced errors complaining about invalid keymaps. This
|
||||
seems to be related to having a `common` directory or file in the directory
|
||||
they've run Packer in, like the Packer source directory. This appears to be an
|
||||
upstream bug with qemu, and the best solution for now is to remove the
|
||||
file/directory or run in another directory.
|
||||
|
||||
Some users have reported issues with incorrect keymaps using qemu version 2.11.
|
||||
This is a bug with qemu, and the solution is to upgrade, or downgrade to 2.10.1
|
||||
or earlier.
|
||||
|
||||
#### Corrupted image after Packer calls qemu-img convert on OSX
|
||||
|
||||
Due to an upstream bug with `qemu-img convert` on OSX, sometimes the qemu-img
|
||||
convert call will create a corrupted image. If this is an issue for you, make
|
||||
sure that the the output format (provided using the option `format`) matches
|
||||
the input file's format and file extension, and Packer will
|
||||
perform a simple copy operation instead. You will also want to set
|
||||
`"skip_compaction": true,` and `"disk_compression": false` to skip a final
|
||||
image conversion at the end of the build. See
|
||||
https://bugs.launchpad.net/qemu/+bug/1776920 for more details.
|
|
@ -1,15 +0,0 @@
|
|||
<!-- Code generated from the comments of the CommConfig struct in builder/qemu/comm_config.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `host_port_min` (int) - The minimum port to use for the Communicator port on the host machine which is forwarded
|
||||
to the SSH or WinRM port on the guest machine. By default this is 2222.
|
||||
|
||||
- `host_port_max` (int) - The maximum port to use for the Communicator port on the host machine which is forwarded
|
||||
to the SSH or WinRM port on the guest machine. Because Packer often runs in parallel,
|
||||
Packer will choose a randomly available port in this range to use as the
|
||||
host port. By default this is 4444.
|
||||
|
||||
- `skip_nat_mapping` (bool) - Defaults to false. When enabled, Packer
|
||||
does not setup forwarded port mapping for communicator (SSH or WinRM) requests and uses ssh_port or winrm_port
|
||||
on the host to communicate to the virtual machine.
|
||||
|
||||
<!-- End of code generated from the comments of the CommConfig struct in builder/qemu/comm_config.go; -->
|
|
@ -1,325 +0,0 @@
|
|||
<!-- Code generated from the comments of the Config struct in builder/qemu/config.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `iso_skip_cache` (bool) - Use iso from provided url. Qemu must support
|
||||
curl block device. This defaults to `false`.
|
||||
|
||||
- `accelerator` (string) - The accelerator type to use when running the VM.
|
||||
This may be `none`, `kvm`, `tcg`, `hax`, `hvf`, `whpx`, or `xen`. The appropriate
|
||||
software must have already been installed on your build machine to use the
|
||||
accelerator you specified. When no accelerator is specified, Packer will try
|
||||
to use `kvm` if it is available but will default to `tcg` otherwise.
|
||||
|
||||
~> The `hax` accelerator has issues attaching CDROM ISOs. This is an
|
||||
upstream issue which can be tracked
|
||||
[here](https://github.com/intel/haxm/issues/20).
|
||||
|
||||
~> The `hvf` and `whpx` accelerator are new and experimental as of
|
||||
[QEMU 2.12.0](https://wiki.qemu.org/ChangeLog/2.12#Host_support).
|
||||
You may encounter issues unrelated to Packer when using these. You may need to
|
||||
add [ "-global", "virtio-pci.disable-modern=on" ] to `qemuargs` depending on the
|
||||
guest operating system.
|
||||
|
||||
~> For `whpx`, note that [Stefan Weil's QEMU for Windows distribution](https://qemu.weilnetz.de/w64/)
|
||||
does not include WHPX support and users may need to compile or source a
|
||||
build of QEMU for Windows themselves with WHPX support.
|
||||
|
||||
- `disk_additional_size` ([]string) - Additional disks to create. Uses `vm_name` as the disk name template and
|
||||
appends `-#` where `#` is the position in the array. `#` starts at 1 since 0
|
||||
is the default disk. Each string represents the disk image size in bytes.
|
||||
Optional suffixes 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G'
|
||||
(gigabyte, 1024M), 'T' (terabyte, 1024G), 'P' (petabyte, 1024T) and 'E'
|
||||
(exabyte, 1024P) are supported. 'b' is ignored. Per qemu-img documentation.
|
||||
Each additional disk uses the same disk parameters as the default disk.
|
||||
Unset by default.
|
||||
|
||||
- `cpus` (int) - The number of cpus to use when building the VM.
|
||||
The default is `1` CPU.
|
||||
|
||||
- `firmware` (string) - The firmware file to be used by QEMU, which is to be set by the -bios
|
||||
option of QEMU. Particularly, this option can be set to use EFI instead
|
||||
of BIOS, by using "OVMF.fd" from OpenFirmware.
|
||||
If unset, no -bios option is passed to QEMU, using the default of QEMU.
|
||||
Also see the QEMU documentation.
|
||||
|
||||
- `disk_interface` (string) - The interface to use for the disk. Allowed values include any of `ide`,
|
||||
`scsi`, `virtio` or `virtio-scsi`^\*. Note also that any boot commands
|
||||
or kickstart type scripts must have proper adjustments for resulting
|
||||
device names. The Qemu builder uses `virtio` by default.
|
||||
|
||||
^\* Please be aware that use of the `scsi` disk interface has been
|
||||
disabled by Red Hat due to a bug described
|
||||
[here](https://bugzilla.redhat.com/show_bug.cgi?id=1019220). If you are
|
||||
running Qemu on RHEL or a RHEL variant such as CentOS, you *must* choose
|
||||
one of the other listed interfaces. Using the `scsi` interface under
|
||||
these circumstances will cause the build to fail.
|
||||
|
||||
- `disk_size` (string) - The size in bytes of the hard disk of the VM. Suffix with the first
|
||||
letter of common byte types. Use "k" or "K" for kilobytes, "M" for
|
||||
megabytes, G for gigabytes, and T for terabytes. If no value is provided
|
||||
for disk_size, Packer uses a default of `40960M` (40 GB). If a disk_size
|
||||
number is provided with no units, Packer will default to Megabytes.
|
||||
|
||||
- `skip_resize_disk` (bool) - Packer resizes the QCOW2 image using
|
||||
qemu-img resize. Set this option to true to disable resizing.
|
||||
Defaults to false.
|
||||
|
||||
- `disk_cache` (string) - The cache mode to use for disk. Allowed values include any of
|
||||
`writethrough`, `writeback`, `none`, `unsafe` or `directsync`. By
|
||||
default, this is set to `writeback`.
|
||||
|
||||
- `disk_discard` (string) - The discard mode to use for disk. Allowed values
|
||||
include any of unmap or ignore. By default, this is set to ignore.
|
||||
|
||||
- `disk_detect_zeroes` (string) - The detect-zeroes mode to use for disk.
|
||||
Allowed values include any of unmap, on or off. Defaults to off.
|
||||
When the value is "off" we don't set the flag in the qemu command, so that
|
||||
Packer still works with old versions of QEMU that don't have this option.
|
||||
|
||||
- `skip_compaction` (bool) - Packer compacts the QCOW2 image using
|
||||
qemu-img convert. Set this option to true to disable compacting.
|
||||
Defaults to false.
|
||||
|
||||
- `disk_compression` (bool) - Apply compression to the QCOW2 disk file
|
||||
using qemu-img convert. Defaults to false.
|
||||
|
||||
- `format` (string) - Either `qcow2` or `raw`, this specifies the output format of the virtual
|
||||
machine image. This defaults to `qcow2`. Due to a long-standing bug with
|
||||
`qemu-img convert` on OSX, sometimes the qemu-img convert call will
|
||||
create a corrupted image. If this is an issue for you, make sure that the
|
||||
the output format matches the input file's format, and Packer will
|
||||
perform a simple copy operation instead. See
|
||||
https://bugs.launchpad.net/qemu/+bug/1776920 for more details.
|
||||
|
||||
- `headless` (bool) - Packer defaults to building QEMU virtual machines by
|
||||
launching a GUI that shows the console of the machine being built. When this
|
||||
value is set to `true`, the machine will start without a console.
|
||||
|
||||
You can still see the console if you make a note of the VNC display
|
||||
number chosen, and then connect using `vncviewer -Shared <host>:<display>`
|
||||
|
||||
- `disk_image` (bool) - Packer defaults to building from an ISO file, this parameter controls
|
||||
whether the ISO URL supplied is actually a bootable QEMU image. When
|
||||
this value is set to `true`, the machine will either clone the source or
|
||||
use it as a backing file (if `use_backing_file` is `true`); then, it
|
||||
will resize the image according to `disk_size` and boot it.
|
||||
|
||||
- `use_backing_file` (bool) - Only applicable when disk_image is true
|
||||
and format is qcow2, set this option to true to create a new QCOW2
|
||||
file that uses the file located at iso_url as a backing file. The new file
|
||||
will only contain blocks that have changed compared to the backing file, so
|
||||
enabling this option can significantly reduce disk usage. If true, Packer
|
||||
will force the `skip_compaction` also to be true as well to skip disk
|
||||
conversion which would render the backing file feature useless.
|
||||
|
||||
- `machine_type` (string) - The type of machine emulation to use. Run your qemu binary with the
|
||||
flags `-machine help` to list available types for your system. This
|
||||
defaults to `pc`.
|
||||
|
||||
- `memory` (int) - The amount of memory to use when building the VM
|
||||
in megabytes. This defaults to 512 megabytes.
|
||||
|
||||
- `net_device` (string) - The driver to use for the network interface. Allowed values `ne2k_pci`,
|
||||
`i82551`, `i82557b`, `i82559er`, `rtl8139`, `e1000`, `pcnet`, `virtio`,
|
||||
`virtio-net`, `virtio-net-pci`, `usb-net`, `i82559a`, `i82559b`,
|
||||
`i82559c`, `i82550`, `i82562`, `i82557a`, `i82557c`, `i82801`,
|
||||
`vmxnet3`, `i82558a` or `i82558b`. The Qemu builder uses `virtio-net` by
|
||||
default.
|
||||
|
||||
- `net_bridge` (string) - Connects the network to this bridge instead of using the user mode
|
||||
networking.
|
||||
|
||||
**NB** This bridge must already exist. You can use the `virbr0` bridge
|
||||
as created by vagrant-libvirt.
|
||||
|
||||
**NB** This will automatically enable the QMP socket (see QMPEnable).
|
||||
|
||||
**NB** This only works in Linux based OSes.
|
||||
|
||||
- `output_directory` (string) - This is the path to the directory where the
|
||||
resulting virtual machine will be created. This may be relative or absolute.
|
||||
If relative, the path is relative to the working directory when packer
|
||||
is executed. This directory must not exist or be empty prior to running
|
||||
the builder. By default this is output-BUILDNAME where "BUILDNAME" is the
|
||||
name of the build.
|
||||
|
||||
- `qemuargs` ([][]string) - Allows complete control over the qemu command line (though not 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 separator.
|
||||
|
||||
~> **Warning:** The qemu command line allows extreme flexibility, so
|
||||
beware of conflicting arguments causing failures of your run.
|
||||
For instance adding a "--drive" or "--device" override will mean that
|
||||
none of the default configuration Packer sets will be used. To see the
|
||||
defaults that Packer sets, look in your packer.log
|
||||
file (set PACKER_LOG=1 to get verbose logging) and search for the
|
||||
qemu-system-x86 command. The arguments are all printed for review, and
|
||||
you can use those arguments along with the template engines allowed
|
||||
by qemu-args to set up a working configuration that includes both the
|
||||
Packer defaults and your extra arguments.
|
||||
|
||||
Another pitfall could be setting arguments like --no-acpi, which could
|
||||
break the ability to send power signal type commands
|
||||
(e.g., shutdown -P now) to the virtual machine, thus preventing proper
|
||||
shutdown.
|
||||
|
||||
The following shows a sample usage:
|
||||
|
||||
In JSON:
|
||||
```json
|
||||
"qemuargs": [
|
||||
[ "-m", "1024M" ],
|
||||
[ "--no-acpi", "" ],
|
||||
[
|
||||
"-netdev",
|
||||
"user,id=mynet0,",
|
||||
"hostfwd=hostip:hostport-guestip:guestport",
|
||||
""
|
||||
],
|
||||
[ "-device", "virtio-net,netdev=mynet0" ]
|
||||
]
|
||||
```
|
||||
|
||||
In HCL2:
|
||||
```hcl
|
||||
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):
|
||||
|
||||
```text
|
||||
qemu-system-x86 -m 1024m --no-acpi -netdev
|
||||
user,id=mynet0,hostfwd=hostip:hostport-guestip:guestport -device
|
||||
virtio-net,netdev=mynet0"
|
||||
```
|
||||
|
||||
~> **Windows Users:** [QEMU for Windows](https://qemu.weilnetz.de/)
|
||||
builds are available though an environmental variable does need to be
|
||||
set for QEMU for Windows to redirect stdout to the console instead of
|
||||
stdout.txt.
|
||||
|
||||
The following shows the environment variable that needs to be set for
|
||||
Windows QEMU support:
|
||||
|
||||
```text
|
||||
setx SDL_STDIO_REDIRECT=0
|
||||
```
|
||||
|
||||
You can also use the `SSHHostPort` template variable to produce a packer
|
||||
template that can be invoked by `make` in parallel:
|
||||
|
||||
In JSON:
|
||||
```json
|
||||
"qemuargs": [
|
||||
[ "-netdev", "user,hostfwd=tcp::{{ .SSHHostPort }}-:22,id=forward"],
|
||||
[ "-device", "virtio-net,netdev=forward,id=net0"]
|
||||
]
|
||||
```
|
||||
|
||||
In HCL2:
|
||||
```hcl
|
||||
qemuargs = [
|
||||
[ "-netdev", "user,hostfwd=tcp::{{ .SSHHostPort }}-:22,id=forward"],
|
||||
[ "-device", "virtio-net,netdev=forward,id=net0"]
|
||||
]
|
||||
|
||||
`make -j 3 my-awesome-packer-templates` spawns 3 packer processes, each
|
||||
of which will bind to their own SSH port as determined by each process.
|
||||
This will also work with WinRM, just change the port forward in
|
||||
`qemuargs` to map to WinRM's default port of `5985` or whatever value
|
||||
you have the service set to listen on.
|
||||
|
||||
This is a template engine and allows access to the following variables:
|
||||
`{{ .HTTPIP }}`, `{{ .HTTPPort }}`, `{{ .HTTPDir }}`,
|
||||
`{{ .OutputDir }}`, `{{ .Name }}`, and `{{ .SSHHostPort }}`
|
||||
|
||||
- `qemu_img_args` (QemuImgArgs) - A map of custom arguments to pass to qemu-img commands, where the key
|
||||
is the subcommand, and the values are lists of strings for each flag.
|
||||
Example:
|
||||
|
||||
In JSON:
|
||||
```json
|
||||
{
|
||||
"qemu_img_args": {
|
||||
"convert": ["-o", "preallocation=full"],
|
||||
"resize": ["-foo", "bar"]
|
||||
}
|
||||
```
|
||||
Please note
|
||||
that unlike qemuargs, these commands are not split into switch-value
|
||||
sub-arrays, because the basic elements in qemu-img calls are unlikely
|
||||
to need an actual override.
|
||||
The arguments will be constructed as follows:
|
||||
- Convert:
|
||||
Default is `qemu-img convert -O $format $sourcepath $targetpath`. Adding
|
||||
arguments ["-foo", "bar"] to qemu_img_args.convert will change this to
|
||||
`qemu-img convert -foo bar -O $format $sourcepath $targetpath`
|
||||
- Create:
|
||||
Default is `create -f $format $targetpath $size`. Adding arguments
|
||||
["-foo", "bar"] to qemu_img_args.create will change this to
|
||||
"create -f qcow2 -foo bar target.qcow2 1234M"
|
||||
- Resize:
|
||||
Default is `qemu-img resize -f $format $sourcepath $size`. Adding
|
||||
arguments ["-foo", "bar"] to qemu_img_args.resize will change this to
|
||||
`qemu-img resize -f $format -foo bar $sourcepath $size`
|
||||
|
||||
- `qemu_binary` (string) - The name of the Qemu binary to look for. This
|
||||
defaults to qemu-system-x86_64, but may need to be changed for
|
||||
some platforms. For example qemu-kvm, or qemu-system-i386 may be a
|
||||
better choice for some systems.
|
||||
|
||||
- `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.
|
||||
|
||||
- `use_default_display` (bool) - If true, do not pass a -display option
|
||||
to qemu, allowing it to choose the default. This may be needed when running
|
||||
under macOS, and getting errors about sdl not being available.
|
||||
|
||||
- `display` (string) - What QEMU -display option to use. Defaults to gtk, use none to not pass the
|
||||
-display option allowing QEMU to choose the default. This may be needed when
|
||||
running under macOS, and getting errors about sdl not being available.
|
||||
|
||||
- `vnc_bind_address` (string) - The IP address that should be
|
||||
binded to for VNC. By default packer will use 127.0.0.1 for this. If you
|
||||
wish to bind to all interfaces use 0.0.0.0.
|
||||
|
||||
- `vnc_use_password` (bool) - Whether or not to set a password on the VNC server. This option
|
||||
automatically enables the QMP socket. See `qmp_socket_path`. Defaults to
|
||||
`false`.
|
||||
|
||||
- `vnc_port_min` (int) - The minimum and maximum port
|
||||
to use for VNC access to the virtual machine. The builder uses VNC to type
|
||||
the initial boot_command. Because Packer generally runs in parallel,
|
||||
Packer uses a randomly chosen port in this range that appears available. By
|
||||
default this is 5900 to 6000. The minimum and maximum ports are inclusive.
|
||||
The minimum port cannot be set below 5900 due to a quirk in how QEMU parses
|
||||
vnc display address.
|
||||
|
||||
- `vnc_port_max` (int) - VNC Port Max
|
||||
|
||||
- `vm_name` (string) - This is the name of the image (QCOW2 or IMG) file for
|
||||
the new virtual machine. By default this is packer-BUILDNAME, where
|
||||
"BUILDNAME" is the name of the build. Currently, no file extension will be
|
||||
used unless it is specified in this option.
|
||||
|
||||
- `cdrom_interface` (string) - The interface to use for the CDROM device which contains the ISO image.
|
||||
Allowed values include any of `ide`, `scsi`, `virtio` or
|
||||
`virtio-scsi`. The Qemu builder uses `virtio` by default.
|
||||
Some ARM64 images require `virtio-scsi`.
|
||||
|
||||
<!-- End of code generated from the comments of the Config struct in builder/qemu/config.go; -->
|
|
@ -1,9 +0,0 @@
|
|||
<!-- Code generated from the comments of the QemuImgArgs struct in builder/qemu/config.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `convert` ([]string) - Convert
|
||||
|
||||
- `create` ([]string) - Create
|
||||
|
||||
- `resize` ([]string) - Resize
|
||||
|
||||
<!-- End of code generated from the comments of the QemuImgArgs struct in builder/qemu/config.go; -->
|
|
@ -845,10 +845,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "QEMU",
|
||||
"path": "builders/qemu"
|
||||
},
|
||||
{
|
||||
"title": "Scaleway",
|
||||
"path": "builders/scaleway"
|
||||
|
|
|
@ -40,5 +40,11 @@
|
|||
"path": "vmware",
|
||||
"repo": "hashicorp/packer-plugin-vmware",
|
||||
"version": "latest"
|
||||
},
|
||||
{
|
||||
"title": "QEMU",
|
||||
"path": "qemu",
|
||||
"repo": "hashicorp/packer-plugin-qemu",
|
||||
"version": "latest"
|
||||
}
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue