core: fix backup task not being registered, add fallback for api to remove info on ImportError
celery only discovers tasks from installed apps, which `lib` is not, hence the schedule didn't trigger it
This commit is contained in:
parent
a5197963b2
commit
f3098418f2
|
@ -50,15 +50,23 @@ class TaskViewSet(ViewSet):
|
||||||
task = TaskInfo.by_name(pk)
|
task = TaskInfo.by_name(pk)
|
||||||
if not task:
|
if not task:
|
||||||
raise Http404
|
raise Http404
|
||||||
|
try:
|
||||||
task_module = import_module(task.task_call_module)
|
task_module = import_module(task.task_call_module)
|
||||||
task_func = getattr(task_module, task.task_call_func)
|
task_func = getattr(task_module, task.task_call_func)
|
||||||
task_func.delay(*task.task_call_args, **task.task_call_kwargs)
|
task_func.delay(*task.task_call_args, **task.task_call_kwargs)
|
||||||
messages.success(
|
messages.success(
|
||||||
self.request,
|
self.request,
|
||||||
_("Successfully re-scheduled Task %(name)s!" % {"name": task.task_name}),
|
_(
|
||||||
|
"Successfully re-scheduled Task %(name)s!"
|
||||||
|
% {"name": task.task_name}
|
||||||
|
),
|
||||||
)
|
)
|
||||||
return Response(
|
return Response(
|
||||||
{
|
{
|
||||||
"successful": True,
|
"successful": True,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
except ImportError:
|
||||||
|
# if we get an import error, the module path has probably changed
|
||||||
|
task.delete()
|
||||||
|
return Response({"successful": False})
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<tr role="row">
|
<tr role="row">
|
||||||
<th role="columnheader" scope="col">{% trans 'Identifier' %}</th>
|
<th role="columnheader" scope="col">{% trans 'Identifier' %}</th>
|
||||||
<th role="columnheader" scope="col">{% trans 'Description' %}</th>
|
<th role="columnheader" scope="col">{% trans 'Description' %}</th>
|
||||||
<th role="columnheader" scope="col">{% trans 'Last Status' %}</th>
|
<th role="columnheader" scope="col">{% trans 'Last Run' %}</th>
|
||||||
<th role="columnheader" scope="col">{% trans 'Status' %}</th>
|
<th role="columnheader" scope="col">{% trans 'Status' %}</th>
|
||||||
<th role="columnheader" scope="col">{% trans 'Messages' %}</th>
|
<th role="columnheader" scope="col">{% trans 'Messages' %}</th>
|
||||||
<th role="cell"></th>
|
<th role="cell"></th>
|
||||||
|
|
|
@ -68,6 +68,9 @@ router.register("core/tokens", TokenViewSet)
|
||||||
router.register("outposts/outposts", OutpostViewSet)
|
router.register("outposts/outposts", OutpostViewSet)
|
||||||
router.register("outposts/proxy", OutpostConfigViewSet)
|
router.register("outposts/proxy", OutpostConfigViewSet)
|
||||||
|
|
||||||
|
router.register("flows/instances", FlowViewSet)
|
||||||
|
router.register("flows/bindings", FlowStageBindingViewSet)
|
||||||
|
|
||||||
router.register("crypto/certificatekeypairs", CertificateKeyPairViewSet)
|
router.register("crypto/certificatekeypairs", CertificateKeyPairViewSet)
|
||||||
|
|
||||||
router.register("audit/events", EventViewSet)
|
router.register("audit/events", EventViewSet)
|
||||||
|
@ -114,9 +117,6 @@ router.register("stages/user_login", UserLoginStageViewSet)
|
||||||
router.register("stages/user_logout", UserLogoutStageViewSet)
|
router.register("stages/user_logout", UserLogoutStageViewSet)
|
||||||
router.register("stages/user_write", UserWriteStageViewSet)
|
router.register("stages/user_write", UserWriteStageViewSet)
|
||||||
|
|
||||||
router.register("flows/instances", FlowViewSet)
|
|
||||||
router.register("flows/bindings", FlowStageBindingViewSet)
|
|
||||||
|
|
||||||
router.register("stages/dummy", DummyStageViewSet)
|
router.register("stages/dummy", DummyStageViewSet)
|
||||||
router.register("policies/dummy", DummyPolicyViewSet)
|
router.register("policies/dummy", DummyPolicyViewSet)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
"""passbook core tasks"""
|
"""passbook core tasks"""
|
||||||
|
from datetime import datetime
|
||||||
|
from io import StringIO
|
||||||
|
|
||||||
|
from boto3.exceptions import Boto3Error
|
||||||
|
from botocore.exceptions import BotoCoreError, ClientError
|
||||||
|
from django.contrib.humanize.templatetags.humanize import naturaltime
|
||||||
|
from django.core import management
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from structlog import get_logger
|
from structlog import get_logger
|
||||||
|
|
||||||
|
@ -24,3 +31,24 @@ def clean_expired_models(self: MonitoredTask):
|
||||||
LOGGER.debug("Deleted expired models", model=cls, amount=amount)
|
LOGGER.debug("Deleted expired models", model=cls, amount=amount)
|
||||||
messages.append(f"Deleted {amount} expired {cls._meta.verbose_name_plural}")
|
messages.append(f"Deleted {amount} expired {cls._meta.verbose_name_plural}")
|
||||||
self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL, messages))
|
self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL, messages))
|
||||||
|
|
||||||
|
|
||||||
|
@CELERY_APP.task(bind=True, base=MonitoredTask)
|
||||||
|
def backup_database(self: MonitoredTask): # pragma: no cover
|
||||||
|
"""Database backup"""
|
||||||
|
try:
|
||||||
|
start = datetime.now()
|
||||||
|
out = StringIO()
|
||||||
|
management.call_command("dbbackup", quiet=True, stdout=out)
|
||||||
|
self.set_status(
|
||||||
|
TaskResult(
|
||||||
|
TaskResultStatus.SUCCESSFUL,
|
||||||
|
[
|
||||||
|
f"Successfully finished database backup {naturaltime(start)}",
|
||||||
|
out.getvalue(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
LOGGER.info("Successfully backed up database.")
|
||||||
|
except (IOError, BotoCoreError, ClientError, Boto3Error) as exc:
|
||||||
|
self.set_status(TaskResult(TaskResultStatus.ERROR).with_error(exc))
|
||||||
|
|
|
@ -62,6 +62,10 @@ class TaskInfo:
|
||||||
"""Get TaskInfo Object by name"""
|
"""Get TaskInfo Object by name"""
|
||||||
return cache.get(f"task_{name}")
|
return cache.get(f"task_{name}")
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
"""Delete task info from cache"""
|
||||||
|
return cache.delete(f"task_{self.task_name}")
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""Save task into cache"""
|
"""Save task into cache"""
|
||||||
key = f"task_{self.task_name}"
|
key = f"task_{self.task_name}"
|
|
@ -1,34 +0,0 @@
|
||||||
"""Database backup task"""
|
|
||||||
from datetime import datetime
|
|
||||||
from io import StringIO
|
|
||||||
|
|
||||||
from botocore.exceptions import BotoCoreError, ClientError
|
|
||||||
from django.contrib.humanize.templatetags.humanize import naturaltime
|
|
||||||
from django.core import management
|
|
||||||
from structlog import get_logger
|
|
||||||
|
|
||||||
from passbook.lib.tasks import MonitoredTask, TaskResult, TaskResultStatus
|
|
||||||
from passbook.root.celery import CELERY_APP
|
|
||||||
|
|
||||||
LOGGER = get_logger()
|
|
||||||
|
|
||||||
|
|
||||||
@CELERY_APP.task(bind=True, base=MonitoredTask)
|
|
||||||
def backup_database(self: MonitoredTask): # pragma: no cover
|
|
||||||
"""Database backup"""
|
|
||||||
try:
|
|
||||||
start = datetime.now()
|
|
||||||
out = StringIO()
|
|
||||||
management.call_command("dbbackup", quiet=True, stdout=out)
|
|
||||||
self.set_status(
|
|
||||||
TaskResult(
|
|
||||||
TaskResultStatus.SUCCESSFUL,
|
|
||||||
[
|
|
||||||
f"Successfully finished database backup {naturaltime(start)}",
|
|
||||||
out.getvalue(),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
LOGGER.info("Successfully backed up database.")
|
|
||||||
except (IOError, BotoCoreError, ClientError) as exc:
|
|
||||||
self.set_status(TaskResult(TaskResultStatus.ERROR).with_error(exc))
|
|
|
@ -273,7 +273,7 @@ CELERY_BEAT_SCHEDULE = {
|
||||||
"options": {"queue": "passbook_scheduled"},
|
"options": {"queue": "passbook_scheduled"},
|
||||||
},
|
},
|
||||||
"db_backup": {
|
"db_backup": {
|
||||||
"task": "passbook.lib.tasks.backup.backup_database",
|
"task": "passbook.core.tasks.backup_database",
|
||||||
"schedule": crontab(minute=0, hour=0),
|
"schedule": crontab(minute=0, hour=0),
|
||||||
"options": {"queue": "passbook_scheduled"},
|
"options": {"queue": "passbook_scheduled"},
|
||||||
},
|
},
|
||||||
|
|
Reference in New Issue