Skip to content

Commit

Permalink
Merge pull request #354 from Tinyblargon/#318
Browse files Browse the repository at this point in the history
Overhaul: `QemuCPU`
  • Loading branch information
Tinyblargon authored Aug 15, 2024
2 parents 2bae894 + c4608ca commit df2e9b5
Show file tree
Hide file tree
Showing 14 changed files with 2,057 additions and 77 deletions.
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

0 comments on commit df2e9b5

Please sign in to comment.