def get(self, vm_name=None): """get info on virtual machine(s)""" data = [] #if no vm name get all if vm_name == None: #get list of all inactive and active vm_defined_list = self.conn.listDefinedDomains() vm_active_list = self.conn.listDomainsID() #iterate over these lists and get some info on each domain for vmid in vm_active_list: dom = self.conn.lookupByID(vmid) data.append(dom.XMLDesc(3)) for name in vm_defined_list: dom = self.conn.lookupByName(name) data.append(dom.XMLDesc(3)) else: vm_name = common.validate_hostname(vm_name) try: dom = self.conn.lookupByName(vm_name) except libvirt.libvirtError: result = common.process_results(data, 'VM') self.log.debug('Result: %s' % result) return result info = dom.XMLDesc(3) data.append(info) #self.conn.close() # Connection closing left to calling app - bad? result = common.process_results(data, 'VM') self.log.debug('Result: %s' % result) return result
def __init__(self, hv_uri, vm_name): '''Get some basic config and connect to hypervisor''' SpokeVMPower.__init__(self, vm_name) self.hv_uri = hv_uri self.vm_name = common.validate_hostname(vm_name) self.conn = None try: self.conn = libvirt.open(self.hv_uri) msg = "Successfully connected to: " + self.hv_uri self.log.debug(msg) except libvirt.libvirtError: trace = traceback.format_exc() msg = 'Libvirt connection to URI %s failed' % self.hv_uri raise error.LibvirtError(msg, trace) except Exception: trace = traceback.format_exc() msg = 'Unknown error' raise error.SpokeError(msg, trace) finally: if self.conn == None: msg = 'Libvirt connection to URI %s failed' % self.hv_uri raise error.LibvirtError(msg) try: self.dom = self.conn.lookupByName(self.vm_name) except libvirt.libvirtError: msg = "VM %s not found." % self.vm_name raise error.NotFound(msg)
def delete(self, host_name): """Delete a Host entry; return an empty search result.""" host_name = common.validate_hostname(host_name) dn = '%s=%s,%s' % (self.host_key, host_name, self.host_container_dn) msg = 'Deleting %s' % dn self.log.debug(msg) result = self._delete_object(dn) self.log.debug('Result: %s' % result) return result
def create(self, lv_name, lv_size): """Create logical volume; return True""" lv_size = str(lv_size) + self.lv_units lv_name = common.validate_hostname( lv_name) # LV names are always hostnames lv_size = common.validate_storage_format(lv_size) args = ['lvcreate', '-n', lv_name, '-L', lv_size, self.vg_name] str_args = " ".join(args) msg = "Running " + str_args self.log.debug(msg) try: result = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) except Exception: msg = 'Running command %s failed' % str_args # trace = traceback.format_exec() raise error.SpokeError(msg) data = result.communicate() stdout = data[0] stderr = data[1] msg = "Command stdout was: %s, stderr was: %s" % (stdout, stderr) self.log.debug(msg) # Errors we know about if "Volume group \"%s\" not found" % self.vg_name in stderr: msg = "volume group '%s' was not found." % self.vg_name raise error.NotFound(msg) elif "Insufficient free extents" in stderr: msg = "Not enough free space to create LV" raise error.InsufficientResource(msg) elif "Logical volume \"%s\" already exists in volume group \"%s\"" % ( lv_name, self.vg_name) in stderr: msg = "Logical volume '%s' already exists in volume group '%s'" % ( lv_name, self.vg_name) raise error.AlreadyExists(msg) # Catch unexpected errors if result.returncode != 0: msg = "Create command returned non-zero: %s stdout was: %s, stderr was: %s" % \ (result.returncode, stdout, stderr) raise error.LVMError(msg) result = self.get(lv_name) if result['exit_code'] == 0 and result['count'] == 1: result['msg'] = "Created %s:" % result['type'] return result else: msg = 'Create operation returned OK, but unable to find object' raise error.NotFound(msg) self.log.debug('Result: %s' % result) return result
def get(self, lv_name=None): """Get logical volume; return list of volume attributes.""" if lv_name is not None: lv_name = common.validate_hostname(lv_name) # LV names are always hostnames args = ['lvs', '--noheadings', '--units', self.lv_units, '-o', 'lv_name,lv_size', '--separator', ':', '/dev/%s/%s' % (self.vg_name, lv_name)] else: args = ['lvs', '--noheadings', '--units', self.lv_units, '-o', 'lv_name,lv_size', '--separator', ':', '/dev/%s' % self.vg_name] str_args = " ".join(args) msg = "Running " + str_args self.log.debug(msg) try: result = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) except Exception: msg = 'Running command %s failed' % str_args #trace = traceback.format_exec() raise error.SpokeError, msg out = result.communicate() (stdout, stderr) = (out[0], out[1]) msg = "Command stdout was: %s, stderr was: %s" % (stdout, stderr) self.log.debug(msg) data = [] # Errors we know about if "Volume group \"%s\" not found" % self.vg_name in stderr: msg = "Volume group '%s' was not found." % self.vg_name raise error.NotFound(msg) elif "logical volume(s) not found" in stderr: result = common.process_results(data) self.log.debug('Result: %s' % result) return result elif stderr == "" and stdout == "": result = common.process_results(data) self.log.debug('Result: %s' % result) return result # Catch unexpected errors if result.returncode != 0: msg = "Search command returned non-zero: %s stdout was: %s, stderr was: %s" % \ (result.returncode, stdout, stderr) raise error.LVMError(msg) output = stdout.strip() output = re.compile('\n').split(output) for item in output: item = item.strip() dic = {} name, size = item.split(':') dic['lv_size'] = size dic['lv_name'] = name data.append(dic) result = common.process_results(data) self.log.debug('Result: %s' % result) return result
def get(self, host_name=None): """Search for a Host entry; return a search result.""" dn = self.host_container_dn if host_name is None: filter = '%s=*' % self.host_key else: host_name = common.validate_hostname(host_name) filter = '%s=%s' % (self.host_key, host_name) msg = 'Searching at %s with scope %s and filter %s' % \ (dn, self.search_scope, filter) self.log.debug(msg) result = self._get_object(dn, self.search_scope, filter) self.log.debug('Result: %s' % result) return result
def create(self, host_name, host_uuid, host_mem, host_cpu, host_family, host_type, host_storage_layout, host_network_layout, host_extra_opts=None): """Create a VM Host; return a VM Host search result.""" host_name = common.validate_hostname(host_name) host_uuid = common.validate_uuid(host_uuid) host_mem = common.validate_mem(host_mem) host_cpu = common.validate_cpu(host_cpu) host_family = common.validate_host_family(host_family) # Verifies that the interfaces referenced in the storage layout # exist in the configuration file host_storage_layout = self._validate_storage_layout( host_storage_layout) # and for network layouts. host_network_layout = self._validate_network_layout( host_network_layout) host_type = common.validate_host_type(host_type) host_extra_opts = common.is_shell_safe(host_extra_opts) filter = '%s=%s' % (self.host_key, host_name) dn = '%s=%s,%s' % (self.host_key, host_name, self.host_container_dn) dn_attr = { 'objectClass': ['top', self.host_class], self.host_key: [host_name], self.host_cpu_attr: [str(host_cpu)], self.host_mem_attr: [str(host_mem)], self.host_family_attr: [host_family], self.host_name_attr: [host_name], self.host_network_layout_attr: [host_network_layout], self.host_storage_layout_attr: [host_storage_layout], self.host_type_attr: [host_type], self.host_uuid_attr: [host_uuid], } if host_extra_opts is not None: dn_attr[self.host_extra_opts_attr] = [host_extra_opts] dn_info = [(k, v) for (k, v) in dn_attr.items()] msg = 'Creating %s with attributes %s' % (dn, dn_info) self.log.debug(msg) result = self._create_object(dn, dn_info) self.log.debug('Result: %s' % result) return result
def create(self, lv_name, lv_size): """Create logical volume; return True""" lv_size = str(lv_size) + self.lv_units lv_name = common.validate_hostname(lv_name) # LV names are always hostnames lv_size = common.validate_storage_format(lv_size) args = ['lvcreate', '-n', lv_name, '-L', lv_size, self.vg_name] str_args = " ".join(args) msg = "Running " + str_args self.log.debug(msg) try: result = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) except Exception: msg = 'Running command %s failed' % str_args # trace = traceback.format_exec() raise error.SpokeError(msg) data = result.communicate() stdout = data[0] stderr = data[1] msg = "Command stdout was: %s, stderr was: %s" % (stdout, stderr) self.log.debug(msg) # Errors we know about if "Volume group \"%s\" not found" % self.vg_name in stderr: msg = "volume group '%s' was not found." % self.vg_name raise error.NotFound(msg) elif "Insufficient free extents" in stderr: msg = "Not enough free space to create LV" raise error.InsufficientResource(msg) elif "Logical volume \"%s\" already exists in volume group \"%s\"" % (lv_name, self.vg_name) in stderr: msg = "Logical volume '%s' already exists in volume group '%s'" % (lv_name, self.vg_name) raise error.AlreadyExists(msg) # Catch unexpected errors if result.returncode != 0: msg = "Create command returned non-zero: %s stdout was: %s, stderr was: %s" % \ (result.returncode, stdout, stderr) raise error.LVMError(msg) result = self.get(lv_name) if result['exit_code'] == 0 and result['count'] == 1: result['msg'] = "Created %s:" % result['type'] return result else: msg = 'Create operation returned OK, but unable to find object' raise error.NotFound(msg) self.log.debug('Result: %s' % result) return result
def delete(self, lv_name): """Delete logical volume; return True.""" lv_name = common.validate_hostname( lv_name) # LV names are always hostnames args = ['lvremove', '-f', '%s/%s' % (self.vg_name, lv_name)] str_args = " ".join(args) msg = "Running " + str_args self.log.debug(msg) try: result = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) except Exception: msg = 'Running command %s failed' % str_args #trace = traceback.format_exec() raise error.SpokeError(msg) data = result.communicate() stdout = data[0] stderr = data[1] msg = "Command stdout was: %s, stderr was: %s" % (stdout, stderr) self.log.debug(msg) if "Volume group \"%s\" not found" % self.vg_name in stderr: msg = "volume group '%s' was not found." % self.vg_name raise error.NotFound(msg) elif "logical volume(s) not found" in stderr: msg = "logical volume '%s' not found." % lv_name raise error.NotFound(msg) # Catch non-specific errors if result.returncode != 0: msg = "Delete command returned non-zero: %s stdout was: %s, stderr was: %s" % \ (result.returncode, stdout, stderr) raise error.LVMError(msg) result = self.get(lv_name) if result['exit_code'] == 3 and result['count'] == 0: result['msg'] = "Deleted %s:" % result['type'] self.log.debug('Result: %s' % result) return result else: msg = 'Delete operation returned OK, but object still there?' raise error.SearchError(msg)
def delete(self, lv_name): """Delete logical volume; return True.""" lv_name = common.validate_hostname(lv_name) # LV names are always hostnames args = ['lvremove', '-f', '%s/%s' % (self.vg_name, lv_name)] str_args = " ".join(args) msg = "Running " + str_args self.log.debug(msg) try: result = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) except Exception: msg = 'Running command %s failed' % str_args #trace = traceback.format_exec() raise error.SpokeError(msg) data = result.communicate() stdout = data[0] stderr = data[1] msg = "Command stdout was: %s, stderr was: %s" % (stdout, stderr) self.log.debug(msg) if "Volume group \"%s\" not found" % self.vg_name in stderr: msg = "volume group '%s' was not found." % self.vg_name raise error.NotFound(msg) elif "logical volume(s) not found" in stderr: msg = "logical volume '%s' not found." % lv_name raise error.NotFound(msg) # Catch non-specific errors if result.returncode != 0: msg = "Delete command returned non-zero: %s stdout was: %s, stderr was: %s" % \ (result.returncode, stdout, stderr) raise error.LVMError(msg) result = self.get(lv_name) if result['exit_code'] == 3 and result['count'] == 0: result['msg'] = "Deleted %s:" % result['type'] self.log.debug('Result: %s' % result) return result else: msg = 'Delete operation returned OK, but object still there?' raise error.SearchError(msg)
def create(self, host_name, host_uuid, host_mem, host_cpu, host_family, host_type, host_storage_layout, host_network_layout, host_extra_opts=None): """Create a VM Host; return a VM Host search result.""" host_name = common.validate_hostname(host_name) host_uuid = common.validate_uuid(host_uuid) host_mem = common.validate_mem(host_mem) host_cpu = common.validate_cpu(host_cpu) host_family = common.validate_host_family(host_family) # Verifies that the interfaces referenced in the storage layout # exist in the configuration file host_storage_layout = self._validate_storage_layout(host_storage_layout) # and for network layouts. host_network_layout = self._validate_network_layout(host_network_layout) host_type = common.validate_host_type(host_type) host_extra_opts = common.is_shell_safe(host_extra_opts) filter = '%s=%s' % (self.host_key, host_name) dn = '%s=%s,%s' % (self.host_key, host_name, self.host_container_dn) dn_attr = {'objectClass': ['top', self.host_class], self.host_key: [host_name], self.host_cpu_attr: [str(host_cpu)], self.host_mem_attr: [str(host_mem)], self.host_family_attr: [host_family], self.host_name_attr: [host_name], self.host_network_layout_attr: [host_network_layout], self.host_storage_layout_attr: [host_storage_layout], self.host_type_attr: [host_type], self.host_uuid_attr: [host_uuid], } if host_extra_opts is not None: dn_attr[self.host_extra_opts_attr] = [host_extra_opts] dn_info = [(k, v) for (k, v) in dn_attr.items()] msg = 'Creating %s with attributes %s' % (dn, dn_info) self.log.debug(msg) result = self._create_object(dn, dn_info) self.log.debug('Result: %s' % result) return result
def get(self, lv_name=None): """Get logical volume; return list of volume attributes.""" if lv_name is not None: lv_name = common.validate_hostname( lv_name) # LV names are always hostnames args = [ 'lvs', '--noheadings', '--units', self.lv_units, '-o', 'lv_name,lv_size', '--separator', ':', '/dev/%s/%s' % (self.vg_name, lv_name) ] else: args = [ 'lvs', '--noheadings', '--units', self.lv_units, '-o', 'lv_name,lv_size', '--separator', ':', '/dev/%s' % self.vg_name ] str_args = " ".join(args) msg = "Running " + str_args self.log.debug(msg) try: result = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) except Exception: msg = 'Running command %s failed' % str_args #trace = traceback.format_exec() raise error.SpokeError, msg out = result.communicate() (stdout, stderr) = (out[0], out[1]) msg = "Command stdout was: %s, stderr was: %s" % (stdout, stderr) self.log.debug(msg) data = [] # Errors we know about if "Volume group \"%s\" not found" % self.vg_name in stderr: msg = "Volume group '%s' was not found." % self.vg_name raise error.NotFound(msg) elif "logical volume(s) not found" in stderr: result = common.process_results(data) self.log.debug('Result: %s' % result) return result elif stderr == "" and stdout == "": result = common.process_results(data) self.log.debug('Result: %s' % result) return result # Catch unexpected errors if result.returncode != 0: msg = "Search command returned non-zero: %s stdout was: %s, stderr was: %s" % \ (result.returncode, stdout, stderr) raise error.LVMError(msg) output = stdout.strip() output = re.compile('\n').split(output) for item in output: item = item.strip() dic = {} name, size = item.split(':') dic['lv_size'] = size dic['lv_name'] = name data.append(dic) result = common.process_results(data) self.log.debug('Result: %s' % result) return result
def create(self, vm_name, vm_uuid, vm_mem, vm_cpu, vm_family, vm_storage_layout, vm_network_layout, vm_install=False, vm_disks=None, vm_interfaces=None): """Define a new VM and add to hypervisor's store (does not start).""" try: vm_name = common.validate_hostname(vm_name) vm_cpu = common.validate_cpu(vm_cpu) vm_mem = common.validate_mem(vm_mem) #vm_type = common.validate_host_type(vm_type) vm_family = common.validate_host_family(vm_family) #vm_extra_opts = common.is_shell_safe(vm_extra_opts) vm_uuid = common.validate_uuid(vm_uuid) except error.InputError as e: self.log.error(e) raise e try: self.conn.lookupByName(vm_name) except libvirt.libvirtError: pass else: msg = "Domain %s already exists, cannot create." % vm_name raise error.AlreadyExists(msg) # Create a UUID in hypervisor format formatted_uuid = self._format_uuid(vm_uuid) #-1 means XEN will give the right XenID when it starts vm_id=-1 #Initial xml structure doc = xml.createDoc("doc") domain = xml.createElement(doc, "domain", {"type": vm_family}) #Variable config options #xml.createChild(doc, domain, "arch name", None, 'i686') xml.createChild(doc, domain, "name", None, vm_name) xml.createChild(doc, domain, "memory", None, vm_mem) xml.createChild(doc, domain, "currentMemory", None, vm_mem) xml.createChild(doc, domain, "vcpu", None, vm_cpu) xml.createChild(doc, domain, "uuid", None, formatted_uuid) #fixed(ish) config options os = xml.createChild(doc, domain, "os", None, None) #ks - the below is going to have to change for 64bit xml.createChild(doc, os, "type", {"arch": "i686"}, "hvm") xml.createChild(doc, domain, "clock", {"offset": "utc"}, None) xml.createChild(doc, domain, "on_poweroff", None, "destroy") xml.createChild(doc, domain, "on_reboot", None, "restart") xml.createChild(doc, domain, "on_crash", None, "restart") devices = xml.createChild(doc, domain, "devices", None, None) console = xml.createChild(doc, devices, "console", {"type": "pty"}, None) xml.createChild(doc, console, "target", {"type": "xen", "port": "0"}, None) #ks #xml.createChild(doc, devices, "input", {"type": "mouse", "bus": "xen"}, None) # TODO Change the port such that it is associated with the UUID and change listen to internal interface only xml.createChild(doc, devices, "graphics", {"type": "vnc", "port": "-1", "autoport": "yes", "listen": "0.0.0.0"}, None) xml.createChild(doc, devices, "emulator", None, "/usr/lib/xen/bin/qemu-dm") # #parse disk info # for item in vm_disks: # #local1 means hda and vg01 # if item[0] == "local1": # disk = xml.createChild(doc, devices, "disk", {"type": "block", "device": "disk"}, None) # xml.createChild(doc, disk, "driver", {"name": "phy"}, None) # xml.createChild(doc, disk, "source", {"dev": "/dev/vg01/%s" % vm_name}, None) # xml.createChild(doc, disk, "target", {"dev": "hda", "bus": "ide"}, None) # #local2 means hdb and vg02 # if item[0] == "local2": # disk = xml.createChild(doc, devices, "disk", {"type": "block", "device": "disk"}, None) # xml.createChild(doc, disk, "driver", {"name": "phy"}, None) # xml.createChild(doc, disk, "source", {"dev": "/dev/vg01/ko-test-02"}, None) # xml.createChild(doc, disk, "target", {"dev": "hdb", "bus": "ide"}, None) if vm_disks is not None: for item in vm_disks: if item[0] == "local1": disk = xml.createChild(doc, devices, "disk", {"type": "block", "device": "disk"}, None) xml.createChild(doc, disk, "driver", {"name": "phy"}, None) xml.createChild(doc, disk, "source", {"dev": "/dev/vg01/%s" % vm_name}, None) xml.createChild(doc, disk, "target", {"dev": "hda", "bus": "ide"}, None) #local2 means hdb and vg02 if item[0] == "local2": disk = xml.createChild(doc, devices, "disk", {"type": "block", "device": "disk"}, None) xml.createChild(doc, disk, "driver", {"name": "phy"}, None) xml.createChild(doc, disk, "source", {"dev": "/dev/vg02/%s" % vm_name}, None) xml.createChild(doc, disk, "target", {"dev": "hdb", "bus": "ide"}, None) elif vm_storage_layout is not None: try: disks = self.dtypes[vm_storage_layout] except KeyError as e: msg = "The disk type %s is not present in config file." % e raise error.InputError, msg for item in disks: item = common.validate_disks_in_conf(self.dnames[item]) hv_dev = item[0] + "/" + vm_name dom_dev = item[1] disk = xml.createChild(doc, devices, "disk", {"type": "block", "device": "disk"}, None) xml.createChild(doc, disk, "driver", {"name": "phy"}, None) xml.createChild(doc, disk, "source", {"dev": hv_dev}, None) xml.createChild(doc, disk, "target", {"dev": dom_dev, "bus": "ide"}, None) #parse interface info if vm_interfaces is not None: for interface in vm_interfaces: #get input from interface list bridge = int( interface[0].lstrip('breth') ) mac = interface[1] source_interface = interface[2] interface = xml.createChild(doc, devices, "interface", {"type": "bridge"}, None) xml.createChild(doc, interface, "mac", {"address": mac}, None) xml.createChild(doc, interface, "source", {"bridge": source_interface}, None) xml.createChild(doc, interface, "script", {"path": "vif-bridge"}, None) xml.createChild(doc, interface, "target", {"dev": "vif%i.%i" % (vm_id, bridge)}, None) elif vm_network_layout is not None: try: interfaces = self.ifacedef[vm_network_layout] except KeyError: msg = "The interface type %s is not present in config file." % vm_network_layout raise error.InputError(msg) # Ensure that br0,x is done first as xen cares about order in xml. interfaces = sorted(interfaces, key=itemgetter(0)) for interface in interfaces: interface = common.validate_interfaces_in_conf(interface) iface_number = int( interface[0].lstrip('breth') ) if iface_number == 0: boot_mac = common.mac_from_uuid(vm_uuid, iface_number) boot_int = interface[1] mac = common.mac_from_uuid(vm_uuid, iface_number) source_interface = interface[1] # KS enumerate avail interfaces via facter, not remote socket op #if not source_interface in self._all_interfaces(): # msg = "%s does not exist on this machine so we cant bridge to it!" % source_interface # raise error.InsufficientResource, msg interface = xml.createChild(doc, devices, "interface", {"type": "bridge"}, None) xml.createChild(doc, interface, "mac", {"address": mac}, None) xml.createChild(doc, interface, "source", {"bridge": source_interface}, None) xml.createChild(doc, interface, "script", {"path": "vif-bridge"}, None) xml.createChild(doc, interface, "target", {"dev": "vif%i.%i" % (vm_id, iface_number)}, None) if vm_install: # Add network boot lines xml.createChild(doc, domain, "bootloader", None, "/usr/sbin/pypxeboot" ) try: xml.createChild(doc, domain, "bootloader_args", None, "--udhcpc=/usr/local/pkg/udhcp/sbin/udhcpc --interface=%s mac=%s --label=install-aethernet" % (boot_int, boot_mac) ) except UnboundLocalError: msg = "In config there must be an interface br0 as the provisioning interface!" raise error.ConfigError(msg) else: xml.createChild(doc, domain, "bootloader", None, "/usr/bin/pygrub" ) try: out = self.conn.defineXML(xml.out(doc)) except Exception, e: trace = traceback.format_exc() raise error.LibvirtError(e, trace)