mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	* NAS B&R Plugin enhancements * Prevent printing mount opts which may include password by removing from response * revert marvin change * add sanity checks to validate minimum qemu and libvirt versions * check is user running script is part of libvirt group * revert changes of retore expunged VM * add code coverage ignore file * remove check * issue with listing schedules and add defensive checks * redirect logs to agent log file * add some more debugging * remove test file * prevent deletion of cks cluster when vms associated to a backup offering * delete all snapshot policies when bkp offering is disassociated from a VM * Fix `updateTemplatePermission` when the UI is set to a language other than English (#9766) * Fix updateTemplatePermission UI in non-english language * Improve fix --------- * Add nobrl in the mountopts for cifs file system * Fix restoration of VM / volumes with cifs * add cifs utils for el8 * add cifs-utils for ubuntu cloudstack-agent * syntax error * remove required constraint on both vmid and id params for the delete bkp schedule command
		
			
				
	
	
		
			234 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			234 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/bash
 | |
| ## Licensed to the Apache Software Foundation (ASF) under one
 | |
| ## or more contributor license agreements.  See the NOTICE file
 | |
| ## distributed with this work for additional information
 | |
| ## regarding copyright ownership.  The ASF licenses this file
 | |
| ## to you under the Apache License, Version 2.0 (the
 | |
| ## "License"); you may not use this file except in compliance
 | |
| ## with the License.  You may obtain a copy of the License at
 | |
| ##
 | |
| ##   http://www.apache.org/licenses/LICENSE-2.0
 | |
| ##
 | |
| ## Unless required by applicable law or agreed to in writing,
 | |
| ## software distributed under the License is distributed on an
 | |
| ## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | |
| ## KIND, either express or implied.  See the License for the
 | |
| ## specific language governing permissions and limitations
 | |
| ## under the License.
 | |
| 
 | |
| set -e
 | |
| 
 | |
| # CloudStack B&R NAS Backup and Recovery Tool for KVM
 | |
| 
 | |
| # TODO: do libvirt/logging etc checks
 | |
| 
 | |
| ### Declare variables ###
 | |
| 
 | |
| OP=""
 | |
| VM=""
 | |
| NAS_TYPE=""
 | |
| NAS_ADDRESS=""
 | |
| MOUNT_OPTS=""
 | |
| BACKUP_DIR=""
 | |
| DISK_PATHS=""
 | |
| logFile="/var/log/cloudstack/agent/agent.log"
 | |
| 
 | |
| log() {
 | |
|   [[ "$verb" -eq 1 ]] && builtin echo "$@"
 | |
|   if [[ "$1" == "-ne"  || "$1" == "-e" || "$1" == "-n" ]]; then
 | |
|     builtin echo -e "$(date '+%Y-%m-%d %H-%M-%S>')" "${@: 2}" >> "$logFile"
 | |
|   else
 | |
|     builtin echo "$(date '+%Y-%m-%d %H-%M-%S>')" "$@" >> "$logFile"
 | |
|   fi
 | |
| }
 | |
| 
 | |
| vercomp() {
 | |
|   local IFS=.
 | |
|   local i ver1=($1) ver2=($3)
 | |
| 
 | |
|   # Compare each segment of the version numbers
 | |
|   for ((i=0; i<${#ver1[@]}; i++)); do
 | |
|       if [[ -z ${ver2[i]} ]]; then
 | |
|           ver2[i]=0
 | |
|       fi
 | |
| 
 | |
|       if ((10#${ver1[i]} > 10#${ver2[i]})); then
 | |
|           return  0 # Version 1 is greater
 | |
|       elif ((10#${ver1[i]} < 10#${ver2[i]})); then
 | |
|           return 2  # Version 2 is greater
 | |
|       fi
 | |
|   done
 | |
|   return 0  # Versions are equal
 | |
| }
 | |
| 
 | |
| sanity_checks() {
 | |
|   hvVersion=$(virsh version | grep hypervisor | awk '{print $(NF)}')
 | |
|   libvVersion=$(virsh version | grep libvirt | awk '{print $(NF)}' | tail -n 1)
 | |
|   apiVersion=$(virsh version | grep API | awk '{print $(NF)}')
 | |
| 
 | |
|   # Compare qemu version (hvVersion >= 4.2.0)
 | |
|   vercomp "$hvVersion" ">=" "4.2.0"
 | |
|   hvStatus=$?
 | |
| 
 | |
|   # Compare libvirt version (libvVersion >= 7.2.0)
 | |
|   vercomp "$libvVersion" ">=" "7.2.0"
 | |
|   libvStatus=$?
 | |
| 
 | |
|   if [[ $hvStatus -eq 0 && $libvStatus -eq 0 ]]; then
 | |
|     log -ne "Success... [ QEMU: $hvVersion Libvirt: $libvVersion apiVersion: $apiVersion ]"
 | |
|   else
 | |
|     echo "Failure... Your QEMU version $hvVersion or libvirt version $libvVersion is unsupported. Consider upgrading to the required minimum version of QEMU: 4.2.0 and Libvirt: 7.2.0"
 | |
|     exit 1
 | |
|   fi
 | |
| 
 | |
|   log -ne "Environment Sanity Checks successfully passed"
 | |
| }
 | |
| 
 | |
| ### Operation methods ###
 | |
| 
 | |
| backup_running_vm() {
 | |
|   mount_operation
 | |
|   mkdir -p $dest
 | |
| 
 | |
|   name="root"
 | |
|   echo "<domainbackup mode='push'><disks>" > $dest/backup.xml
 | |
|   for disk in $(virsh -c qemu:///system domblklist $VM --details 2>/dev/null | awk '/disk/{print$3}'); do
 | |
|     volpath=$(virsh -c qemu:///system domblklist $VM --details | awk "/$disk/{print $4}" | sed 's/.*\///')
 | |
|     echo "<disk name='$disk' backup='yes' type='file' backupmode='full'><driver type='qcow2'/><target file='$dest/$name.$volpath.qcow2' /></disk>" >> $dest/backup.xml
 | |
|     name="datadisk"
 | |
|   done
 | |
|   echo "</disks></domainbackup>" >> $dest/backup.xml
 | |
| 
 | |
|   # Start push backup
 | |
|   virsh -c qemu:///system backup-begin --domain $VM --backupxml $dest/backup.xml > /dev/null 2>/dev/null
 | |
| 
 | |
|   # Backup domain information
 | |
|   virsh -c qemu:///system dumpxml $VM > $dest/domain-config.xml 2>/dev/null
 | |
|   virsh -c qemu:///system dominfo $VM > $dest/dominfo.xml 2>/dev/null
 | |
|   virsh -c qemu:///system domiflist $VM > $dest/domiflist.xml 2>/dev/null
 | |
|   virsh -c qemu:///system domblklist $VM > $dest/domblklist.xml 2>/dev/null
 | |
| 
 | |
|   until virsh -c qemu:///system domjobinfo $VM --completed --keep-completed 2>/dev/null | grep "Completed" > /dev/null; do
 | |
|     sleep 5
 | |
|   done
 | |
|   rm -f $dest/backup.xml
 | |
|   sync
 | |
| 
 | |
|   # Print statistics
 | |
|   virsh -c qemu:///system domjobinfo $VM --completed
 | |
|   du -sb $dest | cut -f1
 | |
| 
 | |
|   umount $mount_point
 | |
|   rmdir $mount_point
 | |
| }
 | |
| 
 | |
| backup_stopped_vm() {
 | |
|   mount_operation
 | |
|   mkdir -p $dest
 | |
| 
 | |
|   IFS=","
 | |
| 
 | |
|   name="root"
 | |
|   for disk in $DISK_PATHS; do
 | |
|     volUuid="${disk##*/}"
 | |
|     qemu-img convert -O qcow2 $disk $dest/$name.$volUuid.qcow2  | tee -a "$logFile"
 | |
|     name="datadisk"
 | |
|   done
 | |
|   sync
 | |
| 
 | |
|   ls -l --numeric-uid-gid $dest | awk '{print $5}'
 | |
| }
 | |
| 
 | |
| delete_backup() {
 | |
|   mount_operation
 | |
| 
 | |
|   rm -frv $dest
 | |
|   sync
 | |
|   umount $mount_point
 | |
|   rmdir $mount_point
 | |
| }
 | |
| 
 | |
| mount_operation() {
 | |
|   mount_point=$(mktemp -d -t csbackup.XXXXX)
 | |
|   dest="$mount_point/${BACKUP_DIR}"
 | |
|   if [ ${NAS_TYPE} == "cifs" ]; then
 | |
|     MOUNT_OPTS="${MOUNT_OPTS},nobrl"
 | |
|   fi
 | |
|   mount -t ${NAS_TYPE} ${NAS_ADDRESS} ${mount_point} $([[ ! -z "${MOUNT_OPTS}" ]] && echo -o ${MOUNT_OPTS}) | tee -a "$logFile"
 | |
|   if [ $? -eq 0 ]; then
 | |
|       log -ne "Successfully mounted ${NAS_TYPE} store"
 | |
|   else
 | |
|       echo "Failed to mount ${NAS_TYPE} store"
 | |
|       exit 1
 | |
|   fi
 | |
| }
 | |
| 
 | |
| function usage {
 | |
|   echo ""
 | |
|   echo "Usage: $0 -o <operation> -v|--vm <domain name> -t <storage type> -s <storage address> -m <mount options> -p <backup path> -d <disks path>"
 | |
|   echo ""
 | |
|   exit 1
 | |
| }
 | |
| 
 | |
| while [[ $# -gt 0 ]]; do
 | |
|   case $1 in
 | |
|     -o|--operation)
 | |
|       OP="$2"
 | |
|       shift
 | |
|       shift
 | |
|       ;;
 | |
|     -v|--vm)
 | |
|       VM="$2"
 | |
|       shift
 | |
|       shift
 | |
|       ;;
 | |
|     -t|--type)
 | |
|       NAS_TYPE="$2"
 | |
|       shift
 | |
|       shift
 | |
|       ;;
 | |
|     -s|--storage)
 | |
|       NAS_ADDRESS="$2"
 | |
|       shift
 | |
|       shift
 | |
|       ;;
 | |
|     -m|--mount)
 | |
|       MOUNT_OPTS="$2"
 | |
|       shift
 | |
|       shift
 | |
|       ;;
 | |
|     -p|--path)
 | |
|       BACKUP_DIR="$2"
 | |
|       shift
 | |
|       shift
 | |
|       ;;
 | |
|     -d|--diskpaths)
 | |
|       DISK_PATHS="$2"
 | |
|       shift
 | |
|       shift
 | |
|       ;;
 | |
|     -h|--help)
 | |
|       usage
 | |
|       shift
 | |
|       ;;
 | |
|     *)
 | |
|       echo "Invalid option: $1"
 | |
|       usage
 | |
|       ;;
 | |
|   esac
 | |
| done
 | |
| 
 | |
| # Perform Initial sanity checks
 | |
| sanity_checks
 | |
| 
 | |
| if [ "$OP" = "backup" ]; then
 | |
|   STATE=$(virsh -c qemu:///system list | grep $VM | awk '{print $3}')
 | |
|   if [ "$STATE" = "running" ]; then
 | |
|     backup_running_vm
 | |
|   else
 | |
|     backup_stopped_vm
 | |
|   fi
 | |
| elif [ "$OP" = "delete" ]; then
 | |
|   delete_backup
 | |
| fi
 |