mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-07 09:25:15 +00:00
[4489] Added support for read only mode in PostgreSQL HR backend.
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/pointer_cast.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
@@ -35,7 +36,7 @@ namespace {
|
||||
|
||||
/// @brief Maximum length of option value.
|
||||
/// The maximum size of the raw option data that may be read from the
|
||||
/// database.
|
||||
/// database.
|
||||
const size_t OPTION_VALUE_MAX_LEN = 4096;
|
||||
|
||||
/// @brief Numeric value representing last supported identifier.
|
||||
@@ -1105,10 +1106,6 @@ public:
|
||||
///
|
||||
/// The contents of the enum are indexes into the list of SQL statements
|
||||
enum StatementIndex {
|
||||
INSERT_HOST, // Insert new host to collection
|
||||
INSERT_V6_RESRV, // Insert v6 reservation
|
||||
INSERT_V4_HOST_OPTION, // Insert DHCPv4 option
|
||||
INSERT_V6_HOST_OPTION, // Insert DHCPv6 option
|
||||
GET_HOST_DHCPID, // Gets hosts by host identifier
|
||||
GET_HOST_ADDR, // Gets hosts by IPv4 address
|
||||
GET_HOST_SUBID4_DHCPID, // Gets host by IPv4 SubnetID, HW address/DUID
|
||||
@@ -1116,9 +1113,20 @@ public:
|
||||
GET_HOST_SUBID_ADDR, // Gets host by IPv4 SubnetID and IPv4 address
|
||||
GET_HOST_PREFIX, // Gets host by IPv6 prefix
|
||||
GET_VERSION, // Obtain version number
|
||||
INSERT_HOST, // Insert new host to collection
|
||||
INSERT_V6_RESRV, // Insert v6 reservation
|
||||
INSERT_V4_HOST_OPTION, // Insert DHCPv4 option
|
||||
INSERT_V6_HOST_OPTION, // Insert DHCPv6 option
|
||||
NUM_STATEMENTS // Number of statements
|
||||
};
|
||||
|
||||
/// @brief Index of first statement performing write to the database.
|
||||
///
|
||||
/// This value is used to mark border line between queries and other
|
||||
/// statements and statements performing write operation on the database,
|
||||
/// such as INSERT, DELETE, UPDATE.
|
||||
static const StatementIndex WRITE_STMTS_BEGIN = INSERT_HOST;
|
||||
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// This constructor opens database connection and initializes prepared
|
||||
@@ -1258,66 +1266,25 @@ public:
|
||||
/// @brief MySQL connection
|
||||
PgSqlConnection conn_;
|
||||
|
||||
/// @brief Indicates if the database is opened in read only mode.
|
||||
bool is_readonly_;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
/// @brief Array of tagged statements.
|
||||
typedef boost::array<PgSqlTaggedStatement, PgSqlHostDataSourceImpl::NUM_STATEMENTS>
|
||||
TaggedStatementArray;
|
||||
|
||||
/// @brief Prepared PosgreSQL statements used by the backend to insert and
|
||||
/// retrieve reservation data from the database.
|
||||
PgSqlTaggedStatement tagged_statements[] = {
|
||||
// PgSqlHostDataSourceImpl::INSERT_HOST
|
||||
// Inserts a host into the 'hosts' table. Returns the inserted host id.
|
||||
{8,
|
||||
{ OID_BYTEA, OID_INT2,
|
||||
OID_INT4, OID_INT4, OID_INT8, OID_VARCHAR,
|
||||
OID_VARCHAR, OID_VARCHAR },
|
||||
"insert_host",
|
||||
"INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, "
|
||||
" dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
|
||||
" dhcp4_client_classes, dhcp6_client_classes) "
|
||||
"VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING host_id"
|
||||
},
|
||||
|
||||
//PgSqlHostDataSourceImpl::INSERT_V6_RESRV
|
||||
// Inserts a single IPv6 reservation into 'reservations' table.
|
||||
{5,
|
||||
{ OID_VARCHAR, OID_INT2, OID_INT4, OID_INT4, OID_INT4 },
|
||||
"insert_v6_resrv",
|
||||
"INSERT INTO ipv6_reservations(address, prefix_len, type, "
|
||||
" dhcp6_iaid, host_id) "
|
||||
"VALUES ($1, $2, $3, $4, $5)"
|
||||
},
|
||||
|
||||
// PgSqlHostDataSourceImpl::INSERT_V4_HOST_OPTION
|
||||
// Inserts a single DHCPv4 option into 'dhcp4_options' table.
|
||||
// Using fixed scope_id = 3, which associates an option with host.
|
||||
{6,
|
||||
{ OID_INT2, OID_BYTEA, OID_TEXT,
|
||||
OID_VARCHAR, OID_BOOL, OID_INT8},
|
||||
"insert_v4_host_option",
|
||||
"INSERT INTO dhcp4_options(code, value, formatted_value, space, "
|
||||
" persistent, host_id, scope_id) "
|
||||
"VALUES ($1, $2, $3, $4, $5, $6, 3)"
|
||||
},
|
||||
|
||||
// PgSqlHostDataSourceImpl::INSERT_V6_HOST_OPTION
|
||||
// Inserts a single DHCPv6 option into 'dhcp6_options' table.
|
||||
// Using fixed scope_id = 3, which associates an option with host.
|
||||
{6,
|
||||
{ OID_INT2, OID_BYTEA, OID_TEXT,
|
||||
OID_VARCHAR, OID_BOOL, OID_INT8},
|
||||
"insert_v6_host_option",
|
||||
"INSERT INTO dhcp6_options(code, value, formatted_value, space, "
|
||||
" persistent, host_id, scope_id) "
|
||||
"VALUES ($1, $2, $3, $4, $5, $6, 3)"
|
||||
},
|
||||
|
||||
TaggedStatementArray tagged_statements = { {
|
||||
// PgSqlHostDataSourceImpl::GET_HOST_DHCPID
|
||||
// Retrieves host information, IPv6 reservations and both DHCPv4 and
|
||||
// DHCPv6 options associated with the host. The LEFT JOIN clause is used
|
||||
// to retrieve information from 4 different tables using a single query.
|
||||
// Hence, this query returns multiple rows for a single host.
|
||||
{2,
|
||||
{2,
|
||||
{ OID_BYTEA, OID_INT2 },
|
||||
"get_host_dhcpid",
|
||||
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
|
||||
@@ -1417,7 +1384,7 @@ PgSqlTaggedStatement tagged_statements[] = {
|
||||
// are returned due to left joining IPv6 reservations and DHCPv6 options.
|
||||
// The number of rows returned is multiplication of number of existing
|
||||
// IPv6 reservations and DHCPv6 options.
|
||||
{2,
|
||||
{2,
|
||||
{ OID_VARCHAR, OID_INT2 },
|
||||
"get_host_prefix",
|
||||
"SELECT h.host_id, h.dhcp_identifier, "
|
||||
@@ -1439,14 +1406,59 @@ PgSqlTaggedStatement tagged_statements[] = {
|
||||
|
||||
//PgSqlHostDataSourceImpl::GET_VERSION
|
||||
// Retrieves MySQL schema version.
|
||||
{0,
|
||||
{0,
|
||||
{ OID_NONE },
|
||||
"get_version",
|
||||
"SELECT version, minor FROM schema_version"
|
||||
},
|
||||
|
||||
// Marks the end of the statements table.
|
||||
{0, { 0 }, NULL, NULL}
|
||||
// PgSqlHostDataSourceImpl::INSERT_HOST
|
||||
// Inserts a host into the 'hosts' table. Returns the inserted host id.
|
||||
{8,
|
||||
{ OID_BYTEA, OID_INT2,
|
||||
OID_INT4, OID_INT4, OID_INT8, OID_VARCHAR,
|
||||
OID_VARCHAR, OID_VARCHAR },
|
||||
"insert_host",
|
||||
"INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, "
|
||||
" dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
|
||||
" dhcp4_client_classes, dhcp6_client_classes) "
|
||||
"VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING host_id"
|
||||
},
|
||||
|
||||
//PgSqlHostDataSourceImpl::INSERT_V6_RESRV
|
||||
// Inserts a single IPv6 reservation into 'reservations' table.
|
||||
{5,
|
||||
{ OID_VARCHAR, OID_INT2, OID_INT4, OID_INT4, OID_INT4 },
|
||||
"insert_v6_resrv",
|
||||
"INSERT INTO ipv6_reservations(address, prefix_len, type, "
|
||||
" dhcp6_iaid, host_id) "
|
||||
"VALUES ($1, $2, $3, $4, $5)"
|
||||
},
|
||||
|
||||
// PgSqlHostDataSourceImpl::INSERT_V4_HOST_OPTION
|
||||
// Inserts a single DHCPv4 option into 'dhcp4_options' table.
|
||||
// Using fixed scope_id = 3, which associates an option with host.
|
||||
{6,
|
||||
{ OID_INT2, OID_BYTEA, OID_TEXT,
|
||||
OID_VARCHAR, OID_BOOL, OID_INT8},
|
||||
"insert_v4_host_option",
|
||||
"INSERT INTO dhcp4_options(code, value, formatted_value, space, "
|
||||
" persistent, host_id, scope_id) "
|
||||
"VALUES ($1, $2, $3, $4, $5, $6, 3)"
|
||||
},
|
||||
|
||||
// PgSqlHostDataSourceImpl::INSERT_V6_HOST_OPTION
|
||||
// Inserts a single DHCPv6 option into 'dhcp6_options' table.
|
||||
// Using fixed scope_id = 3, which associates an option with host.
|
||||
{6,
|
||||
{ OID_INT2, OID_BYTEA, OID_TEXT,
|
||||
OID_VARCHAR, OID_BOOL, OID_INT8},
|
||||
"insert_v6_host_option",
|
||||
"INSERT INTO dhcp6_options(code, value, formatted_value, space, "
|
||||
" persistent, host_id, scope_id) "
|
||||
"VALUES ($1, $2, $3, $4, $5, $6, 3)"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}; // end anonymous namespace
|
||||
@@ -1459,20 +1471,37 @@ PgSqlHostDataSourceImpl(const PgSqlConnection::ParameterMap& parameters)
|
||||
DHCP4_AND_DHCP6)),
|
||||
host_ipv6_reservation_exchange_(new PgSqlIPv6ReservationExchange()),
|
||||
host_option_exchange_(new PgSqlOptionExchange()),
|
||||
conn_(parameters) {
|
||||
conn_(parameters),
|
||||
is_readonly_(false) {
|
||||
|
||||
// Open the database.
|
||||
conn_.openDatabase();
|
||||
|
||||
int i = 0;
|
||||
for( ; tagged_statements[i].text != NULL ; ++i) {
|
||||
conn_.prepareStatement(tagged_statements[i]);
|
||||
conn_.prepareStatements(tagged_statements.begin(),
|
||||
tagged_statements.begin() + WRITE_STMTS_BEGIN);
|
||||
|
||||
std::string readonly_value = "false";
|
||||
try {
|
||||
readonly_value = conn_.getParameter("readonly");
|
||||
boost::algorithm::to_lower(readonly_value);
|
||||
} catch (...) {
|
||||
// Parameter "readonly" hasn't been specified so we simply use
|
||||
// the default value of "false".
|
||||
}
|
||||
|
||||
// Just in case somebody foo-barred things
|
||||
if (i != NUM_STATEMENTS) {
|
||||
isc_throw(DbOpenError, "Number of statements prepared: " << i
|
||||
<< " does not match expected count:" << NUM_STATEMENTS);
|
||||
if (readonly_value == "true") {
|
||||
is_readonly_ = true;
|
||||
|
||||
} else if (readonly_value != "false") {
|
||||
isc_throw(DbInvalidReadOnly, "invalid value '" << readonly_value
|
||||
<< "' specified for boolean parameter 'readonly'");
|
||||
}
|
||||
|
||||
// If we are using read-write mode for the database we also prepare
|
||||
// statements for INSERTS etc.
|
||||
if (!is_readonly_) {
|
||||
conn_.prepareStatements(tagged_statements.begin() + WRITE_STMTS_BEGIN,
|
||||
tagged_statements.end());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1637,11 +1666,14 @@ std::pair<uint32_t, uint32_t> PgSqlHostDataSourceImpl::getVersion() const {
|
||||
|
||||
PgSqlHostDataSource::
|
||||
PgSqlHostDataSource(const PgSqlConnection::ParameterMap& parameters)
|
||||
: impl_(new PgSqlHostDataSourceImpl(parameters)) {
|
||||
: impl_(new PgSqlHostDataSourceImpl(parameters),
|
||||
"PostgreSQL host database backend is configured to"
|
||||
" operate in read only mode") {
|
||||
impl_.allowConstOnly(impl_->is_readonly_);
|
||||
}
|
||||
|
||||
PgSqlHostDataSource::~PgSqlHostDataSource() {
|
||||
delete impl_;
|
||||
delete impl_.getPtr();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1894,5 +1926,16 @@ std::pair<uint32_t, uint32_t> PgSqlHostDataSource::getVersion() const {
|
||||
return(impl_->getVersion());
|
||||
}
|
||||
|
||||
void
|
||||
PgSqlHostDataSource::commit() {
|
||||
impl_->conn_.commit();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PgSqlHostDataSource::rollback() {
|
||||
impl_->conn_.rollback();
|
||||
}
|
||||
|
||||
}; // end of isc::dhcp namespace
|
||||
}; // end of isc namespace
|
||||
|
Reference in New Issue
Block a user