Fix boot_command and update docs

This commit is contained in:
Moss 2020-06-12 12:42:00 +02:00
parent ba767d1663
commit 65cfb880fd
9 changed files with 91 additions and 185 deletions

View File

@ -7,14 +7,24 @@ import (
)
type KeyInput struct {
Message string
Scancode key.Code
Alt bool
Ctrl bool
Shift bool
}
func (vm *VirtualMachine) TypeOnKeyboard(spec types.UsbScanCodeSpec) (int32, error) {
func (vm *VirtualMachine) TypeOnKeyboard(input KeyInput) (int32, error) {
var spec types.UsbScanCodeSpec
spec.KeyEvents = append(spec.KeyEvents, types.UsbScanCodeSpecKeyEvent{
UsbHidCode: int32(input.Scancode)<<16 | 7,
Modifiers: &types.UsbScanCodeSpecModifierType{
LeftControl: &input.Ctrl,
LeftAlt: &input.Alt,
LeftShift: &input.Shift,
},
})
req := &types.PutUsbScanCodes{
This: vm.vm.Reference(),
Spec: spec,

View File

@ -69,8 +69,9 @@ type FlatConfig struct {
FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs" hcl:"floppy_dirs"`
FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label" hcl:"floppy_label"`
BootOrder *string `mapstructure:"boot_order" cty:"boot_order" hcl:"boot_order"`
BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"`
BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"`
BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"`
BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"`
HTTPIP *string `mapstructure:"http_ip" cty:"http_ip" hcl:"http_ip"`
WaitTimeout *string `mapstructure:"ip_wait_timeout" cty:"ip_wait_timeout" hcl:"ip_wait_timeout"`
SettleTimeout *string `mapstructure:"ip_settle_timeout" cty:"ip_settle_timeout" hcl:"ip_settle_timeout"`
@ -196,8 +197,9 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"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},
"boot_order": &hcldec.AttrSpec{Name: "boot_order", Type: cty.String, Required: false},
"boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false},
"boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false},
"boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false},
"boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false},
"http_ip": &hcldec.AttrSpec{Name: "http_ip", Type: cty.String, Required: false},
"ip_wait_timeout": &hcldec.AttrSpec{Name: "ip_wait_timeout", Type: cty.String, Required: false},
"ip_settle_timeout": &hcldec.AttrSpec{Name: "ip_settle_timeout", Type: cty.String, Required: false},

View File

@ -8,9 +8,7 @@ import (
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/vmware/govmomi/vim25/types"
"golang.org/x/mobile/event/key"
"log"
"time"
)
@ -79,35 +77,26 @@ func (s *StepBootCommand) Run(ctx context.Context, state multistep.StateBag) mul
ui.Say(fmt.Sprintf("HTTP server is working at http://%v:%v/", ip, port))
}
sendCodes := func(codes []key.Code, downs []bool) error {
var spec types.UsbScanCodeSpec
sendCodes := func(code key.Code, down bool) error {
var keyAlt, keyCtrl, keyShift bool
for i, code := range codes {
var keyAlt, keyCtrl, keyShift bool
switch code {
case key.CodeLeftAlt:
// <leftAltOn>
keyAlt = downs[i]
case key.CodeLeftControl:
// <leftCtrlOn>
keyCtrl = downs[i]
default:
keyShift = downs[i]
}
log.Printf("Sending code %s, shift %v", code, downs[i])
spec.KeyEvents = append(spec.KeyEvents, types.UsbScanCodeSpecKeyEvent{
UsbHidCode: int32(code)<<16 | 7,
Modifiers: &types.UsbScanCodeSpecModifierType{
LeftControl: &keyCtrl,
LeftAlt: &keyAlt,
LeftShift: &keyShift,
},
})
switch code {
case key.CodeLeftAlt:
// <leftAltOn>
keyAlt = down
case key.CodeLeftControl:
// <leftCtrlOn>
keyCtrl = down
default:
keyShift = down
}
_, err := vm.TypeOnKeyboard(spec)
_, err := vm.TypeOnKeyboard(driver.KeyInput{
Scancode: code,
Ctrl: keyCtrl,
Alt: keyAlt,
Shift: keyShift,
})
if err != nil {
return fmt.Errorf("error typing a boot command: %v", err)
}

View File

@ -1,52 +0,0 @@
package iso
import (
"bytes"
"context"
"github.com/hashicorp/packer/builder/vsphere/driver"
"github.com/hashicorp/packer/common/bootcommand"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"testing"
)
func TestStepBootCommand_Run(t *testing.T) {
state := new(multistep.BasicStateBag)
state.Put("ui", &packer.BasicUi{
Reader: new(bytes.Buffer),
Writer: new(bytes.Buffer),
})
state.Put("debug", false)
state.Put("vm", new(driver.VirtualMachine))
state.Put("http_port", 2222)
state.Put("http_ip", "0.0.0.0")
step := &StepBootCommand{
Config: &BootConfig{
BootConfig: bootcommand.BootConfig{
BootCommand: []string{
"<leftShiftOn><enter><wait><f6><wait><esc><wait>",
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
"<bs><bs><bs>",
"/install/vmlinuz",
" initrd=/install/initrd.gz",
" priority=critical",
" locale=en_US",
" file=/media/preseed_hardcoded_ip.cfg",
" netcfg/get_ipaddress=0.0.0.0",
" netcfg/get_gateway=0.0.0.0",
"<enter>",
},
},
},
}
step.Run(context.TODO(), state)
}

View File

@ -2,18 +2,19 @@ package bootcommand
import (
"fmt"
"github.com/hashicorp/packer/builder/vsphere/driver"
"github.com/hashicorp/packer/common"
"golang.org/x/mobile/event/key"
"log"
"os"
"strings"
"time"
"unicode"
"github.com/hashicorp/packer/builder/vsphere/driver"
"github.com/hashicorp/packer/common"
"golang.org/x/mobile/event/key"
)
// SendUsbScanCodes will be called to send codes to the VM
type SendUsbScanCodes func([]key.Code, []bool) error
type SendUsbScanCodes func(k key.Code, down bool) error
type usbDriver struct {
vm *driver.VirtualMachine
@ -23,9 +24,6 @@ type usbDriver struct {
specialMap map[string]key.Code
scancodeMap map[rune]key.Code
codeBuffer []key.Code
downBuffer []bool
// keyEvent can set this error which will prevent it from continuing
err error
}
@ -103,25 +101,27 @@ func NewUSBDriver(send SendUsbScanCodes, interval time.Duration) *usbDriver {
}
}
// Flush sends codes to the vm
func (d *usbDriver) Flush() error {
defer func() {
d.codeBuffer = nil
}()
if err := d.sendImpl(d.codeBuffer, d.downBuffer); err != nil {
func (d *usbDriver) keyEvent(k key.Code, down bool) error {
if d.err != nil {
return d.err
}
if err := d.sendImpl(k, down); err != nil {
d.err = err
return err
}
time.Sleep(d.interval)
return nil
}
func (d *usbDriver) Flush() error {
return nil
}
func (d *usbDriver) SendKey(k rune, action KeyAction) error {
keyShift := unicode.IsUpper(k) || strings.ContainsRune(shiftedChars, k)
keyCode := d.scancodeMap[k]
log.Printf("Sending char '%c', code %s, shift %v", k, keyCode, keyShift)
d.send(keyCode, keyShift)
return d.err
return d.keyEvent(keyCode, keyShift)
}
func (d *usbDriver) SendSpecial(special string, action KeyAction) error {
@ -133,18 +133,10 @@ func (d *usbDriver) SendSpecial(special string, action KeyAction) error {
switch action {
case KeyOn:
d.send(keyCode, true)
d.keyEvent(keyCode, true)
case KeyOff, KeyPress:
d.send(keyCode, false)
d.keyEvent(keyCode, false)
}
return d.err
}
// send stores the codes in an internal buffer. Use Flush to send them.
func (d *usbDriver) send(code key.Code, down bool) {
// slices to keep the input order
d.codeBuffer = append(d.codeBuffer, code)
d.downBuffer = append(d.downBuffer, down)
}

View File

@ -154,6 +154,11 @@ necessary for this build to succeed and can be found further down the page.
@include 'common/bootcommand/BootConfig.mdx'
Please note that for the Virtuabox builder, the IP address of the HTTP server
Packer launches for you to access files like the preseed file in the example
above (`{{ .HTTPIP }}`) is hardcoded to 10.0.2.2. If you change the network
of your VM you must guarantee that you can still access this HTTP server.
The boot command is sent to the VM through the `VBoxManage` utility in as few
invocations as possible. We send each character in groups of 25, with a default
delay of 100ms between groups. The delay alleviates issues with latency and CPU
@ -176,35 +181,8 @@ contention. If you notice missing keys, you can tune this delay by specifying
@include 'common/bootcommand/BootConfig-not-required.mdx'
@include 'builders/boot-command.mdx'
@include 'builders/virtualbox-ssh-key-pair.mdx'
Example boot command. This is actually a working boot command used to start an
Ubuntu 12.04 installer:
```text
[
"<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>"
]
```
Please note that for the Virtuabox builder, the IP address of the HTTP server
Packer launches for you to access files like the preseed file in the example
above (`{{ .HTTPIP }}`) is hardcoded to 10.0.2.2. If you change the network
of your VM you must guarantee that you can still access this HTTP server.
For more examples of various boot commands, see the sample projects from our
[community templates page](/community-tools#templates).
## Guest Additions
Packer will automatically download the proper guest additions for the version of

View File

@ -145,6 +145,11 @@ necessary for this build to succeed and can be found further down the page.
@include 'common/bootcommand/BootConfig.mdx'
Please note that for the Virtuabox builder, the IP address of the HTTP server
Packer launches for you to access files like the preseed file in the example
above (`{{ .HTTPIP }}`) is hardcoded to 10.0.2.2. If you change the network
of your VM you must guarantee that you can still access this HTTP server.
The boot command is sent to the VM through the `VBoxManage` utility in as few
invocations as possible. We send each character in groups of 25, with a default
delay of 100ms between groups. The delay alleviates issues with latency and CPU
@ -167,30 +172,8 @@ contention. If you notice missing keys, you can tune this delay by specifying
@include 'common/bootcommand/BootConfig-not-required.mdx'
@include 'builders/boot-command.mdx'
@include 'builders/virtualbox-ssh-key-pair.mdx'
Example boot command. This is actually a working boot command used to start an
Ubuntu 12.04 installer:
```text
[
"<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).
## Guest Additions
Packer will automatically download the proper guest additions for the version of

View File

@ -159,6 +159,11 @@ builder.
@include 'common/bootcommand/BootConfig.mdx'
Please note that for the Virtuabox builder, the IP address of the HTTP server
Packer launches for you to access files like the preseed file in the example
above (`{{ .HTTPIP }}`) is hardcoded to 10.0.2.2. If you change the network
of your VM you must guarantee that you can still access this HTTP server.
The boot command is sent to the VM through the `VBoxManage` utility in as few
invocations as possible. We send each character in groups of 25, with a default
delay of 100ms between groups. The delay alleviates issues with latency and CPU
@ -181,34 +186,8 @@ contention. If you notice missing keys, you can tune this delay by specifying
@include 'common/bootcommand/BootConfig-not-required.mdx'
@include 'builders/boot-command.mdx'
@include 'builders/virtualbox-ssh-key-pair.mdx'
Example boot command. This is actually a working boot command used to start an
Ubuntu 12.04 installer:
```text
[
"<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>"
]
```
Please note that for the Virtuabox builder, the IP address of the HTTP server
Packer launches for you to access files like the preseed file in the example
above (`{{ .HTTPIP }}`) is hardcoded to 10.0.2.2. If you change the network
of your VM you must guarantee that you can still access this HTTP server.
For more examples of various boot commands, see the sample projects from our
[community templates page](/community-tools#templates).
## Guest Additions

View File

@ -162,6 +162,31 @@ from the datastore. Example:
@include 'helper/communicator/WinRM-not-required.mdx'
## Boot Configuration
@include 'common/bootcommand/BootConfig.mdx'
We send each character to the VM with a default delay of 100ms between groups.
The delay alleviates possible issues with latency and CPU
contention. If you notice missing keys, you can tune this delay by specifying
"boot_keygroup_interval" in your Packer template, for example:
```json
{
"builders": [
{
"type": "vsphere-iso",
"boot_keygroup_interval": "500ms"
...
}
]
}
```
#### Optional:
@include 'common/bootcommand/BootConfig-not-required.mdx'
## Working with Clusters
#### Standalone Hosts