Skip to content

Commit

Permalink
feat: enable predefined VNC passwords
Browse files Browse the repository at this point in the history
This commit makes it possible to set a predefined password when
connecting to QEMU machines via VNC when `vnc_use_password` is `true`.

This way, having to set `PACKER_LOG=1` to retrieve the password is no
longer needed when troubleshooting builder VM bootstrap issues.

Signed-off-by: Carlos Nunez <13461447+carlosonunez@users.noreply.github.com>
  • Loading branch information
carlosonunez committed Nov 30, 2024
1 parent 5927a29 commit fde0902
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 10 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ dist/*
packer-plugin-scaffolding
example/output-ubuntu1804
crash.log
packer-plugin-qemu
2 changes: 2 additions & 0 deletions builder/qemu/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,8 @@ type Config struct {
// binded to for VNC. By default packer will use 127.0.0.1 for this. If you
// wish to bind to all interfaces use 0.0.0.0.
VNCBindAddress string `mapstructure:"vnc_bind_address" required:"false"`
// The password to set when VNCUsePassword == true.
VNCPassword string `mapstructure:"vnc_password" required:"false"`
// Whether or not to set a password on the VNC server. This option
// automatically enables the QMP socket. See `qmp_socket_path`. Defaults to
// `false`.
Expand Down
37 changes: 37 additions & 0 deletions builder/qemu/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/hashicorp/packer-plugin-sdk/common"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

var testPem = `
Expand Down Expand Up @@ -642,6 +643,42 @@ func TestBuilderPrepare_VNCPassword(t *testing.T) {
}
}

func TestVNCPasswordEmptyWhenUsePasswordFalse(t *testing.T) {
var c Config
config := testConfig()
config["vnc_use_password"] = false
config["vnc_password"] = "supersecret"
warns, err := c.Prepare(config)
require.NoError(t, err)
assert.Len(t, warns, 0, "bad: %#v", warns)
p := vncpwd{}
assert.Empty(t, p.VNCPassword(&c))
}

func TestVNCPasswordRandomWhenVNCPasswordEmpty(t *testing.T) {
var c Config
config := testConfig()
config["vnc_use_password"] = true
config["vnc_password"] = ""
warns, err := c.Prepare(config)
require.NoError(t, err)
assert.Len(t, warns, 0, "bad: %#v", warns)
p := vncpwd{}
assert.Len(t, p.VNCPassword(&c), 8)
}

func TestVNCPasswordSetWhenVNCPasswordNotEmpty(t *testing.T) {
var c Config
config := testConfig()
config["vnc_use_password"] = true
config["vnc_password"] = "supersecret"
warns, err := c.Prepare(config)
require.NoError(t, err)
assert.Len(t, warns, 0, "bad: %#v", warns)
p := vncpwd{}
assert.Equal(t, p.VNCPassword(&c), config["vnc_password"])
}

func TestCommConfigPrepare_BackwardsCompatibility(t *testing.T) {
var c Config
config := testConfig()
Expand Down
21 changes: 11 additions & 10 deletions builder/qemu/step_configure_vnc.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,15 @@ type stepConfigureVNC struct {
l *net.Listener
}

func VNCPassword() string {
type vncpwd struct{}

func (p *vncpwd) VNCPassword(c *Config) string {
if !c.VNCUsePassword {
return ""
}
if len(c.VNCPassword) != 0 {
return c.VNCPassword
}
length := int(8)

charSet := []byte("012345689abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
Expand All @@ -39,7 +47,6 @@ func VNCPassword() string {
for i := 0; i < length; i++ {
password[i] = charSet[rand.Intn(charSetLength)]
}

return string(password)
}

Expand All @@ -54,7 +61,6 @@ func (s *stepConfigureVNC) Run(ctx context.Context, state multistep.StateBag) mu
ui.Say(msg)
log.Print(msg)

var vncPassword string
var err error
s.l, err = net.ListenRangeConfig{
Addr: config.VNCBindAddress,
Expand All @@ -70,16 +76,11 @@ func (s *stepConfigureVNC) Run(ctx context.Context, state multistep.StateBag) mu
}
s.l.Listener.Close() // free port, but don't unlock lock file
vncPort := s.l.Port

if config.VNCUsePassword {
vncPassword = VNCPassword()
} else {
vncPassword = ""
}
vncPassword := vncpwd{}

log.Printf("Found available VNC port: %d on IP: %s", vncPort, config.VNCBindAddress)
state.Put("vnc_port", vncPort)
state.Put("vnc_password", vncPassword)
state.Put("vnc_password", vncPassword.VNCPassword(config))

return multistep.ActionContinue
}
Expand Down
3 changes: 3 additions & 0 deletions docs-partials/builder/qemu/Config-not-required.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,9 @@
binded to for VNC. By default packer will use 127.0.0.1 for this. If you
wish to bind to all interfaces use 0.0.0.0.
- `vnc_password` (bool) - The password to set for the VNC password when
`vnc_use_password` is true; automatically generated otherwise.
- `vnc_use_password` (bool) - Whether or not to set a password on the VNC server. This option
automatically enables the QMP socket. See `qmp_socket_path`. Defaults to
`false`.
Expand Down

0 comments on commit fde0902

Please sign in to comment.