#!/usr/bin/env python import sys import grp import pwd import os import libvirt import ConfigParser import subprocess import shutil import distutils.spawn import platform # this does a very basic test to see if the required packages # are installed, extend list as required def checkPackages(): sys_ok = True check_apps = [ "virsh", "qemu-system-x86_64", "libvirtd" ] for app in check_apps: if distutils.spawn.find_executable(app) == None: print( "Missing: " + app) sys_ok = False if not sys_ok: print("The required libvirt/qemu packages are missing...") distro = platform.dist()[0] if distro == "debian" or distro == "Ubuntu": print( "This appears to be a Debian/Ubuntu distribution\nPlease install " + "packages like libvirt-bin, qemu-system-x86,..." ) elif distro == "redhat" or distro == "fedora": print( "This appears to be a Redhat/Fedora distribution\nPlease install " + "packages like libvirt-client, libvirt-daemon, qemu-system-x86, ..." ) exit(1) return def networkInterfaces(): ifaces = [] for line in open('/proc/net/dev', 'r'): if_info = line.split(":", 1) if len(if_info) > 1: ifaces.append( if_info[0].strip() ) return ifaces def destroyNetwork(conn, network_name): networks = conn.listNetworks() + conn.listDefinedNetworks() if network_name in networks: try: nw = conn.networkLookupByName(network_name) if nw.isActive(): nw.destroy() nw.undefine() except: print( "Failed to destroy network: %s" % network_name ) exit( 1 ) def restartDomain(conn, domain_name): try: domain = conn.lookupByName(domain_name) except: print( "restartDomain: Warning domain " + domain_name + " doesn't exist." ) return if domain.isActive(): domain.reboot() def destroyDomain(conn, auto_destroy, domain_name): try: domain = conn.lookupByName(domain_name) except: return if domain.isActive(): if auto_destroy: print( "Auto destroy enabled, destroying old instance of domain %s" % domain_name ) domain.destroy() else: print( "Domain %s is active, abort..." % domain_name ) print( "To stop: virsh -c %s destroy %s " % ( uri , domain_name ) ) exit(0) domain.undefine() def startDomain(conn, auto_destroy, domain_name, xml_desc): print( "Starting %s...\n%s" % ( domain_name, xml_desc ) ) destroyDomain(conn, auto_destroy, domain_name) try: conn.defineXML(xml_desc) domain = conn.lookupByName(domain_name) domain.create() print( "Starting domain %s..." % domain_name ) print( "To connect to the console: virsh -c %s console %s" % ( uri, domain_name ) ) print( "To stop: virsh -c %s destroy %s" % ( uri, domain_name ) ) except Exception as e: print( e ) exit(1) def make_nw_spec(network_name, bridge_nw_interface, network, auto_assign_ip): spec = '' spec += '' + network_name + '' spec += '' spec += '' spec += '' if auto_assign_ip: nw_parts = network.split('.') nw_parts[-1] = "2" start_dhcp = '.'.join(nw_parts) nw_parts[-1] = "254" end_dhcp = '.'.join(nw_parts) spec += '' spec += '' spec += '' spec += '' spec += '' return spec def make_spec(name, network, kernel, disk, bridge_nw_interface, emulator, auto_assign_ip, ip): if not os.path.exists(kernel): print( "Kernel image %s does not exist!" % kernel ) exit(1) if not os.path.exists(disk): print( "Disk %s does not exist!" % disk ) exit(1) if auto_assign_ip: ip_spec = 'dhcp' else: ip_spec = ip + '::' + network + ':255.255.255.0:' + name + ':eth0:off' spec = '' spec += ' ' + name + '' spec += ' 4096000' spec += ' 4096000' spec += ' 1' spec += ' ' spec += ' kvm64' spec += ' ' spec += ' ' spec += ' hvm' spec += ' ' + kernel + '' spec += ' ' spec += ' root=/dev/vda rw console=ttyS0 ip=' + ip_spec + '' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' destroy' # spec += ' destroy' spec += ' destroy' spec += ' ' spec += ' ' + emulator + '' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += ' ' spec += '' return spec def getConfig(config, section, key): try: return os.path.expandvars(config.get(section, key)) except: print( "Configuration file error! Missing item (section: %s, key: %s)" % ( section, key ) ) exit(1) # does the user have access to libvirt? eligible_groups = [ "libvirt", "libvirtd" ] eligible_user = False euid = os.geteuid() if euid == 0: eligible_user = True else: username = pwd.getpwuid(euid)[0] groups = [g.gr_name for g in grp.getgrall() if username in g.gr_mem] for v in eligible_groups: if v in groups: eligible_user = True checkPackages() if not eligible_user: sys.stderr.write("You need to be the 'root' user or in group [" + '|'.join(eligible_groups) + "] to run this script.\n") exit(1) if len(sys.argv) != 3: sys.stderr.write("Usage: "+sys.argv[0]+" [config file] [start|stop|restart]\n") sys.exit(1) if not os.path.exists(sys.argv[1]): sys.stderr.write("Error: config file \"" + sys.argv[1] + "\" was not found!\n") sys.exit(1) command = sys.argv[2] command_options = ["start", "stop", "restart"] if not command in command_options: sys.stderr.write("Usage: "+sys.argv[0]+" [config file] [start|stop|restart]\n") sys.exit(1) Config = ConfigParser.ConfigParser() Config.read(sys.argv[1]) network_addr = getConfig(Config, "main", "network") getConfig(Config, "main", "auto_destroy") auto_destroy = Config.getboolean("main", "auto_destroy") getConfig(Config, "main", "auto_assign_ip") auto_assign_ip = Config.getboolean("main", "auto_assign_ip") network_name = 'ops_default' uri = 'qemu:///system' # Connect to libvirt conn = libvirt.open(uri) if conn is None: print( "Failed to open connection to the hypervisor" ) exit(1) if command == "start": destroyNetwork(conn, network_name) # Change the default bridge device from virbr0 to virbr%d. # This will make libvirt try virbr0, virbr1, etc. until it finds a free one. cnt = 0 ifaces = networkInterfaces() found_virbr = False while found_virbr == False: if cnt > 254: print( "Giving up on looking for a free virbr network interface!" ) exit(1) bridge_nw_interface = 'virbr' + str(cnt) if bridge_nw_interface not in ifaces: print( "bridge_nw_interface: %s" % bridge_nw_interface ) network_spec = make_nw_spec(network_name, bridge_nw_interface, network_addr, auto_assign_ip) try: conn.networkDefineXML(network_spec) nw = conn.networkLookupByName(network_name) nw.create() found_virbr = True except: print( "Network Name: %s" % network_name ) destroyNetwork( conn, network_name ) print( "Error creating network interface" ) cnt += 1 else: # verify network exists try: nw = conn.networkLookupByName(network_name) except: print( "Error! Virtual network " + network_name + " is not defined!" ) exit(1) if not nw.isActive(): print( "Error! Virtual network " + network_name + " is not running!" ) exit(1) emulator = getConfig(Config, "main", "emulator") if not os.path.exists(emulator): print( "Emulator %s does not exist!" % emulator ) exit(1) controller_name = 'controller' if command == "start": # Define the controller xml controller_kernel = getConfig(Config, "controller", "kernel") controller_disk = getConfig(Config, "controller", "disk") controller_ip = None if not auto_assign_ip: controller_ip = getConfig(Config, "controller", "ip") controller_spec = make_spec(controller_name, network_addr, controller_kernel, controller_disk, bridge_nw_interface, emulator, auto_assign_ip, controller_ip) # Now that network is setup let's actually run the virtual images startDomain(conn, auto_destroy, controller_name, controller_spec) elif command == "stop": destroyDomain(conn, True, controller_name) elif command == "restart": restartDomain(conn, controller_name) for i in Config.sections(): if i.startswith("compute"): if command == "start": # Define the compute xml kernel = getConfig(Config, i, "kernel") disk = getConfig(Config, i, "disk") compute_ip = None if not auto_assign_ip: compute_ip = getConfig(Config, i, "ip") spec = make_spec(i, network_addr, kernel, disk, bridge_nw_interface, emulator, auto_assign_ip, compute_ip) startDomain(conn, auto_destroy, i, spec) elif command == "stop": destroyDomain(conn, True, i) elif command == "restart": restartDomain(conn, i) conn.close()