def _pprint_key_entries(user, key_fn, key_entries, hash_meth='md5', prefix='ci-info: '): if not key_entries: message = ("%sno authorized ssh keys fingerprints found for user %s.\n" % (prefix, user)) util.multi_log(message) return tbl_fields = ['Keytype', 'Fingerprint (%s)' % (hash_meth), 'Options', 'Comment'] tbl = PrettyTable(tbl_fields) for entry in key_entries: if _is_printable_key(entry): row = [] row.append(entry.keytype or '-') row.append(_gen_fingerprint(entry.base64, hash_meth) or '-') row.append(entry.options or '-') row.append(entry.comment or '-') tbl.add_row(row) authtbl_s = tbl.get_string() authtbl_lines = authtbl_s.splitlines() max_len = len(max(authtbl_lines, key=len)) lines = [ util.center("Authorized keys from %s for user %s" % (key_fn, user), "+", max_len), ] lines.extend(authtbl_lines) for line in lines: util.multi_log(text="%s%s\n" % (prefix, line), stderr=False, console=True)
def _pprint_key_entries(user, key_fn, key_entries, hash_meth='md5', prefix='ci-info: '): if not key_entries: message = ("%sno authorized ssh keys fingerprints found for user %s.\n" % (prefix, user)) util.multi_log(message) return tbl_fields = ['Keytype', 'Fingerprint (%s)' % (hash_meth), 'Options', 'Comment'] tbl = SimpleTable(tbl_fields) for entry in key_entries: if _is_printable_key(entry): row = [] row.append(entry.keytype or '-') row.append(_gen_fingerprint(entry.base64, hash_meth) or '-') row.append(entry.options or '-') row.append(entry.comment or '-') tbl.add_row(row) authtbl_s = tbl.get_string() authtbl_lines = authtbl_s.splitlines() max_len = len(max(authtbl_lines, key=len)) lines = [ util.center("Authorized keys from %s for user %s" % (key_fn, user), "+", max_len), ] lines.extend(authtbl_lines) for line in lines: util.multi_log(text="%s%s\n" % (prefix, line), stderr=False, console=True)
def handle(name, cfg, cloud, log, _args): if util.is_false(cfg.get("ssh", {}).get("emit_keys_to_console", True)): log.debug( "Skipping module named %s, logging of SSH host keys disabled", name) return helper_path = _get_helper_tool_path(cloud.distro) if not os.path.exists(helper_path): log.warning( "Unable to activate module %s, helper tool not found at %s", name, helper_path, ) return fp_blacklist = util.get_cfg_option_list(cfg, "ssh_fp_console_blacklist", []) key_blacklist = util.get_cfg_option_list(cfg, "ssh_key_console_blacklist", ["ssh-dss"]) try: cmd = [helper_path, ",".join(fp_blacklist), ",".join(key_blacklist)] (stdout, _stderr) = subp.subp(cmd) util.multi_log("%s\n" % (stdout.strip()), stderr=False, console=True) except Exception: log.warning("Writing keys to the system console failed!") raise
def _handle_exit(signum, frame): (msg, rc) = EXIT_FOR[signum] msg = msg % ({"version": vr.version_string()}) contents = StringIO() contents.write("%s\n" % (msg)) _pprint_frame(frame, 1, BACK_FRAME_TRACE_DEPTH, contents) util.multi_log(contents.getvalue(), console=True, stderr=False, log=LOG) sys.exit(rc)
def _handle_exit(signum, frame): (msg, rc) = EXIT_FOR[signum] msg = msg % ({'version': vr.version()}) contents = StringIO() contents.write("%s\n" % (msg)) _pprint_frame(frame, 1, BACK_FRAME_TRACE_DEPTH, contents) util.multi_log(contents.getvalue(), console=True, stderr=False, log=LOG) sys.exit(rc)
def handle(name, cfg, cloud, log, args): """Handler method activated by cloud-init.""" verbose = util.get_cfg_by_path(cfg, ('debug', 'verbose'), default=True) if args: # if args are provided (from cmdline) then explicitly set verbose out_file = args[0] verbose = True else: out_file = util.get_cfg_by_path(cfg, ('debug', 'output')) if not verbose: log.debug(("Skipping module named %s," " verbose printing disabled"), name) return # Clean out some keys that we just don't care about showing... dump_cfg = copy.deepcopy(cfg) for k in SKIP_KEYS: dump_cfg.pop(k, None) all_keys = list(dump_cfg.keys()) for k in all_keys: if k.startswith("_"): dump_cfg.pop(k, None) # Now dump it... to_print = StringIO() to_print.write(_make_header("Config")) to_print.write(_dumps(dump_cfg)) to_print.write("\n") to_print.write(_make_header("MetaData")) to_print.write(_dumps(cloud.datasource.metadata)) to_print.write("\n") to_print.write(_make_header("Misc")) to_print.write("Datasource: %s\n" % (type_utils.obj_name(cloud.datasource))) to_print.write("Distro: %s\n" % (type_utils.obj_name(cloud.distro))) to_print.write("Hostname: %s\n" % (cloud.get_hostname(True))) to_print.write("Instance ID: %s\n" % (cloud.get_instance_id())) to_print.write("Locale: %s\n" % (cloud.get_locale())) to_print.write("Launch IDX: %s\n" % (cloud.launch_index)) contents = to_print.getvalue() content_to_file = [] for line in contents.splitlines(): line = "ci-info: %s\n" % (line) content_to_file.append(line) if out_file: util.write_file(out_file, "".join(content_to_file), 0644, "w") else: util.multi_log("".join(content_to_file), console=True, stderr=False)
def handle(name, cfg, cloud, log, args): """Handler method activated by cloud-init.""" verbose = util.get_cfg_by_path(cfg, ('debug', 'verbose'), default=True) if args: # if args are provided (from cmdline) then explicitly set verbose out_file = args[0] verbose = True else: out_file = util.get_cfg_by_path(cfg, ('debug', 'output')) if not verbose: log.debug(("Skipping module named %s," " verbose printing disabled"), name) return # Clean out some keys that we just don't care about showing... dump_cfg = copy.deepcopy(cfg) for k in SKIP_KEYS: dump_cfg.pop(k, None) all_keys = list(dump_cfg) for k in all_keys: if k.startswith("_"): dump_cfg.pop(k, None) # Now dump it... to_print = StringIO() to_print.write(_make_header("Config")) to_print.write(_dumps(dump_cfg)) to_print.write("\n") to_print.write(_make_header("MetaData")) to_print.write(_dumps(cloud.datasource.metadata)) to_print.write("\n") to_print.write(_make_header("Misc")) to_print.write("Datasource: %s\n" % (type_utils.obj_name(cloud.datasource))) to_print.write("Distro: %s\n" % (type_utils.obj_name(cloud.distro))) to_print.write("Hostname: %s\n" % (cloud.get_hostname(True))) to_print.write("Instance ID: %s\n" % (cloud.get_instance_id())) to_print.write("Locale: %s\n" % (cloud.get_locale())) to_print.write("Launch IDX: %s\n" % (cloud.launch_index)) contents = to_print.getvalue() content_to_file = [] for line in contents.splitlines(): line = "ci-info: %s\n" % (line) content_to_file.append(line) if out_file: util.write_file(out_file, "".join(content_to_file), 0o644, "w") else: util.multi_log("".join(content_to_file), console=True, stderr=False)
def handle(name, cfg, cloud, log, _args): helper_path = _get_helper_tool_path(cloud.distro) if not os.path.exists(helper_path): log.warning(("Unable to activate module %s," " helper tool not found at %s"), name, helper_path) return fp_blacklist = util.get_cfg_option_list(cfg, "ssh_fp_console_blacklist", []) key_blacklist = util.get_cfg_option_list(cfg, "ssh_key_console_blacklist", ["ssh-dss"]) try: cmd = [helper_path, ','.join(fp_blacklist), ','.join(key_blacklist)] (stdout, _stderr) = subp.subp(cmd) util.multi_log("%s\n" % (stdout.strip()), stderr=False, console=True) except Exception: log.warning("Writing keys to the system console failed!") raise
def _pprint_key_entries(user, key_fn, key_entries, hash_meth="sha256", prefix="ci-info: "): if not key_entries: message = ( "%sno authorized SSH keys fingerprints found for user %s.\n" % (prefix, user)) util.multi_log(message, console=True, stderr=False) return tbl_fields = [ "Keytype", "Fingerprint (%s)" % (hash_meth), "Options", "Comment", ] tbl = SimpleTable(tbl_fields) for entry in key_entries: if _is_printable_key(entry): row = [ entry.keytype or "-", _gen_fingerprint(entry.base64, hash_meth) or "-", entry.options or "-", entry.comment or "-", ] tbl.add_row(row) authtbl_s = tbl.get_string() authtbl_lines = authtbl_s.splitlines() max_len = len(max(authtbl_lines, key=len)) lines = [ util.center( "Authorized keys from %s for user %s" % (key_fn, user), "+", max_len, ), ] lines.extend(authtbl_lines) for line in lines: util.multi_log(text="%s%s\n" % (prefix, line), stderr=False, console=True)
def handle(name, cfg, _cloud, log, _args): if not os.path.exists(HELPER_TOOL): log.warn(("Unable to activate module %s," " helper tool not found at %s"), name, HELPER_TOOL) return fp_blacklist = util.get_cfg_option_list(cfg, "ssh_fp_console_blacklist", []) key_blacklist = util.get_cfg_option_list(cfg, "ssh_key_console_blacklist", ["ssh-dss"]) try: cmd = [HELPER_TOOL] cmd.append(','.join(fp_blacklist)) cmd.append(','.join(key_blacklist)) (stdout, _stderr) = util.subp(cmd) util.multi_log("%s\n" % (stdout.strip()), stderr=False, console=True) except: log.warn("Writing keys to the system console failed!") raise
def handle(_name, cfg, cloud, log, args): msg_in = "" if len(args) != 0: msg_in = str(args[0]) else: msg_in = util.get_cfg_option_str(cfg, "final_message", "") msg_in = msg_in.strip() if not msg_in: msg_in = FINAL_MESSAGE_DEF uptime = util.uptime() ts = util.time_rfc2822() cver = version.version_string() try: subs = { "uptime": uptime, "timestamp": ts, "version": cver, "datasource": str(cloud.datasource), } subs.update(dict([(k.upper(), v) for k, v in subs.items()])) util.multi_log( "%s\n" % (templater.render_string(msg_in, subs)), console=False, stderr=True, log=log, ) except Exception: util.logexc(log, "Failed to render final message template") boot_fin_fn = cloud.paths.boot_finished try: contents = "%s - %s - v. %s\n" % (uptime, ts, cver) util.write_file(boot_fin_fn, contents, ensure_dir_exists=False) except Exception: util.logexc(log, "Failed to write boot finished file %s", boot_fin_fn) if cloud.datasource.is_disconnected: log.warning("Used fallback datasource")
def handle(name, cfg, cloud, log, _args): helper_path = _get_helper_tool_path(cloud.distro) if not os.path.exists(helper_path): log.warn(("Unable to activate module %s," " helper tool not found at %s"), name, helper_path) return fp_blacklist = util.get_cfg_option_list(cfg, "ssh_fp_console_blacklist", []) key_blacklist = util.get_cfg_option_list(cfg, "ssh_key_console_blacklist", ["ssh-dss"]) try: cmd = [helper_path, ','.join(fp_blacklist), ','.join(key_blacklist)] (stdout, _stderr) = util.subp(cmd) util.multi_log("%s\n" % (stdout.strip()), stderr=False, console=True) except Exception: log.warn("Writing keys to the system console failed!") raise
def handle(_name, cfg, cloud, log, args): msg_in = '' if len(args) != 0: msg_in = str(args[0]) else: msg_in = util.get_cfg_option_str(cfg, "final_message", "") msg_in = msg_in.strip() if not msg_in: msg_in = FINAL_MESSAGE_DEF uptime = util.uptime() ts = util.time_rfc2822() cver = version.version_string() try: subs = { 'uptime': uptime, 'timestamp': ts, 'version': cver, 'datasource': str(cloud.datasource), } util.multi_log("%s\n" % (templater.render_string(msg_in, subs)), console=False, stderr=True, log=log) except Exception: util.logexc(log, "Failed to render final message template") boot_fin_fn = cloud.paths.boot_finished try: contents = "%s - %s - v. %s\n" % (uptime, ts, cver) util.write_file(boot_fin_fn, contents) except: util.logexc(log, "Failed to write boot finished file %s", boot_fin_fn) if cloud.datasource.is_disconnected: log.warn("Used fallback datasource")
def handle(_name, cfg, cloud, log, args): msg_in = '' if len(args) != 0: msg_in = str(args[0]) else: msg_in = util.get_cfg_option_str(cfg, "final_message", "") msg_in = msg_in.strip() if not msg_in: msg_in = FINAL_MESSAGE_DEF uptime = util.uptime() ts = util.time_rfc2822() cver = version.version_string() try: subs = { 'uptime': uptime, 'timestamp': ts, 'version': cver, 'datasource': str(cloud.datasource), } subs.update(dict([(k.upper(), v) for k, v in subs.items()])) util.multi_log("%s\n" % (templater.render_string(msg_in, subs)), console=False, stderr=True, log=log) except Exception: util.logexc(log, "Failed to render final message template") boot_fin_fn = cloud.paths.boot_finished try: contents = "%s - %s - v. %s\n" % (uptime, ts, cver) util.write_file(boot_fin_fn, contents) except Exception: util.logexc(log, "Failed to write boot finished file %s", boot_fin_fn) if cloud.datasource.is_disconnected: log.warn("Used fallback datasource")
def welcome(action, msg=None): if not msg: msg = welcome_format(action) util.multi_log("%s\n" % (msg), console=False, stderr=True, log=LOG) return msg
def test_logs_go_to_console_by_default(self): self._createConsole(self.root) logged_string = 'something very important' util.multi_log(logged_string) self.assertEqual(logged_string, open('/dev/console').read())
def test_given_log_level_used(self): log = mock.MagicMock() log_level = mock.Mock() util.multi_log('message', log=log, log_level=log_level) self.assertEqual((log_level, mock.ANY), log.log.call_args[0])
def test_newlines_stripped_from_log_call(self): log = mock.MagicMock() expected_string = 'something very important' util.multi_log('{0}\n'.format(expected_string), log=log) self.assertEqual((mock.ANY, expected_string), log.log.call_args[0])
def test_logs_go_to_stdout_if_console_does_not_exist(self): logged_string = 'something very important' util.multi_log(logged_string) self.assertEqual(logged_string, self.stdout.getvalue())
def test_log_level_defaults_to_debug(self): log = mock.MagicMock() util.multi_log('message', log=log) self.assertEqual((logging.DEBUG, mock.ANY), log.log.call_args[0])
def test_logs_go_to_log_if_given(self): log = mock.MagicMock() logged_string = 'something very important' util.multi_log(logged_string, log=log) self.assertEqual([((mock.ANY, logged_string), {})], log.log.call_args_list)
def test_stderr_used_by_default(self): logged_string = 'test stderr output' util.multi_log(logged_string) self.assertEqual(logged_string, self.stderr.getvalue())
def test_stderr_not_used_if_false(self): util.multi_log('should not see this', stderr=False) self.assertEqual('', self.stderr.getvalue())
def test_logs_dont_go_to_stdout_if_console_exists(self): self._createConsole(self.root) util.multi_log('something') self.assertEqual('', self.stdout.getvalue())
def test_logs_dont_go_to_stdout_if_fallback_to_stdout_is_false(self): util.multi_log('something', fallback_to_stdout=False) self.assertEqual('', self.stdout.getvalue())
def handle(_name, cfg, cloud, log, args): if args: # if run from command line, and give args, wipe the chpasswd['list'] password = args[0] if "chpasswd" in cfg and "list" in cfg["chpasswd"]: del cfg["chpasswd"]["list"] else: password = util.get_cfg_option_str(cfg, "password", None) expire = True plist = None if "chpasswd" in cfg: chfg = cfg["chpasswd"] if "list" in chfg and chfg["list"]: if isinstance(chfg["list"], list): log.debug("Handling input for chpasswd as list.") plist = util.get_cfg_option_list(chfg, "list", plist) else: log.debug("Handling input for chpasswd as multiline string.") plist = util.get_cfg_option_str(chfg, "list", plist) if plist: plist = plist.splitlines() expire = util.get_cfg_option_bool(chfg, "expire", expire) if not plist and password: (users, _groups) = ug_util.normalize_users_groups(cfg, cloud.distro) (user, _user_config) = ug_util.extract_default(users) if user: plist = ["%s:%s" % (user, password)] else: log.warning("No default or defined user to change password for.") errors = [] if plist: plist_in = [] hashed_plist_in = [] hashed_users = [] randlist = [] users = [] # N.B. This regex is included in the documentation (i.e. the module # docstring), so any changes to it should be reflected there. prog = re.compile(r"\$(1|2a|2y|5|6)(\$.+){2}") for line in plist: u, p = line.split(":", 1) if prog.match(p) is not None and ":" not in p: hashed_plist_in.append(line) hashed_users.append(u) else: # in this else branch, we potentially change the password # hence, a deviation from .append(line) if p == "R" or p == "RANDOM": p = rand_user_password() randlist.append("%s:%s" % (u, p)) plist_in.append("%s:%s" % (u, p)) users.append(u) ch_in = "\n".join(plist_in) + "\n" if users: try: log.debug("Changing password for %s:", users) chpasswd(cloud.distro, ch_in) except Exception as e: errors.append(e) util.logexc( log, "Failed to set passwords with chpasswd for %s", users ) hashed_ch_in = "\n".join(hashed_plist_in) + "\n" if hashed_users: try: log.debug("Setting hashed password for %s:", hashed_users) chpasswd(cloud.distro, hashed_ch_in, hashed=True) except Exception as e: errors.append(e) util.logexc( log, "Failed to set hashed passwords with chpasswd for %s", hashed_users, ) if len(randlist): blurb = ( "Set the following 'random' passwords\n", "\n".join(randlist), ) util.multi_log( "%s\n%s\n" % blurb, stderr=False, fallback_to_stdout=False ) if expire: expired_users = [] for u in users: try: cloud.distro.expire_passwd(u) expired_users.append(u) except Exception as e: errors.append(e) util.logexc(log, "Failed to set 'expire' for %s", u) if expired_users: log.debug("Expired passwords for: %s users", expired_users) handle_ssh_pwauth(cfg.get("ssh_pwauth"), cloud.distro) if len(errors): log.debug("%s errors occured, re-raising the last one", len(errors)) raise errors[-1]