Browse Source

[2269] dhcp6 config parser now returns status codes and does not throw.

Tomek Mrugalski 12 years ago
parent
commit
7e7171deec
3 changed files with 93 additions and 19 deletions
  1. 88 18
      src/bin/dhcp6/config_parser.cc
  2. 1 1
      src/bin/dhcp6/config_parser.h
  3. 4 0
      src/bin/dhcp6/dhcp6_messages.mes

+ 88 - 18
src/bin/dhcp6/config_parser.cc

@@ -21,16 +21,16 @@
 #include <boost/scoped_ptr.hpp>
 #include <boost/scoped_ptr.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string.hpp>
+#include <asiolink/io_address.h>
 #include <cc/data.h>
 #include <cc/data.h>
 #include <config/ccsession.h>
 #include <config/ccsession.h>
-#include <asiolink/io_address.h>
-#include <dhcp6/config_parser.h>
+#include <log/logger_support.h>
 #include <dhcp/triplet.h>
 #include <dhcp/triplet.h>
 #include <dhcp/pool.h>
 #include <dhcp/pool.h>
 #include <dhcp/subnet.h>
 #include <dhcp/subnet.h>
 #include <dhcp/cfgmgr.h>
 #include <dhcp/cfgmgr.h>
+#include <dhcp6/config_parser.h>
 #include <dhcp6/dhcp6_log.h>
 #include <dhcp6/dhcp6_log.h>
-#include <log/logger_support.h>
 
 
 using namespace std;
 using namespace std;
 using namespace isc::data;
 using namespace isc::data;
@@ -43,9 +43,7 @@ typedef boost::shared_ptr<Dhcp6ConfigParser> ParserPtr;
 typedef pair<string, ConstElementPtr> ConfigPair;
 typedef pair<string, ConstElementPtr> ConfigPair;
 typedef std::vector<ParserPtr> ParserCollection;
 typedef std::vector<ParserPtr> ParserCollection;
 typedef Dhcp6ConfigParser* ParserFactory(const std::string& config_id);
 typedef Dhcp6ConfigParser* ParserFactory(const std::string& config_id);
-
 typedef std::map<std::string, ParserFactory*> FactoryMap;
 typedef std::map<std::string, ParserFactory*> FactoryMap;
-
 typedef std::map<string, uint32_t> Uint32Storage;
 typedef std::map<string, uint32_t> Uint32Storage;
 /// @brief That is a map with global parameters that will be used as defaults
 /// @brief That is a map with global parameters that will be used as defaults
 Uint32Storage uint32_defaults;
 Uint32Storage uint32_defaults;
@@ -54,23 +52,40 @@ typedef std::map<string, string> StringStorage;
 StringStorage string_defaults;
 StringStorage string_defaults;
 
 
 typedef std::vector<Pool6Ptr> PoolStorage;
 typedef std::vector<Pool6Ptr> PoolStorage;
-PoolStorage pool_defaults;
 
 
 /// @brief a dummy configuration parser
 /// @brief a dummy configuration parser
 ///
 ///
 /// It is a debugging parser. It does not configure anything,
 /// It is a debugging parser. It does not configure anything,
 /// will accept any configuration and will just print it out
 /// will accept any configuration and will just print it out
-/// on commit.
+/// on commit. Useful for debugging existing configurations and
+/// adding new ones.
 class DummyParser : public Dhcp6ConfigParser {
 class DummyParser : public Dhcp6ConfigParser {
 public:
 public:
+
+    /// @brief Constructor
+    ///
+    /// See \ref Dhcp6ConfigParser class for details.
+    ///
+    /// @param param_name name of the parsed parameter
     DummyParser(const std::string& param_name)
     DummyParser(const std::string& param_name)
         :param_name_(param_name) {
         :param_name_(param_name) {
     }
     }
+
+    /// @brief builds parameter value
+    ///
+    /// See \ref Dhcp6ConfigParser class for details.
     virtual void build(ConstElementPtr new_config) {
     virtual void build(ConstElementPtr new_config) {
         std::cout << "Build for token: [" << param_name_ << "] = ["
         std::cout << "Build for token: [" << param_name_ << "] = ["
                   << value_->str() << "]" << std::endl;
                   << value_->str() << "]" << std::endl;
         value_ = new_config;
         value_ = new_config;
     }
     }
+
+    /// @brief pretends to apply the configuration
+    ///
+    /// This is a method required by base class. It pretends to apply the
+    /// configuration, but in fact it only prints the parameter out.
+    ///
+    /// See \ref Dhcp6ConfigParser class for details.
     virtual void commit() {
     virtual void commit() {
         // Debug message. The whole DummyParser class is used only for parser
         // Debug message. The whole DummyParser class is used only for parser
         // debugging, and is not used in production code. It is very convenient
         // debugging, and is not used in production code. It is very convenient
@@ -79,21 +94,45 @@ public:
                   << value_->str() << "]" << std::endl;
                   << value_->str() << "]" << std::endl;
     }
     }
 
 
+    /// @brief factory that constructs DummyParser objects
+    ///
+    /// @param param_name name of the parameter to be parsed
     static Dhcp6ConfigParser* Factory(const std::string& param_name) {
     static Dhcp6ConfigParser* Factory(const std::string& param_name) {
         return (new DummyParser(param_name));
         return (new DummyParser(param_name));
     }
     }
 
 
 protected:
 protected:
+    /// name of the parsed parameter
     std::string param_name_;
     std::string param_name_;
+
+    /// pointer to the actual value of the parameter
     ConstElementPtr value_;
     ConstElementPtr value_;
 };
 };
 
 
