mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1005 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1005 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/python
 | |
| #
 | |
| # A plugin for executing script needed by vmops cloud 
 | |
| 
 | |
| import os, sys, time
 | |
| import XenAPIPlugin
 | |
| sys.path.append("/opt/xensource/sm/")
 | |
| import SR, VDI, SRCommand, util, lvutil
 | |
| from util import CommandException
 | |
| import vhdutil
 | |
| import shutil
 | |
| import lvhdutil
 | |
| import subprocess
 | |
| from lvmcache import LVMCache
 | |
| from journaler import Journaler
 | |
| from lock import Lock
 | |
| import errno
 | |
| import subprocess
 | |
| import xs_errors
 | |
| import cleanup
 | |
| import hostvmstats
 | |
| import socket
 | |
| import stat
 | |
| import random
 | |
| import tempfile
 | |
| 
 | |
| VHD_UTIL = '/usr/sbin/vhd-util'
 | |
| VHD_PREFIX = 'VHD-'
 | |
| 
 | |
| def echo(fn):
 | |
|     def wrapped(*v, **k):
 | |
|         name = fn.__name__
 | |
|         util.SMlog("#### VMOPS enter  %s ####" % name )
 | |
|         res = fn(*v, **k)
 | |
|         util.SMlog("#### VMOPS exit  %s ####" % name )
 | |
|         return res
 | |
|     return wrapped
 | |
| 
 | |
| 
 | |
| @echo
 | |
| def create_secondary_storage_folder(session, args):
 | |
|     local_mount_path = None
 | |
| 
 | |
|     util.SMlog("create_secondary_storage_folder, args: " + str(args))
 | |
| 
 | |
|     try:
 | |
|         try:
 | |
|             # Mount the remote resource folder locally
 | |
|             remote_mount_path = args["remoteMountPath"]
 | |
|             local_mount_path = os.path.join(SR.MOUNT_BASE, "mount" + str(int(random.random() * 1000000)))
 | |
|             mount(remote_mount_path, local_mount_path)
 | |
| 
 | |
|             # Create the new folder
 | |
|             new_folder = local_mount_path + "/" + args["newFolder"]
 | |
|             if not os.path.isdir(new_folder):
 | |
|                 current_umask = os.umask(0)
 | |
|                 os.makedirs(new_folder)
 | |
|                 os.umask(current_umask)
 | |
|         except OSError, (errno, strerror):
 | |
|             errMsg = "create_secondary_storage_folder failed: errno: " + str(errno) + ", strerr: " + strerror
 | |
|             util.SMlog(errMsg)
 | |
|             raise xs_errors.XenError(errMsg)
 | |
|         except:
 | |
|             errMsg = "create_secondary_storage_folder failed."
 | |
|             util.SMlog(errMsg)
 | |
|             raise xs_errors.XenError(errMsg)
 | |
|     finally:
 | |
|         if local_mount_path != None:
 | |
|             # Unmount the local folder
 | |
|             umount(local_mount_path)
 | |
|             # Remove the local folder
 | |
|             os.system("rm -rf " + local_mount_path)
 | |
|         
 | |
|     return "1"
 | |
| 
 | |
| @echo
 | |
| def delete_secondary_storage_folder(session, args):
 | |
|     local_mount_path = None
 | |
| 
 | |
|     util.SMlog("delete_secondary_storage_folder, args: " + str(args))
 | |
| 
 | |
|     try:
 | |
|         try:
 | |
|             # Mount the remote resource folder locally
 | |
|             remote_mount_path = args["remoteMountPath"]
 | |
|             local_mount_path = os.path.join(SR.MOUNT_BASE, "mount" + str(int(random.random() * 1000000)))
 | |
|             mount(remote_mount_path, local_mount_path)
 | |
| 
 | |
|             # Delete the specified folder
 | |
|             folder = local_mount_path + "/" + args["folder"]
 | |
|             if os.path.isdir(folder):
 | |
|                 os.system("rm -rf " + folder)
 | |
|         except OSError, (errno, strerror):
 | |
|             errMsg = "delete_secondary_storage_folder failed: errno: " + str(errno) + ", strerr: " + strerror
 | |
|             util.SMlog(errMsg)
 | |
|             raise xs_errors.XenError(errMsg)
 | |
|         except:
 | |
|             errMsg = "delete_secondary_storage_folder failed."
 | |
|             util.SMlog(errMsg)
 | |
|             raise xs_errors.XenError(errMsg)
 | |
|     finally:
 | |
|         if local_mount_path != None:
 | |
|             # Unmount the local folder
 | |
|             umount(local_mount_path)
 | |
|             # Remove the local folder
 | |
|             os.system("rm -rf " + local_mount_path)
 | |
|         
 | |
|     return "1"
 | |
|     
 | |
| @echo
 | |
| def execute_script(session, args):
 | |
|     return ""
 | |
|     
 | |
| @echo
 | |
| def post_create_private_template(session, args):
 | |
|     local_mount_path = None
 | |
| 
 | |
|     try:
 | |
|         try:
 | |
|             # Mount the remote templates folder locally
 | |
|             remote_mount_path = args["remoteTemplateMountPath"]
 | |
|             local_mount_path = os.path.join(SR.MOUNT_BASE, "template" + str(int(random.random() * 10000)))
 | |
|             mount(remote_mount_path, local_mount_path)
 | |
|             util.SMlog("Mounted secondary storage template folder")
 | |
| 
 | |
|             # Retrieve args
 | |
|             filename = args["templateFilename"]
 | |
|             name = args["templateName"]
 | |
|             description = args["templateDescription"]
 | |
|             checksum = args["checksum"]
 | |
|             virtual_size = args["virtualSize"]
 | |
|             template_id = args["templateId"]
 | |
|             
 | |
|             # Determine the template size
 | |
|             template_download_folder = local_mount_path + "/" + args["templateDownloadFolder"]
 | |
|             template_download_path = template_download_folder + filename
 | |
|             file_size = os.path.getsize(template_download_path)
 | |
|             util.SMlog("Got template file_size: " + str(file_size))
 | |
| 
 | |
|             # Create the template.properties file
 | |
|             template_properties_download_path = template_download_folder + "template.properties"
 | |
|             f = open(template_properties_download_path, "w")
 | |
|             f.write("filename=" + filename + "\n")
 | |
|             f.write("name=" + filename + "\n")
 | |
|             f.write("vhd=true\n")
 | |
|             f.write("id=" + template_id + "\n")
 | |
|             f.write("vhd.filename=" + filename + "\n")
 | |
|             f.write("uniquename=" + name + "\n")
 | |
|             f.write("vhd.virtualsize=" + virtual_size + "\n")
 | |
