Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include "options.h"
7 :
8 : #include <fstream>
9 : #include <iostream>
10 : #include <boost/asio/ip/host_name.hpp>
11 : #include <boost/functional/hash.hpp>
12 :
13 : #include "control-node/buildinfo.h"
14 : #include "base/contrail_ports.h"
15 : #include "base/logging.h"
16 : #include "base/misc_utils.h"
17 : #include "base/util.h"
18 : #include "config_client_manager.h"
19 : #include <base/address_util.h>
20 : #include <base/options_util.h>
21 :
22 : using namespace std;
23 : using namespace boost::asio::ip;
24 : namespace opt = boost::program_options;
25 : using namespace options::util;
26 :
27 : // Process command line options for control-node.
28 14 : Options::Options() {
29 14 : }
30 :
31 13 : bool Options::Parse(EventManager &evm, int argc, char *argv[]) {
32 26 : opt::options_description cmdline_options("Allowed options");
33 13 : Initialize(evm, cmdline_options);
34 :
35 : try {
36 13 : return Process(argc, argv, cmdline_options);
37 0 : } catch (boost::program_options::error &e) {
38 0 : cout << "Error " << e.what() << endl;
39 0 : } catch (...) {
40 0 : cout << "Options Parser: Caught fatal unknown exception" << endl;
41 0 : }
42 :
43 0 : return false;
44 13 : }
45 :
46 : // Initialize control-node's command line option tags with appropriate default
47 : // values. Options can from a config file as well. By default, we read
48 : // options from /etc/contrail/contrail-control.conf
49 13 : void Options::Initialize(EventManager &evm,
50 : opt::options_description &cmdline_options) {
51 13 : boost::system::error_code error;
52 13 : string hostname = host_name(error);
53 13 : string host_ip = GetHostIp(evm.io_service(), hostname);
54 :
55 13 : if (host_ip.empty())
56 0 : host_ip = "127.0.0.1";
57 :
58 26 : opt::options_description generic("Generic options");
59 :
60 : // Command line only options.
61 13 : generic.add_options()
62 26 : ("conf_file", opt::value<string>()->default_value(
63 : "/etc/contrail/contrail-control.conf"),
64 : "Configuration file")
65 13 : ("help", "help message")
66 13 : ("version", "Display version information")
67 : ;
68 :
69 13 : uint16_t default_bgp_port = ContrailPorts::ControlBgp();
70 13 : uint16_t default_http_server_port = ContrailPorts::HttpPortControl();
71 13 : uint16_t default_xmpp_port = ContrailPorts::ControlXmpp();
72 :
73 13 : default_collector_server_list_.push_back("127.0.0.1:8086");
74 :
75 13 : vector<string> default_config_db_server_list;
76 13 : string default_config_db_server(host_ip + ":9042");
77 13 : default_config_db_server_list.push_back(default_config_db_server);
78 :
79 13 : vector<string> default_rabbitmq_server_list;
80 13 : string default_rabbitmq_server(host_ip + ":5672");
81 13 : default_rabbitmq_server_list.push_back(default_rabbitmq_server);
82 :
83 : // Command line and config file options.
84 26 : opt::options_description config("Configuration options");
85 13 : config.add_options()
86 26 : ("DEFAULT.bgp_config_file",
87 26 : opt::value<string>()->default_value("bgp_config.xml"),
88 : "BGP Configuration file")
89 26 : ("DEFAULT.bgp_port",
90 13 : opt::value<uint16_t>()->default_value(default_bgp_port),
91 : "BGP listener port")
92 26 : ("DEFAULT.collectors",
93 39 : opt::value<vector<string> >()->default_value(
94 13 : default_collector_server_list_, "127.0.0.1:8086"),
95 : "Collector server list")
96 :
97 26 : ("DEFAULT.gr_helper_bgp_disable",
98 13 : opt::bool_switch(&gr_helper_bgp_disable_),
99 : "Disable Graceful Restart Helper functionality for BGP peers")
100 26 : ("DEFAULT.gr_helper_xmpp_disable",
101 13 : opt::bool_switch(&gr_helper_xmpp_disable_),
102 : "Disable Graceful Restart Helper functionality for XMPP agents")
103 :
104 13 : ("DEFAULT.hostip", opt::value<string>()->default_value(host_ip),
105 : "IP address of control-node")
106 13 : ("DEFAULT.hostname", opt::value<string>()->default_value(hostname),
107 : "Hostname of control-node")
108 26 : ("DEFAULT.http_server_port",
109 13 : opt::value<uint16_t>()->default_value(default_http_server_port),
110 : "Sandesh HTTP listener port")
111 :
112 26 : ("DEFAULT.log_category",
113 13 : opt::value<string>()->default_value(log_category_),
114 : "Category filter for local logging of sandesh messages")
115 13 : ("DEFAULT.log_disable", opt::bool_switch(&log_disable_),
116 : "Disable sandesh logging")
117 26 : ("DEFAULT.log_file", opt::value<string>()->default_value(
118 : "/var/log/contrail/contrail-control.log"),
119 : "Filename for the logs to be written to")
120 26 : ("DEFAULT.log_property_file", opt::value<string>()->default_value(""),
121 : "log4cplus property file name")
122 26 : ("DEFAULT.log_files_count",
123 13 : opt::value<int>()->default_value(10),
124 : "Maximum log file roll over index")
125 26 : ("DEFAULT.log_file_size",
126 13 : opt::value<long>()->default_value(10*1024*1024),
127 : "Maximum size of the log file")
128 26 : ("DEFAULT.log_level", opt::value<string>()->default_value("SYS_NOTICE"),
129 : "Severity level for local logging of sandesh messages")
130 26 : ("DEFAULT.log_local",
131 13 : opt::bool_switch(&log_local_)->default_value(true),
132 : "Enable local logging of sandesh messages")
133 13 : ("DEFAULT.mvpn_ipv4_enable", opt::bool_switch(&mvpn_ipv4_enable_),
134 : "Enable NGEN Multicast VPN support for IPv4 routes")
135 13 : ("DEFAULT.use_syslog", opt::bool_switch(&use_syslog_),
136 : "Enable logging to syslog")
137 26 : ("DEFAULT.syslog_facility",
138 26 : opt::value<string>()->default_value("LOG_LOCAL0"),
139 : "Syslog facility to receive log lines")
140 13 : ("DEFAULT.task_track_run_time", opt::bool_switch(&task_track_run_time_),
141 : "Enable tracking of run time per task id")
142 13 : ("DEFAULT.test_mode", opt::bool_switch(&test_mode_),
143 : "Enable control-node to run in test-mode")
144 13 : ("DEFAULT.tcp_hold_time", opt::value<int>()->default_value(30),
145 : "Configurable TCP hold time")
146 13 : ("DEFAULT.optimize_snat", opt::bool_switch(&optimize_snat_),
147 : "Enable control-node optimizations for SNAT (deprecated)")
148 26 : ("DEFAULT.xmpp_server_port",
149 13 : opt::value<uint16_t>()->default_value(default_xmpp_port),
150 : "XMPP listener port")
151 13 : ("DEFAULT.xmpp_auth_enable", opt::bool_switch(&xmpp_auth_enable_),
152 : "Enable authentication over Xmpp")
153 26 : ("DEFAULT.xmpp_server_cert",
154 26 : opt::value<string>()->default_value(
155 : "/etc/contrail/ssl/certs/server.pem"),
156 : "XMPP Server ssl certificate")
157 26 : ("DEFAULT.xmpp_server_key",
158 26 : opt::value<string>()->default_value(
159 : "/etc/contrail/ssl/private/server-privkey.pem"),
160 : "XMPP Server ssl private key")
161 26 : ("DEFAULT.xmpp_ca_cert",
162 26 : opt::value<string>()->default_value(
163 : "/etc/contrail/ssl/certs/ca-cert.pem"),
164 : "XMPP CA ssl certificate")
165 :
166 26 : ("CONFIGDB.config_db_server_list",
167 13 : opt::value<vector<string> >()->default_value(
168 : default_config_db_server_list, default_config_db_server),
169 : "Config database server list")
170 26 : ("CONFIGDB.config_db_username",
171 26 : opt::value<string>()->default_value(""),
172 : "ConfigDB user")
173 26 : ("CONFIGDB.config_db_password",
174 26 : opt::value<string>()->default_value(""),
175 : "ConfigDB password")
176 26 : ("CONFIGDB.config_db_use_ssl",
177 13 : opt::value<bool>()->default_value(false),
178 : "Use SSL for Cassandra connection")
179 26 : ("CONFIGDB.config_db_ca_certs",
180 26 : opt::value<string>()->default_value(""),
181 : "CA Certificate file for SSL Cassandra connection")
182 26 : ("CONFIGDB.rabbitmq_server_list",
183 13 : opt::value<vector<string> >()->default_value(
184 : default_rabbitmq_server_list, default_rabbitmq_server),
185 : "RabbitMQ server list")
186 26 : ("CONFIGDB.rabbitmq_user",
187 26 : opt::value<string>()->default_value("guest"),
188 : "RabbitMQ user")
189 26 : ("CONFIGDB.rabbitmq_password",
190 26 : opt::value<string>()->default_value("guest"),
191 : "RabbitMQ password")
192 26 : ("CONFIGDB.rabbitmq_vhost",
193 26 : opt::value<string>()->default_value(""),
194 : "RabbitMQ vhost")
195 26 : ("CONFIGDB.rabbitmq_use_ssl",
196 13 : opt::value<bool>()->default_value(false),
197 : "Use SSL for RabbitMQ connection")
198 26 : ("CONFIGDB.rabbitmq_ssl_version",
199 26 : opt::value<string>()->default_value(""),
200 : "SSL version for RabbitMQ connection")
201 26 : ("CONFIGDB.rabbitmq_ssl_keyfile",
202 26 : opt::value<string>()->default_value(""),
203 : "Keyfile for SSL RabbitMQ connection")
204 26 : ("CONFIGDB.rabbitmq_ssl_certfile",
205 26 : opt::value<string>()->default_value(""),
206 : "Certificate file for SSL RabbitMQ connection")
207 26 : ("CONFIGDB.rabbitmq_ssl_ca_certs",
208 26 : opt::value<string>()->default_value(""),
209 : "CA Certificate file for SSL RabbitMQ connection")
210 :
211 13 : ("CONFIGDB.config_db_use_etcd",
212 13 : opt::value<bool>()->default_value(false),
213 : "Use etcd as the contrail DB client")
214 : ;
215 :
216 13 : sandesh::options::AddOptions(&config, &sandesh_config_);
217 :
218 13 : config_file_options_.add(config);
219 13 : cmdline_options.add(generic).add(config);
220 13 : }
221 :
222 29 : uint32_t Options::GenerateHash(const std::vector<std::string> &list) {
223 29 : std::string concat_servers;
224 29 : std::vector<std::string>::const_iterator iter;
225 68 : for (iter = list.begin(); iter != list.end(); iter++) {
226 39 : concat_servers += *iter;
227 : }
228 : boost::hash<std::string> string_hash;
229 58 : return(string_hash(concat_servers));
230 29 : }
231 :
232 9 : uint32_t Options::GenerateHash(const ConfigClientOptions &config) {
233 9 : uint32_t chk_sum = GenerateHash(config.config_db_server_list);
234 9 : chk_sum += GenerateHash(config.rabbitmq_server_list);
235 : boost::hash<std::string> string_hash;
236 9 : chk_sum += string_hash(config.rabbitmq_user);
237 9 : chk_sum += string_hash(config.rabbitmq_password);
238 9 : chk_sum += string_hash(config.config_db_username);
239 9 : chk_sum += string_hash(config.config_db_password);
240 9 : return chk_sum;
241 : }
242 :
243 : // Process command line options. They can come from a conf file as well. Options
244 : // from command line always overrides those that come from the config file.
245 13 : bool Options::Process(int argc, char *argv[],
246 : opt::options_description &cmdline_options) {
247 : // Process options off command line first.
248 13 : opt::variables_map var_map;
249 13 : opt::store(opt::parse_command_line(argc, argv, cmdline_options), var_map);
250 :
251 : // Process options off configuration file.
252 13 : GetOptValue<string>(var_map, config_file_, "conf_file");
253 13 : ifstream config_file_in;
254 13 : config_file_in.open(config_file_.c_str());
255 13 : if (config_file_in.good()) {
256 9 : opt::store(opt::parse_config_file(config_file_in, config_file_options_),
257 : var_map);
258 : }
259 13 : config_file_in.close();
260 :
261 13 : opt::notify(var_map);
262 :
263 13 : if (var_map.count("help")) {
264 0 : cout << cmdline_options << endl;
265 0 : return false;
266 : }
267 :
268 13 : if (var_map.count("version")) {
269 0 : cout << BuildInfo << endl;
270 0 : return false;
271 : }
272 :
273 : // Retrieve the options.
274 13 : GetOptValue<string>(var_map, bgp_config_file_, "DEFAULT.bgp_config_file");
275 13 : GetOptValue<uint16_t>(var_map, bgp_port_, "DEFAULT.bgp_port");
276 13 : GetOptValue< vector<string> >(var_map, collector_server_list_,
277 : "DEFAULT.collectors");
278 13 : string error_msg;
279 13 : if (!ValidateServerEndpoints(collector_server_list_, &error_msg)) {
280 2 : cout << "Invalid endpoint : " << error_msg;
281 2 : return false;
282 : }
283 :
284 11 : collectors_configured_ = collector_server_list_.size();
285 19 : if (collector_server_list_.size() == 1 &&
286 8 : !collector_server_list_[0].compare(default_collector_server_list_[0])) {
287 8 : collectors_configured_ = false;
288 : }
289 :
290 : // Randomize Collector List
291 11 : collector_chksum_ = GenerateHash(collector_server_list_);
292 11 : randomized_collector_server_list_ = collector_server_list_;
293 11 : std::random_shuffle(randomized_collector_server_list_.begin(),
294 : randomized_collector_server_list_.end());
295 :
296 11 : GetOptValue<string>(var_map, host_ip_, "DEFAULT.hostip");
297 11 : if (!ValidateIPAddressString(host_ip_, &error_msg)) {
298 2 : cout << "Invalid IP address: " << host_ip_ << error_msg;
299 2 : return false;
300 : }
301 :
302 9 : GetOptValue<string>(var_map, hostname_, "DEFAULT.hostname");
303 :
304 9 : GetOptValue<uint16_t>(var_map, http_server_port_,
305 : "DEFAULT.http_server_port");
306 :
307 9 : GetOptValue<string>(var_map, log_category_, "DEFAULT.log_category");
308 9 : GetOptValue<string>(var_map, log_file_, "DEFAULT.log_file");
309 9 : GetOptValue<string>(var_map, log_property_file_, "DEFAULT.log_property_file");
310 9 : GetOptValue<int>(var_map, log_files_count_, "DEFAULT.log_files_count");
311 9 : GetOptValue<long>(var_map, log_file_size_, "DEFAULT.log_file_size");
312 9 : GetOptValue<string>(var_map, log_level_, "DEFAULT.log_level");
313 9 : GetOptValue<string>(var_map, syslog_facility_, "DEFAULT.syslog_facility");
314 9 : GetOptValue<int>(var_map, tcp_hold_time_, "DEFAULT.tcp_hold_time");
315 9 : GetOptValue<uint16_t>(var_map, xmpp_port_, "DEFAULT.xmpp_server_port");
316 9 : GetOptValue<string>(var_map, xmpp_server_cert_, "DEFAULT.xmpp_server_cert");
317 9 : GetOptValue<string>(var_map, xmpp_server_key_, "DEFAULT.xmpp_server_key");
318 9 : GetOptValue<string>(var_map, xmpp_ca_cert_, "DEFAULT.xmpp_ca_cert");
319 :
320 9 : ParseConfigOptions(var_map);
321 :
322 9 : sandesh::options::ProcessOptions(var_map, &sandesh_config_);
323 9 : return true;
324 13 : }
325 :
326 0 : void Options::ParseReConfig(bool force_reinit) {
327 : // ReParse the filtered config params
328 0 : opt::variables_map var_map;
329 0 : ifstream config_file_in;
330 0 : config_file_in.open(config_file_.c_str());
331 0 : if (config_file_in.good()) {
332 0 : opt::store(opt::parse_config_file(config_file_in, config_file_options_),
333 : var_map);
334 : }
335 0 : config_file_in.close();
336 :
337 0 : collector_server_list_.clear();
338 0 : GetOptValue< vector<string> >(var_map, collector_server_list_,
339 : "DEFAULT.collectors");
340 :
341 0 : uint32_t new_chksum = GenerateHash(collector_server_list_);
342 0 : if (collector_chksum_ != new_chksum) {
343 0 : collector_chksum_ = new_chksum;
344 0 : randomized_collector_server_list_.clear();
345 0 : randomized_collector_server_list_ = collector_server_list_;
346 0 : std::random_shuffle(randomized_collector_server_list_.begin(),
347 : randomized_collector_server_list_.end());
348 : }
349 : // ReConnect Collectors irrespective of change list to achieve
350 : // rebalance when older collector node/s are up again.
351 0 : Sandesh::ReConfigCollectors(randomized_collector_server_list_);
352 :
353 0 : uint32_t old_config_chksum = configdb_chksum_;
354 0 : ParseConfigOptions(var_map);
355 0 : if ((force_reinit || old_config_chksum != configdb_chksum_) &&
356 0 : config_client_manager_) {
357 0 : config_client_manager_->ReinitConfigClient(configdb_options());
358 : }
359 0 : }
360 :
361 9 : void Options::ParseConfigOptions(const boost::program_options::variables_map
362 : &var_map) {
363 9 : configdb_options_.config_db_server_list.clear();
364 18 : GetOptValue< vector<string> >(var_map,
365 9 : configdb_options_.config_db_server_list,
366 : "CONFIGDB.config_db_server_list");
367 18 : GetOptValue<string>(var_map,
368 9 : configdb_options_.config_db_username,
369 : "CONFIGDB.config_db_username");
370 18 : GetOptValue<string>(var_map,
371 9 : configdb_options_.config_db_password,
372 : "CONFIGDB.config_db_password");
373 18 : GetOptValue<bool>(var_map,
374 9 : configdb_options_.config_db_use_ssl,
375 : "CONFIGDB.config_db_use_ssl");
376 18 : GetOptValue<string>(var_map,
377 9 : configdb_options_.config_db_ca_certs,
378 : "CONFIGDB.config_db_ca_certs");
379 9 : configdb_options_.rabbitmq_server_list.clear();
380 18 : GetOptValue< vector<string> >(var_map,
381 9 : configdb_options_.rabbitmq_server_list,
382 : "CONFIGDB.rabbitmq_server_list");
383 18 : GetOptValue<string>(var_map,
384 9 : configdb_options_.rabbitmq_user,
385 : "CONFIGDB.rabbitmq_user");
386 18 : GetOptValue<string>(var_map,
387 9 : configdb_options_.rabbitmq_password,
388 : "CONFIGDB.rabbitmq_password");
389 18 : GetOptValue<string>(var_map,
390 9 : configdb_options_.rabbitmq_vhost,
391 : "CONFIGDB.rabbitmq_vhost");
392 18 : GetOptValue<bool>(var_map,
393 9 : configdb_options_.rabbitmq_use_ssl,
394 : "CONFIGDB.rabbitmq_use_ssl");
395 18 : GetOptValue<string>(var_map,
396 9 : configdb_options_.rabbitmq_ssl_version,
397 : "CONFIGDB.rabbitmq_ssl_version");
398 18 : GetOptValue<string>(var_map,
399 9 : configdb_options_.rabbitmq_ssl_keyfile,
400 : "CONFIGDB.rabbitmq_ssl_keyfile");
401 18 : GetOptValue<string>(var_map,
402 9 : configdb_options_.rabbitmq_ssl_certfile,
403 : "CONFIGDB.rabbitmq_ssl_certfile");
404 18 : GetOptValue<string>(var_map,
405 9 : configdb_options_.rabbitmq_ssl_ca_certs,
406 : "CONFIGDB.rabbitmq_ssl_ca_certs");
407 18 : GetOptValue<bool>(var_map,
408 9 : configdb_options_.config_db_use_etcd,
409 : "CONFIGDB.config_db_use_etcd");
410 9 : configdb_chksum_ = GenerateHash(configdb_options_);
411 9 : }
|