Commit dbef8eac authored by Thomas Markwalder's avatar Thomas Markwalder
Browse files

[#32,!23] dhcp6 now parses "config-control" element

parent 71bb1a80
This diff is collapsed.
......@@ -511,6 +511,25 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
\"config-control\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::DHCP6:
return isc::dhcp::Dhcp6Parser::make_CONFIG_CONTROL(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("config-control", driver.loc_);
}
}
\"config-databases\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::CONFIG_CONTROL:
return isc::dhcp::Dhcp6Parser::make_CONFIG_DATABASES(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("config-databases", driver.loc_);
}
}
\"readonly\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
......@@ -526,6 +545,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::OPTION_DEF:
case isc::dhcp::Parser6Context::SERVER_ID:
case isc::dhcp::Parser6Context::CONFIG_DATABASE:
return isc::dhcp::Dhcp6Parser::make_TYPE(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("type", driver.loc_);
......@@ -572,6 +592,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::CONFIG_DATABASE:
return isc::dhcp::Dhcp6Parser::make_USER(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("user", driver.loc_);
......@@ -582,6 +603,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::CONFIG_DATABASE:
return isc::dhcp::Dhcp6Parser::make_PASSWORD(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("password", driver.loc_);
......@@ -592,6 +614,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::CONFIG_DATABASE:
return isc::dhcp::Dhcp6Parser::make_HOST(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("host", driver.loc_);
......@@ -602,6 +625,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::CONFIG_DATABASE:
return isc::dhcp::Dhcp6Parser::make_PORT(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("port", driver.loc_);
......@@ -613,6 +637,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::SERVER_ID:
case isc::dhcp::Parser6Context::CONFIG_DATABASE:
return isc::dhcp::Dhcp6Parser::make_PERSIST(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("persist", driver.loc_);
......@@ -623,6 +648,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::CONFIG_DATABASE:
return isc::dhcp::Dhcp6Parser::make_LFC_INTERVAL(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("lfc-interval", driver.loc_);
......@@ -633,6 +659,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::CONFIG_DATABASE:
return isc::dhcp::Dhcp6Parser::make_CONNECT_TIMEOUT(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("connect-timeout", driver.loc_);
......@@ -643,6 +670,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::CONFIG_DATABASE:
return isc::dhcp::Dhcp6Parser::make_KEYSPACE(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("keyspace", driver.loc_);
......@@ -653,6 +681,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::CONFIG_DATABASE:
return isc::dhcp::Dhcp6Parser::make_RECONNECT_WAIT_TIME(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("reconnect-wait-time", driver.loc_);
......@@ -663,6 +692,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::CONFIG_DATABASE:
return isc::dhcp::Dhcp6Parser::make_REQUEST_TIMEOUT(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("request-timeout", driver.loc_);
......@@ -673,6 +703,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::CONFIG_DATABASE:
return isc::dhcp::Dhcp6Parser::make_TCP_KEEPALIVE(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("tcp-keepalive", driver.loc_);
......@@ -683,6 +714,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::CONFIG_DATABASE:
return isc::dhcp::Dhcp6Parser::make_TCP_NODELAY(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("tcp-nodelay", driver.loc_);
......@@ -693,6 +725,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::CONFIG_DATABASE:
return isc::dhcp::Dhcp6Parser::make_CONTACT_POINTS(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("contact-points", driver.loc_);
......@@ -703,6 +736,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::CONFIG_DATABASE:
return isc::dhcp::Dhcp6Parser::make_MAX_RECONNECT_TRIES(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("max-reconnect-tries", driver.loc_);
......@@ -814,6 +848,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
case isc::dhcp::Parser6Context::CLIENT_CLASSES:
case isc::dhcp::Parser6Context::LOGGERS:
case isc::dhcp::Parser6Context::SHARED_NETWORK:
case isc::dhcp::Parser6Context::CONFIG_DATABASE:
return isc::dhcp::Dhcp6Parser::make_NAME(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("name", driver.loc_);
......
This diff is collapsed.
This diff is collapsed.
......@@ -50,6 +50,8 @@ using namespace std;
NULL_TYPE "null"
DHCP6 "Dhcp6"
CONFIG_CONTROL "config-control"
CONFIG_DATABASES "config-databases"
INTERFACES_CONFIG "interfaces-config"
INTERFACES "interfaces"
RE_DETECT "re-detect"
......@@ -224,6 +226,7 @@ using namespace std;
SUB_HOOKS_LIBRARY
SUB_DHCP_DDNS
SUB_LOGGING
SUB_CONFIG_CONTROL
;
%token <std::string> STRING "constant string"
......@@ -262,6 +265,7 @@ start: TOPLEVEL_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } sub_json
| SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library
| SUB_DHCP_DDNS { ctx.ctx_ = ctx.DHCP_DDNS; } sub_dhcp_ddns
| SUB_LOGGING { ctx.ctx_ = ctx.LOGGING; } sub_logging
| SUB_CONFIG_CONTROL { ctx.ctx_ = ctx.CONFIG_CONTROL; } sub_config_control
;
// ---- generic JSON parser ---------------------------------
......@@ -455,6 +459,7 @@ global_param: preferred_lifetime
| comment
| sanity_checks
| reservations
| config_control
| unknown_map_entry
;
......@@ -2106,6 +2111,56 @@ control_agent_json_object: CONTROL_AGENT {
ctx.leave();
};
// Config control information element
config_control: LCURLY_BRACKET {
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} config_control_params RCURLY_BRACKET {
ctx.stack_.pop_back();
};
config_control: CONFIG_CONTROL {
ElementPtr i(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("config-control", i);
ctx.stack_.push_back(i);
ctx.enter(ctx.CONFIG_CONTROL);
} COLON LCURLY_BRACKET config_control_params RCURLY_BRACKET {
// No config control params are required
ctx.stack_.pop_back();
ctx.leave();
};
sub_config_control: LCURLY_BRACKET {
// Parse the config-control map
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} config_control_params RCURLY_BRACKET {
// No config_control params are required
// parsing completed
};
// This defines that subnet can have one or more parameters.
config_control_params: config_control_param
| config_control_params COMMA config_control_param
;
// This defines a list of allowed parameters for each subnet.
config_control_param: config_databases
| unknown_map_entry
;
config_databases: CONFIG_DATABASES {
ElementPtr l(new ListElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("config-databases", l);
ctx.stack_.push_back(l);
ctx.enter(ctx.CONFIG_DATABASE);
} COLON LSQUARE_BRACKET database_list RSQUARE_BRACKET {
ctx.stack_.pop_back();
ctx.leave();
};
// --- logging entry -----------------------------------------
......
......@@ -37,6 +37,7 @@
#include <dhcpsrv/host_data_source_factory.h>
#include <hooks/hooks_parser.h>
#include <log/logger_support.h>
#include <process/config_ctl_parser.h>
#include <util/encode/hex.h>
#include <util/strutil.h>
......@@ -606,6 +607,13 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
continue;
}
if (config_pair.first == "config-control") {
process::ConfigControlParser parser;
process::ConfigControlInfoPtr config_ctl_info = parser.parse(config_pair.second);
CfgMgr::instance().getStagingCfg()->setConfigControlInfo(config_ctl_info);
continue;
}
// Timers are not used in the global scope. Their values are derived
// to specific subnets (see SimpleParser6::deriveParameters).
// decline-probation-period, dhcp4o6-port and user-context
......
// Generated 201808161138
// Generated 201808161137
// A Bison parser, made by GNU Bison 3.0.5.
// A Bison parser, made by GNU Bison 3.0.4.
// Locations for Bison parsers in C++
// Copyright (C) 2002-2015, 2018 Free Software Foundation, Inc.
// Copyright (C) 2002-2015 Free Software Foundation, Inc.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
......@@ -42,9 +40,9 @@
# include "position.hh"
#line 14 "dhcp6_parser.yy" // location.cc:292
#line 14 "dhcp6_parser.yy" // location.cc:296
namespace isc { namespace dhcp {
#line 46 "location.hh" // location.cc:292
#line 46 "location.hh" // location.cc:296
/// Abstract a location.
class location
{
......@@ -54,27 +52,30 @@ namespace isc { namespace dhcp {
location (const position& b, const position& e)
: begin (b)
, end (e)
{}
{
}
/// Construct a 0-width location in \a p.
explicit location (const position& p = position ())
: begin (p)
, end (p)
{}
{
}
/// Construct a 0-width location in \a f, \a l, \a c.
explicit location (std::string* f,
unsigned l = 1u,
unsigned c = 1u)
unsigned int l = 1u,
unsigned int c = 1u)
: begin (f, l, c)
, end (f, l, c)
{}
{
}
/// Initialization.
void initialize (std::string* f = YY_NULLPTR,
unsigned l = 1u,
unsigned c = 1u)
unsigned int l = 1u,
unsigned int c = 1u)
{
begin.initialize (f, l, c);
end = begin;
......@@ -172,7 +173,7 @@ namespace isc { namespace dhcp {
inline std::basic_ostream<YYChar>&
operator<< (std::basic_ostream<YYChar>& ostr, const location& loc)
{
unsigned end_col = 0 < loc.end.column ? loc.end.column - 1 : 0;
unsigned int end_col = 0 < loc.end.column ? loc.end.column - 1 : 0;
ostr << loc.begin;
if (loc.end.filename
&& (!loc.begin.filename
......@@ -185,7 +186,7 @@ namespace isc { namespace dhcp {
return ostr;
}
#line 14 "dhcp6_parser.yy" // location.cc:292
#line 14 "dhcp6_parser.yy" // location.cc:296
} } // isc::dhcp
#line 189 "location.hh" // location.cc:292
#line 192 "location.hh" // location.cc:296
#endif // !YY_PARSER6_LOCATION_HH_INCLUDED
......@@ -198,6 +198,10 @@ Parser6Context::contextName()
return ("shared-networks");
case SANITY_CHECKS:
return ("sanity-checks");
case CONFIG_CONTROL:
return ("config-control");
case CONFIG_DATABASE:
return ("config-database");
default:
return ("__unknown__");
}
......
......@@ -299,7 +299,13 @@ public:
NCR_FORMAT,
/// Used while parsing Dhcp6/dhcp-ddns/replace-client-name.
REPLACE_CLIENT_NAME
REPLACE_CLIENT_NAME,
/// Used while parsing Dhcp4/config-control
CONFIG_CONTROL,
/// Used while parsing config-control/config-databases
CONFIG_DATABASE
} ParserContext;
......
// Generated 201808161138
// Generated 201808161137
// A Bison parser, made by GNU Bison 3.0.5.
// A Bison parser, made by GNU Bison 3.0.4.
// Positions for Bison parsers in C++
// Copyright (C) 2002-2015, 2018 Free Software Foundation, Inc.
// Copyright (C) 2002-2015 Free Software Foundation, Inc.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
......@@ -52,27 +50,28 @@
# endif
# endif
#line 14 "dhcp6_parser.yy" // location.cc:292
#line 14 "dhcp6_parser.yy" // location.cc:296
namespace isc { namespace dhcp {
#line 56 "position.hh" // location.cc:292
#line 56 "position.hh" // location.cc:296
/// Abstract a position.
class position
{
public:
/// Construct a position.
explicit position (std::string* f = YY_NULLPTR,
unsigned l = 1u,
unsigned c = 1u)
unsigned int l = 1u,
unsigned int c = 1u)
: filename (f)
, line (l)
, column (c)
{}
{
}
/// Initialization.
void initialize (std::string* fn = YY_NULLPTR,
unsigned l = 1u,
unsigned c = 1u)
unsigned int l = 1u,
unsigned int c = 1u)
{
filename = fn;
line = l;
......@@ -101,15 +100,15 @@ namespace isc { namespace dhcp {
/// File name to which this position refers.
std::string* filename;
/// Current line number.
unsigned line;
unsigned int line;
/// Current column number.
unsigned column;
unsigned int column;
private:
/// Compute max(min, lhs+rhs) (provided min <= lhs).
static unsigned add_ (unsigned lhs, int rhs, unsigned min)
static unsigned int add_ (unsigned int lhs, int rhs, unsigned int min)
{
return (0 < rhs || -static_cast<unsigned>(rhs) < lhs
return (0 < rhs || -static_cast<unsigned int>(rhs) < lhs
? rhs + lhs
: min);
}
......@@ -175,7 +174,7 @@ namespace isc { namespace dhcp {
return ostr << pos.line << '.' << pos.column;
}
#line 14 "dhcp6_parser.yy" // location.cc:292
#line 14 "dhcp6_parser.yy" // location.cc:296
} } // isc::dhcp
#line 179 "position.hh" // location.cc:292
#line 180 "position.hh" // location.cc:296
#endif // !YY_PARSER6_POSITION_HH_INCLUDED
// Generated 201808161138
// Generated 201808161137
// A Bison parser, made by GNU Bison 3.0.5.
// A Bison parser, made by GNU Bison 3.0.4.
// Stack handling for Bison parsers in C++
// Copyright (C) 2002-2015, 2018 Free Software Foundation, Inc.
// Copyright (C) 2002-2015 Free Software Foundation, Inc.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
......@@ -42,10 +40,9 @@
# include <vector>
#line 14 "dhcp6_parser.yy" // stack.hh:131
#line 14 "dhcp6_parser.yy" // stack.hh:132
namespace isc { namespace dhcp {
#line 46 "stack.hh" // stack.hh:131
/// A stack with random access from its top.
#line 46 "stack.hh" // stack.hh:132
template <class T, class S = std::vector<T> >
class stack
{
......@@ -60,24 +57,20 @@ namespace isc { namespace dhcp {
seq_.reserve (200);
}
stack (unsigned n)
stack (unsigned int n)
: seq_ (n)
{}
/// Random access.
///
/// Index 0 returns the topmost element.
inline
T&
operator[] (unsigned i)
operator[] (unsigned int i)
{
return seq_[seq_.size () - 1 - i];
}
/// Random access.
///
/// Index 0 returns the topmost element.
inline
const T&
operator[] (unsigned i) const
operator[] (unsigned int i) const
{
return seq_[seq_.size () - 1 - i];
}
......@@ -85,6 +78,7 @@ namespace isc { namespace dhcp {
/// Steal the contents of \a t.
///
/// Close to move-semantics.
inline
void
push (T& t)
{
......@@ -92,8 +86,9 @@ namespace isc { namespace dhcp {
operator[](0).move (t);
}
inline
void
pop (unsigned n = 1)
pop (unsigned int n = 1)
{
for (; n; --n)
seq_.pop_back ();
......@@ -105,18 +100,21 @@ namespace isc { namespace dhcp {
seq_.clear ();
}
inline
typename S::size_type
size () const
{
return seq_.size ();
}
inline
const_iterator
begin () const
{
return seq_.rbegin ();
}
inline
const_iterator
end () const
{
......@@ -135,24 +133,25 @@ namespace isc { namespace dhcp {
class slice
{
public:
slice (const S& stack, unsigned range)
slice (const S& stack, unsigned int range)
: stack_ (stack)
, range_ (range)
{}
inline
const T&
operator [] (unsigned i) const
operator [] (unsigned int i) const
{
return stack_[range_ - i];
}
private:
const S& stack_;
unsigned range_;
unsigned int range_;
};
#line 14 "dhcp6_parser.yy" // stack.hh:131
#line 14 "dhcp6_parser.yy" // stack.hh:132
} } // isc::dhcp
#line 155 "stack.hh" // stack.hh:131
#line 156 "stack.hh" // stack.hh:132
#endif // !YY_PARSER6_STACK_HH_INCLUDED
......@@ -25,6 +25,7 @@
#include <dhcpsrv/subnet_selector.h>
#include <dhcpsrv/testutils/config_result_check.h>
#include <hooks/hooks_manager.h>
#include <process/config_ctl_info.h>
#include "test_data_files_config.h"
#include "test_libraries.h"
......@@ -231,7 +232,31 @@ const char* PARSER_CONFIGS[] = {
" ]"
"}",
// Last configuration for comments
// Configuration 8: config control
"{ \n"
" \"interfaces-config\": { \n"
" \"interfaces\": [\"*\" ] \n"
" }, \n"
" \"valid-lifetime\": 4000, \n"
" \"rebind-timer\": 2000, \n"
" \"renew-timer\": 1000, \n"
" \"config-control\": { \n"
" \"config-databases\": [ { \n"
" \"type\": \"mysql\", \n"
" \"name\": \"keatest1\", \n"
" \"user\": \"keatest\", \n"
" \"password\": \"keatest\" \n"
" },{ \n"
" \"type\": \"mysql\", \n"
" \"name\": \"keatest2\", \n"
" \"user\": \"keatest\", \n"
" \"password\": \"keatest\" \n"
" } \n"
" ] \n"
" } \n"
"} \n",
// Configuration 9 for comments
"{"
" \"comment\": \"A DHCPv6 server\","
" \"server-id\": {"
......@@ -6462,7 +6487,7 @@ TEST_F(Dhcp6ParserTest, hostsDatabases) {
// This test checks comments. Please keep it last.
TEST_F(Dhcp6ParserTest, comments) {
string config = PARSER_CONFIGS[8];
string config = PARSER_CONFIGS[9];
extractConfig(config);
configure(config, CONTROL_RESULT_SUCCESS, "");
......@@ -6828,4 +6853,28 @@ TEST_F(Dhcp6ParserTest, globalReservations) {
EXPECT_EQ(11, static_cast<int>(opt_prf->getValue()));
}
// This test verifies that configuration control info gets populated.
TEST_F(Dhcp6ParserTest, configControlInfo) {
string config = PARSER_CONFIGS[8];
extractConfig(config);
configure(config, CONTROL_RESULT_SUCCESS, "");
// Make sure the config control info is there.
process::ConstConfigControlInfoPtr info =
CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
ASSERT_TRUE(info);
// Fetch the list of config dbs. It should have two entries.
const process::ConfigDbInfoList& dblist = info->getConfigDatabases();
ASSERT_EQ(2, dblist.size());