|             f.write("vhd.size=" + str(file_size) + "\n")
 | |
|             f.write("virtualsize=" + virtual_size + "\n")
 | |
|             f.write("checksum=" + checksum + "\n")
 | |
|             f.write("hvm=true\n")
 | |
|             f.write("description=" + name + "\n")
 | |
|             f.close()
 | |
|             util.SMlog("Created template.properties file")
 | |
| 
 | |
|             # Create the template install folder if necessary
 | |
|             template_install_folder = local_mount_path + "/" + args["templateInstallFolder"]
 | |
|             if not os.path.isdir(template_install_folder):
 | |
|                 current_umask = os.umask(0)
 | |
|                 os.makedirs(template_install_folder)
 | |
|                 os.umask(current_umask)
 | |
|             
 | |
|             # Move the template and the template.properties file to the install folder
 | |
|             os.system("mv " + template_download_folder + "/" + filename + " " + template_install_folder)
 | |
|             os.system("mv " + template_download_folder + "/template.properties " + template_install_folder)
 | |
|             template_install_path = template_install_folder + filename
 | |
|             template_properties_install_path = template_install_folder + "template.properties"
 | |
|             
 | |
|             # Set permissions
 | |
|             permissions = stat.S_IREAD | stat.S_IWRITE | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH | stat.S_IWOTH
 | |
|             os.chmod(template_install_path, permissions)
 | |
|             os.chmod(template_properties_install_path, permissions)
 | |
|             util.SMlog("Set permissions on template and template.properties")
 | |
| 
 | |
|             # Delete the template download folder
 | |
|             os.system("rm -rf " + template_download_folder)
 | |
|         except:
 | |
|             errMsg = "post_create_private_template failed."
 | |
|             util.SMlog(errMsg)
 | |
|             raise xs_errors.XenError(errMsg)
 | |
|     finally:
 | |
|         if local_mount_path != None:
 | |
|             # Unmount the local templates folder
 | |
|             umount(local_mount_path)
 | |
|             # Remove the local templates folder
 | |
|             os.system("rm -rf " + local_mount_path)
 | |
| 
 | |
|     return "1" 
 | |
|   
 | |
| def isfile(path, isISCSI):
 | |
|     errMsg = ''
 | |
|     exists = True
 | |
|     if isISCSI:
 | |
|         exists = checkVolumeAvailablility(path)
 | |
|     else:
 | |
|         exists = os.path.isfile(path)
 | |
|         
 | |
|     if not exists:
 | |
|         errMsg = "File " + path + " does not exist."
 | |
|         util.SMlog(errMsg)
 | |
|         raise xs_errors.XenError(errMsg)
 | |
|     return errMsg
 | |
| 
 | |
| def copyfile(fromFile, toFile, isISCSI):
 | |
|     util.SMlog("Starting to copy " + fromFile + " to " + toFile)
 | |
|     errMsg = ''
 | |
|     if isISCSI:
 | |
|         try:
 | |
|             cmd = ['dd', 'if=' + fromFile, 'of=' + toFile]
 | |
|             txt = util.pread2(cmd)
 | |
|         except:
 | |
|             txt = ''
 | |
|             errMsg = "Error while copying " + fromFile + " to " + toFile + " in ISCSI mode"
 | |
|             util.SMlog(errMsg)
 | |
|             raise xs_errors.XenError(errMsg)
 | |
| 
 | |
|     else:
 | |
|         try:
 | |
|             shutil.copy2(fromFile, toFile)
 | |
|         except OSError, (errno, strerror):
 | |
|             errMsg = "Error while copying " + fromFile + " to " + toFile + " with errno: " + str(errno) + " and strerr: " + strerror
 | |
|             util.SMlog(errMsg)
 | |
|             raise xs_errors.XenError(errMsg)
 | |
| 
 | |
|     util.SMlog("Successfully copied " + fromFile + " to " + toFile)
 | |
|     return errMsg
 | |
| 
 | |
| def chdir(path):
 | |
|     try:
 | |
|         os.chdir(path)
 | |
|     except OSError, (errno, strerror):
 | |
|         errMsg = "Unable to chdir to " + path + " because of OSError with errno: " + str(errno) + " and strerr: " + strerror
 | |
|         util.SMlog(errMsg)
 | |
|         raise xs_errors.XenError(errMsg)
 | |
|     util.SMlog("Chdired to " + path)
 | |
|     return
 | |
| 
 | |
| def coalesce(vhdPath):
 | |
|     util.SMlog("Starting to coalesce " + vhdPath + " with its parent")
 | |
|     try :
 | |
|         cmd = [VHD_UTIL, "coalesce", "-n", vhdPath]
 | |
|         txt = util.pread2(cmd)
 | |
|     except:
 | |
|         errMsg = "Unexpected error while trying to coalesce " + vhdPath + " to its parent"
 | |
|         util.SMlog(errMsg)
 | |
|         raise xs_errors.XenError(errMsg)
 | |
|     util.SMlog("Successfully coalesced " + vhdPath + " with its parent ")
 | |
|     
 | |
|     return
 | |
| 
 | |
| def scanParent(path):
 | |
|     # Do a scan for the parent for ISCSI volumes
 | |
|     # Note that the parent need not be visible on the XenServer
 | |
|     parentUUID = ''
 | |
|     try:
 | |
|         lvName = os.path.basename(path)
 | |
|         dirname = os.path.dirname(path)
 | |
|         vgName = os.path.basename(dirname) 
 | |
|         vhdInfo = vhdutil.getVHDInfoLVM(lvName, lvhdutil.extractUuid, vgName)
 | |
|         parentUUID = vhdInfo.parentUuid
 | |
|     except:
 | |
|         errMsg = "Could not get vhd parent of " + path
 | |
|         util.SMlog(errMsg)
 | |
|         raise xs_errors.XenError(errMsg)
 | |
|     return parentUUID
 | |
| 
 | |
| def getParent(path, isISCSI):
 | |
|     parentUUID = ''
 | |
|     try :
 | |
|         if isISCSI:
 | |
|             parentUUID = vhdutil.getParent(path, lvhdutil.extractUuid)
 | |
|         else:
 | |
|             parentUUID = vhdutil.getParent(path, cleanup.FileVDI.extractUuid)
 | |
|     except:
 | |
|         errMsg = "Could not get vhd parent of " + path
 | |
|         util.SMlog(errMsg)
 | |
|         raise xs_errors.XenError(errMsg)
 | |
|     return parentUUID
 | |
| 
 | |
| def getParentOfSnapshot(snapshotUuid, primarySRPath, isISCSI):
 | |
|     snapshotVHD    = getVHD(snapshotUuid, isISCSI)
 | |
|     snapshotPath   = os.path.join(primarySRPath, snapshotVHD)
 | |
| 
 | |
|     baseCopyUuid = ''
 | |
|     if isISCSI:
 | |
|         checkVolumeAvailablility(snapshotPath)
 | |
|         baseCopyUuid = scanParent(snapshotPath)
 | |
|     else:
 | |
|         baseCopyUuid = getParent(snapshotPath, isISCSI)
 | |
|     
 | |
|     util.SMlog("Base copy of snapshotUuid: " + snapshotUuid + " is " + baseCopyUuid)
 | |
|     return baseCopyUuid
 | |
| 
 | |
| def setParent(parent, child):
 | |
|     try:
 | |
|         cmd = [VHD_UTIL, "modify", "-p", parent, "-n", child]
 | |
|         txt = util.pread2(cmd)
 | |
|     except:
 | |
|         errMsg = "Unexpected error while trying to set parent of " + child + " to " + parent 
 | |
|         util.SMlog(errMsg)
 | |
|         raise xs_errors.XenError(errMsg)
 | |
|     util.SMlog("Successfully set parent of " + child + " to " + parent)
 | |
|     return
 | |
| 
 | |
| def rename(originalVHD, newVHD):
 | |
|     try:
 | |
|         os.rename(originalVHD, newVHD)
 | |
|     except OSError, (errno, strerror):
 | |
|         errMsg = "OSError while renaming " + origiinalVHD + " to " + newVHD + "with errno: " + str(errno) + " and strerr: " + strerror
 | |
|         util.SMlog(errMsg)
 | |
|         raise xs_errors.XenError(errMsg)
 | |
|     return
 | |
| 
 | |
| def coalesceToChild(backupVHD, childUUID, isISCSI):
 | |
|     # coalesce childVHD with its parent
 | |
|     childVHD = getVHD(childUUID, isISCSI)
 | |
|     util.SMlog("childVHD: " + childVHD)
 | |
|     # check for existence of childVHD
 | |
|     isfile(childVHD, False)
 | |
|     util.SMlog("childVHD " + childVHD + " exists")
 | |
|     # No exception thrown, file exists
 | |
|     coalesce(childVHD)
 | |
|     
 | |
|     # rename the existing backupVHD file to childVHD
 | |
|     # childVHD file automatically gets overwritten
 | |
|     rename(backupVHD, childVHD)
 | |
| 
 | |
|     # parent of the newly coalesced file still remains the same.
 | |
|     # child of childVHD has it's parent name still set to childVHD.
 | |
|     # So the VHD chain hasn't been broken.
 | |
|     return
 | |
| 
 | |
| def makedirs(path):
 | |
|     if not os.path.isdir(path):
 | |
|         try:
 | |
|             os.makedirs(path)
 | |
|         except OSError, (errno, strerror):
 | |
|             errMsg = "OSError while creating " + path + " with errno: " + str(errno) + " and strerr: " + strerror
 | |
|             util.SMlog(errMsg)
 | |
|             raise xs_errors.XenError(errMsg)
 | |
|     return
 | |
| 
 | |
| def mount(remoteDir, localDir):
 | |
|     makedirs(localDir)
 | |
|     
 | |
|     try: 
 | |
|         cmd = ['mount', remoteDir, localDir]
 | |
|         txt = util.pread2(cmd)
 | |
|     except:
 | |
|         txt = ''
 | |
|         errMsg = "Unexpected error while trying to mount " + remoteDir + " to " + localDir 
 | |
|         util.SMlog(errMsg)
 | |
|         raise xs_errors.XenError(errMsg)
 | |
|     util.SMlog("Successfully mounted " + remoteDir + " to " + localDir)
 | |
| 
 | |
|     return
 | |
| 
 | |
| def umount(localDir):
 | |
|     success = False
 | |
|     if os.path.isdir(localDir) and os.path.ismount(localDir):
 | |
|         try: 
 | |
|             cmd = ['umount', localDir]
 | |
|             util.pread2(cmd)
 | |
|         except CommandException:
 | |
|             errMsg = "CommandException raised while trying to umount " + localDir 
 | |
|             util.SMlog(errMsg)
 | |
|             raise xs_errors.XenError(errMsg)
 | |
|         util.SMlog("Successfully unmounted " + localDir)
 | |
|         success = True
 | |
|     else:
 | |
|         util.SMlog("LocalDir: " + localDir + " doesn't exist or is not a mount point")
 | |
| 
 | |
|     return
 | |
| 
 | |
| 
 | |
| def mountTemplatesDir(secondaryStorageMountPath, templatePath):
 | |
|     # Aim is to mount <secondaryStorageMountPath>/<templatePath> on 
 | |
|     # SR.MOUNT_BASE/<random_uuid>
 | |
|     # It will be unmounted after createVolumeFromSnapshot finishes.
 | |
|     # It should be mounted read-only, but don't know how to do that
 | |
|     # The random-uuid saves us from conflicts while restoring two different root volumes
 | |
|     
 | |
|     absoluteTemplatePath = os.path.join(secondaryStorageMountPath, templatePath)
 | |
|     absoluteTemplateDir = os.path.dirname(absoluteTemplatePath)
 | |
| 
 | |
|     randomUUID = util.gen_uuid()
 | |
|     localTemplateDir = os.path.join(SR.MOUNT_BASE, randomUUID)
 | |
|     # create the temp dir
 | |
|     makedirs(localTemplateDir)
 | |
|     # mount
 | |
|     mount(absoluteTemplateDir, localTemplateDir)
 | |
| 
 | |
|     return localTemplateDir
 | |
| 
 | |
| def mountSnapshotsDir(secondaryStorageMountPath, relativeDir, dcId, accountId, instanceId):
 | |
|     # The aim is to mount secondaryStorageMountPath on 
 | |
|     # SR.MOUNT_BASE/<dcId>/<relativeDir>
 | |
|     # And create <accountId>/<instanceId> dir on it, if it doesn't exist already.
 | |
|     # Assuming that secondaryStorageMountPath  exists remotely
 | |
| 
 | |
|     # Alex's suggestion and currently implemented:
 | |
|     # Just mount secondaryStorageMountPath/<relativeDir> everytime
 | |
|     # Never unmount.
 | |
|     snapshotsDir = os.path.join(secondaryStorageMountPath, relativeDir)
 | |
| 
 | |
|     # Mkdir local mount point dir, if it doesn't exist.
 | |
|     localMountPointPath = os.path.join(SR.MOUNT_BASE, dcId)
 | |
