Commit 079b862c authored by Thomas Markwalder's avatar Thomas Markwalder
Browse files

[3086] Merge branch 'trac3086'

Adds the initial implementation of b10-dhcp-ddns NameChangeTransaction class.
This class is an abstract, state-model driven class which provides the basic
mechanics for performing DDNS updates based on a NameChangeRequest.
parents 9b97fd86 351b73dc
......@@ -59,6 +59,7 @@ b10_dhcp_ddns_SOURCES += d2_update_message.cc d2_update_message.h
b10_dhcp_ddns_SOURCES += d2_update_mgr.cc d2_update_mgr.h
b10_dhcp_ddns_SOURCES += d2_zone.cc d2_zone.h
b10_dhcp_ddns_SOURCES += dns_client.cc dns_client.h
b10_dhcp_ddns_SOURCES += nc_trans.cc nc_trans.h
nodist_b10_dhcp_ddns_SOURCES = d2_messages.h d2_messages.cc
EXTRA_DIST += d2_messages.mes
......
......@@ -252,3 +252,9 @@ in event loop.
% DHCP_DDNS_SHUTDOWN application received shutdown command with args: %1
This is informational message issued when the application has been instructed
to shut down by the controller.
% DHCP_DDNS_TRANS_PROCESS_EROR application encountered an unexpected error while carrying out a NameChangeRequest: %1
This is error message issued when the application fails to process a
NameChangeRequest correctly. Some or all of the DNS updates requested as part
of this update did not succeed. This is a programmatic error and should be
reported.
......@@ -77,7 +77,7 @@ D2UpdateMgr::checkFinishedTransactions() {
// NOTE: One must use postfix increments of the iterator on the calls
// to erase. This replaces the old iterator which becomes invalid by the
// erase with a the next valid iterator. Prefix incrementing will not
// work.
// work.
TransactionList::iterator it = transaction_list_.begin();
while (it != transaction_list_.end()) {
NameChangeTransactionPtr trans = (*it).second;
......
......@@ -22,6 +22,7 @@
#include <d2/d2_log.h>
#include <d2/d2_queue_mgr.h>
#include <d2/d2_cfg_mgr.h>
#include <d2/nc_trans.h>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
......@@ -37,58 +38,9 @@ public:
isc::Exception(file, line, what) { };
};
//@{
/// @todo This is a stub implementation of NameChangeTransaction that is here
/// strictly to facilitate development of D2UpdateMgr. It will move to its own
/// source file(s) once NameChangeTransaction class development begins.
/// @brief Defines the key for transactions.
typedef isc::dhcp_ddns::D2Dhcid TransactionKey;
class NameChangeTransaction {
public:
NameChangeTransaction(isc::asiolink::IOService& io_service,
dhcp_ddns::NameChangeRequestPtr& ncr,
DdnsDomainPtr forward_domain,
DdnsDomainPtr reverse_domain)
: io_service_(io_service), ncr_(ncr), forward_domain_(forward_domain),
reverse_domain_(reverse_domain) {
}
~NameChangeTransaction(){
}
const dhcp_ddns::NameChangeRequestPtr& getNcr() const {
return (ncr_);
}
const TransactionKey& getTransactionKey() const {
return (ncr_->getDhcid());
}
dhcp_ddns::NameChangeStatus getNcrStatus() const {
return (ncr_->getStatus());
}
private:
isc::asiolink::IOService& io_service_;
dhcp_ddns::NameChangeRequestPtr ncr_;
DdnsDomainPtr forward_domain_;
DdnsDomainPtr reverse_domain_;
};
/// @brief Defines a pointer to a NameChangeTransaction.
typedef boost::shared_ptr<NameChangeTransaction> NameChangeTransactionPtr;
//@}
/// @brief Defines a list of transactions.
typedef std::map<TransactionKey, NameChangeTransactionPtr> TransactionList;
/// @brief D2UpdateMgr creates and manages update transactions.
///
/// D2UpdateMgr is the DHCP_DDNS task master, instantiating and then supervising
......
// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <d2/d2_log.h>
#include <d2/nc_trans.h>
namespace isc {
namespace d2 {
// Common transaction states
const int NameChangeTransaction::NEW_ST;
const int NameChangeTransaction::READY_ST;
const int NameChangeTransaction::SELECTING_FWD_SERVER_ST;
const int NameChangeTransaction::SELECTING_REV_SERVER_ST;
const int NameChangeTransaction::DONE_ST;
const int NameChangeTransaction::DERIVED_STATES;
// Common transaction events
const int NameChangeTransaction::NOP_EVT;
const int NameChangeTransaction::START_TRANSACTION_EVT;
const int NameChangeTransaction::SELECT_SERVER_EVT;
const int NameChangeTransaction::SERVER_SELECTED_EVT;
const int NameChangeTransaction::SERVER_IO_ERROR_EVT;
const int NameChangeTransaction::NO_MORE_SERVERS_EVT;
const int NameChangeTransaction::IO_COMPLETED_EVT;
const int NameChangeTransaction::UPDATE_OK_EVT;
const int NameChangeTransaction::UPDATE_FAILED_EVT;
const int NameChangeTransaction::ALL_DONE_EVT;
const int NameChangeTransaction::DERIVED_EVENTS;
NameChangeTransaction::
NameChangeTransaction(isc::asiolink::IOService& io_service,
dhcp_ddns::NameChangeRequestPtr& ncr,
DdnsDomainPtr& forward_domain,
DdnsDomainPtr& reverse_domain)
: state_handlers_(), io_service_(io_service), ncr_(ncr),
forward_domain_(forward_domain), reverse_domain_(reverse_domain),
dns_client_(), state_(NEW_ST), next_event_(NOP_EVT),
dns_update_status_(DNSClient::OTHER), dns_update_response_(),
forward_change_completed_(false), reverse_change_completed_(false),
current_server_list_(), current_server_(), next_server_pos_(0) {
if (!ncr_) {
isc_throw(NameChangeTransactionError, "NameChangeRequest cannot null");
}
if (ncr_->isForwardChange() && !(forward_domain_)) {
isc_throw(NameChangeTransactionError,
"Forward change must have a forward domain");
}
if (ncr_->isReverseChange() && !(reverse_domain_)) {
isc_throw(NameChangeTransactionError,
"Reverse change must have a reverse domain");
}
// Use setters here so we get proper values for previous state, last event.
setState(state_);
setNextEvent(NOP_EVT);
}
NameChangeTransaction::~NameChangeTransaction(){
}
void
NameChangeTransaction::startTransaction() {
// Initialize the state handler map first.
initStateHandlerMap();
// Test validity of the handler map. This provides an opportunity to
// sanity check the map prior to attempting to execute the model.
verifyStateHandlerMap();
// Set the current state to READY and enter the run loop.
setState(READY_ST);
runStateModel(START_TRANSACTION_EVT);
}
void
NameChangeTransaction::operator()(DNSClient::Status status) {
// Stow the completion status and re-enter the run loop with the event
// set to indicate IO completed.
// runStateModel is exception safe so we are good to call it here.
// It won't exit until we hit the next IO wait or the state model ends.
setDnsUpdateStatus(status);
runStateModel(IO_COMPLETED_EVT);
}
void
NameChangeTransaction::runStateModel(unsigned int run_event) {
try {
// Seed the loop with the given event as the next to process.
setNextEvent(run_event);
do {
// Invoke the current state's handler. It should consume the
// next event, then determine what happens next by setting
// current state and/or the next event.
(getStateHandler(state_))();
// Keep going until a handler sets next event to a NOP_EVT.
} while (getNextEvent() != NOP_EVT);
}
catch (const std::exception& ex) {
// Transaction has suffered an unexpected exception. This indicates
// a programmatic shortcoming. Log it and set status to ST_FAILED.
// In theory, the model should account for all error scenarios and
// deal with them accordingly.
LOG_ERROR(dctl_logger, DHCP_DDNS_TRANS_PROCESS_EROR).arg(ex.what());
setNcrStatus(dhcp_ddns::ST_FAILED);
}
}
StateHandler
NameChangeTransaction::getStateHandler(unsigned int state) {
StateHandlerMap::iterator it = state_handlers_.find(state);
if (it == state_handlers_.end()) {
isc_throw(NameChangeTransactionError, "Invalid state: " << state);
}
return ((*it).second);
}
void
NameChangeTransaction::addToMap(unsigned int state, StateHandler handler) {
StateHandlerMap::iterator it = state_handlers_.find(state);
if (it != state_handlers_.end()) {
isc_throw(NameChangeTransactionError,
"Attempted duplicate entry in state handler mape, state: "
<< state);
}
state_handlers_[state] = handler;
}
void
NameChangeTransaction::setState(unsigned int state) {
prev_state_ = state_;
state_ = state;
}
void
NameChangeTransaction::setNextEvent(unsigned int event) {
last_event_ = next_event_;
next_event_ = event;
}
void
NameChangeTransaction::setDnsUpdateStatus(const DNSClient::Status& status) {
dns_update_status_ = status;
}
void
NameChangeTransaction::setForwardChangeCompleted(const bool value) {
forward_change_completed_ = value;
}
void
NameChangeTransaction::setReverseChangeCompleted(const bool value) {
reverse_change_completed_ = value;
}
const dhcp_ddns::NameChangeRequestPtr&
NameChangeTransaction::getNcr() const {
return (ncr_);
}
const TransactionKey&
NameChangeTransaction::getTransactionKey() const {
return (ncr_->getDhcid());
}
dhcp_ddns::NameChangeStatus
NameChangeTransaction::getNcrStatus() const {
return (ncr_->getStatus());
}
DdnsDomainPtr&
NameChangeTransaction::getForwardDomain() {
return (forward_domain_);
}
DdnsDomainPtr&
NameChangeTransaction::getReverseDomain() {
return (reverse_domain_);
}
void
NameChangeTransaction::initServerSelection(const DdnsDomainPtr& domain) {
if (!domain) {
isc_throw(NameChangeTransactionError,
"initServerSelection called with an empty domain");
}
current_server_list_ = domain->getServers();
next_server_pos_ = 0;
current_server_.reset();
}
bool
NameChangeTransaction::selectNextServer() {
if ((current_server_list_) &&
(next_server_pos_ < current_server_list_->size())) {
current_server_ = (*current_server_list_)[next_server_pos_];
dns_update_response_.reset(new
D2UpdateMessage(D2UpdateMessage::INBOUND));
// @todo Protocol is set on DNSClient constructor. We need
// to propagate a configuration value downward, probably starting
// at global, then domain, then server
// Once that is supported we need to add it here.
dns_client_.reset(new DNSClient(dns_update_response_ , this,
DNSClient::UDP));
++next_server_pos_;
return (true);
}
return (false);
}
const DNSClientPtr&
NameChangeTransaction::getDNSClient() const {
return (dns_client_);
}
const DnsServerInfoPtr&
NameChangeTransaction::getCurrentServer() const {
return (current_server_);
}
void
NameChangeTransaction::setNcrStatus(const dhcp_ddns::NameChangeStatus& status) {
return (ncr_->setStatus(status));
}
unsigned int
NameChangeTransaction::getState() const {
return (state_);
}
unsigned int
NameChangeTransaction::getPrevState() const {
return (prev_state_);
}
unsigned int
NameChangeTransaction::getLastEvent() const {
return (last_event_);
}
unsigned int
NameChangeTransaction::getNextEvent() const {
return (next_event_);
}
DNSClient::Status
NameChangeTransaction::getDnsUpdateStatus() const {
return (dns_update_status_);
}
const D2UpdateMessagePtr&
NameChangeTransaction::getDnsUpdateResponse() const {
return (dns_update_response_);
}
bool
NameChangeTransaction::getForwardChangeCompleted() const {
return (forward_change_completed_);
}
bool
NameChangeTransaction::getReverseChangeCompleted() const {
return (reverse_change_completed_);
}
} // namespace isc::d2
} // namespace isc
This diff is collapsed.
......@@ -64,6 +64,7 @@ d2_unittests_SOURCES += ../d2_update_message.cc ../d2_update_message.h
d2_unittests_SOURCES += ../d2_update_mgr.cc ../d2_update_mgr.h
d2_unittests_SOURCES += ../d2_zone.cc ../d2_zone.h
d2_unittests_SOURCES += ../dns_client.cc ../dns_client.h
d2_unittests_SOURCES += ../nc_trans.cc ../nc_trans.h
d2_unittests_SOURCES += d_test_stubs.cc d_test_stubs.h
d2_unittests_SOURCES += d2_unittests.cc
d2_unittests_SOURCES += d2_process_unittests.cc
......@@ -76,6 +77,7 @@ d2_unittests_SOURCES += d2_update_message_unittests.cc
d2_unittests_SOURCES += d2_update_mgr_unittests.cc
d2_unittests_SOURCES += d2_zone_unittests.cc
d2_unittests_SOURCES += dns_client_unittests.cc
d2_unittests_SOURCES += nc_trans_unittests.cc
nodist_d2_unittests_SOURCES = ../d2_messages.h ../d2_messages.cc
d2_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
......
This diff is collapsed.
......@@ -156,6 +156,14 @@ typedef std::map<std::string, isc::data::ConstElementPtr> ElementMap;
class NameChangeRequest {
public:
/// @brief Default Constructor.
///
/// @todo Currently, fromWire makes use of the ability to create an empty
/// NameChangeRequest and then builds it bit by bit. This means that it
/// is technically possible to create one and attempt to use in ways
/// other than intended and its invalid content may or may not be handled
/// gracefully by consuming code. It might be wise to revisit this
/// structuring such that we do not use a default constructor and only
/// allow valid instantiations.
NameChangeRequest();
/// @brief Constructor. Full constructor, which provides parameters for
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment