Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sebastian Schrader
Kea
Commits
4e0e41f0
Commit
4e0e41f0
authored
Jul 28, 2016
by
Marcin Siodelski
Browse files
[4489] Added support for read only mode in PostgreSQL HR backend.
parent
ef05ff33
Changes
4
Hide whitespace changes
Inline
Side-by-side
src/lib/dhcpsrv/pgsql_connection.cc
View file @
4e0e41f0
...
...
@@ -129,6 +129,16 @@ PgSqlConnection::prepareStatement(const PgSqlTaggedStatement& statement) {
}
}
void
PgSqlConnection
::
prepareStatements
(
const
PgSqlTaggedStatement
*
start_statement
,
const
PgSqlTaggedStatement
*
end_statement
)
{
// Created the PostgreSQL prepared statements.
for
(
const
PgSqlTaggedStatement
*
tagged_statement
=
start_statement
;
tagged_statement
!=
end_statement
;
++
tagged_statement
)
{
prepareStatement
(
*
tagged_statement
);
}
}
void
PgSqlConnection
::
openDatabase
()
{
string
dbconnparameters
;
...
...
src/lib/dhcpsrv/pgsql_connection.h
View file @
4e0e41f0
...
...
@@ -313,6 +313,17 @@ public:
/// failed.
void
prepareStatement
(
const
PgSqlTaggedStatement
&
statement
);
/// @brief Prepare statements
///
/// Creates the prepared statements for all of the SQL statements used
/// by the PostgreSQL backend.
/// @param tagged_statements an array of statements to be compiled
///
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
void
prepareStatements
(
const
PgSqlTaggedStatement
*
start_statement
,
const
PgSqlTaggedStatement
*
end_statement
);
/// @brief Open Database
///
/// Opens the database using the information supplied in the parameters
...
...
src/lib/dhcpsrv/pgsql_host_data_source.cc
View file @
4e0e41f0
...
...
@@ -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".
}
if
(
readonly_value
==
"true"
)
{
is_readonly_
=
true
;
}
else
if
(
readonly_value
!=
"false"
)
{
isc_throw
(
DbInvalidReadOnly
,
"invalid value '"
<<
readonly_value
<<
"' specified for boolean parameter 'readonly'"
);
}
// 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 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
src/lib/dhcpsrv/pgsql_host_data_source.h
View file @
4e0e41f0
...
...
@@ -8,8 +8,10 @@
#define PGSQL_HOST_DATA_SOURCE_H
#include
<dhcpsrv/base_host_data_source.h>
#include
<dhcpsrv/db_exceptions.h>
#include
<dhcpsrv/pgsql_connection.h>
#include
<dhcpsrv/pgsql_exchange.h>
#include
<util/pointer_util.h>
namespace
isc
{
namespace
dhcp
{
...
...
@@ -273,10 +275,20 @@ public:
/// has failed.
virtual
std
::
pair
<
uint32_t
,
uint32_t
>
getVersion
()
const
;
/// @brief Commit Transactions
///
/// Commits all pending database operations.
virtual
void
commit
();
/// @brief Rollback Transactions
///
/// Rolls back all pending database operations.
virtual
void
rollback
();
private:
/// @brief Pointer to the implementation of the @ref PgSqlHostDataSource.
PgSqlHostDataSourceImpl
*
impl_
;
util
::
RestrictedConstPtr
<
PgSqlHostDataSourceImpl
,
ReadOnlyDb
>
impl_
;
};
}
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment