diff --git a/configure.ac b/configure.ac index a583ae05b0..6ddd3f6dbe 100644 --- a/configure.ac +++ b/configure.ac @@ -1393,6 +1393,8 @@ AC_CONFIG_FILES([compatcheck/Makefile src/bin/keactrl/keactrl.conf src/bin/keactrl/tests/Makefile src/bin/keactrl/tests/keactrl_tests.sh + src/bin/lfc/Makefile + src/bin/lfc/tests/Makefile src/bin/perfdhcp/Makefile src/bin/perfdhcp/tests/Makefile src/bin/perfdhcp/tests/testdata/Makefile diff --git a/doc/Doxyfile b/doc/Doxyfile index a78375eef1..b27ce0eb31 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -650,6 +650,7 @@ INPUT = ../src/bin/d2 \ ../src/bin/dhcp6 \ ../src/bin/perfdhcp \ ../src/bin/sockcreator \ + ../src/bin/lfc \ ../src/hooks/dhcp/user_chk \ ../src/lib/asiolink \ ../src/lib/cc \ diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index 372b59b4a0..c254189add 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -1,5 +1,5 @@ # The following build order must be maintained. -SUBDIRS = dhcp4 dhcp6 d2 perfdhcp admin +SUBDIRS = dhcp4 dhcp6 d2 perfdhcp admin lfc if CONFIG_BACKEND_JSON SUBDIRS += keactrl diff --git a/src/bin/lfc/.gitignore b/src/bin/lfc/.gitignore new file mode 100644 index 0000000000..1c52fb03e2 --- /dev/null +++ b/src/bin/lfc/.gitignore @@ -0,0 +1,5 @@ +/kea-lfc +/kea-lfc.8 +/lfc_messages.cc +/lfc_messages.h +/s-messages \ No newline at end of file diff --git a/src/bin/lfc/Makefile.am b/src/bin/lfc/Makefile.am new file mode 100644 index 0000000000..77ae8bfdd0 --- /dev/null +++ b/src/bin/lfc/Makefile.am @@ -0,0 +1,68 @@ +SUBDIRS = . tests + +AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib +AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin +AM_CPPFLAGS += $(BOOST_INCLUDES) + +AM_CXXFLAGS = $(KEA_CXXFLAGS) +if USE_CLANGPP +# Disable unused parameter warning caused by some Boost headers when compiling with clang +AM_CXXFLAGS += -Wno-unused-parameter +endif + +if USE_STATIC_LINK +AM_LDFLAGS = -static +endif + +CLEANFILES = lfc_messages.h lfc_messages.cc s-messages + +man_MANS = kea-lfc.8 +DISTCLEANFILES = $(man_MANS) +EXTRA_DIST = $(man_MANS) kea-lfc.xml + +if GENERATE_DOCS +kea-lfc.8: kea-lfc.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ \ + http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl \ + $(srcdir)/kea-lfc.xml + +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild Kea > $@ + +endif + +lfc_messages.h lfc_messages.cc: s-messages + +s-messages: lfc_messages.mes + $(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/bin/lfc/lfc_messages.mes + touch $@ + +BUILT_SOURCES = lfc_messages.h lfc_messages.cc + +# convenience archive + +noinst_LTLIBRARIES = liblfc.la + +liblfc_la_SOURCES = +liblfc_la_SOURCES += lfc_controller.h +liblfc_la_SOURCES += lfc_controller.cc + +nodist_liblfc_la_SOURCES = lfc_messages.h lfc_messages.cc +EXTRA_DIST += lfc_messages.mes + +sbin_PROGRAMS = kea-lfc + +kea_lfc_SOURCES = main.cc + +kea_lfc_LDADD = liblfc.la +kea_lfc_LDADD += $(top_builddir)/src/lib/log/libkea-log.la +kea_lfc_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la +kea_lfc_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la +kea_lfc_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la +kea_lfc_LDADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la +kea_lfc_LDADD += $(top_builddir)/src/lib/util/libkea-util.la + +kea_lfcdir = $(pkgdatadir) diff --git a/src/bin/lfc/kea-lfc.xml b/src/bin/lfc/kea-lfc.xml new file mode 100644 index 0000000000..d7cb9bb274 --- /dev/null +++ b/src/bin/lfc/kea-lfc.xml @@ -0,0 +1,184 @@ +]> + + + + + + Feb 1, 2015 + + + + kea-lfc + 8 + Kea + + + + kea-lfc + Lease File Cleanup process in Kea + + + + + 2015 + Internet Systems Consortium, Inc. ("ISC") + + + + + + kea-lfc + + + + + + + + + + + + + + + DESCRIPTION + + The kea-lfc service process removes redundant + information for the files used to provide persistent storage for + the memfile data base backend. The service is written to run as + a stand alone process. While it can be started externally it + should be started by the Kea DHCP servers as desired and required. + + + + + ARGUMENTS + + The arguments are as follows: + + + + + + + Verbose mode sets the logging level to debug. This is primarily + for development purposes in stand-alone mode. + + + + + + + version causes the version stamp to be printed. + + + + + + + Version causes a longer form of the version stamp to be printed. + + + + + + + Help causes the usage string to be printed. + + + + + + + The protocol version of the lease files, must be one of 4 or 6. + + + + + + + Configuration file including the configuration for + kea-lfc process. It may also + contain configuration entries for other Kea services. + Currently kea-lfc gets all of its arguments from + the comamnd line, in the future it will be extended to get some arguments + from the config file. + + + + + + + Previous lease file - When kea-lfc starts this + is the result of any previous run of kea-lfc. + When kea-lfc finishes it is the result of this run. + If kea-lfc is interrupted before compelting + this file may not exist. + + + + + + + Input or copy of lease file - Before the DHCP server invokes + kea-lfc it will copy the current lease file + here and then call kea-lfc with this file. + + + + + + + Output lease file - The temporary file kea-lfc + should use to write the leases. Upon completion of writing this + this file it will be moved to the finish file (see below). + + + + + + + Finish or completion file - Another temporary file + kea-lfc uses for bookkeeping. When + kea-lfc completes writing the output + file it moves it to this file name. After + kea-lfc finishes deleting the other + files (previous and input) it moves this file to previous + lease file. By moving the files in this fashion the + kea-lfc and the DHCP server processes + can determine the correct file to use even if one of the + processes was interrupted before completing its task. + + + + + + + HISTORY + + The kea-lfc process was first coded in January + 2015 by the ISC Kea/DHCP team. + + + diff --git a/src/bin/lfc/lfc_controller.cc b/src/bin/lfc/lfc_controller.cc new file mode 100644 index 0000000000..d18247898e --- /dev/null +++ b/src/bin/lfc/lfc_controller.cc @@ -0,0 +1,219 @@ +// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace isc { +namespace lfc { + +/// @brief Defines the application name, it may be used to locate +/// configuration data and appears in log statements. +const char* LFCController::lfc_app_name_ = "DhcpLFC"; + +/// @brief Defines the executable name. +const char* LFCController::lfc_bin_name_ = "kea-lfc"; + +LFCController::LFCController() + : protocol_version_(0), verbose_(false), config_file_(""), previous_file_(""), + copy_file_(""), output_file_(""), finish_file_(""), pid_file_("") { +} + +LFCController::~LFCController() { +} + +void +LFCController::launch(int argc, char* argv[]) { + try { + parseArgs(argc, argv); + } catch (const InvalidUsage& ex) { + usage(ex.what()); + throw; // rethrow it + } +} + +void +LFCController::parseArgs(int argc, char* argv[]) { + int ch; + + opterr = 0; + optind = 1; + while ((ch = getopt(argc, argv, ":46dvVp:i:o:c:f:")) != -1) { + switch (ch) { + case '4': + // Process DHCPv4 lease files. + protocol_version_ = 4; + break; + + case '6': + // Process DHCPv6 lease files. + protocol_version_ = 6; + break; + + case 'v': + // Print just Kea vesion and exit. + std::cout << getVersion(false) << std::endl; + exit(EXIT_SUCCESS); + + case 'V': + // Print extended Kea vesion and exit. + std::cout << getVersion(true) << std::endl; + exit(EXIT_SUCCESS); + + case 'd': + // Verbose output. + verbose_ = true; + break; + + case 'p': + // Previous file name. + if (optarg == NULL) { + isc_throw(InvalidUsage, "Previous file name missing"); + } + previous_file_ = optarg; + break; + + case 'i': + // Copy file name. + if (optarg == NULL) { + isc_throw(InvalidUsage, "Copy file name missing"); + } + copy_file_ = optarg; + break; + + case 'o': + // Output file name. + if (optarg == NULL) { + isc_throw(InvalidUsage, "Output file name missing"); + } + output_file_ = optarg; + break; + + case 'f': + // Output file name. + if (optarg == NULL) { + isc_throw(InvalidUsage, "Finish file name missing"); + } + finish_file_ = optarg; + break; + + case 'c': + // Previous file name. + if (optarg == NULL) { + isc_throw(InvalidUsage, "Configuration file name missing"); + } + config_file_ = optarg; + break; + + case 'h': + usage(""); + exit(EXIT_SUCCESS); + + case '?': + // Unknown argument + isc_throw(InvalidUsage, "Unknown argument"); + + case ':': + // Missing option argument + isc_throw(InvalidUsage, "Missing option argument"); + + default: + // I don't think we should get here as the unknown arguments + // and missing options cases should cover everything else + isc_throw(InvalidUsage, "Invalid command line"); + } + } + + // Check for extraneous parameters. + if (argc > optind) { + isc_throw(InvalidUsage, "Extraneous parameters."); + } + + if (protocol_version_ == 0) { + isc_throw(InvalidUsage, "DHCP version required"); + } + + if (previous_file_.empty()) { + isc_throw(InvalidUsage, "Previous file not specified"); + } + + if (copy_file_.empty()) { + isc_throw(InvalidUsage, "Copy file not specified"); + } + + if (output_file_.empty()) { + isc_throw(InvalidUsage, "Output file not specified"); + } + + if (finish_file_.empty()) { + isc_throw(InvalidUsage, "Finish file not specified"); + } + + if (config_file_.empty()) { + isc_throw(InvalidUsage, "Config file not specified"); + } + + // If verbose is set echo the input information + if (verbose_ == true) { + std::cerr << "Protocol version: DHCPv" << protocol_version_ << std::endl + << "Previous lease file: " << previous_file_ << std::endl + << "Copy lease file: " << copy_file_ << std::endl + << "Output lease file: " << output_file_ << std::endl + << "Finishn file: " << finish_file_ << std::endl + << "Config file: " << config_file_ << std::endl + << "PID file: " << pid_file_ << std::endl; + } +} + +void +LFCController::usage(const std::string& text) { + if (text != "") { + std::cerr << "Usage error: " << text << std::endl; + } + + std::cerr << "Usage: " << lfc_bin_name_ << std::endl + << " [-4|-6] -p file -i file -o file -f file -c file" << std::endl + << " -4 or -6 clean a set of v4 or v6 lease files" << std::endl + << " -p : previous lease file" << std::endl + << " -i : copy of lease file" << std::endl + << " -o : output lease file" << std::endl + << " -f : finish file" << std::endl + << " -c : configuration file" << std::endl + << " -v: print version number and exit" << std::endl + << " -V: print extended version inforamtion and exit" << std::endl + << " -d: optional, verbose output " << std::endl + << " -h: print this message " << std::endl + << std::endl; +} + +std::string +LFCController::getVersion(const bool extended) const{ + std::stringstream version_stream; + + version_stream << VERSION; + if (extended) { + version_stream << std::endl << EXTENDED_VERSION; + } + + return (version_stream.str()); +} + +}; // namespace isc::lfc +}; // namespace isc diff --git a/src/bin/lfc/lfc_controller.h b/src/bin/lfc/lfc_controller.h new file mode 100644 index 0000000000..84f42d7f9f --- /dev/null +++ b/src/bin/lfc/lfc_controller.h @@ -0,0 +1,166 @@ +// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#ifndef LFC_CONTROLLER_H +#define LFC_CONTROLLER_H + +#include +#include + +namespace isc { +namespace lfc { + +/// @brief Exception thrown when the command line is invalid. +class InvalidUsage : public isc::Exception { +public: + InvalidUsage(const char* file, size_t line, const char* what) : + isc::Exception(file, line, what) { }; +}; + +/// @brief Process controller for LFC process +/// +/// This class provides the LFC process functions. These are used to: +/// manage the command line, check for already running instances, +/// invoke the code to process the lease files and finally to rename +/// the lease files as necessary. +/// +/// @todo The current code simply processes the command line we still need to +/// -# handle PID file manipulation +/// -# invoke the code to read, process and write the lease files +/// -# rename and delete the shell files as required +class LFCController { +public: + /// @brief Defines the application name, it may be used to locate + /// configuration data and appears in log statements. + static const char* lfc_app_name_; + + /// @brief Defines the executable name, by convention this should match + /// the executable name. + static const char* lfc_bin_name_; + + /// @brief Constructor + LFCController(); + + /// @brief Destructor + ~LFCController(); + + /// @brief Acts as the primary entry point to start execution + /// of the process. Provides the control logic: + /// + /// -# parse command line arguments + /// -# verifies that it is the only instance + /// -# creates pid file (TBD) + /// -# .... TBD + /// -# remove pid file (TBD) + /// -# exit to the caller + /// + /// @param argc Number of strings in the @c argv array. + /// @param argv Array of arguments passed in via the program's main function. + /// + /// @throw InvalidUsage if the command line parameters are invalid. + void launch(int argc, char* argv[]); + + /// @brief Process the command line arguments. It is the first + /// step taken after the process has been launched. + /// + /// @param argc Number of strings in the @c argv array. + /// @param argv Array of arguments passed in via the program's main function. + /// + /// @throw InvalidUsage if the command line parameters are invalid. + void parseArgs(int argc, char* argv[]); + + /// @brief Prints the program usage text to std error. + /// + /// @param text is a string message which will preceded the usage text. + /// This is intended to be used for specific usage violation messages. + void usage(const std::string& text); + + /// @brief Gets the Kea version number for printing + /// + /// @param extended is a boolean indicating if the version string + /// should be short (false) or extended (true) + std::string getVersion(const bool extended) const; + + /// @name Accessor methods mainly used for testing purposes + //@{ + + /// @brief Gets the protocol version of the leaes files + /// + /// @return Returns the value of the DHCP protocol version. + /// This can be 4 or 6 while in use and 0 before parsing + /// any arguments. + int getProtocolVersion() const { + return (protocol_version_); + } + + /// @brief Gets the config file name + /// + /// @return Returns the path to the config file + std::string getConfigFile() const { + return (config_file_); + } + + /// @brief Gets the prevous file name + /// + /// @return Returns the path to the previous file + std::string getPreviousFile() const { + return (previous_file_); + } + + /// @brief Gets the copy file name + /// + /// @return Returns the path to the copy file + std::string getCopyFile() const { + return (copy_file_); + } + + /// @brief Gets the output file name + /// + /// @return Returns the path to the output file + std::string getOutputFile() const { + return (output_file_); + } + + /// @brief Gets the finish file name + /// + /// @return Returns the path to the finish file + std::string getFinishFile() const { + return (finish_file_); + } + + /// @brief Gets the pid file name + /// + /// @return Returns the path to the pid file + std::string getPidFile() const { + return (pid_file_); + } + //@} + +private: + /// Version of the DHCP protocol used, i.e. 4 or 6. + int protocol_version_; + /// When true output the result of parsing the comamnd line + bool verbose_; + std::string config_file_; ///< The path to the config file + std::string previous_file_; ///< The path to the previous LFC file (if any) + std::string copy_file_; ///< The path to the copy of the lease file + std::string output_file_; ///< The path to the output file + std::string finish_file_; ///< The path to the finished output file + std::string pid_file_; ///< The path to the pid file +}; + +}; // namespace isc::lfc +}; // namespace isc + +#endif // LFC_CONTROLLER_H diff --git a/src/bin/lfc/lfc_messages.mes b/src/bin/lfc/lfc_messages.mes new file mode 100644 index 0000000000..94c6f46373 --- /dev/null +++ b/src/bin/lfc/lfc_messages.mes @@ -0,0 +1,17 @@ +# Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. + +$NAMESPACE isc::lfc +% LFC_TEST_MESSAGE test messages +This is a test and placeholder debug message diff --git a/src/bin/lfc/main.cc b/src/bin/lfc/main.cc new file mode 100644 index 0000000000..c1da3e9ac8 --- /dev/null +++ b/src/bin/lfc/main.cc @@ -0,0 +1,46 @@ +// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include +#include +#include +#include +#include +#include + +using namespace isc::lfc; +using namespace std; + +/// This file contains the entry point (main() function) for the +/// standard LFC process, kea-lfc, component of the Kea software suite. +/// It creates an instance of the LFCController class and invokes +/// its launch method. +/// The exit value of the program will be EXIT_SUCCESS if there were no +/// errors, EXIT_FAILURE otherwise. +int main(int argc, char* argv[]) { + int ret = EXIT_SUCCESS; + LFCController lfc_controller; + + // Launch the controller passing in command line arguments. + // Exit program with the controller's return code. + try { + // 'false' value disables test mode. + lfc_controller.launch(argc, argv); + } catch (const isc::Exception& ex) { + std::cerr << "Service failed: " << ex.what() << std::endl; + ret = EXIT_FAILURE; + } + + return (ret); +} diff --git a/src/bin/lfc/tests/.gitignore b/src/bin/lfc/tests/.gitignore new file mode 100644 index 0000000000..bfcb578d00 --- /dev/null +++ b/src/bin/lfc/tests/.gitignore @@ -0,0 +1 @@ +/lfc_unittests diff --git a/src/bin/lfc/tests/Makefile.am b/src/bin/lfc/tests/Makefile.am new file mode 100644 index 0000000000..9e799a2d81 --- /dev/null +++ b/src/bin/lfc/tests/Makefile.am @@ -0,0 +1,63 @@ +SHTESTS = + +noinst_SCRIPTS = + +EXTRA_DIST = + +# test using command-line arguments, so use check-local target instead of TESTS +check-local: + for shtest in $(SHTESTS) ; do \ + echo Running test: $$shtest ; \ + export KEA_LOCKFILE_DIR=$(abs_top_builddir); \ + ${SHELL} $(abs_builddir)/$$shtest || exit ; \ + done + +AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib +AM_CPPFLAGS += -I$(top_builddir)/src/bin # for generated spec_config.h header +AM_CPPFLAGS += -I$(top_srcdir)/src/bin +AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc +AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink +AM_CPPFLAGS += $(BOOST_INCLUDES) +AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_top_srcdir)/src/lib/testutils/testdata\" +AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/bin/lfc/tests\" +AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\" + +CLEANFILES = $(builddir)/interfaces.txt $(builddir)/logger_lockfile + +DISTCLEANFILES = + +AM_CXXFLAGS = $(KEA_CXXFLAGS) +if USE_CLANGPP +# Disable unused parameter warning caused by some Boost headers when compiling with clang +AM_CXXFLAGS += -Wno-unused-parameter +endif + +if USE_STATIC_LINK +AM_LDFLAGS = -static +endif + +TESTS_ENVIRONMENT = \ + $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) + +TESTS = +if HAVE_GTEST + +TESTS += lfc_unittests + +lfc_unittests_SOURCES = lfc_unittests.cc +lfc_unittests_SOURCES += lfc_controller_unittests.cc + +lfc_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) +lfc_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) +lfc_unittests_LDADD = $(GTEST_LDADD) +lfc_unittests_LDADD += $(top_builddir)/src/bin/lfc/liblfc.la +lfc_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la +lfc_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la +lfc_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la +lfc_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la +lfc_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la +lfc_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la + +endif + +noinst_PROGRAMS = $(TESTS) diff --git a/src/bin/lfc/tests/lfc_controller_unittests.cc b/src/bin/lfc/tests/lfc_controller_unittests.cc new file mode 100644 index 0000000000..163a1606b0 --- /dev/null +++ b/src/bin/lfc/tests/lfc_controller_unittests.cc @@ -0,0 +1,156 @@ +// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include +#include + +using namespace isc::lfc; +using namespace std; + +namespace { + +/// @brief Verify initial state of LFC controller. +/// Create an instance of the controller and see that +/// all of the initial values are empty as expected. +TEST(LFCControllerTest, initialValues) { + LFCController lfc_controller; + + // Verify that we start with all the private variables empty + EXPECT_EQ(lfc_controller.getProtocolVersion(), 0); + EXPECT_TRUE(lfc_controller.getConfigFile().empty()); + EXPECT_TRUE(lfc_controller.getPreviousFile().empty()); + EXPECT_TRUE(lfc_controller.getCopyFile().empty()); + EXPECT_TRUE(lfc_controller.getOutputFile().empty()); + EXPECT_TRUE(lfc_controller.getFinishFile().empty()); + EXPECT_TRUE(lfc_controller.getPidFile().empty()); +} + +/// @brief Verify that parsing a full command line works. +/// Parse a complete command line then verify the parsed +/// and saved data matches our expectations. +TEST(LFCControllerTest, fullCommandLine) { + LFCController lfc_controller; + + // Verify that standard options can be parsed without error + char* argv[] = { const_cast("progName"), + const_cast("-4"), + const_cast("-p"), + const_cast("previous"), + const_cast("-i"), + const_cast("copy"), + const_cast("-o"), + const_cast("output"), + const_cast("-c"), + const_cast("config"), + const_cast("-f"), + const_cast("finish") }; + int argc = 12; + + ASSERT_NO_THROW(lfc_controller.parseArgs(argc, argv)); + + // Check all the parsed data from above to the known values + EXPECT_EQ(lfc_controller.getProtocolVersion(), 4); + EXPECT_EQ(lfc_controller.getConfigFile(), "config"); + EXPECT_EQ(lfc_controller.getPreviousFile(), "previous"); + EXPECT_EQ(lfc_controller.getCopyFile(), "copy"); + EXPECT_EQ(lfc_controller.getOutputFile(), "output"); + EXPECT_EQ(lfc_controller.getFinishFile(), "finish"); +} + +/// @brief Verify that parsing a correct but incomplete line fails. +/// Parse a command line that is correctly formatted but isn't complete +/// (doesn't include some options or an some option arguments). We +/// expect that the parse will fail with an InvalidUsage exception. +TEST(LFCControllerTest, notEnoughData) { + LFCController lfc_controller; + + // Test the results if we don't include all of the required arguments + // This argument list is correct but we shall only suppy part of it + // to the parse routine via the argc variable. + char* argv[] = { const_cast("progName"), + const_cast("-4"), + const_cast("-p"), + const_cast("previous"), + const_cast("-i"), + const_cast("copy"), + const_cast("-o"), + const_cast("output"), + const_cast("-c"), + const_cast("config"), + const_cast("-f"), + const_cast("finish") }; + + int argc = 1; + + for (; argc < 12; ++argc) { + EXPECT_THROW(lfc_controller.parseArgs(argc, argv), InvalidUsage) + << "test failed for argc = " << argc; + } + + // Verify we can still parse the full string properly + ASSERT_NO_THROW(lfc_controller.parseArgs(argc, argv)); +} + +/// @brief Verify that extra arguments cause the parse to fail. +/// Parse a full command line plus some extra arguments on the end +/// to verify that we don't stop parsing when we find all of the +/// required arguments. We exepct the parse to fail with an +/// InvalidUsage exception. +TEST(LFCControllerTest, tooMuchData) { + LFCController lfc_controller; + + // The standard options plus some others + + char* argv[] = { const_cast("progName"), + const_cast("-4"), + const_cast("-p"), + const_cast("previous"), + const_cast("-i"), + const_cast("copy"), + const_cast("-o"), + const_cast("output"), + const_cast("-c"), + const_cast("config"), + const_cast("-f"), + const_cast("finish"), + const_cast("some"), + const_cast("other"), + const_cast("args"), + }; + int argc = 15; + + // We expect an error as we have arguments that aren't valid + EXPECT_THROW(lfc_controller.parseArgs(argc, argv), InvalidUsage); +} + +/// @brief Verify that unknown arguments cause the parse to fail. +/// Parse some unknown arguments to verify that we generate the +/// proper InvalidUsage exception. +TEST(LFCControllerTest, someBadData) { + LFCController lfc_controller; + + // Some random arguments + + char* argv[] = { const_cast("progName"), + const_cast("some"), + const_cast("bad"), + const_cast("args"), + }; + int argc = 4; + + // We expect an error as the arguments aren't valid + EXPECT_THROW(lfc_controller.parseArgs(argc, argv), InvalidUsage); +} + +} // end of anonymous namespace diff --git a/src/bin/lfc/tests/lfc_unittests.cc b/src/bin/lfc/tests/lfc_unittests.cc new file mode 100644 index 0000000000..a2bb34bc26 --- /dev/null +++ b/src/bin/lfc/tests/lfc_unittests.cc @@ -0,0 +1,30 @@ +// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include +#include + +int +main(int argc, char* argv[]) { + + ::testing::InitGoogleTest(&argc, argv); + + // See the documentation of the KEA_* environment variables in + // src/lib/log/README for info on how to tweak logging + isc::log::initLogger(); + + int result = RUN_ALL_TESTS(); + + return (result); +}