1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
#!/usr/bin/env python3
import requests
import argparse
status = {'OK': 0, 'WARNING': 1, 'CRITICAL': 2, 'UNKNOWN': 3}
class APIError(Exception):
pass
class Check:
def __init__(self, status: str, description: str, data: dict[str,str] | None):
self.status = status
self.description = description
self.data = data
def format(self) -> str:
if self.data != None:
formatted_data: str = ' '.join(map(lambda t: f'{t[0]}={t[1]}', dict_to_list(self.data)))
return f"{self.status} - {self.description} | {formatted_data}"
else:
return f"{self.status} - {self.description}"
def exit(self):
print(self.format())
exit(status[self.status])
def dict_to_list(dic):
return [(k, v) for k,v in dic.items()]
parser = argparse.ArgumentParser(description='Check nextcloud status via api')
parser.add_argument('-t', dest='token', action='store', type=str, required=True)
parser.add_argument('--url', dest='url', action='store', type=str, required=True)
parser.add_argument('-u', dest='max_conns', action='store', type=int, default=None, nargs=2)
parser.add_argument('-c', dest='opcache', action='store', type=float, default=None, nargs=2)
parser.add_argument('-a', dest='updates', action='store_true', help='check for app updates')
args= parser.parse_args()
def check_interned_strings_cache(data_json, warning: float, critical: float) -> Check:
data_opcache = data_json['ocs']['data']['server']['php']['opcache']
cache_max = data_opcache['interned_strings_usage']['buffer_size']
cache_used = data_opcache['interned_strings_usage']['used_memory'] / cache_max
data = {'internd_string_cache' : f'{cache_used:.0%};{warning*100:.0f};{critical*100:.0f}'}
if cache_used >= critical:
msg = "The OPcache interned strings buffer is full." if critical == 1 \
else f"OPcache interned strings buffer is to {cache_used:.0%} filled. " + f"This should not be more than {critical:.0%}!"
return Check('CRITICAL', msg, data)
if cache_used >= warning:
return Check('WARNING', f"OPcache interned strings buffer is to {cache_used:.0%} filled. " +
f"This should not be more than {warning:.0%}!", data)
return Check('OK', f"OPcache interned strings buffer is to {cache_used:.0%} filled.", data)
def check_activer_users(data_json, warning: int, critical: int) -> Check:
active_users = data_json['ocs']['data']['activeUsers']['last5minutes']
if active_users >= critical:
status = 'CRITICAL'
elif active_users >= warning:
status = 'WARNING'
else:
status = 'OK'
data = {'active_users' : f'{active_users};{warning};{critical}'}
return Check( status, f'{active_users} {"users were" if active_users != 1 else "user was"} active in the last 5 minutes.', data)
def check_app_updates(data_json) -> Check:
updates = data_json['ocs']['data']['nextcloud']['system']['apps']['app_updates']
if updates != []:
return Check('WARNING', f'The following apps can be updated: {" ".join(updates)}.', None)
else:
return Check('OK', 'No app updates were found.', None)
try:
data_json = requests.get(args.url + '?format=json'
, headers={'NC-Token': args.token}).json()
if data_json['ocs']['meta']['status'] == 'failure':
raise APIError('API call failed!')
if args.updates:
check_app_updates(data_json).exit()
if args.max_conns != None:
warning, critical = args.max_conns
check_activer_users(data_json, warning, critical).exit()
if args.opcache != None:
warning, critical = args.opcache
check_interned_strings_cache(data_json, warning, critical).exit()
except APIError as ex:
Check('UNKNOWN', str(ex), None).exit()
except KeyError as ex:
Check('UNKNOWN', f'The key {ex} could not be found. Did the API change?', None).exit()
|