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,
|
uid=self.pk,
|
||||||
args=(self.pk,),
|
args=(self.pk,),
|
||||||
crontab="3-59/15 * * * *",
|
crontab="3-59/15 * * * *",
|
||||||
|
send_on_save=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -325,6 +326,7 @@ class Outpost(ScheduledModel, SerializerModel, ManagedModel):
|
|||||||
args=(self.pk,),
|
args=(self.pk,),
|
||||||
kwargs={"action": "up", "from_cache": False},
|
kwargs={"action": "up", "from_cache": False},
|
||||||
crontab=f"{fqdn_rand('outpost_controller')} */4 * * *",
|
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.core.models import AuthenticatedSession, Provider
|
||||||
from authentik.crypto.models import CertificateKeyPair
|
from authentik.crypto.models import CertificateKeyPair
|
||||||
from authentik.lib.utils.reflection import class_to_path
|
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 (
|
from authentik.outposts.tasks import (
|
||||||
CACHE_KEY_OUTPOST_DOWN,
|
CACHE_KEY_OUTPOST_DOWN,
|
||||||
outpost_controller,
|
outpost_controller,
|
||||||
|
outpost_send_update,
|
||||||
outpost_session_end,
|
outpost_session_end,
|
||||||
outposts_and_related_update_dispatch,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
@ -45,28 +45,58 @@ def outpost_pre_save(sender, instance: Outpost, **_):
|
|||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=Outpost.providers.through)
|
@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"""
|
"""Update outpost on m2m change, when providers are added or removed"""
|
||||||
if action in ["post_add", "post_remove", "post_clear"]:
|
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, **_):
|
@receiver(post_save, sender=Outpost)
|
||||||
"""If an Outpost is saved, Ensure that token is created/updated
|
def outpost_post_save(sender, instance: Outpost, created: bool, **_):
|
||||||
|
if created:
|
||||||
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:
|
|
||||||
LOGGER.info("New outpost saved, ensuring initial token and user are created")
|
LOGGER.info("New outpost saved, ensuring initial token and user are created")
|
||||||
_ = instance.token
|
_ = 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)
|
def outpost_related_post_save(sender, instance: OutpostServiceConnection | OutpostModel, **_):
|
||||||
post_save.connect(outposts_and_related_post_save, sender=OutpostServiceConnection, weak=False)
|
for outpost in instance.outpost_set.all():
|
||||||
post_save.connect(outposts_and_related_post_save, sender=Provider, weak=False)
|
outpost_send_update.send_with_options(args=(outpost.pk,), rel_obj=outpost)
|
||||||
post_save.connect(outposts_and_related_post_save, sender=CertificateKeyPair, weak=False)
|
|
||||||
post_save.connect(outposts_and_related_post_save, sender=Brand, weak=False)
|
|
||||||
|
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)
|
@receiver(pre_delete, sender=Outpost)
|
||||||
|
|||||||
@ -153,65 +153,6 @@ def outpost_token_ensurer():
|
|||||||
self.info(f"Successfully checked {len(all_outposts)} Outposts.")
|
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"))
|
@actor(description=_("Send update to outpost"))
|
||||||
def outpost_send_update(pk: Any):
|
def outpost_send_update(pk: Any):
|
||||||
"""Update outpost instance"""
|
"""Update outpost instance"""
|
||||||
|
|||||||
@ -18,6 +18,7 @@ from authentik.events.models import Event, EventAction
|
|||||||
from authentik.lib.models import SerializerModel
|
from authentik.lib.models import SerializerModel
|
||||||
from authentik.lib.utils.time import timedelta_string_validator
|
from authentik.lib.utils.time import timedelta_string_validator
|
||||||
from authentik.policies.models import PolicyBindingModel
|
from authentik.policies.models import PolicyBindingModel
|
||||||
|
from authentik.outposts.models import OutpostModel
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ class AuthenticationMode(models.TextChoices):
|
|||||||
PROMPT = "prompt"
|
PROMPT = "prompt"
|
||||||
|
|
||||||
|
|
||||||
class RACProvider(Provider):
|
class RACProvider(OutpostModel, Provider):
|
||||||
"""Remotely access computers/servers via RDP/SSH/VNC."""
|
"""Remotely access computers/servers via RDP/SSH/VNC."""
|
||||||
|
|
||||||
settings = models.JSONField(default=dict)
|
settings = models.JSONField(default=dict)
|
||||||
|
|||||||
Reference in New Issue
Block a user