Parcourir la source

[5029] Implemented test for multi stage boot for MySQL and Postgres.

Marcin Siodelski il y a 8 ans
Parent
commit
bacfbf15f0
2 fichiers modifiés avec 219 ajouts et 0 suppressions
  1. 8 0
      src/bin/dhcp4/tests/dhcp4_test_utils.cc
  2. 211 0
      src/bin/dhcp4/tests/dora_unittest.cc

+ 8 - 0
src/bin/dhcp4/tests/dhcp4_test_utils.cc

@@ -19,6 +19,7 @@
 #include <dhcp/iface_mgr.h>
 #include <dhcp/tests/iface_mgr_test_config.h>
 #include <dhcp/tests/pkt_captures.h>
+#include <dhcpsrv/cfg_db_access.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/lease.h>
 #include <dhcpsrv/lease_mgr.h>
@@ -608,6 +609,13 @@ Dhcpv4SrvTest::configure(const std::string& config, NakedDhcpv4Srv& srv,
     ConstElementPtr comment = config::parseAnswer(rcode, status);
     ASSERT_EQ(0, rcode);
 
+    // Use specified lease database backend.
+    ASSERT_NO_THROW( {
+        CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
+        cfg_db->setAppendedParameters("universe=4");
+        cfg_db->createManagers();
+    } );
+
     if (commit) {
         CfgMgr::instance().commit();
     }

+ 211 - 0
src/bin/dhcp4/tests/dora_unittest.cc

@@ -13,6 +13,8 @@
 #include <dhcpsrv/host.h>
 #include <dhcpsrv/host_mgr.h>
 #include <dhcpsrv/subnet_id.h>
+#include <dhcpsrv/testutils/mysql_schema.h>
+#include <dhcpsrv/testutils/pgsql_schema.h>
 #include <dhcp4/tests/dhcp4_test_utils.h>
 #include <dhcp4/tests/dhcp4_client.h>
 #include <boost/shared_ptr.hpp>
@@ -80,6 +82,15 @@ namespace {
 ///     - next-server = 10.0.0.7
 ///     - server name = "some-name.example.org"
 ///     - boot-file-name = "bootfile.efi"
+///
+/// - Configuration 7:
+///   - Simple configuration with a single subnet and single pool
+///   - Using MySQL lease database backend to store leases
+///
+/// - Configuration 8:
+///   - Simple configuration with a single subnet and single pool
+///   - Using PostgreSQL lease database backend to store leases
+///
 const char* DORA_CONFIGS[] = {
 // Configuration 0
     "{ \"interfaces-config\": {"
@@ -262,6 +273,42 @@ const char* DORA_CONFIGS[] = {
         "       }"
         "    ]"
         "} ]"
+    "}",
+
+// Configuration 7
+    "{ \"interfaces-config\": {"
+        "   \"interfaces\": [ \"*\" ]"
+        "},"
+        "\"lease-database\": {"
+        "   \"type\": \"mysql\","
+        "   \"name\": \"keatest\","
+        "   \"user\": \"keatest\","
+        "   \"password\": \"keatest\""
+        "},"
+        "\"valid-lifetime\": 600,"
+        "\"subnet4\": [ { "
+        "    \"subnet\": \"10.0.0.0/24\", "
+        "    \"id\": 1,"
+        "    \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ]"
+        " } ]"
+    "}",
+
+// Configuration 8
+    "{ \"interfaces-config\": {"
+        "   \"interfaces\": [ \"*\" ]"
+        "},"
+        "\"lease-database\": {"
+        "   \"type\": \"postgresql\","
+        "   \"name\": \"keatest\","
+        "   \"user\": \"keatest\","
+        "   \"password\": \"keatest\""
+        "},"
+        "\"valid-lifetime\": 600,"
+        "\"subnet4\": [ { "
+        "    \"subnet\": \"10.0.0.0/24\", "
+        "    \"id\": 1,"
+        "    \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ]"
+        " } ]"
     "}"
 };
 
@@ -318,6 +365,18 @@ public:
     void oneAllocationOverlapTest(const std::string& clientid_a,
                                   const std::string& clientid_b);
 
+    /// @brief Test that the client using the same hardware address but
+    /// multiple client identifiers will obtain multiple leases.
+    ///
+    /// This reflects the scenario of the OS installation over the network
+    /// when BIOS, installer and the host request DHCPv4 lease assignment
+    /// using the same MAC address/interface but generating different
+    /// client identifiers.
+    ///
+    /// @param config_index Index of the configuration within the
+    /// @c DORA_CONFIGS array.
+    void testMultiStageBoot(const unsigned int config_index);
+
     /// @brief Interface Manager's fake configuration control.
     IfaceMgrTestConfig iface_mgr_test_config_;
 
@@ -1374,4 +1433,156 @@ TEST_F(DORATest, statisticsNAK) {
     EXPECT_EQ(1, pkt4_sent->getInteger().first);
 }
 
+void
+DORATest::testMultiStageBoot(const unsigned int config_index) {
+    Dhcp4Client client(Dhcp4Client::SELECTING);
+    // Configure DHCP server.
+    ASSERT_NO_THROW(configure(DORA_CONFIGS[config_index],
+                              *client.getServer()));
+
+    // Stage 1: get the first lease for our client. In PXE boot, it would be
+    // a stage when the BIOS requests a lease.
+
+    // Include client id apart from the MAC address.
+    client.includeClientId("10:21:32:AB:CD:EF");
+
+    ASSERT_NO_THROW(client.doDORA());
+
+    // Make sure that the server responded.
+    ASSERT_TRUE(client.getContext().response_);
+    Pkt4Ptr resp = client.getContext().response_;
+    // Make sure that the server has responded with DHCPACK.
+    ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
+
+    // Make sure that the client has got the lease which belongs
+    // to a pool.
+    IOAddress leased_address1 = client.config_.lease_.addr_;
+    Subnet4Ptr subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->
+        selectSubnet(leased_address1);
+    ASSERT_TRUE(subnet);
+    // Make sure that the address has been allocated from the dynamic pool.
+    ASSERT_TRUE(subnet->inPool(Lease::TYPE_V4, leased_address1));
+
+    // Stage 2: the client with a given MAC address has a lease in the
+    // lease database. The installer comes up and uses the same MAC address
+    // but generates a different client id. The server should treat the
+    // client with modified client identifier as a different client and
+    // create a new lease for it.
+
+    // Modify client identifier.
+    client.includeClientId("11:54:45:AB:AA:FE");
+
+    ASSERT_NO_THROW(client.doDORA());
+
+    // Make sure that the server responded.
+    ASSERT_TRUE(client.getContext().response_);
+    resp = client.getContext().response_;
+    // Make sure that the server has responded with DHCPACK.
+    ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
+
+    // Make sure that the client has got the lease which belongs
+    // to a pool.
+    IOAddress leased_address2 = client.config_.lease_.addr_;
+    // Make sure that the address has been allocated from the dynamic pool.
+    ASSERT_TRUE(subnet->inPool(Lease::TYPE_V4, leased_address2));
+
+    // The client should have got a new lease.
+    ASSERT_NE(leased_address1, leased_address2);
+
+    // Modify client identifier again.
+    client.includeClientId("22:34:AC:BE:44:54");
+
+    ASSERT_NO_THROW(client.doDORA());
+
+    // Make sure that the server responded.
+    ASSERT_TRUE(client.getContext().response_);
+    resp = client.getContext().response_;
+    // Make sure that the server has responded with DHCPACK.
+    ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
+
+    // Make sure that the client has got the lease which belongs
+    // to a pool.
+    IOAddress leased_address3 = client.config_.lease_.addr_;
+    // Make sure that the address has been allocated from the dynamic pool.
+    ASSERT_TRUE(subnet->inPool(Lease::TYPE_V4, leased_address3));
+
+    // The client should have got a new lease.
+    ASSERT_NE(leased_address1, leased_address3);
+    ASSERT_NE(leased_address2, leased_address3);
+}
+
+
+// Test that the client using the same hardware address but multiple
+// client identifiers will obtain multiple leases.
+TEST_F(DORATest, multiStageBoot) {
+    // DORA_CONFIGS[0] to be used for server configuration.
+    testMultiStageBoot(0);
+}
+
+// Starting tests which require MySQL backend availability. Those tests
+// will not be executed if Kea has been compiled without the
+// --with-dhcp-mysql.
+#ifdef HAVE_MYSQL
+
+/// @brief Test fixture class for the test utilizing MySQL database backend.
+class DORAMySQLTest : public DORATest {
+public:
+    /// @brief Constructor.
+    ///
+    /// Recreats MySQL schema for a test.
+    DORAMySQLTest() : DORATest() {
+        destroyMySQLSchema();
+        createMySQLSchema();
+    }
+
+    /// @brief Destructor.
+    ///
+    /// Destroys MySQL schema.
+    virtual ~DORAMySQLTest() {
+        destroyMySQLSchema();
+    }
+};
+
+// Test that the client using the same hardware address but multiple
+// client identifiers will obtain multiple leases (MySQL lease database).
+TEST_F(DORAMySQLTest, multiStageBoot) {
+    // DORA_CONFIGS[7] to be used for server configuration.
+    testMultiStageBoot(7);
+}
+
+#endif
+
+// Starting tests which require MySQL backend availability. Those tests
+// will not be executed if Kea has been compiled without the
+// --with-dhcp-pgsql.
+#ifdef HAVE_PGSQL
+
+/// @brief Test fixture class for the test utilizing MySQL database backend.
+class DORAPgSQLTest : public DORATest {
+public:
+    /// @brief Constructor.
+    ///
+    /// Recreats MySQL schema for a test.
+    DORAPgSQLTest() : DORATest() {
+        destroyPgSQLSchema();
+        createPgSQLSchema();
+    }
+
+    /// @brief Destructor.
+    ///
+    /// Destroys MySQL schema.
+    virtual ~DORAPgSQLTest() {
+        destroyPgSQLSchema();
+    }
+};
+
+// Test that the client using the same hardware address but multiple
+// client identifiers will obtain multiple leases (PostgreSQL lease database).
+TEST_F(DORAPgSQLTest, multiStageBoot) {
+    // DORA_CONFIGS[8] to be used for server configuration.
+    testMultiStageBoot(8);
+}
+
+#endif
+
 } // end of anonymous namespace