From 3eedb42c4bf8b362b4a123154f50a5911de1a08f Mon Sep 17 00:00:00 2001 From: "Kali Kaneko (leap communications)" Date: Thu, 15 Jun 2017 14:55:56 +0200 Subject: [feat] process logs through management interface --- src/leap/bitmask/vpn/_management.py | 30 ++++++++++++++++++++++-------- src/leap/bitmask/vpn/_status.py | 2 +- src/leap/bitmask/vpn/process.py | 33 ++++++++++++++++++--------------- 3 files changed, 41 insertions(+), 24 deletions(-) (limited to 'src/leap/bitmask/vpn') diff --git a/src/leap/bitmask/vpn/_management.py b/src/leap/bitmask/vpn/_management.py index 16bb86fe..26050be6 100644 --- a/src/leap/bitmask/vpn/_management.py +++ b/src/leap/bitmask/vpn/_management.py @@ -2,7 +2,7 @@ import os import shutil import socket -from twisted.internet import defer, reactor +from twisted.internet import reactor from twisted.logger import Logger import psutil @@ -56,6 +56,7 @@ class VPNManagement(object): self._last_state = None self._last_status = None self._status = None + self._logs = {} def set_connection(self, host, port): """ @@ -68,6 +69,9 @@ class VPNManagement(object): self._host = host self._port = port + def set_watcher(self, watcher): + self._watcher = watcher + def is_connected(self): return bool(self._tn) @@ -112,6 +116,23 @@ class VPNManagement(object): self.CONNECTION_RETRY_TIME, self.connect_retry, retry + 1) + def process_log(self): + if not self._watcher: + return + + lines = self._send_command('log 20') + for line in lines: + try: + splitted = line.split(',') + ts = splitted[0] + msg = ','.join(splitted[2:]) + if ts not in self._logs: + self._watcher.watch(msg) + self.log.info('VPN: %s' % msg) + self._logs[ts] = msg + except Exception: + pass + def _seek_to_eof(self): """ Read as much as available. Position seek pointer to end of stream @@ -172,7 +193,6 @@ class VPNManagement(object): self._tn.get_socket().close() self._tn = None - def _parse_state_and_notify(self, output): """ Parses the output of the state command, and trigger a state transition @@ -183,7 +203,6 @@ class VPNManagement(object): :type output: list """ for line in output: - print "PARSING", line stripped = line.strip() if stripped == "END": continue @@ -199,8 +218,6 @@ class VPNManagement(object): if state != self._last_state: # XXX this status object is the vpn status observer if self._status: - # XXX DEBUG ----------------------- - print "SETTING STATUS", state self._status.set_status(state, None) self._last_state = state @@ -213,13 +230,11 @@ class VPNManagement(object): as its output :type output: list """ - print "PARSING STATUS", output tun_tap_read = "" tun_tap_write = "" for line in output: stripped = line.strip() - print "LINE", stripped if stripped.endswith("STATISTICS") or stripped == "END": continue parts = stripped.split(",") @@ -245,7 +260,6 @@ class VPNManagement(object): traffic_status = (tun_tap_read, tun_tap_write) if traffic_status != self._last_status: - # XXX this status object is the vpn status observer if self._status: self._status.set_traffic_status(traffic_status) self._last_status = traffic_status diff --git a/src/leap/bitmask/vpn/_status.py b/src/leap/bitmask/vpn/_status.py index 7cd48968..6bd9c7c9 100644 --- a/src/leap/bitmask/vpn/_status.py +++ b/src/leap/bitmask/vpn/_status.py @@ -1,8 +1,8 @@ from itertools import chain, repeat -from ._human import bytes2human from leap.common.events import catalog, emit_async +from leap.bitmask.vpn._human import bytes2human # TODO implement a more explicit state machine # TODO check good transitions diff --git a/src/leap/bitmask/vpn/process.py b/src/leap/bitmask/vpn/process.py index 34548bff..9b235260 100644 --- a/src/leap/bitmask/vpn/process.py +++ b/src/leap/bitmask/vpn/process.py @@ -94,8 +94,9 @@ class _VPNProcess(protocol.ProcessProtocol, _management.VPNManagement): self._restartfun = restartfun self._status = _status.VPNStatus() - self.restarting = False + self.set_watcher(self._status) + self.restarting = False self._remotes = remotes @property @@ -115,8 +116,6 @@ class _VPNProcess(protocol.ProcessProtocol, _management.VPNManagement): def connectionMade(self): """ Called when the connection is made. - - .. seeAlso: `http://twistedmatrix.com/documents/13.0.0/api/twisted.internet.protocol.ProcessProtocol.html` # noqa """ self._alive = True self.aborted = False @@ -125,23 +124,25 @@ class _VPNProcess(protocol.ProcessProtocol, _management.VPNManagement): def outReceived(self, data): """ Called when new data is available on stdout. + We only use this to drive the status state machine in linux, OSX uses + the management interface. :param data: the data read on stdout - - .. seeAlso: `http://twistedmatrix.com/documents/13.0.0/api/twisted.internet.protocol.ProcessProtocol.html` # noqa """ - # truncate the newline - line = data[:-1] - if 'SIGTERM[soft,ping-restart]' in line: - self.restarting = True - self.log.info(line) - self._status.watch(line) + # TODO deprecate, use log through management interface too. + + if IS_LINUX: + # truncate the newline + line = data[:-1] + # TODO -- internalize this into _status!!! so that it can be shared + if 'SIGTERM[soft,ping-restart]' in line: + self.restarting = True + self.log.info(line) + # self._status.watch(line) def processExited(self, failure): """ Called when the child process exits. - - .. seeAlso: `http://twistedmatrix.com/documents/13.0.0/api/twisted.internet.protocol.ProcessProtocol.html` # noqa """ err = failure.trap( internet_error.ProcessDone, internet_error.ProcessTerminated) @@ -162,8 +163,6 @@ class _VPNProcess(protocol.ProcessProtocol, _management.VPNManagement): """ Called when the child process exits and all file descriptors associated with it have been closed. - - .. seeAlso: `http://twistedmatrix.com/documents/13.0.0/api/twisted.internet.protocol.ProcessProtocol.html` # noqa """ exit_code = reason.value.exitCode if isinstance(exit_code, int): @@ -188,6 +187,10 @@ class _VPNProcess(protocol.ProcessProtocol, _management.VPNManagement): if self._alive: self.get_state() + def pollLog(self): + if self._alive: + self.process_log() + # launcher def preUp(self): -- cgit v1.2.3