| #!/usr/bin/env python3 | |
| # 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. | |
| # Version @VERSION@ | |
| # | |
| # A plugin for executing script needed by vmops cloud | |
| import os, sys, time | |
| import XenAPIPlugin | |
| if os.path.exists("/opt/xensource/sm"): | |
| sys.path.extend(["/opt/xensource/sm/", "/usr/local/sbin/", "/sbin/"]) | |
| if os.path.exists("/usr/lib/xcp/sm"): | |
| sys.path.extend(["/usr/lib/xcp/sm/", "/usr/local/sbin/", "/sbin/"]) | |
| import SR, VDI, SRCommand, util, lvutil | |
| from util import CommandException | |
| import vhdutil | |
| import shutil | |
| import lvhdutil | |
| import errno | |
| import subprocess | |
| import xs_errors | |
| import cleanup | |
| import stat | |
| import random | |
| import cloudstack_pluginlib as lib | |
| import logging | |
| lib.setup_logging("/var/log/cloud/cloud.log") | |
| VHDUTIL = "vhd-util" | |
| VHD_PREFIX = 'VHD-' | |
| CLOUD_DIR = '/var/run/cloud_mount' | |
| def echo(fn): | |
| def wrapped(*v, **k): | |
| name = fn.__name__ | |
| logging.debug("#### CLOUD enter %s ####" % name ) | |
| res = fn(*v, **k) | |
| logging.debug("#### CLOUD exit %s ####" % name ) | |
| return res | |
| return wrapped | |
| @echo | |
| def create_secondary_storage_folder(session, args): | |
| local_mount_path = None | |
| logging.debug("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(CLOUD_DIR, util.gen_uuid()) | |
| nfsVersion = args["nfsVersion"] | |
| mount(remote_mount_path, local_mount_path, nfsVersion) | |
| # 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 as e: | |
| errMsg = "create_secondary_storage_folder failed: errno: " + str(e.errno) + ", strerr: " + e.strerror | |
| logging.debug(errMsg) | |
| raise xs_errors.XenError(errMsg) | |
| except: | |
| errMsg = "create_secondary_storage_folder failed." | |
| logging.debug(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("rmdir " + local_mount_path) | |
| return "1" | |
| @echo | |
| def delete_secondary_storage_folder(session, args): | |
| local_mount_path = None | |
| logging.debug("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(CLOUD_DIR, util.gen_uuid()) | |
| nfsVersion = args["nfsVersion"] | |
| mount(remote_mount_path, local_mount_path, nfsVersion) | |
| # Delete the specified folder | |
| folder = local_mount_path + "/" + args["folder"] | |
| if os.path.isdir(folder): | |
| os.system("rm -f " + folder + "/*") | |
| os.system("rmdir " + folder) | |
| except OSError as e: | |
| errMsg = "delete_secondary_storage_folder failed: errno: " + str(e.errno) + ", strerr: " + e.strerror | |
| logging.debug(errMsg) | |
| raise xs_errors.XenError(errMsg) | |
| except: | |
| errMsg = "delete_secondary_storage_folder failed." | |
| logging.debug(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("rmdir " + local_mount_path) | |
| return "1" | |
| @echo | |
| def post_create_private_template(session, args): | |
| local_mount_path = None | |
| try: | |
| try: | |
| # get local template folder | |
| templatePath = args["templatePath"] | |
| local_mount_path = os.path.join(CLOUD_DIR, util.gen_uuid()) | |
| nfsVersion = args["nfsVersion"] | |
| mount(templatePath, local_mount_path, nfsVersion) | |
| # Retrieve args | |
| filename = args["templateFilename"] | |
| name = args["templateName"] | |
| description = args["templateDescription"] | |
| checksum = args["checksum"] | |
| file_size = args["size"] | |
| virtual_size = args["virtualSize"] | |
| template_id = args["templateId"] | |
| # Create the template.properties file | |
| template_properties_install_path = local_mount_path + "/template.properties" | |
| f = open(template_properties_install_path, "w") | |
| f.write("filename=" + filename + "\n") | |
| f.write("vhd=true\n") | |
| f.write("id=" + template_id + "\n") | |
| f.write("vhd.filename=" + filename + "\n") | |
| f.write("public=false\n") | |
| f.write("uniquename=" + name + "\n") | |
| f.write("vhd.virtualsize=" + virtual_size + "\n") | |
| f.write("virtualsize=" + virtual_size + "\n") | |
| f.write("checksum=" + checksum + "\n") | |
| f.write("hvm=true\n") | |
| f.write("description=" + description + "\n") | |
| f.write("vhd.size=" + str(file_size) + "\n") | |
| f.write("size=" + str(file_size) + "\n") | |
| f.close() | |
| logging.debug("Created template.properties file") | |
| # Set permissions | |
| permissions = stat.S_IREAD | stat.S_IWRITE | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH | stat.S_IWOTH | |
| os.chmod(template_properties_install_path, permissions) | |
| logging.debug("Set permissions on template and template.properties") | |
| except: | |
| errMsg = "post_create_private_template failed." | |
| logging.debug(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("rmdir " + local_mount_path) | |
| return "1" | |
| def isfile(path, isISCSI): | |
| errMsg = '' | |
| exists = True | |
| if isISCSI: | |
| exists = checkVolumeAvailability(path) | |
| else: | |
| exists = os.path.isfile(path) | |
| if not exists: | |
| errMsg = "File " + path + " does not exist." | |
| logging.debug(errMsg) | |
| raise xs_errors.XenError(errMsg) | |
| return errMsg | |
| def copyfile(fromFile, toFile, isISCSI): | |
| logging.debug("Starting to copy " + fromFile + " to " + toFile) | |
| errMsg = '' | |
| if isISCSI: | |
| bs = "4M" | |
| else: | |
| bs = "128k" | |
| try: | |
| cmd = ['dd', 'if=' + fromFile, 'iflag=direct', 'of=' + toFile, 'oflag=direct', 'bs=' + bs] | |
| txt = util.pread2(cmd) | |
| except: | |
| try: | |
| os.system("rm -f " + toFile) | |
| except: | |
| txt = '' | |
| txt = '' | |
| errMsg = "Error while copying " + fromFile + " to " + toFile + " in secondary storage" | |
| logging.debug(errMsg) | |
| raise xs_errors.XenError(errMsg) | |
| logging.debug("Successfully copied " + fromFile + " to " + toFile) | |
| return errMsg | |
| def chdir(path): | |
| try: | |
| os.chdir(path) | |
| except OSError as e: | |
| errMsg = "Unable to chdir to " + path + " because of OSError with errno: " + str(e.errno) + " and strerr: " + e.strerror | |
| logging.debug(errMsg) | |
| raise xs_errors.XenError(errMsg) | |
| logging.debug("Chdired to " + path) | |
| 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 | |
| logging.debug(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 | |
| logging.debug(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: | |
| checkVolumeAvailability(snapshotPath) | |
| baseCopyUuid = scanParent(snapshotPath) | |
| else: | |
| baseCopyUuid = getParent(snapshotPath, isISCSI) | |
| logging.debug("Base copy of snapshotUuid: " + snapshotUuid + " is " + baseCopyUuid) | |
| return baseCopyUuid | |
| def setParent(parent, child): | |
| try: | |
| cmd = [VHDUTIL, "modify", "-p", parent, "-n", child] | |
| txt = util.pread2(cmd) | |
| except: | |
| errMsg = "Unexpected error while trying to set parent of " + child + " to " + parent | |
| logging.debug(errMsg) | |
| raise xs_errors.XenError(errMsg) | |
| logging.debug("Successfully set parent of " + child + " to " + parent) | |
| return | |
| def rename(originalVHD, newVHD): | |
| try: | |
| os.rename(originalVHD, newVHD) | |
| except OSError as e: | |
| errMsg = "OSError while renaming " + origiinalVHD + " to " + newVHD + "with errno: " + str(e.errno) + " and strerr: " + e.strerror | |
| logging.debug(errMsg) | |
| raise xs_errors.XenError(errMsg) | |
| return | |
| def makedirs(path): | |
| if not os.path.isdir(path): | |
| try: | |
| os.makedirs(path) | |
| except OSError as e: | |
| umount(path) | |
| if os.path.isdir(path): | |
| return | |
| errMsg = "OSError while creating " + path + " with errno: " + str(e.errno) + " and strerr: " + e.strerror | |
| logging.debug(errMsg) | |
| raise xs_errors.XenError(errMsg) | |
| return | |
| def mount(remoteDir, localDir, nfsVersion=None): | |
| makedirs(localDir) | |
| options = "soft,tcp,timeo=133,retrans=1" | |
| if nfsVersion: | |
| options += ",vers=" + nfsVersion | |
| try: | |
| cmd = ['mount', '-o', options, remoteDir, localDir] | |
| txt = util.pread2(cmd) | |
| except: | |
| txt = '' | |
| errMsg = "Unexpected error while trying to mount " + remoteDir + " to " + localDir | |
| logging.debug(errMsg) | |
| raise xs_errors.XenError(errMsg) | |
| logging.debug("Successfully mounted " + remoteDir + " to " + localDir) | |
| return | |
| def umount(localDir): | |
| try: | |
| cmd = ['umount', localDir] | |
| util.pread2(cmd) | |
| except CommandException: | |
| errMsg = "CommandException raised while trying to umount " + localDir | |
| logging.debug(errMsg) | |
| raise xs_errors.XenError(errMsg) | |
| logging.debug("Successfully unmounted " + localDir) | |
| return | |
| def mountSnapshotsDir(secondaryStorageMountPath, localMountPointPath, path): | |
| # The aim is to mount secondaryStorageMountPath on | |
| # And create <accountId>/<instanceId> dir on it, if it doesn't exist already. | |
| # Assuming that secondaryStorageMountPath exists remotely | |
| # Just mount secondaryStorageMountPath/<relativeDir>/SecondaryStorageHost/ everytime | |
| # Never unmount. | |
| # path is like "snapshots/account/volumeId", we mount secondary_storage:/snapshots | |
| relativeDir = path.split("/")[0] | |
| restDir = "/".join(path.split("/")[1:]) | |
| snapshotsDir = os.path.join(secondaryStorageMountPath, relativeDir) | |
| makedirs(localMountPointPath) | |
| # if something is not mounted already on localMountPointPath, | |
| # mount secondaryStorageMountPath on localMountPath | |
| if os.path.ismount(localMountPointPath): | |
| # There is more than 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. | |
| logging.debug("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, restDir) | |
| makedirs(backupsDir) | |
| return backupsDir | |
| def unmountAll(path): | |
| try: | |
| for dir in os.listdir(path): | |
| if dir.isdigit(): | |
| logging.debug("Unmounting Sub-Directory: " + dir) | |
| localMountPointPath = os.path.join(path, dir) | |
| umount(localMountPointPath) | |
| except: | |
| logging.debug("Ignoring the error while trying to unmount the snapshots dir") | |
| @echo | |
| def unmountSnapshotsDir(session, args): | |
| dcId = args['dcId'] | |
| localMountPointPath = os.path.join(CLOUD_DIR, dcId) | |
| localMountPointPath = os.path.join(localMountPointPath, "snapshots") | |
| unmountAll(localMountPointPath) | |
| try: | |
| umount(localMountPointPath) | |
| except: | |
| logging.debug("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 getBackupVHD(UUID): | |
| return UUID + '.' + SR.DEFAULT_TAP | |
| 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 | |
| logging.debug("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" | |
| logging.debug(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 checkVolumeAvailability(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 | |
| logging.debug(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: | |
| logging.debug("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: | |
| logging.debug("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 | |
| logging.debug(errMsg) | |
| raise xs_errors.XenError(errMsg) | |
| return (status == "1") | |
| def getVhdParent(session, args): | |
| logging.debug("getParent with " + str(args)) | |
| primaryStorageSRUuid = args['primaryStorageSRUuid'] | |
| snapshotUuid = args['snapshotUuid'] | |
| isISCSI = getIsTrueString(args['isISCSI']) | |
| primarySRPath = getPrimarySRPath(primaryStorageSRUuid, isISCSI) | |
| logging.debug("primarySRPath: " + primarySRPath) | |
| baseCopyUuid = getParentOfSnapshot(snapshotUuid, primarySRPath, isISCSI) | |
| return baseCopyUuid | |
| def getSnapshotSize(session, args): | |
| primaryStorageSRUuid = args['primaryStorageSRUuid'] | |
| snapshotUuid = args['snapshotUuid'] | |
| isISCSI = getIsTrueString(args['isISCSI']) | |
| primarySRPath = getPrimarySRPath(primaryStorageSRUuid, isISCSI) | |
| logging.debug("primarySRPath: " + primarySRPath) | |
| snapshotVHD = getVHD(snapshotUuid, isISCSI) | |
| snapshotPath = os.path.join(primarySRPath, snapshotVHD) | |
| physicalSize = vhdutil.getSizePhys(snapshotPath) | |
| return str(physicalSize) | |
| def backupSnapshot(session, args): | |
| logging.debug("Called backupSnapshot with " + str(args)) | |
| primaryStorageSRUuid = args['primaryStorageSRUuid'] | |
| secondaryStorageMountPath = args['secondaryStorageMountPath'] | |
| snapshotUuid = args['snapshotUuid'] | |
| prevBackupUuid = args['prevBackupUuid'] | |
| backupUuid = args['backupUuid'] | |
| isISCSI = getIsTrueString(args['isISCSI']) | |
| path = args['path'] | |
| localMountPoint = args['localMountPoint'] | |
| primarySRPath = getPrimarySRPath(primaryStorageSRUuid, isISCSI) | |
| logging.debug("primarySRPath: " + primarySRPath) | |
| baseCopyUuid = getParentOfSnapshot(snapshotUuid, primarySRPath, isISCSI) | |
| baseCopyVHD = getVHD(baseCopyUuid, isISCSI) | |
| baseCopyPath = os.path.join(primarySRPath, baseCopyVHD) | |
| logging.debug("Base copy path: " + baseCopyPath) | |
| # 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, localMountPoint, path) | |
| logging.debug("Backups dir " + backupsDir) | |
| prevBackupUuid = prevBackupUuid.split("/")[-1] | |
| # Check existence of snapshot on primary storage | |
| isfile(baseCopyPath, isISCSI) | |
| physicalSize = vhdutil.getSizePhys(baseCopyPath) | |
| if prevBackupUuid: | |
| # Check existence of prevBackupFile | |
| prevBackupVHD = getBackupVHD(prevBackupUuid) | |
| prevBackupFile = os.path.join(backupsDir, prevBackupVHD) | |
| isfile(prevBackupFile, False) | |
| # copy baseCopyPath to backupsDir with new uuid | |
| backupVHD = getBackupVHD(backupUuid) | |
| backupFile = os.path.join(backupsDir, backupVHD) | |
| logging.debug("Back up " + baseCopyUuid + " to Secondary Storage as " + backupUuid) | |
| copyfile(baseCopyPath, backupFile, isISCSI) | |
| vhdutil.setHidden(backupFile, False) | |
| # 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 | |
| setParent(prevBackupFile, backupFile) | |
| txt = "1#" + backupUuid + "#" + str(physicalSize) | |
| return txt | |
| @echo | |
| def deleteSnapshotBackup(session, args): | |
| logging.debug("Calling deleteSnapshotBackup with " + str(args)) | |
| secondaryStorageMountPath = args['secondaryStorageMountPath'] | |
| backupUUID = args['backupUUID'] | |
| path = args['path'] | |
| localMountPoint = args['localMountPoint'] | |
| backupsDir = mountSnapshotsDir(secondaryStorageMountPath, localMountPoint, path) | |
| # chdir to the backupsDir for convenience | |
| chdir(backupsDir) | |
| backupVHD = getBackupVHD(backupUUID) | |
| logging.debug("checking existence of " + backupVHD) | |
| # The backupVHD is on secondary which is NFS and not ISCSI. | |
| if not os.path.isfile(backupVHD): | |
| logging.debug("backupVHD " + backupVHD + "does not exist. Not trying to delete it") | |
| return "1" | |
| logging.debug("backupVHD " + backupVHD + " exists.") | |
| # Just delete the backupVHD | |
| try: | |
| os.remove(backupVHD) | |
| except OSError as e: | |
| errMsg = "OSError while removing " + backupVHD + " with errno: " + str(e.errno) + " and strerr: " + e.strerror | |
| logging.debug(errMsg) | |
| raise xs_errors.XenError(errMsg) | |
| return "1" | |
| @echo | |
| def revert_memory_snapshot(session, args): | |
| logging.debug("Calling revert_memory_snapshot with " + str(args)) | |
| vmName = args['vmName'] | |
| snapshotUUID = args['snapshotUUID'] | |
| oldVmUuid = args['oldVmUuid'] | |
| snapshotMemory = args['snapshotMemory'] | |
| hostUUID = args['hostUUID'] | |
| try: | |
| cmd = '''xe vbd-list vm-uuid=%s | grep 'vdi-uuid' | grep -v 'not in database' | sed -e 's/vdi-uuid ( RO)://g' ''' % oldVmUuid | |
| vdiUuids = os.popen(cmd).read().split() | |
| cmd2 = '''xe vm-param-get param-name=power-state uuid=''' + oldVmUuid | |
| if os.popen(cmd2).read().split()[0] != 'halted': | |
| os.system("xe vm-shutdown force=true vm=" + vmName) | |
| os.system("xe vm-destroy uuid=" + oldVmUuid) | |
| os.system("xe snapshot-revert snapshot-uuid=" + snapshotUUID) | |
| if snapshotMemory == 'true': | |
| os.system("xe vm-resume vm=" + vmName + " on=" + hostUUID) | |
| for vdiUuid in vdiUuids: | |
| os.system("xe vdi-destroy uuid=" + vdiUuid) | |
| except OSError as e: | |
| errMsg = "OSError while reverting vm " + vmName + " to snapshot " + snapshotUUID + " with errno: " + str(e.errno) + " and strerr: " + e.strerror | |
| logging.debug(errMsg) | |
| raise xs_errors.XenError(errMsg) | |
| return "0" | |
| if __name__ == "__main__": | |
| XenAPIPlugin.dispatch({"getVhdParent":getVhdParent, "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, "unmountSnapshotsDir": unmountSnapshotsDir, "revert_memory_snapshot":revert_memory_snapshot, "getSnapshotSize":getSnapshotSize}) |