diff --git a/docs/resources/vm.md b/docs/resources/vm.md
index 79f46fa..a5d16d5 100644
--- a/docs/resources/vm.md
+++ b/docs/resources/vm.md
@@ -36,7 +36,7 @@ locals {
}
resource "hypercore_vm" "empty-vm" {
- group = "my-group"
+ tags = ["my-group"]
name = "empty-vm"
description = "some description"
@@ -49,7 +49,7 @@ data "hypercore_vms" "clone_source_vm" {
}
resource "hypercore_vm" "myvm" {
- group = "my-group"
+ tags = ["my-group"]
name = local.vm_name
description = "some description"
@@ -71,7 +71,7 @@ resource "hypercore_vm" "myvm" {
}
resource "hypercore_vm" "import-from-smb" {
- group = "my-group"
+ tags = ["my-group"]
name = "imported-vm"
description = "some description"
@@ -104,10 +104,10 @@ output "vm_uuid" {
- `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
- `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))
- `memory` (Number) Memory (RAM) size in `MiB`: If the cloned VM was already created
and it's memory was modified, the cloned VM will be rebooted (either gracefully or forcefully)
- `snapshot_schedule_uuid` (String) UUID of the snapshot schedule to create automatic snapshots
+- `tags` (List of String) List of tags to create this VM in
- `vcpu` (Number) Number of CPUs on this VM. If the cloned VM was already created and it's
`VCPU` was modified, the cloned VM will be rebooted (either gracefully or forcefully)
### Read-Only
diff --git a/examples/resources/hypercore_vm/resource.tf b/examples/resources/hypercore_vm/resource.tf
index 900b614..cc30b8a 100644
--- a/examples/resources/hypercore_vm/resource.tf
+++ b/examples/resources/hypercore_vm/resource.tf
@@ -5,7 +5,7 @@ locals {
}
resource "hypercore_vm" "empty-vm" {
- group = "my-group"
+ tags = ["my-group"]
name = "empty-vm"
description = "some description"
@@ -18,7 +18,7 @@ data "hypercore_vms" "clone_source_vm" {
}
resource "hypercore_vm" "myvm" {
- group = "my-group"
+ tags = ["my-group"]
name = local.vm_name
description = "some description"
@@ -40,7 +40,7 @@ resource "hypercore_vm" "myvm" {
}
resource "hypercore_vm" "import-from-smb" {
- group = "my-group"
+ tags = ["my-group"]
name = "imported-vm"
description = "some description"
diff --git a/internal/provider/hypercore_vm_resource.go b/internal/provider/hypercore_vm_resource.go
index d82da03..9d391d8 100644
--- a/internal/provider/hypercore_vm_resource.go
+++ b/internal/provider/hypercore_vm_resource.go
@@ -8,6 +8,7 @@ import (
"fmt"
"os"
"strconv"
+ "strings"
"time"
"github.com/hashicorp/terraform-plugin-framework/attr"
@@ -39,7 +40,7 @@ type HypercoreVMResource struct {
// HypercoreVMResourceModel describes the resource data model.
type HypercoreVMResourceModel struct {
- Group types.String `tfsdk:"group"`
+ Tags types.List `tfsdk:"tags"`
Name types.String `tfsdk:"name"`
Description types.String `tfsdk:"description"`
VCPU types.Int32 `tfsdk:"vcpu"`
@@ -91,8 +92,9 @@ HC_VM_SHUTDOWN_TIMEOUT can be changed via environ.
The provider will currently try to shutdown VM only before VM delete.`,
Attributes: map[string]schema.Attribute{
- "group": schema.StringAttribute{
- MarkdownDescription: "Group/tag to create this VM in",
+ "tags": schema.ListAttribute{
+ ElementType: types.StringType,
+ MarkdownDescription: "List of tags to create this VM in",
Optional: true,
},
"name": schema.StringAttribute{
@@ -240,23 +242,20 @@ func getVMStruct(data *HypercoreVMResourceModel, vmDescription *string, vmTags *
return vmStruct
}
-func validateParameters(data *HypercoreVMResourceModel) (*string, *[]string) {
+func validateParameters(data *HypercoreVMResourceModel, ctx context.Context) (*string, *[]string, diag.Diagnostics) {
var tags *[]string
var description *string
- if data.Group.ValueString() == "" {
- tags = nil
- } else {
- t := []string{data.Group.ValueString()}
- tags = &t
- }
+ tflog.Debug(ctx, "TTRT Loading tags")
+ diags := data.Tags.ElementsAs(ctx, &tags, false)
+ tflog.Debug(ctx, fmt.Sprintf("TTRT Tags: %v", tags))
if data.Description.ValueString() == "" {
description = nil
} else {
description = data.Description.ValueStringPointer()
}
- return description, tags
+ return description, tags, diags
}
func isHTTPImport(data *HypercoreVMResourceModel) bool {
// Check if HTTP URI is being used for VM import
@@ -285,6 +284,7 @@ func (r *HypercoreVMResource) handleCloneLogic(data *HypercoreVMResourceModel, c
data.Id = types.StringValue(vmNew.UUID)
tflog.Info(ctx, fmt.Sprintf("Changed: %t, Was VM Rebooted: %t, Diff: %v", changed, vmWasRebooted, vmDiff))
}
+
func (r *HypercoreVMResource) handleImportFromSMBLogic(data *HypercoreVMResourceModel, ctx context.Context, resp *resource.CreateResponse, vmNew *utils.VM, path string, fileName string) {
smbServer, smbUsername, smbPassword := data.Import.Server.ValueString(), data.Import.Username.ValueString(), data.Import.Password.ValueString()
errorDiagnostic := utils.ValidateSMB(smbServer, smbUsername, smbPassword)
@@ -299,6 +299,7 @@ func (r *HypercoreVMResource) handleImportFromSMBLogic(data *HypercoreVMResource
data.Id = types.StringValue(vmNew.UUID)
tflog.Info(ctx, fmt.Sprintf("Changed: %t, Was VM Rebooted: %t, Diff: %v", changed, vmWasRebooted, vmDiff))
}
+
func (r *HypercoreVMResource) handleImportFromURILogic(data *HypercoreVMResourceModel, ctx context.Context, resp *resource.CreateResponse, vmNew *utils.VM, path string, fileName string) {
httpUri := data.Import.HTTPUri.ValueString()
errorDiagnostic := utils.ValidateHTTP(httpUri, path)
@@ -313,6 +314,7 @@ func (r *HypercoreVMResource) handleImportFromURILogic(data *HypercoreVMResource
data.Id = types.StringValue(vmNew.UUID)
tflog.Info(ctx, fmt.Sprintf("Changed: %t, Was VM Rebooted: %t, Diff: %v", changed, vmWasRebooted, vmDiff))
}
+
func (r *HypercoreVMResource) doCreateLogic(data *HypercoreVMResourceModel, ctx context.Context, resp *resource.CreateResponse, description *string, tags *[]string) {
vmNew := getVMStruct(data, description, tags)
// Chose which VM create logic we're going with (clone, import, from scratch)
@@ -354,7 +356,11 @@ func (r *HypercoreVMResource) Create(ctx context.Context, req resource.CreateReq
}
// Validate parameters TODO: Add other inputs here from schema if validation is needed
- description, tags := validateParameters(&data)
+ description, tags, diags := validateParameters(&data, ctx)
+ if diags.HasError() {
+ resp.Diagnostics.Append(diags.Errors()...)
+ return
+ }
// Right now handles import or clone TODO: Add other VM create options here
r.doCreateLogic(&data, ctx, resp, description, tags)
@@ -398,7 +404,23 @@ func (r *HypercoreVMResource) Read(ctx context.Context, req resource.ReadRequest
data.Name = types.StringValue(utils.AnyToString(hc3_vm["name"]))
data.Description = types.StringValue(utils.AnyToString(hc3_vm["description"]))
- // data.Group TODO - replace "group" string with "tags" list of strings
+
+ // Read tags from the hc3 api
+ // - hc3Tags = "tag1,tag2,..."
+ // - tfTags = hc3Tags -> ["tag1", "tag2", ...]
+ hc3Tags := utils.AnyToString(hc3_vm["tags"])
+ goTagsList := strings.Split(hc3Tags, ",")
+ tfTagsValues := make([]attr.Value, len(goTagsList))
+ for i, tag := range goTagsList {
+ tfTagsValues[i] = types.StringValue(tag)
+ }
+
+ var diags diag.Diagnostics
+ data.Tags, diags = types.ListValue(types.StringType, tfTagsValues)
+ if diags.HasError() {
+ resp.Diagnostics.Append(diags.Errors()...)
+ return
+ }
// NOTE: power state not needed here anymore because of the hypercore_vm_power_state resource
// hc3_power_state := utils.AnyToString(hc3_vm["state"])
@@ -494,7 +516,16 @@ func (r *HypercoreVMResource) Update(ctx context.Context, req resource.UpdateReq
updatePayload["affinityStrategy"] = affinityStrategy
}
- taskTag, _ := restClient.UpdateRecord( /**/
+ // update tags: ["tag1", "tag2", ...] -> "tag1,tag2,..."
+ var tagsList []string
+ diags := data.Tags.ElementsAs(ctx, &tagsList, false)
+ if diags.HasError() {
+ resp.Diagnostics.Append(diags.Errors()...)
+ return
+ }
+ updatePayload["tags"] = utils.TagsListToCommaString(tagsList)
+
+ taskTag, _ := restClient.UpdateRecord(
fmt.Sprintf("/rest/v1/VirDomain/%s", vm_uuid),
updatePayload,
-1,
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 14d2a76..7d9d155 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
@@ -21,7 +21,8 @@ func TestAccHypercoreVMResourceSnapshotSchedule(t *testing.T) {
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("hypercore_vm.test", "description", "testtf-vm-description"),
resource.TestCheckResourceAttr("hypercore_vm.test", "memory", "4096"),
- resource.TestCheckResourceAttr("hypercore_vm.test", "group", "testtf"),
+ resource.TestCheckResourceAttr("hypercore_vm.test", "tags.#", "1"),
+ resource.TestCheckResourceAttr("hypercore_vm.test", "tags.0", "testtf"),
resource.TestCheckNoResourceAttr("hypercore_vm.test", "clone"),
resource.TestCheckResourceAttr("hypercore_vm.test", "name", "testtf-vm"),
resource.TestCheckResourceAttr("hypercore_vm.test", "vcpu", "4"),
@@ -62,7 +63,8 @@ func TestAccHypercoreVMResourceSnapshotSchedule(t *testing.T) {
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("hypercore_vm.test", "name", "testtf-vm"),
resource.TestCheckResourceAttr("hypercore_vm.test", "description", "testtf-vm-description"),
- resource.TestCheckResourceAttr("hypercore_vm.test", "group", "testtf"),
+ resource.TestCheckResourceAttr("hypercore_vm.test", "tags.#", "1"),
+ resource.TestCheckResourceAttr("hypercore_vm.test", "tags.1", "testtf"),
resource.TestCheckNoResourceAttr("hypercore_vm.test", "clone"),
resource.TestCheckResourceAttr("hypercore_vm.test", "vcpu", "4"),
resource.TestCheckResourceAttr("hypercore_vm.test", "memory", "4096"),
@@ -92,7 +94,7 @@ func testConfig_NoSnapshotScheduleUUID(vm_name string) string {
return fmt.Sprintf(`
resource "hypercore_vm" "test" {
name = %[1]q
- group = "testtf"
+ tags = ["testtf"]
vcpu = 4
memory = 4096
description = "testtf-vm-description"
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 163cadd..5777ed5 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
@@ -23,7 +23,9 @@ func TestAccHypercoreVMResourceClone(t *testing.T) {
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("hypercore_vm.test", "description", "testtf-vm-description"),
resource.TestCheckResourceAttr("hypercore_vm.test", "memory", "4096"),
- resource.TestCheckResourceAttr("hypercore_vm.test", "group", "testtf"),
+ resource.TestCheckResourceAttr("hypercore_vm.test", "tags.#", "2"),
+ resource.TestCheckResourceAttr("hypercore_vm.test", "tags.0", "testtf-tag-1"),
+ resource.TestCheckResourceAttr("hypercore_vm.test", "tags.1", "testtf-tag-2"),
resource.TestCheckResourceAttr("hypercore_vm.test", "clone.meta_data", ""),
resource.TestCheckResourceAttr("hypercore_vm.test", "clone.user_data", ""),
resource.TestCheckResourceAttr("hypercore_vm.test", "clone.source_vm_uuid", source_vm_uuid),
@@ -69,7 +71,9 @@ func TestAccHypercoreVMResourceClone(t *testing.T) {
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("hypercore_vm.test", "name", "testtf-vm"),
resource.TestCheckResourceAttr("hypercore_vm.test", "description", "testtf-vm-description"),
- resource.TestCheckResourceAttr("hypercore_vm.test", "group", "testtf"),
+ resource.TestCheckResourceAttr("hypercore_vm.test", "tags.#", "2"),
+ resource.TestCheckResourceAttr("hypercore_vm.test", "tags.0", "testtf-tag-1"),
+ resource.TestCheckResourceAttr("hypercore_vm.test", "tags.1", "testtf-tag-2"),
resource.TestCheckResourceAttr("hypercore_vm.test", "vcpu", "4"),
resource.TestCheckResourceAttr("hypercore_vm.test", "memory", "4096"),
// resource.TestCheckResourceAttr("hypercore_vm.test", "power_state", requested_power_state),
@@ -108,7 +112,10 @@ func testAccHypercoreVMResourceCloneConfig(vm_name string) string {
return fmt.Sprintf(`
resource "hypercore_vm" "test" {
name = %[1]q
- group = "testtf"
+ tags = [
+ "testtf-tag-1",
+ "testtf-tag-2",
+ ]
vcpu = 4
memory = 4096
description = "testtf-vm-description"
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 517a051..01613ab 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
@@ -21,7 +21,8 @@ func TestAccHypercoreVMResourceImport(t *testing.T) {
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("hypercore_vm.test", "description", "imported-vm"),
resource.TestCheckResourceAttr("hypercore_vm.test", "memory", "4096"),
- resource.TestCheckResourceAttr("hypercore_vm.test", "group", "Xlabintegrationtest"),
+ resource.TestCheckResourceAttr("hypercore_vm.test", "tags.#", "1"),
+ resource.TestCheckResourceAttr("hypercore_vm.test", "tags.0", "Xlabintegrationtest"),
resource.TestCheckResourceAttr("hypercore_vm.test", "name", "imported_vm_integration"),
resource.TestCheckResourceAttr("hypercore_vm.test", "vcpu", "4"),
),
@@ -34,7 +35,7 @@ func testAccHypercoreVMResourceImportConfig(vm_name string) string {
return fmt.Sprintf(`
resource "hypercore_vm" "test" {
name = %[1]q
- group = "Xlabintegrationtest"
+ tags = ["Xlabintegrationtest"]
vcpu = 4
memory = 4096
description = "imported-vm"
diff --git a/internal/utils/helper.go b/internal/utils/helper.go
index d9567dd..25057b1 100644
--- a/internal/utils/helper.go
+++ b/internal/utils/helper.go
@@ -106,7 +106,7 @@ func jsonObjectToTaskTag(jsonObj any) *TaskTag {
return taskTag
}
-func tagsListToCommaString(tags []string) string {
+func TagsListToCommaString(tags []string) string {
tagsHyp := ""
for _, tag := range tags {
tagsHyp += tag + ","
diff --git a/internal/utils/vm.go b/internal/utils/vm.go
index a1f2633..eabba4d 100644
--- a/internal/utils/vm.go
+++ b/internal/utils/vm.go
@@ -468,7 +468,7 @@ func (vc *VM) BuildUpdatePayload(changedParams map[string]bool) map[string]any {
updatePayload["description"] = *vc.description
}
if changed, ok := changedParams["tags"]; ok && changed {
- updatePayload["tags"] = tagsListToCommaString(*vc.tags)
+ updatePayload["tags"] = TagsListToCommaString(*vc.tags)
}
if changed, ok := changedParams["memory"]; ok && changed {
vcMemoryBytes := *vc.memory * 1024 * 1024 // MB to B
@@ -505,7 +505,7 @@ func (vc *VM) BuildImportTemplate() map[string]any {
importTemplate["description"] = *vc.description
}
if vc.tags != nil {
- importTemplate["tags"] = tagsListToCommaString(*vc.tags)
+ importTemplate["tags"] = TagsListToCommaString(*vc.tags)
}
if vc.memory != nil {
vcMemoryBytes := *vc.memory * 1024 * 1024 // MB to B
diff --git a/local/main.tf b/local/main.tf
index 14209ce..b84ebd2 100644
--- a/local/main.tf
+++ b/local/main.tf
@@ -10,38 +10,26 @@ terraform {
}
locals {
- vm_name = "testtf-remove-running"
- src_vm_name = "testtf-src-empty"
+ vm_name = "testtf-ana-tags-2"
+ src_vm_name = "ana"
}
provider "hypercore" {}
-data "hypercore_vms" "no-such-vm" {
- name = "no-such-vm"
+data "hypercore_vms" "src_empty" {
+ name = local.src_vm_name
}
-# resource "hypercore_vm" "vm_on" {
-# group = "testtf"
-# name = local.vm_name
-# description = "VM created from scratch"
-# vcpu = 1
-# memory = 1234 # MiB
-
-# # clone = {
-# # source_vm_uuid = data.hypercore_vm.src_empty.vms.0.uuid
-# # meta_data = ""
-# # user_data = ""
-# # }
-# }
-
-# resource "hypercore_vm_power_state" "vm_on" {
-# vm_uuid = hypercore_vm.vm_on.id
-# state = "SHUTOFF" // RUNNING SHUTOFF
-# }
-
-# output "vm_on_uuid" {
-# value = hypercore_vm.vm_on.id
-# }
-# output "power_state" {
-# value = hypercore_vm_power_state.vm_on.state
-# }
+resource "hypercore_vm" "vm_on" {
+ tags = ["ana-tftag2"]
+ name = local.vm_name
+ description = "VM created from scratch"
+ vcpu = 1
+ memory = 1234 # MiB
+
+ clone = {
+ source_vm_uuid = data.hypercore_vms.src_empty.vms.0.uuid
+ meta_data = ""
+ user_data = ""
+ }
+}