root: early spring clean for linting (#8498)
* remove pyright Signed-off-by: Jens Langhammer <jens@goauthentik.io> * remove pylint Signed-off-by: Jens Langhammer <jens@goauthentik.io> * replace pylint with ruff Signed-off-by: Jens Langhammer <jens@goauthentik.io> * ruff fix Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> * fix UP038 Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix DJ012 Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix default arg Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix UP031 Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rename stage type to view Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix DJ008 Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix remaining upgrade Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix PLR2004 Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix B904 Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix PLW2901 Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix remaining issues Signed-off-by: Jens Langhammer <jens@goauthentik.io> * prevent ruff from breaking the code Signed-off-by: Jens Langhammer <jens@goauthentik.io> * stages/prompt: refactor field building Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> * fix tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix lint Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fully remove isort Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
This commit is contained in:
@ -133,7 +133,7 @@ class KubernetesServiceConnectionSerializer(ServiceConnectionSerializer):
|
||||
try:
|
||||
load_kube_config_from_dict(kubeconfig, client_configuration=config)
|
||||
except ConfigException:
|
||||
raise serializers.ValidationError(_("Invalid kubeconfig"))
|
||||
raise serializers.ValidationError(_("Invalid kubeconfig")) from None
|
||||
return kubeconfig
|
||||
|
||||
class Meta:
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from datetime import datetime
|
||||
from enum import IntEnum
|
||||
from typing import Any, Optional
|
||||
from typing import Any
|
||||
|
||||
from asgiref.sync import async_to_sync
|
||||
from channels.exceptions import DenyConnection
|
||||
@ -49,10 +49,10 @@ class WebsocketMessage:
|
||||
class OutpostConsumer(JsonWebsocketConsumer):
|
||||
"""Handler for Outposts that connect over websockets for health checks and live updates"""
|
||||
|
||||
outpost: Optional[Outpost] = None
|
||||
outpost: Outpost | None = None
|
||||
logger: BoundLogger
|
||||
|
||||
instance_uid: Optional[str] = None
|
||||
instance_uid: str | None = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@ -71,7 +71,7 @@ class OutpostConsumer(JsonWebsocketConsumer):
|
||||
self.accept()
|
||||
except RuntimeError as exc:
|
||||
self.logger.warning("runtime error during accept", exc=exc)
|
||||
raise DenyConnection()
|
||||
raise DenyConnection() from None
|
||||
self.outpost = outpost
|
||||
query = QueryDict(self.scope["query_string"].decode())
|
||||
self.instance_uid = query.get("instance_uuid", self.channel_name)
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
"""Base Controller"""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
from structlog.stdlib import get_logger
|
||||
from structlog.testing import capture_logs
|
||||
@ -29,7 +28,7 @@ class DeploymentPort:
|
||||
port: int
|
||||
name: str
|
||||
protocol: str
|
||||
inner_port: Optional[int] = None
|
||||
inner_port: int | None = None
|
||||
|
||||
|
||||
class BaseClient:
|
||||
@ -60,7 +59,6 @@ class BaseController:
|
||||
self.logger = get_logger()
|
||||
self.deployment_ports = []
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
def up(self):
|
||||
"""Called by scheduled task to reconcile deployment/service/etc"""
|
||||
raise NotImplementedError
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
"""Docker controller"""
|
||||
|
||||
from time import sleep
|
||||
from typing import Optional
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from django.conf import settings
|
||||
@ -25,12 +24,14 @@ from authentik.outposts.models import (
|
||||
ServiceConnectionInvalid,
|
||||
)
|
||||
|
||||
DOCKER_MAX_ATTEMPTS = 10
|
||||
|
||||
|
||||
class DockerClient(UpstreamDockerClient, BaseClient):
|
||||
"""Custom docker client, which can handle TLS and SSH from a database."""
|
||||
|
||||
tls: Optional[DockerInlineTLS]
|
||||
ssh: Optional[DockerInlineSSH]
|
||||
tls: DockerInlineTLS | None
|
||||
ssh: DockerInlineSSH | None
|
||||
|
||||
def __init__(self, connection: DockerServiceConnection):
|
||||
self.tls = None
|
||||
@ -226,11 +227,10 @@ class DockerController(BaseController):
|
||||
except NotFound:
|
||||
return
|
||||
|
||||
# pylint: disable=too-many-return-statements
|
||||
def up(self, depth=1):
|
||||
if self.outpost.managed == MANAGED_OUTPOST:
|
||||
return None
|
||||
if depth >= 10:
|
||||
if depth >= DOCKER_MAX_ATTEMPTS:
|
||||
raise ControllerException("Giving up since we exceeded recursion limit.")
|
||||
self._migrate_container_name()
|
||||
try:
|
||||
|
||||
@ -2,9 +2,10 @@
|
||||
|
||||
from dataclasses import asdict
|
||||
from json import dumps
|
||||
from typing import TYPE_CHECKING, Generic, Optional, TypeVar
|
||||
from typing import TYPE_CHECKING, Generic, TypeVar
|
||||
|
||||
from dacite.core import from_dict
|
||||
from django.http import HttpResponseNotFound
|
||||
from django.utils.text import slugify
|
||||
from jsonpatch import JsonPatchConflict, JsonPatchException, JsonPatchTestFailed, apply_patch
|
||||
from kubernetes.client import ApiClient, V1ObjectMeta
|
||||
@ -100,7 +101,6 @@ class KubernetesObjectReconciler(Generic[T]):
|
||||
|
||||
return result
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
def up(self):
|
||||
"""Create object if it doesn't exist, update if needed or recreate if needed."""
|
||||
current = None
|
||||
@ -112,8 +112,8 @@ class KubernetesObjectReconciler(Generic[T]):
|
||||
try:
|
||||
current = self.retrieve()
|
||||
except (OpenApiException, HTTPError) as exc:
|
||||
# pylint: disable=no-member
|
||||
if isinstance(exc, ApiException) and exc.status == 404:
|
||||
|
||||
if isinstance(exc, ApiException) and exc.status == HttpResponseNotFound.status_code:
|
||||
self.logger.debug("Failed to get current, triggering recreate")
|
||||
raise NeedsRecreate from exc
|
||||
self.logger.debug("Other unhandled error", exc=exc)
|
||||
@ -124,8 +124,8 @@ class KubernetesObjectReconciler(Generic[T]):
|
||||
self.update(current, reference)
|
||||
self.logger.debug("Updating")
|
||||
except (OpenApiException, HTTPError) as exc:
|
||||
# pylint: disable=no-member
|
||||
if isinstance(exc, ApiException) and exc.status == 422:
|
||||
|
||||
if isinstance(exc, ApiException) and exc.status == 422: # noqa: PLR2004
|
||||
self.logger.debug("Failed to update current, triggering re-create")
|
||||
self._recreate(current=current, reference=reference)
|
||||
return
|
||||
@ -136,7 +136,7 @@ class KubernetesObjectReconciler(Generic[T]):
|
||||
else:
|
||||
self.logger.debug("Object is up-to-date.")
|
||||
|
||||
def _recreate(self, reference: T, current: Optional[T] = None):
|
||||
def _recreate(self, reference: T, current: T | None = None):
|
||||
"""Recreate object"""
|
||||
self.logger.debug("Recreate requested")
|
||||
if current:
|
||||
@ -157,8 +157,8 @@ class KubernetesObjectReconciler(Generic[T]):
|
||||
self.delete(current)
|
||||
self.logger.debug("Removing")
|
||||
except (OpenApiException, HTTPError) as exc:
|
||||
# pylint: disable=no-member
|
||||
if isinstance(exc, ApiException) and exc.status == 404:
|
||||
|
||||
if isinstance(exc, ApiException) and exc.status == HttpResponseNotFound.status_code:
|
||||
self.logger.debug("Failed to get current, assuming non-existent")
|
||||
return
|
||||
self.logger.debug("Other unhandled error", exc=exc)
|
||||
|
||||
@ -25,7 +25,6 @@ class PrometheusServiceMonitorSpecEndpoint:
|
||||
class PrometheusServiceMonitorSpecSelector:
|
||||
"""Prometheus ServiceMonitor selector spec"""
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
matchLabels: dict
|
||||
|
||||
|
||||
@ -34,7 +33,7 @@ class PrometheusServiceMonitorSpec:
|
||||
"""Prometheus ServiceMonitor spec"""
|
||||
|
||||
endpoints: list[PrometheusServiceMonitorSpecEndpoint]
|
||||
# pylint: disable=invalid-name
|
||||
|
||||
selector: PrometheusServiceMonitorSpecSelector
|
||||
|
||||
|
||||
@ -51,7 +50,6 @@ class PrometheusServiceMonitorMetadata:
|
||||
class PrometheusServiceMonitor:
|
||||
"""Prometheus ServiceMonitor"""
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
apiVersion: str
|
||||
kind: str
|
||||
metadata: PrometheusServiceMonitorMetadata
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
"""k8s utils"""
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from kubernetes.client.models.v1_container_port import V1ContainerPort
|
||||
from kubernetes.client.models.v1_service_port import V1ServicePort
|
||||
@ -14,7 +13,7 @@ def get_namespace() -> str:
|
||||
"""Get the namespace if we're running in a pod, otherwise default to default"""
|
||||
path = Path(SERVICE_TOKEN_FILENAME.replace("token", "namespace"))
|
||||
if path.exists():
|
||||
with open(path, "r", encoding="utf8") as _namespace_file:
|
||||
with open(path, encoding="utf8") as _namespace_file:
|
||||
return _namespace_file.read()
|
||||
return "default"
|
||||
|
||||
@ -39,8 +38,8 @@ def compare_port(
|
||||
|
||||
|
||||
def compare_ports(
|
||||
current: Optional[list[V1ServicePort | V1ContainerPort]],
|
||||
reference: Optional[list[V1ServicePort | V1ContainerPort]],
|
||||
current: list[V1ServicePort | V1ContainerPort] | None,
|
||||
reference: list[V1ServicePort | V1ContainerPort] | None,
|
||||
):
|
||||
"""Compare ports of a list"""
|
||||
if not current or not reference:
|
||||
|
||||
@ -81,7 +81,7 @@ class DockerInlineSSH:
|
||||
"""Cleanup when we're done"""
|
||||
try:
|
||||
os.unlink(self.key_path)
|
||||
with open(self.config_path, "r", encoding="utf-8") as ssh_config:
|
||||
with open(self.config_path, encoding="utf-8") as ssh_config:
|
||||
start = 0
|
||||
end = 0
|
||||
lines = ssh_config.readlines()
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
from os import unlink
|
||||
from pathlib import Path
|
||||
from tempfile import gettempdir
|
||||
from typing import Optional
|
||||
|
||||
from docker.tls import TLSConfig
|
||||
|
||||
@ -13,15 +12,15 @@ from authentik.crypto.models import CertificateKeyPair
|
||||
class DockerInlineTLS:
|
||||
"""Create Docker TLSConfig from CertificateKeyPair"""
|
||||
|
||||
verification_kp: Optional[CertificateKeyPair]
|
||||
authentication_kp: Optional[CertificateKeyPair]
|
||||
verification_kp: CertificateKeyPair | None
|
||||
authentication_kp: CertificateKeyPair | None
|
||||
|
||||
_paths: list[str]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
verification_kp: Optional[CertificateKeyPair],
|
||||
authentication_kp: Optional[CertificateKeyPair],
|
||||
verification_kp: CertificateKeyPair | None,
|
||||
authentication_kp: CertificateKeyPair | None,
|
||||
) -> None:
|
||||
self.verification_kp = verification_kp
|
||||
self.authentication_kp = authentication_kp
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
"""Outpost models"""
|
||||
|
||||
from collections.abc import Iterable
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from datetime import datetime
|
||||
from typing import Any, Iterable, Optional
|
||||
from typing import Any
|
||||
from uuid import uuid4
|
||||
|
||||
from dacite.core import from_dict
|
||||
@ -49,7 +50,6 @@ class ServiceConnectionInvalid(SentryIgnoredException):
|
||||
|
||||
|
||||
@dataclass
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
class OutpostConfig:
|
||||
"""Configuration an outpost uses to configure it self"""
|
||||
|
||||
@ -62,21 +62,21 @@ class OutpostConfig:
|
||||
log_level: str = CONFIG.get("log_level")
|
||||
object_naming_template: str = field(default="ak-outpost-%(name)s")
|
||||
|
||||
container_image: Optional[str] = field(default=None)
|
||||
container_image: str | None = field(default=None)
|
||||
|
||||
docker_network: Optional[str] = field(default=None)
|
||||
docker_network: str | None = field(default=None)
|
||||
docker_map_ports: bool = field(default=True)
|
||||
docker_labels: Optional[dict[str, str]] = field(default=None)
|
||||
docker_labels: dict[str, str] | None = field(default=None)
|
||||
|
||||
kubernetes_replicas: int = field(default=1)
|
||||
kubernetes_namespace: str = field(default_factory=get_namespace)
|
||||
kubernetes_ingress_annotations: dict[str, str] = field(default_factory=dict)
|
||||
kubernetes_ingress_secret_name: str = field(default="authentik-outpost-tls")
|
||||
kubernetes_ingress_class_name: Optional[str] = field(default=None)
|
||||
kubernetes_ingress_class_name: str | None = field(default=None)
|
||||
kubernetes_service_type: str = field(default="ClusterIP")
|
||||
kubernetes_disabled_components: list[str] = field(default_factory=list)
|
||||
kubernetes_image_pull_secrets: list[str] = field(default_factory=list)
|
||||
kubernetes_json_patches: Optional[dict[str, list[dict[str, Any]]]] = field(default=None)
|
||||
kubernetes_json_patches: dict[str, list[dict[str, Any]]] | None = field(default=None)
|
||||
|
||||
|
||||
class OutpostModel(Model):
|
||||
@ -99,7 +99,7 @@ class OutpostType(models.TextChoices):
|
||||
RAC = "rac"
|
||||
|
||||
|
||||
def default_outpost_config(host: Optional[str] = None):
|
||||
def default_outpost_config(host: str | None = None):
|
||||
"""Get default outpost config"""
|
||||
return asdict(OutpostConfig(authentik_host=host or ""))
|
||||
|
||||
@ -127,6 +127,13 @@ class OutpostServiceConnection(models.Model):
|
||||
|
||||
objects = InheritanceManager()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Outpost Service-Connection")
|
||||
verbose_name_plural = _("Outpost Service-Connections")
|
||||
|
||||
def __str__(self) -> __version__:
|
||||
return f"Outpost service connection {self.name}"
|
||||
|
||||
@property
|
||||
def state_key(self) -> str:
|
||||
"""Key used to save connection state in cache"""
|
||||
@ -150,10 +157,6 @@ class OutpostServiceConnection(models.Model):
|
||||
# since the response doesn't use the correct inheritance
|
||||
return ""
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Outpost Service-Connection")
|
||||
verbose_name_plural = _("Outpost Service-Connections")
|
||||
|
||||
|
||||
class DockerServiceConnection(SerializerModel, OutpostServiceConnection):
|
||||
"""Service Connection to a Docker endpoint"""
|
||||
@ -188,6 +191,13 @@ class DockerServiceConnection(SerializerModel, OutpostServiceConnection):
|
||||
),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Docker Service-Connection")
|
||||
verbose_name_plural = _("Docker Service-Connections")
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"Docker Service-Connection {self.name}"
|
||||
|
||||
@property
|
||||
def serializer(self) -> Serializer:
|
||||
from authentik.outposts.api.service_connections import DockerServiceConnectionSerializer
|
||||
@ -198,13 +208,6 @@ class DockerServiceConnection(SerializerModel, OutpostServiceConnection):
|
||||
def component(self) -> str:
|
||||
return "ak-service-connection-docker-form"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"Docker Service-Connection {self.name}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Docker Service-Connection")
|
||||
verbose_name_plural = _("Docker Service-Connections")
|
||||
|
||||
|
||||
class KubernetesServiceConnection(SerializerModel, OutpostServiceConnection):
|
||||
"""Service Connection to a Kubernetes cluster"""
|
||||
@ -220,6 +223,13 @@ class KubernetesServiceConnection(SerializerModel, OutpostServiceConnection):
|
||||
default=True, help_text=_("Verify SSL Certificates of the Kubernetes API endpoint")
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Kubernetes Service-Connection")
|
||||
verbose_name_plural = _("Kubernetes Service-Connections")
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"Kubernetes Service-Connection {self.name}"
|
||||
|
||||
@property
|
||||
def serializer(self) -> Serializer:
|
||||
from authentik.outposts.api.service_connections import KubernetesServiceConnectionSerializer
|
||||
@ -230,13 +240,6 @@ class KubernetesServiceConnection(SerializerModel, OutpostServiceConnection):
|
||||
def component(self) -> str:
|
||||
return "ak-service-connection-kubernetes-form"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"Kubernetes Service-Connection {self.name}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Kubernetes Service-Connection")
|
||||
verbose_name_plural = _("Kubernetes Service-Connections")
|
||||
|
||||
|
||||
class Outpost(SerializerModel, ManagedModel):
|
||||
"""Outpost instance which manages a service user and token"""
|
||||
@ -427,14 +430,14 @@ class OutpostState:
|
||||
"""Outpost instance state, last_seen and version"""
|
||||
|
||||
uid: str
|
||||
last_seen: Optional[datetime] = field(default=None)
|
||||
version: Optional[str] = field(default=None)
|
||||
last_seen: datetime | None = field(default=None)
|
||||
version: str | None = field(default=None)
|
||||
version_should: Version = field(default=OUR_VERSION)
|
||||
build_hash: str = field(default="")
|
||||
hostname: str = field(default="")
|
||||
args: dict = field(default_factory=dict)
|
||||
|
||||
_outpost: Optional[Outpost] = field(default=None)
|
||||
_outpost: Outpost | None = field(default=None)
|
||||
|
||||
@property
|
||||
def version_outdated(self) -> bool:
|
||||
@ -467,7 +470,7 @@ class OutpostState:
|
||||
cache.delete(key)
|
||||
data = default_data
|
||||
state = from_dict(OutpostState, data)
|
||||
# pylint: disable=protected-access
|
||||
|
||||
state._outpost = outpost
|
||||
return state
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
from os import R_OK, access
|
||||
from pathlib import Path
|
||||
from socket import gethostname
|
||||
from typing import Any, Optional
|
||||
from typing import Any
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from asgiref.sync import async_to_sync
|
||||
@ -49,8 +49,7 @@ LOGGER = get_logger()
|
||||
CACHE_KEY_OUTPOST_DOWN = "goauthentik.io/outposts/teardown/%s"
|
||||
|
||||
|
||||
# pylint: disable=too-many-return-statements
|
||||
def controller_for_outpost(outpost: Outpost) -> Optional[type[BaseController]]:
|
||||
def controller_for_outpost(outpost: Outpost) -> type[BaseController] | None:
|
||||
"""Get a controller for the outpost, when a service connection is defined"""
|
||||
if not outpost.service_connection:
|
||||
return None
|
||||
@ -195,7 +194,7 @@ def outpost_post_save(model_class: str, model_pk: Any):
|
||||
LOGGER.debug("Trigger reconcile for outpost", instance=instance)
|
||||
outpost_controller.delay(str(instance.pk))
|
||||
|
||||
if isinstance(instance, (OutpostModel, Outpost)):
|
||||
if isinstance(instance, OutpostModel | Outpost):
|
||||
LOGGER.debug("triggering outpost update from outpostmodel/outpost", instance=instance)
|
||||
outpost_send_update(instance)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user