def exec_search(file_name, rootdir='/', dirnames=False): """ Find the filename in the rootdir tree. Parameters ---------- file_name: str The filename to look for. rootdir: str The directory to start from, default is root. dirnames: bool If True, also consider directory names. Returns ------- str: The full path of the filename if found, None otherwise. """ _logger.debug('__ Looking for %s in %s', file_name, rootdir) result_msg(msg='Looking for %s in %s, might take a while.' % (file_name, rootdir)) try: for path_name, directories, files in os.walk(rootdir): # _logger.debug('%s %s %s', path_name, directories, files) if file_name in files: _logger.debug('Found %s', os.path.join(rootdir, path_name, file_name)) return os.path.join(rootdir, path_name, file_name) if dirnames and file_name in directories: _logger.debug('Found %s as directory.', os.path.join(rootdir, path_name, file_name)) return os.path.join(rootdir, path_name, file_name) except Exception as e: _logger.error(' Error while looking for %s: %s', file_name, str(e)) raise OciMigrateException('Error while looking for %s:' % file_name) from e return None
def __init__(self, filename): """ Initialisation of the qcow2 header analysis. Parameters ---------- filename: str Full path of the qcow2 image file. """ _logger.debug('qcow2 header size: %d bytes', self.head_size) super().__init__(filename) head_size = struct.calcsize(Qcow2Head.qcowhead_fmt) try: with open(self._fn, 'rb') as f: head_bin = f.read(head_size) _logger.debug('%s header successfully read', self._fn) except Exception as e: _logger.critical(' Failed to read header of %s: %s', self._fn, str(e)) raise OciMigrateException('Failed to read the header of %s' % self._fn) from e qcow2header = struct.unpack(Qcow2Head.qcowhead_fmt, head_bin) self.stat = os.stat(self._fn) self.img_tag = os.path.splitext(os.path.split(self._fn)[1])[0] self.qcowhead_dict = dict( (name[2], qcow2header[i]) for i, name in enumerate(Qcow2Head.header2_structure)) self.img_header = dict() self.img_header['head'] = self.qcowhead_dict result_msg(msg='Got image %s header' % filename, result=False)
def update_network_config(rootdir): """ Modify the network configuration in the image file to prevent conflicts during import. Currently ifcfg, NetworkManager, netplan, network connections systemd-networkd and interface file are scanned. Bonding and bridging are not supported for now, nor multiple ip per interface. Parameters ---------- rootdir: str Full path of image root dir. Returns ------- list: Network interfaces dict: List with dictionary representation of the network configuration files. """ result_msg(msg='Adjust network configuration.', result=False) network_config = dict() network_list = list() # # Cleanup udev network device naming. if cleanup_udev(rootdir): _logger.debug('udev successfully modified.') else: _logger.debug( 'Failed to modify udev rules with respect to network device naming.' ) # # ifcfg ifcfg_nics, ifcfg_data = reconfigure_ifcfg_config(rootdir) network_list += ifcfg_nics network_config['ifcfg'] = ifcfg_data # # netplan netplan_nics, netplan_data = reconfigure_netplan(rootdir) network_list += netplan_nics network_config['netplan'] = netplan_data # # network manager nwmg_nics, nwmg_data = reconfigure_networkmanager(rootdir) network_list += nwmg_nics network_config['network_manager'] = nwmg_data # # interfaces int_list, int_data = reconfigure_interfaces(rootdir) network_list += int_list network_config['interfaces'] = int_data # # systemd netsys_nics, netsys_data = reconfigure_systemd_networkd(rootdir) network_list += netsys_nics network_config['systemd-networkd'] = netsys_data result_msg(msg='Adjusted network configuration.', result=True) return network_list, network_config
def show_default_kernel(kernelversion): """ Show the default kernel version. Parameters ---------- kernelversion: str The version of the kernel booted by default. Returns ------- No return value. """ result_msg(msg='\n Default kernel: %s' % kernelversion, result=True)
def show_fstab(fstabdata): """ Show the relevant data in the fstab file. Parameters ---------- fstabdata: list of lists, one list per fstab line. Returns ------- No return value. """ for line in fstabdata: result_msg(msg='%60s %20s %8s %20s %2s %2s' % (line[0], line[1], line[2], line[3], line[4], line[5]), result=True)
def show_kernel_list(kernels): """ Show the kernels defined in the grub config file. Parameters ---------- kernels: list List of kernels defined in the grub config file. Returns ------- No return value. """ for kver in sorted(kernels): result_msg(msg=' %s' % kver, result=True)
def print_header(head): """ Display header for image data component. Parameters ---------- head: str The header Returns ------- No return value. """ result_msg(msg='\n %30s\n %30s' % (head, '-' * 30), result=True)
def show_header(self): """ Lists the header contents formatted. Returns ------- No return value. """ result_msg(msg='\n %30s\n %30s' % ('QCOW2 file header data', '-' * 30), result=False) for f in Qcow2Head.header2_structure: result_msg(msg=''.join( [" %-30s" % f[2], f[1] % self.qcowhead_dict[f[2]]]), result=False)
def __init__(self, filename): """ Initialisation of the vmdk header analysis. Parameters ---------- filename: str Full path of the vmdk image file. """ super().__init__(filename) _logger.debug('VMDK header size: %d bytes', self.head_size) try: with open(self._fn, 'rb') as f: head_bin = f.read(self.head_size) _logger.debug('%s header successfully read', self._fn) except Exception as e: _logger.critical(' Failed to read header of %s: %s', self._fn, str(e)) raise OciMigrateException('Failed to read the header of %s: %s' % self._fn) from e vmdkheader = struct.unpack(VmdkHead.vmdkhead_fmt, head_bin) try: with open(self._fn, 'rb') as f: f.seek(512) head_descr = [ it for it in f.read(1024).decode('utf-8').splitlines() if '=' in it ] except Exception as e: _logger.critical(' Failed to read description of %s: %s', self._fn, str(e)) raise OciMigrateException( 'Failed to read the description of %s: %s' % self._fn) from e self.stat = os.stat(self._fn) self.img_tag = os.path.splitext(os.path.split(self._fn)[1])[0] self.vmdkhead_dict = dict( (name[2], vmdkheader[i]) for i, name in enumerate(VmdkHead.header0_structure)) self.vmdkdesc_dict = dict( [re.sub(r'"', '', kv).split('=') for kv in head_descr]) self.img_header = dict() self.img_header['head'] = self.vmdkhead_dict self.img_header['desc'] = self.vmdkdesc_dict result_msg(msg='Got image %s header' % filename, result=False)
def exec_sfdisk(devname): """ Collect the data about the partitions on the image file mounted on the device devname using the sfdisk utility. Parameters ---------- devname: str The device. Returns ------- dict: The partition data with sfdisk results on success, None otherwise. """ cmd = ['sfdisk', '-d', devname] _logger.debug('__ Running %s', cmd) pause_msg(cmd, pause_flag='_OCI_EXEC') try: result = run_popen_cmd(cmd)['output'].decode('utf-8') partdata = dict() for devx in result.splitlines(): if devx.startswith(devname): key = devx.split(':')[0].strip() result_msg(msg='sfdisk partition %s' % key, result=False) thispart = {'start': 0, 'size': 0, 'Id': 0, 'bootable': False} val = devx.split(':')[1].split(',') for it in val: if 'start' in it: x = it.split('=')[1] thispart['start'] = int(x) elif 'size' in it: x = it.split('=')[1] thispart['size'] = int(x) elif 'Id' in it: x = it.split('=')[1] thispart['Id'] = x.strip() elif 'bootable' in it: thispart['bootable'] = True else: _logger.debug('unrecognised item: %s', val) partdata[key] = thispart _logger.debug(partdata) return partdata except Exception as e: _logger.error(' Failed to collect sfdisk %s partition data: %s', devname, str(e)) return None
def show_network_data(networkdata): """ Show the collected data on the network interfaces. Parameters ---------- networkdata: dict Dictionary of dictionaries containing the network configuration data. Returns ------- No return value. """ for nic, nicdata in sorted(networkdata.items()): result_msg(msg=' %20s:' % nic, result=True) for k, v in sorted(nicdata.items()): result_msg(msg=' %30s = %s' % (k, v), result=True)
def show_img_header(headerdata): """ Show the header data. Parameters ---------- headerdata: dict Dictionary containing data extracted from the image header; contents is dependent form image type. Returns ------- No return value. """ result_msg(msg='\n %30s\n %30s' % ('Image header:', '-'*30), result=True) for k, v in sorted(headerdata): result_msg(msg=' %30s : %s' % (k, v), result=True)
def image_size(self): """ Get the size of the image file. Returns ------- dict: physical file size, logical file size """ img_sz = { 'physical': float(self.stat.st_size) / gigabyte, 'logical': float(self.vmdkhead_dict['capacity'] * 512) / gigabyte } result_msg(msg='Image size: physical %10.2f GB, logical %10.2f GB' % (img_sz['physical'], img_sz['logical']), result=True) return img_sz
def show_grub_data(grublist): """ Show the relevant data in the grub config file. Parameters ---------- grublist: list of dictionaries, 1 per boot section, containing grub lines as list. Returns ------- No return value. """ for entry in grublist: _logger.debug('%s', entry) for grubkey in entry: for grubline in entry[grubkey]: result_msg(msg=grubline, result=True) result_msg(msg='\n', result=True)
def show_partition_table(table): """ Show the relevant data of the partition table. Parameters ---------- table: list of dict. The partition table data. Returns ------- No return value. """ result_msg(msg=' %2s %5s %16s %32s' % ('nb', 'boot', 'type', 'data'), result=True) result_msg(msg=' %2s %5s %16s %32s' % ('-' * 2, '-' * 5, '-' * 16, '-' * 32), result=True) for i in range(0, 4): if table[i]['boot']: bootflag = 'YES' else: bootflag = ' NO' result_msg(msg=' %02d %5s %16s %32s' % (i, bootflag, table[i]['type'], table[i]['entry']), result=True)
def __init__(self, filename): """ Initialisation of the templatetype header analysis. Parameters ---------- filename: str Full path of the template_type image file. """ super().__init__(filename) _logger.debug('templatetype header size: %d bytes', self.head_size) try: with open(self._fn, 'rb') as f: head_bin = f.read(self.head_size) _logger.debug('%s header successfully read', self._fn) except Exception as e: _logger.critical(' Failed to read header of %s: %s', self._fn, str(e)) raise OciMigrateException('Failed to read the header of %s' % self._fn) from e templatetypeheader = struct.unpack(TemplateTypeHead.templatetypehead_fmt, head_bin) self.stat = os.stat(self._fn) self.img_tag = os.path.splitext(os.path.split(self._fn)[1])[0] self.templatehead_dict = \ dict((name[2], templatetypeheader[i]) for i, name in enumerate(TemplateTypeHead.header2_structure)) self.img_header = dict() self.img_header['head'] = self.templatehead_dict result_msg(msg='Got image %s header' % filename, result=False) # # mount the image using the nbd try: self.device_name = self.mount_img() _logger.debug('Image data %s', self.device_name) result_msg(msg='Mounted %s' % self.device_name, result=False) deviceinfo = self.handle_image() except Exception as e: _logger.critical(' Error %s', str(e)) raise OciMigrateException('Failed') from e
def show_partition_data(partition_dict): """ Show the collected data on the partitions of the image file. Parameters ---------- partition_dict: dict The data. Returns ------- No return value """ for k, v in sorted(partition_dict.items()): result_msg(msg='%30s :\n%s' % ('partition %s' % k, '-'*60), result=True) for x, y in sorted(v.items()): result_msg(msg='%30s : %s' % (x, y), result=True) result_msg(msg='\n', result=True) result_msg(msg='\n', result=True)
def show_header(self): """ Lists the header contents formatted. Returns ------- No return value. """ result_msg(msg='\n %30s\n %30s %30s' % ('VMDK file header data', '-' * 30, '-' * 30), result=False) for f in VmdkHead.header0_structure: result_msg(msg=''.join( [' %30s : ' % f[2], f[1] % self.vmdkhead_dict[f[2]]]), result=False) result_msg(msg='\n %30s\n %30s %30s' % ('VMDK file descriptor data', '-' * 30, '-' * 30), result=False) for k in sorted(self.vmdkdesc_dict): result_msg(msg=' %30s : %-30s' % (k, self.vmdkdesc_dict[k]), result=False)
def show_parted_data(parted_dict): """ Show the data collected by the parted command. Parameters ---------- parted_dict: dict The data. Returns ------- No return value. """ for k, v in sorted(parted_dict.items()): if k == 'Partition List': result_msg(msg='%30s :' % k, result=True) for part in v: result_msg(msg='%30s : %s' % (' ', ' '.join(part)), result=True) else: result_msg(msg='%30s : %s' % (k, v), result=True) result_msg(msg='\n', result=True)
def mount_imgfn(imgname): """ Link vm image with an nbd device. Parameters ---------- imgname: str Full path of the image file. Returns ------- str: Device name on success, raises an exception otherwise. """ # # create nbd devices _logger.debug('__ Running mount image file %s.', imgname) result_msg(msg='Load nbd') if not system_tools.create_nbd(): raise OciMigrateException('Failed ot load nbd module') _logger.debug('nbd module loaded') # # find free nbd device result_msg(msg='Find free nbd device') devpath = system_tools.get_free_nbd() _logger.debug('Device %s is free.', devpath) # # link img with first free nbd device result_msg(msg='Mount image %s' % imgname, result=True) _, nbcols = terminal_dimension() try: mountwait = ProgressBar(nbcols, 0.2, progress_chars=['mounting image']) mountwait.start() qemucmd = ['-c', devpath, imgname] pause_msg(qemucmd, pause_flag='_OCI_MOUNT') qemunbd_ret = system_tools.exec_qemunbd(qemucmd) if qemunbd_ret == 0: time.sleep(5) _logger.debug('qemu-nbd %s succeeded', qemucmd) return devpath _logger.critical('\n Failed to create nbd devices: %d', qemunbd_ret) raise Exception('Failed to create nbd devices: %d' % qemunbd_ret) except Exception as e: _logger.critical('\n Something wrong with creating nbd devices: %s', str(e)) raise OciMigrateException('Unable to create nbd devices:') from e finally: if system_tools.is_thread_running(mountwait): mountwait.stop()
def show_lvm2_data(lvm2_data): """ Show the collected lvm2 data. Parameters ---------- lvm2_data: dict Dictionary containing the recognised volume groups and logical volumes. Returns ------- No return value. """ for k, v in sorted(lvm2_data.items()): result_msg(msg='\n Volume Group: %s:' % k, result=True) for t in v: result_msg(msg='%40s : %-30s' % (t[0], t[1]), result=True) result_msg(msg='\n', result=True)
def show_image_data(imgobj): """ Show the collected data about the image. Parameters ---------- imgobj: object The data about the image. Returns ------- No return value. """ print_header('Components collected.') for k, _ in sorted(imgobj.image_info.items()): result_msg(msg=' %30s' % k, result=True) _logger.debug('show data') print('\n %25s\n %s' % ('Image data:', '-' * 60)) # # name fnname = ' missing' print_header('Image file path.') if 'img_name' in imgobj.image_info: fnname = imgobj.image_info['img_name'] result_msg(msg=' %30s' % fnname, result=True) # # type imgtype = ' missing' print_header('Image type.') if 'img_type' in imgobj.image_info: imgtype = imgobj.image_info['img_type'] result_msg(msg=' %30s' % imgtype, result=True) # # size imgsizes = ' physical: missing data\n logical: missing data' print_header('Image size:') if 'img_size' in imgobj.image_info: imgsizes = ' physical: %8.2f GB\n logical: %8.2f GB' \ % (imgobj.image_info['img_size']['physical'], imgobj.image_info['img_size']['logical']) result_msg(msg='%s' % imgsizes, result=True) # # header if 'img_header' in imgobj.image_info: try: imgobj.show_header() except Exception as e: result_msg(msg='Failed to show the image hadear: %s' % str(e), result=True) else: result_msg(msg='\n Image header data missing.', result=True) # # mbr mbr = ' missing' print_header('Master Boot Record.') if 'mbr' in imgobj.image_info: if 'hex' in imgobj.image_info['mbr']: mbr = imgobj.image_info['mbr']['hex'] result_msg(msg='%s' % mbr, result=True) # # partition table print_header('Partiton Table.') parttabmissing = ' Partition table data is missing.' if 'partition_table' in imgobj.image_info['mbr']: show_partition_table(imgobj.image_info['mbr']['partition_table']) else: result_msg(msg=parttabmissing, result=True) # # parted data print_header('Parted data.') parteddata = ' Parted data is missing.' if 'parted' in imgobj.image_info: show_parted_data(imgobj.image_info['parted']) else: result_msg(msg='%s' % parteddata, result=True) # # partition data print_header('Partition Data.') partdata = ' Partition data is missing.' if 'partitions' in imgobj.image_info: show_partition_data(imgobj.image_info['partitions']) else: result_msg(msg='%s' % partdata, result=True) # # grub config data print_header('Grub configuration data.') grubdat = ' Grub configuration data is missing.' if 'grubdata' in imgobj.image_info: show_grub_data(imgobj.image_info['grubdata']) else: result_msg(msg='%s' % grubdat, result=True) # # kernel versions print_header('Default kernel version.') kerneldefdat = ' Default kernel data not found or is missing.' if 'kernelversion' in imgobj.image_info: show_default_kernel(imgobj.image_info['kernelversion']) else: result_msg(msg='%s' % kerneldefdat, result=True) print_header('Installed kernels.') kernellisdat = ' List of kernels is missing.' if 'kernellist' in imgobj.image_info: show_kernel_list(imgobj.image_info['kernellist']) else: result_msg(msg='%s' % kernellisdat, result=True) # # logical volume data print_header('Logical Volume data.') lvmdata = ' Logical Volume data is missing.' if 'volume_groups' in imgobj.image_info: if imgobj.image_info['volume_groups']: show_lvm2_data(imgobj.image_info['volume_groups']) else: result_msg(msg=lvmdata, result=True) # # various data: print_header('Various data.') if 'bootmnt' in imgobj.image_info: result_msg(msg=' %30s: %s mounted on %s' % ('boot', imgobj.image_info['bootmnt'][0], imgobj.image_info['bootmnt'][1]), result=True) if 'rootmnt' in imgobj.image_info: result_msg(msg=' %30s: %s mounted on %s' % ('root', imgobj.image_info['rootmnt'][0], imgobj.image_info['rootmnt'][1]), result=True) if 'boot_type' in imgobj.image_info: result_msg(msg=' %30s: %-30s' % ('boot type:', imgobj.image_info['boot_type']), result=True) # # fstab print_header('fstab data.') fstabmiss = ' fstab data is missing.' if 'fstab' in imgobj.image_info: show_fstab(imgobj.image_info['fstab']) else: result_msg(msg=fstabmiss, result=True) # # os release data print_header('Operating System information.') osinfomissing = ' Operation System information is missing.' if 'osinformation' in imgobj.image_info: for k in sorted(imgobj.image_info['osinformation']): result_msg(msg=' %35s : %-30s' % (k, imgobj.image_info['osinformation'][k]), result=True) else: result_msg(msg=osinfomissing, result=True)
def reconfigure_networkmanager(rootdir): """ Replace the networkmanager configuration with Oracle Cloud Infrastructure compatible version. Parameters ---------- rootdir: str Full path of image root dir as loopback mounted. Returns ------- list: list of nic. dict: the network manager system-connections configurations """ _logger.debug('__ The NetworkManager configuration.') netwmg_data = dict() netwmg_nics = list() network_config_dir = rootdir + get_config_data('default_nwconnections') _logger.debug('Network manager dir: %s', network_config_dir) nw_mgr_cfg = rootdir + get_config_data('default_nwmconfig') _logger.debug('Network manager conf: %s', nw_mgr_cfg) # # backup try: # # copy if os.path.isfile(nw_mgr_cfg): bck_nw_mgr_cfg = system_tools.exec_rename(nw_mgr_cfg) if bool(bck_nw_mgr_cfg): _logger.debug('Copied %s to %s', nw_mgr_cfg, bck_nw_mgr_cfg) else: _logger.warning( 'Failed to backup network manager configuration.') else: _logger.debug('No %s found.', nw_mgr_cfg) # if os.path.isdir(network_config_dir): bck_network_config_dir = system_tools.backup_dir( network_config_dir) _logger.debug('Copied %s to %s', network_config_dir, bck_network_config_dir) else: _logger.debug('%s not found.', network_config_dir) except Exception as e: error_msg('Failed to backup the networkmanager configuration: %s' % str(e)) # # if os.path.isdir(network_config_dir): _logger.debug('NetworkManager/%s directory exists.', network_config_dir) # # contains nwm keyfiles? nwm_files = glob(network_config_dir + '/*') if len(nwm_files) > 0: system_tools.exec_rmdir(network_config_dir) system_tools.exec_mkdir(network_config_dir) _logger.debug('%s emptied.', network_config_dir) else: _logger.debug('No network manager keyfiles found.') # # update networkmanager configuration # TODO: write config file with configparser nwm_config_data = get_config_data('default_nwm_conf_file') with open(nw_mgr_cfg, 'w') as nwmf: nwmf.write('\n'.join(str(x) for x in nwm_config_data)) result_msg(msg='Networkmanager configuration updated.', result=False) else: _logger.debug(msg=' No NetworkManager configuration present.') return netwmg_nics, netwmg_data
def reconfigure_interfaces(rootdir): """ Parse the network interfaces file. Parameters ---------- rootdir: str Full path of image root dir as loopback mounted. Returns ------- list: list of nic. dict: the interfaces configuration. """ _logger.debug('__ The network interfaces configuration.') int_data = dict() int_nics = list() root_path = rootdir + get_config_data('default_interfaces') net_ifcfg_config = root_path + '/interfaces' if os.path.isfile(net_ifcfg_config): int_data[get_config_data('default_interfaces')] = list() _logger.debug('%s file exists', net_ifcfg_config) try: with open(net_ifcfg_config, 'r') as inf: for ln in inf: int_data[get_config_data('default_interfaces')].append(ln) if 'iface' in ln.split(): if ln.split()[1] != 'lo': int_nics.append(ln.split()[1]) else: _logger.debug('no iface in %s', ln) except Exception as e: _logger.error(' Error occured while reading %s: %s', net_ifcfg_config, str(e)) # # rewrite if len(int_nics) == 0: _logger.debug('No interface definitions found in %s', net_ifcfg_config) else: try: # # backup bck_root_path = system_tools.backup_dir(root_path) _logger.debug('Copied %s to %s', root_path, bck_root_path) # # remove dir shutil.rmtree(root_path + '/interfaces.d') # # recreate interfaces config with open(net_ifcfg_config, 'w') as fi: fi.writelines( ln.replace('_XXXX_', int_nics[0]) + '\n' for ln in get_config_data('default_interfaces_config')) result_msg(msg='Network interfaces file rewritten.', result=False) except Exception as e: _logger.error( ' Failed to write new interfaces configuration file %s: %s', net_ifcfg_config, str(e)) else: _logger.debug('No network interfaces configuration.') return int_nics, int_data
def reconfigure_systemd_networkd(rootdir): """ Parse the systemd network configuration. Parameters ---------- rootdir: str Full path of image root dir as loopback mounted. Returns ------- list: list of nic. dict: the interfaces configuration. """ _logger.debug('__ The network systemd-networkd configuration.') sys_data = dict() sys_nics = list() nw_ignore = ['container-host0', 'container-ve', 'container-vz'] for root_path in get_config_data('default_systemd'): networkd_root = rootdir + root_path if os.path.isdir(networkd_root): _logger.debug('systemd network directory exists.') systemd_files = glob(root_path + '/*.network') if len(systemd_files) > 0: for sf in sorted(systemd_files): ignore = False for ig in nw_ignore: if ig in sf: ignore = True break if not ignore: systemtd_net_config = ConfigParser() sys_data[sf] = dict() try: _ = systemtd_net_config.read(sf) if 'Match' in systemtd_net_config.sections(): ifname = systemtd_net_config.get( 'Match', 'Name') sys_nics.append(ifname) else: _logger.debug('-- No Match section in %s', sf) # for sec in systemtd_net_config.sections(): sys_data[sf][sec] = systemtd_net_config.items( sec) _logger.debug('%s', sys_data[sf][sec]) except Exception as e: _logger.error(' Failed to parse %s: %s', sf, str(e)) # # rename - backup bcknm = system_tools.exec_rename(sf) if bool(bcknm): _logger.debug( 'Network config file %s renamed to %s', sf, bcknm) else: _logger.error(' Failed to rename %s', sf) raise OciMigrateException('Failed to rename %s ' % sf) else: _logger.debug('No systemd-networkd configuration.') else: _logger.debug('%s does not exist.', get_config_data('default_systemd')) # # write new config if len(sys_nics) > 0: nicname = sorted(sys_nics)[0] with open(rootdir + get_config_data('default_systemd_file'), 'w') as sdf: sdf.writelines( ln.replace('_XXXX_', nicname) + '\n' for ln in get_config_data('default_systemd_config')) result_msg(msg='systemd-networkd configuration rewritten.', result=True) else: _logger.debug('No systemd-networkd configuration.') return sorted(sys_nics), sys_data
def reconfigure_ifcfg_config(rootdir): """ Modify the network configuration in the image file to prevent conflicts during import. This is only for ol-type linux. Parameters ---------- rootdir: str Full path of image root dir as loopback mounted. Returns ------- list: list of nic. dict: the interfaces configuration. """ # # Rename the config files _logger.debug('__ The network ifcfg configuration.') ifcfg_list = list() ifcfg_data = dict() ifrootdir = rootdir + get_config_data('default_ifcfg') if os.path.isdir(ifrootdir): for cfgfile in glob(ifrootdir + '/ifcfg-*'): _logger.debug('Checking configfile: %s', cfgfile) try: with open(cfgfile, 'r') as f: # nl = filter(None, [x[:x.find('#')] for x in f]) nl = [_f for _f in [x[:x.find('#')] for x in f] if _f] ifcfg = dict(dl.replace('"', '').split('=') for dl in nl) if 'DEVICE' in ifcfg: devname = ifcfg['DEVICE'] else: _logger.debug('Missing device name in %s', cfgfile) devname = cfgfile.split('/')[-1] ifcfg_list.append(devname) ifcfg_data[devname] = ifcfg _logger.debug('Network interface: %s', devname) except Exception as e: _logger.error( ' Problem reading network configuration file %s: %s', cfgfile, str(e)) else: _logger.debug('No ifcfg network configuration.') # # backup for fn in glob(ifrootdir + '/ifcfg-*'): if 'ifcfg-lo' not in fn: fn_bck = system_tools.exec_rename(fn) if bool(fn_bck): _logger.debug( 'Network config file %s successfully renamed to %s', fn, fn_bck) else: _logger.debug( 'Failed to backup network configuration file %s to %s.', fn, fn_bck) # error_msg('Failed to backup network configuration ' # 'file %s to %s.' % (fn, fn_bck)) # raise OciMigrateException('Failed to rename network config ' # 'file %s to %s' % (fn, fn_bck)) else: _logger.debug('ifcfg-lo found.') # # Generate new default network configuration. if len(ifcfg_list) > 0: nic0 = sorted(ifcfg_list)[0] dhcpniccfg = ifrootdir + '/ifcfg-%s' % nic0 _logger.debug('Replacing network config file %s', dhcpniccfg) try: with open(dhcpniccfg, 'w') as f: f.writelines( ln.replace('_XXXX_', nic0) + '\n' for ln in get_config_data('default_ifcfg_config')) result_msg(msg='Replaced ifcfg network configuration.', result=False) except Exception as e: _logger.error(' Failed to write %s/ifcfg-eth0', ifrootdir) error_msg('Failed to write %s: %s' % (dhcpniccfg, str(e))) raise OciMigrateException('Failed to write %s:' % dhcpniccfg) from e else: _logger.debug('No ifcfg definitions found.') return ifcfg_list, ifcfg_data
def a30_set_oci_region(): """ Add a job to cloud-init config file to complete the ociregion data at first boot. Returns ------- bool: True on success, False otherwise. """ def add_oci_region(regionscript): """ Update the default user name in the cloud.cfg file. Parameters: ---------- regionscript: str full path of the bash script. Returns: ------- bool: True on success, False otherwise. """ _logger.debug('__ Add oci region.') try: cloudconfig = get_config_data('cloudconfig_file') _logger.debug( 'Updating cloud.cfg file %s, adding oci region detection.', cloudconfig) except Exception as e: _logger.error('Failed to find cloud config file location: %s.', str(e)) return False if os.path.isfile(cloudconfig): with open(cloudconfig, 'r') as f: cloudcfg = yaml.load(f, Loader=yaml.SafeLoader) region_definition = False if isinstance(cloudcfg, dict): if 'runcmd' in list(cloudcfg.keys()): # # runcmd present in cloud config file run_cmd = cloudcfg['runcmd'] for yaml_key in run_cmd: if isinstance(yaml_key, list): for yamlval in yaml_key: if regionscript in yamlval: _logger.debug( '%s already in cloud_init', regionscript) region_definition = True break else: if regionscript in yaml_key: _logger.debug('%s already in cloud_init', regionscript) region_definition = True break if not region_definition: # # the regionscript not yet defined in runcmd run_cmd.append(regionscript) else: # # runcmd not yet present in cloud config file cloudcfg['runcmd'] = [regionscript] with open(cloudconfig, 'w') as f: yaml.dump(cloudcfg, f, width=50) _logger.debug( 'Cloud configuration file %s successfully updated.', cloudconfig) return True _logger.error('Invalid cloud config file.') return False _logger.error('Cloud config file %s does not exist.', cloudconfig) return False _logger.debug('__ Set OCI region.') # # get the script name try: oci_region_script = get_config_data('ol_os_oci_region_script') _logger.debug('Got oci-region script name: %s', oci_region_script) except Exception as e: _logger.warning('Failed to collect the oci_region_script path: %s', str(e)) return False # # write the oci region script code with open(oci_region_script, 'w') as fi: fi.writelines(ln + '\n' for ln in get_config_data('ol_os_oci_region_bash')) os.chmod(oci_region_script, stat.S_IRWXU) # # update cloud-init with runcmd command if add_oci_region(oci_region_script): _logger.debug('oci region successfully added.') result_msg(msg='Updated OCI region.', result=False) return True _logger.debug('Failed to update oci region.') return False
def a20_install_extra_pkgs(self): """ Install required and useful packages for OL-type installs, read the list of packages from oci-migrate-conf.yaml, ol_os_packages_to_install. Returns ------- bool: True on success, False otherwise. """ def get_ol_package_list(): """ Retrieve the list of packages to install from oci-migrate-config file. Returns ------- list: list of package names to install. """ _logger.debug('Collection list of packages.') try: pkg_list = get_config_data('ol_os_packages_to_install') if not bool(pkg_list): _logger.debug('Package list is empty.') return False _logger.debug('Package list: %s', pkg_list) return pkg_list except Exception as e: _logger.warning('Failed to find a list of packages: %s', str(e)) return False _logger.debug('__ Installing extra packages.') # # collect packages to install packages = get_ol_package_list() if not bool(packages): _logger.debug('No extra packages to install.') return True # # try: # # set current nameserver config. if system_tools.set_nameserver(): _logger.debug('Updating nameserver info succeeded.') else: _logger.error(' Failed to update nameserver info.') # # get package manipulation tool. pkg_mgr = self._exec_yum \ if self.package_tool['pkg_mgr'] == 'yum' else self._exec_dnf # # install packages for pkg in packages: # # verify if the package is available, the correct channel enabled. rpmlist = pkg_mgr(self.package_tool['package_available'] + [pkg]) pkg_present = False for lline in rpmlist.splitlines(): _logger.debug('%s', lline) if pkg in lline: _logger.debug('The rpm %s is available.', pkg) pkg_present = True break if not pkg_present: _logger.error(' The rpm %s is missing.', pkg) migrate_data.migrate_preparation = False migrate_data.migrate_non_upload_reason += \ '\n The rpm package %s is missing from ' \ 'the yum repository.' % pkg return False installoutput = pkg_mgr(self.package_tool['package_install'] + [pkg]) _logger.debug('Successfully installed pkg %s:\n%s', pkg, installoutput) result_msg(msg='Installed %s.' % pkg, result=False) pause_msg(msg='Installed %s here, or not.' % pkg, pause_flag='_OCI_CHROOT') # # restore nameserver data if system_tools.restore_nameserver(): _logger.debug('Restoring nameserver info succeeded.') else: _logger.error(' Failed to restore nameserver info.') except Exception as e: errmsg = 'Failed to install one or more packages of ' \ '%s:\n%s' % (packages, str(e)) _logger.critical(' %s', errmsg) error_msg('%s' % errmsg) migrate_data.migrate_preparation = False migrate_data.migrate_non_upload_reason += '\n %s' % errmsg return False return True
def main(): """ Main Returns ------- int 0 on success, 1 otherwise. """ # # set locale lc_all_to_set = get_config_data('lc_all') os.environ['LC_ALL'] = "%s" % lc_all_to_set _logger.debug('Locale set to %s', lc_all_to_set) # # python version python_version = sys.version_info[0] _logger.debug('Python version is %s', python_version) # # parse the commandline args = parse_args() # # Operator needs to be root. if system_tools.is_root(): _logger.debug('User is root.') else: exit_with_msg(' *** ERROR *** You must run this program with root ' 'privileges') # # Verbose mode is False by default migrate_data.verbose_flag = args.verbose_flag _logger.debug('Verbose level set to %s', migrate_data.verbose_flag) # # Yes flag migrate_data.yes_flag = args.yes_flag _logger.debug('Answer to yes/no questions supposed to be yes always.') # # collect and save configuration data migrate_data.oci_image_migrate_config = get_config_data('*') # try: # # input image if args.input_image: image_path = args.input_image.name result_filename = get_config_data('result_filepath') \ + '_' \ + os.path.splitext(os.path.basename(image_path))[0] \ + '.res' migrate_data.result_filename = result_filename result_msg(msg='\n Running %s at %s\n' % ((os.path.basename(sys.argv[0]) + ' ' + ' '.join(sys.argv[1:])), time.ctime()), flags='w', result=True) else: raise OciMigrateException('Missing argument: input image path.') # # Import the 'format' modules and collect the format data supported_formats = migrate_tools.import_formats() if not bool(supported_formats): exit_with_msg(' *** ERROR *** No image format modules found') if migrate_data.verbose_flag: show_supported_formats_data(supported_formats) # # Check the utilities installed. util_list, missing_list = test_helpers() _logger.debug('%s', util_list) if migrate_data.verbose_flag: show_utilities(util_list, missing_list) if missing_list: raise OciMigrateException('%s needs packages %s installed.\n' % (sys.argv[0], missing_list)) # # if qemu-img is used, the minimal version is 2 qemu_version_info = qemu_img_version() if qemu_version_info[1] < 2: raise OciMigrateException('Minimal version of qemu-img is 2, ' '%s found.' % qemu_version_info[0]) _logger.debug('release data ok') # # Get the nameserver definition if system_tools.get_nameserver(): result_msg(msg='nameserver %s identified.' % migrate_data.nameserver, result=False) _logger.debug('Nameserver identified as %s', migrate_data.nameserver) else: error_msg( 'Failed to identify nameserver, using %s, but might cause issues.' % migrate_data.nameserver) except Exception as e: _logger.error('*** ERROR *** %s\n', str(e)) exit_with_msg(' *** ERROR *** %s\n' % str(e)) # # More on command line arguments. # # initialise output result_msg(msg='Results are written to %s.' % migrate_data.result_filename, result=True) result_msg(msg='Input image: %s' % image_path, result=True) # # Verify if readable. fn_magic = migrate_tools.get_magic_data(image_path) if fn_magic is None: exit_with_msg('*** ERROR *** An error occurred while trying to read ' 'magic number of File %s.' % image_path) else: pause_msg('Image Magic Number: %s' % fn_magic) _logger.debug('Magic number %s successfully read', fn_magic) # # Verify if image type is supported. _logger.debug('Magic number of %s is %s', image_path, fn_magic) if fn_magic not in supported_formats: exit_with_msg('*** ERROR *** Image type %s is not recognised.' % fn_magic) else: _logger.debug('Image type recognised.') # # Get the correct class. image_clazz = supported_formats[fn_magic] result_msg(msg='Type of image %s identified as %s' % (image_path, image_clazz['name']), result=True) pause_msg('Image type is %s' % image_clazz['name']) # # Locate the class and module image_class_def = getattr( sys.modules['oci_utils.migrate.image_types.%s' % supported_formats[fn_magic]['name']], image_clazz['clazz']) image_object = image_class_def(image_path) # # Local volume groups. vgs_result = system_tools.exec_vgs_noheadings() migrate_data.local_volume_groups = vgs_result if bool(vgs_result) else [] _logger.debug('Workstation volume groups: %s', migrate_data.local_volume_groups) # # Rename local volume groups if bool(migrate_data.local_volume_groups): rename_msg = '\n The workstation has logical volumes defined. To avoid ' \ 'duplicates, the \n logical volume groups will be temporary' \ ' renamed to a hexadecimal uuid.\n If you are sure the ' \ 'image to be uploaded does not contain logical volumes,\n' \ ' or there are no conflicting volume group names, '\ 'the rename can be skipped\n\n Keep the volume group names?' if not read_yn( rename_msg, waitenter=True, suppose_yes=migrate_data.yes_flag): if migrate_tools.verify_local_fstab(): fstab_msg = '\n The fstab file on this workstation seems to ' \ 'contain device references\n using /dev/mapper ' \ 'devices. The volume group names on this ' \ 'workstation\n will be renamed temporarily. ' \ '/dev/mapper devices referring to logical volumes\n' \ ' can create problems in this context. To avoid ' \ 'this situation\n exit now and modify the ' \ 'device specification to LABEL or UUID.\n\n Continue?' if not read_yn(fstab_msg, waitenter=True, suppose_yes=migrate_data.yes_flag): exit_with_msg('Exiting.') _logger.debug('Rename local volume groups to avoid conflicts.') vgrename_res = system_tools.exec_rename_volume_groups( migrate_data.local_volume_groups, 'FORWARD') if not vgrename_res: _logger.warning('Failed to rename local volume groups.') if not read_yn( '\n Failed to rename the local volume groups. ' 'Continue on your own responsibility?', waitenter=True, suppose_yes=migrate_data.yes_flag): exit_with_msg('Exiting.') migrate_data.local_volume_group_rename = True else: _logger.debug('fstab file has no /dev/mapper devices.') else: _logger.debug('Not renaming the volume groups.') _ = system_tools.reset_vg_list(migrate_data.local_volume_groups) else: _logger.debug('No local volume groups, no conflicts.') # # Generic data collection try: imgres, imagedata = collect_image_data(image_object) if migrate_data.verbose_flag: migrate_tools.show_image_data(image_object) if imgres: _logger.debug('Image processing succeeded.') else: _logger.critical(' Image processing failed.', exc_info=False) # if imagedata: _logger.debug('%s passed.', image_path) else: _logger.critical(' %s failed.', image_path, exc_info=False) except Exception as e: _logger.critical(' %s failed: %s', image_path, str(e)) exit_with_msg('*** ERROR *** Problem detected during investigation of ' 'the image %s: %s, exiting.' % (image_path, str(e))) # # Restore volume group names. if migrate_data.local_volume_group_rename: _logger.debug('Restore local volume groups.') vgrename_res = system_tools.exec_rename_volume_groups( migrate_data.local_volume_groups, 'BACKWARD') if not vgrename_res: _logger.warning('Failed to restore local volume group names.') else: _logger.debug('No local volume group names to restore.') # # passed prerequisites and changes? prereq_passed = True # # Image type specific prerequisites prereq_msg = '' sup, msg = image_object.type_specific_prereq_test() if sup: result_msg(msg='%s' % msg, result=True) else: prereq_passed = False prereq_msg = msg # # Generic prerequisites verification try: gen_prereq, msg = image_object.generic_prereq_check() if gen_prereq: prereq_msg += '\n %s passed the generic preqrequisites.' % image_path else: prereq_passed = False prereq_msg += msg # if imgres: prereq_msg += '\n\n %s data collection and processing succeeded.' \ % image_path else: prereq_passed = False # if prereq_passed: result_msg(msg=prereq_msg, result=True) if imagedata['boot_type'] == 'BIOS': result_msg( msg= '\n Boot type is BIOS, use launch_mode PARAVIRTUALIZED (or EMULATED) at import.', result=True) elif imagedata['boot_type'] == 'UEFI': result_msg( msg= '\n Boot type is UEFI, use launch_mode NATIVE (or EMULATED) at import.', result=True) else: raise OciMigrateException('Something wrong checking ' 'the boot type') else: prereq_msg += '\n\n %s processing failed, check the logfile ' \ 'and/or set environment variable _OCI_UTILS_DEBUG.' \ % image_path raise OciMigrateException(prereq_msg) except Exception as e: exit_with_msg('*** ERROR *** %s' % str(e)) # # While prerequisite check did not hit a fatal issue, there might be # situations where upload should not proceed. if not migrate_data.migrate_preparation: exit_with_msg('*** ERROR *** Unable to proceed with uploading image ' 'to Oracle Cloud Infrastructure: %s' % migrate_data.migrate_non_upload_reason) else: result_msg( 'Successfully verified and processed image %s and is ready for upload.' % image_path) return 0