mirror of https://github.com/hashicorp/packer
Refactor communicator config for Qemu and add SkipNatMapping option (#9307)
parent
374f82b978
commit
ce45a1990a
@ -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")
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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.
|
||||
|
||||
Loading…
Reference in new issue