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 <netconf/netconf_log.h>
10 #include <netconf/netconf_cfg_mgr.h>
11 #include <exceptions/exceptions.h>
12 #include <asiolink/io_error.h>
13
14 #include <boost/foreach.hpp>
15 #include <boost/scoped_ptr.hpp>
16 #include <boost/algorithm/string/predicate.hpp>
17
18 #include <sstream>
19 #include <string>
20
21 using namespace std;
22 using namespace isc::process;
23 using namespace isc::data;
24 using namespace isc::http;
25
26 namespace isc {
27 namespace netconf {
28
29 // *********************** CfgControlSocket *************************
30
CfgControlSocket(Type type,const string & name,const Url & url)31 CfgControlSocket::CfgControlSocket(Type type, const string& name,
32 const Url& url)
33 : type_(type), name_(name), url_(url) {
34 }
35
36 CfgControlSocket::Type
stringToType(const string & type)37 CfgControlSocket::stringToType(const string& type) {
38 if (type == "unix") {
39 return (CfgControlSocket::Type::UNIX);
40 } else if (type == "http") {
41 return (CfgControlSocket::Type::HTTP);
42 } else if (type == "stdout") {
43 return (CfgControlSocket::Type::STDOUT);
44 }
45
46 isc_throw(BadValue, "Unknown control socket type: " << type);
47 }
48
49 const string
typeToString(CfgControlSocket::Type type)50 CfgControlSocket::typeToString(CfgControlSocket::Type type) {
51 switch (type) {
52 case CfgControlSocket::Type::UNIX:
53 return ("unix");
54 case CfgControlSocket::Type::HTTP:
55 return ("http");
56 case CfgControlSocket::Type::STDOUT:
57 return ("stdout");
58 default:
59 isc_throw(BadValue, "Unknown control socket type: " << type);
60 }
61 }
62
63 ElementPtr
toElement() const64 CfgControlSocket::toElement() const {
65 ElementPtr result = Element::createMap();
66 // Set user-context
67 contextToElement(result);
68 // Set type
69 result->set("socket-type", Element::create(typeToString(type_)));
70 // Set name
71 result->set("socket-name", Element::create(name_));
72 // Set url
73 result->set("socket-url", Element::create(url_.toText()));
74 return (result);
75 }
76
77 // *********************** CfgServer *************************
CfgServer(const string & model,CfgControlSocketPtr ctrl_sock)78 CfgServer::CfgServer(const string& model, CfgControlSocketPtr ctrl_sock)
79 : model_(model), boot_update_(true), subscribe_changes_(true),
80 subscribe_notifications_(true), validate_changes_(true),
81 control_socket_(ctrl_sock) {
82 }
83
84 string
toText() const85 CfgServer::toText() const {
86 ostringstream s;
87 s << "model: " << model_ << ", control socker: ";
88 if (!control_socket_) {
89 s << "none";
90 } else {
91 switch (control_socket_->getType()) {
92 case CfgControlSocket::Type::UNIX:
93 s << "UNIX:'" << control_socket_->getName() << "'";
94 break;
95 case CfgControlSocket::Type::HTTP:
96 s << "HTTP:'" << control_socket_->getUrl().toText() << "'";
97 break;
98 case CfgControlSocket::Type::STDOUT:
99 s << "STDOUT";
100 break;
101 }
102 }
103 return (s.str());
104 }
105
106 ElementPtr
toElement() const107 CfgServer::toElement() const {
108 ElementPtr result = Element::createMap();
109 // Set user-context
110 contextToElement(result);
111 // Set model
112 result->set("model", Element::create(model_));
113 // Set boot-update
114 result->set("boot-update", Element::create(boot_update_));
115 // Set subscribe-changes
116 result->set("subscribe-changes", Element::create(subscribe_changes_));
117 // Set validate-changes
118 result->set("validate-changes", Element::create(validate_changes_));
119 // Set control-socket
120 if (control_socket_) {
121 result->set("control-socket", control_socket_->toElement());
122 }
123 return (result);
124 }
125
126 ostream&
operator <<(ostream & os,const CfgServer & server)127 operator<<(ostream& os, const CfgServer& server) {
128 os << server.toText();
129 return (os);
130 }
131
132 // *************************** PARSERS ***********************************
133
134 // *********************** ControlSocketConfigParser *************************
135
136 CfgControlSocketPtr
parse(ConstElementPtr ctrl_sock_config)137 ControlSocketConfigParser::parse(ConstElementPtr ctrl_sock_config) {
138 CfgControlSocketPtr result;
139 string type_str = getString(ctrl_sock_config, "socket-type");
140 string name = getString(ctrl_sock_config, "socket-name");
141 string url_str = getString(ctrl_sock_config, "socket-url");
142 ConstElementPtr user_context = ctrl_sock_config->get("user-context");
143
144 // Type must be valid.
145 CfgControlSocket::Type type;
146 try {
147 type = CfgControlSocket::stringToType(type_str);
148 } catch (const std::exception& ex) {
149 isc_throw(ConfigError, ex.what() << " '" << type_str << "' ("
150 << getPosition("socket-type", ctrl_sock_config) << ")");
151 }
152
153 // Url must be valid.
154 Url url(url_str);
155 if (!url.isValid()) {
156 isc_throw(ConfigError, "invalid control socket url: "
157 << url.getErrorMessage() << " '" << url_str << "' ("
158 << getPosition("socket-url", ctrl_sock_config) << ")");
159 }
160
161 // Create the control socket.
162 try {
163 result.reset(new CfgControlSocket(type, name, url));
164 } catch (const std::exception& ex) {
165 isc_throw(ConfigError, ex.what() << " ("
166 << ctrl_sock_config->getPosition() << ")");
167 }
168
169 // Add user-context.
170 if (user_context) {
171 result->setContext(user_context);
172 }
173
174 return (result);
175 }
176
177 // *********************** ServerConfigParser *************************
178
179 CfgServerPtr
parse(ConstElementPtr server_config)180 ServerConfigParser::parse(ConstElementPtr server_config) {
181 CfgServerPtr result;
182 string model = getString(server_config, "model");
183 ConstElementPtr user_context = server_config->get("user-context");
184 ConstElementPtr ctrl_sock_config = server_config->get("control-socket");
185 CfgControlSocketPtr ctrl_sock;
186 if (ctrl_sock_config) {
187 ControlSocketConfigParser parser;
188 ctrl_sock = parser.parse(ctrl_sock_config);
189 }
190 try {
191 result.reset(new CfgServer(model, ctrl_sock));
192 } catch (const std::exception& ex) {
193 isc_throw(ConfigError, ex.what() << " ("
194 << server_config->getPosition() << ")");
195 }
196
197 // Add flags.
198 result->setBootUpdate(getBoolean(server_config, "boot-update"));
199 result->setSubscribeChanges(getBoolean(server_config, "subscribe-changes"));
200 result->setValidateChanges(getBoolean(server_config, "validate-changes"));
201
202 // Add user-context.
203 if (user_context) {
204 result->setContext(user_context);
205 }
206
207 return (result);
208 }
209
210 } // namespace netconf
211 } // namespace isc
212