mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 22:15:23 +00:00
[#549] implement reservation-update
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2015-2022 Internet Systems Consortium, Inc. ("ISC")
|
// Copyright (C) 2015-2023 Internet Systems Consortium, Inc. ("ISC")
|
||||||
//
|
//
|
||||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
// 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
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
@@ -85,6 +85,14 @@ public:
|
|||||||
isc::Exception(file, line, what) {}
|
isc::Exception(file, line, what) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @brief Thrown when it is expected that some rows are affected,
|
||||||
|
/// usually during a DELETE or an UPDATE, but none are.
|
||||||
|
class NoRowsAffected : public Exception {
|
||||||
|
public:
|
||||||
|
NoRowsAffected(const char* file, size_t line, const char* what) :
|
||||||
|
isc::Exception(file, line, what) {}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace isc
|
} // namespace isc
|
||||||
} // namespace db
|
} // namespace db
|
||||||
|
|
||||||
|
@@ -25,6 +25,13 @@ public:
|
|||||||
isc::Exception(file, line, what) { };
|
isc::Exception(file, line, what) { };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @brief Exception thrown when a @c Host object is expected, but none are found.
|
||||||
|
class HostNotFound : public Exception {
|
||||||
|
public:
|
||||||
|
HostNotFound(const char* file, size_t line, const char* what) :
|
||||||
|
isc::Exception(file, line, what) { };
|
||||||
|
};
|
||||||
|
|
||||||
/// @brief Exception thrown when an address is already reserved by a @c Host
|
/// @brief Exception thrown when an address is already reserved by a @c Host
|
||||||
/// object (DuplicateHost is same identity, ReservedAddress same address).
|
/// object (DuplicateHost is same identity, ReservedAddress same address).
|
||||||
class ReservedAddress : public Exception {
|
class ReservedAddress : public Exception {
|
||||||
@@ -452,6 +459,13 @@ public:
|
|||||||
const Host::IdentifierType& identifier_type,
|
const Host::IdentifierType& identifier_type,
|
||||||
const uint8_t* identifier_begin, const size_t identifier_len) = 0;
|
const uint8_t* identifier_begin, const size_t identifier_len) = 0;
|
||||||
|
|
||||||
|
/// @brief Attempts to update an existing host entry.
|
||||||
|
///
|
||||||
|
/// @param host the host up to date with the requested changes
|
||||||
|
///
|
||||||
|
/// @return true if deletion was successful, false if the host was not there.
|
||||||
|
virtual void update(HostPtr const& host) = 0;
|
||||||
|
|
||||||
/// @brief Return backend type
|
/// @brief Return backend type
|
||||||
///
|
///
|
||||||
/// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
|
/// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
|
||||||
@@ -516,7 +530,7 @@ typedef boost::shared_ptr<BaseHostDataSource> HostDataSourcePtr;
|
|||||||
/// @brief HostDataSource list
|
/// @brief HostDataSource list
|
||||||
typedef std::vector<HostDataSourcePtr> HostDataSourceList;
|
typedef std::vector<HostDataSourcePtr> HostDataSourceList;
|
||||||
|
|
||||||
}
|
} // namespace dhcp
|
||||||
}
|
} // namespace isc
|
||||||
|
|
||||||
#endif // BASE_HOST_DATA_SOURCE_H
|
#endif // BASE_HOST_DATA_SOURCE_H
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
using namespace isc::asiolink;
|
using namespace isc::asiolink;
|
||||||
using namespace isc::data;
|
using namespace isc::data;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
namespace isc {
|
namespace isc {
|
||||||
namespace dhcp {
|
namespace dhcp {
|
||||||
@@ -1141,6 +1142,24 @@ CfgHosts::del6(const SubnetID& /*subnet_id*/,
|
|||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CfgHosts::update(HostPtr const& host) {
|
||||||
|
bool deleted(false);
|
||||||
|
if (CfgMgr::instance().getFamily() == AF_INET) {
|
||||||
|
vector<uint8_t> const& identifier(host->getIdentifier());
|
||||||
|
deleted = del4(host->getIPv4SubnetID(), host->getIdentifierType(), identifier.data(),
|
||||||
|
identifier.size());
|
||||||
|
} else {
|
||||||
|
vector<uint8_t> const& identifier(host->getIdentifier());
|
||||||
|
deleted = del6(host->getIPv6SubnetID(), host->getIdentifierType(), identifier.data(),
|
||||||
|
identifier.size());
|
||||||
|
}
|
||||||
|
if (!deleted) {
|
||||||
|
isc_throw(HostNotFound, "Host not updated (not found).");
|
||||||
|
}
|
||||||
|
add(host);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CfgHosts::setIPReservationsUnique(const bool unique) {
|
CfgHosts::setIPReservationsUnique(const bool unique) {
|
||||||
ip_reservations_unique_ = unique;
|
ip_reservations_unique_ = unique;
|
||||||
|
@@ -589,6 +589,9 @@ public:
|
|||||||
const Host::IdentifierType& identifier_type,
|
const Host::IdentifierType& identifier_type,
|
||||||
const uint8_t* identifier_begin, const size_t identifier_len);
|
const uint8_t* identifier_begin, const size_t identifier_len);
|
||||||
|
|
||||||
|
/// @brief Implements @ref BaseHostDataSource::update() for config hosts.
|
||||||
|
void update(HostPtr const& host);
|
||||||
|
|
||||||
/// @brief Return backend type
|
/// @brief Return backend type
|
||||||
///
|
///
|
||||||
/// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
|
/// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
|
||||||
|
@@ -617,6 +617,21 @@ HostMgr::del6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_
|
|||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HostMgr::update(HostPtr const& host) {
|
||||||
|
if (alternate_sources_.empty()) {
|
||||||
|
isc_throw(NoHostDataSourceManager,
|
||||||
|
"Unable to update existing host because there is no hosts-database configured.");
|
||||||
|
}
|
||||||
|
for (HostDataSourcePtr const& source : alternate_sources_) {
|
||||||
|
source->update(host);
|
||||||
|
}
|
||||||
|
// If no backend throws the host should be cached.
|
||||||
|
if (cache_ptr_) {
|
||||||
|
cache(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
HostMgr::cache(ConstHostPtr host) const {
|
HostMgr::cache(ConstHostPtr host) const {
|
||||||
if (cache_ptr_) {
|
if (cache_ptr_) {
|
||||||
|
@@ -555,6 +555,9 @@ public:
|
|||||||
del6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
|
del6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
|
||||||
const uint8_t* identifier_begin, const size_t identifier_len);
|
const uint8_t* identifier_begin, const size_t identifier_len);
|
||||||
|
|
||||||
|
/// @brief Implements @ref BaseHostDataSource::update() for alternate sources.
|
||||||
|
void update(HostPtr const& host);
|
||||||
|
|
||||||
/// @brief Return backend type
|
/// @brief Return backend type
|
||||||
///
|
///
|
||||||
/// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
|
/// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
|
||||||
|
@@ -3921,6 +3921,45 @@ MySqlHostDataSource::getAll6(const SubnetID& subnet_id,
|
|||||||
return (collection);
|
return (collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MySqlHostDataSource::update(HostPtr const& host) {
|
||||||
|
// Get a context.
|
||||||
|
MySqlHostContextAlloc const context(*impl_);
|
||||||
|
MySqlHostContextPtr ctx(context.ctx_);
|
||||||
|
|
||||||
|
// If operating in read-only mode, throw exception.
|
||||||
|
impl_->checkReadOnly(ctx);
|
||||||
|
|
||||||
|
// Initiate MySQL transaction as we will have to make multiple queries
|
||||||
|
// to update host information into multiple tables. If that fails on
|
||||||
|
// any stage, the transaction will be rolled back by the destructor of
|
||||||
|
// the MySqlTransaction class.
|
||||||
|
MySqlTransaction transaction(ctx->conn_);
|
||||||
|
|
||||||
|
// As much as having dedicated prepared statements for updating tables would be consistent with
|
||||||
|
// the implementation of other commands, it's difficult if not impossible to cover all cases for
|
||||||
|
// updating the host to exactly as is described in the command, which may involve inserts and
|
||||||
|
// deletes alongside updates. So let's delete and add. The delete cascades into all tables. The
|
||||||
|
// add explicitly adds into all tables.
|
||||||
|
bool deleted(false);
|
||||||
|
if (CfgMgr::instance().getFamily() == AF_INET) {
|
||||||
|
vector<uint8_t> const& identifier(host->getIdentifier());
|
||||||
|
deleted = del4(host->getIPv4SubnetID(), host->getIdentifierType(), identifier.data(),
|
||||||
|
identifier.size());
|
||||||
|
} else {
|
||||||
|
vector<uint8_t> const& identifier(host->getIdentifier());
|
||||||
|
deleted = del6(host->getIPv6SubnetID(), host->getIdentifierType(), identifier.data(),
|
||||||
|
identifier.size());
|
||||||
|
}
|
||||||
|
if (!deleted) {
|
||||||
|
isc_throw(NoRowsAffected, "Host not updated (not found).");
|
||||||
|
}
|
||||||
|
add(host);
|
||||||
|
|
||||||
|
// Everything went fine, so explicitly commit the transaction.
|
||||||
|
transaction.commit();
|
||||||
|
}
|
||||||
|
|
||||||
// Miscellaneous database methods.
|
// Miscellaneous database methods.
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
|
@@ -403,6 +403,9 @@ public:
|
|||||||
getAll6(const SubnetID& subnet_id,
|
getAll6(const SubnetID& subnet_id,
|
||||||
const asiolink::IOAddress& address) const;
|
const asiolink::IOAddress& address) const;
|
||||||
|
|
||||||
|
/// @brief Implements @ref BaseHostDataSource::update() for MySQL.
|
||||||
|
void update(HostPtr const& host);
|
||||||
|
|
||||||
/// @brief Return backend type
|
/// @brief Return backend type
|
||||||
///
|
///
|
||||||
/// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
|
/// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
|
||||||
|
@@ -3191,6 +3191,45 @@ PgSqlHostDataSource::getAll6(const SubnetID& subnet_id,
|
|||||||
return (collection);
|
return (collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PgSqlHostDataSource::update(HostPtr const& host) {
|
||||||
|
// Get a context.
|
||||||
|
PgSqlHostContextAlloc const context(*impl_);
|
||||||
|
PgSqlHostContextPtr ctx(context.ctx_);
|
||||||
|
|
||||||
|
// If operating in read-only mode, throw exception.
|
||||||
|
impl_->checkReadOnly(ctx);
|
||||||
|
|
||||||
|
// Initiate PostgreSQL transaction as we will have to make multiple queries
|
||||||
|
// to update host information into multiple tables. If that fails on
|
||||||
|
// any stage, the transaction will be rolled back by the destructor of
|
||||||
|
// the PgSqlTransaction class.
|
||||||
|
PgSqlTransaction transaction(ctx->conn_);
|
||||||
|
|
||||||
|
// As much as having dedicated prepared statements for updating tables would be consistent with
|
||||||
|
// the implementation of other commands, it's difficult if not impossible to cover all cases for
|
||||||
|
// updating the host to exactly as is described in the command, which may involve inserts and
|
||||||
|
// deletes alongside updates. So let's delete and add. The delete cascades into all tables. The
|
||||||
|
// add explicitly adds into all tables.
|
||||||
|
bool deleted(false);
|
||||||
|
if (CfgMgr::instance().getFamily() == AF_INET) {
|
||||||
|
vector<uint8_t> const& identifier(host->getIdentifier());
|
||||||
|
deleted = del4(host->getIPv4SubnetID(), host->getIdentifierType(), identifier.data(),
|
||||||
|
identifier.size());
|
||||||
|
} else {
|
||||||
|
vector<uint8_t> const& identifier(host->getIdentifier());
|
||||||
|
deleted = del6(host->getIPv6SubnetID(), host->getIdentifierType(), identifier.data(),
|
||||||
|
identifier.size());
|
||||||
|
}
|
||||||
|
if (!deleted) {
|
||||||
|
isc_throw(NoRowsAffected, "Host not updated (not found).");
|
||||||
|
}
|
||||||
|
add(host);
|
||||||
|
|
||||||
|
// Everything went fine, so explicitly commit the transaction.
|
||||||
|
transaction.commit();
|
||||||
|
}
|
||||||
|
|
||||||
// Miscellaneous database methods.
|
// Miscellaneous database methods.
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
|
@@ -451,6 +451,9 @@ public:
|
|||||||
getAll6(const SubnetID& subnet_id,
|
getAll6(const SubnetID& subnet_id,
|
||||||
const asiolink::IOAddress& address) const;
|
const asiolink::IOAddress& address) const;
|
||||||
|
|
||||||
|
/// @brief Implements @ref BaseHostDataSource::update() for PostgreSQL.
|
||||||
|
void update(HostPtr const& host);
|
||||||
|
|
||||||
/// @brief Return backend type
|
/// @brief Return backend type
|
||||||
///
|
///
|
||||||
/// Returns the type of database as the string "postgresql". This is
|
/// Returns the type of database as the string "postgresql". This is
|
||||||
|
Reference in New Issue
Block a user