diff --git a/lib/tfw/components/__init__.py b/lib/tfw/components/__init__.py index 7aabc38..73c889d 100644 --- a/lib/tfw/components/__init__.py +++ b/lib/tfw/components/__init__.py @@ -11,4 +11,4 @@ from .log_monitoring_event_handler import LogMonitoringEventHandler from .fsm_managing_event_handler import FSMManagingEventHandler from .snapshot_provider import SnapshotProvider from .pipe_io_event_handler import PipeIOEventHandlerBase, PipeIOEventHandler, PipeIOServer -from .pipe_io_event_handler import TransformerPipeIOEventHandler +from .pipe_io_event_handler import TransformerPipeIOEventHandler, CommandEventHandler diff --git a/lib/tfw/components/pipe_io_event_handler.py b/lib/tfw/components/pipe_io_event_handler.py index 451e9d1..63855b6 100644 --- a/lib/tfw/components/pipe_io_event_handler.py +++ b/lib/tfw/components/pipe_io_event_handler.py @@ -1,7 +1,11 @@ from abc import abstractmethod from json import loads, dumps -from subprocess import run, PIPE +from subprocess import run, PIPE, Popen from functools import partial +from os import getpgid, killpg +from os.path import join +from signal import SIGTERM +from secrets import token_urlsafe from tfw import EventHandlerBase from tfw.config.logs import logging @@ -85,3 +89,33 @@ class TransformerPipeIOEventHandler(PipeIOEventHandlerBase): if transformed_bytes: json_message = loads(transformed_bytes) self.server_connector.send(json_message) + + +class CommandEventHandler(PipeIOEventHandler): + def __init__(self, key, command, permissions=DEFAULT_PERMISSIONS): + super().__init__( + key, + self._generate_tempfilename(), + self._generate_tempfilename(), + permissions + ) + + self._proc_stdin = open(self.pipe_io.out_pipe, 'rb') + self._proc_stdout = open(self.pipe_io.in_pipe, 'wb') + self._proc = Popen( + command, shell=True, executable='/bin/bash', + stdin=self._proc_stdin, stdout=self._proc_stdout, + start_new_session=True + ) + + def _generate_tempfilename(self): + # pylint: disable=no-self-use + random_filename = partial(token_urlsafe, 10) + return join('/tmp', f'{type(self).__name__}.{random_filename()}') + + def cleanup(self): + process_group_id = getpgid(self._proc.pid) + killpg(process_group_id, SIGTERM) + self._proc_stdin.close() + self._proc_stdout.close() + super().cleanup()