simplify outpost signals
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
This commit is contained in:
@ -173,6 +173,7 @@ class OutpostServiceConnection(ScheduledModel, models.Model):
|
||||
uid=self.pk,
|
||||
args=(self.pk,),
|
||||
crontab="3-59/15 * * * *",
|
||||
send_on_save=True,
|
||||
),
|
||||
]
|
||||
|
||||
@ -325,6 +326,7 @@ class Outpost(ScheduledModel, SerializerModel, ManagedModel):
|
||||
args=(self.pk,),
|
||||
kwargs={"action": "up", "from_cache": False},
|
||||
crontab=f"{fqdn_rand('outpost_controller')} */4 * * *",
|
||||
send_on_save=True,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@ -10,12 +10,12 @@ from authentik.brands.models import Brand
|
||||
from authentik.core.models import AuthenticatedSession, Provider
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
from authentik.lib.utils.reflection import class_to_path
|
||||
from authentik.outposts.models import Outpost, OutpostServiceConnection
|
||||
from authentik.outposts.models import Outpost, OutpostModel, OutpostServiceConnection
|
||||
from authentik.outposts.tasks import (
|
||||
CACHE_KEY_OUTPOST_DOWN,
|
||||
outpost_controller,
|
||||
outpost_send_update,
|
||||
outpost_session_end,
|
||||
outposts_and_related_update_dispatch,
|
||||
)
|
||||
|
||||
LOGGER = get_logger()
|
||||
@ -45,28 +45,58 @@ def outpost_pre_save(sender, instance: Outpost, **_):
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=Outpost.providers.through)
|
||||
def outpost_m2m_changed(sender, instance: Model, action: str, **_):
|
||||
def outpost_m2m_changed(sender, instance: Provider, action: str, **_):
|
||||
"""Update outpost on m2m change, when providers are added or removed"""
|
||||
if action in ["post_add", "post_remove", "post_clear"]:
|
||||
outposts_and_related_update_dispatch.send(class_to_path(instance.__class__), instance.pk)
|
||||
if not isinstance(instance, OutpostModel):
|
||||
return
|
||||
for outpost in instance.outpost_set.all():
|
||||
outpost_send_update.send_with_options(args=(outpost.pk,), rel_obj=outpost)
|
||||
|
||||
|
||||
def outposts_and_related_post_save(sender, instance: Model, created: bool, **_):
|
||||
"""If an Outpost is saved, Ensure that token is created/updated
|
||||
|
||||
If an OutpostModel, or a model that is somehow connected to an OutpostModel is saved,
|
||||
we send a message down the relevant OutpostModels WS connection to trigger an update"""
|
||||
if isinstance(instance, Outpost) and created:
|
||||
@receiver(post_save, sender=Outpost)
|
||||
def outpost_post_save(sender, instance: Outpost, created: bool, **_):
|
||||
if created:
|
||||
LOGGER.info("New outpost saved, ensuring initial token and user are created")
|
||||
_ = instance.token
|
||||
outposts_and_related_update_dispatch.send(class_to_path(instance.__class__), instance.pk)
|
||||
outpost_send_update.send_with_options(args=(instance.pk,), rel_obj=instance)
|
||||
|
||||
|
||||
post_save.connect(outposts_and_related_post_save, sender=Outpost, weak=False)
|
||||
post_save.connect(outposts_and_related_post_save, sender=OutpostServiceConnection, weak=False)
|
||||
post_save.connect(outposts_and_related_post_save, sender=Provider, weak=False)
|
||||
post_save.connect(outposts_and_related_post_save, sender=CertificateKeyPair, weak=False)
|
||||
post_save.connect(outposts_and_related_post_save, sender=Brand, weak=False)
|
||||
def outpost_related_post_save(sender, instance: OutpostServiceConnection | OutpostModel, **_):
|
||||
for outpost in instance.outpost_set.all():
|
||||
outpost_send_update.send_with_options(args=(outpost.pk,), rel_obj=outpost)
|
||||
|
||||
|
||||
post_save.connect(outpost_related_post_save, sender=OutpostServiceConnection, weak=False)
|
||||
post_save.connect(outpost_related_post_save, sender=OutpostModel, weak=False)
|
||||
|
||||
|
||||
def outpost_reverse_related_post_save(sender, instance: CertificateKeyPair | Brand, **_):
|
||||
for field in instance._meta.get_fields():
|
||||
# Each field is checked if it has a `related_model` attribute (when ForeginKeys or M2Ms)
|
||||
# are used, and if it has a value
|
||||
if not hasattr(field, "related_model"):
|
||||
continue
|
||||
if not field.related_model:
|
||||
continue
|
||||
if not issubclass(field.related_model, OutpostModel):
|
||||
continue
|
||||
|
||||
field_name = f"{field.name}_set"
|
||||
if not hasattr(instance, field_name):
|
||||
continue
|
||||
|
||||
LOGGER.debug("triggering outpost update from field", field=field.name)
|
||||
# Because the Outpost Model has an M2M to Provider,
|
||||
# we have to iterate over the entire QS
|
||||
for reverse in getattr(instance, field_name).all():
|
||||
if isinstance(reverse, OutpostModel):
|
||||
for outpost in reverse.outpost_set.all():
|
||||
outpost_send_update.send_with_options(args=(outpost.pk,), rel_obj=outpost)
|
||||
|
||||
|
||||
post_save.connect(outpost_reverse_related_post_save, sender=Brand, weak=False)
|
||||
post_save.connect(outpost_reverse_related_post_save, sender=CertificateKeyPair, weak=False)
|
||||
|
||||
|
||||
@receiver(pre_delete, sender=Outpost)
|
||||
|
||||
@ -153,65 +153,6 @@ def outpost_token_ensurer():
|
||||
self.info(f"Successfully checked {len(all_outposts)} Outposts.")
|
||||
|
||||
|
||||
@actor(description=_("Dispatch tasks to update outposts when related objects are updated."))
|
||||
def outposts_and_related_update_dispatch(model_class: str, pk: Any):
|
||||
"""If an Outpost is saved, Ensure that token is created/updated
|
||||
|
||||
If an OutpostModel, or a model that is somehow connected to an OutpostModel is saved,
|
||||
we send a message down the relevant OutpostModels WS connection to trigger an update"""
|
||||
|
||||
model: Model = path_to_class(model_class)
|
||||
try:
|
||||
instance = model.objects.get(pk=pk)
|
||||
except model.DoesNotExist:
|
||||
LOGGER.warning("Model does not exist", model=model, pk=pk)
|
||||
return
|
||||
|
||||
if isinstance(instance, Outpost):
|
||||
LOGGER.debug("Trigger reconcile for outpost", instance=instance)
|
||||
for schedule in instance.schedules.all():
|
||||
schedule.send()
|
||||
|
||||
if isinstance(instance, OutpostModel | Outpost):
|
||||
LOGGER.debug("triggering outpost update from outpostmodel/outpost", instance=instance)
|
||||
outposts_and_related_send_update(instance)
|
||||
|
||||
if isinstance(instance, OutpostServiceConnection):
|
||||
LOGGER.debug("triggering ServiceConnection state update", instance=instance)
|
||||
for schedule in instance.schedules.all():
|
||||
schedule.send()
|
||||
|
||||
for field in instance._meta.get_fields():
|
||||
# Each field is checked if it has a `related_model` attribute (when ForeginKeys or M2Ms)
|
||||
# are used, and if it has a value
|
||||
if not hasattr(field, "related_model"):
|
||||
continue
|
||||
if not field.related_model:
|
||||
continue
|
||||
if not issubclass(field.related_model, OutpostModel):
|
||||
continue
|
||||
|
||||
field_name = f"{field.name}_set"
|
||||
if not hasattr(instance, field_name):
|
||||
continue
|
||||
|
||||
LOGGER.debug("triggering outpost update from field", field=field.name)
|
||||
# Because the Outpost Model has an M2M to Provider,
|
||||
# we have to iterate over the entire QS
|
||||
for reverse in getattr(instance, field_name).all():
|
||||
outposts_and_related_send_update(reverse)
|
||||
|
||||
|
||||
def outposts_and_related_send_update(model_instance: Model):
|
||||
"""Send outpost update to all related outposts"""
|
||||
if isinstance(model_instance, OutpostModel):
|
||||
for outpost in model_instance.outpost_set.all():
|
||||
outpost_send_update.send_with_options(args=(outpost.pk,), rel_obj=outpost)
|
||||
elif isinstance(model_instance, Outpost):
|
||||
outpost = model_instance
|
||||
outpost_send_update.send_with_options(args=(outpost.pk,), rel_obj=outpost)
|
||||
|
||||
|
||||
@actor(description=_("Send update to outpost"))
|
||||
def outpost_send_update(pk: Any):
|
||||
"""Update outpost instance"""
|
||||
|
||||
@ -18,6 +18,7 @@ from authentik.events.models import Event, EventAction
|
||||
from authentik.lib.models import SerializerModel
|
||||
from authentik.lib.utils.time import timedelta_string_validator
|
||||
from authentik.policies.models import PolicyBindingModel
|
||||
from authentik.outposts.models import OutpostModel
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
@ -37,7 +38,7 @@ class AuthenticationMode(models.TextChoices):
|
||||
PROMPT = "prompt"
|
||||
|
||||
|
||||
class RACProvider(Provider):
|
||||
class RACProvider(OutpostModel, Provider):
|
||||
"""Remotely access computers/servers via RDP/SSH/VNC."""
|
||||
|
||||
settings = models.JSONField(default=dict)
|
||||
|
||||
Reference in New Issue
Block a user