]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[master] Finishing merge of trac5528/trac5533a (register host backend / host cache)
authorFrancis Dupont <fdupont@isc.org>
Tue, 27 Mar 2018 12:26:41 +0000 (14:26 +0200)
committerFrancis Dupont <fdupont@isc.org>
Tue, 27 Mar 2018 12:26:41 +0000 (14:26 +0200)
23 files changed:
1  2 
configure.ac
doc/guide/dhcp4-srv.xml
doc/guide/dhcp6-srv.xml
doc/guide/hooks.xml
src/bin/dhcp4/dhcp4_lexer.ll
src/bin/dhcp4/dhcp4_parser.yy
src/bin/dhcp4/tests/get_config_unittest.cc
src/bin/dhcp6/dhcp6_lexer.ll
src/bin/dhcp6/dhcp6_parser.yy
src/bin/dhcp6/tests/get_config_unittest.cc
src/lib/dhcpsrv/base_host_data_source.h
src/lib/dhcpsrv/cfg_db_access.h
src/lib/dhcpsrv/host_data_source_factory.cc
src/lib/dhcpsrv/host_data_source_factory.h
src/lib/dhcpsrv/host_mgr.h
src/lib/dhcpsrv/parsers/dbaccess_parser.cc
src/lib/dhcpsrv/tests/Makefile.am
src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc
src/lib/dhcpsrv/tests/host_mgr_unittest.cc
src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc
src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc
src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.cc
src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.h

diff --cc configure.ac
Simple merge
index 63147ff7ade7c6a8304b345309e01e7822ac4c9f,38c0c1d38a09edaf92acd59089d4cfbb9fda8bfe..395b74b5be3e2456d01230d333c1c1e1923e2987
@@@ -634,8 -579,14 +640,16 @@@ Similar parameters can be specified fo
    If there is no password to the account, set the password to the empty string
    "". (This is also the default.)</para>
  
 -   </para>
+   <para>The multiple storage extension uses a similar syntax: a configuration
+   is placed into a "hosts-databases" list instead of into a "hosts-database"
+   entry as in:
+ <screen>
+ "Dhcp4": { "hosts-databases": [ { <userinput>"type": "mysql"</userinput>, ... }, ... ], ... }
+ </screen>
++  </para>
 +  <para>For additional Cassandra specific parameters, see <xref
 +  linkend="cassandra-database-configuration4"/>.</para>
  
  </section>
  
index 26cb9d5ca3c334782829d7d8c7aeb80b27eb98b0,33d67958a4e1480e2b1eda9b40c293f732245912..9ca2dd62dc0c6903a287ae659561b5b587287d84
@@@ -573,9 -572,15 +579,18 @@@ linkend="cassandra-database-configurati
    If there is no password to the account, set the password to the empty string
    "". (This is also the default.)</para>
  
 -
+   <para>The multiple storage extension uses a similar syntax: a configuration
+   is placed into a "hosts-databases" list instead of into a "hosts-database"
+   entry as in:
+ <screen>
+ "Dhcp6": { "hosts-databases": [ { <userinput>"type": "mysql"</userinput>, ... }, ... ], ... }
+ </screen>
+   </para>
 +  <para>
 +    For additional Cassandra specific parameters, see <xref
 +    linkend="cassandra-database-configuration4" />.</para>
++
  </section>
  
  <section xml:id="read-only-database-configuration6">
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 9e82ec5fdfedef50b6392f1469672e7a7814fdfd,1ee71430525b9c72f78853b63d785b590d05333d..640715ca31107183bdc4682ee3f4c889250feb7b
@@@ -285,7 -235,59 +235,60 @@@ public
      ///
      /// @return Const @c Host object using a specified IPv6 address/prefix.
      virtual ConstHostPtr