|     localMountPointPath = os.path.join(localMountPointPath, relativeDir)
 | |
| 
 | |
|     makedirs(localMountPointPath)
 | |
|     # if something is not mounted already on localMountPointPath, 
 | |
|     # mount secondaryStorageMountPath on localMountPath
 | |
|     if os.path.ismount(localMountPointPath):
 | |
|         # There is only one secondary storage per zone. 
 | |
|         # And we are mounting each sec storage under a zone-specific directory
 | |
|         # So two secondary storage snapshot dirs will never get mounted on the same point on the same XenServer.
 | |
|         util.SMlog("The remote snapshots directory has already been mounted on " + localMountPointPath)
 | |
|     else:
 | |
|         mount(snapshotsDir, localMountPointPath)
 | |
| 
 | |
|     # Create accountId/instanceId dir on localMountPointPath, if it doesn't exist
 | |
|     backupsDir = os.path.join(localMountPointPath, accountId)
 | |
|     backupsDir = os.path.join(backupsDir, instanceId)
 | |
|     makedirs(backupsDir)
 | |
|     return backupsDir
 | |
| 
 | |
| @echo
 | |
| def unmountSnapshotsDir(session, args):
 | |
|     dcId = args['dcId']
 | |
|     localMountPointPath = os.path.join(SR.MOUNT_BASE, dcId)
 | |
|     localMountPointPath = os.path.join(localMountPointPath, "snapshots")
 | |
|     try:
 | |
|         umount(localMountPointPath)
 | |
|     except:
 | |
|         util.SMlog("Ignoring the error while trying to unmount the snapshots dir.")
 | |
| 
 | |
|     return "1"
 | |
| 
 | |
| def getPrimarySRPath(primaryStorageSRUuid, isISCSI):
 | |
|     if isISCSI:
 | |
|         primarySRDir = lvhdutil.VG_PREFIX + primaryStorageSRUuid
 | |
|         return os.path.join(lvhdutil.VG_LOCATION, primarySRDir)
 | |
|     else:
 | |
|         return os.path.join(SR.MOUNT_BASE, primaryStorageSRUuid)
 | |
| 
 | |
| def getVHD(UUID, isISCSI):
 | |
|     if isISCSI:
 | |
|         return VHD_PREFIX + UUID
 | |
|     else:
 | |
|         return UUID + '.' + SR.DEFAULT_TAP
 | |
| 
 | |
| def getIsTrueString(stringValue):
 | |
|     booleanValue = False
 | |
|     if (stringValue and stringValue == 'true'):
 | |
|         booleanValue = True
 | |
|     return booleanValue 
 | |
| 
 | |
| def makeUnavailable(uuid, primarySRPath, isISCSI):
 | |
|     if not isISCSI:
 | |
|         return
 | |
|     VHD = getVHD(uuid, isISCSI)
 | |
|     path = os.path.join(primarySRPath, VHD)
 | |
|     manageAvailability(path, '-an')
 | |
|     return
 | |
| 
 | |
| def manageAvailability(path, value):
 | |
|     if path.__contains__("/var/run/sr-mount"):
 | |
|         return
 | |
|     util.SMlog("Setting availability of " + path + " to " + value)
 | |
|     try:
 | |
|         cmd = ['/usr/sbin/lvchange', value, path]
 | |
|         util.pread2(cmd)
 | |
|     except: #CommandException, (rc, cmdListStr, stderr):
 | |
|         #errMsg = "CommandException thrown while executing: " + cmdListStr + " with return code: " + str(rc) + " and stderr: " + stderr
 | |
|         errMsg = "Unexpected exception thrown by lvchange"
 | |
|         util.SMlog(errMsg)
 | |
|         if value == "-ay":
 | |
|             # Raise an error only if we are trying to make it available.
 | |
|             # Just warn if we are trying to make it unavailable after the 
 | |
|             # snapshot operation is done.
 | |
|             raise xs_errors.XenError(errMsg)
 | |
|     return
 | |
| 
 | |
| 
 | |
| def checkVolumeAvailablility(path):
 | |
|     try:
 | |
|         if not isVolumeAvailable(path):
 | |
|             # The VHD file is not available on XenSever. The volume is probably
 | |
|             # inactive or detached.
 | |
|             # Do lvchange -ay to make it available on XenServer
 | |
|             manageAvailability(path, '-ay')
 | |
|     except:
 | |
|         errMsg = "Could not determine status of ISCSI path: " + path
 | |
|         util.SMlog(errMsg)
 | |
|         raise xs_errors.XenError(errMsg)
 | |
|     
 | |
|     success = False
 | |
|     i = 0
 | |
|     while i < 6:
 | |
|         i = i + 1
 | |
|         # Check if the vhd is actually visible by checking for the link
 | |
|         # set isISCSI to true
 | |
|         success = isVolumeAvailable(path)
 | |
|         if success:
 | |
|             util.SMlog("Made vhd: " + path + " available and confirmed that it is visible")
 | |
|             break
 | |
| 
 | |
|         # Sleep for 10 seconds before checking again.
 | |
|         time.sleep(10)
 | |
| 
 | |
|     # If not visible within 1 min fail
 | |
|     if not success:
 | |
|         util.SMlog("Could not make vhd: " +  path + " available despite waiting for 1 minute. Does it exist?")
 | |
| 
 | |
|     return success
 | |
| 
 | |
| def isVolumeAvailable(path):
 | |
|     # Check if iscsi volume is available on this XenServer.
 | |
|     status = "0"
 | |
|     try:
 | |
|         p = subprocess.Popen(["/bin/bash", "-c", "if [ -L " + path + " ]; then echo 1; else echo 0;fi"], stdout=subprocess.PIPE)
 | |
|         status = p.communicate()[0].strip("\n")
 | |
|     except:
 | |
|         errMsg = "Could not determine status of ISCSI path: " + path
 | |
|         util.SMlog(errMsg)
 | |
|         raise xs_errors.XenError(errMsg)
 | |
| 
 | |
|     return (status == "1")
 | |
| 
 | |
| def getLastSnapshotUuid(volumeUuid, expectedLastSnapshotUuid):
 | |
|     actualLastSnapshotUuid = ''
 | |
|     if volumeUuid:
 | |
|         cmd = ['xe', 'vdi-param-get', 'uuid=' + volumeUuid, 'param-name=snapshots']
 | |
|         stdout = ''
 | |
|         try:
 | |
|             stdout = util.pread2(cmd)
 | |
|         except: #CommandException, (rc, cmdListStr, stderr):
 | |
|             #errMsg = "CommandException thrown while executing: " + cmdListStr + " with return code: " + str(rc) + " and stderr: " + stderr
 | |
