def revert(self): time.sleep(2.0) sh.virsh("snapshot-revert", dom.name, "--snapshotname", self.sname, "--force") sh.virsh("snapshot-delete", dom.name, self.sname) debug("Deleted snap %r of dom %r" % (self.sname, dom.name))
def reboot(self, wait=True, timeout=90): """Ask the VM to reboot (via ACPI) """ self.ssh("systemctl reboot &") sh.virsh("reboot", "--mode=acpi", self.name) if wait: self.wait_event("reboot", timeout=timeout)
def _rm(name): log.info("Removing %s" % name) try: sh.virsh("destroy", name) except: pass sh.virsh("undefine", name)
def undefine(self): """Remove a VM definition and it's snapshots """ try: self.destroy() except Exception: pass sh.virsh("undefine", "--snapshots-metadata", self.name)
def __init__(self): sh.virsh("snapshot-create-as", dom.name) self.sname = str(sh.virsh("snapshot-current", "--name", dom.name)).strip() debug("Created snap %r of dom %r" % (self.sname, dom.name)) # Snapshots just use seconds, sometimes we have more than # one snap per second, thus we add an extra sleep to prevent # snap-id collisions time.sleep(2.0)
def revert(self): time.sleep(2.0) sh.virsh("snapshot-revert", dom.name, "--snapshotname", self.sname, "--force") if self.remove: sh.virsh("snapshot-delete", dom.name, self.sname) debug("Deleted snap %r of dom %r" % (self.sname, dom.name))
def start(self): """Start the VM """ sh.virsh("start", self.name) try: self.wait_event(timeout=5) except: pass
def shutdown(self, wait=True, timeout=300): """Ask the VM to shutdown (via ACPI) Also block until the VM is shutdown """ with self.wait_event_ctx("lifecycle", timeout=timeout): self.run("systemctl", "poweroff", "&") sh.virsh("shutdown", "--mode=acpi", self.name)
def wait_event(self, evnt=None, timeout=None): """Wait for a event of a VM virsh event --help """ args = ["--event", evnt] if evnt else ["--all"] if timeout: args += ["--timeout", timeout] sh.virsh("event", "--domain", self.name, *args)
def shutdown(self, wait=True, timeout=90): """Ask the VM to shutdown (via ACPI) Also block until the VM is shutdown """ self.ssh("systemctl poweroff &") sh.virsh("shutdown", "--mode=acpi", self.name) if wait: self.wait_event("lifecycle", timeout=timeout)
def create_vm(self, xml_config_path=""): """ Create the actual VM with virsh with hostname """ if not os.path.exists(xml_config_path): sys.exit("Error opening %s" % (xml_config_path)) with sh.sudo: sh.virsh("create", xml_config_path)
def cmd_virsh_launch(): vms = output(virsh('list', '--all')).split('\n') # virsh output: # # Id Name State # ---------------------------------------------------- # - foobar shut off vms = (vm.strip() for vm in vms[2:]) vms = (re.split(' {2,}', i) for i in vms) names = [i[1] for i in vms] name = output(dmenu(names)) virsh('start', name)
def console(self): """Attach to the VM serial console """ pty = str(sh.virsh("ttyconsole", self.name)).strip() with open(pty, "rb") as src: for line in src: yield line
def do_add_network(args): log.info("Adding network %s" % args.NAME) print(args.subnet.netmask) netmask = args.subnet.netmask network_ip = args.subnet.network_address broadcast_ip = args.subnet.broadcast_address def_string = """ <network> <name>%s</name> <bridge name="vocker-%s" /> <ip address="%s" netmask="%s"> <dhcp> <range start="%s" end="%s" /> </dhcp> </ip> </network> """ % (args.NAME, args.NAME, network_ip + 1, netmask, network_ip + 2, broadcast_ip - 1) with tempfile.NamedTemporaryFile(delete=True) as net_def: net_def.write(def_string.encode()) net_def.flush() print(sh.virsh("net-create", net_def.name))
def _hotplug_empty_disk(self): self._tmpdir = tempfile.mkdtemp() sh.chmod("o+rwx", self._tmpdir) self._tmpdisk = os.path.join(self._tmpdir, "tmpdisk.img") sh.dd("if=/dev/null", "bs=1K", "of={}".format(self._tmpdisk), "seek=1030") sh.Command("mkfs.ntfs")("-F", self._tmpdisk) disk_file = os.path.join(self._tmpdir, "disk.xml") with open(disk_file, "wb") as f: f.write(""" <disk type="file" device="disk"> <driver name="qemu" type="raw" cache="none" io="native"/> <source file="{}"/> <target dev="sda" bus="usb"/> </disk> """.format(self._tmpdisk)) sh.virsh("attach-device", self._domain, disk_file)
def __get_host_count(self, host_type=""): """ Get the current number of VMs running that match host_type string """ hosts = 0 if host_type: hosts = sh.wc(sh.awk(sh.grep(sh.virsh('list', '--all'), '%s' % host_type), '{print $2}'), '-l') else: sys.exit("Can't count non-existant host_type") return str(hosts).rstrip()
def do_rm_network(args): log.info("Removing network %s" % args.NAME) print(sh.virsh("net-destroy", args.NAME))
def destroy(self): """Forefully shutdown a VM """ sh.virsh("destroy", self.name)
def do_list_networks(args): print(sh.virsh("net-list"))
def create_vm(self, new_xml=""): """ use virsh to start the new vm """ sh.virsh('create', '%s' % (new_xml))
def get_virsh_nics(self): command = ['-c', 'qemu:///system', 'domiflist', self._domain_uuid ] ret = virsh(command) return ret
def do_run(args): log.info("Instanciating %s as %s" % (args.IMAGE, args.name)) diskname = args.IMAGE + "-" + args.name image = Layer() image.name = args.IMAGE disk = image.derive(diskname) disk.create() if args.net != "user": args.net = "network=%s" % args.net # FIXME set the hostname inside the VM if args.hack_hostname: fish(disk.filename, "write", "/etc/hostname", args.name) xml = virt_install("--name", args.name, "--memory", args.memory, "--vcpus", "4", "--metadata", "description=vocker/%s" % args.name, "--import", "--disk", disk.filename, "--network", args.net, "--graphics", "spice", "--memballoon", "model=virtio", "--rng", "/dev/random", "--noautoconsole", "--print-xml") # Decode it right away xml = str(xml).encode("UTF-8") if args.publish: hostport, innerport = args.publish.split(":") def random_mac(): """Generate a random mac """ mac = [ 0x00, 0x16, 0x3e, random.randint(0x00, 0x7f), random.randint(0x00, 0xff), random.randint(0x00, 0xff) ] return ':'.join(map(lambda x: "%02x" % x, mac)) domroot = ET.fromstring(xml) # Needed to make guest ssh port accessible from the outside # http://blog.vmsplice.net/2011/04/ # how-to-pass-qemu-command-line-options.html ET.register_namespace( "qemu", "http://libvirt.org/" "schemas/domain/qemu/1.0") snippet = ET.fromstring(""" <qemu:commandline xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"> <qemu:arg value='-redir'/> <qemu:arg value='tcp:{hostport}::{innerport}'/> <qemu:arg value='-netdev'/> <qemu:arg value='socket,id=busnet0,mcast=230.0.0.1:1234'/> <qemu:arg value='-device'/> <qemu:arg value='virtio-net-pci,netdev=busnet0,mac={mac}'/> </qemu:commandline> """.format(hostport=hostport, innerport=innerport, mac=random_mac())) domroot.append(snippet) xml = ET.tostring(domroot) with tempfile.NamedTemporaryFile("wb") as spec: spec.write(xml) spec.flush() sh.virsh("define", spec.name) sh.virsh("start", args.name) print(args.name) if args.i: _attach(args.name) if args.rm: _rm(args.name)
def get_virsh_nics(self): command = ['-c', 'qemu:///system', 'domiflist', self._domain_uuid] ret = virsh(command) return ret
def nets(self): """Return vagrant machine network cards.""" command = ['-c', 'qemu:///system', 'domifaddr', self._domain_uuid] grep_cmd = ['-oE', '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'] ret = grep(virsh(command), grep_cmd) return ret
def get_ips_in_net(self, net_name): """Return ip in network.""" command = ['-c', 'qemu:///system', 'net-dhcp-leases', net_name] grep_cmd = ['-w', self.name()] ret = grep(virsh(command), grep_cmd) return ret
def start(self): """Start the VM """ sh.virsh("start", self.name)
def revert(self): sh.virsh("snapshot-revert", dom.name, self.sname) sh.virsh("snapshot-delete", dom.name, self.sname) debug("Deleted snap %r of dom %r" % (self.sname, dom.name))
def reboot(self, wait=True, timeout=600): """Ask the VM to reboot (via ACPI) """ with self.wait_event_ctx("reboot", timeout=timeout): self.run("systemctl", "reboot", "&") sh.virsh("reboot", "--mode=acpi", self.name)
def do_run(args): log.info("Instanciating %s as %s" % (args.IMAGE, args.name)) diskname = args.IMAGE + "-" + args.name image = Layer() image.name = args.IMAGE disk = image.derive(diskname) disk.create() if args.net != "user": args.net = "network=%s" % args.net # FIXME set the hostname inside the VM if args.hack_hostname: fish(disk.filename, "write", "/etc/hostname", args.name) xml = virt_install("--name", args.name, "--memory", args.memory, "--vcpus", "4", "--metadata", "description=vocker/%s" % args.name, "--import", "--disk", disk.filename, "--network", args.net, "--graphics", "spice", "--memballoon", "model=virtio", "--rng", "/dev/random", "--noautoconsole", "--print-xml") # Decode it right away xml = str(xml).encode("UTF-8") if args.publish: hostport, innerport = args.publish.split(":") def random_mac(): """Generate a random mac """ mac = [0x00, 0x16, 0x3e, random.randint(0x00, 0x7f), random.randint(0x00, 0xff), random.randint(0x00, 0xff)] return ':'.join(map(lambda x: "%02x" % x, mac)) domroot = ET.fromstring(xml) # Needed to make guest ssh port accessible from the outside # http://blog.vmsplice.net/2011/04/ # how-to-pass-qemu-command-line-options.html ET.register_namespace("qemu", "http://libvirt.org/" "schemas/domain/qemu/1.0") snippet = ET.fromstring(""" <qemu:commandline xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"> <qemu:arg value='-redir'/> <qemu:arg value='tcp:{hostport}::{innerport}'/> <qemu:arg value='-netdev'/> <qemu:arg value='socket,id=busnet0,mcast=230.0.0.1:1234'/> <qemu:arg value='-device'/> <qemu:arg value='virtio-net-pci,netdev=busnet0,mac={mac}'/> </qemu:commandline> """.format(hostport=hostport, innerport=innerport, mac=random_mac())) domroot.append(snippet) xml = ET.tostring(domroot) with tempfile.NamedTemporaryFile("wb") as spec: spec.write(xml) spec.flush() sh.virsh("define", spec.name) sh.virsh("start", args.name) print(args.name) if args.i: _attach(args.name) if args.rm: _rm(args.name)
def nets(self): """Return vagrant machine network cards.""" command = ['-c', 'qemu:///system', 'domifaddr', self._domain_uuid ] grep_cmd = ['-oE' ,'[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' ] ret = grep(virsh(command),grep_cmd) return ret
def get_ips_in_net(self, net_name): """Return ip in network.""" command = ['-c', 'qemu:///system', 'net-dhcp-leases', net_name ] grep_cmd = ['-w' ,self.name() ] ret = grep(virsh(command),grep_cmd) return ret