MKP 3.2.0 released, fixed bugs when users are deleted and rules without levels are active
This commit is contained in:
BIN
.README.md.swp
Normal file
BIN
.README.md.swp
Normal file
Binary file not shown.
12
README.md
12
README.md
@@ -1,11 +1,16 @@
|
|||||||
# Nextcloud CheckMK Special Agent
|
# Nextcloud CheckMK Special Agent
|
||||||
Monitors various aspects of Nextcloud instances like state, quota and disk usage of all users, number of apps with available updates, database php opcache hit rate and so on.
|
Monitors various aspects of Nextcloud instances like state, quota and disk usage of all users, number of apps with available updates, database php opcache hit rate and so on.
|
||||||
Gives additional information regarding versions of Nextcloud, database, number of storages and active users etc.
|
Gives additional information regarding versions of Nextcloud, database, number of storages and active users etc.
|
||||||
Tested only with Nextcloud versions 29/30
|
|
||||||
|
Tested only with Nextcloud versions 29/30/31/32
|
||||||
|
|
||||||
Tested only with MariaDB as database backend
|
Tested only with MariaDB as database backend
|
||||||
|
|
||||||
The whole plugin is now migrated to the new plugin API version, introduced with CheckMK 2.3
|
The whole plugin is now migrated to the new plugin API version, introduced with CheckMK 2.3
|
||||||
|
|
||||||
Feel free to report other working environments.
|
Feel free to report other working environments.
|
||||||
|
|
||||||
|
|
||||||
Upgrade from older MKPs (before 3.1.1):
|
Upgrade from older MKPs (before 3.1.1):
|
||||||
|
|
||||||
If you upgrade from a already installed MKP version before 3.1.0, you have to re-create your rules for the "Nextcloud Server Information" (reason: some parameter changes combined with the migration to the new plugin API).
|
If you upgrade from a already installed MKP version before 3.1.0, you have to re-create your rules for the "Nextcloud Server Information" (reason: some parameter changes combined with the migration to the new plugin API).
|
||||||
@@ -18,7 +23,7 @@ Hint: It is always a good idea to create screenshots from all other Nextcloud ru
|
|||||||
5. Re-create your rules with the previously saved information from steps 1 and 2
|
5. Re-create your rules with the previously saved information from steps 1 and 2
|
||||||
6. Apply your changes
|
6. Apply your changes
|
||||||
|
|
||||||
Hint: You have to create an app password now for accessing your Nextcloud instance. For this to accomplish login to your Nextcloud server with an administrative user account. Go to "Personal Settings|Security" and take note of the section "Devices & Sessions". Create the app password via clicking the button "create new app password". You may use this password explicitly within the rule or store it first in the password safe of CheckMK.
|
Hint: You have to create an app password now for accessing your Nextcloud instance. For this to accomplish login to your Nextcloud server with an administrative user account. Go to "Personal Settings|Security" and take note of the section "Devices & Sessions". Create the app password via clicking the button "create new app password". You may use this password explicitly within the rule or store it first in the password safe of CheckMK (recommended).
|
||||||
|
|
||||||
|
|
||||||
General installation instructions:
|
General installation instructions:
|
||||||
@@ -40,7 +45,8 @@ Version History:
|
|||||||
--
|
--
|
||||||
|Date|Version|Changes|
|
|Date|Version|Changes|
|
||||||
|----|-------|-------|
|
|----|-------|-------|
|
||||||
|2025/03/30|3.1.1|Migration to the new plugin API version finished, (hopefully) ready for CheckMK version 2.4
|
|2026/03/09|3.2.0|Fixed bugs when: Users are deleted, quotas not set, rules with no levels are active|
|
||||||
|
|2025/03/30|3.1.1|Migration to the new plugin API version finished, (hopefully) ready for CheckMK version 2.4|
|
||||||
|2023/01/13|2.5.2|Repackaged only to set the minimum required version back to 2.1.0p1, due to serveral user requests|
|
|2023/01/13|2.5.2|Repackaged only to set the minimum required version back to 2.1.0p1, due to serveral user requests|
|
||||||
|2023/01/12|2.5.1|Added versions for apps with available updates|
|
|2023/01/12|2.5.1|Added versions for apps with available updates|
|
||||||
|2023/01/12|2.4.1|Removed Parameter "token", switched to parameter "app password" only|
|
|2023/01/12|2.4.1|Removed Parameter "token", switched to parameter "app password" only|
|
||||||
|
|||||||
BIN
mkp/Nextcloud-3.2.0.mkp
Normal file
BIN
mkp/Nextcloud-3.2.0.mkp
Normal file
Binary file not shown.
@@ -2,6 +2,7 @@
|
|||||||
# pylint: disable=missing-module-docstring, unused-argument, missing-function-docstring
|
# pylint: disable=missing-module-docstring, unused-argument, missing-function-docstring
|
||||||
# pylint: disable=line-too-long
|
# pylint: disable=line-too-long
|
||||||
|
|
||||||
|
from typing import Final
|
||||||
from collections.abc import Mapping
|
from collections.abc import Mapping
|
||||||
from typing import NotRequired, TypedDict
|
from typing import NotRequired, TypedDict
|
||||||
|
|
||||||
@@ -18,6 +19,8 @@ from cmk.agent_based.v2 import (
|
|||||||
DiscoveryResult,
|
DiscoveryResult,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
NO_LEVELS: Final[str] = "no_levels"
|
||||||
|
|
||||||
|
|
||||||
class _ItemData(TypedDict):
|
class _ItemData(TypedDict):
|
||||||
dbtype: NotRequired[str]
|
dbtype: NotRequired[str]
|
||||||
@@ -49,14 +52,18 @@ def check_nextcloud_database(params, section) -> CheckResult:
|
|||||||
size = section[key]["size"]
|
size = section[key]["size"]
|
||||||
dbtype = section[key]["dbtype"]
|
dbtype = section[key]["dbtype"]
|
||||||
version = section[key]["version"]
|
version = section[key]["version"]
|
||||||
_level_type, levels = params["levels_database_opcache_hit_rate"]
|
level_type, levels = params["levels_database_opcache_hit_rate"]
|
||||||
# create graph for opcache hit rate
|
# create graph for opcache hit rate
|
||||||
yield Metric(
|
if level_type == NO_LEVELS:
|
||||||
"nc_database_opcache_hit_rate", opcache_hit_rate, levels=levels
|
yield Metric("nc_database_opcache_hit_rate", opcache_hit_rate)
|
||||||
)
|
state = State.OK
|
||||||
|
else:
|
||||||
|
yield Metric(
|
||||||
|
"nc_database_opcache_hit_rate", opcache_hit_rate, levels=levels
|
||||||
|
)
|
||||||
|
state = get_state_lower(levels, opcache_hit_rate)
|
||||||
# create graph for database size
|
# create graph for database size
|
||||||
yield Metric("nc_database_size", size)
|
yield Metric("nc_database_size", size)
|
||||||
state = get_state_lower(levels, opcache_hit_rate)
|
|
||||||
summary = f"PHP OPCache hit rate: {render.percent(opcache_hit_rate)}"
|
summary = f"PHP OPCache hit rate: {render.percent(opcache_hit_rate)}"
|
||||||
if opcache_hit_rate == 0:
|
if opcache_hit_rate == 0:
|
||||||
state = State.UNKNOWN
|
state = State.UNKNOWN
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
# pylint: disable=line-too-long, too-many-branches, too-many-locals, too-many-statements
|
# pylint: disable=line-too-long, too-many-branches, too-many-locals, too-many-statements
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Final
|
||||||
|
|
||||||
from cmk.agent_based.v2 import (
|
from cmk.agent_based.v2 import (
|
||||||
AgentSection,
|
AgentSection,
|
||||||
@@ -17,6 +18,7 @@ from cmk.agent_based.v2 import (
|
|||||||
DiscoveryResult,
|
DiscoveryResult,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
NO_LEVELS: Final[str] = "no_levels"
|
||||||
|
|
||||||
def get_state_upper(levels, value):
|
def get_state_upper(levels, value):
|
||||||
warn, crit = levels
|
warn, crit = levels
|
||||||
@@ -43,8 +45,8 @@ def discover_nextcloud_info(section) -> DiscoveryResult:
|
|||||||
def check_nextcloud_info(params, section) -> CheckResult:
|
def check_nextcloud_info(params, section) -> CheckResult:
|
||||||
for key in section:
|
for key in section:
|
||||||
if key == "nextcloud":
|
if key == "nextcloud":
|
||||||
_level_type, levels_free_space = params["levels_free_space"]
|
level_type_free_space, levels_free_space = params["levels_free_space"]
|
||||||
_level_type, levels_number_of_files = params["levels_number_of_files"]
|
level_type_number_of_files, levels_number_of_files = params["levels_number_of_files"]
|
||||||
# update infos are available only from Nextcloud version 28 onwards
|
# update infos are available only from Nextcloud version 28 onwards
|
||||||
try:
|
try:
|
||||||
last_update = section[key]["last_update"]
|
last_update = section[key]["last_update"]
|
||||||
@@ -89,19 +91,28 @@ def check_nextcloud_info(params, section) -> CheckResult:
|
|||||||
|
|
||||||
# Create result for free space on disk
|
# Create result for free space on disk
|
||||||
# Levels for free space are given in GBytes, we have to adjust this here
|
# Levels for free space are given in GBytes, we have to adjust this here
|
||||||
warn, crit = levels_free_space
|
if level_type_free_space != NO_LEVELS:
|
||||||
warn = warn * 1024 * 1024 * 1024
|
warn, crit = levels_free_space
|
||||||
crit = crit * 1024 * 1024 * 1024
|
warn = warn * 1024 * 1024 * 1024
|
||||||
state = get_state_lower((warn, crit), free_space)
|
crit = crit * 1024 * 1024 * 1024
|
||||||
# create graph for free space on disk
|
state = get_state_lower((warn, crit), free_space)
|
||||||
yield Metric("nc_free_space", free_space, levels=(warn, crit))
|
# create graph for free space on disk
|
||||||
|
yield Metric("nc_free_space", free_space, levels=(warn, crit))
|
||||||
|
else:
|
||||||
|
# a rule with no levels set is active, assume OK state
|
||||||
|
state = State.OK
|
||||||
|
yield Metric("nc_free_space", free_space)
|
||||||
notice = f"Remaining free space on disk: {render.bytes(free_space)}"
|
notice = f"Remaining free space on disk: {render.bytes(free_space)}"
|
||||||
if state != State.OK:
|
if state != State.OK:
|
||||||
yield Result(state=state, notice=notice)
|
yield Result(state=state, notice=notice)
|
||||||
|
|
||||||
# Create result for number of files
|
# Create result for number of files
|
||||||
warn, crit = levels_number_of_files
|
if level_type_number_of_files != NO_LEVELS:
|
||||||
state = get_state_upper((warn, crit), num_files)
|
warn, crit = levels_number_of_files
|
||||||
|
state = get_state_upper((warn, crit), num_files)
|
||||||
|
else:
|
||||||
|
# a rule with no levels set is active, assume OK state
|
||||||
|
state = State.OK
|
||||||
notice = f"Number of files: {num_files}"
|
notice = f"Number of files: {num_files}"
|
||||||
if state != State.OK:
|
if state != State.OK:
|
||||||
yield Result(state=state, notice=notice)
|
yield Result(state=state, notice=notice)
|
||||||
@@ -139,14 +150,22 @@ def check_nextcloud_info(params, section) -> CheckResult:
|
|||||||
else:
|
else:
|
||||||
app_versions = ""
|
app_versions = ""
|
||||||
# create graphs for number of apps
|
# create graphs for number of apps
|
||||||
_level_type, levels = params["levels_apps_with_updates_available"]
|
level_type, levels = params["levels_apps_with_updates_available"]
|
||||||
yield Metric("nc_num_apps_installed", num_apps_installed)
|
yield Metric("nc_num_apps_installed", num_apps_installed)
|
||||||
yield Metric(
|
if level_type != NO_LEVELS:
|
||||||
"nc_apps_with_updates_available",
|
yield Metric(
|
||||||
num_apps_with_updates_available,
|
"nc_apps_with_updates_available",
|
||||||
levels=levels,
|
num_apps_with_updates_available,
|
||||||
)
|
levels=levels,
|
||||||
state = get_state_upper(levels, num_apps_with_updates_available)
|
)
|
||||||
|
state = get_state_upper(levels, num_apps_with_updates_available)
|
||||||
|
else:
|
||||||
|
# a rule with no levels set is active, assume OK state
|
||||||
|
yield Metric(
|
||||||
|
"nc_apps_with_updates_available",
|
||||||
|
num_apps_with_updates_available,
|
||||||
|
)
|
||||||
|
state = State.OK
|
||||||
if app_versions == "":
|
if app_versions == "":
|
||||||
notice = f"Number of installed apps: {num_apps_installed}\nNumber of apps with updates available: {num_apps_with_updates_available}"
|
notice = f"Number of installed apps: {num_apps_installed}\nNumber of apps with updates available: {num_apps_with_updates_available}"
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
# pylint: disable=line-too-long, too-many-locals
|
# pylint: disable=line-too-long, too-many-locals
|
||||||
|
|
||||||
from time import time
|
from time import time
|
||||||
from pprint import pprint
|
from typing import Final
|
||||||
|
|
||||||
from cmk.agent_based.v2 import (
|
from cmk.agent_based.v2 import (
|
||||||
AgentSection,
|
AgentSection,
|
||||||
@@ -18,6 +18,7 @@ from cmk.agent_based.v2 import (
|
|||||||
DiscoveryResult,
|
DiscoveryResult,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
NO_LEVELS: Final[str] = "no_levels"
|
||||||
|
|
||||||
def get_state_upper(levels, value):
|
def get_state_upper(levels, value):
|
||||||
warn, crit = levels
|
warn, crit = levels
|
||||||
@@ -43,6 +44,10 @@ def discover_nextcloud_users(section) -> DiscoveryResult:
|
|||||||
|
|
||||||
|
|
||||||
def check_nextcloud_users(item, params, section) -> CheckResult:
|
def check_nextcloud_users(item, params, section) -> CheckResult:
|
||||||
|
attr = section.get(item)
|
||||||
|
if not attr:
|
||||||
|
yield Result(state=State.UNKNOWN, summary="User not found anymore, maybe it has been deleted.")
|
||||||
|
return
|
||||||
userid = item
|
userid = item
|
||||||
quota_used_percent = section[item][0]
|
quota_used_percent = section[item][0]
|
||||||
quota_used_bytes = section[item][1]
|
quota_used_bytes = section[item][1]
|
||||||
@@ -56,8 +61,8 @@ def check_nextcloud_users(item, params, section) -> CheckResult:
|
|||||||
quota_is_set = False
|
quota_is_set = False
|
||||||
else:
|
else:
|
||||||
quota_is_set = True
|
quota_is_set = True
|
||||||
_level_type, levels_quota_used = params["levels_users_quota_used"]
|
level_type_quota_used, levels_quota_used = params["levels_users_quota_used"]
|
||||||
_level_type, levels_free_space = params["levels_users_free_space"]
|
level_type_free_space, levels_free_space = params["levels_users_free_space"]
|
||||||
if (last_login_human == "never") or (not quota_is_set):
|
if (last_login_human == "never") or (not quota_is_set):
|
||||||
details = f"User ID is '{userid}', Last login: {last_login_human}"
|
details = f"User ID is '{userid}', Last login: {last_login_human}"
|
||||||
summary = (
|
summary = (
|
||||||
@@ -65,19 +70,29 @@ def check_nextcloud_users(item, params, section) -> CheckResult:
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# Levels are given in MBytes, we have to adjust this here
|
# Levels are given in MBytes, we have to adjust this here
|
||||||
warn, crit = levels_free_space
|
if level_type_free_space != NO_LEVELS:
|
||||||
warn = warn * 1024 * 1024
|
warn, crit = levels_free_space
|
||||||
crit = crit * 1024 * 1024
|
warn = warn * 1024 * 1024
|
||||||
state = get_state_lower((warn, crit), free_space)
|
crit = crit * 1024 * 1024
|
||||||
|
state = get_state_lower((warn, crit), free_space)
|
||||||
|
yield Metric("nc_users_free_space", free_space, levels=(warn, crit))
|
||||||
|
else:
|
||||||
|
# a rule with no levels set is active, so assume OK state
|
||||||
|
state = State.OK
|
||||||
|
yield Metric("nc_users_free_space", free_space)
|
||||||
|
|
||||||
details = f"User ID is '{userid}'\nLast login: {last_login_human} ({last_login_since} ago)\nFree space: {render.bytes(free_space)}"
|
details = f"User ID is '{userid}'\nLast login: {last_login_human} ({last_login_since} ago)\nFree space: {render.bytes(free_space)}"
|
||||||
summary = f"Used quota of '{display_name}' is {render.percent(quota_used_percent)}, {render.bytes(quota_used_bytes)}/{render.bytes(quota_total_bytes)} used"
|
summary = f"Used quota of '{display_name}' is {render.percent(quota_used_percent)}, {render.bytes(quota_used_bytes)}/{render.bytes(quota_total_bytes)} used"
|
||||||
notice = f"Remaining free space: {render.bytes(free_space)}"
|
notice = f"Remaining free space: {render.bytes(free_space)}"
|
||||||
yield Metric("nc_users_free_space", free_space, levels=(warn, crit))
|
|
||||||
if state != State.OK:
|
if state != State.OK:
|
||||||
yield Result(state=state, notice=notice)
|
yield Result(state=state, notice=notice)
|
||||||
yield Metric("nc_users_free_space", free_space, levels=(warn, crit))
|
if level_type_quota_used != NO_LEVELS:
|
||||||
yield Metric("nc_users_quota_used", quota_used_percent, levels=levels_quota_used)
|
yield Metric("nc_users_quota_used", quota_used_percent, levels=levels_quota_used)
|
||||||
state = get_state_upper(levels_quota_used, quota_used_percent)
|
state = get_state_upper(levels_quota_used, quota_used_percent)
|
||||||
|
else:
|
||||||
|
# a rule with no levels set is active, so assume OK state
|
||||||
|
yield Metric("nc_users_quota_used", quota_used_percent)
|
||||||
|
state = State.OK
|
||||||
yield Result(state=state, summary=summary, details=details)
|
yield Result(state=state, summary=summary, details=details)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ catalog: unsorted
|
|||||||
license: GPL
|
license: GPL
|
||||||
distribution: check_mk
|
distribution: check_mk
|
||||||
description:
|
description:
|
||||||
Works with Nextcloud version 25/26/27/28/29/30 (use at your own risk with lower versions).
|
Works with Nextcloud version 25/26/27/28/29/30/31/32 (use at your own risk with lower versions).
|
||||||
Tested only with mariab as underlying database.
|
Tested only with mariab as underlying database.
|
||||||
You have to use a username/app password combination to get access to the Nextcloud API.
|
You have to use a username/app password combination to get access to the Nextcloud API.
|
||||||
You can create this app password within the personal settings of an administrative user in Nextcloud.
|
You can create this app password within the personal settings of an administrative user in Nextcloud.
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ catalog: unsorted
|
|||||||
license: GPL
|
license: GPL
|
||||||
distribution: check_mk
|
distribution: check_mk
|
||||||
description:
|
description:
|
||||||
Works with Nextcloud version 25/26/27/28/29/30 (use at your own risk with lower versions).
|
Works with Nextcloud version 25/26/27/28/29/30/31/32 (use at your own risk with lower versions).
|
||||||
Tested only with mariab as underlying database.
|
Tested only with mariab as underlying database.
|
||||||
You have to use a username/app password combination to get access to the Nextcloud API.
|
You have to use a username/app password combination to get access to the Nextcloud API (including user info).
|
||||||
You can create this app password within the personal settings of an administrative user in Nextcloud.
|
You can create this app password within the personal settings of an administrative user in Nextcloud.
|
||||||
Got to security settings and create a new app password.
|
Got to security settings and create a new app password.
|
||||||
The user must not be secured with 2FA.
|
The user must not be secured with 2FA.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ catalog: unsorted
|
|||||||
license: GPL
|
license: GPL
|
||||||
distribution: check_mk
|
distribution: check_mk
|
||||||
description:
|
description:
|
||||||
Works with Nextcloud version 25/26/27/28/29/30 (use at your own risk with lower versions).
|
Works with Nextcloud version 25/26/27/28/29/30/31/32 (use at your own risk with lower versions).
|
||||||
Tested only with mariab as underlying database.
|
Tested only with mariab as underlying database.
|
||||||
You have to use a username/app password combination to get access to the Nextcloud API.
|
You have to use a username/app password combination to get access to the Nextcloud API.
|
||||||
You can create this app password within the personal settings of an administrative user in Nextcloud.
|
You can create this app password within the personal settings of an administrative user in Nextcloud.
|
||||||
|
|||||||
Reference in New Issue
Block a user