outposts: make state more consistent (#5403)

This commit is contained in:
Jens L 2023-04-28 13:53:07 +03:00 committed by GitHub
parent 01663468de
commit 9d1ad104ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 13 additions and 11 deletions

View File

@ -128,7 +128,7 @@ class OutpostServiceConnection(models.Model):
@property @property
def state_key(self) -> str: def state_key(self) -> str:
"""Key used to save connection state in cache""" """Key used to save connection state in cache"""
return f"outpost_service_connection_{self.pk.hex}" return f"goauthentik.io/outposts/service_connection_state/{self.pk.hex}"
@property @property
def state(self) -> OutpostServiceConnectionState: def state(self) -> OutpostServiceConnectionState:
@ -278,7 +278,7 @@ class Outpost(SerializerModel, ManagedModel):
@property @property
def state_cache_prefix(self) -> str: def state_cache_prefix(self) -> str:
"""Key by which the outposts status is saved""" """Key by which the outposts status is saved"""
return f"goauthentik.io/outposts/{self.uuid.hex}_state" return f"goauthentik.io/outposts/state/{self.uuid.hex}"
@property @property
def state(self) -> list["OutpostState"]: def state(self) -> list["OutpostState"]:
@ -433,19 +433,19 @@ class OutpostState:
@staticmethod @staticmethod
def for_outpost(outpost: Outpost) -> list["OutpostState"]: def for_outpost(outpost: Outpost) -> list["OutpostState"]:
"""Get all states for an outpost""" """Get all states for an outpost"""
keys = cache.keys(f"{outpost.state_cache_prefix}_*") keys = cache.keys(f"{outpost.state_cache_prefix}/*")
if not keys: if not keys:
return [] return []
states = [] states = []
for key in keys: for key in keys:
instance_uid = key.replace(f"{outpost.state_cache_prefix}_", "") instance_uid = key.replace(f"{outpost.state_cache_prefix}/", "")
states.append(OutpostState.for_instance_uid(outpost, instance_uid)) states.append(OutpostState.for_instance_uid(outpost, instance_uid))
return states return states
@staticmethod @staticmethod
def for_instance_uid(outpost: Outpost, uid: str) -> "OutpostState": def for_instance_uid(outpost: Outpost, uid: str) -> "OutpostState":
"""Get state for a single instance""" """Get state for a single instance"""
key = f"{outpost.state_cache_prefix}_{uid}" key = f"{outpost.state_cache_prefix}/{uid}"
default_data = {"uid": uid, "channel_ids": []} default_data = {"uid": uid, "channel_ids": []}
data = cache.get(key, default_data) data = cache.get(key, default_data)
if isinstance(data, str): if isinstance(data, str):
@ -458,10 +458,10 @@ class OutpostState:
def save(self, timeout=OUTPOST_HELLO_INTERVAL): def save(self, timeout=OUTPOST_HELLO_INTERVAL):
"""Save current state to cache""" """Save current state to cache"""
full_key = f"{self._outpost.state_cache_prefix}_{self.uid}" full_key = f"{self._outpost.state_cache_prefix}/{self.uid}"
return cache.set(full_key, asdict(self), timeout=timeout) return cache.set(full_key, asdict(self), timeout=timeout)
def delete(self): def delete(self):
"""Manually delete from cache, used on channel disconnect""" """Manually delete from cache, used on channel disconnect"""
full_key = f"{self._outpost.state_cache_prefix}_{self.uid}" full_key = f"{self._outpost.state_cache_prefix}/{self.uid}"
cache.delete(full_key) cache.delete(full_key)

View File

@ -45,7 +45,7 @@ from authentik.providers.proxy.controllers.kubernetes import ProxyKubernetesCont
from authentik.root.celery import CELERY_APP from authentik.root.celery import CELERY_APP
LOGGER = get_logger() LOGGER = get_logger()
CACHE_KEY_OUTPOST_DOWN = "outpost_teardown_%s" CACHE_KEY_OUTPOST_DOWN = "goauthentik.io/outposts/teardown/%s"
def controller_for_outpost(outpost: Outpost) -> Optional[type[BaseController]]: def controller_for_outpost(outpost: Outpost) -> Optional[type[BaseController]]:
@ -148,6 +148,8 @@ def outpost_controller(
except (ControllerException, ServiceConnectionInvalid) as exc: except (ControllerException, ServiceConnectionInvalid) as exc:
self.set_status(TaskResult(TaskResultStatus.ERROR).with_error(exc)) self.set_status(TaskResult(TaskResultStatus.ERROR).with_error(exc))
else: else:
if from_cache:
cache.delete(CACHE_KEY_OUTPOST_DOWN % outpost_pk)
self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL, logs)) self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL, logs))

View File

@ -208,7 +208,7 @@ class TestProviderProxyConnect(ChannelsLiveServerTestCase):
"""Test proxy connectivity over websocket""" """Test proxy connectivity over websocket"""
outpost_connection_discovery() # pylint: disable=no-value-for-parameter outpost_connection_discovery() # pylint: disable=no-value-for-parameter
proxy: ProxyProvider = ProxyProvider.objects.create( proxy: ProxyProvider = ProxyProvider.objects.create(
name="proxy_provider", name=generate_id(),
authorization_flow=Flow.objects.get( authorization_flow=Flow.objects.get(
slug="default-provider-authorization-implicit-consent" slug="default-provider-authorization-implicit-consent"
), ),
@ -222,7 +222,7 @@ class TestProviderProxyConnect(ChannelsLiveServerTestCase):
Application.objects.create(name="proxy", slug="proxy", provider=proxy) Application.objects.create(name="proxy", slug="proxy", provider=proxy)
service_connection = DockerServiceConnection.objects.get(local=True) service_connection = DockerServiceConnection.objects.get(local=True)
outpost: Outpost = Outpost.objects.create( outpost: Outpost = Outpost.objects.create(
name="proxy_outpost", name=generate_id(),
type=OutpostType.PROXY, type=OutpostType.PROXY,
service_connection=service_connection, service_connection=service_connection,
_config=asdict(OutpostConfig(authentik_host=self.live_server_url, log_level="debug")), _config=asdict(OutpostConfig(authentik_host=self.live_server_url, log_level="debug")),
@ -241,7 +241,7 @@ class TestProviderProxyConnect(ChannelsLiveServerTestCase):
sleep(0.5) sleep(0.5)
state = outpost.state state = outpost.state
self.assertEqual(len(state), 1) self.assertGreaterEqual(len(state), 1)
# Make sure to delete the outpost to remove the container # Make sure to delete the outpost to remove the container
outpost.delete() outpost.delete()