summaryrefslogtreecommitdiffstats
path: root/src/bin/shell
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:15:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:15:43 +0000
commitf5f56e1a1c4d9e9496fcb9d81131066a964ccd23 (patch)
tree49e44c6f87febed37efb953ab5485aa49f6481a7 /src/bin/shell
parentInitial commit. (diff)
downloadisc-kea-upstream.tar.xz
isc-kea-upstream.zip
Adding upstream version 2.4.1.upstream/2.4.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/bin/shell')
-rw-r--r--src/bin/shell/Makefile.am12
-rw-r--r--src/bin/shell/Makefile.in857
-rw-r--r--src/bin/shell/kea-shell.in152
-rw-r--r--src/bin/shell/kea_conn.py107
-rw-r--r--src/bin/shell/kea_connector3.py50
-rw-r--r--src/bin/shell/tests/Makefile.am30
-rw-r--r--src/bin/shell/tests/Makefile.in883
-rw-r--r--src/bin/shell/tests/basic_auth_tests.sh.in196
-rw-r--r--src/bin/shell/tests/shell_process_tests.sh.in196
-rw-r--r--src/bin/shell/tests/shell_unittest.py.in199
-rw-r--r--src/bin/shell/tests/tls_ca_process_tests.sh.in222
11 files changed, 2904 insertions, 0 deletions
diff --git a/src/bin/shell/Makefile.am b/src/bin/shell/Makefile.am
new file mode 100644
index 0000000..5dd6251
--- /dev/null
+++ b/src/bin/shell/Makefile.am
@@ -0,0 +1,12 @@
+SUBDIRS = . tests
+
+pkgpython_PYTHON = kea_conn.py kea_connector3.py
+
+sbin_SCRIPTS = kea-shell
+
+CLEANFILES = *.pyc
+
+CLEANDIRS = __pycache__
+
+clean-local:
+ rm -rf $(CLEANDIRS)
diff --git a/src/bin/shell/Makefile.in b/src/bin/shell/Makefile.in
new file mode 100644
index 0000000..053684d
--- /dev/null
+++ b/src/bin/shell/Makefile.in
@@ -0,0 +1,857 @@
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/bin/shell
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \
+ $(top_srcdir)/m4macros/ax_cpp11.m4 \
+ $(top_srcdir)/m4macros/ax_cpp20.m4 \
+ $(top_srcdir)/m4macros/ax_crypto.m4 \
+ $(top_srcdir)/m4macros/ax_find_library.m4 \
+ $(top_srcdir)/m4macros/ax_gssapi.m4 \
+ $(top_srcdir)/m4macros/ax_gtest.m4 \
+ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \
+ $(top_srcdir)/m4macros/ax_netconf.m4 \
+ $(top_srcdir)/m4macros/libtool.m4 \
+ $(top_srcdir)/m4macros/ltoptions.m4 \
+ $(top_srcdir)/m4macros/ltsugar.m4 \
+ $(top_srcdir)/m4macros/ltversion.m4 \
+ $(top_srcdir)/m4macros/lt~obsolete.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(pkgpython_PYTHON) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = kea-shell
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(pkgpythondir)"
+SCRIPTS = $(sbin_SCRIPTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__py_compile = PYTHON=$(PYTHON) $(SHELL) $(py_compile)
+am__pep3147_tweak = \
+ sed -e 's|\.py$$||' -e 's|[^/]*$$|&.*.pyc\n&.*.pyo|'
+py_compile = $(top_srcdir)/py-compile
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/kea-shell.in \
+ $(top_srcdir)/py-compile
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+ASCIIDOC = @ASCIIDOC@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_INCLUDES = @BOOST_INCLUDES@
+BOOST_LIBS = @BOOST_LIBS@
+BOTAN_TOOL = @BOTAN_TOOL@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CONTRIB_DIR = @CONTRIB_DIR@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CRYPTO_CFLAGS = @CRYPTO_CFLAGS@
+CRYPTO_INCLUDES = @CRYPTO_INCLUDES@
+CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@
+CRYPTO_LIBS = @CRYPTO_LIBS@
+CRYPTO_PACKAGE = @CRYPTO_PACKAGE@
+CRYPTO_RPATH = @CRYPTO_RPATH@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@
+DISTCHECK_CONTRIB_CONFIGURE_FLAG = @DISTCHECK_CONTRIB_CONFIGURE_FLAG@
+DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@
+DISTCHECK_GSSAPI_CONFIGURE_FLAG = @DISTCHECK_GSSAPI_CONFIGURE_FLAG@
+DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@
+DISTCHECK_KEA_SHELL_CONFIGURE_FLAG = @DISTCHECK_KEA_SHELL_CONFIGURE_FLAG@
+DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG = @DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG@
+DISTCHECK_LIBYANG_CONFIGURE_FLAG = @DISTCHECK_LIBYANG_CONFIGURE_FLAG@
+DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG = @DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG@
+DISTCHECK_MYSQL_CONFIGURE_FLAG = @DISTCHECK_MYSQL_CONFIGURE_FLAG@
+DISTCHECK_PERFDHCP_CONFIGURE_FLAG = @DISTCHECK_PERFDHCP_CONFIGURE_FLAG@
+DISTCHECK_PGSQL_CONFIGURE_FLAG = @DISTCHECK_PGSQL_CONFIGURE_FLAG@
+DISTCHECK_PREMIUM_CONFIGURE_FLAG = @DISTCHECK_PREMIUM_CONFIGURE_FLAG@
+DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG = @DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG@
+DISTCHECK_SYSREPO_CONFIGURE_FLAG = @DISTCHECK_SYSREPO_CONFIGURE_FLAG@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GENHTML = @GENHTML@
+GREP = @GREP@
+GSSAPI_CFLAGS = @GSSAPI_CFLAGS@
+GSSAPI_LIBS = @GSSAPI_LIBS@
+GTEST_CONFIG = @GTEST_CONFIG@
+GTEST_INCLUDES = @GTEST_INCLUDES@
+GTEST_LDADD = @GTEST_LDADD@
+GTEST_LDFLAGS = @GTEST_LDFLAGS@
+GTEST_SOURCE = @GTEST_SOURCE@
+HAVE_NETCONF = @HAVE_NETCONF@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KEA_CXXFLAGS = @KEA_CXXFLAGS@
+KEA_SRCID = @KEA_SRCID@
+KRB5_CONFIG = @KRB5_CONFIG@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBYANGCPP_CPPFLAGS = @LIBYANGCPP_CPPFLAGS@
+LIBYANGCPP_INCLUDEDIR = @LIBYANGCPP_INCLUDEDIR@
+LIBYANGCPP_LIBS = @LIBYANGCPP_LIBS@
+LIBYANGCPP_PREFIX = @LIBYANGCPP_PREFIX@
+LIBYANGCPP_VERSION = @LIBYANGCPP_VERSION@
+LIBYANG_CPPFLAGS = @LIBYANG_CPPFLAGS@
+LIBYANG_INCLUDEDIR = @LIBYANG_INCLUDEDIR@
+LIBYANG_LIBS = @LIBYANG_LIBS@
+LIBYANG_PREFIX = @LIBYANG_PREFIX@
+LIBYANG_VERSION = @LIBYANG_VERSION@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@
+LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_TYPE = @PACKAGE_VERSION_TYPE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PERL = @PERL@
+PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@
+PGSQL_LIBS = @PGSQL_LIBS@
+PKGPYTHONDIR = @PKGPYTHONDIR@
+PKG_CONFIG = @PKG_CONFIG@
+PLANTUML = @PLANTUML@
+PREMIUM_DIR = @PREMIUM_DIR@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SEP = @SEP@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINXBUILD = @SPHINXBUILD@
+SRPD_PLUGINS_PATH = @SRPD_PLUGINS_PATH@
+SR_PLUGINS_PATH = @SR_PLUGINS_PATH@
+SR_REPO_PATH = @SR_REPO_PATH@
+STRIP = @STRIP@
+SYSREPOCPP_CPPFLAGS = @SYSREPOCPP_CPPFLAGS@
+SYSREPOCPP_INCLUDEDIR = @SYSREPOCPP_INCLUDEDIR@
+SYSREPOCPP_LIBS = @SYSREPOCPP_LIBS@
+SYSREPOCPP_PREFIX = @SYSREPOCPP_PREFIX@
+SYSREPOCPP_VERSION = @SYSREPOCPP_VERSION@
+SYSREPO_CPPFLAGS = @SYSREPO_CPPFLAGS@
+SYSREPO_INCLUDEDIR = @SYSREPO_INCLUDEDIR@
+SYSREPO_LIBS = @SYSREPO_LIBS@
+SYSREPO_PREFIX = @SYSREPO_PREFIX@
+SYSREPO_VERSION = @SYSREPO_VERSION@
+USE_LCOV = @USE_LCOV@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = . tests
+pkgpython_PYTHON = kea_conn.py kea_connector3.py
+sbin_SCRIPTS = kea-shell
+CLEANFILES = *.pyc
+CLEANDIRS = __pycache__
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/bin/shell/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/bin/shell/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+kea-shell: $(top_builddir)/config.status $(srcdir)/kea-shell.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-sbinSCRIPTS: $(sbin_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ @list='$(sbin_SCRIPTS)'; test -n "$(sbindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n' \
+ -e 'h;s|.*|.|' \
+ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) { files[d] = files[d] " " $$1; \
+ if (++n[d] == $(am__install_max)) { \
+ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
+ else { print "f", d "/" $$4, $$1 } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
+ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-sbinSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_SCRIPTS)'; test -n "$(sbindir)" || exit 0; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 's,.*/,,;$(transform)'`; \
+ dir='$(DESTDIR)$(sbindir)'; $(am__uninstall_files_from_dir)
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkgpythonPYTHON: $(pkgpython_PYTHON)
+ @$(NORMAL_INSTALL)
+ @list='$(pkgpython_PYTHON)'; dlist=; list2=; test -n "$(pkgpythondir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgpythondir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgpythondir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \
+ if test -f $$b$$p; then \
+ $(am__strip_dir) \
+ dlist="$$dlist $$f"; \
+ list2="$$list2 $$b$$p"; \
+ else :; fi; \
+ done; \
+ for file in $$list2; do echo $$file; done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgpythondir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgpythondir)" || exit $$?; \
+ done || exit $$?; \
+ if test -n "$$dlist"; then \
+ $(am__py_compile) --destdir "$(DESTDIR)" \
+ --basedir "$(pkgpythondir)" $$dlist; \
+ else :; fi
+
+uninstall-pkgpythonPYTHON:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkgpython_PYTHON)'; test -n "$(pkgpythondir)" || list=; \
+ py_files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$py_files" || exit 0; \
+ dir='$(DESTDIR)$(pkgpythondir)'; \
+ pyc_files=`echo "$$py_files" | sed 's|$$|c|'`; \
+ pyo_files=`echo "$$py_files" | sed 's|$$|o|'`; \
+ st=0; \
+ for files in "$$py_files" "$$pyc_files" "$$pyo_files"; do \
+ $(am__uninstall_files_from_dir) || st=$$?; \
+ done; \
+ dir='$(DESTDIR)$(pkgpythondir)/__pycache__'; \
+ echo "$$py_files" | $(am__pep3147_tweak) | $(am__base_list) | \
+ while read files; do \
+ $(am__uninstall_files_from_dir) || st=$$?; \
+ done || exit $$?; \
+ exit $$st
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(SCRIPTS)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(pkgpythondir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-pkgpythonPYTHON
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-sbinSCRIPTS
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-pkgpythonPYTHON uninstall-sbinSCRIPTS
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool clean-local \
+ cscopelist-am ctags ctags-am distclean distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pkgpythonPYTHON install-ps install-ps-am \
+ install-sbinSCRIPTS install-strip installcheck installcheck-am \
+ installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-pkgpythonPYTHON uninstall-sbinSCRIPTS
+
+.PRECIOUS: Makefile
+
+
+clean-local:
+ rm -rf $(CLEANDIRS)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
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()
diff --git a/src/bin/shell/kea_conn.py b/src/bin/shell/kea_conn.py
new file mode 100644
index 0000000..887e4d0
--- /dev/null
+++ b/src/bin/shell/kea_conn.py
@@ -0,0 +1,107 @@
+# Copyright (C) 2017-2021 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.
+"""
+
+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 /)
+ - scheme - http or https
+ - http_host - hostname of the CA
+ - http_port - TCP port of the CA
+ - ca - False or CA file or path
+ - cert - False or cert file
+ - key - False or private key file
+ - command - specifies the command to send (e.g. list-commands)
+ - service - specifies service that is target for the command (e.g. dhcp4)
+ - timeout - timeout (in ms)
+ - auth - basic HTTP authentication credential
+ - args - extra arguments my be added here
+ - headers - extra HTTP headers may be added here
+ - version - version to be reported in HTTP header
+ """
+ path = '/'
+ scheme = 'http'
+ http_host = ''
+ http_port = 0
+ ca = False
+ cert = False
+ key = False
+ command = ''
+ service = ''
+ timeout = 0
+ auth = None
+ args = ''
+ headers = {}
+ version = ""
+ # This is a storage for generated command (input data to be sent over POST)
+ content = ''
+
+ def generate_body(self):
+ """
+ Generates the content, out of specified command line
+ and optional content.
+ this stores the output in self.content
+ """
+ self.content = '{ "command": "' + self.command + '"'
+ if self.service is not None:
+ self.service = [x for x in self.service if x]
+ if len(self.service) > 0:
+ self.content += ', "service": ["' + '","'.join(self.service) + '"]'
+ if len(self.args) > 1:
+ self.content += ', "arguments": { ' + self.args + ' }'
+ self.content += ' }'
+
+ def generate_headers(self):
+ """
+ Generate HTTP headers
+
+ In particular, this method generates Content-Length and its value.
+ """
+ self.headers['User-Agent'] = "Kea-shell/%s"%(self.version)
+ self.headers['Accept'] = '*/*'
+ if self.auth is not None:
+ self.headers['Authorization'] = "Basic %s"%(self.auth)
+ self.headers['Content-Type'] = 'application/json'
+ self.headers['Content-Length'] = "%d"%(len(self.content))
+
+
+class CAResponse:
+ """
+ This class represents the HTTP 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
+
+ status = 0
+ reason = ''
+ body = ''
+
+ 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)
diff --git a/src/bin/shell/kea_connector3.py b/src/bin/shell/kea_connector3.py
new file mode 100644
index 0000000..c1d4f5c
--- /dev/null
+++ b/src/bin/shell/kea_connector3.py
@@ -0,0 +1,50 @@
+# Copyright (C) 2017-2021 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 3.x version of HTTP connection establishment
+"""
+
+import urllib.request
+import ssl
+import os
+
+from kea_conn import CAResponse # CARequest
+
+def send_to_control_agent(params):
+ """ Sends a request to Control Agent, receives a response and returns it."""
+
+ # First, create the URL
+ url = params.scheme + "://" + params.http_host + ":"
+ url += str(params.http_port) + str(params.path)
+
+ # Now prepare the request (URL, headers and body)
+ req = urllib.request.Request(url=url,
+ data=str.encode(params.content),
+ headers=params.headers)
+
+ # Set up the SSL context.
+ ssl_ctx = None
+ capath = None
+ cafile = None
+ if params.ca:
+ ssl_ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
+ if os.path.isdir(params.ca):
+ capath = params.ca
+ else:
+ cafile = params.ca
+ ssl_ctx.load_verify_locations(cafile, capath)
+ if params.cert and params.key:
+ ssl_ctx.load_cert_chain(params.cert, params.key)
+
+ # Establish connection, send the request.
+ resp = urllib.request.urlopen(req, context=ssl_ctx)
+
+ # 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
diff --git a/src/bin/shell/tests/Makefile.am b/src/bin/shell/tests/Makefile.am
new file mode 100644
index 0000000..101e064
--- /dev/null
+++ b/src/bin/shell/tests/Makefile.am
@@ -0,0 +1,30 @@
+SUBDIRS = .
+
+# Needed by shell_unittest.py to access python modules like kea_conn.
+TESTS_ENVIRONMENT = PYTHONPATH="$(abs_top_srcdir)/src/bin/shell"
+
+# Python tests
+PYTESTS = shell_unittest.py
+
+# Shell tests
+SHTESTS =
+SHTESTS += basic_auth_tests.sh
+SHTESTS += shell_process_tests.sh
+if CA_TLS_TEST
+SHTESTS += tls_ca_process_tests.sh
+endif
+
+# As with every file generated by ./configure, clean them up when running
+# "make distclean", but not on "make clean".
+DISTCLEANFILES = $(PYTESTS) $(SHTESTS)
+
+if HAVE_GTEST
+
+# Run tests on "make check".
+check_SCRIPTS = $(PYTESTS) $(SHTESTS)
+TESTS = $(PYTESTS) $(SHTESTS)
+
+endif
+
+# Don't install tests.
+noinst_SCRIPTS = $(PYTESTS) $(SHTESTS)
diff --git a/src/bin/shell/tests/Makefile.in b/src/bin/shell/tests/Makefile.in
new file mode 100644
index 0000000..e544072
--- /dev/null
+++ b/src/bin/shell/tests/Makefile.in
@@ -0,0 +1,883 @@
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@CA_TLS_TEST_TRUE@am__append_1 = tls_ca_process_tests.sh
+subdir = src/bin/shell/tests
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \
+ $(top_srcdir)/m4macros/ax_cpp11.m4 \
+ $(top_srcdir)/m4macros/ax_cpp20.m4 \
+ $(top_srcdir)/m4macros/ax_crypto.m4 \
+ $(top_srcdir)/m4macros/ax_find_library.m4 \
+ $(top_srcdir)/m4macros/ax_gssapi.m4 \
+ $(top_srcdir)/m4macros/ax_gtest.m4 \
+ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \
+ $(top_srcdir)/m4macros/ax_netconf.m4 \
+ $(top_srcdir)/m4macros/libtool.m4 \
+ $(top_srcdir)/m4macros/ltoptions.m4 \
+ $(top_srcdir)/m4macros/ltsugar.m4 \
+ $(top_srcdir)/m4macros/ltversion.m4 \
+ $(top_srcdir)/m4macros/lt~obsolete.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = basic_auth_tests.sh shell_process_tests.sh \
+ shell_unittest.py tls_ca_process_tests.sh
+CONFIG_CLEAN_VPATH_FILES =
+SCRIPTS = $(noinst_SCRIPTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(srcdir)/basic_auth_tests.sh.in \
+ $(srcdir)/shell_process_tests.sh.in \
+ $(srcdir)/shell_unittest.py.in \
+ $(srcdir)/tls_ca_process_tests.sh.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+ASCIIDOC = @ASCIIDOC@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_INCLUDES = @BOOST_INCLUDES@
+BOOST_LIBS = @BOOST_LIBS@
+BOTAN_TOOL = @BOTAN_TOOL@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CONTRIB_DIR = @CONTRIB_DIR@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CRYPTO_CFLAGS = @CRYPTO_CFLAGS@
+CRYPTO_INCLUDES = @CRYPTO_INCLUDES@
+CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@
+CRYPTO_LIBS = @CRYPTO_LIBS@
+CRYPTO_PACKAGE = @CRYPTO_PACKAGE@
+CRYPTO_RPATH = @CRYPTO_RPATH@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@
+DISTCHECK_CONTRIB_CONFIGURE_FLAG = @DISTCHECK_CONTRIB_CONFIGURE_FLAG@
+DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@
+DISTCHECK_GSSAPI_CONFIGURE_FLAG = @DISTCHECK_GSSAPI_CONFIGURE_FLAG@
+DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@
+DISTCHECK_KEA_SHELL_CONFIGURE_FLAG = @DISTCHECK_KEA_SHELL_CONFIGURE_FLAG@
+DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG = @DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG@
+DISTCHECK_LIBYANG_CONFIGURE_FLAG = @DISTCHECK_LIBYANG_CONFIGURE_FLAG@
+DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG = @DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG@
+DISTCHECK_MYSQL_CONFIGURE_FLAG = @DISTCHECK_MYSQL_CONFIGURE_FLAG@
+DISTCHECK_PERFDHCP_CONFIGURE_FLAG = @DISTCHECK_PERFDHCP_CONFIGURE_FLAG@
+DISTCHECK_PGSQL_CONFIGURE_FLAG = @DISTCHECK_PGSQL_CONFIGURE_FLAG@
+DISTCHECK_PREMIUM_CONFIGURE_FLAG = @DISTCHECK_PREMIUM_CONFIGURE_FLAG@
+DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG = @DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG@
+DISTCHECK_SYSREPO_CONFIGURE_FLAG = @DISTCHECK_SYSREPO_CONFIGURE_FLAG@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GENHTML = @GENHTML@
+GREP = @GREP@
+GSSAPI_CFLAGS = @GSSAPI_CFLAGS@
+GSSAPI_LIBS = @GSSAPI_LIBS@
+GTEST_CONFIG = @GTEST_CONFIG@
+GTEST_INCLUDES = @GTEST_INCLUDES@
+GTEST_LDADD = @GTEST_LDADD@
+GTEST_LDFLAGS = @GTEST_LDFLAGS@
+GTEST_SOURCE = @GTEST_SOURCE@
+HAVE_NETCONF = @HAVE_NETCONF@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KEA_CXXFLAGS = @KEA_CXXFLAGS@
+KEA_SRCID = @KEA_SRCID@
+KRB5_CONFIG = @KRB5_CONFIG@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBYANGCPP_CPPFLAGS = @LIBYANGCPP_CPPFLAGS@
+LIBYANGCPP_INCLUDEDIR = @LIBYANGCPP_INCLUDEDIR@
+LIBYANGCPP_LIBS = @LIBYANGCPP_LIBS@
+LIBYANGCPP_PREFIX = @LIBYANGCPP_PREFIX@
+LIBYANGCPP_VERSION = @LIBYANGCPP_VERSION@
+LIBYANG_CPPFLAGS = @LIBYANG_CPPFLAGS@
+LIBYANG_INCLUDEDIR = @LIBYANG_INCLUDEDIR@
+LIBYANG_LIBS = @LIBYANG_LIBS@
+LIBYANG_PREFIX = @LIBYANG_PREFIX@
+LIBYANG_VERSION = @LIBYANG_VERSION@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@
+LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_TYPE = @PACKAGE_VERSION_TYPE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PERL = @PERL@
+PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@
+PGSQL_LIBS = @PGSQL_LIBS@
+PKGPYTHONDIR = @PKGPYTHONDIR@
+PKG_CONFIG = @PKG_CONFIG@
+PLANTUML = @PLANTUML@
+PREMIUM_DIR = @PREMIUM_DIR@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SEP = @SEP@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINXBUILD = @SPHINXBUILD@
+SRPD_PLUGINS_PATH = @SRPD_PLUGINS_PATH@
+SR_PLUGINS_PATH = @SR_PLUGINS_PATH@
+SR_REPO_PATH = @SR_REPO_PATH@
+STRIP = @STRIP@
+SYSREPOCPP_CPPFLAGS = @SYSREPOCPP_CPPFLAGS@
+SYSREPOCPP_INCLUDEDIR = @SYSREPOCPP_INCLUDEDIR@
+SYSREPOCPP_LIBS = @SYSREPOCPP_LIBS@
+SYSREPOCPP_PREFIX = @SYSREPOCPP_PREFIX@
+SYSREPOCPP_VERSION = @SYSREPOCPP_VERSION@
+SYSREPO_CPPFLAGS = @SYSREPO_CPPFLAGS@
+SYSREPO_INCLUDEDIR = @SYSREPO_INCLUDEDIR@
+SYSREPO_LIBS = @SYSREPO_LIBS@
+SYSREPO_PREFIX = @SYSREPO_PREFIX@
+SYSREPO_VERSION = @SYSREPO_VERSION@
+USE_LCOV = @USE_LCOV@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = .
+
+# Needed by shell_unittest.py to access python modules like kea_conn.
+TESTS_ENVIRONMENT = PYTHONPATH="$(abs_top_srcdir)/src/bin/shell"
+
+# Python tests
+PYTESTS = shell_unittest.py
+
+# Shell tests
+SHTESTS = basic_auth_tests.sh shell_process_tests.sh $(am__append_1)
+
+# As with every file generated by ./configure, clean them up when running
+# "make distclean", but not on "make clean".
+DISTCLEANFILES = $(PYTESTS) $(SHTESTS)
+
+# Run tests on "make check".
+@HAVE_GTEST_TRUE@check_SCRIPTS = $(PYTESTS) $(SHTESTS)
+@HAVE_GTEST_TRUE@TESTS = $(PYTESTS) $(SHTESTS)
+
+# Don't install tests.
+noinst_SCRIPTS = $(PYTESTS) $(SHTESTS)
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/bin/shell/tests/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/bin/shell/tests/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+basic_auth_tests.sh: $(top_builddir)/config.status $(srcdir)/basic_auth_tests.sh.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+shell_process_tests.sh: $(top_builddir)/config.status $(srcdir)/shell_process_tests.sh.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+shell_unittest.py: $(top_builddir)/config.status $(srcdir)/shell_unittest.py.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+tls_ca_process_tests.sh: $(top_builddir)/config.status $(srcdir)/tls_ca_process_tests.sh.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ fi; \
+ echo "$${col}$$dashes$${std}"; \
+ echo "$${col}$$banner$${std}"; \
+ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+ test -z "$$report" || echo "$${col}$$report$${std}"; \
+ echo "$${col}$$dashes$${std}"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_SCRIPTS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-recursive
+all-am: Makefile $(SCRIPTS)
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) check-am install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-TESTS check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags ctags-am distclean distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/bin/shell/tests/basic_auth_tests.sh.in b/src/bin/shell/tests/basic_auth_tests.sh.in
new file mode 100644
index 0000000..36ea16c
--- /dev/null
+++ b/src/bin/shell/tests/basic_auth_tests.sh.in
@@ -0,0 +1,196 @@
+#!/bin/sh
+
+# Copyright (C) 2020-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/.
+
+# shellcheck disable=SC1091
+# SC1091: Not following: ... was not specified as input (see shellcheck -x).
+
+# Exit with error if commands exit with non-zero and if undefined variables are
+# used.
+set -eu
+
+# Path to the temporary configuration file.
+# shellcheck disable=SC2034
+# SC2034: ... appears unused. Verify use (or export if used externally).
+# reason: used in dhcp_test_lib.sh.in
+CFG_FILE="@abs_top_builddir@/src/bin/shell/tests/test_config.json"
+
+# Path to the Control Agent log file.
+LOG_FILE="@abs_top_builddir@/src/bin/shell/tests/test.log"
+
+# Control Agent configuration to be stored in the configuration file.
+# todo: use actual configuration once we support it.
+CONFIG="{
+ \"Control-agent\":
+ {
+ \"http-host\": \"127.0.0.1\",
+ \"http-port\": 8081,
+ \"authentication\":
+ {
+ \"type\": \"basic\",
+ \"realm\": \"ISC.ORG\",
+ \"clients\": [
+ {
+ \"user\": \"pet\",
+ \"password\": \"meow\"
+ }
+ ]
+ },
+ \"loggers\": [
+ {
+ \"name\": \"kea-ctrl-agent\",
+ \"output_options\": [
+ {
+ \"output\": \"$LOG_FILE\"
+ }
+ ],
+ \"severity\": \"DEBUG\"
+ }
+ ]
+ }
+}"
+
+# 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.
+ca_bin="kea-ctrl-agent"
+ca_bin_path="@abs_top_builddir@/src/bin/agent"
+
+shell_bin="kea-shell"
+shell_bin_path="@abs_top_builddir@/src/bin/shell"
+
+tmpfile_path="@abs_top_builddir@/src/bin/shell/tests"
+
+# Import common test library.
+. "@abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh"
+
+run_kea_shell() {
+ # shellcheck disable=SC2086
+ # SC2086: Double quote to prevent globbing and word splitting.
+ # reason: ${auth} can be empty here, if we quote, it will be interpreted as
+ # an empty string which is not desired as it will result in unrecognized
+ # argument from kea-shell.
+ echo | "${shell_bin_path}/${shell_bin}" --host 127.0.0.1 --port 8081 \
+ ${auth} "${cmd}" > "${tmpfile_path}/shell-stdout.txt"
+}
+
+# This test verifies that Control Agent is shut down gracefully when it
+# receives a SIGINT or SIGTERM signal.
+shell_command_test() {
+ test_name=${1} # Test name
+ auth=${2} # Authentication
+ cmd=${3} # Command to be sent
+ exp_result=${4} # Expected result
+ exp_rsp=${5} # Expected response
+
+ # Setup phase: start CA.
+
+ # Log the start of the test and print test name.
+ test_start "${test_name}"
+
+ # Create new configuration file.
+ create_config "${CONFIG}"
+
+ # Instruct Control Agent to log to the specific file.
+ set_logger
+ # Start Control Agent.
+ start_kea ${ca_bin_path}/${ca_bin}
+ # Wait up to 20s for Control Agent to start.
+ wait_for_kea 20
+ if [ "${_WAIT_FOR_KEA}" -eq 0 ]; then
+ printf "ERROR: timeout waiting for Control Agent to start.\n"
+ clean_exit 1
+ fi
+
+ # Check if it is still running. It could have terminated (e.g. as a result
+ # 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}"
+ clean_exit 1
+ fi
+
+ # Check in the log file, how many times server has been configured.
+ # It should be just once on startup.
+ get_reconfigs
+ if [ "${_GET_RECONFIGS}" -ne 1 ]; then
+ printf "ERROR: server been configured %s time(s),\
+ but exactly 1 was expected.\n" "${_GET_RECONFIGS}"
+ clean_exit 1
+ else
+ printf "Server successfully configured.\n"
+ fi
+
+ # Main test phase: send command, check response.
+ tmp="echo | ${shell_bin_path}/${shell_bin} --host \
+ 127.0.0.1 --port 8081 ${auth} ${cmd} > ${tmpfile_path}/shell-stdout.txt"
+ echo "Executing kea-shell ($tmp)"
+
+ run_command \
+ run_kea_shell
+
+ # Check the exit code
+ if [ "${exp_result}" = "fail" ]; then
+ if [ "${EXIT_CODE}" -eq 0 ]; then
+ echo "ERROR:" \
+ "kea-shell returned ${EXIT_CODE} exit code, expected 1."
+ else
+ echo "kea-shell returned ${EXIT_CODE} exit code as expected."
+ fi
+ elif [ "${EXIT_CODE}" -ne 0 ]; then
+ echo "ERROR:" \
+ "kea-shell returned ${EXIT_CODE} exit code, expected 0."
+ else
+ echo "kea-shell returned ${EXIT_CODE} exit code as expected."
+ fi
+
+ # Now check the response
+ rm -f ${tmpfile_path}/shell-expected.txt
+ printf '%s\n' "${exp_rsp}" > ${tmpfile_path}/shell-expected.txt
+ if diff "${tmpfile_path}/shell-stdout.txt" "${tmpfile_path}/shell-expected.txt"; then
+ echo "Content returned by kea-shell meets expectation."
+ rm ${tmpfile_path}/shell-*.txt
+ else
+ echo "ERROR:" \
+ "content returned is different than expected." \
+ "See ${tmpfile_path}/shell-*.txt"
+ echo "EXPECTED:"
+ cat ${tmpfile_path}/shell-expected.txt
+ echo "ACTUAL RESULT:"
+ cat ${tmpfile_path}/shell-stdout.txt
+ clean_exit 1
+ fi
+ # Main test phase ends.
+
+ # Cleanup phase: shutdown CA
+ # Send SIGTERM signal to Control Agent
+ send_signal 15 ${ca_bin}
+
+ # Now wait for process to log that it is exiting.
+ wait_for_message 10 "DCTL_SHUTDOWN" 1
+ if [ "${_WAIT_FOR_MESSAGE}" -eq 0 ]; then
+ printf "ERROR: Control Agent did not log shutdown.\n"
+ clean_exit 1
+ fi
+
+ # Make sure the server is down.
+ wait_for_server_down 5 ${ca_bin}
+ assert_eq 1 "${_WAIT_FOR_SERVER_DOWN}" \
+ "Expected wait_for_server_down return %d, returned %d"
+
+ test_finish 0
+}
+
+shell_command_test "shell.no-auth" "" "list-commands" "fail" \
+ "Failed to run: HTTP Error 401: Unauthorized"
+shell_command_test "shell.bad-auth" \
+ "--auth-user foo --auth-password bar" "list-commands" "fail" \
+ "Failed to run: HTTP Error 401: Unauthorized"
+shell_command_test "shell.authorized" \
+ "--auth-user pet --auth-password meow" "list-commands" "" \
+ "[ { \"arguments\": [ \"build-report\", \"config-get\", \"config-hash-get\", \"config-reload\", \"config-set\", \"config-test\", \"config-write\", \"list-commands\", \"shutdown\", \"status-get\", \"version-get\" ], \"result\": 0 } ]"
diff --git a/src/bin/shell/tests/shell_process_tests.sh.in b/src/bin/shell/tests/shell_process_tests.sh.in
new file mode 100644
index 0000000..5f2e00a
--- /dev/null
+++ b/src/bin/shell/tests/shell_process_tests.sh.in
@@ -0,0 +1,196 @@
+#!/bin/sh
+
+# 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/.
+
+# shellcheck disable=SC1091
+# SC1091: Not following: ... was not specified as input (see shellcheck -x).
+
+# Exit with error if commands exit with non-zero and if undefined variables are
+# used.
+set -eu
+
+# Path to the temporary configuration file.
+# shellcheck disable=SC2034
+# SC2034: ... appears unused. Verify use (or export if used externally).
+# reason: used in dhcp_test_lib.sh.in
+CFG_FILE="@abs_top_builddir@/src/bin/shell/tests/test_config.json"
+
+# Path to the Control Agent log file.
+LOG_FILE="@abs_top_builddir@/src/bin/shell/tests/test.log"
+
+# Control Agent configuration to be stored in the configuration file.
+# todo: use actual configuration once we support it.
+CONFIG="{
+ \"Control-agent\":
+ {
+ \"http-host\": \"127.0.0.1\",
+ \"http-port\": 8081,
+ \"loggers\": [
+ {
+ \"name\": \"kea-ctrl-agent\",
+ \"output_options\": [
+ {
+ \"output\": \"$LOG_FILE\"
+ }
+ ],
+ \"severity\": \"DEBUG\"
+ }
+ ]
+ }
+}"
+
+# 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.
+ca_bin="kea-ctrl-agent"
+ca_bin_path="@abs_top_builddir@/src/bin/agent"
+
+shell_bin="kea-shell"
+shell_bin_path="@abs_top_builddir@/src/bin/shell"
+
+tmpfile_path="@abs_top_builddir@/src/bin/shell/tests"
+
+# Import common test library.
+. "@abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh"
+
+# This test verifies that Control Agent is shut down gracefully when it
+# receives a SIGINT or SIGTERM signal.
+shell_command_test() {
+ test_name=${1} # Test name
+ cmd=${2} # Command to be sent
+ exp_rsp=${3} # Expected response
+ params=${4} # Any extra parameters
+
+ # Setup phase: start CA.
+
+ # Log the start of the test and print test name.
+ test_start "${test_name}"
+
+ # Create new configuration file.
+ create_config "${CONFIG}"
+
+ # Instruct Control Agent to log to the specific file.
+ set_logger
+ # Start Control Agent.
+ start_kea ${ca_bin_path}/${ca_bin}
+ # Wait up to 20s for Control Agent to start.
+ wait_for_kea 20
+ if [ "${_WAIT_FOR_KEA}" -eq 0 ]; then
+ printf "ERROR: timeout waiting for Control Agent to start.\n"
+ clean_exit 1
+ fi
+
+ # Check if it is still running. It could have terminated (e.g. as a result
+ # 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}"
+ clean_exit 1
+ fi
+
+ # Check in the log file, how many times server has been configured.
+ # It should be just once on startup.
+ get_reconfigs
+ if [ "${_GET_RECONFIGS}" -ne 1 ]; then
+ printf "ERROR: server been configured %s time(s),\
+ but exactly 1 was expected.\n" "${_GET_RECONFIGS}"
+ 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"
+ 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
+ shell_exit_code=$?
+
+ # Check the exit code
+ if [ "${shell_exit_code}" -ne 0 ]; then
+ 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
+
+ # Now check the response
+ rm -f ${tmpfile_path}/shell-expected.txt
+ printf '%s\n' "${exp_rsp}" > ${tmpfile_path}/shell-expected.txt
+ 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 "EXPECTED:"
+ cat ${tmpfile_path}/shell-expected.txt
+ echo "ACTUAL RESULT:"
+ cat ${tmpfile_path}/shell-stdout.txt
+ clean_exit 1
+ else
+ echo "Content returned by kea-shell meets expectation."
+ rm ${tmpfile_path}/shell-*.txt
+ fi
+ # Main test phase ends.
+
+ # Cleanup phase: shutdown CA
+ # Send SIGTERM signal to Control Agent
+ send_signal 15 ${ca_bin}
+
+ # Now wait for process to log that it is exiting.
+ wait_for_message 10 "DCTL_SHUTDOWN" 1
+ if [ "${_WAIT_FOR_MESSAGE}" -eq 0 ]; then
+ printf "ERROR: Control Agent did not log shutdown.\n"
+ clean_exit 1
+ fi
+
+ # Make sure the server is down.
+ wait_for_server_down 5 ${ca_bin}
+ assert_eq 1 "${_WAIT_FOR_SERVER_DOWN}" \
+ "Expected wait_for_server_down return %d, returned %d"
+
+ test_finish 0
+}
+
+# This test verifies that the binary is reporting its version properly.
+version_test() {
+ test_name=${1} # Test name
+
+ # Log the start of the test and print test name.
+ test_start "${test_name}"
+
+ REPORTED_VERSION=$(${shell_bin_path}/${shell_bin} -v)
+
+ if test "${REPORTED_VERSION}" = "${EXPECTED_VERSION}"; then
+ test_finish 0
+ else
+ echo "ERROR:" \
+ "Expected version ${EXPECTED_VERSION}, got ${REPORTED_VERSION}"
+ test_finish 1
+ fi
+}
+
+version_test "shell.version"
+shell_command_test "shell.list-commands" "list-commands" \
+ "[ { \"arguments\": [ \"build-report\", \"config-get\", \"config-hash-get\", \"config-reload\", \"config-set\", \"config-test\", \"config-write\", \"list-commands\", \"shutdown\", \"status-get\", \"version-get\" ], \"result\": 0 } ]" ""
+shell_command_test "shell.bogus" "give-me-a-beer" \
+"[ { \"result\": 2, \"text\": \"'give-me-a-beer' command not supported. You did not include \\\"service\\\" parameter in the command, which indicates that Kea Control Agent should process this command rather than forward it to one or more Kea servers. If you aimed to send this command to one of the Kea servers you should include the \\\"service\\\" parameter in your request, e.g. \\\"service\\\": [ \\\"dhcp4\\\" ] to forward the command to the DHCPv4 server, or \\\"service\\\": [ \\\"dhcp4\\\", \\\"dhcp6\\\", \\\"d2\\\" ] to forward it to DHCPv4, DHCPv6 and D2 servers etc.\" } ]" ""
+shell_command_test "shell.empty-config-test" "config-test" \
+ "[ { \"result\": 1, \"text\": \"Missing mandatory 'arguments' parameter.\" } ]" ""
+shell_command_test "shell.no-app-config-test" "config-test" \
+ "[ { \"result\": 1, \"text\": \"Missing mandatory 'Control-agent' parameter.\" } ]" \
+ "\"FooBar\": { }"
+shell_command_test "shell.no-map-config-test" "config-test" \
+ "[ { \"result\": 1, \"text\": \"'Control-agent' parameter expected to be a map.\" } ]" \
+ "\"Control-agent\": [ ]"
+shell_command_test "shell.bad-value-config-test" "config-test" \
+ "[ { \"result\": 1, \"text\": \"out of range value (80000) specified for parameter 'http-port' (<string>:1:76)\" } ]" \
+ "\"Control-agent\": { \"http-port\": 80000 }"
diff --git a/src/bin/shell/tests/shell_unittest.py.in b/src/bin/shell/tests/shell_unittest.py.in
new file mode 100644
index 0000000..08a05f5
--- /dev/null
+++ b/src/bin/shell/tests/shell_unittest.py.in
@@ -0,0 +1,199 @@
+#!@PYTHON@
+
+# Copyright (C) 2017-2020 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
+import sys
+from base64 import b64encode
+
+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.
+ """
+
+ def test_body_with_service(self):
+ """
+ This test verifies if the CARequest object generates the request
+ content properly when there is one target service.
+ """
+ request = CARequest()
+ request.command = "foo"
+ request.service = ["service1"]
+ request.generate_body()
+ self.assertEqual(request.content,
+ '{ "command": "foo", "service": ["service1"] }')
+
+ def test_body_with_multiple_service(self):
+ """
+ This test verifies if the CARequest object generates the request
+ content properly when there are two target service.
+ """
+ request = CARequest()
+ request.command = "foo"
+ request.service = ["service1", "service2/2"]
+ request.generate_body()
+ self.assertEqual(request.content,
+ '{ "command": "foo", "service": ["service1","service2/2"] }')
+
+ def test_body_with_malformed_service(self):
+ """
+ This test verifies if the CARequest object generates the request
+ content properly when there are two target service, one is empty
+ """
+ request = CARequest()
+ request.command = "foo"
+ request.service = ["service1", ""]
+ request.generate_body()
+ self.assertEqual(request.content,
+ '{ "command": "foo", "service": ["service1"] }')
+
+ def test_body_without_args(self):
+ """
+ This test verifies if the CARequest object generates the request
+ content properly when there are no arguments.
+ """
+ request = CARequest()
+ request.command = "foo"
+ request.generate_body()
+ self.assertEqual(request.content, '{ "command": "foo" }')
+
+ def test_body_with_args(self):
+ """
+ This test verifies if the CARequest object generates the request
+ content properly when there are arguments.
+ """
+ request = CARequest()
+ request.command = "foo"
+ request.args = '"bar": "baz"'
+ request.generate_body()
+ self.assertEqual(request.content,
+ '{ "command": "foo", "arguments": { "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
+ print("Expected value: " + value +
+ " does not match actual value: " +
+ headers[header_name])
+ return False
+ 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 test_basic_http_auth(self):
+ """
+ This test check if the basic HTTP authentication credential
+ generated properly.
+ """
+ user = 'foo'
+ password = 'bar'
+ buser = user.encode('utf-8')
+ bpassword = password.encode('utf-8')
+ secret = b':'.join((buser, bpassword))
+ self.assertEqual(b'foo:bar', secret)
+ if sys.version_info[0] == 3:
+ auth = b64encode(secret).strip().decode('ascii')
+ else:
+ auth = b64encode(secret).strip().encode('ascii')
+ self.assertEqual('Zm9vOmJhcg==', auth)
+
+ def test_auth_unicode(self):
+ """
+ This test check if the basic HTTP authentication uses UTF-8 encoding.
+ """
+ if sys.version_info[0] == 3:
+ user = 'libert\xe9'
+ password = '\xe9galit\xe9'
+ else:
+ user = u'libert\xe9'
+ password = u'\xe9galit\xe9'
+ buser = user.encode('utf-8')
+ bpassword = password.encode('utf-8')
+ secret = b':'.join((buser, bpassword))
+ self.assertEqual(b'libert\xc3\xa9:\xc3\xa9galit\xc3\xa9', secret)
+ if sys.version_info[0] == 3:
+ auth = b64encode(secret).strip().decode('ascii')
+ else:
+ auth = b64encode(secret).strip().encode('ascii')
+ self.assertEqual('bGliZXJ0w6k6w6lnYWxpdMOp', auth)
+
+ def test_header_auth(self):
+ """
+ This test checks if the basic HTTP authentication header is
+ generated properly.
+ """
+ request = CARequest()
+ request.auth = "Zm9vOmJhcg=="
+ request.generate_headers()
+
+ self.assertTrue(self.check_header(request.headers,
+ 'Authorization',
+ 'Basic Zm9vOmJhcg=='))
+
+ def tearDown(self):
+ """
+ This method is called after each test. Currently it does nothing.
+ """
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/src/bin/shell/tests/tls_ca_process_tests.sh.in b/src/bin/shell/tests/tls_ca_process_tests.sh.in
new file mode 100644
index 0000000..2c23188
--- /dev/null
+++ b/src/bin/shell/tests/tls_ca_process_tests.sh.in
@@ -0,0 +1,222 @@
+#!/bin/sh
+
+# Copyright (C) 2016-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/.
+
+# shellcheck disable=SC1091
+# SC1091: Not following: ... was not specified as input (see shellcheck -x).
+
+# shellcheck disable=SC2039
+# SC2039: In POSIX sh, 'local' is undefined.
+
+# Exit with error if commands exit with non-zero and if undefined variables are
+# used.
+set -eu
+
+# Include common test library.
+. "@abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh"
+
+# Path to the temporary configuration file.
+CFG_FILE="@abs_top_builddir@/src/bin/agent/tests/test_config.json"
+
+# Path to the Control Agent log file.
+LOG_FILE="@abs_top_builddir@/src/bin/agent/tests/test.log"
+
+# Path to the test certificate authority directory.
+TEST_CA_DIR="@abs_top_srcdir@/src/lib/asiolink/testutils/ca"
+
+# Configuration without TLS.
+CONFIG_NONE="{
+ \"Control-agent\":
+ {
+ \"http-host\": \"127.0.0.1\",
+ \"http-port\": 8443,
+ \"loggers\": [
+ {
+ \"name\": \"kea-ctrl-agent\",
+ \"output_options\": [
+ {
+ \"output\": \"${LOG_FILE}\"
+ }
+ ],
+ \"severity\": \"DEBUG\"
+ }
+ ]
+ }
+}"
+
+# Configuration without mutual authentication i.e. only channel protection.
+CONFIG_NOCR="{
+ \"Control-agent\":
+ {
+ \"http-host\": \"127.0.0.1\",
+ \"http-port\": 8443,
+ \"trust-anchor\": \"${TEST_CA_DIR}/kea-ca.crt\",
+ \"cert-file\": \"${TEST_CA_DIR}/kea-server-addr.crt\",
+ \"key-file\": \"${TEST_CA_DIR}/kea-server.key\",
+ \"cert-required\": false,
+ \"loggers\": [
+ {
+ \"name\": \"kea-ctrl-agent\",
+ \"output_options\": [
+ {
+ \"output\": \"${LOG_FILE}\"
+ }
+ ],
+ \"severity\": \"DEBUG\"
+ }
+ ]
+ }
+}"
+
+# Configuration with mutual authentication.
+CONFIG="{
+ \"Control-agent\":
+ {
+ \"http-host\": \"127.0.0.1\",
+ \"http-port\": 8443,
+ \"trust-anchor\": \"${TEST_CA_DIR}/kea-ca.crt\",
+ \"cert-file\": \"${TEST_CA_DIR}/kea-server-addr.crt\",
+ \"key-file\": \"${TEST_CA_DIR}/kea-server.key\",
+ \"cert-required\": true,
+ \"loggers\": [
+ {
+ \"name\": \"kea-ctrl-agent\",
+ \"output_options\": [
+ {
+ \"output\": \"${LOG_FILE}\"
+ }
+ ],
+ \"severity\": \"DEBUG\"
+ }
+ ]
+ }
+}"
+
+# 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.
+ca_bin="kea-ctrl-agent"
+ca_bin_path="@abs_top_builddir@/src/bin/agent"
+
+shell_bin="kea-shell"
+shell_bin_path="@abs_top_builddir@/src/bin/shell"
+
+tmpfile_path="@abs_top_builddir@/src/bin/agent/tests"
+
+# Import common test library.
+. "@abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh"
+
+list_commands_test() {
+ local test_name="${1}"
+ local config="${2}"
+ local arguments="${3}"
+ local expected_response="${4}"
+
+ # Setup phase: start CA.
+
+ # Log the start of the test and print test name.
+ test_start "${test_name}"
+
+ # Create correct configuration file.
+ create_config "${config}"
+
+ # Instruct Control Agent to log to the specific file.
+ set_logger
+
+ # Start Control Agent
+ start_kea ${ca_bin_path}/${ca_bin}
+
+ # Wait up to 20s for Control Agent to start.
+ wait_for_kea 20
+ if [ "${_WAIT_FOR_KEA}" -eq 0 ]; then
+ printf "ERROR: timeout waiting for Control Agent to start.\n"
+ clean_exit 1
+ fi
+
+ # Check if it is still running. It could have terminated (e.g. as a result
+ # 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}"
+ clean_exit 1
+ fi
+
+ # Check in the log file, how many times server has been configured.
+ # It should be just once on startup.
+ get_reconfigs
+ if [ "${_GET_RECONFIGS}" -ne 1 ]; then
+ printf 'ERROR: server been configured %s time(s), but exactly 1 was expected.\n' "${_GET_RECONFIGS}"
+ clean_exit 1
+ else
+ printf "Server successfully configured.\n"
+ fi
+
+ # Main test phase: send command, check response.
+ tmp="echo | ${shell_bin_path}/${shell_bin} --port 8443 \
+ ${arguments} > ${tmpfile_path}/shell-stdout.txt"
+ echo "Executing kea-shell ($tmp)"
+
+ echo | ${shell_bin_path}/${shell_bin} --port 8443 \
+ ${arguments} > ${tmpfile_path}/shell-stdout.txt
+ EXIT_CODE=$?
+
+ # Check the exit code
+ if [ "${EXIT_CODE}" -ne 0 ]; then
+ echo "ERROR: kea-shell returned ${EXIT_CODE} exit code, expected 0."
+ else
+ echo "kea-shell returned ${EXIT_CODE} exit code as expected."
+ fi
+
+ # Now check the response
+ rm -f ${tmpfile_path}/shell-expected.txt
+ printf '%s\n' "${expected_response}" > ${tmpfile_path}/shell-expected.txt
+ 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 "EXPECTED:"
+ cat ${tmpfile_path}/shell-expected.txt
+ echo "ACTUAL RESULT:"
+ cat ${tmpfile_path}/shell-stdout.txt
+ clean_exit 1
+ else
+ echo "Content returned by kea-shell meets expectation."
+ rm ${tmpfile_path}/shell-*.txt
+ fi
+ # Main test phase ends.
+
+ # Cleanup phase: shutdown Control Agent
+
+ # Send SIGTERM signal to Control Agent
+ send_signal 15 ${ca_bin}
+
+ # Now wait for process to log that it is exiting.
+ wait_for_message 10 "DCTL_SHUTDOWN" 1
+ if [ "${_WAIT_FOR_MESSAGE}" -eq 0 ]; then
+ printf "ERROR: Control Agent did not log shutdown.\n"
+ clean_exit 1
+ fi
+
+ # Make sure the agent is down.
+ wait_for_server_down 5 ${ca_bin}
+ assert_eq 1 "${_WAIT_FOR_SERVER_DOWN}" \
+ "Expected wait_for_server_down return %d, returned %d"
+
+ test_finish 0
+}
+
+list_commands_test "NoTLS" "${CONFIG_NONE}" "" \
+"[ { \"arguments\": [ \"build-report\", \"config-get\", \"config-hash-get\", \"config-reload\", \"config-set\", \"config-test\", \"config-write\", \"list-commands\", \"shutdown\", \"status-get\", \"version-get\" ], \"result\": 0 } ]"
+list_commands_test "Encrypted" "${CONFIG_NOCR}" \
+"--ca ${TEST_CA_DIR}/kea-ca.crt" \
+"[ { \"arguments\": [ \"build-report\", \"config-get\", \"config-hash-get\", \"config-reload\", \"config-set\", \"config-test\", \"config-write\", \"list-commands\", \"shutdown\", \"status-get\", \"version-get\" ], \"result\": 0 } ]"
+list_commands_test "Authenticated" "${CONFIG}" \
+"--ca ${TEST_CA_DIR}/kea-ca.crt --cert ${TEST_CA_DIR}/kea-client.crt --key ${TEST_CA_DIR}/kea-client.key" \
+"[ { \"arguments\": [ \"build-report\", \"config-get\", \"config-hash-get\", \"config-reload\", \"config-set\", \"config-test\", \"config-write\", \"list-commands\", \"shutdown\", \"status-get\", \"version-get\" ], \"result\": 0 } ]"