def check_scout(app, what: str, ir: Optional[IR] = None) -> None: uptime = datetime.datetime.now() - boot_time hr_uptime = td_format(uptime) app.notices.reset() app.scout = Scout() app.scout_args = { "uptime": int(uptime.total_seconds()), "hr_uptime": hr_uptime } if ir and not os.environ.get("AMBASSADOR_DISABLE_FEATURES", None): app.scout_args["features"] = ir.features() app.scout_result = app.scout.report(mode="diagd", action=what, **app.scout_args) scout_notices = app.scout_result.pop('notices', []) app.notices.extend(scout_notices) app.logger.info("Scout reports %s" % json.dumps(app.scout_result)) app.logger.info("Scout notices: %s" % json.dumps(scout_notices)) app.logger.info("App notices after scout: %s" % json.dumps(app.notices.notices))
def setup(self, snapshot_path: str, bootstrap_path: str, ads_path: str, config_path: Optional[str], ambex_pid: int, kick: Optional[str], k8s=False, do_checks=True, no_envoy=False, reload=False, debug=False, verbose=False, notices=None, validation_retries=5, allow_fs_commands=False, local_scout=False, report_action_keys=False): self.estats = EnvoyStats() self.health_checks = do_checks self.no_envoy = no_envoy self.debugging = reload self.verbose = verbose self.notice_path = notices self.notices = Notices(self.notice_path) self.notices.reset() self.k8s = k8s self.validation_retries = validation_retries self.allow_fs_commands = allow_fs_commands self.local_scout = local_scout self.report_action_keys = report_action_keys # This will raise an exception and crash if you pass it a string. That's intentional. self.ambex_pid = int(ambex_pid) self.kick = kick # This feels like overkill. self.logger = logging.getLogger("ambassador.diagd") self.logger.setLevel(logging.INFO) if debug: self.logger.setLevel(logging.DEBUG) logging.getLogger('ambassador').setLevel(logging.DEBUG) self.config_path = config_path self.bootstrap_path = bootstrap_path self.ads_path = ads_path self.snapshot_path = snapshot_path self.ir = None self.stats_updater = None self.scout_checker = None self.last_request_info = {} self.last_request_time = None # self.scout = Scout(update_frequency=datetime.timedelta(seconds=10)) self.scout = Scout(local_only=self.local_scout)
def showid(): """ Show Ambassador's installation ID """ scout = Scout() print("Ambassador Scout installation ID %s" % scout.install_id) result = scout.report(action="showid", mode="cli") show_notices(result, printer=stdout_printer)
def handle_exception(what, e, **kwargs): tb = "\n".join(traceback.format_exception(*sys.exc_info())) scout = Scout() result = scout.report(action=what, mode="cli", exception=str(e), traceback=tb, **kwargs) logger.debug("Scout %s, result: %s" % ("enabled" if scout._scout else "disabled", result)) logger.error("%s: %s\n%s" % (what, e, tb)) show_notices(result)
def version(): """ Show Ambassador's version """ print("Ambassador %s" % __version__) scout = Scout() print("Ambassador Scout version %s" % scout.version) print("Ambassador Scout semver %s" % scout.get_semver(scout.version)) result = scout.report(action="version", mode="cli") show_notices(result, printer=stdout_printer)
def setup(self, snapshot_path: str, bootstrap_path: str, ads_path: str, config_path: Optional[str], ambex_pid: int, kick: Optional[str], do_checks=True, no_envoy=False, reload=False, debug=False, verbose=False, notices=None): self.estats = EnvoyStats() self.health_checks = do_checks self.no_envoy = no_envoy self.debugging = reload self.verbose = verbose self.notice_path = notices self.notices = Notices(self.notice_path) self.notices.reset() # This will raise an exception and crash if you pass it a string. That's intentional. self.ambex_pid = int(ambex_pid) self.kick = kick # This feels like overkill. self.logger = logging.getLogger("ambassador.diagd") self.logger.setLevel(logging.INFO) if debug: self.logger.setLevel(logging.DEBUG) logging.getLogger('ambassador').setLevel(logging.DEBUG) self.config_path = config_path self.bootstrap_path = bootstrap_path self.ads_path = ads_path self.snapshot_path = snapshot_path self.ir = None self.stats_updater = None # self.scout = Scout(update_frequency=datetime.timedelta(seconds=30)) self.scout = Scout()
def generate_config(self, changes, output): if os.path.exists(output): shutil.rmtree(output) os.makedirs(output) for filename, config in self.configs.items(): path = os.path.join(output, filename) with open(path, "w") as fd: fd.write(config) logger.debug("Wrote %s to %s" % (filename, path)) plural = "" if (changes == 1) else "s" logger.info("generating config with gencount %d (%d change%s)" % (self.restart_count, changes, plural)) aconf = Config() aconf.load_from_directory(output) ir = IR(aconf, secret_reader=KubeSecretReader(secret_root)) envoy_config = V2Config(ir) bootstrap_config, ads_config = envoy_config.split_config() scout = Scout(install_id=self.cluster_id) scout_args = {"gencount": self.restart_count} if not os.environ.get("AMBASSADOR_DISABLE_FEATURES", None): scout_args["features"] = ir.features() result = scout.report(mode="kubewatch", action="reconfigure", **scout_args) notices = result.pop("notices", []) logger.debug("scout result %s" % json.dumps(result, sort_keys=True, indent=4)) for notice in notices: logger.log(logging.getLevelName(notice.get('level', 'WARNING')), notice.get('message', '?????')) return bootstrap_config, ads_config
def config(config_dir_path: Parameter.REQUIRED, output_json_path: Parameter.REQUIRED, *, debug=False, debug_scout=False, check=False, k8s=False, ir=None, aconf=None, exit_on_error=False): """ Generate an Envoy configuration :param config_dir_path: Configuration directory to scan for Ambassador YAML files :param output_json_path: Path to output envoy.json :param debug: If set, generate debugging output :param debug_scout: If set, generate debugging output when talking to Scout :param check: If set, generate configuration only if it doesn't already exist :param k8s: If set, assume configuration files are annotated K8s manifests :param exit_on_error: If set, will exit with status 1 on any configuration error :param ir: Pathname to which to dump the IR (not dumped if not present) :param aconf: Pathname to which to dump the aconf (not dumped if not present) """ if debug: logger.setLevel(logging.DEBUG) if debug_scout: logging.getLogger('ambassador.scout').setLevel(logging.DEBUG) try: logger.debug("CHECK MODE %s" % check) logger.debug("CONFIG DIR %s" % config_dir_path) logger.debug("OUTPUT PATH %s" % output_json_path) dump_aconf: Optional[str] = aconf dump_ir: Optional[str] = ir # Bypass the existence check... output_exists = False if check: # ...oh no wait, they explicitly asked for the existence check! # Assume that the file exists (ie, we'll do nothing) unless we # determine otherwise. output_exists = True try: parse_json(open(output_json_path, "r").read()) except FileNotFoundError: logger.debug("output file does not exist") output_exists = False except OSError: logger.warning("output file is not sane?") output_exists = False except json.decoder.JSONDecodeError: logger.warning("output file is not valid JSON") output_exists = False logger.info("Output file %s" % ("exists" if output_exists else "does not exist")) rc = RichStatus.fromError("impossible error") if not output_exists: # Either we didn't need to check, or the check didn't turn up # a valid config. Regenerate. logger.info("Generating new Envoy configuration...") aconf = Config() fetcher = ResourceFetcher(logger, aconf) fetcher.load_from_filesystem(config_dir_path, k8s=k8s) aconf.load_all(fetcher.sorted()) if dump_aconf: with open(dump_aconf, "w") as output: output.write(aconf.as_json()) output.write("\n") # If exit_on_error is set, log _errors and exit with status 1 if exit_on_error and aconf.errors: raise Exception("errors in: {0}".format(', '.join( aconf.errors.keys()))) secret_handler = NullSecretHandler(logger, config_dir_path, config_dir_path, "0") ir = IR(aconf, file_checker=file_checker, secret_handler=secret_handler) if dump_ir: with open(dump_ir, "w") as output: output.write(ir.as_json()) output.write("\n") # clize considers kwargs with False for default value as flags, # resulting in the logic below. # https://clize.readthedocs.io/en/stable/basics.html#accepting-flags logger.info("Writing envoy V2 configuration") v2config = V2Config(ir) rc = RichStatus.OK(msg="huh_v2") if rc: with open(output_json_path, "w") as output: output.write(v2config.as_json()) output.write("\n") else: logger.error("Could not generate new Envoy configuration: %s" % rc.error) scout = Scout() result = scout.report(action="config", mode="cli") show_notices(result) except Exception as e: handle_exception("EXCEPTION from config", e, config_dir_path=config_dir_path, output_json_path=output_json_path) # This is fatal. sys.exit(1)