Delete VM Snapshot over REST
-
Hi Community
I was able to create a bash script that uses the local machines uuid (from bios) in order to trigger a snapshot creation (of the vm itself) over xo rest api.
Now, I would like to do some very basic kind of retention. I want my script to get all snapshots of the same VM and remove older snapshots that exceed a limit provided over command line. Otherwise, you'd have to care manually about removing older snapshots.
However, I was unable to find a how to for deleting a snapshot over rest. Is this not possible yet?
Thanks,
Rainer -
Let me ask to @lsouai-vates

-
Hello @RaHu !
I am asking the XO team and keep you in touch
-
@RaHu you can take a look there: https://github.com/vatesfr/xen-orchestra/blob/master/packages/xo-server/docs/rest-api.md#vm-destruction
curl \ -X DELETE \ -b authenticationToken=KQxQdm2vMiv7jBIK0hgkmgxKzemd8wSJ7ugFGKFkTbs \ 'https://xo.company.lan/rest/v0/vms/770aa52a-fd42-8faf-f167-8c5c4a237cac'Hope it will help you

-
Thanks! Will try it out!
//update: but if I see this correctly, this would delete the whole vm, not a snapshot - or is this just an example that could be applied to https://xo.company.lan/rest/v0/vm-snapshots/uuid ?
-
@RaHu Your are correct. To delete an individual snapshot, change
/vms/to/vm-snapshots/. -
@Danp Thanks! Finally I was able to get my script working. Also some contribution to "GROK" who assisted quite well!