|             errMsg = "Unexpected error while executing cmd: " + str(cmd)
 | |
|             util.SMlog(errMsg)
 | |
|             raise xs_errors.XenError(errMsg)
 | |
|         if stdout:
 | |
|             snapshots = stdout.split(';')
 | |
|             if len(snapshots) == 1:
 | |
|                 if snapshots[0] == expectedLastSnapshotUuid:
 | |
|                     actualLastSnapshotUuid = expectedLastSnapshotUuid
 | |
|             elif len(snapshots) == 2:
 | |
|                 # We expect only 1 snapshot to be present. If there is another that is unexpected and the last one
 | |
|                 if (expectedLastSnapshotUuid == snapshots[0].strip()):
 | |
|                     actualLastSnapshotUuid = snapshots[1].strip()
 | |
|                 else:
 | |
|                     # it should be equal to snapshots[1]. Else I have no idea.
 | |
|                     actualLastSnapshotUuid = snapshots[0].strip()
 | |
|             else:
 | |
|                 # len(snapshots) > 2:
 | |
|                 errMsg = "Volume: " + volumeUuid + " has more than 2 snapshots: " + str(snapshots)
 | |
|                 util.SMlog(errMsg)
 | |
|                 raise xs_errors.XenError(errMsg)
 | |
|                 
 | |
|     return actualLastSnapshotUuid
 | |
|     
 | |
| @echo
 | |
| def validateSnapshot(session, args):
 | |
|     util.SMlog("Called validateSnapshot with " + str(args))
 | |
|     primaryStorageSRUuid = args['primaryStorageSRUuid']
 | |
|     volumeUuid           = args['volumeUuid']
 | |
|     firstBackupUuid      = args['firstBackupUuid']
 | |
|     previousSnapshotUuid = args['previousSnapshotUuid']
 | |
|     templateUuid         = args['templateUuid']
 | |
|     isISCSI              = getIsTrueString(args['isISCSI'])
 | |
|    
 | |
|     primarySRPath = getPrimarySRPath(primaryStorageSRUuid, isISCSI)
 | |
|     util.SMlog("primarySRPath: " + primarySRPath)
 | |
|     volumeVHD    = getVHD(volumeUuid, isISCSI)
 | |
|     volumePath   = os.path.join(primarySRPath, volumeVHD)
 | |
|     util.SMlog("volumePath: " + volumePath)
 | |
| 
 | |
|     baseCopyUuid = ''
 | |
|     wasVolumeAvailable = True
 | |
|     if isISCSI:
 | |
|         wasVolumeAvailable = isVolumeAvailable(volumePath)
 | |
|         if not wasVolumeAvailable:
 | |
|             # make it available
 | |
|             checkVolumeAvailablility(volumePath)
 | |
|         baseCopyUuid = scanParent(volumePath)
 | |
|     else:
 | |
|         baseCopyUuid = getParent(volumePath, isISCSI)
 | |
| 
 | |
|     if baseCopyUuid is None:
 | |
|         # Make it an empty string so that it can be used in the return value
 | |
|         baseCopyUuid = ''
 | |
| 
 | |
|     actualSnapshotUuid = getLastSnapshotUuid(volumeUuid, previousSnapshotUuid)
 | |
|     expectedActual = firstBackupUuid + "#" + baseCopyUuid + "#" + actualSnapshotUuid
 | |
|     if firstBackupUuid:
 | |
|         # This is not the first snapshot
 | |
|         if baseCopyUuid and (baseCopyUuid == firstBackupUuid):
 | |
|             retval = "1#"
 | |
|         else:
 | |
|             retval = "0#"
 | |
|     else: 
 | |
|         if templateUuid:
 | |
|             # The DB thinks this is the first snapshot of a ROOT DISK
 | |
|             # The parent of the volume should be the base template, which is also the parent of the given templateUuid.
 | |
|             templateVHD = getVHD(templateUuid, isISCSI)
 | |
|             templatePath = os.path.join(primarySRPath, templateVHD)
 | |
|             baseTemplateUuid = ''
 | |
|             wasTemplateAvailable = True
 | |
|             if isISCSI:
 | |
|                 wasTemplateAvailable = isVolumeAvailable(templatePath)
 | |
|                 if not wasVolumeAvailable:
 | |
|                     # make it available
 | |
|                     checkVolumeAvailablility(templatePath)
 | |
|                 baseTemplateUuid = scanParent(templatePath)
 | |
|             else:
 | |
|                 baseTemplateUuid = getParent(templatePath, isISCSI)
 | |
| 
 | |
|             if baseTemplateUuid is None:
 | |
|                 # This will never happen.
 | |
|                 baseTemplateUuid = ''
 | |
| 
 | |
|             expectedActual = baseTemplateUuid + "#" + baseCopyUuid + "#" + actualSnapshotUuid
 | |
|             if baseTemplateUuid and (baseCopyUuid == baseTemplateUuid):
 | |
|                 retval = "1#"
 | |
|             else:
 | |
|                 retval = "0#"
 | |
| 
 | |
|             if isISCSI and not wasTemplateAvailable:
 | |
|                 manageAvailability(templatePath, '-an')
 | |
| 
 | |
|         else:
 | |
|             # The DB thinks this is the first snapshot of a DATA DISK. 
 | |
|             # The volume VDI should not have any parent.
 | |
|             if not baseCopyUuid:
 | |
|                 retval = "1#"
 | |
|             else:
 | |
|                 retval = "0#"
 | |
| 
 | |
|     # Set the volume's visibility back to what it was.
 | |
|     if isISCSI and not wasVolumeAvailable:
 | |
|         manageAvailability(volumePath, '-an')
 | |
| 
 | |
|     return retval + expectedActual
 | |
| 
 | |
| @echo
 | |
| def backupSnapshot(session, args):
 | |
|     util.SMlog("Called backupSnapshot with " + str(args))
 | |
|     primaryStorageSRUuid      = args['primaryStorageSRUuid']
 | |
|     dcId                      = args['dcId']
 | |
|     accountId                 = args['accountId']
 | |
|     volumeId                  = args['volumeId']
 | |
|     secondaryStorageMountPath = args['secondaryStorageMountPath']
 | |
|     snapshotUuid              = args['snapshotUuid']
 | |
|     prevSnapshotUuid          = args['prevSnapshotUuid']
 | |
|     prevBackupUuid            = args['prevBackupUuid']
 | |
|     isFirstSnapshotOfRootVolume =  getIsTrueString(args['isFirstSnapshotOfRootVolume'])
 | |
|     isISCSI                   = getIsTrueString(args['isISCSI']) 
 | |
| 
 | |
