blob: 34e038878f860e8eb6ca297836380bb1037cd878 [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{
Václav Kubernát80aacc02018-08-22 17:41:54 +020038}
39
Václav Kubernátf5d75152020-12-03 03:52:34 +010040namespace {
41auto targetToDs_get(const DatastoreTarget target)
42{
43 switch (target) {
44 case DatastoreTarget::Operational:
Václav Kubernátcfdb9222021-07-07 22:36:24 +020045 return sysrepo::Datastore::Operational;
Václav Kubernátf5d75152020-12-03 03:52:34 +010046 case DatastoreTarget::Running:
Václav Kubernátcfdb9222021-07-07 22:36:24 +020047 return sysrepo::Datastore::Running;
Václav Kubernátf5d75152020-12-03 03:52:34 +010048 case DatastoreTarget::Startup:
Václav Kubernátcfdb9222021-07-07 22:36:24 +020049 return sysrepo::Datastore::Startup;
Václav Kubernátf5d75152020-12-03 03:52:34 +010050 }
51
52 __builtin_unreachable();
53}
54
55auto targetToDs_set(const DatastoreTarget target)
56{
57 switch (target) {
58 case DatastoreTarget::Operational:
59 case DatastoreTarget::Running:
60 // TODO: Doing candidate here doesn't work, why?
Václav Kubernátcfdb9222021-07-07 22:36:24 +020061 return sysrepo::Datastore::Running;
Václav Kubernátf5d75152020-12-03 03:52:34 +010062 case DatastoreTarget::Startup:
Václav Kubernátcfdb9222021-07-07 22:36:24 +020063 return sysrepo::Datastore::Startup;
Václav Kubernátf5d75152020-12-03 03:52:34 +010064 }
65
66 __builtin_unreachable();
67}
68}
69
Václav Kubernátd6282912020-06-23 14:49:34 +020070DatastoreAccess::Tree SysrepoAccess::getItems(const std::string& path) const
Václav Kubernát80aacc02018-08-22 17:41:54 +020071{
Václav Kubernátb6ff0b62018-08-30 16:14:53 +020072 using namespace std::string_literals;
Jan Kundrátb331b552020-01-23 15:25:29 +010073 Tree res;
Václav Kubernát80aacc02018-08-22 17:41:54 +020074
Václav Kubernátc58e4aa2019-04-03 18:37:32 +020075 try {
Václav Kubernátcfdb9222021-07-07 22:36:24 +020076 m_session.switchDatastore(targetToDs_get(m_target));
Jan Kundrátf59b83c2022-03-18 18:12:08 +010077 auto config = m_session.getData((path == "/") ? "/*" : path);
Václav Kubernát654303f2020-07-31 13:16:54 +020078 if (config) {
Václav Kubernátcfdb9222021-07-07 22:36:24 +020079 lyNodesToTree(res, config->siblings());
Václav Kubernátb6ff0b62018-08-30 16:14:53 +020080 }
Václav Kubernátcfdb9222021-07-07 22:36:24 +020081 } catch (sysrepo::Error& ex) {
Václav Kubernátc58e4aa2019-04-03 18:37:32 +020082 reportErrors();
Václav Kubernátc89736b2018-08-30 16:14:05 +020083 }
Václav Kubernát80aacc02018-08-22 17:41:54 +020084 return res;
85}
86
87void SysrepoAccess::setLeaf(const std::string& path, leaf_data_ value)
88{
Václav Kubernátc58e4aa2019-04-03 18:37:32 +020089 try {
Václav Kubernátcfdb9222021-07-07 22:36:24 +020090 m_session.switchDatastore(targetToDs_set(m_target));
91 auto lyValue = value.type() == typeid(empty_) ? "" : leafDataToString(value);
Jan Kundrátf59b83c2022-03-18 18:12:08 +010092 m_session.setItem(path, lyValue, sysrepo::EditOptions::Isolate);
Václav Kubernátcfdb9222021-07-07 22:36:24 +020093 } catch (sysrepo::Error& ex) {
Václav Kubernátc58e4aa2019-04-03 18:37:32 +020094 reportErrors();
95 }
Václav Kubernát80aacc02018-08-22 17:41:54 +020096}
97
Jan Kundrátcbf288b2020-06-18 20:44:39 +020098void SysrepoAccess::createItem(const std::string& path)
Václav Kubernát80aacc02018-08-22 17:41:54 +020099{
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200100 try {
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200101 m_session.switchDatastore(targetToDs_set(m_target));
Jan Kundrátf59b83c2022-03-18 18:12:08 +0100102 m_session.setItem(path, std::nullopt);
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200103 } catch (sysrepo::Error& ex) {
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200104 reportErrors();
105 }
Václav Kubernát80aacc02018-08-22 17:41:54 +0200106}
107
Jan Kundrátcbf288b2020-06-18 20:44:39 +0200108void SysrepoAccess::deleteItem(const std::string& path)
Václav Kubernátf5f64f02019-03-19 17:15:47 +0100109{
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200110 try {
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200111 // Have to use sysrepo::EditOptions::Isolate, because deleting something that's been set without committing is
112 // not supported.
Václav Kubernát654303f2020-07-31 13:16:54 +0200113 // https://github.com/sysrepo/sysrepo/issues/1967#issuecomment-625085090
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200114 m_session.switchDatastore(targetToDs_set(m_target));
Jan Kundrátf59b83c2022-03-18 18:12:08 +0100115 m_session.deleteItem(path, sysrepo::EditOptions::Isolate);
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200116 } catch (sysrepo::Error& ex) {
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200117 reportErrors();
118 }
Václav Kubernátf5f64f02019-03-19 17:15:47 +0100119}
120
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200121struct impl_toSrMoveOp {
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200122 sysrepo::MovePosition operator()(yang::move::Absolute& absolute)
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200123 {
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200124 return absolute == yang::move::Absolute::Begin ? sysrepo::MovePosition::First : sysrepo::MovePosition::Last;
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200125 }
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200126 sysrepo::MovePosition operator()(yang::move::Relative& relative)
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200127 {
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200128 return relative.m_position == yang::move::Relative::Position::After ? sysrepo::MovePosition::After : sysrepo::MovePosition::Before;
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200129 }
130};
131
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200132sysrepo::MovePosition toSrMoveOp(std::variant<yang::move::Absolute, yang::move::Relative> move)
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200133{
134 return std::visit(impl_toSrMoveOp{}, move);
135}
136
137void SysrepoAccess::moveItem(const std::string& source, std::variant<yang::move::Absolute, yang::move::Relative> move)
138{
Václav Kubernát654303f2020-07-31 13:16:54 +0200139 std::string destination;
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200140 if (std::holds_alternative<yang::move::Relative>(move)) {
141 auto relative = std::get<yang::move::Relative>(move);
142 if (m_schema->nodeType(source) == yang::NodeTypes::LeafList) {
Václav Kubernát654303f2020-07-31 13:16:54 +0200143 destination = leafDataToString(relative.m_path.at("."));
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200144 } else {
Václav Kubernát654303f2020-07-31 13:16:54 +0200145 destination = instanceToString(relative.m_path);
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200146 }
147 }
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200148 m_session.switchDatastore(targetToDs_set(m_target));
Jan Kundrátf59b83c2022-03-18 18:12:08 +0100149 m_session.moveItem(source, toSrMoveOp(move), destination);
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200150}
151
Václav Kubernát812ee282018-08-30 17:10:03 +0200152void SysrepoAccess::commitChanges()
153{
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200154 try {
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200155 m_session.switchDatastore(targetToDs_set(m_target));
156 m_session.applyChanges(OPERATION_TIMEOUT_MS);
157 } catch (sysrepo::Error& ex) {
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200158 reportErrors();
159 }
Václav Kubernát812ee282018-08-30 17:10:03 +0200160}
Václav Kubernáta6c5fff2018-09-07 15:16:25 +0200161
Václav Kubernát6d791432018-10-25 16:00:35 +0200162void SysrepoAccess::discardChanges()
163{
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200164 try {
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200165 m_session.switchDatastore(targetToDs_set(m_target));
166 m_session.discardChanges();
167 } catch (sysrepo::Error& ex) {
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200168 reportErrors();
169 }
Václav Kubernát6d791432018-10-25 16:00:35 +0200170}
171
Václav Kubernátb3960f82020-12-01 03:21:48 +0100172DatastoreAccess::Tree SysrepoAccess::execute(const std::string& path, const Tree& input)
Václav Kubernáta8789602020-07-20 15:18:19 +0200173{
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200174 auto inputNode = treeToRpcInput(m_session.getContext(), path, input);
175 m_session.switchDatastore(targetToDs_set(m_target));
176 auto output = m_session.sendRPC(inputNode);
177 return rpcOutputToTree(output);
Václav Kubernáta8789602020-07-20 15:18:19 +0200178}
Jan Kundrát6ee84792020-01-24 01:43:36 +0100179
Václav Kubernát7160a132020-04-03 02:11:01 +0200180void SysrepoAccess::copyConfig(const Datastore source, const Datastore destination)
181{
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200182 m_session.switchDatastore(toSrDatastore(destination));
Jan Kundrátf59b83c2022-03-18 18:12:08 +0100183 m_session.copyConfig(toSrDatastore(source), std::nullopt, OPERATION_TIMEOUT_MS);
Václav Kubernáta6c5fff2018-09-07 15:16:25 +0200184}
185
186std::shared_ptr<Schema> SysrepoAccess::schema()
187{
188 return m_schema;
189}
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200190
Václav Kubernátd6282912020-06-23 14:49:34 +0200191[[noreturn]] void SysrepoAccess::reportErrors() const
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200192{
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200193 std::vector<DatastoreError> res;
194
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200195 for (const auto& err : m_session.getErrors()) {
196 res.emplace_back(err.errorMessage);
197 }
198
199 for (const auto& err : m_session.getNetconfErrors()) {
200 res.emplace_back(err.message, err.path);
Václav Kubernátc58e4aa2019-04-03 18:37:32 +0200201 }
202
203 throw DatastoreException(res);
204}
Václav Kubernátab612e92019-11-26 19:51:31 +0100205
206std::vector<ListInstance> SysrepoAccess::listInstances(const std::string& path)
207{
208 std::vector<ListInstance> res;
Jan Kundrátf59b83c2022-03-18 18:12:08 +0100209 auto lists = m_session.getData(path);
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200210 if (!lists) {
211 return res;
212 }
Václav Kubernátab612e92019-11-26 19:51:31 +0100213
Jan Kundrátf59b83c2022-03-18 18:12:08 +0100214 auto instances = lists->findXPath(path);
Václav Kubernátab612e92019-11-26 19:51:31 +0100215 if (instances.empty()) {
216 return res;
217 }
218
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200219 auto keys = instances.front().schema().asList().keys();
Václav Kubernátab612e92019-11-26 19:51:31 +0100220
Václav Kubernátab612e92019-11-26 19:51:31 +0100221 for (const auto& instance : instances) {
Václav Kubernátab612e92019-11-26 19:51:31 +0100222 ListInstance instanceRes;
223 for (const auto& key : keys) {
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200224 auto leaf = instance.findPath(key.name().data());
225 instanceRes.emplace(std::string{leaf->schema().name()}, leafValueFromNode(leaf->asTerm()));
Václav Kubernátab612e92019-11-26 19:51:31 +0100226 }
Václav Kubernátfaacd022020-07-08 16:44:38 +0200227 res.emplace_back(instanceRes);
Václav Kubernátab612e92019-11-26 19:51:31 +0100228 }
229
230 return res;
231}
Václav Kubernát70d7f7a2020-06-23 14:40:40 +0200232
233std::string SysrepoAccess::dump(const DataFormat format) const
234{
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200235 auto root = m_session.getData("/*");
236 auto str = root->printStr(format == DataFormat::Xml ? libyang::DataFormat::XML : libyang::DataFormat::JSON, libyang::PrintFlags::WithSiblings);
237 if (!str) {
238 return "";
239 }
240
241 return std::string{*str};
Václav Kubernát70d7f7a2020-06-23 14:40:40 +0200242}