Browse Source

[4765] Client classes in HR can be specified in configuration file.

Marcin Siodelski 8 years ago
parent
commit
24213920f8

+ 3 - 1
src/lib/dhcpsrv/cfg_hosts.cc

@@ -580,7 +580,9 @@ CfgHosts::add4(const HostPtr& host) {
         host->getServerHostname().empty() &&
         host->getServerHostname().empty() &&
         host->getBootFileName().empty() &&
         host->getBootFileName().empty() &&
         host->getCfgOption4()->empty() &&
         host->getCfgOption4()->empty() &&
-        host->getCfgOption6()->empty()) {
+        host->getCfgOption6()->empty() &&
+        host->getClientClasses4().empty() &&
+        host->getClientClasses6().empty()) {
         std::ostringstream s;
         std::ostringstream s;
         if (hwaddr) {
         if (hwaddr) {
             s << "for DUID: " << hwaddr->toText();
             s << "for DUID: " << hwaddr->toText();

+ 1 - 0
src/lib/dhcpsrv/host.cc

@@ -347,6 +347,7 @@ Host::addClientClass4(const std::string& class_name) {
     addClientClassInternal(dhcp4_client_classes_, class_name);
     addClientClassInternal(dhcp4_client_classes_, class_name);
 }
 }
 
 
+
 void
 void
 Host::addClientClass6(const std::string& class_name) {
 Host::addClientClass6(const std::string& class_name) {
     addClientClassInternal(dhcp6_client_classes_, class_name);
     addClientClassInternal(dhcp6_client_classes_, class_name);

+ 28 - 12
src/lib/dhcpsrv/parsers/host_reservation_parser.cc

@@ -52,6 +52,7 @@ getSupportedParams4(const bool identifiers_only = false) {
         params_set.insert("next-server");
         params_set.insert("next-server");
         params_set.insert("server-hostname");
         params_set.insert("server-hostname");
         params_set.insert("boot-file-name");
         params_set.insert("boot-file-name");
+        params_set.insert("client-classes");
     }
     }
     return (identifiers_only ? identifiers_set : params_set);
     return (identifiers_only ? identifiers_set : params_set);
 }
 }
@@ -83,6 +84,7 @@ getSupportedParams6(const bool identifiers_only = false) {
         params_set.insert("ip-addresses");
         params_set.insert("ip-addresses");
         params_set.insert("prefixes");
         params_set.insert("prefixes");
         params_set.insert("option-data");
         params_set.insert("option-data");
+        params_set.insert("client-classes");
     }
     }
     return (identifiers_only ? identifiers_set : params_set);
     return (identifiers_only ? identifiers_set : params_set);
 }
 }
@@ -102,10 +104,10 @@ HostReservationParser::build(isc::data::ConstElementPtr reservation_data) {
     std::string identifier_name;
     std::string identifier_name;
     std::string hostname;
     std::string hostname;
 
 
-    // Gather those parameters that are common for both IPv4 and IPv6
-    // reservations.
-    BOOST_FOREACH(ConfigPair element, reservation_data->mapValue()) {
-        try {
+    try {
+        // Gather those parameters that are common for both IPv4 and IPv6
+        // reservations.
+        BOOST_FOREACH(ConfigPair element, reservation_data->mapValue()) {
             // Check if we support this parameter.
             // Check if we support this parameter.
             if (!isSupportedParameter(element.first)) {
             if (!isSupportedParameter(element.first)) {
                 isc_throw(DhcpConfigError, "unsupported configuration"
                 isc_throw(DhcpConfigError, "unsupported configuration"
@@ -123,15 +125,10 @@ HostReservationParser::build(isc::data::ConstElementPtr reservation_data) {
 
 
             } else if (element.first == "hostname") {
             } else if (element.first == "hostname") {
                 hostname = element.second->stringValue();
                 hostname = element.second->stringValue();
+
             }
             }
-        } catch (const std::exception& ex) {
-            // Append line number where the error occurred.
-            isc_throw(DhcpConfigError, ex.what() << " ("
-                      << element.second->getPosition() << ")");
         }
         }
-    }
 
 
-    try {
         // Host identifier is a must.
         // Host identifier is a must.
         if (identifier_name.empty()) {
         if (identifier_name.empty()) {
             // If there is no identifier specified, we have to display an
             // If there is no identifier specified, we have to display an
@@ -210,19 +207,25 @@ HostReservationParser4::build(isc::data::ConstElementPtr reservation_data) {
                     host_->setIPv4Reservation(IOAddress(element.second->
                     host_->setIPv4Reservation(IOAddress(element.second->
                                                         stringValue()));
                                                         stringValue()));
                 } else if (element.first == "next-server") {
                 } else if (element.first == "next-server") {
-                host_->setNextServer(IOAddress(element.second->stringValue()));
+                    host_->setNextServer(IOAddress(element.second->stringValue()));
 
 
                 } else if (element.first == "server-hostname") {
                 } else if (element.first == "server-hostname") {
                     host_->setServerHostname(element.second->stringValue());
                     host_->setServerHostname(element.second->stringValue());
 
 
                 } else if (element.first == "boot-file-name") {
                 } else if (element.first == "boot-file-name") {
                     host_->setBootFileName(element.second->stringValue());
                     host_->setBootFileName(element.second->stringValue());
+
+                } else if (element.first == "client-classes") {
+                    BOOST_FOREACH(ConstElementPtr class_element,
+                                  element.second->listValue()) {
+                        host_->addClientClass4(class_element->stringValue());
+                    }
                 }
                 }
 
 
             } catch (const std::exception& ex) {
             } catch (const std::exception& ex) {
                 // Append line number where the error occurred.
                 // Append line number where the error occurred.
                 isc_throw(DhcpConfigError, ex.what() << " ("
                 isc_throw(DhcpConfigError, ex.what() << " ("
-                          << reservation_data->getPosition() << ")");
+                          << element.second->getPosition() << ")");
             }
             }
         }
         }
     }
     }
@@ -318,6 +321,19 @@ HostReservationParser6::build(isc::data::ConstElementPtr reservation_data) {
                               << prefix_element->getPosition() << ")");
                               << prefix_element->getPosition() << ")");
                 }
                 }
             }
             }