--    get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) const = 0;
++    get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) const =
++ 0;
+     /// @brief Adds a new host to the collection.
+     ///
+     /// The implementations of this method should guard against duplicate
+     /// reservations for the same host, where possible. For example, when the
+     /// reservation for the same HW address and subnet id is added twice, the
+     /// implementation should throw an exception. Note, that usually it is
+     /// impossible to guard against adding duplicated host, where one instance
+     /// is identified by HW address, another one by DUID.
+     ///
+     /// @param host Pointer to the new @c Host object being added.
+     virtual void add(const HostPtr& host) = 0;
+     /// @brief Attempts to delete a host by (subnet-id, address)
+     ///
+     /// This method supports both v4 and v6.
+     ///
+     /// @param subnet_id subnet identifier.
+     /// @param addr specified address.
+     /// @return true if deletion was successful, false if the host was not there.
+     /// @throw various exceptions in case of errors
+     virtual bool del(const SubnetID& subnet_id, const asiolink::IOAddress& addr) = 0;
+     /// @brief Attempts to delete a host by (subnet-id4, identifier, identifier-type)
+     ///
+     /// This method supports v4 hosts only.
+     ///
+     /// @param subnet_id IPv4 Subnet identifier.
+     /// @param identifier_type Identifier type.
+     /// @param identifier_begin Pointer to a beginning of a buffer containing
+     /// an identifier.
+     /// @param identifier_len Identifier length.
+     /// @return true if deletion was successful, false if the host was not there.
+     /// @throw various exceptions in case of errors
+     virtual bool del4(const SubnetID& subnet_id,
+                       const Host::IdentifierType& identifier_type,
+                       const uint8_t* identifier_begin, const size_t identifier_len) = 0;
+     /// @brief Attempts to delete a host by (subnet-id6, identifier, identifier-type)
+     ///
+     /// This method supports v6 hosts only.
+     ///
+     /// @param subnet_id IPv6 Subnet identifier.
+     /// @param identifier_type Identifier type.
+     /// @param identifier_begin Pointer to a beginning of a buffer containing
+     /// an identifier.
+     /// @param identifier_len Identifier length.
+     /// @return true if deletion was successful, false if the host was not there.
+     /// @throw various exceptions in case of errors
+     virtual bool del6(const SubnetID& subnet_id,
+                       const Host::IdentifierType& identifier_type,
+                       const uint8_t* identifier_begin, const size_t identifier_len) = 0;
  
      /// @brief Return backend type
      ///
index 6ed28523a18c2461368b6270df3830808111a9d6,376bb814a7503378ec17214c8fc4168944c3c5ce..f3f043983d24488025883d6d81df23ace568ee26
@@@ -8,10 -8,9 +8,11 @@@
  #define CFG_DBACCESS_H
  
  #include <cc/cfg_to_element.h>
 +#include <dhcpsrv/database_connection.h>
 +
  #include <boost/shared_ptr.hpp>
  #include <string>
+ #include <list>
  
  namespace isc {
  namespace dhcp {
index 879734c798c1b9d092fd761017f2fe9719be5c1d,dbe24f468bd1d2c17f4ee5aff4c5397483692bc3..3d467bc927e533879c6a74120653016eca5bdb49
@@@ -78,29 -176,28 +176,29 @@@ PgSqlHostDataSourceInit pgsql_init_
  #endif
  
  #ifdef HAVE_CQL
-     if (db_type == "cql") {
+ struct CqlHostDataSourceInit {
+     // Constructor registers
+     CqlHostDataSourceInit() {
+         HostDataSourceFactory::registerFactory("cql", factory);
+     }
+     // Destructor deregisters
+     ~CqlHostDataSourceInit() {
+         HostDataSourceFactory::deregisterFactory("cql");
+     }
+     // Factory class method
+     static HostDataSourcePtr
+     factory(const DatabaseConnection::ParameterMap& parameters) {
          LOG_INFO(dhcpsrv_logger, DHCPSRV_CQL_HOST_DB)
              .arg(DatabaseConnection::redactedAccessString(parameters));
-         getHostDataSourcePtr().reset(new CqlHostDataSource(parameters));
-         return;
+         return (HostDataSourcePtr(new CqlHostDataSource(parameters)));
      }
- #endif
+ };
  
-     // Get here on no match.
-     isc_throw(InvalidType, "Hosts database access parameter 'type': " <<
-                            db_type << " is invalid");
- }
+ // Database backend will be registered at object initialization
+ CqlHostDataSourceInit cql_init_;
+ #endif
  
- void
- HostDataSourceFactory::destroy() {
-     // Destroy current host data source instance.  This is a no-op if no host
-     // data source is available.
-     if (getHostDataSourcePtr()) {
-         LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, HOSTS_CFG_CLOSE_HOST_DATA_SOURCE)
-             .arg(getHostDataSourcePtr()->getType());
-     }
-     getHostDataSourcePtr().reset();
- }
+ } // end of anonymous namespace
 +
