From c032d463d3a45dfd7b76079ed23b7ed4ed0d8470 Mon Sep 17 00:00:00 2001 From: Andreas Botzner Date: Mon, 14 Sep 2020 17:17:38 +0200 Subject: [PATCH] Bootcommand Fix For Proxmox Builder (#9885) --- builder/proxmox/bootcommand_driver.go | 105 +++++++++++++----- .../proxmox/step_type_boot_command_test.go | 28 +++++ 2 files changed, 105 insertions(+), 28 deletions(-) diff --git a/builder/proxmox/bootcommand_driver.go b/builder/proxmox/bootcommand_driver.go index 372e34829..304db3ef4 100644 --- a/builder/proxmox/bootcommand_driver.go +++ b/builder/proxmox/bootcommand_driver.go @@ -2,6 +2,7 @@ package proxmox import ( "fmt" + "strings" "time" "unicode" @@ -10,23 +11,33 @@ import ( ) type proxmoxDriver struct { - client commandTyper - vmRef *proxmox.VmRef - specialMap map[string]string - runeMap map[rune]string - interval time.Duration + client commandTyper + vmRef *proxmox.VmRef + specialMap map[string]string + runeMap map[rune]string + interval time.Duration + specialBuffer []string + normalBuffer []string } func NewProxmoxDriver(c commandTyper, vmRef *proxmox.VmRef, interval time.Duration) *proxmoxDriver { // Mappings for packer shorthand to qemu qkeycodes sMap := map[string]string{ - "spacebar": "spc", - "bs": "backspace", - "del": "delete", - "return": "ret", - "enter": "ret", - "pageUp": "pgup", - "pageDown": "pgdn", + "spacebar": "spc", + "bs": "backspace", + "del": "delete", + "return": "ret", + "enter": "ret", + "pageUp": "pgup", + "pageDown": "pgdn", + "leftshift": "shift", + "rightshift": "shift", + "leftalt": "alt", + "rightalt": "alt_r", + "leftctrl": "ctrl", + "rightctrl": "ctrl_r", + "leftsuper": "meta_l", + "rightsuper": "meta_r", } // Mappings for runes that need to be translated to special qkeycodes // Taken from https://github.com/qemu/qemu/blob/master/pc-bios/keymaps/en-us @@ -78,18 +89,26 @@ func NewProxmoxDriver(c commandTyper, vmRef *proxmox.VmRef, interval time.Durati } func (p *proxmoxDriver) SendKey(key rune, action bootcommand.KeyAction) error { - if special, ok := p.runeMap[key]; ok { - return p.send(special) + switch action.String() { + case "Press": + if special, ok := p.runeMap[key]; ok { + return p.send(special) + } + var keys string + if unicode.IsUpper(key) { + keys = fmt.Sprintf("shift-%c", unicode.ToLower(key)) + } else { + keys = fmt.Sprintf("%c", key) + } + return p.send(keys) + case "On": + key := fmt.Sprintf("%c", key) + p.normalBuffer = addKeyToBuffer(p.normalBuffer, key) + case "Off": + key := fmt.Sprintf("%c", key) + p.normalBuffer = removeKeyFromBuffer(p.normalBuffer, key) } - - var keys string - if unicode.IsUpper(key) { - keys = fmt.Sprintf("shift-%c", unicode.ToLower(key)) - } else { - keys = fmt.Sprintf("%c", key) - } - - return p.send(keys) + return nil } func (p *proxmoxDriver) SendSpecial(special string, action bootcommand.KeyAction) error { @@ -97,18 +116,48 @@ func (p *proxmoxDriver) SendSpecial(special string, action bootcommand.KeyAction if replacement, ok := p.specialMap[special]; ok { keys = replacement } - - return p.send(keys) + switch action.String() { + case "Press": + return p.send(keys) + case "On": + p.specialBuffer = addKeyToBuffer(p.specialBuffer, keys) + case "Off": + p.specialBuffer = removeKeyFromBuffer(p.specialBuffer, keys) + } + return nil } -func (p *proxmoxDriver) send(keys string) error { - err := p.client.Sendkey(p.vmRef, keys) +func (p *proxmoxDriver) send(key string) error { + keys := append(p.specialBuffer, p.normalBuffer...) + keys = append(keys, key) + keyEventString := bufferToKeyEvent(keys) + err := p.client.Sendkey(p.vmRef, keyEventString) if err != nil { return err } - time.Sleep(p.interval) return nil } func (p *proxmoxDriver) Flush() error { return nil } + +func bufferToKeyEvent(keys []string) string { + return strings.Join(keys, "-") +} +func addKeyToBuffer(buffer []string, key string) []string { + for _, value := range buffer { + if value == key { + return buffer + } + } + return append(buffer, key) +} +func removeKeyFromBuffer(buffer []string, key string) []string { + for index, value := range buffer { + if value == key { + buffer[index] = buffer[len(buffer)-1] + return buffer[:len(buffer)-1] + } + } + return buffer +} diff --git a/builder/proxmox/step_type_boot_command_test.go b/builder/proxmox/step_type_boot_command_test.go index c1581a3f8..99a759e80 100644 --- a/builder/proxmox/step_type_boot_command_test.go +++ b/builder/proxmox/step_type_boot_command_test.go @@ -52,6 +52,34 @@ func TestTypeBootCommand(t *testing.T) { expectedKeysSent: "shift-hellospcshift-worldspc2dot0fooshift-1barshift-2baz", expectedAction: multistep.ActionContinue, }, + { + name: "holding and releasing keys", + builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"helloworld"}}}, + expectCallSendkey: true, + expectedKeysSent: "shift-hshift-eshift-lshift-lshift-oshift-alt_r-wshift-alt_r-oshift-alt_r-rshift-alt_r-lshift-alt_r-d", + expectedAction: multistep.ActionContinue, + }, + { + name: "holding multiple alphabetical keys and shift", + builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"n"}}}, + expectCallSendkey: true, + expectedKeysSent: "shift-c-n", + expectedAction: multistep.ActionContinue, + }, + { + name: "noop keystrokes", + builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{""}}}, + expectCallSendkey: true, + expectedKeysSent: "", + expectedAction: multistep.ActionContinue, + }, + { + name: "noop keystrokes mixed", + builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"h"}}}, + expectCallSendkey: true, + expectedKeysSent: "shift-h", + expectedAction: multistep.ActionContinue, + }, { name: "without boot command sendkey should not be called", builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{}}},