Example #1
0
def remove_artifacts(remove_logs, remove_seed=False):
    """Helper which removes artifacts dir and optionally log files.

    @param: remove_logs: Boolean. Set True to delete the cloud_dir path. False
        preserves them.
    @param: remove_seed: Boolean. Set True to also delete seed subdir in
        paths.cloud_dir.
    @returns: 0 on success, 1 otherwise.
    """
    init = Init(ds_deps=[])
    init.read_cfg()
    if remove_logs:
        for log_file in get_config_logfiles(init.cfg):
            del_file(log_file)

    if not os.path.isdir(init.paths.cloud_dir):
        return 0  # Artifacts dir already cleaned
    seed_path = os.path.join(init.paths.cloud_dir, 'seed')
    for path in glob.glob('%s/*' % init.paths.cloud_dir):
        if path == seed_path and not remove_seed:
            continue
        try:
            if os.path.isdir(path) and not is_link(path):
                del_dir(path)
            else:
                del_file(path)
        except OSError as e:
            error('Could not remove {0}: {1}'.format(path, str(e)))
            return 1
    return 0
Example #2
0
def remove_artifacts(remove_logs, remove_seed=False):
    """Helper which removes artifacts dir and optionally log files.

    @param: remove_logs: Boolean. Set True to delete the cloud_dir path. False
        preserves them.
    @param: remove_seed: Boolean. Set True to also delete seed subdir in
        paths.cloud_dir.
    @returns: 0 on success, 1 otherwise.
    """
    init = Init(ds_deps=[])
    init.read_cfg()
    if remove_logs:
        for log_file in get_config_logfiles(init.cfg):
            del_file(log_file)

    if not os.path.isdir(init.paths.cloud_dir):
        return 0  # Artifacts dir already cleaned
    seed_path = os.path.join(init.paths.cloud_dir, "seed")
    for path in glob.glob("%s/*" % init.paths.cloud_dir):
        if path == seed_path and not remove_seed:
            continue
        try:
            if os.path.isdir(path) and not is_link(path):
                del_dir(path)
            else:
                del_file(path)
        except OSError as e:
            error("Could not remove {0}: {1}".format(path, str(e)))
            return 1
    return 0
Example #3
0
def get_status_details(paths=None):
    """Return a 3-tuple of status, status_details and time of last event.

    @param paths: An initialized cloudinit.helpers.paths object.

    Values are obtained from parsing paths.run_dir/status.json.
    """
    if not paths:
        init = Init(ds_deps=[])
        init.read_cfg()
        paths = init.paths

    status = UXAppStatus.NOT_RUN
    status_detail = ""
    status_v1 = {}

    status_file = os.path.join(paths.run_dir, "status.json")
    result_file = os.path.join(paths.run_dir, "result.json")

    (is_disabled, reason) = _is_cloudinit_disabled(CLOUDINIT_DISABLED_FILE,
                                                   paths)
    if is_disabled:
        status = UXAppStatus.DISABLED
        status_detail = reason
    if os.path.exists(status_file):
        if not os.path.exists(result_file):
            status = UXAppStatus.RUNNING
        status_v1 = load_json(load_file(status_file)).get("v1", {})
    errors = []
    latest_event = 0
    for key, value in sorted(status_v1.items()):
        if key == "stage":
            if value:
                status = UXAppStatus.RUNNING
                status_detail = "Running in stage: {0}".format(value)
        elif key == "datasource":
            status_detail = value
        elif isinstance(value, dict):
            errors.extend(value.get("errors", []))
            start = value.get("start") or 0
            finished = value.get("finished") or 0
            if finished == 0 and start != 0:
                status = UXAppStatus.RUNNING
            event_time = max(start, finished)
            if event_time > latest_event:
                latest_event = event_time
    if errors:
        status = UXAppStatus.ERROR
        status_detail = "\n".join(errors)
    elif status == UXAppStatus.NOT_RUN and latest_event > 0:
        status = UXAppStatus.DONE
    if latest_event:
        time = strftime("%a, %d %b %Y %H:%M:%S %z", gmtime(latest_event))
    else:
        time = ""
    return status, status_detail, time