- }  // namespace dhcp
- }  // namespace isc
index 89e3f52bfbab13461d73f2ccb01975b10855dfe2,94f5f78b04e5c82b14ff6e6437f3ea843e92e754..28d0f22daf1877a49710cb6c43e7386f0177ab92
@@@ -10,7 -10,7 +10,8 @@@
  #include <dhcp/duid.h>
  #include <dhcp/hwaddr.h>
  #include <dhcpsrv/base_host_data_source.h>
+ #include <dhcpsrv/cache_host_data_source.h>
 +#include <dhcpsrv/database_connection.h>
  #include <dhcpsrv/host.h>
  #include <dhcpsrv/subnet_id.h>
  #include <boost/noncopyable.hpp>
index 2f2b567492099052bcc4c3450c404920cc8bc062,b2ff9165182859f406beaa43e7e13041ba9d578f..4c1f99a177f546ed3fe98e4f2a056062bbe61552
@@@ -103,10 -105,8 +105,9 @@@ libdhcpsrv_unittests_SOURCES += lease_m
  libdhcpsrv_unittests_SOURCES += logging_unittest.cc
  libdhcpsrv_unittests_SOURCES += logging_info_unittest.cc
  libdhcpsrv_unittests_SOURCES += generic_lease_mgr_unittest.cc generic_lease_mgr_unittest.h
- libdhcpsrv_unittests_SOURCES += generic_host_data_source_unittest.cc generic_host_data_source_unittest.h
  libdhcpsrv_unittests_SOURCES += memfile_lease_mgr_unittest.cc
  libdhcpsrv_unittests_SOURCES += dhcp_parsers_unittest.cc
 +libdhcpsrv_unittests_SOURCES += ncr_generator_unittest.cc
  if HAVE_MYSQL
  libdhcpsrv_unittests_SOURCES += mysql_lease_mgr_unittest.cc
  libdhcpsrv_unittests_SOURCES += mysql_host_data_source_unittest.cc
index 17bac48b8c4f3539ece18614b072c69a6ef23742,00a46360270b32bff3df8e816a3b29f8d4ab82d1..46c21e53375131d1949cb93350cbe4c7e861bd95
  
  #include <config.h>
  
- #include <asiolink/io_address.h>
- #include <dhcpsrv/tests/test_utils.h>
 +#include <exceptions/exceptions.h>
+ #include <asiolink/io_address.h>
 -#include <dhcpsrv/cql_connection.h>
 -#include <dhcpsrv/cql_host_data_source.h>
 -#include <dhcpsrv/cql_lease_mgr.h>
  #include <dhcpsrv/host.h>
 -#include <dhcpsrv/testutils/generic_host_data_source_unittest.h>
 -#include <dhcpsrv/tests/test_utils.h>
+ #include <dhcpsrv/host_mgr.h>
+ #include <dhcpsrv/host_data_source_factory.h>
- #include <dhcpsrv/cql_exchange.h>
- #include <dhcpsrv/tests/generic_host_data_source_unittest.h>
 +#include <dhcpsrv/cql_connection.h>
