File: config.go

package info (click to toggle)
packer 1.6.6%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 33,156 kB
  • sloc: sh: 1,154; python: 619; makefile: 251; ruby: 205; xml: 97
file content (215 lines) | stat: -rw-r--r-- 8,067 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
//go:generate struct-markdown

package bootcommand

import (
	"fmt"
	"strings"
	"time"

	"github.com/hashicorp/packer/packer-plugin-sdk/template/interpolate"
)

// PackerKeyEnv is used to specify the key interval (delay) between keystrokes
// sent to the VM, typically in boot commands. This is to prevent host CPU
// utilization from causing key presses to be skipped or repeated incorrectly.
const PackerKeyEnv = "PACKER_KEY_INTERVAL"

// PackerKeyDefault 100ms is appropriate for shared build infrastructure while a
// shorter delay (e.g. 10ms) can be used on a workstation. See PackerKeyEnv.
const PackerKeyDefault = 100 * time.Millisecond

// The boot configuration is very important: `boot_command` specifies the keys
// to type when the virtual machine is first booted in order to start the OS
// installer. This command is typed after boot_wait, which gives the virtual
// machine some time to actually load.
//
// The boot_command is an array of strings. The strings are all typed in
// sequence. It is an array only to improve readability within the template.
//
// There are a set of special keys available. If these are in your boot
// command, they will be replaced by the proper key:
//
// -   `<bs>` - Backspace
//
// -   `<del>` - Delete
//
// -   `<enter> <return>` - Simulates an actual "enter" or "return" keypress.
//
// -   `<esc>` - Simulates pressing the escape key.
//
// -   `<tab>` - Simulates pressing the tab key.
//
// -   `<f1> - <f12>` - Simulates pressing a function key.
//
// -   `<up> <down> <left> <right>` - Simulates pressing an arrow key.
//
// -   `<spacebar>` - Simulates pressing the spacebar.
//
// -   `<insert>` - Simulates pressing the insert key.
//
// -   `<home> <end>` - Simulates pressing the home and end keys.
//
// -   `<pageUp> <pageDown>` - Simulates pressing the page up and page down
//     keys.
//
// -   `<menu>` - Simulates pressing the Menu key.
//
// -   `<leftAlt> <rightAlt>` - Simulates pressing the alt key.
//
// -   `<leftCtrl> <rightCtrl>` - Simulates pressing the ctrl key.
//
// -   `<leftShift> <rightShift>` - Simulates pressing the shift key.
//
// -   `<leftSuper> <rightSuper>` - Simulates pressing the ⌘ or Windows key.
//
// -   `<wait> <wait5> <wait10>` - Adds a 1, 5 or 10 second pause before
//     sending any additional keys. This is useful if you have to generally
//     wait for the UI to update before typing more.
//
// -   `<waitXX>` - Add an arbitrary pause before sending any additional keys.
//     The format of `XX` is a sequence of positive decimal numbers, each with
//     optional fraction and a unit suffix, such as `300ms`, `1.5h` or `2h45m`.
//     Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For
//     example `<wait10m>` or `<wait1m20s>`.
//
// -   `<XXXOn> <XXXOff>` - Any printable keyboard character, and of these
//      "special" expressions, with the exception of the `<wait>` types, can
//      also be toggled on or off. For example, to simulate ctrl+c, use
//      `<leftCtrlOn>c<leftCtrlOff>`. Be sure to release them, otherwise they
//      will be held down until the machine reboots. To hold the `c` key down,
//      you would use `<cOn>`. Likewise, `<cOff>` to release.
//
// -   `{{ .HTTPIP }} {{ .HTTPPort }}` - The IP and port, respectively of an
//     HTTP server that is started serving the directory specified by the
//     `http_directory` configuration parameter. If `http_directory` isn't
//     specified, these will be blank!
//
// -   `{{ .Name }}` - The name of the VM.
//
// Example boot command. This is actually a working boot command used to start an
// CentOS 6.4 installer:
//
// In JSON:
//
// ```json
// "boot_command": [
//     "<tab><wait>",
//     " ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/centos6-ks.cfg<enter>"
//  ]
// ```
//
// In HCL2:
//
// ```hcl
// boot_command = [
//     "<tab><wait>",
//     " ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/centos6-ks.cfg<enter>"
//  ]
// ```
//
// The example shown below is a working boot command used to start an Ubuntu
// 12.04 installer:
//
// In JSON:
//
// ```json
// "boot_command": [
//   "<esc><esc><enter><wait>",
//   "/install/vmlinuz noapic ",
//   "preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg ",
//   "debian-installer=en_US auto locale=en_US kbd-chooser/method=us ",
//   "hostname={{ .Name }} ",
//   "fb=false debconf/frontend=noninteractive ",
//   "keyboard-configuration/modelcode=SKIP keyboard-configuration/layout=USA ",
//   "keyboard-configuration/variant=USA console-setup/ask_detect=false ",
//   "initrd=/install/initrd.gz -- <enter>"
// ]
// ```
//
// In HCL2:
//
// ```hcl
// boot_command = [
//   "<esc><esc><enter><wait>",
//   "/install/vmlinuz noapic ",
//   "preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg ",
//   "debian-installer=en_US auto locale=en_US kbd-chooser/method=us ",
//   "hostname={{ .Name }} ",
//   "fb=false debconf/frontend=noninteractive ",
//   "keyboard-configuration/modelcode=SKIP keyboard-configuration/layout=USA ",
//   "keyboard-configuration/variant=USA console-setup/ask_detect=false ",
//   "initrd=/install/initrd.gz -- <enter>"
// ]
// ```
//
// For more examples of various boot commands, see the sample projects from our
// [community templates page](/community-tools#templates).
type BootConfig struct {
	// Time to wait after sending a group of key pressses. The value of this
	// should be a duration. Examples are `5s` and `1m30s` which will cause
	// Packer to wait five seconds and one minute 30 seconds, respectively. If
	// this isn't specified, a sensible default value is picked depending on
	// the builder type.
	BootGroupInterval time.Duration `mapstructure:"boot_keygroup_interval"`
	// The time to wait after booting the initial virtual machine before typing
	// the `boot_command`. The value of this should be a duration. Examples are
	// `5s` and `1m30s` which will cause Packer to wait five seconds and one
	// minute 30 seconds, respectively. If this isn't specified, the default is
	// `10s` or 10 seconds. To set boot_wait to 0s, use a negative number, such
	// as "-1s"
	BootWait time.Duration `mapstructure:"boot_wait"`
	// This is an array of commands to type when the virtual machine is first
	// booted. The goal of these commands should be to type just enough to
	// initialize the operating system installer. Special keys can be typed as
	// well, and are covered in the section below on the boot command. If this
	// is not specified, it is assumed the installer will start itself.
	BootCommand []string `mapstructure:"boot_command"`
}

