Browse Source

[3560] Added methods to add classes to the Host object.

Marcin Siodelski 10 years ago
parent
commit
da9288ba1d
3 changed files with 128 additions and 12 deletions
  1. 19 4
      src/lib/dhcpsrv/host.cc
  2. 41 2
      src/lib/dhcpsrv/host.h
  3. 68 6
      src/lib/dhcpsrv/tests/host_unittest.cc

+ 19 - 4
src/lib/dhcpsrv/host.cc

@@ -13,6 +13,7 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <dhcpsrv/host.h>
+#include <util/strutil.h>
 #include <exceptions/exceptions.h>
 
 namespace isc {
@@ -34,10 +35,13 @@ Host::Host(const uint8_t* identifier, const size_t identifier_len,
            const IdentifierType& identifier_type,
            const SubnetID ipv4_subnet_id, const SubnetID ipv6_subnet_id,
            const asiolink::IOAddress& ipv4_reservation,
-           const std::string& hostname)
+           const std::string& hostname,
+           const std::string& dhcp4_client_classes,
+           const std::string& dhcp6_client_classes)
     : hw_address_(), duid_(), ipv4_subnet_id_(ipv4_subnet_id),
       ipv6_subnet_id_(ipv6_subnet_id), ipv4_reservation_(ipv4_reservation),
-      hostname_(hostname), dhcp4_client_classes_(), dhcp6_client_classes_() {
+       hostname_(hostname), dhcp4_client_classes_(dhcp4_client_classes),
+       dhcp6_client_classes_(dhcp6_client_classes) {
 
     // Initialize HWAddr or DUID
     setIdentifier(identifier, identifier_len, identifier_type);
@@ -46,10 +50,13 @@ Host::Host(const uint8_t* identifier, const size_t identifier_len,
 Host::Host(const std::string& identifier, const std::string& identifier_name,
            const SubnetID ipv4_subnet_id, const SubnetID ipv6_subnet_id,
            const asiolink::IOAddress& ipv4_reservation,
-           const std::string& hostname)
+           const std::string& hostname,
+           const std::string& dhcp4_client_classes,
+           const std::string& dhcp6_client_classes)
     : hw_address_(), duid_(), ipv4_subnet_id_(ipv4_subnet_id),
       ipv6_subnet_id_(ipv6_subnet_id), ipv4_reservation_(ipv4_reservation),
-      hostname_(hostname), dhcp4_client_classes_(), dhcp6_client_classes_() {
+      hostname_(hostname), dhcp4_client_classes_(dhcp4_client_classes),
+      dhcp6_client_classes_(dhcp6_client_classes) {
 
     // Initialize HWAddr or DUID
     setIdentifier(identifier, identifier_name);
@@ -99,6 +106,14 @@ Host::getIPv6Reservations(const IPv6Resrv::Type& type) const {
     return (ipv6_reservations_.equal_range(type));
 }
 
+void
+Host::addClientClassInternal(ClientClasses& classes,
+                             const std::string& class_name) {
+    std::string trimmed = util::str::trim(class_name);
+    if (!class_name.empty()) {
+        classes.insert(ClientClass(class_name));
+    }
+}
 
 } // end of namespace isc::dhcp
 } // end of namespace isc

+ 41 - 2
src/lib/dhcpsrv/host.h

@@ -178,6 +178,10 @@ public:
     /// this address is set to 0, there is no reservation.
     /// @param hostname Hostname to be allocated to both DHCPv4 and DHCPv6
     /// clients. This is empty string if hostname is not allocated.
+    /// @param dhcp4_client_classes A string holding DHCPv4 client class names
+    /// separated by commas. The names get trimmed by this constructor.
+    /// @param dhcp6_client_classes A string holding DHCPv6 client class names
+    /// separated by commas. The names get trimmed by this constructor.
     ///
     /// @throw BadValue if the provided values are invalid. In particular,
     /// if the identifier is invalid.
@@ -185,7 +189,9 @@ public:
          const IdentifierType& identifier_type,
          const SubnetID ipv4_subnet_id, const SubnetID ipv6_subnet_id,
          const asiolink::IOAddress& ipv4_reservation,
-         const std::string& hostname = "");
+         const std::string& hostname = "",
+         const std::string& dhcp4_client_classes = "",
+         const std::string& dhcp6_client_classes = "");
 
     /// @brief Constructor.
     ///
@@ -206,13 +212,19 @@ public:
     /// this address is set to 0, there is no reservation.
     /// @param hostname Hostname to be allocated to both DHCPv4 and DHCPv6
     /// clients. This is empty string if hostname is not allocated.
+    /// @param dhcp4_client_classes A string holding DHCPv4 client class names
+    /// separated by commas. The names get trimmed by this constructor.
+    /// @param dhcp6_client_classes A string holding DHCPv6 client class names
+    /// separated by commas. The names get trimmed by this constructor.
     ///
     /// @throw BadValue if the provided values are invalid. In particular,
     /// if the identifier is invalid.
     Host(const std::string& identifier, const std::string& identifier_name,
          const SubnetID ipv4_subnet_id, const SubnetID ipv6_subnet_id,
          const asiolink::IOAddress& ipv4_reservation,
-         const std::string& hostname = "");
+         const std::string& hostname = "",
+         const std::string& dhcp4_client_classes = "",
+         const std::string& dhcp6_client_classes = "");
 
     /// @brief Replaces currently used identifier with a new identifier.
     ///
@@ -325,11 +337,25 @@ public:
         return (hostname_);
     }
 
+    /// @brief Adds new client class for DHCPv4.
+    ///
+    /// @param class_name Class name.
+    void addClientClass4(const std::string& class_name) {
+        addClientClassInternal(dhcp4_client_classes_, class_name);
+    }
+
     /// @brief Returns classes which DHCPv4 client is associated with.
     const ClientClasses& getClientClasses4() const {
         return (dhcp4_client_classes_);
     }
 