++#include <dhcpsrv/cql_lease_mgr.h>
 +#include <dhcpsrv/cql_host_data_source.h>
  #include <dhcpsrv/testutils/cql_schema.h>
++#include <dhcpsrv/testutils/generic_host_data_source_unittest.h>
  #include <dhcpsrv/testutils/host_data_source_utils.h>
- #include <dhcpsrv/host_data_source_factory.h>
 -#include <exceptions/exceptions.h>
++#include <dhcpsrv/tests/test_utils.h>
  
  #include <gtest/gtest.h>
  
@@@ -56,13 -55,14 +57,14 @@@ public
  
          // Connect to the database
          try {
-             HostDataSourceFactory::create(validCqlConnectionString());
+             HostMgr::create();
+             HostMgr::addBackend(validCqlConnectionString());
          } catch (...) {
 -            std::cerr << "*** ERROR: unable to open database. The test"
 -                         "*** environment is broken and must be fixed before"
 -                         "*** the CQL tests will run correctly."
 -                         "*** The reason for the problem is described in the"
 -                         "*** accompanying exception output.";
 +            std::cerr << "*** ERROR: unable to open database. The test\n"
 +                         "*** environment is broken and must be fixed before\n"
 +                         "*** the CQL tests will run correctly.\n"
 +                         "*** The reason for the problem is described in the\n"
 +                         "*** accompanying exception output.\n";
              throw;
          }
  
      /// Closes the database and re-open it.  Anything committed should be
      /// visible.
      ///
-     /// Parameter is ignored for CQL backend as the v4 and v6 leases share
+     /// Parameter is ignored for CQL backend as the v4 and v6 hosts share
      /// the same database.
      void reopen(Universe) {
-         HostDataSourceFactory::destroy();
-         HostDataSourceFactory::create(validCqlConnectionString());
-         hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
+         HostMgr::create();
+         HostMgr::addBackend(validCqlConnectionString());
+         hdsptr_ = HostMgr::instance().getHostDataSource();
      }
 +
 +    /// @brief Returns number of IPv4 options currently stored in DB.
 +    virtual int countDBOptions4() {
 +        int result = 0;
 +
 +        const CqlHostDataSource* cql_host_mgr = dynamic_cast<const CqlHostDataSource*>(&(*hdsptr_));
 +        ConstHostCollection all = cql_host_mgr->getAllHosts();
 +
 +        for (ConstHostCollection::const_iterator it = all.begin();
 +             it != all.end(); ++it) {
 +            ConstCfgOptionPtr cfg_option4 = (*it)->getCfgOption4();
 +            std::list<std::string> option_spaces4 = cfg_option4->getOptionSpaceNames();
 +            std::list<std::string> vendor_spaces4 = cfg_option4->getVendorIdsSpaceNames();
 +            option_spaces4.insert(option_spaces4.end(), vendor_spaces4.begin(),
 +                                  vendor_spaces4.end());
 +            for (const std::string& space : option_spaces4) {
 +                OptionContainerPtr options = cfg_option4->getAll(space);
 +                result += options->size();
 +            }
 +        }
 +
 +        return (result);
 +    }
 +
 +    /// @brief Returns number of IPv6 options currently stored in DB.
 +    virtual int countDBOptions6() {
 +        int result = 0;
 +
 +        const CqlHostDataSource* cql_host_mgr = dynamic_cast<const CqlHostDataSource*>(&(*hdsptr_));
 +        ConstHostCollection all = cql_host_mgr->getAllHosts();
 +
 +        for (ConstHostCollection::const_iterator it = all.begin();
 +             it != all.end(); ++it) {
 +            ConstCfgOptionPtr cfg_option6 = (*it)->getCfgOption6();
 +            std::list<std::string> option_spaces6 = cfg_option6->getOptionSpaceNames();
 +            std::list<std::string> vendor_spaces6 = cfg_option6->getVendorIdsSpaceNames();
 +            option_spaces6.insert(option_spaces6.end(), vendor_spaces6.begin(),
 +                                  vendor_spaces6.end());
 +            for (const std::string& space : option_spaces6) {
 +                OptionContainerPtr options = cfg_option6->getAll(space);
 +                result += options->size();
 +            }
 +        }
 +
 +        return (result);
 +    }
 +
 +    /// @brief Returns number of IPv6 reservations currently stored in DB.
 +    virtual int countDBReservations6() {
 +        int result = 0;
 +
 +        const CqlHostDataSource* cql_host_mgr = dynamic_cast<const CqlHostDataSource*>(&(*hdsptr_));
 +        ConstHostCollection all = cql_host_mgr->getAllHosts();
 +
 +        for (ConstHostCollection::const_iterator it = all.begin();
 +             it != all.end(); ++it) {
 +            IPv6ResrvRange reservations = (*it)->getIPv6Reservations();
 +                result += std::distance(reservations.first, reservations.second);
 +        }
 +
 +        return (result);
 +    }
 +
  };
  
  /// @brief Check that database can be opened
