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,21 +21,32 @@ 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"] | ||||||
|             php_version = section[key]["php_version"] |             php_version = section[key]["php_version"] | ||||||
|             webserver = section[key]["webserver"] |             webserver = section[key]["webserver"] | ||||||
|             num_files = section[key]["number_files"] |             num_files = section[key]["number_files"] | ||||||
|             num_shares = section[key]["number_shares"] |             num_shares = section[key]["number_shares"]          | ||||||
| 
 | 
 | ||||||
|             # create graph for number of files and shares |             # create graph for number of files and shares | ||||||
|             yield(Metric("nc_num_files", num_files)) |             yield(Metric("nc_num_files", num_files)) | ||||||
| @ -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") | ||||||
| @ -290,13 +289,22 @@ def main(): | |||||||
|         sys.exit(1) |         sys.exit(1) | ||||||
|     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