Refactor communicator config for Qemu and add SkipNatMapping option (#9307)
This commit is contained in:
parent
374f82b978
commit
ce45a1990a
|
@ -25,6 +25,9 @@
|
|||
* builder/google: Implement iap proxy for googlecompute [GH-9105]
|
||||
* builder/googlecompute: Changed default disk size. [GH-9071]
|
||||
* builder/qemu: add support for using a network bridge [GH-9159]
|
||||
* builder/qemu: Added `skip_nat_mapping` option to skip the
|
||||
communicator (SSH or WinRM) automatic port forward and use the guest port directly. [GH-9307]
|
||||
* builder/qemu: Replace deprecated `ssh_host_port_min` and `ssh_host_port_max` by `host_port_min` and `host_port_max`. [GH-9307]
|
||||
* builder/virtualbox: Add `output_filename` config option to allow to set a
|
||||
custom filename instead of forcing to be the same as vm_name. [GH-9174]
|
||||
* builder/vsphere: floppy_label Parameter for vsphere-iso Builder [GH-9187]
|
||||
|
|
|
@ -75,7 +75,7 @@ type Config struct {
|
|||
common.ISOConfig `mapstructure:",squash"`
|
||||
bootcommand.VNCConfig `mapstructure:",squash"`
|
||||
shutdowncommand.ShutdownConfig `mapstructure:",squash"`
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
CommConfig CommConfig `mapstructure:",squash"`
|
||||
common.FloppyConfig `mapstructure:",squash"`
|
||||
// Use iso from provided url. Qemu must support
|
||||
// curl block device. This defaults to `false`.
|
||||
|
@ -288,12 +288,6 @@ type Config struct {
|
|||
// QMP Socket Path when `qmp_enable` is true. Defaults to
|
||||
// `output_directory`/`vm_name`.monitor.
|
||||
QMPSocketPath string `mapstructure:"qmp_socket_path" required:"false"`
|
||||
// The minimum and maximum port to use for the SSH port on the host machine
|
||||
// which is forwarded to the SSH 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 2222 to 4444.
|
||||
SSHHostPortMin int `mapstructure:"ssh_host_port_min" required:"false"`
|
||||
SSHHostPortMax int `mapstructure:"ssh_host_port_max" required:"false"`
|
||||
// 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.
|
||||
|
@ -425,14 +419,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
|
|||
b.config.CpuCount = 1
|
||||
}
|
||||
|
||||
if b.config.SSHHostPortMin == 0 {
|
||||
b.config.SSHHostPortMin = 2222
|
||||
}
|
||||
|
||||
if b.config.SSHHostPortMax == 0 {
|
||||
b.config.SSHHostPortMax = 4444
|
||||
}
|
||||
|
||||
if b.config.VNCBindAddress == "" {
|
||||
b.config.VNCBindAddress = "127.0.0.1"
|
||||
}
|
||||
|
@ -472,9 +458,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
|
|||
errs = packer.MultiErrorAppend(errs, isoErrs...)
|
||||
|
||||
errs = packer.MultiErrorAppend(errs, b.config.HTTPConfig.Prepare(&b.config.ctx)...)
|
||||
if es := b.config.Comm.Prepare(&b.config.ctx); len(es) > 0 {
|
||||
commConfigWarnings, es := b.config.CommConfig.Prepare(&b.config.ctx)
|
||||
if len(es) > 0 {
|
||||
errs = packer.MultiErrorAppend(errs, es...)
|
||||
}
|
||||
warnings = append(warnings, commConfigWarnings...)
|
||||
|
||||
if !(b.config.Format == "qcow2" || b.config.Format == "raw") {
|
||||
errs = packer.MultiErrorAppend(
|
||||
|
@ -529,16 +517,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if b.config.SSHHostPortMin > b.config.SSHHostPortMax {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, errors.New("ssh_host_port_min must be less than ssh_host_port_max"))
|
||||
}
|
||||
|
||||
if b.config.SSHHostPortMin < 0 {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, errors.New("ssh_host_port_min must be positive"))
|
||||
}
|
||||
|
||||
if b.config.VNCPortMin > b.config.VNCPortMax {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, fmt.Errorf("vnc_port_min must be less than vnc_port_max"))
|
||||
|
@ -621,9 +599,9 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
},
|
||||
)
|
||||
|
||||
if b.config.Comm.Type != "none" && b.config.NetBridge == "" {
|
||||
if b.config.CommConfig.Comm.Type != "none" && b.config.NetBridge == "" {
|
||||
steps = append(steps,
|
||||
new(stepForwardSSH),
|
||||
new(stepPortForward),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -636,20 +614,20 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
&stepTypeBootCommand{},
|
||||
)
|
||||
|
||||
if b.config.Comm.Type != "none" && b.config.NetBridge != "" {
|
||||
if b.config.CommConfig.Comm.Type != "none" && b.config.NetBridge != "" {
|
||||
steps = append(steps,
|
||||
&stepWaitGuestAddress{
|
||||
timeout: b.config.Comm.SSHTimeout,
|
||||
timeout: b.config.CommConfig.Comm.SSHTimeout,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if b.config.Comm.Type != "none" {
|
||||
if b.config.CommConfig.Comm.Type != "none" {
|
||||
steps = append(steps,
|
||||
&communicator.StepConnect{
|
||||
Config: &b.config.Comm,
|
||||
Host: commHost(b.config.Comm.Host()),
|
||||
SSHConfig: b.config.Comm.SSHConfigFunc(),
|
||||
Config: &b.config.CommConfig.Comm,
|
||||
Host: commHost(b.config.CommConfig.Comm.Host()),
|
||||
SSHConfig: b.config.CommConfig.Comm.SSHConfigFunc(),
|
||||
SSHPort: commPort,
|
||||
WinRMPort: commPort,
|
||||
},
|
||||
|
@ -662,7 +640,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
|
||||
steps = append(steps,
|
||||
&common.StepCleanupTempKeys{
|
||||
Comm: &b.config.Comm,
|
||||
Comm: &b.config.CommConfig.Comm,
|
||||
},
|
||||
)
|
||||
steps = append(steps,
|
||||
|
|
|
@ -73,6 +73,11 @@ type FlatConfig struct {
|
|||
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"`
|
||||
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
|
||||
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
|
||||
HostPortMin *int `mapstructure:"host_port_min" required:"false" cty:"host_port_min" hcl:"host_port_min"`
|
||||
HostPortMax *int `mapstructure:"host_port_max" required:"false" cty:"host_port_max" hcl:"host_port_max"`
|
||||
SkipNatMapping *bool `mapstructure:"skip_nat_mapping" required:"false" cty:"skip_nat_mapping" hcl:"skip_nat_mapping"`
|
||||
SSHHostPortMin *int `mapstructure:"ssh_host_port_min" required:"false" cty:"ssh_host_port_min" hcl:"ssh_host_port_min"`
|
||||
SSHHostPortMax *int `mapstructure:"ssh_host_port_max" cty:"ssh_host_port_max" hcl:"ssh_host_port_max"`
|
||||
FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files" hcl:"floppy_files"`
|
||||
FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs" hcl:"floppy_dirs"`
|
||||
FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label" hcl:"floppy_label"`
|
||||
|
@ -100,8 +105,6 @@ type FlatConfig struct {
|
|||
QemuBinary *string `mapstructure:"qemu_binary" required:"false" cty:"qemu_binary" hcl:"qemu_binary"`
|
||||
QMPEnable *bool `mapstructure:"qmp_enable" required:"false" cty:"qmp_enable" hcl:"qmp_enable"`
|
||||
QMPSocketPath *string `mapstructure:"qmp_socket_path" required:"false" cty:"qmp_socket_path" hcl:"qmp_socket_path"`
|
||||
SSHHostPortMin *int `mapstructure:"ssh_host_port_min" required:"false" cty:"ssh_host_port_min" hcl:"ssh_host_port_min"`
|
||||
SSHHostPortMax *int `mapstructure:"ssh_host_port_max" required:"false" cty:"ssh_host_port_max" hcl:"ssh_host_port_max"`
|
||||
UseDefaultDisplay *bool `mapstructure:"use_default_display" required:"false" cty:"use_default_display" hcl:"use_default_display"`
|
||||
Display *string `mapstructure:"display" required:"false" cty:"display" hcl:"display"`
|
||||
VNCBindAddress *string `mapstructure:"vnc_bind_address" required:"false" cty:"vnc_bind_address" hcl:"vnc_bind_address"`
|
||||
|
@ -188,6 +191,11 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"winrm_use_ssl": &hcldec.AttrSpec{Name: "winrm_use_ssl", Type: cty.Bool, Required: false},
|
||||
"winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false},
|
||||
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
|
||||
"host_port_min": &hcldec.AttrSpec{Name: "host_port_min", Type: cty.Number, Required: false},
|
||||
"host_port_max": &hcldec.AttrSpec{Name: "host_port_max", Type: cty.Number, Required: false},
|
||||
"skip_nat_mapping": &hcldec.AttrSpec{Name: "skip_nat_mapping", Type: cty.Bool, Required: false},
|
||||
"ssh_host_port_min": &hcldec.AttrSpec{Name: "ssh_host_port_min", Type: cty.Number, Required: false},
|
||||
"ssh_host_port_max": &hcldec.AttrSpec{Name: "ssh_host_port_max", Type: cty.Number, Required: false},
|
||||
"floppy_files": &hcldec.AttrSpec{Name: "floppy_files", Type: cty.List(cty.String), Required: false},
|
||||
"floppy_dirs": &hcldec.AttrSpec{Name: "floppy_dirs", Type: cty.List(cty.String), Required: false},
|
||||
"floppy_label": &hcldec.AttrSpec{Name: "floppy_label", Type: cty.String, Required: false},
|
||||
|
@ -215,8 +223,6 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"qemu_binary": &hcldec.AttrSpec{Name: "qemu_binary", Type: cty.String, Required: false},
|
||||
"qmp_enable": &hcldec.AttrSpec{Name: "qmp_enable", Type: cty.Bool, Required: false},
|
||||
"qmp_socket_path": &hcldec.AttrSpec{Name: "qmp_socket_path", Type: cty.String, Required: false},
|
||||
"ssh_host_port_min": &hcldec.AttrSpec{Name: "ssh_host_port_min", Type: cty.Number, Required: false},
|
||||
"ssh_host_port_max": &hcldec.AttrSpec{Name: "ssh_host_port_max", Type: cty.Number, Required: false},
|
||||
"use_default_display": &hcldec.AttrSpec{Name: "use_default_display", Type: cty.Bool, Required: false},
|
||||
"display": &hcldec.AttrSpec{Name: "display", Type: cty.String, Required: false},
|
||||
"vnc_bind_address": &hcldec.AttrSpec{Name: "vnc_bind_address", Type: cty.String, Required: false},
|
||||
|
|
|
@ -74,16 +74,16 @@ func TestBuilderPrepare_Defaults(t *testing.T) {
|
|||
t.Errorf("bad output dir: %s", b.config.OutputDir)
|
||||
}
|
||||
|
||||
if b.config.SSHHostPortMin != 2222 {
|
||||
t.Errorf("bad min ssh host port: %d", b.config.SSHHostPortMin)
|
||||
if b.config.CommConfig.HostPortMin != 2222 {
|
||||
t.Errorf("bad min ssh host port: %d", b.config.CommConfig.HostPortMin)
|
||||
}
|
||||
|
||||
if b.config.SSHHostPortMax != 4444 {
|
||||
t.Errorf("bad max ssh host port: %d", b.config.SSHHostPortMax)
|
||||
if b.config.CommConfig.HostPortMax != 4444 {
|
||||
t.Errorf("bad max ssh host port: %d", b.config.CommConfig.HostPortMax)
|
||||
}
|
||||
|
||||
if b.config.Comm.SSHPort != 22 {
|
||||
t.Errorf("bad ssh port: %d", b.config.Comm.SSHPort)
|
||||
if b.config.CommConfig.Comm.SSHPort != 22 {
|
||||
t.Errorf("bad ssh port: %d", b.config.CommConfig.Comm.SSHPort)
|
||||
}
|
||||
|
||||
if b.config.VMName != "packer-foo" {
|
||||
|
@ -430,8 +430,8 @@ func TestBuilderPrepare_SSHHostPort(t *testing.T) {
|
|||
config := testConfig()
|
||||
|
||||
// Bad
|
||||
config["ssh_host_port_min"] = 1000
|
||||
config["ssh_host_port_max"] = 500
|
||||
config["host_port_min"] = 1000
|
||||
config["host_port_max"] = 500
|
||||
b = Builder{}
|
||||
_, warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
|
@ -442,7 +442,7 @@ func TestBuilderPrepare_SSHHostPort(t *testing.T) {
|
|||
}
|
||||
|
||||
// Bad
|
||||
config["ssh_host_port_min"] = -500
|
||||
config["host_port_min"] = -500
|
||||
b = Builder{}
|
||||
_, warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
|
@ -453,8 +453,8 @@ func TestBuilderPrepare_SSHHostPort(t *testing.T) {
|
|||
}
|
||||
|
||||
// Good
|
||||
config["ssh_host_port_min"] = 500
|
||||
config["ssh_host_port_max"] = 1000
|
||||
config["host_port_min"] = 500
|
||||
config["host_port_max"] = 1000
|
||||
b = Builder{}
|
||||
_, warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
|
@ -628,18 +628,31 @@ func TestBuilderPrepare_VNCPassword(t *testing.T) {
|
|||
func TestCommConfigPrepare_BackwardsCompatibility(t *testing.T) {
|
||||
var b Builder
|
||||
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 := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
if len(warns) == 0 {
|
||||
t.Fatalf("should have deprecation warn")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
if b.config.Comm.SSHTimeout != sshTimeout {
|
||||
t.Fatalf("SSHTimeout should be %s for backwards compatibility, but it was %s", sshTimeout.String(), b.config.Comm.SSHTimeout.String())
|
||||
if b.config.CommConfig.Comm.SSHTimeout != sshTimeout {
|
||||
t.Fatalf("SSHTimeout should be %s for backwards compatibility, but it was %s", sshTimeout.String(), b.config.CommConfig.Comm.SSHTimeout.String())
|
||||
}
|
||||
|
||||
if b.config.CommConfig.HostPortMin != hostPortMin {
|
||||
t.Fatalf("HostPortMin should be %d for backwards compatibility, but it was %d", hostPortMin, b.config.CommConfig.HostPortMin)
|
||||
}
|
||||
|
||||
if b.config.CommConfig.HostPortMax != hostPortMax {
|
||||
t.Fatalf("HostPortMax should be %d for backwards compatibility, but it was %d", hostPortMax, b.config.CommConfig.HostPortMax)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
//go:generate struct-markdown
|
||||
package qemu
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
type CommConfig struct {
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
// 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.
|
||||
HostPortMin int `mapstructure:"host_port_min" required:"false"`
|
||||
// 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.
|
||||
HostPortMax int `mapstructure:"host_port_max" required:"false"`
|
||||
// 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.
|
||||
SkipNatMapping bool `mapstructure:"skip_nat_mapping" required:"false"`
|
||||
|
||||
// These are deprecated, but we keep them around for backwards compatibility
|
||||
// TODO: remove later
|
||||
SSHHostPortMin int `mapstructure:"ssh_host_port_min" required:"false"`
|
||||
// TODO: remove later
|
||||
SSHHostPortMax int `mapstructure:"ssh_host_port_max"`
|
||||
}
|
||||
|
||||
func (c *CommConfig) Prepare(ctx *interpolate.Context) (warnings []string, errs []error) {
|
||||
|
||||
// Backwards compatibility
|
||||
if c.SSHHostPortMin != 0 {
|
||||
warnings = append(warnings, "ssh_host_port_min is deprecated and is being replaced by host_port_min. "+
|
||||
"Please, update your template to use host_port_min. In future versions of Packer, inclusion of ssh_host_port_min will error your builds.")
|
||||
c.HostPortMin = c.SSHHostPortMin
|
||||
}
|
||||
|
||||
// Backwards compatibility
|
||||
if c.SSHHostPortMax != 0 {
|
||||
warnings = append(warnings, "ssh_host_port_max is deprecated and is being replaced by host_port_max. "+
|
||||
"Please, update your template to use host_port_max. In future versions of Packer, inclusion of ssh_host_port_max will error your builds.")
|
||||
c.HostPortMax = c.SSHHostPortMax
|
||||
}
|
||||
|
||||
if c.Comm.SSHHost == "" {
|
||||
c.Comm.SSHHost = "127.0.0.1"
|
||||
}
|
||||
|
||||
if c.HostPortMin == 0 {
|
||||
c.HostPortMin = 2222
|
||||
}
|
||||
|
||||
if c.HostPortMax == 0 {
|
||||
c.HostPortMax = 4444
|
||||
}
|
||||
|
||||
errs = c.Comm.Prepare(ctx)
|
||||
if c.HostPortMin > c.HostPortMax {
|
||||
errs = append(errs,
|
||||
errors.New("host_port_min must be less than host_port_max"))
|
||||
}
|
||||
|
||||
if c.HostPortMin < 0 {
|
||||
errs = append(errs, errors.New("host_port_min must be positive"))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
package qemu
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
"github.com/hashicorp/packer/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")
|
||||
}
|
||||
}
|
|
@ -22,9 +22,9 @@ func commHost(host string) func(multistep.StateBag) (string, error) {
|
|||
}
|
||||
|
||||
func commPort(state multistep.StateBag) (int, error) {
|
||||
sshHostPort, ok := state.Get("sshHostPort").(int)
|
||||
commHostPort, ok := state.Get("commHostPort").(int)
|
||||
if !ok {
|
||||
sshHostPort = 22
|
||||
commHostPort = 22
|
||||
}
|
||||
return int(sshHostPort), nil
|
||||
return commHostPort, nil
|
||||
}
|
||||
|
|
|
@ -10,26 +10,30 @@ import (
|
|||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
// This step adds a NAT port forwarding definition so that SSH is available
|
||||
// This step adds a NAT port forwarding definition so that SSH or WinRM is available
|
||||
// on the guest machine.
|
||||
//
|
||||
// Uses:
|
||||
//
|
||||
// Produces:
|
||||
type stepForwardSSH struct {
|
||||
type stepPortForward struct {
|
||||
l *net.Listener
|
||||
}
|
||||
|
||||
func (s *stepForwardSSH) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
func (s *stepPortForward) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
log.Printf("Looking for available communicator (SSH, WinRM, etc) port between %d and %d", config.SSHHostPortMin, config.SSHHostPortMax)
|
||||
commHostPort := config.CommConfig.Comm.Port()
|
||||
|
||||
if config.CommConfig.SkipNatMapping {
|
||||
log.Printf("Skipping NAT port forwarding. Using communicator (SSH, WinRM, etc) port %d", commHostPort)
|
||||
state.Put("commHostPort", commHostPort)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
log.Printf("Looking for available communicator (SSH, WinRM, etc) port between %d and %d", config.CommConfig.HostPortMin, config.CommConfig.HostPortMax)
|
||||
var err error
|
||||
s.l, err = net.ListenRangeConfig{
|
||||
Addr: config.VNCBindAddress,
|
||||
Min: config.SSHHostPortMin,
|
||||
Max: config.SSHHostPortMax,
|
||||
Min: config.CommConfig.HostPortMin,
|
||||
Max: config.CommConfig.HostPortMax,
|
||||
Network: "tcp",
|
||||
}.Listen(ctx)
|
||||
if err != nil {
|
||||
|
@ -39,16 +43,16 @@ func (s *stepForwardSSH) Run(ctx context.Context, state multistep.StateBag) mult
|
|||
return multistep.ActionHalt
|
||||
}
|
||||
s.l.Listener.Close() // free port, but don't unlock lock file
|
||||
sshHostPort := s.l.Port
|
||||
ui.Say(fmt.Sprintf("Found port for communicator (SSH, WinRM, etc): %d.", sshHostPort))
|
||||
commHostPort = s.l.Port
|
||||
ui.Say(fmt.Sprintf("Found port for communicator (SSH, WinRM, etc): %d.", commHostPort))
|
||||
|
||||
// Save the port we're using so that future steps can use it
|
||||
state.Put("sshHostPort", sshHostPort)
|
||||
state.Put("commHostPort", commHostPort)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepForwardSSH) Cleanup(state multistep.StateBag) {
|
||||
func (s *stepPortForward) Cleanup(state multistep.StateBag) {
|
||||
if s.l != nil {
|
||||
err := s.l.Close()
|
||||
if err != nil {
|
|
@ -72,7 +72,7 @@ func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error
|
|||
defaultArgs := make(map[string]interface{})
|
||||
var deviceArgs []string
|
||||
var driveArgs []string
|
||||
var sshHostPort int
|
||||
var commHostPort int
|
||||
var vnc string
|
||||
|
||||
if !config.VNCUsePassword {
|
||||
|
@ -89,9 +89,9 @@ func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error
|
|||
defaultArgs["-machine"] = fmt.Sprintf("type=%s", config.MachineType)
|
||||
|
||||
if config.NetBridge == "" {
|
||||
if config.Comm.Type != "none" {
|
||||
sshHostPort = state.Get("sshHostPort").(int)
|
||||
defaultArgs["-netdev"] = fmt.Sprintf("user,id=user.0,hostfwd=tcp::%v-:%d", sshHostPort, config.Comm.Port())
|
||||
if config.CommConfig.Comm.Type != "none" {
|
||||
commHostPort = state.Get("commHostPort").(int)
|
||||
defaultArgs["-netdev"] = fmt.Sprintf("user,id=user.0,hostfwd=tcp::%v-:%d", commHostPort, config.CommConfig.Comm.Port())
|
||||
} else {
|
||||
defaultArgs["-netdev"] = fmt.Sprintf("user,id=user.0")
|
||||
}
|
||||
|
@ -226,14 +226,14 @@ func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error
|
|||
httpIp := state.Get("http_ip").(string)
|
||||
httpPort := state.Get("http_port").(int)
|
||||
ictx := config.ctx
|
||||
if config.Comm.Type != "none" {
|
||||
if config.CommConfig.Comm.Type != "none" {
|
||||
ictx.Data = qemuArgsTemplateData{
|
||||
httpIp,
|
||||
httpPort,
|
||||
config.HTTPDir,
|
||||
config.OutputDir,
|
||||
config.VMName,
|
||||
sshHostPort,
|
||||
commHostPort,
|
||||
}
|
||||
} else {
|
||||
ictx.Data = qemuArgsTemplateData{
|
||||
|
|
|
@ -57,6 +57,7 @@ func init() {
|
|||
"docker-tag-tags": new(FixerDockerTagtoTags),
|
||||
"vsphere-iso-net-disk": new(FixerVSphereNetworkDisk),
|
||||
"iso-checksum-type-and-url": new(FixerISOChecksumTypeAndURL),
|
||||
"qemu-host-port": new(FixerQEMUHostPort),
|
||||
}
|
||||
|
||||
FixerOrder = []string{
|
||||
|
@ -91,5 +92,6 @@ func init() {
|
|||
"ssh-wait-timeout",
|
||||
"vsphere-iso-net-disk",
|
||||
"iso-checksum-type-and-url",
|
||||
"qemu-host-port",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package fix
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
// FixerQEMUHostPort updates ssh_host_port_min and ssh_host_port_max to host_port_min and host_port_max for QEMU builders
|
||||
type FixerQEMUHostPort struct{}
|
||||
|
||||
func (FixerQEMUHostPort) Fix(input map[string]interface{}) (map[string]interface{}, error) {
|
||||
type template struct {
|
||||
Builders []map[string]interface{}
|
||||
}
|
||||
|
||||
// Decode the input into our structure, if we can
|
||||
var tpl template
|
||||
if err := mapstructure.Decode(input, &tpl); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, builder := range tpl.Builders {
|
||||
builderTypeRaw, ok := builder["type"]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
builderType, ok := builderTypeRaw.(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if builderType != "qemu" {
|
||||
continue
|
||||
}
|
||||
|
||||
// replace ssh_host_port_min with host_port_min if it exists
|
||||
sshHostPortMin, ok := builder["ssh_host_port_min"]
|
||||
if ok {
|
||||
delete(builder, "ssh_host_port_min")
|
||||
builder["host_port_min"] = sshHostPortMin
|
||||
}
|
||||
|
||||
// replace ssh_host_port_min with host_port_min if it exists
|
||||
sshHostPortMax, ok := builder["ssh_host_port_max"]
|
||||
if ok {
|
||||
delete(builder, "ssh_host_port_max")
|
||||
builder["host_port_max"] = sshHostPortMax
|
||||
}
|
||||
}
|
||||
|
||||
input["builders"] = tpl.Builders
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (FixerQEMUHostPort) Synopsis() string {
|
||||
return `Updates ssh_host_port_min and ssh_host_port_max to host_port_min and host_port_max`
|
||||
}
|
||||
|
||||
func (FixerQEMUHostPort) DeprecatedOptions() []string {
|
||||
return []string{"ssh_host_port_max", "ssh_host_port_min"}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package fix
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFixerQEMUHostPort_impl(t *testing.T) {
|
||||
var _ Fixer = new(FixerQEMUHostPort)
|
||||
}
|
||||
|
||||
func TestFixerQEMUHostPort(t *testing.T) {
|
||||
cases := []struct {
|
||||
Input map[string]interface{}
|
||||
Expected map[string]interface{}
|
||||
}{
|
||||
{
|
||||
Input: map[string]interface{}{
|
||||
"type": "qemu",
|
||||
"ssh_host_port_min": 2222,
|
||||
},
|
||||
|
||||
Expected: map[string]interface{}{
|
||||
"type": "qemu",
|
||||
"host_port_min": 2222,
|
||||
},
|
||||
},
|
||||
{
|
||||
Input: map[string]interface{}{
|
||||
"type": "qemu",
|
||||
"ssh_host_port_max": 4444,
|
||||
},
|
||||
|
||||
Expected: map[string]interface{}{
|
||||
"type": "qemu",
|
||||
"host_port_max": 4444,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
var f FixerQEMUHostPort
|
||||
|
||||
input := map[string]interface{}{
|
||||
"builders": []map[string]interface{}{tc.Input},
|
||||
}
|
||||
|
||||
expected := map[string]interface{}{
|
||||
"builders": []map[string]interface{}{tc.Expected},
|
||||
}
|
||||
|
||||
output, err := f.Fix(input)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(output, expected) {
|
||||
t.Fatalf("unexpected: %#v\nexpected: %#v\n", output, expected)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,4 +38,6 @@ var DeprecatedOptions = []string{
|
|||
"disk_eagerly_scrub",
|
||||
"iso_checksum_url",
|
||||
"iso_checksum_type",
|
||||
"ssh_host_port_max",
|
||||
"ssh_host_port_min",
|
||||
}
|
||||
|
|
|
@ -117,6 +117,22 @@ necessary for this build to succeed and can be found further down the page.
|
|||
|
||||
@include 'common/shutdowncommand/ShutdownConfig-not-required.mdx'
|
||||
|
||||
## Communicator configuration
|
||||
|
||||
### Optional common fields:
|
||||
|
||||
@include 'helper/communicator/Config-not-required.mdx'
|
||||
|
||||
@include 'builder/qemu/CommConfig-not-required.mdx'
|
||||
|
||||
### Optional SSH fields:
|
||||
|
||||
@include 'helper/communicator/SSH-not-required.mdx'
|
||||
|
||||
### Optional WinRM fields:
|
||||
|
||||
@include 'helper/communicator/WinRM-not-required.mdx'
|
||||
|
||||
## Boot Configuration
|
||||
|
||||
@include 'common/bootcommand/VNCConfig.mdx'
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<!-- 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.
|
||||
|
|
@ -211,12 +211,6 @@
|
|||
- `qmp_socket_path` (string) - QMP Socket Path when `qmp_enable` is true. Defaults to
|
||||
`output_directory`/`vm_name`.monitor.
|
||||
|
||||
- `ssh_host_port_min` (int) - The minimum and maximum port to use for the SSH port on the host machine
|
||||
which is forwarded to the SSH 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 2222 to 4444.
|
||||
|
||||
- `ssh_host_port_max` (int) - SSH Host Port Max
|
||||
- `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.
|
||||
|
|
Loading…
Reference in New Issue