|     primarySRPath = getPrimarySRPath(primaryStorageSRUuid, isISCSI)
 | |
|     util.SMlog("primarySRPath: " + primarySRPath)
 | |
| 
 | |
|     baseCopyUuid = getParentOfSnapshot(snapshotUuid, primarySRPath, isISCSI)
 | |
|     baseCopyVHD  = getVHD(baseCopyUuid, isISCSI)
 | |
|     baseCopyPath = os.path.join(primarySRPath, baseCopyVHD)
 | |
|     util.SMlog("Base copy path: " + baseCopyPath)
 | |
| 
 | |
|     prevBaseCopyUuid = ''
 | |
|     if prevSnapshotUuid:
 | |
|         prevBaseCopyUuid = getParentOfSnapshot(prevSnapshotUuid, primarySRPath, isISCSI)
 | |
| 
 | |
|     # Mount secondary storage mount path on XenServer along the path
 | |
|     # /var/run/sr-mount/<dcId>/snapshots/ and create <accountId>/<volumeId> dir
 | |
|     # on it.
 | |
|     backupsDir = mountSnapshotsDir(secondaryStorageMountPath, "snapshots", dcId, accountId, volumeId)
 | |
|     util.SMlog("Backups dir " + backupsDir)
 | |
|     # chdir to the backupsDir for convenience
 | |
|     chdir(backupsDir)
 | |
| 
 | |
|     if baseCopyUuid == prevBaseCopyUuid:
 | |
|         # There has been no change since the last snapshot so no need to backup 
 | |
|         util.SMlog("There has been no change since the last snapshot with backup: " + prevBaseCopyUuid) 
 | |
|         if isFirstSnapshotOfRootVolume:
 | |
|             # baseCopyUuid is template. That is *NOT* the backup of any
 | |
|             # snapshot. There is no backup. So create an empty dummyVHD representing the empty snapshot.
 | |
|             # This will prevent deleteSnapshotBackup and createVolumeFromSnapshot from breaking.
 | |
|             prevBaseCopyUuid = createDummyVHD(baseCopyPath, backupsDir, isISCSI)
 | |
|             # The backup snapshot is the new dummy VHD created. 
 | |
| 
 | |
|         # Set the uuid of the current backup to that of last backup
 | |
|         txt = "1#" + prevBaseCopyUuid
 | |
|         return txt
 | |
| 
 | |
|     # Check existence of snapshot on primary storage 
 | |
|     isfile(baseCopyPath, isISCSI)
 | |
|     # copy baseCopyPath to backupsDir
 | |
|     backupFile = os.path.join(backupsDir, baseCopyVHD)
 | |
|     copyfile(baseCopyPath, backupFile, isISCSI)
 | |
|     
 | |
|     # Now set the availability of the snapshotPath and the baseCopyPath to false
 | |
|     makeUnavailable(snapshotUuid, primarySRPath, isISCSI)
 | |
|     manageAvailability(baseCopyPath, '-an')
 | |
|     if prevSnapshotUuid:
 | |
|         makeUnavailable(prevSnapshotUuid, primarySRPath, isISCSI)
 | |
|         makeUnavailable(prevBaseCopyUuid, primarySRPath, isISCSI)
 | |
| 
 | |
|     if isFirstSnapshotOfRootVolume:
 | |
|         # First snapshot of the root volume.
 | |
|         # It's parent is not null, but the template vhd.
 | |
|         # Create a dummy empty vhd and set the parent of backupVHD to it.
 | |
|         # This will prevent deleteSnapshotBackup and createVolumeFromSnapshot from breaking
 | |
|         prevBackupUuid = createDummyVHD(baseCopyPath, backupsDir, isISCSI)
 | |
| 
 | |
|     # Because the primary storage is always scanned, the parent of this base copy is always the first base copy.
 | |
|     # We don't want that, we want a chain of VHDs each of which is a delta from the previous.
 | |
|     # So set the parent of the current baseCopyVHD to prevBackupVHD 
 | |
|     if prevBackupUuid:
 | |
|         # If there was a previous snapshot
 | |
|         prevBackupVHD = getVHD(prevBackupUuid, isISCSI)
 | |
|         setParent(prevBackupVHD, backupFile)
 | |
| 
 | |
|     txt = "1#" + baseCopyUuid
 | |
|     return txt
 | |
| 
 | |
| def createDummyVHD(baseCopyPath, backupsDir, isISCSI):
 | |
|     dummyUUID = ''
 | |
|     try:
 | |
|         dummyUUID = util.gen_uuid()
 | |
|         dummyVHD = getVHD(dummyUUID, isISCSI)
 | |
|         if isISCSI:
 | |
|             checkVolumeAvailablility(baseCopyPath)
 | |
|         cmd = [VHD_UTIL, 'query', '-v', '-n', baseCopyPath]
 | |
|         virtualSizeInMB = util.pread2(cmd)
 | |
|         util.SMlog("Virtual size of " + baseCopyPath + " is " + virtualSizeInMB)
 | |
|         cmd = [VHD_UTIL, 'create', '-n', dummyVHD, '-s', virtualSizeInMB]
 | |
|         util.pread2(cmd)
 | |
|     except CommandException:
 | |
|         errMsg = "Unexpected error while creating a dummy VHD " + dummyVHD + " on " + backupsDir
 | |
|         util.SMlog(errMsg)
 | |
|         raise xs_errors.XenError(errMsg)
 | |
|     util.SMlog("Successfully created a new dummy VHD: " + dummyVHD + " on " + backupsDir)
 | |
| 
 | |
|     return dummyUUID
 | |
| 
 | |
| @echo
 | |
| def deleteSnapshotBackup(session, args):
 | |
|     util.SMlog("Calling deleteSnapshotBackup with " + str(args))
 | |
|     dcId                      = args['dcId']
 | |
|     accountId                 = args['accountId']
 | |
|     volumeId                  = args['volumeId']
 | |
|     secondaryStorageMountPath = args['secondaryStorageMountPath']
 | |
|     backupUUID                = args['backupUUID']
 | |
|     childUUID                 = args['childUUID']
 | |
|     isISCSI                   = getIsTrueString(args['isISCSI'])
 | |
| 
 | |
|     backupsDir = mountSnapshotsDir(secondaryStorageMountPath, "snapshots", dcId, accountId, volumeId)
 | |
|     # chdir to the backupsDir for convenience
 | |
|     chdir(backupsDir)
 | |
| 
 | |
|     backupVHD = getVHD(backupUUID, isISCSI)
 | |
|     util.SMlog("checking existence of " + backupVHD)
 | |
| 
 | |
|     # The backupVHD is on secondary which is NFS and not ISCSI.
 | |
