cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From edi...@apache.org
Subject [1/2] fix devcloud: get back whatever we have before
Date Thu, 09 Jan 2014 23:26:16 GMT
Updated Branches:
  refs/heads/4.3 d11560d27 -> 9583c47a3


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/9583c47a/scripts/vm/hypervisor/xenserver/xcposs/vmopsSnapshot
----------------------------------------------------------------------
diff --git a/scripts/vm/hypervisor/xenserver/xcposs/vmopsSnapshot b/scripts/vm/hypervisor/xenserver/xcposs/vmopsSnapshot
new file mode 100644
index 0000000..53f31a9
--- /dev/null
+++ b/scripts/vm/hypervisor/xenserver/xcposs/vmopsSnapshot
@@ -0,0 +1,601 @@
+#!/usr/bin/python
+# 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
+sys.path.append("/usr/lib/xcp/sm/")
+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
+
+VHD_UTIL = 'vhd-util'
+VHD_PREFIX = 'VHD-'
+CLOUD_DIR = '/run/cloud_mount'
+
+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(CLOUD_DIR, util.gen_uuid())
+            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("rmdir " + 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(CLOUD_DIR, util.gen_uuid())
+            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 -f " + folder + "/*")
+                os.system("rmdir " + 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("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())
+            mount(templatePath, local_mount_path)
+            # 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()
+            util.SMlog("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)
+            util.SMlog("Set permissions on template and template.properties")
+
+        except:
+            errMsg = "post_create_private_template 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("rmdir " + 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 = ''
+    try:
+        cmd = ['dd', 'if=' + fromFile, 'of=' + toFile, 'bs=4M']
+        txt = util.pread2(cmd)
+    except:
+        try:
+            os.system("rm -f " + toFile)
+        except:
+            txt = ''
+        txt = ''
+        errMsg = "Error while copying " + fromFile + " to " + toFile + " in secondary storage"
+        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 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 makedirs(path):
+    if not os.path.isdir(path):
+        try:
+            os.makedirs(path)
+        except OSError, (errno, strerror):
+            umount(path)
+            if os.path.isdir(path):
+                return
+            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)
+    options = "soft,tcp,timeo=133,retrans=1"
+    try: 
+        cmd = ['mount', '-o', options, 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):
+    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)
+    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.
+        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, restDir)
+    makedirs(backupsDir)
+    return backupsDir
+
+def unmountAll(path):
+    try:
+        for dir in os.listdir(path):
+            if dir.isdigit():
+                util.SMlog("Unmounting Sub-Directory: " + dir)
+                localMountPointPath = os.path.join(path, dir)
+                umount(localMountPointPath)
+    except:
+        util.SMlog("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:
+        util.SMlog("Ignoring the error while trying to unmount the snapshots dir.")
+
+    return "1"
+
+def getPrimarySRPath(session, primaryStorageSRUuid, isISCSI):
+    sr = session.xenapi.SR.get_by_uuid(primaryStorageSRUuid)
+    srrec = session.xenapi.SR.get_record(sr)
+    srtype = srrec["type"]
+    if srtype == "file":
+        pbd = session.xenapi.SR.get_PBDs(sr)[0]
+        pbdrec = session.xenapi.PBD.get_record(pbd)
+        primarySRPath = pbdrec["device_config"]["location"]
+        return primarySRPath
+    elif 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
+    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 getVhdParent(session, args):
+    util.SMlog("getParent with " + str(args))
+    primaryStorageSRUuid      = args['primaryStorageSRUuid']
+    snapshotUuid              = args['snapshotUuid']
+    isISCSI                   = getIsTrueString(args['isISCSI']) 
+
+    primarySRPath = getPrimarySRPath(session, primaryStorageSRUuid, isISCSI)
+    util.SMlog("primarySRPath: " + primarySRPath)
+
+    baseCopyUuid = getParentOfSnapshot(snapshotUuid, primarySRPath, isISCSI)
+
+    return  baseCopyUuid
+
+
+def backupSnapshot(session, args):
+    util.SMlog("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(session, 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)
+
+
+    # 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)
+    util.SMlog("Backups dir " + backupsDir)
+    prevBackupUuid = prevBackupUuid.split("/")[-1]
+    # Check existence of snapshot on primary storage
+    isfile(baseCopyPath, isISCSI)
+    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)
+    util.SMlog("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
+    return txt
+
+@echo
+def deleteSnapshotBackup(session, args):
+    util.SMlog("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)
+    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.")
+        
+    # 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 revert_memory_snapshot(session, args):
+    util.SMlog("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, (errno, strerror):
+        errMsg = "OSError while reverting vm " + vmName + " to snapshot " + snapshotUUID
+ " with errno: " + str(errno) + " and strerr: " + strerror
+        util.SMlog(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})
+    
+


Mime
View raw message