diff options
Diffstat (limited to 'src/bin/shell/kea-shell.in')
-rw-r--r-- | src/bin/shell/kea-shell.in | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/src/bin/shell/kea-shell.in b/src/bin/shell/kea-shell.in new file mode 100644 index 0000000..3098861 --- /dev/null +++ b/src/bin/shell/kea-shell.in @@ -0,0 +1,152 @@ +#!@PYTHON@ + +# Copyright (C) 2017-2023 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. +# Only the python 3.x is supported. +# 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 argparse +import signal +import sys +from base64 import b64encode + +sys.path.append('@PKGPYTHONDIR@') + +import kea_connector3 as kea_connector +from kea_conn import CARequest # CAResponse + + +VERSION = "@PACKAGE_VERSION@" + + +def timeout_handler(signum, frame): + """Connection timeout handler""" + del signum, frame + print("Connection timeout") + sys.exit(1) + + +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 ' + '(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('--path', type=str, default='', + help='Path of the URL to connect to ' + '(default: "")') + parser.add_argument('--ca', type=str, default='', + help='File or directory name of the CA ' + '(default: "" i.e. do not use HTTPS)') + parser.add_argument('--cert', type=str, default='', + help='File name of the client certificate ' + '(default: "")') + parser.add_argument('--key', type=str, default='', + help='File name of the client private key ' + '(default: "")') + parser.add_argument('--timeout', type=int, default='10', + help='Timeout (in seconds) when attempting to ' + 'connect to CA (default: 10)') + parser.add_argument('--service', nargs="?", action="append", + help='target specified service. If not specified,' + 'control agent will receive command.') + parser.add_argument('--auth-user', type=str, default='', + help='Basic HTTP authentication user') + parser.add_argument('--auth-password', type=str, default='', + help='Basic HTTP authentication password') + 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) + sys.exit(0) + + # Ok, now it's time to put the parameters parsed into the structure to be + # used by the connection. + params = CARequest() + params.command = cmd_args.command + params.service = cmd_args.service + params.http_host = cmd_args.host + params.http_port = cmd_args.port + params.path += cmd_args.path + if cmd_args.ca: + params.ca = cmd_args.ca + params.scheme = 'https' + if (cmd_args.cert != '' and cmd_args.key == '') or \ + (cmd_args.cert == '' and cmd_args.key != ''): + print("--cert and --key must be used together") + sys.exit(1) + if cmd_args.cert: + if cmd_args.ca == '': + print("--cert and --key with HTTPS disabled (no --ca)") + sys.exit(1) + params.cert = cmd_args.cert + if cmd_args.key: + # HTTPS check already done for the cert + params.key = cmd_args.key + if cmd_args.auth_user != '': + user = cmd_args.auth_user + password = cmd_args.auth_password + secret = b':'.join((user.encode('utf-8'), password.encode('utf-8'))) + params.auth = b64encode(secret).strip().decode('ascii') + params.timeout = cmd_args.timeout + params.version = VERSION + + # Load command processor + # @todo - command specific processing will be added as part of + # future work (either #5138 or #5139, whichever is implemented + # first) + + # Read arguments from stdin (they're optional for some commands) + for line in sys.stdin: + params.args += line + + # Now we have the arguments so we can build the request + params.generate_body() + params.generate_headers() + + # 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() |