Move NPM configuration and client behind plugin boundary
This commit is contained in:
+12
-58
@@ -79,15 +79,6 @@ def parse_endpoint_list(
|
||||
return tuple(endpoints)
|
||||
|
||||
|
||||
def endpoint_host(endpoint: Endpoint) -> str:
|
||||
parsed = urlsplit(f"//{endpoint.address}")
|
||||
if not parsed.hostname:
|
||||
raise RuntimeError(
|
||||
f"Invalid endpoint address: {endpoint.address!r}"
|
||||
)
|
||||
return parsed.hostname
|
||||
|
||||
|
||||
def env_bool(name: str, default: bool) -> bool:
|
||||
value = os.getenv(name)
|
||||
if value is None:
|
||||
@@ -97,64 +88,32 @@ def env_bool(name: str, default: bool) -> bool:
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AppConfig:
|
||||
npm_endpoints: tuple[Endpoint, ...]
|
||||
proxy_ip: str
|
||||
proxy_api_port: int
|
||||
proxy_api_scheme: str
|
||||
target_ip: str
|
||||
proxy_verify_tls: bool
|
||||
domain_matching: bool
|
||||
domain: str | None
|
||||
include_disabled: bool = False
|
||||
|
||||
@classmethod
|
||||
def from_env(cls, include_disabled: bool = False) -> "AppConfig":
|
||||
try:
|
||||
port = int(os.getenv("PROXY_API_PORT", "81"))
|
||||
except ValueError as exc:
|
||||
raise RuntimeError("PROXY_API_PORT must be an integer") from exc
|
||||
if not 1 <= port <= 65535:
|
||||
raise RuntimeError("PROXY_API_PORT must be between 1 and 65535")
|
||||
|
||||
scheme = os.getenv("PROXY_API_SCHEME", "http").strip().lower()
|
||||
if scheme not in {"http", "https"}:
|
||||
raise RuntimeError("PROXY_API_SCHEME must be http or https")
|
||||
|
||||
raw_proxy_ip = os.getenv("PROXY_IP")
|
||||
raw_npm_endpoints = os.getenv("NPM_ENDPOINTS")
|
||||
|
||||
if raw_npm_endpoints is None:
|
||||
if not raw_proxy_ip:
|
||||
raise RuntimeError(
|
||||
"NPM_ENDPOINTS or legacy PROXY_IP is required"
|
||||
)
|
||||
proxy_ip = normalize_ipv4(raw_proxy_ip, "PROXY_IP")
|
||||
npm_endpoints = parse_endpoint_list("npm", proxy_ip, port)
|
||||
else:
|
||||
npm_endpoints = parse_endpoint_list(
|
||||
"npm",
|
||||
raw_npm_endpoints,
|
||||
port,
|
||||
)
|
||||
if raw_proxy_ip:
|
||||
proxy_ip = normalize_ipv4(raw_proxy_ip, "PROXY_IP")
|
||||
else:
|
||||
proxy_ip = endpoint_host(npm_endpoints[0])
|
||||
|
||||
raw_target_ip = os.getenv("DNS_TARGET_IP")
|
||||
raw_proxy_ip = os.getenv("PROXY_IP")
|
||||
|
||||
if raw_target_ip:
|
||||
target_ip = normalize_ipv4(raw_target_ip, "DNS_TARGET_IP")
|
||||
elif raw_proxy_ip:
|
||||
target_ip = proxy_ip
|
||||
elif len(npm_endpoints) == 1:
|
||||
target_ip = normalize_ipv4(
|
||||
endpoint_host(npm_endpoints[0]),
|
||||
raw_target_ip,
|
||||
"DNS_TARGET_IP",
|
||||
)
|
||||
elif raw_proxy_ip:
|
||||
# Deprecated compatibility fallback. Core no longer treats
|
||||
# PROXY_IP as an NPM endpoint.
|
||||
target_ip = normalize_ipv4(
|
||||
raw_proxy_ip,
|
||||
"PROXY_IP",
|
||||
)
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"DNS_TARGET_IP is required when multiple NPM_ENDPOINTS "
|
||||
"are configured without legacy PROXY_IP"
|
||||
"DNS_TARGET_IP is required "
|
||||
"(legacy PROXY_IP is also accepted)"
|
||||
)
|
||||
|
||||
domain_matching = env_bool("DOMAIN_MATCHING", False)
|
||||
@@ -173,12 +132,7 @@ class AppConfig:
|
||||
)
|
||||
|
||||
return cls(
|
||||
npm_endpoints=npm_endpoints,
|
||||
proxy_ip=proxy_ip,
|
||||
proxy_api_port=port,
|
||||
proxy_api_scheme=scheme,
|
||||
target_ip=target_ip,
|
||||
proxy_verify_tls=env_bool("PROXY_VERIFY_TLS", True),
|
||||
domain_matching=domain_matching,
|
||||
domain=domain,
|
||||
include_disabled=include_disabled,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
from ...adapters import (
|
||||
from ....adapters import (
|
||||
CERTIFICATES,
|
||||
PROXY_HOSTS,
|
||||
ApplyResult,
|
||||
@@ -13,18 +14,49 @@ from ...adapters import (
|
||||
PlanOperation,
|
||||
RetireRequest,
|
||||
)
|
||||
from ...adapter_support import (
|
||||
from ....adapter_support import (
|
||||
require_action_endpoint,
|
||||
require_desired,
|
||||
require_endpoint_plugin,
|
||||
)
|
||||
from ...certificates.material import CertificateMaterial
|
||||
from ...npm_client import NpmClient
|
||||
from ...object_normalizer import normalize_discovered_object
|
||||
from ....certificates.material import CertificateMaterial
|
||||
from ....config import parse_endpoint_list
|
||||
from ....normalizer import normalize_ipv4
|
||||
from .client import NpmClient
|
||||
from ....object_normalizer import normalize_discovered_object
|
||||
|
||||
|
||||
def configured_endpoints(config):
|
||||
return config.npm_endpoints
|
||||
try:
|
||||
port = int(os.getenv("PROXY_API_PORT", "81"))
|
||||
except ValueError as exc:
|
||||
raise RuntimeError(
|
||||
"PROXY_API_PORT must be an integer"
|
||||
) from exc
|
||||
|
||||
if not 1 <= port <= 65535:
|
||||
raise RuntimeError(
|
||||
"PROXY_API_PORT must be between 1 and 65535"
|
||||
)
|
||||
|
||||
raw_endpoints = os.getenv("NPM_ENDPOINTS")
|
||||
if raw_endpoints is None:
|
||||
raw_proxy_ip = os.getenv("PROXY_IP")
|
||||
if not raw_proxy_ip:
|
||||
raise RuntimeError(
|
||||
"NPM_ENDPOINTS or legacy PROXY_IP is required"
|
||||
)
|
||||
|
||||
raw_endpoints = normalize_ipv4(
|
||||
raw_proxy_ip,
|
||||
"PROXY_IP",
|
||||
)
|
||||
|
||||
return parse_endpoint_list(
|
||||
"npm",
|
||||
raw_endpoints,
|
||||
port,
|
||||
)
|
||||
|
||||
|
||||
_PROXY_HOST_FIELDS = (
|
||||
@@ -77,9 +109,9 @@ class Plugin:
|
||||
|
||||
def __init__(self, config, endpoint):
|
||||
require_endpoint_plugin(endpoint, self.name)
|
||||
self.config = config
|
||||
self.endpoints = configured_endpoints(config)
|
||||
self.endpoint = endpoint
|
||||
self.client = NpmClient(config, endpoint)
|
||||
self.client = NpmClient(endpoint)
|
||||
|
||||
@staticmethod
|
||||
def _local_key(row: dict[str, Any], label: str) -> str:
|
||||
@@ -246,16 +278,13 @@ class Plugin:
|
||||
source_errors: list[str] = []
|
||||
|
||||
for endpoint in sorted(
|
||||
self.config.npm_endpoints,
|
||||
self.endpoints,
|
||||
key=lambda item: item.identity,
|
||||
):
|
||||
if endpoint.identity == self.endpoint.identity:
|
||||
continue
|
||||
|
||||
client = NpmClient(
|
||||
self.config,
|
||||
endpoint,
|
||||
)
|
||||
client = NpmClient(endpoint)
|
||||
|
||||
try:
|
||||
rows = client.certificates()
|
||||
@@ -7,8 +7,9 @@ from zipfile import BadZipFile, ZipFile
|
||||
import requests
|
||||
import urllib3
|
||||
|
||||
from .adapters import Endpoint
|
||||
from .certificates.material import CertificateMaterial
|
||||
from ....adapters import Endpoint
|
||||
from ....certificates.material import CertificateMaterial
|
||||
from ....config import env_bool
|
||||
|
||||
|
||||
class NpmClient:
|
||||
@@ -16,11 +17,9 @@ class NpmClient:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
config,
|
||||
endpoint: Endpoint | None = None,
|
||||
endpoint: Endpoint,
|
||||
):
|
||||
self.config = config
|
||||
self.endpoint = endpoint or config.npm_endpoints[0]
|
||||
self.endpoint = endpoint
|
||||
|
||||
if self.endpoint.plugin != "npm":
|
||||
raise RuntimeError("NpmClient requires an npm endpoint")
|
||||
@@ -34,10 +33,25 @@ class NpmClient:
|
||||
if not self.secret:
|
||||
raise RuntimeError("NPM_SECRET is required")
|
||||
|
||||
self.api_scheme = os.getenv(
|
||||
"PROXY_API_SCHEME",
|
||||
"http",
|
||||
).strip().lower()
|
||||
|
||||
if self.api_scheme not in {"http", "https"}:
|
||||
raise RuntimeError(
|
||||
"PROXY_API_SCHEME must be http or https"
|
||||
)
|
||||
|
||||
self.verify_tls = env_bool(
|
||||
"PROXY_VERIFY_TLS",
|
||||
True,
|
||||
)
|
||||
|
||||
self.session = requests.Session()
|
||||
self.token: str | None = None
|
||||
|
||||
if not config.proxy_verify_tls:
|
||||
if not self.verify_tls:
|
||||
urllib3.disable_warnings(
|
||||
urllib3.exceptions.InsecureRequestWarning
|
||||
)
|
||||
@@ -45,7 +59,7 @@ class NpmClient:
|
||||
@property
|
||||
def api_url(self) -> str:
|
||||
return (
|
||||
f"{self.config.proxy_api_scheme}://"
|
||||
f"{self.api_scheme}://"
|
||||
f"{self.endpoint.address}/api"
|
||||
)
|
||||
|
||||
@@ -57,7 +71,7 @@ class NpmClient:
|
||||
"secret": self.secret,
|
||||
},
|
||||
timeout=15,
|
||||
verify=self.config.proxy_verify_tls,
|
||||
verify=self.verify_tls,
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
@@ -107,7 +121,7 @@ class NpmClient:
|
||||
method,
|
||||
f"{self.api_url}{path}",
|
||||
timeout=kwargs.pop("timeout", 15),
|
||||
verify=self.config.proxy_verify_tls,
|
||||
verify=self.verify_tls,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user