Browse Source

[3399] Kea configuration backend for DHCPv4

Tomek Mrugalski 11 years ago
parent
commit
e6b9ed0da8
2 changed files with 150 additions and 6 deletions
  1. 143 0
      src/bin/dhcp4/kea_controller.cc
  2. 7 6
      src/bin/dhcp4/tests/kea_controller_unittest.cc

+ 143 - 0
src/bin/dhcp4/kea_controller.cc

@@ -0,0 +1,143 @@
+// Copyright (C) 2014 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 <config.h>
+
+#include <asiolink/asiolink.h>
+#include <dhcp/iface_mgr.h>
+#include <dhcpsrv/dhcp_config_parser.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcp4/json_config_parser.h>
+#include <dhcp4/ctrl_dhcp4_srv.h>
+#include <dhcp4/dhcp4_log.h>
+#include <dhcp4/spec_config.h>
+#include <log/logger_level.h>
+#include <log/logger_name.h>
+#include <log/logger_manager.h>
+#include <log/logger_specification.h>
+#include <log/logger_support.h>
+#include <log/output_option.h>
+#include <exceptions/exceptions.h>
+#include <util/buffer.h>
+
+#include <cassert>
+#include <iostream>
+#include <string>
+#include <vector>
+
+using namespace isc::asiolink;
+using namespace isc::cc;
+using namespace isc::config;
+using namespace isc::data;
+using namespace isc::dhcp;
+using namespace isc::log;
+using namespace isc::util;
+using namespace std;
+
+namespace isc {
+namespace dhcp {
+
+void
+ControlledDhcpv4Srv::init(const std::string& file_name) {
+    // This is a configuration backend implementation that reads the
+    // configuration from a JSON file.
+
+    isc::data::ConstElementPtr json;
+    isc::data::ConstElementPtr dhcp4;
+    isc::data::ConstElementPtr result;
+
+    // Basic sanity check: file name must not be empty.
+    try {
+        if (file_name.empty()) {
+            // Basic sanity check: file name must not be empty.
+            isc_throw(BadValue, "JSON configuration file not specified. Please "
+                      "use -c command line option.");
+        }
+
+        // Read contents of the file and parse it as JSON
+        json = Element::fromJSONFile(file_name, true);
+
+        if (!json) {
+            LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL)
+                .arg("Config file " + file_name + " missing or empty.");
+            isc_throw(BadValue, "Unable to process JSON configuration file:"
+                      + file_name);
+        }
+
+        // Get Dhcp4 component from the config
+        dhcp4 = json->get("Dhcp4");
+
+        if (!dhcp4) {
+            LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL)
+                .arg("Config file " + file_name + " does not include 'Dhcp4' entry.");
+            isc_throw(BadValue, "Unable to process JSON configuration file:"
+                      + file_name);
+        }
+
+        // Use parsed JSON structures to configure the server
+        result = processCommand("config-reload", dhcp4);
+
+    }  catch (const std::exception& ex) {
+        LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL).arg(ex.what());
+        isc_throw(BadValue, "Unable to process JSON configuration file:"
+                  + file_name);
+    }
+
+    if (!result) {
+        // Undetermined status of the configuration. This should never happen,
+        // but as the configureDhcp4Server returns a pointer, it is theoretically
+        // possible that it will return NULL.
+        LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL)
+            .arg("Configuration failed: Undefined result of configureDhcp4Server"
+                 "() function after attempting to read " + file_name);
+        return;
+    }
+
+    // Now check is the returned result is successful (rcode=0) or not
+    ConstElementPtr comment; /// see @ref isc::config::parseAnswer
+    int rcode;
+    comment = parseAnswer(rcode, result);
+    if (rcode != 0) {
+        string reason = "";
+        if (comment) {
+            reason = string(" (") + comment->stringValue() + string(")");
+        }
+        LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL).arg(reason);
+        isc_throw(BadValue, "Failed to apply configuration:" << reason);
+    }
+
+    // We don't need to call openActiveSockets() or startD2() as these
+    // methods are called in processConfig() which is called by
+    // processCommand("reload-config", ...)
+}
+
+void ControlledDhcpv4Srv::cleanup() {
+    // Nothing to do here. No need to disconnect from anything.
+}
+
+/// This is a logger initialization for JSON file backend.
+/// For now, it's just setting log messages to be printed on stdout.
+/// @todo: Implement this properly (see #3427)
+void Daemon::loggerInit(const char*, bool verbose, bool ) {
+
+    setenv("B10_LOCKFILE_DIR_FROM_BUILD", "/tmp", 1);
+    setenv("B10_LOGGER_ROOT", "kea", 0);
+    setenv("B10_LOGGER_SEVERITY", (verbose ? "DEBUG":"INFO"), 0);
+    setenv("B10_LOGGER_DBGLEVEL", "99", 0);
+    setenv("B10_LOGGER_DESTINATION",  "stdout", 0);
+    isc::log::initLogger();
+}
+
+};
+};

