From 4d3003729b31beb75bf36c30b12e24c089d5fa75 Mon Sep 17 00:00:00 2001 From: Justin Cinkelj Date: Wed, 2 Apr 2025 10:57:23 +0200 Subject: [PATCH 1/2] Implement hypercore_vm_replication resource --- .../hypercore_vm_replication_resource.go | 330 ++++++++++++++++++ internal/provider/provider.go | 1 + internal/utils/rest_client.go | 9 + internal/utils/vm_replication.go | 102 ++++++ local/main.tf | 91 ++--- 5 files changed, 467 insertions(+), 66 deletions(-) create mode 100644 internal/provider/hypercore_vm_replication_resource.go create mode 100644 internal/utils/vm_replication.go diff --git a/internal/provider/hypercore_vm_replication_resource.go b/internal/provider/hypercore_vm_replication_resource.go new file mode 100644 index 0000000..0120d4e --- /dev/null +++ b/internal/provider/hypercore_vm_replication_resource.go @@ -0,0 +1,330 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package provider + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "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/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-provider-hypercore/internal/utils" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var _ resource.Resource = &HypercoreVMReplicationResource{} +var _ resource.ResourceWithImportState = &HypercoreVMReplicationResource{} + +func NewHypercoreVMReplicationResource() resource.Resource { + return &HypercoreVMReplicationResource{} +} + +// HypercoreVMReplicationResource defines the resource implementation. +type HypercoreVMReplicationResource struct { + client *utils.RestClient +} + +// HypercoreVMReplicationResourceModel describes the resource data model. +type HypercoreVMReplicationResourceModel struct { + Id types.String `tfsdk:"id"` + VmUUID types.String `tfsdk:"vm_uuid"` + Label types.String `tfsdk:"label"` + ConnectionUUID types.String `tfsdk:"connection_uuid"` + Enable types.Bool `tfsdk:"enable"` + TargetVmUUID types.String `tfsdk:"target_vm_uuid"` +} + +func (r *HypercoreVMReplicationResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_vm_replication" +} + +func (r *HypercoreVMReplicationResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + // This description is used by the documentation generator and the language server. + MarkdownDescription: "Hypercore VM replication resource to manage VM boot devices' order", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "Replication identifier", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "target_vm_uuid": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "Remote target VM UUID", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "vm_uuid": schema.StringAttribute{ + MarkdownDescription: "VM UUID of which we want to make a replication", + Required: true, + }, + "label": schema.StringAttribute{ + MarkdownDescription: "Human-readable label describing the replication purpose", + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "connection_uuid": schema.StringAttribute{ + MarkdownDescription: "Remote connection UUID", + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "enable": schema.BoolAttribute{ + MarkdownDescription: "Enable or disable replication", + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.Bool{ + boolplanmodifier.UseStateForUnknown(), + }, + }, + }, + } +} + +func (r *HypercoreVMReplicationResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + tflog.Info(ctx, "TTRT HypercoreVMReplicationResource CONFIGURE") + // Prevent padisk if the provider has not been configured. + if req.ProviderData == nil { + return + } + + restClient, ok := req.ProviderData.(*utils.RestClient) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected *http.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = restClient +} + +func (r *HypercoreVMReplicationResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + tflog.Info(ctx, "TTRT HypercoreVMReplicationResource CREATE") + var data HypercoreVMReplicationResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if r.client == nil { + resp.Diagnostics.AddError( + "Unconfigured HTTP Client", + "Expected configured HTTP client. Please report this issue to the provider developers.", + ) + return + } + if resp.Diagnostics.HasError() { + return + } + + restClient := *r.client + vmUUID := data.VmUUID.ValueString() // is required + connectionUUID := data.ConnectionUUID.ValueString() // should be required + label := data.Label.ValueString() // default empty string "" + + enable := data.Enable.ValueBool() + if data.Enable.IsUnknown() || data.Enable.IsNull() { + enable = true // default it to true, like in the API + } + + if connectionUUID == "" { + resp.Diagnostics.AddError( + "Missing connection_uuid", + "Parameter 'connection_uuid' is required for creating a VM replication", + ) + } + + tflog.Info(ctx, fmt.Sprintf("TTRT Create: vm_uuid=%s, connection_uuid=%s, label=%s, enable=%t", vmUUID, connectionUUID, label, enable)) + + replicationUUID, replication, _diag := utils.CreateVMReplication(restClient, vmUUID, connectionUUID, label, enable, ctx) + if _diag != nil { + if _diag.Severity() == 0 { // if is error + resp.Diagnostics.AddError(_diag.Summary(), _diag.Detail()) + return + } + + // otherwise it's a warning + resp.Diagnostics.AddWarning(_diag.Summary(), _diag.Detail()) + } + + tflog.Info(ctx, fmt.Sprintf("TTRT Created: vm_uuid=%s, connection_uuid=%s, label=%s, enable=%t, replication=%v", vmUUID, connectionUUID, label, enable, replication)) + + targetVmUUID := "" + if replication["targetDomainUUID"] != nil { + targetVmUUID = utils.AnyToString(targetVmUUID) + } + + // TODO: Check if HC3 matches TF + // save into the Terraform state. + data.Id = types.StringValue(replicationUUID) + data.TargetVmUUID = types.StringValue(targetVmUUID) + data.Enable = types.BoolValue(enable) + + // Write logs using the tflog package + // Documentation: https://terraform.io/plugin/log + tflog.Trace(ctx, "Created a replication") + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *HypercoreVMReplicationResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + tflog.Info(ctx, "TTRT HypercoreVMReplicationResource READ") + var data HypercoreVMReplicationResourceModel + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + // Boot Order read ====================================================================== + restClient := *r.client + replicationUUID := data.Id.ValueString() + vmUUID := data.VmUUID.ValueString() + + tflog.Debug(ctx, fmt.Sprintf("TTRT HypercoreVMReplicationResource Read oldState replicationUUID=%s\n", replicationUUID)) + + pHc3Replication := utils.GetVMReplicationByUUID(restClient, replicationUUID) + if pHc3Replication == nil { + resp.Diagnostics.AddError("VM not found", fmt.Sprintf("VM replication not found - replicationUUID=%s", replicationUUID)) + return + } + hc3Replication := *pHc3Replication + + tflog.Info(ctx, fmt.Sprintf("TTRT HypercoreVMReplicationResource: vm_uuid=%s, replication_uuid=%s", vmUUID, replicationUUID)) + + // save into the Terraform state. + data.Id = types.StringValue(replicationUUID) + data.TargetVmUUID = types.StringValue(utils.AnyToString(hc3Replication["targetDomainUUID"])) + data.VmUUID = types.StringValue(utils.AnyToString(hc3Replication["sourceDomainUUID"])) + data.ConnectionUUID = types.StringValue(utils.AnyToString(hc3Replication["connectionUUID"])) + data.Label = types.StringValue(utils.AnyToString(hc3Replication["label"])) + data.Enable = types.BoolValue(utils.AnyToBool(hc3Replication["enable"])) + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *HypercoreVMReplicationResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + tflog.Info(ctx, "TTRT HypercoreVMReplicationResource UPDATE") + var data_state HypercoreVMReplicationResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &data_state)...) + var data HypercoreVMReplicationResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + restClient := *r.client + replicationUUID := data.Id.ValueString() + vmUUID := data.VmUUID.ValueString() + connectionUUID := data.ConnectionUUID.ValueString() + label := data.Label.ValueString() + + enable := data.Enable.ValueBool() + if data.Enable.IsUnknown() || data.Enable.IsNull() { + enable = true // default it to true, like in the API + } + data.Enable = types.BoolValue(enable) + + if connectionUUID == "" { + resp.Diagnostics.AddError( + "Missing connection_uuid", + "Parameter 'connection_uuid' is required for updating a VM replication", + ) + } + + diag := utils.UpdateVMReplication(restClient, replicationUUID, vmUUID, connectionUUID, label, enable, ctx) + if diag != nil { + resp.Diagnostics.AddWarning(diag.Summary(), diag.Detail()) + } + + // TODO: Check if HC3 matches TF + // Do not trust UpdateVMReplication made what we asked for. Read new power state from HC3. + pHc3Replication := utils.GetVMReplicationByUUID(restClient, replicationUUID) + if pHc3Replication == nil { + msg := fmt.Sprintf("VM replication not found - replicationUUID=%s.", replicationUUID) + resp.Diagnostics.AddError("VM replication not found", msg) + return + } + newHc3Replication := *pHc3Replication + + tflog.Info(ctx, fmt.Sprintf("TTRT HypercoreVMReplicationResource: replication_uuid=%s, replication=%v", replicationUUID, newHc3Replication)) + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *HypercoreVMReplicationResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + tflog.Info(ctx, "TTRT HypercoreVMReplicationResource DELETE") + var data HypercoreVMReplicationResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + // Extra implementation not needed - VirDomainReplication doesn't have a DELETE endpoint + + // If applicable, this is a great opportunity to initialize any necessary + // provider client data and make a call using it. + // httpResp, err := r.client.Do(httpReq) + // if err != nil { + // resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete example, got error: %s", err)) + // return + // } +} + +func (r *HypercoreVMReplicationResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + tflog.Info(ctx, "TTRT HypercoreVMReplicationResource IMPORT_STATE") + + replicationUUID := req.ID + tflog.Info(ctx, fmt.Sprintf("TTRT HypercoreVMReplicationResource: replicationUUID=%s", replicationUUID)) + + restClient := *r.client + hc3Replication := utils.GetVMReplicationByUUID(restClient, replicationUUID) + + if hc3Replication == nil { + msg := fmt.Sprintf("VM Replication import, VM not found - 'replication_uuid'='%s'.", req.ID) + resp.Diagnostics.AddError("VM Replication import error, VM not found", msg) + return + } + + vmUUID := utils.AnyToString((*hc3Replication)["sourceDomainUUID"]) + targetVmUUID := utils.AnyToString((*hc3Replication)["targetDomainUUID"]) + connectionUUID := utils.AnyToString((*hc3Replication)["connectionUUID"]) + label := utils.AnyToString((*hc3Replication)["label"]) + enable := utils.AnyToBool((*hc3Replication)["enable"]) + + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), replicationUUID)...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("target_vm_uuid"), targetVmUUID)...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("vm_uuid"), vmUUID)...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("connection_uuid"), connectionUUID)...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("label"), label)...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("enable"), enable)...) +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index c878f43..5c63425 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -173,6 +173,7 @@ func (p *HypercoreProvider) Resources(ctx context.Context) []func() resource.Res NewHypercoreVMBootOrderResource, NewHypercoreVMSnapshotResource, NewHypercoreVMSnapshotScheduleResource, + NewHypercoreVMReplicationResource, } } diff --git a/internal/utils/rest_client.go b/internal/utils/rest_client.go index 8ac7fed..c2b031e 100644 --- a/internal/utils/rest_client.go +++ b/internal/utils/rest_client.go @@ -289,7 +289,16 @@ func (rc *RestClient) CreateRecord(endpoint string, payload map[string]any, time respJson := rc.ToJson(resp) if resp.StatusCode == 400 { respByte, ok := respJson.([]byte) + if !ok { // this check is needed because of conversion from any to []byte + // jsonErrorString, err := json.Marshal(respJson) + // if err != nil { + // panic(fmt.Errorf("Unexpected response body: %v", respJson)) + // } + respJsonMap := AnyToMap(respJson) + 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("Error making a request: Maybe the arguments passed to were incorrectly formatted: %v - response: %v", payload, string(respByte))) diff --git a/internal/utils/vm_replication.go b/internal/utils/vm_replication.go new file mode 100644 index 0000000..d914bd1 --- /dev/null +++ b/internal/utils/vm_replication.go @@ -0,0 +1,102 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package utils + +import ( + "context" + "fmt" + "strings" + + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +func GetVMReplicationByUUID( + restClient RestClient, + replicationUUID string, +) *map[string]any { + replication := restClient.GetRecord( + fmt.Sprintf("/rest/v1/VirDomainReplication/%s", replicationUUID), + nil, + false, + -1, + ) + return replication +} + +func CreateVMReplication( + restClient RestClient, + sourceVmUUID string, + connectionUUID string, + label string, + enable bool, + ctx context.Context, +) (string, map[string]any, diag.Diagnostic) { + payload := map[string]any{ + "sourceDomainUUID": sourceVmUUID, + "connectionUUID": connectionUUID, + "label": label, + "enable": enable, + } + taskTag, status, err := restClient.CreateRecord( + "/rest/v1/VirDomainReplication", + payload, + -1, + ) + + if status == 400 && err != nil { + isReplicationError := strings.Contains(err.Error(), "Failed to create replication") + if isReplicationError { + return "", nil, diag.NewWarningDiagnostic( + "Couldn't create a VM replication", + fmt.Sprintf("VM replication failed. Source VM '%s' might already have configured replication. Response message: %s", sourceVmUUID, err.Error()), + ) + } + return "", nil, diag.NewErrorDiagnostic( + "Couldn't create a VM replication", + fmt.Sprintf("Something unexpected happened while attempting to create replication for VM '%s'. Response message: %s", sourceVmUUID, err.Error()), + ) + } + + taskTag.WaitTask(restClient, ctx) + replicationUUID := taskTag.CreatedUUID + replication := GetVMReplicationByUUID(restClient, replicationUUID) + return replicationUUID, *replication, nil +} + +func UpdateVMReplication( + restClient RestClient, + replicationUUID string, + sourceVmUUID string, + connectionUUID string, + label string, + enable bool, + ctx context.Context, +) diag.Diagnostic { + payload := map[string]any{ + "sourceDomainUUID": sourceVmUUID, + "connectionUUID": connectionUUID, + "label": label, + "enable": enable, + } + + taskTag, err := restClient.UpdateRecord( + fmt.Sprintf("/rest/v1/VirDomainReplication/%s", replicationUUID), + payload, + -1, + ctx, + ) + + if err != nil { + return diag.NewWarningDiagnostic( + "HC3 is receiving too many requests at the same time.", + fmt.Sprintf("Please retry apply after Terraform finishes it's current operation. HC3 response message: %v", err.Error()), + ) + } + + taskTag.WaitTask(restClient, ctx) + tflog.Debug(ctx, fmt.Sprintf("TTRT Task Tag: %v\n", taskTag)) + + return nil +} diff --git a/local/main.tf b/local/main.tf index 12058ac..199cc90 100644 --- a/local/main.tf +++ b/local/main.tf @@ -12,88 +12,47 @@ terraform { provider "hypercore" {} locals { - vm_name = "testtf-ana" - another_vm_name = "testtf-ana-3" - create_vm_name = "testtf-ana-scheduled" + vm_name = "testtf-ana-replication" + another_vm_name = "testtf-ana" } - -data "hypercore_vm" "snapvm" { +data "hypercore_vm" "vm-repl" { name = local.vm_name } -output "testtf-ana" { - value = data.hypercore_vm.snapvm.vms.0.snapshot_schedule_uuid -} - -data "hypercore_vm" "another_snapvm_schedule" { +data "hypercore_vm" "vm-repl-2" { name = local.another_vm_name } -resource "hypercore_vm_snapshot" "snapshot" { - vm_uuid = data.hypercore_vm.snapvm.vms.0.uuid - label = "testtf-ana-snapshot" -} - -resource "hypercore_vm_snapshot" "imported-snapshot" { - vm_uuid = data.hypercore_vm.snapvm.vms.0.uuid -} - -import { - to = hypercore_vm_snapshot.imported-snapshot - id = "24ab2255-ca77-49ec-bc96-f469cec3affb" -} - -resource "hypercore_vm_snapshot_schedule" "testtf-schedule" { - name = "testtf-schedule-2" - rules = [ - { - name = "testtf-rule-1", - start_timestamp = "2023-02-01 00:00:00", - frequency = "FREQ=MINUTELY;INTERVAL=1", - local_retention_seconds = 300 - }, - { - name = "testtf-rule-2", - start_timestamp = "2023-02-01 00:00:00", - frequency = "FREQ=MINUTELY;INTERVAL=1", - local_retention_seconds = 300 - } - ] -} +resource "hypercore_vm_replication" "testtf-replication" { + vm_uuid = data.hypercore_vm.vm-repl.vms.0.uuid + label = "testtf-ana-create-replication" -resource "hypercore_vm" "testtf-ana-scheduled" { - group = "testtfxlab" - name = local.create_vm_name - description = "Testing terraform resources" - vcpu = 4 - memory = 4096 # MiB - snapshot_schedule_uuid = hypercore_vm_snapshot_schedule.testtf-schedule.id + connection_uuid = "6ab8c456-85af-4c97-8cb7-76246552b1e6" # remote connection UUID + enable = false # should this default to true like in the HC3 swagger docs or make it required either way (whether it's true or false)? - clone = { - meta_data = "" - source_vm_uuid = "" - user_data = "" + # I'm testing with replication localhost - added the connection to itself + # - become two vm_uuid's when searching by vm by name. One is replication so vm_uuid would change + # - when actually replicating (with two different clusters), this "ignore_changes" wouldn't be necessary + lifecycle { + ignore_changes = [vm_uuid] } - - depends_on = [ - hypercore_vm_snapshot_schedule.testtf-schedule # make sure the schedule was created first - ] } -output "testtf-ana-scheduled" { - value = hypercore_vm.testtf-ana-scheduled.snapshot_schedule_uuid -} +resource "hypercore_vm_replication" "testtf-replication-imported" { + vm_uuid = data.hypercore_vm.vm-repl-2.vms.0.uuid -resource "hypercore_vm_snapshot_schedule" "testtf-schedule-no-rules" { - name = "testtf-schedule-no-rules-3" -} + # enable = true -resource "hypercore_vm_snapshot_schedule" "testtf-schedule-imported" { - name = "testtf-existing-schedule" + # I'm testing with replication localhost - added the connection to itself + # - become two vm_uuid's when searching by vm by name. One is replication so vm_uuid would change + # - when actually replicating (with two different clusters), this "ignore_changes" wouldn't be necessary + lifecycle { + ignore_changes = [vm_uuid] + } } import { - to = hypercore_vm_snapshot_schedule.testtf-schedule-imported - id = "69b21f14-6bb6-4dd5-a6bc-6dec9bd59c96" + to = hypercore_vm_replication.testtf-replication-imported + id = "7eb23160-2c80-4519-b23d-b43fb3ca9da4" } From 453e817ba1ef2dffd77d1b9d28583346b7cfec86 Mon Sep 17 00:00:00 2001 From: Ana Zobec Date: Tue, 1 Apr 2025 12:33:55 +0200 Subject: [PATCH 2/2] Add hypercore_vm_replication docs --- docs/resources/vm_replication.md | 63 +++++++++++++++++++ .../hypercore_vm_replication/resource.tf | 29 +++++++++ 2 files changed, 92 insertions(+) create mode 100644 docs/resources/vm_replication.md create mode 100644 examples/resources/hypercore_vm_replication/resource.tf diff --git a/docs/resources/vm_replication.md b/docs/resources/vm_replication.md new file mode 100644 index 0000000..134a6a6 --- /dev/null +++ b/docs/resources/vm_replication.md @@ -0,0 +1,63 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "hypercore_vm_replication Resource - hypercore" +subcategory: "" +description: |- + Hypercore VM replication resource to manage VM boot devices' order +--- + +# hypercore_vm_replication (Resource) + +Hypercore VM replication resource to manage VM boot devices' order + +## Example Usage + +```terraform +locals { + vm_name = "example-vm" + another_vm_name = "example-vm-two" +} + +data "hypercore_vm" "example-vm" { + name = local.vm_name +} + +data "hypercore_vm" "example-vm-two" { + name = local.another_vm_name +} + +resource "hypercore_vm_replication" "example-replication" { + vm_uuid = data.hypercore_vm.vm-repl.vms.0.uuid + label = "my-example-replication" + + connection_uuid = "6ab8c456-85af-4c97-8cb7-76246552b1e6" # remote connection UUID + enable = false +} + +resource "hypercore_vm_replication" "example-replication-imported" { + vm_uuid = data.hypercore_vm.example-vm-two.vms.0.uuid +} + +import { + to = hypercore_vm_replication.example-replication-imported + id = "7eb23160-2c80-4519-b23d-b43fb3ca9da4" +} +``` + + +## Schema + +### Required + +- `vm_uuid` (String) VM UUID of which we want to make a replication + +### Optional + +- `connection_uuid` (String) Remote connection UUID +- `enable` (Boolean) Enable or disable replication +- `label` (String) Human-readable label describing the replication purpose + +### Read-Only + +- `id` (String) Replication identifier +- `target_vm_uuid` (String) Remote target VM UUID diff --git a/examples/resources/hypercore_vm_replication/resource.tf b/examples/resources/hypercore_vm_replication/resource.tf new file mode 100644 index 0000000..7d4ab77 --- /dev/null +++ b/examples/resources/hypercore_vm_replication/resource.tf @@ -0,0 +1,29 @@ +locals { + vm_name = "example-vm" + another_vm_name = "example-vm-two" +} + +data "hypercore_vm" "example-vm" { + name = local.vm_name +} + +data "hypercore_vm" "example-vm-two" { + name = local.another_vm_name +} + +resource "hypercore_vm_replication" "example-replication" { + vm_uuid = data.hypercore_vm.vm-repl.vms.0.uuid + label = "my-example-replication" + + connection_uuid = "6ab8c456-85af-4c97-8cb7-76246552b1e6" # remote connection UUID + enable = false +} + +resource "hypercore_vm_replication" "example-replication-imported" { + vm_uuid = data.hypercore_vm.example-vm-two.vms.0.uuid +} + +import { + to = hypercore_vm_replication.example-replication-imported + id = "7eb23160-2c80-4519-b23d-b43fb3ca9da4" +}