Add ProxyDatastore
This class will be used to intercept certain commands from the cli, like
entering RPC input. Right now, it works just as a pass-through.
Change-Id: I2d252609c1354005a0ccf4a1f26399dc895a73e8
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4fd1b0d..4081ce1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -133,10 +133,15 @@
)
target_link_libraries(parser schemas utils ast_values)
+add_library(proxydatastore STATIC
+ src/proxy_datastore.cpp
+ )
+target_link_libraries(proxydatastore PUBLIC datastoreaccess)
+
# Links libraries, that aren't specific to a datastore type
function(cli_link_required cli_target)
target_include_directories(${cli_target} PRIVATE ${REPLXX_PATH})
- target_link_libraries(${cli_target} yangschema docopt parser ${REPLXX_LIBRARY})
+ target_link_libraries(${cli_target} proxydatastore yangschema docopt parser ${REPLXX_LIBRARY})
add_dependencies(${cli_target} target-NETCONF_CLI_VERSION)
target_include_directories(${cli_target} PRIVATE ${PROJECT_BINARY_DIR})
endfunction()
@@ -302,6 +307,7 @@
target_link_libraries(test_set_value_completion leaf_data_type)
cli_test(list_manipulation)
cli_test(interpreter)
+ target_link_libraries(test_interpreter proxydatastore)
cli_test(path_utils)
target_link_libraries(test_path_utils path)
cli_test(keyvalue_completion)
diff --git a/src/cli.cpp b/src/cli.cpp
index 8a3536f..1f62f78 100644
--- a/src/cli.cpp
+++ b/src/cli.cpp
@@ -12,6 +12,7 @@
#include <sstream>
#include "NETCONF_CLI_VERSION.h"
#include "interpreter.hpp"
+#include "proxy_datastore.hpp"
#if defined(SYSREPO_CLI)
#include "sysrepo_access.hpp"
#define PROGRAM_NAME "sysrepo-cli"
@@ -72,10 +73,10 @@
return 1;
}
}
- SysrepoAccess datastore(PROGRAM_NAME, datastoreType);
+ auto datastore = std::make_shared<SysrepoAccess>(PROGRAM_NAME, datastoreType);
std::cout << "Connected to sysrepo [datastore: " << (datastoreType == Datastore::Startup ? "startup" : "running") << "]" << std::endl;
#elif defined(YANG_CLI)
- YangAccess datastore;
+ auto datastore = std::make_shared<YangAccess>();
if (args["--configonly"].asBool()) {
writableOps = WritableOps::No;
} else {
@@ -83,13 +84,13 @@
std::cout << "ops is writable" << std::endl;
}
if (const auto& search_dir = args["-s"]) {
- datastore.addSchemaDir(search_dir.asString());
+ datastore->addSchemaDir(search_dir.asString());
}
for (const auto& schemaFile : args["<schema_file_or_module_name>"].asStringList()) {
if (std::filesystem::exists(schemaFile)) {
- datastore.addSchemaFile(schemaFile);
+ datastore->addSchemaFile(schemaFile);
} else if (schemaFile.find('/') == std::string::npos) { // Module names cannot have a slash
- datastore.loadModule(schemaFile);
+ datastore->loadModule(schemaFile);
} else {
std::cerr << "Cannot load YANG module " << schemaFile << "\n";
}
@@ -106,7 +107,7 @@
return 1;
}
try {
- datastore.enableFeature(parsed.first, parsed.second);
+ datastore->enableFeature(parsed.first, parsed.second);
} catch (std::runtime_error& ex) {
std::cerr << ex.what() << "\n";
return 1;
@@ -116,15 +117,16 @@
}
if (const auto& dataFiles = args["-i"]) {
for (const auto& dataFile : dataFiles.asStringList()) {
- datastore.addDataFile(dataFile);
+ datastore->addDataFile(dataFile);
}
}
#else
#error "Unknown CLI backend"
#endif
- auto dataQuery = std::make_shared<DataQuery>(datastore);
- Parser parser(datastore.schema(), writableOps, dataQuery);
+ ProxyDatastore proxyDatastore(datastore);
+ auto dataQuery = std::make_shared<DataQuery>(*datastore);
+ Parser parser(datastore->schema(), writableOps, dataQuery);
using replxx::Replxx;
@@ -182,7 +184,7 @@
try {
command_ cmd = parser.parseCommand(line, std::cout);
- boost::apply_visitor(Interpreter(parser, datastore), cmd);
+ boost::apply_visitor(Interpreter(parser, proxyDatastore), cmd);
} catch (InvalidCommandException& ex) {
std::cerr << ex.what() << std::endl;
} catch (DatastoreException& ex) {
diff --git a/src/interpreter.cpp b/src/interpreter.cpp
index 3b52960..5ff73e7 100644
--- a/src/interpreter.cpp
+++ b/src/interpreter.cpp
@@ -293,7 +293,7 @@
}
}
-Interpreter::Interpreter(Parser& parser, DatastoreAccess& datastore)
+Interpreter::Interpreter(Parser& parser, ProxyDatastore& datastore)
: m_parser(parser)
, m_datastore(datastore)
{
diff --git a/src/interpreter.hpp b/src/interpreter.hpp
index 543fb2e..000cc21 100644
--- a/src/interpreter.hpp
+++ b/src/interpreter.hpp
@@ -9,12 +9,12 @@
#pragma once
#include <boost/variant/static_visitor.hpp>
-#include "datastore_access.hpp"
+#include "proxy_datastore.hpp"
#include "parser.hpp"
struct Interpreter : boost::static_visitor<void> {
- Interpreter(Parser& parser, DatastoreAccess& datastore);
+ Interpreter(Parser& parser, ProxyDatastore& datastore);
void operator()(const commit_&) const;
void operator()(const set_&) const;
@@ -40,5 +40,5 @@
[[nodiscard]] boost::variant<dataPath_, schemaPath_, module_> toCanonicalPath(const PathType& path) const;
Parser& m_parser;
- DatastoreAccess& m_datastore;
+ ProxyDatastore& m_datastore;
};
diff --git a/src/proxy_datastore.cpp b/src/proxy_datastore.cpp
new file mode 100644
index 0000000..ab9193c
--- /dev/null
+++ b/src/proxy_datastore.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 CESNET, https://photonics.cesnet.cz/
+ *
+ * Written by Václav Kubernát <kubernat@cesnet.cz>
+ *
+*/
+#include "proxy_datastore.hpp"
+
+ProxyDatastore::ProxyDatastore(const std::shared_ptr<DatastoreAccess>& datastore)
+ : m_datastore(datastore)
+{
+}
+
+DatastoreAccess::Tree ProxyDatastore::getItems(const std::string& path) const
+{
+ return m_datastore->getItems(path);
+}
+
+void ProxyDatastore::setLeaf(const std::string& path, leaf_data_ value)
+{
+ m_datastore->setLeaf(path, value);
+}
+
+void ProxyDatastore::createItem(const std::string& path)
+{
+ m_datastore->createItem(path);
+}
+
+void ProxyDatastore::deleteItem(const std::string& path)
+{
+ m_datastore->deleteItem(path);
+}
+
+void ProxyDatastore::moveItem(const std::string& source, std::variant<yang::move::Absolute, yang::move::Relative> move)
+{
+ m_datastore->moveItem(source, move);
+}
+
+void ProxyDatastore::commitChanges()
+{
+ m_datastore->commitChanges();
+}
+
+void ProxyDatastore::discardChanges()
+{
+ m_datastore->discardChanges();
+}
+
+void ProxyDatastore::copyConfig(const Datastore source, const Datastore destination)
+{
+ m_datastore->copyConfig(source, destination);
+}
+
+std::string ProxyDatastore::dump(const DataFormat format) const
+{
+ return m_datastore->dump(format);
+}
+
+std::shared_ptr<Schema> ProxyDatastore::schema() const
+{
+ return m_datastore->schema();
+}
diff --git a/src/proxy_datastore.hpp b/src/proxy_datastore.hpp
new file mode 100644
index 0000000..0ed5e2d
--- /dev/null
+++ b/src/proxy_datastore.hpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 CESNET, https://photonics.cesnet.cz/
+ *
+ * Written by Václav Kubernát <kubernat@cesnet.cz>
+ *
+*/
+
+#pragma once
+#include "datastore_access.hpp"
+
+/*! \class ProxyDatastore
+ * \brief DatastoreAccess wrapper that handles RPC input
+ */
+class ProxyDatastore {
+public:
+ ProxyDatastore(const std::shared_ptr<DatastoreAccess>& datastore);
+ [[nodiscard]] DatastoreAccess::Tree getItems(const std::string& path) const;
+ void setLeaf(const std::string& path, leaf_data_ value);
+ void createItem(const std::string& path);
+ void deleteItem(const std::string& path);
+ void moveItem(const std::string& source, std::variant<yang::move::Absolute, yang::move::Relative> move);
+ void commitChanges();
+ void discardChanges();
+ void copyConfig(const Datastore source, const Datastore destination);
+ [[nodiscard]] std::string dump(const DataFormat format) const;
+
+ [[nodiscard]] std::shared_ptr<Schema> schema() const;
+private:
+ std::shared_ptr<DatastoreAccess> m_datastore;
+};
diff --git a/tests/interpreter.cpp b/tests/interpreter.cpp
index 3b9736b..89fbd29 100644
--- a/tests/interpreter.cpp
+++ b/tests/interpreter.cpp
@@ -38,7 +38,8 @@
{
auto schema = std::make_shared<MockSchema>();
Parser parser(schema);
- MockDatastoreAccess datastore;
+ auto datastore = std::make_shared<MockDatastoreAccess>();
+ ProxyDatastore proxyDatastore(datastore);
std::vector<std::unique_ptr<trompeloeil::expectation>> expectations;
std::vector<command_> toInterpret;
@@ -173,7 +174,7 @@
}
ls_ ls;
ls.m_path = lsArg;
- expectations.emplace_back(NAMED_REQUIRE_CALL(datastore, schema()).RETURN(schema));
+ expectations.emplace_back(NAMED_REQUIRE_CALL(*datastore, schema()).RETURN(schema));
expectations.emplace_back(NAMED_REQUIRE_CALL(*schema, availableNodes(expectedPath, Recursion::NonRecursive)).RETURN(std::set<ModuleNodePair>{}));
toInterpret.emplace_back(ls);
}
@@ -323,7 +324,7 @@
get_ getCmd;
getCmd.m_path = inputPath;
- expectations.emplace_back(NAMED_REQUIRE_CALL(datastore, getItems(expectedPathArg)).RETURN(treeReturned));
+ expectations.emplace_back(NAMED_REQUIRE_CALL(*datastore, getItems(expectedPathArg)).RETURN(treeReturned));
toInterpret.emplace_back(getCmd);
}
@@ -335,22 +336,22 @@
SECTION("list instance")
{
inputPath.m_nodes = {dataNode_{{"mod"}, listElement_{"department", {{"name", "engineering"s}}}}};
- expectations.emplace_back(NAMED_REQUIRE_CALL(datastore, createItem("/mod:department[name='engineering']")));
- expectations.emplace_back(NAMED_REQUIRE_CALL(datastore, deleteItem("/mod:department[name='engineering']")));
+ expectations.emplace_back(NAMED_REQUIRE_CALL(*datastore, createItem("/mod:department[name='engineering']")));
+ expectations.emplace_back(NAMED_REQUIRE_CALL(*datastore, deleteItem("/mod:department[name='engineering']")));
}
SECTION("leaflist instance")
{
inputPath.m_nodes = {dataNode_{{"mod"}, leafListElement_{"addresses", "127.0.0.1"s}}};
- expectations.emplace_back(NAMED_REQUIRE_CALL(datastore, createItem("/mod:addresses[.='127.0.0.1']")));
- expectations.emplace_back(NAMED_REQUIRE_CALL(datastore, deleteItem("/mod:addresses[.='127.0.0.1']")));
+ expectations.emplace_back(NAMED_REQUIRE_CALL(*datastore, createItem("/mod:addresses[.='127.0.0.1']")));
+ expectations.emplace_back(NAMED_REQUIRE_CALL(*datastore, deleteItem("/mod:addresses[.='127.0.0.1']")));
}
SECTION("presence container")
{
inputPath.m_nodes = {dataNode_{{"mod"}, container_{"pContainer"}}};
- expectations.emplace_back(NAMED_REQUIRE_CALL(datastore, createItem("/mod:pContainer")));
- expectations.emplace_back(NAMED_REQUIRE_CALL(datastore, deleteItem("/mod:pContainer")));
+ expectations.emplace_back(NAMED_REQUIRE_CALL(*datastore, createItem("/mod:pContainer")));
+ expectations.emplace_back(NAMED_REQUIRE_CALL(*datastore, deleteItem("/mod:pContainer")));
}
create_ createCmd;
@@ -363,7 +364,7 @@
SECTION("delete a leaf")
{
- expectations.emplace_back(NAMED_REQUIRE_CALL(datastore, deleteItem("/mod:someLeaf")));
+ expectations.emplace_back(NAMED_REQUIRE_CALL(*datastore, deleteItem("/mod:someLeaf")));
delete_ deleteCmd;
deleteCmd.m_path = {Scope::Absolute, {dataNode_{{"mod"}, leaf_{"someLeaf"}}, }};
toInterpret.emplace_back(deleteCmd);
@@ -371,13 +372,13 @@
SECTION("commit")
{
- expectations.emplace_back(NAMED_REQUIRE_CALL(datastore, commitChanges()));
+ expectations.emplace_back(NAMED_REQUIRE_CALL(*datastore, commitChanges()));
toInterpret.emplace_back(commit_{});
}
SECTION("discard")
{
- expectations.emplace_back(NAMED_REQUIRE_CALL(datastore, discardChanges()));
+ expectations.emplace_back(NAMED_REQUIRE_CALL(*datastore, discardChanges()));
toInterpret.emplace_back(discard_{});
}
@@ -391,7 +392,7 @@
{
inputPath.m_nodes = {dataNode_{{"mod"}, leaf_{"animal"}}};
inputData = identityRef_{"Doge"};
- expectations.emplace_back(NAMED_REQUIRE_CALL(datastore, setLeaf("/mod:animal", identityRef_{"mod", "Doge"})));
+ expectations.emplace_back(NAMED_REQUIRE_CALL(*datastore, setLeaf("/mod:animal", identityRef_{"mod", "Doge"})));
}
@@ -406,18 +407,18 @@
{
SECTION("running -> startup")
{
- expectations.emplace_back(NAMED_REQUIRE_CALL(datastore, copyConfig(Datastore::Running, Datastore::Startup)));
+ expectations.emplace_back(NAMED_REQUIRE_CALL(*datastore, copyConfig(Datastore::Running, Datastore::Startup)));
toInterpret.emplace_back(copy_{{}, Datastore::Running, Datastore::Startup});
}
SECTION("startup -> running")
{
- expectations.emplace_back(NAMED_REQUIRE_CALL(datastore, copyConfig(Datastore::Startup, Datastore::Running)));
+ expectations.emplace_back(NAMED_REQUIRE_CALL(*datastore, copyConfig(Datastore::Startup, Datastore::Running)));
toInterpret.emplace_back(copy_{{}, Datastore::Startup, Datastore::Running});
}
}
for (const auto& command : toInterpret) {
- boost::apply_visitor(Interpreter(parser, datastore), command);
+ boost::apply_visitor(Interpreter(parser, proxyDatastore), command);
}
}