Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
13 changes: 13 additions & 0 deletions docs/data-sources/vms.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -74,3 +75,15 @@ Read-Only:
- `slot` (Number) slot
- `type` (String) type
- `uuid` (String) UUID


<a id="nestedatt--vms--nics"></a>
### Nested Schema for `vms.nics`

Read-Only:

- `ipv4_addresses` (List of String) IPv4 addresses
- `mac_address` (String) MAC address
- `type` (String) type
- `uuid` (String) UUID
- `vlan` (Number) vlan
93 changes: 80 additions & 13 deletions internal/provider/hypercore_vms_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -43,17 +44,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 {
Expand All @@ -63,6 +64,14 @@ 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"`
Ipv4Adresses []types.String `tfsdk:"ipv4_addresses"`
}

// Metadata returns the data source type name.
func (d *hypercoreVMsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_vms"
Expand Down Expand Up @@ -141,6 +150,35 @@ 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,
},
"ipv4_addresses": schema.ListAttribute{
ElementType: types.StringType,
MarkdownDescription: "IPv4 addresses",
Computed: true,
},
},
},
},
},
},
},
Expand Down Expand Up @@ -227,13 +265,41 @@ 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"])
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),
Ipv4Adresses: ipv4_addresses_string_value,
}
nics = append(nics, nic)
}
hc3affinityStrategy := utils.AnyToMap(vm["affinityStrategy"])
var affinityStrategy AffinityStrategyModel
affinityStrategy.StrictAffinity = types.BoolValue(utils.AnyToBool(hc3affinityStrategy["strictAffinity"]))
Expand All @@ -254,6 +320,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)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// 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"),

// 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"),
// 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.TestCheckResourceAttr("data.hypercore_vms.test", "vms.0.nics.0.ipv4_addresses.#", "0"),
),
},
},
})
}

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"
}
`)
}
*/
Loading