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