+ 7 - 6
src/bin/dhcp4/tests/kea_controller_unittest.cc

@@ -16,7 +16,7 @@
 
 #include <config/ccsession.h>
 #include <dhcp/dhcp4.h>
-#include <dhcp6/ctrl_dhcp4_srv.h>
+#include <dhcp4/ctrl_dhcp4_srv.h>
 #include <dhcpsrv/cfgmgr.h>
 
 #include <boost/scoped_ptr.hpp>
@@ -73,7 +73,7 @@ const char* JSONFileBackendTest::TEST_FILE = "test-config.json";
 TEST_F(JSONFileBackendTest, jsonFile) {
 
     // Prepare configuration file.
-    string config = "{ \"interfaces\": [ \"*\" ],"
+    string config = "{ \"Dhcp4\": { \"interfaces\": [ \"*\" ],"
         "\"rebind-timer\": 2000, "
         "\"renew-timer\": 1000, "
         "\"subnet4\": [ { "
@@ -89,7 +89,8 @@ TEST_F(JSONFileBackendTest, jsonFile) {
         "    \"pool\": [ \"192.0.4.101 - 192.0.4.150\" ],"
         "    \"subnet\": \"192.0.4.0/24\" "
         " } ],"
-        "\"valid-lifetime\": 4000 }";
+        "\"valid-lifetime\": 4000 }"
+        "}";
 
     writeFile(TEST_FILE, config);
 
@@ -138,7 +139,7 @@ TEST_F(JSONFileBackendTest, jsonFile) {
     const PoolCollection& pools3 = subnets->at(2)->getPools(Lease::TYPE_V4);
     EXPECT_EQ("192.0.4.101", pools3.at(0)->getFirstAddress().toText());
     EXPECT_EQ("192.0.4.150", pools3.at(0)->getLastAddress().toText());
-    EXPECT_EQ(Lease::TYPE_NA, pools3.at(0)->getType());
+    EXPECT_EQ(Lease::TYPE_V4, pools3.at(0)->getType());
 }
 
 // This test checks if configuration can be read from a JSON file.
@@ -181,11 +182,11 @@ TEST_F(JSONFileBackendTest, comments) {
     EXPECT_EQ(22, subnets->at(0)->get().second);
 
     // Check pools in the first subnet.
-    const PoolCollection& pools1 = subnets->at(0)->getPools(Lease::TYPE_NA);
+    const PoolCollection& pools1 = subnets->at(0)->getPools(Lease::TYPE_V4);
     ASSERT_EQ(1, pools1.size());
     EXPECT_EQ("192.0.2.0", pools1.at(0)->getFirstAddress().toText());
     EXPECT_EQ("192.0.2.255", pools1.at(0)->getLastAddress().toText());
-    EXPECT_EQ(Lease::TYPE_NA, pools1.at(0)->getType());
+    EXPECT_EQ(Lease::TYPE_V4, pools1.at(0)->getType());
 }
 
 // This test checks if configuration detects failure when trying: