2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-30 21:45:37 +00:00

[#2722] config set follows the same path as config test and can rollback

This commit is contained in:
Razvan Becheriu
2023-02-26 17:23:40 +02:00
parent 66df0bd1d7
commit db352cc04c
16 changed files with 251 additions and 182 deletions

View File

@@ -321,29 +321,11 @@ void configureCommandChannel() {
}
isc::data::ConstElementPtr
configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
bool check_only) {
if (!config_set) {
ConstElementPtr answer = isc::config::createAnswer(CONTROL_RESULT_ERROR,
string("Can't parse NULL config"));
return (answer);
}
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND, DHCP4_CONFIG_START)
.arg(server.redactConfig(config_set)->str());
processDhcp4Config(isc::data::ConstElementPtr config_set) {
// Before starting any subnet operations, let's reset the subnet-id counter,
// so newly recreated configuration starts with first subnet-id equal 1.
Subnet::resetSubnetID();
// Close DHCP sockets and remove any existing timers.
if (!check_only) {
IfaceMgr::instance().closeSockets();
TimerMgr::instance()->unregisterTimers();
server.discardPackets();
server.getCBControl()->reset();
}
// Revert any runtime option definitions configured so far and not committed.
LibDHCP::revertRuntimeOptionDefs();
// Let's set empty container in case a user hasn't specified any configuration
@@ -355,9 +337,7 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
// Answer will hold the result.
ConstElementPtr answer;
// Rollback informs whether error occurred and original data
// have to be restored to global storages.
bool rollback = false;
// Global parameter name in case of an error.
string parameter_name;
ElementPtr mutable_cfg;
@@ -459,7 +439,7 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
ConstElementPtr ifaces_config = mutable_cfg->get("interfaces-config");
if (ifaces_config) {
parameter_name = "interfaces-config";
IfacesConfigParser parser(AF_INET, check_only);
IfacesConfigParser parser(AF_INET, true);
CfgIfacePtr cfg_iface = srv_config->getCfgIface();
parser.parse(cfg_iface, ifaces_config);
}
@@ -740,25 +720,95 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_FAIL)
.arg(parameter_name).arg(ex.what());
answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, ex.what());
// An error occurred, so make sure that we restore original data.
rollback = true;
} catch (...) {
// For things like bad_cast in boost::lexical_cast
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_EXCEPTION).arg(parameter_name);
answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
" processing error");
answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration "
"processing error");
}
// An error occurred, so make sure that we restore original data.
if (!answer) {
answer = isc::config::createAnswer(CONTROL_RESULT_SUCCESS, "Configuration seems sane. "
"Control-socket, hook-libraries, and D2 configuration "
"were sanity checked, but not applied.");
}
return (answer);
}
isc::data::ConstElementPtr
configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
bool check_only) {
if (!config_set) {
ConstElementPtr answer = isc::config::createAnswer(CONTROL_RESULT_ERROR,
"Can't parse NULL config");
return (answer);
}
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND, DHCP4_CONFIG_START)
.arg(server.redactConfig(config_set)->str());
// Rollback informs whether error occurred and original data
// have to be restored to global storages.
bool rollback = false;
auto answer = processDhcp4Config(config_set);
int status_code = 0;
isc::config::parseAnswer(status_code, answer);
if (status_code != CONTROL_RESULT_SUCCESS) {
rollback = true;
}
if (check_only) {
rollback = true;
if (!answer) {
answer = isc::config::createAnswer(CONTROL_RESULT_SUCCESS,
"Configuration seems sane. Control-socket, hook-libraries, and D2 "
"configuration were sanity checked, but not applied.");
SrvConfigPtr srv_config;
if (!rollback) {
if (!check_only) {
string parameter_name;
ElementPtr mutable_cfg;
// Close DHCP sockets and remove any existing timers.
IfaceMgr::instance().closeSockets();
TimerMgr::instance()->unregisterTimers();
server.discardPackets();
server.getCBControl()->reset();
try {
// Get the staging configuration.
srv_config = CfgMgr::instance().getStagingCfg();
// This is a way to convert ConstElementPtr to ElementPtr.
// We need a config that can be edited, because we will insert
// default values and will insert derived values as well.
mutable_cfg = boost::const_pointer_cast<Element>(config_set);
ConstElementPtr ifaces_config = mutable_cfg->get("interfaces-config");
if (ifaces_config) {
parameter_name = "interfaces-config";
IfacesConfigParser parser(AF_INET, false);
CfgIfacePtr cfg_iface = srv_config->getCfgIface();
cfg_iface->reset();
parser.parse(cfg_iface, ifaces_config);
}
} catch (const isc::Exception& ex) {
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_FAIL)
.arg(parameter_name).arg(ex.what());
answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, ex.what());
// An error occurred, so make sure that we restore original data.
rollback = true;
} catch (...) {
// For things like bad_cast in boost::lexical_cast
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_EXCEPTION).arg(parameter_name);
answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
" processing error");
// An error occurred, so make sure that we restore original data.
rollback = true;
}
} else {
rollback = true;
}
}