Bootcommand Fix For Proxmox Builder (#9885)

This commit is contained in:
Andreas Botzner 2020-09-14 17:17:38 +02:00 committed by GitHub
parent caf65781d7
commit c032d463d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 105 additions and 28 deletions

View File

@ -2,6 +2,7 @@ package proxmox
import ( import (
"fmt" "fmt"
"strings"
"time" "time"
"unicode" "unicode"
@ -10,23 +11,33 @@ import (
) )
type proxmoxDriver struct { type proxmoxDriver struct {
client commandTyper client commandTyper
vmRef *proxmox.VmRef vmRef *proxmox.VmRef
specialMap map[string]string specialMap map[string]string
runeMap map[rune]string runeMap map[rune]string
interval time.Duration interval time.Duration
specialBuffer []string
normalBuffer []string
} }
func NewProxmoxDriver(c commandTyper, vmRef *proxmox.VmRef, interval time.Duration) *proxmoxDriver { func NewProxmoxDriver(c commandTyper, vmRef *proxmox.VmRef, interval time.Duration) *proxmoxDriver {
// Mappings for packer shorthand to qemu qkeycodes // Mappings for packer shorthand to qemu qkeycodes
sMap := map[string]string{ sMap := map[string]string{
"spacebar": "spc", "spacebar": "spc",
"bs": "backspace", "bs": "backspace",
"del": "delete", "del": "delete",
"return": "ret", "return": "ret",
"enter": "ret", "enter": "ret",
"pageUp": "pgup", "pageUp": "pgup",
"pageDown": "pgdn", "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 // 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 // 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 { func (p *proxmoxDriver) SendKey(key rune, action bootcommand.KeyAction) error {
if special, ok := p.runeMap[key]; ok { switch action.String() {
return p.send(special) 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)
} }
return nil
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)
} }
func (p *proxmoxDriver) SendSpecial(special string, action bootcommand.KeyAction) error { 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 { if replacement, ok := p.specialMap[special]; ok {
keys = replacement keys = replacement
} }
switch action.String() {
return p.send(keys) 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 { func (p *proxmoxDriver) send(key string) error {
err := p.client.Sendkey(p.vmRef, keys) keys := append(p.specialBuffer, p.normalBuffer...)
keys = append(keys, key)
keyEventString := bufferToKeyEvent(keys)
err := p.client.Sendkey(p.vmRef, keyEventString)
if err != nil { if err != nil {
return err return err
} }
time.Sleep(p.interval) time.Sleep(p.interval)
return nil return nil
} }
func (p *proxmoxDriver) Flush() error { 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
}

View File

@ -52,6 +52,34 @@ func TestTypeBootCommand(t *testing.T) {
expectedKeysSent: "shift-hellospcshift-worldspc2dot0fooshift-1barshift-2baz", expectedKeysSent: "shift-hellospcshift-worldspc2dot0fooshift-1barshift-2baz",
expectedAction: multistep.ActionContinue, expectedAction: multistep.ActionContinue,
}, },
{
name: "holding and releasing keys",
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"<leftShiftOn>hello<rightAltOn>world<leftShiftOff><rightAltOff>"}}},
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{"<cOn><leftShiftOn>n<leftShiftOff><cOff>"}}},
expectCallSendkey: true,
expectedKeysSent: "shift-c-n",
expectedAction: multistep.ActionContinue,
},
{
name: "noop keystrokes",
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"<cOn><leftShiftOn><cOff><leftAltOn><leftShiftOff><leftAltOff>"}}},
expectCallSendkey: true,
expectedKeysSent: "",
expectedAction: multistep.ActionContinue,
},
{
name: "noop keystrokes mixed",
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"<cOn><leftShiftOn><cOff>h<leftShiftOff>"}}},
expectCallSendkey: true,
expectedKeysSent: "shift-h",
expectedAction: multistep.ActionContinue,
},
{ {
name: "without boot command sendkey should not be called", name: "without boot command sendkey should not be called",
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{}}}, builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{}}},