Example #4
0
def handle_args(name, args):
    # Note that if an exception happens between now and when logging is
    # setup, we'll only see it in the journal
    hotplug_reporter = events.ReportEventStack(name,
                                               __doc__,
                                               reporting_enabled=True)

    hotplug_init = Init(ds_deps=[], reporter=hotplug_reporter)
    hotplug_init.read_cfg()

    log.setupLogging(hotplug_init.cfg)
    if "reporting" in hotplug_init.cfg:
        reporting.update_configuration(hotplug_init.cfg.get("reporting"))
    # Logging isn't going to be setup until now
    LOG.debug(
        "%s called with the following arguments: {"
        "hotplug_action: %s, subsystem: %s, udevaction: %s, devpath: %s}",
        name,
        args.hotplug_action,
        args.subsystem,
        args.udevaction if "udevaction" in args else None,
        args.devpath if "devpath" in args else None,
    )

    with hotplug_reporter:
        try:
            if args.hotplug_action == "query":
                try:
                    datasource = initialize_datasource(hotplug_init,
                                                       args.subsystem)
                except DataSourceNotFoundException:
                    print("Unable to determine hotplug state. No datasource "
                          "detected")
                    sys.exit(1)
                print("enabled" if datasource else "disabled")
            else:
                handle_hotplug(
                    hotplug_init=hotplug_init,
                    devpath=args.devpath,
                    subsystem=args.subsystem,
                    udevaction=args.udevaction,
                )
        except Exception:
            LOG.exception("Received fatal exception handling hotplug!")
            raise

    LOG.debug("Exiting hotplug handler")
    reporting.flush_events()
Example #5
0
def handle_status_args(name, args):
    """Handle calls to 'cloud-init status' as a subcommand."""
    # Read configured paths
    init = Init(ds_deps=[])
    init.read_cfg()
    status, status_detail, time = get_status_details(init.paths)
    if args.wait:
        while status in (UXAppStatus.NOT_RUN, UXAppStatus.RUNNING):
            sys.stdout.write(".")
            sys.stdout.flush()
            status, status_detail, time = get_status_details(init.paths)
            sleep(0.25)
        sys.stdout.write("\n")
    print("status: {0}".format(status.value))
    if args.long:
        if time:
            print("time: {0}".format(time))
        print("detail:\n{0}".format(status_detail))
    return 1 if status == UXAppStatus.ERROR else 0
Example #6
0
def handle_hotplug(hotplug_init: Init, devpath, subsystem, udevaction):
    handler_cls, event_scope = SUBSYSTEM_PROPERTES_MAP.get(
        subsystem, (None, None))
    if handler_cls is None:
        raise Exception(
            'hotplug-hook: cannot handle events for subsystem: {}'.format(
                subsystem))

    LOG.debug('Fetching datasource')
    datasource = hotplug_init.fetch(existing="trust")

    if not hotplug_init.update_event_enabled(
            event_source_type=EventType.HOTPLUG, scope=EventScope.NETWORK):
        LOG.debug('hotplug not enabled for event of type %s', event_scope)
        return

    LOG.debug('Creating %s event handler', subsystem)
    event_handler = handler_cls(
        datasource=datasource,
        devpath=devpath,
        action=udevaction,
        success_fn=hotplug_init._write_to_cache)  # type: UeventHandler
    wait_times = [1, 3, 5, 10, 30]
    for attempt, wait in enumerate(wait_times):
        LOG.debug('subsystem=%s update attempt %s/%s', subsystem, attempt,
                  len(wait_times))
        try:
            LOG.debug('Refreshing metadata')
            event_handler.update_metadata()
            LOG.debug('Detecting device in updated metadata')
            event_handler.detect_hotplugged_device()
            LOG.debug('Applying config change')
            event_handler.apply()
            LOG.debug('Updating cache')
            event_handler.success()
            break
        except Exception as e:
            LOG.debug('Exception while processing hotplug event. %s', e)
            time.sleep(wait)
            last_exception = e
    else:
        raise last_exception  # type: ignore
