Différences entre les versions de « Migration VM de kvm vers hyperv »

De BlaxWiki
Aller à la navigationAller à la recherche
(Page créée avec « _TOC_CONTENTS Ce script sert à migrer ### Infos ### ### Script ### <pre> #!/usr/bin/env python from optparse import OptionParser import logging, subprocess, os, err... »)
 
Ligne 1 : Ligne 1 :
_TOC_CONTENTS
_TOC_
Ce script sert à migrer  
Ce script sert à migrer  



Version du 11 mars 2019 à 10:50

_TOC_ Ce script sert à migrer

      1. Infos ###
      1. Script ###



#!/usr/bin/env python
from optparse import OptionParser
import logging, subprocess, os, errno, atexit, time, re, tempfile
import xml.etree.ElementTree

logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', level=logging.INFO)
force_flag=False

#
srcVM=""
dstPath=""
noCopy_flag=False
doNotClean_flag=False
exportedRaw=[]
mountedPartPath=[]

def main():
    global srcVM, noCopy_flag, doNotClean_flag
    parser = OptionParser(usage="usage: %prog [options] VMname", version="%prog 1.0")
    parser.add_option("-f", "--force",
                      action="store_true",
                      dest="force_flag",
                      default=False,
                      help="force")
    parser.add_option("-n", "--no-copy",
                      action="store_true",
                      dest="noCopy_flag",
                      default=False,
                      help="Do not copy disk")
    parser.add_option("-d", "--debug",
                      action="store_true",
                      dest="debug_flag",
                      default=False,
                      help="Print debug")
    parser.add_option("-X", "--no-clean",
                      action="store_true",
                      dest="noclean_flag",
                      default=False,
                      help="No umount/no kpartx -d")

    (options, args) = parser.parse_args()

    if len(args) != 1:
        parser.error("wrong number of arguments")

    logging.debug("Starting script")
    srcVM=args[0]
    noCopy_flag=options.noCopy_flag
    doNotClean_flag=options.noclean_flag
    if options.debug_flag:
        logging.getLogger().setLevel(logging.DEBUG)
    check_VM()
    exportXML()
    copyDisk()
    systemPart=getSystemPartition()
    if not systemPart:
        logging.critical("Could not find system partition")
        exit()
    linux_vers=detectLinuxVersion(systemPart)
    if linux_vers == "unknown":
        logging.critical("Could not determine Linux Version")
        exit()
    logging.info("VM - Linux Version : {0}".format(linux_vers))
    filesPath=dstPath+"/files"
    if not os.path.exists(filesPath):
        try:
            os.makedirs(filesPath)
        except OSError as e:
            logging.critical("main: Error creating {0} : {1}".format(filesPath,e))
            exit()

            #TODO : faire le reste
        # modifie le fstab
        #refait le truc udev
        #installe un nouveau kernel
        #refait le grub.conf bien


def check_VM():
    """Check existence of the VM"""
    logging.debug("check_VM: Checking VM existence with virsh list")
    proc = subprocess.Popen(['/usr/bin/virsh','list --all --name'], stdout=subprocess.PIPE)
    tmp = proc.stdout.read()
    VMs = tmp.splitlines()
    logging.debug("check_VM: Found {0} VM on HV".format(len(VMs)))
    if srcVM in VMs:
        logging.info("check_VM: Found VM : {0}".format(srcVM))
    else:
        logging.critical("check_VM: VM {0} not found on this HV".format(srcVM))
        exit()

def exportXML():
    """Export libvirt XML config to /export"""
    global dstPath
    dstPath = "/export/{0}".format(srcVM)
    logging.debug("exportXML: Checking dir")
    if not os.path.exists(dstPath):
        logging.debug("exportXML: {0} does not exist, creating it".format(dstPath))
        try:
            os.makedirs(dstPath)
        except OSError as e:
            logging.critical("exportXML: Error creating {0} : {1}".format(dstPath,e))
            exit()
    else:
        logging.debug("exportXML: {0} exists".format(dstPath))
    logging.info("exportXML: exporting VM conf")
    os.system("/usr/bin/virsh dumpxml {0} > {1}/{0}.xml".format(srcVM, dstPath))

def copyDisk():
    """Read XML conf to find all disk and copy them to export"""
    global exportedRaw
    disks=[]
    logging.info("copyDisk: Searching for disk in XML")
    tree = xml.etree.ElementTree.parse("{0}/{1}.xml".format(dstPath,srcVM))
    root = tree.getroot()
    for vmdisk in root.findall("./devices/disk"):
        if vmdisk.attrib['device'] == 'disk':
                srcDiskPath=vmdisk.find('source').attrib['dev']
                logging.info("copyDisk: Found disk {0}".format(srcDiskPath))
                disks.append(srcDiskPath)
    for disk in disks:
        dstRaw="{0}/{1}.raw".format(dstPath,os.path.basename(disk))
        logging.info("copyDisk : Copying {0} to {1}".format(disk,dstRaw))
        exportedRaw.append(dstRaw)
        if noCopy_flag:
            logging.info("copyDisk : option no-copy - skipping disk")
        else:
            #os.system("/bin/dd if={0} of={1} bs=2M".format(disk,dstRaw))
            logging.info("copyDisk : temp")

def getSystemPartition():
    """Mount the system partition of the VM and return the path"""
    logging.info("mountSystemPartition : Searching & mounting VM root partition")
    for raw in exportedRaw:
        logging.debug("mountSystemPartition : Searching {0}".format(raw))
        mappings=run_kpartx(raw)
        for mapping in mappings:
            path="/dev/mapper/{0}".format(mapping)
            # if kpartx fails
            if not os.path.exists(path):
                logging.critical("mountSystemPartition : {0} does not exist ! kpartx error?".format(path))
                exit()
            # Verify that there is a filesystem on the mapping
            proc = subprocess.Popen(['/usr/bin/file','-s',path], stdout=subprocess.PIPE)
            tmp = proc.stdout.read()
            if "filesystem" not in tmp:
                logging.debug("mountSystemPartition : ignoring {0} file return : \"{1}\"".format(path,tmp))
            else:
                tmpDir=tempfile.mkdtemp()
                logging.debug("mountSystemPartition : mounting {0} file on {1}".format(path,tmpDir))
                os.system("/bin/mount {0} {1}".format(path,tmpDir))
                if not doNotClean_flag: atexit.register(undo_mount,tmpDir)

                if os.path.exists(tmpDir+"/etc/passwd"):
                    logging.info("mountSystemPartition : Found system partition : {0}".format(path))
                    return tmpDir
    return

def run_kpartx(raw):
    """Run kpartx and return a list of partition mappings"""
    cleanMappings = []
    proc = subprocess.Popen(['/sbin/kpartx','-av','{0}'.format(raw)], stdout=subprocess.PIPE)
    tmp = proc.stdout.read()
    output = tmp.splitlines()
    if not doNotClean_flag: atexit.register(undo_kpartx,raw)
    mapping_regex = re.compile(r'^add map ')
    mappings = filter(mapping_regex.search, output)
    for mapping in mappings:
        m=mapping.split()[2]
        logging.debug("run_kpartx : Mapping created : {0}".format(m))
        cleanMappings.append(m)
    return cleanMappings

def undo_kpartx(raw):
    logging.debug("undo_kpartx : unmapping {0}".format(raw))
    time.sleep(1)
    os.system("kpartx -d {0} > /dev/null".format(raw))

def undo_mount(tmpDir):
    logging.debug("undo_mount : unmounting {0}".format(tmpDir))
    os.system("/bin/umount {0}".format(tmpDir))
    os.system("/bin/rmdir {0}".format(tmpDir))

def detectLinuxVersion(root):
    """return centos6/centos7/debian7 or unknown"""
    if os.path.exists(root+"/etc/redhat-release"):
        file=open(root+"/etc/redhat-release", "r")
        line=file.readline()
        file.close()
        if line.startswith("CentOS release 6"):
            return "centos6"
        if line.startswith("CentOS Linux release 7"):
            return "centos7"
    if os.path.exists(root+"/etc/debian_version"):
        file=open(root+"/etc/debian_version", "r")
        line=file.readline()
        file.close()
        if line.startswith("7."):
            return "debian7"
    return "unknown"

def changeFstab(root,filespath):
    logging.debug("changeFstab : Copying original file to {0}/fstab.orig".format(filespath))
    os.system("/bin/cp {0}/etc/fstab {1}/fstab.orig".format(root,filespath))


if __name__ == '__main__':
    main()