MKP 2.4.0, added password store for app password, some changes for compatibility with NC 28
This commit is contained in:
		
							parent
							
								
									1fbeae93a1
								
							
						
					
					
						commit
						714990bffb
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -16,7 +16,7 @@ __pycache__/
 | 
				
			|||||||
*.vsix
 | 
					*.vsix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Exclude all "private" files (Ralf Mellis)
 | 
					# Exclude all "private" files (Ralf Mellis)
 | 
				
			||||||
RaMe*
 | 
					RM*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Exclude all "private" files (Torsten Behne)
 | 
					# Exclude all "private" files (Torsten Behne)
 | 
				
			||||||
TB*
 | 
					TB*
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
# 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 with Nextcloud 25/26/27.
 | 
					Tested with Nextcloud 25/26/27/28.
 | 
				
			||||||
Tested only with MySQL/MariaDB as database backend.
 | 
					Tested only with MySQL/MariaDB as database backend.
 | 
				
			||||||
Feel free to report other working environments.
 | 
					Feel free to report other working environments.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -9,6 +9,7 @@ Version History:
 | 
				
			|||||||
--
 | 
					--
 | 
				
			||||||
|Date|Version|Changes|
 | 
					|Date|Version|Changes|
 | 
				
			||||||
|----|-------|-------|
 | 
					|----|-------|-------|
 | 
				
			||||||
 | 
					|2023/01/12|2.4.0|Integrated Password Store for App Password, some changes for compatibility with NC 28 added|
 | 
				
			||||||
|2023/11/26|2.3.4|Fixed agent crash if opcache_get_status is disabled by server settings|
 | 
					|2023/11/26|2.3.4|Fixed agent crash if opcache_get_status is disabled by server settings|
 | 
				
			||||||
|2023/08/16|2.3.3|Fixed some misleading info strings regarding database opcache|
 | 
					|2023/08/16|2.3.3|Fixed some misleading info strings regarding database opcache|
 | 
				
			||||||
|2023/08/12|2.3.2|MKP now compatible with CheckMK 2.2|
 | 
					|2023/08/12|2.3.2|MKP now compatible with CheckMK 2.2|
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,9 @@
 | 
				
			|||||||
#!/usr/bin/env python3
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
from pprint import pprint
 | 
					from pprint import pprint
 | 
				
			||||||
 | 
					from datetime import datetime
 | 
				
			||||||
from .agent_based_api.v1 import register, render, Service, Result, State, Metric
 | 
					from .agent_based_api.v1 import register, render, Service, Result, State, Metric
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getStateUpper(levels, value):
 | 
					def getStateUpper(levels, value):
 | 
				
			||||||
    warn, crit = levels
 | 
					    warn, crit = levels
 | 
				
			||||||
    if value >= crit:
 | 
					    if value >= crit:
 | 
				
			||||||
@ -10,6 +12,7 @@ def getStateUpper(levels, value):
 | 
				
			|||||||
        return State.WARN
 | 
					        return State.WARN
 | 
				
			||||||
    return State.OK
 | 
					    return State.OK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getStateLower(levels, value):
 | 
					def getStateLower(levels, value):
 | 
				
			||||||
    warn, crit = levels
 | 
					    warn, crit = levels
 | 
				
			||||||
    if value < crit:
 | 
					    if value < crit:
 | 
				
			||||||
@ -18,14 +21,25 @@ def getStateLower(levels, value):
 | 
				
			|||||||
        return State.WARN
 | 
					        return State.WARN
 | 
				
			||||||
    return State.OK
 | 
					    return State.OK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def discover_nextcloud_info(section):
 | 
					def discover_nextcloud_info(section):
 | 
				
			||||||
    yield(Service())
 | 
					    yield(Service())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def check_nextcloud_info(params, section): 
 | 
					def check_nextcloud_info(params, section): 
 | 
				
			||||||
    for key in section:
 | 
					    for key in section:
 | 
				
			||||||
        if key == "nextcloud":
 | 
					        if key == "nextcloud":
 | 
				
			||||||
            levels_free_space = params["levels_free_space"]
 | 
					            levels_free_space = params["levels_free_space"]
 | 
				
			||||||
            levels_number_of_files = params["levels_number_of_files"]
 | 
					            levels_number_of_files = params["levels_number_of_files"]
 | 
				
			||||||
 | 
					            # update infos are available only from Nextcloud version 28 onwards
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                last_update = section[key]["last_update"]
 | 
				
			||||||
 | 
					                update_available = section[key]["update_available"]
 | 
				
			||||||
 | 
					                last_update_human = datetime.fromtimestamp(last_update)
 | 
				
			||||||
 | 
					            except KeyError:
 | 
				
			||||||
 | 
					                last_update = "Update information not available, update to at least version 28"
 | 
				
			||||||
 | 
					                update_available = "False"
 | 
				
			||||||
 | 
					                last_update_human = "Update information not available"
 | 
				
			||||||
            status = section[key]["status"]
 | 
					            status = section[key]["status"]
 | 
				
			||||||
            free_space = section[key]["freespace"]
 | 
					            free_space = section[key]["freespace"]
 | 
				
			||||||
            version = section[key]["version"]
 | 
					            version = section[key]["version"]
 | 
				
			||||||
