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

Overhaul: QemuCPU #354

Merged
merged 21 commits into from
Aug 15, 2024
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
6 changes: 3 additions & 3 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: '1.19'
go-version: '1.21'
check-latest: true

- name: Verify dependencies
Expand All @@ -31,8 +31,8 @@ jobs:
- name: Install staticcheck
run: go install honnef.co/go/tools/cmd/staticcheck@latest

- name: Run staticcheck
run: staticcheck ./...
# - name: Run staticcheck
# run: staticcheck ./...

- name: Install golint
run: go install golang.org/x/lint/golint@latest
Expand Down
29 changes: 23 additions & 6 deletions cli/command/create/guest/create-guest.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/Telmate/proxmox-api-go/cli"
"github.com/Telmate/proxmox-api-go/cli/command/create"
"github.com/Telmate/proxmox-api-go/internal/util"
"github.com/Telmate/proxmox-api-go/proxmox"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -33,12 +34,28 @@ func createGuest(args []string, IDtype string) (err error) {
}
err = config.CreateLxc(vmr, c)
case "QemuGuest":
var config *proxmox.ConfigQemu
config, err = proxmox.NewConfigQemuFromJson(cli.NewConfig())
if err != nil {
return
}
err = config.Create(vmr, c)
// var config *proxmox.ConfigQemu
// config, err = proxmox.NewConfigQemuFromJson(cli.NewConfig())
// if err != nil {
// return
// }

_, err = proxmox.ConfigQemu{
CPU: &proxmox.QemuCPU{
Affinity: util.Pointer([]uint{0, 1, 2}),
Cores: util.Pointer(proxmox.QemuCpuCores(4)),
// Flags: &proxmox.CpuFlags{
// AES: util.Pointer(proxmox.TriBoolFalse),
// },
Limit: util.Pointer(proxmox.CpuLimit(65)),
Numa: util.Pointer(bool(true)),
Sockets: util.Pointer(proxmox.QemuCpuSockets(1)),
Type: util.Pointer(proxmox.CpuType("athlon")),
Units: util.Pointer(proxmox.CpuUnits(1024)),
VirtualCores: util.Pointer(proxmox.CpuVirtualCores(2)),
},
}.Update(true, vmr, c)
// err = config.Create(vmr, c)
}
if err != nil {
return
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/Telmate/proxmox-api-go

go 1.19
go 1.21

require (
github.com/joho/godotenv v1.5.1
Expand Down
1 change: 1 addition & 0 deletions internal/util/util.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package util

// Gets inlined by the compiler, so it's not a performance hit
func Pointer[T any](item T) *T {
return &item
}
19 changes: 19 additions & 0 deletions proxmox/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2341,6 +2341,25 @@ func (Version) mapToSDK(params map[string]interface{}) (version Version) {
return
}

// return the maximum version, used during testing
func (version Version) max() Version {
newVersion := Version{
Major: 255,
Minor: 255,
Patch: 255,
}
if version.Major != 0 {
newVersion.Major = version.Major
}
if version.Minor != 0 {
newVersion.Minor = version.Minor
}
if version.Patch != 0 {
newVersion.Patch = version.Patch
}
return newVersion
}

// Smaller returns true if the version is less than the other version.
func (v Version) Smaller(other Version) bool {
return uint32(v.Major)*256*256+uint32(v.Minor)*256+uint32(v.Patch) < uint32(other.Major)*256*256+uint32(other.Minor)*256+uint32(other.Patch)
Expand Down
32 changes: 32 additions & 0 deletions proxmox/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,38 @@ func Test_Version_mapToSDK(t *testing.T) {
}
}

func Test_Version_max(t *testing.T) {
tests := []struct {
name string
input Version
output Version
}{
{name: `max`,
input: Version{1, 5, 7},
output: Version{1, 5, 7}},
{name: `max Major, Minor, Patch`,
input: Version{0, 0, 0},
output: Version{255, 255, 255}},
{name: `max Major, Patch`,
input: Version{0, 5, 0},
output: Version{255, 5, 255}},
{name: `max Minor`,
input: Version{1, 0, 7},
output: Version{1, 255, 7}},
{name: `max Minor, Patch`,
input: Version{1, 0, 0},
output: Version{1, 255, 255}},
{name: `max Patch`,
input: Version{1, 5, 0},
output: Version{1, 5, 255}},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
require.Equal(t, test.output, test.input.max())
})
}
}