|     if not os.path.isfile(backupVHD):
 | |
|         util.SMlog("backupVHD " + backupVHD + "does not exist. Not trying to delete it")
 | |
|         return "1"
 | |
|     util.SMlog("backupVHD " + backupVHD + " exists.")
 | |
|         
 | |
|     # Case 1) childUUID exists
 | |
|     if childUUID:
 | |
|         coalesceToChild(backupVHD, childUUID, isISCSI)
 | |
|     else:
 | |
|         # Just delete the backupVHD
 | |
|         try:
 | |
|             os.remove(backupVHD)
 | |
|         except OSError, (errno, strerror):
 | |
|             errMsg = "OSError while removing " + backupVHD + " with errno: " + str(errno) + " and strerr: " + strerror
 | |
|             util.SMlog(errMsg)
 | |
|             raise xs_errors.XenError(errMsg)
 | |
| 
 | |
|     return "1"
 | |
| 
 | |
| @echo
 | |
| def createVolumeFromSnapshot(session, args):
 | |
|     util.SMlog("Calling createVolumeFromSnapshot with " + str(args))
 | |
|     dcId                      = args['dcId']
 | |
|     accountId                 = args['accountId']
 | |
|     volumeId                  = args['volumeId']
 | |
|     secondaryStorageMountPath = args['secondaryStorageMountPath']
 | |
|     backedUpSnapshotUuid      = args['backedUpSnapshotUuid']
 | |
|     templatePath              = args['templatePath']
 | |
|     templateDownloadFolder    = args['templateDownloadFolder']
 | |
|     isISCSI                   = getIsTrueString(args['isISCSI'])
 | |
| 
 | |
|     backupsDir = mountSnapshotsDir(secondaryStorageMountPath, "snapshots", dcId, accountId, volumeId)
 | |
|     util.SMlog("Backups dir " + backupsDir)
 | |
| 
 | |
|     # chdir to the backupsDir for convenience
 | |
|     chdir(backupsDir)
 | |
| 
 | |
|     # Get the parent VHD chain of the backupSnapshotVHD
 | |
|     vhdChain = []
 | |
|     uuid = backedUpSnapshotUuid
 | |
|     while uuid is not None:
 | |
|         util.SMlog("Current uuid in parent chain " + uuid)
 | |
|         vhd = getVHD(uuid, isISCSI)
 | |
|         vhdChain.append(vhd)
 | |
|         uuid = getParent(vhd, isISCSI)
 | |
|     util.SMlog("successfully created the parent chain " + str(vhdChain))
 | |
| 
 | |
|     destDirParent = ''
 | |
|     destDir = ''
 | |
|     if templateDownloadFolder:
 | |
|         # Copy all the vhds to the final destination templates dir
 | |
|         # It is some random directory on the primary created for templates.
 | |
|         destDirParent = os.path.join(SR.MOUNT_BASE, "mount" + str(int(random.random() * 1000000)))
 | |
|         destDir = os.path.join(destDirParent, templateDownloadFolder)
 | |
|         # create the this directory, if it isn't there
 | |
|         makedirs(destDir)
 | |
|     else:
 | |
|         # Copy all the vhds to a temp directory
 | |
|         # Create a temp directory
 | |
|         destDir = backupsDir + '_temp'
 | |
| 
 | |
|     # Delete the temp directory if it already exists (from a previous createVolumeFromSnapshot)
 | |
|     rmtree(destDir)
 | |
|     
 | |
|     if templateDownloadFolder:
 | |
|         # The destDir was created in create_secondary_storage_folder but is not mounted on the primary. Mount it again.
 | |
|         remoteMountPoint = os.path.join(secondaryStorageMountPath, "template");
 | |
|         remoteMountPoint = os.path.join(remoteMountPoint, templateDownloadFolder)
 | |
|         mount(remoteMountPoint, destDir)
 | |
|     else:
 | |
|         # The parent of the destDir is the snapshots dir and is mounted on the primary. Just create the directory structure.
 | |
|         makedirs(destDir)
 | |
| 
 | |
|     # Copy
 | |
|     for vhd in vhdChain:
 | |
|         vhdPath = os.path.join(backupsDir, vhd)
 | |
|         tempFile = os.path.join(destDir, vhd)
 | |
|         # We are copying files on secondary storage which is NFS. Set isISCSI to false
 | |
|         copyfile(vhdPath, tempFile, False)
 | |
|     util.SMlog("Successfully copied all files")
 | |
| 
 | |
|     # coalesce the vhd chains from bottom to top
 | |
|     # chdir to destDir for convenience
 | |
|     chdir(destDir)
 | |
|        
 | |
|     # coalesce
 | |
|     i = 0
 | |
|     finalVhd = vhdChain[0]
 | |
|     for vhd in vhdChain:
 | |
|         finalVhd = vhdChain[i]
 | |
|         last = len(vhdChain) - 1
 | |
|         if i == last:
 | |
|             # last vhd, has no parent. Don't coalesce
 | |
|             break
 | |
|         if templatePath and i == (last - 1):
 | |
|             # Hack for root disks, the first Vhd is a dummy one. 
 | |
|             # Do not coalesce the actual disk with the dummy one.
 | |
|             # Instead coalesce it with the templateVHD.
 | |
|             break
 | |
| 
 | |
|         i = i + 1
 | |
|         # They are arranged from child to parent.
 | |
|         util.SMlog("Starting to coalesce " + vhd + " with its parent")
 | |
|         try:
 | |
|             cmd = [VHD_UTIL, "coalesce", "-n", vhd]
 | |
|             txt = util.pread2(cmd)
 | |
|         except:
 | |
|             errMsg = "Unexpected error while trying to coalesce " + vhd + " to its parent" 
 | |
|             util.SMlog(errMsg)
 | |
|             raise xs_errors.XenError(errMsg)
 | |
|         util.SMlog("Successfully coalesced " + vhd + " with its parent")
 | |
| 
 | |
|         # Remove the child vhd
 | |
|         try:
 | |
|             os.remove(vhd)
 | |
|         except OSError, (errno, strerror):
 | |
|             errMsg = "OSError while removing " + vhd + " with errno: " + str(errno) + " and strerr: " + strerror
 | |
|             util.SMlog(errMsg)
 | |
|             raise xs_errors.XenError(errMsg)
 | |
|     
 | |
|     util.SMlog("successfully coalesced all vhds to the parent " + finalVhd)
 | |
|     finalVhdPath = os.path.join(destDir, finalVhd)
 | |
| 
 | |
|     # This vhd has to be introduced with a new uuid because of the VDI UUID
 | |
