From 73cfb13cf609eafd021974eca9019cd455356588 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Martin Date: Thu, 7 Nov 2024 23:12:33 +0100 Subject: [PATCH] feature: possibility to clone vm based on id --- docs/resources/vm_qemu.md | 3 ++- proxmox/resource_vm_qemu.go | 40 +++++++++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/docs/resources/vm_qemu.md b/docs/resources/vm_qemu.md index 96ac1346..24571a23 100644 --- a/docs/resources/vm_qemu.md +++ b/docs/resources/vm_qemu.md @@ -107,7 +107,8 @@ The following arguments are supported in the top level resource block. | `bootdisk` | `str` | | Enable booting from specified disk. You shouldn't need to change it under most circumstances. | | `agent` | `int` | `0` | Set to `1` to enable the QEMU Guest Agent. Note, you must run the [`qemu-guest-agent`](https://pve.proxmox.com/wiki/Qemu-guest-agent) daemon in the guest for this to have any effect. | | `pxe` | `bool` | `false` | If set to `true`, enable PXE boot of the VM. Also requires a `boot` order be set with Network included (eg `boot = "order=scsi0;net0"`). Note that `pxe` is mutually exclusive with `clone` modes. | -| `clone` | `str` | | The base VM from which to clone to create the new VM. Note that `clone` is mutually exclusive with `pxe` modes. | +| `clone` | `str` | | The base VM name from which to clone to create the new VM. Note that `clone` is mutually exclusive with `clone_id` and `pxe` modes. | +| `clone_id` | `int` | | The base VM id from which to clone to create the new VM. Note that `clone_id` is mutually exclusive with `clone` and `pxe` modes. | | `full_clone` | `bool` | `true` | Set to `true` to create a full clone, or `false` to create a linked clone. See the [docs about cloning](https://pve.proxmox.com/pve-docs/chapter-qm.html#qm_copy_and_clone) for more info. Only applies when `clone` is set. | | `hastate` | `str` | | Requested HA state for the resource. One of "started", "stopped", "enabled", "disabled", or "ignored". See the [docs about HA](https://pve.proxmox.com/pve-docs/chapter-ha-manager.html#ha_manager_resource_config) for more info. | | `hagroup` | `str` | | The HA group identifier the resource belongs to (requires `hastate` to be set!). See the [docs about HA](https://pve.proxmox.com/pve-docs/chapter-ha-manager.html#ha_manager_resource_config) for more info. | diff --git a/proxmox/resource_vm_qemu.go b/proxmox/resource_vm_qemu.go index 6ccad17d..243f3f36 100755 --- a/proxmox/resource_vm_qemu.go +++ b/proxmox/resource_vm_qemu.go @@ -4,6 +4,7 @@ import ( "context" "encoding/base64" "encoding/json" + "errors" "fmt" "log" "math/rand" @@ -208,6 +209,12 @@ func resourceVmQemu() *schema.Resource { ForceNew: true, ConflictsWith: []string{"pxe"}, }, + "clone_id": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"clone", "pxe"}, + }, "full_clone": { Type: schema.TypeBool, Optional: true, @@ -869,6 +876,27 @@ func resourceVmQemu() *schema.Resource { return thisResource } +func getSourceVmr(client *pxapi.Client, name string, id int, targetNode string) (*pxapi.VmRef, error) { + if name != "" { + sourceVmrs, err := client.GetVmRefsByName(name) + if err != nil { + return nil, err + } + // Prefer source VM on the same node + sourceVmr := sourceVmrs[0] + for _, candVmr := range sourceVmrs { + if candVmr.Node() == targetNode { + sourceVmr = candVmr + } + } + return sourceVmr, nil + } else if id != 0 { + return client.GetVmRefById(id) + } + + return nil, errors.New("either 'clone' name or 'clone_id' must be specified") +} + func resourceVmQemuCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { // create a logger for this function logger, _ := CreateSubLogger("resource_vm_create") @@ -997,26 +1025,18 @@ func resourceVmQemuCreate(ctx context.Context, d *schema.ResourceData, meta inte vmr.SetPool(d.Get("pool").(string)) // check if clone, or PXE boot - if d.Get("clone").(string) != "" { + if d.Get("clone").(string) != "" || d.Get("clone_id").(int) != 0 { fullClone := 1 if !d.Get("full_clone").(bool) { fullClone = 0 } config.FullClone = &fullClone - sourceVmrs, err := client.GetVmRefsByName(d.Get("clone").(string)) + sourceVmr, err := getSourceVmr(client, d.Get("clone").(string), d.Get("clone_id").(int), vmr.Node()) if err != nil { return append(diags, diag.FromErr(err)...) } - // prefer source Vm located on same node - sourceVmr := sourceVmrs[0] - for _, candVmr := range sourceVmrs { - if candVmr.Node() == vmr.Node() { - sourceVmr = candVmr - } - } - log.Print("[DEBUG][QemuVmCreate] cloning VM") logger.Debug().Str("vmid", d.Id()).Msgf("Cloning VM") err = config.CloneVm(sourceVmr, vmr, client)