Skip to content
Snippets Groups Projects
settings.py 5.71 KiB
""":term:`GSO` settings.

Ensuring that the required parameters are set correctly. An example file ``oss-params-example.json`` is present in the
:term:`GSO` package itself.
"""

import ipaddress
import json
import logging
import os
from pathlib import Path
from typing import Annotated

from pydantic import EmailStr, Field
from pydantic_forms.types import UUIDstr, strEnum
from pydantic_settings import BaseSettings
from typing_extensions import Doc

from gso.utils.shared_enums import PortNumber

logger = logging.getLogger(__name__)


class EnvironmentEnum(strEnum):
    """The different environments in which the GSO system can run."""

    DEVELOPMENT = "development"
    TEST = "test"
    UAT = "uat"
    PRODUCTION = "production"


class GeneralParams(BaseSettings):
    """General parameters for a :term:`GSO` configuration file."""

    public_hostname: str
    """The hostname that :term:`GSO` is publicly served at, used for building callback URLs for public use."""
    internal_hostname: str
    """The hostname of :term:`GSO` that is for internal use, such as the provisioning proxy."""
    isis_high_metric: int
    environment: EnvironmentEnum


class CeleryParams(BaseSettings):
    """Parameters for Celery."""

    broker_url: str
    result_backend: str
    timezone: str = "Europe/Amsterdam"
    enable_utc: bool = True
    result_expires: int = 3600


class InfoBloxParams(BaseSettings):
    """Parameters related to InfoBlox."""

    scheme: str
    wapi_version: str
    host: str
    username: str
    password: str


V4Netmask = Annotated[int, Field(ge=0, le=32), Doc("A valid netmask for an IPv4 network or address.")]
V6Netmask = Annotated[int, Field(ge=0, le=128), Doc("A valid netmask for an IPv6 network or address.")]


class V4NetworkParams(BaseSettings):
    """A set of parameters that describe an IPv4 network in InfoBlox."""

    containers: list[ipaddress.IPv4Network]
    networks: list[ipaddress.IPv4Network]
    mask: V4Netmask


class V6NetworkParams(BaseSettings):
    """A set of parameters that describe an IPv6 network in InfoBlox."""

    containers: list[ipaddress.IPv6Network]
    networks: list[ipaddress.IPv6Network]
    mask: V6Netmask


class ServiceNetworkParams(BaseSettings):
    """Parameters for InfoBlox.

    The parameters describe IPv4 and v6 networks, and the corresponding domain name that should be used as a suffix.
    """

    V4: V4NetworkParams
    V6: V6NetworkParams
    domain_name: str
    dns_view: str
    network_view: str


class IPAMParams(BaseSettings):
    """A set of parameters related to :term:`IPAM`."""

    INFOBLOX: InfoBloxParams
    LO: ServiceNetworkParams
    TRUNK: ServiceNetworkParams
    GEANT_IP: ServiceNetworkParams
    SI: ServiceNetworkParams
    LT_IAS: ServiceNetworkParams


class MonitoringSNMPV2Params(BaseSettings):
    """Parameters related to SNMPv2."""

    community: str


class MonitoringSNMPV3Params(BaseSettings):
    """Parameters related to SNMPv3."""

    authlevel: str
    authname: str
    authpass: str
    authalgo: str
    cryptopass: str
    cryptoalgo: str


class MonitoringLibreNMSParams(BaseSettings):
    """Parameters related to LibreNMS."""

    base_url: str
    token: str


class SNMPParams(BaseSettings):
    """Parameters for SNMP in LibreNMS."""

    v2c: MonitoringSNMPV2Params
    #: .. versionadded :: 2.0
    #:    Support for :term:`SNMP` v3 will get added in a later version of :term:`GSO`. Parameters are optional for now.
    v3: MonitoringSNMPV3Params | None = None


class MonitoringParams(BaseSettings):
    """Parameters related to the monitoring."""

    LIBRENMS: MonitoringLibreNMSParams
    SNMP: SNMPParams


class ProvisioningProxyParams(BaseSettings):
    """Parameters for the provisioning proxy."""

    scheme: str
    api_base: str
    api_version: int


class NetBoxParams(BaseSettings):
    """Parameters for NetBox."""

    token: str
    api: str


class EmailParams(BaseSettings):
    """Parameters for the email service."""

    from_address: EmailStr
    smtp_host: str
    smtp_port: PortNumber
    starttls_enabled: bool
    smtp_username: str | None = None
    smtp_password: str | None = None
    #: List of email addresses that should receive notifications when validation of a subscription fails.
    #: Can be a comma-separated list of multiple addresses.
    notification_email_destinations: str


class SharepointParams(BaseSettings):
    """Settings for different Sharepoint sites."""

    client_id: UUIDstr
    tenant_id: UUIDstr
    certificate_path: str
    certificate_password: str
    site_id: UUIDstr
    list_ids: dict[str, UUIDstr]
    scopes: list[str]


class KentikParams(BaseSettings):
    """Settings for accessing Kentik's API."""

    api_base: str
    user_email: str
    api_key: str
    device_type: str
    minimize_snmp: bool
    placeholder_license_key: str
    sample_rate: int
    bgp_type: str
    bgp_lookup_strategy: str
    ASN: int
    snmp_community: str
    md5_password: str


class SentryParams(BaseSettings):
    """Settings for Sentry."""

    DSN: str


class OSSParams(BaseSettings):
    """The set of parameters required for running :term:`GSO`."""

    GENERAL: GeneralParams
    IPAM: IPAMParams
    NETBOX: NetBoxParams
    MONITORING: MonitoringParams
    PROVISIONING_PROXY: ProvisioningProxyParams
    CELERY: CeleryParams
    THIRD_PARTY_API_KEYS: dict[str, str]
    EMAIL: EmailParams
    SHAREPOINT: SharepointParams
    KENTIK: KentikParams
    SENTRY: SentryParams | None = None


def load_oss_params() -> OSSParams:
    """Look for ``OSS_PARAMS_FILENAME`` in the environment and load the parameters from that file."""
    with Path(os.environ["OSS_PARAMS_FILENAME"]).open(encoding="utf-8") as file:
        return OSSParams(**json.loads(file.read()))


if __name__ == "__main__":
    logger.debug(load_oss_params())