diff --git a/internal/provider/hypercore_vm_resource.go b/internal/provider/hypercore_vm_resource.go
index 13fc534..4b0a332 100644
--- a/internal/provider/hypercore_vm_resource.go
+++ b/internal/provider/hypercore_vm_resource.go
@@ -39,12 +39,22 @@ type HypercoreVMResourceModel struct {
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 {
+ HTTPUri types.String `tfsdk:"http_uri"`
+ Server types.String `tfsdk:"server"`
+ Username types.String `tfsdk:"username"`
+ Password types.String `tfsdk:"password"`
+ Path types.String `tfsdk:"path"`
+ FileName types.String `tfsdk:"file_name"`
+}
+
type CloneModel struct {
SourceVMUUID types.String `tfsdk:"source_vm_uuid"`
UserData types.String `tfsdk:"user_data"`
@@ -95,6 +105,19 @@ func (r *HypercoreVMResource) Schema(ctx context.Context, req resource.SchemaReq
MarkdownDescription: "UUID of the snapshot schedule to create automatic snapshots",
Optional: true,
},
+ "import": schema.ObjectAttribute{
+ MarkdownDescription: "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. Paramaters path and file_name are always **required**",
+ Optional: true,
+ AttributeTypes: map[string]attr.Type{
+ "http_uri": types.StringType,
+ "server": types.StringType,
+ "username": types.StringType,
+ "password": types.StringType,
+ "path": types.StringType,
+ "file_name": types.StringType,
+ },
+ },
"clone": schema.ObjectAttribute{
MarkdownDescription: "" +
"Clone options if the VM is being created as a clone. The `source_vm_uuid` is the UUID of the VM used for cloning,
" +
@@ -203,6 +226,7 @@ func (r *HypercoreVMResource) Create(ctx context.Context, req resource.CreateReq
tflog.Info(ctx, fmt.Sprintf("TTRT Create: name=%s, source_uuid=%s", data.Name.ValueString(), data.Clone.SourceVMUUID.ValueString()))
+ // Import or clone
vmClone, _ := utils.NewVM(
data.Name.ValueString(),
data.Clone.SourceVMUUID.ValueString(),
@@ -218,13 +242,48 @@ func (r *HypercoreVMResource) Create(ctx context.Context, req resource.CreateReq
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))
- // General parametrization
- // set: description, group, vcpu, memory, power_state
- changed, vmWasRebooted, vmDiff := vmClone.SetVMParams(*r.client, ctx)
- tflog.Info(ctx, fmt.Sprintf("Changed: %t, Was VM Rebooted: %t, Diff: %v", changed, vmWasRebooted, vmDiff))
+ // http import
+ httpUri := data.Import.HTTPUri.ValueString()
+
+ // smb import
+ smbServer := data.Import.Server.ValueString()
+ smbUsername := data.Import.Username.ValueString()
+ smbPassword := data.Import.Password.ValueString()
+
+ // location
+ path := data.Import.Path.ValueString()
+ fileName := data.Import.FileName.ValueString()
+
+ isSMBImport := smbServer != "" || smbUsername != "" || smbPassword != ""
+ isHTTPImport := httpUri != ""
+
+ if isHTTPImport && !isSMBImport {
+ nameDiag := utils.ValidateHTTP(httpUri, path)
+ if nameDiag != nil {
+ resp.Diagnostics.AddError(nameDiag.Summary(), nameDiag.Detail())
+ return
+ }
+ httpSource := utils.BuildHTTPImportSource(httpUri, path, fileName)
+ vmClone.ImportVM(*r.client, httpSource, ctx)
+ } else if isSMBImport && !isHTTPImport {
+ nameDiag := utils.ValidateSMB(smbServer, smbUsername, smbPassword, path)
+ if nameDiag != nil {
+ resp.Diagnostics.AddError(nameDiag.Summary(), nameDiag.Detail())
+ return
+ }
+ smbSource := utils.BuildSMBImportSource(smbUsername, smbPassword, smbServer, path, fileName)
+ vmClone.ImportVM(*r.client, smbSource, ctx)
+ } else {
+ // Cloning
+ changed, msg := vmClone.Create(*r.client, ctx)
+ tflog.Info(ctx, fmt.Sprintf("Changed: %t, Message: %s\n", changed, msg))
+
+ // General parametrization
+ // set: description, group, vcpu, memory, power_state
+ changed, vmWasRebooted, vmDiff := vmClone.SetVMParams(*r.client, ctx)
+ tflog.Info(ctx, fmt.Sprintf("Changed: %t, Was VM Rebooted: %t, Diff: %v", changed, vmWasRebooted, vmDiff))
+ }
// save into the Terraform state.
data.Id = types.StringValue(vmClone.UUID)
diff --git a/internal/utils/helper.go b/internal/utils/helper.go
index 25f3de5..9235319 100644
--- a/internal/utils/helper.go
+++ b/internal/utils/helper.go
@@ -12,6 +12,9 @@ import (
"net/http"
"os"
"strconv"
+ "strings"
+
+ "github.com/hashicorp/terraform-plugin-framework/diag"
)
func isSuperset(superset map[string]any, candidate map[string]any) bool {
@@ -83,21 +86,6 @@ func filterResultsRecursive(results []map[string]any, filterData map[string]any)
return filtered
}
-// nolint:unused
-func filterMap(input map[string]any, fieldNames ...string) map[string]any {
- output := map[string]any{}
-
- for _, fieldName := range fieldNames {
- if value, ok := input[fieldName]; ok {
- if value != nil || value != "" {
- output[fieldName] = value
- }
- }
- }
-
- return output
-}
-
func jsonObjectToTaskTag(jsonObj any) *TaskTag {
var taskTag *TaskTag
@@ -247,7 +235,7 @@ func AnyToListOfStrings(list any) []string {
func ReadLocalFileBinary(filePath string) ([]byte, error) {
file, err := os.Open(filePath)
if err != nil {
- return nil, fmt.Errorf("Error opening file '%s': %s", filePath, err)
+ return nil, fmt.Errorf("error opening file '%s': %s", filePath, err)
}
defer file.Close()
@@ -303,3 +291,48 @@ func GetFileSize(sourceFilePath string) int64 {
}
return fileInfo.Size()
}
+
+func ValidateSMB(server string, username string, password string, path string) diag.Diagnostic {
+ if server == "" {
+ return diag.NewErrorDiagnostic(
+ "Missing 'server' parameter",
+ "For using SMB, you must specify the 'server' parameter",
+ )
+ }
+ if username == "" {
+ return diag.NewErrorDiagnostic(
+ "Missing 'username' parameter",
+ "For using SMB, you must specify the 'username' parameter",
+ )
+ }
+ if password == "" {
+ return diag.NewErrorDiagnostic(
+ "Missing 'password' parameter",
+ "For using SMB, you must specify the 'password' parameter",
+ )
+ }
+ if path == "" {
+ return diag.NewErrorDiagnostic(
+ "Missing 'path' parameter",
+ "For using SMB, you must specify the 'path' parameter",
+ )
+ }
+ return nil
+}
+
+func ValidateHTTP(httpUri string, path string) diag.Diagnostic {
+ if !strings.HasPrefix(httpUri, "http://") && !strings.HasPrefix(httpUri, "https://") {
+ return diag.NewErrorDiagnostic(
+ "Invalid HTTP uri",
+ "Invalid HTTP uri. Uri must start with 'http://' or 'https://'",
+ )
+ }
+ if path == "" {
+ return diag.NewErrorDiagnostic(
+ "Invalid path",
+ "Invalid path. Path parameter must be defined and start with '/'",
+ )
+ }
+
+ return nil
+}
diff --git a/internal/utils/rest_client.go b/internal/utils/rest_client.go
index f9e45e2..07faeac 100644
--- a/internal/utils/rest_client.go
+++ b/internal/utils/rest_client.go
@@ -60,7 +60,7 @@ func (rc *RestClient) GetAuthHeader() map[string]string {
func (rc *RestClient) ToJson(response *http.Response) any {
respBytes, err := io.ReadAll(response.Body)
if err != nil {
- panic(fmt.Errorf("Failed to read response body: %s", err.Error()))
+ panic(fmt.Errorf("failed to read response body: %s", err.Error()))
}
var respJson any
@@ -80,18 +80,18 @@ func (rc *RestClient) ToJsonObjectList(response *http.Response) []map[string]any
if obj, ok := item.(map[string]any); ok {
result = append(result, obj)
} else {
- panic(fmt.Errorf("Unexpected item in response list: %v", item))
+ panic(fmt.Errorf("unexpected item in response list: %v", item))
}
}
return result
}
- panic(fmt.Errorf("Expected a JSON list of objects, go: %v", respJson))
+ panic(fmt.Errorf("expected a JSON list of objects, go: %v", respJson))
}
func (rc *RestClient) ToString(response *http.Response) string {
respBytes, err := io.ReadAll(response.Body)
if err != nil {
- panic(fmt.Errorf("Failed to read response body: %s", err.Error()))
+ panic(fmt.Errorf("failed to read response body: %s", err.Error()))
}
return string(respBytes)
}
@@ -103,7 +103,7 @@ func (rc *RestClient) Request(method string, endpoint string, body map[string]an
if body != nil {
jsonBody, err = json.Marshal(body)
if err != nil {
- panic(fmt.Errorf("Failed to marshal JSON body: %s", err.Error()))
+ panic(fmt.Errorf("failed to marshal JSON body: %s", err.Error()))
}
}
@@ -113,7 +113,7 @@ func (rc *RestClient) Request(method string, endpoint string, body map[string]an
bytes.NewBuffer(jsonBody),
)
if err != nil {
- panic(fmt.Errorf("Invalid request: %s", err.Error()))
+ panic(fmt.Errorf("invalid request: %s", err.Error()))
}
req.Header.Set("Accept", "application/json")
@@ -141,7 +141,7 @@ func (rc *RestClient) RequestBinary(
bytes.NewBuffer(binaryData),
)
if err != nil {
- panic(fmt.Errorf("Invalid request: %s", err.Error()))
+ panic(fmt.Errorf("invalid request: %s", err.Error()))
}
req.Header.Set("Accept", "application/json")
@@ -162,7 +162,7 @@ func (rc *RestClient) RequestWithList(method string, endpoint string, body []map
if body != nil {
jsonBody, err = json.Marshal(body)
if err != nil {
- panic(fmt.Errorf("Failed to marshal JSON body: %s", err.Error()))
+ panic(fmt.Errorf("failed to marshal JSON body: %s", err.Error()))
}
}
@@ -172,7 +172,7 @@ func (rc *RestClient) RequestWithList(method string, endpoint string, body []map
bytes.NewBuffer(jsonBody),
)
if err != nil {
- panic(fmt.Errorf("Invalid request: %s", err.Error()))
+ panic(fmt.Errorf("invalid request: %s", err.Error()))
}
req.Header.Set("Accept", "application/json")
@@ -199,12 +199,12 @@ func (rc *RestClient) Login() {
resp, err := rc.HttpClient.Do(req)
if err != nil {
- panic(fmt.Errorf("Couldn't authenticate: %s", err.Error()))
+ panic(fmt.Errorf("couldn't authenticate: %s", err.Error()))
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
- panic(fmt.Errorf("Authentication failed with status code: %d", resp.StatusCode))
+ panic(fmt.Errorf("authentication failed with status code: %d", resp.StatusCode))
}
if respJson, ok := rc.ToJson(resp).(map[string]any); ok {
@@ -212,7 +212,7 @@ func (rc *RestClient) Login() {
"Cookie": fmt.Sprintf("sessionID=%s", respJson["sessionID"]),
}
} else {
- panic(fmt.Errorf("Session ID not found in response"))
+ panic(fmt.Errorf("session ID not found in response"))
}
}
@@ -233,12 +233,12 @@ func (rc *RestClient) ListRecords(endpoint string, query map[string]any, timeout
resp, err := client.Do(req)
if err != nil {
- panic(fmt.Errorf("Error making a request: %s", err.Error()))
+ panic(fmt.Errorf("error making a request: %s", err.Error()))
}
defer resp.Body.Close()
if !(resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusNoContent) {
- panic(fmt.Errorf("Unexpected response: %d - %v", resp.StatusCode, rc.ToString(resp)))
+ panic(fmt.Errorf("unexpected response: %d - %v", resp.StatusCode, rc.ToString(resp)))
}
records := rc.ToJsonObjectList(resp)
@@ -302,9 +302,9 @@ func (rc *RestClient) CreateRecord(endpoint string, payload map[string]any, time
if respErr, ok := respJsonMap["error"]; ok {
return nil, resp.StatusCode, fmt.Errorf("%s", AnyToString(respErr))
}
- panic(fmt.Errorf("Unexpected response body: %v", respJson))
+ panic(fmt.Errorf("unexpected response body: %v", respJson))
}
- panic(fmt.Errorf("Error making a request: Maybe the arguments passed to were incorrectly formatted: %v - response: %v", payload, string(respByte)))
+ panic(fmt.Errorf("error making a request: Maybe the arguments passed to were incorrectly formatted: %v - response: %v", payload, string(respByte)))
}
if _, ok := AnyToMap(respJson)["taskTag"]; !ok {
@@ -340,9 +340,9 @@ func (rc *RestClient) CreateRecordWithList(endpoint string, payload []map[string
if resp.StatusCode == 400 {
respByte, ok := respJson.([]byte)
if !ok { // this check is needed because of conversion from any to []byte
- panic(fmt.Errorf("Unexpected response body: %v", respJson))
+ panic(fmt.Errorf("unexpected response body: %v", respJson))
}
- panic(fmt.Errorf("Error making a request: Maybe the arguments passed were incorrectly formatted: %v - response: %v", payload, string(respByte)))
+ panic(fmt.Errorf("error making a request: Maybe the arguments passed were incorrectly formatted: %v - response: %v", payload, string(respByte)))
}
if _, ok := AnyToMap(respJson)["taskTag"]; !ok {
@@ -370,7 +370,7 @@ func (rc *RestClient) UpdateRecord(endpoint string, payload map[string]any, time
resp, err := client.Do(req)
if err != nil {
- panic(fmt.Errorf("Error making a request: %s", err.Error()))
+ panic(fmt.Errorf("error making a request: %s", err.Error()))
}
defer resp.Body.Close()
@@ -378,9 +378,9 @@ func (rc *RestClient) UpdateRecord(endpoint string, payload map[string]any, time
if resp.StatusCode == 400 {
respByte, ok := respJson.([]byte)
if !ok { // this check is needed because of conversion from any to []byte
- panic(fmt.Errorf("Unexpected response body: %v", respJson))
+ panic(fmt.Errorf("unexpected response body: %v", respJson))
}
- panic(fmt.Errorf("Error making a request: Maybe the arguments passed were incorrectly formatted: %v - response: %v", payload, string(respByte)))
+ panic(fmt.Errorf("error making a request: Maybe the arguments passed were incorrectly formatted: %v - response: %v", payload, string(respByte)))
}
if _, ok := AnyToMap(respJson)["taskTag"]; !ok {
@@ -408,7 +408,7 @@ func (rc *RestClient) PutRecord(endpoint string, payload map[string]any, timeout
resp, err := client.Do(req)
if err != nil {
- panic(fmt.Errorf("Error making a request: %s", err.Error()))
+ panic(fmt.Errorf("error making a request: %s", err.Error()))
}
defer resp.Body.Close()
@@ -416,9 +416,9 @@ func (rc *RestClient) PutRecord(endpoint string, payload map[string]any, timeout
if resp.StatusCode == 400 {
respByte, ok := respJson.([]byte)
if !ok { // this check is needed because of conversion from any to []byte
- panic(fmt.Errorf("Unexpected response body: %v", respJson))
+ panic(fmt.Errorf("unexpected response body: %v", respJson))
}
- panic(fmt.Errorf("Error making a request: Maybe the arguments passed were incorrectly formatted: %v - response: %v", payload, string(respByte)))
+ panic(fmt.Errorf("error making a request: Maybe the arguments passed were incorrectly formatted: %v - response: %v", payload, string(respByte)))
}
if _, ok := AnyToMap(respJson)["taskTag"]; !ok {
@@ -447,7 +447,7 @@ func (rc *RestClient) PutBinaryRecord(endpoint string, binaryData []byte, conten
resp, err := client.Do(req)
if err != nil {
- panic(fmt.Errorf("Error making a request: %s", err.Error()))
+ panic(fmt.Errorf("error making a request: %s", err.Error()))
}
defer resp.Body.Close()
@@ -455,9 +455,9 @@ func (rc *RestClient) PutBinaryRecord(endpoint string, binaryData []byte, conten
if resp.StatusCode == 400 {
respByte, ok := respJson.([]byte)
if !ok { // this check is needed because of conversion from any to []byte
- panic(fmt.Errorf("Unexpected response body: %v", respJson))
+ panic(fmt.Errorf("unexpected response body: %v", respJson))
}
- panic(fmt.Errorf("Error making a request: Maybe the arguments passed were incorrectly formatted: %v - response: %v", binaryData, string(respByte)))
+ panic(fmt.Errorf("error making a request: Maybe the arguments passed were incorrectly formatted: %v - response: %v", binaryData, string(respByte)))
}
if _, ok := AnyToMap(respJson)["taskTag"]; !ok {
@@ -486,12 +486,12 @@ func (rc *RestClient) PutBinaryRecordWithoutTaskTag(endpoint string, binaryData
resp, err := client.Do(req)
if err != nil {
- panic(fmt.Errorf("Error making a request: %s", err.Error()))
+ panic(fmt.Errorf("error making a request: %s", err.Error()))
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
- panic(fmt.Errorf("Error making a request: got response status code %v", resp.StatusCode))
+ panic(fmt.Errorf("error making a request: got response status code %v", resp.StatusCode))
}
return resp.StatusCode, nil
@@ -514,7 +514,7 @@ func (rc *RestClient) DeleteRecord(endpoint string, timeout float64, ctx context
resp, err := client.Do(req)
if err != nil {
- panic(fmt.Errorf("Error making a request: %s", err.Error()))
+ panic(fmt.Errorf("error making a request: %s", err.Error()))
}
defer resp.Body.Close()
diff --git a/internal/utils/vm.go b/internal/utils/vm.go
index 619ebfa..1f636c7 100644
--- a/internal/utils/vm.go
+++ b/internal/utils/vm.go
@@ -175,6 +175,33 @@ func (vc *VM) Create(restClient RestClient, ctx context.Context) (bool, string)
panic(fmt.Sprintf("There was a problem during cloning of %s %s, cloning failed.", sourceVMName, vc.sourceVMUUID))
}
+func (vc *VM) ImportVM(
+ restClient RestClient,
+ source map[string]any,
+ ctx context.Context,
+) map[string]any {
+ payload := map[string]any{
+ "source": source,
+ }
+
+ importTemplate := vc.BuildImportTemplate()
+ if len(importTemplate) > 0 {
+ payload["template"] = importTemplate
+ }
+
+ taskTag, _, _ := restClient.CreateRecord(
+ "/rest/v1/VirDomain/import",
+ payload,
+ -1,
+ )
+ taskTag.WaitTask(restClient, ctx)
+ vmUUID := taskTag.CreatedUUID
+ vm := GetOneVM(vmUUID, restClient)
+
+ vc.UUID = vmUUID
+ return vm
+}
+
func (vc *VM) SetVMParams(restClient RestClient, ctx context.Context) (bool, bool, map[string]any) {
vm := GetVMByName(vc.VMName, restClient, true)
changed, changedParams := vc.GetChangedParams(ctx, *vm)
@@ -436,6 +463,40 @@ func (vc *VM) BuildUpdatePayload(changedParams map[string]bool) map[string]any {
return updatePayload
}
+func (vc *VM) BuildImportTemplate() map[string]any {
+ importTemplate := map[string]any{}
+
+ if vc.description != nil {
+ importTemplate["description"] = *vc.description
+ }
+ if vc.tags != nil {
+ importTemplate["tags"] = tagsListToCommaString(*vc.tags)
+ }
+ if vc.memory != nil {
+ vcMemoryBytes := *vc.memory * 1024 * 1024 // MB to B
+ importTemplate["mem"] = vcMemoryBytes
+ }
+ if vc.vcpu != nil {
+ importTemplate["numVCPU"] = *vc.vcpu
+ }
+
+ affinityStrategy := map[string]any{
+ "strictAffinity": vc.strictAffinity,
+ }
+
+ if vc.preferredNodeUUID != "" {
+ affinityStrategy["preferredNodeUUID"] = vc.preferredNodeUUID
+ }
+
+ if vc.backupNodeUUID != "" {
+ affinityStrategy["backupNodeUUID"] = vc.backupNodeUUID
+ }
+
+ importTemplate["affinityStrategy"] = affinityStrategy
+
+ return importTemplate
+}
+
func (vc *VM) GetChangedParams(ctx context.Context, vmFromClient map[string]any) (bool, map[string]bool) {
changedParams := map[string]bool{}
@@ -478,6 +539,32 @@ func (vc *VM) GetChangedParams(ctx context.Context, vmFromClient map[string]any)
return false, changedParams
}
+func BuildSMBImportSource(username string, password string, server string, path string, fileName string) map[string]any {
+ pathURI := fmt.Sprintf("smb://%s:%s@%s%s", username, password, server, path)
+
+ source := map[string]any{
+ "pathURI": pathURI,
+ }
+ if fileName != "" {
+ source["definitionFileName"] = fileName
+ }
+
+ return source
+}
+
+func BuildHTTPImportSource(httpUri string, path string, fileName string) map[string]any {
+ pathURI := fmt.Sprintf("%s%s", httpUri, path)
+ source := map[string]any{
+ "pathURI": pathURI,
+ }
+
+ if fileName != "" {
+ source["definitionFileName"] = fileName
+ }
+
+ return source
+}
+
func GetOneVM(uuid string, restClient RestClient) map[string]any {
url := "/rest/v1/VirDomain/" + uuid
records := restClient.ListRecords(
@@ -503,7 +590,7 @@ func GetOneVMWithError(uuid string, restClient RestClient) (*map[string]any, err
)
if record == nil {
- return nil, fmt.Errorf("VM not found - vmUUID=%s.\n", uuid)
+ return nil, fmt.Errorf("vm not found - vmUUID=%s", uuid)
}
return record, nil
@@ -518,7 +605,7 @@ func GetVMOrFail(query map[string]any, restClient RestClient) []map[string]any {
)
if len(records) == 0 {
- panic(fmt.Errorf("No VM found: %v", query))
+ panic(fmt.Errorf("no VM found: %v", query))
}
return records
diff --git a/internal/utils/vm_disk.go b/internal/utils/vm_disk.go
index f37d320..f8d49ad 100644
--- a/internal/utils/vm_disk.go
+++ b/internal/utils/vm_disk.go
@@ -36,7 +36,7 @@ func NewVMDisk(
_size *float64,
) (*VMDisk, error) {
if !ALLOWED_DISK_TYPES[_type] {
- return nil, fmt.Errorf("Disk type '%s' not allowed. Allowed types are: IDE_DISK, SCSI_DISK, VIRTIO_DISK, IDE_FLOPPY, NVRAM, VTPM\n", _type)
+ return nil, fmt.Errorf("disk type '%s' not allowed. Allowed types are: IDE_DISK, SCSI_DISK, VIRTIO_DISK, IDE_FLOPPY, NVRAM, VTPM", _type)
}
var byteSize *float64
@@ -108,7 +108,7 @@ func (vd *VMDisk) CreateOrUpdate(
desiredDiskSize := AnyToFloat64(desiredDisk["capacity"]) / 1000 / 1000 / 1000
if existingDiskSize > desiredDiskSize {
return false, false, "", fmt.Errorf(
- "Disk of type '%s' on slot %d can only be expanded. Use a different slot or use a larger size. %v GB > %v GB\n",
+ "disk of type '%s' on slot %d can only be expanded. Use a different slot or use a larger size. %v GB > %v GB",
existingDiskType, existingDiskSlot, existingDiskSize, desiredDiskSize,
)
}
diff --git a/local/main.tf b/local/main.tf
index 5c6bdc9..139802c 100644
--- a/local/main.tf
+++ b/local/main.tf
@@ -11,16 +11,49 @@ terraform {
provider "hypercore" {}
-data "hypercore_remote_cluster_connection" "all_clusters" {}
+locals {
+ vm_meta_data_tmpl = "./assets/meta-data.ubuntu-22.04.yml.tftpl"
+ vm_user_data_tmpl = "./assets/user-data.ubuntu-22.04.yml.tftpl"
+ vm_name = "my-vm"
+}
+
+data "hypercore_vm" "clone_source_vm" {
+ name = "source_vm"
+}
+
+# This is what the updated resource will look like with import
+resource "hypercore_vm" "import-from-http" {
+ group = "my-group"
+ name = local.vm_name
+ description = "some description"
+
+ vcpu = 4
+ memory = 4096 # MiB
-data "hypercore_remote_cluster_connection" "cluster-a" {
- remote_cluster_name = "cluster-a"
+ import = {
+ http_path = "http://someurl/my-vm"
+ }
}
-output "all_remote_clusters" {
- value = jsonencode(data.hypercore_remote_cluster_connection.all_clusters)
+resource "hypercore_vm" "import-from-smb" {
+ group = "my-group"
+ name = local.vm_name
+ description = "some description"
+
+ vcpu = 4
+ memory = 4096 # MiB
+
+ import = {
+ server = "server"
+ username = "username"
+ password = "password"
+ path = "path"
+ file_name = "file_name"
+ }
}
-output "filtered_remote_cluster" {
- value = jsonencode(data.hypercore_remote_cluster_connection.cluster-a)
+# NOTE: 'clone' parameter can still be defined along with 'import', but in THIS case, 'import' will be the one taking effect, not clone
+
+output "vm_uuid" {
+ value = hypercore_vm.myvm.id
}