added code to initialize db with models and recodres

This commit is contained in:
Tobias Kurze
2019-11-20 12:41:05 +01:00
parent bc1347fe99
commit 60ff5bdeaf
20 changed files with 1658 additions and 136 deletions

View File

@@ -5,6 +5,7 @@ Backend base module
import logging
from io import StringIO
from logging.config import dictConfig
from logging.handlers import MemoryHandler
from typing import Union
import coloredlogs as coloredlogs
@@ -28,6 +29,8 @@ __email__ = "it@t-kurze.de"
# __status__ = "Production"
__status__ = "Development"
from .tools.send_mail import get_smtp_default_handler
dictConfig({
'version': 1,
'formatters': {
@@ -82,6 +85,9 @@ dictConfig({
main_logger = logging.getLogger("lrc")
# following might be dangerous, as buffer might be filled without a mechanism to empty it
smtp_error_handler = get_smtp_default_handler(subject="Warnings, errors and worse...!")
mem_handler = MemoryHandler(capacity=10, flushLevel=logging.ERROR, target=smtp_error_handler)
mem_handler.setLevel(logging.WARNING)
# error_log_stream = StringIO()
# error_log_stream_handler = logging.StreamHandler(stream=error_log_stream)
# error_log_stream_handler.setLevel(logging.ERROR)

View File

@@ -8,7 +8,8 @@ import ssl
from jinja2.exceptions import TemplateNotFound
from backend import app, db
from backend.models import pre_fill_table
from backend.models import room_model, recorder_model
from backend.recorder_adapters import get_defined_recorder_adapters
from backend.tools.model_updater import update_recorder_models_database
@@ -30,7 +31,8 @@ def main():
except Exception as e:
logging.critical(e)
pre_fill_table()
room_model.pre_fill_table()
recorder_model.pre_fill_table()
update_recorder_models_database()
app.run(debug=True, host="0.0.0.0")

Binary file not shown.

View File

@@ -1,10 +1,14 @@
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
"""
Models for lecture recorder
"""
import importlib
import json
import pkgutil
import os
from sqlalchemy import MetaData
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import validates
@@ -14,11 +18,18 @@ from sqlalchemy import or_
from datetime import datetime, timedelta
from backend.models.virtual_command_model import virtual_command_recorder_command_table, virtual_command_recorder_table
from backend.recorder_adapters import get_defined_recorder_adapters
from backend.tools.helpers import file_md5
metadata = MetaData()
KNOWN_RECORDERS = {re.compile(r'(SMP)[\s]*([\d]+)[\s]*.?[\s]*([\S]*)'): 'SMP',
re.compile(
r'(LectureRecorder X2|LectureRecorder|VGADVI Recorder|DVI Broadcaster DL|DVIRecorderDL)'): 'Epiphan'}
class RecorderModel(db.Model):
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
last_time_modified = db.Column(db.DateTime, nullable=True, default=None)
@@ -27,7 +38,8 @@ class RecorderModel(db.Model):
notes = db.Column(db.Unicode(255), unique=False, nullable=True, default=None)
recorder_commands = db.relationship('RecorderCommand', back_populates='recorder_model')
recorders = db.relationship('Recorder', back_populates='recorder_model')
checksum = db.Column(db.String(63), unique=True, nullable=False)
checksum = db.Column(db.String(63), unique=True,
nullable=False) # checksum of the recorder commands! (see: model_updater.py)
_requires_user = db.Column(db.Integer, default=False, name='requires_user')
_requires_password = db.Column(db.Integer, default=True, name='requires_password')
@@ -65,6 +77,7 @@ class RecorderModel(db.Model):
class Recorder(db.Model):
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
last_time_modified = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
@@ -76,6 +89,8 @@ class Recorder(db.Model):
room_id = db.Column(db.Integer, db.ForeignKey('room.id'))
room = db.relationship('Room', uselist=False, back_populates='recorder') # one-to-one relation (uselist=False)
ip = db.Column(db.String(15), unique=True, nullable=True, default=None)
configured_options_json_string = db.Column(db.UnicodeText, default='')
firmware_version = db.Column(db.String, nullable=True, default=None)
ip6 = db.Column(db.String(46), unique=True, nullable=True, default=None)
network_name = db.Column(db.String(127), unique=True, nullable=True, default=None)
telnet_port = db.Column(db.Integer, unique=False, nullable=False, default=23)
@@ -84,7 +99,8 @@ class Recorder(db.Model):
password = db.Column(db.String, nullable=True, default=None)
recorder_model_id = db.Column(db.Integer, db.ForeignKey('recorder_model.id'))
recorder_model = db.relationship('RecorderModel', back_populates='recorders')
virtual_commands = db.relationship('VirtualCommand', secondary=virtual_command_recorder_table, back_populates='recorders')
virtual_commands = db.relationship('VirtualCommand', secondary=virtual_command_recorder_table,
back_populates='recorders')
def __init__(self, **kwargs):
super(Recorder, self).__init__(**kwargs)
@@ -106,6 +122,17 @@ class Recorder(db.Model):
assert len(value) > 2
return value
@hybrid_property
def configured_options(self) -> list:
return json.loads(self.configured_options_json_string)
@configured_options.setter
def configured_options(self, value: list):
self.configured_options_json_string = json.dumps(value)
def add_configured_option(self, value: str):
self.configured_options_json_string = json.dumps(self.configured_options.append(value))
def __str__(self):
return self.name
@@ -118,10 +145,11 @@ class Recorder(db.Model):
class RecorderCommand(db.Model):
__table_args__ = {'extend_existing': True}
"""Table containing permissions associated with groups."""
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
last_time_modified = db.Column(db.DateTime, nullable=True, default=None)
last_time_modified = db.Column(db.DateTime, nullable=True, default=datetime.utcnow())
name = db.Column(db.Unicode(63), unique=True, nullable=False)
alternative_name = db.Column(db.Unicode(63), unique=True, nullable=True, default=None)
disabled = db.Column(db.Boolean, default=False)
@@ -130,7 +158,7 @@ class RecorderCommand(db.Model):
recorder_model = db.relationship('RecorderModel', back_populates='recorder_commands')
recorder_model_id = db.Column(db.Integer, db.ForeignKey('recorder_model.id'))
virtual_commands = db.relationship('VirtualCommand', secondary=virtual_command_recorder_command_table,
back_populates='recorder_commands')
back_populates='recorder_commands')
@staticmethod
def get_all():
@@ -145,3 +173,35 @@ class RecorderCommand(db.Model):
@parameters.setter
def parameters(self, parameters_dict: dict):
self.parameters_string = json.dumps(parameters_dict)
def pre_create_recorders():
models = set()
f = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir, 'models', 'initial_recorders.json'))
with open(f, 'r') as json_file:
recorders = json.load(json_file)['recorders']
for r in recorders:
type = r.get('type')
firmware_version = r.get('firmware_version', None)
for k_r in KNOWN_RECORDERS:
if match := k_r.search(type):
print(KNOWN_RECORDERS[k_r])
print(match)
print(match.groups())
models.add(r.get('type', ''))
models.discard('')
print(models)
def pre_fill_table():
try:
pre_create_recorders()
print(db.session.commit())
except IntegrityError as e:
db.session.rollback()
if __name__ == '__main__':
pass
# pre_create_recorder_models()

View File

@@ -1,10 +1,15 @@
import importlib
import inspect
import pkgutil
import sys
import telnetlib
from abc import ABC, abstractmethod
defined_recorder_adapters = None
# monkey patching of telnet lib
from pprint import pprint
original_read_until = telnetlib.Telnet.read_until
original_write = telnetlib.Telnet.write
@@ -92,6 +97,16 @@ class TelnetAdapter(ABC):
class RecorderAdapter:
def __init__(self, address: str, user: str, password: str):
self.address = address
self.user = user
self.password = password
@classmethod
@abstractmethod
def get_recorder_params(cls) -> dict:
pass
@abstractmethod
def _get_name(self):
pass
@@ -108,13 +123,15 @@ class RecorderAdapter:
pass
def get_defined_recorder_adapters():
def get_defined_recorder_adapters() -> list:
rec_adapters_module = importlib.import_module(".recorder_adapters", package='backend')
rec_adapter_class = getattr(rec_adapters_module, "RecorderAdapter") # needed, otherwise subclass check may fail
models = []
found_packages = list(pkgutil.iter_modules(sys.modules[__name__].__path__))
found_packages = list(pkgutil.iter_modules(rec_adapters_module.__path__))
for f_p in found_packages:
importer = f_p[0]
rec_model_module = importer.find_module(f_p[1]).load_module(f_p[1])
rec_model = {'id': f_p[1], 'name': f_p[1], 'commands': {}}
rec_model = {'id': f_p[1], 'name': f_p[1], 'commands': {}, 'path': rec_model_module.__file__}
if hasattr(rec_model_module, 'RECORDER_MODEL_NAME'):
rec_model['name'] = rec_model_module.RECORDER_MODEL_NAME
if hasattr(rec_model_module, 'REQUIRES_USER'):
@@ -122,7 +139,9 @@ def get_defined_recorder_adapters():
if hasattr(rec_model_module, 'REQUIRES_PW'):
rec_model['requires_password'] = rec_model_module.REQUIRES_PW
for name, obj in inspect.getmembers(rec_model_module, inspect.isclass):
if issubclass(obj, RecorderAdapter):
if issubclass(obj, rec_adapter_class) and name != "RecorderAdapter":
rec_model['id'] = rec_model['id'] + "." + obj.__name__
rec_model['class'] = obj
commands = {}
for method_name, method in inspect.getmembers(obj, predicate=inspect.isfunction):
if len(method_name) > 0 and "_" == method_name[0]:
@@ -141,3 +160,19 @@ def get_defined_recorder_adapters():
rec_model["commands"] = commands
models.append(rec_model)
return models
def get_recorder_adapter_by_id(id: str, **kwargs):
global defined_recorder_adapters
if defined_recorder_adapters is None:
defined_recorder_adapters = get_defined_recorder_adapters()
for rec_adapter in defined_recorder_adapters:
if id in rec_adapter.get('id', '').split("."):
return rec_adapter['class'](**kwargs)
return None
if __name__ == '__main__':
print(get_defined_recorder_adapters())
get_recorder_adapter_by_id('SMP35x', address="172.22.246.207", password="123mzsmp")
exit()

View File

@@ -1,4 +1,12 @@
# Copyright (c) 2019. Tobias Kurze
"""
This is the recorder adapter implementation for Epiphan Recorders. The following Epiphan recorder models are supported:
- LectureRecorder X2
- LectureRecorder
- VGADVI Recorder
- DVI Broadcaster DL
- DVIRecorderDL
"""
import shutil
import time
from datetime import datetime
@@ -14,39 +22,44 @@ from backend.recorder_adapters import RecorderAdapter
# HOST = "localhost"
from backend.tools.exception_decorator import exception_decorator
RECORDER_MODEL_NAME = "Epiphan Recorder Adapter (for: )"
BASE_URL = "http://172.23.8.102" # Audimax SMP 351
USER = "admin"
PW = "lrgrashof+-"
class EpiphanV1(RecorderAdapter):
def __init__(self, url: str, admin_user: str, admin_pw: str):
if not url.startswith('http'):
url = 'http://' + url
self.url = url
self.user = admin_user
self.password = admin_pw
class Epiphan(RecorderAdapter):
def __init__(self, address: str, user: str, password: str, firmware_version: str = "", **kwargs):
if not address.startswith('http'):
address = 'http://' + address
super().__init__(address, user, password)
self.firmware_version = firmware_version
self.session = requests.Session()
self.session.auth = HTTPBasicAuth(self.user, self.password)
@classmethod
def get_recorder_params(cls) -> dict:
return {'_requires_user': True,
'_requires_password': True}
def _get_name(self):
pass
return RECORDER_MODEL_NAME
def _get_version(self):
pass
@exception_decorator(ConnectionError)
def get_recording_status(self) -> dict:
res = self.session.get(self.url + "/admin/ajax/recorder_status.cgi")
res = self.session.get(self.address + "/admin/ajax/recorder_status.cgi")
if res.ok:
return res.json()
raise LrcException(res.text, res.status_code)
@exception_decorator(ConnectionError)
def get_sysinfo(self) -> dict:
res = self.session.get(self.url + "/ajax/sysinfo.cgi")
res = self.session.get(self.address + "/ajax/sysinfo.cgi")
if res.ok:
return res.json()
raise LrcException(res.text, res.status_code)
@@ -63,13 +76,13 @@ class EpiphanV1(RecorderAdapter):
return self.get_recording_status().get('seconds', None)
def start_recording(self):
res = self.session.get(self.url + "/admin/ajax/start_recorder.cgi")
res = self.session.get(self.address + "/admin/ajax/start_recorder.cgi")
if not res.ok:
raise LrcException(res.text, res.status_code)
time.sleep(2) # just a little bit of waiting time -> it takes a bit for the Epiphan to update its state
def stop_recording(self):
res = self.session.get(self.url + "/admin/ajax/stop_recorder.cgi")
res = self.session.get(self.address + "/admin/ajax/stop_recorder.cgi")
if not res.ok:
raise LrcException(res.text, res.status_code)
time.sleep(4) # just a little bit of waiting time -> it takes a bit for the Epiphan to update its state
@@ -114,7 +127,7 @@ class EpiphanV1(RecorderAdapter):
raise LrcException(str(err))
def get_screenshot(self):
ret = self.session.get(self.url + "/admin/grab_frame.cgi?size=256x192&device=DAV93133.vga&_t=1573471990578",
ret = self.session.get(self.address + "/admin/grab_frame.cgi?size=256x192&device=DAV93133.vga&_t=1573471990578",
stream=True)
print(ret)
@@ -125,7 +138,7 @@ class EpiphanV1(RecorderAdapter):
if __name__ == '__main__':
e = EpiphanV1(BASE_URL, USER, PW)
e = Epiphan(BASE_URL, USER, PW)
try:
# print(e.is_recording())
"""

View File

@@ -1,3 +1,6 @@
"""
Recorder Adapter for SMP
"""
import logging
from backend import LrcException
@@ -6,7 +9,7 @@ from backend.tools.exception_decorator import exception_decorator
logger = logging.getLogger("lrc.recorder_adapters.extron_smp")
RECORDER_MODEL_NAME = "SMP 351 / 352"
RECORDER_MODEL_NAME = "Recorder Adapter for SMP 351 and 352"
VERSION = "0.9.0"
REQUIRES_USER = False
REQUIRES_PW = True
@@ -19,14 +22,14 @@ HOST = "129.13.51.109" # Hertz
USER = "admin"
PW = "123mzsmp"
#PW = "audimaxsmp"
# PW = "audimaxsmp"
PW = "smphertz"
class SMP(TelnetAdapter, RecorderAdapter):
class SMP35x(TelnetAdapter, RecorderAdapter):
def __init__(self, address, password, auto_login=True, **kwargs):
super().__init__(address)
self.admin_pw = password
RecorderAdapter.__init__(self, address, "", password)
TelnetAdapter.__init__(self, address)
if auto_login:
self._login()
@@ -40,7 +43,7 @@ class SMP(TelnetAdapter, RecorderAdapter):
raise LrcException(str(e))
self.tn.read_until("\r\nPassword:")
# password = getpass.getpass()
password = self.admin_pw
password = self.password
self.tn.write(password + "\n\r")
out = self.tn.assert_string_in_output("Login Administrator")
@@ -51,10 +54,10 @@ class SMP(TelnetAdapter, RecorderAdapter):
# TODO: loop until logged in...
logger.warning("Could not login (as admin) with given password! {}".format(self.address))
print("re-enter pw")
self.tn.write(self.admin_pw+"\n\r")
self.tn.write(self.password + "\n\r")
print(self.tn.assert_string_in_output("Login Administrator"))
print("WRONG (admin) password!! Exiting!")
print(self.admin_pw)
print(self.password)
self.tn = None
logger.error("Could definitely not login (as admin) with given password! {}".format(self.address))
raise Exception("Could not login as administrator with given pw!")
@@ -725,6 +728,11 @@ class SMP(TelnetAdapter, RecorderAdapter):
some advanced options skipped
"""
@classmethod
def get_recorder_params(cls) -> dict:
return {'_requires_user': False,
'_requires_password': True}
def get_input_hdcp_status(self, input_number: int):
"""
returns:
@@ -783,9 +791,8 @@ class SMP(TelnetAdapter, RecorderAdapter):
return TelnetAdapter._get_response_str(self.tn.read_until_non_empty_line())
def main():
smp = SMP(HOST, PW, True)
smp = SMP35x(HOST, PW, True)
print(smp)
print(smp.get_recording_status())
@@ -833,6 +840,6 @@ def main():
print(smp.unmute_output(2))
print(smp.is_muted(2))
if __name__ == '__main__':
main()

18
backend/tools/helpers.py Normal file
View File

@@ -0,0 +1,18 @@
import hashlib
def calculate_md5_checksum(string_to_md5_sum: str):
return hashlib.md5(string_to_md5_sum.encode('utf-8')).hexdigest()
def file_md5(fname: str) -> str:
hash_md5 = hashlib.md5()
with open(fname, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
if __name__ == '__main__':
print(file_md5(__file__))

View File

@@ -14,10 +14,7 @@ from sqlalchemy import and_
from backend import db
from backend.models.recorder_model import RecorderModel, RecorderCommand
from backend.recorder_adapters import get_defined_recorder_adapters
def calculate_md5_checksum(string_to_md5_sum: str):
return hashlib.md5(string_to_md5_sum.encode('utf-8')).hexdigest()
from backend.tools.helpers import calculate_md5_checksum
def create_recorder_commands_for_recorder_adapter(command_definitions: dict, recorder_model: RecorderModel):
@@ -61,9 +58,9 @@ def update_recorder_models_database():
else:
if not model_checksum == r_m.checksum:
r_m.model_name = r_a["name"]
r_m.model_name = r_a["name"]
r_m.last_time_modified = datetime.utcnow()
r_m.checksum = model_checksum
create_recorder_commands_for_recorder_adapter(r_a["commands"], r_m)
create_recorder_commands_for_recorder_adapter(r_a["commands"], r_m)
db.session.commit()

View File

@@ -1,9 +1,10 @@
import smtplib
import traceback
from email.message import EmailMessage
from logging.handlers import SMTPHandler
from typing import List, Union
from backend import main_logger, Config
from backend import Config
def send_mail(subject: str, msg_body: str, to_mail: List, from_mail: str = Config.FROM_MAIL):
@@ -18,7 +19,7 @@ def send_mail(subject: str, msg_body: str, to_mail: List, from_mail: str = Confi
s.send_message(msg)
s.quit()
except Exception as e:
main_logger.error(
print(
"Could not send E-Mail (Exception: {})".format(str(e)))
@@ -43,3 +44,17 @@ def send_error_mail(message_or_exception: Union[str, Exception], subject: str =
def send_warning_mail():
pass
def get_smtp_default_handler(receiver_mail_addresses=Config.ADMIN_E_MAIL_TO, subject: str = None,
subject_prefix: str = "[LRC] Log: "):
subject = subject if subject.startswith("[LRC]") else subject_prefix + subject
return SMTPHandler(Config.SMTP_SERVER, Config.FROM_MAIL, receiver_mail_addresses, subject)
def get_smtp_error_handler(receiver_mail_addresses=Config.ERROR_E_MAIL_TO, subject: str = None,
subject_prefix: str = "[LRC] Error: "):
subject = subject if subject.startswith("[LRC]") else subject_prefix + subject
return SMTPHandler(Config.SMTP_SERVER, Config.FROM_MAIL, receiver_mail_addresses, subject)

View File

@@ -1,32 +1,38 @@
import json
import os
import logging
import subprocess
import threading
from io import StringIO
from logging.handlers import MemoryHandler
import requests
from requests.auth import HTTPBasicAuth
from multiprocessing.pool import ThreadPool
from multiprocessing.context import TimeoutError
from pprint import pprint
from ics import Calendar
from backend import LrcException
from backend.config import Config
from backend.recorder_adapters import RecorderAdapter
from backend.recorder_adapters.epiphan_base import EpiphanV1
from backend.recorder_adapters.extron_smp import SMP
from backend.tools.send_mail import send_error_mail
from backend.recorder_adapters.epiphan_base import Epiphan
from backend.recorder_adapters.extron_smp import SMP35x
from backend.tools.send_mail import send_error_mail, get_smtp_error_handler
logger = logging.getLogger("lrc.tools.simple_state_checker")
smtp_error_handler = get_smtp_error_handler(subject="Errors have been detected while checking recorder states!")
#mem_handler = MemoryHandler(capacity=100, flushLevel=logging.FATAL, target=smtp_error_handler)
#mem_handler.setLevel(logging.WARNING)
rec_err_state_log_stream = StringIO()
rec_err_state_log_stream_handler = logging.StreamHandler(stream=rec_err_state_log_stream)
rec_err_state_log_stream_handler.setLevel(logging.WARNING)
logger.addHandler(rec_err_state_log_stream_handler)
#logger.addHandler(mem_handler)
base_url = "https://opencast.bibliothek.kit.edu"
@@ -37,6 +43,9 @@ config = {'service_urls': {}}
recorders = None
agent_states_lock = threading.RLock()
agent_states = {}
def get_service_url(service_type: str):
if service_type in config['service_urls']:
@@ -90,9 +99,9 @@ def notify_users_of_problem(msg: str):
def get_recorder_adapter(recorder_info: dict) -> RecorderAdapter:
if "SMP" in recorder_info["type"]:
rec = SMP(recorder_info['ip'], recorder_info['password'])
rec = SMP35x(recorder_info['ip'], recorder_info['password'])
else:
rec = EpiphanV1(recorder_info['ip'], recorder_info["username"], recorder_info["password"])
rec = Epiphan(recorder_info['ip'], recorder_info["username"], recorder_info["password"])
return rec
@@ -108,9 +117,13 @@ def check_capture_agent_state(a: dict):
rec = get_recorder_adapter(recorder_info)
if rec.is_recording():
logger.info("OK recorder {} is recording :)".format(a['name']))
with agent_states_lock:
agent_states[a['name']] = 'OK - recorder is recording'
else:
logger.info(rec.get_recording_status())
logger.error("FATAL - recorder {} must be recording but is not!!!!".format(a['name']))
with agent_states_lock:
agent_states[a['name']] = 'FATAL - recorder is NOT recording, but should!'
except LrcException as e:
logger.fatal("Exception occurred: {}".format(str(e)))
logger.error("Could not check state of recorder {}, Address: {}".format(a['name'], recorder_info['ip']))
@@ -122,20 +135,51 @@ def check_capture_agent_state(a: dict):
rec = get_recorder_adapter(recorder_info)
if rec.is_recording():
logger.error("FATAL - recorder must not be recording!!!!")
with agent_states_lock:
agent_states[a['name']] = 'FATAL - recorder IS recording, but should NOT!'
else:
logger.info("OK recorder is not recording :)")
with agent_states_lock:
agent_states[a['name']] = 'OK - recorder is NOT recording'
except LrcException as e:
logger.fatal("Exception occurred: {}".format(str(e)))
logger.error("Could not check state of recorder {}, Address: {}".format(a['name'], recorder_info['ip']))
def ping_capture_agent(a: dict):
recorder_ip = get_recorder_by_name(a['name'])['ip']
try:
response = subprocess.check_call(
['ping', '-W', '10', '-c', '2', recorder_ip],
# stderr=subprocess.STDOUT, # get all output
stdout=subprocess.DEVNULL, # suppress output
stderr=subprocess.DEVNULL,
universal_newlines=True # return string not bytes
)
logger.info("Successfully pinged {} ({}). :-)".format(a['name'], recorder_ip))
except subprocess.CalledProcessError:
logger.error("Can not ping {} ({})!!".format(a['name'], recorder_ip))
agents = get_capture_agents()
logger.info("Got {} capture agents that will be checked...".format(len(agents)))
for a in agents:
agent_states[a['name']] = 'PROBLEMATIC - unknown'
# pool = ThreadPool(5)
# pool.map(check_capture_agent_state, agents)
NUM_THREADS = 5
NUM_THREADS = 8
with ThreadPool(NUM_THREADS) as pool:
results = [pool.apply_async(ping_capture_agent, (agent,)) for agent in agents]
try:
[res.get(timeout=12) for res in results]
except TimeoutError as e:
logger.error("Timeout while pinging capture agent! {}".format(e))
with ThreadPool(NUM_THREADS) as pool:
results = [pool.apply_async(check_capture_agent_state, (agent,)) for agent in agents]
@@ -148,4 +192,9 @@ logger.info("DONE checking capture agents / recorders!")
logged_events = rec_err_state_log_stream.getvalue()
if len(logged_events) > 0:
logged_events += "\n\n=============\nAgent States:\n\n{}".format(''.join(
"{:<48}: {}\n".format(a, agent_states[a]) for a in agent_states
))
send_error_mail(logged_events, "Errors have been detected while checking recorder states!")
#mem_handler.close()