From d06d615db70eb5e219bcab0ca613806ebc152c33 Mon Sep 17 00:00:00 2001 From: Justin Cinkelj Date: Tue, 15 Jul 2025 14:08:40 +0200 Subject: [PATCH 1/4] Cleanup spaces Signed-off-by: Justin Cinkelj --- DEVELOPMENT.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index fd18fef..f4c32c9 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -28,15 +28,15 @@ Add needed variables/secrets to github project: ``` Prior to running acceptance tests we need to setup: - - Virtual machine - - name integration-test-vm - - has two disks - - type VIRTIO (1.2GB, 2.4GB) - - has two nics - - first of type INTEL_E1000, vlan 10, MAC 7C:4C:58:12:34:56 - - second of type VIRTIO, vlan ALL - - boot order is configured as [disk, nic] - - Virtual disk (as standalone not attached to the testing VM) - - Add names and UUIDs to the env.txt file in /tests/acceptance/setup directory - - There are multiple env-*.txt files, for different test HyperCore clusters. + - Virtual machine + - name integration-test-vm + - has two disks + - type VIRTIO (1.2GB, 2.4GB) + - has two nics + - first of type INTEL_E1000, vlan 10, MAC 7C:4C:58:12:34:56 + - second of type VIRTIO, vlan ALL + - boot order is configured as [disk, nic] + - Virtual disk (as standalone not attached to the testing VM) + - Add names and UUIDs to the env.txt file in /tests/acceptance/setup directory + - There are multiple env-*.txt files, for different test HyperCore clusters. - Virtual machine needs to be powered off From f9529d9963a294f23744427a3119bf85f66de1c8 Mon Sep 17 00:00:00 2001 From: Justin Cinkelj Date: Tue, 15 Jul 2025 14:10:59 +0200 Subject: [PATCH 2/4] Test hypercore_vms datasource Signed-off-by: Justin Cinkelj --- .../hypercore_vms_data_source_acc_test.go | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 internal/provider/tests/acceptance/hypercore_vms_data_source_acc_test.go diff --git a/internal/provider/tests/acceptance/hypercore_vms_data_source_acc_test.go b/internal/provider/tests/acceptance/hypercore_vms_data_source_acc_test.go new file mode 100644 index 0000000..da3a333 --- /dev/null +++ b/internal/provider/tests/acceptance/hypercore_vms_data_source_acc_test.go @@ -0,0 +1,151 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package acceptance + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +/* +func testCheckListIsPresentEvenIfEmpty(resourceName string, attrName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("resource not found: %s", resourceName) + } + // val, ok := rs.Primary.Attributes[attrName+".#"] + _, ok = rs.Primary.Attributes[attrName+".#"] + if !ok { + return fmt.Errorf("attribute %s is not set", attrName) + } + // val is a string representing the number of elements + // if val != "0" { + // return fmt.Errorf("expected %s to be empty, got length: %s", attrName, val) + // } + return nil + } +} +*/ + +func TestAccHypercoreVMsDatasource_stopped(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create and Read testing + { + Config: testConfig_stopped("integration-test-vm"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.name", "integration-test-vm"), + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.memory", "4096"), + // resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.vcpu", "1"), + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.power_state", "SHUTOFF"), + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.disks.#", "2"), + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.disks.0.type", "VIRTIO_DISK"), + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.disks.0.slot", "0"), + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.disks.0.size", "1.2"), + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.disks.1.type", "VIRTIO_DISK"), + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.disks.1.slot", "1"), + // resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.disks.1.size", "2.4"), + ), + }, + }, + }) +} + +func testConfig_stopped(vm_name string) string { + return fmt.Sprintf(` +data "hypercore_vms" "test" { + name = %[1]q +} +`, vm_name) +} + +/* +TODO - test VM IP is actually returned. +To test this, we need a bootable ISO, with qemu-geust-agent. +Or similar qcow2 image. +func x_TestAccHypercoreVMsDatasource_running(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create and Read testing + { + Config: testConfig_running_step1(), + }, + { + Config: testConfig_running_step2(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.name", "testtf-datasource-vms-running"), + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.memory", "4096"), + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.vcpu", "4"), + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.power_state", "RUNNING"), + ), + }, + }, + }) +} + +func testConfig_running_step1() string { + return fmt.Sprintf(` +# bootable ISO, it needs to get IP from DHCP, and needs to contain qemu guest agent. +resource "hypercore_iso" "liveiso" { + name = "Porteus-XFCE-v5.0-x86_64.iso" + source_url = "https://mirrors.dotsrc.org/porteus/x86_64/Porteus-v5.0/Porteus-XFCE-v5.0-x86_64.iso" +} + +resource "hypercore_vm" "test" { + tags = ["testtf", "vms-datasource-running"] + name = "testtf-vms-datasource-running" + description = "testtf-vms-datasource-running description" + + vcpu = 4 + memory = 4096 # MiB + affinity_strategy = {} +} + +resource "hypercore_disk" "liveiso" { + vm_uuid = hypercore_vm.test.id + type = "IDE_CDROM" + iso_uuid = hypercore_iso.liveiso.id + size = 0.364904448 +} +`) +} + +func testConfig_running_step2() string { + return fmt.Sprintf(` +# bootable ISO, it needs to get IP from DHCP, and needs to contain qemu guest agent. +resource "hypercore_iso" "liveiso" { + name = "Porteus-XFCE-v5.0-x86_64.iso" + source_url = "https://mirrors.dotsrc.org/porteus/x86_64/Porteus-v5.0/Porteus-XFCE-v5.0-x86_64.iso" +} + +resource "hypercore_vm" "test" { + tags = ["testtf", "vms-datasource-running"] + name = "testtf-vms-datasource-running" + description = "testtf-vms-datasource-running description" + + vcpu = 4 + memory = 4096 # MiB + affinity_strategy = {} +} + +resource "hypercore_disk" "liveiso" { + vm_uuid = hypercore_vm.test.id + type = "IDE_CDROM" + iso_uuid = hypercore_iso.liveiso.id + size = 0.364904448 +} + +data "hypercore_vms" "test" { + name = "testtf-vms-datasource-running" +} +`) +} +*/ From 282387334a85f10be1138776c05daf97039fedda Mon Sep 17 00:00:00 2001 From: Justin Cinkelj Date: Tue, 15 Jul 2025 14:35:48 +0200 Subject: [PATCH 3/4] Add nics to hypercore_vms datasource Signed-off-by: Justin Cinkelj --- docs/data-sources/vms.md | 12 +++ .../provider/hypercore_vms_data_source.go | 80 ++++++++++++++++--- .../hypercore_vms_data_source_acc_test.go | 14 ++++ 3 files changed, 93 insertions(+), 13 deletions(-) diff --git a/docs/data-sources/vms.md b/docs/data-sources/vms.md index 1d817ae..97a0b7e 100644 --- a/docs/data-sources/vms.md +++ b/docs/data-sources/vms.md @@ -51,6 +51,7 @@ Read-Only: - `description` (String) - `disks` (Attributes List) List of disks (see [below for nested schema](#nestedatt--vms--disks)) - `name` (String) +- `nics` (Attributes List) List of NICs (see [below for nested schema](#nestedatt--vms--nics)) - `power_state` (String) - `snapshot_schedule_uuid` (String) UUID of the applied snapshot schedule for creating automated snapshots - `uuid` (String) @@ -74,3 +75,14 @@ Read-Only: - `slot` (Number) slot - `type` (String) type - `uuid` (String) UUID + + + +### Nested Schema for `vms.nics` + +Read-Only: + +- `mac_address` (String) MAC address +- `type` (String) type +- `uuid` (String) UUID +- `vlan` (Number) vlan diff --git a/internal/provider/hypercore_vms_data_source.go b/internal/provider/hypercore_vms_data_source.go index 43f1ef8..8be596f 100644 --- a/internal/provider/hypercore_vms_data_source.go +++ b/internal/provider/hypercore_vms_data_source.go @@ -43,17 +43,17 @@ type hypercoreVMsDataSourceModel struct { // hypercoreVMModel maps VM schema data. type hypercoreVMModel struct { - UUID types.String `tfsdk:"uuid"` - Name types.String `tfsdk:"name"` - Description types.String `tfsdk:"description"` - PowerState types.String `tfsdk:"power_state"` - VCPU types.Int32 `tfsdk:"vcpu"` - Memory types.Int64 `tfsdk:"memory"` - SnapshotScheduleUUID types.String `tfsdk:"snapshot_schedule_uuid"` - Tags []types.String `tfsdk:"tags"` - Disks []HypercoreDiskModel `tfsdk:"disks"` - // TODO nics - AffinityStrategy AffinityStrategyModel `tfsdk:"affinity_strategy"` + UUID types.String `tfsdk:"uuid"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + PowerState types.String `tfsdk:"power_state"` + VCPU types.Int32 `tfsdk:"vcpu"` + Memory types.Int64 `tfsdk:"memory"` + SnapshotScheduleUUID types.String `tfsdk:"snapshot_schedule_uuid"` + Tags []types.String `tfsdk:"tags"` + Disks []HypercoreDiskModel `tfsdk:"disks"` + Nics []HypercoreNicModel `tfsdk:"nics"` + AffinityStrategy AffinityStrategyModel `tfsdk:"affinity_strategy"` } type HypercoreDiskModel struct { @@ -63,6 +63,13 @@ type HypercoreDiskModel struct { Size types.Float64 `tfsdk:"size"` } +type HypercoreNicModel struct { + UUID types.String `tfsdk:"uuid"` + Vlan types.Int64 `tfsdk:"vlan"` + Type types.String `tfsdk:"type"` + MacAddress types.String `tfsdk:"mac_address"` +} + // Metadata returns the data source type name. func (d *hypercoreVMsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_vms" @@ -141,6 +148,30 @@ func (d *hypercoreVMsDataSource) Schema(_ context.Context, _ datasource.SchemaRe }, }, }, + "nics": schema.ListNestedAttribute{ + MarkdownDescription: "List of NICs", + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "uuid": schema.StringAttribute{ + MarkdownDescription: "UUID", + Computed: true, + }, + "type": schema.StringAttribute{ + MarkdownDescription: "type", + Computed: true, + }, + "vlan": schema.Int64Attribute{ + MarkdownDescription: "vlan", + Computed: true, + }, + "mac_address": schema.StringAttribute{ + MarkdownDescription: "MAC address", + Computed: true, + }, + }, + }, + }, }, }, }, @@ -227,13 +258,35 @@ func (d *hypercoreVMsDataSource) Read(ctx context.Context, req datasource.ReadRe size_GB := types.Float64Value(size_B / 1000 / 1000 / 1000) disk := HypercoreDiskModel{ UUID: types.StringValue(uuid), - Type: types.StringValue(disk_type), // TODO convert "VIRTIO_DISK" to "virtio_disk" - or not? + Type: types.StringValue(disk_type), Slot: types.Int64Value(slot), Size: size_GB, } disks = append(disks, disk) } - + // nics + nicDevs, ok := vm["netDevs"].([]interface{}) + if !ok { + panic(fmt.Sprintf("Unexpected netDevs field: %v", vm["netDevs"])) + } + nics := make([]HypercoreNicModel, 0) + for _, nicDev1 := range nicDevs { + nicDev2, ok := nicDev1.(map[string]any) + if !ok { + panic(fmt.Sprintf("Unexpected nicDevs field: %v", vm["nicDevs"])) + } + uuid := utils.AnyToString(nicDev2["uuid"]) + nic_type := utils.AnyToString(nicDev2["type"]) + vlan := utils.AnyToInteger64(nicDev2["vlan"]) + mac := utils.AnyToString(nicDev2["macAddress"]) + nic := HypercoreNicModel{ + UUID: types.StringValue(uuid), + Type: types.StringValue(nic_type), + Vlan: types.Int64Value(vlan), + MacAddress: types.StringValue(mac), + } + nics = append(nics, nic) + } hc3affinityStrategy := utils.AnyToMap(vm["affinityStrategy"]) var affinityStrategy AffinityStrategyModel affinityStrategy.StrictAffinity = types.BoolValue(utils.AnyToBool(hc3affinityStrategy["strictAffinity"])) @@ -254,6 +307,7 @@ func (d *hypercoreVMsDataSource) Read(ctx context.Context, req datasource.ReadRe Tags: tags_String, AffinityStrategy: affinityStrategy, Disks: disks, + Nics: nics, } state.Vms = append(state.Vms, hypercoreVMState) } diff --git a/internal/provider/tests/acceptance/hypercore_vms_data_source_acc_test.go b/internal/provider/tests/acceptance/hypercore_vms_data_source_acc_test.go index da3a333..f14346b 100644 --- a/internal/provider/tests/acceptance/hypercore_vms_data_source_acc_test.go +++ b/internal/provider/tests/acceptance/hypercore_vms_data_source_acc_test.go @@ -51,6 +51,20 @@ func TestAccHypercoreVMsDatasource_stopped(t *testing.T) { resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.disks.1.type", "VIRTIO_DISK"), resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.disks.1.slot", "1"), // resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.disks.1.size", "2.4"), + + // VM on XLAB NUC + // resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.nics.#", "1"), + // resource.TestCheckResourceAttrSet("data.hypercore_vms.test", "vms.0.nics.0.uuid"), + // resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.nics.0.type", "INTEL_E1000"), + // resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.nics.0.vlan", "10"), + // resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.nics.0.mac_address", "7C:4C:58:12:34:56"), + + // VM on CI VSNS https://10.5.11.205/ + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.nics.#", "1"), + resource.TestCheckResourceAttrSet("data.hypercore_vms.test", "vms.0.nics.0.uuid"), + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.nics.0.type", "VIRTIO"), + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.nics.0.vlan", "0"), + resource.TestCheckResourceAttrSet("data.hypercore_vms.test", "vms.0.nics.0.mac_address"), ), }, }, From 87cd91801da4321c863a9f26d34df9a3c6522130 Mon Sep 17 00:00:00 2001 From: Justin Cinkelj Date: Tue, 15 Jul 2025 16:16:54 +0200 Subject: [PATCH 4/4] Add ipv4_addresses to hypercore_vms datasource Fixes #69 Signed-off-by: Justin Cinkelj --- docs/data-sources/vms.md | 1 + .../provider/hypercore_vms_data_source.go | 29 ++++++++++++++----- .../hypercore_vms_data_source_acc_test.go | 3 +- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/docs/data-sources/vms.md b/docs/data-sources/vms.md index 97a0b7e..5aa3d72 100644 --- a/docs/data-sources/vms.md +++ b/docs/data-sources/vms.md @@ -82,6 +82,7 @@ Read-Only: Read-Only: +- `ipv4_addresses` (List of String) IPv4 addresses - `mac_address` (String) MAC address - `type` (String) type - `uuid` (String) UUID diff --git a/internal/provider/hypercore_vms_data_source.go b/internal/provider/hypercore_vms_data_source.go index 8be596f..595b4b6 100644 --- a/internal/provider/hypercore_vms_data_source.go +++ b/internal/provider/hypercore_vms_data_source.go @@ -15,6 +15,7 @@ import ( "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-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-provider-hypercore/internal/utils" ) @@ -64,10 +65,11 @@ type HypercoreDiskModel struct { } type HypercoreNicModel struct { - UUID types.String `tfsdk:"uuid"` - Vlan types.Int64 `tfsdk:"vlan"` - Type types.String `tfsdk:"type"` - MacAddress types.String `tfsdk:"mac_address"` + UUID types.String `tfsdk:"uuid"` + Vlan types.Int64 `tfsdk:"vlan"` + Type types.String `tfsdk:"type"` + MacAddress types.String `tfsdk:"mac_address"` + Ipv4Adresses []types.String `tfsdk:"ipv4_addresses"` } // Metadata returns the data source type name. @@ -169,6 +171,11 @@ func (d *hypercoreVMsDataSource) Schema(_ context.Context, _ datasource.SchemaRe MarkdownDescription: "MAC address", Computed: true, }, + "ipv4_addresses": schema.ListAttribute{ + ElementType: types.StringType, + MarkdownDescription: "IPv4 addresses", + Computed: true, + }, }, }, }, @@ -279,11 +286,17 @@ func (d *hypercoreVMsDataSource) Read(ctx context.Context, req datasource.ReadRe nic_type := utils.AnyToString(nicDev2["type"]) vlan := utils.AnyToInteger64(nicDev2["vlan"]) mac := utils.AnyToString(nicDev2["macAddress"]) + ipv4_addresses := utils.AnyToListOfStrings(nicDev2["ipv4Addresses"]) + ipv4_addresses_string_value := make([]basetypes.StringValue, 0) + for _, addr := range ipv4_addresses { + ipv4_addresses_string_value = append(ipv4_addresses_string_value, types.StringValue(addr)) + } nic := HypercoreNicModel{ - UUID: types.StringValue(uuid), - Type: types.StringValue(nic_type), - Vlan: types.Int64Value(vlan), - MacAddress: types.StringValue(mac), + UUID: types.StringValue(uuid), + Type: types.StringValue(nic_type), + Vlan: types.Int64Value(vlan), + MacAddress: types.StringValue(mac), + Ipv4Adresses: ipv4_addresses_string_value, } nics = append(nics, nic) } diff --git a/internal/provider/tests/acceptance/hypercore_vms_data_source_acc_test.go b/internal/provider/tests/acceptance/hypercore_vms_data_source_acc_test.go index f14346b..c2a27f4 100644 --- a/internal/provider/tests/acceptance/hypercore_vms_data_source_acc_test.go +++ b/internal/provider/tests/acceptance/hypercore_vms_data_source_acc_test.go @@ -58,13 +58,14 @@ func TestAccHypercoreVMsDatasource_stopped(t *testing.T) { // resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.nics.0.type", "INTEL_E1000"), // resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.nics.0.vlan", "10"), // resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.nics.0.mac_address", "7C:4C:58:12:34:56"), + // resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.nics.0.ipv4_addresses.#", "0"), // VM on CI VSNS https://10.5.11.205/ resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.nics.#", "1"), resource.TestCheckResourceAttrSet("data.hypercore_vms.test", "vms.0.nics.0.uuid"), resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.nics.0.type", "VIRTIO"), resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.nics.0.vlan", "0"), - resource.TestCheckResourceAttrSet("data.hypercore_vms.test", "vms.0.nics.0.mac_address"), + resource.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.nics.0.ipv4_addresses.#", "0"), ), }, },