def parse_raw(cls, raw: str) -> "State": for line in raw.splitlines(): if line.startswith(">INFO") or line.startswith(">CLIENT") or line.startswith(">STATE"): continue if line.strip() == "END": break parts = line.split(",") # 0 - Unix timestamp of server start (UTC?) up_since = datetime.datetime.utcfromtimestamp(int(parts[0])) if parts[0] != "" else None # 1 - Connection state state_name = cls._parse_string(parts[1]) # 2 - Connection state description desc_string = cls._parse_string(parts[2]) # 3 - TUN/TAP local v4 address local_virtual_v4_addr = cls._parse_ipv4(parts[3]) # 4 - Remote server address (client only) remote_addr = cls._parse_ipv4(parts[4]) # 5 - Remote server port (client only) remote_port = cls._parse_int(parts[5]) # 6 - Local address local_addr = cls._parse_ipv4(parts[6]) # 7 - Local port local_port = cls._parse_int(parts[7]) return cls( up_since=up_since, state_name=state_name, desc_string=desc_string, local_virtual_v4_addr=local_virtual_v4_addr, remote_addr=remote_addr, remote_port=remote_port, local_addr=local_addr, local_port=local_port, ) raise errors.ParseError("Did not get expected data from state.")
def parse_raw(cls, raw: str) -> "ServerStats": """Parse raw `load-stats` response into an instance.""" for line in raw.splitlines(): if not line.startswith("SUCCESS"): continue match = re.search( r"SUCCESS: nclients=(?P<nclients>\d+),bytesin=(?P<bytesin>\d+),bytesout=(?P<bytesout>\d+)", line ) if not match: raise errors.ParseError("Unable to parse stats from raw load-stats response.") return cls( client_count=int(match.group("nclients")), bytes_in=int(match.group("bytesin")), bytes_out=int(match.group("bytesout")), ) raise errors.ParseError("Did not get expected data from load-stats.")
def send_sigterm(self) -> None: """Send a SIGTERM to the OpenVPN process. """ raw = self.send_command("signal SIGTERM") if raw.strip() != "SUCCESS: signal SIGTERM thrown": raise errors.ParseError( "Did not get expected response after issuing SIGTERM.") self.disconnect(_quit=False)
def version(self) -> Optional[str]: """OpenVPN version number. """ if self.release is None: return None match = re.search(r"OpenVPN (?P<version>\d+.\d+.\d+)", self.release) if not match: raise errors.ParseError( "Unable to parse version from release string.") return match.group("version")
def _get_version(self) -> str: """Get OpenVPN version from socket. """ raw = self.send_command("version") for line in raw.splitlines(): if line.startswith("OpenVPN Version"): return line.replace("OpenVPN Version: ", "") raise errors.ParseError( "Unable to get OpenVPN version, no matches found in socket response." )
def get_stats(self) -> ServerStats: """Get latest VPN stats. """ raw = self.send_command("load-stats") for line in raw.splitlines(): if not line.startswith("SUCCESS"): continue match = re.search( r"SUCCESS: nclients=(?P<nclients>\d+),bytesin=(?P<bytesin>\d+),bytesout=(?P<bytesout>\d+)", line) if not match: raise errors.ParseError( "Unable to parse stats from load-stats response.") return ServerStats( client_count=match.group("nclients"), bytes_in=match.group("bytesin"), bytes_out=match.group("bytesout"), ) raise errors.ParseError( "Did not get expected response from load-stats.")