@@@ -199,16 -137,14 +202,16 @@@ TEST(CqlHostDataSource, OpenDatabase) 
                 << "*** before the CQL tests will run correctly.\n";
      }
  
-     // Check that lease manager open the database opens correctly with a longer
+     // Check that host manager open the database opens correctly with a longer
      // timeout.  If it fails, print the error message.
      try {
 -        std::string connection_string = validCqlConnectionString() + std::string(" ") +
 -                                        std::string(VALID_TIMEOUT);
 +        // CQL specifies the timeout values in ms, not seconds. Therefore
 +        // we need to add extra 000 to the "connect-timeout=10" string.
 +        string connection_string = validCqlConnectionString() + string(" ") +
 +            string(VALID_TIMEOUT) + string("000");
-         HostDataSourceFactory::create(connection_string);
-         EXPECT_NO_THROW((void) HostDataSourceFactory::getHostDataSourcePtr());
-         HostDataSourceFactory::destroy();
+         HostMgr::create();
+         EXPECT_NO_THROW(HostMgr::addBackend(connection_string));
+         HostMgr::delBackend("cql");
      } catch (const isc::Exception& ex) {
          FAIL() << "*** ERROR: unable to open database, reason:\n"
                 << "    " << ex.what() << "\n"
index 09eb7c1922262fc115ba6d297b51ee237a3b107f,6e4937cb9f34984bc9c6040a440005f1d7b39d8a..92ceff5dcce570127c2fd33a8652e1c8ab67fc83
@@@ -54,11 -59,14 +56,11 @@@ public
              throw;
          }
  
