XCP-ng
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Register
    • Login
    1. Home
    2. RaHu
    3. Best
    R
    Offline
    • Profile
    • Following 0
    • Followers 0
    • Topics 2
    • Posts 9
    • Groups 0

    Posts

    Recent Best Controversial
    • RE: Delete VM Snapshot over REST

      @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 0
      

      Cheers!

      posted in REST API
      R
      RaHu
    • RE: Host/Guest Console Scrolling

      @olivierlambert

      Hi there

      I also have this issue. Neither in XCP-NG-Center nor in XO I am able to use Shift + PgUp to scroll upwards. (Just nothing happens)
      I tested it with Ubuntu 18, 20 and also with Rocky 9.1 VMs.

      Is there a way to activate it?

      Many thanks,
      Cheers

      posted in Xen Orchestra
      R
      RaHu