From 7a5459a01653503cbc6606c6d37ef389103587d2 Mon Sep 17 00:00:00 2001 From: Justin Cinkelj Date: Mon, 19 May 2025 10:07:51 +0200 Subject: [PATCH 1/2] fix vm affinity partially fixes #45 we still need to "terraform apply" twice Signed-off-by: Justin Cinkelj --- internal/provider/hypercore_vm_resource.go | 89 ++++++++++++++-------- local/main.tf | 42 +++++----- 2 files changed, 80 insertions(+), 51 deletions(-) diff --git a/internal/provider/hypercore_vm_resource.go b/internal/provider/hypercore_vm_resource.go index d30392c..6752229 100644 --- a/internal/provider/hypercore_vm_resource.go +++ b/internal/provider/hypercore_vm_resource.go @@ -17,7 +17,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" @@ -41,16 +41,16 @@ type HypercoreVMResource struct { // HypercoreVMResourceModel describes the resource data model. type HypercoreVMResourceModel struct { - Tags types.List `tfsdk:"tags"` - Name types.String `tfsdk:"name"` - Description types.String `tfsdk:"description"` - VCPU types.Int32 `tfsdk:"vcpu"` - Memory types.Int64 `tfsdk:"memory"` - Import *ImportModel `tfsdk:"import"` - SnapshotScheduleUUID types.String `tfsdk:"snapshot_schedule_uuid"` - Clone *CloneModel `tfsdk:"clone"` - AffinityStrategy AffinityStrategyModel `tfsdk:"affinity_strategy"` - Id types.String `tfsdk:"id"` + Tags types.List `tfsdk:"tags"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + VCPU types.Int32 `tfsdk:"vcpu"` + Memory types.Int64 `tfsdk:"memory"` + Import *ImportModel `tfsdk:"import"` + SnapshotScheduleUUID types.String `tfsdk:"snapshot_schedule_uuid"` + Clone *CloneModel `tfsdk:"clone"` + AffinityStrategy *AffinityStrategyModel `tfsdk:"affinity_strategy"` + Id types.String `tfsdk:"id"` } type ImportModel struct { @@ -173,29 +173,35 @@ The provider will currently try to shutdown VM only before VM delete.`, }, }, }, - "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, - }, + "affinity_strategy": schema.SingleNestedAttribute{ + Optional: true, 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, + Attributes: map[string]schema.Attribute{ + "strict_affinity": schema.BoolAttribute{ + Optional: true, + Computed: true, + //Default: booldefault.StaticBool(false), + PlanModifiers: []planmodifier.Bool{ + boolplanmodifier.UseStateForUnknown(), }, - map[string]attr.Value{ - "strict_affinity": types.BoolValue(false), - "preferred_node_uuid": types.StringValue(""), - "backup_node_uuid": types.StringValue(""), + }, + "preferred_node_uuid": schema.StringAttribute{ + Optional: true, + Computed: true, + // Default: stringdefault.StaticString(""), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "backup_node_uuid": schema.StringAttribute{ + Optional: true, + Computed: true, + // Default: stringdefault.StaticString(""), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - ), - ), + }, + }, }, "id": schema.StringAttribute{ Computed: true, @@ -357,13 +363,30 @@ func (r *HypercoreVMResource) Create(ctx context.Context, req resource.CreateReq // Read Terraform plan data into the model resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + // tflog.Info(ctx, fmt.Sprintf("TTRT a ----------------------- : %v", data.AffinityStrategy)) + if data.AffinityStrategy == nil { + data.AffinityStrategy = &AffinityStrategyModel{ + StrictAffinity: types.BoolValue(false), + PreferredNodeUUID: types.StringValue(""), + BackupNodeUUID: types.StringValue(""), + } + } + if data.AffinityStrategy.StrictAffinity.IsUnknown() { + data.AffinityStrategy.StrictAffinity = types.BoolValue(false) + } + if data.AffinityStrategy.PreferredNodeUUID.IsUnknown() { + data.AffinityStrategy.PreferredNodeUUID = types.StringValue("") + } + if data.AffinityStrategy.BackupNodeUUID.IsUnknown() { + data.AffinityStrategy.BackupNodeUUID = types.StringValue("") + } + // tflog.Info(ctx, fmt.Sprintf("TTRT b ----------------------- : %v", data.AffinityStrategy)) if r.client == nil { resp.Diagnostics.AddError( "Unconfigured HTTP Client", "Expected configured HTTP client. Please report this issue to the provider developers.", ) - return } @@ -457,6 +480,7 @@ func (r *HypercoreVMResource) Read(ctx context.Context, req resource.ReadRequest data.SnapshotScheduleUUID = types.StringValue(utils.AnyToString(hc3_vm["snapshotScheduleUUID"])) affinityStrategy := utils.AnyToMap(hc3_vm["affinityStrategy"]) + data.AffinityStrategy = &AffinityStrategyModel{} 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"])) @@ -477,7 +501,6 @@ func (r *HypercoreVMResource) Update(ctx context.Context, req resource.UpdateReq // Read Terraform plan data into the model resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - if resp.Diagnostics.HasError() { return } diff --git a/local/main.tf b/local/main.tf index b9b6dd6..b60e215 100644 --- a/local/main.tf +++ b/local/main.tf @@ -10,30 +10,36 @@ terraform { } locals { - vm_name = "testtf-justin-nic-mac" + src_vm_name = "testtf-src-empty" + vm_name = "testtf-justin-affinity" } provider "hypercore" {} -data "hypercore_vms" "myvm" { - name = local.vm_name -} - -resource "hypercore_nic" "nic_newly_created" { - vm_uuid = data.hypercore_vms.myvm.vms.0.uuid - type = "INTEL_E1000" - vlan = 11 +data "hypercore_vms" "srcvm" { + name = local.src_vm_name } -resource "hypercore_nic" "nic_imported" { - vm_uuid = data.hypercore_vms.myvm.vms.0.uuid - type = "VIRTIO" - vlan = 0 - - depends_on = [hypercore_nic.nic_newly_created] +resource "hypercore_vm" "myvm" { + name = local.vm_name + clone = { + source_vm_uuid = data.hypercore_vms.srcvm.vms.0.uuid + user_data = "" + meta_data = "" + } + # TODO - are computed, on HC3 side + memory = 1024 + tags = [""] + vcpu = 1 + description = "" + affinity_strategy = { + # strict_affinity = true + # preferred_node_uuid = "d676b39c-595f-4c3b-a8df-a18f308243c0" + } } -import { - to = hypercore_nic.nic_imported - id = format("%s:%s:%d", data.hypercore_vms.myvm.vms.0.uuid, "VIRTIO", 0) +resource "hypercore_vm_power_state" "myvm" { + vm_uuid = hypercore_vm.myvm.id + # state = "SHUTOFF" # available states are: SHUTOFF, RUNNING, PAUSED + state = "RUNNING" # available states are: SHUTOFF, RUNNING, PAUSED } From 09fe685b0d5f526afa1376a6dfb71fc19bb0035b Mon Sep 17 00:00:00 2001 From: Justin Cinkelj Date: Wed, 21 May 2025 17:58:53 +0200 Subject: [PATCH 2/2] Update tests, docs Signed-off-by: Justin Cinkelj --- demo/sc_demo_vm.tf | 2 +- docs/resources/vm.md | 13 ++++++++----- examples/resources/hypercore_vm/resource.tf | 11 +++++++---- ...core_vm_resource__snapshot_schedule__acc_test.go | 1 + .../hypercore_vm_resource_clone_acc_test.go | 1 + .../hypercore_vm_resource_import_acc_test.go | 1 + 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/demo/sc_demo_vm.tf b/demo/sc_demo_vm.tf index 974108a..ca41f75 100644 --- a/demo/sc_demo_vm.tf +++ b/demo/sc_demo_vm.tf @@ -4,7 +4,7 @@ # After we have virtual disk, we use it to create new VM from it # First create VM without any disk. resource "hypercore_vm" "demo_vm" { - group = "testtf" + tags = ["testtf"] name = local.vm_name description = "Demo Ana's cloned VM" vcpu = 4 diff --git a/docs/resources/vm.md b/docs/resources/vm.md index 6999ad8..9e1da70 100644 --- a/docs/resources/vm.md +++ b/docs/resources/vm.md @@ -40,8 +40,9 @@ resource "hypercore_vm" "empty-vm" { name = "empty-vm" description = "some description" - vcpu = 4 - memory = 4096 # MiB + vcpu = 4 + memory = 4096 # MiB + affinity_strategy = {} } data "hypercore_vms" "clone_source_vm" { @@ -55,6 +56,7 @@ resource "hypercore_vm" "myvm" { vcpu = 4 memory = 4096 # MiB + affinity_strategy = {} snapshot_schedule_uuid = data.hypercore_vms.clone_source_vm.vms.0.snapshot_schedule_uuid clone = { @@ -76,8 +78,9 @@ resource "hypercore_vm" "import-from-smb" { name = "imported-vm" description = "some description" - vcpu = 4 - memory = 4096 # MiB + vcpu = 4 + memory = 4096 # MiB + affinity_strategy = {} import = { server = "10.5.11.39" @@ -102,7 +105,7 @@ output "vm_uuid" { ### Optional -- `affinity_strategy` (Object) VM node affinity. (see [below for nested schema](#nestedatt--affinity_strategy)) +- `affinity_strategy` (Attributes) (see [below for nested schema](#nestedatt--affinity_strategy)) - `clone` (Attributes) 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 - `import` (Attributes) Options for importing a VM through a SMB server or some other HTTP location.
Use server, username, password for SMB or http_uri for some other HTTP location. Parameters path and file_name are always **required** (see [below for nested schema](#nestedatt--import)) diff --git a/examples/resources/hypercore_vm/resource.tf b/examples/resources/hypercore_vm/resource.tf index aded50a..33701d2 100644 --- a/examples/resources/hypercore_vm/resource.tf +++ b/examples/resources/hypercore_vm/resource.tf @@ -9,8 +9,9 @@ resource "hypercore_vm" "empty-vm" { name = "empty-vm" description = "some description" - vcpu = 4 - memory = 4096 # MiB + vcpu = 4 + memory = 4096 # MiB + affinity_strategy = {} } data "hypercore_vms" "clone_source_vm" { @@ -24,6 +25,7 @@ resource "hypercore_vm" "myvm" { vcpu = 4 memory = 4096 # MiB + affinity_strategy = {} snapshot_schedule_uuid = data.hypercore_vms.clone_source_vm.vms.0.snapshot_schedule_uuid clone = { @@ -45,8 +47,9 @@ resource "hypercore_vm" "import-from-smb" { name = "imported-vm" description = "some description" - vcpu = 4 - memory = 4096 # MiB + vcpu = 4 + memory = 4096 # MiB + affinity_strategy = {} import = { server = "10.5.11.39" diff --git a/internal/provider/tests/acceptance/hypercore_vm_resource__snapshot_schedule__acc_test.go b/internal/provider/tests/acceptance/hypercore_vm_resource__snapshot_schedule__acc_test.go index 626ce6a..52fd680 100644 --- a/internal/provider/tests/acceptance/hypercore_vm_resource__snapshot_schedule__acc_test.go +++ b/internal/provider/tests/acceptance/hypercore_vm_resource__snapshot_schedule__acc_test.go @@ -99,6 +99,7 @@ resource "hypercore_vm" "test" { memory = 4096 description = "testtf-vm-description" // snapshot_schedule_uuid = "" + affinity_strategy = {} } `, vm_name) } diff --git a/internal/provider/tests/acceptance/hypercore_vm_resource_clone_acc_test.go b/internal/provider/tests/acceptance/hypercore_vm_resource_clone_acc_test.go index 71013fc..14dc1a2 100644 --- a/internal/provider/tests/acceptance/hypercore_vm_resource_clone_acc_test.go +++ b/internal/provider/tests/acceptance/hypercore_vm_resource_clone_acc_test.go @@ -96,6 +96,7 @@ resource "hypercore_vm" "test" { meta_data = "" preserve_mac_address = false } + affinity_strategy = {} } `, vm_name, source_vm_uuid, requested_power_state) } diff --git a/internal/provider/tests/acceptance/hypercore_vm_resource_import_acc_test.go b/internal/provider/tests/acceptance/hypercore_vm_resource_import_acc_test.go index 01613ab..b9deb51 100644 --- a/internal/provider/tests/acceptance/hypercore_vm_resource_import_acc_test.go +++ b/internal/provider/tests/acceptance/hypercore_vm_resource_import_acc_test.go @@ -48,6 +48,7 @@ resource "hypercore_vm" "test" { path = %[5]q file_name = %[6]q } + affinity_strategy = {} } `, vm_name, smb_server, smb_username, smb_password, smb_path, smb_filename, requested_power_state) }