diff --git a/CHANGELOG.md b/CHANGELOG.md index 2db310015..330a5f4ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ read more about this[GH-8437] ### FEATURES: +* HCL2/core: it is now possible to set source fields from the `build` block + [GH-9291] * **New post-processor** Yandex Export [GH-9124] ### IMPROVEMENTS: @@ -25,6 +27,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] diff --git a/builder/qemu/builder.go b/builder/qemu/builder.go index 3e797b0e4..33129af51 100644 --- a/builder/qemu/builder.go +++ b/builder/qemu/builder.go @@ -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, diff --git a/builder/qemu/builder.hcl2spec.go b/builder/qemu/builder.hcl2spec.go index a0d6ea5d4..0500eecd2 100644 --- a/builder/qemu/builder.hcl2spec.go +++ b/builder/qemu/builder.hcl2spec.go @@ -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}, diff --git a/builder/qemu/builder_test.go b/builder/qemu/builder_test.go index 963c121db..3eb243abb 100644 --- a/builder/qemu/builder_test.go +++ b/builder/qemu/builder_test.go @@ -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) } } diff --git a/builder/qemu/comm_config.go b/builder/qemu/comm_config.go new file mode 100644 index 000000000..45b68b79a --- /dev/null +++ b/builder/qemu/comm_config.go @@ -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 +} diff --git a/builder/qemu/comm_config_test.go b/builder/qemu/comm_config_test.go new file mode 100644 index 000000000..4912c7d96 --- /dev/null +++ b/builder/qemu/comm_config_test.go @@ -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") + } +} diff --git a/builder/qemu/ssh.go b/builder/qemu/ssh.go index 8f4ceee5c..d722df9e1 100644 --- a/builder/qemu/ssh.go +++ b/builder/qemu/ssh.go @@ -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 } diff --git a/builder/qemu/step_forward_ssh.go b/builder/qemu/step_port_forward.go similarity index 54% rename from builder/qemu/step_forward_ssh.go rename to builder/qemu/step_port_forward.go index a296fb078..e4f24b691 100644 --- a/builder/qemu/step_forward_ssh.go +++ b/builder/qemu/step_port_forward.go @@ -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 { diff --git a/builder/qemu/step_run.go b/builder/qemu/step_run.go index 900162f4f..10727530e 100644 --- a/builder/qemu/step_run.go +++ b/builder/qemu/step_run.go @@ -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{ diff --git a/fix/fixer.go b/fix/fixer.go index 8e3ef76e0..d77c23152 100644 --- a/fix/fixer.go +++ b/fix/fixer.go @@ -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", } } diff --git a/fix/fixer_qemu_host_port.go b/fix/fixer_qemu_host_port.go new file mode 100644 index 000000000..c1f6a3e3a --- /dev/null +++ b/fix/fixer_qemu_host_port.go @@ -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"} +} diff --git a/fix/fixer_qemu_host_port_test.go b/fix/fixer_qemu_host_port_test.go new file mode 100644 index 000000000..e2ec753c5 --- /dev/null +++ b/fix/fixer_qemu_host_port_test.go @@ -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) + } + } +} diff --git a/hcl2template/parser.go b/hcl2template/parser.go index 59efd69c0..5aab7d5d8 100644 --- a/hcl2template/parser.go +++ b/hcl2template/parser.go @@ -191,7 +191,7 @@ func (p *Parser) decodeConfig(f *hcl.File, cfg *PackerConfig) hcl.Diagnostics { } ref := source.Ref() - if existing := cfg.Sources[ref]; existing != nil { + if existing, found := cfg.Sources[ref]; found { diags = append(diags, &hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "Duplicate " + sourceLabel + " block", @@ -205,7 +205,7 @@ func (p *Parser) decodeConfig(f *hcl.File, cfg *PackerConfig) hcl.Diagnostics { } if cfg.Sources == nil { - cfg.Sources = map[SourceRef]*SourceBlock{} + cfg.Sources = map[SourceRef]SourceBlock{} } cfg.Sources[ref] = source diff --git a/hcl2template/testdata/complete/build.pkr.hcl b/hcl2template/testdata/complete/build.pkr.hcl index 5641e540b..327d2399f 100644 --- a/hcl2template/testdata/complete/build.pkr.hcl +++ b/hcl2template/testdata/complete/build.pkr.hcl @@ -5,6 +5,10 @@ build { "source.virtualbox-iso.ubuntu-1204", ] + source "source.amazon-ebs.ubuntu-1604" { + string = "setting from build section" + } + provisioner "shell" { name = "provisioner that does something" not_squashed = var.foo diff --git a/hcl2template/testdata/complete/sources.pkr.hcl b/hcl2template/testdata/complete/sources.pkr.hcl index 2575929c7..8b05624d5 100644 --- a/hcl2template/testdata/complete/sources.pkr.hcl +++ b/hcl2template/testdata/complete/sources.pkr.hcl @@ -1,3 +1,9 @@ + +source "amazon-ebs" "ubuntu-1604" { + int = 42 +} + + source "virtualbox-iso" "ubuntu-1204" { string = "string" int = 42 @@ -85,4 +91,4 @@ source "virtualbox-iso" "ubuntu-1204" { ["c","d"] ] } -} \ No newline at end of file +} diff --git a/hcl2template/types.build.go b/hcl2template/types.build.go index bf5802771..829038c85 100644 --- a/hcl2template/types.build.go +++ b/hcl2template/types.build.go @@ -19,6 +19,7 @@ const ( var buildSchema = &hcl.BodySchema{ Blocks: []hcl.BlockHeaderSchema{ {Type: buildFromLabel, LabelNames: []string{"type"}}, + {Type: sourceLabel, LabelNames: []string{"reference"}}, {Type: buildProvisionerLabel, LabelNames: []string{"type"}}, {Type: buildPostProcessorLabel, LabelNames: []string{"type"}}, }, @@ -60,7 +61,7 @@ func (p *Parser) decodeBuildConfig(block *hcl.Block) (*BuildBlock, hcl.Diagnosti var b struct { Name string `hcl:"name,optional"` - FromSources []string `hcl:"sources"` + FromSources []string `hcl:"sources,optional"` Config hcl.Body `hcl:",remain"` } diags := gohcl.DecodeBody(block.Body, nil, &b) @@ -98,6 +99,13 @@ func (p *Parser) decodeBuildConfig(block *hcl.Block) (*BuildBlock, hcl.Diagnosti } for _, block := range content.Blocks { switch block.Type { + case sourceLabel: + ref, moreDiags := p.decodeBuildSource(block) + diags = append(diags, moreDiags...) + if moreDiags.HasErrors() { + continue + } + build.Sources = append(build.Sources, ref) case buildProvisionerLabel: p, moreDiags := p.decodeProvisioner(block) diags = append(diags, moreDiags...) diff --git a/hcl2template/types.build.post-processor.go b/hcl2template/types.build.post-processor.go index 8add11514..bedbb1ad0 100644 --- a/hcl2template/types.build.post-processor.go +++ b/hcl2template/types.build.post-processor.go @@ -49,7 +49,7 @@ func (p *Parser) decodePostProcessor(block *hcl.Block) (*PostProcessorBlock, hcl return postProcessor, diags } -func (cfg *PackerConfig) startPostProcessor(source *SourceBlock, pp *PostProcessorBlock, ectx *hcl.EvalContext, generatedVars map[string]string) (packer.PostProcessor, hcl.Diagnostics) { +func (cfg *PackerConfig) startPostProcessor(source SourceBlock, pp *PostProcessorBlock, ectx *hcl.EvalContext, generatedVars map[string]string) (packer.PostProcessor, hcl.Diagnostics) { // ProvisionerBlock represents a detected but unparsed provisioner var diags hcl.Diagnostics diff --git a/hcl2template/types.build.provisioners.go b/hcl2template/types.build.provisioners.go index df10d77dc..c41ba2eb4 100644 --- a/hcl2template/types.build.provisioners.go +++ b/hcl2template/types.build.provisioners.go @@ -77,7 +77,7 @@ func (p *Parser) decodeProvisioner(block *hcl.Block) (*ProvisionerBlock, hcl.Dia return provisioner, diags } -func (cfg *PackerConfig) startProvisioner(source *SourceBlock, pb *ProvisionerBlock, ectx *hcl.EvalContext, generatedVars map[string]string) (packer.Provisioner, hcl.Diagnostics) { +func (cfg *PackerConfig) startProvisioner(source SourceBlock, pb *ProvisionerBlock, ectx *hcl.EvalContext, generatedVars map[string]string) (packer.Provisioner, hcl.Diagnostics) { var diags hcl.Diagnostics provisioner, err := cfg.provisionersSchemas.Start(pb.PType) diff --git a/hcl2template/types.packer_config.go b/hcl2template/types.packer_config.go index 7306f8763..81eb4bad8 100644 --- a/hcl2template/types.packer_config.go +++ b/hcl2template/types.packer_config.go @@ -18,7 +18,7 @@ type PackerConfig struct { Basedir string // Available Source blocks - Sources map[SourceRef]*SourceBlock + Sources map[SourceRef]SourceBlock // InputVariables and LocalVariables are the list of defined input and // local variables. They are of the same type but are not used in the same @@ -194,7 +194,7 @@ func (c *PackerConfig) evaluateLocalVariable(local *Local) hcl.Diagnostics { // getCoreBuildProvisioners takes a list of provisioner block, starts according // provisioners and sends parsed HCL2 over to it. -func (cfg *PackerConfig) getCoreBuildProvisioners(source *SourceBlock, blocks []*ProvisionerBlock, ectx *hcl.EvalContext, generatedVars map[string]string) ([]packer.CoreBuildProvisioner, hcl.Diagnostics) { +func (cfg *PackerConfig) getCoreBuildProvisioners(source SourceBlock, blocks []*ProvisionerBlock, ectx *hcl.EvalContext, generatedVars map[string]string) ([]packer.CoreBuildProvisioner, hcl.Diagnostics) { var diags hcl.Diagnostics res := []packer.CoreBuildProvisioner{} for _, pb := range blocks { @@ -234,7 +234,7 @@ func (cfg *PackerConfig) getCoreBuildProvisioners(source *SourceBlock, blocks [] // getCoreBuildProvisioners takes a list of post processor block, starts // according provisioners and sends parsed HCL2 over to it. -func (cfg *PackerConfig) getCoreBuildPostProcessors(source *SourceBlock, blocks []*PostProcessorBlock, ectx *hcl.EvalContext, generatedVars map[string]string) ([]packer.CoreBuildPostProcessor, hcl.Diagnostics) { +func (cfg *PackerConfig) getCoreBuildPostProcessors(source SourceBlock, blocks []*PostProcessorBlock, ectx *hcl.EvalContext, generatedVars map[string]string) ([]packer.CoreBuildPostProcessor, hcl.Diagnostics) { var diags hcl.Diagnostics res := []packer.CoreBuildPostProcessor{} for _, ppb := range blocks { @@ -262,15 +262,17 @@ func (cfg *PackerConfig) GetBuilds(opts packer.GetBuildsOptions) ([]packer.Build for _, build := range cfg.Builds { for _, from := range build.Sources { - src, found := cfg.Sources[from] + src, found := cfg.Sources[from.Ref()] if !found { diags = append(diags, &hcl.Diagnostic{ Summary: "Unknown " + sourceLabel + " " + from.String(), Subject: build.HCL2Ref.DefRange.Ptr(), Severity: hcl.DiagError, + Detail: fmt.Sprintf("Known: %v", cfg.Sources), }) continue } + src.addition = from.addition // Apply the -only and -except command-line options to exclude matching builds. buildName := fmt.Sprintf("%s.%s", src.Type, src.Name) diff --git a/hcl2template/types.packer_config_test.go b/hcl2template/types.packer_config_test.go index 844038f19..e3675d478 100644 --- a/hcl2template/types.packer_config_test.go +++ b/hcl2template/types.packer_config_test.go @@ -1,10 +1,9 @@ package hcl2template import ( - "path/filepath" "testing" - "time" + . "github.com/hashicorp/packer/hcl2template/internal" "github.com/hashicorp/packer/packer" "github.com/zclconf/go-cty/cty" ) @@ -72,12 +71,16 @@ func TestParser_complete(t *testing.T) { }), }, }, - Sources: map[SourceRef]*SourceBlock{ - refVBIsoUbuntu1204: {Type: "virtualbox-iso", Name: "ubuntu-1204"}, + Sources: map[SourceRef]SourceBlock{ + refVBIsoUbuntu1204: {Type: "virtualbox-iso", Name: "ubuntu-1204"}, + refAWSEBSUbuntu1204: {Type: "amazon-ebs", Name: "ubuntu-1604"}, }, Builds: Builds{ &BuildBlock{ - Sources: []SourceRef{refVBIsoUbuntu1204}, + Sources: []SourceRef{ + refVBIsoUbuntu1204, + refAWSEBSUbuntu1204, + }, ProvisionerBlocks: []*ProvisionerBlock{ { PType: "shell", @@ -125,136 +128,40 @@ func TestParser_complete(t *testing.T) { }, }, }, - }, - false, - }, - {"dir with no config files", - defaultParser, - parseTestArgs{"testdata/empty", nil, nil}, - nil, - true, true, - nil, - false, - }, - {name: "inexistent dir", - parser: defaultParser, - args: parseTestArgs{"testdata/inexistent", nil, nil}, - parseWantCfg: nil, - parseWantDiags: true, - parseWantDiagHasErrors: true, - }, - {name: "folder named build.pkr.hcl with an unknown src", - parser: defaultParser, - args: parseTestArgs{"testdata/build.pkr.hcl", nil, nil}, - parseWantCfg: &PackerConfig{ - Basedir: "testdata/build.pkr.hcl", - Builds: Builds{ - &BuildBlock{ - Sources: []SourceRef{refAWSEBSUbuntu1204, refVBIsoUbuntu1204}, - ProvisionerBlocks: []*ProvisionerBlock{ - {PType: "shell"}, - {PType: "file"}, - }, - PostProcessors: []*PostProcessorBlock{ - {PType: "amazon-import"}, - }, - }, - }, - }, - parseWantDiags: false, - parseWantDiagHasErrors: false, - getBuildsWantBuilds: []packer.Build{}, - getBuildsWantDiags: true, - }, - {name: "unknown block type", - parser: defaultParser, - args: parseTestArgs{"testdata/unknown", nil, nil}, - parseWantCfg: &PackerConfig{ - Basedir: "testdata/unknown", - }, - parseWantDiags: true, - parseWantDiagHasErrors: true, - }, - {"provisioner with wrappers pause_before and max_retriers", - defaultParser, - parseTestArgs{"testdata/build/provisioner_paused_before_retry.pkr.hcl", nil, nil}, - &PackerConfig{ - Basedir: filepath.Join("testdata", "build"), - Sources: map[SourceRef]*SourceBlock{ - refVBIsoUbuntu1204: {Type: "virtualbox-iso", Name: "ubuntu-1204"}, - }, - Builds: Builds{ - &BuildBlock{ - Sources: []SourceRef{refVBIsoUbuntu1204}, - ProvisionerBlocks: []*ProvisionerBlock{ - { - PType: "shell", - PauseBefore: time.Second * 10, - MaxRetries: 5, - }, - }, - }, - }, - }, - false, false, - []packer.Build{ &packer.CoreBuild{ - Type: "virtualbox-iso.ubuntu-1204", + Type: "amazon-ebs.ubuntu-1604", Prepared: true, - Builder: emptyMockBuilder, + Builder: &MockBuilder{ + Config: MockConfig{ + NestedMockConfig: NestedMockConfig{ + String: "setting from build section", + Int: 42, + Tags: []MockTag{}, + }, + NestedSlice: []NestedMockConfig{}, + }, + }, Provisioners: []packer.CoreBuildProvisioner{ { - PType: "shell", - Provisioner: &packer.RetriedProvisioner{ - MaxRetries: 5, - Provisioner: &packer.PausedProvisioner{ - PauseBefore: time.Second * 10, - Provisioner: emptyMockProvisioner, - }, - }, + PType: "shell", + PName: "provisioner that does something", + Provisioner: basicMockProvisioner, }, + {PType: "file", Provisioner: basicMockProvisioner}, }, - PostProcessors: [][]packer.CoreBuildPostProcessor{}, - }, - }, - false, - }, - {"provisioner with wrappers timeout", - defaultParser, - parseTestArgs{"testdata/build/provisioner_timeout.pkr.hcl", nil, nil}, - &PackerConfig{ - Basedir: filepath.Join("testdata", "build"), - Sources: map[SourceRef]*SourceBlock{ - refVBIsoUbuntu1204: {Type: "virtualbox-iso", Name: "ubuntu-1204"}, - }, - Builds: Builds{ - &BuildBlock{ - Sources: []SourceRef{refVBIsoUbuntu1204}, - ProvisionerBlocks: []*ProvisionerBlock{ - { - PType: "shell", - Timeout: time.Second * 10, - }, - }, - }, - }, - }, - false, false, - []packer.Build{ - &packer.CoreBuild{ - Type: "virtualbox-iso.ubuntu-1204", - Prepared: true, - Builder: emptyMockBuilder, - Provisioners: []packer.CoreBuildProvisioner{ + PostProcessors: [][]packer.CoreBuildPostProcessor{ { - PType: "shell", - Provisioner: &packer.TimeoutProvisioner{ - Timeout: time.Second * 10, - Provisioner: emptyMockProvisioner, + { + PType: "amazon-import", + PName: "something", + PostProcessor: basicMockPostProcessor, + }, + { + PType: "amazon-import", + PostProcessor: basicMockPostProcessor, }, }, }, - PostProcessors: [][]packer.CoreBuildPostProcessor{}, }, }, false, diff --git a/hcl2template/types.source.go b/hcl2template/types.source.go index dbc5a9724..94c7aa538 100644 --- a/hcl2template/types.source.go +++ b/hcl2template/types.source.go @@ -16,10 +16,24 @@ type SourceBlock struct { Name string block *hcl.Block + + // addition will be merged into block to allow user to override builder settings + // per build.source block. + addition hcl.Body } -func (p *Parser) decodeSource(block *hcl.Block) (*SourceBlock, hcl.Diagnostics) { - source := &SourceBlock{ +// decodeBuildSource reads a used source block from a build: +// build { +// source "type.example" {} +// } +func (p *Parser) decodeBuildSource(block *hcl.Block) (SourceRef, hcl.Diagnostics) { + ref := sourceRefFromString(block.Labels[0]) + ref.addition = block.Body + return ref, nil +} + +func (p *Parser) decodeSource(block *hcl.Block) (SourceBlock, hcl.Diagnostics) { + source := SourceBlock{ Type: block.Labels[0], Name: block.Labels[1], block: block, @@ -33,13 +47,13 @@ func (p *Parser) decodeSource(block *hcl.Block) (*SourceBlock, hcl.Diagnostics) Detail: fmt.Sprintf("known builders: %v", p.BuilderSchemas.List()), Severity: hcl.DiagError, }) - return nil, diags + return source, diags } return source, diags } -func (cfg *PackerConfig) startBuilder(source *SourceBlock, ectx *hcl.EvalContext, opts packer.GetBuildsOptions) (packer.Builder, hcl.Diagnostics, []string) { +func (cfg *PackerConfig) startBuilder(source SourceBlock, ectx *hcl.EvalContext, opts packer.GetBuildsOptions) (packer.Builder, hcl.Diagnostics, []string) { var diags hcl.Diagnostics builder, err := cfg.builderSchemas.Start(source.Type) @@ -52,7 +66,12 @@ func (cfg *PackerConfig) startBuilder(source *SourceBlock, ectx *hcl.EvalContext return builder, diags, nil } - decoded, moreDiags := decodeHCL2Spec(source.block.Body, ectx, builder) + body := source.block.Body + if source.addition != nil { + body = hcl.MergeBodies([]hcl.Body{source.block.Body, source.addition}) + } + + decoded, moreDiags := decodeHCL2Spec(body, ectx, builder) diags = append(diags, moreDiags...) if moreDiags.HasErrors() { return nil, diags, nil @@ -92,6 +111,19 @@ func (source *SourceBlock) Ref() SourceRef { type SourceRef struct { Type string Name string + + // The content of this body will be merged into a new block to allow to + // override builder settings per build section. + addition hcl.Body +} + +// the 'addition' field makes of ref a different entry in the sources map, so +// Ref is here to make sure only one is returned. +func (r *SourceRef) Ref() SourceRef { + return SourceRef{ + Type: r.Type, + Name: r.Name, + } } // NoSource is the zero value of sourceRef, representing the absense of an diff --git a/hcl2template/types.source_test.go b/hcl2template/types.source_test.go index 423d20422..9a344765c 100644 --- a/hcl2template/types.source_test.go +++ b/hcl2template/types.source_test.go @@ -16,7 +16,7 @@ func TestParse_source(t *testing.T) { parseTestArgs{"testdata/sources/basic.pkr.hcl", nil, nil}, &PackerConfig{ Basedir: filepath.Join("testdata", "sources"), - Sources: map[SourceRef]*SourceBlock{ + Sources: map[SourceRef]SourceBlock{ { Type: "virtualbox-iso", Name: "ubuntu-1204", @@ -65,7 +65,7 @@ func TestParse_source(t *testing.T) { parseTestArgs{"testdata/sources/duplicate.pkr.hcl", nil, nil}, &PackerConfig{ Basedir: filepath.Join("testdata", "sources"), - Sources: map[SourceRef]*SourceBlock{ + Sources: map[SourceRef]SourceBlock{ { Type: "virtualbox-iso", Name: "ubuntu-1204", diff --git a/hcl2template/types.variables_test.go b/hcl2template/types.variables_test.go index 15f5fc9f6..df87594eb 100644 --- a/hcl2template/types.variables_test.go +++ b/hcl2template/types.variables_test.go @@ -162,15 +162,17 @@ func TestParse_variables(t *testing.T) { Name: "foo", }, }, - Sources: map[SourceRef]*SourceBlock{ - SourceRef{"null", "null-builder"}: &SourceBlock{ + Sources: map[SourceRef]SourceBlock{ + SourceRef{"null", "null-builder", nil}: SourceBlock{ Name: "null-builder", Type: "null", }, }, Builds: Builds{ &BuildBlock{ - Sources: []SourceRef{SourceRef{"null", "null-builder"}}, + Sources: []SourceRef{ + {"null", "null-builder", nil}, + }, }, }, }, diff --git a/helper/config/deprecated_options.go b/helper/config/deprecated_options.go index 9875b3750..538d50fe5 100644 --- a/helper/config/deprecated_options.go +++ b/helper/config/deprecated_options.go @@ -38,4 +38,6 @@ var DeprecatedOptions = []string{ "disk_eagerly_scrub", "iso_checksum_url", "iso_checksum_type", + "ssh_host_port_max", + "ssh_host_port_min", } diff --git a/website/data/docs-navigation.js b/website/data/docs-navigation.js index 9afe6a4aa..3b29ceaa9 100644 --- a/website/data/docs-navigation.js +++ b/website/data/docs-navigation.js @@ -14,6 +14,15 @@ export default [ 'syntax', 'expressions', 'syntax-json', + { + category: 'blocks', + content: [ + { + category: 'build', + content: [ 'source', 'provisioner', 'post-processor' ], + }, + 'locals', 'source', 'variable' ], + }, { category: 'functions', content: [ diff --git a/website/pages/docs/builders/qemu.mdx b/website/pages/docs/builders/qemu.mdx index 6cc0c02e3..a25907988 100644 --- a/website/pages/docs/builders/qemu.mdx +++ b/website/pages/docs/builders/qemu.mdx @@ -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' diff --git a/website/pages/docs/from-1.5/blocks/build/index.mdx b/website/pages/docs/from-1.5/blocks/build/index.mdx new file mode 100644 index 000000000..10e6b53ec --- /dev/null +++ b/website/pages/docs/from-1.5/blocks/build/index.mdx @@ -0,0 +1,35 @@ +--- +description: > + The source block defines what builders are started. +layout: docs +page_title: build - Blocks +sidebar_title: build +--- + +# The `build` block + +`@include 'from-1.5/beta-hcl2-note.mdx'` + +The `build` block defines what builders are started, how to `provision` them +and if necessary what to do with their artifacts using `post-process`. + +`@include 'from-1.5/builds/example-block.mdx'` + + +Define [top-level `source` blocks](/docs/from-1.5/blocks/source) to configure +your builders. The list of available builders can be found in the +[builders](/docs/builders) section. + +To use builders in a `build` block you can either: + +* Set the `sources` array of string with references to defined sources. + +* Define [build-level `source` blocks](/docs/from-1.5/blocks/build/source) or +`sources` to use builders. This also allows you to set specific fields. + +## Related + +* A list of [community +builders](/community-tools#community-builders) is available. + +* Create your own [custom builder](/docs/extending/custom-builders) ! diff --git a/website/pages/docs/from-1.5/blocks/build/post-processor.mdx b/website/pages/docs/from-1.5/blocks/build/post-processor.mdx new file mode 100644 index 000000000..dd8c16afd --- /dev/null +++ b/website/pages/docs/from-1.5/blocks/build/post-processor.mdx @@ -0,0 +1,29 @@ +--- +description: > + The post-processor block defines how a post-processor is configured. +layout: docs +page_title: post-processor - build - Blocks +sidebar_title: post-processor +--- + +# The `post-processor` block + +`@include 'from-1.5/beta-hcl2-note.mdx'` + +The `post-processor` block defines how a post-processor is configured. + +```hcl +# builds.pkr.hcl +build { + # ... + post-processor "checksum" { + checksum_types = [ "md5", "sha512" ] + keep_input_artifact = true + } +} +``` + +Post-processors run after the image is built by the builder and provisioned by +the provisioner(s). Post-processors are optional, and they can be used to +upload artifacts, re-package, or more. The list of available post-processors +can be found in the [post-processors](/docs/post-processors) section. \ No newline at end of file diff --git a/website/pages/docs/from-1.5/blocks/build/provisioner.mdx b/website/pages/docs/from-1.5/blocks/build/provisioner.mdx new file mode 100644 index 000000000..900fdacd9 --- /dev/null +++ b/website/pages/docs/from-1.5/blocks/build/provisioner.mdx @@ -0,0 +1,32 @@ +--- +description: > + The provisioner block defines how a provisioner is configured. +layout: docs +page_title: provisioner - build - Blocks +sidebar_title: provisioner +--- + +# The `provisioner` block + +`@include 'from-1.5/beta-hcl2-note.mdx'` + +The `provisioner` block defines how a provisioner is configured. + +```hcl +# builds.pkr.hcl +build { + # ... + provisioner "shell" { + inline = [ + "echo provisioning all the things", + "echo the value of 'foo' is '${var.foo}'", + ] + } +} +``` + +Provisioners use builtin and third-party software to install and configure the +machine image after booting. Provisioners prepare the system for use. + +The list of available provisioners can be found in the +[provisioners](/docs/provisioners) section. diff --git a/website/pages/docs/from-1.5/blocks/build/source.mdx b/website/pages/docs/from-1.5/blocks/build/source.mdx new file mode 100644 index 000000000..73b8747a2 --- /dev/null +++ b/website/pages/docs/from-1.5/blocks/build/source.mdx @@ -0,0 +1,30 @@ +--- +description: > + A source block nested in a build block allows you to use an already defined + source and to set specific fields. +layout: docs +page_title: source - build - Blocks +sidebar_title: source +--- + +# The `source` block + +`@include 'from-1.5/beta-hcl2-note.mdx'` + +A `source` block nested in a `build` block allows to use an already defined +source and to set specific fields. + +```hcl +# builds.pkr.hcl +build { + source "amazon-ebs.example" { + output = "specific-value" + } + # ... +} +``` + +-> **Note:** It is **not allowed** to set the same field in a top-level source + block and in a used source block. For example, if in the above example, the + top-level "amazon-ebs.example" source block also had an `output` field; + Packer would error. diff --git a/website/pages/docs/from-1.5/blocks/index.mdx b/website/pages/docs/from-1.5/blocks/index.mdx new file mode 100644 index 000000000..ea4fc2ed8 --- /dev/null +++ b/website/pages/docs/from-1.5/blocks/index.mdx @@ -0,0 +1,31 @@ +--- +layout: docs +page_title: Blocks - Configuration Language +sidebar_title: Blocks +description: |- + The HCL language has a number of blocks that can be used to configure builds. +--- + +# Built-in Blocks + +`@include 'from-1.5/beta-hcl2-note.mdx'` + +The Packer - HCL2 language includes a number of built-in blocks that you can +use. A block is a container for configuration. + +Blocks can be defined in multiple files and `packer build folder` will build +using solely the files from a directory named `folder`. + +Packer does not support user-defined blocks and so only the blocks built in to +the language are available for use. The navigation for this section includes a +list of all of the available built-in HCL2 blocks. + +## Config example: + +`@include 'from-1.5/variables/foo-block.mdx'` + +`@include 'from-1.5/locals/example-block.mdx'` + +`@include 'from-1.5/sources/example-block.mdx'` + +`@include 'from-1.5/builds/example-block.mdx'` diff --git a/website/pages/docs/from-1.5/blocks/locals.mdx b/website/pages/docs/from-1.5/blocks/locals.mdx new file mode 100644 index 000000000..0a3c767c3 --- /dev/null +++ b/website/pages/docs/from-1.5/blocks/locals.mdx @@ -0,0 +1,23 @@ +--- +description: > + The locals block also called the local-variable block defines locals within + your Packer configuration. +layout: docs +page_title: locals - Blocks +sidebar_title: locals +--- + +# The `locals` block + +`@include 'from-1.5/beta-hcl2-note.mdx'` + +The `locals` block, also called the `local-variable` block, defines locals within +your Packer configuration. + +`@include 'from-1.5/locals/example-block.mdx'` + +# More on variables + +- Read the [full locals](/docs/from-1.5/locals) description for a more + thorough read. +- Read the [variables guide](/guides/hcl/variables) for more examples. diff --git a/website/pages/docs/from-1.5/blocks/source.mdx b/website/pages/docs/from-1.5/blocks/source.mdx new file mode 100644 index 000000000..f129718ef --- /dev/null +++ b/website/pages/docs/from-1.5/blocks/source.mdx @@ -0,0 +1,50 @@ +--- +description: > + The top-level source block defines reusable builder configuration blocks +layout: docs +page_title: source - Blocks +sidebar_title: source +--- + +# The `source` block + +`@include 'from-1.5/beta-hcl2-note.mdx'` + +The top-level `source` block defines reusable builder configuration blocks: + +`@include 'from-1.5/sources/example-block.mdx'` + +You can start builders by refering to those source blocks form a [`build` +block](/docs/from-1.5/blocks/build), for example : + +```hcl +build { + source = [ + # Here Packer will use a default ami_name when saving the image. + "sources.amazon-ebs.example", + "sources.amazon-ebs.foo", + ] +} +``` + +The build-level [`source` block](/docs/from-1.5/blocks/build/source) allows to +set specific source fields. + +```hcl +build { + source "sources.amazon-ebs.example" { + # Here Packer will use the provided ami_name instead of defaulting it. + ami_name = "specific" + } +} +``` + +## Related + +* The list of available builders can be found in the [builders](/docs/builders) + section. + +* A list of [community + builders](/community-tools#community-builders) is available. + +* Create your own [custom builder](/docs/extending/custom-builders) ! diff --git a/website/pages/docs/from-1.5/blocks/variable.mdx b/website/pages/docs/from-1.5/blocks/variable.mdx new file mode 100644 index 000000000..16bf86f0f --- /dev/null +++ b/website/pages/docs/from-1.5/blocks/variable.mdx @@ -0,0 +1,37 @@ +--- +description: > + The variable block, also called the input-variable block, defines variables + within your Packer configuration. +layout: docs +page_title: variable - Blocks +sidebar_title: variable +--- + +# The `variable` block + +`@include 'from-1.5/beta-hcl2-note.mdx'` + +The `variable` block, also called the `input-variable` block, defines variables +within your Packer configuration. An input-variable cannot be used in another +input variable: we recommend using [locals](/docs/from-1.5/blocks/locals) for that instead. + +`@include 'from-1.5/variables/foo-block.mdx'` + +## Default value + +If a default value is set, the variable is optional. Otherwise, the variable +**must** be set. + +`@include 'from-1.5/variables/assignment.mdx'` + +Example of a variable assignment from a file: + +`@include 'from-1.5/variables/foo-pkrvar.mdx'` + +`@include 'from-1.5/variables/must-be-set.mdx'` + +# More on variables + +- Read the [full variables](/docs/from-1.5/variables) description for a more + thorough read. +- Read the [variables guide](/guides/hcl/variables) for more examples. diff --git a/website/pages/docs/from-1.5/expressions.mdx b/website/pages/docs/from-1.5/expressions.mdx index b7ecdf8d4..cd3ef307d 100644 --- a/website/pages/docs/from-1.5/expressions.mdx +++ b/website/pages/docs/from-1.5/expressions.mdx @@ -9,11 +9,7 @@ description: |- # Expressions --> **Note:** This page is about HCL2 in Packer 1.5 and later. HCL2 support for -Packer is still in Beta. Please see the [Packer Issue -Tracker](https://github.com/hashicorp/packer/issues/9176) for a list of -supported features. For the old-style stable configuration language see -[template docs](/docs/templates). +`@include 'from-1.5/beta-hcl2-note.mdx'` _Expressions_ are used to refer to or compute values within a configuration. The simplest expressions are just literal values, like `"hello"` or `5`, but diff --git a/website/pages/docs/from-1.5/functions/index.mdx b/website/pages/docs/from-1.5/functions/index.mdx index 525f15fd2..acfa04087 100644 --- a/website/pages/docs/from-1.5/functions/index.mdx +++ b/website/pages/docs/from-1.5/functions/index.mdx @@ -9,9 +9,7 @@ description: |- # Built-in Functions --> **Note:** This page is about HCL2 in Packer 1.5 and later. HCL2 support for -Packer is still in Beta. For the old-style stable configuration language see -[template docs](/docs/templates). +`@include 'from-1.5/beta-hcl2-note.mdx'` The HCL language includes a number of built-in functions that you can call from within expressions to transform and combine values. The general diff --git a/website/pages/docs/from-1.5/index.mdx b/website/pages/docs/from-1.5/index.mdx index d2d218d37..e5fb91b29 100644 --- a/website/pages/docs/from-1.5/index.mdx +++ b/website/pages/docs/from-1.5/index.mdx @@ -10,11 +10,7 @@ description: |- # HCL Configuration Language --> **Note:** This page is about HCL2 in Packer 1.5 and later. HCL2 support for -Packer is still in Beta. Please see the [Packer Issue -Tracker](https://github.com/hashicorp/packer/issues/9176) for a list of -supported features. For the old-style stable configuration language see -[template docs](/docs/templates). +`@include 'from-1.5/beta-hcl2-note.mdx'` Packer uses the Hashicorp Configuration Language - HCL - designed to allow concise descriptions of the required steps to get to a build file. This page diff --git a/website/pages/docs/from-1.5/locals.mdx b/website/pages/docs/from-1.5/locals.mdx index 2d2f45a3d..f482be743 100644 --- a/website/pages/docs/from-1.5/locals.mdx +++ b/website/pages/docs/from-1.5/locals.mdx @@ -9,11 +9,7 @@ description: >- # Local Values --> **Note:** This page is about HCL2 in Packer 1.5 and later. HCL2 support for -Packer is still in Beta. Please see the [Packer Issue -Tracker](https://github.com/hashicorp/packer/issues/9176) for a list of -supported features. For the old-style stable configuration language see -[template docs](/docs/templates). +`@include 'from-1.5/beta-hcl2-note.mdx'` Local values assign a name to an expression, that can then be used multiple times within a folder. diff --git a/website/pages/docs/from-1.5/syntax-json.mdx b/website/pages/docs/from-1.5/syntax-json.mdx index 2eb90708f..238b1f0ca 100644 --- a/website/pages/docs/from-1.5/syntax-json.mdx +++ b/website/pages/docs/from-1.5/syntax-json.mdx @@ -9,11 +9,7 @@ description: |- # JSON Configuration Syntax --> **Note:** This page is about HCL2 in Packer 1.5 and later. Whilst HCL2 -supports JSON the JSON - JSON and the HCL2 - JSON have differents formats for -Packer. HCL2 support for Packer is still in Beta. For the old-style stable -configuration language see [template -docs](/docs/templates). +`@include 'from-1.5/beta-hcl2-note.mdx'` Most Packer configurations are written in [the native HCL syntax](/docs/from-1.5/syntax), which is designed to be easy for humans to read and diff --git a/website/pages/docs/from-1.5/syntax.mdx b/website/pages/docs/from-1.5/syntax.mdx index 602d22512..ce6e8e5f7 100644 --- a/website/pages/docs/from-1.5/syntax.mdx +++ b/website/pages/docs/from-1.5/syntax.mdx @@ -10,11 +10,7 @@ description: |- # HCL Configuration Syntax --> **Note:** This page is about HCL2 in Packer 1.5 and later. HCL2 support for -Packer is still in Beta. Please see the [Packer Issue -Tracker](https://github.com/hashicorp/packer/issues/9176) for a list of -supported features. For the old-style stable configuration language see -[template docs](/docs/templates). +`@include 'from-1.5/beta-hcl2-note.mdx'` Other pages in this section have described various configuration constructs that can appear in HCL. This page describes the lower-level syntax of the diff --git a/website/pages/docs/from-1.5/variables.mdx b/website/pages/docs/from-1.5/variables.mdx index 60f6214e8..f8ee0752f 100644 --- a/website/pages/docs/from-1.5/variables.mdx +++ b/website/pages/docs/from-1.5/variables.mdx @@ -9,11 +9,7 @@ description: |- # Input Variables --> **Note:** This page is about HCL2 in Packer 1.5 and later. HCL2 support for -Packer is still in Beta. Please see the [Packer Issue -Tracker](https://github.com/hashicorp/packer/issues/9176) for a list of -supported features. For the old-style stable configuration language see -[template docs](/docs/templates). +`@include 'from-1.5/beta-hcl2-note.mdx'` Input variables serve as parameters for a Packer build, allowing aspects of the build to be customized without altering the build's own source code. @@ -155,15 +151,7 @@ documentation about the build, and so it should be written from the perspective of the user of the build rather than its maintainer. For commentary for build maintainers, use comments. -## Assigning Values to build Variables - -When variables are declared in the build of your configuration, they can be set -in a number of ways: - -- Individually, with the `-var` command line option. -- In variable definitions (`.pkrvars.hcl`) files, either specified on the - command line or automatically loaded. -- As environment variables. +`@include 'from-1.5/variables/assignment.mdx'` The following sections describe these options in more detail. @@ -285,40 +273,7 @@ precedence over earlier ones: ~> **Important:** Variables with map and object values behave the same way as other variables: the last value found overrides the previous values. -### A variable value must be known: - -Take the following variable for example: - -```hcl -variable "foo" { - type = string -``` - -Here `foo` must have a known value but you can default it to `null` to make -this behavior optional : - -| | no default | `default = null` | `default = "xy"` | -| :---------------------------: | :--------------------------: | :--------------: | :--------------: | -| foo unused | error, "foo needs to be set" | - | - | -| var.foo | error, "foo needs to be set" | null¹ | xy | -| `PKR_VAR_foo=yz`
var.foo | yz | yz | yz | -| `-var foo=yz`
var.foo | yz | yz | yz | - -1: Null is a valid value. Packer will only error when the receiving field needs -a value, example: - -```hcl -variable "example" { - type = string - default = null -} - -source "example" "foo" { - arg = var.example -} -``` - -In the above case, as long as "arg" is optional for an "example" source, there is no error and arg won’t be set. +`@include 'from-1.5/variables/must-be-set.mdx'` ### Setting an unknown variable will not always fail: diff --git a/website/pages/partials/builder/qemu/CommConfig-not-required.mdx b/website/pages/partials/builder/qemu/CommConfig-not-required.mdx new file mode 100644 index 000000000..53f6138ba --- /dev/null +++ b/website/pages/partials/builder/qemu/CommConfig-not-required.mdx @@ -0,0 +1,14 @@ + + +- `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. + \ No newline at end of file diff --git a/website/pages/partials/builder/qemu/Config-not-required.mdx b/website/pages/partials/builder/qemu/Config-not-required.mdx index edc950048..d6a40041e 100644 --- a/website/pages/partials/builder/qemu/Config-not-required.mdx +++ b/website/pages/partials/builder/qemu/Config-not-required.mdx @@ -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. diff --git a/website/pages/partials/builders/community_builders.mdx b/website/pages/partials/builders/community_builders.mdx index ffd7c068c..79598629b 100644 --- a/website/pages/partials/builders/community_builders.mdx +++ b/website/pages/partials/builders/community_builders.mdx @@ -5,10 +5,6 @@ - [packer-builder-arm-image](https://github.com/solo-io/packer-builder-arm-image) - simple builder lets you extend on existing system images. - [packer-builder-arm](https://github.com/mkaczanowski/packer-builder-arm) - flexible builder lets you extend or build images from scratch with variety of options (ie. custom partition table). -- [vSphere builder](https://github.com/jetbrains-infra/packer-builder-vsphere) - - A builder for interacting directly with the vSphere API rather than the esx - host directly. - - [Vultr builder](https://github.com/vultr/packer-builder-vultr) - A builder for creating [Vultr](https://www.vultr.com/) snapshots. diff --git a/website/pages/partials/from-1.5/beta-hcl2-note.mdx b/website/pages/partials/from-1.5/beta-hcl2-note.mdx new file mode 100644 index 000000000..c9f996646 --- /dev/null +++ b/website/pages/partials/from-1.5/beta-hcl2-note.mdx @@ -0,0 +1,5 @@ +-> **Note:** This page is about HCL2 in Packer 1.5 and later. HCL2 support for +Packer is still in Beta. Please see the [Packer Issue +Tracker](https://github.com/hashicorp/packer/issues/9176) for a list of +supported features. For the old-style stable configuration language see +[template docs](/docs/templates). \ No newline at end of file diff --git a/website/pages/partials/from-1.5/builds/example-block.mdx b/website/pages/partials/from-1.5/builds/example-block.mdx new file mode 100644 index 000000000..811ca559c --- /dev/null +++ b/website/pages/partials/from-1.5/builds/example-block.mdx @@ -0,0 +1,28 @@ +```hcl +# build.pkr.hcl +build { + + sources = [ + # use the plural `sources` block to simply use sources + # without changing any field. + "source.amazon-ebs.example", + ] + + source "source.amazon-ebs.example" { + # Use the singular `source` block set + # specific fields. + # Note that fields cannot be overwritten, in other words, you cannot + # set the 'output' field from the top-level source block and here. + output = "different value" + name = var.foo + } + + provisioner "shell-local" { + inline = ["echo Hello World"] + } + + post-processor "shell-local" { + inline = ["echo Hello World"] + } +} +``` \ No newline at end of file diff --git a/website/pages/partials/from-1.5/locals/example-block.mdx b/website/pages/partials/from-1.5/locals/example-block.mdx new file mode 100644 index 000000000..c0cb5e663 --- /dev/null +++ b/website/pages/partials/from-1.5/locals/example-block.mdx @@ -0,0 +1,9 @@ +```hcl +# locals.pkr.hcl +locals { + # locals can be bare values like: + wee = local.baz + # locals can also be set with input variables : + baz = "Foo is '${var.foo}'" +} +``` \ No newline at end of file diff --git a/website/pages/partials/from-1.5/sources/example-block.mdx b/website/pages/partials/from-1.5/sources/example-block.mdx new file mode 100644 index 000000000..05b2c5012 --- /dev/null +++ b/website/pages/partials/from-1.5/sources/example-block.mdx @@ -0,0 +1,6 @@ +```hcl +# sources.pkr.hcl +source "amazon-ebs" "example" { + // ... +} +``` \ No newline at end of file diff --git a/website/pages/partials/from-1.5/variables/assignment.mdx b/website/pages/partials/from-1.5/variables/assignment.mdx new file mode 100644 index 000000000..c4cc41297 --- /dev/null +++ b/website/pages/partials/from-1.5/variables/assignment.mdx @@ -0,0 +1,8 @@ +## Assigning Values to build Variables + +Once a variable is declared in your configuration, you can set it: + +- Individually, with the `-var foo=bar` command line option. +- In variable definitions (`.pkrvars.hcl`) files, either specified on the + command line or automatically loaded. +- As environment variables, for example: `PKR_VAR_foo=bar` \ No newline at end of file diff --git a/website/pages/partials/from-1.5/variables/foo-block.mdx b/website/pages/partials/from-1.5/variables/foo-block.mdx new file mode 100644 index 000000000..ca6601526 --- /dev/null +++ b/website/pages/partials/from-1.5/variables/foo-block.mdx @@ -0,0 +1,8 @@ +```hcl +# variables.pkr.hcl +variable "foo" { + type = string + default = "the default value of the `foo` variable" + description = "description of the `foo` variable" +} +``` \ No newline at end of file diff --git a/website/pages/partials/from-1.5/variables/foo-pkrvar.mdx b/website/pages/partials/from-1.5/variables/foo-pkrvar.mdx new file mode 100644 index 000000000..04f44e1be --- /dev/null +++ b/website/pages/partials/from-1.5/variables/foo-pkrvar.mdx @@ -0,0 +1,4 @@ +```hcl +# foo.pkrvars.hcl +foo = "value" +``` diff --git a/website/pages/partials/from-1.5/variables/must-be-set.mdx b/website/pages/partials/from-1.5/variables/must-be-set.mdx new file mode 100644 index 000000000..1413aeab2 --- /dev/null +++ b/website/pages/partials/from-1.5/variables/must-be-set.mdx @@ -0,0 +1,34 @@ +## A variable value must be known: + +Take the following variable for example: + +```hcl +variable "foo" { + type = string +``` + +Here `foo` must have a known value but you can default it to `null` to make +this behavior optional : + +| | no default | `default = null` | `default = "xy"` | +| :---------------------------: | :--------------------------: | :--------------: | :--------------: | +| foo unused | error, "foo needs to be set" | - | - | +| var.foo | error, "foo needs to be set" | null¹ | xy | +| `PKR_VAR_foo=yz`
var.foo | yz | yz | yz | +| `-var foo=yz`
var.foo | yz | yz | yz | + +1: Null is a valid value. Packer will only error when the receiving field needs +a value, example: + +```hcl +variable "example" { + type = string + default = null +} + +source "example" "foo" { + arg = var.example +} +``` + +In the above case, as long as "arg" is optional for an "example" source, there is no error and arg won’t be set. \ No newline at end of file