mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-01 06:25:34 +00:00
[5351] Checkpoint: found a shared-network bug
This commit is contained in:
@@ -120,9 +120,9 @@
|
|||||||
"subnet": "192.0.2.0/24",
|
"subnet": "192.0.2.0/24",
|
||||||
"user-context": {
|
"user-context": {
|
||||||
"comment": "Our first subnet!"
|
"comment": "Our first subnet!"
|
||||||
}
|
},
|
||||||
// Equivalent using smart parser
|
// Equivalent using smart parser
|
||||||
// "comment": "Our first subnet!"
|
"comment": "Our first subnet!"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// This particular subnet has match-client-id value changed.
|
// This particular subnet has match-client-id value changed.
|
||||||
|
@@ -107,7 +107,7 @@
|
|||||||
// Here's the user-context for the whole subnet.
|
// Here's the user-context for the whole subnet.
|
||||||
"user-context": { "comment": "Floor one, west wing" },
|
"user-context": { "comment": "Floor one, west wing" },
|
||||||
// Equivalent using smart parser
|
// Equivalent using smart parser
|
||||||
// "comment": "Floor one, west wing",
|
"comment": "Floor one, west wing",
|
||||||
|
|
||||||
// This defines PD (prefix delegation) pools. In this case
|
// This defines PD (prefix delegation) pools. In this case
|
||||||
// we have only one pool. That consists of /64 prefixes
|
// we have only one pool. That consists of /64 prefixes
|
||||||
|
@@ -5607,4 +5607,74 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDeriveClientClass) {
|
|||||||
EXPECT_TRUE(classes.empty());
|
EXPECT_TRUE(classes.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This test checks comments. Please keep it last.
|
||||||
|
TEST_F(Dhcp4ParserTest, comments) {
|
||||||
|
|
||||||
|
string config = "{\n"
|
||||||
|
"\"shared-networks\": [ {\n"
|
||||||
|
" \"name\": \"foo\"\n,"
|
||||||
|
" \"comment\": \"A shared-network\"\n,"
|
||||||
|
" \"subnet4\": [\n"
|
||||||
|
" { \n"
|
||||||
|
" \"subnet\": \"192.0.1.0/24\",\n"
|
||||||
|
" \"comment\": \"A subnet\"\n,"
|
||||||
|
" \"pools\": [\n"
|
||||||
|
" {\n"
|
||||||
|
" \"pool\": \"192.0.1.1-192.0.1.10\",\n"
|
||||||
|
" \"comment\": \"A pool\"\n"
|
||||||
|
" }\n"
|
||||||
|
" ]\n"
|
||||||
|
" }\n"
|
||||||
|
" ]\n"
|
||||||
|
" } ]\n"
|
||||||
|
"} \n";
|
||||||
|
|
||||||
|
extractConfig(config);
|
||||||
|
configure(config, CONTROL_RESULT_SUCCESS, "");
|
||||||
|
|
||||||
|
// Now verify that the shared network was indeed configured.
|
||||||
|
CfgSharedNetworks4Ptr cfg_net = CfgMgr::instance().getStagingCfg()
|
||||||
|
->getCfgSharedNetworks4();
|
||||||
|
ASSERT_TRUE(cfg_net);
|
||||||
|
const SharedNetwork4Collection* nets = cfg_net->getAll();
|
||||||
|
ASSERT_TRUE(nets);
|
||||||
|
ASSERT_EQ(1, nets->size());
|
||||||
|
SharedNetwork4Ptr net = nets->at(0);
|
||||||
|
ASSERT_TRUE(net);
|
||||||
|
|
||||||
|
// Check shared network user context
|
||||||
|
ConstElementPtr ctx_net = net->getContext();
|
||||||
|
ASSERT_TRUE(ctx_net);
|
||||||
|
ASSERT_EQ(1, ctx_net->size());
|
||||||
|
ASSERT_TRUE(ctx_net->get("comment"));
|
||||||
|
EXPECT_EQ("\"A shared-network\"", ctx_net->get("comment")->str());
|
||||||
|
|
||||||
|
// The shared network has a subnet.
|
||||||
|
const Subnet4Collection * subs = net->getAllSubnets();
|
||||||
|
ASSERT_TRUE(subs);
|
||||||
|
ASSERT_EQ(1, subs->size());
|
||||||
|
Subnet4Ptr sub = subs->at(0);
|
||||||
|
ASSERT_TRUE(sub);
|
||||||
|
|
||||||
|
// Check subnet user context
|
||||||
|
ConstElementPtr ctx_sub = sub->getContext();
|
||||||
|
ASSERT_TRUE(ctx_sub);
|
||||||
|
ASSERT_EQ(1, ctx_sub->size());
|
||||||
|
ASSERT_TRUE(ctx_sub->get("comment"));
|
||||||
|
EXPECT_EQ("\"A subnet\"", ctx_sub->get("comment")->str());
|
||||||
|
|
||||||
|
// The subnet has a pool
|
||||||
|
const PoolCollection& pools = sub->getPools(Lease::TYPE_V4);
|
||||||
|
ASSERT_EQ(1, pools.size());
|
||||||
|
PoolPtr pool = pools.at(0);
|
||||||
|
ASSERT_TRUE(pool);
|
||||||
|
|
||||||
|
// Check pool user context
|
||||||
|
ConstElementPtr ctx_pool = pool->getContext();
|
||||||
|
ASSERT_TRUE(ctx_pool);
|
||||||
|
ASSERT_EQ(1, ctx_pool->size());
|
||||||
|
ASSERT_TRUE(ctx_pool->get("comment"));
|
||||||
|
EXPECT_EQ("\"A pool\"", ctx_pool->get("comment")->str());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#include <cc/data.h>
|
#include <cc/data.h>
|
||||||
#include <dhcp4/parser_context.h>
|
#include <dhcp4/parser_context.h>
|
||||||
#include <testutils/io_utils.h>
|
#include <testutils/io_utils.h>
|
||||||
|
#include <testutils/user_context_utils.h>
|
||||||
|
|
||||||
using namespace isc::data;
|
using namespace isc::data;
|
||||||
using namespace isc::test;
|
using namespace isc::test;
|
||||||
@@ -209,6 +210,7 @@ TEST(ParserTest, multilineComments) {
|
|||||||
///
|
///
|
||||||
/// @param fname name of the file to be loaded
|
/// @param fname name of the file to be loaded
|
||||||
void testFile(const std::string& fname) {
|
void testFile(const std::string& fname) {
|
||||||
|
ElementPtr json;
|
||||||
ElementPtr reference_json;
|
ElementPtr reference_json;
|
||||||
ConstElementPtr test_json;
|
ConstElementPtr test_json;
|
||||||
|
|
||||||
@@ -216,7 +218,8 @@ void testFile(const std::string& fname) {
|
|||||||
|
|
||||||
cout << "Parsing file " << fname << " (" << decommented << ")" << endl;
|
cout << "Parsing file " << fname << " (" << decommented << ")" << endl;
|
||||||
|
|
||||||
EXPECT_NO_THROW(reference_json = Element::fromJSONFile(decommented, true));
|
EXPECT_NO_THROW(json = Element::fromJSONFile(decommented, true));
|
||||||
|
reference_json = moveComments(json);
|
||||||
|
|
||||||
// remove the temporary file
|
// remove the temporary file
|
||||||
EXPECT_NO_THROW(::remove(decommented.c_str()));
|
EXPECT_NO_THROW(::remove(decommented.c_str()));
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#include <cc/data.h>
|
#include <cc/data.h>
|
||||||
#include <dhcp6/parser_context.h>
|
#include <dhcp6/parser_context.h>
|
||||||
#include <testutils/io_utils.h>
|
#include <testutils/io_utils.h>
|
||||||
|
#include <testutils/user_context_utils.h>
|
||||||
|
|
||||||
using namespace isc::data;
|
using namespace isc::data;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@@ -212,6 +213,7 @@ TEST(ParserTest, multilineComments) {
|
|||||||
///
|
///
|
||||||
/// @param fname name of the file to be loaded
|
/// @param fname name of the file to be loaded
|
||||||
void testFile(const std::string& fname) {
|
void testFile(const std::string& fname) {
|
||||||
|
ElementPtr json;
|
||||||
ElementPtr reference_json;
|
ElementPtr reference_json;
|
||||||
ConstElementPtr test_json;
|
ConstElementPtr test_json;
|
||||||
|
|
||||||
@@ -219,7 +221,8 @@ void testFile(const std::string& fname) {
|
|||||||
|
|
||||||
cout << "Parsing file " << fname << "(" << decommented << ")" << endl;
|
cout << "Parsing file " << fname << "(" << decommented << ")" << endl;
|
||||||
|
|
||||||
EXPECT_NO_THROW(reference_json = Element::fromJSONFile(decommented, true));
|
EXPECT_NO_THROW(json = Element::fromJSONFile(decommented, true));
|
||||||
|
reference_json = moveComments(json);
|
||||||
|
|
||||||
// remove the temporary file
|
// remove the temporary file
|
||||||
EXPECT_NO_THROW(::remove(decommented.c_str()));
|
EXPECT_NO_THROW(::remove(decommented.c_str()));
|
||||||
|
@@ -135,11 +135,6 @@ protected:
|
|||||||
/// @brief The last address in a pool
|
/// @brief The last address in a pool
|
||||||
isc::asiolink::IOAddress last_;
|
isc::asiolink::IOAddress last_;
|
||||||
|
|
||||||
/// @brief Comments field
|
|
||||||
///
|
|
||||||
/// @todo: This field is currently not used.
|
|
||||||
std::string comments_;
|
|
||||||
|
|
||||||
/// @brief defines a lease type that will be served from this pool
|
/// @brief defines a lease type that will be served from this pool
|
||||||
Lease::Type type_;
|
Lease::Type type_;
|
||||||
|
|
||||||
|
@@ -10,7 +10,8 @@ noinst_LTLIBRARIES = libkea-testutils.la
|
|||||||
libkea_testutils_la_SOURCES = io_utils.cc io_utils.h
|
libkea_testutils_la_SOURCES = io_utils.cc io_utils.h
|
||||||
libkea_testutils_la_SOURCES += log_utils.cc log_utils.h
|
libkea_testutils_la_SOURCES += log_utils.cc log_utils.h
|
||||||
libkea_testutils_la_SOURCES += test_to_element.cc test_to_element.h
|
libkea_testutils_la_SOURCES += test_to_element.cc test_to_element.h
|
||||||
libkea_testutils_la_SOURCES += unix_control_client.h unix_control_client.cc
|
libkea_testutils_la_SOURCES += unix_control_client.cc unix_control_client.h
|
||||||
|
libkea_testutils_la_SOURCES += user_context_utils.cc user_context_utils.h
|
||||||
libkea_testutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
|
libkea_testutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
|
||||||
libkea_testutils_la_LIBADD = $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
|
libkea_testutils_la_LIBADD = $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
|
||||||
libkea_testutils_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
|
libkea_testutils_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
|
||||||
|
125
src/lib/testutils/user_context_utils.cc
Normal file
125
src/lib/testutils/user_context_utils.cc
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <testutils/user_context_utils.h>
|
||||||
|
|
||||||
|
using namespace isc::data;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/// @brief Exception to handle a unmodified value
|
||||||
|
/// @tparam EP ElementPtr or ConstElementPtr (compiler can't infer which one)
|
||||||
|
template<typename EP>
|
||||||
|
class UnModified {
|
||||||
|
public:
|
||||||
|
/// @brief Constructor
|
||||||
|
/// @param value the unmodified value
|
||||||
|
UnModified(EP value) : value_(value) { }
|
||||||
|
|
||||||
|
/// @brief Get the value
|
||||||
|
/// @return the value
|
||||||
|
EP get() const { return (value_); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// @brief the unmodified value
|
||||||
|
EP value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Recursive helper
|
||||||
|
///
|
||||||
|
/// Instead of returning a unmodified copy a @ref UnModified exception
|
||||||
|
/// is raised with the unmodified value
|
||||||
|
///
|
||||||
|
/// @tparam EP ElementPtr or ConstElementPtr (compiler will infer which one)
|
||||||
|
/// @param element the element to traverse
|
||||||
|
/// @return a modified copy where comment entries were moved to user-context
|
||||||
|
/// @throw UnModified with the unmodified value
|
||||||
|
template<typename EP>
|
||||||
|
EP moveComments1(EP element) {
|
||||||
|
bool modified = false;
|
||||||
|
|
||||||
|
// On lists recurse on items
|
||||||
|
if (element->getType() == Element::list) {
|
||||||
|
ElementPtr result = ElementPtr(new ListElement());
|
||||||
|
typedef std::vector<ElementPtr> ListType;
|
||||||
|
const ListType& list = element->listValue();
|
||||||
|
for (ListType::const_iterator it = list.cbegin();
|
||||||
|
it != list.cend(); ++it) {
|
||||||
|
try {
|
||||||
|
result->add(moveComments1(*it));
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
catch (const UnModified<ElementPtr>& ex) {
|
||||||
|
result->add(ex.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!modified) {
|
||||||
|
throw UnModified<EP>(element);
|
||||||
|
}
|
||||||
|
return (result);
|
||||||
|
} else if (element->getType() != Element::map) {
|
||||||
|
throw UnModified<EP>(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process maps: recurse on items
|
||||||
|
ElementPtr result = ElementPtr(new MapElement());
|
||||||
|
bool has_comment = false;
|
||||||
|
typedef std::map<std::string, ConstElementPtr> map_type;
|
||||||
|
const map_type& map = element->mapValue();
|
||||||
|
for (map_type::const_iterator it = map.cbegin(); it != map.cend(); ++it) {
|
||||||
|
if (it->first == "comment") {
|
||||||
|
// Note there is a comment entry to move
|
||||||
|
has_comment = true;
|
||||||
|
} else if (it->first == "user-context") {
|
||||||
|
// Do not traverse user-context entries
|
||||||
|
result->set("user-context", it->second);
|
||||||
|
} else {
|
||||||
|
// Not comment or user-context
|
||||||
|
try {
|
||||||
|
result->set(it->first, moveComments1(it->second));
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
catch (const UnModified<ConstElementPtr>& ex) {
|
||||||
|
result->set(it->first, ex.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check if the value should be not modified
|
||||||
|
if (!has_comment && !modified) {
|
||||||
|
throw UnModified<EP>(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_comment) {
|
||||||
|
// Move the comment entry
|
||||||
|
ConstElementPtr comment = element->get("comment");
|
||||||
|
ElementPtr moved = Element::createMap();
|
||||||
|
moved->set("comment", comment);
|
||||||
|
result->combine_set("user-context", moved);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
namespace isc {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
ElementPtr moveComments(ElementPtr element) {
|
||||||
|
ElementPtr result;
|
||||||
|
try {
|
||||||
|
result = moveComments1(element);
|
||||||
|
}
|
||||||
|
catch (const UnModified<ElementPtr>& ex) {
|
||||||
|
result = ex.get();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // end of isc::test namespace
|
||||||
|
}; // end of isc namespace
|
24
src/lib/testutils/user_context_utils.h
Normal file
24
src/lib/testutils/user_context_utils.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
#ifndef USER_CONTEXT_UTILS_H
|
||||||
|
#define USER_CONTEXT_UTILS_H
|
||||||
|
|
||||||
|
#include <cc/data.h>
|
||||||
|
|
||||||
|
namespace isc {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
/// @brief Move comment entries to user-context
|
||||||
|
///
|
||||||
|
/// @param element
|
||||||
|
/// @return a processed copy of element or unmodified element
|
||||||
|
isc::data::ElementPtr moveComments(isc::data::ElementPtr element);
|
||||||
|
|
||||||
|
}; // end of isc::test namespace
|
||||||
|
}; // end of isc namespace
|
||||||
|
|
||||||
|
#endif // USER_CONTEXT_UTILS_H
|
Reference in New Issue
Block a user