aboutsummaryrefslogtreecommitdiffstats
path: root/src/libcharon/plugins/vici/python
diff options
context:
space:
mode:
authorBjörn Schuberg <bjorn.schuberg@gmail.com>2015-02-14 15:53:25 +0100
committerMartin Willi <martin@revosec.ch>2015-03-18 13:59:13 +0100
commit8c089cddef38217cf555aa8183d3621830bb6044 (patch)
tree57d83d9d53a428d065e8c549966b351a41d883af /src/libcharon/plugins/vici/python
parentb26e1428638a309acb7a3744c831082e32085d39 (diff)
downloadstrongswan-8c089cddef38217cf555aa8183d3621830bb6044.tar.bz2
strongswan-8c089cddef38217cf555aa8183d3621830bb6044.tar.xz
vici: Add a python vici command execution handler
Diffstat (limited to 'src/libcharon/plugins/vici/python')
-rw-r--r--src/libcharon/plugins/vici/python/vici/exception.py5
-rw-r--r--src/libcharon/plugins/vici/python/vici/session.py130
2 files changed, 134 insertions, 1 deletions
diff --git a/src/libcharon/plugins/vici/python/vici/exception.py b/src/libcharon/plugins/vici/python/vici/exception.py
index 25d73490b..89d76ab80 100644
--- a/src/libcharon/plugins/vici/python/vici/exception.py
+++ b/src/libcharon/plugins/vici/python/vici/exception.py
@@ -1,4 +1,7 @@
"""Exception types that may be thrown by this library."""
class DeserializationException(Exception):
- """Encountered an unexpected byte sequence or missing element type.""" \ No newline at end of file
+ """Encountered an unexpected byte sequence or missing element type."""
+
+class SessionException(Exception):
+ """Session request exception.""" \ No newline at end of file
diff --git a/src/libcharon/plugins/vici/python/vici/session.py b/src/libcharon/plugins/vici/python/vici/session.py
new file mode 100644
index 000000000..ef708feaf
--- /dev/null
+++ b/src/libcharon/plugins/vici/python/vici/session.py
@@ -0,0 +1,130 @@
+import collections
+
+from .exception import SessionException
+from .protocol import Packet, Message
+
+
+class SessionHandler(object):
+ """Handles client command execution requests over vici."""
+
+ def __init__(self, transport):
+ self.transport = transport
+ self.log_events = collections.deque()
+
+ def _communicate(self, packet):
+ """Send packet over transport and parse response.
+
+ :param packet: packet to send
+ :type packet: :py:class:`vici.protocol.Packet`
+ :return: parsed packet in a tuple with message type and payload
+ :rtype: :py:class:`collections.namedtuple`
+ """
+ self.transport.send(packet)
+ return self._read()
+
+ def request(self, command, message=None):
+ """Send command request with an optional message.
+
+ :param command: command to send
+ :type command: str
+ :param message: message (optional)
+ :type message: str
+ :return: command result
+ :rtype: dict
+ """
+ if message is not None:
+ message = Message.serialize(message)
+ packet = Packet.request(command, message)
+ response = self._communicate(packet)
+
+ if response.response_type != Packet.CMD_RESPONSE:
+ raise SessionException(
+ "Unexpected response type {type}, "
+ "expected '{response}' (CMD_RESPONSE)".format(
+ type=response.response_type,
+ response=Packet.CMD_RESPONSE
+ )
+ )
+
+ return Message.deserialize(response.payload)
+
+ def streamed_request(self, command, event_stream_type, message=None):
+ """Send command request and collect and return all emitted events.
+
+ :param command: command to send
+ :type command: str
+ :param event_stream_type: event type emitted on command execution
+ :type event_stream_type: str
+ :param message: message (optional)
+ :type message: str
+ :return: a pair of the command result and a list of emitted events
+ :rtype: tuple
+ """
+ result = []
+
+ if message is not None:
+ message = Message.serialize(message)
+
+ # subscribe to event stream
+ packet = Packet.register_event(event_stream_type)
+ response = self._communicate(packet)
+
+ if response.response_type != Packet.EVENT_CONFIRM:
+ raise SessionException(
+ "Unexpected response type {type}, "
+ "expected '{confirm}' (EVENT_CONFIRM)".format(
+ type=response.response_type,
+ confirm=Packet.EVENT_CONFIRM,
+ )
+ )
+
+ # issue command, and read any event messages
+ packet = Packet.request(command, message)
+ self.transport.send(packet)
+ response = self._read()
+ while response.response_type == Packet.EVENT:
+ result.append(Message.deserialize(response.payload))
+ response = self._read()
+
+ if response.response_type == Packet.CMD_RESPONSE:
+ response_message = Message.deserialize(response.payload)
+ else:
+ raise SessionException(
+ "Unexpected response type {type}, "
+ "expected '{response}' (CMD_RESPONSE)".format(
+ type=response.response_type,
+ response=Packet.CMD_RESPONSE
+ )
+ )
+
+ # unsubscribe from event stream
+ packet = Packet.unregister_event(event_stream_type)
+ response = self._communicate(packet)
+ if response.response_type != Packet.EVENT_CONFIRM:
+ raise SessionException(
+ "Unexpected response type {type}, "
+ "expected '{confirm}' (EVENT_CONFIRM)".format(
+ type=response.response_type,
+ confirm=Packet.EVENT_CONFIRM,
+ )
+ )
+
+ return (response_message, result)
+
+ def _read(self):
+ """Get next packet from transport.
+
+ :return: parsed packet in a tuple with message type and payload
+ :rtype: :py:class:`collections.namedtuple`
+ """
+ raw_response = self.transport.receive()
+ response = Packet.parse(raw_response)
+
+ # FIXME
+ if response.response_type == Packet.EVENT and response.event_type == "log":
+ # queue up any debug log messages, and get next
+ self.log_events.append(response)
+ # do something?
+ self._read()
+ else:
+ return response