def set_nameserver(): """ Setting temporary nameserver. Returns ------- bool: True on success, False otherwise. """ # global resolv_conf_path _logger.debug('__ Set nameserver.') # # rename eventual existing resolv.conf resolvpath = '/etc/resolv.conf' try: # # save current if os.path.isfile(resolvpath) \ or os.path.islink(resolvpath) \ or os.path.isdir(resolvpath): migrate_data.resolv_conf_path = exec_rename(resolvpath) if not bool(migrate_data.resolv_conf_path): _logger.debug( 'Failed to save current nameserver configuration.') else: _logger.error(' No %s found' % resolvpath) # # write new with open(resolvpath, 'w') as f: f.writelines('nameserver %s\n' % migrate_data.nameserver) return True except Exception as e: migrate_tools.error_msg( 'Failed to set nameserver: %s\n continuing ' 'but might cause issues installing cloud-init.' % str(e)) return False
def restore_nameserver(): """ Restore nameserver configuration. Returns ------- bool: True on success, False otherwise. """ _logger.debug('__ Restore nameserver data.') # global resolv_conf_path resolvpath = '/etc/resolv.conf' try: # # save used one if os.path.isfile(resolvpath): if not bool( exec_rename( resolvpath, resolvpath + '_temp_' + migrate_data.current_time)): _logger.debug('Failed to rename %s to %s, no harm done.' % (resolvpath, resolvpath + '_temp_' + migrate_data.current_time)) else: _logger.debug('No %s found.' % resolvpath) # # restore original one if os.path.isfile(migrate_data.resolv_conf_path): if bool(exec_rename(migrate_data.resolv_conf_path, resolvpath)): _logger.debug('Successfully restored %s' % resolvpath) else: _logger.debug('Failed to restore %s.' % resolvpath) raise OciMigrateException( 'Failed to restore nameserver config.') else: _logger.debug('No %s found.' % migrate_data.resolv_conf_path) return True except Exception as e: migrate_tools.error_msg('Continuing but might cause issues ' 'installing cloud-init: %s' % str(e)) return False
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)) # migrate_tools.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')) migrate_tools.result_msg( msg='Replaced ifcfg network configuration.', result=False) except Exception as e: _logger.error(' Failed to write %s/ifcfg-eth0' % ifrootdir) migrate_tools.error_msg('Failed to write %s: %s' % (dhcpniccfg, str(e))) raise OciMigrateException('Failed to write %s: %s' % (dhcpniccfg, str(e))) else: _logger.debug('No ifcfg definitions found.') return ifcfg_list, ifcfg_data
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: migrate_tools.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)) migrate_tools.result_msg( msg='Networkmanager configuration updated.', result=False) else: _logger.debug(msg=' No NetworkManager configuration present.') return netwmg_nics, netwmg_data
def reconfigure_netplan(rootdir): """ Parse the yaml netplan files and look for network interface names. Parameters ---------- rootdir: str Full path of image root dir as loopback mounted. Returns ------- list: list of nic. dict: the netplan network configurations. """ _logger.debug('__ The netplan configuration.') netplan_data = dict() netplan_nics = list() root_path = rootdir + get_config_data('default_netplan') if os.path.isdir(root_path): _logger.debug('netplan directory exists.') # # contains yaml files? yaml_files = glob(root_path + '/*.yaml') if len(yaml_files) > 0: for yf in sorted(yaml_files): try: with open(yf, 'r') as yfd: yaml_data = yaml.safe_load(yfd) netplan_data[yf] = yaml_data _logger.debug('netplan: %s' % yaml_data) except Exception as e: _logger.error(' Failed to parse %s: %s' % (yf, str(e))) migrate_tools.error_msg('Failed to parse %s: %s' % (yf, str(e))) break # if 'network' in yaml_data: if 'ethernets' in yaml_data['network']: for k, _ in sorted( yaml_data['network']['ethernets'].items()): netplan_nics.append(k) else: _logger.debug('ethernets key missing.') else: _logger.debug('network key missing.') if len(netplan_nics) == 0: _logger.debug('No netplan definitions found in %s' % root_path) else: nicname = sorted(netplan_nics)[0] # # rename and recreate try: # # backup if not bool(system_tools.exec_rename(root_path)): _logger.warning('Failed to backup %s.' % root_path) # # recreate dir os.mkdir(root_path) mode755 = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH | \ stat.S_IWUSR | stat.S_IRUSR | stat.S_IRGRP | \ stat.S_IROTH os.chmod(root_path, mode755) _logger.debug((' Recreated %s' % root_path)) # # recreate netplan config # # __GT__ commenting out this one to avoid conflicts, # cloud-init recreates it from scratch. # # netplan_config = get_config_data('default_netplan_config') # netplan_config['network']['ethernets'][nicname] \ # = netplan_config['network']['ethernets'].pop('_XXXX_') # with open(root_path + '/' # + get_config_data('default_netplan_file'), 'w') \ # as yf: # yaml.safe_dump(netplan_config, yf, default_flow_style=False) # migrate_tools.result_msg(msg='Netplan network configuration ' # 'files replaced.', result=True) except Exception as e: migrate_tools.error_msg( 'Failed to write new netplan ' 'configuration file %s: %s' % (get_config_data('default_netplan_file'), str(e))) raise OciMigrateException( 'Failed to write new netplan ' 'configuration file %s: %s' % (get_config_data('default_netplan_file'), str(e))) else: _logger.debug(' No netplan yaml config files found.') else: _logger.debug('No netplan configuration found.') return netplan_nics, netplan_data
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 pythonver = sys.version_info[0] _logger.debug('Python version is %s' % pythonver) # # 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: imagepath = args.input_image.name resultfilename = get_config_data('resultfilepath') + \ '_' + \ os.path.splitext(os.path.basename(imagepath))[0] \ + '.res' migrate_data.resultfilename = resultfilename migrate_tools.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 qemuversioninfo = qemu_img_version() if qemuversioninfo[1] < 2: raise OciMigrateException('Minimal version of qemu-img is 2, ' '%s found.' % qemuversioninfo[0]) else: _logger.debug('release data ok') # # Get the nameserver definition if system_tools.get_nameserver(): migrate_tools.result_msg(msg='nameserver %s identified.' % migrate_data.nameserver, result=False) _logger.debug('Nameserver identified as %s' % migrate_data.nameserver) else: migrate_tools.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 migrate_tools.result_msg(msg='Results are written to %s.' % migrate_data.resultfilename, result=True) migrate_tools.result_msg(msg='Input image: %s' % imagepath, result=True) # # Verify if readable. fn_magic = migrate_tools.get_magic_data(imagepath) if fn_magic is None: exit_with_msg('*** ERROR *** An error occured while trying to read ' 'magic number of File %s.' % imagepath) 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' % (imagepath, 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. imageclazz = supported_formats[fn_magic] migrate_tools.result_msg(msg='Type of image %s identified as %s' % (imagepath, imageclazz['name']), result=True) pause_msg('Image type is %s' % imageclazz['name']) # # Locate the class and module imageclassdef = getattr(sys.modules['oci_utils.migrate.image_types.%s' % supported_formats[fn_magic]['name']], imageclazz['clazz']) image_object = imageclassdef(imagepath) # # 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') 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.' % imagepath) else: _logger.critical(' %s failed.' % imagepath, exc_info=False) except Exception as e: _logger.critical(' %s failed: %s' % (imagepath, str(e))) exit_with_msg('*** ERROR *** Problem detected during investigation of ' 'the image %s: %s, exiting.' % (imagepath, 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') 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: migrate_tools.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.' % imagepath else: prereq_passed = False prereq_msg += msg # if imgres: prereq_msg += '\n\n %s data collection and processing succeeded.' \ % imagepath else: prereq_passed = False # if prereq_passed: migrate_tools.result_msg(msg=prereq_msg, result=True) if imagedata['boot_type'] == 'BIOS': migrate_tools.result_msg(msg='\n Boot type is BIOS, ' 'use launch_mode PARAVIRTUALIZED ' '(or EMULATED) at import.', result=True) elif imagedata['boot_type'] == 'UEFI': migrate_tools.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.' \ % imagepath 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: migrate_tools.result_msg('Successfully verified and processed image %s ' 'and is ready for upload.' % imagepath) return 0
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') _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 else: installoutput = \ pkg_mgr(self.package_tool['package_install'] + [pkg]) _logger.debug('Successfully installed pkg %s:\n%s' % (pkg, installoutput)) migrate_tools.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) migrate_tools.error_msg('%s' % errmsg) migrate_data.migrate_preparation = False migrate_data.migrate_non_upload_reason += '\n %s' % errmsg return False return True
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_ubuntu_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('ubuntu_os_packages_to_install') _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.') packages = get_ubuntu_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.') for pkg in packages: # # verify if the package is available. pkg_present = False deblist = self.exec_apt(['list', pkg]) for lline in deblist.splitlines(): _logger.debug('%s' % lline) if pkg in lline: _logger.debug('The deb package %s is available.' % pkg) pkg_present = True break if not pkg_present: _logger.debug('The deb package %s is missing.' % pkg) migrate_data.migrate_preparation = False migrate_data.migrate_non_upload_reason +=\ '\n The deb package %s is missing from ' \ 'the repository.' % pkg return False else: installoutput = self.exec_apt(['install', '-y', pkg]) _logger.debug('Successfully installed %s:\n%s' % (pkg, installoutput)) pause_msg(msg='Installed %s here, or not.' % pkg, pause_flag='_OCI_CHROOT') if system_tools.restore_nameserver(): _logger.debug('Restoring nameserver info succeeded.') else: _logger.error(' Failed to restore nameserver info.') except Exception as e: _logger.critical(' Failed to install one or more packages ' 'of %s:\n%s' % (packages, str(e))) migrate_tools.error_msg('Failed to install one or more packages ' 'of %s:\n%s' % (packages, str(e))) migrate_data.migrate_non_upload_reason += \ '\n Failed to install on or more packages ' \ 'of %s: %s' % (packages, str(e)) return False return True