def get_host_manage_interface_infor(self): """ The manage interface, or the default interface configured with a managed IP :return: """ if self._hypervisor_handler is None: self._hypervisor_handler = self.get_handler() try: host_ref = self._hypervisor_handler.xenapi.host.get_all()[0] pif_ref = self._hypervisor_handler.xenapi.host.get_management_interface( host_ref) pif_record = self._hypervisor_handler.xenapi.PIF.get_record( pif_ref) except Exception as error: log.exception("Except when get host manage interface: %s", error) return {} default_infor = {} default_infor.setdefault('device', pif_record.get('device', None)) default_infor.setdefault('IP', pif_record.get('IP', None)) default_infor.setdefault('DNS', pif_record.get('DNS', None)) default_infor.setdefault('MAC', pif_record.get('MAC', None)) default_infor.setdefault('gateway', pif_record.get('gateway', None)) default_infor.setdefault('netmask', pif_record.get('netmask', None)) return default_infor
def get_host_cpu_info(self): """ Return HV CPU info: cpu speed: MHZ; """ if self._hypervisor_handler is None: self._hypervisor_handler = self.get_handler() ret_cpu_dict = {} try: host_ref = self._hypervisor_handler.xenapi.host.get_all()[0] cpu_info = self._hypervisor_handler.xenapi.host.get_cpu_info( host_ref) ret_cpu_dict['cpu_model'] = cpu_info.get('model', "") ret_cpu_dict['cpu_modelname'] = cpu_info.get('modelname', "") ret_cpu_dict['cpu_cores'] = cpu_info.get("cpu_count", 0) ret_cpu_dict['cpu_speed'] = cpu_info.get('speed', "0") ret_cpu_dict['cpu_sockets'] = cpu_info.get("socket_count", 0) # number of threads per core, xenserver6.5 has no infor about this, set default to 2 ret_cpu_dict['thread_per_core'] = 2 # number of cores per socket ret_cpu_dict['cores_per_socket'] = int( ret_cpu_dict['cpu_cores']) / int( ret_cpu_dict['cpu_sockets']) / int( ret_cpu_dict['thread_per_core']) except Exception, error: log.exception("Exceptions when get host cpu infor: %s", error) return ret_cpu_dict
def set_vm_vcpu_live(self, inst_name, vcpu_num): """ set the vcpu numbers for a running VM; and set vcpus in the config file when domain is deactive :param inst_name: :param vcpu_num: should be str of a int number :return: True or False """ dom = self._get_domain_handler(domain_name=inst_name) if dom is None: return False vcpu_num = int(vcpu_num) if vcpu_num > self.get_vm_vcpu_max(inst_name): log.error("vCpus number [%s] exceed the limit of max vcpus: %s", vcpu_num, dom.maxVcpus()) return False try: if dom.isActive(): # dom.setVcpus(vcpu_num) # only effect the live domain, when power off, the config lose ret = dom.setVcpusFlags(vcpu_num, libvirt.VIR_DOMAIN_AFFECT_LIVE | libvirt.VIR_DOMAIN_AFFECT_CONFIG) else: ret = dom.setVcpusFlags(vcpu_num, libvirt.VIR_DOMAIN_AFFECT_CURRENT) except libvirtError as error: log.exception("Exceptions when set vcpu lively: %s", error) return False return ret == 0
def delete_instance(self, inst_name): ''' undefine:If the domain is running, it's converted to transient domain, without stopping it. If the domain is inactive, the domain configuration is removed. ''' domain = self._get_domain_handler(inst_name) if not domain: return True if domain.isActive(): domain.destroy( ) # It will shutdown the domain force, if it is already shutdown, libvirtError will raise try: ret = domain.undefine() if ret == 0: target_disk = VM_HOUSE + inst_name + ".qcow2" cmd = "rm -f %s" % target_disk log.debug("remove the disk file for %s: %s", inst_name, cmd) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) _, perr = p.communicate() if perr: log.error("Deleting the disk for vm %s meet an error:%s", inst_name, perr) return False return ret == 0 except Exception, error: log.exception(error) return False
def update_ip_infor_to_database(inst_name, vif_index=None, ip=None, host_ip=None): """ As the IP for xenserver'VM is not accessable when it is down, so update it with user's input :param inst_name: :param vif_index: vif index :param ip: the IP on vif :param host_ip: Host server IP :return: """ log.info("Update [%s] IP information [%s, %s] to database.", inst_name, vif_index, ip) sync_data = {} if host_ip: sync_data['vm_host_ip'] = host_ip if vif_index == "0": sync_data["first_ip"] = ip elif vif_index == "1": sync_data["second_ip"] = ip else: log.warn("Database only record the first and second IP for VM.") if not sync_data: return True db_driver = DbFactory.get_db_driver("VirtHost") try: #json_data = json.dumps(sync_data) ret = db_driver.update(hostname=inst_name, data=sync_data) except Exception as error: log.exception("update IP information raise error: %s", error) ret = False if not ret: log.warn("Update IP information to database with ret: [%s], data: %s", ret, sync_data) return ret
def destroy_vif(self, inst_name, vif_index): """ @param vif_index: index of virtual interface in guest VM """ if self._hypervisor_handler is None: self._hypervisor_handler = self.get_handler() vif_ref = self._get_vif_by_index(inst_name, vif_index) if vif_ref is None: log.error( "No virtual interface device found with index [%s] when try to destroy vif.", vif_index) return False # unplug in allowed_operations, means the vif has plugged in VM if 'unplug' in self._hypervisor_handler.xenapi.VIF.get_record( vif_ref)['allowed_operations']: log.error( "Error when destroy, please firstly unplug the VIF or power off the VM." ) return False try: self._hypervisor_handler.xenapi.VIF.destroy(vif_ref) except Exception as error: log.exception("Exceptions raised when destroy VIF:%s", error) return False return True
def power_off_vm(self, inst_name): """ @see: void shutdown (session ref session_id, VM ref vm), it will attempts to first clean shutdown a VM and if it should fail then perform a hard shutdown on it. """ log.debug("Start power off vm [%s].", inst_name) if self.is_instance_halted(inst_name): log.info("VM [%s] is already not running.", inst_name) return True handler = self.get_handler() if handler is None: log.error("Can not get handler when try to power off VM [%s].", inst_name) return False vm_ref = handler.xenapi.VM.get_by_name_label(inst_name)[0] try: handler.xenapi.VM.shutdown(vm_ref) time.sleep(0.5) except Exception, error: log.exception("Exception raised: %s when shutdown VM [%s].", error, inst_name) return False
def get_disk_size(self, inst_name, device_num): """ :param inst_name: VM name :param device_num: the disk index number :return: return size in GB, or 0 if no device found """ disk_list = self.__get_disk_elements_list(inst_name) try: disk_element = disk_list[int(device_num)] except IndexError: log.error("No disk found with device number: %s", device_num) return 0 source = disk_element.find("source") if source is None: return 0 file_path = source.get("file", None) try: volume_obj = self._hypervisor_handler.storageVolLookupByPath(file_path) # volume_list.info(): type, Capacity, Allocation(used) return volume_obj.info()[1] / 1024.0 / 1024.0 / 1024.0 except (TypeError, IndexError) as error: log.exception("Exceptions raise when get disk size: %s", error) return 0
def set_vm_static_memory(self, inst_name, memory_max=None, memory_min=None): """ set memory for a inactive domain :param inst_name: :param memory_max: size of GB :param memory_min: size of GB :return: """ # dom.setMaxMemory() need dom to be inactive dom = self._get_domain_handler(domain_name=inst_name) if dom is None: return False if dom.isActive(): log.error("Set domain max memory need it to be stopped.") return False gitabyte = 1024 * 1024 # unit is KB if memory_max: memory_size = int(memory_max) * gitabyte elif memory_min: log.info("Don't support min memory set.") return True else: log.error("Neither maxMemory nor minMemory is supplied.") return False # dom.setMemoryFlags(memory_size, libvirt.VIR_DOMAIN_AFFECT_CURRENT|libvirt.VIR_DOMAIN_MEM_MAXIMUM) also OK try: ret = dom.setMaxMemory(memory_size) except libvirtError as error: log.exception("Exception: %s", error) return False return ret == 0
def set_vm_dynamic_memory(self, inst_name, memory_max=None, memory_min=None): """ set memory for a domain, if it is active, set it lively and the config file, if it is deactive, set the config file :param inst_name: :param memory_max: :param memory_min: :return: """ dom = self._get_domain_handler(domain_name=inst_name) if dom is None: return False gitabyte = 1024 * 1024 # unit is KB if memory_max: memory_size = int(memory_max) * gitabyte elif memory_min: log.info("Don't support min memory set.") return True else: log.error("Neither maxMemory nor minMemory is supplied.") return False try: if dom.isActive(): ret = dom.setMemoryFlags(memory_size, libvirt.VIR_DOMAIN_AFFECT_LIVE | libvirt.VIR_DOMAIN_AFFECT_CONFIG) else: ret = dom.setMemoryFlags(memory_size) # dom.setMemory need dom to be active except libvirtError as error: log.exception("Exception: %s", error) return False return ret == 0
def delete_instance(self, inst_name, delete_disk=False): ''' undefine:If the domain is running, it's converted to transient domain, without stopping it. If the domain is inactive, the domain configuration is removed. ''' domain = self._get_domain_handler(inst_name) if not domain: return True if domain.isActive(): log.info("Try to power off vm [%s] gracefully.", inst_name) ret = domain.destroyFlags(flags=libvirt.VIR_DOMAIN_DESTROY_GRACEFUL) if ret != 0: log.info("Power off failed, try to poweroff forcely.") domain.destroy() # It will shutdown the domain force, if it is already shutdown, libvirtError will raise try: self.detach_disk_from_domain(inst_name, force=delete_disk) except libvirtError: pass try: ret = domain.undefine() # may use undefineFlags to handler managed save image or snapshots except libvirtError as error: log.exception("Exception raise when undefine domain [%s]: %s.", inst_name, error) return False return ret == 0
def set_vm_vcpu_live(self, inst_name, vcpu_num): """ set the vcpu numbers for a running VM :param inst_name: :param vcpu_num: should be str of a int number :return: True or False """ if self._hypervisor_handler is None: self._hypervisor_handler = self.get_handler() try: vm_ref = self._hypervisor_handler.xenapi.VM.get_by_name_label( inst_name)[0] cpu_max = self._hypervisor_handler.xenapi.VM.get_VCPUs_max(vm_ref) if int(vcpu_num) > int(cpu_max): log.warn( "VCPU number exceed the max cpu number:%s, will set it to the max instead.", cpu_max) vcpu_num = cpu_max self._hypervisor_handler.xenapi.VM.set_VCPUs_number_live( vm_ref, str(vcpu_num)) return True except Exception, error: log.exception("Raise exceptions: [%s].", error) return False
def get_handler(self): ''' return the handler of the virt_driver ''' if self._hypervisor_handler is not None: return self._hypervisor_handler if self.hostname is None: self._hypervisor_handler = XenAPI.xapi_local() #no __nonzero__, can not use if/not for bool test else: log.debug("connecting to %s with user:%s,passwd:%s", "http://" + str(self.hostname), self.user, self.passwd) self._hypervisor_handler = XenAPI.Session("http://" + str(self.hostname)) old = signal.signal(signal.SIGALRM, self.timeout_handler) signal.alarm(4) # connetctions timeout set to 5 secs try: self._hypervisor_handler.xenapi.login_with_password(self.user, self.passwd, API_VERSION_1_1, 'XenVirtDriver') except Exception as error: log.warn("Exception raised: %s when get handler.", error) log.info("Retry connecting to :%s", "https://" + str(self.hostname)) self._hypervisor_handler = XenAPI.Session("https://" + str(self.hostname)) signal.alarm(4) try: self._hypervisor_handler.xenapi.login_with_password(self.user, self.passwd, API_VERSION_1_1, 'XenVirtDriver') except Exception as errors: log.exception("Exception errors:%s when get handler", errors) return None finally: signal.alarm(0) signal.signal(signal.SIGALRM, old) log.debug("Get handler ID in vnet driver: %s", id(self._hypervisor_handler)) return self._hypervisor_handler
def unplug_vif_from_vm(self, inst_name, vif_index): """ Hot-unplug the specified VIF, dynamically unattaching it from the running VM @param vif_index: virtual interface index @note It should check the power_state before use this API """ if self._hypervisor_handler is None: self._hypervisor_handler = self.get_handler() vif_ref = self._get_vif_by_index(inst_name, vif_index) if vif_ref is None: log.error("No vif found with index [%s] when try to detach vif.", vif_index) return False vm_ref = self._hypervisor_handler.xenapi.VIF.get_VM(vif_ref) power_status = self._hypervisor_handler.xenapi.VM.get_record( vm_ref)['power_state'] allowed_opera = self._hypervisor_handler.xenapi.VIF.get_record( vif_ref)['allowed_operations'] if 'unplug' not in allowed_opera and power_status == 'Running': log.info("VIF [%s] is already unpluged.", vif_index) return True try: self._hypervisor_handler.xenapi.VIF.unplug(vif_ref) except Exception as error: log.exception("Exceptions raised when unplug a VIF:%s", error) return False return True
def set_vm_vcpu_max(self, inst_name, vcpu_num): """ set the vcpu numbers for a halted VM :param inst_name: :param vcpu_num: :return: True or False """ if self._hypervisor_handler is None: self._hypervisor_handler = self.get_handler() vcpu_num = int(vcpu_num) try: vm_ref = self._hypervisor_handler.xenapi.VM.get_by_name_label( inst_name)[0] # 0 < VCPUs_at_startup <= VCPUs_max cpu_at_start = self._hypervisor_handler.xenapi.VM.get_VCPUs_at_startup( vm_ref) if vcpu_num < int(cpu_at_start): log.warn( "The max cpu number is smaller than the live number [%s] and will change live cpu to it.", cpu_at_start) self._hypervisor_handler.xenapi.VM.set_VCPUs_at_startup( vm_ref, str(vcpu_num)) self._hypervisor_handler.xenapi.VM.set_VCPUs_max( vm_ref, str(vcpu_num)) return True except Exception, error: log.exception("Raise exceptions: [%s].", error) return False
def get_host_mem_info(self): """ Return HV memory info: Unit is GB """ if self._hypervisor_handler is None: self._hypervisor_handler = self.get_handler() ret_mem_dict = {} try: host_ref = self._hypervisor_handler.xenapi.host.get_all()[0] host_metrics_ref = self._hypervisor_handler.xenapi.host.get_metrics( host_ref) total = self._hypervisor_handler.xenapi.host_metrics.get_memory_total( host_metrics_ref) free = self._hypervisor_handler.xenapi.host_metrics.get_memory_free( host_metrics_ref) except Exception as error: log.exception("Exception raised when get host memory infor:%s", error) return ret_mem_dict ret_mem_dict['size_total'] = float("%.3f" % (float(total) / 1024 / 1024 / 1024)) ret_mem_dict['size_free'] = float("%.3f" % (float(free) / 1024 / 1024 / 1024)) ret_mem_dict['size_used'] = float( "%.3f" % (ret_mem_dict['size_total'] - ret_mem_dict['size_free'])) return ret_mem_dict
def set_vm_memory_live(self, inst_name, memory_target): """ :param memory_target: Memory in GB, set dynamic_max and dynamic_min to the target size :return: """ if self._hypervisor_handler is None: self._hypervisor_handler = self.get_handler() if not self.is_instance_running(inst_name=inst_name): log.error("Set live memory need VM to be running.") return False try: vm_ref = self._hypervisor_handler.xenapi.VM.get_by_name_label( inst_name)[0] gb = 1024.0 * 1024.0 * 1024.0 memory_size = int(gb * float(memory_target)) # set_memory_target_live has been deprecated # self._hypervisor_handler.xenapi.VM.set_memory_target_live(vm_ref, str(memory_size)) self._hypervisor_handler.xenapi.VM.set_memory_dynamic_range( vm_ref, str(memory_size), str(memory_size)) return True except Exception as error: log.exception("Exception raise when set live memory: %s", error) return False
def get_host_storage_info(self, storage_name="Local storage"): """ Return HV storage info: Unit is GB """ if self._hypervisor_handler is None: self._hypervisor_handler = self.get_handler() ret_storage_dict = {} try: sr_ref = self._hypervisor_handler.xenapi.SR.get_by_name_label( storage_name)[0] except Exception as error: log.exception("No storage repository named: [%s], %s", storage_name, error) return ret_storage_dict total = self._hypervisor_handler.xenapi.SR.get_physical_size(sr_ref) used = self._hypervisor_handler.xenapi.SR.get_physical_utilisation( sr_ref) ret_storage_dict['size_total'] = float( "%.3f" % (float(total) / 1024 / 1024 / 1024)) ret_storage_dict['size_used'] = float( "%.3f" % (float(used) / 1024 / 1024 / 1024)) ret_storage_dict['size_free'] = float( "%.3f" % (ret_storage_dict['size_total'] - ret_storage_dict['size_used'])) return ret_storage_dict
def power_off_vm(self, inst_name): """ current we do not consider the power states :param inst_name: :return: """ domain = self._get_domain_handler(domain_name=inst_name) if not domain: return False try: # flags will prevent the forceful termination of the guest, and will instead # return an error if the guest doesn't terminate by the end of the timeout if domain.isActive(): ret = domain.destroyFlags( flags=libvirt.VIR_DOMAIN_DESTROY_GRACEFUL ) # VIR_DOMAIN_DESTROY_GRACEFUL = 1 if ret != 0: ret = domain.destroyFlags( flags=libvirt.VIR_DOMAIN_DESTROY_DEFAULT) return ret == 0 else: return True except Exception as e: log.exception(e) return False
def __init__(self, user="******", passwd="admin"): super(HostDbDriver, self).__init__(user, passwd) self.db_host = DB_HOST self.login_url = LOGIN_URL self.logout_url = LOGOUT_URL self.url = None login_data = {'username': self.user, 'password': self.passwd} try: self.session = requests.Session() login_res = self.session.post(self.login_url, data=login_data) res_content = json.loads(login_res.content) if res_content[ 'status'] == 1: # the success check depend on the login html log.debug("Login url [%s] check with username [%s] success.", self.db_host, self.user) else: log.error("Login url [%s] check with username [%s] failed.", self.db_host, self.user) self.session = None except requests.exceptions.ConnectionError as connerror: log.exception("Connection exception: %s", connerror) self.session = None except Exception as error: log.exception("Exception when init session: %s", error) self.session = None
def add_vdisk_to_vm(self, inst_name, storage_name='Local storage', size=2): """ @param inst_name: the name of VM @param storage_name: which storage repository the virtual disk put @param size: the disk size """ handler = self.get_handler() userdevice = self._get_available_device_num(inst_name) if not userdevice: return False log.info("Start to add virtual disk [%s] to VM: [%s]", userdevice, inst_name) name_description = "VDI created by API, on VM: %s, SR: %s" % ( inst_name, storage_name) record = { "name_label": inst_name + " data " + userdevice, "name_description": name_description } try: sr_ref = handler.xenapi.SR.get_by_name_label(storage_name)[0] except Exception, error: log.exception("No storage named [%s], exception: %s", storage_name, error) return False
def is_IP_available(self, vif_ip=None, vif_netmask=None, device=None, network=None, bridge=None): """ check if a IP and Netmask usable """ # No ip , don't need to check if not vif_ip: return True dest_metmask = "" dest_gateway = None if device is not None: try: device_info = self.vnet_driver.get_device_infor( device_name=device) dest_metmask = device_info["netmask"] dest_gateway = device_info['gateway'] except KeyError as error: log.exception(str(error)) elif network is not None or bridge is not None: # TODO: need to add API to get network infor accroding to network or bridge pass if vif_netmask: if dest_metmask and dest_metmask != vif_netmask: log.error( "Netmask [%s] is not corresponding with the target network.", vif_netmask) return False else: # get the netmask on device as the default one vif_netmask = dest_metmask log.debug("VIF IP is: %s, netmask is: %s", vif_ip, vif_netmask) if not vif_netmask: # No default netmask and no given log.warn("No netmask given, the default one is '255.255.255.0'.") else: vif_gateway = dest_gateway if dest_gateway else None if not IpCheck.is_valid_ipv4_parameter( vif_ip, vif_netmask, gateway=vif_gateway): return False # First check it from database if self.check_ip_used(vif_ip): log.error("Ip address [%s] already in used.(Check from database).", vif_ip) return False # This ping test take a second, put it at last. if is_IP_pingable(vif_ip): log.error("Ipaddress [%s] is already be used(Ping test).", vif_ip) return False return True
def set_mac_address(self, inst_name, eth_index, new_mac): """ <mac address='52:54:00:68:43:c2'/> """ domain = self._get_domain_handler(domain_name=inst_name) if not domain: log.error("Domain %s doesn't exist, set mac failed.", inst_name) return False if domain.isActive(): log.warn("New MAC will take effect after domain reboot.") vif_list = self._get_dom_interfaces_elements_list(inst_name) try: interface = vif_list[eth_index] mac_element = interface.find("mac") old_mac = mac_element.get("address") except IndexError: log.exception("No interfaces at index [%s] find in domain [%s]", eth_index, inst_name) return False tree = xmlEtree.fromstring(domain.XMLDesc()) mac_list = tree.findall('devices/interface/mac') try: for mac_element in mac_list: if mac_element.get("address") == old_mac: log.debug( "Change old mac [%s] to new [%s] on interface index %s", old_mac, new_mac, eth_index) mac_element.set("address", new_mac) except ValueError as error: log.exception("Exception when set mac: %s on domain: [%s]", error, inst_name) return False domain_xml = xmlEtree.tostring(tree) # after change the xml, redeine it hv_handler = self.get_handler() if not hv_handler: log.error("Can not connect to host: %s when create domain %s.", self.hostname, inst_name) return False try: # if failed it will raise libvirtError, return value is always a Domain object _ = hv_handler.defineXML(domain_xml) except libvirtError: log.error( "Create domain %s failed when define by xml after set MAC.", inst_name) return False return True
def get_all_devices(self): """ @return: return a list of all the interfaces device name in host """ if self._hypervisor_handler is None: self._hypervisor_handler = self.get_handler() try: all_pifs = self._hypervisor_handler.xenapi.PIF.get_all() return [self._hypervisor_handler.xenapi.PIF.get_device(pif) for pif in all_pifs] except Exception as error: log.exception(error) return []
def _get_bridge_name_by_networkref(self, network_ref): """ :param network_ref: :return: a bridge name or "" """ if self._hypervisor_handler is None: self._hypervisor_handler = self.get_handler() try: return self._hypervisor_handler.xenapi.network.get_bridge(network_ref) except Exception as error: log.exception("Raise exception when get bridge name: %s", error) return ""
def _get_vm_metrics_record(self, inst_name): """ :return: a dict as :{'VCPUs_number': '8', 'memory_actual': '1073741824', 'VCPUs_params': {}, 'VCPUs_utilisation': {'0': 0.0}} """ handler = self.get_handler() try: vm_ref = handler.xenapi.VM.get_by_name_label(inst_name)[0] vm_metrics_ref = handler.xenapi.VM.get_metrics(vm_ref) return handler.xenapi.VM_metrics.get_record(vm_metrics_ref) except Exception, error: log.exception("Exceptions raised:%s", error) return {}
def get_host_storage_info(self, storage_name="default"): """ Return HV storage info: Unit is GB """ # Here only the VM storage directory calculated ret_storage_dict = {} hv_driver = self.get_handler() try: pool_dom = hv_driver.storagePoolLookupByName(storage_name) pool_info = pool_dom.info() except libvirtError, error: log.exception("Exceptions: %s", error) return ret_storage_dict
def respond_data(self): """ return the HTTP response data :return: """ try: if isinstance(self.resp, requests.models.Response): return json.loads(self.resp.content).get('data', {}) elif isinstance(self.resp, str): return json.loads(self.resp).get('data', {}) elif isinstance(self.resp, dict): return self.resp.get('data', {}) except ValueError, error: log.exception(error)
def get_vm_record(self, inst_name): """ return the record dict for inst_name """ handler = self.get_handler() vm_record = {} try: vm_ref = handler.xenapi.VM.get_by_name_label(inst_name)[0] record = handler.xenapi.VM.get_record(vm_ref) except Exception, error: log.exception("Exception: %s when get record for VM [%s].", error, inst_name) return {}
def _get_vm_ref(self, inst_name): """ @param inst_name: vm instance name @return: return a reference object to the vm """ if self._hypervisor_handler is None: self._hypervisor_handler = self.get_handler() try: vm_ref = self._hypervisor_handler.xenapi.VM.get_by_name_label( inst_name)[0] except Exception, error: log.exception("Raise exceptions when get vm reference: [%s].", error) return None