// The boot command "typed" character for character over a VNC connection to
// the machine, simulating a human actually typing the keyboard.
//
// Keystrokes are typed as separate key up/down events over VNC with a default
// 100ms delay. The delay alleviates issues with latency and CPU contention.
// You can tune this delay on a per-builder basis by specifying
// "boot_key_interval" in your Packer template.
type VNCConfig struct {
	BootConfig `mapstructure:",squash"`
	// Whether to create a VNC connection or not. A boot_command cannot be used
	// when this is true. Defaults to false.
	DisableVNC bool `mapstructure:"disable_vnc"`
	// Time in ms to wait between each key press
	BootKeyInterval time.Duration `mapstructure:"boot_key_interval"`
}

func (c *BootConfig) Prepare(ctx *interpolate.Context) (errs []error) {
	if c.BootWait == 0 {
		c.BootWait = 10 * time.Second
	}

	if c.BootCommand != nil {
		expSeq, err := GenerateExpressionSequence(c.FlatBootCommand())
		if err != nil {
			errs = append(errs, err)
		} else if vErrs := expSeq.Validate(); vErrs != nil {
			errs = append(errs, vErrs...)
		}
	}

	return
}

func (c *BootConfig) FlatBootCommand() string {
	return strings.Join(c.BootCommand, "")
}

func (c *VNCConfig) Prepare(ctx *interpolate.Context) (errs []error) {
	if len(c.BootCommand) > 0 && c.DisableVNC {
		errs = append(errs,
			fmt.Errorf("A boot command cannot be used when vnc is disabled."))
	}

	errs = append(errs, c.BootConfig.Prepare(ctx)...)
	return
}