mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 14:05:33 +00:00
[5137] A few fixes and many python style improvements
This commit is contained in:
13
configure.ac
13
configure.ac
@@ -470,7 +470,10 @@ AC_ARG_ENABLE(shell, [AC_HELP_STRING([--enable-shell],
|
||||
|
||||
if test "x$enable_shell" != xno ; then
|
||||
# If kea-shell is enabled, we really need python. 2.7 or anything newer will do.
|
||||
AM_PATH_PYTHON([2.7])
|
||||
AM_PATH_PYTHON([3], [found="yes"], [found="no"])
|
||||
if test "x$found" = xno ; then
|
||||
AM_PATH_PYTHON([2.7])
|
||||
fi
|
||||
else
|
||||
PYTHON=no
|
||||
fi
|
||||
@@ -1628,8 +1631,10 @@ AC_CONFIG_FILES([compatcheck/Makefile
|
||||
src/bin/admin/tests/cql_tests.sh
|
||||
src/bin/agent/tests/test_libraries.h
|
||||
src/bin/shell/Makefile
|
||||
src/bin/shell/kea-shell
|
||||
src/bin/shell/tests/Makefile
|
||||
src/bin/shell/tests/shell_process_tests.sh
|
||||
src/bin/shell/tests/shell_unittest.py
|
||||
src/hooks/Makefile
|
||||
src/hooks/dhcp/Makefile
|
||||
src/hooks/dhcp/user_chk/Makefile
|
||||
@@ -1720,11 +1725,14 @@ AC_CONFIG_FILES([compatcheck/Makefile
|
||||
])
|
||||
|
||||
AC_CONFIG_COMMANDS([permissions], [
|
||||
chmod +x src/bin/admin/kea-admin
|
||||
chmod +x src/bin/dhcp4/tests/dhcp4_process_tests.sh
|
||||
chmod +x src/bin/dhcp6/tests/dhcp6_process_tests.sh
|
||||
chmod +x src/bin/keactrl/keactrl
|
||||
chmod +x src/bin/keactrl/tests/keactrl_tests.sh
|
||||
chmod +x src/bin/admin/kea-admin
|
||||
chmod +x src/bin/shell/kea-shell
|
||||
chmod +x src/bin/shell/tests/shell_process_tests.sh
|
||||
chmod +x src/bin/shell/tests/shell_unittest.py
|
||||
chmod +x src/lib/dns/gen-rdatacode.py
|
||||
chmod +x src/lib/log/tests/console_test.sh
|
||||
chmod +x src/lib/log/tests/destination_test.sh
|
||||
@@ -1800,6 +1808,7 @@ if test "$PYTHON" != "no" ; then
|
||||
cat >> config.report << END
|
||||
|
||||
Python:
|
||||
PYTHON: ${PYTHON}
|
||||
PYTHON_VERSION: ${PYTHON_VERSION}
|
||||
|
||||
END
|
||||
|
@@ -5,7 +5,6 @@ SHTESTS += ca_process_tests.sh
|
||||
|
||||
noinst_SCRIPTS = ca_process_tests.sh
|
||||
EXTRA_DIST = ca_process_tests.sh.in
|
||||
noinst_LTLIBRARIES = libbasic.la
|
||||
|
||||
# test using command-line arguments, so use check-local target instead of TESTS
|
||||
check-local:
|
||||
@@ -40,6 +39,8 @@ TESTS_ENVIRONMENT = \
|
||||
TESTS =
|
||||
if HAVE_GTEST
|
||||
|
||||
noinst_LTLIBRARIES = libbasic.la
|
||||
|
||||
TESTS += ca_unittests
|
||||
|
||||
ca_unittests_SOURCES = ca_cfg_mgr_unittests.cc
|
||||
|
@@ -5,7 +5,7 @@ EXTRA_DIST =
|
||||
if KEA_SHELL
|
||||
|
||||
# Kea-shell is enabled, here are proper rules for it.
|
||||
kea_shell_PYTHON = kea-shell.py kea_conn.py kea_connector2.py kea_connector3.py
|
||||
kea_shell_PYTHON = kea_conn.py kea_connector2.py kea_connector3.py
|
||||
kea_shelldir = @localstatedir@/@PACKAGE@
|
||||
|
||||
bin_SCRIPTS = kea-shell
|
||||
@@ -13,12 +13,11 @@ bin_SCRIPTS = kea-shell
|
||||
else
|
||||
|
||||
# Kea-shell is disabled, simply keep the files for make dist
|
||||
EXTRA_DIST += kea-shell.py kea_conn.py kea_connector2.py kea_connector3.py
|
||||
EXTRA_DIST += kea-shell kea_conn.py kea_connector2.py kea_connector3.py
|
||||
|
||||
endif
|
||||
|
||||
CLEANFILES = kea-shell kea-shell.pyc
|
||||
|
||||
CLEANFILES = *.pyc
|
||||
|
||||
man_MANS = kea-shell.8
|
||||
DISTCLEANFILES = $(man_MANS)
|
||||
@@ -38,13 +37,6 @@ $(man_MANS):
|
||||
|
||||
endif
|
||||
|
||||
# This is done here since configure.ac AC_OUTPUT doesn't expand certain variables.
|
||||
kea-shell: kea-shell.py
|
||||
$(SED) "s|@@PYTHONPATH@@|@pyexecdir@|" kea-shell.py > kea-shell.tmp
|
||||
$(SED) "s|REPORTED_VERSION|@PACKAGE_VERSION@|" kea-shell.tmp >$@
|
||||
rm -f kea-shell.tmp
|
||||
chmod a+x $@
|
||||
|
||||
install-data-local:
|
||||
$(mkinstalldirs) $(DESTDIR)/@localstatedir@/@PACKAGE@
|
||||
|
||||
|
112
src/bin/shell/kea-shell.in
Normal file
112
src/bin/shell/kea-shell.in
Normal file
@@ -0,0 +1,112 @@
|
||||
#!@PYTHON@
|
||||
|
||||
# Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
"""
|
||||
Text client for Control Agent process
|
||||
"""
|
||||
|
||||
# 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
|
||||
import signal
|
||||
import argparse
|
||||
|
||||
from kea_conn import CARequest # CAResponse
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
# This is Python 2.x
|
||||
import kea_connector2 as kea_connector
|
||||
elif 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]))
|
||||
|
||||
def timeout_handler(signum, frame):
|
||||
"""Connection timeoout handler"""
|
||||
del signum, frame
|
||||
print("Connection timeout")
|
||||
sys.exit(1)
|
||||
|
||||
VERSION = "@PACKAGE_VERSION@"
|
||||
|
||||
def shell_body():
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(description='kea-shell is a simple text '
|
||||
'client that uses REST interface to '
|
||||
'connect to Kea Control Agent.')
|
||||
parser.add_argument('--host', type=str, default='127.0.0.1',
|
||||
help='hostname of the CA to connect to '
|
||||
'(defaul:; 127.0.0.1)')
|
||||
parser.add_argument('--port', type=int, default=8000,
|
||||
help='TCP port of the CA to connect to '
|
||||
'(default: 8000)')
|
||||
parser.add_argument('--timeout', type=int, default='10',
|
||||
help='Timeout (in seconds) when attempting to '
|
||||
'connect to CA (default: 10)')
|
||||
parser.add_argument('command', type=str, nargs="?",
|
||||
default='list-commands',
|
||||
help='command to be executed. If not specified, '
|
||||
'"list-commands" is used')
|
||||
parser.add_argument('-v', action="store_true", help="Prints version")
|
||||
cmd_args = parser.parse_args()
|
||||
|
||||
if cmd_args.v:
|
||||
print(VERSION)
|
||||
exit(0)
|
||||
|
||||
# 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
|
||||
params.http_port = cmd_args.port
|
||||
params.timeout = cmd_args.timeout
|
||||
params.version = VERSION
|
||||
|
||||
params.generate_body()
|
||||
params.generate_headers()
|
||||
|
||||
# Load command processor
|
||||
# @todo - command specific processing will be added as part of
|
||||
# future work (either #5138 or #5139, whichever is implemented
|
||||
# first)
|
||||
|
||||
# Read parameters from stdin (they're optional for some commands)
|
||||
for line in sys.stdin:
|
||||
params.params += line
|
||||
|
||||
# Set the timeout timer. If the connection takes too long,
|
||||
# it will send a signal to us.
|
||||
signal.signal(signal.SIGALRM, timeout_handler)
|
||||
signal.alarm(params.timeout)
|
||||
|
||||
# Ok, everything is ready. Let's send the command and get a response.
|
||||
try:
|
||||
resp = kea_connector.send_to_control_agent(params)
|
||||
except Exception as exc:
|
||||
print("Failed to run: " + str(exc))
|
||||
sys.exit(1)
|
||||
|
||||
resp.print_response()
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
shell_body()
|
@@ -1,92 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# This is going to be replaced with the actual version (see kea-shell target
|
||||
# in Makefile.am)
|
||||
VERSION = "REPORTED_VERSION"
|
||||
|
||||
# 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
|
||||
import signal
|
||||
import argparse
|
||||
|
||||
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.
|
||||
|
||||
parser = argparse.ArgumentParser(description='kea-shell is a simple text client that uses REST '
|
||||
'interface to connect to Kea Control Agent.')
|
||||
parser.add_argument('--host', type=str, default='127.0.0.1',
|
||||
help='hostname of the CA to connect to (default; 127.0.0.1)')
|
||||
parser.add_argument('--port', type=int, default=8000,
|
||||
help='TCP port of the CA to connect to (default: 8000)')
|
||||
parser.add_argument('--timeout', type=int, default='10',
|
||||
help='Timeout (in seconds) when attempting to connect to CA (default: 10)')
|
||||
parser.add_argument('command', type=str, nargs="?", default='list-commands',
|
||||
help='command to be executed. If not specified, "list-commands" is used')
|
||||
parser.add_argument('-v', action="store_true", help="Prints version")
|
||||
cmd_args = parser.parse_args()
|
||||
|
||||
if (cmd_args.v):
|
||||
print (VERSION)
|
||||
exit(0)
|
||||
|
||||
# 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
|
||||
params.http_port = cmd_args.port
|
||||
params.timeout = cmd_args.timeout
|
||||
params.version = VERSION
|
||||
|
||||
params.generateBody()
|
||||
params.generateHeaders()
|
||||
|
||||
conn = kea_connector.KeaConnector()
|
||||
|
||||
def timeout_handler(signum, frame):
|
||||
print ("Connection timeout")
|
||||
sys.exit(1)
|
||||
|
||||
# Load command processor
|
||||
# @todo - command specific processing will be added as part of future work
|
||||
# (either #5138 or #5139, whichever is implemented first)
|
||||
|
||||
# Read parameters from stdin (they're optional for some commands)
|
||||
for line in sys.stdin:
|
||||
params.params += line
|
||||
|
||||
# Set the timeout timer. If the connection takes too long,
|
||||
# it will send a signal to us.
|
||||
signal.signal(signal.SIGALRM, timeout_handler)
|
||||
signal.alarm(params.timeout)
|
||||
|
||||
# Ok, everything is ready. Let's send the command and get a response.
|
||||
try:
|
||||
resp = conn.sendCA(params)
|
||||
except Exception as e:
|
||||
print("Failed to run: " + str(e))
|
||||
sys.exit(1)
|
||||
|
||||
resp.printResp()
|
||||
|
||||
sys.exit(0)
|
@@ -49,9 +49,10 @@
|
||||
<cmdsynopsis>
|
||||
<command>kea-shell</command>
|
||||
<arg><option>-h</option></arg>
|
||||
<arg><option>-v</option></arg>
|
||||
<arg><option>--host</option></arg>
|
||||
<arg><option>--port</option></arg>
|
||||
<arg><option>-v</option></arg>
|
||||
<arg><option>--timeout</option></arg>
|
||||
<arg><option>command</option></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
@@ -64,8 +65,8 @@
|
||||
Kea Control Agent (CA). It takes command as a command-line parameter
|
||||
that is being sent to CA with proper JSON
|
||||
encapsulation. Optional parameters may be specified on the
|
||||
stdin. The request it sent of HTTP and a response is
|
||||
retrieved. That response is printed out on stdout.
|
||||
standard input. The request it sent of HTTP and a response is
|
||||
retrieved. That response is displayed out on the standard output.
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
@@ -78,16 +79,16 @@
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-v</option></term>
|
||||
<term><option>-h</option></term>
|
||||
<listitem><para>
|
||||
Display the version.
|
||||
Displays help regarding command line parameters.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-h</option></term>
|
||||
<term><option>-v</option></term>
|
||||
<listitem><para>
|
||||
Displays help regarding command line parameters.
|
||||
Display the version.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@@ -1,17 +1,25 @@
|
||||
#!/usr/bin/python
|
||||
# Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# This file contains classes used for communication with Control Agent.
|
||||
"""
|
||||
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
|
||||
# - version - version to be reported in HTTP header
|
||||
class CARequest:
|
||||
"""
|
||||
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
|
||||
- version - version to be reported in HTTP header
|
||||
"""
|
||||
path = '/'
|
||||
http_host = ''
|
||||
http_port = 0
|
||||
@@ -20,39 +28,47 @@ class CARequest:
|
||||
params = ''
|
||||
headers = {}
|
||||
version = ""
|
||||
# This is a storage for generated command (input data to be sent over POST)
|
||||
content = ''
|
||||
|
||||
# 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):
|
||||
def generate_body(self):
|
||||
"""
|
||||
Generates the content, out of specified command line
|
||||
and optional content.
|
||||
@todo: Add support for parameters
|
||||
this stores the output in self.content
|
||||
"""
|
||||
self.content = '{ "command": "' + self.command + '"'
|
||||
if (len(self.params)):
|
||||
if len(self.params):
|
||||
self.content += ', "parameters": { ' + self.params + ' }'
|
||||
self.content += ' }'
|
||||
|
||||
# Generate HTTP headers
|
||||
#
|
||||
# In particular, this method generates Content-Length and its value.
|
||||
def generateHeaders(self):
|
||||
def generate_headers(self):
|
||||
"""
|
||||
Generate HTTP headers
|
||||
|
||||
In particular, this method generates Content-Length and its value.
|
||||
"""
|
||||
self.headers['Content-Type'] = 'application/json'
|
||||
self.headers['User-Agent'] = "Kea-shell/%s"%(self.version)
|
||||
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:
|
||||
"""
|
||||
This class represents the HTTP response
|
||||
"""
|
||||
|
||||
# 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):
|
||||
"""
|
||||
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
|
||||
"""
|
||||
self.status = status
|
||||
self.reason = reason
|
||||
self.body = body
|
||||
@@ -61,11 +77,13 @@ class CAResponse:
|
||||
reason = ''
|
||||
body = ''
|
||||
|
||||
# Used for debugging
|
||||
#
|
||||
# if defug is true, this prints even more information
|
||||
def printResp(self, debug = False):
|
||||
if (debug):
|
||||
def print_response(self, debug=False):
|
||||
"""
|
||||
Used for debugging
|
||||
|
||||
if debug is true, this prints even more information
|
||||
"""
|
||||
if debug:
|
||||
print(self.status)
|
||||
print(self.reason)
|
||||
print(self.body)
|
||||
|
@@ -1,34 +1,39 @@
|
||||
#!/usr/bin/python
|
||||
# Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# This is PYTHON 2.x version of HTTP connection establishment
|
||||
|
||||
from kea_conn import CARequest, CAResponse
|
||||
"""
|
||||
This is PYTHON 2.x version of HTTP connection establishment
|
||||
"""
|
||||
|
||||
import httplib
|
||||
|
||||
class KeaConnector:
|
||||
def sendCA(self, params):
|
||||
# Estalbish HTTP connection first.
|
||||
conn = httplib.HTTPConnection(params.http_host, params.http_port)
|
||||
conn.connect()
|
||||
from kea_conn import CAResponse # CARequest
|
||||
|
||||
# Use POST to send it
|
||||
request = conn.putrequest('POST', params.path)
|
||||
def send_to_control_agent(params):
|
||||
"""Establish HTTP connection first."""
|
||||
conn = httplib.HTTPConnection(params.http_host, params.http_port)
|
||||
conn.connect()
|
||||
|
||||
# Send the headers first
|
||||
for k in params.headers:
|
||||
conn.putheader(k, params.headers[k])
|
||||
conn.endheaders()
|
||||
# Use POST to send it
|
||||
_ = conn.putrequest('POST', params.path)
|
||||
|
||||
# Send the content
|
||||
conn.send(params.content)
|
||||
# Send the headers first
|
||||
for k in params.headers:
|
||||
conn.putheader(k, params.headers[k])
|
||||
conn.endheaders()
|
||||
|
||||
# Now get the response
|
||||
resp = conn.getresponse()
|
||||
# Send the content
|
||||
conn.send(params.content)
|
||||
|
||||
# Now get the response details, put it in CAResponse and
|
||||
# return it
|
||||
x = CAResponse(resp.status, resp.reason, resp.read())
|
||||
conn.close()
|
||||
# Now get the response
|
||||
resp = conn.getresponse()
|
||||
|
||||
return (x)
|
||||
# Now get the response details, put it in CAResponse and
|
||||
# return it
|
||||
result = CAResponse(resp.status, resp.reason, resp.read())
|
||||
conn.close()
|
||||
|
||||
return result
|
||||
|
@@ -1,20 +1,29 @@
|
||||
#!/usr/bin/python
|
||||
# Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from kea_conn import CARequest, CAResponse
|
||||
"""
|
||||
This is PYTHON 3.x version of HTTP connection establishment
|
||||
"""
|
||||
|
||||
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)
|
||||
from kea_conn import CAResponse # CARequest
|
||||
|
||||
# Now get the response details, put it in CAResponse and
|
||||
# return it
|
||||
x = CAResponse(resp.getcode(), resp.reason, resp.read().decode("utf-8"))
|
||||
def send_to_control_agent(params):
|
||||
"""Establish HTTP connection first."""
|
||||
url = "http://" + params.http_host + ":"
|
||||
url += str(params.http_port) + str(params.path)
|
||||
|
||||
return (x)
|
||||
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
|
||||
result = CAResponse(resp.getcode(), resp.reason,
|
||||
resp.read().decode("utf-8"))
|
||||
|
||||
return result
|
||||
|
@@ -36,8 +36,8 @@ CONFIG="{
|
||||
}"
|
||||
|
||||
# In these tests we need to use two binaries: Control Agent and Kea shell.
|
||||
# Using bin and bin_path would be confusing, so we omit defining bin and bin_path
|
||||
# on purpose.
|
||||
# Using bin and bin_path would be confusing, so we omit defining bin
|
||||
# and bin_path on purpose.
|
||||
ca_bin="kea-ctrl-agent"
|
||||
ca_bin_path=@abs_top_builddir@/src/bin/agent
|
||||
|
||||
@@ -83,8 +83,8 @@ shell_command_test() {
|
||||
# of configuration failure).
|
||||
get_pid ${ca_bin}
|
||||
if [ ${_GET_PIDS_NUM} -ne 1 ]; then
|
||||
printf "ERROR: expected one Control Agent process to be started. Found %d processes\
|
||||
started.\n" ${_GET_PIDS_NUM}
|
||||
printf "ERROR: expected one Control Agent process to be started.\
|
||||
Found %d processes started.\n" ${_GET_PIDS_NUM}
|
||||
clean_exit 1
|
||||
fi
|
||||
|
||||
@@ -92,22 +92,26 @@ shell_command_test() {
|
||||
# It should be just once on startup.
|
||||
get_reconfigs
|
||||
if [ ${_GET_RECONFIGS} -ne 1 ]; then
|
||||
printf "ERROR: server been configured ${_GET_RECONFIGS} time(s), but exactly 1 was expected.\n"
|
||||
printf "ERROR: server been configured ${_GET_RECONFIGS} time(s),\
|
||||
but exactly 1 was expected.\n"
|
||||
clean_exit 1
|
||||
else
|
||||
printf "Server successfully configured.\n"
|
||||
fi
|
||||
|
||||
# Main test phase: send command, check response.
|
||||
tmp="echo \"${params}\" | ${shell_bin_path}/${shell_bin} --host 127.0.0.1 --port 8081 ${cmd} > ${tmpfile_path}/shell-stdout.txt"
|
||||
tmp="echo \"${params}\" | ${shell_bin_path}/${shell_bin} --host \
|
||||
127.0.0.1 --port 8081 ${cmd} > ${tmpfile_path}/shell-stdout.txt"
|
||||
echo "Executing kea-shell ($tmp)"
|
||||
|
||||
echo "${params}" | ${shell_bin_path}/${shell_bin} --host 127.0.0.1 --port 8081 ${cmd} > ${tmpfile_path}/shell-stdout.txt
|
||||
echo "${params}" | ${shell_bin_path}/${shell_bin} --host 127.0.0.1 \
|
||||
--port 8081 ${cmd} > ${tmpfile_path}/shell-stdout.txt
|
||||
|
||||
# Check the exit code
|
||||
shell_exit_code=$?
|
||||
if [ ${shell_exit_code} -ne 0 ]; then
|
||||
echo "ERROR: kea-shell returned ${shell_exit_code} exit code, expected 0."
|
||||
echo "ERROR:" \
|
||||
"kea-shell returned ${shell_exit_code} exit code, expected 0."
|
||||
else
|
||||
echo "kea-shell returned ${shell_exit_code} exit code as expected."
|
||||
fi
|
||||
@@ -118,7 +122,9 @@ shell_command_test() {
|
||||
diff ${tmpfile_path}/shell-stdout.txt ${tmpfile_path}/shell-expected.txt
|
||||
diff_code=$?
|
||||
if [ ${diff_code} -ne 0 ]; then
|
||||
echo "ERROR: content returned is different than expected. See ${tmpfile_path}/shell-*.txt"
|
||||
echo "ERROR:" \
|
||||
"content returned is different than expected." \
|
||||
"See ${tmpfile_path}/shell-*.txt"
|
||||
echo "EXPECTED:"
|
||||
cat ${tmpfile_path}/shell-expected.txt
|
||||
echo "ACTUAL RESULT:"
|
||||
@@ -164,7 +170,8 @@ version_test() {
|
||||
if test "${REPORTED_VERSION}" == "${EXPECTED_VERSION}"; then
|
||||
test_finish 0
|
||||
else
|
||||
printf "ERROR: Expected version ${EXPECTED_VERSION}, got ${REPORTED_VERSION}\n"
|
||||
echo "ERROR:" \
|
||||
"Expected version ${EXPECTED_VERSION}, got ${REPORTED_VERSION}"
|
||||
test_finish 1
|
||||
fi
|
||||
}
|
||||
@@ -174,5 +181,3 @@ shell_command_test "shell.list-commands" "list-commands" \
|
||||
"[ { \"arguments\": [ \"list-commands\" ], \"result\": 0 } ]" ""
|
||||
shell_command_test "shell.bogus" "give-me-a-beer" \
|
||||
"[ { \"result\": 1, \"text\": \"'give-me-a-beer' command not supported.\" } ]" ""
|
||||
|
||||
|
||||
|
@@ -1,104 +0,0 @@
|
||||
# Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import unittest
|
||||
|
||||
from kea_conn import CARequest
|
||||
|
||||
class CARequestUnitTest(unittest.TestCase):
|
||||
"""
|
||||
This class is dedicated to testing CARequest class. That class
|
||||
is responsible for generation of the body and headers.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
This method is called before each test. Currently it does nothing.
|
||||
"""
|
||||
pass
|
||||
|
||||
def test_bodyWithoutParams(self):
|
||||
"""
|
||||
This test verifies if the CARequest object generates the request
|
||||
content properly when there are no parameters.
|
||||
"""
|
||||
|
||||
x = CARequest()
|
||||
x.command = "foo"
|
||||
x.generateBody()
|
||||
self.assertEqual(x.content, '{ "command": "foo" }')
|
||||
|
||||
def test_bodyWithParams(self):
|
||||
"""
|
||||
This test verifies if the CARequest object generates the request
|
||||
content properly when there are parameters.
|
||||
"""
|
||||
|
||||
x = CARequest()
|
||||
x.command = "foo"
|
||||
x.params = '"bar": "baz"'
|
||||
x.generateBody()
|
||||
self.assertEqual(x.content, '{ "command": "foo", "parameters": { "bar": "baz" } }')
|
||||
|
||||
def checkHeader(self, headers, header_name, value):
|
||||
"""
|
||||
Checks if headers array contains an entry specified by header_name and that
|
||||
its value matches specified value
|
||||
"""
|
||||
|
||||
if header_name in headers:
|
||||
if (headers[header_name] == value):
|
||||
return True
|
||||
else:
|
||||
print ("Expected value: " + value + " does not match actual value: "
|
||||
+ headers[header_name])
|
||||
return ()
|
||||
else:
|
||||
print ("Expected header: " + header_name + " missing")
|
||||
return (false)
|
||||
|
||||
def test_headers(self):
|
||||
"""
|
||||
This test checks if the headers are generated properly. Note that since
|
||||
the content is not specified, it is 0. Therefore Content-Length is 0.
|
||||
"""
|
||||
x = CARequest()
|
||||
x.generateHeaders()
|
||||
|
||||
self.assertTrue(self.checkHeader(x.headers, 'Content-Type', 'application/json'))
|
||||
self.assertTrue(self.checkHeader(x.headers, 'Accept', '*/*'))
|
||||
self.assertTrue(self.checkHeader(x.headers, 'Content-Length', "0"))
|
||||
|
||||
def test_headerLength(self):
|
||||
"""
|
||||
This test checks if the headers are generated properly. In this test there
|
||||
is specific content of non-zero length, and its size should be reflected
|
||||
in the header.
|
||||
"""
|
||||
x = CARequest()
|
||||
x.content = '{ "command": "foo" }'
|
||||
x.generateHeaders()
|
||||
|
||||
self.assertTrue(self.checkHeader(x.headers, 'Content-Length', str(len(x.content))))
|
||||
|
||||
def test_headerVersion(self):
|
||||
"""
|
||||
This test checks if the version reported in HTTP headers is generated properly.
|
||||
"""
|
||||
x = CARequest()
|
||||
x.version = "1.2.3"
|
||||
x.generateHeaders()
|
||||
self.assertTrue(self.checkHeader(x.headers, 'User-Agent', 'Kea-shell/1.2.3'))
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
This method is called after each test. Currently it does nothing.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
115
src/bin/shell/tests/shell_unittest.py.in
Normal file
115
src/bin/shell/tests/shell_unittest.py.in
Normal file
@@ -0,0 +1,115 @@
|
||||
#!@PYTHON@
|
||||
|
||||
# Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
"""
|
||||
Kea shell unittest (python part)
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
from kea_conn import CARequest
|
||||
|
||||
class CARequestUnitTest(unittest.TestCase):
|
||||
"""
|
||||
This class is dedicated to testing CARequest class. That class
|
||||
is responsible for generation of the body and headers.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
This method is called before each test. Currently it does nothing.
|
||||
"""
|
||||
pass
|
||||
|
||||
def test_body_without_params(self):
|
||||
"""
|
||||
This test verifies if the CARequest object generates the request
|
||||
content properly when there are no parameters.
|
||||
"""
|
||||
request = CARequest()
|
||||
request.command = "foo"
|
||||
request.generate_body()
|
||||
self.assertEqual(request.content, '{ "command": "foo" }')
|
||||
|
||||
def test_body_with_params(self):
|
||||
"""
|
||||
This test verifies if the CARequest object generates the request
|
||||
content properly when there are parameters.
|
||||
"""
|
||||
request = CARequest()
|
||||
request.command = "foo"
|
||||
request.params = '"bar": "baz"'
|
||||
request.generate_body()
|
||||
self.assertEqual(request.content,
|
||||
'{ "command": "foo", "parameters": { "bar": "baz" } }')
|
||||
|
||||
@staticmethod
|
||||
def check_header(headers, header_name, value):
|
||||
"""
|
||||
Checks if headers array contains an entry specified by
|
||||
header_name and that its value matches specified value
|
||||
"""
|
||||
if header_name in headers:
|
||||
if headers[header_name] == value:
|
||||
return True
|
||||
else:
|
||||
print("Expected value: " + value +
|
||||
" does not match actual value: " +
|
||||
headers[header_name])
|
||||
return False
|
||||
else:
|
||||
print("Expected header: " + header_name + " missing")
|
||||
return False
|
||||
|
||||
def test_headers(self):
|
||||
"""
|
||||
This test checks if the headers are generated properly. Note that since
|
||||
the content is not specified, it is 0. Therefore Content-Length is 0.
|
||||
"""
|
||||
request = CARequest()
|
||||
request.generate_headers()
|
||||
|
||||
self.assertTrue(self.check_header(request.headers,
|
||||
'Content-Type', 'application/json'))
|
||||
self.assertTrue(self.check_header(request.headers,
|
||||
'Accept', '*/*'))
|
||||
self.assertTrue(self.check_header(request.headers,
|
||||
'Content-Length', '0'))
|
||||
|
||||
def test_header_length(self):
|
||||
"""
|
||||
This test checks if the headers are generated properly. In
|
||||
this test there is specific content of non-zero length, and
|
||||
its size should be reflected in the header.
|
||||
"""
|
||||
request = CARequest()
|
||||
request.content = '{ "command": "foo" }'
|
||||
request.generate_headers()
|
||||
|
||||
self.assertTrue(self.check_header(request.headers, 'Content-Length',
|
||||
str(len(request.content))))
|
||||
|
||||
def test_header_version(self):
|
||||
"""
|
||||
This test checks if the version reported in HTTP headers is
|
||||
generated properly.
|
||||
"""
|
||||
request = CARequest()
|
||||
request.version = "1.2.3"
|
||||
request.generate_headers()
|
||||
self.assertTrue(self.check_header(request.headers, 'User-Agent',
|
||||
'Kea-shell/1.2.3'))
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
This method is called after each test. Currently it does nothing.
|
||||
"""
|
||||
pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Reference in New Issue
Block a user