From b290d3c3d2902f54839dca5bf2d1c8622976c7ec Mon Sep 17 00:00:00 2001 From: void-spark <81029971+void-spark@users.noreply.github.com> Date: Sun, 10 May 2026 18:15:05 +0200 Subject: [PATCH 1/7] First attempt at kea dhcp support --- front/plugins/kea_api/README.md | 70 +++++ front/plugins/kea_api/config.json | 455 ++++++++++++++++++++++++++++++ front/plugins/kea_api/script.py | 70 +++++ 3 files changed, 595 insertions(+) create mode 100755 front/plugins/kea_api/README.md create mode 100644 front/plugins/kea_api/config.json create mode 100644 front/plugins/kea_api/script.py diff --git a/front/plugins/kea_api/README.md b/front/plugins/kea_api/README.md new file mode 100755 index 00000000..8a35edf2 --- /dev/null +++ b/front/plugins/kea_api/README.md @@ -0,0 +1,70 @@ +## Overview + +A plugin allowing for importing devices from the Kea DHCP API. +https://www.isc.org/kea/ + +And specifically: +https://kea.readthedocs.io/en/kea-2.6.3/api.html#lease4-get-all + + +### Usage + +To enable the API, first you want to add something like this to your main kea configuration (this is for debian 13): + +```json + "control-socket": { + "socket-type": "unix", + "socket-name": "/run/kea/kea4-ctrl-socket" + }, + + "hooks-libraries": [ + { + "library": "/usr/lib/x86_64-linux-gnu/kea/hooks/libdhcp_lease_cmds.so" + } + ], +``` + + +And you need to install kea-ctrl-agent, with a config that looks something like this: + +```json +{ +"Control-agent": { + "http-host": "127.0.0.1", + "http-port": 8000, + + "authentication": { + "type": "basic", + "realm": "Kea Control Agent", + "directory": "/etc/kea", + "clients": [ + { + "user": "kea-api", + "password-file": "kea-api-password" + } + ] + }, + "control-sockets": { + "dhcp4": { + "socket-type": "unix", + "socket-name": "/run/kea/kea4-ctrl-socket" + } + }, + "loggers": [ + { + "name": "kea-ctrl-agent", + "output-options": [ + { + "output": "stdout", + "pattern": "%-5p %m\n" + } + ], + "severity": "INFO", + "debuglevel": 0 + } + ] +} +} +``` + +You will need to configure the plugin with the URL to the API, and the username and password configured above (from kea-api-password file in the example) diff --git a/front/plugins/kea_api/config.json b/front/plugins/kea_api/config.json new file mode 100644 index 00000000..ffa434bd --- /dev/null +++ b/front/plugins/kea_api/config.json @@ -0,0 +1,455 @@ +{ + "code_name": "kea_api", + "unique_prefix": "KEALSS", + "plugin_type": "device_scanner", + "execution_order" : "Layer_3", + "enabled": true, + "data_source": "script", + "data_filters": [ + { + "compare_column": "objectPrimaryId", + "compare_operator": "==", + "compare_field_id": "txtMacFilter", + "compare_js_template": "'{value}'.toString()", + "compare_use_quotes": true + } + ], + "show_ui": true, + "localized": ["display_name", "description", "icon"], + "mapped_to_table": "CurrentScan", + "display_name": [{"language_code": "en_us", "string": "Kea DHCP API"}], + "icon": [{"language_code": "en_us", "string": ""}], + "description": [{"language_code": "en_us", "string": "Imports leases via Kea Control Agent REST API"}], + "database_column_definitions": [ + { + "column": "index", + "css_classes": "col-sm-2", + "show": true, + "type": "none", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "Index"}] + }, + { + "column": "objectPrimaryId", + "mapped_to_column": "scanMac", + "css_classes": "col-sm-2", + "show": true, + "type": "device_mac", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "MAC address"}] + }, + { + "column": "objectSecondaryId", + "mapped_to_column": "scanLastIP", + "css_classes": "col-sm-2", + "show": true, + "type": "device_ip", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "IP" }] + }, + { + "column": "dateTimeCreated", + "css_classes": "col-sm-2", + "show": true, + "type": "label", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "Created"}] + }, + { + "column": "dateTimeChanged", + "mapped_to_column": "scanLastConnection", + "css_classes": "col-sm-2", + "show": true, + "type": "label", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "Changed"}] + }, + { + "column": "watchedValue1", + "css_classes": "col-sm-2", + "show": true, + "type": "label", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "Is active"}] + }, + { + "column": "watchedValue2", + "mapped_to_column": "scanName", + "css_classes": "col-sm-2", + "show": true, + "type": "label", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "Hostname"}] + }, + { + "column": "watchedValue4", + "css_classes": "col-sm-2", + "show": true, + "type": "label", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "State"}] + }, + { + "column": "userData", + "css_classes": "col-sm-2", + "show": false, + "type": "textbox_save", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "Comments"}] + }, + { + "column": "Dummy", + "mapped_to_column": "scanSourcePlugin", + "mapped_to_column_data": { + "value": "KEALSS" + }, + "css_classes": "col-sm-2", + "show": false, + "type": "label", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "Scan method"}] + }, + { + "column": "status", + "css_classes": "col-sm-1", + "show": true, + "type": "replace", + "default_value": "", + "options": [ + { + "equals": "watched-not-changed", + "replacement": "
" + }, + { + "equals": "watched-changed", + "replacement": "
" + }, + { + "equals": "new", + "replacement": "
" + }, + { + "equals": "missing-in-last-scan", + "replacement": "
" + } + ], + "localized": ["name"], + "name": [{"language_code": "en_us", "string": "Status"}] + } + ], + "settings": [ + { + "function": "RUN", + "events": ["run"], + "type": { + "dataType": "string", + "elements": [{"elementType": "select", "elementOptions": [], "transformers": []}] + }, + "default_value": "disabled", + "options": [ + "disabled", + "once", + "schedule", + "always_after_scan", + "on_new_device" + ], + "localized": ["name", "description"], + "name": [{"language_code": "en_us", "string": "When to run"}], + "description": [ + { + "language_code": "en_us", + "string": "Enable import of devices from Kea API. If you select schedule the scheduling settings from below are applied. If you select once the scan is run only once on start of the application (container) or after you update your settings. ⚠ Use the same schedule if you have multiple Device scanners enabled." + } + ] + }, + { + "function": "CMD", + "type": { + "dataType": "string", + "elements": [ + { "elementType": "input", "elementOptions": [], "transformers": [] } + ] + }, + "default_value": "python3 /app/front/plugins/kea_api/script.py", + "options": [], + "localized": ["name", "description"], + "name": [{"language_code": "en_us", "string": "Command"}], + "description": [{"language_code": "en_us", "string": "Command to run"}] + }, + { + "function": "URL", + "localized": ["name", "description"], + "name": [{"language_code": "en_us", "string": "API URL"}], + "description": [{"language_code": "en_us", "string": "Kea Control Agent URL"}], + "type": { + "dataType": "string", + "elements": [ + { + "elementType": "input", + "elementOptions": [], + "transformers": [] + } + ] + }, + "default_value": "http://127.0.0.1:8000" + }, + { + "function": "USER", + "localized": ["name", "description"], + "name": [{"language_code": "en_us", "string": "API User"}], + "description": [{"language_code": "en_us", "string": "Basic Auth Username"}], + "type": { + "dataType": "string", + "elements": [ + { + "elementType": "input", + "elementOptions": [], + "transformers": [] + } + ] + }, + "default_value": "kea-api" + }, + { + "function": "PASS", + "localized": ["name", "description"], + "name": [{"language_code": "en_us", "string": "API Password"}], + "description": [{"language_code": "en_us", "string": "Basic Auth Password"}], + "type": { + "dataType": "string", + "elements": [ + { + "elementType": "input", + "elementOptions": [{"type": "password"}], + "transformers": [] + } + ] + }, + "default_value": "" + }, + { + "function": "RUN_SCHD", + "type": { + "dataType": "string", + "elements": [ + { + "elementType": "span", + "elementOptions": [ + { + "cssClasses": "input-group-addon validityCheck" + }, + { + "getStringKey": "Gen_ValidIcon" + } + ], + "transformers": [] + }, + { + "elementType": "input", + "elementOptions": [ + { + "focusout": "validateRegex(this)" + }, + { + "base64Regex": "Xig/OlwqfCg/OlswLTldfFsxLTVdWzAtOV18WzAtOV0rLVswLTldK3xcKi9bMC05XSspKVxzKyg/OlwqfCg/OlswLTldfDFbMC05XXwyWzAtM118WzAtOV0rLVswLTldK3xcKi9bMC05XSspKVxzKyg/OlwqfCg/OlsxLTldfFsxMl1bMC05XXwzWzAxXXxbMC05XSstWzAtOV0rfFwqL1swLTldKykpXHMrKD86XCp8KD86WzEtOV18MVswLTJdfFswLTldKy1bMC05XSt8XCovWzAtOV0rKSlccysoPzpcKnwoPzpbMC02XXxbMC02XS1bMC02XXxcKi9bMC05XSspKSQ=" + } + ], + "transformers": [] + } + ] + }, + "default_value": "0 2 * * *", + "options": [], + "localized": ["name", "description"], + "name": [ + { + "language_code": "en_us", + "string": "Schedule" + } + ], + "description": [ + { + "language_code": "en_us", + "string": "Only enabled if you select schedule in the KEALSS_RUN setting. Make sure you enter the schedule in the correct cron-like format (e.g. validate at crontab.guru). For example entering 0 4 * * * will run the scan after 4 am in the TIMEZONE you set above. Will be run NEXT time the time passes.
It's recommended to use the same schedule interval for all plugins responsible for discovering new devices." + } + ] + }, + { + "function": "RUN_TIMEOUT", + "type": { + "dataType": "integer", + "elements": [ + { + "elementType": "input", + "elementOptions": [{ "type": "number" }], + "transformers": [] + } + ] + }, + "default_value": 5, + "options": [], + "localized": ["name", "description"], + "name": [ + { + "language_code": "en_us", + "string": "Run timeout" + } + ], + "description": [ + { + "language_code": "en_us", + "string": "Maximum time in seconds to wait for the script to finish. If this time is exceeded the script is aborted." + } + ] + }, + { + "function": "SET_ALWAYS", + "type": { + "dataType": "array", + "elements": [ + { + "elementType": "select", + "elementOptions": [{ "multiple": "true", "orderable": "true"}], + "transformers": [] + } + ] + }, + "default_value": ["devMac", "devLastIP"], + "options": [ + "devMac", + "devLastIP" + ], + "localized": ["name", "description"], + "name": [ + { + "language_code": "en_us", + "string": "Set always columns" + } + ], + "description": [ + { + "language_code": "en_us", + "string": "These columns are treated as authoritative and will overwrite existing values, including those set by other plugins, unless the current value was explicitly set by the user (Source = USER or Source = LOCKED)." + } + ] + }, + { + "function": "SET_EMPTY", + "type": { + "dataType": "array", + "elements": [ + { + "elementType": "select", + "elementOptions": [{ "multiple": "true", "orderable": "true" }], + "transformers": [] + } + ] + }, + "default_value": [], + "options": [ + "devMac", + "devLastIP", + "devName", + "devSourcePlugin" + ], + "localized": ["name", "description"], + "name": [ + { + "language_code": "en_us", + "string": "Set empty columns" + } + ], + "description": [ + { + "language_code": "en_us", + "string": "These columns are only overwritten if they are empty (NULL / empty string) or if their Source is set to NEWDEV" + } + ] + }, + { + "function": "WATCH", + "type": { + "dataType": "array", + "elements": [ + { + "elementType": "select", + "elementOptions": [{ "multiple": "true", "orderable": "true"}], + "transformers": [] + } + ] + }, + "default_value": ["watchedValue1", "watchedValue4"], + "options": [ + "watchedValue1", + "watchedValue2", + "watchedValue4" + ], + "localized": ["name", "description"], + "name": [ + { + "language_code": "en_us", + "string": "Watched" + } + ], + "description": [ + { + "language_code": "en_us", + "string": "Send a notification if selected values change. Use CTRL + Click to select/deselect. " + } + ] + }, + { + "function": "REPORT_ON", + "type": { + "dataType": "array", + "elements": [ + { + "elementType": "select", + "elementOptions": [{ "multiple": "true", "orderable": "true"}], + "transformers": [] + } + ] + }, + "default_value": ["new", "watched-changed"], + "options": [ + "new", + "watched-changed", + "watched-not-changed", + "missing-in-last-scan" + ], + "localized": ["name", "description"], + "name": [ + { + "language_code": "en_us", + "string": "Report on" + } + ], + "description": [ + { + "language_code": "en_us", + "string": "Send a notification only on these statuses. new means a new unique (unique combination of PrimaryId and SecondaryId) object was discovered. watched-changed means that selected watchedValueN columns changed." + } + ] + } + ] +} \ No newline at end of file diff --git a/front/plugins/kea_api/script.py b/front/plugins/kea_api/script.py new file mode 100644 index 00000000..1f65253a --- /dev/null +++ b/front/plugins/kea_api/script.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +import os +import sys +import requests + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../server')) +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../plugins')) + +from plugin_helper import Plugin_Objects, mylog, handleEmpty, is_mac +from helper import get_setting_value +from const import logPath + +pluginName = "KEALSS" +LOG_PATH = logPath + "/plugins" +LOG_FILE = os.path.join(LOG_PATH, f'script.{pluginName}.log') +RESULT_FILE = os.path.join(LOG_PATH, f'last_result.{pluginName}.log') + +plugin_objects = Plugin_Objects(RESULT_FILE) + + +def main(): + try: + url = get_setting_value(f'{pluginName}_URL') + user = get_setting_value(f'{pluginName}_USER') + password = get_setting_value(f'{pluginName}_PASS') + + mylog('verbose', [f'[{pluginName}] Querying Kea API at {url}']) + + payload = {'command': 'lease4-get-all', 'service': ['dhcp4']} + + response = requests.post(url, json=payload, auth=(user, password), timeout=10) + response.raise_for_status() + data = response.json() + + count = 0 + for entry in data: + # Result: 0 (success), 1 (error), or 3 (empty). + if entry.get("result") == 0: + leases = entry["arguments"].get("leases", []) + for l in leases: + mac = l['hw-address'] + state = l['state'] + if is_mac(mac): + plugin_objects.add_object( + primaryId = mac, + secondaryId = l['ip-address'], + # Active or not, similar to watched 1 of DHCPLSS plugin + watched1 = state == 0, + watched2 = l['hostname'], + watched3 = None, + # Default (or assigned) (0), declined (1), expired-reclaimed (2), released (3), and registered (4)). + watched4 = state, + extra = None, + foreignKey = mac + ) + count += 1 + elif entry.get("result") == 1: + mylog('none', [f'[{pluginName}] ⚠ ERROR: Kea API indicated error']) + + plugin_objects.write_result_file() + + mylog('verbose', [f'[{pluginName}] Successfully imported {count} devices reported by Kea API']) + + except Exception as e: + mylog('none', [f'[{pluginName}] ⚠ ERROR: {str(e)}']) + + + +if __name__ == '__main__': + main() From 608686e4bd3a88c7b492225e432a27d77adf2c69 Mon Sep 17 00:00:00 2001 From: void-spark <81029971+void-spark@users.noreply.github.com> Date: Mon, 11 May 2026 21:51:32 +0200 Subject: [PATCH 2/7] Add list with settings to readme --- front/plugins/kea_api/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/front/plugins/kea_api/README.md b/front/plugins/kea_api/README.md index 8a35edf2..6bbd2aa9 100755 --- a/front/plugins/kea_api/README.md +++ b/front/plugins/kea_api/README.md @@ -68,3 +68,20 @@ And you need to install kea-ctrl-agent, with a config that looks something like ``` You will need to configure the plugin with the URL to the API, and the username and password configured above (from kea-api-password file in the example) + + +#### Required Settings + +These settings are required, besides the common device scanner settings: + +- **Kea Control Agent URL** (`KEALSS_URL`): The full URL, including port number, to the Kea API. + - Default: `http://127.0.0.1:8000` + - This mirrors what you set up in the kea-ctrl-agent configuration. + +- **Basic Auth Username** (`KEALSS_USER`): The user to use for authenticating with the Kea API. + - Default: `kea-api` + - This mirrors what you set up in the kea-ctrl-agent configuration. + +- **Basic Auth Password** (`KEALSS_PASS`): The password to use for authenticating with the Kea API. + - This mirrors what you set up in the kea-ctrl-agent configuration. + - When using a password file, it should be the content of the password file. From 7273899e3ec51e01f4648efe5cd6e44e27e15ba6 Mon Sep 17 00:00:00 2001 From: void-spark <81029971+void-spark@users.noreply.github.com> Date: Mon, 11 May 2026 22:03:29 +0200 Subject: [PATCH 3/7] Use single quote consistently Use 'l' instead of 'lease' (I see you little rabbit) Use [] over get in most places, if expected fields are missing an error is an acceptable outcome. Include 'text' field in logging. Add logging for result '3' --- front/plugins/kea_api/script.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/front/plugins/kea_api/script.py b/front/plugins/kea_api/script.py index 1f65253a..74d543f8 100644 --- a/front/plugins/kea_api/script.py +++ b/front/plugins/kea_api/script.py @@ -10,8 +10,8 @@ from plugin_helper import Plugin_Objects, mylog, handleEmpty, is_mac from helper import get_setting_value from const import logPath -pluginName = "KEALSS" -LOG_PATH = logPath + "/plugins" +pluginName = 'KEALSS' +LOG_PATH = logPath + '/plugins' LOG_FILE = os.path.join(LOG_PATH, f'script.{pluginName}.log') RESULT_FILE = os.path.join(LOG_PATH, f'last_result.{pluginName}.log') @@ -34,19 +34,20 @@ def main(): count = 0 for entry in data: + text = entry.get('text', '[API provided no text]'); # Result: 0 (success), 1 (error), or 3 (empty). - if entry.get("result") == 0: - leases = entry["arguments"].get("leases", []) - for l in leases: - mac = l['hw-address'] - state = l['state'] + if entry['result'] == 0: + leases = entry['arguments']['leases'] + for lease in leases: + mac = lease['hw-address'] + state = lease['state'] if is_mac(mac): plugin_objects.add_object( primaryId = mac, - secondaryId = l['ip-address'], - # Active or not, similar to watched 1 of DHCPLSS plugin + secondaryId = lease['ip-address'], + # Active or not, similar to watched1 of DHCPLSS plugin watched1 = state == 0, - watched2 = l['hostname'], + watched2 = lease['hostname'], watched3 = None, # Default (or assigned) (0), declined (1), expired-reclaimed (2), released (3), and registered (4)). watched4 = state, @@ -54,12 +55,15 @@ def main(): foreignKey = mac ) count += 1 - elif entry.get("result") == 1: - mylog('none', [f'[{pluginName}] ⚠ ERROR: Kea API indicated error']) + plugin_objects.write_result_file() - plugin_objects.write_result_file() + mylog('verbose', [f'[{pluginName}] Kea API response: {text}']) + mylog('verbose', [f'[{pluginName}] Successfully imported {count} devices reported by Kea API']) + elif entry['result'] == 1: + mylog('none', [f'[{pluginName}] ⚠ ERROR: Kea API indicated error: {text}']) + elif entry['result'] == 3: + mylog('verbose', [f'[{pluginName}] Kea API indicates no entries found: {text}']) - mylog('verbose', [f'[{pluginName}] Successfully imported {count} devices reported by Kea API']) except Exception as e: mylog('none', [f'[{pluginName}] ⚠ ERROR: {str(e)}']) From 76612e5d0ea5796172c8e5ededef4a750d1f23ba Mon Sep 17 00:00:00 2001 From: void-spark <81029971+void-spark@users.noreply.github.com> Date: Mon, 11 May 2026 22:09:07 +0200 Subject: [PATCH 4/7] Change default timeout to 10 seconds, match request timeout to script timeout -1 second. Always use at least 1 sec. timeout for request. --- front/plugins/kea_api/config.json | 2 +- front/plugins/kea_api/script.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/front/plugins/kea_api/config.json b/front/plugins/kea_api/config.json index ffa434bd..6bc00f3d 100644 --- a/front/plugins/kea_api/config.json +++ b/front/plugins/kea_api/config.json @@ -306,7 +306,7 @@ } ] }, - "default_value": 5, + "default_value": 10, "options": [], "localized": ["name", "description"], "name": [ diff --git a/front/plugins/kea_api/script.py b/front/plugins/kea_api/script.py index 74d543f8..a772929d 100644 --- a/front/plugins/kea_api/script.py +++ b/front/plugins/kea_api/script.py @@ -23,12 +23,13 @@ def main(): url = get_setting_value(f'{pluginName}_URL') user = get_setting_value(f'{pluginName}_USER') password = get_setting_value(f'{pluginName}_PASS') + timeout = get_setting_value(f'{pluginName}_RUN_TIMEOUT') mylog('verbose', [f'[{pluginName}] Querying Kea API at {url}']) payload = {'command': 'lease4-get-all', 'service': ['dhcp4']} - response = requests.post(url, json=payload, auth=(user, password), timeout=10) + response = requests.post(url, json=payload, auth=(user, password), timeout=max(1, timeout - 1)) response.raise_for_status() data = response.json() From 957c779cb5b326b5abfb754fb2772f7344f29d30 Mon Sep 17 00:00:00 2001 From: void-spark <81029971+void-spark@users.noreply.github.com> Date: Mon, 11 May 2026 22:16:51 +0200 Subject: [PATCH 5/7] Add KEALSS to plugin list --- docs/PLUGINS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/PLUGINS.md b/docs/PLUGINS.md index d108aeea..e8224fd2 100755 --- a/docs/PLUGINS.md +++ b/docs/PLUGINS.md @@ -62,6 +62,7 @@ Device-detecting plugins insert values into the `CurrentScan` database table. T | `INTRNT` | [internet_ip](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/internet_ip/) | 🔍 | Internet IP scanner | | | | `INTRSPD` | [internet_speedtest](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/internet_speedtest/) | ♻ | Internet speed test | | | | `IPNEIGH` | [ipneigh](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/ipneigh/) | 🔍 | Scan ARP (IPv4) and NDP (IPv6) tables | | | +| `KEALSS` | [kea_api](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/kea_api/) | 🔍/🆎 | Pull lease data from the Kea DHCP API | | | | `LUCIRPC` | [luci_import](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/luci_import/) | 🔍 | Import connected devices from OpenWRT | | | | `MAINT` | [maintenance](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/maintenance/) | ⚙ | Maintenance of logs, etc. | | | | `MQTT` | [_publisher_mqtt](https://github.com/netalertx/NetAlertX/tree/main/front/plugins/_publisher_mqtt/) | ▶️ | MQTT for synching to Home Assistant | | | From 39068e982442f715436bd879d5b8d51494e57966 Mon Sep 17 00:00:00 2001 From: void-spark <81029971+void-spark@users.noreply.github.com> Date: Mon, 11 May 2026 22:21:10 +0200 Subject: [PATCH 6/7] And 'notes' to README.md --- front/plugins/kea_api/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/front/plugins/kea_api/README.md b/front/plugins/kea_api/README.md index 6bbd2aa9..9ddc174c 100755 --- a/front/plugins/kea_api/README.md +++ b/front/plugins/kea_api/README.md @@ -85,3 +85,15 @@ These settings are required, besides the common device scanner settings: - **Basic Auth Password** (`KEALSS_PASS`): The password to use for authenticating with the Kea API. - This mirrors what you set up in the kea-ctrl-agent configuration. - When using a password file, it should be the content of the password file. + + +### Notes + +- This was tested on a basic Debian 13 install. +- When you install kea-ctrl-agent, it should ask you about creating a password. +- It's possible to run kea-ctrl-agent without password, but it's not recommended and at the moment we don't support that. +- I may provide some minimal support, if you ask nicely :) + +- Version: 1.0.0 +- Author: `void-spark` +- Release Date: `11/05/2026` From 6d661dd12c09476ee9e784ebc3fba3a1f42f7651 Mon Sep 17 00:00:00 2001 From: void-spark <81029971+void-spark@users.noreply.github.com> Date: Mon, 11 May 2026 22:29:37 +0200 Subject: [PATCH 7/7] I did add a ';' from habit, removed again, must please the bunny :) --- front/plugins/kea_api/script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/plugins/kea_api/script.py b/front/plugins/kea_api/script.py index a772929d..9dc72d8c 100644 --- a/front/plugins/kea_api/script.py +++ b/front/plugins/kea_api/script.py @@ -35,7 +35,7 @@ def main(): count = 0 for entry in data: - text = entry.get('text', '[API provided no text]'); + text = entry.get('text', '[API provided no text]') # Result: 0 (success), 1 (error), or 3 (empty). if entry['result'] == 0: leases = entry['arguments']['leases']