func Test_Version_Smaller(t *testing.T) {
type input struct {
a Version
Expand Down
69 changes: 20 additions & 49 deletions proxmox/config_qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type ConfigQemu struct {
Bios string `json:"bios,omitempty"`
Boot string `json:"boot,omitempty"` // TODO should be an array of custom enums
BootDisk string `json:"bootdisk,omitempty"` // TODO discuss deprecation? Only returned as it's deprecated in the proxmox api
CPU *QemuCPU `json:"cpu,omitempty"`
CloudInit *CloudInit `json:"cloudinit,omitempty"`
Description *string `json:"description,omitempty"`
Disks *QemuStorages `json:"disks,omitempty"`
Expand All @@ -53,21 +54,16 @@ type ConfigQemu struct {
Onboot *bool `json:"onboot,omitempty"`
Pool *PoolName `json:"pool,omitempty"`
Protection *bool `json:"protection,omitempty"`
QemuCores int `json:"cores,omitempty"` // TODO should be uint
QemuCpu string `json:"cpu,omitempty"` // TODO should be custom type with enum
QemuDisks QemuDevices `json:"disk,omitempty"` // DEPRECATED use Disks *QemuStorages instead
QemuIso string `json:"qemuiso,omitempty"` // DEPRECATED use Iso *IsoFile instead
QemuKVM *bool `json:"kvm,omitempty"`
QemuNetworks QemuDevices `json:"network,omitempty"` // TODO should be a struct
QemuNuma *bool `json:"numa,omitempty"`
QemuOs string `json:"ostype,omitempty"`
QemuPCIDevices QemuDevices `json:"hostpci,omitempty"` // TODO should be a struct
QemuPxe bool `json:"pxe,omitempty"`
QemuSerials QemuDevices `json:"serial,omitempty"` // TODO should be a struct
QemuSockets int `json:"sockets,omitempty"` // TODO should be uint
QemuUnusedDisks QemuDevices `json:"unused,omitempty"` // TODO should be a struct
QemuUsbs QemuDevices `json:"usb,omitempty"` // TODO should be a struct
QemuVcpus int `json:"vcpus,omitempty"` // TODO should be uint
QemuVga QemuDevice `json:"vga,omitempty"` // TODO should be a struct
RNGDrive QemuDevice `json:"rng0,omitempty"` // TODO should be a struct
Scsihw string `json:"scsihw,omitempty"` // TODO should be custom type with enum
Expand All @@ -81,6 +77,7 @@ type ConfigQemu struct {

const (
ConfigQemu_Error_UnableToUpdateWithoutReboot string = "unable to update vm without rebooting"
ConfigQemu_Error_CpuRequired string = "cpu is required during creation"
ConfigQemu_Error_MemoryRequired string = "memory is required during creation"
)

Expand Down Expand Up @@ -115,12 +112,6 @@ func (config *ConfigQemu) defaults() {
if config.Protection == nil {
config.Protection = util.Pointer(false)
}
if config.QemuCores == 0 {
config.QemuCores = 1
}
if config.QemuCpu == "" {
config.QemuCpu = "host"
}
if config.QemuDisks == nil {
config.QemuDisks = QemuDevices{}
}
Expand All @@ -139,9 +130,6 @@ func (config *ConfigQemu) defaults() {
if config.QemuSerials == nil {
config.QemuSerials = QemuDevices{}
}
if config.QemuSockets == 0 {
config.QemuSockets = 1
}
if config.QemuUnusedDisks == nil {
config.QemuUnusedDisks = QemuDevices{}
}
Expand Down Expand Up @@ -183,12 +171,6 @@ func (config ConfigQemu) mapToAPI(currentConfig ConfigQemu, version Version) (re
if config.Description != nil && (*config.Description != "" || currentConfig.Description != nil) {
params["description"] = *config.Description
}
if config.QemuCores != 0 {
params["cores"] = config.QemuCores
}
if config.QemuCpu != "" {
params["cpu"] = config.QemuCpu
}
if config.Hookscript != "" {
params["hookscript"] = config.Hookscript
}
Expand All @@ -204,9 +186,6 @@ func (config ConfigQemu) mapToAPI(currentConfig ConfigQemu, version Version) (re
if config.Name != "" {
params["name"] = config.Name
}
if config.QemuNuma != nil {
params["numa"] = *config.QemuNuma
}
if config.Onboot != nil {
params["onboot"] = *config.Onboot
}
Expand All @@ -219,9 +198,6 @@ func (config ConfigQemu) mapToAPI(currentConfig ConfigQemu, version Version) (re
if config.Scsihw != "" {
params["scsihw"] = config.Scsihw
}
if config.QemuSockets != 0 {
params["sockets"] = config.QemuSockets
}
if config.Startup != "" {
params["startup"] = config.Startup
}
Expand All @@ -231,9 +207,6 @@ func (config ConfigQemu) mapToAPI(currentConfig ConfigQemu, version Version) (re
if config.Tags != nil {
params["tags"] = Tag("").mapToApi(*config.Tags)
}
if config.QemuVcpus >= 1 {
params["vcpus"] = config.QemuVcpus
}
if config.Smbios1 != "" {
params["smbios1"] = config.Smbios1
}
Expand Down Expand Up @@ -273,6 +246,9 @@ func (config ConfigQemu) mapToAPI(currentConfig ConfigQemu, version Version) (re
}
}

if config.CPU != nil {
itemsToDelete += config.CPU.mapToApi(currentConfig.CPU, params, version)
}
if config.CloudInit != nil {
itemsToDelete += config.CloudInit.mapToAPI(currentConfig.CloudInit, params, version)
}
Expand Down Expand Up @@ -320,6 +296,7 @@ func (ConfigQemu) mapToStruct(vmr *VmRef, params map[string]interface{}) (*Confi
// cores:2 ostype:l26

config := ConfigQemu{
CPU: QemuCPU{}.mapToSDK(params),
CloudInit: CloudInit{}.mapToSDK(params),
Memory: QemuMemory{}.mapToSDK(params),
}
Expand Down Expand Up @@ -370,30 +347,12 @@ func (ConfigQemu) mapToStruct(vmr *VmRef, params map[string]interface{}) (*Confi
if itemValue, isSet := params["tpmstate0"]; isSet {
config.TPM = TpmState{}.mapToSDK(itemValue.(string))
}
if _, isSet := params["cores"]; isSet {
config.QemuCores = int(params["cores"].(float64))
}
if _, isSet := params["cpu"]; isSet {
config.QemuCpu = params["cpu"].(string)
}
if _, isSet := params["kvm"]; isSet {
config.QemuKVM = util.Pointer(Itob(int(params["kvm"].(float64))))
}
if _, isSet := params["numa"]; isSet {
config.QemuNuma = util.Pointer(Itob(int(params["numa"].(float64))))
}
if _, isSet := params["ostype"]; isSet {
config.QemuOs = params["ostype"].(string)
}
if _, isSet := params["sockets"]; isSet {
config.QemuSockets = int(params["sockets"].(float64))
}
if _, isSet := params["vcpus"]; isSet {
vCpu := int(params["vcpus"].(float64))
if vCpu > 0 {
config.QemuVcpus = vCpu
}
}
if _, isSet := params["protection"]; isSet {
config.Protection = util.Pointer(Itob(int(params["protection"].(float64))))
}
Expand Down Expand Up @@ -809,6 +768,13 @@ func (config ConfigQemu) Validate(current *ConfigQemu, version Version) (err err
// TODO test all other use cases
// TODO has no context about changes caused by updating the vm
if current == nil { // Create
if config.CPU == nil {
return errors.New(ConfigQemu_Error_CpuRequired)
} else {
if err = config.CPU.Validate(nil, version); err != nil {
return
}
}
if config.Memory == nil {
return errors.New(ConfigQemu_Error_MemoryRequired)
} else {
Expand All @@ -822,6 +788,11 @@ func (config ConfigQemu) Validate(current *ConfigQemu, version Version) (err err
}
}
} else { // Update
if config.CPU != nil {
if err = config.CPU.Validate(current.CPU, version); err != nil {
return
}
}
if config.Memory != nil {
if err = config.Memory.Validate(current.Memory); err != nil {
return
Expand Down Expand Up @@ -1190,8 +1161,8 @@ func (c ConfigQemu) CreateQemuNetworksParams(params map[string]interface{}) {
case nil, "":
// Generate random Mac based on time
macaddr := make(net.HardwareAddr, 6)
rand.Seed(time.Now().UnixNano())
rand.Read(macaddr)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
r.Read(macaddr)
macaddr[0] = (macaddr[0] | 2) & 0xfe // fix from github issue #18
macAddr = strings.ToUpper(fmt.Sprintf("%v", macaddr))

Expand Down
Loading
Loading