+/// @brief Configuration parser for uint32 types
+///
+/// This class is a generic parser that is able to handle any uint32 integer
+/// type. By default it stores the value in external global container
+/// (uint32_defaults). If used in smaller scopes (e.g. to parse parameters
+/// in subnet config), it can be pointed to a different storage, using
+/// setStorage() method. This class follows the parser interface, laid out
+/// in its base class, \ref Dhcp6ConfigParser.
+
 class Uint32Parser : public Dhcp6ConfigParser {
 class Uint32Parser : public Dhcp6ConfigParser {
 public:
 public:
+
+    /// @brief constructor for Uint32Parser
+    /// @param param_name name of the parameter that is going to be parsed
     Uint32Parser(const std::string& param_name)
     Uint32Parser(const std::string& param_name)
         :storage_(&uint32_defaults), param_name_(param_name) {
         :storage_(&uint32_defaults), param_name_(param_name) {
     }
     }
 
 
+    /// @brief builds parameter value
+    ///
+    /// Parses configuration entry and stored it in storage. See
+    /// \ref setStorage() for details.
+    ///
+    /// @param value pointer to the content of parsed values
     virtual void build(ConstElementPtr value) {
     virtual void build(ConstElementPtr value) {
         try {
         try {
             value_ = boost::lexical_cast<uint32_t>(value->str());
             value_ = boost::lexical_cast<uint32_t>(value->str());
@@ -104,9 +143,20 @@ public:
         storage_->insert(pair<string, uint32_t>(param_name_, value_));
         storage_->insert(pair<string, uint32_t>(param_name_, value_));
     }
     }
 
 
+    /// @brief does nothing
+    ///
+    /// This method is required for all parser. The value itself
+    /// is not commited anywhere. Higher level parsers are expected to
+    /// use values stored in the storage, e.g. renew-timer for a given
+    /// subnet is stored in subnet-specific storage. It is not commited
+    /// here, but is rather used by \ref Subnet6Parser when constructing
+    /// the subnet.
     virtual void commit() {
     virtual void commit() {
     }
     }
 
 
+    /// @brief factory that constructs DummyParser objects
+    ///
+    /// @param param_name name of the parameter to be parsed
     static Dhcp6ConfigParser* Factory(const std::string& param_name) {
     static Dhcp6ConfigParser* Factory(const std::string& param_name) {
         return (new Uint32Parser(param_name));
         return (new Uint32Parser(param_name));
     }
     }
@@ -325,13 +375,18 @@ public:
         Triplet<uint32_t> valid = getParam("valid-lifetime");
         Triplet<uint32_t> valid = getParam("valid-lifetime");
 
 
         /// @todo: Convert this to logger once the parser is working reliably
         /// @todo: Convert this to logger once the parser is working reliably
-        cout << "Adding subnet " << addr.toText() << "/" << (int)len
-             << " with params t1=" << t1 << ", t2=" << t2 << ", pref="
-             << pref << ", valid=" << valid << endl;
+        stringstream tmp;
+        tmp << addr.toText() << "/" << (int)len
+            << " with params t1=" << t1 << ", t2=" << t2 << ", pref="
+            << pref << ", valid=" << valid;
 
 
-        Subnet6Ptr subnet(new Subnet6(addr, len, t1, t2, pref, valid));
+        LOG_INFO(dhcp6_logger, DHCP6_CONFIG_NEW_SUBNET).arg(tmp.str());
 
 
+        Subnet6Ptr subnet(new Subnet6(addr, len, t1, t2, pref, valid));
 
 
+        for (PoolStorage::iterator it = pools_.begin(); it != pools_.end(); ++it) {
+            subnet->addPool6(*it);
+        }
 
 
         CfgMgr::instance().addSubnet6(subnet);
         CfgMgr::instance().addSubnet6(subnet);
     }
     }
@@ -418,6 +473,12 @@ public:
     }
     }
 
 
     void commit() {
     void commit() {
+        // @todo: Implement more subtle reconfiguration than toss
+        // the old one and replace with the new one.
+
+        // remove old subnets
+        CfgMgr::instance().deleteSubnets6();
+
         BOOST_FOREACH(ParserPtr subnet, subnets_) {
         BOOST_FOREACH(ParserPtr subnet, subnets_) {
             subnet->commit();
             subnet->commit();
         }
         }
@@ -469,7 +530,7 @@ Dhcp6ConfigParser* createGlobalDhcp6ConfigParser(const std::string& config_id) {
 }
 }
 
 
 ConstElementPtr
 ConstElementPtr
-configureDhcp6Server(Dhcpv6Srv& server, ConstElementPtr config_set) {
+configureDhcp6Server(Dhcpv6Srv& , ConstElementPtr config_set) {
     if (!config_set) {
     if (!config_set) {
         isc_throw(Dhcp6ConfigError,
         isc_throw(Dhcp6ConfigError,
                   "Null pointer is passed to configuration parser");
                   "Null pointer is passed to configuration parser");
@@ -488,20 +549,29 @@ configureDhcp6Server(Dhcpv6Srv& server, ConstElementPtr config_set) {
             parser->build(config_pair.second);
             parser->build(config_pair.second);
             parsers.push_back(parser);
             parsers.push_back(parser);
         }
         }
-    } catch (const Dhcp6ConfigError& ex) {
-        throw;                  // simply rethrowing it
     } catch (const isc::Exception& ex) {
     } catch (const isc::Exception& ex) {
-        isc_throw(Dhcp6ConfigError, "Server configuration failed: " <<
-                  ex.what());
+        ConstElementPtr answer = isc::config::createAnswer(1,
+                                 string("Configuration parsing failed:") + ex.what());
+        return (answer);
+    } catch (...) {
+        // for things like bad_cast in boost::lexical_cast
+        ConstElementPtr answer = isc::config::createAnswer(1,
+                                 string("Configuration parsing failed"));
     }
     }
 
 
     try {
     try {
         BOOST_FOREACH(ParserPtr parser, parsers) {
         BOOST_FOREACH(ParserPtr parser, parsers) {
             parser->commit();
             parser->commit();
         }
         }
+    }
+    catch (const isc::Exception& ex) {
+        ConstElementPtr answer = isc::config::createAnswer(2,
+                                 string("Configuration commit failed:") + ex.what());
+        return (answer);
     } catch (...) {
     } catch (...) {
-        isc_throw(Dhcp6ConfigError, "Unrecoverable error: "
-                  "a configuration parser threw in commit");
+        // for things like bad_cast in boost::lexical_cast
+        ConstElementPtr answer = isc::config::createAnswer(2,
+                                 string("Configuration commit failed"));
     }
     }
 
 
     LOG_INFO(dhcp6_logger, DHCP6_CONFIG_COMPLETE).arg(config_details);
     LOG_INFO(dhcp6_logger, DHCP6_CONFIG_COMPLETE).arg(config_details);

+ 1 - 1
src/bin/dhcp6/config_parser.h

@@ -162,7 +162,7 @@ configureDhcp6Server(Dhcpv6Srv& server,
 /// is to be created.
 /// is to be created.
 /// \return A pointer to an \c Dhcp6ConfigParser object.
 /// \return A pointer to an \c Dhcp6ConfigParser object.
 Dhcp6ConfigParser* createDhcp6ConfigParser(Dhcpv6Srv& server,
 Dhcp6ConfigParser* createDhcp6ConfigParser(Dhcpv6Srv& server,
-                                         const std::string& config_id);
+                                           const std::string& config_id);
 
 
 }; // end of isc::dhcp namespace
 }; // end of isc::dhcp namespace
 }; // end of isc namespace
 }; // end of isc namespace

+ 4 - 0
src/bin/dhcp6/dhcp6_messages.mes

@@ -111,6 +111,10 @@ This is a debug message that is issued every time the server receives
 configuration. That happens during every start up and also when server
 configuration. That happens during every start up and also when server
 configuration change is committed by the administrator.
 configuration change is committed by the administrator.
 
 
+% DHCP6_CONFIG_NEW_SUBNET A new subnet has been added to configuration: %1
+This is an informational message that the configuration has extended
+and specified new subnet is now supported.
+
 % DHCP6_CONFIG_COMPLETE DHCPv6 server has completed configuration: %1
 % DHCP6_CONFIG_COMPLETE DHCPv6 server has completed configuration: %1
 This is an informational message that announces successful processing
 This is an informational message that announces successful processing
 of a new configuration. That may happen as a result of one of two
 of a new configuration. That may happen as a result of one of two