1
0
mirror of https://github.com/quay/quay.git synced 2026-01-27 18:42:52 +03:00
Files
quay/workers/security_notification_worker.py
2020-02-05 19:55:07 -08:00

107 lines
3.9 KiB
Python

import logging
import time
import json
import features
from app import secscan_notification_queue
from data.secscan_model import secscan_model
from workers.queueworker import QueueWorker, JobException
from util.secscan.notifier import SecurityNotificationHandler, ProcessNotificationPageResult
logger = logging.getLogger(__name__)
_PROCESSING_SECONDS = 60 * 60 # 1 hour
_LAYER_LIMIT = 1000 # The number of layers to request on each page.
class SecurityNotificationWorker(QueueWorker):
""" NOTE: This worker is legacy code and should be removed after we've fully moved to Clair V4
API.
"""
def process_queue_item(self, data):
self.perform_notification_work(data)
def perform_notification_work(self, data, layer_limit=_LAYER_LIMIT):
"""
Performs the work for handling a security notification as referenced by the given data
object.
Returns True on successful handling, False on non-retryable failure and raises a
JobException on retryable failure.
"""
secscan_api = secscan_model.legacy_api_handler
notification_name = data["Name"]
current_page = data.get("page", None)
handler = SecurityNotificationHandler(secscan_api, layer_limit)
while True:
# Retrieve the current page of notification data from the security scanner.
(response_data, should_retry) = secscan_api.get_notification(
notification_name, layer_limit=layer_limit, page=current_page
)
# If no response, something went wrong.
if response_data is None:
if should_retry:
raise JobException()
else:
# Remove the job from the API.
logger.error("Failed to handle security notification %s", notification_name)
secscan_api.mark_notification_read(notification_name)
# Return to mark the job as "complete", as we'll never be able to finish it.
return False
# Extend processing on the queue item so it doesn't expire while we're working.
self.extend_processing(_PROCESSING_SECONDS, json.dumps(data))
# Process the notification data.
notification_data = response_data["Notification"]
result = handler.process_notification_page_data(notification_data)
# Possible states after processing: failed to process, finished processing entirely
# or finished processing the page.
if result == ProcessNotificationPageResult.FAILED:
# Something went wrong.
raise JobException
if result == ProcessNotificationPageResult.FINISHED_PROCESSING:
# Mark the notification as read.
if not secscan_api.mark_notification_read(notification_name):
# Return to mark the job as "complete", as we'll never be able to finish it.
logger.error("Failed to mark notification %s as read", notification_name)
return False
# Send the generated Quay notifications.
handler.send_notifications()
return True
if result == ProcessNotificationPageResult.FINISHED_PAGE:
# Continue onto the next page.
current_page = notification_data["NextPage"]
continue
if __name__ == "__main__":
if (
not features.SECURITY_SCANNER
or not features.SECURITY_NOTIFICATIONS
or not secscan_model.legacy_api_handler
):
logger.debug("Security scanner disabled; skipping SecurityNotificationWorker")
while True:
time.sleep(100000)
worker = SecurityNotificationWorker(
secscan_notification_queue,
poll_period_seconds=30,
reservation_seconds=30,
retry_after_seconds=30,
)
worker.start()