0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-07-02 03:22:59 +00:00
terraform-provider-proxmox/fwprovider/vm/cloudinit/resource.go
Pavel Boldyrev d91a559fb5
clone works
Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
2024-09-22 21:34:23 -04:00

191 lines
5.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 cloudinit
import (
"context"
"fmt"
"reflect"
"strings"
"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"
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types"
"github.com/bpg/terraform-provider-proxmox/proxmox/helpers/ptr"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/vms"
)
// Value represents the type for CPU settings.
type Value = types.Object
type DNSValue = types.Object
// NewValue returns a new Value with the given CPU settings from the PVE API.
func NewValue(ctx context.Context, config *vms.GetResponseData, vmID int, diags *diag.Diagnostics) Value {
ci := Model{}
devices := config.CustomStorageDevices.Filter(func(device *vms.CustomStorageDevice) bool {
return device.IsCloudInitDrive(vmID)
})
if len(devices) != 1 {
types.ObjectNull(attributeTypes())
}
for iface, device := range devices {
ci.Interface = types.StringValue(iface)
ci.DatastoreID = types.StringValue(device.GetDatastoreID())
dns := ModelDNS{}
dns.Domain = types.StringPointerValue(config.CloudInitDNSDomain)
if config.CloudInitDNSServer != nil && strings.Trim(*config.CloudInitDNSServer, " ") != "" {
dnsServers := strings.Split(*config.CloudInitDNSServer, " ")
servers, d := types.ListValueFrom(ctx, customtypes.IPAddrType{}, dnsServers)
diags.Append(d...)
dns.Servers = servers
} else {
dns.Servers = types.ListNull(customtypes.IPAddrType{})
}
if !reflect.DeepEqual(dns, ModelDNS{}) {
dnsObj, d := types.ObjectValueFrom(ctx, attributeTypesDNS(), dns)
diags.Append(d...)
ci.DNS = dnsObj
}
obj, d := types.ObjectValueFrom(ctx, attributeTypes(), ci)
diags.Append(d...)
return obj
}
return types.ObjectNull(attributeTypes())
}
// FillCreateBody fills the CreateRequestBody with the Cloud-Init settings from the Value.
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
}
ci := vms.CustomCloudInitConfig{}
// TODO: should we check for !null?
if !plan.DNS.IsUnknown() {
var dns ModelDNS
plan.DNS.As(ctx, &dns, basetypes.ObjectAsOptions{})
if !dns.Domain.IsUnknown() {
ci.SearchDomain = dns.Domain.ValueStringPointer()
}
if !dns.Servers.IsUnknown() {
var servers []string
dns.Servers.ElementsAs(ctx, &servers, false)
ci.Nameserver = ptr.Ptr(strings.Join(servers, " "))
}
}
body.CloudInitConfig = &ci
device := vms.CustomStorageDevice{
Enabled: true,
FileVolume: fmt.Sprintf("%s:cloudinit", plan.DatastoreID.ValueString()),
Media: ptr.Ptr("cdrom"),
}
body.AddCustomStorageDevice(plan.Interface.ValueString(), device)
}
// FillUpdateBody fills the UpdateRequestBody with the Cloud-Init settings from the Value.
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
}
del := func(field ...string) {
updateBody.Delete = append(updateBody.Delete, field...)
}
// TODO: migrate cloud init to another datastore
if !reflect.DeepEqual(plan.DNS, state.DNS) {
if attribute.ShouldBeRemoved(plan.DNS, state.DNS, isClone) {
del("searchdomain", "nameserver")
} else if attribute.IsDefined(plan.DNS) {
ci := vms.CustomCloudInitConfig{}
var planDNS, stateDNS ModelDNS
d = plan.DNS.As(ctx, &planDNS, basetypes.ObjectAsOptions{})
diags.Append(d...)
d = state.DNS.As(ctx, &stateDNS, basetypes.ObjectAsOptions{})
diags.Append(d...)
if diags.HasError() {
return
}
if !planDNS.Domain.Equal(stateDNS.Domain) {
if attribute.ShouldBeRemoved(planDNS.Domain, stateDNS.Domain, isClone) {
del("searchdomain")
} else if attribute.IsDefined(planDNS.Domain) {
ci.SearchDomain = planDNS.Domain.ValueStringPointer()
}
}
if !planDNS.Servers.Equal(stateDNS.Servers) {
if attribute.ShouldBeRemoved(planDNS.Servers, stateDNS.Servers, isClone) {
del("nameserver")
} else if attribute.IsDefined(planDNS.Servers) {
var servers []string
planDNS.Servers.ElementsAs(ctx, &servers, false)
ci.Nameserver = ptr.Ptr(strings.Join(servers, " "))
}
}
updateBody.CloudInitConfig = &ci
}
}
}