def unmount_main(args): """ run util.umount(target, recursive=True) """ if args.target is None: msg = "Missing target. Please provide target path parameter" raise ValueError(msg) if not os.path.exists(args.target): msg = "Cannot unmount target path %s: it does not exist" % args.target raise util.FileMissingError(msg) LOG.info("Unmounting devices from target path: %s", args.target) recursive_mode = not args.disable_recursive_mounts util.do_umount(args.target, recursive=recursive_mode)
def get_root_device(dev, paths=None): """ Get root partition for specified device, based on presence of any paths in the provided paths list: """ if paths is None: paths = ["curtin"] LOG.debug('Searching for filesystem on %s containing one of: %s', dev, paths) partitions = get_pardevs_on_blockdevs(dev) target = None tmp_mount = tempfile.mkdtemp() for i in partitions: dev_path = partitions[i]['device_path'] mp = None try: util.do_mount(dev_path, tmp_mount) mp = tmp_mount for path in paths: fullpath = os.path.join(tmp_mount, path) if os.path.isdir(fullpath): target = dev_path LOG.debug("Found path '%s' on device '%s'", path, dev_path) break except Exception: pass finally: if mp: util.do_umount(mp) os.rmdir(tmp_mount) if target is None: raise ValueError( "Did not find any filesystem on %s that contained one of %s" % (dev, paths)) return target
def cmd_install(args): from .collect_logs import create_log_tarfile cfg = deepcopy(CONFIG_BUILTIN) config.merge_config(cfg, args.config) for source in args.source: src = util.sanitize_source(source) cfg['sources']["%02d_cmdline" % len(cfg['sources'])] = src LOG.info(INSTALL_START_MSG) LOG.debug('LANG=%s', os.environ.get('LANG')) LOG.debug("merged config: %s" % cfg) if not len(cfg.get('sources', [])): raise util.BadUsage("no sources provided to install") for i in cfg['sources']: # we default to tgz for old style sources config cfg['sources'][i] = util.sanitize_source(cfg['sources'][i]) migrate_proxy_settings(cfg) for k in ('http_proxy', 'https_proxy', 'no_proxy'): if k in cfg['proxy']: os.environ[k] = cfg['proxy'][k] instcfg = cfg.get('install', {}) logfile = instcfg.get('log_file') error_tarfile = instcfg.get('error_tarfile') post_files = instcfg.get('post_files', [logfile]) # Generate curtin configuration dump and add to write_files unless # installation config disables dump yaml_dump_file = instcfg.get('save_install_config', SAVE_INSTALL_CONFIG) if yaml_dump_file: write_files = cfg.get('write_files', {}) write_files['curtin_install_cfg'] = { 'path': yaml_dump_file, 'permissions': '0400', 'owner': 'root:root', 'content': config.dump_config(cfg) } cfg['write_files'] = write_files # Load reporter clear_install_log(logfile) legacy_reporter = load_reporter(cfg) legacy_reporter.files = post_files writeline_and_stdout(logfile, INSTALL_START_MSG) args.reportstack.post_files = post_files workingd = None try: workingd = WorkingDir(cfg) dd_images = util.get_dd_images(cfg.get('sources', {})) if len(dd_images) > 1: raise ValueError("You may not use more than one disk image") LOG.debug(workingd.env()) env = os.environ.copy() env.update(workingd.env()) for name in cfg.get('stages'): desc = STAGE_DESCRIPTIONS.get(name, "stage %s" % name) reportstack = events.ReportEventStack( "stage-%s" % name, description=desc, parent=args.reportstack) env['CURTIN_REPORTSTACK'] = reportstack.fullname with reportstack: commands_name = '%s_commands' % name with util.LogTimer(LOG.debug, 'stage_%s' % name): stage = Stage(name, cfg.get(commands_name, {}), env, reportstack=reportstack, logfile=logfile) stage.run() if apply_kexec(cfg.get('kexec'), workingd.target): cfg['power_state'] = {'mode': 'reboot', 'delay': 'now', 'message': "'rebooting with kexec'"} writeline_and_stdout(logfile, INSTALL_PASS_MSG) legacy_reporter.report_success() except Exception as e: exp_msg = INSTALL_FAIL_MSG.format(exception=e) writeline(logfile, exp_msg) LOG.error(exp_msg) legacy_reporter.report_failure(exp_msg) if error_tarfile: create_log_tarfile(error_tarfile, cfg) raise e finally: log_target_path = instcfg.get('save_install_log', SAVE_INSTALL_LOG) if log_target_path and workingd: copy_install_log(logfile, workingd.target, log_target_path) if instcfg.get('unmount', "") == "disabled": LOG.info('Skipping unmount: config disabled target unmounting') elif workingd: # unmount everything (including iscsi disks) util.do_umount(workingd.target, recursive=True) # The open-iscsi service in the ephemeral environment handles # disconnecting active sessions. On Artful release the systemd # unit file has conditionals that are not met at boot time and # results in open-iscsi service not being started; This breaks # shutdown on Artful releases. # Additionally, in release < Artful, if the storage configuration # is layered, like RAID over iscsi volumes, then disconnecting # iscsi sessions before stopping the raid device hangs. # As it turns out, letting the open-iscsi service take down the # session last is the cleanest way to handle all releases # regardless of what may be layered on top of the iscsi disks. # # Check if storage configuration has iscsi volumes and if so ensure # iscsi service is active before exiting install if iscsi.get_iscsi_disks_from_config(cfg): iscsi.restart_iscsi_service() shutil.rmtree(workingd.top) apply_power_state(cfg.get('power_state')) sys.exit(0)