Example #1
0
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)
Example #2
0
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)
Example #3
0
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)
Example #4
0
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))
Example #5
0
    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)
Example #6
0
    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
Example #7
0
    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()
Example #8
0
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)