Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add VritIO RNG device #195

Merged
merged 3 commits into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions builder/proxmox/clone/config.hcl2spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 65 additions & 1 deletion builder/proxmox/common/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: MPL-2.0

//go:generate packer-sdc struct-markdown
//go:generate packer-sdc mapstructure-to-hcl2 -type Config,NICConfig,diskConfig,vgaConfig,additionalISOsConfig,efiConfig
//go:generate packer-sdc mapstructure-to-hcl2 -type Config,NICConfig,diskConfig,rng0Config,vgaConfig,additionalISOsConfig,efiConfig

package proxmox

Expand Down Expand Up @@ -59,6 +59,7 @@ type Config struct {
EFIConfig efiConfig `mapstructure:"efi_config"`
EFIDisk string `mapstructure:"efidisk"`
Machine string `mapstructure:"machine"`
Rng0 rng0Config `mapstructure:"rng0"`
VGA vgaConfig `mapstructure:"vga"`
NICs []NICConfig `mapstructure:"network_adapters"`
Disks []diskConfig `mapstructure:"disks"`
Expand Down Expand Up @@ -114,6 +115,54 @@ type efiConfig struct {
PreEnrolledKeys bool `mapstructure:"pre_enrolled_keys"`
EFIType string `mapstructure:"efi_type"`
}

// - `rng0` (object): Configure Random Number Generator via VirtIO.
// A virtual hardware-RNG can be used to provide entropy from the host system to a guest VM helping avoid entropy starvation which might cause the guest system slow down.
// The device is sourced from a host device and guest, his use can be limited: `max_bytes` bytes of data will become available on a `period` ms timer.
// [PVE documentation](https://pve.proxmox.com/pve-docs/pve-admin-guide.html) recommends to always use a limiter to avoid guests using too many host resources.
//
// HCL2 example:
//
// ```hcl
//
// rng0 {
// source = "/dev/urandom"
// max_bytes = 1024
// period = 1000
// }
//
// ```
//
// JSON example:
//
// ```json
//
// {
// "rng0": {
// "source": "/dev/urandom",
// "max_bytes": 1024,
// "period": 1000
// }
// }
//
// ```
type rng0Config struct {
// Device on the host to gather entropy from.
// `/dev/urandom` should be preferred over `/dev/random` as Proxmox PVE documentation suggests.
// `/dev/hwrng` can be used to pass through a hardware RNG.
// Can be one of `/dev/urandom`, `/dev/random`, `/dev/hwrng`.
Source string `mapstructure:"source" required:"true"`
// Maximum bytes of entropy allowed to get injected into the guest every `period` milliseconds.
// Use a lower value when using `/dev/random` since can lead to entropy starvation on the host system.
// `0` disables limiting and according to PVE documentation is potentially dangerous for the host.
// Recommended value: `1024`.
MaxBytes int `mapstructure:"max_bytes" required:"true"`
// Period in milliseconds on which the the entropy-injection quota is reset.
// Can be a positive value.
// Recommended value: `1000`.
Period int `mapstructure:"period" required:"false"`
}

type vgaConfig struct {
Type string `mapstructure:"type"`
Memory int `mapstructure:"memory"`
Expand Down Expand Up @@ -391,6 +440,21 @@ func (c *Config) Prepare(upper interface{}, raws ...interface{}) ([]string, []st
errs = packersdk.MultiErrorAppend(errs, errors.New("efi_storage_pool not set for efi_config"))
}
}
if c.Rng0 != (rng0Config{}) {
if !(c.Rng0.Source == "/dev/urandom" || c.Rng0.Source == "/dev/random" || c.Rng0.Source == "/dev/hwrng") {
errs = packersdk.MultiErrorAppend(errs, errors.New("source must be one of \"/dev/urandom\", \"/dev/random\", \"/dev/hwrng\""))
}
if c.Rng0.MaxBytes < 0 {
errs = packersdk.MultiErrorAppend(errs, errors.New("max_bytes must be >= 0"))
} else {
if c.Rng0.MaxBytes == 0 {
warnings = append(warnings, "max_bytes is 0: potentially dangerous: this disables limiting the entropy allowed to get injected into the guest")
}
}
if c.Rng0.Period < 0 {
errs = packersdk.MultiErrorAppend(errs, errors.New("period must be >= 0"))
}
}

if errs != nil && len(errs.Errors) > 0 {
return nil, warnings, errs
Expand Down
29 changes: 29 additions & 0 deletions builder/proxmox/common/config.hcl2spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

83 changes: 83 additions & 0 deletions builder/proxmox/common/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,89 @@ func TestAdditionalISOs(t *testing.T) {

}

func TestRng0(t *testing.T) {
Rng0Test := []struct {
name string
rng_config rng0Config
expectFailure bool
}{
{
name: "no error",
expectFailure: false,
rng_config: rng0Config{
Source: "/dev/urandom",
MaxBytes: 1024,
Period: 1000,
},
},
{
name: "empty Source, error",
expectFailure: true,
rng_config: rng0Config{
Source: "",
MaxBytes: 1024,
Period: 1000,
},
},
{
name: "negative Period, error",
expectFailure: true,
rng_config: rng0Config{
Source: "/dev/urandom",
MaxBytes: 1024,
Period: -10,
},
},
{
name: "zero Period, noerror",
expectFailure: false,
rng_config: rng0Config{
Source: "/dev/urandom",
MaxBytes: 1024,
Period: 0,
},
},
{
name: "malformed Source error, error",
expectFailure: true,
rng_config: rng0Config{
Source: "/dev/abcde",
MaxBytes: 1024,
Period: 1000,
},
},
{
name: "negative Period, error",
expectFailure: true,
rng_config: rng0Config{
Source: "/dev/urandom",
MaxBytes: 1024,
Period: -10,
},
},
}

for _, tt := range Rng0Test {
t.Run(tt.name, func(t *testing.T) {
cfg := mandatoryConfig(t)
cfg["rng0"] = &tt.rng_config

var c Config
_, _, err := c.Prepare(&c, cfg)
if err != nil {
if !tt.expectFailure {
t.Fatalf("unexpected failure to prepare config: %s", err)
}
t.Logf("got expected failure: %s", err)
}

if err == nil && tt.expectFailure {
t.Errorf("expected failure, but prepare succeeded")
}
})
}
}

func TestSerials(t *testing.T) {
serialsTest := []struct {
name string
Expand Down
23 changes: 16 additions & 7 deletions builder/proxmox/common/step_start_vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multist
Bios: c.BIOS,
EFIDisk: generateProxmoxEfi(c.EFIConfig),
Machine: c.Machine,
RNGDrive: generateProxmoxRng0(c.Rng0),
QemuVga: generateProxmoxVga(c.VGA),
QemuNetworks: generateProxmoxNetworkAdapters(c.NICs),
QemuDisks: generateProxmoxDisks(c.Disks),
Expand Down Expand Up @@ -220,13 +221,8 @@ func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multist
// so let's make sure it's there.
if c.EFIConfig != (efiConfig{}) && c.Ctx.BuildType == "proxmox-clone" {
addEFIConfig := make(map[string]interface{})
err := config.CreateQemuEfiParams(addEFIConfig)
if err != nil {
err := fmt.Errorf("error creating EFI parameters: %s", err)
state.Put("error", err)
ui.Error(err.Error())
}
_, err = client.SetVmConfig(vmRef, addEFIConfig)
config.CreateQemuEfiParams(addEFIConfig)
mabeett marked this conversation as resolved.
Show resolved Hide resolved
_, err := client.SetVmConfig(vmRef, addEFIConfig)
if err != nil {
err := fmt.Errorf("error updating template: %s", err)
state.Put("error", err)
Expand Down Expand Up @@ -300,6 +296,19 @@ func generateProxmoxSerials(serials []string) proxmox.QemuDevices {
return devs
}

func generateProxmoxRng0(rng0 rng0Config) proxmox.QemuDevice {
dev := make(proxmox.QemuDevice)
setDeviceParamIfDefined(dev, "source", rng0.Source)

if rng0.MaxBytes >= 0 {
dev["max_bytes"] = rng0.MaxBytes
}
if rng0.Period > 0 {
dev["period"] = rng0.Period
}
return dev
}

func generateProxmoxVga(vga vgaConfig) proxmox.QemuDevice {
dev := make(proxmox.QemuDevice)
setDeviceParamIfDefined(dev, "type", vga.Type)
Expand Down
2 changes: 2 additions & 0 deletions builder/proxmox/iso/config.hcl2spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@

- `machine` (string) - Machine

- `rng0` (rng0Config) - Rng 0

- `vga` (vgaConfig) - VGA

- `network_adapters` ([]NICConfig) - NI Cs
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!-- Code generated from the comments of the rng0Config struct in builder/proxmox/common/config.go; DO NOT EDIT MANUALLY -->

- `period` (int) - Period in milliseconds on which the the entropy-injection quota is reset.
Can be a positive value.
Recommended value: `1000`.

<!-- End of code generated from the comments of the rng0Config struct in builder/proxmox/common/config.go; -->
13 changes: 13 additions & 0 deletions docs-partials/builder/proxmox/common/rng0Config-required.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Code generated from the comments of the rng0Config struct in builder/proxmox/common/config.go; DO NOT EDIT MANUALLY -->

- `source` (string) - Device on the host to gather entropy from.
`/dev/urandom` should be preferred over `/dev/random` as Proxmox PVE documentation suggests.
`/dev/hwrng` can be used to pass through a hardware RNG.
Can be one of `/dev/urandom`, `/dev/random`, `/dev/hwrng`.

- `max_bytes` (int) - Maximum bytes of entropy allowed to get injected into the guest every `period` milliseconds.
Use a lower value when using `/dev/random` since can lead to entropy starvation on the host system.
`0` disables limiting and according to PVE documentation is potentially dangerous for the host.
Recommended value: `1024`.

<!-- End of code generated from the comments of the rng0Config struct in builder/proxmox/common/config.go; -->
34 changes: 34 additions & 0 deletions docs-partials/builder/proxmox/common/rng0Config.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!-- Code generated from the comments of the rng0Config struct in builder/proxmox/common/config.go; DO NOT EDIT MANUALLY -->

- `rng0` (object): Configure Random Number Generator via VirtIO.
A virtual hardware-RNG can be used to provide entropy from the host system to a guest VM helping avoid entropy starvation which might cause the guest system slow down.
The device is sourced from a host device and guest, his use can be limited: `max_bytes` bytes of data will become available on a `period` ms timer.
[PVE documentation](https://pve.proxmox.com/pve-docs/pve-admin-guide.html) recommends to always use a limiter to avoid guests using too many host resources.

HCL2 example:

```hcl

rng0 {
source = "/dev/urandom"
max_bytes = 1024
period = 1000
}

```

JSON example:

```json

{
"rng0": {
"source": "/dev/urandom",
"max_bytes": 1024,
"period": 1000
}
}

```

<!-- End of code generated from the comments of the rng0Config struct in builder/proxmox/common/config.go; -->
12 changes: 12 additions & 0 deletions docs/builders/clone.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,18 @@ or responding to pattern `/dev/.+`. Example:

- `machine` - (string) - Set the machine type. Supported values are 'pc' or 'q35'.

#### VirtIO RNG device

@include 'builder/proxmox/common/rng0Config.mdx'

##### Required:

@include 'builder/proxmox/common/rng0Config-required.mdx'

##### Optional:

@include 'builder/proxmox/common/rng0Config-not-required.mdx'

## Example: Cloud-Init enabled Debian

Here is a basic example creating a Debian 10 server image. This assumes
Expand Down
Loading