@ -40,13 +54,23 @@ def check_nextcloud_info(params, section):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            # create overall result
 | 
					            # create overall result
 | 
				
			||||||
            summary = f"Status is {status}"
 | 
					            summary = f"Status is {status}"
 | 
				
			||||||
            details = f"Nextcloud version: {version}\nPHP version: {php_version}\nWebserver: {webserver}\n\nNumber of files: {num_files}\nNumber of shares: {num_shares}\n\nFree space on disk: {render.bytes(free_space)}\n"
 | 
					            details = f"Nextcloud version: {version}\nLast update: {last_update_human}\nPHP version: {php_version}\nWebserver: {webserver}\n\nNumber of files: {num_files}\nNumber of shares: {num_shares}\n\nFree space on disk: {render.bytes(free_space)}\n"
 | 
				
			||||||
            if status == "ok":
 | 
					            if status == "ok":
 | 
				
			||||||
                state = State.OK
 | 
					                state = State.OK
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                state = State.CRIT
 | 
					                state = State.CRIT
 | 
				
			||||||
            yield Result(state=state, summary=summary, details=details)
 | 
					            yield Result(state=state, summary=summary, details=details)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Create result for available updates
 | 
				
			||||||
 | 
					            if update_available != "False":
 | 
				
			||||||
 | 
					                state = State.WARN
 | 
				
			||||||
 | 
					                notice = f"Update is available"
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                state = State.OK
 | 
				
			||||||
 | 
					                notice = "No update available"
 | 
				
			||||||
 | 
					            if state != State.OK:
 | 
				
			||||||
 | 
					                yield(Result(state=state, notice=notice))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # 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
 | 
					            warn, crit = levels_free_space
 | 
				
			||||||