+    /// @brief Adds new client class for DHCPv6.
+    ///
+    /// @param class_name Class name.
+    void addClientClass6(const std::string& class_name) {
+        addClientClassInternal(dhcp6_client_classes_, class_name);
+    }
+
     /// @brief Returns classes which DHCPv6 client is associated with.
     const ClientClasses& getClientClasses6() const {
         return (dhcp6_client_classes_);
@@ -337,6 +363,19 @@ public:
 
 private:
 
+    /// @brief Adds new client class for DHCPv4 or DHCPv6.
+    ///
+    /// This method is called internally by the @c addClientClass4 and
+    /// @c addClientClass6 functions. It adds the class of the specified name
+    /// to the supplied class set. The class names are trimmed before they are
+    /// added. Empty class names are ignored.
+    ///
+    /// @param [out] classes Set of classes to which the new class should be
+    /// inserted.
+    /// @param class_name Class name.
+    void addClientClassInternal(ClientClasses& classes,
+                                const std::string& class_name);
+
     /// @brief Pointer to the hardware address associated with the reservations
     /// for the host.
     HWAddrPtr hw_address_;

+ 68 - 6
src/lib/dhcpsrv/tests/host_unittest.cc

@@ -146,12 +146,6 @@ TEST(HostTest, createFromDUIDString) {
                  isc::BadValue);
 
     // Empty DUID is also not allowed.
-    try {
-        Host("", "duid", SubnetID(1), SubnetID(2),
-             IOAddress("192.0.2.3"), "somehost.example.org");
-    } catch (const std::exception& ex) {
-        std::cout << ex.what() << std::endl;
-    }
     EXPECT_THROW(Host("", "duid", SubnetID(1), SubnetID(2),
                       IOAddress("192.0.2.3"), "somehost.example.org"),
                  isc::BadValue);
@@ -362,4 +356,72 @@ TEST(HostTest, setValues) {
     EXPECT_EQ("10.0.0.1", host->getIPv4Reservation().toText());
 }
 
+// Test that Host constructors initialize client classes from string.
+TEST(HostTest, clientClassesFromConstructor) {
+    boost::scoped_ptr<Host> host;
+    // Prepare the hardware address in binary format.
+    const uint8_t hwaddr_data[] = {
+        0xaa, 0xab, 0xca, 0xda, 0xbb, 0xee
+    };
+
+    // Try the "from binary" constructor.
+    ASSERT_NO_THROW(host.reset(new Host(hwaddr_data,
+                                        sizeof(hwaddr_data),
+                                        Host::IDENT_HWADDR,
+                                        SubnetID(1), SubnetID(2),
+                                        IOAddress("192.0.2.3"),
+                                        "somehost.example.org",
+                                        "alpha, , beta",
+                                        "gamma")));
+
+    EXPECT_TRUE(host->getClientClasses4().contains("alpha"));
+    EXPECT_TRUE(host->getClientClasses4().contains("beta"));
+    EXPECT_FALSE(host->getClientClasses4().contains("gamma"));
+    EXPECT_TRUE(host->getClientClasses6().contains("gamma"));
+    EXPECT_FALSE(host->getClientClasses6().contains("alpha"));
+    EXPECT_FALSE(host->getClientClasses6().contains("beta"));
+
+    // Try the "from string" constructor.
+    ASSERT_NO_THROW(host.reset(new Host("01:02:03:04:05:06", "hw-address",
+                                        SubnetID(1), SubnetID(2),
+                                        IOAddress("192.0.2.3"),
+                                        "somehost.example.org",
+                                        "alpha, beta, gamma",
+                                        "beta, gamma")));
+
+    EXPECT_TRUE(host->getClientClasses4().contains("alpha"));
+    EXPECT_TRUE(host->getClientClasses4().contains("beta"));
+    EXPECT_TRUE(host->getClientClasses4().contains("gamma"));
+    EXPECT_FALSE(host->getClientClasses6().contains("alpha"));
+    EXPECT_TRUE(host->getClientClasses6().contains("beta"));
+    EXPECT_TRUE(host->getClientClasses6().contains("gamma"));
+}
+
+// Test that new client classes can be added for the Host.
+TEST(HostTest, addClientClasses) {
+    boost::scoped_ptr<Host> host;
+    ASSERT_NO_THROW(host.reset(new Host("01:02:03:04:05:06", "hw-address",
+                                        SubnetID(1), SubnetID(2),
+                                        IOAddress("192.0.2.3"))));
+
+    EXPECT_FALSE(host->getClientClasses4().contains("foo"));
+    EXPECT_FALSE(host->getClientClasses6().contains("foo"));
+    EXPECT_FALSE(host->getClientClasses4().contains("bar"));
+    EXPECT_FALSE(host->getClientClasses6().contains("bar"));
+
+    host->addClientClass4("foo");
+    host->addClientClass6("bar");
+    EXPECT_TRUE(host->getClientClasses4().contains("foo"));
+    EXPECT_FALSE(host->getClientClasses6().contains("foo"));
+    EXPECT_FALSE(host->getClientClasses4().contains("bar"));
+    EXPECT_TRUE(host->getClientClasses6().contains("bar"));
+
+    host->addClientClass4("bar");
+    host->addClientClass6("foo");
+    EXPECT_TRUE(host->getClientClasses4().contains("foo"));
+    EXPECT_TRUE(host->getClientClasses6().contains("foo"));
+    EXPECT_TRUE(host->getClientClasses4().contains("bar"));
+    EXPECT_TRUE(host->getClientClasses6().contains("bar"));
+}
+
 } // end of anonymous namespace