Exemplo n.º 1
0
class ServiceInventory:
    """The inventory enumerates available backends for a single service.

    :param str filename: The absolute path to the Synapse-generated
        inventory file in JSON format.

    """
    def __init__(self, filename):
        self._filewatcher = FileWatcher(filename, _parse)

    def get_backends(self):
        """Return a list of all available backends in the inventory.

        If the inventory file becomes unavailable, the previously seen
        inventory is returned.

        :rtype: list of :py:class:`Backend` objects

        """
        try:
            # pylint: disable=maybe-no-member
            return self._filewatcher.get_data().backends
        except WatchedFileNotAvailableError:
            return []

    def get_backend(self):
        """Return a randomly chosen backend from the available backends.

        If weights are specified in the inventory, they will be
        respected when making the random selection.

        :rtype: :py:class:`Backend`
        :raises: :py:exc:`NoBackendsAvailableError` if the inventory
            has no available endpoints.

        """
        try:
            inventory = self._filewatcher.get_data()
        except WatchedFileNotAvailableError:
            inventory = None

        # pylint: disable=maybe-no-member
        if not inventory or not inventory.backends:
            raise NoBackendsAvailableError

        return inventory.lottery.pick()
Exemplo n.º 2
0
 def __init__(self, path: str, timeout: Optional[int] = None):
     self._filewatcher = FileWatcher(path, json.load, timeout=timeout)
Exemplo n.º 3
0
class SecretsStore(ContextFactory):
    """Access to secret tokens with automatic refresh when changed.

    This local vault allows access to the secrets cached on disk by the fetcher
    daemon. It will automatically reload the cache when it is changed. Do not
    cache or store the values returned by this class's methods but rather get
    them from this class each time you need them. The secrets are served from
    memory so there's little performance impact to doing so and you will be
    sure to always have the current version in the face of key rotation etc.

    """
    def __init__(self, path: str, timeout: Optional[int] = None):
        self._filewatcher = FileWatcher(path, json.load, timeout=timeout)

    def _get_data(self) -> Any:
        try:
            return self._filewatcher.get_data()
        except WatchedFileNotAvailableError as exc:
            raise SecretsNotAvailableError(exc)

    def get_raw(self, path: str) -> Dict[str, str]:
        """Return a dictionary of key/value pairs for the given secret path.

        This is the raw representation of the secret in the underlying store.

        """
        data = self._get_data()

        try:
            return data["secrets"][path]
        except KeyError:
            raise SecretNotFoundError(path)

    def get_credentials(self, path: str) -> CredentialSecret:
        """Decode and return a credential secret.

        Credential secrets are a convention of username/password pairs stored as
        separate values in the raw secret payload.

        The following keys are significant:

        ``type``
            This must always be ``credential`` for this method.
        ``encoding``
            This must be un-set or set to ``identity``.
        ``username``
            This contains the raw username.
        ``password``
            This contains the raw password.

        """
        secret_attributes = self.get_raw(path)

        if secret_attributes.get("type") != "credential":
            raise CorruptSecretError(path,
                                     "secret does not have type=credential")

        encoding = secret_attributes.get("encoding", "identity")

        if encoding != "identity":
            raise CorruptSecretError(
                path, "secret has encoding=%s rather than "
                "encoding=identity" % encoding)

        values = {}
        for key in ("username", "password"):
            try:
                val = secret_attributes[key]
                if not isinstance(val, str):
                    raise CorruptSecretError(
                        path, "secret value '%s' is not a string" % key)
                values[key] = val
            except KeyError:
                raise CorruptSecretError(path,
                                         "secret does not have key '%s'" % key)

        return CredentialSecret(**values)

    def get_simple(self, path: str) -> bytes:
        """Decode and return a simple secret.

        Simple secrets are a convention of key/value pairs in the raw secret
        payload.  The following keys are significant:

        ``type``
            This must always be ``simple`` for this method.
        ``value``
            This contains the raw value of the secret token.
        ``encoding``
            (Optional) If present, how to decode the value from how it's
            encoded at rest (only ``base64`` currently supported).

        """
        secret_attributes = self.get_raw(path)

        if secret_attributes.get("type") != "simple":
            raise CorruptSecretError(path, "secret does not have type=simple")

        try:
            value = secret_attributes["value"]
        except KeyError:
            raise CorruptSecretError(path, "secret does not have value")

        encoding = secret_attributes.get("encoding", "identity")
        return _decode_secret(path, encoding, value)

    def get_versioned(self, path: str) -> VersionedSecret:
        """Decode and return a versioned secret.

        Versioned secrets are a convention of key/value pairs in the raw secret
        payload. The following keys are significant:

        ``type``
            This must always be ``versioned`` for this method.
        ``current``, ``next``, and ``previous``
            The raw secret value's versions. ``current`` is the "active"
            version, which is used for new creation/signing operations.
            ``previous`` and ``next`` are only used for validation (e.g.
            checking signatures) to ensure continuity when keys rotate. Both
            ``previous`` and ``next`` are optional.
        ``encoding``
            (Optional) If present, how to decode the values from how they are
            encoded at rest (only ``base64`` currently supported).

        """
        secret_attributes = self.get_raw(path)

        if secret_attributes.get("type") != "versioned":
            raise CorruptSecretError(path,
                                     "secret does not have type=versioned")

        previous_value = secret_attributes.get("previous")
        next_value = secret_attributes.get("next")

        try:
            current_value = secret_attributes["current"]
        except KeyError:
            raise CorruptSecretError(path,
                                     "secret does not have 'current' value")

        encoding = secret_attributes.get("encoding", "identity")
        return VersionedSecret(
            previous=_decode_secret(path, encoding, previous_value)
            if previous_value else None,
            current=_decode_secret(path, encoding, current_value),
            next=_decode_secret(path, encoding, next_value)
            if next_value else None,
        )

    def get_vault_url(self) -> str:
        """Return the URL for accessing Vault directly.

        .. seealso:: The :py:mod:`baseplate.context.hvac` module provides
            integration with HVAC, a Vault client.

        """
        data = self._get_data()
        return data["vault"]["url"]

    def get_vault_token(self) -> str:
        """Return a Vault authentication token.

        The token will have policies attached based on the current EC2 server's
        Vault role. This is only necessary if talking directly to Vault.

        .. seealso:: The :py:mod:`baseplate.context.hvac` module provides
            integration with HVAC, a Vault client.

        """
        data = self._get_data()
        return data["vault"]["token"]

    def make_object_for_context(self, name: str, span: Span) -> "SecretsStore":
        """Return an object that can be added to the context object.

        This allows the secret store to be used with
        :py:meth:`~baseplate.core.Baseplate.add_to_context`::

           secrets = SecretsStore("/var/local/secrets.json")
           baseplate.add_to_context("secrets", secrets)

        """
        return _CachingSecretsStore(self._filewatcher)