Example #7
0
def handle_status_args(name, args):
    """Handle calls to 'cloud-init status' as a subcommand."""
    # Read configured paths
    init = Init(ds_deps=[])
    init.read_cfg()

    status, status_detail, time = _get_status_details(init.paths)
    if args.wait:
        while status in (STATUS_ENABLED_NOT_RUN, STATUS_RUNNING):
            sys.stdout.write('.')
            sys.stdout.flush()
            status, status_detail, time = _get_status_details(init.paths)
            sleep(0.25)
        sys.stdout.write('\n')
    if args.long:
        print('status: {0}'.format(status))
        if time:
            print('time: {0}'.format(time))
        print('detail:\n{0}'.format(status_detail))
    else:
        print('status: {0}'.format(status))
    return 1 if status == STATUS_ERROR else 0
Example #8
0
def handle_status_args(name, args):
    """Handle calls to 'cloud-init status' as a subcommand."""
    # Read configured paths
    init = Init(ds_deps=[])
    init.read_cfg()

    status, status_detail, time = _get_status_details(init.paths)
    if args.wait:
        while status in (STATUS_ENABLED_NOT_RUN, STATUS_RUNNING):
            sys.stdout.write('.')
            sys.stdout.flush()
            status, status_detail, time = _get_status_details(init.paths)
            sleep(0.25)
        sys.stdout.write('\n')
    if args.long:
        print('status: {0}'.format(status))
        if time:
            print('time: {0}'.format(time))
        print('detail:\n{0}'.format(status_detail))
    else:
        print('status: {0}'.format(status))
    return 1 if status == STATUS_ERROR else 0
Example #9
0
def handle_args(name, args):
    # Note that if an exception happens between now and when logging is
    # setup, we'll only see it in the journal
    hotplug_reporter = events.ReportEventStack(name,
                                               __doc__,
                                               reporting_enabled=True)

    hotplug_init = Init(ds_deps=[], reporter=hotplug_reporter)
    hotplug_init.read_cfg()

    log.setupLogging(hotplug_init.cfg)
    if 'reporting' in hotplug_init.cfg:
        reporting.update_configuration(hotplug_init.cfg.get('reporting'))

    # Logging isn't going to be setup until now
    LOG.debug(
        '%s called with the following arguments: {udevaction: %s, '
        'subsystem: %s, devpath: %s}', name, args.udevaction, args.subsystem,
        args.devpath)
    LOG.debug(
        '%s called with the following arguments:\n'
        'udevaction: %s\n'
        'subsystem: %s\n'
        'devpath: %s', name, args.udevaction, args.subsystem, args.devpath)

    with hotplug_reporter:
        try:
            handle_hotplug(
                hotplug_init=hotplug_init,
                devpath=args.devpath,
                subsystem=args.subsystem,
                udevaction=args.udevaction,
            )
        except Exception:
            LOG.exception('Received fatal exception handling hotplug!')
            raise

    LOG.debug('Exiting hotplug handler')
    reporting.flush_events()
Example #10
0
def read_cfg_paths():
    """Return a Paths object based on the system configuration on disk."""
    init = Init(ds_deps=[])
    init.read_cfg()
    return init.paths
Example #11
0
def handle(name, cfg, cloud, log, _args):
    logger.debug("Cloud-init config: {}".format(cfg))
    # fetch all required data from Cloud-init
    # Datasource name
    dsname = cloud.datasource.dsname
    logger.debug("Datasource: {}".format(dsname))
    # Metadata (datasource specific)
    metadata_ds = cloud.datasource.metadata
    logger.debug("Meta-Data ds: {}".format(metadata_ds))
    # Metadata in stable v1 format (the same structure for all datasources)
    instance_data_json = load_json(load_file("{}/{}".format(cloud.datasource.paths.run_dir, INSTANCE_JSON_FILE)))
    metadata_v1 = instance_data_json.get('v1')
    logger.debug("Meta-Data v1: {}".format(metadata_v1))
    # User-Data
    userdata = cloud.datasource.userdata
    logger.debug("User-Data: {}".format(userdata))
    # Vendor-Data
    vendordata = cloud.datasource.vendordata
    logger.debug("Vendor-Data: {}".format(vendordata))
    # Network-config
    init_stage = Init()
    (netcfg, netcfg_src) = init_stage._find_networking_config()
    logger.debug("Network-config: {}".format(netcfg))
    logger.debug("Network-config source: {}".format(netcfg_src))
    # Hostname with FQDN (if exist)
    (hostname, fqdn) = get_hostname_fqdn(cfg, cloud, metadata_only=True)
    logger.debug("Hostname: {}, FQDN: {}".format(hostname, fqdn))
    # Get users list
    (users, _) = ug_util.normalize_users_groups(cfg, cloud.distro)
    logger.debug("Users: {}".format(users))
    (default_user, default_user_config) = ug_util.extract_default(users)
    logger.debug("Default user: {}".format(default_user))
    # Get OVF properties
    if 'OVF' in dsname:
        ovf_environment = ovf_get_properties(cloud.datasource.environment)
        logger.debug("OVF environment: {}".format(ovf_environment))

    # VyOS configuration file selection
    cfg_file_name = '/opt/vyatta/etc/config/config.boot'
    bak_file_name = '/opt/vyatta/etc/config.boot.default'

    # open configuration file
    if not path.exists(cfg_file_name):
        file_name = bak_file_name
    else:
        file_name = cfg_file_name

    logger.debug("Using configuration file: {}".format(file_name))
    with open(file_name, 'r') as f:
        config_file = f.read()
    config = ConfigTree(config_file)

    # Initialization of variables
    DEFAULT_VYOS_USER = '******'
    DEFAULT_VYOS_PASSWORD = '******'
    logins_configured = False
    network_configured = False

    # configure system logins
    # Prepare SSH public keys for default user, to be sure that global keys applied to the default account (if it exist)
    ssh_keys = metadata_v1['public_ssh_keys']
    # append SSH keys from cloud-config
    ssh_keys.extend(cfg.get('ssh_authorized_keys', []))
    # Configure authentication for default user account
    if default_user:
        # key-based
        for ssh_key in ssh_keys:
            if set_ssh_login(config, default_user, ssh_key):
                logins_configured = True
        # password-based
        password = cfg.get('password')
        if password:
            if set_pass_login(config, default_user, password):
                logins_configured = True

    # Configure all users accounts
    for user, user_cfg in users.items():
        # Configure password-based authentication
        password = user_cfg.get('passwd')
        if password and password != '':
            if set_pass_login(config, user, password):
                logins_configured = True

        # Configure key-based authentication
        for ssh_key in user_cfg.get('ssh_authorized_keys', []):
            if set_ssh_login(config, user, ssh_key):
                logins_configured = True

    # Create a fallback user if there was no others
    if not logins_configured:
        logger.debug("Adding fallback user: {}".format(DEFAULT_VYOS_USER))
        set_pass_login(config, DEFAULT_VYOS_USER, DEFAULT_VYOS_PASSWORD)

    # apply settings from OVF template
    if 'OVF' in dsname:
        set_config_ovf(config, ovf_environment)
        # Empty hostname option may be interpreted as 'null' string by some hypervisors
        # we need to replace it to the empty value to process it later properly
        if hostname and hostname == 'null':
            hostname = None
        network_configured = True

    # process networking configuration data
    if netcfg and network_configured is False:
        # check which one version of config we have
        # version 1
        if netcfg['version'] == 1:
            for interface_config in netcfg['config']:
                set_config_interfaces_v1(config, interface_config)
            network_configured = True

        # version 2
        if netcfg['version'] == 2:
            if 'ethernets' in netcfg:
                for interface_name, interface_config in netcfg['ethernets'].items():
                    set_config_interfaces_v2(config, interface_name, interface_config)
                network_configured = True

    # enable DHCPv4 on eth0 if network still not configured
    if network_configured is False:
        set_config_dhcp(config)

    # enable SSH service
    set_config_ssh(config)
    # configure hostname and domain
    if hostname:
        set_config_hostname(config, hostname, fqdn)
    else:
        set_config_hostname(config, 'vyos', None)

    # save a new configuration file
    try:
        with open(cfg_file_name, 'w') as f:
            f.write(config.to_string())
            logger.debug("Configuration file saved: {}".format(cfg_file_name))
    except Exception as e:
        logger.error("Failed to write configs into file {}: {}".format(cfg_file_name, e))
Example #12
0
def read_cfg_paths():
    """Return a Paths object based on the system configuration on disk."""
    init = Init(ds_deps=[])
    init.read_cfg()
    return init.paths