mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-06-30 02:31:10 +00:00
chore(api): refactor nodes/vms/vms_types.go
: split into multiple files (#1368)
Split all `Custom*` structs and marshaling code into separate files from `vms_types.go` Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
This commit is contained in:
parent
5d4193b6be
commit
580381f892
87
proxmox/nodes/vms/custom_agent.go
Normal file
87
proxmox/nodes/vms/custom_agent.go
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||
)
|
||||
|
||||
// CustomAgent handles QEMU agent parameters.
|
||||
type CustomAgent struct {
|
||||
Enabled *types.CustomBool `json:"enabled,omitempty" url:"enabled,int"`
|
||||
TrimClonedDisks *types.CustomBool `json:"fstrim_cloned_disks" url:"fstrim_cloned_disks,int"`
|
||||
Type *string `json:"type" url:"type"`
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomAgent struct to a URL value.
|
||||
func (r *CustomAgent) EncodeValues(key string, v *url.Values) error {
|
||||
var values []string
|
||||
|
||||
if r.Enabled != nil {
|
||||
if *r.Enabled {
|
||||
values = append(values, "enabled=1")
|
||||
} else {
|
||||
values = append(values, "enabled=0")
|
||||
}
|
||||
}
|
||||
|
||||
if r.TrimClonedDisks != nil {
|
||||
if *r.TrimClonedDisks {
|
||||
values = append(values, "fstrim_cloned_disks=1")
|
||||
} else {
|
||||
values = append(values, "fstrim_cloned_disks=0")
|
||||
}
|
||||
}
|
||||
|
||||
if r.Type != nil {
|
||||
values = append(values, fmt.Sprintf("type=%s", *r.Type))
|
||||
}
|
||||
|
||||
if len(values) > 0 {
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomAgent string to an object.
|
||||
func (r *CustomAgent) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("error unmarshalling CustomAgent: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
|
||||
if len(v) == 1 {
|
||||
enabled := types.CustomBool(v[0] == "1")
|
||||
r.Enabled = &enabled
|
||||
} else if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "enabled":
|
||||
enabled := types.CustomBool(v[1] == "1")
|
||||
r.Enabled = &enabled
|
||||
case "fstrim_cloned_disks":
|
||||
fstrim := types.CustomBool(v[1] == "1")
|
||||
r.TrimClonedDisks = &fstrim
|
||||
case "type":
|
||||
r.Type = &v[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
76
proxmox/nodes/vms/custom_audio_device.go
Normal file
76
proxmox/nodes/vms/custom_audio_device.go
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CustomAudioDevice handles QEMU audio parameters.
|
||||
type CustomAudioDevice struct {
|
||||
Device string `json:"device" url:"device"`
|
||||
Driver *string `json:"driver" url:"driver"`
|
||||
Enabled bool `json:"-" url:"-"`
|
||||
}
|
||||
|
||||
// CustomAudioDevices handles QEMU audio device parameters.
|
||||
type CustomAudioDevices []CustomAudioDevice
|
||||
|
||||
// EncodeValues converts a CustomAudioDevice struct to a URL value.
|
||||
func (r *CustomAudioDevice) EncodeValues(key string, v *url.Values) error {
|
||||
values := []string{fmt.Sprintf("device=%s", r.Device)}
|
||||
|
||||
if r.Driver != nil {
|
||||
values = append(values, fmt.Sprintf("driver=%s", *r.Driver))
|
||||
}
|
||||
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomAudioDevice string to an object.
|
||||
func (r *CustomAudioDevice) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("error unmarshalling CustomAudioDevice: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
|
||||
if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "device":
|
||||
r.Device = v[1]
|
||||
case "driver":
|
||||
r.Driver = &v[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomAudioDevices array to multiple URL values.
|
||||
func (r CustomAudioDevices) EncodeValues(key string, v *url.Values) error {
|
||||
for i, d := range r {
|
||||
if d.Enabled {
|
||||
if err := d.EncodeValues(fmt.Sprintf("%s%d", key, i), v); err != nil {
|
||||
return fmt.Errorf("unable to encode audio device %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
52
proxmox/nodes/vms/custom_boot.go
Normal file
52
proxmox/nodes/vms/custom_boot.go
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CustomBoot handles QEMU boot parameters.
|
||||
type CustomBoot struct {
|
||||
Order *[]string `json:"order,omitempty" url:"order,omitempty,semicolon"`
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomBoot struct to multiple URL values.
|
||||
func (r *CustomBoot) EncodeValues(key string, v *url.Values) error {
|
||||
if r.Order != nil && len(*r.Order) > 0 {
|
||||
v.Add(key, fmt.Sprintf("order=%s", strings.Join(*r.Order, ";")))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomBoot string to an object.
|
||||
func (r *CustomBoot) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("error unmarshalling CustomBoot: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
|
||||
if len(v) == 2 {
|
||||
if v[0] == "order" {
|
||||
o := strings.Split(strings.TrimSpace(v[1]), ";")
|
||||
r.Order = &o
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
210
proxmox/nodes/vms/custom_cloud_init.go
Normal file
210
proxmox/nodes/vms/custom_cloud_init.go
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CustomCloudInitConfig handles QEMU cloud-init parameters.
|
||||
type CustomCloudInitConfig struct {
|
||||
Files *CustomCloudInitFiles `json:"cicustom,omitempty" url:"cicustom,omitempty"`
|
||||
IPConfig []CustomCloudInitIPConfig `json:"ipconfig,omitempty" url:"ipconfig,omitempty,numbered"`
|
||||
Nameserver *string `json:"nameserver,omitempty" url:"nameserver,omitempty"`
|
||||
Password *string `json:"cipassword,omitempty" url:"cipassword,omitempty"`
|
||||
SearchDomain *string `json:"searchdomain,omitempty" url:"searchdomain,omitempty"`
|
||||
SSHKeys *CustomCloudInitSSHKeys `json:"sshkeys,omitempty" url:"sshkeys,omitempty"`
|
||||
Type *string `json:"citype,omitempty" url:"citype,omitempty"`
|
||||
// Can't be reliably set, it is TRUE by default in PVE
|
||||
// Upgrade *types.CustomBool `json:"ciupgrade,omitempty" url:"ciupgrade,omitempty,int"`
|
||||
Username *string `json:"ciuser,omitempty" url:"ciuser,omitempty"`
|
||||
}
|
||||
|
||||
// CustomCloudInitFiles handles QEMU cloud-init custom files parameters.
|
||||
type CustomCloudInitFiles struct {
|
||||
MetaVolume *string `json:"meta,omitempty" url:"meta,omitempty"`
|
||||
NetworkVolume *string `json:"network,omitempty" url:"network,omitempty"`
|
||||
UserVolume *string `json:"user,omitempty" url:"user,omitempty"`
|
||||
VendorVolume *string `json:"vendor,omitempty" url:"vendor,omitempty"`
|
||||
}
|
||||
|
||||
// CustomCloudInitIPConfig handles QEMU cloud-init IP configuration parameters.
|
||||
type CustomCloudInitIPConfig struct {
|
||||
GatewayIPv4 *string `json:"gw,omitempty" url:"gw,omitempty"`
|
||||
GatewayIPv6 *string `json:"gw6,omitempty" url:"gw6,omitempty"`
|
||||
IPv4 *string `json:"ip,omitempty" url:"ip,omitempty"`
|
||||
IPv6 *string `json:"ip6,omitempty" url:"ip6,omitempty"`
|
||||
}
|
||||
|
||||
// CustomCloudInitSSHKeys handles QEMU cloud-init SSH keys parameters.
|
||||
type CustomCloudInitSSHKeys []string
|
||||
|
||||
// EncodeValues converts a CustomCloudInitConfig struct to multiple URL values.
|
||||
func (r CustomCloudInitConfig) EncodeValues(_ string, v *url.Values) error {
|
||||
//nolint:nestif
|
||||
if r.Files != nil {
|
||||
var volumes []string
|
||||
|
||||
if r.Files.MetaVolume != nil {
|
||||
volumes = append(volumes, fmt.Sprintf("meta=%s", *r.Files.MetaVolume))
|
||||
}
|
||||
|
||||
if r.Files.NetworkVolume != nil {
|
||||
volumes = append(volumes, fmt.Sprintf("network=%s", *r.Files.NetworkVolume))
|
||||
}
|
||||
|
||||
if r.Files.UserVolume != nil {
|
||||
volumes = append(volumes, fmt.Sprintf("user=%s", *r.Files.UserVolume))
|
||||
}
|
||||
|
||||
if r.Files.VendorVolume != nil {
|
||||
volumes = append(volumes, fmt.Sprintf("vendor=%s", *r.Files.VendorVolume))
|
||||
}
|
||||
|
||||
if len(volumes) > 0 {
|
||||
v.Add("cicustom", strings.Join(volumes, ","))
|
||||
}
|
||||
}
|
||||
|
||||
for i, c := range r.IPConfig {
|
||||
var config []string
|
||||
|
||||
if c.GatewayIPv4 != nil {
|
||||
config = append(config, fmt.Sprintf("gw=%s", *c.GatewayIPv4))
|
||||
}
|
||||
|
||||
if c.GatewayIPv6 != nil {
|
||||
config = append(config, fmt.Sprintf("gw6=%s", *c.GatewayIPv6))
|
||||
}
|
||||
|
||||
if c.IPv4 != nil {
|
||||
config = append(config, fmt.Sprintf("ip=%s", *c.IPv4))
|
||||
}
|
||||
|
||||
if c.IPv6 != nil {
|
||||
config = append(config, fmt.Sprintf("ip6=%s", *c.IPv6))
|
||||
}
|
||||
|
||||
if len(config) > 0 {
|
||||
v.Add(fmt.Sprintf("ipconfig%d", i), strings.Join(config, ","))
|
||||
}
|
||||
}
|
||||
|
||||
if r.Nameserver != nil {
|
||||
v.Add("nameserver", *r.Nameserver)
|
||||
}
|
||||
|
||||
if r.Password != nil {
|
||||
v.Add("cipassword", *r.Password)
|
||||
}
|
||||
|
||||
if r.SearchDomain != nil {
|
||||
v.Add("searchdomain", *r.SearchDomain)
|
||||
}
|
||||
|
||||
if r.SSHKeys != nil {
|
||||
v.Add(
|
||||
"sshkeys",
|
||||
strings.ReplaceAll(url.QueryEscape(strings.Join(*r.SSHKeys, "\n")), "+", "%20"),
|
||||
)
|
||||
}
|
||||
|
||||
if r.Type != nil {
|
||||
v.Add("citype", *r.Type)
|
||||
}
|
||||
|
||||
if r.Username != nil {
|
||||
v.Add("ciuser", *r.Username)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomCloudInitFiles string to an object.
|
||||
func (r *CustomCloudInitFiles) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("error unmarshalling CustomCloudInitFiles: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
|
||||
if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "meta":
|
||||
r.MetaVolume = &v[1]
|
||||
case "network":
|
||||
r.NetworkVolume = &v[1]
|
||||
case "user":
|
||||
r.UserVolume = &v[1]
|
||||
case "vendor":
|
||||
r.VendorVolume = &v[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomCloudInitIPConfig string to an object.
|
||||
func (r *CustomCloudInitIPConfig) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("error unmarshalling CustomCloudInitIPConfig: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
|
||||
if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "gw":
|
||||
r.GatewayIPv4 = &v[1]
|
||||
case "gw6":
|
||||
r.GatewayIPv6 = &v[1]
|
||||
case "ip":
|
||||
r.IPv4 = &v[1]
|
||||
case "ip6":
|
||||
r.IPv6 = &v[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomCloudInitFiles string to an object.
|
||||
func (r *CustomCloudInitSSHKeys) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("error unmarshalling CustomCloudInitSSHKeys: %w", err)
|
||||
}
|
||||
|
||||
s, err := url.QueryUnescape(s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error unescaping CustomCloudInitSSHKeys: %w", err)
|
||||
}
|
||||
|
||||
if s != "" {
|
||||
*r = strings.Split(strings.TrimSpace(s), "\n")
|
||||
} else {
|
||||
*r = []string{}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
95
proxmox/nodes/vms/custom_cpu_emulation.go
Normal file
95
proxmox/nodes/vms/custom_cpu_emulation.go
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||
)
|
||||
|
||||
// CustomCPUEmulation handles QEMU CPU emulation parameters.
|
||||
type CustomCPUEmulation struct {
|
||||
Flags *[]string `json:"flags,omitempty" url:"flags,omitempty,semicolon"`
|
||||
Hidden *types.CustomBool `json:"hidden,omitempty" url:"hidden,omitempty,int"`
|
||||
HVVendorID *string `json:"hv-vendor-id,omitempty" url:"hv-vendor-id,omitempty"`
|
||||
Type string `json:"cputype,omitempty" url:"cputype,omitempty"`
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomCPUEmulation struct to a URL value.
|
||||
func (r *CustomCPUEmulation) EncodeValues(key string, v *url.Values) error {
|
||||
values := []string{
|
||||
fmt.Sprintf("cputype=%s", r.Type),
|
||||
}
|
||||
|
||||
if r.Flags != nil && len(*r.Flags) > 0 {
|
||||
values = append(values, fmt.Sprintf("flags=%s", strings.Join(*r.Flags, ";")))
|
||||
}
|
||||
|
||||
if r.Hidden != nil {
|
||||
if *r.Hidden {
|
||||
values = append(values, "hidden=1")
|
||||
} else {
|
||||
values = append(values, "hidden=0")
|
||||
}
|
||||
}
|
||||
|
||||
if r.HVVendorID != nil {
|
||||
values = append(values, fmt.Sprintf("hv-vendor-id=%s", *r.HVVendorID))
|
||||
}
|
||||
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomCPUEmulation string to an object.
|
||||
func (r *CustomCPUEmulation) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("error unmarshalling CustomCPUEmulation: %w", err)
|
||||
}
|
||||
|
||||
if s == "" {
|
||||
return errors.New("unexpected empty string")
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
|
||||
if len(v) == 1 {
|
||||
r.Type = v[0]
|
||||
} else if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "cputype":
|
||||
r.Type = v[1]
|
||||
case "flags":
|
||||
if v[1] != "" {
|
||||
f := strings.Split(v[1], ";")
|
||||
r.Flags = &f
|
||||
} else {
|
||||
var f []string
|
||||
r.Flags = &f
|
||||
}
|
||||
case "hidden":
|
||||
bv := types.CustomBool(v[1] == "1")
|
||||
r.Hidden = &bv
|
||||
case "hv-vendor-id":
|
||||
r.HVVendorID = &v[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
87
proxmox/nodes/vms/custom_efi_disk.go
Normal file
87
proxmox/nodes/vms/custom_efi_disk.go
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||
)
|
||||
|
||||
// CustomEFIDisk handles QEMU EFI disk parameters.
|
||||
type CustomEFIDisk struct {
|
||||
FileVolume string `json:"file" url:"file"`
|
||||
Format *string `json:"format,omitempty" url:"format,omitempty"`
|
||||
Type *string `json:"efitype,omitempty" url:"efitype,omitempty"`
|
||||
PreEnrolledKeys *types.CustomBool `json:"pre-enrolled-keys,omitempty" url:"pre-enrolled-keys,omitempty,int"`
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomEFIDisk struct to a URL value.
|
||||
func (r *CustomEFIDisk) EncodeValues(key string, v *url.Values) error {
|
||||
values := []string{
|
||||
fmt.Sprintf("file=%s", r.FileVolume),
|
||||
}
|
||||
|
||||
if r.Format != nil {
|
||||
values = append(values, fmt.Sprintf("format=%s", *r.Format))
|
||||
}
|
||||
|
||||
if r.Type != nil {
|
||||
values = append(values, fmt.Sprintf("efitype=%s", *r.Type))
|
||||
}
|
||||
|
||||
if r.PreEnrolledKeys != nil {
|
||||
if *r.PreEnrolledKeys {
|
||||
values = append(values, "pre-enrolled-keys=1")
|
||||
} else {
|
||||
values = append(values, "pre-enrolled-keys=0")
|
||||
}
|
||||
}
|
||||
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomEFIDisk string to an object.
|
||||
func (r *CustomEFIDisk) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal CustomEFIDisk: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for i, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
|
||||
if len(v) == 1 && i == 0 {
|
||||
r.FileVolume = v[0]
|
||||
}
|
||||
|
||||
if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "file":
|
||||
r.FileVolume = v[1]
|
||||
case "format":
|
||||
r.Format = &v[1]
|
||||
case "efitype":
|
||||
t := strings.ToLower(v[1])
|
||||
r.Type = &t
|
||||
case "pre-enrolled-keys":
|
||||
bv := types.CustomBool(v[1] == "1")
|
||||
r.PreEnrolledKeys = &bv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
191
proxmox/nodes/vms/custom_network_device.go
Normal file
191
proxmox/nodes/vms/custom_network_device.go
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||
)
|
||||
|
||||
// CustomNetworkDevice handles QEMU network device parameters.
|
||||
type CustomNetworkDevice struct {
|
||||
Enabled bool `json:"-" url:"-"`
|
||||
Bridge *string `json:"bridge,omitempty" url:"bridge,omitempty"`
|
||||
Firewall *types.CustomBool `json:"firewall,omitempty" url:"firewall,omitempty,int"`
|
||||
LinkDown *types.CustomBool `json:"link_down,omitempty" url:"link_down,omitempty,int"`
|
||||
MACAddress *string `json:"macaddr,omitempty" url:"macaddr,omitempty"`
|
||||
MTU *int `json:"mtu,omitempty" url:"mtu,omitempty"`
|
||||
Model string `json:"model" url:"model"`
|
||||
Queues *int `json:"queues,omitempty" url:"queues,omitempty"`
|
||||
RateLimit *float64 `json:"rate,omitempty" url:"rate,omitempty"`
|
||||
Tag *int `json:"tag,omitempty" url:"tag,omitempty"`
|
||||
Trunks []int `json:"trunks,omitempty" url:"trunks,omitempty"`
|
||||
}
|
||||
|
||||
// CustomNetworkDevices handles QEMU network device parameters.
|
||||
type CustomNetworkDevices []CustomNetworkDevice
|
||||
|
||||
// EncodeValues converts a CustomNetworkDevice struct to a URL value.
|
||||
func (r *CustomNetworkDevice) EncodeValues(key string, v *url.Values) error {
|
||||
values := []string{
|
||||
fmt.Sprintf("model=%s", r.Model),
|
||||
}
|
||||
|
||||
if r.Bridge != nil {
|
||||
values = append(values, fmt.Sprintf("bridge=%s", *r.Bridge))
|
||||
}
|
||||
|
||||
if r.Firewall != nil {
|
||||
if *r.Firewall {
|
||||
values = append(values, "firewall=1")
|
||||
} else {
|
||||
values = append(values, "firewall=0")
|
||||
}
|
||||
}
|
||||
|
||||
if r.LinkDown != nil {
|
||||
if *r.LinkDown {
|
||||
values = append(values, "link_down=1")
|
||||
} else {
|
||||
values = append(values, "link_down=0")
|
||||
}
|
||||
}
|
||||
|
||||
if r.MACAddress != nil {
|
||||
values = append(values, fmt.Sprintf("macaddr=%s", *r.MACAddress))
|
||||
}
|
||||
|
||||
if r.Queues != nil {
|
||||
values = append(values, fmt.Sprintf("queues=%d", *r.Queues))
|
||||
}
|
||||
|
||||
if r.RateLimit != nil {
|
||||
values = append(values, fmt.Sprintf("rate=%f", *r.RateLimit))
|
||||
}
|
||||
|
||||
if r.Tag != nil {
|
||||
values = append(values, fmt.Sprintf("tag=%d", *r.Tag))
|
||||
}
|
||||
|
||||
if r.MTU != nil {
|
||||
values = append(values, fmt.Sprintf("mtu=%d", *r.MTU))
|
||||
}
|
||||
|
||||
if len(r.Trunks) > 0 {
|
||||
trunks := make([]string, len(r.Trunks))
|
||||
|
||||
for i, v := range r.Trunks {
|
||||
trunks[i] = strconv.Itoa(v)
|
||||
}
|
||||
|
||||
values = append(values, fmt.Sprintf("trunks=%s", strings.Join(trunks, ";")))
|
||||
}
|
||||
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomNetworkDevices array to multiple URL values.
|
||||
func (r CustomNetworkDevices) EncodeValues(key string, v *url.Values) error {
|
||||
for i, d := range r {
|
||||
if d.Enabled {
|
||||
if err := d.EncodeValues(fmt.Sprintf("%s%d", key, i), v); err != nil {
|
||||
return fmt.Errorf("failed to encode network device %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomNetworkDevice string to an object.
|
||||
func (r *CustomNetworkDevice) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal CustomNetworkDevice: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
|
||||
//nolint:nestif
|
||||
if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "bridge":
|
||||
r.Bridge = &v[1]
|
||||
case "firewall":
|
||||
bv := types.CustomBool(v[1] == "1")
|
||||
r.Firewall = &bv
|
||||
case "link_down":
|
||||
bv := types.CustomBool(v[1] == "1")
|
||||
r.LinkDown = &bv
|
||||
case "macaddr":
|
||||
r.MACAddress = &v[1]
|
||||
case "model":
|
||||
r.Model = v[1]
|
||||
case "queues":
|
||||
iv, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse queues: %w", err)
|
||||
}
|
||||
|
||||
r.Queues = &iv
|
||||
case "rate":
|
||||
fv, err := strconv.ParseFloat(v[1], 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse rate: %w", err)
|
||||
}
|
||||
|
||||
r.RateLimit = &fv
|
||||
|
||||
case "mtu":
|
||||
iv, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse mtu: %w", err)
|
||||
}
|
||||
|
||||
r.MTU = &iv
|
||||
|
||||
case "tag":
|
||||
iv, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse tag: %w", err)
|
||||
}
|
||||
|
||||
r.Tag = &iv
|
||||
case "trunks":
|
||||
trunks := strings.Split(v[1], ";")
|
||||
r.Trunks = make([]int, len(trunks))
|
||||
|
||||
for i, trunk := range trunks {
|
||||
iv, err := strconv.Atoi(trunk)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse trunk %d: %w", i, err)
|
||||
}
|
||||
|
||||
r.Trunks[i] = iv
|
||||
}
|
||||
default:
|
||||
r.MACAddress = &v[1]
|
||||
r.Model = v[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r.Enabled = true
|
||||
|
||||
return nil
|
||||
}
|
95
proxmox/nodes/vms/custom_numa_device.go
Normal file
95
proxmox/nodes/vms/custom_numa_device.go
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CustomNUMADevice handles QEMU NUMA device parameters.
|
||||
type CustomNUMADevice struct {
|
||||
CPUIDs []string `json:"cpus" url:"cpus,semicolon"`
|
||||
HostNodeNames *[]string `json:"hostnodes,omitempty" url:"hostnodes,omitempty,semicolon"`
|
||||
Memory *int `json:"memory,omitempty" url:"memory,omitempty"`
|
||||
Policy *string `json:"policy,omitempty" url:"policy,omitempty"`
|
||||
}
|
||||
|
||||
// CustomNUMADevices handles QEMU NUMA device parameters.
|
||||
type CustomNUMADevices []CustomNUMADevice
|
||||
|
||||
// EncodeValues converts a CustomNUMADevice struct to a URL value.
|
||||
func (r *CustomNUMADevice) EncodeValues(key string, v *url.Values) error {
|
||||
values := []string{
|
||||
fmt.Sprintf("cpus=%s", strings.Join(r.CPUIDs, ";")),
|
||||
}
|
||||
|
||||
if r.HostNodeNames != nil {
|
||||
values = append(values, fmt.Sprintf("hostnodes=%s", strings.Join(*r.HostNodeNames, ";")))
|
||||
}
|
||||
|
||||
if r.Memory != nil {
|
||||
values = append(values, fmt.Sprintf("memory=%d", *r.Memory))
|
||||
}
|
||||
|
||||
if r.Policy != nil {
|
||||
values = append(values, fmt.Sprintf("policy=%s", *r.Policy))
|
||||
}
|
||||
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomNUMADevices array to multiple URL values.
|
||||
func (r CustomNUMADevices) EncodeValues(key string, v *url.Values) error {
|
||||
for i, d := range r {
|
||||
if err := d.EncodeValues(fmt.Sprintf("%s%d", key, i), v); err != nil {
|
||||
return fmt.Errorf("failed to encode NUMA device %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomNUMADevice string to an object.
|
||||
func (r *CustomNUMADevice) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal CustomNUMADevice: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "cpus":
|
||||
r.CPUIDs = strings.Split(v[1], ";")
|
||||
case "hostnodes":
|
||||
hostnodes := strings.Split(v[1], ";")
|
||||
r.HostNodeNames = &hostnodes
|
||||
case "memory":
|
||||
memory, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse memory size: %w", err)
|
||||
}
|
||||
|
||||
r.Memory = &memory
|
||||
case "policy":
|
||||
r.Policy = &v[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
54
proxmox/nodes/vms/custom_numa_device_test.go
Normal file
54
proxmox/nodes/vms/custom_numa_device_test.go
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/helpers/ptr"
|
||||
)
|
||||
|
||||
func TestCustomNUMADevice_UnmarshalJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
line string
|
||||
want *CustomNUMADevice
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "numa device all options",
|
||||
line: `"cpus=1-2;3-4,hostnodes=1-2,memory=1024,policy=preferred"`,
|
||||
want: &CustomNUMADevice{
|
||||
CPUIDs: []string{"1-2", "3-4"},
|
||||
HostNodeNames: &[]string{"1-2"},
|
||||
Memory: ptr.Ptr(1024),
|
||||
Policy: ptr.Ptr("preferred"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "numa device cpus/memory only",
|
||||
line: `"cpus=1-2,memory=1024"`,
|
||||
want: &CustomNUMADevice{
|
||||
CPUIDs: []string{"1-2"},
|
||||
Memory: ptr.Ptr(1024),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := &CustomNUMADevice{}
|
||||
if err := r.UnmarshalJSON([]byte(tt.line)); (err != nil) != tt.wantErr {
|
||||
t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
136
proxmox/nodes/vms/custom_pci_device.go
Normal file
136
proxmox/nodes/vms/custom_pci_device.go
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||
)
|
||||
|
||||
// CustomPCIDevice handles QEMU host PCI device mapping parameters.
|
||||
type CustomPCIDevice struct {
|
||||
DeviceIDs *[]string `json:"host,omitempty" url:"host,omitempty,semicolon"`
|
||||
Mapping *string `json:"mapping,omitempty" url:"mapping,omitempty"`
|
||||
MDev *string `json:"mdev,omitempty" url:"mdev,omitempty"`
|
||||
PCIExpress *types.CustomBool `json:"pcie,omitempty" url:"pcie,omitempty,int"`
|
||||
ROMBAR *types.CustomBool `json:"rombar,omitempty" url:"rombar,omitempty,int"`
|
||||
ROMFile *string `json:"romfile,omitempty" url:"romfile,omitempty"`
|
||||
XVGA *types.CustomBool `json:"x-vga,omitempty" url:"x-vga,omitempty,int"`
|
||||
}
|
||||
|
||||
// CustomPCIDevices handles QEMU host PCI device mapping parameters.
|
||||
type CustomPCIDevices []CustomPCIDevice
|
||||
|
||||
// EncodeValues converts a CustomPCIDevice struct to a URL value.
|
||||
func (r *CustomPCIDevice) EncodeValues(key string, v *url.Values) error {
|
||||
var values []string
|
||||
|
||||
if r.DeviceIDs == nil && r.Mapping == nil {
|
||||
return fmt.Errorf("either device ID or resource mapping must be set")
|
||||
}
|
||||
|
||||
if r.DeviceIDs != nil {
|
||||
values = append(values, fmt.Sprintf("host=%s", strings.Join(*r.DeviceIDs, ";")))
|
||||
}
|
||||
|
||||
if r.Mapping != nil {
|
||||
values = append(values, fmt.Sprintf("mapping=%s", *r.Mapping))
|
||||
}
|
||||
|
||||
if r.MDev != nil {
|
||||
values = append(values, fmt.Sprintf("mdev=%s", *r.MDev))
|
||||
}
|
||||
|
||||
if r.PCIExpress != nil {
|
||||
if *r.PCIExpress {
|
||||
values = append(values, "pcie=1")
|
||||
} else {
|
||||
values = append(values, "pcie=0")
|
||||
}
|
||||
}
|
||||
|
||||
if r.ROMBAR != nil {
|
||||
if *r.ROMBAR {
|
||||
values = append(values, "rombar=1")
|
||||
} else {
|
||||
values = append(values, "rombar=0")
|
||||
}
|
||||
}
|
||||
|
||||
if r.ROMFile != nil {
|
||||
values = append(values, fmt.Sprintf("romfile=%s", *r.ROMFile))
|
||||
}
|
||||
|
||||
if r.XVGA != nil {
|
||||
if *r.XVGA {
|
||||
values = append(values, "x-vga=1")
|
||||
} else {
|
||||
values = append(values, "x-vga=0")
|
||||
}
|
||||
}
|
||||
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomPCIDevices array to multiple URL values.
|
||||
func (r CustomPCIDevices) EncodeValues(key string, v *url.Values) error {
|
||||
for i, d := range r {
|
||||
if err := d.EncodeValues(fmt.Sprintf("%s%d", key, i), v); err != nil {
|
||||
return fmt.Errorf("failed to encode PCI device %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomPCIDevice string to an object.
|
||||
func (r *CustomPCIDevice) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal CustomPCIDevice: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
if len(v) == 1 {
|
||||
dIDs := strings.Split(v[0], ";")
|
||||
r.DeviceIDs = &dIDs
|
||||
} else if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "host":
|
||||
dIDs := strings.Split(v[1], ";")
|
||||
r.DeviceIDs = &dIDs
|
||||
case "mapping":
|
||||
r.Mapping = &v[1]
|
||||
case "mdev":
|
||||
r.MDev = &v[1]
|
||||
case "pcie":
|
||||
bv := types.CustomBool(v[1] == "1")
|
||||
r.PCIExpress = &bv
|
||||
case "rombar":
|
||||
bv := types.CustomBool(v[1] == "1")
|
||||
r.ROMBAR = &bv
|
||||
case "romfile":
|
||||
r.ROMFile = &v[1]
|
||||
case "x-vga":
|
||||
bv := types.CustomBool(v[1] == "1")
|
||||
r.XVGA = &bv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
73
proxmox/nodes/vms/custom_pci_device_test.go
Normal file
73
proxmox/nodes/vms/custom_pci_device_test.go
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/helpers/ptr"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||
)
|
||||
|
||||
func TestCustomPCIDevice_UnmarshalJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
line string
|
||||
want *CustomPCIDevice
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "id only pci device",
|
||||
line: `"0000:81:00.2"`,
|
||||
want: &CustomPCIDevice{
|
||||
DeviceIDs: &[]string{"0000:81:00.2"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "pci device with more details",
|
||||
line: `"host=81:00.4,pcie=0,rombar=1,x-vga=0"`,
|
||||
want: &CustomPCIDevice{
|
||||
DeviceIDs: &[]string{"81:00.4"},
|
||||
MDev: nil,
|
||||
PCIExpress: types.CustomBool(false).Pointer(),
|
||||
ROMBAR: types.CustomBool(true).Pointer(),
|
||||
ROMFile: nil,
|
||||
XVGA: types.CustomBool(false).Pointer(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "pci device with mapping",
|
||||
line: `"mapping=mappeddevice,pcie=0,rombar=1,x-vga=0"`,
|
||||
want: &CustomPCIDevice{
|
||||
DeviceIDs: nil,
|
||||
Mapping: ptr.Ptr("mappeddevice"),
|
||||
MDev: nil,
|
||||
PCIExpress: types.CustomBool(false).Pointer(),
|
||||
ROMBAR: types.CustomBool(true).Pointer(),
|
||||
ROMFile: nil,
|
||||
XVGA: types.CustomBool(false).Pointer(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := &CustomPCIDevice{}
|
||||
if err := r.UnmarshalJSON([]byte(tt.line)); (err != nil) != tt.wantErr {
|
||||
t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
||||
require.Equal(t, tt.want, r)
|
||||
})
|
||||
}
|
||||
}
|
24
proxmox/nodes/vms/custom_serial_device.go
Normal file
24
proxmox/nodes/vms/custom_serial_device.go
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// CustomSerialDevices handles QEMU serial device parameters.
|
||||
type CustomSerialDevices []string
|
||||
|
||||
// EncodeValues converts a CustomSerialDevices array to multiple URL values.
|
||||
func (r CustomSerialDevices) EncodeValues(key string, v *url.Values) error {
|
||||
for i, d := range r {
|
||||
v.Add(fmt.Sprintf("%s%d", key, i), d)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
67
proxmox/nodes/vms/custom_shared_memory.go
Normal file
67
proxmox/nodes/vms/custom_shared_memory.go
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CustomSharedMemory handles QEMU Inter-VM shared memory parameters.
|
||||
type CustomSharedMemory struct {
|
||||
Name *string `json:"name,omitempty" url:"name,omitempty"`
|
||||
Size int `json:"size" url:"size"`
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomSharedMemory struct to a URL value.
|
||||
func (r *CustomSharedMemory) EncodeValues(key string, v *url.Values) error {
|
||||
values := []string{
|
||||
fmt.Sprintf("size=%d", r.Size),
|
||||
}
|
||||
|
||||
if r.Name != nil {
|
||||
values = append(values, fmt.Sprintf("name=%s", *r.Name))
|
||||
}
|
||||
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomSharedMemory string to an object.
|
||||
func (r *CustomSharedMemory) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal CustomSharedMemory: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
|
||||
if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "name":
|
||||
r.Name = &v[1]
|
||||
case "size":
|
||||
var err error
|
||||
|
||||
r.Size, err = strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse shared memory size: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
114
proxmox/nodes/vms/custom_smbios.go
Normal file
114
proxmox/nodes/vms/custom_smbios.go
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||
)
|
||||
|
||||
// CustomSMBIOS handles QEMU SMBIOS parameters.
|
||||
type CustomSMBIOS struct {
|
||||
Base64 *types.CustomBool `json:"base64,omitempty" url:"base64,omitempty,int"`
|
||||
Family *string `json:"family,omitempty" url:"family,omitempty"`
|
||||
Manufacturer *string `json:"manufacturer,omitempty" url:"manufacturer,omitempty"`
|
||||
Product *string `json:"product,omitempty" url:"product,omitempty"`
|
||||
Serial *string `json:"serial,omitempty" url:"serial,omitempty"`
|
||||
SKU *string `json:"sku,omitempty" url:"sku,omitempty"`
|
||||
UUID *string `json:"uuid,omitempty" url:"uuid,omitempty"`
|
||||
Version *string `json:"version,omitempty" url:"version,omitempty"`
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomSMBIOS struct to a URL value.
|
||||
func (r *CustomSMBIOS) EncodeValues(key string, v *url.Values) error {
|
||||
var values []string
|
||||
|
||||
if r.Base64 != nil {
|
||||
if *r.Base64 {
|
||||
values = append(values, "base64=1")
|
||||
} else {
|
||||
values = append(values, "base64=0")
|
||||
}
|
||||
}
|
||||
|
||||
if r.Family != nil {
|
||||
values = append(values, fmt.Sprintf("family=%s", *r.Family))
|
||||
}
|
||||
|
||||
if r.Manufacturer != nil {
|
||||
values = append(values, fmt.Sprintf("manufacturer=%s", *r.Manufacturer))
|
||||
}
|
||||
|
||||
if r.Product != nil {
|
||||
values = append(values, fmt.Sprintf("product=%s", *r.Product))
|
||||
}
|
||||
|
||||
if r.Serial != nil {
|
||||
values = append(values, fmt.Sprintf("serial=%s", *r.Serial))
|
||||
}
|
||||
|
||||
if r.SKU != nil {
|
||||
values = append(values, fmt.Sprintf("sku=%s", *r.SKU))
|
||||
}
|
||||
|
||||
if r.UUID != nil {
|
||||
values = append(values, fmt.Sprintf("uuid=%s", *r.UUID))
|
||||
}
|
||||
|
||||
if r.Version != nil {
|
||||
values = append(values, fmt.Sprintf("version=%s", *r.Version))
|
||||
}
|
||||
|
||||
if len(values) > 0 {
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomSMBIOS string to an object.
|
||||
func (r *CustomSMBIOS) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal CustomSMBIOS: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.SplitN(strings.TrimSpace(p), "=", 2)
|
||||
|
||||
if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "base64":
|
||||
base64 := types.CustomBool(v[1] == "1")
|
||||
r.Base64 = &base64
|
||||
case "family":
|
||||
r.Family = &v[1]
|
||||
case "manufacturer":
|
||||
r.Manufacturer = &v[1]
|
||||
case "product":
|
||||
r.Product = &v[1]
|
||||
case "serial":
|
||||
r.Serial = &v[1]
|
||||
case "sku":
|
||||
r.SKU = &v[1]
|
||||
case "uuid":
|
||||
r.UUID = &v[1]
|
||||
case "version":
|
||||
r.Version = &v[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
72
proxmox/nodes/vms/custom_spice_enhancements.go
Normal file
72
proxmox/nodes/vms/custom_spice_enhancements.go
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||
)
|
||||
|
||||
// CustomSpiceEnhancements handles QEMU spice enhancement parameters.
|
||||
type CustomSpiceEnhancements struct {
|
||||
FolderSharing *types.CustomBool `json:"foldersharing,omitempty" url:"foldersharing,omitempty"`
|
||||
VideoStreaming *string `json:"videostreaming,omitempty" url:"videostreaming,omitempty"`
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomSpiceEnhancements struct to a URL value.
|
||||
func (r *CustomSpiceEnhancements) EncodeValues(key string, v *url.Values) error {
|
||||
var values []string
|
||||
|
||||
if r.FolderSharing != nil {
|
||||
if *r.FolderSharing {
|
||||
values = append(values, "foldersharing=1")
|
||||
} else {
|
||||
values = append(values, "foldersharing=0")
|
||||
}
|
||||
}
|
||||
|
||||
if r.VideoStreaming != nil {
|
||||
values = append(values, fmt.Sprintf("videostreaming=%s", *r.VideoStreaming))
|
||||
}
|
||||
|
||||
if len(values) > 0 {
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts JSON to a CustomSpiceEnhancements struct.
|
||||
func (r *CustomSpiceEnhancements) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal CustomSpiceEnhancements: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
|
||||
if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "foldersharing":
|
||||
v := types.CustomBool(v[1] == "1")
|
||||
r.FolderSharing = &v
|
||||
case "videostreaming":
|
||||
r.VideoStreaming = &v[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
88
proxmox/nodes/vms/custom_startup_order.go
Normal file
88
proxmox/nodes/vms/custom_startup_order.go
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CustomStartupOrder handles QEMU startup order parameters.
|
||||
type CustomStartupOrder struct {
|
||||
Down *int `json:"down,omitempty" url:"down,omitempty"`
|
||||
Order *int `json:"order,omitempty" url:"order,omitempty"`
|
||||
Up *int `json:"up,omitempty" url:"up,omitempty"`
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomStartupOrder struct to a URL value.
|
||||
func (r *CustomStartupOrder) EncodeValues(key string, v *url.Values) error {
|
||||
var values []string
|
||||
|
||||
if r.Order != nil {
|
||||
values = append(values, fmt.Sprintf("order=%d", *r.Order))
|
||||
}
|
||||
|
||||
if r.Up != nil {
|
||||
values = append(values, fmt.Sprintf("up=%d", *r.Up))
|
||||
}
|
||||
|
||||
if r.Down != nil {
|
||||
values = append(values, fmt.Sprintf("down=%d", *r.Down))
|
||||
}
|
||||
|
||||
if len(values) > 0 {
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomStartupOrder string to an object.
|
||||
func (r *CustomStartupOrder) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal CustomStartupOrder: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
|
||||
if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "order":
|
||||
order, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse int: %w", err)
|
||||
}
|
||||
|
||||
r.Order = &order
|
||||
case "up":
|
||||
up, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse int: %w", err)
|
||||
}
|
||||
|
||||
r.Up = &up
|
||||
case "down":
|
||||
down, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse int: %w", err)
|
||||
}
|
||||
|
||||
r.Down = &down
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,8 +1,18 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
@ -36,8 +46,11 @@ type CustomStorageDevice struct {
|
||||
Interface *string `json:"-" url:"-"`
|
||||
}
|
||||
|
||||
// CustomStorageDevices handles map of QEMU storage device per disk interface.
|
||||
type CustomStorageDevices map[string]*CustomStorageDevice
|
||||
|
||||
// PathInDatastore returns path part of FileVolume or nil if it is not yet allocated.
|
||||
func (d CustomStorageDevice) PathInDatastore() *string {
|
||||
func (d *CustomStorageDevice) PathInDatastore() *string {
|
||||
probablyDatastoreID, pathInDatastore, hasDatastoreID := strings.Cut(d.FileVolume, ":")
|
||||
if !hasDatastoreID {
|
||||
// when no ':' separator is found, 'Cut' places the whole string to 'probablyDatastoreID',
|
||||
@ -67,7 +80,7 @@ func (d CustomStorageDevice) PathInDatastore() *string {
|
||||
|
||||
// IsOwnedBy returns true, if CustomStorageDevice is owned by given VM.
|
||||
// Not yet allocated volumes are not owned by any VM.
|
||||
func (d CustomStorageDevice) IsOwnedBy(vmID int) bool {
|
||||
func (d *CustomStorageDevice) IsOwnedBy(vmID int) bool {
|
||||
pathInDatastore := d.PathInDatastore()
|
||||
if pathInDatastore == nil {
|
||||
// not yet allocated volume, consider disk not owned by any VM
|
||||
@ -89,14 +102,14 @@ func (d CustomStorageDevice) IsOwnedBy(vmID int) bool {
|
||||
}
|
||||
|
||||
// IsCloudInitDrive returns true, if CustomStorageDevice is a cloud-init drive.
|
||||
func (d CustomStorageDevice) IsCloudInitDrive(vmID int) bool {
|
||||
func (d *CustomStorageDevice) IsCloudInitDrive(vmID int) bool {
|
||||
return d.Media != nil && *d.Media == "cdrom" &&
|
||||
strings.Contains(d.FileVolume, fmt.Sprintf("vm-%d-cloudinit", vmID))
|
||||
}
|
||||
|
||||
// StorageInterface returns the storage interface of the CustomStorageDevice,
|
||||
// e.g. "virtio" or "scsi" for "virtio0" or "scsi2".
|
||||
func (d CustomStorageDevice) StorageInterface() string {
|
||||
func (d *CustomStorageDevice) StorageInterface() string {
|
||||
for i, r := range *d.Interface {
|
||||
if unicode.IsDigit(r) {
|
||||
return (*d.Interface)[:i]
|
||||
@ -108,7 +121,7 @@ func (d CustomStorageDevice) StorageInterface() string {
|
||||
}
|
||||
|
||||
// EncodeOptions converts a CustomStorageDevice's common options a URL value.
|
||||
func (d CustomStorageDevice) EncodeOptions() string {
|
||||
func (d *CustomStorageDevice) EncodeOptions() string {
|
||||
values := []string{}
|
||||
|
||||
if d.AIO != nil {
|
||||
@ -191,7 +204,7 @@ func (d CustomStorageDevice) EncodeOptions() string {
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomStorageDevice struct to a URL value.
|
||||
func (d CustomStorageDevice) EncodeValues(key string, v *url.Values) error {
|
||||
func (d *CustomStorageDevice) EncodeValues(key string, v *url.Values) error {
|
||||
values := []string{
|
||||
fmt.Sprintf("file=%s", d.FileVolume),
|
||||
}
|
||||
@ -215,15 +228,157 @@ func (d CustomStorageDevice) EncodeValues(key string, v *url.Values) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CustomStorageDevices handles map of QEMU storage device per disk interface.
|
||||
type CustomStorageDevices map[string]*CustomStorageDevice
|
||||
// UnmarshalJSON converts a CustomStorageDevice string to an object.
|
||||
func (d *CustomStorageDevice) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal CustomStorageDevice: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
|
||||
//nolint:nestif
|
||||
if len(v) == 1 {
|
||||
d.FileVolume = v[0]
|
||||
|
||||
ext := filepath.Ext(v[0])
|
||||
if ext != "" {
|
||||
format := string([]byte(ext)[1:])
|
||||
d.Format = &format
|
||||
}
|
||||
} else if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "aio":
|
||||
d.AIO = &v[1]
|
||||
|
||||
case "backup":
|
||||
bv := types.CustomBool(v[1] == "1")
|
||||
d.Backup = &bv
|
||||
|
||||
case "cache":
|
||||
d.Cache = &v[1]
|
||||
|
||||
case "discard":
|
||||
d.Discard = &v[1]
|
||||
|
||||
case "file":
|
||||
d.FileVolume = v[1]
|
||||
|
||||
case "format":
|
||||
d.Format = &v[1]
|
||||
|
||||
case "iops_rd":
|
||||
iv, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert iops_rd to int: %w", err)
|
||||
}
|
||||
|
||||
d.IopsRead = &iv
|
||||
|
||||
case "iops_rd_max":
|
||||
iv, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert iops_rd_max to int: %w", err)
|
||||
}
|
||||
|
||||
d.MaxIopsRead = &iv
|
||||
|
||||
case "iops_wr":
|
||||
iv, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert iops_wr to int: %w", err)
|
||||
}
|
||||
|
||||
d.IopsWrite = &iv
|
||||
|
||||
case "iops_wr_max":
|
||||
iv, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert iops_wr_max to int: %w", err)
|
||||
}
|
||||
|
||||
d.MaxIopsWrite = &iv
|
||||
|
||||
case "iothread":
|
||||
bv := types.CustomBool(v[1] == "1")
|
||||
d.IOThread = &bv
|
||||
|
||||
case "mbps_rd":
|
||||
iv, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert mbps_rd to int: %w", err)
|
||||
}
|
||||
|
||||
d.MaxReadSpeedMbps = &iv
|
||||
|
||||
case "mbps_rd_max":
|
||||
iv, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert mbps_rd_max to int: %w", err)
|
||||
}
|
||||
|
||||
d.BurstableReadSpeedMbps = &iv
|
||||
|
||||
case "mbps_wr":
|
||||
iv, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert mbps_wr to int: %w", err)
|
||||
}
|
||||
|
||||
d.MaxWriteSpeedMbps = &iv
|
||||
|
||||
case "mbps_wr_max":
|
||||
iv, err := strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert mbps_wr_max to int: %w", err)
|
||||
}
|
||||
|
||||
d.BurstableWriteSpeedMbps = &iv
|
||||
|
||||
case "media":
|
||||
d.Media = &v[1]
|
||||
|
||||
case "replicate":
|
||||
bv := types.CustomBool(v[1] == "1")
|
||||
d.Replicate = &bv
|
||||
|
||||
case "size":
|
||||
d.Size = new(types.DiskSize)
|
||||
|
||||
err := d.Size.UnmarshalJSON([]byte(v[1]))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal disk size: %w", err)
|
||||
}
|
||||
|
||||
case "ssd":
|
||||
bv := types.CustomBool(v[1] == "1")
|
||||
d.SSD = &bv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d.Enabled = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ByStorageInterface returns a map of CustomStorageDevices filtered by the given storage interface.
|
||||
func (d CustomStorageDevices) ByStorageInterface(storageInterface string) CustomStorageDevices {
|
||||
return d.Filter(func(d *CustomStorageDevice) bool {
|
||||
return d.StorageInterface() == storageInterface
|
||||
})
|
||||
}
|
||||
|
||||
// Filter returns a map of CustomStorageDevices filtered by the given function.
|
||||
func (d CustomStorageDevices) Filter(fn func(*CustomStorageDevice) bool) CustomStorageDevices {
|
||||
result := make(CustomStorageDevices)
|
||||
|
||||
for k, v := range d {
|
||||
if v.StorageInterface() == storageInterface {
|
||||
if fn(v) {
|
||||
result[k] = v
|
||||
}
|
||||
}
|
||||
@ -243,3 +398,27 @@ func (d CustomStorageDevices) EncodeValues(_ string, v *url.Values) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MapCustomStorageDevices maps the custom storage devices from the API response.
|
||||
func MapCustomStorageDevices(resp GetResponseData) CustomStorageDevices {
|
||||
csd := CustomStorageDevices{}
|
||||
|
||||
mapDevice(csd, resp, "ide", "IDE", 3)
|
||||
mapDevice(csd, resp, "sata", "SATA", 5)
|
||||
mapDevice(csd, resp, "scsi", "SCSI", 13)
|
||||
mapDevice(csd, resp, "virtio", "VirtualIO", 15)
|
||||
|
||||
return csd
|
||||
}
|
||||
|
||||
func mapDevice(csd CustomStorageDevices, resp GetResponseData, keyPrefix, fieldPrefix string, end int) {
|
||||
for i := 0; i <= end; i++ {
|
||||
field := reflect.ValueOf(resp).FieldByName(fieldPrefix + "Device" + strconv.Itoa(i))
|
||||
if !field.IsZero() {
|
||||
val := field.Interface()
|
||||
if val != nil {
|
||||
csd[keyPrefix+strconv.Itoa(i)] = val.(*CustomStorageDevice)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -171,7 +171,7 @@ func TestCustomStorageDevices_ByStorageInterface(t *testing.T) {
|
||||
want: CustomStorageDevices{},
|
||||
},
|
||||
{
|
||||
name: "not in the list",
|
||||
name: "nothing matches",
|
||||
iface: "sata",
|
||||
devices: CustomStorageDevices{
|
||||
"virtio0": &CustomStorageDevice{
|
||||
@ -184,7 +184,7 @@ func TestCustomStorageDevices_ByStorageInterface(t *testing.T) {
|
||||
want: CustomStorageDevices{},
|
||||
},
|
||||
{
|
||||
name: "not in the list",
|
||||
name: "partially matches",
|
||||
iface: "virtio",
|
||||
devices: CustomStorageDevices{
|
||||
"virtio0": &CustomStorageDevice{
|
||||
@ -218,45 +218,47 @@ func TestCustomStorageDevices_ByStorageInterface(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomPCIDevice_UnmarshalJSON(t *testing.T) {
|
||||
func TestMapCustomStorageDevices(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
resp GetResponseData
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
line string
|
||||
want *CustomPCIDevice
|
||||
wantErr bool
|
||||
name string
|
||||
args args
|
||||
want CustomStorageDevices
|
||||
}{
|
||||
{"no storage devices", args{GetResponseData{}}, CustomStorageDevices{}},
|
||||
{
|
||||
name: "id only pci device",
|
||||
line: `"0000:81:00.2"`,
|
||||
want: &CustomPCIDevice{
|
||||
DeviceIDs: &[]string{"0000:81:00.2"},
|
||||
},
|
||||
"ide0 storage devices",
|
||||
args{GetResponseData{IDEDevice0: &CustomStorageDevice{}}},
|
||||
map[string]*CustomStorageDevice{"ide0": {}},
|
||||
},
|
||||
{
|
||||
name: "pci device with more details",
|
||||
line: `"host=81:00.4,pcie=0,rombar=1,x-vga=0"`,
|
||||
want: &CustomPCIDevice{
|
||||
DeviceIDs: &[]string{"81:00.4"},
|
||||
MDev: nil,
|
||||
PCIExpress: types.CustomBool(false).Pointer(),
|
||||
ROMBAR: types.CustomBool(true).Pointer(),
|
||||
ROMFile: nil,
|
||||
XVGA: types.CustomBool(false).Pointer(),
|
||||
},
|
||||
"multiple ide storage devices",
|
||||
args{GetResponseData{
|
||||
IDEDevice1: &CustomStorageDevice{},
|
||||
IDEDevice3: &CustomStorageDevice{},
|
||||
}},
|
||||
map[string]*CustomStorageDevice{"ide1": {}, "ide3": {}},
|
||||
},
|
||||
{
|
||||
name: "pci device with mapping",
|
||||
line: `"mapping=mappeddevice,pcie=0,rombar=1,x-vga=0"`,
|
||||
want: &CustomPCIDevice{
|
||||
DeviceIDs: nil,
|
||||
Mapping: ptr.Ptr("mappeddevice"),
|
||||
MDev: nil,
|
||||
PCIExpress: types.CustomBool(false).Pointer(),
|
||||
ROMBAR: types.CustomBool(true).Pointer(),
|
||||
ROMFile: nil,
|
||||
XVGA: types.CustomBool(false).Pointer(),
|
||||
"mixed storage devices",
|
||||
args{GetResponseData{
|
||||
IDEDevice1: &CustomStorageDevice{},
|
||||
VirtualIODevice5: &CustomStorageDevice{},
|
||||
SATADevice0: &CustomStorageDevice{},
|
||||
IDEDevice3: &CustomStorageDevice{},
|
||||
SCSIDevice10: &CustomStorageDevice{},
|
||||
}},
|
||||
map[string]*CustomStorageDevice{
|
||||
"ide1": {},
|
||||
"virtio5": {},
|
||||
"sata0": {},
|
||||
"ide3": {},
|
||||
"scsi10": {},
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -265,100 +267,7 @@ func TestCustomPCIDevice_UnmarshalJSON(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := &CustomPCIDevice{}
|
||||
if err := r.UnmarshalJSON([]byte(tt.line)); (err != nil) != tt.wantErr {
|
||||
t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
||||
require.Equal(t, tt.want, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomNUMADevice_UnmarshalJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
line string
|
||||
want *CustomNUMADevice
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "numa device all options",
|
||||
line: `"cpus=1-2;3-4,hostnodes=1-2,memory=1024,policy=preferred"`,
|
||||
want: &CustomNUMADevice{
|
||||
CPUIDs: []string{"1-2", "3-4"},
|
||||
HostNodeNames: &[]string{"1-2"},
|
||||
Memory: ptr.Ptr(1024),
|
||||
Policy: ptr.Ptr("preferred"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "numa device cpus/memory only",
|
||||
line: `"cpus=1-2,memory=1024"`,
|
||||
want: &CustomNUMADevice{
|
||||
CPUIDs: []string{"1-2"},
|
||||
Memory: ptr.Ptr(1024),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := &CustomNUMADevice{}
|
||||
if err := r.UnmarshalJSON([]byte(tt.line)); (err != nil) != tt.wantErr {
|
||||
t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomUSBDevice_UnmarshalJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
line string
|
||||
want *CustomUSBDevice
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "id only usb device",
|
||||
line: `"host=0000:81"`,
|
||||
want: &CustomUSBDevice{
|
||||
HostDevice: ptr.Ptr("0000:81"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "usb device with more details",
|
||||
line: `"host=81:00,usb3=0"`,
|
||||
want: &CustomUSBDevice{
|
||||
HostDevice: ptr.Ptr("81:00"),
|
||||
USB3: types.CustomBool(false).Pointer(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "usb device with mapping",
|
||||
line: `"mapping=mappeddevice,usb=0"`,
|
||||
want: &CustomUSBDevice{
|
||||
HostDevice: nil,
|
||||
Mapping: ptr.Ptr("mappeddevice"),
|
||||
USB3: types.CustomBool(false).Pointer(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := &CustomUSBDevice{}
|
||||
if err := r.UnmarshalJSON([]byte(tt.line)); (err != nil) != tt.wantErr {
|
||||
t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
assert.Equalf(t, tt.want, MapCustomStorageDevices(tt.args.resp), "MapCustomStorageDevices(%v)", tt.args.resp)
|
||||
})
|
||||
}
|
||||
}
|
62
proxmox/nodes/vms/custom_tpm_state.go
Normal file
62
proxmox/nodes/vms/custom_tpm_state.go
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CustomTPMState handles QEMU TPM state parameters.
|
||||
type CustomTPMState struct {
|
||||
FileVolume string `json:"file" url:"file"`
|
||||
Version *string `json:"version,omitempty" url:"version,omitempty"`
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomTPMState struct to a URL value.
|
||||
func (r *CustomTPMState) EncodeValues(key string, v *url.Values) error {
|
||||
values := []string{
|
||||
fmt.Sprintf("file=%s", r.FileVolume),
|
||||
}
|
||||
|
||||
if r.Version != nil {
|
||||
values = append(values, fmt.Sprintf("version=%s", *r.Version))
|
||||
}
|
||||
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomTPMState string to an object.
|
||||
func (r *CustomTPMState) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal CustomTPMState: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
if len(v) == 1 {
|
||||
r.FileVolume = v[0]
|
||||
} else if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "file":
|
||||
r.FileVolume = v[1]
|
||||
case "version":
|
||||
r.Version = &v[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
95
proxmox/nodes/vms/custom_usb_device.go
Normal file
95
proxmox/nodes/vms/custom_usb_device.go
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||
)
|
||||
|
||||
// CustomUSBDevice handles QEMU USB device parameters.
|
||||
type CustomUSBDevice struct {
|
||||
HostDevice *string `json:"host" url:"host"`
|
||||
Mapping *string `json:"mapping,omitempty" url:"mapping,omitempty"`
|
||||
USB3 *types.CustomBool `json:"usb3,omitempty" url:"usb3,omitempty,int"`
|
||||
}
|
||||
|
||||
// CustomUSBDevices handles QEMU USB device parameters.
|
||||
type CustomUSBDevices []CustomUSBDevice
|
||||
|
||||
// EncodeValues converts a CustomUSBDevice struct to a URL value.
|
||||
func (r *CustomUSBDevice) EncodeValues(key string, v *url.Values) error {
|
||||
if r.HostDevice == nil && r.Mapping == nil {
|
||||
return fmt.Errorf("either device ID or resource mapping must be set")
|
||||
}
|
||||
|
||||
values := []string{}
|
||||
if r.HostDevice != nil {
|
||||
values = append(values, fmt.Sprintf("host=%s", *(r.HostDevice)))
|
||||
}
|
||||
|
||||
if r.Mapping != nil {
|
||||
values = append(values, fmt.Sprintf("mapping=%s", *r.Mapping))
|
||||
}
|
||||
|
||||
if r.USB3 != nil {
|
||||
if *r.USB3 {
|
||||
values = append(values, "usb3=1")
|
||||
} else {
|
||||
values = append(values, "usb3=0")
|
||||
}
|
||||
}
|
||||
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomUSBDevices array to multiple URL values.
|
||||
func (r CustomUSBDevices) EncodeValues(key string, v *url.Values) error {
|
||||
for i, d := range r {
|
||||
if err := d.EncodeValues(fmt.Sprintf("%s%d", key, i), v); err != nil {
|
||||
return fmt.Errorf("error encoding USB device %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomUSBDevice string to an object.
|
||||
func (r *CustomUSBDevice) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal CustomUSBDevice: %w", err)
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
if len(v) == 1 {
|
||||
r.HostDevice = &v[1]
|
||||
} else if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "host":
|
||||
r.HostDevice = &v[1]
|
||||
case "mapping":
|
||||
r.Mapping = &v[1]
|
||||
case "usb3":
|
||||
bv := types.CustomBool(v[1] == "1")
|
||||
r.USB3 = &bv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
61
proxmox/nodes/vms/custom_usb_device_test.go
Normal file
61
proxmox/nodes/vms/custom_usb_device_test.go
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/helpers/ptr"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||
)
|
||||
|
||||
func TestCustomUSBDevice_UnmarshalJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
line string
|
||||
want *CustomUSBDevice
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "id only usb device",
|
||||
line: `"host=0000:81"`,
|
||||
want: &CustomUSBDevice{
|
||||
HostDevice: ptr.Ptr("0000:81"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "usb device with more details",
|
||||
line: `"host=81:00,usb3=0"`,
|
||||
want: &CustomUSBDevice{
|
||||
HostDevice: ptr.Ptr("81:00"),
|
||||
USB3: types.CustomBool(false).Pointer(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "usb device with mapping",
|
||||
line: `"mapping=mappeddevice,usb=0"`,
|
||||
want: &CustomUSBDevice{
|
||||
HostDevice: nil,
|
||||
Mapping: ptr.Ptr("mappeddevice"),
|
||||
USB3: types.CustomBool(false).Pointer(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := &CustomUSBDevice{}
|
||||
if err := r.UnmarshalJSON([]byte(tt.line)); (err != nil) != tt.wantErr {
|
||||
t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
83
proxmox/nodes/vms/custom_vga_device.go
Normal file
83
proxmox/nodes/vms/custom_vga_device.go
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CustomVGADevice handles QEMU VGA device parameters.
|
||||
type CustomVGADevice struct {
|
||||
Clipboard *string `json:"clipboard,omitempty" url:"memory,omitempty"`
|
||||
Memory *int64 `json:"memory,omitempty" url:"memory,omitempty"`
|
||||
Type *string `json:"type,omitempty" url:"type,omitempty"`
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomVGADevice struct to a URL value.
|
||||
func (r CustomVGADevice) EncodeValues(key string, v *url.Values) error {
|
||||
var values []string
|
||||
|
||||
if r.Clipboard != nil {
|
||||
values = append(values, fmt.Sprintf("clipboard=%s", *r.Clipboard))
|
||||
}
|
||||
|
||||
if r.Memory != nil {
|
||||
values = append(values, fmt.Sprintf("memory=%d", *r.Memory))
|
||||
}
|
||||
|
||||
if r.Type != nil {
|
||||
values = append(values, fmt.Sprintf("type=%s", *r.Type))
|
||||
}
|
||||
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomVGADevice string to an object.
|
||||
func (r *CustomVGADevice) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal CustomVGADevice: %w", err)
|
||||
}
|
||||
|
||||
if s == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
|
||||
if len(v) == 1 {
|
||||
r.Type = &v[0]
|
||||
} else if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "clipboard":
|
||||
r.Clipboard = &v[1]
|
||||
|
||||
case "memory":
|
||||
m, err := strconv.ParseInt(v[1], 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert memory to int: %w", err)
|
||||
}
|
||||
|
||||
r.Memory = &m
|
||||
case "type":
|
||||
r.Type = &v[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
62
proxmox/nodes/vms/custom_virtualio_device.go
Normal file
62
proxmox/nodes/vms/custom_virtualio_device.go
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||
)
|
||||
|
||||
// CustomVirtualIODevice handles QEMU VirtIO device parameters.
|
||||
type CustomVirtualIODevice struct {
|
||||
AIO *string `json:"aio,omitempty" url:"aio,omitempty"`
|
||||
BackupEnabled *types.CustomBool `json:"backup,omitempty" url:"backup,omitempty,int"`
|
||||
Enabled bool `json:"-" url:"-"`
|
||||
FileVolume string `json:"file" url:"file"`
|
||||
}
|
||||
|
||||
// CustomVirtualIODevices handles QEMU VirtIO device parameters.
|
||||
type CustomVirtualIODevices []CustomVirtualIODevice
|
||||
|
||||
// EncodeValues converts a CustomVirtualIODevice struct to a URL value.
|
||||
func (r CustomVirtualIODevice) EncodeValues(key string, v *url.Values) error {
|
||||
values := []string{
|
||||
fmt.Sprintf("file=%s", r.FileVolume),
|
||||
}
|
||||
|
||||
if r.AIO != nil {
|
||||
values = append(values, fmt.Sprintf("aio=%s", *r.AIO))
|
||||
}
|
||||
|
||||
if r.BackupEnabled != nil {
|
||||
if *r.BackupEnabled {
|
||||
values = append(values, "backup=1")
|
||||
} else {
|
||||
values = append(values, "backup=0")
|
||||
}
|
||||
}
|
||||
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomVirtualIODevices array to multiple URL values.
|
||||
func (r CustomVirtualIODevices) EncodeValues(key string, v *url.Values) error {
|
||||
for i, d := range r {
|
||||
if d.Enabled {
|
||||
if err := d.EncodeValues(fmt.Sprintf("%s%d", key, i), v); err != nil {
|
||||
return fmt.Errorf("error encoding virtual IO device %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
67
proxmox/nodes/vms/custom_watchdog_device.go
Normal file
67
proxmox/nodes/vms/custom_watchdog_device.go
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package vms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CustomWatchdogDevice handles QEMU watchdog device parameters.
|
||||
type CustomWatchdogDevice struct {
|
||||
Action *string `json:"action,omitempty" url:"action,omitempty"`
|
||||
Model *string `json:"model" url:"model"`
|
||||
}
|
||||
|
||||
// EncodeValues converts a CustomWatchdogDevice struct to a URL value.
|
||||
func (r *CustomWatchdogDevice) EncodeValues(key string, v *url.Values) error {
|
||||
values := []string{
|
||||
fmt.Sprintf("model=%+v", r.Model),
|
||||
}
|
||||
|
||||
if r.Action != nil {
|
||||
values = append(values, fmt.Sprintf("action=%s", *r.Action))
|
||||
}
|
||||
|
||||
v.Add(key, strings.Join(values, ","))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a CustomWatchdogDevice string to an object.
|
||||
func (r *CustomWatchdogDevice) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal CustomWatchdogDevice: %w", err)
|
||||
}
|
||||
|
||||
if s == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
pairs := strings.Split(s, ",")
|
||||
|
||||
for _, p := range pairs {
|
||||
v := strings.Split(strings.TrimSpace(p), "=")
|
||||
|
||||
if len(v) == 1 {
|
||||
r.Model = &v[0]
|
||||
} else if len(v) == 2 {
|
||||
switch v[0] {
|
||||
case "action":
|
||||
r.Action = &v[1]
|
||||
case "model":
|
||||
r.Model = &v[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -2215,8 +2215,6 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
|
||||
return diag.FromErr(e)
|
||||
}
|
||||
|
||||
/////////////////
|
||||
|
||||
allDiskInfo := disk.GetInfo(vmConfig, d) // from the cloned VM
|
||||
|
||||
planDisks, e := disk.GetDiskDeviceObjects(d, VM(), nil) // from the resource config
|
||||
|
Loading…
Reference in New Issue
Block a user