def main(): arguments = parser.parse_args() basic_config(level=arguments.log_level, log_format=arguments.log_format, buffered=False) setproctitle(os.path.basename("[Master] %s" % sys.argv[0])) tcp_sock = bind_socket(address=arguments.tcp_listen, port=arguments.tcp_port) pickle_sock = bind_socket(address=arguments.pickle_listen, port=arguments.pickle_port) udp_sock = bind_socket( socket.AF_INET6 if ':' in arguments.udp_listen else socket.AF_INET, socket.SOCK_DGRAM, address=arguments.udp_listen, port=arguments.udp_port) def run(): setproctitle(os.path.basename("[Worker] %s" % sys.argv[0])) storage = Storage( os.path.join(arguments.storage, "%03d.db" % forklib.get_id())) services = [ CarbonTCPServer(sock=tcp_sock, storage=storage), CarbonPickleServer(sock=pickle_sock, storage=storage), CarbonUDPServer(sock=udp_sock, storage=storage), SenderService( proxy_url=arguments.carbon_proxy_url, secret=arguments.carbon_proxy_secret, storage=storage, interval=arguments.sender_interval, chunk_size=arguments.chunk_size, ) ] with entrypoint(*services, log_level=arguments.log_level, log_format=arguments.log_format, pool_size=arguments.pool_size) as loop: loop.set_debug(arguments.debug) loop.run_forever() if arguments.debug: run() else: forklib.fork(arguments.forks, run)
def main(): args = parser.parse_args() clear_environ(lambda i: i.startswith(ENV_VAR_PREFIX)) # Чтобы логи не блокировали основной поток (и event loop) во время операций # записи в stderr или файл - логи можно буфферизовать и обрабатывать в # отдельном потоке (aiomisc.basic_config настроит буфферизацию # автоматически). basic_config(args.log_level, args.log_format, buffered=True) # Аллоцируем сокет из под привиллегированного пользователя отдельным шагом, # чтобы была возможность перед запуском приложения сменить пользователя ОС. sock = bind_socket( address=args.api_address, port=args.api_port, proto_name='http', ) # После того как приложение аллоцировало сокет и ему больше не нужны # привиллегии - хорошим решением будет сменить пользователя (например, # на nobody, у которого нет никаких специальных привиллегий) - это также # усложнит жизнь злоумышленникам. if args.user is not None: logging.info('Changing user to %r', args.user.pw_name) os.setgid(args.user.pw_gid) os.setuid(args.user.pw_uid) # В списке процессов намного удобнее видеть название текущего приложения setproctitle(os.path.basename(argv[0])) app = create_app(args) run_app(app, sock=sock)
def test_sdwatchdog_service(loop): with TemporaryDirectory(dir="/tmp") as tmp_dir: tmp_path = Path(tmp_dir) sock_path = str(tmp_path / "notify.sock") packets = deque() class FakeSystemd(UDPServer): def handle_datagram(self, data: bytes, addr: tuple) -> None: packets.append((data.decode().split("=", 1), addr)) with bind_socket( socket.AF_UNIX, socket.SOCK_DGRAM, address=sock_path, ) as sock: try: os.environ["NOTIFY_SOCKET"] = sock_path os.environ["WATCHDOG_USEC"] = "100000" service = sdwatchdog.SDWatchdogService( watchdog_interval=sdwatchdog._get_watchdog_interval(), ) assert service.watchdog_interval == 0.1 with aiomisc.entrypoint( FakeSystemd(sock=sock), service, loop=loop, ): loop.run_until_complete(asyncio.sleep(1)) finally: for key in ("NOTIFY_SOCKET", "WATCHDOG_USEC"): os.environ.pop(key) assert packets messages_count = Counter() messages = defaultdict(set) for (key, value), sender in packets: assert key assert value messages_count[key] += 1 messages[key].add(value) assert 5 < messages_count["WATCHDOG"] < 25 assert messages_count["STATUS"] == 2 assert messages_count["WATCHDOG_USEC"] == 1 assert tuple(messages["WATCHDOG_USEC"])[0] == "100000"
def main(): args = parser.parse_args() clear_environ(lambda i: i.startswith(ENV_VAR_PREFIX)) basic_config(args.log_level, args.log_format, buffered=True) sock = bind_socket(address=args.api_address, port=args.api_port, proto_name='http') if args.user is not None: logging.info('Changing user to %r', args.user.pw_name) os.setgid(args.user.pw_gid) os.setuid(args.user.pw_uid) setproctitle(os.path.basename(argv[0])) app = create_app(args) run_app(app, sock=sock)
def main(): args = parser.parse_args() # После получения конфигурации приложения переменные окружения приложения # больше не нужны и даже могут представлять опасность - например, они могут # случайно "утечь" с отображением информации об ошибке. Злоумышленники # в первую очередь будут пытаться получить информацию об окружении, очистка # переменных окружения считается хорошим тоном. # Python позволяет управлять поведением stdlib модулей с помощью # многочисленных переменных окружения, разумно очищать переменные окружения # по префиксу приложения, указанного в ConfigArgParser. clear_environ(lambda i: i.startswith(ENV_VAR_PREFIX)) # Чтобы логи не блокировали основной поток (и event loop) во время операций # записи в stderr или файл - логи можно буфферизовать и обрабатывать в # отдельном потоке (aiomisc.basic_config настроит буфферизацию # автоматически). basic_config(args.log_level, args.log_format, buffered=True) # Аллоцируем сокет из под привиллегированного пользователя отдельным шагом, # чтобы была возможность перед запуском приложения сменить пользователя ОС. sock = bind_socket(address=args.api_address, port=args.api_port, proto_name='http') # После того как приложение аллоцировало сокет и ему больше не нужны # привиллегии - хорошим решением будет сменить пользователя (например, # на nobody, у которого нет никаких специальных привиллегий) - это также # усложнит жизнь злоумышленникам. if args.user is not None: logging.info('Changing user to %r', args.user.pw_name) os.setgid(args.user.pw_gid) os.setuid(args.user.pw_uid) # В списке процессов намного удобнее видеть название текущего приложения setproctitle(os.path.basename(argv[0])) app = create_app(args) run_app(app, sock=sock)
def run(self): self.init_logger() logger = logging.getLogger(__class__.__name__) # Socket is allocated for ability change the OS user try: sock = bind_socket(address=self.api_address, port=self.api_port, proto_name='http') except OSError as e: logger.exception(e) exit(1) if self.user is not None: logger.info('Changing user to %r', self.user.pw_name) os.setgid(self.user.pw_gid) os.setuid(self.user.pw_uid) app = create_app() app['storage_path'] = self.storage run_app(app, sock=sock)
def test_bind_address(address, family, aiomisc_unused_port): sock = aiomisc.bind_socket(address=address, port=aiomisc_unused_port) assert isinstance(sock, socket.socket) assert sock.family == family
def test_journald_logger(loop, subtests): with TemporaryDirectory(dir="/tmp") as tmp_dir: tmp_path = Path(tmp_dir) sock_path = tmp_path / "notify.sock" logs = deque() class FakeJournald(UDPServer): VALUE_LEN_STRUCT = struct.Struct("<Q") def handle_datagram(self, data: bytes, addr: tuple) -> None: result = {} with BytesIO(data) as fp: line = fp.readline() while line: if b"=" not in line: key = line.decode().strip() value_len = self.VALUE_LEN_STRUCT.unpack( fp.read( self.VALUE_LEN_STRUCT.size, ), )[0] value = fp.read(value_len).decode() assert fp.read(1) == b"\n" else: key, value = map( lambda x: x.strip(), line.decode().split("=", 1), ) result[key] = value line = fp.readline() logs.append(result) @threaded def log_writer(): log = logging.getLogger("test") log.propagate = False log.handlers.clear() log.handlers.append(JournaldLogHandler()) log.info("Test message") log.info("Test multiline\nmessage") log.info( "Test formatted: int=%d str=%s repr=%r float=%0.1f", 1, 2, 3, 4, ) log.info( "Message with extra", extra={ "foo": "bar", }, ) try: 1 / 0 except ZeroDivisionError: log.exception("Sample exception") with bind_socket( socket.AF_UNIX, socket.SOCK_DGRAM, address=str(sock_path), ) as sock: JournaldLogHandler.SOCKET_PATH = sock_path with aiomisc.entrypoint(FakeJournald(sock=sock), loop=loop): loop.run_until_complete(log_writer()) assert len(logs) == 5 required_fields = { "MESSAGE", "MESSAGE_ID", "MESSAGE_RAW", "PRIORITY", "SYSLOG_FACILITY", "CODE", "CODE_FUNC", "CODE_FILE", "CODE_LINE", "CODE_MODULE", "LOGGER_NAME", "PID", "PROCESS_NAME", "THREAD_ID", "THREAD_NAME", "RELATIVE_USEC", "CREATED_USEC", } with subtests.test("simple message"): message = logs.popleft() assert message["MESSAGE"] == "Test message" assert message["MESSAGE_RAW"] == "Test message" assert message["PRIORITY"] == "6" assert message["CODE_FUNC"] == "log_writer" assert int(message["PID"]) == os.getpid() for field in required_fields: assert field in message with subtests.test("multiline message"): message = logs.popleft() assert message["MESSAGE"] == "Test multiline\nmessage" assert message["MESSAGE_RAW"] == "Test multiline\nmessage" assert message["PRIORITY"] == "6" assert message["CODE_FUNC"] == "log_writer" assert int(message["PID"]) == os.getpid() for field in required_fields: assert field in message with subtests.test("formatted message"): message = logs.popleft() assert message["MESSAGE"] == ( "Test formatted: int=1 str=2 repr=3 float=4.0" ) assert message["MESSAGE_RAW"] == ( "Test formatted: int=%d str=%s repr=%r float=%0.1f" ) assert message["ARGUMENTS_0"] == "1" assert message["ARGUMENTS_1"] == "2" assert message["ARGUMENTS_2"] == "3" assert message["ARGUMENTS_3"] == "4" assert message["PRIORITY"] == "6" assert message["CODE_FUNC"] == "log_writer" assert int(message["PID"]) == os.getpid() for field in required_fields: assert field in message with subtests.test("message with extra"): message = logs.popleft() assert message["MESSAGE"] == "Message with extra" assert message["MESSAGE_RAW"] == "Message with extra" assert message["PRIORITY"] == "6" assert message["CODE_FUNC"] == "log_writer" assert message["EXTRA_FOO"] == "bar" assert int(message["PID"]) == os.getpid() for field in required_fields: assert field in message with subtests.test("exception message"): message = logs.popleft() assert message["MESSAGE"].startswith("Sample exception\nTraceback") assert message["MESSAGE_RAW"] == "Sample exception" assert message["PRIORITY"] == "3" assert message["CODE_FUNC"] == "log_writer" assert int(message["PID"]) == os.getpid() assert message["EXCEPTION_TYPE"] == "<class 'ZeroDivisionError'>" assert message["EXCEPTION_VALUE"] == "division by zero" assert message["TRACEBACK"].startswith( "Traceback (most recent call last)", ) for field in required_fields: assert field in message