feat(scan, schedule): add next_scan_at field to scans and POST /schedules/daily (#5978)

This commit is contained in:
Víctor Fernández Poyatos authored and GitHub committed 2024-12-01 09:12:19 +01:00
1 parent ff80a47123
commit ffaa267b5e
11 files changed
+306 -30

No files matched your search

+22 -4
View File
@@ -1,7 +1,8 @@
import json
from django.utils import timezone
from django_celery_beat.models import PeriodicTask, IntervalSchedule
from django_celery_beat.models import IntervalSchedule, PeriodicTask
from rest_framework_json_api.serializers import ValidationError
from tasks.tasks import perform_scheduled_scan_task
from api.models import Provider
@@ -16,7 +17,7 @@ def schedule_provider_scan(provider_instance: Provider):
task_name = f"scan-perform-scheduled-{provider_instance.id}"
# Schedule the task
PeriodicTask.objects.create(
_, created = PeriodicTask.objects.get_or_create(
interval=schedule,
name=task_name,
task="scan-perform-scheduled",
@@ -26,6 +27,23 @@ def schedule_provider_scan(provider_instance: Provider):
"provider_id": str(provider_instance.id),
}
),
start_time=provider_instance.inserted_at + timezone.timedelta(hours=24),
one_off=False,
)
if not created:
raise ValidationError(
[
{
"detail": "There is already a scheduled scan for this provider.",
"status": 400,
"source": {"pointer": "/data/attributes/provider_id"},
"code": "invalid",
}
]
)
return perform_scheduled_scan_task.apply_async(
kwargs={
"tenant_id": str(provider_instance.tenant_id),
"provider_id": str(provider_instance.id),
},
)
+18 -1
View File
@@ -1,5 +1,8 @@
from datetime import datetime, timedelta, timezone
from celery import shared_task
from config.celery import RLSTask
from django_celery_beat.models import PeriodicTask
from tasks.jobs.connection import check_provider_connection
from tasks.jobs.deletion import delete_provider
from tasks.jobs.scan import aggregate_findings, perform_prowler_scan
@@ -98,20 +101,34 @@ def perform_scheduled_scan_task(self, tenant_id: str, provider_id: str):
with tenant_transaction(tenant_id):
provider_instance = Provider.objects.get(pk=provider_id)
periodic_task_instance = PeriodicTask.objects.get(
name=f"scan-perform-scheduled-{provider_id}"
)
next_scan_date = datetime.combine(
datetime.now(timezone.utc), periodic_task_instance.date_changed.time()
) + timedelta(hours=24)
scan_instance = Scan.objects.create(
tenant_id=tenant_id,
name="Daily scheduled scan",
provider=provider_instance,
trigger=Scan.TriggerChoices.SCHEDULED,
next_scan_at=next_scan_date,
task_id=task_id,
)
return perform_prowler_scan(
result = perform_prowler_scan(
tenant_id=tenant_id,
scan_id=str(scan_instance.id),
provider_id=provider_id,
)
perform_scan_summary_task.apply_async(
kwargs={
"tenant_id": tenant_id,
"scan_id": str(scan_instance.id),
}
),
return result
@shared_task(name="scan-summary")
+53
View File
@@ -0,0 +1,53 @@
import json
from unittest.mock import patch
import pytest
from django_celery_beat.models import IntervalSchedule, PeriodicTask
from rest_framework_json_api.serializers import ValidationError
from tasks.beat import schedule_provider_scan
@pytest.mark.django_db
class TestScheduleProviderScan:
def test_schedule_provider_scan_success(self, providers_fixture):
provider_instance, *_ = providers_fixture
with patch(
"tasks.tasks.perform_scheduled_scan_task.apply_async"
) as mock_apply_async:
result = schedule_provider_scan(provider_instance)
assert result is not None
mock_apply_async.assert_called_once_with(
kwargs={
"tenant_id": str(provider_instance.tenant_id),
"provider_id": str(provider_instance.id),
},
)
task_name = f"scan-perform-scheduled-{provider_instance.id}"
periodic_task = PeriodicTask.objects.get(name=task_name)
assert periodic_task is not None
assert periodic_task.interval.every == 24
assert periodic_task.interval.period == IntervalSchedule.HOURS
assert periodic_task.task == "scan-perform-scheduled"
assert json.loads(periodic_task.kwargs) == {
"tenant_id": str(provider_instance.tenant_id),
"provider_id": str(provider_instance.id),
}
def test_schedule_provider_scan_already_exists(self, providers_fixture):
provider_instance, *_ = providers_fixture
# First, schedule the scan
with patch("tasks.tasks.perform_scheduled_scan_task.apply_async"):
schedule_provider_scan(provider_instance)
# Now, try scheduling again, should raise ValidationError
with pytest.raises(ValidationError) as exc_info:
schedule_provider_scan(provider_instance)
assert "There is already a scheduled scan for this provider." in str(
exc_info.value
)