def reject(self, name): command = ['update_flash', '-r'] output, error, rc = run_command(command) if rc: raise OperationFailed('GINFW0006E', {'rc': rc}) # update_flash returns a message on success, so log it. kimchi_log.info(output)
def update(self, name, params): if detect_live_vm(): kimchi_log.error('Cannot update system fw while running VMs.') raise OperationFailed('GINFW0001E') fw_path = params['path'] pow_ok = params.get('overwrite-perm-ok', True) # First unpack the rpm to get the fw img file # FIXME: When there's a .deb package available, add support for that command = ['rpm', '-U', '--force', '--ignoreos', fw_path] output, error, rc = run_command(command) if rc: # rpm returns num failed pkgs on failure or neg for unknown raise OperationFailed('GINFW0002E', {'rc': rc, 'err': error}) # The image file should now be in /tmp/fwupdate/ # and match the rpm name. image_file, ext = os.path.splitext(os.path.basename(fw_path)) if image_file is None: kimchi_log.error('FW update failed: ' 'No image file found in the package file.') raise OperationFailed('GINFW0003E') command = [ 'update_flash', '-f', os.path.join('/tmp/fwupdate', '%s.img' % image_file) ] if not pow_ok: command.insert(1, '-n') kimchi_log.info('FW update: System will reboot to flash the firmware.') output, error, rc = run_command(command) if rc: raise OperationFailed('GINFW0004E', {'rc': rc})
def get_disk_ref_cnt(objstore, conn, path): try: with objstore as session: try: ref_cnt = session.get('storagevolume', path)['ref_cnt'] except NotFoundError: kimchi_log.info('Volume %s not found in obj store.' % path) ref_cnt = 0 # try to find this volume in existing vm vms_list = VMsModel.get_vms(conn) for vm in vms_list: dom = VMModel.get_vm(vm, conn) storages = get_vm_disks(dom) for disk in storages.keys(): d_info = get_vm_disk_info(dom, disk) if path == d_info['path']: ref_cnt = ref_cnt + 1 try: session.store('storagevolume', path, {'ref_cnt': ref_cnt}) except Exception as e: # Let the exception be raised. If we allow disks' # ref_cnts to be out of sync, data corruption could # occour if a disk is added to two guests # unknowingly. kimchi_log.error( 'Unable to store storage volume id in' ' objectstore due error: %s', e.message) raise OperationFailed('KCHVOL0017E', {'err': e.message}) except Exception as e: # This exception is going to catch errors returned by 'with', # specially ones generated by 'session.store'. It is outside # to avoid conflict with the __exit__ function of 'with' raise OperationFailed('KCHVOL0017E', {'err': e.message}) return ref_cnt
def update(self, name, params): if detect_live_vm(): kimchi_log.error('Cannot update system fw while running VMs.') raise OperationFailed('GINFW0001E') fw_path = params['path'] pow_ok = params.get('overwrite-perm-ok', True) # First unpack the rpm to get the fw img file # FIXME: When there's a .deb package available, add support for that command = ['rpm', '-U', '--force', '--ignoreos', fw_path] output, error, rc = run_command(command) if rc: # rpm returns num failed pkgs on failure or neg for unknown raise OperationFailed('GINFW0002E', {'rc': rc, 'err': error}) # The image file should now be in /tmp/fwupdate/ # and match the rpm name. image_file, ext = os.path.splitext(os.path.basename(fw_path)) if image_file is None: kimchi_log.error('FW update failed: ' 'No image file found in the package file.') raise OperationFailed('GINFW0003E') command = ['update_flash', '-f', os.path.join('/tmp/fwupdate', '%s.img' % image_file)] if not pow_ok: command.insert(1, '-n') kimchi_log.info('FW update: System will reboot to flash the firmware.') output, error, rc = run_command(command) if rc: raise OperationFailed('GINFW0004E', {'rc': rc})
def shutdown(self, args=None): # Check for running vms before shutdown running_vms = self._get_vms_list_by_state('running') if len(running_vms) > 0: raise OperationFailed("KCHHOST0001E") kimchi_log.info('Host is going to shutdown.') os.system('shutdown -h now')
def reboot(self, args=None): # Find running VMs running_vms = self._get_vms_list_by_state('running') if len(running_vms) > 0: raise OperationFailed("KCHHOST0002E") kimchi_log.info('Host is going to reboot.') os.system('reboot')
def wait_task(task_lookup, taskid, timeout=10): for i in range(0, timeout): task_info = task_lookup(taskid) if task_info['status'] == "running": kimchi_log.info("Waiting task %s, message: %s", taskid, task_info['message']) time.sleep(1) else: return kimchi_log.error("Timeout while process long-run task, " "try to increase timeout value.")
def _set_capabilities(self): kimchi_log.info("*** Running feature tests ***") self.qemu_stream = FeatureTests.qemu_supports_iso_stream() self.qemu_stream_dns = FeatureTests.qemu_iso_stream_dns() self.libvirt_stream_protocols = [] for p in ['http', 'https', 'ftp', 'ftps', 'tftp']: if FeatureTests.libvirt_supports_iso_stream(p): self.libvirt_stream_protocols.append(p) kimchi_log.info("*** Feature tests completed ***")
def __init__(self, **kargs): self.guest_threads_enabled = False self.sockets = 0 self.cores_present = 0 self.cores_available = 0 self.cores_per_socket = 0 self.threads_per_core = 0 self.max_threads = 0 self.conn = kargs['conn'] libvirt_topology = None try: connect = self.conn.get() libvirt_topology = get_topo_capabilities(connect) except Exception as e: kimchi_log.info("Unable to get CPU topology capabilities: %s" % e.message) return if libvirt_topology is None: kimchi_log.info("cpu_info topology not supported.") return if ARCH == 'power': # IBM PowerPC self.guest_threads_enabled = True out, error, rc = run_command(['ppc64_cpu', '--smt']) if rc or 'on' in out: # SMT has to be disabled for guest to use threads as CPUs. # rc is always zero, whether SMT is off or on. self.guest_threads_enabled = False out, error, rc = run_command(['ppc64_cpu', '--cores-present']) if not rc: self.cores_present = int(out.split()[-1]) out, error, rc = run_command(['ppc64_cpu', '--cores-on']) if not rc: self.cores_available = int(out.split()[-1]) out, error, rc = run_command(['ppc64_cpu', '--threads-per-core']) if not rc: self.threads_per_core = int(out.split()[-1]) self.sockets = self.cores_present / self.threads_per_core if self.sockets == 0: self.sockets = 1 self.cores_per_socket = self.cores_present / self.sockets else: # Intel or AMD self.guest_threads_enabled = True self.sockets = int(libvirt_topology.get('sockets')) self.cores_per_socket = int(libvirt_topology.get('cores')) self.cores_present = self.cores_per_socket * self.sockets self.cores_available = self.cores_present self.threads_per_core = int(libvirt_topology.get('threads'))
def __init__(self, **kargs): self.guest_threads_enabled = False self.sockets = 0 self.cores_present = 0 self.cores_available = 0 self.cores_per_socket = 0 self.threads_per_core = 0 self.max_threads = 0 self.conn = kargs['conn'] libvirt_topology = None try: connect = self.conn.get() libvirt_topology = get_topo_capabilities(connect) except Exception as e: kimchi_log.info("Unable to get CPU topology capabilities: %s" % e.message) return if libvirt_topology is None: kimchi_log.info("cpu_info topology not supported.") return if ARCH == 'power': # IBM PowerPC self.guest_threads_enabled = True out, error, rc = run_command(['ppc64_cpu', '--smt']) if rc or 'on' in out: # SMT has to be disabled for guest to use threads as CPUs. # rc is always zero, whether SMT is off or on. self.guest_threads_enabled = False out, error, rc = run_command(['ppc64_cpu', '--cores-present']) if not rc: self.cores_present = int(out.split()[-1]) out, error, rc = run_command(['ppc64_cpu', '--cores-on']) if not rc: self.cores_available = int(out.split()[-1]) out, error, rc = run_command(['ppc64_cpu', '--threads-per-core']) if not rc: self.threads_per_core = int(out.split()[-1]) self.sockets = self.cores_present/self.threads_per_core if self.sockets == 0: self.sockets = 1 self.cores_per_socket = self.cores_present/self.sockets else: # Intel or AMD self.guest_threads_enabled = True self.sockets = int(libvirt_topology.get('sockets')) self.cores_per_socket = int(libvirt_topology.get('cores')) self.cores_present = self.cores_per_socket * self.sockets self.cores_available = self.cores_present self.threads_per_core = int(libvirt_topology.get('threads'))
def _set_capabilities(self): kimchi_log.info("*** Running feature tests ***") self.qemu_stream = FeatureTests.qemu_supports_iso_stream() self.qemu_stream_dns = FeatureTests.qemu_iso_stream_dns() self.nfs_target_probe = FeatureTests.libvirt_support_nfs_probe() self.fc_host_support = FeatureTests.libvirt_support_fc_host() self.metadata_support = FeatureTests.has_metadata_support() self.libvirt_stream_protocols = [] for p in ['http', 'https', 'ftp', 'ftps', 'tftp']: if FeatureTests.libvirt_supports_iso_stream(p): self.libvirt_stream_protocols.append(p) kimchi_log.info("*** Feature tests completed ***")
def prepare(self, conn=None): tmp_name = self.poolArgs['source']['name'] self.poolArgs['source']['name'] = tmp_name.replace('scsi_', '') # fc_host adapters type are only available in libvirt >= 1.0.5 if not self.poolArgs['fc_host_support']: self.poolArgs['source']['adapter_type'] = 'scsi_host' msg = "Libvirt version <= 1.0.5. Setting SCSI host name as '%s'; "\ "setting SCSI adapter type as 'scsi_host'; "\ "ignoring wwnn and wwpn." % tmp_name kimchi_log.info(msg) # Path for Fibre Channel scsi hosts self.poolArgs['path'] = '/dev/disk/by-path' if not self.poolArgs['source']['adapter_type']: self.poolArgs['source']['adapter_type'] = 'scsi_host'
def prepare(self, conn=None): tmp_name = self.poolArgs['source']['name'] self.poolArgs['source']['name'] = tmp_name.replace('scsi_', '') # fc_host adapters type are only available in libvirt >= 1.0.5 if not self.poolArgs['fc_host_support']: self.poolArgs['source']['adapter']['type'] = 'scsi_host' msg = "Libvirt version <= 1.0.5. Setting SCSI host name as '%s'; "\ "setting SCSI adapter type as 'scsi_host'; "\ "ignoring wwnn and wwpn." % tmp_name kimchi_log.info(msg) # Path for Fibre Channel scsi hosts self.poolArgs['path'] = '/dev/disk/by-path' if not self.poolArgs['source']['adapter']['type']: self.poolArgs['source']['adapter']['type'] = 'scsi_host'
def _set_capabilities(self): kimchi_log.info("*** Running feature tests ***") conn = self.conn.get() self.qemu_stream = FeatureTests.qemu_supports_iso_stream() self.nfs_target_probe = FeatureTests.libvirt_support_nfs_probe(conn) self.fc_host_support = FeatureTests.libvirt_support_fc_host(conn) self.kernel_vfio = FeatureTests.kernel_support_vfio() self.mem_hotplug_support = FeatureTests.has_mem_hotplug_support(conn) self.libvirt_stream_protocols = [] for p in ['http', 'https', 'ftp', 'ftps', 'tftp']: if FeatureTests.libvirt_supports_iso_stream(conn, p): self.libvirt_stream_protocols.append(p) kimchi_log.info("*** Feature tests completed ***")
def update(self, name, params): path = config.get_debugreports_path() file_pattern = os.path.join(path, name + '.*') try: file_source = glob.glob(file_pattern)[0] except IndexError: raise NotFoundError("KCHDR0001E", {'name': name}) file_target = file_source.replace(name, params['name']) if os.path.isfile(file_target): raise InvalidParameter('KCHDR0008E', {'name': params['name']}) shutil.move(file_source, file_target) kimchi_log.info('%s renamed to %s' % (file_source, file_target)) return params['name']
def _set_capabilities(self): kimchi_log.info("*** Running feature tests ***") conn = self.conn.get() self.qemu_stream = FeatureTests.qemu_supports_iso_stream() self.nfs_target_probe = FeatureTests.libvirt_support_nfs_probe(conn) self.fc_host_support = FeatureTests.libvirt_support_fc_host(conn) self.metadata_support = FeatureTests.has_metadata_support(conn) self.kernel_vfio = FeatureTests.kernel_support_vfio() self.mem_hotplug_support = FeatureTests.has_mem_hotplug_support(conn) self.libvirt_stream_protocols = [] for p in ['http', 'https', 'ftp', 'ftps', 'tftp']: if FeatureTests.libvirt_supports_iso_stream(conn, p): self.libvirt_stream_protocols.append(p) kimchi_log.info("*** Feature tests completed ***")
def get_system_report_tool(): # Please add new possible debug report command here # and implement the report generating function # based on the new report command report_tools = ({'cmd': 'sosreport --help', 'fn': DebugReportsModel.sosreport_generate},) # check if the command can be found by shell one by one for helper_tool in report_tools: try: retcode = subprocess.call(helper_tool['cmd'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if retcode == 0: return helper_tool['fn'] except Exception, e: kimchi_log.info('Exception running command: %s', e)
def get_system_report_tool(): # Please add new possible debug report command here # and implement the report generating function # based on the new report command report_tools = ({ 'cmd': 'sosreport --help', 'fn': DebugReportsModel.sosreport_generate }, ) # check if the command can be found by shell one by one for helper_tool in report_tools: try: retcode = subprocess.call(helper_tool['cmd'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if retcode == 0: return helper_tool['fn'] except Exception, e: kimchi_log.info('Exception running command: %s', e)
def __init__(self): # This stores all packages to be updated for Kimchi perspective. It's a # dictionary of dictionaries, in the format {'package_name': package}, # where: # package = {'package_name': <string>, 'version': <string>, # 'arch': <string>, 'repository': <string> # } self._packages = {} # This stores the number of packages to update self._num2update = 0 # Get the distro of host machine and creates an object related to # correct package management system try: __import__('yum') kimchi_log.info("Loading YumUpdate features.") self._pkg_mnger = YumUpdate() except ImportError: try: __import__('apt') kimchi_log.info("Loading AptUpdate features.") self._pkg_mnger = AptUpdate() except ImportError: zypper_help = ["zypper", "--help"] (stdout, stderr, returncode) = run_command(zypper_help) if returncode == 0: kimchi_log.info("Loading ZypperUpdate features.") self._pkg_mnger = ZypperUpdate() else: raise Exception("There is no compatible package manager " "for this system.")
def __init__(self): # This stores all packages to be updated for Kimchi perspective. It's a # dictionary of dictionaries, in the format {'package_name': package}, # where: # package = {'package_name': <string>, 'version': <string>, # 'arch': <string>, 'repository': <string> # } self._packages = {} # This stores the number of packages to update self._num2update = 0 # Get the distro of host machine and creates an object related to # correct package management system self._distro = platform.linux_distribution()[0].lower() if self._distro in YUM_DISTROS: kimchi_log.info("Loading YumUpdate features.") self._pkg_mnger = YumUpdate() elif self._distro in APT_DISTROS: kimchi_log.info("Loading AptUpdate features.") self._pkg_mnger = AptUpdate() elif self._distro in ZYPPER_DISTROS: kimchi_log.info("Loading ZypperUpdate features.") self._pkg_mnger = ZypperUpdate() else: raise Exception("There is no compatible package manager for " "this system.")
def __init__(self): # This stores all packages to be updated for Kimchi perspective. It's a # dictionary of dictionaries, in the format {'package_name': package}, # where: # package = {'package_name': <string>, 'version': <string>, # 'arch': <string>, 'repository': <string> # } self._packages = {} # This stores the number of packages to update self._num2update = 0 # Get the distro of host machine and creates an object related to # correct package management system self._distro = platform.linux_distribution()[0].lower() if (self._distro in YUM_DISTROS): kimchi_log.info("Loading YumUpdate features.") self._pkg_mnger = YumUpdate() elif (self._distro in APT_DISTROS): kimchi_log.info("Loading AptUpdate features.") self._pkg_mnger = AptUpdate() elif (self._distro in ZYPPER_DISTROS): kimchi_log.info("Loading ZypperUpdate features.") self._pkg_mnger = ZypperUpdate() else: raise Exception("There is no compatible package manager for " "this system.")
def sosreport_generate(cb, name): try: command = ['sosreport', '--batch', '--name=%s' % name] output, error, retcode = run_command(command) if retcode < 0: raise OperationFailed("KCHDR0003E", {'name': name, 'err': retcode}) elif retcode > 0: raise OperationFailed("KCHDR0003E", {'name': name, 'err': retcode}) # SOSREPORT might create file in /tmp or /var/tmp # FIXME: The right way should be passing the tar.xz file directory # though the parameter '--tmp-dir', but it is failing in Fedora 20 patterns = ['/tmp/sosreport-%s-*', '/var/tmp/sosreport-%s-*'] reports = [] reportFile = None for p in patterns: reports = reports + [f for f in glob.glob(p % name)] for f in reports: if not fnmatch.fnmatch(f, '*.md5'): reportFile = f break # Some error in sosreport happened if reportFile is None: kimchi_log.error('Debug report file not found. See sosreport ' 'output for detail:\n%s', output) fname = (patterns[0] % name).split('/')[-1] raise OperationFailed('KCHDR0004E', {'name': fname}) md5_report_file = reportFile + '.md5' report_file_extension = '.' + reportFile.split('.', 1)[1] path = config.get_debugreports_path() target = os.path.join(path, name + report_file_extension) # Moving report msg = 'Moving debug report file "%s" to "%s"' % (reportFile, target) kimchi_log.info(msg) shutil.move(reportFile, target) # Deleting md5 msg = 'Deleting report md5 file: "%s"' % (md5_report_file) kimchi_log.info(msg) md5 = open(md5_report_file).read().strip() kimchi_log.info('Md5 file content: "%s"', md5) os.remove(md5_report_file) cb('OK', True) return except OSError: raise except Exception, e: # No need to call cb to update the task status here. # The task object will catch the exception rasied here # and update the task status there log = logging.getLogger('Model') log.warning('Exception in generating debug file: %s', e) raise OperationFailed("KCHDR0005E", {'name': name, 'err': e})
def get_disk_ref_cnt(objstore, conn, path): try: with objstore as session: try: ref_cnt = session.get('storagevolume', path)['ref_cnt'] except NotFoundError: kimchi_log.info('Volume %s not found in obj store.' % path) ref_cnt = 0 # try to find this volume in existing vm vms_list = VMsModel.get_vms(conn) for vm in vms_list: dom = VMModel.get_vm(vm, conn) storages = get_vm_disks(dom) for disk in storages.keys(): d_info = get_vm_disk_info(dom, disk) if path == d_info['path']: ref_cnt = ref_cnt + 1 try: session.store('storagevolume', path, {'ref_cnt': ref_cnt}) except Exception as e: # Let the exception be raised. If we allow disks' # ref_cnts to be out of sync, data corruption could # occour if a disk is added to two guests # unknowingly. kimchi_log.error('Unable to store storage volume id in' ' objectstore due error: %s', e.message) raise OperationFailed('KCHVOL0017E', {'err': e.message}) except Exception as e: # This exception is going to catch errors returned by 'with', # specially ones generated by 'session.store'. It is outside # to avoid conflict with the __exit__ function of 'with' raise OperationFailed('KCHVOL0017E', {'err': e.message}) return ref_cnt
def sosreport_generate(cb, name): try: command = ['sosreport', '--batch', '--name=%s' % name] output, error, retcode = run_command(command) if retcode < 0: raise OperationFailed("KCHDR0003E", { 'name': name, 'err': retcode }) elif retcode > 0: raise OperationFailed("KCHDR0003E", { 'name': name, 'err': retcode }) # SOSREPORT might create file in /tmp or /var/tmp # FIXME: The right way should be passing the tar.xz file directory # though the parameter '--tmp-dir', but it is failing in Fedora 20 patterns = ['/tmp/sosreport-%s-*', '/var/tmp/sosreport-%s-*'] reports = [] reportFile = None for p in patterns: reports = reports + [f for f in glob.glob(p % name)] for f in reports: if not fnmatch.fnmatch(f, '*.md5'): reportFile = f break # Some error in sosreport happened if reportFile is None: kimchi_log.error( 'Debug report file not found. See sosreport ' 'output for detail:\n%s', output) fname = (patterns[0] % name).split('/')[-1] raise OperationFailed('KCHDR0004E', {'name': fname}) md5_report_file = reportFile + '.md5' report_file_extension = '.' + reportFile.split('.', 1)[1] path = config.get_debugreports_path() target = os.path.join(path, name + report_file_extension) # Moving report msg = 'Moving debug report file "%s" to "%s"' % (reportFile, target) kimchi_log.info(msg) shutil.move(reportFile, target) # Deleting md5 msg = 'Deleting report md5 file: "%s"' % (md5_report_file) kimchi_log.info(msg) md5 = open(md5_report_file).read().strip() kimchi_log.info('Md5 file content: "%s"', md5) os.remove(md5_report_file) cb('OK', True) return except OSError: raise except Exception, e: # No need to call cb to update the task status here. # The task object will catch the exception rasied here # and update the task status there log = logging.getLogger('Model') log.warning('Exception in generating debug file: %s', e) raise OperationFailed("KCHDR0005E", {'name': name, 'err': e})
def _mock_host_shutdown(self, *name): kimchi_log.info("The host system will be shutted down")
def _mock_host_reboot(self, *name): kimchi_log.info("The host system will be rebooted")