Exemplo n.º 1
0
def on_exit(server: Arbiter):
    """Gunicorn shutdown tasks."""

    log.critical("Stopping hyperglass {}", __version__)

    async def runner():
        await clear_cache()

    aiorun(runner())
Exemplo n.º 2
0
def _config_required(config_path: Path) -> Dict:
    try:
        with config_path.open("r") as cf:
            config = yaml.safe_load(cf)

    except (yaml.YAMLError, yaml.MarkedYAMLError) as yaml_error:
        raise ConfigError(str(yaml_error))

    if config is None:
        log.critical("{} appears to be empty", str(config_path))
        raise ConfigMissing(missing_item=config_path.name)

    return config
Exemplo n.º 3
0
 def __init__(
     self,
     message: str = "",
     level: str = "warning",
     keywords: Optional[List[str]] = None,
 ) -> None:
     """Initialize the hyperglass base exception class."""
     self._message = message
     self._level = level
     self._keywords = keywords or []
     if self._level == "warning":
         log.error(repr(self))
     elif self._level == "danger":
         log.critical(repr(self))
     else:
         log.info(repr(self))
Exemplo n.º 4
0
    def __init__(self, message="", level="warning", keywords=None):
        """Initialize the hyperglass base exception class.

        Keyword Arguments:
            message {str} -- Error message (default: {""})
            level {str} -- Error severity (default: {"warning"})
            keywords {list} -- 'Important' keywords (default: {None})
        """
        self._message = message
        self._level = level
        self._keywords = keywords or []
        if self._level == "warning":
            log.error(repr(self))
        elif self._level == "danger":
            log.critical(repr(self))
        else:
            log.info(repr(self))
Exemplo n.º 5
0
    def __init__(
        self,
        message: str = "",
        level: str = "warning",
        keywords: Optional[List[str]] = None,
    ) -> None:
        """Initialize the hyperglass base exception class."""
        self._message = message
        self._level = level
        self._keywords = keywords or []
        if self._level == "warning":
            log.error(repr(self))
        elif self._level == "danger":
            log.critical(repr(self))
        else:
            log.info(repr(self))

        if all(sys.exc_info()):
            # Rich will raise a ValueError if print_exception() is used
            # outside of a try/except block. Only use Rich for traceback
            # printing if the exception is caught.
            console.print_exception(extra_lines=6)
Exemplo n.º 6
0
def parse_juniper(output):
    """Parse a Juniper BGP XML response."""
    data = {}
    for i, response in enumerate(output):
        try:
            parsed = xmltodict.parse(response,
                                     force_list=("rt", "rt-entry",
                                                 "community"))

            if "rpc-reply" in parsed.keys():
                parsed_base = parsed["rpc-reply"]["route-information"]
            elif "route-information" in parsed.keys():
                parsed_base = parsed["route-information"]

            if "route-table" not in parsed_base:
                raise ResponseEmpty(params.messages.no_output)

            if "rt" not in parsed_base["route-table"]:
                raise ResponseEmpty(params.messages.no_output)

            parsed = parsed_base["route-table"]

            validated = JuniperRoute(**parsed)
            serialized = validated.serialize().export_dict()

            if i == 0:
                data.update(serialized)
            else:
                data["routes"].extend(serialized["routes"])

        except xmltodict.expat.ExpatError as err:
            log.critical(str(err))
            raise ParsingError("Error parsing response data")

        except KeyError as err:
            log.critical(f"'{str(err)}' was not found in the response")
            raise ParsingError("Error parsing response data")

    return data
Exemplo n.º 7
0
def parse_arista(output: Sequence[str]) -> Dict:  # noqa: C901
    """Parse a Arista BGP JSON response."""
    data = {}

    for i, response in enumerate(output):

        try:
            data: Dict = json.loads(response)

            log.debug("Pre-parsed data: {}", data)

            vrf = list(data["vrfs"].keys())[0]
            routes = data["vrfs"][vrf]

            log.debug("Pre-validated data: {}", routes)

            validated = AristaRoute(**routes)
            serialized = validated.serialize().export_dict()

            if i == 0:
                data.update(serialized)
            else:
                data["routes"].extend(serialized["routes"])

        except json.JSONDecodeError as err:
            log.critical("Error decoding JSON: {}", str(err))
            raise ParsingError("Error parsing response data")

        except KeyError as err:
            log.critical("'{}' was not found in the response", str(err))
            raise ParsingError("Error parsing response data")

        except IndexError as err:
            log.critical(str(err))
            raise ParsingError("Error parsing response data")

        except ValidationError as err:
            log.critical(str(err))
            raise ParsingError(err.errors())

    log.debug("Serialzed: {}", data)
    return data
