From fe7415c05edd55fcaf0cb69abf581974ea8d41ad Mon Sep 17 00:00:00 2001 From: Madelon D Date: Thu, 30 Jan 2025 13:35:16 +0100 Subject: [PATCH 01/26] Add run_on to Boefje in katalogus --- boefjes/boefjes/katalogus/plugins.py | 1 + boefjes/boefjes/models.py | 1 + boefjes/boefjes/sql/db_models.py | 1 + boefjes/boefjes/sql/plugin_storage.py | 2 ++ rocky/katalogus/client.py | 2 ++ 5 files changed, 7 insertions(+) diff --git a/boefjes/boefjes/katalogus/plugins.py b/boefjes/boefjes/katalogus/plugins.py index 1284401726a..ac587a9e640 100644 --- a/boefjes/boefjes/katalogus/plugins.py +++ b/boefjes/boefjes/katalogus/plugins.py @@ -130,6 +130,7 @@ class BoefjeIn(BaseModel): boefje_schema: dict | None = None cron: str | None = None interval: int | None = None + run_on: list[str] | None = None oci_image: str | None = None oci_arguments: list[str] = Field(default_factory=list) diff --git a/boefjes/boefjes/models.py b/boefjes/boefjes/models.py index 752de2aa298..88d586eb697 100644 --- a/boefjes/boefjes/models.py +++ b/boefjes/boefjes/models.py @@ -34,6 +34,7 @@ class Boefje(Plugin): boefje_schema: dict | None = None cron: str | None = None interval: int | None = None + run_on: list[str] | None = None runnable_hash: str | None = None oci_image: str | None = None oci_arguments: list[str] = Field(default_factory=list) diff --git a/boefjes/boefjes/sql/db_models.py b/boefjes/boefjes/sql/db_models.py index d2b9a15e4b8..9e12b9b7787 100644 --- a/boefjes/boefjes/sql/db_models.py +++ b/boefjes/boefjes/sql/db_models.py @@ -72,6 +72,7 @@ class BoefjeInDB(SQL_BASE): schema = Column(types.JSON(), nullable=True) cron = Column(types.String(length=128), nullable=True) interval = Column(types.Integer, nullable=True) + run_on = Column(types.ARRAY(types.String(length=128)), nullable=True) # Image specifications oci_image = Column(types.String(length=256), nullable=True) diff --git a/boefjes/boefjes/sql/plugin_storage.py b/boefjes/boefjes/sql/plugin_storage.py index 204f7fb8e21..6fae0f2346a 100644 --- a/boefjes/boefjes/sql/plugin_storage.py +++ b/boefjes/boefjes/sql/plugin_storage.py @@ -109,6 +109,7 @@ def to_boefje_in_db(boefje: Boefje, pk: int | None = None) -> BoefjeInDB: schema=boefje.boefje_schema, cron=boefje.cron, interval=boefje.interval, + run_on=boefje.run_on, oci_image=boefje.oci_image, oci_arguments=boefje.oci_arguments, version=boefje.version, @@ -152,6 +153,7 @@ def to_boefje(boefje_in_db: BoefjeInDB) -> Boefje: boefje_schema=boefje_in_db.schema, cron=boefje_in_db.cron, interval=boefje_in_db.interval, + run_on=boefje_in_db.run_on, oci_image=boefje_in_db.oci_image, oci_arguments=boefje_in_db.oci_arguments, version=boefje_in_db.version, diff --git a/rocky/katalogus/client.py b/rocky/katalogus/client.py index 38d6274682d..287a56836f9 100644 --- a/rocky/katalogus/client.py +++ b/rocky/katalogus/client.py @@ -67,6 +67,7 @@ class Boefje(Plugin): options: list[str] | None = None runnable_hash: str | None = None interval: int | None = None + run_on: list[str] | None = None boefje_schema: dict | None = None oci_image: str | None = None oci_arguments: list[str] = Field(default_factory=list) @@ -426,6 +427,7 @@ def parse_boefje(boefje: dict) -> Boefje: created=boefje.get("created"), description=boefje.get("description"), interval=boefje.get("interval"), + run_on=boefje.get("run_on"), enabled=boefje["enabled"], type=boefje["type"], scan_level=scan_level, From 828caa9eb539681ff6c6e4337a17a32b284cda52 Mon Sep 17 00:00:00 2001 From: Madelon D Date: Thu, 30 Jan 2025 13:36:45 +0100 Subject: [PATCH 02/26] Add run_on to boefje setup page (with js) --- rocky/assets/css/components/form.scss | 4 ++ rocky/assets/js/boefjeSetupRunOn.js | 28 ++++++++++++++ rocky/katalogus/templates/boefje_setup.html | 7 ++++ rocky/katalogus/views/boefje_setup.py | 43 +++++++++++++++++++-- rocky/tools/forms/boefje.py | 37 ++++++++++++++++-- rocky/tools/forms/settings.py | 6 +++ 6 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 rocky/assets/js/boefjeSetupRunOn.js diff --git a/rocky/assets/css/components/form.scss b/rocky/assets/css/components/form.scss index cb741c63629..af3b28a2256 100644 --- a/rocky/assets/css/components/form.scss +++ b/rocky/assets/css/components/form.scss @@ -40,6 +40,10 @@ form { } } + .hidden-input { + display: none; + } + @media (min-width: $breakpoint-filter) { .filter-fields-direction { &.row { diff --git a/rocky/assets/js/boefjeSetupRunOn.js b/rocky/assets/js/boefjeSetupRunOn.js new file mode 100644 index 00000000000..4344e16d16b --- /dev/null +++ b/rocky/assets/js/boefjeSetupRunOn.js @@ -0,0 +1,28 @@ +document.addEventListener("DOMContentLoaded", function () { + const radioButtons = document.querySelectorAll(".radio-choice"); + const intervalNumber = document.querySelector( + "label[for='id_interval_number']", + ).parentElement; + const intervalFrequency = document.querySelector( + "label[for='id_interval_frequency']", + ).parentElement; + const runOn = document.querySelector("label[for='id_run_on']").parentElement; + + intervalNumber.classList.add("hidden-input"); + intervalFrequency.classList.add("hidden-input"); + runOn.classList.add("hidden-input"); + + radioButtons.forEach(function (radio) { + radio.addEventListener("change", function () { + if (radio.value === "interval") { + intervalNumber.classList.remove("hidden-input"); + intervalFrequency.classList.remove("hidden-input"); + runOn.classList.add("hidden-input"); + } else { + intervalNumber.classList.add("hidden-input"); + intervalFrequency.classList.add("hidden-input"); + runOn.classList.remove("hidden-input"); + } + }); + }); +}); diff --git a/rocky/katalogus/templates/boefje_setup.html b/rocky/katalogus/templates/boefje_setup.html index 48c2d75c0fe..04e2b1a0920 100644 --- a/rocky/katalogus/templates/boefje_setup.html +++ b/rocky/katalogus/templates/boefje_setup.html @@ -2,6 +2,7 @@ {% load i18n %} {% load static %} +{% load compress %} {% block content %} {% include "header.html" %} @@ -46,3 +47,9 @@

