Browse Source

Merge branch 'trac3664' Add base LFC process code

This merge adds the basic code for handling lease file cleanup (LFC).
It provides the basic framework for the process as well as code to
do argument parsing.
Shawn Routhier 10 years ago
parent
commit
cc85938b35

+ 2 - 0
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

+ 1 - 0
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 \

+ 1 - 1
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

+ 5 - 0
src/bin/lfc/.gitignore

@@ -0,0 +1,5 @@
+/kea-lfc
+/kea-lfc.8
+/lfc_messages.cc
+/lfc_messages.h
+/s-messages

+ 68 - 0
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)

+ 184 - 0
src/bin/lfc/kea-lfc.xml

@@ -0,0 +1,184 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+               "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+               [<!ENTITY mdash "&#8212;">]>
+<!--
+ - 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.
+-->
+
+<refentry>
+
+  <refentryinfo>
+    <date>Feb 1, 2015</date>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>kea-lfc</refentrytitle>
+    <manvolnum>8</manvolnum>
+    <refmiscinfo>Kea</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>kea-lfc</refname>
+    <refpurpose>Lease File Cleanup  process in Kea</refpurpose>
+  </refnamediv>
+
+  <docinfo>
+    <copyright>
+      <year>2015</year>
+      <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+    </copyright>
+  </docinfo>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>kea-lfc</command>
+      <arg><option>-4|-6</option></arg>
+      <arg><option>-c <replaceable class="parameter">config-file</replaceable></option></arg>
+      <arg><option>-p <replaceable class="parameter">previous-file</replaceable></option></arg>
+      <arg><option>-i <replaceable class="parameter">copy-file</replaceable></option></arg>
+      <arg><option>-o <replaceable class="parameter">output-file</replaceable></option></arg>
+      <arg><option>-f <replaceable class="parameter">finish-file</replaceable></option></arg>
+      <arg><option>-v</option></arg>
+      <arg><option>-V</option></arg>
+      <arg><option>-d</option></arg>
+      <arg><option>-h</option></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+    <para>
+      The <command>kea-lfc</command> 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.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>ARGUMENTS</title>
+
+    <para>The arguments are as follows:</para>
+
+    <variablelist>
+
+      <varlistentry>
+        <term><option>-d</option></term>
+        <listitem><para>
+          Verbose mode sets the logging level to debug. This is primarily
+          for development purposes in stand-alone mode.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-v</option></term>
+        <listitem><para>
+          version causes the version stamp to be printed.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-V</option></term>
+        <listitem><para>
+          Version causes a longer form of the version stamp to be printed.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-h</option></term>
+        <listitem><para>
+          Help causes the usage string to be printed.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-4 | -6</option></term>
+        <listitem><para>
+          The protocol version of the lease files, must be one of 4 or 6.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-c</option></term>
+        <listitem><para>
+          Configuration file including the configuration for
+          <command>kea-lfc</command> process.  It may also
+          contain configuration entries for other Kea services.
+          Currently <command>kea-lfc</command> gets all of its arguments from 
+          the comamnd line, in the future it will be extended to get some arguments
+          from the config file.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-p</option></term>
+        <listitem><para>
+          Previous lease file - When <command>kea-lfc</command> starts this
+          is the result of any previous run of <command>kea-lfc</command>.
+          When <command>kea-lfc</command> finishes it is the result of this run.
+          If <command>kea-lfc</command> is interrupted before compelting
+          this file may not exist.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-i</option></term>
+        <listitem><para>
+          Input or copy of lease file - Before the DHCP server invokes
+          <command>kea-lfc</command> it will copy the current lease file
+          here and then call <command>kea-lfc</command> with this file.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-o</option></term>
+        <listitem><para>
+          Output lease file - The temporary file <command>kea-lfc</command>
+          should use to write the leases.  Upon completion of writing this
+          this file it will be moved to the finish file (see below).
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-f</option></term>
+        <listitem><para>
+          Finish or completion file - Another temporary file
+          <command>kea-lfc</command> uses for bookkeeping.  When
+          <command>kea-lfc</command> completes writing the output
+          file it moves it to this file name.  After
+          <command>kea-lfc</command> finishes deleting the other
+          files (previous and input) it moves this file to previous
+          lease file.  By moving the files in this fashion the
+          <command>kea-lfc</command> and the DHCP server processes
+          can determine the correct file to use even if one of the
+          processes was interrupted before completing its task.
+        </para></listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>HISTORY</title>
+    <para>
+      The <command>kea-lfc</command> process was first coded in January
+      2015 by the ISC Kea/DHCP team.
+    </para>
+  </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->

+ 219 - 0
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 <lfc/lfc_controller.h>
+#include <exceptions/exceptions.h>
+#include <config.h>
+#include <iostream>
+#include <sstream>
+#include <unistd.h>
+
+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 <file>: previous lease file" << std::endl
+              << "   -i <file>: copy of lease file" << std::endl
+              << "   -o <file>: output lease file" << std::endl
+              << "   -f <file>: finish file" << std::endl
+              << "   -c <file>: 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

+ 166 - 0
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 <exceptions/exceptions.h>
+#include <string>
+
+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

+ 17 - 0
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

+ 46 - 0
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 <lfc/lfc_controller.h>
+#include <exceptions/exceptions.h>
+#include <log/logger_support.h>
+#include <log/logger_manager.h>
+#include <config.h>
+#include <iostream>
+
+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);
+}

+ 1 - 0
src/bin/lfc/tests/.gitignore

@@ -0,0 +1 @@
+/lfc_unittests

+ 63 - 0
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)

+ 156 - 0
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 <lfc/lfc_controller.h>
+#include <gtest/gtest.h>
+
+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<char*>("progName"),
+                     const_cast<char*>("-4"),
+                     const_cast<char*>("-p"),
+                     const_cast<char*>("previous"),
+                     const_cast<char*>("-i"),
+                     const_cast<char*>("copy"),
+                     const_cast<char*>("-o"),
+                     const_cast<char*>("output"),
+                     const_cast<char*>("-c"),
+                     const_cast<char*>("config"),
+                     const_cast<char*>("-f"),
+                     const_cast<char*>("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<char*>("progName"),
+                     const_cast<char*>("-4"),
+                     const_cast<char*>("-p"),
+                     const_cast<char*>("previous"),
+                     const_cast<char*>("-i"),
+                     const_cast<char*>("copy"),
+                     const_cast<char*>("-o"),
+                     const_cast<char*>("output"),
+                     const_cast<char*>("-c"),
+                     const_cast<char*>("config"),
+                     const_cast<char*>("-f"),
+                     const_cast<char*>("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<char*>("progName"),
+                     const_cast<char*>("-4"),
+                     const_cast<char*>("-p"),
+                     const_cast<char*>("previous"),
+                     const_cast<char*>("-i"),
+                     const_cast<char*>("copy"),
+                     const_cast<char*>("-o"),
+                     const_cast<char*>("output"),
+                     const_cast<char*>("-c"),
+                     const_cast<char*>("config"),
+                     const_cast<char*>("-f"),
+                     const_cast<char*>("finish"),
+                     const_cast<char*>("some"),
+                     const_cast<char*>("other"),
+                     const_cast<char*>("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<char*>("progName"),
+                     const_cast<char*>("some"),
+                     const_cast<char*>("bad"),
+                     const_cast<char*>("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

+ 30 - 0
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 <log/logger_support.h>
+#include <gtest/gtest.h>
+
+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);
+}