blob: 4f1a04a3f9d744c67f9edf885c78e4451f00d196 [file] [log] [blame]
Václav Kubernát80aacc02018-08-22 17:41:54 +02001/*
2 * Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
3 * Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
4 *
5 * Written by Václav Kubernát <kubervac@fit.cvut.cz>
6 *
7*/
8
Václav Kubernát19097f32020-10-05 10:08:29 +02009#include <experimental/iterator>
Václav Kubernát19097f32020-10-05 10:08:29 +020010#include <sstream>
Václav Kubernátb4e5b182020-11-16 19:55:09 +010011#include <sysrepo-cpp/Session.hpp>
Václav Kubernátcfdb9222021-07-07 22:36:24 +020012#include <sysrepo-cpp/utils/exception.hpp>
Václav Kubernátab612e92019-11-26 19:51:31 +010013#include "libyang_utils.hpp"
Václav Kubernát80aacc02018-08-22 17:41:54 +020014#include "sysrepo_access.hpp"
Jan Kundrát6ee84792020-01-24 01:43:36 +010015#include "utils.hpp"
Václav Kubernáta6c5fff2018-09-07 15:16:25 +020016#include "yang_schema.hpp"
Václav Kubernát80aacc02018-08-22 17:41:54 +020017
Václav Kubernátcfdb9222021-07-07 22:36:24 +020018const auto OPERATION_TIMEOUT_MS = std::chrono::milliseconds{1000};
Václav Kubernát80aacc02018-08-22 17:41:54 +020019
Václav Kubernát812ee282018-08-30 17:10:03 +020020SysrepoAccess::~SysrepoAccess() = default;
Václav Kubernát80aacc02018-08-22 17:41:54 +020021
Václav Kubernátcfdb9222021-07-07 22:36:24 +020022sysrepo::Datastore toSrDatastore(Datastore datastore)
Václav Kubernát715c85c2020-04-14 01:46:08 +020023{
24 switch (datastore) {
25 case Datastore::Running:
Václav Kubernátcfdb9222021-07-07 22:36:24 +020026 return sysrepo::Datastore::Running;
Václav Kubernát715c85c2020-04-14 01:46:08 +020027 case Datastore::Startup:
Václav Kubernátcfdb9222021-07-07 22:36:24 +020028 return sysrepo::Datastore::Startup;
Václav Kubernát715c85c2020-04-14 01:46:08 +020029 }
30 __builtin_unreachable();
31}
32
Václav Kubernátf5d75152020-12-03 03:52:34 +010033SysrepoAccess::SysrepoAccess()
Václav Kubernátcfdb9222021-07-07 22:36:24 +020034 : m_connection()
35 , m_session(m_connection.sessionStart())
36 , m_schema(std::make_shared<YangSchema>(m_session.getContext()))
Václav Kubernát80aacc02018-08-22 17:41:54 +020037{
Jan Kundrát0b9ef8f2023-10-03 13:02:53 +020038 m_session.setOriginatorName("sysrepo-cli");
Václav Kubernát80aacc02018-08-22 17:41:54 +020039}
40
Václav Kubernátf5d75152020-12-03 03:52:34 +010041namespace {
42auto targetToDs_get(const DatastoreTarget target)
43{
44 switch (target) {
45 case DatastoreTarget::Operational:
Václav Kubernátcfdb9222021-07-07 22:36:24 +020046 return sysrepo::Datastore::Operational;
Václav Kubernátf5d75152020-12-03 03:52:34 +010047 case DatastoreTarget::Running:
Václav Kubernátcfdb9222021-07-07 22:36:24 +020048 return sysrepo::Datastore::Running;
Václav Kubernátf5d75152020-12-03 03:52:34 +010049 case DatastoreTarget::Startup:
Václav Kubernátcfdb9222021-07-07 22:36:24 +020050 return sysrepo::Datastore::Startup;
Václav Kubernátf5d75152020-12-03 03:52:34 +010051 }
52
53 __builtin_unreachable();
54}
55
56auto targetToDs_set(const DatastoreTarget target)
57{
58 switch (target) {
59 case DatastoreTarget::Operational:
60 case DatastoreTarget::Running:
61 // TODO: Doing candidate here doesn't work, why?
Václav Kubernátcfdb9222021-07-07 22:36:24 +020062 return sysrepo::Datastore::Running;
Václav Kubernátf5d75152020-12-03 03:52:34 +010063 case DatastoreTarget::Startup:
Václav Kubernátcfdb9222021-07-07 22:36:24 +020064 return sysrepo::Datastore::Startup;
Václav Kubernátf5d75152020-12-03 03:52:34 +010065 }
66
67 __builtin_unreachable();
68}
69}
70
Václav Kubernátd6282912020-06-23 14:49:34 +020071DatastoreAccess::Tree SysrepoAccess::getItems(const std::string& path) const
Václav Kubernát80aacc02018-08-22 17:41:54 +020072{
Václav Kubernátb6ff0b62018-08-30 16:14:53 +020073 using namespace std::string_literals;
Jan Kundrátb331b552020-01-23 15:25:29 +010074 Tree res;
Václav Kubernát80aacc02018-08-22 17:41:54 +020075
Václav Kubernátc58e4aa2019-04-03 18:37:32 +020076 try {
Václav Kubernátcfdb9222021-07-07 22:36:24 +020077 m_session.switchDatastore(targetToDs_get(m_target));
Jan Kundrátf59b83c2022-03-18 18:12:08 +010078 auto config = m_session.getData((path == "/") ? "/*" : path);
Václav Kubernát654303f2020-07-31 13:16:54 +020079 if (config) {
Václav Kubernátcfdb9222021-07-07 22:36:24 +020080 lyNodesToTree(res, config->siblings());
Václav Kubernátb6ff0b62018-08-30 16:14:53 +020081 }
Václav Kubernátcfdb9222021-07-07 22:36:24 +020082 } catch (sysrepo::Error& ex) {
Václav Kubernátc58e4aa2019-04-03 18:37:32 +020083 reportErrors();
Václav Kubernátc89736b2018-08-30 16:14:05 +020084 }
Václav Kubernát80aacc02018-08-22 17:41:54 +020085 return res;
86}
87
88void SysrepoAccess::setLeaf(const std::string& path, leaf_data_ value)
89{
Václav Kubernátc58e4aa2019-04-03 18:37:32 +020090 try {
Václav Kubernátcfdb9222021-07-07 22:36:24 +020091 m_session.switchDatastore(targetToDs_set(m_target));
92 auto lyValue = value.type() == typeid(empty_) ? "" : leafDataToString(value);
Jan Kundrátf59b83c2022-03-18 18:12:08 +010093 m_session.setItem(path, lyValue, sysrepo::EditOptions::Isolate);
Václav Kubernátcfdb9222021-07-07 22:36:24 +020094 } catch (sysrepo::Error& ex) {
Václav Kubernátc58e4aa2019-04-03 18:37:32 +020095 reportErrors();
96 }
Václav Kubernát80aacc02018-08-22 17:41:54 +020097}
98
Jan Kundrátcbf288b2020-06-18 20:44:39 +020099void SysrepoAccess::createItem(const std::string& path)
Václav Kubernát80aacc02018-08-22 17:41:54 +0200100{
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200101 try {
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200102 m_session.switchDatastore(targetToDs_set(m_target));
Jan Kundrátf59b83c2022-03-18 18:12:08 +0100103 m_session.setItem(path, std::nullopt);
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200104 } catch (sysrepo::Error& ex) {
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200105 reportErrors();
106 }
Václav Kubernát80aacc02018-08-22 17:41:54 +0200107}
108
Jan Kundrátcbf288b2020-06-18 20:44:39 +0200109void SysrepoAccess::deleteItem(const std::string& path)
Václav Kubernátf5f64f02019-03-19 17:15:47 +0100110{
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200111 try {
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200112 // Have to use sysrepo::EditOptions::Isolate, because deleting something that's been set without committing is
113 // not supported.
Václav Kubernát654303f2020-07-31 13:16:54 +0200114 // https://github.com/sysrepo/sysrepo/issues/1967#issuecomment-625085090
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200115 m_session.switchDatastore(targetToDs_set(m_target));
Jan Kundrátf59b83c2022-03-18 18:12:08 +0100116 m_session.deleteItem(path, sysrepo::EditOptions::Isolate);
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200117 } catch (sysrepo::Error& ex) {
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200118 reportErrors();
119 }
Václav Kubernátf5f64f02019-03-19 17:15:47 +0100120}
121
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200122struct impl_toSrMoveOp {
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200123 sysrepo::MovePosition operator()(yang::move::Absolute& absolute)
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200124 {
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200125 return absolute == yang::move::Absolute::Begin ? sysrepo::MovePosition::First : sysrepo::MovePosition::Last;
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200126 }
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200127 sysrepo::MovePosition operator()(yang::move::Relative& relative)
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200128 {
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200129 return relative.m_position == yang::move::Relative::Position::After ? sysrepo::MovePosition::After : sysrepo::MovePosition::Before;
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200130 }
131};
132
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200133sysrepo::MovePosition toSrMoveOp(std::variant<yang::move::Absolute, yang::move::Relative> move)
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200134{
135 return std::visit(impl_toSrMoveOp{}, move);
136}
137
138void SysrepoAccess::moveItem(const std::string& source, std::variant<yang::move::Absolute, yang::move::Relative> move)
139{
Václav Kubernát654303f2020-07-31 13:16:54 +0200140 std::string destination;
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200141 if (std::holds_alternative<yang::move::Relative>(move)) {
142 auto relative = std::get<yang::move::Relative>(move);
143 if (m_schema->nodeType(source) == yang::NodeTypes::LeafList) {
Václav Kubernát654303f2020-07-31 13:16:54 +0200144 destination = leafDataToString(relative.m_path.at("."));
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200145 } else {
Václav Kubernát654303f2020-07-31 13:16:54 +0200146 destination = instanceToString(relative.m_path);
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200147 }
148 }
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200149 m_session.switchDatastore(targetToDs_set(m_target));
Jan Kundrátf59b83c2022-03-18 18:12:08 +0100150 m_session.moveItem(source, toSrMoveOp(move), destination);
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200151}
152
Václav Kubernát812ee282018-08-30 17:10:03 +0200153void SysrepoAccess::commitChanges()
154{
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200155 try {
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200156 m_session.switchDatastore(targetToDs_set(m_target));
157 m_session.applyChanges(OPERATION_TIMEOUT_MS);
158 } catch (sysrepo::Error& ex) {
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200159 reportErrors();
160 }
Václav Kubernát812ee282018-08-30 17:10:03 +0200161}
Václav Kubernáta6c5fff2018-09-07 15:16:25 +0200162
Václav Kubernát6d791432018-10-25 16:00:35 +0200163void SysrepoAccess::discardChanges()
164{
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200165 try {
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200166 m_session.switchDatastore(targetToDs_set(m_target));
167 m_session.discardChanges();
168 } catch (sysrepo::Error& ex) {
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200169 reportErrors();
170 }
Václav Kubernát6d791432018-10-25 16:00:35 +0200171}
172
Václav Kubernátb3960f82020-12-01 03:21:48 +0100173DatastoreAccess::Tree SysrepoAccess::execute(const std::string& path, const Tree& input)
Václav Kubernáta8789602020-07-20 15:18:19 +0200174{
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200175 auto inputNode = treeToRpcInput(m_session.getContext(), path, input);
176 m_session.switchDatastore(targetToDs_set(m_target));
177 auto output = m_session.sendRPC(inputNode);
178 return rpcOutputToTree(output);
Václav Kubernáta8789602020-07-20 15:18:19 +0200179}
Jan Kundrát6ee84792020-01-24 01:43:36 +0100180
Václav Kubernát7160a132020-04-03 02:11:01 +0200181void SysrepoAccess::copyConfig(const Datastore source, const Datastore destination)
182{
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200183 m_session.switchDatastore(toSrDatastore(destination));
Jan Kundrátf59b83c2022-03-18 18:12:08 +0100184 m_session.copyConfig(toSrDatastore(source), std::nullopt, OPERATION_TIMEOUT_MS);
Václav Kubernáta6c5fff2018-09-07 15:16:25 +0200185}
186
187std::shared_ptr<Schema> SysrepoAccess::schema()
188{
189 return m_schema;
190}
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200191
Václav Kubernátd6282912020-06-23 14:49:34 +0200192[[noreturn]] void SysrepoAccess::reportErrors() const
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200193{
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200194 std::vector<DatastoreError> res;
195
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200196 for (const auto& err : m_session.getErrors()) {
197 res.emplace_back(err.errorMessage);
198 }
199
200 for (const auto& err : m_session.getNetconfErrors()) {
201 res.emplace_back(err.message, err.path);
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200202 }
203
204 throw DatastoreException(res);
205}
Václav Kubernátab612e92019-11-26 19:51:31 +0100206
207std::vector<ListInstance> SysrepoAccess::listInstances(const std::string& path)
208{
209 std::vector<ListInstance> res;
Jan Kundrátf59b83c2022-03-18 18:12:08 +0100210 auto lists = m_session.getData(path);
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200211 if (!lists) {
212 return res;
213 }
Václav Kubernátab612e92019-11-26 19:51:31 +0100214
Jan Kundrátf59b83c2022-03-18 18:12:08 +0100215 auto instances = lists->findXPath(path);
Václav Kubernátab612e92019-11-26 19:51:31 +0100216 if (instances.empty()) {
217 return res;
218 }
219
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200220 auto keys = instances.front().schema().asList().keys();
Václav Kubernátab612e92019-11-26 19:51:31 +0100221
Václav Kubernátab612e92019-11-26 19:51:31 +0100222 for (const auto& instance : instances) {
Václav Kubernátab612e92019-11-26 19:51:31 +0100223 ListInstance instanceRes;
224 for (const auto& key : keys) {
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200225 auto leaf = instance.findPath(key.name().data());
226 instanceRes.emplace(std::string{leaf->schema().name()}, leafValueFromNode(leaf->asTerm()));
Václav Kubernátab612e92019-11-26 19:51:31 +0100227 }
Václav Kubernátfaacd022020-07-08 16:44:38 +0200228 res.emplace_back(instanceRes);
Václav Kubernátab612e92019-11-26 19:51:31 +0100229 }
230
231 return res;
232}
Václav Kubernát70d7f7a2020-06-23 14:40:40 +0200233
234std::string SysrepoAccess::dump(const DataFormat format) const
235{
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200236 auto root = m_session.getData("/*");
237 auto str = root->printStr(format == DataFormat::Xml ? libyang::DataFormat::XML : libyang::DataFormat::JSON, libyang::PrintFlags::WithSiblings);
238 if (!str) {
239 return "";
240 }
241
242 return std::string{*str};
Václav Kubernát70d7f7a2020-06-23 14:40:40 +0200243}