Différences entre les versions de « Migration VM de kvm vers hyperv »
De BlaxWiki
Aller à la navigationAller à la recherche| Ligne 2 : | Ligne 2 : | ||
Ce script sert à migrer | Ce script sert à migrer | ||
=== Infos === | |||
=== Script === | |||
Version du 11 mars 2019 à 10:51
_TOC_ Ce script sert à migrer
Infos
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()