{% translate "Boefje setup" %}

{% endblock content %} +{% block html_at_end_body %} + {{ block.super }} + {% compress js %} + + {% endcompress %} +{% endblock html_at_end_body %} diff --git a/rocky/katalogus/views/boefje_setup.py b/rocky/katalogus/views/boefje_setup.py index 8ab588aa97b..fc0621c8f91 100644 --- a/rocky/katalogus/views/boefje_setup.py +++ b/rocky/katalogus/views/boefje_setup.py @@ -88,7 +88,14 @@ def get_initial(self): initial["consumes"] = consumes initial["produces"] = ", ".join(self.plugin.produces) initial["scan_level"] = self.plugin.scan_level - initial["interval"] = self.plugin.interval + initial["interval_number"] = self.plugin.interval + initial["interval_frequency"] = "minutes" + initial["run_on"] = self.plugin.run_on + + if self.plugin.interval: + initial["choose_scan_type"] = "interval" + elif self.plugin.run_on: + initial["choose_scan_type"] = "run_on" return initial @@ -157,7 +164,14 @@ def get_initial(self): initial["consumes"] = consumes initial["produces"] = ", ".join(self.plugin.produces) initial["scan_level"] = self.plugin.scan_level - initial["interval"] = self.plugin.interval + initial["interval_number"] = self.plugin.interval + initial["interval_frequency"] = "minutes" + initial["run_on"] = self.plugin.run_on + + if self.plugin.interval: + initial["choose_scan_type"] = "interval" + elif self.plugin.run_on: + initial["choose_scan_type"] = "run_on" return initial @@ -211,7 +225,10 @@ def create_boefje_with_form_data(form_data, plugin_id: str, created: str | None) consumes = [] if not form_data["consumes"] else form_data["consumes"].strip("[]").replace("'", "").split(", ") produces = [] if not form_data["produces"] else form_data["produces"].split(",") produces = {p.strip() for p in produces} - interval = int(form_data.get("interval") or 0) or None + logger.error("Run on form_data: %s", form_data["run_on"]) + run_on = None if not form_data["run_on"] else [form_data["run_on"]] + logger.error("Run_on: %s", run_on) + interval = get_interval_minutes(int(form_data.get("interval_number")) or 0, form_data["interval_frequency"]) input_objects = set() for input_object in consumes: @@ -223,6 +240,7 @@ def create_boefje_with_form_data(form_data, plugin_id: str, created: str | None) created=created, description=form_data["description"], interval=interval, + run_on=run_on, enabled=False, type="boefje", scan_level=form_data["scan_level"], @@ -232,3 +250,22 @@ def create_boefje_with_form_data(form_data, plugin_id: str, created: str | None) oci_image=form_data["oci_image"], oci_arguments=arguments, ) + + +def get_interval_minutes(interval_number, interval_frequency) -> int: + interval_minutes = 0 + if interval_number == 0: + return None + + if interval_frequency == "minutes": + interval_minutes = interval_number + elif interval_frequency == "hours": + interval_minutes = interval_number * 60 + elif interval_frequency == "days": + interval_minutes = interval_number * 60 * 24 + elif interval_frequency == "weeks": + interval_minutes = interval_number * 60 * 24 * 7 + elif interval_frequency == "years": + interval_minutes = interval_number * 60 * 24 * 365 + + return int(interval_minutes) diff --git a/rocky/tools/forms/boefje.py b/rocky/tools/forms/boefje.py index fcf93934e78..0664ebe2721 100644 --- a/rocky/tools/forms/boefje.py +++ b/rocky/tools/forms/boefje.py @@ -9,11 +9,21 @@ BOEFJE_CONTAINER_IMAGE_HELP_TEXT, BOEFJE_DESCRIPTION_HELP_TEXT, BOEFJE_PRODUCES_HELP_TEXT, + BOEFJE_RUN_ON_HELP_TEXT, BOEFJE_SCAN_LEVEL_HELP_TEXT, BOEFJE_SCHEMA_HELP_TEXT, ) OOI_TYPE_CHOICES = sorted((ooi_type.get_object_type(), ooi_type.get_object_type()) for ooi_type in ALL_TYPES) +SCAN_TYPE_CHOICES = [("interval", "Run on interval, every:"), ("run_on", "Run on object creation/change:")] +INTERVAL_CHOICES = [ + ("minutes", "minutes"), + ("hours", "hours"), + ("days", "days"), + ("weeks", "weeks"), + ("years", "years"), +] +OBJECT_CHANGE_CHOICES = [("create", "Creation"), ("update", "Change"), ("create, update", "Creation and change")] class BoefjeSetupForm(BaseRockyForm): @@ -46,15 +56,34 @@ class BoefjeSetupForm(BaseRockyForm): widget=forms.Select(choices=SCAN_LEVEL.choices), help_text=BOEFJE_SCAN_LEVEL_HELP_TEXT, ) - interval = forms.CharField( + scan_type = forms.CharField( required=False, - label=_("Scan frequency"), + label=_("Scan type"), + widget=forms.RadioSelect(choices=SCAN_TYPE_CHOICES, attrs={"class": "radio-choice"}), + help_text=BOEFJE_RUN_ON_HELP_TEXT, + ) + interval_number = forms.CharField( + required=False, + label=_("Interval amount"), widget=forms.TextInput( attrs={ "description": _( - "Specify the scanning frequency for this Boefje in minutes. The default is 24 hours. " - "For example: 5 minutes will let the boefje scan every 5 minutes." + "Specify the scanning interval for this Boefje. The default is 24 hours. " + "For example: 5 minutes will let the Boefje scan every 5 minutes." ) } ), ) + interval_frequency = forms.CharField( + required=False, label=_("Interval frequency"), widget=forms.Select(choices=INTERVAL_CHOICES) + ) + run_on = forms.CharField( + required=False, + label=_("Object creation/change"), + widget=forms.Select( + choices=OBJECT_CHANGE_CHOICES, + attrs={ + "description": _("Choose weather a the Boefje should run after creating and/or changing an object. ") + }, + ), + ) diff --git a/rocky/tools/forms/settings.py b/rocky/tools/forms/settings.py index 88af5cf2f38..cced63c97d2 100644 --- a/rocky/tools/forms/settings.py +++ b/rocky/tools/forms/settings.py @@ -99,6 +99,12 @@ ) ) +BOEFJE_RUN_ON_HELP_TEXT = _( + "Choose when this Boefje will scan objects. " + "It can run on a given interval or it can run every time an object " + "has been created or changed. " +) + DEPTH_DEFAULT = 9 DEPTH_MAX = 15 DEPTH_HELP_TEXT = _("Depth of the tree.") From 3a0e4105d8511ded4136152eead6cd75961bdeae Mon Sep 17 00:00:00 2001 From: Madelon D Date: Thu, 30 Jan 2025 13:37:29 +0100 Subject: [PATCH 03/26] Show run_on on boefje detail page --- rocky/katalogus/templates/plugin_container_image.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rocky/katalogus/templates/plugin_container_image.html b/rocky/katalogus/templates/plugin_container_image.html index 7cfadd1c5a7..7295ad007da 100644 --- a/rocky/katalogus/templates/plugin_container_image.html +++ b/rocky/katalogus/templates/plugin_container_image.html @@ -46,7 +46,8 @@

{% translate "Variants" %}

{% translate "Scan level" %} {% translate "Status" %} {% translate "Age" %} - {% translate "Scan frequency" %} + {% translate "Scan interval" %} + {% translate "Run on" %} @@ -85,6 +86,9 @@

{% translate "Variants" %}

{% endif %} + + {{ variant.run_on }} +