-// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
isc::Exception(file, line, what) {}
};
+/// @brief Attempt to modify data in read-only database.
+class ReadOnlyDb : public Exception {
+public:
+ ReadOnlyDb(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
};
};
#include <dhcp/option_string.h>
#include <dhcp/option_int.h>
#include <dhcp/option_vendor.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/schema.h>
#include <dhcpsrv/database_connection.h>
#include <asiolink/io_address.h>
#include <util/buffer.h>
LibDHCP::setRuntimeOptionDefs(defs);
}
+void
+GenericHostDataSourceTest::testReadOnlyDatabase(const char* valid_db_type) {
+ ASSERT_TRUE(hdsptr_);
+
+ // The database is initially opened in "read-write" mode. We can
+ // insert some data to the databse.
+ HostPtr host = initializeHost6("2001:db8::1", Host::IDENT_DUID, false);
+ ASSERT_NO_THROW(hdsptr_->add(host));
+
+ // Subnet id will be used in queries to the database.
+ SubnetID subnet_id = host->getIPv6SubnetID();
+
+ // Make sure that the host has been inserted and that the data can be
+ // retrieved.
+ ConstHostPtr host_by_id = hdsptr_->get6(subnet_id, host->getIdentifierType(),
+ &host->getIdentifier()[0],
+ host->getIdentifier().size());
+ ASSERT_NO_FATAL_FAILURE(compareHosts(host, host_by_id));
+
+ // Close the database connection and reopen in "read-only" mode as
+ // specified by the "VALID_READONLY_DB" parameter.
+ HostDataSourceFactory::destroy();
+ HostDataSourceFactory::create(connectionString(valid_db_type,
+ VALID_NAME,
+ VALID_HOST,
+ VALID_USER,
+ VALID_PASSWORD,
+ VALID_READONLY_DB));
+
+ // Check that an attempt to insert new host would result in
+ // exception.
+ host = initializeHost6("2001:db8::2", Host::IDENT_DUID, false);
+ ASSERT_THROW(hdsptr_->add(host), ReadOnlyDb);
+
+ // Reading from the database should still be possible, though.
+ host_by_id = hdsptr_->get6(subnet_id, host->getIdentifierType(),
+ &host->getIdentifier()[0],
+ host->getIdentifier().size());
+ ASSERT_NO_FATAL_FAILURE(compareHosts(host, host_by_id));
+}
+
void GenericHostDataSourceTest::testBasic4(const Host::IdentifierType& id) {
// Make sure we have the pointer to the host data source.
ASSERT_TRUE(hdsptr_);
/// @brief Pointer to the host data source
HostDataSourcePtr hdsptr_;
+ /// @brief Test that backend can be started in read-only mode.
+ ///
+ /// Some backends can operate when the database is read only, e.g.
+ /// host reservation tables are read only, or the database user has
+ /// read only privileges on the entire database. In such cases, the
+ /// Kea server administrator can specify in the backend configuration
+ /// that the database should be opened in read only mode, i.e.
+ /// INSERT, UPDATE, DELETE statements can't be issued. If any of the
+ /// functions updating the database is called for the backend, the
+ /// error is reported. The database running in read only mode can
+ /// be merely used to retrieve existing host reservations from the
+ /// database. This test verifies that this is the case.
+ ///
+ /// @param valid_db_type Parameter specifying type of backend to
+ /// be used, e.g. type=mysql.
+ void testReadOnlyDatabase(const char* valid_db_type);
+
/// @brief Test that checks that simple host with IPv4 reservation
/// can be inserted and later retrieved.
///
destroyMySQLSchema();
}
+
+
/// @brief Check conversion functions
///
/// The server works using cltt and valid_filetime. In the database, the
EXPECT_EQ(cltt, converted_cltt);
}
+TEST_F(MySqlHostDataSourceTest, testReadOnlyDatabase) {
+ testReadOnlyDatabase(MYSQL_VALID_TYPE);
+}
+
// Test verifies if a host reservation can be added and later retrieved by IPv4
// address. Host uses hw address as identifier.
TEST_F(MySqlHostDataSourceTest, basic4HWAddr) {
const char* VALID_TIMEOUT = "connect-timeout=10";
const char* INVALID_TIMEOUT_1 = "connect-timeout=foo";
const char* INVALID_TIMEOUT_2 = "connect-timeout=-17";
+const char* VALID_READONLY_DB = "readonly=true";
string connectionString(const char* type, const char* name, const char* host,
- const char* user, const char* password, const char* timeout) {
+ const char* user, const char* password, const char* timeout,
+ const char* readonly_db = NULL) {
const string space = " ";
string result = "";
result += string(timeout);
}
+ if (readonly_db != NULL) {
+ if (! result.empty()) {
+ result += space;
+ }
+ result += string(readonly_db);
+ }
+
return (result);
}
extern const char* VALID_TIMEOUT;
extern const char* INVALID_TIMEOUT_1;
extern const char* INVALID_TIMEOUT_2;
+extern const char* VALID_READONLY_DB;
+
/// @brief Given a combination of strings above, produce a connection string.
///
/// @param type type of the database
/// @param user username used to authenticate during connection attempt
/// @param password password used to authenticate during connection attempt
/// @param timeout timeout used during connection attempt
+/// @param readonly_db specifies if database is read only
/// @return string containing all specified parameters
std::string connectionString(const char* type, const char* name = NULL,
const char* host = NULL, const char* user = NULL,
- const char* password = NULL, const char* timeout = NULL);
+ const char* password = NULL, const char* timeout = NULL,
+ const char* readonly_db = NULL);
};
};
};