linuxfabrik-lib 6.0.0__tar.gz → 7.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {linuxfabrik_lib-6.0.0/linuxfabrik_lib.egg-info → linuxfabrik_lib-7.0.0}/PKG-INFO +9 -6
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/README.md +8 -5
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/args.py +172 -3
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/base.py +191 -20
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/bexio.py +6 -3
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/cache.py +76 -4
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/db_mysql.py +133 -20
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/db_sqlite.py +801 -149
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/disk.py +360 -13
- linuxfabrik_lib-7.0.0/distro.py +1661 -0
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/dmidecode.py +1 -1
- linuxfabrik_lib-7.0.0/endoflifedate.py +5465 -0
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/feedparser.py +114 -14
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/globals.py +1 -1
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/grassfish.py +1 -1
- linuxfabrik_lib-7.0.0/huawei_dorado.py +2314 -0
- linuxfabrik_lib-7.0.0/huawei_pacific.py +1709 -0
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/human.py +1 -1
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/icinga.py +198 -2
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/infomaniak.py +1 -1
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/jitsi.py +1 -1
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/keycloak.py +16 -4
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/lftest.py +157 -11
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/librenms.py +1 -1
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0/linuxfabrik_lib.egg-info}/PKG-INFO +9 -6
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/linuxfabrik_lib.egg-info/SOURCES.txt +6 -0
- linuxfabrik_lib-7.0.0/mail.py +101 -0
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/net.py +1 -1
- linuxfabrik_lib-7.0.0/nextcloud.py +138 -0
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/nodebb.py +1 -1
- linuxfabrik_lib-7.0.0/openmetrics.py +724 -0
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/powershell.py +1 -1
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/psutil.py +1 -1
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/pyproject.toml +22 -4
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/qts.py +1 -1
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/redfish.py +423 -45
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/rocket.py +46 -2
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/shell.py +40 -16
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/smb.py +1 -1
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/ssh.py +38 -15
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/time.py +41 -6
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/txt.py +232 -6
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/uptimerobot.py +1 -1
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/url.py +283 -8
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/veeam.py +1 -1
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/version.py +8 -38
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/wildfly.py +1 -1
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/winrm.py +1 -1
- linuxfabrik_lib-7.0.0/wordpress.py +488 -0
- linuxfabrik_lib-6.0.0/distro.py +0 -449
- linuxfabrik_lib-6.0.0/endoflifedate.py +0 -4253
- linuxfabrik_lib-6.0.0/huawei_dorado.py +0 -866
- linuxfabrik_lib-6.0.0/huawei_pacific.py +0 -288
- linuxfabrik_lib-6.0.0/nextcloud.py +0 -113
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/LICENSE +0 -0
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/__init__.py +0 -0
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/linuxfabrik_lib.egg-info/dependency_links.txt +0 -0
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/linuxfabrik_lib.egg-info/requires.txt +0 -0
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/linuxfabrik_lib.egg-info/top_level.txt +0 -0
- {linuxfabrik_lib-6.0.0 → linuxfabrik_lib-7.0.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: linuxfabrik-lib
|
|
3
|
-
Version:
|
|
3
|
+
Version: 7.0.0
|
|
4
4
|
Summary: Python libraries used in various Linuxfabrik projects, including the 'Linuxfabrik Monitoring Plugins' project.
|
|
5
5
|
Author-email: "Linuxfabrik GmbH, Zurich, Switzerland" <info@linuxfabrik.ch>
|
|
6
6
|
License: This is free and unencumbered software released into the public domain.
|
|
@@ -79,7 +79,6 @@ Dynamic: license-file
|
|
|
79
79
|
<div align="center">
|
|
80
80
|
|
|
81
81
|

|
|
82
|
-
[](https://star-history.com/#Linuxfabrik/lib&Date)
|
|
83
82
|

|
|
84
83
|

|
|
85
84
|
[](https://pypi.org/project/linuxfabrik-lib/)
|
|
@@ -137,13 +136,14 @@ These libraries are built with a clear set of priorities:
|
|
|
137
136
|
|
|
138
137
|
| Module | Description | Key Functions |
|
|
139
138
|
|--------|-------------|---------------|
|
|
140
|
-
| **args.py** | Extends `argparse` with custom input types for monitoring thresholds
|
|
139
|
+
| **args.py** | Extends `argparse` with custom input types for monitoring thresholds, a registry of reusable `--help` texts, and reading a secret from a file instead of the command line. | `csv()`, `float_or_none()`, `help()`, `int_or_none()`, `load_secret()`, `number_unit_method()` |
|
|
141
140
|
| **base.py** | The central library for plugin development. Provides state evaluation, threshold comparison, performance data formatting, ASCII table output, and the `coe()` error-handling pattern. | `coe()`, `cu()`, `get_perfdata()`, `get_state()`, `get_table()`, `get_worst()`, `oao()`, `state2str()` |
|
|
142
141
|
| **globals.py** | Defines the four Nagios/Icinga plugin states: `STATE_OK` (0), `STATE_WARN` (1), `STATE_CRIT` (2), `STATE_UNKNOWN` (3). | -- |
|
|
143
142
|
| **human.py** | Converts raw numbers, byte sizes, bit rates, and durations to human-readable representations and back. Supports binary/SI prefixes and Nagios range syntax with units. | `bits2human()`, `bps2human()`, `bytes2human()`, `human2bytes()`, `human2seconds()`, `humanrange2bytes()`, `number2human()`, `seconds2human()` |
|
|
144
|
-
| **lftest.py** | Test harness for data-driven plugin unit tests, spinning up throwaway containers (including MySQL/MariaDB) as fixtures. | `attach_each()`, `attach_tests()`, `run()`, `run_container()`, `run_mysql_compatible_from_containerfile()`, `test()` |
|
|
143
|
+
| **lftest.py** | Test harness for data-driven plugin unit tests, spinning up throwaway containers (including MySQL/MariaDB) as fixtures. | `attach_each()`, `attach_tests()`, `run()`, `run_container()`, `run_mysql_compatible_from_containerfile()`, `test()`, `test_json()` |
|
|
144
|
+
| **openmetrics.py** | Reads the OpenMetrics and Prometheus text exposition formats served by a `/metrics` endpoint into plain samples, and selects a metric by name and labels. | `get_samples()`, `get_value()`, `parse()` |
|
|
145
145
|
| **time.py** | Date/time conversions between UNIX epochs, ISO strings, and datetime objects, plus time-macro expansion and time differences. Timezone-aware. | `epoch2iso()`, `now()`, `timestr2datetime()`, `timestrdiff()` |
|
|
146
|
-
| **txt.py** | Text processing: regex compilation, substring extraction, multi-line parsing, sensitive data redaction, pluralization, and byte/text encoding conversion. | `compile_regex()`, `extract_str()`, `match_regex()`, `mltext2array()`, `pluralize()`, `to_bytes()`, `to_text()` |
|
|
146
|
+
| **txt.py** | Text processing: regex compilation, substring extraction, multi-line parsing, sensitive data redaction, pluralization, shortening for display, HTML character reference resolution, and byte/text encoding conversion. | `compile_regex()`, `extract_str()`, `match_regex()`, `mltext2array()`, `pluralize()`, `shorten()`, `to_bytes()`, `to_text()`, `unescape()` |
|
|
147
147
|
| **version.py** | Software version parsing, comparison, and End-of-Life checking against [endoflife.date](https://endoflife.date). | `check_eol()`, `version()`, `version2float()` |
|
|
148
148
|
|
|
149
149
|
|
|
@@ -173,6 +173,7 @@ These libraries are built with a clear set of priorities:
|
|
|
173
173
|
| Module | Description | Key Functions |
|
|
174
174
|
|--------|-------------|---------------|
|
|
175
175
|
| **feedparser.py** | Parses Atom and RSS feeds from URLs using BeautifulSoup. | `parse()` |
|
|
176
|
+
| **mail.py** | Sends email over SMTP, with an optional HTML body alongside the plain-text one and inline images referenced by Content-ID. Authenticates when a password is given. | `send()` |
|
|
176
177
|
| **net.py** | Low-level networking: TCP/UDP/TLS and Unix domain sockets, public IP lookup, subnet enumeration, netmask conversion, and hostname validation. | `cidr_to_hosts()`, `fetch()`, `fetch_socket()`, `get_public_ip()`, `get_subnet_hosts()`, `ip_to_cidr()` |
|
|
177
178
|
| **ssh.py** | Runs commands and copies files over SSH by building shell-free `ssh`/`scp`/`rsync` argument lists. | `build_options()`, `rsync()`, `run()`, `scp()`, `target()` |
|
|
178
179
|
| **url.py** | HTTP/1.x and HTTP/2 client (httpx) for HTML, JSON, or raw data. Supports GET/POST, Basic/Digest authentication, TLS version pinning, proxy control, and connection telemetry. | `fetch()`, `fetch_json()`, `get_latest_version_from_github()`, `split_basic_auth()`, `strip_tags()` |
|
|
@@ -193,7 +194,8 @@ These libraries are built with a clear set of priorities:
|
|
|
193
194
|
|--------|-------------|---------------|
|
|
194
195
|
| **bexio.py** | [Bexio](https://www.bexio.com/) business software REST API (contacts, invoices, projects, items, timesheets, and more). | `call_api()`, `fetch_accounts()`, `fetch_contacts()`, `fetch_invoices()`, `fetch_projects()`, `get_all()` |
|
|
195
196
|
| **grassfish.py** | [Grassfish](https://www.grassfish.com/) digital signage REST API. | `fetch_json()`, `set_player_defaults()`, `set_screen_defaults()` |
|
|
196
|
-
| **
|
|
197
|
+
| **huawei_dorado.py** | Huawei [OceanStor Dorado](https://www.huawei.com/) storage DeviceManager REST API: session handling with device ID discovery, paged list walks, current performance counters, sector-to-byte capacity conversion, and the numeric status, model and hardware codes it reports. | `as_code()`, `assert_ok()`, `field()`, `get_all_data()`, `get_data()`, `get_health_status()`, `get_health_status_state()`, `get_performance()`, `get_running_status()`, `get_running_status_state()`, `get_uuid()`, `sectors2bytes()` |
|
|
198
|
+
| **huawei_pacific.py** | Huawei [OceanStor Pacific](https://www.huawei.com/) storage REST API, including the older endpoint generation below `/dsware/service/`, the batch performance interface, and the status codes it reports as numbers and as strings. | `as_code()`, `assert_ok()`, `get_all_data()`, `get_data()`, `get_disk_status()`, `get_disk_status_state()`, `get_management_ips()`, `get_performance()`, `get_pool_status()`, `get_pool_status_state()`, `get_result_code()` |
|
|
197
199
|
| **icinga.py** | [Icinga2](https://icinga.com/) REST API client for querying services and managing acknowledgements and downtimes. | `get_service()`, `remove_ack()`, `remove_downtime()`, `set_ack()`, `set_downtime()` |
|
|
198
200
|
| **infomaniak.py** | [Infomaniak](https://www.infomaniak.com/) Swiss Backup REST API for events, backup products, and slots. | `get_events()`, `get_swiss_backup_products()`, `get_swiss_backup_slots()` |
|
|
199
201
|
| **jitsi.py** | [Jitsi Meet](https://jitsi.org/) server statistics endpoint, with optional HTTP Basic auth. | `get_data()` |
|
|
@@ -207,6 +209,7 @@ These libraries are built with a clear set of priorities:
|
|
|
207
209
|
| **uptimerobot.py** | [UptimeRobot](https://uptimerobot.com/) API for monitors, alert contacts, maintenance windows, and status pages. | `delete_monitor()`, `edit_monitor()`, `get_account_details()`, `get_alert_contacts()`, `get_monitors()`, `get_mwindows()`, `get_psps()`, `new_monitor()` |
|
|
208
210
|
| **veeam.py** | [Veeam](https://www.veeam.com/) Backup & Replication Enterprise Manager REST API. | `get_token()` |
|
|
209
211
|
| **wildfly.py** | [WildFly/JBoss](https://www.wildfly.org/) management API with digest auth (standalone and domain mode). | `get_data()` |
|
|
212
|
+
| **wordpress.py** | [WordPress](https://wordpress.org/) installation read straight from the filesystem: core version, installed plugins and themes, the configured site URL, and any file header field. Needs no database, no HTTP request and no `wp-cli`. | `get_header_value()`, `get_plugins()`, `get_site_url()`, `get_themes()`, `get_version()`, `is_installation()` |
|
|
210
213
|
|
|
211
214
|
|
|
212
215
|
## Usage Example
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
<div align="center">
|
|
10
10
|
|
|
11
11
|

|
|
12
|
-
[](https://star-history.com/#Linuxfabrik/lib&Date)
|
|
13
12
|

|
|
14
13
|

|
|
15
14
|
[](https://pypi.org/project/linuxfabrik-lib/)
|
|
@@ -67,13 +66,14 @@ These libraries are built with a clear set of priorities:
|
|
|
67
66
|
|
|
68
67
|
| Module | Description | Key Functions |
|
|
69
68
|
|--------|-------------|---------------|
|
|
70
|
-
| **args.py** | Extends `argparse` with custom input types for monitoring thresholds
|
|
69
|
+
| **args.py** | Extends `argparse` with custom input types for monitoring thresholds, a registry of reusable `--help` texts, and reading a secret from a file instead of the command line. | `csv()`, `float_or_none()`, `help()`, `int_or_none()`, `load_secret()`, `number_unit_method()` |
|
|
71
70
|
| **base.py** | The central library for plugin development. Provides state evaluation, threshold comparison, performance data formatting, ASCII table output, and the `coe()` error-handling pattern. | `coe()`, `cu()`, `get_perfdata()`, `get_state()`, `get_table()`, `get_worst()`, `oao()`, `state2str()` |
|
|
72
71
|
| **globals.py** | Defines the four Nagios/Icinga plugin states: `STATE_OK` (0), `STATE_WARN` (1), `STATE_CRIT` (2), `STATE_UNKNOWN` (3). | -- |
|
|
73
72
|
| **human.py** | Converts raw numbers, byte sizes, bit rates, and durations to human-readable representations and back. Supports binary/SI prefixes and Nagios range syntax with units. | `bits2human()`, `bps2human()`, `bytes2human()`, `human2bytes()`, `human2seconds()`, `humanrange2bytes()`, `number2human()`, `seconds2human()` |
|
|
74
|
-
| **lftest.py** | Test harness for data-driven plugin unit tests, spinning up throwaway containers (including MySQL/MariaDB) as fixtures. | `attach_each()`, `attach_tests()`, `run()`, `run_container()`, `run_mysql_compatible_from_containerfile()`, `test()` |
|
|
73
|
+
| **lftest.py** | Test harness for data-driven plugin unit tests, spinning up throwaway containers (including MySQL/MariaDB) as fixtures. | `attach_each()`, `attach_tests()`, `run()`, `run_container()`, `run_mysql_compatible_from_containerfile()`, `test()`, `test_json()` |
|
|
74
|
+
| **openmetrics.py** | Reads the OpenMetrics and Prometheus text exposition formats served by a `/metrics` endpoint into plain samples, and selects a metric by name and labels. | `get_samples()`, `get_value()`, `parse()` |
|
|
75
75
|
| **time.py** | Date/time conversions between UNIX epochs, ISO strings, and datetime objects, plus time-macro expansion and time differences. Timezone-aware. | `epoch2iso()`, `now()`, `timestr2datetime()`, `timestrdiff()` |
|
|
76
|
-
| **txt.py** | Text processing: regex compilation, substring extraction, multi-line parsing, sensitive data redaction, pluralization, and byte/text encoding conversion. | `compile_regex()`, `extract_str()`, `match_regex()`, `mltext2array()`, `pluralize()`, `to_bytes()`, `to_text()` |
|
|
76
|
+
| **txt.py** | Text processing: regex compilation, substring extraction, multi-line parsing, sensitive data redaction, pluralization, shortening for display, HTML character reference resolution, and byte/text encoding conversion. | `compile_regex()`, `extract_str()`, `match_regex()`, `mltext2array()`, `pluralize()`, `shorten()`, `to_bytes()`, `to_text()`, `unescape()` |
|
|
77
77
|
| **version.py** | Software version parsing, comparison, and End-of-Life checking against [endoflife.date](https://endoflife.date). | `check_eol()`, `version()`, `version2float()` |
|
|
78
78
|
|
|
79
79
|
|
|
@@ -103,6 +103,7 @@ These libraries are built with a clear set of priorities:
|
|
|
103
103
|
| Module | Description | Key Functions |
|
|
104
104
|
|--------|-------------|---------------|
|
|
105
105
|
| **feedparser.py** | Parses Atom and RSS feeds from URLs using BeautifulSoup. | `parse()` |
|
|
106
|
+
| **mail.py** | Sends email over SMTP, with an optional HTML body alongside the plain-text one and inline images referenced by Content-ID. Authenticates when a password is given. | `send()` |
|
|
106
107
|
| **net.py** | Low-level networking: TCP/UDP/TLS and Unix domain sockets, public IP lookup, subnet enumeration, netmask conversion, and hostname validation. | `cidr_to_hosts()`, `fetch()`, `fetch_socket()`, `get_public_ip()`, `get_subnet_hosts()`, `ip_to_cidr()` |
|
|
107
108
|
| **ssh.py** | Runs commands and copies files over SSH by building shell-free `ssh`/`scp`/`rsync` argument lists. | `build_options()`, `rsync()`, `run()`, `scp()`, `target()` |
|
|
108
109
|
| **url.py** | HTTP/1.x and HTTP/2 client (httpx) for HTML, JSON, or raw data. Supports GET/POST, Basic/Digest authentication, TLS version pinning, proxy control, and connection telemetry. | `fetch()`, `fetch_json()`, `get_latest_version_from_github()`, `split_basic_auth()`, `strip_tags()` |
|
|
@@ -123,7 +124,8 @@ These libraries are built with a clear set of priorities:
|
|
|
123
124
|
|--------|-------------|---------------|
|
|
124
125
|
| **bexio.py** | [Bexio](https://www.bexio.com/) business software REST API (contacts, invoices, projects, items, timesheets, and more). | `call_api()`, `fetch_accounts()`, `fetch_contacts()`, `fetch_invoices()`, `fetch_projects()`, `get_all()` |
|
|
125
126
|
| **grassfish.py** | [Grassfish](https://www.grassfish.com/) digital signage REST API. | `fetch_json()`, `set_player_defaults()`, `set_screen_defaults()` |
|
|
126
|
-
| **
|
|
127
|
+
| **huawei_dorado.py** | Huawei [OceanStor Dorado](https://www.huawei.com/) storage DeviceManager REST API: session handling with device ID discovery, paged list walks, current performance counters, sector-to-byte capacity conversion, and the numeric status, model and hardware codes it reports. | `as_code()`, `assert_ok()`, `field()`, `get_all_data()`, `get_data()`, `get_health_status()`, `get_health_status_state()`, `get_performance()`, `get_running_status()`, `get_running_status_state()`, `get_uuid()`, `sectors2bytes()` |
|
|
128
|
+
| **huawei_pacific.py** | Huawei [OceanStor Pacific](https://www.huawei.com/) storage REST API, including the older endpoint generation below `/dsware/service/`, the batch performance interface, and the status codes it reports as numbers and as strings. | `as_code()`, `assert_ok()`, `get_all_data()`, `get_data()`, `get_disk_status()`, `get_disk_status_state()`, `get_management_ips()`, `get_performance()`, `get_pool_status()`, `get_pool_status_state()`, `get_result_code()` |
|
|
127
129
|
| **icinga.py** | [Icinga2](https://icinga.com/) REST API client for querying services and managing acknowledgements and downtimes. | `get_service()`, `remove_ack()`, `remove_downtime()`, `set_ack()`, `set_downtime()` |
|
|
128
130
|
| **infomaniak.py** | [Infomaniak](https://www.infomaniak.com/) Swiss Backup REST API for events, backup products, and slots. | `get_events()`, `get_swiss_backup_products()`, `get_swiss_backup_slots()` |
|
|
129
131
|
| **jitsi.py** | [Jitsi Meet](https://jitsi.org/) server statistics endpoint, with optional HTTP Basic auth. | `get_data()` |
|
|
@@ -137,6 +139,7 @@ These libraries are built with a clear set of priorities:
|
|
|
137
139
|
| **uptimerobot.py** | [UptimeRobot](https://uptimerobot.com/) API for monitors, alert contacts, maintenance windows, and status pages. | `delete_monitor()`, `edit_monitor()`, `get_account_details()`, `get_alert_contacts()`, `get_monitors()`, `get_mwindows()`, `get_psps()`, `new_monitor()` |
|
|
138
140
|
| **veeam.py** | [Veeam](https://www.veeam.com/) Backup & Replication Enterprise Manager REST API. | `get_token()` |
|
|
139
141
|
| **wildfly.py** | [WildFly/JBoss](https://www.wildfly.org/) management API with digest auth (standalone and domain mode). | `get_data()` |
|
|
142
|
+
| **wordpress.py** | [WordPress](https://wordpress.org/) installation read straight from the filesystem: core version, installed plugins and themes, the configured site URL, and any file header field. Needs no database, no HTTP request and no `wp-cli`. | `get_header_value()`, `get_plugins()`, `get_site_url()`, `get_themes()`, `get_version()`, `is_installation()` |
|
|
140
143
|
|
|
141
144
|
|
|
142
145
|
## Usage Example
|
|
@@ -11,9 +11,28 @@
|
|
|
11
11
|
"""Extends argparse by new input argument data types on demand."""
|
|
12
12
|
|
|
13
13
|
import argparse
|
|
14
|
+
import os
|
|
15
|
+
import re
|
|
16
|
+
import textwrap
|
|
17
|
+
|
|
18
|
+
from . import base, disk
|
|
14
19
|
|
|
15
20
|
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
|
|
16
|
-
__version__ = '
|
|
21
|
+
__version__ = '2026081003'
|
|
22
|
+
|
|
23
|
+
# Base URL of the rendered online documentation.
|
|
24
|
+
DOCS_BASE_URL = 'https://linuxfabrik.github.io/monitoring-plugins'
|
|
25
|
+
|
|
26
|
+
# How an include filter and an exclude filter combine, for the consumers that offer both.
|
|
27
|
+
# Kept out of the two help texts themselves and appended by the consumer, because the
|
|
28
|
+
# purpose sentence in front of it names whatever the consumer filters - items, mount
|
|
29
|
+
# points, disks, findings - while this sentence is the same everywhere. It belongs on the
|
|
30
|
+
# include filter alone: it describes the pair, and saying it twice only makes both entries
|
|
31
|
+
# longer.
|
|
32
|
+
MATCH_IGNORE_PRECEDENCE = (
|
|
33
|
+
'If both `--match` and `--ignore` are given, an item must match `--match` AND not '
|
|
34
|
+
'match `--ignore` to be reported (include first, exclude second).'
|
|
35
|
+
)
|
|
17
36
|
|
|
18
37
|
|
|
19
38
|
# Help text descriptions only - no "Default:" here.
|
|
@@ -22,6 +41,12 @@ __version__ = '2026070201'
|
|
|
22
41
|
# Switches (store_true/store_false) don't need a default.
|
|
23
42
|
HELP_TEXTS = {
|
|
24
43
|
'--always-ok': 'Always returns OK.',
|
|
44
|
+
'--brief': (
|
|
45
|
+
'Hide the rows that are within the thresholds and show only those in a WARN or '
|
|
46
|
+
'CRIT state. '
|
|
47
|
+
'Perfdata and alerting are unaffected: every item still emits performance data '
|
|
48
|
+
'and still drives the overall check state, so this is safe to leave on.'
|
|
49
|
+
),
|
|
25
50
|
'--cache-expire': (
|
|
26
51
|
'The amount of time after which the credential/data cache expires, in minutes.'
|
|
27
52
|
),
|
|
@@ -53,11 +78,19 @@ HELP_TEXTS = {
|
|
|
53
78
|
'--critical': 'CRIT threshold in percent.',
|
|
54
79
|
'--critical-count': 'CRIT threshold for the number of matching items.',
|
|
55
80
|
'--critical-seconds': 'CRIT threshold in seconds.',
|
|
81
|
+
'--critical-temperature': 'CRIT threshold in degrees Celsius.',
|
|
82
|
+
'--critical-voltage': 'CRIT threshold in volts.',
|
|
56
83
|
'--defaults-file': (
|
|
57
84
|
'Specifies a cnf file to read parameters like user, host and password from '
|
|
58
85
|
'(for MySQL/MariaDB cnf-style files).'
|
|
59
86
|
),
|
|
60
87
|
'--defaults-group': 'Group/section to read from in the cnf file.',
|
|
88
|
+
'--fail-severity': (
|
|
89
|
+
'State to report for an item the monitored system itself marks as failed. '
|
|
90
|
+
'A failed item means the installation is broken in a way that stops it from '
|
|
91
|
+
'working correctly, which is worth acting on but rarely worth waking somebody '
|
|
92
|
+
'up for.'
|
|
93
|
+
),
|
|
61
94
|
'--hostname': 'Hostname or IP address.',
|
|
62
95
|
'--ipv6': 'Use IPv6.',
|
|
63
96
|
'--ignore': (
|
|
@@ -78,22 +111,60 @@ HELP_TEXTS = {
|
|
|
78
111
|
),
|
|
79
112
|
'--insecure': 'This option explicitly allows insecure SSL connections.',
|
|
80
113
|
'--lengthy': 'Extended reporting.',
|
|
114
|
+
'--link-down-severity': (
|
|
115
|
+
'State to report for a port whose link is down. '
|
|
116
|
+
'A port that is simply not cabled reports the same thing, which is why this '
|
|
117
|
+
'defaults to not alerting.'
|
|
118
|
+
),
|
|
81
119
|
'--match': (
|
|
82
120
|
'Filter by this Python regular expression. '
|
|
83
121
|
'Case-sensitive by default; use `(?i)` for case-insensitive matching. '
|
|
84
122
|
'Can be specified multiple times. '
|
|
123
|
+
f'{MATCH_IGNORE_PRECEDENCE} '
|
|
85
124
|
'Examples: '
|
|
86
125
|
'`(?i)example` to match "example" regardless of case. '
|
|
87
126
|
'`^(?!.*example).*$` to match any string except "example" (negative lookahead).'
|
|
88
127
|
),
|
|
128
|
+
'--no-checksum-data-severity': (
|
|
129
|
+
'State to report when no published checksums are available for a component and it '
|
|
130
|
+
'could not be verified. '
|
|
131
|
+
'The check still verifies everything it has checksums for, but a clean result then '
|
|
132
|
+
'only covers those components, not the ones it had to skip.'
|
|
133
|
+
),
|
|
134
|
+
'--no-insecure': (
|
|
135
|
+
'Verify the TLS certificate against the system trust store, overriding the '
|
|
136
|
+
'insecure default of this check. '
|
|
137
|
+
'Use it once the endpoint presents a publicly trusted certificate, or once its '
|
|
138
|
+
'CA has been added to the system trust store.'
|
|
139
|
+
),
|
|
89
140
|
'--no-match-severity': (
|
|
90
141
|
'State to report when no item matches the filters and nothing is checked.'
|
|
91
142
|
),
|
|
143
|
+
'--no-perfdata': (
|
|
144
|
+
'Suppress the performance data section from the output. '
|
|
145
|
+
'The status message and the exit code are unaffected, so alerting keeps working '
|
|
146
|
+
'while trending data is dropped.'
|
|
147
|
+
),
|
|
92
148
|
'--no-proxy': 'Do not use a proxy.',
|
|
149
|
+
'--no-vuln-data-severity': (
|
|
150
|
+
'State to report when the vulnerability database could not be queried and no '
|
|
151
|
+
'vulnerability data is available. '
|
|
152
|
+
'The check still reports everything it can determine without that data, but a '
|
|
153
|
+
'clean result then only means nothing else was found, not that the target is '
|
|
154
|
+
'free of known vulnerabilities.'
|
|
155
|
+
),
|
|
93
156
|
'--offset-eol': (
|
|
94
157
|
'Alert n days before ("-30") or after an EOL date ("30" or "+30").'
|
|
95
158
|
),
|
|
96
159
|
'--password': 'Password.',
|
|
160
|
+
'--password-file': (
|
|
161
|
+
'Path to a file holding the password, read from its first line. '
|
|
162
|
+
'Keeps the password out of the process list, where a command-line argument is '
|
|
163
|
+
'visible to every user on the host. '
|
|
164
|
+
'Takes precedence over `--password`. '
|
|
165
|
+
'Keep the file readable only by the monitoring user. '
|
|
166
|
+
'Example: `--password-file=/etc/icinga2/secrets/storage`.'
|
|
167
|
+
),
|
|
97
168
|
'--path': 'Local path to the installation.',
|
|
98
169
|
'--port': 'Port number.',
|
|
99
170
|
'--severity': 'Severity for alerting.',
|
|
@@ -112,8 +183,16 @@ HELP_TEXTS = {
|
|
|
112
183
|
'--test': argparse.SUPPRESS,
|
|
113
184
|
'--timeout': 'Network timeout in seconds.',
|
|
114
185
|
'--unreachable-severity': (
|
|
115
|
-
'State to report when the online
|
|
116
|
-
'
|
|
186
|
+
'State to report when the online source is unreachable. '
|
|
187
|
+
'What is used instead - bundled offline data, a cached copy, or nothing at all - '
|
|
188
|
+
'is named in the output, and a clean result then only covers what that fallback '
|
|
189
|
+
'could confirm.'
|
|
190
|
+
),
|
|
191
|
+
'--unscored-severity': (
|
|
192
|
+
'State to report for a finding that carries no severity score of its own. '
|
|
193
|
+
'A source that scores its findings rarely scores all of them, and the unrated '
|
|
194
|
+
'ones need a state of their own rather than the one a score would have earned '
|
|
195
|
+
'them.'
|
|
117
196
|
),
|
|
118
197
|
'--url': 'URL to the endpoint.',
|
|
119
198
|
'--username': 'Username.',
|
|
@@ -124,6 +203,8 @@ HELP_TEXTS = {
|
|
|
124
203
|
'--warning': 'WARN threshold in percent.',
|
|
125
204
|
'--warning-count': 'WARN threshold for the number of matching items.',
|
|
126
205
|
'--warning-seconds': 'WARN threshold in seconds.',
|
|
206
|
+
'--warning-temperature': 'WARN threshold in degrees Celsius.',
|
|
207
|
+
'--warning-voltage': 'WARN threshold in volts.',
|
|
127
208
|
}
|
|
128
209
|
|
|
129
210
|
|
|
@@ -132,6 +213,25 @@ _UNITS = {'%', 'K', 'M', 'G', 'T', 'P'}
|
|
|
132
213
|
_METHODS = {'USED', 'FREE'}
|
|
133
214
|
|
|
134
215
|
|
|
216
|
+
class HelpFormatter(argparse.HelpFormatter):
|
|
217
|
+
"""Formats the help output like argparse does, but never splits long words.
|
|
218
|
+
|
|
219
|
+
argparse's default formatter breaks words at hyphens to fit the terminal width,
|
|
220
|
+
which turns a URL like `https://example.com/a-b/c/` into two unusable fragments.
|
|
221
|
+
Here, a word that does not fit is kept intact and overflows instead.
|
|
222
|
+
"""
|
|
223
|
+
|
|
224
|
+
def _fill_text(self, text, width, indent):
|
|
225
|
+
return textwrap.fill(
|
|
226
|
+
re.sub(r'\s+', ' ', text).strip(),
|
|
227
|
+
width,
|
|
228
|
+
initial_indent=indent,
|
|
229
|
+
subsequent_indent=indent,
|
|
230
|
+
break_long_words=False,
|
|
231
|
+
break_on_hyphens=False,
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
|
|
135
235
|
def csv(arg):
|
|
136
236
|
"""Converts a CSV string into a list of values.
|
|
137
237
|
|
|
@@ -148,6 +248,34 @@ def csv(arg):
|
|
|
148
248
|
return [x.strip() for x in arg.split(',')]
|
|
149
249
|
|
|
150
250
|
|
|
251
|
+
def epilog(path, section='check-plugins'):
|
|
252
|
+
"""Builds a pointer to the online documentation, to be used as an argparse epilog.
|
|
253
|
+
|
|
254
|
+
The document name is derived from the file name of the calling script, so pass
|
|
255
|
+
`__file__`. A trailing `.exe` or `.py` extension is stripped.
|
|
256
|
+
|
|
257
|
+
Use together with `HelpFormatter`, otherwise argparse breaks the URL at its hyphens.
|
|
258
|
+
|
|
259
|
+
### Parameters
|
|
260
|
+
- **path** (`str`): Path of the calling script, normally `__file__`.
|
|
261
|
+
- **section** (`str`, optional): Section the document lives in.
|
|
262
|
+
Defaults to `check-plugins`.
|
|
263
|
+
|
|
264
|
+
### Returns
|
|
265
|
+
- **str**: A single line pointing to the documentation URL.
|
|
266
|
+
|
|
267
|
+
### Example
|
|
268
|
+
>>> epilog('/usr/lib64/nagios/plugins/example')
|
|
269
|
+
'Documentation: https://linuxfabrik.github.io/monitoring-plugins/check-plugins/example/'
|
|
270
|
+
"""
|
|
271
|
+
name = os.path.basename(path)
|
|
272
|
+
for suffix in ('.exe', '.py'):
|
|
273
|
+
if name.lower().endswith(suffix):
|
|
274
|
+
name = name[: -len(suffix)]
|
|
275
|
+
break
|
|
276
|
+
return f'Documentation: {DOCS_BASE_URL}/{section}/{name}/'
|
|
277
|
+
|
|
278
|
+
|
|
151
279
|
def float_or_none(arg):
|
|
152
280
|
"""Converts an input to a float, or returns None if the input is 'none' or None.
|
|
153
281
|
|
|
@@ -214,6 +342,47 @@ def int_or_none(arg):
|
|
|
214
342
|
return int(arg)
|
|
215
343
|
|
|
216
344
|
|
|
345
|
+
def load_secret(path, param='--password-file'):
|
|
346
|
+
"""
|
|
347
|
+
Read a secret out of a file, so it does not have to be passed on the command line.
|
|
348
|
+
|
|
349
|
+
A command-line argument is visible to every user on the host for as long as the
|
|
350
|
+
process runs, and a monitoring plugin runs on a schedule. Reading the secret from a
|
|
351
|
+
file that only the monitoring user can read keeps it out of the process list.
|
|
352
|
+
|
|
353
|
+
### Parameters
|
|
354
|
+
- **path** (`str`): The file to read.
|
|
355
|
+
- **param** (`str`, optional): The parameter name to use in an error message.
|
|
356
|
+
|
|
357
|
+
### Returns
|
|
358
|
+
- **str**: The secret, without the trailing newline a text editor appends.
|
|
359
|
+
|
|
360
|
+
### Notes
|
|
361
|
+
- Aborts the calling process (UNKNOWN) when the file cannot be read or holds nothing.
|
|
362
|
+
A secret that silently comes out empty would be sent to the remote end as an empty
|
|
363
|
+
password, which drives the account towards its lockout threshold.
|
|
364
|
+
- Only the first line is used, and only its trailing newline is stripped. Leading and
|
|
365
|
+
trailing spaces are part of a password, and stripping them would make a valid
|
|
366
|
+
password fail with no way to tell why.
|
|
367
|
+
- The file permissions are deliberately not enforced here. Which user a check runs as
|
|
368
|
+
differs per deployment, and refusing to start over a permission bit would take a
|
|
369
|
+
working check down; keeping the file readable only by the monitoring user is the
|
|
370
|
+
documented operator's job.
|
|
371
|
+
|
|
372
|
+
### Example
|
|
373
|
+
>>> load_secret('/etc/icinga2/secrets/storage')
|
|
374
|
+
'linuxfabrik'
|
|
375
|
+
"""
|
|
376
|
+
success, content = disk.read_file(path)
|
|
377
|
+
if not success:
|
|
378
|
+
base.cu(f'Cannot read the file given in {param}: {content}')
|
|
379
|
+
|
|
380
|
+
secret = content.split('\n', 1)[0].rstrip('\r')
|
|
381
|
+
if not secret:
|
|
382
|
+
base.cu(f'The file given in {param} is empty.')
|
|
383
|
+
return secret
|
|
384
|
+
|
|
385
|
+
|
|
217
386
|
def number_unit_method(arg, unit='%', method='USED'):
|
|
218
387
|
"""Parses a string in the format `<number>[unit][method]` for threshold arguments.
|
|
219
388
|
|