From: Tomek Mrugalski Date: Fri, 3 Mar 2017 17:09:17 +0000 (+0100) Subject: [5137] Initial kea-shell code X-Git-Tag: trac5152_base~6^2~21 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7d49bb73796c5d7cbdfd6be9edf02ab742b66f28;p=thirdparty%2Fkea.git [5137] Initial kea-shell code --- diff --git a/src/bin/shell/kea-shell b/src/bin/shell/kea-shell new file mode 100644 index 0000000000..ae1ab65b4b --- /dev/null +++ b/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) diff --git a/src/bin/shell/kea_conn.py b/src/bin/shell/kea_conn.py new file mode 100644 index 0000000000..c1fb2dc5aa --- /dev/null +++ b/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) + diff --git a/src/bin/shell/kea_connector2.py b/src/bin/shell/kea_connector2.py new file mode 100644 index 0000000000..1f00191173 --- /dev/null +++ b/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) diff --git a/src/bin/shell/kea_connector3.py b/src/bin/shell/kea_connector3.py new file mode 100644 index 0000000000..8c255588db --- /dev/null +++ b/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)