lookyloo/tools/monitoring.py

155 lines
5.8 KiB
Python
Raw Normal View History

2021-08-31 14:57:12 +02:00
#!/usr/bin/env python3
2024-01-12 17:15:41 +01:00
from __future__ import annotations
2021-08-31 15:38:03 +02:00
import os
import sys
2024-01-23 17:27:33 +01:00
from typing import Any
2021-08-31 14:57:12 +02:00
from redis import Redis
2021-08-31 15:38:03 +02:00
from redis.exceptions import ConnectionError
2021-09-01 12:45:36 +02:00
from rich.console import Console
from rich.padding import Padding
2021-08-31 14:57:12 +02:00
2024-01-23 17:27:33 +01:00
from pylacus import PyLacus
from lookyloo.default import get_socket_path, AbstractManager, get_config
2021-08-31 14:57:12 +02:00
2021-09-01 12:45:36 +02:00
# NOTE: run with watch:
# watch --color tools/monitoring.py
console = Console(color_system="256")
2021-08-31 14:57:12 +02:00
class Monitoring():
2024-01-23 17:27:33 +01:00
lacus: PyLacus | None = None
2021-08-31 14:57:12 +02:00
def __init__(self) -> None:
2024-01-12 17:15:41 +01:00
self.redis_cache: Redis = Redis(unix_socket_path=get_socket_path('cache'), decode_responses=True) # type: ignore[type-arg]
self.redis_indexing: Redis = Redis(unix_socket_path=get_socket_path('indexing'), decode_responses=True) # type: ignore[type-arg]
2024-01-23 17:27:33 +01:00
# try to connect to a remote lacus if lookyloo is configured this way
if remote_lacus_config := get_config('generic', 'remote_lacus'):
if remote_lacus_config.get('enable'):
remote_lacus_url = remote_lacus_config.get('url')
self.lacus = PyLacus(remote_lacus_url)
if not self.lacus.is_up:
self.lacus = None
console.print(f'[red]WARNING[/red]: Remote lacus is configured but not reachable: {remote_lacus_url}.')
2021-08-31 14:57:12 +02:00
2021-08-31 15:38:03 +02:00
@property
2024-01-12 17:15:41 +01:00
def backend_status(self) -> bool:
2021-08-31 15:38:03 +02:00
socket_path_cache = get_socket_path('cache')
socket_path_index = get_socket_path('indexing')
backend_up = True
if not os.path.exists(socket_path_cache):
2021-09-01 12:45:36 +02:00
console.print(f'Socket path for the [blue]cache[/blue] redis DB [red]does not exists[/red] ({socket_path_cache}).')
2021-08-31 15:38:03 +02:00
backend_up = False
if not os.path.exists(socket_path_index):
2021-09-01 12:45:36 +02:00
console.print(f'Socket path for the [blue]indexing[/blue] redis DB [red]does not exists[/red] ({socket_path_index}).')
2021-08-31 15:38:03 +02:00
backend_up = False
if backend_up:
try:
cache_reachable = True if self.redis_cache.ping() else False
if not cache_reachable:
2021-09-01 12:45:36 +02:00
console.print('Unable to ping the redis cache db.')
2021-08-31 15:38:03 +02:00
backend_up = False
except ConnectionError:
2021-09-01 12:45:36 +02:00
console.print('Unable to connect to the redis cache db.')
2021-08-31 15:38:03 +02:00
backend_up = False
try:
indexing_reachable = True if self.redis_indexing.ping() else False
if not indexing_reachable:
2021-09-01 12:45:36 +02:00
console.print('Unable to ping the redis indexing db.')
2021-08-31 15:38:03 +02:00
backend_up = False
except ConnectionError:
2021-09-01 12:45:36 +02:00
console.print('Unable to connect to the redis indexing db.')
2021-08-31 15:38:03 +02:00
backend_up = False
return backend_up
2021-08-31 14:57:12 +02:00
@property
2024-01-12 17:15:41 +01:00
def queues(self) -> list[tuple[str, float]]:
2021-08-31 14:57:12 +02:00
return self.redis_cache.zrevrangebyscore('queues', 'Inf', '-Inf', withscores=True)
@property
2024-01-12 17:15:41 +01:00
def ongoing_captures(self) -> list[tuple[str, float, dict[str, Any]]]:
captures_uuid: list[tuple[str, float]] = self.redis_cache.zrevrangebyscore('to_capture', 'Inf', '-Inf', withscores=True)
2021-08-31 14:57:12 +02:00
if not captures_uuid:
return []
to_return = []
for uuid, rank in captures_uuid:
capture_params = self.redis_cache.hgetall(uuid)
if 'document' in capture_params:
capture_params.pop('document')
2021-08-31 14:57:12 +02:00
if capture_params:
to_return.append((uuid, rank, capture_params))
return to_return
@property
2024-01-12 17:15:41 +01:00
def tree_cache(self) -> dict[str, str]:
to_return = {}
for pid_name, value in self.redis_cache.hgetall('tree_cache').items():
pid, name = pid_name.split('|', 1)
try:
os.kill(int(pid), 0)
except OSError:
self.redis_cache.hdel('tree_cache', pid_name)
continue
to_return[pid_name] = value
return to_return
2024-01-23 17:27:33 +01:00
def lacus_status(self) -> dict[str, Any]:
if not self.lacus:
return {}
to_return = {}
to_return['is_busy'] = self.lacus.is_busy()
status = self.lacus.status()
to_return['max_concurrent_captures'] = status['max_concurrent_captures']
to_return['ongoing_captures'] = status['ongoing_captures']
to_return['enqueued_captures'] = status['enqueued_captures']
return to_return
2021-08-31 14:57:12 +02:00
if __name__ == '__main__':
m = Monitoring()
2021-08-31 15:38:03 +02:00
backend_up = m.backend_status
if not backend_up:
2021-09-01 12:45:36 +02:00
console.print('[bold red]Backend not up, breaking.[/bold red]')
2021-08-31 15:38:03 +02:00
sys.exit()
2021-09-01 12:45:36 +02:00
console.print('Services currently running:')
2021-08-31 15:38:03 +02:00
running = AbstractManager.is_running()
for service, number, pids in running:
s = Padding(f'{service} ({int(number)} service(s)) - PIDs: {", ".join(pids)}', (0, 2))
2021-09-01 12:45:36 +02:00
console.print(s)
2021-08-31 15:38:03 +02:00
console.print('Current cache status:')
for name, status in m.tree_cache.items():
s = Padding(f'{name}: {status}', (0, 2))
console.print(s)
2024-01-23 17:27:33 +01:00
if m.lacus is not None:
2024-01-23 17:45:32 +01:00
lacus_status = m.lacus_status()
2024-01-23 17:27:33 +01:00
console.print('Lacus status:')
2024-01-23 17:45:32 +01:00
if lacus_status['is_busy']:
2024-01-23 17:27:33 +01:00
console.print(Padding('[red]WARNING[/red]: Lacus is busy.', (0, 2)))
2024-01-23 17:45:32 +01:00
console.print(Padding(f'Ongoing captures: {lacus_status["ongoing_captures"]}', (0, 2)))
console.print(Padding(f'Enqueued captures: {lacus_status["enqueued_captures"]}', (0, 2)))
2024-01-23 17:27:33 +01:00
2021-09-01 12:45:36 +02:00
console.print('Current queues:')
2021-08-31 15:38:03 +02:00
for q, priority in m.queues:
2021-09-07 16:28:50 +02:00
s = Padding(f'{q} Recently enqueued captures: {int(priority)}', (0, 2))
2021-09-01 12:45:36 +02:00
console.print(s)
2021-08-31 14:57:12 +02:00
# ------------------
2021-09-01 12:45:36 +02:00
console.print('Captures details:')
2021-08-31 14:57:12 +02:00
captures = m.ongoing_captures
2021-09-01 12:45:36 +02:00
console.print(f'Queue length: [yellow]{len(captures)}[/yellow]')
2021-08-31 14:57:12 +02:00
for uuid, rank, d in captures:
2021-09-01 12:45:36 +02:00
a = Padding(f'{uuid} Rank: {int(rank)}', (0, 2))
console.print(a)
console.print(d)