Browse Source

[5137] Initial kea-shell code

Tomek Mrugalski 8 years ago
parent
commit
7d49bb7379
4 changed files with 181 additions and 0 deletions
  1. 61 0
      src/bin/shell/kea-shell
  2. 66 0
      src/bin/shell/kea_conn.py
  3. 34 0
      src/bin/shell/kea_connector2.py
  4. 20 0
      src/bin/shell/kea_connector3.py

+ 61 - 0
src/bin/shell/kea-shell

@@ -0,0 +1,61 @@
+#!/usr/bin/python
+
+# First, let's import the right kea_connector.
+# We have two versions: one for python 2.x and another for python 3.x.
+# Sadly, there's no unified way to handle http connections. The recommended
+# way is to use Requests (http://docs.python-requests.org/en/master/), but
+# that's a stand alone package that requires separate installation. One of
+# the design requirements was to not require any additional packages, so
+# the code uses standard libraries available in python. Hence two versions.
+import sys
+if (sys.version_info[0] == 2):
+    # This is Python 2.x
+    import kea_connector2 as kea_connector
+else:
+    if (sys.version_info[0] == 3):
+        # This is Python 3.x
+        import kea_connector3 as kea_connector
+    else:
+        # This is... have no idea what it is.
+        raise SystemExit("Unknown python version:" + str(sys.version_info[0]))
+
+from kea_conn import CARequest, CAResponse
+
+# Second step: Need to parse command line parameters. We will use argparse for
+# that purpose. It does great job with having default values, taking care of
+# the help and sanity checking input parameters.
+
+import argparse
+parser = argparse.ArgumentParser(description='Connects to Kea Control Agent.')
+parser.add_argument('--host', type=str, nargs=1, default='localhost',
+                    help='hostname of the CA to connect to')
+parser.add_argument('--port', type=int, nargs=1, default='8000',
+                    help='TCP port of the CA to connect to')
+parser.add_argument('--timeout', type=int, nargs=1, default='10000',
+                    help='Timeout (in milliseconds) when attempting to connect to CA')
+parser.add_argument('command', type=str, nargs="?", default='list-commands',
+                    help='command to be executed. If not specified, "list-commands" is used')
+cmd_args = parser.parse_args()
+
+# Ok, now time to put the parameters parsed into the structure to be used by the
+# connection.
+params = CARequest()
+params.command = cmd_args.command
+params.http_host = cmd_args.host[0]
+params.http_port = cmd_args.port[0]
+params.timeout = cmd_args.timeout
+
+params.generateBody()
+params.generateHeaders()
+
+conn = kea_connector.KeaConnector()
+
+try:
+    resp = conn.sendCA(params)
+except Exception as e:
+    print("Failed to run: " + str(e))
+    sys.exit(1)
+
+resp.printResp()
+
+sys.exit(0)

+ 66 - 0
src/bin/shell/kea_conn.py

@@ -0,0 +1,66 @@
+#!/usr/bin/python
+
+# This file contains classes used for communication with Control Agent.
+
+# This class defines the HTTP request to be sent.
+# The supported parameters listed are:
+# - path (specifies the path on the server, CA uses only /)
+# - http_host - hostname of the CA
+# - http-port - TCP port of the CA
+# - command - specifies the command to send (e.g. list-commands)
+# - timeout - timeout (in ms)
+# - headers - extra HTTP headers may be added here
+class CARequest:
+    path = '/'
+    http_host = ''
+    http_port = 0
+    command = ''
+    timeout = 0
+    headers = {}
+
+    # Generates the content, out of specified command line
+    # and optional content.
+    # @todo: Add support for parameters
+    # this stores the output in self.content
+    def generateBody(self):
+        self.content = '{"command": "' + self.command + '"}'
+
+    # Generate HTTP headers
+    #
+    # In particular, this method generates Content-Length and its value.
+    def generateHeaders(self):
+        self.headers['Content-Type'] = 'application/json'
+        self.headers['User-Agent'] = 'Kea-shell/0.1'
+        self.headers['Accept'] = '*/*'
+        self.headers['Content-Length'] = "%d"%(len(self.content))
+
+    # This is a storage for generated command (input data to be sent over POST)
+    content = ''
+        
+# This class represents the HTTP response
+class CAResponse:
+
+    # Constructor
+    #
+    # Three mandatory parameters are:
+    # status - numerical number the describe the status (e.g. 200 = OK)
+    # reason - textual explanation of what happened
+    # body - the actual body structure of the response
+    def __init__(self, status, reason, body):
+        self.status = status
+        self.reason = reason
+        self.body = body
+
+    status = 0
+    reason = ''
+    body = ''
+
+    # Used for debugging
+    #
+    # if defug is true, this prints even more information
+    def printResp(self, debug = False):
+        if (debug):
+            print(self.status)
+            print(self.reason)
+        print(self.body)
+        

+ 34 - 0
src/bin/shell/kea_connector2.py

@@ -0,0 +1,34 @@
+#!/usr/bin/python
+
+# This is PYTHON 2.x version of HTTP connection establishment
+
+from kea_conn import CARequest, CAResponse
+
+import httplib
+
+class KeaConnector:
+    def sendCA(self, params):
+        # Estalbish HTTP connection first.
+        conn = httplib.HTTPConnection(params.http_host, params.http_port)
+        conn.connect()
+
+        # Use POST to send it
+        request = conn.putrequest('POST', params.path)
+
+        # Send the headers first
+        for k in params.headers:
+            conn.putheader(k, params.headers[k])
+        conn.endheaders()
+
+        # Send the content
+        conn.send(params.content)
+
+        # Now get the response
+        resp = conn.getresponse()
+
+        # Now get the response details, put it in CAResponse and
+        # return it
+        x = CAResponse(resp.status, resp.reason, resp.read())
+        conn.close()
+
+        return (x)

+ 20 - 0
src/bin/shell/kea_connector3.py

@@ -0,0 +1,20 @@
+#!/usr/bin/python
+
+from kea_conn import CARequest, CAResponse
+
+import urllib.request
+
+class KeaConnector:
+    def sendCA(self, params):
+        # Estalbish HTTP connection first.
+        url = "http://" + params.http_host + ":" + str(params.http_port) + str(params.path)
+        
+        req = urllib.request.Request(url = url, data = str.encode(params.content),
+                                     headers = params.headers)
+        resp = urllib.request.urlopen(req)
+
+        # Now get the response details, put it in CAResponse and
+        # return it
+        x = CAResponse(resp.getcode(), resp.reason, resp.read().decode("utf-8"))
+
+        return (x)