+
+
+        } else if (element.first == "client-classes") {
+            try {
+                BOOST_FOREACH(ConstElementPtr class_element,
+                              element.second->listValue()) {
+                    host_->addClientClass6(class_element->stringValue());
+                }
+            } catch (const std::exception& ex) {
+                // Append line number where the error occurred.
+                isc_throw(DhcpConfigError, ex.what() << " ("
+                          << element.second->getPosition() << ")");
+            }
         }
         }
     }
     }
 
 

+ 46 - 0
src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc

@@ -300,6 +300,29 @@ TEST_F(HostReservationParserTest, dhcp4NoHostname) {
     EXPECT_TRUE(hosts[0]->getHostname().empty());
     EXPECT_TRUE(hosts[0]->getHostname().empty());
 }
 }
 
 
+// This test verifies that it is possible to specify DHCPv4 client classes
+// within the host reservation.
+TEST_F(HostReservationParserTest, dhcp4ClientClasses) {
+    std::string config = "{ \"hw-address\": \"01:02:03:04:05:06\","
+        "\"client-classes\": [ \"foo\", \"bar\" ] }";
+
+    ElementPtr config_element = Element::fromJSON(config);
+
+    HostReservationParser4 parser(SubnetID(10));
+    ASSERT_NO_THROW(parser.build(config_element));
+
+    CfgHostsPtr cfg_hosts = CfgMgr::instance().getStagingCfg()->getCfgHosts();
+    HostCollection hosts;
+    ASSERT_NO_THROW(hosts = cfg_hosts->getAll(hwaddr_));
+
+    ASSERT_EQ(1, hosts.size());
+
+    const ClientClasses& classes = hosts[0]->getClientClasses4();
+    ASSERT_EQ(2, classes.size());
+    EXPECT_EQ(1, classes.count("foo"));
+    EXPECT_EQ(1, classes.count("bar"));
+}
+
 // This test verifies that the parser can parse reservation entry
 // This test verifies that the parser can parse reservation entry
 // containing next-server, server-hostname and boot-file-name values for
 // containing next-server, server-hostname and boot-file-name values for
 // DHCPv4 message fields.
 // DHCPv4 message fields.
@@ -627,6 +650,29 @@ TEST_F(HostReservationParserTest, dhcp6NoHostname) {
     ASSERT_EQ(0, std::distance(prefixes.first, prefixes.second));
     ASSERT_EQ(0, std::distance(prefixes.first, prefixes.second));
 }
 }
 
 
+// This test verifies that it is possible to specify DHCPv4 client classes
+// within the host reservation.
+TEST_F(HostReservationParserTest, dhcp6ClientClasses) {
+    std::string config = "{ \"duid\": \"01:02:03:04:05:06:07:08:09:0A\","
+        "\"client-classes\": [ \"foo\", \"bar\" ] }";
+
+    ElementPtr config_element = Element::fromJSON(config);
+
+    HostReservationParser6 parser(SubnetID(10));
+    ASSERT_NO_THROW(parser.build(config_element));
+
+    CfgHostsPtr cfg_hosts = CfgMgr::instance().getStagingCfg()->getCfgHosts();
+    HostCollection hosts;
+    ASSERT_NO_THROW(hosts = cfg_hosts->getAll(Host::IDENT_DUID,
+                                              &duid_->getDuid()[0],
+                                              duid_->getDuid().size()));
+    ASSERT_EQ(1, hosts.size());
+
+    const ClientClasses& classes = hosts[0]->getClientClasses6();
+    ASSERT_EQ(2, classes.size());
+    EXPECT_EQ(1, classes.count("foo"));
+    EXPECT_EQ(1, classes.count("bar"));
+}
 
 
 // This test verifies that the configuration parser throws an exception
 // This test verifies that the configuration parser throws an exception
 // when IPv4 address is specified for IPv6 reservation.
 // when IPv4 address is specified for IPv6 reservation.