@ -90,15 +114,20 @@ def check_nextcloud_info(params, section):
 | 
				
			|||||||
            notice = f"Number of storages: {num_storages}\nNumber of home/local/other storages: {num_storages_home}/{num_storages_local}/{num_storages_other}"
 | 
					            notice = f"Number of storages: {num_storages}\nNumber of home/local/other storages: {num_storages_home}/{num_storages_local}/{num_storages_other}"
 | 
				
			||||||
            yield(Result(state=State.OK, notice=notice))
 | 
					            yield(Result(state=State.OK, notice=notice))
 | 
				
			||||||
        elif key == "apps":
 | 
					        elif key == "apps":
 | 
				
			||||||
            num_apps_installed = section[key]["installed"]
 | 
					            # Workaround for Nextcloud 28, "apps" info is not always available
 | 
				
			||||||
            num_apps_with_updates_available = section[key]["with_updates_available"]
 | 
					            try:
 | 
				
			||||||
            # create graphs for number of apps
 | 
					                num_apps_installed = section[key]["installed"]
 | 
				
			||||||
            levels = params["levels_apps_with_updates_available"]
 | 
					                num_apps_with_updates_available = section[key]["with_updates_available"]
 | 
				
			||||||
            yield Metric("nc_num_apps_installed", num_apps_installed)
 | 
					                # create graphs for number of apps
 | 
				
			||||||
            yield Metric("nc_apps_with_updates_available", num_apps_with_updates_available, levels=levels)
 | 
					                levels = params["levels_apps_with_updates_available"]
 | 
				
			||||||
            state = getStateUpper(levels, num_apps_with_updates_available)
 | 
					                yield Metric("nc_num_apps_installed", num_apps_installed)
 | 
				
			||||||
            notice = f"Number of installed apps: {num_apps_installed}\nNumber of apps with updates available: {num_apps_with_updates_available}"
 | 
					                yield Metric("nc_apps_with_updates_available", num_apps_with_updates_available, levels=levels)
 | 
				
			||||||
            yield(Result(state=state, notice=notice))
 | 
					                state = getStateUpper(levels, 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}"
 | 
				
			||||||
 | 
					                yield(Result(state=state, notice=notice))
 | 
				
			||||||
 | 
					            except KeyError:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def parse_nextcloud_info_section(string_table):
 | 
					def parse_nextcloud_info_section(string_table):
 | 
				
			||||||
    parsed_data = {
 | 
					    parsed_data = {
 | 
				
			||||||
@ -111,6 +140,8 @@ def parse_nextcloud_info_section(string_table):
 | 
				
			|||||||
        "NC_Version",
 | 
					        "NC_Version",
 | 
				
			||||||
        "NC_Freespace",
 | 
					        "NC_Freespace",
 | 
				
			||||||
        "NC_Status",
 | 
					        "NC_Status",
 | 
				
			||||||
 | 
					        "NC_Last_Update",
 | 
				
			||||||
 | 
					        "NC_Update_Available",
 | 
				
			||||||
        "NC_Webserver",
 | 
					        "NC_Webserver",
 | 
				
			||||||
        "NC_PHP_Version",
 | 
					        "NC_PHP_Version",
 | 
				
			||||||
        "NC_Num_Users",
 | 
					        "NC_Num_Users",
 | 
				
			||||||
@ -136,6 +167,10 @@ def parse_nextcloud_info_section(string_table):
 | 
				
			|||||||
                parsed_data["nextcloud"]["freespace"] = float(value)
 | 
					                parsed_data["nextcloud"]["freespace"] = float(value)
 | 
				
			||||||
            elif param == "NC_Status":
 | 
					            elif param == "NC_Status":
 | 
				
			||||||
                parsed_data["nextcloud"]["status"] = value
 | 
					                parsed_data["nextcloud"]["status"] = value
 | 
				
			||||||
 | 
					            elif param == "NC_Last_Update":
 | 
				
			||||||
 | 
					                parsed_data["nextcloud"]["last_update"] = int(value)
 | 
				
			||||||
 | 
					            elif param == "NC_Update_Available":
 | 
				
			||||||
 | 
					                parsed_data["nextcloud"]["update_available"] = value
 | 
				
			||||||
            elif param == "NC_Webserver":
 | 
					            elif param == "NC_Webserver":
 | 
				
			||||||
                parsed_data["nextcloud"]["webserver"] = value
 | 
					                parsed_data["nextcloud"]["webserver"] = value
 | 
				
			||||||
            elif param == "NC_PHP_Version":
 | 
					            elif param == "NC_PHP_Version":
 | 
				
			||||||
@ -164,13 +199,16 @@ def parse_nextcloud_info_section(string_table):
 | 
				
			|||||||
                parsed_data["users"]["active_last1hour"] = int(value)
 | 
					                parsed_data["users"]["active_last1hour"] = int(value)
 | 
				
			||||||
            elif param == "NC_Active_Users_Last_1Day":
 | 
					            elif param == "NC_Active_Users_Last_1Day":
 | 
				
			||||||
                parsed_data["users"]["active_last1day"] = int(value)
 | 
					                parsed_data["users"]["active_last1day"] = int(value)
 | 
				
			||||||
 | 
					    #pprint(parsed_data)
 | 
				
			||||||
    return parsed_data
 | 
					    return parsed_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
register.agent_section(
 | 
					register.agent_section(
 | 
				
			||||||
    name="nextcloud_info",
 | 
					    name="nextcloud_info",
 | 
				
			||||||
    parse_function=parse_nextcloud_info_section,
 | 
					    parse_function=parse_nextcloud_info_section,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
register.check_plugin(
 | 
					register.check_plugin(
 | 
				
			||||||
    name="nextcloud_info",
 | 
					    name="nextcloud_info",
 | 
				
			||||||
    service_name="Nextcloud Info",
 | 
					    service_name="Nextcloud Info",
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,7 @@ import os
 | 
				
			|||||||
from pprint import pprint
 | 
					from pprint import pprint
 | 
				
			||||||
from requests.structures import CaseInsensitiveDict
 | 
					from requests.structures import CaseInsensitiveDict
 | 
				
			||||||
from requests.auth import HTTPBasicAuth
 | 
					from requests.auth import HTTPBasicAuth
 | 
				
			||||||
 | 
					import cmk.utils.password_store
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def showUsage():
 | 
					def showUsage():
 | 
				
			||||||
    sys.stderr.write("""CheckMK Nextcloud Special Agent
 | 
					    sys.stderr.write("""CheckMK Nextcloud Special Agent
 | 
				
			||||||
@ -34,7 +35,7 @@ OPTIONS:
 | 
				
			|||||||
# be aware: activating this logs very sensitive information to debug files in ~/tmp 
 | 
					# be aware: activating this logs very sensitive information to debug files in ~/tmp 
 | 
				
			||||||
# !!DO NOT FORGET to delete these files after debugging is done!!
 | 
					# !!DO NOT FORGET to delete these files after debugging is done!!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEBUG = False
 | 
					DEBUG = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
nc_api_endpoint = "ocs/v2.php/apps/serverinfo/api/v1/info?format=json"
 | 
					nc_api_endpoint = "ocs/v2.php/apps/serverinfo/api/v1/info?format=json"
 | 
				
			||||||
nc_api_endpoint_all_users = "ocs/v1.php/cloud/users?format=json"
 | 
					nc_api_endpoint_all_users = "ocs/v1.php/cloud/users?format=json"
 | 
				
			||||||
@ -54,6 +55,15 @@ long_options = [
 | 
				
			|||||||
    'hostname=', 'username=', 'password=', 'port=', 'token=', 'folder=', 'no-https=', 'no-cert-check=', 'help'
 | 
					    'hostname=', 'username=', 'password=', 'port=', 'token=', 'folder=', 'no-https=', 'no-cert-check=', 'help'
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def logDebug(line):
 | 
				
			||||||
 | 
					    if DEBUG:
 | 
				
			||||||
 | 
					        home_path = os.getenv("HOME")
 | 
				
			||||||
 | 
					        tmp_path = f"{home_path}/tmp"
 | 
				
			||||||
 | 
					        help_file = f"{tmp_path}/nextcloud_{opt_hostname}_{opt_port}_debug.txt"
 | 
				
			||||||
 | 
					        with open(help_file, "a") as file:
 | 
				
			||||||
 | 
					            file.write(line)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getOptions():
 | 
					def getOptions():
 | 
				
			||||||
    global opt_hostname
 | 
					    global opt_hostname
 | 
				
			||||||
    global opt_username
 | 
					    global opt_username
 | 
				
			||||||
@ -91,12 +101,7 @@ def getOptions():
 | 
				
			|||||||
        elif opt in ['-h', '--help']:
 | 
					        elif opt in ['-h', '--help']:
 | 
				
			||||||
            showUsage()
 | 
					            showUsage()
 | 
				
			||||||
            sys.exit(0)
 | 
					            sys.exit(0)
 | 
				
			||||||
    if DEBUG:
 | 
					    logDebug(f"getOptions - Number of Arguments: {len(sys.argv)}, Argument List: {str(sys.argv)}\n")
 | 
				
			||||||
        home_path = os.getenv("HOME")
 | 
					 | 
				
			||||||
        tmp_path = f"{home_path}/tmp"
 | 
					 | 
				
			||||||
        help_file = f"{tmp_path}/nextcloud_{opt_hostname}_debug.txt"
 | 
					 | 
				
			||||||
        with open(help_file, "a") as file:
 | 
					 | 
				
			||||||
            file.write(f"Number of Arguments: {len(sys.argv)}, Argument List: {str(sys.argv)}\n")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
def showOptions():
 | 
					def showOptions():
 | 
				
			||||||
    print(f"Hostname: {opt_hostname}")
 | 
					    print(f"Hostname: {opt_hostname}")
 | 
				
			||||||
@ -107,48 +112,41 @@ def showOptions():
 | 
				
			|||||||
    print(f"Token: {opt_token}")
 | 
					    print(f"Token: {opt_token}")
 | 
				
			||||||
    print(f"No HTTPS: {opt_no_https}")
 | 
					    print(f"No HTTPS: {opt_no_https}")
 | 
				
			||||||
    print(f"No TLS Check: {opt_no_cert_check}")
 | 
					    print(f"No TLS Check: {opt_no_cert_check}")
 | 
				
			||||||
    home_path = os.getenv("HOME")
 | 
					    logDebug(f"showOptions - Hostname: {opt_hostname}, Port: {opt_port}, No HTTPS: {opt_no_https}, No Cert Check: {opt_no_cert_check}\n")
 | 
				
			||||||
    tmp_path = f"{home_path}/tmp"
 | 
					 | 
				
			||||||
    help_file = f"{tmp_path}/nextcloud_{opt_hostname}_debug.txt"
 | 
					 | 
				
			||||||
    with open(help_file, "a") as file:
 | 
					 | 
				
			||||||
        file.write(f"Hostname: {opt_hostname}, Port: {opt_port}, No HTTPS: {opt_no_https}, No Cert Check: {opt_no_cert_check}\n")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
def createUrl(endpoint, hostname, protocol, port, folder):
 | 
					def createUrl(endpoint, hostname, protocol, port, folder):
 | 
				
			||||||
 | 
					    # these parameters are needed, otherwise no information about updates regarding apps and Nextcloud itself are not reported (since version 28)
 | 
				
			||||||
 | 
					    params = "skipApps=false&skipUpdate=false"
 | 
				
			||||||
    if folder == "":
 | 
					    if folder == "":
 | 
				
			||||||
        url = f"{protocol}://{hostname}:{port}/{endpoint}"
 | 
					        url = f"{protocol}://{hostname}:{port}/{endpoint}"
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        url = f"{protocol}://{hostname}:{port}/{folder}/{endpoint}"
 | 
					        url = f"{protocol}://{hostname}:{port}/{folder}/{endpoint}"
 | 
				
			||||||
    if DEBUG:
 | 
					    if endpoint == nc_api_endpoint:
 | 
				
			||||||
        home_path = os.getenv("HOME")
 | 
					        url = f"{url}&{params}"
 | 
				
			||||||
        tmp_path = f"{home_path}/tmp"
 | 
					    logDebug(f"createUrl - Data URL: {url}\n")
 | 
				
			||||||
        help_file = f"{tmp_path}/nextcloud_{hostname}_debug.txt"
 | 
					 | 
				
			||||||
        with open(help_file, "a") as file:
 | 
					 | 
				
			||||||
            file.write(f"Data URL: {url}\n")
 | 
					 | 
				
			||||||
    return url
 | 
					    return url
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def createUrlUser(user, endpoint, hostname, protocol, port, folder):
 | 
					def createUrlUser(user, endpoint, hostname, protocol, port, folder):
 | 
				
			||||||
 | 
					    params = "format=json"
 | 
				
			||||||
    if folder == "":
 | 
					    if folder == "":
 | 
				
			||||||
        url = f"{protocol}://{hostname}:{port}/{endpoint}/{user}?format=json"
 | 
					        url = f"{protocol}://{hostname}:{port}/{endpoint}/{user}?{params}"
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        url = f"{protocol}://{hostname}:{port}/{folder}/{endpoint}/{user}?format=json"
 | 
					        url = f"{protocol}://{hostname}:{port}/{folder}/{endpoint}/{user}?{params}"
 | 
				
			||||||
    if DEBUG:
 | 
					    logDebug(f"createUrlUser - User URL: {url}\n")
 | 
				
			||||||
        home_path = os.getenv("HOME")
 | 
					 | 
				
			||||||
        tmp_path = f"{home_path}/tmp"
 | 
					 | 
				
			||||||
        help_file = f"{tmp_path}/nextcloud_{hostname}_debug.txt"
 | 
					 | 
				
			||||||
        with open(help_file, "a") as file:
 | 
					 | 
				
			||||||
            file.write(f"User URL: {url}\n")
 | 
					 | 
				
			||||||
    return url
 | 
					    return url
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getData(url, verify):
 | 
					def getSession(username, secret):
 | 
				
			||||||
 | 
					    session = requests.session()
 | 
				
			||||||
 | 
					    session.cookies.set("SameSite", "Strict")
 | 
				
			||||||
 | 
					    session.auth = (username, secret)
 | 
				
			||||||
 | 
					    session.headers['Accept'] = "application/json"
 | 
				
			||||||
 | 
					    return session
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def getData(session, url, verify):
 | 
				
			||||||
    headers = CaseInsensitiveDict()
 | 
					    headers = CaseInsensitiveDict()
 | 
				
			||||||
    headers["Accept"] = "application/json"
 | 
					    headers["Accept"] = "application/json"
 | 
				
			||||||
    if (opt_token == '0'):
 | 
					    cookies = {"nc_sameSiteCookiestrict": "true"}
 | 
				
			||||||
        # authenticate with username and password
 | 
					    response = session.get(url, headers=headers, cookies=cookies, verify=verify)
 | 
				
			||||||
        pwd = opt_password
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        # authenticate with token
 | 
					 | 
				
			||||||
        pwd = opt_token
 | 
					 | 
				
			||||||
    response = requests.get(url, auth=HTTPBasicAuth(opt_username, pwd), headers=headers, verify=verify)
 | 
					 | 
				
			||||||
    status = response.status_code
 | 
					    status = response.status_code
 | 
				
			||||||
    if (status == 200):
 | 
					    if (status == 200):
 | 
				
			||||||
        jsdata = response.text
 | 
					        jsdata = response.text
 | 
				
			||||||
@ -162,17 +160,12 @@ def getData(url, verify):
 | 
				
			|||||||
        sys.stderr.write(f"Request response code is {response.status_code} with URL {url}\n")
 | 
					        sys.stderr.write(f"Request response code is {response.status_code} with URL {url}\n")
 | 
				
			||||||
        sys.exit(1)
 | 
					        sys.exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getDataAllUsers(url, verify):
 | 
					def getDataAllUsers(session, url, verify):
 | 
				
			||||||
    headers = CaseInsensitiveDict()
 | 
					    headers = CaseInsensitiveDict()
 | 
				
			||||||
    headers["Accept"] = "application/json"
 | 
					    headers["Accept"] = "application/json"
 | 
				
			||||||
    headers["OCS-APIRequest"] = "true"
 | 
					    headers["OCS-APIRequest"] = "true"
 | 
				
			||||||
    if (opt_token == '0'):
 | 
					    cookies = {"nc_sameSiteCookiestrict": "true"}
 | 
				
			||||||
        # authenticate with username and password
 | 
					    response = session.get(url, headers=headers, cookies=cookies, verify=verify)
 | 
				
			||||||
        pwd = opt_password
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        # authenticate with token
 | 
					 | 
				
			||||||
        pwd = opt_token 
 | 
					 | 
				
			||||||
    response = requests.get(url, auth=HTTPBasicAuth(opt_username, pwd), headers=headers, verify=verify)
 | 
					 | 
				
			||||||
    status = response.status_code
 | 
					    status = response.status_code
 | 
				
			||||||
    if (status == 200):
 | 
					    if (status == 200):
 | 
				
			||||||
        jsdata = response.text
 | 
					        jsdata = response.text
 | 
				
			||||||
@ -182,18 +175,12 @@ def getDataAllUsers(url, verify):
 | 
				
			|||||||
        sys.stderr.write(f"Request response code is {response.status_code} with URL {url}\n")
 | 
					        sys.stderr.write(f"Request response code is {response.status_code} with URL {url}\n")
 | 
				
			||||||
        sys.exit(1)
 | 
					        sys.exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getDataUser(url, verify):
 | 
					def getDataUser(session, url, verify):
 | 
				
			||||||
    #print(url)
 | 
					 | 
				
			||||||
    headers = CaseInsensitiveDict()
 | 
					    headers = CaseInsensitiveDict()
 | 
				
			||||||
    headers["Accept"] = "application/json"
 | 
					    headers["Accept"] = "application/json"
 | 
				
			||||||
    headers["OCS-APIRequest"] = "true"
 | 
					    headers["OCS-APIRequest"] = "true"
 | 
				
			||||||
    if (opt_token == '0'):
 | 
					    cookies = {"nc_sameSiteCookiestrict": "true"}
 | 
				
			||||||
        # authenticate with username and password
 | 
					    response = session.get(url, headers=headers, cookies=cookies, verify=verify)
 | 
				
			||||||
        pwd = opt_password
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        # authenticate with token
 | 
					 | 
				
			||||||
        pwd = opt_token 
 | 
					 | 
				
			||||||
    response = requests.get(url, auth=HTTPBasicAuth(opt_username, pwd), headers=headers, verify=verify)
 | 
					 | 
				
			||||||
    status = response.status_code
 | 
					    status = response.status_code
 | 
				
			||||||
    if (status == 200):
 | 
					    if (status == 200):
 | 
				
			||||||
        jsdata = response.text
 | 
					        jsdata = response.text
 | 
				
			||||||
@ -208,6 +195,12 @@ def doCmkOutput(data):
 | 
				
			|||||||
    print(f"NC_Version;{data['ocs']['data']['nextcloud']['system']['version']}")
 | 
					    print(f"NC_Version;{data['ocs']['data']['nextcloud']['system']['version']}")
 | 
				
			||||||
    print(f"NC_Freespace;{data['ocs']['data']['nextcloud']['system']['freespace']}")
 | 
					    print(f"NC_Freespace;{data['ocs']['data']['nextcloud']['system']['freespace']}")
 | 
				
			||||||
    print(f"NC_Status;{data['ocs']['meta']['status']}")
 | 
					    print(f"NC_Status;{data['ocs']['meta']['status']}")
 | 
				
			||||||
 | 
					    # This update info is available only from version 28 onwards, so the key "update" does not exist in all versions before
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        print(f"NC_Last_Update;{data['ocs']['data']['nextcloud']['system']['update']['lastupdatedat']}")
 | 
				
			||||||
 | 
					        print(f"NC_Update_Available;{data['ocs']['data']['nextcloud']['system']['update']['available']}")
 | 
				
			||||||
 | 
					    except KeyError:
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
    print(f"NC_Num_Users;{data['ocs']['data']['nextcloud']['storage']['num_users']}")
 | 
					    print(f"NC_Num_Users;{data['ocs']['data']['nextcloud']['storage']['num_users']}")
 | 
				
			||||||
    print(f"NC_Num_Files;{data['ocs']['data']['nextcloud']['storage']['num_files']}")
 | 
					    print(f"NC_Num_Files;{data['ocs']['data']['nextcloud']['storage']['num_files']}")
 | 
				
			||||||
    print(f"NC_Num_Shares;{data['ocs']['data']['nextcloud']['shares']['num_shares']}")
 | 
					    print(f"NC_Num_Shares;{data['ocs']['data']['nextcloud']['shares']['num_shares']}")
 | 
				
			||||||
@ -215,8 +208,12 @@ def doCmkOutput(data):
 | 
				
			|||||||
    print(f"NC_Num_Storages_Home;{data['ocs']['data']['nextcloud']['storage']['num_storages_home']}")
 | 
					    print(f"NC_Num_Storages_Home;{data['ocs']['data']['nextcloud']['storage']['num_storages_home']}")
 | 
				
			||||||
    print(f"NC_Num_Storages_Local;{data['ocs']['data']['nextcloud']['storage']['num_storages_local']}")
 | 
					    print(f"NC_Num_Storages_Local;{data['ocs']['data']['nextcloud']['storage']['num_storages_local']}")
 | 
				
			||||||
    print(f"NC_Num_Storages_Other;{data['ocs']['data']['nextcloud']['storage']['num_storages_other']}")
 | 
					    print(f"NC_Num_Storages_Other;{data['ocs']['data']['nextcloud']['storage']['num_storages_other']}")
 | 
				
			||||||
    print(f"NC_Num_Apps_Installed;{data['ocs']['data']['nextcloud']['system']['apps']['num_installed']}")
 | 
					    # Workaround for Nextcloud 28.0.1 (KeyError "apps")
 | 
				
			||||||
    print(f"NC_Num_Apps_Updates_Available;{data['ocs']['data']['nextcloud']['system']['apps']['num_updates_available']}")
 | 
					    try:
 | 
				
			||||||
 | 
					        print(f"NC_Num_Apps_Installed;{data['ocs']['data']['nextcloud']['system']['apps']['num_installed']}")
 | 
				
			||||||
 | 
					        print(f"NC_Num_Apps_Updates_Available;{data['ocs']['data']['nextcloud']['system']['apps']['num_updates_available']}")
 | 
				
			||||||
 | 
					    except KeyError:
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
    print(f"NC_Active_Users_Last_5Min;{data['ocs']['data']['activeUsers']['last5minutes']}")
 | 
					    print(f"NC_Active_Users_Last_5Min;{data['ocs']['data']['activeUsers']['last5minutes']}")
 | 
				
			||||||
    print(f"NC_Active_Users_Last_1Hour;{data['ocs']['data']['activeUsers']['last1hour']}")
 | 
					    print(f"NC_Active_Users_Last_1Hour;{data['ocs']['data']['activeUsers']['last1hour']}")
 | 
				
			||||||
    print(f"NC_Active_Users_Last_1Day;{data['ocs']['data']['activeUsers']['last24hours']}")
 | 
					    print(f"NC_Active_Users_Last_1Day;{data['ocs']['data']['activeUsers']['last24hours']}")
 | 
				
			||||||
@ -234,11 +231,11 @@ def doCmkOutput(data):
 | 
				
			|||||||
    else:
 | 
					    else:
 | 
				
			||||||
        print(f"NC_OPCache_Hit_Rate;0")
 | 
					        print(f"NC_OPCache_Hit_Rate;0")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def doCmkOutputAllUsers(data, verify, hostname, protocol, port, folder):
 | 
					def doCmkOutputAllUsers(session, data, verify, hostname, protocol, port, folder):
 | 
				
			||||||
    print("<<<nextcloud_users:sep(59)>>>")
 | 
					    print("<<<nextcloud_users:sep(59)>>>")
 | 
				
			||||||
    for user in data['ocs']['data']['users']:
 | 
					    for user in data['ocs']['data']['users']:
 | 
				
			||||||
        nc_url = createUrlUser(user, nc_api_endpoint_user, hostname, protocol, port, folder)
 | 
					        nc_url = createUrlUser(user, nc_api_endpoint_user, hostname, protocol, port, folder)
 | 
				
			||||||
        user_data = getDataUser(nc_url, verify)
 | 
					        user_data = getDataUser(session, nc_url, verify)
 | 
				
			||||||
        userid = user_data['ocs']['data']['id']
 | 
					        userid = user_data['ocs']['data']['id']
 | 
				
			||||||
        displayname = user_data['ocs']['data']['displayname']
 | 
					        displayname = user_data['ocs']['data']['displayname']
 | 
				
			||||||
        lastlogin = int(user_data['ocs']['data']['lastLogin'])
 | 
					        lastlogin = int(user_data['ocs']['data']['lastLogin'])
 | 
				
			||||||
@ -260,6 +257,8 @@ def doCmkOutputAllUsers(data, verify, hostname, protocol, port, folder):
 | 
				
			|||||||
        print(f"{userid};{displayname};{lastlogin};{quota_free};{quota_quota};{quota_relative};{quota_total};{quota_used}")
 | 
					        print(f"{userid};{displayname};{lastlogin};{quota_free};{quota_quota};{quota_relative};{quota_total};{quota_used}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def main():
 | 
					def main():
 | 
				
			||||||
 | 
					    # replace password from pwd store
 | 
				
			||||||
 | 
					    cmk.utils.password_store.replace_passwords()
 | 
				
			||||||
    getOptions()
 | 
					    getOptions()
 | 
				
			||||||
    if (opt_hostname == ""):
 | 
					    if (opt_hostname == ""):
 | 
				
			||||||
        sys.stderr.write(f"No hostname given.\n")
 | 
					        sys.stderr.write(f"No hostname given.\n")
 | 
				
			||||||
@ -291,12 +290,21 @@ def main():
 | 
				
			|||||||
    if (protocol == "https" and port == "80"):
 | 
					    if (protocol == "https" and port == "80"):
 | 
				
			||||||
        sys.stderr.write(f"Combining HTTPS with port 80 is not supported.\n")
 | 
					        sys.stderr.write(f"Combining HTTPS with port 80 is not supported.\n")
 | 
				
			||||||
        sys.exit(1)
 | 
					        sys.exit(1)
 | 
				
			||||||
 | 
					    if (opt_token == '0'):
 | 
				
			||||||
 | 
					        # authenticate with username and password
 | 
				
			||||||
 | 
					        pwd = opt_password
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        # authenticate with token
 | 
				
			||||||
 | 
					        pwd = opt_token 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # create session    
 | 
				
			||||||
 | 
					    session = getSession(opt_username, pwd)
 | 
				
			||||||
    nc_url = createUrl(nc_api_endpoint, opt_hostname, protocol, port, opt_folder)
 | 
					    nc_url = createUrl(nc_api_endpoint, opt_hostname, protocol, port, opt_folder)
 | 
				
			||||||
    nc_data = getData(nc_url, verify)
 | 
					    nc_data = getData(session, nc_url, verify)
 | 
				
			||||||
    doCmkOutput(nc_data)
 | 
					    doCmkOutput(nc_data)
 | 
				
			||||||
    nc_url = createUrl(nc_api_endpoint_all_users, opt_hostname, protocol, port, opt_folder)
 | 
					    nc_url = createUrl(nc_api_endpoint_all_users, opt_hostname, protocol, port, opt_folder)
 | 
				
			||||||
    nc_data = getDataAllUsers(nc_url, verify)
 | 
					    nc_data = getDataAllUsers(session, nc_url, verify)
 | 
				
			||||||
    doCmkOutputAllUsers(nc_data, verify, opt_hostname, protocol, port, opt_folder)
 | 
					    doCmkOutputAllUsers(session, nc_data, verify, opt_hostname, protocol, port, opt_folder)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
    main()
 | 
					    main()
 | 
				
			||||||
@ -3,7 +3,7 @@ def agent_nextcloud_arguments(params, hostname, ipaddress):
 | 
				
			|||||||
                "--hostname", params["hostname"],
 | 
					                "--hostname", params["hostname"],
 | 
				
			||||||
                "--username", params["username"],
 | 
					                "--username", params["username"],
 | 
				
			||||||
                "--password", params["password"],
 | 
					                "--password", params["password"],
 | 
				
			||||||
                "--token", params["token"],
 | 
					                "--token", passwordstore_get_cmdline("%s", params["token"]),
 | 
				
			||||||
                "--port", params["port"],
 | 
					                "--port", params["port"],
 | 
				
			||||||
                "--folder", params["folder"],
 | 
					                "--folder", params["folder"],
 | 
				
			||||||
                "--no-https", params["no_https"],
 | 
					                "--no-https", params["no_https"],
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,13 @@
 | 
				
			|||||||
from cmk.gui.i18n import _
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
from cmk.gui.plugins.wato import (
 | 
					 | 
				
			||||||
    CheckParameterRulespecWithItem,
 | 
					 | 
				
			||||||
    rulespec_registry,
 | 
					 | 
				
			||||||
    RulespecGroupCheckParametersOperatingSystem,
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cmk.gui.i18n import _
 | 
				
			||||||
 | 
					from cmk.gui.plugins.wato.special_agents.common import RulespecGroupDatasourceProgramsApps
 | 
				
			||||||
 | 
					from cmk.gui.plugins.wato.utils import (
 | 
				
			||||||
 | 
					    HostRulespec,
 | 
				
			||||||
 | 
					    Rulespec,
 | 
				
			||||||
 | 
					    IndividualOrStoredPassword,
 | 
				
			||||||
 | 
					    rulespec_registry,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
from cmk.gui.valuespec import (
 | 
					from cmk.gui.valuespec import (
 | 
				
			||||||
    Dictionary,
 | 
					    Dictionary,
 | 
				
			||||||
    ListChoice,
 | 
					    ListChoice,
 | 
				
			||||||
@ -13,11 +16,8 @@ from cmk.gui.valuespec import (
 | 
				
			|||||||
    Password,
 | 
					    Password,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from cmk.gui.plugins.wato import (
 | 
					def _factory_default_special_agent_nextcloud():
 | 
				
			||||||
    HostRulespec,
 | 
					    return Rulespec.FACTORY_DEFAULT_UNUSED
 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from cmk.gui.plugins.wato.datasource_programs import RulespecGroupDatasourceProgramsCustom
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _valuespec_special_agent_nextcloud():
 | 
					def _valuespec_special_agent_nextcloud():
 | 
				
			||||||
    return Dictionary(
 | 
					    return Dictionary(
 | 
				
			||||||
@ -33,7 +33,7 @@ def _valuespec_special_agent_nextcloud():
 | 
				
			|||||||
            ("password", Password(title=_("Password"),
 | 
					            ("password", Password(title=_("Password"),
 | 
				
			||||||
                allow_empty=True,
 | 
					                allow_empty=True,
 | 
				
			||||||
                help=_("Specify password OR token, not both, token recommended"))),
 | 
					                help=_("Specify password OR token, not both, token recommended"))),
 | 
				
			||||||
            ("token", Password(title=_("Token"),
 | 
					            ("token", IndividualOrStoredPassword(title=_("App Password"),
 | 
				
			||||||
                allow_empty=True,
 | 
					                allow_empty=True,
 | 
				
			||||||
                help=_("Specify password OR token, not both, token recommended"))),
 | 
					                help=_("Specify password OR token, not both, token recommended"))),
 | 
				
			||||||
            ("port", TextAscii(title=_("Port"),
 | 
					            ("port", TextAscii(title=_("Port"),
 | 
				
			||||||
@ -52,8 +52,9 @@ def _valuespec_special_agent_nextcloud():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
rulespec_registry.register(
 | 
					rulespec_registry.register(
 | 
				
			||||||
    HostRulespec(
 | 
					    HostRulespec(
 | 
				
			||||||
        group=RulespecGroupDatasourceProgramsCustom,
 | 
					        factory_default = _factory_default_special_agent_nextcloud(),
 | 
				
			||||||
        name="special_agents:nextcloud",
 | 
					        group = RulespecGroupDatasourceProgramsApps,
 | 
				
			||||||
        valuespec=_valuespec_special_agent_nextcloud,
 | 
					        name = "special_agents:nextcloud",
 | 
				
			||||||
 | 
					        valuespec = _valuespec_special_agent_nextcloud,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								mkp/Nextcloud-2.4.0.mkp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mkp/Nextcloud-2.4.0.mkp
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user