|     # uniqueness constraint
 | |
|     newUUID = ''
 | |
|     try:
 | |
|         newUUID = util.gen_uuid()
 | |
|     except:
 | |
|         errMsg = "Unexpected error while trying to generate a uuid"
 | |
|         util.SMlog(errMsg)
 | |
|         raise xs_errors.XenError(errMsg)
 | |
|     util.SMlog("generated a uuid " + newUUID)
 | |
| 
 | |
|     # Now, at the Java layer an NFS SR is created with mount point destDir and scanned. The vhd
 | |
|     # file is automatically introduced and a vdi.copy is done to move it to
 | |
|     # primary storage.
 | |
|     # new vhd file is created on NFS. So it should have NFS naming convention,
 | |
|     # set isISCSI to false
 | |
|     newVhd = getVHD(newUUID, False)
 | |
|     rename(finalVhd, newVhd)
 | |
| 
 | |
|     # For root disk
 | |
|     if templatePath:
 | |
|         # This will create a vhd on secondary storage destDir with name newVhd
 | |
|         mergeTemplateAndSnapshot(secondaryStorageMountPath, templatePath, destDir, newVhd, isISCSI)
 | |
| 
 | |
|     # set the hidden flag of the new VHD to false, so that it doesn't get deleted when the SR scan is done.
 | |
|     try:
 | |
|         vhdutil.setHidden(newVhd, False)
 | |
|     except:
 | |
|         errMsg = "Unexpected error while trying to set Hidden flag of " + newVhd
 | |
|         util.SMlog(errMsg)
 | |
|         raise xs_errors.XenError(errMsg)
 | |
|     util.SMlog("Successfully set hidden flag of " + newVhd)
 | |
| 
 | |
|     virtualSizeInMB = 0
 | |
|     try:
 | |
|         cmd = [VHD_UTIL, 'query', '-v', '-n', newVhd]
 | |
|         virtualSizeInMB = util.pread2(cmd)
 | |
|         util.SMlog("Virtual size of " + newVhd + " is " + virtualSizeInMB)
 | |
|     except:
 | |
|         errMsg = "Unexpected error while trying to get the virtual size of " + newVhd
 | |
|         util.SMlog(errMsg)
 | |
|         raise xs_errors.XenError(errMsg)
 | |
| 
 | |
|     if templateDownloadFolder:
 | |
|         # We are done with the destDir on the primary, unmount it and delete the random directory.
 | |
|         # Current dir is destDir
 | |
|         # cd to something else before unmounting
 | |
|         chdir(backupsDir) # as good as anything else
 | |
|         # unmount what was mounted.
 | |
|         umount(destDir)
 | |
|         # Remove the tree starting from the mountXXXX part, just the directories
 | |
|         rmtree(destDirParent)
 | |
|         # The coalesced data is still available on the secondary.
 | |
| 
 | |
|     return "1#" + newUUID + "#" + virtualSizeInMB
 | |
| 
 | |
| def mergeTemplateAndSnapshot(secondaryStorageMountPath, templatePath, destDir, newVhd, isISCSI):
 | |
|     # Mount the template directory present on the secondary to the primary
 | |
|     templateDirOnPrimary = mountTemplatesDir(secondaryStorageMountPath, templatePath)
 | |
| 
 | |
|     # Current dir is destDir
 | |
|     templateVHD = os.path.basename(templatePath)
 | |
|     templatePathOnPrimary = os.path.join(templateDirOnPrimary, templateVHD)
 | |
|     templatePathOnTemp = os.path.join(destDir, templateVHD)
 | |
|     # Copying from secondary to secondary, so set ISCSI to False
 | |
|     copyfile(templatePathOnPrimary, templatePathOnTemp, False)
 | |
|     
 | |
|     # unmount the temporary directory created for copying the template
 | |
|     umount(templateDirOnPrimary)
 | |
| 
 | |
|     # get the dummyVHD which is the parent of the new Vhd
 | |
|     dummyUUID = getParent(newVhd, isISCSI)
 | |
|     dummyVHD = getVHD(dummyUUID, isISCSI)
 | |
|     # set the parent of the newVhd to the templateVHD on secondary
 | |
|     setParent(templateVHD, newVhd)
 | |
|     # remove the dummyVHD as we don't have any use for it and it wil
 | |
|     # lie around after we do an SR scan
 | |
|     os.remove(dummyVHD)
 | |
|     
 | |
|     # coalesce the two VHDs into templateVHD
 | |
|     coalesce(newVhd)
 | |
| 
 | |
|     # rename templateVHD to newVhd
 | |
|     rename(templateVHD, newVhd)
 | |
| 
 | |
|     return
 | |
|     
 | |
| def rmtree(path):
 | |
|     if os.path.isdir(path):
 | |
|         try:
 | |
|             shutil.rmtree(path)
 | |
|         except OSError, (errno, strerror):
 | |
|             errMsg = "Error while deleting " + path + " on secondary storage with errno: " + str(errno) + " and strerr: " + strerror + ". Please delete it manually"
 | |
|             util.SMlog(errMsg)
 | |
|         util.SMlog("Successfully deleted " + path)
 | |
|     else:
 | |
|         util.SMlog("Could not find directory with path " + path)
 | |
|     return
 | |
| 
 | |
| @echo
 | |
| def deleteSnapshotsDir(session, args):
 | |
|     util.SMlog("Calling deleteSnapshotsDir with " + str(args))
 | |
|     dcId                      = args['dcId']
 | |
|     accountId                 = args['accountId']
 | |
|     volumeId                  = args['volumeId']
 | |
|     secondaryStorageMountPath = args['secondaryStorageMountPath']
 | |
| 
 | |
|     backupsDir = mountSnapshotsDir(secondaryStorageMountPath, "snapshots", dcId, accountId, volumeId)
 | |
|     accountDir = os.path.dirname(backupsDir)
 | |
|     util.SMlog("accountDir is " + accountDir)
 | |
|     rmtree(accountDir)
 | |
| 
 | |
|     return "1"
 | |
|    
 | |
| if __name__ == "__main__":
 | |
|     XenAPIPlugin.dispatch({"create_secondary_storage_folder":create_secondary_storage_folder, "delete_secondary_storage_folder":delete_secondary_storage_folder, "post_create_private_template":post_create_private_template, "backupSnapshot": backupSnapshot, "deleteSnapshotBackup": deleteSnapshotBackup, "createVolumeFromSnapshot": createVolumeFromSnapshot, "unmountSnapshotsDir": unmountSnapshotsDir, "deleteSnapshotsDir": deleteSnapshotsDir, "validateSnapshot" : validateSnapshot})
 | |
| 
 |