LinuxMonitor 1.3.4__tar.gz → 1.3.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {linuxmonitor-1.3.4 → linuxmonitor-1.3.7/LinuxMonitor.egg-info}/PKG-INFO +12 -1
- {linuxmonitor-1.3.4/LinuxMonitor.egg-info → linuxmonitor-1.3.7}/PKG-INFO +12 -1
- {linuxmonitor-1.3.4 → linuxmonitor-1.3.7}/README.md +11 -0
- {linuxmonitor-1.3.4 → linuxmonitor-1.3.7}/linuxmonitor/__main__.py +21 -0
- {linuxmonitor-1.3.4 → linuxmonitor-1.3.7}/linuxmonitor/linuxmonitor.py +206 -10
- {linuxmonitor-1.3.4 → linuxmonitor-1.3.7}/setup.py +1 -1
- {linuxmonitor-1.3.4 → linuxmonitor-1.3.7}/LICENSE.md +0 -0
- {linuxmonitor-1.3.4 → linuxmonitor-1.3.7}/LinuxMonitor.egg-info/SOURCES.txt +0 -0
- {linuxmonitor-1.3.4 → linuxmonitor-1.3.7}/LinuxMonitor.egg-info/dependency_links.txt +0 -0
- {linuxmonitor-1.3.4 → linuxmonitor-1.3.7}/LinuxMonitor.egg-info/requires.txt +0 -0
- {linuxmonitor-1.3.4 → linuxmonitor-1.3.7}/LinuxMonitor.egg-info/top_level.txt +0 -0
- {linuxmonitor-1.3.4 → linuxmonitor-1.3.7}/linuxmonitor/__init__.py +0 -0
- {linuxmonitor-1.3.4 → linuxmonitor-1.3.7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: LinuxMonitor
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.7
|
|
4
4
|
Summary: Get information and warning status of Linux server like service, port, ping, ssl certificate, disk/folder/cpu/ram/swap usage, ip connection, ... (Python and shell library, Linux ONLY)
|
|
5
5
|
Home-page: https://github.com/QuentinCG/Linux-Monitor-Python-Library
|
|
6
6
|
Author: Quentin Comte-Gaz
|
|
@@ -54,6 +54,7 @@ List of 'check' functionalities:
|
|
|
54
54
|
- Check certificates expiration and validity
|
|
55
55
|
- Check last user connections IPs
|
|
56
56
|
- Check uptime (to inform if the server has been rebooted)
|
|
57
|
+
- Check custom commands
|
|
57
58
|
|
|
58
59
|
Additionnal functionalities:
|
|
59
60
|
- Get hostname, OS details, kernel version, server datetime, uptime
|
|
@@ -62,6 +63,7 @@ Additionnal functionalities:
|
|
|
62
63
|
- Kill a process by PID
|
|
63
64
|
- Reboot server
|
|
64
65
|
- Restart/stop a service
|
|
66
|
+
- Execute custom commands
|
|
65
67
|
|
|
66
68
|
## How to install (python script and shell)
|
|
67
69
|
|
|
@@ -150,6 +152,15 @@ python3 -m linuxmonitor --kill_process PID_HERE --config_file config-example.jso
|
|
|
150
152
|
|
|
151
153
|
# Restart the entire server
|
|
152
154
|
python3 -m linuxmonitor --reboot_server --config_file config-example.json --nodebug
|
|
155
|
+
|
|
156
|
+
# List all custom commands
|
|
157
|
+
python3 -m linuxmonitor --list_commands --config_file config-example.json --nodebug
|
|
158
|
+
|
|
159
|
+
# Execute a custom commands
|
|
160
|
+
python3 -m linuxmonitor --execute_command CUSTOM_COMMAND_HERE --config_file config-example.json --nodebug
|
|
161
|
+
|
|
162
|
+
# Execute all custom commands
|
|
163
|
+
python3 -m linuxmonitor --execute_all_commands --config_file config-example.json --nodebug
|
|
153
164
|
```
|
|
154
165
|
|
|
155
166
|
## How to use in python script
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: LinuxMonitor
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.7
|
|
4
4
|
Summary: Get information and warning status of Linux server like service, port, ping, ssl certificate, disk/folder/cpu/ram/swap usage, ip connection, ... (Python and shell library, Linux ONLY)
|
|
5
5
|
Home-page: https://github.com/QuentinCG/Linux-Monitor-Python-Library
|
|
6
6
|
Author: Quentin Comte-Gaz
|
|
@@ -54,6 +54,7 @@ List of 'check' functionalities:
|
|
|
54
54
|
- Check certificates expiration and validity
|
|
55
55
|
- Check last user connections IPs
|
|
56
56
|
- Check uptime (to inform if the server has been rebooted)
|
|
57
|
+
- Check custom commands
|
|
57
58
|
|
|
58
59
|
Additionnal functionalities:
|
|
59
60
|
- Get hostname, OS details, kernel version, server datetime, uptime
|
|
@@ -62,6 +63,7 @@ Additionnal functionalities:
|
|
|
62
63
|
- Kill a process by PID
|
|
63
64
|
- Reboot server
|
|
64
65
|
- Restart/stop a service
|
|
66
|
+
- Execute custom commands
|
|
65
67
|
|
|
66
68
|
## How to install (python script and shell)
|
|
67
69
|
|
|
@@ -150,6 +152,15 @@ python3 -m linuxmonitor --kill_process PID_HERE --config_file config-example.jso
|
|
|
150
152
|
|
|
151
153
|
# Restart the entire server
|
|
152
154
|
python3 -m linuxmonitor --reboot_server --config_file config-example.json --nodebug
|
|
155
|
+
|
|
156
|
+
# List all custom commands
|
|
157
|
+
python3 -m linuxmonitor --list_commands --config_file config-example.json --nodebug
|
|
158
|
+
|
|
159
|
+
# Execute a custom commands
|
|
160
|
+
python3 -m linuxmonitor --execute_command CUSTOM_COMMAND_HERE --config_file config-example.json --nodebug
|
|
161
|
+
|
|
162
|
+
# Execute all custom commands
|
|
163
|
+
python3 -m linuxmonitor --execute_all_commands --config_file config-example.json --nodebug
|
|
153
164
|
```
|
|
154
165
|
|
|
155
166
|
## How to use in python script
|
|
@@ -26,6 +26,7 @@ List of 'check' functionalities:
|
|
|
26
26
|
- Check certificates expiration and validity
|
|
27
27
|
- Check last user connections IPs
|
|
28
28
|
- Check uptime (to inform if the server has been rebooted)
|
|
29
|
+
- Check custom commands
|
|
29
30
|
|
|
30
31
|
Additionnal functionalities:
|
|
31
32
|
- Get hostname, OS details, kernel version, server datetime, uptime
|
|
@@ -34,6 +35,7 @@ Additionnal functionalities:
|
|
|
34
35
|
- Kill a process by PID
|
|
35
36
|
- Reboot server
|
|
36
37
|
- Restart/stop a service
|
|
38
|
+
- Execute custom commands
|
|
37
39
|
|
|
38
40
|
## How to install (python script and shell)
|
|
39
41
|
|
|
@@ -122,6 +124,15 @@ python3 -m linuxmonitor --kill_process PID_HERE --config_file config-example.jso
|
|
|
122
124
|
|
|
123
125
|
# Restart the entire server
|
|
124
126
|
python3 -m linuxmonitor --reboot_server --config_file config-example.json --nodebug
|
|
127
|
+
|
|
128
|
+
# List all custom commands
|
|
129
|
+
python3 -m linuxmonitor --list_commands --config_file config-example.json --nodebug
|
|
130
|
+
|
|
131
|
+
# Execute a custom commands
|
|
132
|
+
python3 -m linuxmonitor --execute_command CUSTOM_COMMAND_HERE --config_file config-example.json --nodebug
|
|
133
|
+
|
|
134
|
+
# Execute all custom commands
|
|
135
|
+
python3 -m linuxmonitor --execute_all_commands --config_file config-example.json --nodebug
|
|
125
136
|
```
|
|
126
137
|
|
|
127
138
|
## How to use in python script
|
|
@@ -28,6 +28,9 @@ def main() -> None:
|
|
|
28
28
|
parser.add_argument('--ports', action='store_true', help='🔒 Check ports 🔒')
|
|
29
29
|
parser.add_argument('--list_processes', action='store_true', help='📋 List active processes 📋')
|
|
30
30
|
parser.add_argument('--kill_process', type=int, help='🚫 Stop a process by PID 🚫')
|
|
31
|
+
parser.add_argument('--list_commands', action='store_true', help='📋 List all available commands 📋')
|
|
32
|
+
parser.add_argument('execute_command', type=str, help='📋 Execute a command 📋')
|
|
33
|
+
parser.add_argument('execute_all_commands', type=str, help='📋 Execute all commands 📋')
|
|
31
34
|
|
|
32
35
|
parser.add_argument('--debug', action='store_true', help='Enable debug mode')
|
|
33
36
|
parser.add_argument('--nodebug', action='store_true', help='Disable all logs')
|
|
@@ -150,6 +153,24 @@ def main() -> None:
|
|
|
150
153
|
out_msg: str = monitoring.get_all_services(is_private=True)
|
|
151
154
|
print(out_msg)
|
|
152
155
|
|
|
156
|
+
if args.list_commands:
|
|
157
|
+
handled = True
|
|
158
|
+
print("Listing all available commands...")
|
|
159
|
+
out_msg: str = asyncio.run(monitoring.list_commands(is_private=True))
|
|
160
|
+
print(out_msg)
|
|
161
|
+
|
|
162
|
+
if args.execute_command is not None:
|
|
163
|
+
handled = True
|
|
164
|
+
print(f"Executing command: {args.execute_command}...")
|
|
165
|
+
out_msg: str = asyncio.run(monitoring.execute_command(is_private=True, command_name=args.execute_command))
|
|
166
|
+
print(out_msg)
|
|
167
|
+
|
|
168
|
+
if args.execute_all_commands is not None:
|
|
169
|
+
handled = True
|
|
170
|
+
print(f"Executing all commands...")
|
|
171
|
+
out_msg: str = asyncio.run(monitoring.execute_all_commands(is_private=True))
|
|
172
|
+
print(out_msg)
|
|
173
|
+
|
|
153
174
|
if args.ports:
|
|
154
175
|
handled = True
|
|
155
176
|
print("Checking ports...")
|
|
@@ -33,7 +33,7 @@ __email__ = "quentin@comte-gaz.com"
|
|
|
33
33
|
__license__ = "MIT License"
|
|
34
34
|
__copyright__ = "Copyright Quentin Comte-Gaz (2024)"
|
|
35
35
|
__python_version__ = "3.+"
|
|
36
|
-
__version__ = "1.3.
|
|
36
|
+
__version__ = "1.3.7 (2024/09/19)"
|
|
37
37
|
__status__ = "Usable for any Linux project"
|
|
38
38
|
|
|
39
39
|
import json
|
|
@@ -182,7 +182,47 @@ class LinuxMonitor:
|
|
|
182
182
|
|
|
183
183
|
#region Execute Command
|
|
184
184
|
|
|
185
|
-
|
|
185
|
+
def _json_to_md(self, json_string: str, level: int = 0) -> str:
|
|
186
|
+
"""
|
|
187
|
+
Convert a JSON string into a Markdown representation.
|
|
188
|
+
|
|
189
|
+
Parameters:
|
|
190
|
+
json_string (str): The input JSON string.
|
|
191
|
+
level (int): The current indentation level (default is 0).
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
str: The resulting Markdown formatted string.
|
|
195
|
+
"""
|
|
196
|
+
md: str = ""
|
|
197
|
+
indent: str = " " * level # type: ignore # Indentation for markdown headings
|
|
198
|
+
|
|
199
|
+
# Parse the JSON string to a Python object
|
|
200
|
+
try:
|
|
201
|
+
data = json.loads(json_string)
|
|
202
|
+
except json.JSONDecodeError as e:
|
|
203
|
+
return f"Error parsing JSON: {str(e)}"
|
|
204
|
+
|
|
205
|
+
# Helper function to convert the parsed JSON to markdown
|
|
206
|
+
def process_data(data, level: int) -> None: # type: ignore
|
|
207
|
+
nonlocal md # Declare md as nonlocal so it can be modified
|
|
208
|
+
indent = " " * level
|
|
209
|
+
|
|
210
|
+
if isinstance(data, dict):
|
|
211
|
+
for key, value in data.items(): # type: ignore
|
|
212
|
+
md += f"{indent}- {key}\n"
|
|
213
|
+
process_data(value, level + 1) # type: ignore
|
|
214
|
+
elif isinstance(data, list):
|
|
215
|
+
for index, item in enumerate(data): # type: ignore
|
|
216
|
+
md += f"{indent}- Item {index + 1}\n"
|
|
217
|
+
process_data(item, level + 1) # type: ignore
|
|
218
|
+
else:
|
|
219
|
+
md += f"{indent} - {data}\n"
|
|
220
|
+
|
|
221
|
+
process_data(data, level)
|
|
222
|
+
|
|
223
|
+
return md
|
|
224
|
+
|
|
225
|
+
async def execute_and_verify(self, command: str, display_name: str, show_only_std_and_exception: bool, timeout_in_sec: Optional[int] = None, display_only_if_critical: bool = False, check_also_stdout_not_containing: Optional[str] = None, is_stdout_json: bool=False) -> Tuple[Optional[bool], str]:
|
|
186
226
|
"""
|
|
187
227
|
Execute a shell command asynchronously and verify its correct execution.
|
|
188
228
|
|
|
@@ -211,11 +251,11 @@ class LinuxMonitor:
|
|
|
211
251
|
except asyncio.TimeoutError:
|
|
212
252
|
logging.warning(msg=f"Timeout expired for {display_name} (command: {command})")
|
|
213
253
|
process.kill()
|
|
214
|
-
return None, f"⚠️ **Error {display_name}**:\n- Failed to execute the command in less than {timeout_in_sec} seconds)"
|
|
254
|
+
return None, f" - ⚠️ **Error {display_name}**:\n - Failed to execute the command in less than {timeout_in_sec} seconds)"
|
|
215
255
|
except Exception as e:
|
|
216
256
|
# Failed to execute the command
|
|
217
257
|
if not show_only_std_and_exception:
|
|
218
|
-
out_msg = f"⚠️ **Error {display_name}**:\n```sh\n{e}\n```"
|
|
258
|
+
out_msg = f" - ⚠️ **Error {display_name}**:\n```sh\n{e}\n```"
|
|
219
259
|
else:
|
|
220
260
|
out_msg = f"```sh\n{e}\n```"
|
|
221
261
|
logging.exception(msg=out_msg)
|
|
@@ -234,24 +274,27 @@ class LinuxMonitor:
|
|
|
234
274
|
if res == False:
|
|
235
275
|
# Command returned an error code
|
|
236
276
|
if not show_only_std_and_exception:
|
|
237
|
-
out_msg = f"❌ **Error {display_name}**\n"
|
|
277
|
+
out_msg = f" - ❌ **Error {display_name}**\n"
|
|
238
278
|
out_msg += f" - Error code: `{returncode}`"
|
|
239
279
|
|
|
240
280
|
if stderr_str != "":
|
|
241
281
|
out_msg += f"\n - Error log:\n```sh\n{stderr_str}\n```"
|
|
242
282
|
|
|
243
283
|
if stdout_str != "":
|
|
244
|
-
|
|
284
|
+
msg_stout: str = stdout_str
|
|
285
|
+
if is_stdout_json:
|
|
286
|
+
msg_stout = self._json_to_md(stdout_str)
|
|
287
|
+
out_msg += f"\n - Info:\n```sh\n{msg_stout}\n```"
|
|
245
288
|
elif res == None:
|
|
246
289
|
# Command timed out
|
|
247
290
|
if not show_only_std_and_exception:
|
|
248
|
-
out_msg = f"⚠️ **Error {display_name}**\n"
|
|
249
|
-
out_msg += f"- Failed to wait for the command to finish (due to timeout of {timeout_in_sec} seconds)"
|
|
291
|
+
out_msg = f" - ⚠️ **Error {display_name}**\n"
|
|
292
|
+
out_msg += f" - Failed to wait for the command to finish (due to timeout of {timeout_in_sec} seconds)"
|
|
250
293
|
else:
|
|
251
294
|
# Command executed successfully
|
|
252
295
|
if not display_only_if_critical:
|
|
253
296
|
if not show_only_std_and_exception:
|
|
254
|
-
out_msg = f"✅ **{display_name} executed successfully**"
|
|
297
|
+
out_msg = f" - ✅ **{display_name} executed successfully**"
|
|
255
298
|
|
|
256
299
|
if res == True:
|
|
257
300
|
logging.info(msg=f"Command {display_name} (command {command}) executed successfully")
|
|
@@ -274,6 +317,10 @@ class LinuxMonitor:
|
|
|
274
317
|
"""
|
|
275
318
|
logging.info(msg="Rebooting the server...")
|
|
276
319
|
_, out_msg = await self.execute_and_verify(command="sudo /sbin/reboot", display_name="Server reboot", show_only_std_and_exception=False, timeout_in_sec=None, display_only_if_critical=False)
|
|
320
|
+
|
|
321
|
+
if out_msg != "":
|
|
322
|
+
out_msg = f"# 🔄 Reboot 🔄\n{out_msg}"
|
|
323
|
+
|
|
277
324
|
return out_msg
|
|
278
325
|
|
|
279
326
|
#endregion
|
|
@@ -963,7 +1010,7 @@ class LinuxMonitor:
|
|
|
963
1010
|
return out_msg
|
|
964
1011
|
|
|
965
1012
|
if not force_restart and not service.get('auto_restart', False):
|
|
966
|
-
out_msg = f"⚠️ **Service {
|
|
1013
|
+
out_msg = f"⚠️ **Service {display_name} can be restarted only manually** (change configuration if needed)."
|
|
967
1014
|
logging.error(msg=out_msg)
|
|
968
1015
|
return out_msg
|
|
969
1016
|
|
|
@@ -1809,6 +1856,126 @@ class LinuxMonitor:
|
|
|
1809
1856
|
|
|
1810
1857
|
#endregion
|
|
1811
1858
|
|
|
1859
|
+
#region Commands
|
|
1860
|
+
|
|
1861
|
+
async def _execute_command(self, command: str, display_name: str, show_content_if_success: bool, show_content_if_issue: bool, is_content_json: bool, timeout_in_sec: int, display_only_if_critical: bool) -> str:
|
|
1862
|
+
try:
|
|
1863
|
+
out_msg: str = ""
|
|
1864
|
+
|
|
1865
|
+
# Execute the command
|
|
1866
|
+
start_time: float = time.time()
|
|
1867
|
+
res, res_msg = await self.execute_and_verify(command=command, display_name=display_name, show_only_std_and_exception=True, timeout_in_sec=timeout_in_sec, display_only_if_critical=display_only_if_critical, is_stdout_json=is_content_json)
|
|
1868
|
+
end_time: float = time.time()
|
|
1869
|
+
|
|
1870
|
+
if res == True:
|
|
1871
|
+
readable_duration: str = "{:.2f}".format(end_time - start_time)
|
|
1872
|
+
out_msg = f"✅ **{display_name} executed with success** in {readable_duration}sec."
|
|
1873
|
+
logging.info(msg=out_msg)
|
|
1874
|
+
|
|
1875
|
+
if show_content_if_success:
|
|
1876
|
+
out_msg += f"\n{res_msg}"
|
|
1877
|
+
|
|
1878
|
+
elif res == False:
|
|
1879
|
+
out_msg = f"⚠️ **{display_name} failed to execute**."
|
|
1880
|
+
logging.warning(msg=out_msg)
|
|
1881
|
+
|
|
1882
|
+
if show_content_if_issue:
|
|
1883
|
+
out_msg += f"\n{res_msg}"
|
|
1884
|
+
|
|
1885
|
+
else:
|
|
1886
|
+
out_msg = f"⚠️ **{display_name} expired**."
|
|
1887
|
+
logging.warning(msg=out_msg)
|
|
1888
|
+
|
|
1889
|
+
return out_msg
|
|
1890
|
+
except Exception as e:
|
|
1891
|
+
out_msg = f"⚠️ **Error while executing {display_name}**:\n```sh\n{e}\n```"
|
|
1892
|
+
logging.exception(msg=out_msg)
|
|
1893
|
+
return out_msg
|
|
1894
|
+
|
|
1895
|
+
async def execute_command(self, is_private: bool, command_name: str) -> str:
|
|
1896
|
+
try:
|
|
1897
|
+
out_msg: str = ""
|
|
1898
|
+
display_name: str = command_name
|
|
1899
|
+
for command_config_key in self.config['commands'].keys():
|
|
1900
|
+
if self.config['commands'][command_config_key]['command'] == command_name:
|
|
1901
|
+
display_name = self.config['commands'][command_config_key]['display_name']
|
|
1902
|
+
command: str = self.config['commands'][command_config_key]['command']
|
|
1903
|
+
is_private_cmd: bool = self.config['commands'][command_config_key]['is_private']
|
|
1904
|
+
|
|
1905
|
+
if is_private or is_private == is_private_cmd:
|
|
1906
|
+
show_content_if_success: bool = self.config['commands'][command_config_key].get('show_content_if_success', False)
|
|
1907
|
+
show_content_if_issue: bool = self.config['commands'][command_config_key].get('show_content_if_issue', False)
|
|
1908
|
+
is_content_json: bool = self.config['commands'][command_config_key].get('is_content_json', False)
|
|
1909
|
+
timeout_in_sec: int = self.config['commands'][command_config_key].get('timeout_in_sec', 10)
|
|
1910
|
+
|
|
1911
|
+
res: str = await self._execute_command(command=command, display_name=display_name, show_content_if_success=show_content_if_success, show_content_if_issue=show_content_if_issue, is_content_json=is_content_json, timeout_in_sec=timeout_in_sec, display_only_if_critical=False)
|
|
1912
|
+
if res != "":
|
|
1913
|
+
if out_msg != "":
|
|
1914
|
+
out_msg += "\n"
|
|
1915
|
+
out_msg += f"{res}"
|
|
1916
|
+
else:
|
|
1917
|
+
out_msg = f"⚠️ **Command {display_name} is not allowed**"
|
|
1918
|
+
logging.warning(msg=out_msg)
|
|
1919
|
+
|
|
1920
|
+
if out_msg != "":
|
|
1921
|
+
out_msg = f"# 📜 Command {display_name} 📜\n{out_msg}"
|
|
1922
|
+
|
|
1923
|
+
return out_msg
|
|
1924
|
+
|
|
1925
|
+
out_msg = f"⚠️ **Command {display_name} not found**"
|
|
1926
|
+
logging.warning(msg=out_msg)
|
|
1927
|
+
return out_msg
|
|
1928
|
+
except Exception as e:
|
|
1929
|
+
return f"⚠️ **Error executing command {command_name}**:\n```sh\n{e}\n```"
|
|
1930
|
+
|
|
1931
|
+
async def execute_all_commands(self, is_private: bool, is_scheduled_tasks_for_issues: bool=False, is_scheduled_tasks_for_infos: bool=False, display_only_if_critical: bool=False) -> str:
|
|
1932
|
+
try:
|
|
1933
|
+
out_msg: str = ""
|
|
1934
|
+
|
|
1935
|
+
for command_config_key in self.config['commands'].keys():
|
|
1936
|
+
if is_private or is_private == self.config['commands'][command_config_key]['is_private']:
|
|
1937
|
+
display_name: str = self.config['commands'][command_config_key]['display_name']
|
|
1938
|
+
command: str = self.config['commands'][command_config_key]['command']
|
|
1939
|
+
show_content_if_success: bool = self.config['commands'][command_config_key].get('show_content_if_success', False)
|
|
1940
|
+
show_content_if_issue: bool = self.config['commands'][command_config_key].get('show_content_if_issue', False)
|
|
1941
|
+
is_content_json: bool = self.config['commands'][command_config_key].get('is_content_json', False)
|
|
1942
|
+
timeout_in_sec: int = self.config['commands'][command_config_key].get('timeout_in_sec', 10)
|
|
1943
|
+
|
|
1944
|
+
if is_scheduled_tasks_for_issues and not self.config['commands'][command_config_key].get('execute_in_scheduled_tasks_for_issues', False):
|
|
1945
|
+
continue
|
|
1946
|
+
if is_scheduled_tasks_for_infos and not self.config['commands'][command_config_key].get('execute_in_scheduled_tasks_for_infos', False):
|
|
1947
|
+
continue
|
|
1948
|
+
|
|
1949
|
+
res: str = await self._execute_command(command=command, display_name=display_name, show_content_if_success=show_content_if_success, show_content_if_issue=show_content_if_issue, is_content_json=is_content_json, timeout_in_sec=timeout_in_sec, display_only_if_critical=display_only_if_critical)
|
|
1950
|
+
if res != "":
|
|
1951
|
+
if out_msg != "":
|
|
1952
|
+
out_msg += "\n"
|
|
1953
|
+
out_msg += f"{res}"
|
|
1954
|
+
|
|
1955
|
+
if out_msg != "":
|
|
1956
|
+
out_msg = f"# 📜 Commands 📜\n{out_msg}"
|
|
1957
|
+
|
|
1958
|
+
return out_msg
|
|
1959
|
+
except Exception as e:
|
|
1960
|
+
return f"⚠️ **Error executing commands**:\n```sh\n{e}\n```"
|
|
1961
|
+
|
|
1962
|
+
async def list_commands(self, is_private: bool) -> str:
|
|
1963
|
+
try:
|
|
1964
|
+
out_msg: str = "# 📜 Commands 📜\n"
|
|
1965
|
+
for command_config_key in self.config['commands'].keys():
|
|
1966
|
+
if is_private or is_private == self.config['commands'][command_config_key]['is_private']:
|
|
1967
|
+
display_name: str = self.config['commands'][command_config_key]['display_name']
|
|
1968
|
+
out_msg += f"- {display_name}\n"
|
|
1969
|
+
|
|
1970
|
+
logging.info(msg=out_msg)
|
|
1971
|
+
return out_msg
|
|
1972
|
+
except Exception as e:
|
|
1973
|
+
out_msg = f"⚠️ **Error listing commands**:\n```sh\n{e}\n```"
|
|
1974
|
+
logging.exception(msg=out_msg)
|
|
1975
|
+
return out_msg
|
|
1976
|
+
|
|
1977
|
+
#endregion
|
|
1978
|
+
|
|
1812
1979
|
#region Scheduled Tasks
|
|
1813
1980
|
|
|
1814
1981
|
async def schedule_task(self, handle_error_message: Callable[[str], Awaitable[None]], is_private: bool) -> None:
|
|
@@ -1839,6 +2006,7 @@ class LinuxMonitor:
|
|
|
1839
2006
|
datetime_last_user_logins_error_displayed: Optional[datetime] = None
|
|
1840
2007
|
datetime_last_port_error_displayed: Optional[datetime] = None
|
|
1841
2008
|
datetime_last_services_error_displayed: Optional[datetime] = None
|
|
2009
|
+
datetime_last_commands_error_displayed: Optional[datetime] = None
|
|
1842
2010
|
need_to_check_uptime: bool = True # No need to check uptime every time (since once ok, it can't be wrong)
|
|
1843
2011
|
|
|
1844
2012
|
if not self.start_scheduled_tasks_immediately:
|
|
@@ -1997,6 +2165,27 @@ class LinuxMonitor:
|
|
|
1997
2165
|
else:
|
|
1998
2166
|
logging.info(msg="- ✅ All ports are OK.")
|
|
1999
2167
|
|
|
2168
|
+
# Commands
|
|
2169
|
+
msg = await self.execute_all_commands(is_private=is_private, is_scheduled_tasks_for_issues=True, is_scheduled_tasks_for_infos=False, display_only_if_critical=True)
|
|
2170
|
+
if msg != "":
|
|
2171
|
+
logging.warning(msg=msg)
|
|
2172
|
+
if datetime_last_commands_error_displayed is None or ((datetime.now() - datetime_last_commands_error_displayed).total_seconds() > self.max_duration_seconds_showing_same_error_again_in_scheduled_tasks):
|
|
2173
|
+
if out_msg != "":
|
|
2174
|
+
out_msg += "\n"
|
|
2175
|
+
out_msg += msg
|
|
2176
|
+
datetime_last_commands_error_displayed = datetime.now()
|
|
2177
|
+
else:
|
|
2178
|
+
logging.warning(msg="Commands critical but already notified less than 12 hours ago, not notifying...")
|
|
2179
|
+
elif datetime_last_commands_error_displayed is not None:
|
|
2180
|
+
msg="✅ **Commands returned to normal state**"
|
|
2181
|
+
logging.info(msg=msg)
|
|
2182
|
+
if out_msg != "":
|
|
2183
|
+
out_msg += "\n"
|
|
2184
|
+
out_msg += msg
|
|
2185
|
+
datetime_last_commands_error_displayed = None
|
|
2186
|
+
else:
|
|
2187
|
+
logging.info(msg="- ✅ All commands are OK.")
|
|
2188
|
+
|
|
2000
2189
|
# User logins
|
|
2001
2190
|
if is_private:
|
|
2002
2191
|
msg = self.check_all_recent_user_logins(display_only_if_critical=True)
|
|
@@ -2206,6 +2395,13 @@ class LinuxMonitor:
|
|
|
2206
2395
|
out_msg += "\n"
|
|
2207
2396
|
out_msg += msg
|
|
2208
2397
|
|
|
2398
|
+
# Commands
|
|
2399
|
+
msg = await self.execute_all_commands(is_private=is_private, is_scheduled_tasks_for_issues=False, is_scheduled_tasks_for_infos=True, display_only_if_critical=False)
|
|
2400
|
+
if msg != "":
|
|
2401
|
+
if out_msg != "":
|
|
2402
|
+
out_msg += "\n"
|
|
2403
|
+
out_msg += msg
|
|
2404
|
+
|
|
2209
2405
|
# User logins
|
|
2210
2406
|
if is_private:
|
|
2211
2407
|
msg = self.check_all_recent_user_logins(display_only_if_critical=False)
|
|
@@ -6,7 +6,7 @@ with io.open(file='README.md', mode='r', encoding='utf-8') as readme_file:
|
|
|
6
6
|
|
|
7
7
|
setup(
|
|
8
8
|
name="LinuxMonitor",
|
|
9
|
-
version="1.3.
|
|
9
|
+
version="1.3.7",
|
|
10
10
|
description="Get information and warning status of Linux server like service, port, ping, ssl certificate, disk/folder/cpu/ram/swap usage, ip connection, ... (Python and shell library, Linux ONLY)",
|
|
11
11
|
long_description=readme,
|
|
12
12
|
long_description_content_type="text/markdown",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|