0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-06-30 02:31:10 +00:00
terraform-provider-proxmox/fwprovider/vm/cpu/resource.go
Pavel Boldyrev 80cafa689f
feat(vm2): add initial support for cdrom (#1370)
feat(vm2): add initial support for `cdrom`

This is a breaking change comparing to v1 - switching the cdrom schema from a nested block to a nested attribute map.

Improvements comparing to v1:
- support for `ide`, `sata`, `scsi` interfaces
- support for multiple cdroms

Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
2024-06-10 01:28:18 +00:00

255 lines
7.0 KiB
Go

/*
* 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 cpu
import (
"context"
"reflect"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/vms"
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types"
)
// Value represents the type for CPU settings.
type Value = types.Object
// NewValue returns a new Value with the given CPU settings from the PVE API.
func NewValue(ctx context.Context, config *vms.GetResponseData, diags *diag.Diagnostics) Value {
cpu := Model{}
cpu.Affinity = types.StringPointerValue(config.CPUAffinity)
cpu.Architecture = types.StringPointerValue(config.CPUArchitecture)
cpu.Hotplugged = types.Int64PointerValue(config.VirtualCPUCount)
cpu.Limit = types.Int64PointerValue(config.CPULimit.PointerInt64())
cpu.Numa = types.BoolPointerValue(config.NUMAEnabled.PointerBool())
cpu.Units = types.Int64PointerValue(config.CPUUnits)
// special cases: PVE does not return actual value for cores VM, etc is using default (i.e. a value is not specified)
if config.CPUCores != nil {
cpu.Cores = types.Int64PointerValue(config.CPUCores)
} else {
cpu.Cores = types.Int64Value(1)
}
if config.CPUSockets != nil {
cpu.Sockets = types.Int64PointerValue(config.CPUSockets)
} else {
cpu.Sockets = types.Int64Value(1)
}
if config.CPUEmulation != nil {
cpu.Type = types.StringValue(config.CPUEmulation.Type)
flags, d := types.SetValueFrom(ctx, basetypes.StringType{}, config.CPUEmulation.Flags)
diags.Append(d...)
cpu.Flags = flags
} else {
cpu.Type = types.StringValue("kvm64")
cpu.Flags = types.SetNull(basetypes.StringType{})
}
obj, d := types.ObjectValueFrom(ctx, attributeTypes(), cpu)
diags.Append(d...)
return obj
}
// FillCreateBody fills the CreateRequestBody with the CPU settings from the Value.
//
// In the 'create' context, v is the plan.
func FillCreateBody(ctx context.Context, planValue Value, body *vms.CreateRequestBody, diags *diag.Diagnostics) {
var plan Model
if planValue.IsNull() || planValue.IsUnknown() {
return
}
d := planValue.As(ctx, &plan, basetypes.ObjectAsOptions{})
diags.Append(d...)
if d.HasError() {
return
}
// for computed fields, we need to check if they are unknown
if !plan.Affinity.IsUnknown() {
body.CPUAffinity = plan.Affinity.ValueStringPointer()
}
if !plan.Architecture.IsUnknown() {
body.CPUArchitecture = plan.Architecture.ValueStringPointer()
}
if !plan.Cores.IsUnknown() {
body.CPUCores = plan.Cores.ValueInt64Pointer()
}
if !plan.Limit.IsUnknown() {
body.CPULimit = plan.Limit.ValueInt64Pointer()
}
if !plan.Sockets.IsUnknown() {
body.CPUSockets = plan.Sockets.ValueInt64Pointer()
}
if !plan.Units.IsUnknown() {
body.CPUUnits = plan.Units.ValueInt64Pointer()
}
if !plan.Numa.IsUnknown() {
body.NUMAEnabled = proxmoxtypes.CustomBoolPtr(plan.Numa.ValueBoolPointer())
}
if !plan.Hotplugged.IsUnknown() {
body.VirtualCPUCount = plan.Hotplugged.ValueInt64Pointer()
}
body.CPUEmulation = &vms.CustomCPUEmulation{}
if !plan.Type.IsUnknown() {
body.CPUEmulation.Type = plan.Type.ValueString()
}
if !plan.Flags.IsUnknown() {
d = plan.Flags.ElementsAs(ctx, &body.CPUEmulation.Flags, false)
diags.Append(d...)
}
}
// FillUpdateBody fills the UpdateRequestBody with the CPU settings from the Value.
//
// In the 'update' context, v is the plan and stateValue is the current state.
func FillUpdateBody(
ctx context.Context,
planValue, stateValue Value,
updateBody *vms.UpdateRequestBody,
isClone bool,
diags *diag.Diagnostics,
) {
var plan, state Model
if planValue.IsNull() || planValue.IsUnknown() || planValue.Equal(stateValue) {
return
}
d := planValue.As(ctx, &plan, basetypes.ObjectAsOptions{})
diags.Append(d...)
d = stateValue.As(ctx, &state, basetypes.ObjectAsOptions{})
diags.Append(d...)
if diags.HasError() {
return
}
var errs []error
del := func(field string) {
errs = append(errs, updateBody.ToDelete(field))
}
if !plan.Affinity.Equal(state.Affinity) {
if attribute.ShouldBeRemoved(plan.Affinity, state.Affinity, isClone) {
del("CPUAffinity")
} else if attribute.IsDefined(plan.Affinity) {
updateBody.CPUAffinity = plan.Affinity.ValueStringPointer()
}
}
if !plan.Architecture.Equal(state.Architecture) {
if attribute.ShouldBeRemoved(plan.Architecture, state.Architecture, isClone) {
del("CPUArchitecture")
} else if attribute.IsDefined(plan.Architecture) {
updateBody.CPUArchitecture = plan.Architecture.ValueStringPointer()
}
}
if !plan.Cores.Equal(state.Cores) {
if attribute.ShouldBeRemoved(plan.Cores, state.Cores, isClone) {
del("CPUCores")
} else if attribute.IsDefined(plan.Cores) {
updateBody.CPUCores = plan.Cores.ValueInt64Pointer()
}
}
if !plan.Limit.Equal(state.Limit) {
if attribute.ShouldBeRemoved(plan.Limit, state.Limit, isClone) {
del("CPULimit")
} else if attribute.IsDefined(plan.Sockets) {
updateBody.CPULimit = plan.Limit.ValueInt64Pointer()
}
}
if !plan.Sockets.Equal(state.Sockets) {
if attribute.ShouldBeRemoved(plan.Sockets, state.Sockets, isClone) {
del("CPUSockets")
} else if attribute.IsDefined(plan.Sockets) {
updateBody.CPUSockets = plan.Sockets.ValueInt64Pointer()
}
}
if !plan.Units.Equal(state.Units) {
if attribute.ShouldBeRemoved(plan.Units, state.Units, isClone) {
del("CPUUnits")
} else if attribute.IsDefined(plan.Units) {
updateBody.CPUUnits = plan.Units.ValueInt64Pointer()
}
}
if !plan.Numa.Equal(state.Numa) {
if attribute.ShouldBeRemoved(plan.Numa, state.Numa, isClone) {
del("NUMAEnabled")
} else if attribute.IsDefined(plan.Numa) {
updateBody.NUMAEnabled = proxmoxtypes.CustomBoolPtr(plan.Numa.ValueBoolPointer())
}
}
if !plan.Hotplugged.Equal(state.Hotplugged) {
if attribute.ShouldBeRemoved(plan.Hotplugged, state.Hotplugged, isClone) {
del("VirtualCPUCount")
} else if attribute.IsDefined(plan.Hotplugged) {
updateBody.VirtualCPUCount = plan.Hotplugged.ValueInt64Pointer()
}
}
var delType, delFlags bool
cpuEmulation := &vms.CustomCPUEmulation{}
if !plan.Type.Equal(state.Type) {
if attribute.ShouldBeRemoved(plan.Type, state.Type, isClone) {
delType = true
} else if attribute.IsDefined(plan.Type) {
cpuEmulation.Type = plan.Type.ValueString()
}
}
if !plan.Flags.Equal(state.Flags) {
if attribute.ShouldBeRemoved(plan.Flags, state.Flags, isClone) {
delFlags = true
} else if attribute.IsDefined(plan.Flags) {
d = plan.Flags.ElementsAs(ctx, &cpuEmulation.Flags, false)
diags.Append(d...)
}
}
switch {
case delType && !delFlags:
diags.AddError("Cannot have CPU flags without explicit definition of CPU type", "")
case delType:
del("CPUEmulation")
case !reflect.DeepEqual(cpuEmulation, &vms.CustomCPUEmulation{}):
updateBody.CPUEmulation = cpuEmulation
}
}