1 // Copyright (C) 2018-2021 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
9 #include <yang/translator_option_data.h>
10 #include <yang/adaptor.h>
11 #include <yang/yang_models.h>
12 #include <sstream>
13 
14 using namespace std;
15 using namespace isc::data;
16 using namespace sysrepo;
17 
18 namespace isc {
19 namespace yang {
20 
TranslatorOptionData(S_Session session,const string & model)21 TranslatorOptionData::TranslatorOptionData(S_Session session,
22                                            const string& model)
23     : TranslatorBasic(session, model) {
24 }
25 
~TranslatorOptionData()26 TranslatorOptionData::~TranslatorOptionData() {
27 }
28 
29 ElementPtr
getOptionData(const string & xpath)30 TranslatorOptionData::getOptionData(const string& xpath) {
31     try {
32         if ((model_ == KEA_DHCP4_SERVER) ||
33             (model_ == KEA_DHCP6_SERVER)) {
34             return (getOptionDataKea(xpath));
35         }
36     } catch (const sysrepo_exception& ex) {
37         isc_throw(SysrepoError,
38                   "sysrepo error getting option data at '" << xpath
39                   << "': " << ex.what());
40     }
41     isc_throw(NotImplemented,
42               "getOptionData not implemented for the model: " << model_);
43 }
44 
45 ElementPtr
getOptionDataKea(const string & xpath)46 TranslatorOptionData::getOptionDataKea(const string& xpath) {
47     ConstElementPtr code = getItem(xpath + "/code");
48     ConstElementPtr space = getItem(xpath + "/space");
49     if (!code || !space) {
50         // Can't happen as code and space are the keys.
51         isc_throw(Unexpected, "getOptionDataKea requires code and space: "
52                   << xpath);
53     }
54     ElementPtr result = Element::createMap();
55     result->set("code", code);
56     result->set("space", space);
57     ConstElementPtr name = getItem(xpath + "/name");
58     if (name) {
59         result->set("name", name);
60     }
61     ConstElementPtr data = getItem(xpath + "/data");
62     if (data) {
63         result->set("data", data);
64     }
65     ConstElementPtr format = getItem(xpath + "/csv-format");
66     if (format) {
67         result->set("csv-format", format);
68     }
69     ConstElementPtr send = getItem(xpath + "/always-send");
70     if (send) {
71         result->set("always-send", send);
72     }
73     ConstElementPtr context = getItem(xpath + "/user-context");
74     if (context) {
75         result->set("user-context", Element::fromJSON(context->stringValue()));
76     }
77     return (result);
78 }
79 
80 void
setOptionData(const string & xpath,ConstElementPtr elem)81 TranslatorOptionData::setOptionData(const string& xpath,
82                                     ConstElementPtr elem) {
83     try {
84         if ((model_ == KEA_DHCP4_SERVER) ||
85             (model_ == KEA_DHCP6_SERVER)) {
86             setOptionDataKea(xpath, elem);
87         } else {
88             isc_throw(NotImplemented,
89                       "setOptionData not implemented for the model: "
90                       << model_);
91         }
92     } catch (const sysrepo_exception& ex) {
93         isc_throw(SysrepoError,
94                   "sysrepo error setting option data '" << elem->str()
95                   << "' at '" << xpath << "': " << ex.what());
96     }
97 }
98 
99 void
setOptionDataKea(const string & xpath,ConstElementPtr elem)100 TranslatorOptionData::setOptionDataKea(const string& xpath,
101                                        ConstElementPtr elem) {
102     // Skip keys code and space.
103     ConstElementPtr name = elem->get("name");
104     if (name) {
105         setItem(xpath + "/name", name, SR_STRING_T);
106     }
107     ConstElementPtr data = elem->get("data");
108     if (data) {
109         setItem(xpath + "/data", data, SR_STRING_T);
110     }
111     ConstElementPtr format = elem->get("csv-format");
112     if (format) {
113         setItem(xpath + "/csv-format", format, SR_BOOL_T);
114     }
115     ConstElementPtr send = elem->get("always-send");
116     if (send) {
117         setItem(xpath + "/always-send", send, SR_BOOL_T);
118     }
119     ConstElementPtr context = Adaptor::getContext(elem);
120     if (context) {
121         setItem(xpath + "/user-context", Element::create(context->str()),
122                 SR_STRING_T);
123     }
124 }
125 
TranslatorOptionDataList(S_Session session,const string & model)126 TranslatorOptionDataList::TranslatorOptionDataList(S_Session session,
127                                                    const string& model)
128     : TranslatorBasic(session, model),
129       TranslatorOptionData(session, model) {
130 }
131 
~TranslatorOptionDataList()132 TranslatorOptionDataList::~TranslatorOptionDataList() {
133 }
134 
135 ConstElementPtr
getOptionDataList(const string & xpath)136 TranslatorOptionDataList::getOptionDataList(const string& xpath) {
137     try {
138         if ((model_ == KEA_DHCP4_SERVER) ||
139             (model_ == KEA_DHCP6_SERVER)) {
140             return (getOptionDataListKea(xpath));
141         }
142     } catch (const sysrepo_exception& ex) {
143         isc_throw(SysrepoError,
144                   "sysrepo error getting option data list at '" << xpath
145                   << "': " << ex.what());
146     }
147     isc_throw(NotImplemented,
148               "getOptionDataList not implemented for the model: " << model_);
149 }
150 
151 ConstElementPtr
getOptionDataListKea(const string & xpath)152 TranslatorOptionDataList::getOptionDataListKea(const string& xpath) {
153     return getList<TranslatorOptionData>(xpath + "/option-data", *this,
154                                          &TranslatorOptionData::getOptionData);
155 }
156 
157 void
setOptionDataList(const string & xpath,ConstElementPtr elem)158 TranslatorOptionDataList::setOptionDataList(const string& xpath,
159                                             ConstElementPtr elem) {
160     try {
161         if ((model_ == KEA_DHCP4_SERVER) ||
162             (model_ == KEA_DHCP6_SERVER)) {
163             setOptionDataListKea(xpath, elem);
164         } else {
165             isc_throw(NotImplemented,
166                       "setOptionDataList not implemented for the model: "
167                       << model_);
168         }
169     } catch (const sysrepo_exception& ex) {
170         isc_throw(SysrepoError,
171                   "sysrepo error setting option data list '" << elem->str()
172                   << "' at '" << xpath << "': " << ex.what());
173     }
174 }
175 
176 void
setOptionDataListKea(const string & xpath,ConstElementPtr elem)177 TranslatorOptionDataList::setOptionDataListKea(const string& xpath,
178                                                ConstElementPtr elem) {
179     for (size_t i = 0; i < elem->size(); ++i) {
180         ConstElementPtr option = elem->get(i);
181         if (!option->contains("code")) {
182             isc_throw(BadValue, "option data without code: " << option->str());
183         }
184         unsigned code = static_cast<unsigned>(option->get("code")->intValue());
185         if (!option->contains("space")) {
186             isc_throw(BadValue, "option data without space: " <<option->str());
187         }
188         string space = option->get("space")->stringValue();
189         ostringstream keys;
190         keys << xpath << "/option-data[code='" << code
191              << "'][space='" << space << "']";
192         setOptionData(keys.str(), option);
193     }
194 }
195 
196 }  // namespace yang
197 }  // namespace isc
198