-         hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
+         hdsptr_ = HostMgr::instance().getHostDataSource();
      }
  
 -    /// @brief Destructor
 -    ///
 -    /// Rolls back all pending transactions.  The deletion of myhdsptr_ will close
 -    /// the database.  Then reopen it and delete everything created by the test.
 -    virtual ~MySqlHostDataSourceTest() {
 +    /// @brief Destroys the HDS and the schema.
 +    void destroyTest() {
          try {
              hdsptr_->rollback();
          } catch (...) {
@@@ -184,17 -176,17 +187,17 @@@ TEST(MySqlHostDataSource, OpenDatabase
                 << "*** before the MySQL tests will run correctly.\n";
      }
  
-     // Check that attempting to get an instance of the host data source when
+     // Check that attempting to get an instance of the host manager when
      // none is set throws an exception.
-     EXPECT_FALSE(HostDataSourceFactory::getHostDataSourcePtr());
+     EXPECT_FALSE(HostMgr::instance().getHostDataSource());
  
      // Check that wrong specification of backend throws an exception.
 -    // (This is really a check on LeaseMgrFactory, but is convenient to
 +    // (This is really a check on HostDataSourceFactory, but is convenient to
      // perform here.)
-     EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+     EXPECT_THROW(HostMgr::addBackend(connectionString(
          NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
          InvalidParameter);
-     EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+     EXPECT_THROW(HostMgr::addBackend(connectionString(
          INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
          InvalidType);
  
index 945e97c61e45586e0c1aaac38dd6db90a3a1622a,33c11746a96dddc5663e7a9a22ea36eeed1c52ce..293f9e5fc1bae48638a1d045c9d4bac6ef905978
@@@ -54,11 -59,15 +56,11 @@@ public
              throw;
          }
  
-         hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
+         hdsptr_ = HostMgr::instance().getHostDataSource();
      }
  
 -    /// @brief Destructor
 -    ///
 -    /// Rolls back all pending transactions.  The deletion of myhdsptr_ will
 -    /// close the database.  Then reopen it and delete everything created by
 -    /// the test.
 -    virtual ~PgSqlHostDataSourceTest() {
 +    /// @brief Destroys the HDS and the schema.
 +    void destroyTest() {
          try {
              hdsptr_->rollback();
          } catch (...) {
      /// Closes the database and re-open it.  Anything committed should be
      /// visible.
      ///
 -    /// Parameter is ignored for PostgreSQL backend as the v4 and v6 leases
 -    /// share the same database.
 +    /// Parameter is ignored for PostgreSQL backend as the v4 and v6 leases share
 +    /// the same database.
      void reopen(Universe) {
-         HostDataSourceFactory::destroy();
-         HostDataSourceFactory::create(validPgSQLConnectionString());
-         hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
+         HostMgr::create();
+         HostMgr::addBackend(validPgSQLConnectionString());
+         hdsptr_ = HostMgr::instance().getHostDataSource();
      }
  
      /// @brief returns number of rows in a table
@@@ -182,17 -175,17 +184,17 @@@ TEST(PgSqlHostDataSource, OpenDatabase
                 << "*** before the PostgreSQL tests will run correctly.\n";
      }
  
-     // Check that attempting to get an instance of the host data source when
+     // Check that attempting to get an instance of the host manager when
      // none is set throws an exception.
-     EXPECT_FALSE(HostDataSourceFactory::getHostDataSourcePtr());
+     EXPECT_FALSE(HostMgr::instance().getHostDataSource());
  
      // Check that wrong specification of backend throws an exception.
 -    // (This is really a check on LeaseMgrFactory, but is convenient to
 +    // (This is really a check on HostDataSourceFactory, but is convenient to
      // perform here.)
-     EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+     EXPECT_THROW(HostMgr::addBackend(connectionString(
          NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
          InvalidParameter);
-     EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+     EXPECT_THROW(HostMgr::addBackend(connectionString(
          INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
          InvalidType);
  
index c84633895ac38a935db979263bc6174bf87ed678,0c2b3f3e956b72b361d1038094ac0585831ed64f..9a58475edf82e1fd78b955e4449bc2cc716c4bfa
  #include <dhcp/option_string.h>
  #include <dhcp/option_vendor.h>
  #include <dhcpsrv/database_connection.h>
+ #include <dhcpsrv/db_exceptions.h>
+ #include <dhcpsrv/host_mgr.h>
  #include <dhcpsrv/host_data_source_factory.h>
- #include <dhcpsrv/tests/generic_host_data_source_unittest.h>
- #include <dhcpsrv/tests/test_utils.h>
+ #include <dhcpsrv/testutils/generic_host_data_source_unittest.h>
 -#include <dhcpsrv/testutils/schema.h>
+ #include <dhcpsrv/testutils/host_data_source_utils.h>
 +#include <dhcpsrv/testutils/schema.h>
+ #include <util/buffer.h>
  #include <boost/foreach.hpp>
- #include <dhcpsrv/testutils/host_data_source_utils.h>
  #include <gtest/gtest.h>
- #include <util/buffer.h>
  
  #include <chrono>
  #include <cstring>