Exemplo n.º 4
0
        stage = pull_request.review_stage()
        pull_requests[stage].append(pull_request)

    metrics = load_metrics()
    return render_template(
        "repo.html",
        repo_name=repo_name,
        pull_requests=pull_requests,
        metrics=metrics["repository"].get(repo_name.lower(), {
            "counters": {},
            "timers": {}
        }),
    )


SALON_FILEWATCHER = FileWatcher("/var/lib/harold/salons.json", json.load)


@app.route("/salons")
def salons():
    return render_template(
        "salons.html",
        salons=SALON_FILEWATCHER.get_data(),
    )


@app.route("/emoji")
def emoji():
    return render_template("emoji.html")

Exemplo n.º 5
0
 def __init__(self, path, event_logger=None, timeout=None):
     self._filewatcher = FileWatcher(path, json.load, timeout=timeout)
     self._event_logger = event_logger
Exemplo n.º 6
0
 def __init__(self, path, timeout=None):
     self._filewatcher = FileWatcher(path, json.load, timeout=timeout)
Exemplo n.º 7
0
import collections
import datetime
import json

from baseplate.file_watcher import FileWatcher

from salon.app import app
from salon.models import db
from salon.models import Event

METRICS_FILE_PATH = "/var/lib/harold/metrics.json"
METRICS_HORIZON_DAYS = 90
FILEWATCHER = FileWatcher(METRICS_FILE_PATH, json.load)

HOLIDAYS = [
    datetime.date(2019, 1, 1),
    datetime.date(2019, 1, 2),
    datetime.date(2019, 1, 21),
    datetime.date(2019, 2, 18),
    datetime.date(2019, 5, 27),
    datetime.date(2019, 7, 4),
    datetime.date(2019, 9, 2),
    datetime.date(2019, 11, 28),
    datetime.date(2019, 11, 29),
    datetime.date(2019, 12, 24),
    datetime.date(2019, 12, 25),
    datetime.date(2019, 12, 31),
    datetime.date(2020, 1, 1),
    datetime.date(2020, 1, 2),
    datetime.date(2020, 1, 20),
    datetime.date(2020, 2, 17),
Exemplo n.º 8
0
 def __init__(self, filename: str):
     self._filewatcher = FileWatcher(filename, _parse)