From 358f56ec9047107c2d59714f69a0775a6d78c211 Mon Sep 17 00:00:00 2001 From: Justin Cinkelj Date: Tue, 25 Mar 2025 14:49:43 +0100 Subject: [PATCH 1/4] Add hypercore_node data source Signed-off-by: Justin Cinkelj --- .../hypercore_node/data-source.tf | 19 +++ .../provider/hypercore_node_data_source.go | 142 ++++++++++++++++++ internal/provider/provider.go | 1 + local/main.tf | 116 +------------- 4 files changed, 167 insertions(+), 111 deletions(-) create mode 100644 examples/data-sources/hypercore_node/data-source.tf create mode 100644 internal/provider/hypercore_node_data_source.go diff --git a/examples/data-sources/hypercore_node/data-source.tf b/examples/data-sources/hypercore_node/data-source.tf new file mode 100644 index 0000000..79e6ee7 --- /dev/null +++ b/examples/data-sources/hypercore_node/data-source.tf @@ -0,0 +1,19 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +# Get all nodes +data "hypercore_node" "all_nodes" { +} + +output "hypercore_nodes" { + value = data.hypercore_node.all_nodes.nodes +} + +# Get a specific node +data "hypercore_node" "node_1" { + peer_id = 1 +} + +output "hypercore_node_1_uuid" { + value = data.hypercore_node.node_1.nodes.0.uuid +} diff --git a/internal/provider/hypercore_node_data_source.go b/internal/provider/hypercore_node_data_source.go new file mode 100644 index 0000000..b83af0e --- /dev/null +++ b/internal/provider/hypercore_node_data_source.go @@ -0,0 +1,142 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// https://developer.hashicorp.com/terraform/tutorials/providers-plugin-framework/providers-plugin-framework-data-source-read +// https://developer.hashicorp.com/terraform/plugin/framework/migrating + +package provider + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-provider-hypercore/internal/utils" +) + +// Ensure the implementation satisfies the expected interfaces. +var ( + _ datasource.DataSource = &hypercoreNodeDataSource{} + _ datasource.DataSourceWithConfigure = &hypercoreNodeDataSource{} +) + +// NewHypercoreNodeDataSource is a helper function to simplify the provider implementation. +func NewHypercoreNodeDataSource() datasource.DataSource { + return &hypercoreNodeDataSource{} +} + +// hypercoreNodeDataSource is the data source implementation. +type hypercoreNodeDataSource struct { + client *utils.RestClient +} + +// coffeesDataSourceModel maps the data source schema data. +type hypercoreNodesDataSourceModel struct { + FilterPeerID types.Int64 `tfsdk:"peer_id"` + Nodes []hypercoreNodeModel `tfsdk:"nodes"` +} + +// hypercoreVMModel maps VM schema data. +type hypercoreNodeModel struct { + UUID types.String `tfsdk:"uuid"` + BackplaneIP types.String `tfsdk:"backplane_ip"` + LanIP types.String `tfsdk:"lan_ip"` + PeerID types.Int64 `tfsdk:"peer_id"` +} + +// Metadata returns the data source type name. +func (d *hypercoreNodeDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_node" +} + +// Schema defines the schema for the data source. +func (d *hypercoreNodeDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "peer_id": schema.Int64Attribute{ + Optional: true, + }, + "nodes": schema.ListNestedAttribute{ + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "uuid": schema.StringAttribute{ + Computed: true, + }, + "backplane_ip": schema.StringAttribute{ + Computed: true, + }, + "lan_ip": schema.StringAttribute{ + Computed: true, + }, + "peer_id": schema.Int64Attribute{ + Computed: true, + }, + }, + }, + }, + }, + } +} + +// Configure adds the provider configured client to the data source. +func (d *hypercoreNodeDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + // Add a nil check when handling ProviderData because Terraform + // sets that data after it calls the ConfigureProvider RPC. + if req.ProviderData == nil { + return + } + + restClient, ok := req.ProviderData.(*utils.RestClient) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected *http.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + + d.client = restClient +} + +// Read refreshes the Terraform state with the latest data. +func (d *hypercoreNodeDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var conf hypercoreNodesDataSourceModel + req.Config.Get(ctx, &conf) + // use float64, because this is the type of loaded json data + filter_peer_id := float64(conf.FilterPeerID.ValueInt64()) + + query := map[string]any{} + // peerID=0 is reserved value, never returned by HC3 + if filter_peer_id != 0.0 { + query = map[string]any{"peerID": filter_peer_id} + } + + hc3_nodes := d.client.ListRecords( + "/rest/v1/Node", + query, + -1.0, + ) + tflog.Info(ctx, fmt.Sprintf("TTRT: filter_peer_id=%v node_count=%d\n", filter_peer_id, len(hc3_nodes))) + + var state hypercoreNodesDataSourceModel + for _, node := range hc3_nodes { + hypercoreNodeState := hypercoreNodeModel{ + UUID: types.StringValue(utils.AnyToString(node["uuid"])), + BackplaneIP: types.StringValue(utils.AnyToString(node["backplaneIP"])), + LanIP: types.StringValue(utils.AnyToString(node["lanIP"])), + PeerID: types.Int64Value(utils.AnyToInteger64(node["peerID"])), + } + state.Nodes = append(state.Nodes, hypercoreNodeState) + } + + // Set state + diags := resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 8e5a92b..5292e97 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -177,6 +177,7 @@ func (p *HypercoreProvider) Resources(ctx context.Context) []func() resource.Res func (p *HypercoreProvider) DataSources(ctx context.Context) []func() datasource.DataSource { return []func() datasource.DataSource{ NewHypercoreVMDataSource, + NewHypercoreNodeDataSource, } } diff --git a/local/main.tf b/local/main.tf index 756d515..0defa99 100644 --- a/local/main.tf +++ b/local/main.tf @@ -20,119 +20,13 @@ locals { vm_user_data_tmpl = "./assets/user-data.ubuntu-22.04.yml.tftpl" } -data "hypercore_vm" "diskvm" { - name = local.vm_name +data "hypercore_node" "cluster0_all" { } -data "hypercore_vm" "empty" { - name = local.empty_vm +data "hypercore_node" "cluster0_peer1" { + peer_id = 1 } -output "empty_vm" { - value = data.hypercore_vm.empty.vms.0.uuid -} - -output "disk_vm" { - value = data.hypercore_vm.diskvm.vms.0.uuid -} - -resource "hypercore_vm" "clone_empty" { - group = "ananas-clone" - name = local.clone_empty_vm - description = "some description" - - vcpu = 4 - memory = 4096 # MiB - - clone = { - source_vm_uuid = data.hypercore_vm.empty.vms.0.uuid - meta_data = templatefile(local.vm_meta_data_tmpl, { - name = local.clone_empty_vm, - }) - user_data = templatefile(local.vm_user_data_tmpl, { - name = local.clone_empty_vm, - ssh_authorized_keys = "", - ssh_import_id = "", - }) - } -} - -resource "hypercore_vm_power_state" "start_clone_empy" { - vm_uuid = hypercore_vm.clone_empty.id - state = "RUNNING" - - depends_on = [hypercore_vm.clone_empty] -} - -resource "hypercore_vm_power_state" "stop_clone_empy" { - vm_uuid = hypercore_vm.clone_empty.id - state = "SHUTOFF" - force_shutoff = true - - depends_on = [hypercore_vm_power_state.start_clone_empy] -} - -resource "hypercore_virtual_disk" "vd_import_os" { - name = "testtf-ana-ubuntu.img" -} - -resource "hypercore_nic" "some_nic" { - vm_uuid = data.hypercore_vm.empty.vms.0.uuid - vlan = 11 - type = "VIRTIO" - - depends_on = [ hypercore_vm.clone_empty ] -} - -resource "hypercore_disk" "os" { - vm_uuid = data.hypercore_vm.empty.vms.0.uuid - type = "VIRTIO_DISK" - size = 42.2 - source_virtual_disk_id = hypercore_virtual_disk.vd_import_os.id - - depends_on = [hypercore_nic.some_nic] -} - -import { - to = hypercore_virtual_disk.vd_import_os - id = "4cf1cbc7-588c-4897-b0b1-d212d61e4bc5" -} - -resource "hypercore_disk" "another_disk" { - vm_uuid = data.hypercore_vm.empty.vms.0.uuid - type = "IDE_DISK" - size = 3.14 - - depends_on = [hypercore_disk.os] -} - -# On a VM with no disks at all. Disks were created and attached here -resource "hypercore_vm_boot_order" "testtf_created_boot_order" { - vm_uuid = data.hypercore_vm.empty.vms.0.uuid - boot_devices = [ - hypercore_disk.os.id, - hypercore_nic.some_nic.id, - hypercore_disk.another_disk.id, - ] - - depends_on = [ - hypercore_disk.os, - hypercore_disk.another_disk, - hypercore_nic.some_nic, - ] -} - -# On a VM with already existing boot order and now modified -resource "hypercore_vm_boot_order" "testtf_imported_boot_order" { - vm_uuid = data.hypercore_vm.diskvm.vms.0.uuid - boot_devices = [ - "c801157d-d454-4842-88ea-d8461e9b802f", - "ce837222-e4da-40b5-9d12-abdc5f6f73ae", - "5c566e31-44a1-4619-9490-5403e906b2ab", - ] -} - -import { - to = hypercore_vm_boot_order.testtf_imported_boot_order - id = data.hypercore_vm.diskvm.vms.0.uuid +output "cluster_0_peer_1_uuid" { + value = data.hypercore_node.cluster0_peer1.nodes.0.uuid } From dffe1d8ed3577b4bcf9bd14bdb7c0e2bb274a524 Mon Sep 17 00:00:00 2001 From: Justin Cinkelj Date: Wed, 26 Mar 2025 11:23:27 +0100 Subject: [PATCH 2/4] Add node affinity to VM Signed-off-by: Justin Cinkelj --- internal/provider/hypercore_vm_resource.go | 68 +++++++++++++++++++--- internal/utils/helper.go | 9 +++ internal/utils/vm.go | 42 ++++++++++--- local/main.tf | 20 ++++++- 4 files changed, 124 insertions(+), 15 deletions(-) diff --git a/internal/provider/hypercore_vm_resource.go b/internal/provider/hypercore_vm_resource.go index 451f2c8..64a8811 100644 --- a/internal/provider/hypercore_vm_resource.go +++ b/internal/provider/hypercore_vm_resource.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" @@ -33,13 +34,14 @@ type HypercoreVMResource struct { // HypercoreVMResourceModel describes the resource data model. type HypercoreVMResourceModel struct { - Group types.String `tfsdk:"group"` - Name types.String `tfsdk:"name"` - Description types.String `tfsdk:"description"` - VCPU types.Int32 `tfsdk:"vcpu"` - Memory types.Int64 `tfsdk:"memory"` - Clone CloneModel `tfsdk:"clone"` - Id types.String `tfsdk:"id"` + Group types.String `tfsdk:"group"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + VCPU types.Int32 `tfsdk:"vcpu"` + Memory types.Int64 `tfsdk:"memory"` + Clone CloneModel `tfsdk:"clone"` + AffinityStrategy AffinityStrategyModel `tfsdk:"affinity_strategy"` + Id types.String `tfsdk:"id"` } type CloneModel struct { @@ -48,6 +50,12 @@ type CloneModel struct { MetaData types.String `tfsdk:"meta_data"` } +type AffinityStrategyModel struct { + StrictAffinity types.Bool `tfsdk:"strict_affinity"` + PreferredNodeUUID types.String `tfsdk:"preferred_node_uuid"` + BackupNodeUUID types.String `tfsdk:"backup_node_uuid"` +} + func (r *HypercoreVMResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_vm" } @@ -93,6 +101,30 @@ func (r *HypercoreVMResource) Schema(ctx context.Context, req resource.SchemaReq "meta_data": types.StringType, }, }, + "affinity_strategy": schema.ObjectAttribute{ + MarkdownDescription: "VM node affinity.", + Optional: true, + AttributeTypes: map[string]attr.Type{ + "strict_affinity": types.BoolType, + "preferred_node_uuid": types.StringType, + "backup_node_uuid": types.StringType, + }, + Computed: true, + Default: objectdefault.StaticValue( + types.ObjectValueMust( + map[string]attr.Type{ + "strict_affinity": types.BoolType, + "preferred_node_uuid": types.StringType, + "backup_node_uuid": types.StringType, + }, + map[string]attr.Value{ + "strict_affinity": types.BoolValue(false), + "preferred_node_uuid": types.StringValue(""), + "backup_node_uuid": types.StringValue(""), + }, + ), + ), + }, "id": schema.StringAttribute{ Computed: true, MarkdownDescription: "HypercoreVM identifier", @@ -176,6 +208,9 @@ func (r *HypercoreVMResource) Create(ctx context.Context, req resource.CreateReq data.VCPU.ValueInt32Pointer(), data.Memory.ValueInt64Pointer(), nil, + data.AffinityStrategy.StrictAffinity.ValueBool(), + data.AffinityStrategy.PreferredNodeUUID.ValueString(), + data.AffinityStrategy.BackupNodeUUID.ValueString(), ) changed, msg := vmClone.Create(*r.client, ctx) tflog.Info(ctx, fmt.Sprintf("Changed: %t, Message: %s\n", changed, msg)) @@ -244,6 +279,11 @@ func (r *HypercoreVMResource) Read(ctx context.Context, req resource.ReadRequest data.VCPU = types.Int32Value(int32(utils.AnyToInteger64(hc3_vm["numVCPU"]))) data.Memory = types.Int64Value(utils.AnyToInteger64(hc3_vm["mem"]) / 1024 / 1024) + affinityStrategy := utils.AnyToMap(hc3_vm["affinityStrategy"]) + data.AffinityStrategy.StrictAffinity = types.BoolValue(utils.AnyToBool(affinityStrategy["strictAffinity"])) + data.AffinityStrategy.PreferredNodeUUID = types.StringValue(utils.AnyToString(affinityStrategy["preferredNodeUUID"])) + data.AffinityStrategy.BackupNodeUUID = types.StringValue(utils.AnyToString(affinityStrategy["backupNodeUUID"])) + // ============================================================================== // Save updated data into Terraform state @@ -296,6 +336,20 @@ func (r *HypercoreVMResource) Update(ctx context.Context, req resource.UpdateReq updatePayload["numVCPU"] = data.VCPU.ValueInt32() } + affinityStrategy := map[string]any{} + if data_state.AffinityStrategy.StrictAffinity != data.AffinityStrategy.StrictAffinity { + affinityStrategy["strictAffinity"] = data.AffinityStrategy.StrictAffinity.ValueBool() + } + if data_state.AffinityStrategy.PreferredNodeUUID != data.AffinityStrategy.PreferredNodeUUID { + affinityStrategy["preferredNodeUUID"] = data.AffinityStrategy.PreferredNodeUUID.ValueString() + } + if data_state.AffinityStrategy.BackupNodeUUID != data.AffinityStrategy.BackupNodeUUID { + affinityStrategy["backupNodeUUID"] = data.AffinityStrategy.BackupNodeUUID.ValueString() + } + if len(affinityStrategy) > 0 { + updatePayload["affinityStrategy"] = affinityStrategy + } + taskTag, _ := restClient.UpdateRecord( /**/ fmt.Sprintf("/rest/v1/VirDomain/%s", vm_uuid), updatePayload, diff --git a/internal/utils/helper.go b/internal/utils/helper.go index d938267..84a1a4a 100644 --- a/internal/utils/helper.go +++ b/internal/utils/helper.go @@ -93,6 +93,15 @@ func AnyToString(str any) string { return stringifiedAny } +func AnyToBool(value any) bool { + switch v := value.(type) { + case bool: + return v + } + + panic(fmt.Sprintf("Unexpected variable where an bool was expected: %v (type %T)", value, value)) +} + func AnyToInteger64(integer any) int64 { switch v := integer.(type) { case int: diff --git a/internal/utils/vm.go b/internal/utils/vm.go index a6eefa0..879b6bc 100644 --- a/internal/utils/vm.go +++ b/internal/utils/vm.go @@ -66,6 +66,9 @@ type VM struct { vcpu *int32 memory *int64 powerState *string + strictAffinity bool + preferredNodeUUID string + backupNodeUUID string _wasNiceShutdownTried bool _didNiceShutdownWork bool @@ -85,6 +88,9 @@ func NewVM( _vcpu *int32, _memory *int64, _powerState *string, + _strictAffinity bool, + _preferredNodeUUID string, + _backupNodeUUID string, ) (*VM, error) { userDataB64 := base64.StdEncoding.EncodeToString([]byte(userData)) metaDataB64 := base64.StdEncoding.EncodeToString([]byte(metaData)) @@ -98,11 +104,14 @@ func NewVM( "userData": userDataB64, "metaData": metaDataB64, }, - description: _description, - tags: _tags, - vcpu: _vcpu, - memory: _memory, - powerState: _powerState, + description: _description, + tags: _tags, + vcpu: _vcpu, + memory: _memory, + powerState: _powerState, + strictAffinity: _strictAffinity, + preferredNodeUUID: _preferredNodeUUID, + backupNodeUUID: _backupNodeUUID, // helpers _wasNiceShutdownTried: false, @@ -165,7 +174,7 @@ func (vc *VM) Create(restClient RestClient, ctx context.Context) (bool, string) func (vc *VM) SetVMParams(restClient RestClient, ctx context.Context) (bool, bool, map[string]any) { vm := GetVMByName(vc.VMName, restClient, true) - changed, changedParams := vc.GetChangedParams(*vm) + changed, changedParams := vc.GetChangedParams(ctx, *vm) if changed { updatePayload := vc.BuildUpdatePayload(changedParams) @@ -404,10 +413,24 @@ func (vc *VM) BuildUpdatePayload(changedParams map[string]bool) map[string]any { updatePayload["numVCPU"] = *vc.vcpu } + affinityStrategy := map[string]any{} + if changed, ok := changedParams["strictAffinity"]; ok && changed { + affinityStrategy["strictAffinity"] = vc.strictAffinity + } + if changed, ok := changedParams["preferredNodeUUID"]; ok && changed { + affinityStrategy["preferredNodeUUID"] = vc.preferredNodeUUID + } + if changed, ok := changedParams["backupNodeUUID"]; ok && changed { + affinityStrategy["backupNodeUUID"] = vc.backupNodeUUID + } + if len(affinityStrategy) > 0 { + updatePayload["affinityStrategy"] = affinityStrategy + } + return updatePayload } -func (vc *VM) GetChangedParams(vmFromClient map[string]any) (bool, map[string]bool) { +func (vc *VM) GetChangedParams(ctx context.Context, vmFromClient map[string]any) (bool, map[string]bool) { changedParams := map[string]bool{} if vc.description != nil { @@ -433,6 +456,11 @@ func (vc *VM) GetChangedParams(vmFromClient map[string]any) (bool, map[string]bo } } + hc3AffinityStrategy := AnyToMap(vmFromClient["affinityStrategy"]) + changedParams["strictAffinity"] = vc.strictAffinity != hc3AffinityStrategy["strictAffinity"] + changedParams["preferredNodeUUID"] = vc.preferredNodeUUID != hc3AffinityStrategy["preferredNodeUUID"] + changedParams["backupNodeUUID"] = vc.backupNodeUUID != hc3AffinityStrategy["backupNodeUUID"] + for _, changed := range changedParams { if changed { return true, changedParams diff --git a/local/main.tf b/local/main.tf index 0defa99..5082ec4 100644 --- a/local/main.tf +++ b/local/main.tf @@ -12,7 +12,7 @@ terraform { provider "hypercore" {} locals { - vm_name = "testtf-disk-ana" + vm_name = "testtf-disk-justin" empty_vm = "testtf-ana" clone_empty_vm = "testtf-clone-ana" @@ -20,6 +20,20 @@ locals { vm_user_data_tmpl = "./assets/user-data.ubuntu-22.04.yml.tftpl" } +resource "hypercore_vm" "myvm" { + name = local.vm_name + clone = { + source_vm_uuid = "" + meta_data = "" + user_data = "" + } + affinity_strategy = { + strict_affinity = true + preferred_node_uuid = data.hypercore_node.cluster0_peer1.nodes.0.uuid + backup_node_uuid = data.hypercore_node.cluster0_peer1.nodes.0.uuid + } +} + data "hypercore_node" "cluster0_all" { } @@ -27,6 +41,10 @@ data "hypercore_node" "cluster0_peer1" { peer_id = 1 } +output "myvm" { + value = hypercore_vm.myvm +} + output "cluster_0_peer_1_uuid" { value = data.hypercore_node.cluster0_peer1.nodes.0.uuid } From c99675789b0453f20b35aaf0ab0aae43ea2bf3d6 Mon Sep 17 00:00:00 2001 From: Justin Cinkelj Date: Wed, 26 Mar 2025 15:20:22 +0100 Subject: [PATCH 3/4] Add affinity_strategy to VM data source Signed-off-by: Justin Cinkelj --- internal/provider/hypercore_vm_data_source.go | 35 ++++++++++++++----- local/main.tf | 7 ++++ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/internal/provider/hypercore_vm_data_source.go b/internal/provider/hypercore_vm_data_source.go index 563ea1d..de790cf 100644 --- a/internal/provider/hypercore_vm_data_source.go +++ b/internal/provider/hypercore_vm_data_source.go @@ -11,6 +11,7 @@ import ( "fmt" "strings" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" @@ -51,6 +52,7 @@ type hypercoreVMModel struct { Tags []types.String `tfsdk:"tags"` Disks []HypercoreDiskModel `tfsdk:"disks"` // TODO nics + AffinityStrategy AffinityStrategyModel `tfsdk:"affinity_strategy"` } type HypercoreDiskModel struct { @@ -100,6 +102,15 @@ func (d *hypercoreVMDataSource) Schema(_ context.Context, _ datasource.SchemaReq ElementType: types.StringType, Optional: true, }, + "affinity_strategy": schema.ObjectAttribute{ + MarkdownDescription: "VM node affinity.", + Computed: true, + AttributeTypes: map[string]attr.Type{ + "strict_affinity": types.BoolType, + "preferred_node_uuid": types.StringType, + "backup_node_uuid": types.StringType, + }, + }, "disks": schema.ListNestedAttribute{ MarkdownDescription: "List of disks", @@ -204,18 +215,26 @@ func (d *hypercoreVMDataSource) Read(ctx context.Context, req datasource.ReadReq } disks = append(disks, disk) } + + hc3affinityStrategy := utils.AnyToMap(vm["affinityStrategy"]) + var affinityStrategy AffinityStrategyModel + affinityStrategy.StrictAffinity = types.BoolValue(utils.AnyToBool(hc3affinityStrategy["strictAffinity"])) + affinityStrategy.PreferredNodeUUID = types.StringValue(utils.AnyToString(hc3affinityStrategy["preferredNodeUUID"])) + affinityStrategy.BackupNodeUUID = types.StringValue(utils.AnyToString(hc3affinityStrategy["backupNodeUUID"])) + // VM memory_B := utils.AnyToInteger64(vm["mem"]) memory_MiB := memory_B / 1024 / 1024 hypercoreVMState := hypercoreVMModel{ - UUID: types.StringValue(utils.AnyToString(vm["uuid"])), - Name: types.StringValue(utils.AnyToString(vm["name"])), - VCPU: types.Int32Value(int32(utils.AnyToInteger64(vm["numVCPU"]))), - Memory: types.Int64Value(memory_MiB), - Description: types.StringValue(utils.AnyToString(vm["description"])), - PowerState: types.StringValue(utils.AnyToString(vm["state"])), // TODO convert (stopped vs SHUTOFF) - Tags: tags_String, - Disks: disks, + UUID: types.StringValue(utils.AnyToString(vm["uuid"])), + Name: types.StringValue(utils.AnyToString(vm["name"])), + VCPU: types.Int32Value(int32(utils.AnyToInteger64(vm["numVCPU"]))), + Memory: types.Int64Value(memory_MiB), + Description: types.StringValue(utils.AnyToString(vm["description"])), + PowerState: types.StringValue(utils.AnyToString(vm["state"])), // TODO convert (stopped vs SHUTOFF) + Tags: tags_String, + AffinityStrategy: affinityStrategy, + Disks: disks, } state.Vms = append(state.Vms, hypercoreVMState) } diff --git a/local/main.tf b/local/main.tf index 5082ec4..e1af49c 100644 --- a/local/main.tf +++ b/local/main.tf @@ -48,3 +48,10 @@ output "myvm" { output "cluster_0_peer_1_uuid" { value = data.hypercore_node.cluster0_peer1.nodes.0.uuid } + +data "hypercore_vm" "demo" { + name = "demo-vm" +} +output "vm_demo" { + value = data.hypercore_vm.demo +} From 5edda988463f31097063267b4206d997ced5250f Mon Sep 17 00:00:00 2001 From: Justin Cinkelj Date: Wed, 26 Mar 2025 15:33:12 +0100 Subject: [PATCH 4/4] Add docs related to affinity_strategy Signed-off-by: Justin Cinkelj --- docs/data-sources/node.md | 56 +++++++++++++++++++++++++++++++++++++++ docs/data-sources/vm.md | 11 ++++++++ docs/resources/vm.md | 11 ++++++++ 3 files changed, 78 insertions(+) create mode 100644 docs/data-sources/node.md diff --git a/docs/data-sources/node.md b/docs/data-sources/node.md new file mode 100644 index 0000000..60f7117 --- /dev/null +++ b/docs/data-sources/node.md @@ -0,0 +1,56 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "hypercore_node Data Source - hypercore" +subcategory: "" +description: |- + +--- + +# hypercore_node (Data Source) + + + +## Example Usage + +```terraform +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +# Get all nodes +data "hypercore_node" "all_nodes" { +} + +output "hypercore_nodes" { + value = data.hypercore_node.all_nodes.nodes +} + +# Get a specific node +data "hypercore_node" "node_1" { + peer_id = 1 +} + +output "hypercore_node_1_uuid" { + value = data.hypercore_node.node_1.nodes.0.uuid +} +``` + + +## Schema + +### Optional + +- `peer_id` (Number) + +### Read-Only + +- `nodes` (Attributes List) (see [below for nested schema](#nestedatt--nodes)) + + +### Nested Schema for `nodes` + +Read-Only: + +- `backplane_ip` (String) +- `lan_ip` (String) +- `peer_id` (Number) +- `uuid` (String) diff --git a/docs/data-sources/vm.md b/docs/data-sources/vm.md index b918e78..c535128 100644 --- a/docs/data-sources/vm.md +++ b/docs/data-sources/vm.md @@ -47,12 +47,23 @@ Optional: Read-Only: +- `affinity_strategy` (Object) VM node affinity. (see [below for nested schema](#nestedatt--vms--affinity_strategy)) - `description` (String) - `disks` (Attributes List) List of disks (see [below for nested schema](#nestedatt--vms--disks)) - `name` (String) - `power_state` (String) - `uuid` (String) + +### Nested Schema for `vms.affinity_strategy` + +Read-Only: + +- `backup_node_uuid` (String) +- `preferred_node_uuid` (String) +- `strict_affinity` (Boolean) + + ### Nested Schema for `vms.disks` diff --git a/docs/resources/vm.md b/docs/resources/vm.md index fe72f60..8f62f3e 100644 --- a/docs/resources/vm.md +++ b/docs/resources/vm.md @@ -58,6 +58,7 @@ output "vm_uuid" { ### Optional +- `affinity_strategy` (Object) VM node affinity. (see [below for nested schema](#nestedatt--affinity_strategy)) - `clone` (Object) Clone options if the VM is being created as a clone. The `source_vm_uuid` is the UUID of the VM used for cloning,
`user_data` and `meta_data` are used for the cloud init data. (see [below for nested schema](#nestedatt--clone)) - `description` (String) Description of this VM - `group` (String) Group/tag to create this VM in @@ -68,6 +69,16 @@ output "vm_uuid" { - `id` (String) HypercoreVM identifier + +### Nested Schema for `affinity_strategy` + +Optional: + +- `backup_node_uuid` (String) +- `preferred_node_uuid` (String) +- `strict_affinity` (Boolean) + + ### Nested Schema for `clone`