# -*- coding: utf-8 -*- import subprocess import socket import guestfs import re import libvirt from xml.etree.ElementTree import * import logging import os import time def clone(args): image = args["image"] hostname = args["hostname"] format = None if args.has_key("format"): format = args["format"] conn = libvirt.open(None) dom = conn.lookupByName(image) desc = fromstring(dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)) sources = [] for disk in desc.findall(".//disk"): if disk.get("device") == "disk": sources.append(disk.find(".//source").get("file")) target_paths = [] for source in sources: target_file = os.path.basename(source) target_file = target_file.replace(image, hostname) target_dir = _select_most_free_dir(conn) if not target_dir: target_dir = os.path.dirname(source) target_paths.append(os.path.join(target_dir, target_file)) cmdline = [ "virt-clone", "-o", image, "-n", hostname, ] for path in target_paths: cmdline.append("-f") cmdline.append(path) proc = subprocess.Popen( cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = proc.communicate() message = None status = 1 if proc.returncode: status = 2 message = stderr g = guestfs.GuestFS() for path in target_paths: g.add_drive(path) g.launch() roots = g.inspect_os() mountpoints = g.inspect_get_mountpoints(roots[0]) mountpoints.sort() for mountpoint in mountpoints: g.mount(mountpoint[1], mountpoint[0]) ostype = None if g.exists('/etc/redhat-release'): ostype = 'redhat' elif g.exists('/etc/debian_version'): ostype = 'debian' # TODO: OS 毎に別モジュールにする if ostype == 'redhat': ifcfg = '''DEVICE=%s BOOTPROTO=dhcp ONBOOT=yes TYPE="Ethernet" DHCP_HOSTNAME=%s ''' network = '''NETWORKING=yes HOSTNAME=%s ''' ifcfg0 = ifcfg % ('eth0', hostname) network = network % (hostname) g.write_file('/etc/sysconfig/network-scripts/ifcfg-eth0', ifcfg0, 0) g.write_file('/etc/sysconfig/network', network, 0) g.write_file('/etc/udev/rules.d/70-persistent-net.rules', '', 0) if g.exists('/etc/sysconfig/network-scripts/ifcfg-eth1'): ifcfg1 = ifcfg % ('eth1', re.sub(r"\.pb$", ".pblan", hostname)) g.write_file( '/etc/sysconfig/network-scripts/ifcfg-eth1', ifcfg1, 0) elif ostype == 'debian': g.write_file('/etc/hosts', '127.0.0.1 localhost', 0) g.write_file('/etc/hostname', hostname, 0) g.write_file('/etc/udev/rules.d/70-persistent-net.rules', '', 0) interface = ''' interface "%s" { send host-name "%s"; } ''' eth0 = interface % ('eth0', hostname) eth1 = interface % ('eth1', re.sub(r"\.pb$", ".pblan", hostname)) conf = g.read_file('/etc/dhcp/dhclient.conf') g.write_file('/etc/dhcp/dhclient.conf', conf + eth0 + eth1, 0) shadow = g.read_file("/etc/shadow") g.write_file("/etc/shadow", re.sub( r"^root:[^:]+:", "root:$1$ZJsvbRbB$dWzQZuu8dDFR8wr6PTPjp0:", shadow), 0) if format == "vmdk": grub = g.read_file("/boot/grub/grub.conf") g.write_file("/boot/grub/grub.conf", re.sub( r"console=[^\s]+", "", grub), 0) g.sync() g.umount_all() dom = conn.lookupByName(hostname) if args["start"] and format != "vmdk": dom.create() if format == "vmdk": vmdk_path = "/var/www/html/maglica/%s.vmdk" % hostname cmdline = [ "qemu-img", "convert", "-f", "raw", "-O", "vmdk", target_paths[0], vmdk_path, ] proc = subprocess.Popen( cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = proc.communicate() if proc.returncode: status = 2 message = stderr else: message = "Get vmdk file from http://%s/maglica/%s.vmdk" % ( socket.gethostname(), hostname) remove({"name": hostname}) if status == 1 and not message: message = "%s was cloned from %s on %s successfully" % ( hostname, image, socket.gethostname()) return { "message": message, "status": status, } def remove(args): conn = libvirt.open(None) dom = conn.lookupByName(args["name"]) desc = fromstring(dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)) for disk in desc.findall(".//disk"): if disk.get("device") == "disk": file = disk.find(".//source").get("file") os.remove(file) dom.undefine() return { "message": "%s removed successfully" % args["name"], "status": 1, } def attach_disk(args): conn = libvirt.open(None) name = args["name"] size = int(args["size"]) dom = conn.lookupByName(name) devs = [] desc = fromstring(dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)) for disk in desc.findall(".//disk"): if disk.get("device") == "disk": dev = disk.find(".//target").get("dev") if re.match(r'^vd', dev): devs.append(dev) devs.sort() if len(devs) > 0: dev = devs[-1] last_char = chr(ord(dev[-1]) + 1) dev = 'vd' + last_char else: dev = 'vda' dir = _select_most_free_dir(conn) if not dir: dir = "/var/lib/libvirt/images" path = os.path.join(dir, name + "-" + str(time.time())) _create_raw_image(path, size) xml = ''' <disk type='file' device='disk'> <driver name='qemu' type='raw' cache='none'/> <source file='%s' /> <target dev='%s' bus='virtio'/> </disk> ''' xml = xml % (path, dev) dom.attachDevice(xml) desc.find(".//devices").insert(-1, fromstring(xml)) conn.defineXML(tostring(desc)) return { "message": "%s kbytes disk attached to %s as /dev/%s successfully" % (size, name, dev), "status": 1, } def _select_most_free_dir(conn): current_free_size = 0 pools = conn.listStoragePools() most_free_dir = None for pool in pools: desc = fromstring(conn.storagePoolLookupByName(pool).XMLDesc(0)) path = desc.find(".//path").text s = os.statvfs(path) free_size = s.f_bsize * s.f_bfree if free_size > current_free_size: most_free_dir = path current_free_size = free_size return most_free_dir def _create_raw_image(path, size): cmd = ['qemu-img', 'create', '-f', 'raw', path, str(size * 1024)] proc = subprocess.call(cmd)