Commit e4ff65bc authored by Vitaly Lipatov's avatar Vitaly Lipatov

pve: add pve-clone.sh to clone VM/CT with safety checks

Allocates the next free VMID, defaults the target pool to Testing. For running LXC sources, takes a temporary snapshot, clones from it and removes the snapshot afterwards. Reminds the operator to set the new IP before starting the cloned container. Co-Authored-By: 's avatarClaude Opus 4.7 (1M context) <noreply@anthropic.com>
parent f39d03af
#!/bin/sh
# Clone VM or CT with safety checks
# Usage: pve-clone.sh VMID [--name NAME] [--pool POOL] [--full] [--node NODE]
set -e
MYDIR=$(dirname "$0")
. "$MYDIR/functions"
SRC_VMID=""
CLONE_NAME=""
CLONE_POOL="Testing"
FULL_CLONE=""
TARGET_NODE=""
while [ $# -gt 0 ] ; do
case "$1" in
--name) CLONE_NAME="$2" ; shift 2 ;;
--pool) CLONE_POOL="$2" ; shift 2 ;;
--full) FULL_CLONE=1 ; shift ;;
--node) TARGET_NODE="$2" ; shift 2 ;;
--help|-h)
echo "Usage: $(basename "$0") VMID [--name NAME] [--pool POOL] [--full] [--node NODE]"
echo ""
echo "Clone a VM or CT in the PVE cluster."
echo ""
echo "Options:"
echo " --name NAME Clone name (default: prompted as USER-BUGNUM-OS)"
echo " --pool POOL Target pool (default: Testing)"
echo " --full Full clone (default: linked for qemu, full for lxc)"
echo " --node NODE Target node (default: same as source)"
exit 0
;;
-*)
fatal "unknown option: $1"
;;
*)
SRC_VMID="$1" ; shift ;;
esac
done
if [ -z "$SRC_VMID" ] ; then
echo "Usage: $(basename "$0") VMID [--name NAME] [--pool POOL] [--full] [--node NODE]" >&2
exit 1
fi
resolve_vmid "$SRC_VMID"
mgr=$(vm_mgr)
log "Source: $RES_TYPE $SRC_VMID ($RES_NAME) on $RES_NODE [$RES_STATUS]"
# Prompt for name if not specified
if [ -z "$CLONE_NAME" ] ; then
printf "Clone name (USER-BUGNUM-OS): "
read CLONE_NAME
[ -n "$CLONE_NAME" ] || fatal "name is required"
fi
# Get next free VMID
NEW_VMID=$(pvesh_cmd "get /cluster/nextid") || fatal "cannot get next free VMID"
# pvesh may return quoted value
NEW_VMID=$(echo "$NEW_VMID" | tr -d '"')
log "New VMID: $NEW_VMID"
# Target node
if [ -z "$TARGET_NODE" ] ; then
TARGET_NODE="$RES_NODE"
fi
# LXC always needs full clone
if [ "$RES_TYPE" = "lxc" ] ; then
FULL_CLONE=1
fi
# Safety: running LXC — snapshot first, clone from snapshot, cleanup
SNAP_NAME=""
if [ "$RES_TYPE" = "lxc" ] && [ "$RES_STATUS" = "running" ] ; then
SNAP_NAME="clone-snap-$$"
log "Source LXC is running — creating snapshot '$SNAP_NAME' ..."
vm_cmd pct snapshot "$SRC_VMID" "$SNAP_NAME"
fi
# Build clone command
clone_args="$SRC_VMID $NEW_VMID --name $CLONE_NAME --pool $CLONE_POOL --target $TARGET_NODE"
if [ -n "$FULL_CLONE" ] ; then
clone_args="$clone_args --full"
fi
if [ -n "$SNAP_NAME" ] ; then
clone_args="$clone_args --snapname $SNAP_NAME"
fi
log "Cloning ..."
vm_cmd "$mgr" clone $clone_args
# Cleanup snapshot if we created one
if [ -n "$SNAP_NAME" ] ; then
log "Cleaning up snapshot '$SNAP_NAME' ..."
vm_cmd pct delsnapshot "$SRC_VMID" "$SNAP_NAME" || log "WARNING: snapshot cleanup failed"
fi
log "Cloned $RES_TYPE $SRC_VMID -> $NEW_VMID ($CLONE_NAME) on $TARGET_NODE, pool $CLONE_POOL"
# Safety reminder for LXC
if [ "$RES_TYPE" = "lxc" ] ; then
echo ""
echo "*** IMPORTANT: Set IP address before starting the container! ***"
echo " ssh root@$TARGET_NODE \"pct set $NEW_VMID --net0 name=eth0,bridge=vmbr0,ip=NEW_IP/MASK,gw=GATEWAY\""
echo ""
fi
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment