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
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
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
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()
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
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
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
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()
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
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))