It allows a VM to Snapshot itself, before running automated maintenance over cron. And it allows minimalistic retention of the snapshots created this way.
Happy to share it with the community:
#!/bin/bash : <<'END' Snapshot Management Script for Xen Orchestra Usage: ./snapshot-vm.sh [OPTIONS] Options: -v Enable verbose output (detailed logging) -s Silent mode (suppress all non-error output) -r <number> Set retention limit (delete oldest snapshots beyond this number) -n No-snapshot mode (skip snapshot creation, only manage retention) Examples: ./snapshot-vm.sh # Create a snapshot, no retention ./snapshot-vm.sh -v -r 3 # Create a snapshot, keep latest 3, verbose ./snapshot-vm.sh -r 5 -n # Skip snapshot, keep latest 5 ./snapshot-vm.sh -v -s -r 2 # Create a snapshot, keep latest 2, verbose but silent Configuration: Edit XO_URL, TOKEN, and SNAPSHOT_PREFIX at the top of the script. END # Configuration variables XO_URL="http://your-xen-orchestra-server" TOKEN="your-authentication-token" VM_UUID=$(dmidecode -s system-uuid | tr '[:upper:]' '[:lower:]') SNAPSHOT_PREFIX="AutoMaintenance" # Prefix for snapshot names # Default retention (no deletion if not specified) RETENTION=-1 # Flags VERBOSE=0 SILENT=0 NOSNAPSHOT=0 # Parse command-line options while getopts "vsr:n" opt; do case $opt in v) VERBOSE=1;; s) SILENT=1;; r) RETENTION="$OPTARG";; n) NOSNAPSHOT=1;; esac done # Function to print messages based on mode print_msg() { if [ $SILENT -eq 0 ]; then if [ $VERBOSE -eq 1 ]; then echo "$1" else echo -e "$1" fi fi } # Check if we got the UUID if [ -z "$VM_UUID" ]; then echo "Error: Could not retrieve system UUID" exit 1 fi # Function to check if jq is installed check_jq() { if ! command -v jq &> /dev/null; then echo "Error: jq is required but not installed" exit 1 fi } # Function to get VM name get_vm_name() { local vm_info=$(curl -s -X GET \ -b "authenticationToken=$TOKEN" \ -H "Accept: application/json" \ "$XO_URL/rest/v0/vms/$VM_UUID") vm_name=$(echo "$vm_info" | jq -r '.name_label // "Unknown"') } # Function to trigger snapshot trigger_snapshot() { local SNAPSHOT_NAME="${SNAPSHOT_PREFIX}-$(date +%Y%m%d-%H%M%S)" if [ $VERBOSE -eq 1 ]; then local curl_cmd="curl -s -X POST \ -b \"authenticationToken=$TOKEN\" \ -H \"Content-Type: application/json\" \ -H \"Accept: application/json\" \ -d '{\"name_label\": \"$SNAPSHOT_NAME\"}' \ \"$XO_URL/rest/v0/vms/$VM_UUID/actions/snapshot\"" print_msg "Executing snapshot trigger command:" print_msg "$curl_cmd" print_msg "-----" fi response=$(curl -s -X POST \ -b "authenticationToken=$TOKEN" \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ -d "{\"name_label\": \"$SNAPSHOT_NAME\"}" \ "$XO_URL/rest/v0/vms/$VM_UUID/actions/snapshot") if [ $VERBOSE -eq 1 ]; then print_msg "Snapshot trigger response: $response" print_msg "-----" fi if [[ "$response" =~ /rest/v0/tasks/([a-z0-9]+) ]]; then task_id="${BASH_REMATCH[1]}" if [ $VERBOSE -eq 1 ]; then print_msg "Snapshot triggered (Task ID: $task_id)" fi return 0 elif [[ "$response" =~ ^[a-z0-9]+$ ]]; then task_id="$response" if [ $VERBOSE -eq 1 ]; then print_msg "Snapshot triggered (Task ID: $task_id)" fi return 0 else print_msg "Error: Failed to get task ID. Response: $response" exit 1 fi } # Function to monitor task status monitor_task() { local task_id=$1 local max_attempts=30 local attempt=1 if [ $VERBOSE -eq 1 ]; then print_msg "Monitoring task $task_id..." fi while [ $attempt -le $max_attempts ]; do status_response=$(curl -s -X GET \ -b "authenticationToken=$TOKEN" \ -H "Accept: application/json" \ "$XO_URL/rest/v0/tasks/$task_id") if [ $VERBOSE -eq 1 ]; then print_msg "Attempt $attempt - Raw response: $status_response" fi if [ -n "$status_response" ] && echo "$status_response" | jq -e . >/dev/null 2>&1; then status=$(echo "$status_response" | jq -r '.status') if [ $VERBOSE -eq 1 ]; then print_msg "Status: $status" else print_msg "Taking Snapshot of VM: $vm_name... Status: $status" fi case "$status" in "pending"|"running") if [ $VERBOSE -eq 1 ]; then print_msg "Task still in progress" fi sleep 5 ((attempt++)) ;; "success") if [ $VERBOSE -eq 1 ]; then print_msg "Snapshot completed successfully" else print_msg "Taking Snapshot of VM: $vm_name... Status: Completed" fi return 0 ;; "failure") error=$(echo "$status_response" | jq -r '.result.message // "Unknown error"') print_msg "Task failed: $error" exit 1 ;; *) if [ $VERBOSE -eq 1 ]; then print_msg "Unknown status: $status" fi sleep 5 ((attempt++)) ;; esac else if [ $VERBOSE -eq 1 ]; then print_msg "Invalid or empty response" fi sleep 5 ((attempt++)) fi done print_msg "Timeout waiting for task completion" exit 1 } # Function to manage snapshot retention manage_retention() { if [ $RETENTION -lt 0 ]; then print_msg "Retention not specified, skipping cleanup" return 0 fi # Get VM data with snapshot UUIDs vm_data=$(curl -s -X GET \ -b "authenticationToken=$TOKEN" \ -H "Accept: application/json" \ "$XO_URL/rest/v0/vms/$VM_UUID") if [ $VERBOSE -eq 1 ]; then print_msg "Raw VM data response: $vm_data" print_msg "-----" fi if ! echo "$vm_data" | jq -e . >/dev/null 2>&1; then print_msg "Error: Invalid JSON response from VM endpoint" print_msg "Response: $vm_data" exit 1 fi # Extract snapshot UUIDs snapshot_uuids=$(echo "$vm_data" | jq -r '.snapshots[]') # Fetch details for each snapshot, verify existence, and filter by prefix auto_snapshots="" for uuid in $snapshot_uuids; do # Check existence with a HEAD request to avoid full body download http_status=$(curl -s -o /dev/null -w "%{http_code}" -I \ -b "authenticationToken=$TOKEN" \ "$XO_URL/rest/v0/vm-snapshots/$uuid") if [ "$http_status" -eq 404 ]; then if [ $VERBOSE -eq 1 ]; then print_msg "Snapshot $uuid does not exist (HTTP 404), skipping" print_msg "-----" fi continue elif [ "$http_status" -ne 200 ]; then if [ $VERBOSE -eq 1 ]; then print_msg "Unexpected HTTP status $http_status for snapshot $uuid, skipping" print_msg "-----" fi continue fi # Fetch full snapshot data if it exists snapshot_data=$(curl -s -X GET \ -b "authenticationToken=$TOKEN" \ -H "Accept: application/json" \ "$XO_URL/rest/v0/vm-snapshots/$uuid") if [ $VERBOSE -eq 1 ]; then print_msg "Snapshot $uuid data: $snapshot_data" print_msg "-----" fi # Verify itβs a valid JSON response if ! echo "$snapshot_data" | jq -e . >/dev/null 2>&1; then print_msg "Error: Invalid JSON response for snapshot $uuid" print_msg "Response: $snapshot_data" continue fi # Filter for snapshots with the specified prefix if echo "$snapshot_data" | jq -e ".name_label | startswith(\"$SNAPSHOT_PREFIX\")" >/dev/null 2>&1; then snapshot_line=$(echo "$snapshot_data" | jq -r '[.id, .name_label, .snapshot_time] | join("\t")') auto_snapshots="$auto_snapshots$snapshot_line\n" fi done # Sort by snapshot_time auto_snapshots=$(echo -e "$auto_snapshots" | sort -k3 -n | grep -v '^$') if [ $VERBOSE -eq 1 ]; then print_msg "Filtered and sorted $SNAPSHOT_PREFIX snapshots:" print_msg "$auto_snapshots" print_msg "-----" fi # Count current snapshots snapshot_count=$(echo "$auto_snapshots" | wc -l) print_msg "Current $SNAPSHOT_PREFIX snapshot count: $snapshot_count" # If over retention limit, delete oldest if [ $snapshot_count -gt $RETENTION ]; then excess=$((snapshot_count - RETENTION)) print_msg "Excess snapshots to delete: $excess" # Get IDs of oldest snapshots to delete delete_ids=$(echo "$auto_snapshots" | head -n $excess | cut -f1) for id in $delete_ids; do if [ $VERBOSE -eq 1 ]; then print_msg "Deleting snapshot $id" print_msg "Delete command: curl -s -X DELETE -b \"authenticationToken=$TOKEN\" \"$XO_URL/rest/v0/vm-snapshots/$id\"" fi delete_response=$(curl -s -X DELETE \ -b "authenticationToken=$TOKEN" \ "$XO_URL/rest/v0/vm-snapshots/$id") if [ $VERBOSE -eq 1 ]; then print_msg "Delete response: $delete_response" print_msg "-----" fi # Treat empty response, {"status": "success"}, or "OK" as success if [ -z "$delete_response" ] || echo "$delete_response" | jq -e '.status == "success"' >/dev/null 2>&1 || [ "$delete_response" = "OK" ]; then print_msg "Successfully deleted snapshot $id" else print_msg "Warning: Failed to delete snapshot $id. Response: $delete_response" fi done else if [ $VERBOSE -eq 1 ]; then print_msg "No excess snapshots to delete" fi fi } # Main execution check_jq get_vm_name if [ $VERBOSE -eq 1 ]; then print_msg "Using VM UUID: $VM_UUID" fi if [ $NOSNAPSHOT -eq 0 ]; then trigger_snapshot monitor_task "$task_id" else if [ $VERBOSE -eq 1 ]; then print_msg "Skipping snapshot creation due to --nosnapshot flag" fi fi manage_retention exit 0Cheers!
-
O olivierlambert marked this topic as a question on
-
O olivierlambert has marked this topic as solved on
Hello! It looks like you're interested in this conversation, but you don't have an account yet.
Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.
With your input, this post could be even better π
Register Login