def get_context(): """ Create the context to be used for nghttpx, other than the one provided by the configs. """ context = {} context['backends'] = [] for service in ServiceRegistry.list_services(): (ip_address, port) = ServiceRegistry.get_service_address(service) backend = {'service': service, 'ip': ip_address, 'port': port} context['backends'].append(backend) # We get the gateway cert after bootstrapping, but we do want nghttpx # to run before that for communication locally. Update the flag for # jinja to act upon. gateway_cert = get_service_config_value('control_proxy', 'gateway_cert', None) if gateway_cert and os.path.exists(gateway_cert): context['use_gateway_cert'] = True else: context['use_gateway_cert'] = False context['dev_mode'] = is_dev_mode() context['allow_http_proxy'] = get_service_config_value( 'control_proxy', 'allow_http_proxy', False) context['http_proxy'] = os.getenv('http_proxy', '') return context
def TailLogs(self, request, context): """ Provides an infinite stream of logs to the client. The client can stop the stream by closing the connection. """ self._print_grpc(request) if request.service and \ request.service not in ServiceRegistry.list_services(): set_grpc_err( context, grpc.StatusCode.NOT_FOUND, 'Service {} not found'.format(request.service), ) return if not request.service: exec_list = ['sudo', 'tail', '-f', '/var/log/syslog'] else: exec_list = [ 'sudo', 'journalctl', '-fu', 'magma@{}'.format(request.service), ] logging.debug('Tailing logs') log_queue = queue.Queue() async def enqueue_log_lines(): # https://stackoverflow.com/a/32222971 proc = await asyncio.create_subprocess_exec( *exec_list, stdout=asyncio.subprocess.PIPE, preexec_fn=os.setsid, ) try: while context.is_active(): try: line = await asyncio.wait_for( proc.stdout.readline(), timeout=10.0, ) log_queue.put(line) except asyncio.TimeoutError: pass finally: logging.debug('Terminating log stream') os.killpg(os.getpgid(proc.pid), signal.SIGTERM) self._loop.create_task(enqueue_log_lines()) while context.is_active(): try: log_line = log_queue.get(block=True, timeout=10.0) yield magmad_pb2.LogLine(line=log_line) except queue.Empty: pass