Exemplo n.º 8
0
def parse_juniper(output: Sequence) -> Dict:  # noqa: C901
    """Parse a Juniper BGP XML response."""
    data = {}

    for i, response in enumerate(output):
        cleaned = clean_xml_output(response)

        try:
            parsed = xmltodict.parse(
                cleaned, force_list=("rt", "rt-entry", "community")
            )

            log.debug("Initially Parsed Response: \n{}", parsed)

            if "rpc-reply" in parsed.keys():
                parsed_base = parsed["rpc-reply"]["route-information"]
            elif "route-information" in parsed.keys():
                parsed_base = parsed["route-information"]

            if "route-table" not in parsed_base:
                return data

            if "rt" not in parsed_base["route-table"]:
                return data

            parsed = parsed_base["route-table"]

            validated = JuniperRoute(**parsed)
            serialized = validated.serialize().export_dict()

            if i == 0:
                data.update(serialized)
            else:
                data["routes"].extend(serialized["routes"])

        except xmltodict.expat.ExpatError as err:
            log.critical(str(err))
            raise ParsingError("Error parsing response data") from err

        except KeyError as err:
            log.critical("{} was not found in the response", str(err))
            raise ParsingError("Error parsing response data")

        except ValidationError as err:
            log.critical(str(err))
            raise ParsingError(err.errors())

    return data
Exemplo n.º 9
0
    async def collect(self) -> Iterable:  # noqa: C901
        """Connect to a device running hyperglass-agent via HTTP."""
        log.debug("Query parameters: {}", self.query)

        client_params = {
            "headers": {
                "Content-Type": "application/json"
            },
            "timeout": params.request_timeout,
        }
        if self.device.ssl is not None and self.device.ssl.enable:
            with self.device.ssl.cert.open("r") as file:
                cert = file.read()
                if not cert:
                    raise RestError(
                        "SSL Certificate for device {d} has not been imported",
                        level="danger",
                        d=self.device.display_name,
                    )
            http_protocol = "https"
            client_params.update({"verify": str(self.device.ssl.cert)})
            log.debug(
                (f"Using {str(self.device.ssl.cert)} to validate connection "
                 f"to {self.device.name}"))
        else:
            http_protocol = "http"
        endpoint = "{protocol}://{address}:{port}/query/".format(
            protocol=http_protocol,
            address=self.device._target,
            port=self.device.port)

        log.debug("URL endpoint: {}", endpoint)

        try:
            async with httpx.AsyncClient(**client_params) as http_client:
                responses = ()

                for query in self.query:
                    encoded_query = await jwt_encode(
                        payload=query,
                        secret=self.device.credential.password.
                        get_secret_value(),
                        duration=params.request_timeout,
                    )
                    log.debug("Encoded JWT: {}", encoded_query)

                    raw_response = await http_client.post(
                        endpoint, json={"encoded": encoded_query})
                    log.debug("HTTP status code: {}", raw_response.status_code)

                    raw = raw_response.text
                    log.debug("Raw Response:\n{}", raw)

                    if raw_response.status_code == 200:
                        decoded = await jwt_decode(
                            payload=raw_response.json()["encoded"],
                            secret=self.device.credential.password.
                            get_secret_value(),
                        )
                        log.debug("Decoded Response:\n{}", decoded)
                        responses += (decoded, )

                    elif raw_response.status_code == 204:
                        raise ResponseEmpty(
                            params.messages.no_output,
                            device_name=self.device.display_name,
                        )

                    else:
                        log.error(raw_response.text)

        except httpx.exceptions.HTTPError as rest_error:
            msg = parse_exception(rest_error)
            log.error("Error connecting to device {}: {}", self.device.name,
                      msg)
            raise RestError(
                params.messages.connection_error,
                device_name=self.device.display_name,
                error=msg,
            )
        except OSError as ose:
            log.critical(str(ose))
            raise RestError(
                params.messages.connection_error,
                device_name=self.device.display_name,
                error="System error",
            )
        except CertificateError as cert_error:
            log.critical(str(cert_error))
            msg = parse_exception(cert_error)
            raise RestError(
                params.messages.connection_error,
                device_name=self.device.display_name,
                error=f"{msg}: {cert_error}",
            )

        if raw_response.status_code != 200:
            log.error("Response code is {}", raw_response.status_code)
            raise RestError(
                params.messages.connection_error,
                device_name=self.device.display_name,
                error=params.messages.general,
            )

        if not responses:
            log.error("No response from device {}", self.device.name)
            raise RestError(
                params.messages.connection_error,
                device_name=self.device.display_name,
                error=params.messages.no_response,
            )

        return responses