Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1#include <string>
2#include <vector>
3#include <math.h>
4#include <sstream>
5#include <regex>
6
7#include <boost/algorithm/string.hpp>
8#include <boost/asio/ip/tcp.hpp>
9#include <boost/asio/ip/host_name.hpp>
10#include <boost/program_options.hpp>
11#pragma GCC diagnostic push
12#pragma GCC diagnostic ignored "-Wunused-result"
13#include <boost/process/child.hpp>
14#pragma GCC diagnostic pop
15#include <boost/process/env.hpp>
16#include <boost/process/system.hpp>
17#include <boost/process/io.hpp>
18#include <boost/lexical_cast.hpp>
19#include <boost/filesystem.hpp>
20#include <boost/filesystem/path.hpp>
21#include <boost/filesystem/fstream.hpp>
24#include <fc/io/json.hpp>
25#include <fc/network/ip.hpp>
28#include <ifaddrs.h>
29#include <sys/types.h>
30#include <netinet/in.h>
31#include <net/if.h>
33
34#include "config.hpp"
35
36using namespace std;
37namespace bfs = boost::filesystem;
38namespace bp = boost::process;
39namespace bpo = boost::program_options;
40using boost::asio::ip::tcp;
41using boost::asio::ip::host_name;
42using bpo::options_description;
43using bpo::variables_map;
46using namespace sysio::launcher::config;
47
48const string block_dir = "blocks";
49const string shared_mem_dir = "state";
50
52 vector <fc::ip::address> addrs;
53 vector <string> names;
54
55 void initialize () {
56 names.push_back ("localhost");
57 names.push_back ("127.0.0.1");
58
59 boost::system::error_code ec;
60 string hn = host_name (ec);
61 if (ec.value() != boost::system::errc::success) {
62 cerr << "unable to retrieve host name: " << ec.message() << endl;
63 }
64 else {
65 names.push_back (hn);
66 if (hn.find ('.') != string::npos) {
67 names.push_back (hn.substr (0,hn.find('.')));
68 }
69 }
70
71 ifaddrs *ifap = 0;
72 if (::getifaddrs (&ifap) == 0) {
73 for (ifaddrs *p_if = ifap; p_if != 0; p_if = p_if->ifa_next) {
74 if (p_if->ifa_addr != 0 &&
75 p_if->ifa_addr->sa_family == AF_INET &&
76 (p_if->ifa_flags & IFF_UP) == IFF_UP) {
77 sockaddr_in *ifaddr = reinterpret_cast<sockaddr_in *>(p_if->ifa_addr);
78 int32_t in_addr = ntohl(ifaddr->sin_addr.s_addr);
79
80 if (in_addr != 0) {
81 fc::ip::address ifa(in_addr);
82 addrs.push_back (ifa);
83 }
84 }
85 }
86 ::freeifaddrs (ifap);
87 }
88 else {
89 cerr << "unable to query local ip interfaces" << endl;
90 addrs.push_back (fc::ip::address("127.0.0.1"));
91 }
92 }
93
94 bool contains (const string &name) const {
95 try {
97 for (const auto &a : addrs) {
98 if (a == test)
99 return true;
100 }
101 }
102 catch (...) {
103 // not an ip address
104 for (const auto& n : names) {
105 if (n == name)
106 return true;
107 }
108 }
109 return false;
110 }
111
113
114class eosd_def;
115
116class host_def {
117public:
119 : genesis("genesis.json"),
120 ssh_identity (""),
121 ssh_args (""),
122 sysio_home(),
123 host_name("127.0.0.1"),
124 public_name("localhost"),
125 listen_addr("0.0.0.0"),
126 base_p2p_port(9876),
127 base_http_port(8888),
128 def_file_size(8192),
129 instances(),
130 p2p_count(0),
131 http_count(0),
132 dot_label_str()
133 {}
134
135 string genesis;
137 string ssh_args;
139 string host_name;
145 vector<eosd_def> instances;
146
148 return base_p2p_port + p2p_count++;
149 }
150
152 return base_http_port + http_count++;
153 }
154
156 return base_p2p_port - 100;
157 }
158
160 return base_http_port - 100;
161 }
162
163 bool is_local( ) const {
164 return local_id.contains( host_name );
165 }
166
167 const string &dot_label () {
168 if (dot_label_str.empty() ) {
169 mk_dot_label();
170 }
171 return dot_label_str;
172 }
173
174
175private:
176 uint16_t p2p_count;
177 uint16_t http_count;
178 string dot_label_str;
179
180protected:
182 if (public_name.empty()) {
183 dot_label_str = host_name;
184 }
185 else if (boost::iequals(public_name,host_name)) {
186 dot_label_str = public_name;
187 }
188 else
189 dot_label_str = public_name + "/" + host_name;
190 }
191};
192
193class tn_node_def;
194
195class eosd_def {
196public:
198 : config_dir_name (),
199 data_dir_name (),
200 p2p_port(),
201 http_port(),
202 file_size(),
203 name(),
204 node(),
205 host(),
206 p2p_endpoint() {}
207
208
209
215 string name;
217 string host;
219
220 void set_host (host_def* h, bool is_bios);
221 void mk_dot_label ();
222 const string &dot_label () {
223 if (dot_label_str.empty() ) {
224 mk_dot_label();
225 }
226 return dot_label_str;
227 }
228
229 string get_node_num() const {
230 return name.substr( name.length() - 2 );
231 }
232private:
233 string dot_label_str;
234};
235
237public:
238 string name;
239 vector<private_key_type> keys;
240 vector<string> peers;
241 vector<string> producers;
244 bool dont_start = false;
245};
246
247void
249 dot_label_str = name + "\\nprod=";
250 if (node == 0 || node->producers.empty()) {
251 dot_label_str += "<none>";
252 }
253 else {
254 bool docomma = false;
255 for (auto &prod: node->producers) {
256 if (docomma)
257 dot_label_str += ",";
258 else
259 docomma = true;
260 dot_label_str += prod;
261 }
262 }
263}
264
265void
266eosd_def::set_host( host_def* h, bool is_bios ) {
267 host = h->host_name;
268 p2p_port = is_bios ? h->p2p_bios_port() : h->p2p_port();
269 http_port = is_bios ? h->http_bios_port() : h->http_port();
271 p2p_endpoint = h->public_name + ":" + boost::lexical_cast<string, uint16_t>(p2p_port);
272}
273
275 string ssh_cmd = "/usr/bin/ssh";
276 string scp_cmd = "/usr/bin/scp";
278 string ssh_args;
279 bfs::path local_config_file = "temp_config";
280};
281
283 string name;
285 map <string,tn_node_def> nodes;
286};
287
290 public_key_type block_signing_key;
291};
292
294 vector<prodkey_def> schedule;
295};
296
305
307 vector<server_name_def> producer;
308 vector<server_name_def> nonprod;
309 vector<string> db;
312};
313
315 bool remote;
316 string pid_file;
317 string kill_cmd;
318};
319
321 vector <node_rt_info> running_nodes;
322};
323
332
335 PC_PRODUCERS = 1 << 0,
336 PC_SPECIFIED = 1 << 1,
337 PC_ANY = 1 << 2
339
341public:
342 static string producer_name(unsigned int producer_number, bool shared_producer = false);
343private:
344 static const int total_chars = 12;
345 static const char slot_chars[];
346 static const char valid_char_range;
347};
348
349const char producer_names::slot_chars[] = "abcdefghijklmnopqrstuvwxyz";
350const char producer_names::valid_char_range = sizeof(producer_names::slot_chars) - 1;
351
352// for 26 or fewer total producers create "defproducera" .. "defproducerz"
353// above 26 produce "defproducera" .. "defproducerz", "defproduceaa" .. "defproducerb", etc.
354string producer_names::producer_name(unsigned int producer_number, bool shared_producer) {
355 // keeping legacy "defproducer[a-z]", but if greater than valid_char_range, will use "defpraaaaaaa"
356 // shared_producer will appear in all nodes' config
357 char prod_name[] = "defproducera";
358 if (producer_number > valid_char_range) {
359 for (int current_char_loc = 5; current_char_loc < total_chars; ++current_char_loc) {
360 prod_name[current_char_loc] = slot_chars[0];
361 }
362 }
363
364 prod_name[total_chars] = '\0';
365 for (int current_char_loc = total_chars - 1; current_char_loc >= 0; --current_char_loc) {
366 const unsigned int slot_value = static_cast<char>(producer_number % valid_char_range);
367 producer_number /= valid_char_range;
368 prod_name[current_char_loc] = slot_chars[slot_value];
369 if (!producer_number)
370 break;
371 }
372
373 // make sure we haven't cycled back to the first 26 names (some time after 26^6)
374 if (string(prod_name) == "defproducera" && producer_number != 0)
375 throw std::runtime_error( "launcher not designed to handle numbers this large " );
376
377 if (shared_producer) {
378 prod_name[0] = 's';
379 prod_name[1] = 'h';
380 prod_name[2] = 'r';
381 }
382 return prod_name;
383}
384
390 size_t producers;
392 size_t next_node;
393 string shape;
395 bfs::path genesis;
396 bfs::path output;
397 bfs::path host_map_file;
399 bfs::path stage;
400
401 string erd;
403 bfs::path data_dir_base;
406 std::map<uint,string> specific_nodeop_args;
410 vector <string> aliases;
411 vector <host_def> bindings;
412 int per_host = 0;
414 int start_delay = 0;
416 bool nogen;
417 bool boot;
425 std::optional<uint32_t> max_block_cpu_usage;
426 std::optional<uint32_t> max_transaction_cpu_usage;
428
429 void assign_name (eosd_def &node, bool is_bios);
430
431 void set_options (bpo::options_description &cli);
432 void initialize (const variables_map &vmap);
433 void init_genesis ();
434 void load_servers ();
435 bool generate ();
436 void define_network ();
437 void bind_nodes ();
438 host_def *find_host (const string &name);
441 string compose_scp_command (const host_def &host, const bfs::path &source,
442 const bfs::path &destination);
443 void write_config_file (tn_node_def &node);
445 void write_genesis_file (tn_node_def &node);
446 void write_setprods_file ();
447 void write_bios_boot ();
448
449 bool is_bios_ndx (size_t ndx);
450 size_t start_ndx();
451 bool next_ndx(size_t &ndx);
452 size_t skip_ndx (size_t from, size_t offset);
453
454 void make_line (bool make_ring = true);
455 void make_star ();
456 void make_mesh ();
457 void make_custom ();
458 void write_dot_file ();
459 void format_ssh (const string &cmd, const string &host_name, string &ssh_cmd_line);
460 void do_command(const host_def& host, const string& name, vector<pair<string, string>> env_pairs, const string& cmd);
461 bool do_ssh (const string &cmd, const string &host_name);
462 void prep_remote_config_dir (eosd_def &node, host_def *host);
463 void launch (eosd_def &node, string &gts);
464 void kill (launch_modes mode, string sig_opt);
465 static string get_node_num(uint16_t node_num);
466 pair<host_def, eosd_def> find_node(uint16_t node_num);
467 vector<pair<host_def, eosd_def>> get_nodes(const string& node_number_list);
468 void bounce (const string& node_numbers);
469 void down (const string& node_numbers);
470 void roll (const string& host_names);
471 void start_all (string &gts, launch_modes mode);
472 void ignite ();
473 string find_and_remove_arg(string str, string substr);
474};
475
476void
477launcher_def::set_options (bpo::options_description &cfg) {
478 cfg.add_options()
479 ("force,f", bpo::bool_switch(&force_overwrite)->default_value(false), "Force overwrite of existing configuration files and erase blockchain")
480 ("nodes,n",bpo::value<size_t>(&total_nodes)->default_value(1),"total number of nodes to configure and launch")
481 ("unstarted-nodes",bpo::value<size_t>(&unstarted_nodes)->default_value(0),"total number of nodes to configure, but not launch")
482 ("pnodes,p",bpo::value<size_t>(&prod_nodes)->default_value(1),"number of nodes that contain one or more producers")
483 ("producers",bpo::value<size_t>(&producers)->default_value(21),"total number of non-bios and non-shared producer instances in this network")
484 ("shared-producers",bpo::value<size_t>(&shared_producers)->default_value(0),"total number of shared producers on each non-bios nodes")
485 ("mode,m",bpo::value<vector<string>>()->multitoken()->default_value({"any"}, "any"),"connection mode, combination of \"any\", \"producers\", \"specified\", \"none\"")
486 ("shape,s",bpo::value<string>(&shape)->default_value("star"),"network topology, use \"star\", \"mesh\", \"ring\", \"line\" or give a filename for custom")
487 ("genesis,g",bpo::value<string>()->default_value("./genesis.json"),"set the path to genesis.json")
488 ("skip-signature", bpo::bool_switch(&skip_transaction_signatures)->default_value(false), (string(node_executable_name) + " does not require transaction signatures.").c_str())
489 (node_executable_name, bpo::value<string>(&eosd_extra_args), ("forward " + string(node_executable_name) + " command line argument(s) to each instance of " + string(node_executable_name) + ", enclose arg(s) in quotes").c_str())
490 ("specific-num", bpo::value<vector<uint>>()->composing(), ("forward " + string(node_executable_name) + " command line argument(s) (using \"--specific-" + string(node_executable_name) + "\" flag) to this specific instance of " + string(node_executable_name) + ". This parameter can be entered multiple times and requires a paired \"--specific-" + string(node_executable_name) +"\" flag each time it is used").c_str())
491 (("specific-" + string(node_executable_name)).c_str(), bpo::value<vector<string>>()->composing(), ("forward " + string(node_executable_name) + " command line argument(s) to its paired specific instance of " + string(node_executable_name) + "(using \"--specific-num\"), enclose arg(s) in quotes").c_str())
492 ("spcfc-inst-num", bpo::value<vector<uint>>()->composing(), ("Specify a specific version installation path (using \"--spcfc-inst-"+ string(node_executable_name) + "\" flag) for launching this specific instance of " + string(node_executable_name) + ". This parameter can be entered multiple times and requires a paired \"--spcfc-inst-" + string(node_executable_name) + "\" flag each time it is used").c_str())
493 (("spcfc-inst-" + string(node_executable_name)).c_str(), bpo::value<vector<string>>()->composing(), ("Provide a specific version installation path to its paired specific instance of " + string(node_executable_name) + "(using \"--spcfc-inst-num\")").c_str())
494 ("delay,d",bpo::value<int>(&start_delay)->default_value(0),"seconds delay before starting each node after the first")
495 ("boot",bpo::bool_switch(&boot)->default_value(false),"After deploying the nodes and generating a boot script, invoke it.")
496 ("nogen",bpo::bool_switch(&nogen)->default_value(false),"launch nodes without writing new config files")
497 ("host-map",bpo::value<string>(),"a file containing mapping specific nodes to hosts. Used to enhance the custom shape argument")
498 ("servers",bpo::value<string>(),"a file containing ip addresses and names of individual servers to deploy as producers or non-producers ")
499 ("per-host",bpo::value<int>(&per_host)->default_value(0),("specifies how many " + string(node_executable_name) + " instances will run on a single host. Use 0 to indicate all on one.").c_str())
500 ("network-name",bpo::value<string>(&network.name)->default_value("testnet_"),"network name prefix used in GELF logging source")
501 ("enable-gelf-logging",bpo::value<bool>(&gelf_enabled)->default_value(false),"enable gelf logging appender in logging configuration file")
502 ("gelf-endpoint",bpo::value<string>(&gelf_endpoint)->default_value("10.160.11.21:12201"),"hostname:port or ip:port of GELF endpoint")
503 ("template",bpo::value<string>(&start_temp)->default_value("testnet.template"),"the startup script template")
504 ("script",bpo::value<string>(&start_script)->default_value("bios_boot.sh"),"the generated startup script name")
505 ("max-block-cpu-usage",bpo::value<uint32_t>(),"Provide the \"max-block-cpu-usage\" value to use in the genesis.json file")
506 ("max-transaction-cpu-usage",bpo::value<uint32_t>(),"Provide the \"max-transaction-cpu-usage\" value to use in the genesis.json file")
507 ;
508}
509
510template<class enum_type, class=typename std::enable_if<std::is_enum<enum_type>::value>::type>
511inline enum_type& operator|=(enum_type&lhs, const enum_type& rhs)
512{
513 using T = std::underlying_type_t <enum_type>;
514 return lhs = static_cast<enum_type>(static_cast<T>(lhs) | static_cast<T>(rhs));
515}
516
517template <typename T>
518void retrieve_paired_array_parameters (const variables_map &vmap, const std::string& num_selector, const std::string& paired_selector, std::map<uint,T>& selector_map) {
519 if (vmap.count(num_selector)) {
520 const auto specific_nums = vmap[num_selector].as<vector<uint>>();
521 const auto specific_args = vmap[paired_selector].as<vector<string>>();
522 if (specific_nums.size() != specific_args.size()) {
523 cerr << "ERROR: every " << num_selector << " argument must be paired with a " << paired_selector << " argument" << endl;
524 exit (-1);
525 }
526 const auto total_nodes = vmap["nodes"].as<size_t>();
527 for(uint i = 0; i < specific_nums.size(); ++i)
528 {
529 const auto& num = specific_nums[i];
530 if (num >= total_nodes) {
531 cerr << "\"--" << num_selector << "\" provided value= " << num << " is higher than \"--nodes\" provided value=" << total_nodes << endl;
532 exit (-1);
533 }
534 selector_map[num] = specific_args[i];
535 }
536 }
537}
538
539void
540launcher_def::initialize (const variables_map &vmap) {
541 if (vmap.count("mode")) {
542 const vector<string> modes = vmap["mode"].as<vector<string>>();
543 for(const string&m : modes)
544 {
545 if (boost::iequals(m, "any"))
547 else if (boost::iequals(m, "producers"))
549 else if (boost::iequals(m, "specified"))
551 else if (boost::iequals(m, "none"))
553 else {
554 cerr << "unrecognized connection mode: " << m << endl;
555 exit (-1);
556 }
557 }
558 }
559
560 if (vmap.count("max-block-cpu-usage")) {
561 max_block_cpu_usage = vmap["max-block-cpu-usage"].as<uint32_t>();
562 }
563
564 if (vmap.count("max-transaction-cpu-usage")) {
565 max_transaction_cpu_usage = vmap["max-transaction-cpu-usage"].as<uint32_t>();
566 }
567
568 genesis = vmap["genesis"].as<string>();
569 if (vmap.count("host-map")) {
570 host_map_file = vmap["host-map"].as<string>();
571 }
572 if (vmap.count("servers")) {
573 server_ident_file = vmap["servers"].as<string>();
574 }
575
576 retrieve_paired_array_parameters(vmap, "specific-num", "specific-" + string(node_executable_name), specific_nodeop_args);
577 retrieve_paired_array_parameters(vmap, "spcfc-inst-num", "spcfc-inst-" + string(node_executable_name), specific_nodeop_installation_paths);
578
579 using namespace std::chrono;
580 system_clock::time_point now = system_clock::now();
581 std::time_t now_c = system_clock::to_time_t(now);
582 ostringstream dstrm;
583 dstrm << std::put_time(std::localtime(&now_c), "%Y_%m_%d_%H_%M_%S");
584 launch_time = dstrm.str();
585
586 if ( ! (shape.empty() ||
587 boost::iequals( shape, "ring" ) ||
588 boost::iequals( shape, "line" ) ||
589 boost::iequals( shape, "star" ) ||
590 boost::iequals( shape, "mesh" )) &&
591 host_map_file.empty()) {
592 bfs::path src = shape;
593 host_map_file = src.stem().string() + "_hosts.json";
594 }
595
596 if( !host_map_file.empty() ) {
597 try {
598 fc::json::from_file(host_map_file).as<vector<host_def>>(bindings);
599 for (auto &binding : bindings) {
600 for (auto &eosd : binding.instances) {
601 eosd.host = binding.host_name;
602 eosd.p2p_endpoint = binding.public_name + ":" + boost::lexical_cast<string,uint16_t>(eosd.p2p_port);
603
604 aliases.push_back (eosd.name);
605 }
606 }
607 } catch (...) { // this is an optional feature, so an exception is OK
608 }
609 }
610
611 config_dir_base = "etc/sysio";
612 data_dir_base = "var/lib";
613 next_node = 0;
614 ++prod_nodes; // add one for the bios node
615 ++total_nodes;
616
617 load_servers ();
618
619 if (prod_nodes > (producers + 1))
624 cerr << "ERROR: if provided, \"--nodes\" must be equal or greater than the number of nodes indicated by \"--pnodes\" and \"--unstarted-nodes\"." << endl;
625 exit (-1);
626 }
627
628 if (vmap.count("specific-num")) {
629 const auto specific_nums = vmap["specific-num"].as<vector<uint>>();
630 const auto specific_args = vmap["specific-" + string(node_executable_name)].as<vector<string>>();
631 if (specific_nums.size() != specific_args.size()) {
632 cerr << "ERROR: every specific-num argument must be paired with a specific-" << node_executable_name << " argument" << endl;
633 exit (-1);
634 }
635 // don't include bios
636 const auto allowed_nums = total_nodes - 1;
637 for(uint i = 0; i < specific_nums.size(); ++i)
638 {
639 const auto& num = specific_nums[i];
640 if (num >= allowed_nums) {
641 cerr << "\"--specific-num\" provided value= " << num << " is higher than \"--nodes\" provided value=" << total_nodes << endl;
642 exit (-1);
643 }
644 specific_nodeop_args[num] = specific_args[i];
645 }
646 }
647
648 char* erd_env_var = getenv ("SYSIO_HOME");
649 if (erd_env_var == nullptr || std::string(erd_env_var).empty()) {
650 erd_env_var = getenv ("PWD");
651 }
652
653 if (erd_env_var != nullptr) {
654 erd = erd_env_var;
655 } else {
656 erd.clear();
657 }
658
659 stage = bfs::path(erd);
660 if (!bfs::exists(stage)) {
661 cerr << "\"" << erd << "\" is not a valid path. Please ensure environment variable SYSIO_HOME is set to the build path." << endl;
662 exit (-1);
663 }
664 stage /= bfs::path("staging");
665 bfs::create_directories (stage);
666 if (bindings.empty()) {
668 }
669
670}
671
672void
674 if (!server_ident_file.empty()) {
675 try {
677 prod_nodes = 0;
678 for (auto &s : servers.producer) {
679 prod_nodes += s.instances;
680 }
681
683 for (auto &s : servers.nonprod) {
684 total_nodes += s.instances;
685 }
686
687 per_host = 1;
688 network.ssh_helper = servers.ssh;
689 }
690 catch (...) {
691 cerr << "unable to load server identity file " << server_ident_file << endl;
692 exit (-1);
693 }
694 }
695}
696
697
698void
699launcher_def::assign_name (eosd_def &node, bool is_bios) {
700 string node_cfg_name;
701
702 if (is_bios) {
703 node.name = "bios";
704 node_cfg_name = "node_bios";
705 }
706 else {
707 string dex = next_node < 10 ? "0":"";
708 dex += boost::lexical_cast<string,int>(next_node++);
709 node.name = network.name + dex;
710 node_cfg_name = "node_" + dex;
711 }
712 node.config_dir_name = (config_dir_base / node_cfg_name).string();
713 node.data_dir_name = (data_dir_base / node_cfg_name).string();
714}
715
716bool
718
719 if (boost::iequals (shape,"ring")) {
720 make_line ();
721 }
722 else if (boost::iequals (shape,"line")) {
723 make_line(false);
724 }
725 else if (boost::iequals (shape, "star")) {
726 make_star ();
727 }
728 else if (boost::iequals (shape, "mesh")) {
729 make_mesh ();
730 }
731 else {
732 make_custom ();
733 }
734
735 if( !nogen ) {
738 init_genesis();
739 for (auto &node : network.nodes) {
740 write_config_file(node.second);
741 write_logging_config_file(node.second);
742 write_genesis_file(node.second);
743 }
744 }
746
747 if (!output.empty()) {
748 bfs::path savefile = output;
749 {
750 bfs::ofstream sf (savefile);
751 sf << fc::json::to_pretty_string (network) << endl;
752 sf.close();
753 }
754 if (host_map_file.empty()) {
755 savefile = bfs::path (output.stem().string() + "_hosts.json");
756 }
757 else {
758 savefile = bfs::path (host_map_file);
759 }
760
761 {
762 bfs::ofstream sf (savefile);
763
764 sf << fc::json::to_pretty_string (bindings) << endl;
765 sf.close();
766 }
767 return false;
768 }
769
770 return true;
771}
772
773void
775 bfs::ofstream df ("testnet.dot");
776 df << "digraph G\n{\nlayout=\"circo\";\n";
777 for (auto &node : network.nodes) {
778 for (const auto &p : node.second.peers) {
779 string pname=network.nodes.find(p)->second.instance->dot_label();
780 df << "\"" << node.second.instance->dot_label ()
781 << "\"->\"" << pname
782 << "\" [dir=\"forward\"];" << std::endl;
783 }
784 }
785 df << "}\n";
786}
787
788void
790
791 if (per_host == 0) {
792 host_def local_host;
793 local_host.sysio_home = erd;
794 local_host.genesis = genesis.string();
795 for (size_t i = 0; i < (total_nodes); i++) {
796 eosd_def eosd;
797 assign_name(eosd, i == 0);
798 aliases.push_back(eosd.name);
799 eosd.set_host (&local_host, i == 0);
800 local_host.instances.emplace_back(move(eosd));
801 }
802 bindings.emplace_back(move(local_host));
803 }
804 else {
805 int ph_count = 0;
806 host_def *lhost = nullptr;
807 size_t host_ndx = 0;
808 size_t num_prod_addr = servers.producer.size();
809 size_t num_nonprod_addr = servers.nonprod.size();
810 for (size_t i = total_nodes; i > 0; i--) {
811 bool do_bios = false;
812 if (ph_count == 0) {
813 if (lhost) {
814 bindings.emplace_back(move(*lhost));
815 delete lhost;
816 }
817 lhost = new host_def;
818 lhost->genesis = genesis.string();
819 if (host_ndx < num_prod_addr ) {
820 do_bios = servers.producer[host_ndx].has_bios;
821 lhost->host_name = servers.producer[host_ndx].ipaddr;
822 lhost->public_name = servers.producer[host_ndx].name;
823 ph_count = servers.producer[host_ndx].instances;
824 }
825 else if (host_ndx - num_prod_addr < num_nonprod_addr) {
826 size_t ondx = host_ndx - num_prod_addr;
827 do_bios = servers.nonprod[ondx].has_bios;
828 lhost->host_name = servers.nonprod[ondx].ipaddr;
829 lhost->public_name = servers.nonprod[ondx].name;
830 ph_count = servers.nonprod[ondx].instances;
831 }
832 else {
833 string ext = host_ndx < 10 ? "0" : "";
834 ext += boost::lexical_cast<string,int>(host_ndx);
835 lhost->host_name = "pseudo_" + ext;
836 lhost->public_name = lhost->host_name;
837 ph_count = 1;
838 }
839 lhost->sysio_home =
840 (local_id.contains (lhost->host_name) || servers.default_sysio_home.empty()) ?
842 host_ndx++;
843 } // ph_count == 0
844
845 eosd_def eosd;
846 assign_name(eosd, do_bios);
847
848 aliases.push_back(eosd.name);
849 eosd.set_host (lhost, do_bios);
850 do_bios = false;
851 lhost->instances.emplace_back(move(eosd));
852 --ph_count;
853 } // for i
854 bindings.emplace_back( move(*lhost) );
855 delete lhost;
856 }
857}
858
859
860void
862 if (prod_nodes < 2) {
863 cerr << "Unable to allocate producers due to insufficient prod_nodes = " << prod_nodes << "\n";
864 exit (10);
865 }
866 size_t non_bios = prod_nodes - 1;
867 int per_node = producers / non_bios;
868 int extra = producers % non_bios;
869 unsigned int i = 0;
870 unsigned int producer_number = 0;
871 const auto to_not_start_node = total_nodes - unstarted_nodes - 1;
872 for (auto &h : bindings) {
873 for (auto &inst : h.instances) {
874 bool is_bios = inst.name == "bios";
875 tn_node_def node;
876 node.name = inst.name;
877 node.instance = &inst;
878 auto kp = is_bios ?
879 private_key_type(string("5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3")) :
880 private_key_type::generate();
881 auto pubkey = kp.get_public_key();
882 node.keys.emplace_back (move(kp));
883 if (is_bios) {
884 string prodname = "sysio";
885 node.producers.push_back(prodname);
886 producer_set.schedule.push_back({prodname,pubkey});
887 }
888 else {
889 if (i < non_bios) {
890 int count = per_node;
891 if (extra ) {
892 ++count;
893 --extra;
894 }
895 while (count--) {
896 const auto prodname = producer_names::producer_name(producer_number);
897 node.producers.push_back(prodname);
898 producer_set.schedule.push_back({prodname,pubkey});
899 ++producer_number;
900 }
901 for (unsigned j = 0; j < shared_producers; ++j) {
902 const auto prodname = producer_names::producer_name(j, true);
903 node.producers.push_back(prodname);
904 producer_set.schedule.push_back({prodname,pubkey});
905 }
906 }
907 node.dont_start = i >= to_not_start_node;
908 }
910 network.nodes[node.name] = move(node);
911 inst.node = &network.nodes[inst.name];
912 if (!is_bios) i++;
913 }
914 }
915}
916
917host_def *
919{
920 host_def *host = nullptr;
921 for (auto &h : bindings) {
922 if (h.host_name == name) {
923 host = &h;
924 break;
925 }
926 }
927 if (host == 0) {
928 cerr << "could not find host for " << name << endl;
929 exit(-1);
930 }
931 return host;
932}
933
934host_def *
936{
937 host_def *host = nullptr;
938 for (auto &h : bindings) {
939 if ((h.host_name == host_id) || (h.public_name == host_id)) {
940 host = &h;
941 break;
942 }
943 }
944 if (host == 0) {
945 cerr << "could not find host for " << host_id << endl;
946 exit(-1);
947 }
948 return host;
949}
950
951host_def *
953 boost::system::error_code ec;
954 eosd_def &instance = *node.instance;
955 host_def *host = find_host (instance.host);
956
957 bfs::path source = stage / instance.config_dir_name / "config.ini";
958 bfs::path logging_source = stage / instance.config_dir_name / "logging.json";
959 bfs::path genesis_source = stage / instance.config_dir_name / "genesis.json";
960
961 if (host->is_local()) {
962 bfs::path cfgdir = bfs::path(host->sysio_home) / instance.config_dir_name;
963 bfs::path dd = bfs::path(host->sysio_home) / instance.data_dir_name;
964
965 if (!bfs::exists (cfgdir)) {
966 if (!bfs::create_directories (cfgdir, ec) && ec.value()) {
967 cerr << "could not create new directory: " << instance.config_dir_name
968 << " errno " << ec.value() << " " << strerror(ec.value()) << endl;
969 exit (-1);
970 }
971 }
972 else if (bfs::exists (cfgdir / "config.ini") && !force_overwrite) {
973 cerr << cfgdir / "config.ini" << " exists. Use -f|--force to overwrite configuration\n";
974 exit (-1);
975 }
976
977 if (!bfs::exists (dd)) {
978 if (!bfs::create_directories (dd, ec) && ec.value()) {
979 cerr << "could not create new directory: " << instance.config_dir_name
980 << " errno " << ec.value() << " " << strerror(ec.value()) << endl;
981 exit (-1);
982 }
983 }
984 else if (force_overwrite) {
985 int64_t count = bfs::remove_all (dd / block_dir, ec);
986 if (ec.value() != 0) {
987 cerr << "count = " << count << " could not remove old directory: " << dd
988 << " " << strerror(ec.value()) << endl;
989 exit (-1);
990 }
991 count = bfs::remove_all (dd / shared_mem_dir, ec);
992 if (ec.value() != 0) {
993 cerr << "count = " << count << " could not remove old directory: " << dd
994 << " " << strerror(ec.value()) << endl;
995 exit (-1);
996 }
997 }
998 else if (bfs::exists (dd/ block_dir) || bfs::exists (dd / shared_mem_dir)) {
999 cerr << "either " << block_dir << " or " << shared_mem_dir << " exist in \n";
1000 cerr << dd << ". Use -f|--force to erase blockchain data" << endl;
1001 exit (-1);
1002 }
1003
1004 bfs::copy_file (genesis_source, cfgdir / "genesis.json", bfs::copy_option::overwrite_if_exists);
1005 bfs::copy_file (logging_source, cfgdir / "logging.json", bfs::copy_option::overwrite_if_exists);
1006 bfs::copy_file (source, cfgdir / "config.ini", bfs::copy_option::overwrite_if_exists);
1007 }
1008 else {
1009 prep_remote_config_dir (instance, host);
1010
1011 bfs::path rfile = bfs::path (host->sysio_home) / instance.config_dir_name / "config.ini";
1012 auto scp_cmd_line = compose_scp_command(*host, source, rfile);
1013
1014 cerr << "cmdline = " << scp_cmd_line << endl;
1015 int res = boost::process::system (scp_cmd_line);
1016 if (res != 0) {
1017 cerr << "unable to scp config file to host " << host->host_name << endl;
1018 exit(-1);
1019 }
1020
1021 rfile = bfs::path (host->sysio_home) / instance.config_dir_name / "logging.json";
1022
1023 scp_cmd_line = compose_scp_command(*host, logging_source, rfile);
1024
1025 res = boost::process::system (scp_cmd_line);
1026 if (res != 0) {
1027 cerr << "unable to scp logging config file to host " << host->host_name << endl;
1028 exit(-1);
1029 }
1030
1031 rfile = bfs::path (host->sysio_home) / instance.config_dir_name / "genesis.json";
1032
1033 scp_cmd_line = compose_scp_command(*host, genesis_source, rfile);
1034
1035 res = boost::process::system (scp_cmd_line);
1036 if (res != 0) {
1037 cerr << "unable to scp genesis.json file to host " << host->host_name << endl;
1038 exit(-1);
1039 }
1040 }
1041 return host;
1042}
1043
1044string
1045launcher_def::compose_scp_command (const host_def& host, const bfs::path& source, const bfs::path& destination) {
1046 string scp_cmd_line = network.ssh_helper.scp_cmd + " ";
1047 const string &args = host.ssh_args.length() ? host.ssh_args : network.ssh_helper.ssh_args;
1048 if (args.length()) {
1049 scp_cmd_line += args + " ";
1050 }
1051 scp_cmd_line += source.string() + " ";
1052
1053 const string &uid = host.ssh_identity.length() ? host.ssh_identity : network.ssh_helper.ssh_identity;
1054 if (uid.length()) {
1055 scp_cmd_line += uid + "@";
1056 }
1057
1058 scp_cmd_line += host.host_name + ":" + destination.string();
1059
1060 return scp_cmd_line;
1061}
1062
1063void
1065 bool is_bios = (node.name == "bios");
1066 bfs::path filename;
1067 eosd_def &instance = *node.instance;
1068 host_def *host = find_host (instance.host);
1069
1070 bfs::path dd = stage / instance.config_dir_name;
1071 if (!bfs::exists(dd)) {
1072 try {
1073 bfs::create_directories (dd);
1074 } catch (const bfs::filesystem_error &ex) {
1075 cerr << "write_config_files threw " << ex.what() << endl;
1076 exit (-1);
1077 }
1078 }
1079
1080 filename = dd / "config.ini";
1081
1082 bfs::ofstream cfg(filename);
1083 if (!cfg.good()) {
1084 cerr << "unable to open " << filename << " " << strerror(errno) << "\n";
1085 exit (-1);
1086 }
1087
1088 cfg << "blocks-dir = " << block_dir << "\n";
1089 cfg << "http-server-address = " << host->host_name << ":" << instance.http_port << "\n";
1090 cfg << "http-validate-host = false\n";
1091 cfg << "p2p-listen-endpoint = " << host->listen_addr << ":" << instance.p2p_port << "\n";
1092 cfg << "p2p-server-address = " << host->public_name << ":" << instance.p2p_port << "\n";
1093
1094
1095 if (is_bios) {
1096 cfg << "enable-stale-production = true\n";
1097 }
1099 cfg << "allowed-connection = any\n";
1100 }
1101 else if (allowed_connections == PC_NONE) {
1102 cfg << "allowed-connection = none\n";
1103 }
1104 else
1105 {
1107 cfg << "allowed-connection = producers\n";
1108 }
1110 cfg << "allowed-connection = specified\n";
1111 cfg << "peer-key = \"" << node.keys.begin()->get_public_key().to_string() << "\"\n";
1112 cfg << "peer-private-key = [\"" << node.keys.begin()->get_public_key().to_string()
1113 << "\",\"" << node.keys.begin()->to_string() << "\"]\n";
1114 }
1115 }
1116
1117 if(!is_bios) {
1118 auto &bios_node = network.nodes["bios"];
1119 cfg << "p2p-peer-address = " << bios_node.instance->p2p_endpoint<< "\n";
1120 }
1121 for (const auto &p : node.peers) {
1122 cfg << "p2p-peer-address = " << network.nodes.find(p)->second.instance->p2p_endpoint << "\n";
1123 }
1124 if (node.producers.size()) {
1125 for (const auto &kp : node.keys ) {
1126 cfg << "private-key = [\"" << kp.get_public_key().to_string()
1127 << "\",\"" << kp.to_string() << "\"]\n";
1128 }
1129 for (auto &p : node.producers) {
1130 cfg << "producer-name = " << p << "\n";
1131 }
1132 cfg << "plugin = sysio::producer_plugin\n";
1133 }
1134 cfg << "plugin = sysio::net_plugin\n";
1135 cfg << "plugin = sysio::chain_api_plugin\n";
1136 cfg.close();
1137}
1138
1139void
1141 bfs::path filename;
1142 eosd_def &instance = *node.instance;
1143
1144 bfs::path dd = stage / instance.config_dir_name;
1145 if (!bfs::exists(dd)) {
1146 bfs::create_directories(dd);
1147 }
1148
1149 filename = dd / "logging.json";
1150
1151 bfs::ofstream cfg(filename);
1152 if (!cfg.good()) {
1153 cerr << "unable to open " << filename << " " << strerror(errno) << "\n";
1154 exit (9);
1155 }
1156
1157 auto log_config = fc::logging_config::default_config();
1158 if(gelf_enabled) {
1159 log_config.appenders.push_back(
1160 fc::appender_config( "net", "gelf",
1162 ( "endpoint", node.gelf_endpoint )
1163 ( "host", instance.name )
1164 ) );
1165 log_config.loggers.front().appenders.push_back( "net" );
1166 }
1167
1168 fc::logger_config p2p( "net_plugin_impl" );
1170 p2p.appenders.push_back( "stderr" );
1171 if( gelf_enabled ) p2p.appenders.push_back( "net" );
1172 log_config.loggers.emplace_back( p2p );
1173
1174 fc::logger_config http( "http_plugin" );
1175 http.level = fc::log_level::debug;
1176 http.appenders.push_back( "stderr" );
1177 if( gelf_enabled ) http.appenders.push_back( "net" );
1178 log_config.loggers.emplace_back( http );
1179
1180 fc::logger_config pp( "producer_plugin" );
1182 pp.appenders.push_back( "stderr" );
1183 if( gelf_enabled ) pp.appenders.push_back( "net" );
1184 log_config.loggers.emplace_back( pp );
1185
1186 fc::logger_config tt( "transaction_success_tracing" );
1188 tt.appenders.push_back( "stderr" );
1189 if( gelf_enabled ) tt.appenders.push_back( "net" );
1190 log_config.loggers.emplace_back( tt );
1191
1192 fc::logger_config tft( "transaction_failure_tracing" );
1194 tft.appenders.push_back( "stderr" );
1195 if( gelf_enabled ) tft.appenders.push_back( "net" );
1196 log_config.loggers.emplace_back( tft );
1197
1198 fc::logger_config tts( "transaction_trace_success" );
1200 tts.appenders.push_back( "stderr" );
1201 if( gelf_enabled ) tts.appenders.push_back( "net" );
1202 log_config.loggers.emplace_back( tts );
1203
1204 fc::logger_config ttf( "transaction_trace_failure" );
1206 ttf.appenders.push_back( "stderr" );
1207 if( gelf_enabled ) ttf.appenders.push_back( "net" );
1208 log_config.loggers.emplace_back( ttf );
1209
1210 fc::logger_config ta( "trace_api" );
1212 ta.appenders.push_back( "stderr" );
1213 if( gelf_enabled ) ta.appenders.push_back( "net" );
1214 log_config.loggers.emplace_back( ta );
1215
1217 cfg.write( str.c_str(), str.size() );
1218 cfg.close();
1219}
1220
1221void
1223 const bfs::path genesis_path = genesis.is_complete() ? genesis : bfs::current_path() / genesis;
1224 if (!bfs::exists(genesis_path)) {
1225 cout << "generating default genesis file " << genesis_path << endl;
1226 sysio::chain::genesis_state default_genesis;
1227 fc::json::save_to_file( default_genesis, genesis_path, true );
1228 }
1229 string bioskey = network.nodes["bios"].keys[0].get_public_key().to_string();
1230
1232 genesis_from_file.initial_key = public_key_type(bioskey);
1237}
1238
1239void
1241 bfs::path filename;
1242 eosd_def &instance = *node.instance;
1243
1244 bfs::path dd = stage / instance.config_dir_name;
1245 if (!bfs::exists(dd)) {
1246 bfs::create_directories(dd);
1247 }
1248
1249 filename = dd / "genesis.json";
1250 fc::json::save_to_file( genesis_from_file, dd / "genesis.json", true );
1251}
1252
1253void
1255 bfs::path filename = bfs::current_path() / "setprods.json";
1256 bfs::ofstream psfile (filename);
1257 if(!psfile.good()) {
1258 cerr << "unable to open " << filename << " " << strerror(errno) << "\n";
1259 exit (9);
1260 }
1261 producer_set_def no_bios;
1262 for (auto &p : producer_set.schedule) {
1263 if (p.producer_name != "sysio")
1264 no_bios.schedule.push_back(p);
1265 }
1267 psfile.write( str.c_str(), str.size() );
1268 psfile.close();
1269}
1270
1271void
1273 bfs::ifstream src(bfs::path(config_dir_base) / "launcher" / start_temp);
1274 if(!src.good()) {
1275 cerr << "unable to open " << config_dir_base << "launcher/" << start_temp << " " << strerror(errno) << "\n";
1276 exit (9);
1277 }
1278
1279 bfs::ofstream brb (bfs::current_path() / start_script);
1280 if(!brb.good()) {
1281 cerr << "unable to open " << bfs::current_path() << "/" << start_script << " " << strerror(errno) << "\n";
1282 exit (9);
1283 }
1284
1285 auto &bios_node = network.nodes["bios"];
1286 uint16_t biosport = bios_node.instance->http_port;
1287 string bhost = bios_node.instance->host;
1288 string line;
1289 string prefix = "###INSERT ";
1290 size_t len = prefix.length();
1291 while (getline(src,line)) {
1292 if (line.substr(0,len) == prefix) {
1293 string key = line.substr(len);
1294 if (key == "envars") {
1295 brb << "bioshost=" << bhost << "\nbiosport=" << biosport << "\n";
1296 }
1297 else if (key == "prodkeys" ) {
1298 for (auto &node : network.nodes) {
1299 brb << "wcmd import -n ignition --private-key " << node.second.keys[0].to_string() << "\n";
1300 }
1301 }
1302 else if (key == "cacmd") {
1303 for (auto &p : producer_set.schedule) {
1304 if (p.producer_name == "sysio") {
1305 continue;
1306 }
1307 brb << "cacmd " << p.producer_name
1308 << " " << p.block_signing_key.to_string() << " " << p.block_signing_key.to_string() << "\n";
1309 }
1310 }
1311 }
1312 brb << line << "\n";
1313 }
1314 src.close();
1315 brb.close();
1316}
1317
1318bool launcher_def::is_bios_ndx (size_t ndx) {
1319 return aliases[ndx] == "bios";
1320}
1321
1323 return is_bios_ndx(0) ? 1 : 0;
1324}
1325
1326bool launcher_def::next_ndx(size_t &ndx) {
1327 ++ndx;
1328 bool loop = ndx == total_nodes;
1329 if (loop)
1330 ndx = start_ndx();
1331 else
1332 if (is_bios_ndx(ndx)) {
1333 loop = next_ndx(ndx);
1334 }
1335 return loop;
1336}
1337
1338size_t launcher_def::skip_ndx (size_t from, size_t offset) {
1339 size_t ndx = (from + offset) % total_nodes;
1340 if (total_nodes > 2) {
1341 size_t attempts = total_nodes - 1;
1342 while (--attempts && (is_bios_ndx(ndx) || ndx == from)) {
1343 next_ndx(ndx);
1344 }
1345 }
1346 return ndx;
1347}
1348
1349void
1350launcher_def::make_line (bool make_ring) {
1351 bind_nodes();
1352 size_t non_bios = total_nodes - 1;
1353 if (non_bios > 2) {
1354 // since we have at least 3 indexes, every next_ndx(i) call is guaranteed to not be the end of the loop
1355 bool end_of_loop = false;
1356 for (size_t i = start_ndx(); !end_of_loop; next_ndx(i)) {
1357 size_t front = i;
1358 end_of_loop = next_ndx (front);
1359 // if this is the end of the loop and this is not a ring, then don't connect the end to the beginning to make a ring
1360 if (end_of_loop && !make_ring) {
1361 break;
1362 }
1363 network.nodes.find(aliases[i])->second.peers.push_back (aliases[front]);
1364 }
1365 }
1366 else if (non_bios == 2) {
1367 size_t n0 = start_ndx();
1368 size_t n1 = n0;
1369 next_ndx(n1);
1370 network.nodes.find(aliases[n0])->second.peers.push_back (aliases[n1]);
1371 if (make_ring) {
1372 network.nodes.find(aliases[n1])->second.peers.push_back (aliases[n0]);
1373 }
1374 // since there are only 2 nodes, this really just affects startup and that only index 0 will initiate the connection if !make_ring
1375 }
1376}
1377
1378void
1380 size_t non_bios = total_nodes - 1;
1381 if (non_bios < 4) {
1382 make_line ();
1383 return;
1384 }
1385 bind_nodes();
1386
1387 size_t links = 3;
1388 if (non_bios > 12) {
1389 links = static_cast<size_t>(sqrt(non_bios)) + 2;
1390 }
1391 size_t gap = non_bios > 6 ? 3 : (non_bios - links)/2 +1;
1392 while (non_bios % gap == 0) {
1393 ++gap;
1394 }
1395 // use to prevent duplicates since all connections are bidirectional
1396 std::map <string, std::set<string>> peers_to_from;
1397 bool loop = false;
1398 for (size_t i = start_ndx(); !loop; loop = next_ndx(i)) {
1399 const auto& iter = network.nodes.find(aliases[i]);
1400 auto &current = iter->second;
1401 const auto& current_name = iter->first;
1402 size_t ndx = i;
1403 for (size_t l = 1; l <= links; l++) {
1404 ndx = skip_ndx(ndx, l * gap);
1405 auto &peer = aliases[ndx];
1406 for (bool found = true; found; ) {
1407 found = false;
1408 for (auto &p : current.peers) {
1409 if (p == peer) {
1410 next_ndx(ndx);
1411 if (ndx == i) {
1412 next_ndx(ndx);
1413 }
1414 peer = aliases[ndx];
1415 found = true;
1416 break;
1417 }
1418 }
1419 }
1420 // if already established, don't add to list
1421 if (peers_to_from[peer].count(current_name) < 2) {
1422 current.peers.push_back(peer); // current_name -> peer
1423 // keep track of bidirectional relationships to prevent duplicates
1424 peers_to_from[current_name].insert(peer);
1425 }
1426 }
1427 }
1428}
1429
1430void
1432 size_t non_bios = total_nodes - 1;
1433 bind_nodes();
1434 // use to prevent duplicates since all connections are bidirectional
1435 std::map <string, std::set<string>> peers_to_from;
1436 bool loop = false;
1437 for (size_t i = start_ndx();!loop; loop = next_ndx(i)) {
1438 const auto& iter = network.nodes.find(aliases[i]);
1439 auto &current = iter->second;
1440 const auto& current_name = iter->first;
1441
1442 for (size_t j = 1; j < non_bios; j++) {
1443 size_t ndx = skip_ndx(i,j);
1444 const auto& peer = aliases[ndx];
1445 // if already established, don't add to list
1446 if (peers_to_from[peer].count(current_name) < 2) {
1447 current.peers.push_back (peer);
1448 // keep track of bidirectional relationships to prevent duplicates
1449 peers_to_from[current_name].insert(peer);
1450 }
1451 }
1452 }
1453}
1454
1455void
1457 bfs::path source = shape;
1459 for (auto &h : bindings) {
1460 for (auto &inst : h.instances) {
1461 tn_node_def *node = &network.nodes[inst.name];
1462 for (auto &p : node->producers) {
1463 producer_set.schedule.push_back({p,node->keys[0].get_public_key()});
1464 }
1465 node->instance = &inst;
1466 inst.node = node;
1467 }
1468 }
1469}
1470
1471void
1472launcher_def::format_ssh (const string &cmd,
1473 const string &host_name,
1474 string & ssh_cmd_line) {
1475
1476 ssh_cmd_line = network.ssh_helper.ssh_cmd + " ";
1477 if (network.ssh_helper.ssh_args.length()) {
1478 ssh_cmd_line += network.ssh_helper.ssh_args + " ";
1479 }
1480 if (network.ssh_helper.ssh_identity.length()) {
1481 ssh_cmd_line += network.ssh_helper.ssh_identity + "@";
1482 }
1483 ssh_cmd_line += host_name + " \"" + cmd + "\"";
1484 cerr << "cmdline = " << ssh_cmd_line << endl;
1485}
1486
1487bool
1488launcher_def::do_ssh (const string &cmd, const string &host_name) {
1489 string ssh_cmd_line;
1490 format_ssh (cmd, host_name, ssh_cmd_line);
1491 int res = boost::process::system (ssh_cmd_line);
1492 return (res == 0);
1493}
1494
1495void
1497 bfs::path abs_config_dir = bfs::path(host->sysio_home) / node.config_dir_name;
1498 bfs::path abs_data_dir = bfs::path(host->sysio_home) / node.data_dir_name;
1499
1500 string acd = abs_config_dir.string();
1501 string add = abs_data_dir.string();
1502 string cmd = "cd " + host->sysio_home;
1503
1504 cmd = "cd " + host->sysio_home;
1505 if (!do_ssh(cmd, host->host_name)) {
1506 cerr << "Unable to switch to path " << host->sysio_home
1507 << " on host " << host->host_name << endl;
1508 exit (-1);
1509 }
1510
1511 cmd = "cd " + acd;
1512 if (!do_ssh(cmd,host->host_name)) {
1513 cmd = "mkdir -p " + acd;
1514 if (!do_ssh (cmd, host->host_name)) {
1515 cerr << "Unable to invoke " << cmd << " on host " << host->host_name << endl;
1516 exit (01);
1517 }
1518 }
1519 cmd = "cd " + add;
1520 if (do_ssh(cmd,host->host_name)) {
1521 if(force_overwrite) {
1522 cmd = "rm -rf " + add + "/" + block_dir + " ;"
1523 + "rm -rf " + add + "/" + shared_mem_dir;
1524 if (!do_ssh (cmd, host->host_name)) {
1525 cerr << "Unable to remove old data directories on host "
1526 << host->host_name << endl;
1527 exit (-1);
1528 }
1529 }
1530 else {
1531 cerr << add << " already exists on host " << host->host_name << ". Use -f/--force to overwrite configuration and erase blockchain" << endl;
1532 exit (-1);
1533 }
1534 }
1535 else {
1536 cmd = "mkdir -p " + add;
1537 if (!do_ssh (cmd, host->host_name)) {
1538 cerr << "Unable to invoke " << cmd << " on host "
1539 << host->host_name << endl;
1540 exit (-1);
1541 }
1542 }
1543}
1544
1545string
1546launcher_def::find_and_remove_arg(string args, string arg ){
1547 if (args.empty() || arg.empty())
1548 return args;
1549
1550 string left, middle, right;
1551 size_t found = args.find(arg);
1552 if (found != std::string::npos){
1553 left = args.substr(0, found);
1554 middle = args.substr(found + 2); //skip --
1555 found = middle.find("--");
1556 if (found != std::string::npos){
1557 right = middle.substr(found);
1558 }
1559 return left + right;
1560 } else {
1561 return args;
1562 }
1563}
1564
1565void
1566launcher_def::launch (eosd_def &instance, string &gts) {
1567 bfs::path dd = instance.data_dir_name;
1568 bfs::path reout = dd / "stdout.txt";
1569 bfs::path reerr_sl = dd / "stderr.txt";
1570 bfs::path reerr_base = bfs::path("stderr." + launch_time + ".txt");
1571 bfs::path reerr = dd / reerr_base;
1572 bfs::path pidf = dd / bfs::path(string(node_executable_name) + ".pid");
1573 host_def* host;
1574 try {
1575 host = deploy_config_files (*instance.node);
1576 } catch (const bfs::filesystem_error &ex) {
1577 cerr << "deploy_config_files threw " << ex.what() << endl;
1578 exit (-1);
1579 }
1580
1581 node_rt_info info;
1582 info.remote = !host->is_local();
1583
1584 string install_path;
1585 if (instance.name != "bios" && !specific_nodeop_installation_paths.empty()) {
1586 const auto node_num = boost::lexical_cast<uint16_t,string>(instance.get_node_num());
1587 if (specific_nodeop_installation_paths.count(node_num)) {
1588 install_path = specific_nodeop_installation_paths[node_num] + "/";
1589 }
1590 }
1591 string eosdcmd = install_path + "programs/nodeop/" + string(node_executable_name) + " ";
1593 eosdcmd += "--skip-transaction-signatures ";
1594 }
1595 if (!eosd_extra_args.empty()) {
1596 eosdcmd += eosd_extra_args + " ";
1597 }
1598 if (instance.name != "bios" && !specific_nodeop_args.empty()) {
1599 const auto node_num = boost::lexical_cast<uint16_t,string>(instance.get_node_num());
1600 if (specific_nodeop_args.count(node_num)) {
1601 eosdcmd += specific_nodeop_args[node_num] + " ";
1602 }
1603 }
1604
1606 eosdcmd += "--enable-stale-production true ";
1608 }
1609
1610 eosdcmd += " --config-dir " + instance.config_dir_name + " --data-dir " + instance.data_dir_name;
1611 eosdcmd += " --genesis-json " + instance.config_dir_name + "/genesis.json";
1612 if (gts.length()) {
1613 eosdcmd += " --genesis-timestamp " + gts;
1614 }
1615
1616 if (eosdcmd.find("sysio::history_api_plugin") != string::npos && eosdcmd.find("sysio::trace_api_plugin") != string::npos){
1617 // remove trace_api_plugin from old version nodes in multiversion test
1618 eosdcmd = find_and_remove_arg(eosdcmd, "--plugin sysio::trace_api_plugin");
1619 eosdcmd = find_and_remove_arg(eosdcmd, "--trace-no-abis");
1620 eosdcmd = find_and_remove_arg(eosdcmd, "--trace-rpc-abi");
1621 }
1622
1623 if (!host->is_local()) {
1624 if (instance.node->dont_start) {
1625 cerr << "Unable to use \"unstarted-nodes\" with a remote hose" << endl;
1626 exit (-1);
1627 }
1628 string cmdl ("cd ");
1629 cmdl += host->sysio_home + "; nohup " + eosdcmd + " > "
1630 + reout.string() + " 2> " + reerr.string() + "& echo $! > " + pidf.string()
1631 + "; rm -f " + reerr_sl.string()
1632 + "; ln -s " + reerr_base.string() + " " + reerr_sl.string();
1633 if (!do_ssh (cmdl, host->host_name)){
1634 cerr << "Unable to invoke " << cmdl
1635 << " on host " << host->host_name << endl;
1636 exit (-1);
1637 }
1638
1639 string cmd = "cd " + host->sysio_home + "; kill -15 $(cat " + pidf.string() + ")";
1640 format_ssh (cmd, host->host_name, info.kill_cmd);
1641 }
1642 else if (!instance.node->dont_start) {
1643 cerr << "spawning child, " << eosdcmd << endl;
1644
1645 bp::child c(eosdcmd, bp::std_out > reout, bp::std_err > reerr );
1646 bfs::remove(reerr_sl);
1647 bfs::create_symlink (reerr_base, reerr_sl);
1648
1649 bfs::ofstream pidout (pidf);
1650 pidout << c.id() << flush;
1651 pidout.close();
1652
1653 info.pid_file = pidf.string();
1654 info.kill_cmd = "";
1655
1656 if(!c.running()) {
1657 cerr << "child not running after spawn " << eosdcmd << endl;
1658 for (int i = 0; i > 0; i++) {
1659 if (c.running () ) break;
1660 }
1661 }
1662 c.detach();
1663 }
1664 else {
1665 cerr << "not spawning child, " << eosdcmd << endl;
1666
1667 const bfs::path dd = instance.data_dir_name;
1668 const bfs::path start_file = dd / "start.cmd";
1669 bfs::ofstream sf (start_file);
1670
1671 sf << eosdcmd << endl;
1672 sf.close();
1673 }
1674 last_run.running_nodes.emplace_back (move(info));
1675}
1676
1677#if 0
1678void
1679launcher_def::kill_instance(eosd_def, string sig_opt) {
1680}
1681#endif
1682
1683void
1684launcher_def::kill (launch_modes mode, string sig_opt) {
1685 switch (mode) {
1686 case LM_NONE:
1687 return;
1688 case LM_VERIFY:
1689 // no-op
1690 return;
1691 case LM_NAMED: {
1692 cerr << "feature not yet implemented " << endl;
1693 #if 0
1694 auto node = network.nodes.find(launch_name);
1695 kill_instance (node.second.instance, sig_opt);
1696 #endif
1697 break;
1698 }
1699 case LM_ALL:
1700 case LM_LOCAL:
1701 case LM_REMOTE : {
1702 bfs::path source = "last_run.json";
1703 try {
1705 for( auto& info : last_run.running_nodes ) {
1706 if( mode == LM_ALL || (info.remote && mode == LM_REMOTE) ||
1707 (!info.remote && mode == LM_LOCAL) ) {
1708 try {
1709 if( info.pid_file.length() ) {
1710 string pid;
1711 fc::json::from_file( info.pid_file ).as<string>( pid );
1712 string kill_cmd = "kill " + sig_opt + " " + pid;
1713 boost::process::system( kill_cmd );
1714 } else {
1715 boost::process::system( info.kill_cmd );
1716 }
1717 } catch( fc::exception& fce ) {
1718 cerr << "unable to kill fc::exception=" << fce.to_detail_string() << endl;
1719 } catch( std::exception& stde ) {
1720 cerr << "unable to kill std::exception=" << stde.what() << endl;
1721 } catch( ... ) {
1722 cerr << "Unable to kill" << endl;
1723 }
1724 }
1725 }
1726 } catch( fc::exception& fce ) {
1727 cerr << "unable to open " << source << " fc::exception=" << fce.to_detail_string() << endl;
1728 } catch( std::exception& stde ) {
1729 cerr << "unable to open " << source << " std::exception=" << stde.what() << endl;
1730 } catch( ... ) {
1731 cerr << "Unable to open " << source << endl;
1732 }
1733 }
1734 }
1735}
1736
1737string
1739 string node_num_str = node_num < 10 ? "0":"";
1740 node_num_str += boost::lexical_cast<string,uint16_t>(node_num);
1741 return node_num_str;
1742}
1743
1744pair<host_def, eosd_def>
1746 const string node_name = network.name + get_node_num(node_num);
1747 for (const auto& host: bindings) {
1748 for (const auto& node: host.instances) {
1749 if (node_name == node.name) {
1750 return make_pair(host, node);
1751 }
1752 }
1753 }
1754 cerr << "Unable to find node " << node_num << endl;
1755 exit (-1);
1756}
1757
1758vector<pair<host_def, eosd_def>>
1759launcher_def::get_nodes(const string& node_number_list) {
1760 vector<pair<host_def, eosd_def>> node_list;
1761 if (fc::to_lower(node_number_list) == "all") {
1762 for (auto host: bindings) {
1763 for (auto node: host.instances) {
1764 cout << "host=" << host.host_name << ", node=" << node.name << endl;
1765 node_list.push_back(make_pair(host, node));
1766 }
1767 }
1768 }
1769 else {
1770 vector<string> nodes;
1771 boost::split(nodes, node_number_list, boost::is_any_of(","));
1772 for (string node_number: nodes) {
1773 uint16_t node = -1;
1774 try {
1775 node = boost::lexical_cast<uint16_t,string>(node_number);
1776 }
1777 catch(boost::bad_lexical_cast &) {
1778 // This exception will be handled below
1779 }
1780 if (node < 0 || node > 99) {
1781 cerr << "Bad node number found in node number list: " << node_number << endl;
1782 exit(-1);
1783 }
1784 node_list.push_back(find_node(node));
1785 }
1786 }
1787 return node_list;
1788}
1789
1790void
1791launcher_def::do_command(const host_def& host, const string& name,
1792 vector<pair<string, string>> env_pairs, const string& cmd) {
1793 if (!host.is_local()) {
1794 string rcmd = "cd " + host.sysio_home + "; ";
1795 for (auto& env_pair : env_pairs) {
1796 rcmd += "export " + env_pair.first + "=" + env_pair.second + "; ";
1797 }
1798 rcmd += cmd;
1799 if (!do_ssh(rcmd, host.host_name)) {
1800 cerr << "Remote command failed for " << name << endl;
1801 exit (-1);
1802 }
1803 }
1804 else {
1805 bp::environment e;
1806 for (auto& env_pair : env_pairs) {
1807 e.emplace(env_pair.first, env_pair.second);
1808 }
1809 bp::child c(cmd, e);
1810 c.wait();
1811 }
1812}
1813
1814void
1815launcher_def::bounce (const string& node_numbers) {
1816 auto node_list = get_nodes(node_numbers);
1817 for (auto node_pair: node_list) {
1818 const host_def& host = node_pair.first;
1819 const eosd_def& node = node_pair.second;
1820 const string node_num = node.get_node_num();
1821 cout << "Bouncing " << node.name << endl;
1822 string cmd = "./scripts/sysio-tn_bounce.sh " + eosd_extra_args;
1823 if (node_num != "bios" && !specific_nodeop_args.empty()) {
1824 const auto node_num_i = boost::lexical_cast<uint16_t,string>(node_num);
1825 if (specific_nodeop_args.count(node_num_i)) {
1826 cmd += " " + specific_nodeop_args[node_num_i];
1827 }
1828 }
1829
1830 do_command(host, node.name, { { "SYSIO_HOME", host.sysio_home }, { "SYSIO_NODE", node_num } }, cmd);
1831 }
1832}
1833
1834void
1835launcher_def::down (const string& node_numbers) {
1836 auto node_list = get_nodes(node_numbers);
1837 for (auto node_pair: node_list) {
1838 const host_def& host = node_pair.first;
1839 const eosd_def& node = node_pair.second;
1840 const string node_num = node.get_node_num();
1841 cout << "Taking down " << node.name << endl;
1842 string cmd = "./scripts/sysio-tn_down.sh ";
1843 do_command(host, node.name,
1844 { { "SYSIO_HOME", host.sysio_home }, { "SYSIO_NODE", node_num }, { "SYSIO_TN_RESTART_CONFIG_DIR", node.config_dir_name } },
1845 cmd);
1846 }
1847}
1848
1849void
1850launcher_def::roll (const string& host_names) {
1851 vector<string> hosts;
1852 boost::split(hosts, host_names, boost::is_any_of(","));
1853 for (string host_name: hosts) {
1854 cout << "Rolling " << host_name << endl;
1855 auto host = find_host_by_name_or_address(host_name);
1856 string cmd = "./scripts/sysio-tn_roll.sh ";
1857 do_command(*host, host_name, { { "SYSIO_HOME", host->sysio_home } }, cmd);
1858 }
1859}
1860
1861void
1863 if (boot) {
1864 cerr << "Invoking the blockchain boot script, " << start_script << "\n";
1865 string script("bash " + start_script);
1866 bp::child c(script);
1867 try {
1868 cerr << "waiting for script completion\n";
1869 c.wait();
1870 } catch (bfs::filesystem_error &ex) {
1871 cerr << "wait threw error " << ex.what() << "\n";
1872 }
1873 catch (...) {
1874 // when script dies wait throws an exception but that is ok
1875 }
1876 } else {
1877 cerr << "**********************************************************************\n"
1878 << "run 'bash " << start_script << "' to kick off delegated block production\n"
1879 << "**********************************************************************\n";
1880 }
1881
1882 }
1883
1884void
1886 switch (mode) {
1887 case LM_NONE:
1888 return;
1889 case LM_VERIFY:
1890 //validate configuration, report findings, exit
1891 return;
1892 case LM_NAMED : {
1893 try {
1895 auto node = network.nodes.find(launch_name);
1896 launch(*node->second.instance, gts);
1897 } catch (fc::exception& fce) {
1898 cerr << "unable to launch " << launch_name << " fc::exception=" << fce.to_detail_string() << endl;
1899 } catch (std::exception& stde) {
1900 cerr << "unable to launch " << launch_name << " std::exception=" << stde.what() << endl;
1901 } catch (...) {
1902 cerr << "Unable to launch " << launch_name << endl;
1903 exit (-1);
1904 }
1905 break;
1906 }
1907 case LM_ALL:
1908 case LM_REMOTE:
1909 case LM_LOCAL: {
1910
1911 for (auto &h : bindings ) {
1912 if (mode == LM_ALL ||
1913 (h.is_local() ? mode == LM_LOCAL : mode == LM_REMOTE)) {
1914 for (auto &inst : h.instances) {
1915 try {
1916 cerr << "launching " << inst.name << endl;
1917 launch (inst, gts);
1918 } catch (fc::exception& fce) {
1919 cerr << "unable to launch " << inst.name << " fc::exception=" << fce.to_detail_string() << endl;
1920 } catch (std::exception& stde) {
1921 cerr << "unable to launch " << inst.name << " std::exception=" << stde.what() << endl;
1922 } catch (...) {
1923 cerr << "unable to launch " << inst.name << endl;
1924 }
1925 sleep (start_delay);
1926 }
1927 }
1928 }
1929 break;
1930 }
1931 }
1932 bfs::path savefile = "last_run.json";
1933 bfs::ofstream sf (savefile);
1934
1935 sf << fc::json::to_pretty_string (last_run) << endl;
1936 sf.close();
1937}
1938
1939//------------------------------------------------------------
1940
1941void write_default_config(const bfs::path& cfg_file, const options_description &cfg ) {
1942 bfs::path parent = cfg_file.parent_path();
1943 if (parent.empty()) {
1944 parent = ".";
1945 }
1946 if(!bfs::exists(parent)) {
1947 try {
1948 bfs::create_directories(parent);
1949 } catch (bfs::filesystem_error &ex) {
1950 cerr << "could not create new directory: " << cfg_file.parent_path()
1951 << " caught " << ex.what() << endl;
1952 exit (-1);
1953 }
1954 }
1955
1956 std::ofstream out_cfg( bfs::path(cfg_file).make_preferred().string());
1957 for(const boost::shared_ptr<bpo::option_description>& od : cfg.options())
1958 {
1959 if(!od->description().empty()) {
1960 out_cfg << "# " << od->description() << std::endl;
1961 }
1962 boost::any store;
1963 if(!od->semantic()->apply_default(store))
1964 out_cfg << "# " << od->long_name() << " = " << std::endl;
1965 else {
1966 auto example = od->format_parameter();
1967 if(example.empty())
1968 // This is a boolean switch
1969 out_cfg << od->long_name() << " = " << "false" << std::endl;
1970 else {
1971 // The string is formatted "arg (=<interesting part>)"
1972 example.erase(0, 6);
1973 example.erase(example.length()-1);
1974 out_cfg << od->long_name() << " = " << example << std::endl;
1975 }
1976 }
1977 out_cfg << std::endl;
1978 }
1979 out_cfg.close();
1980}
1981
1982
1983int main (int argc, char *argv[]) {
1984
1985 variables_map vmap;
1986 options_description cfg ("Testnet launcher config options");
1987 options_description cli ("launcher command line options");
1988 launcher_def top;
1989 string gts;
1990 launch_modes mode;
1991 string kill_arg;
1992 string bounce_nodes;
1993 string down_nodes;
1994 string roll_nodes;
1995 bfs::path config_dir;
1996 bfs::path config_file;
1997
1998 local_id.initialize();
1999 top.set_options(cfg);
2000
2001 cli.add_options()
2002 ("timestamp,i",bpo::value<string>(&gts),"set the timestamp for the first block. Use \"now\" to indicate the current time")
2003 ("launch,l",bpo::value<string>(), "select a subset of nodes to launch. Currently may be \"all\", \"none\", or \"local\". If not set, the default is to launch all unless an output file is named, in which case it starts none.")
2004 ("output,o",bpo::value<bfs::path>(&top.output),"save a copy of the generated topology in this file")
2005 ("kill,k", bpo::value<string>(&kill_arg),"The launcher retrieves the previously started process ids and issues a kill to each.")
2006 ("down", bpo::value<string>(&down_nodes),"comma-separated list of node numbers that will be taken down using the sysio-tn_down.sh script")
2007 ("bounce", bpo::value<string>(&bounce_nodes),"comma-separated list of node numbers that will be restarted using the sysio-tn_bounce.sh script")
2008 ("roll", bpo::value<string>(&roll_nodes),"comma-separated list of host names where the nodes should be rolled to a new version using the sysio-tn_roll.sh script")
2009 ("version,v", "print version information")
2010 ("help,h","print this list")
2011 ("config-dir", bpo::value<bfs::path>(), "Directory containing configuration files such as config.ini")
2012 ("config,c", bpo::value<bfs::path>()->default_value( "config.ini" ), "Configuration file name relative to config-dir");
2013
2014 cli.add(cfg);
2015
2016 try {
2017 bpo::store(bpo::parse_command_line(argc, argv, cli), vmap);
2018 bpo::notify(vmap);
2019
2020 top.initialize(vmap);
2021
2022 if (vmap.count("help") > 0) {
2023 cli.print(cerr);
2024 return 0;
2025 }
2026 if (vmap.count("version") > 0) {
2027 cout << sysio::launcher::config::version_str << endl;
2028 return 0;
2029 }
2030
2031 if( vmap.count( "config-dir" ) ) {
2032 config_dir = vmap["config-dir"].as<bfs::path>();
2033 if( config_dir.is_relative() )
2034 config_dir = bfs::current_path() / config_dir;
2035 }
2036
2037 bfs::path config_file_name = config_dir / "config.ini";
2038 if( vmap.count( "config" ) ) {
2039 config_file_name = vmap["config"].as<bfs::path>();
2040 if( config_file_name.is_relative() )
2041 config_file_name = config_dir / config_file_name;
2042 }
2043
2044 if(!bfs::exists(config_file_name)) {
2045 if(config_file_name.compare(config_dir / "config.ini") != 0)
2046 {
2047 cout << "Config file " << config_file_name << " missing." << std::endl;
2048 return -1;
2049 }
2050 write_default_config(config_file_name, cfg);
2051 }
2052
2053
2054 bpo::store(bpo::parse_config_file<char>(config_file_name.make_preferred().string().c_str(),
2055 cfg, true), vmap);
2056
2057
2058
2059 if (vmap.count("launch")) {
2060 string l = vmap["launch"].as<string>();
2061 if (boost::iequals(l,"all"))
2062 mode = LM_ALL;
2063 else if (boost::iequals(l,"local"))
2064 mode = LM_LOCAL;
2065 else if (boost::iequals(l,"remote"))
2066 mode = LM_REMOTE;
2067 else if (boost::iequals(l,"none"))
2068 mode = LM_NONE;
2069 else if (boost::iequals(l,"verify"))
2070 mode = LM_VERIFY;
2071 else {
2072 mode = LM_NAMED;
2073 top.launch_name = l;
2074 }
2075 }
2076 else {
2077 mode = !kill_arg.empty() || top.output.empty() ? LM_ALL : LM_NONE;
2078 }
2079
2080 if (!kill_arg.empty()) {
2081 cout << "killing" << std::endl;
2082 if (kill_arg[0] != '-') {
2083 kill_arg = "-" + kill_arg;
2084 }
2085 top.kill (mode, kill_arg);
2086 }
2087 else if (!bounce_nodes.empty()) {
2088 top.bounce(bounce_nodes);
2089 }
2090 else if (!down_nodes.empty()) {
2091 top.down(down_nodes);
2092 }
2093 else if (!roll_nodes.empty()) {
2094 top.roll(roll_nodes);
2095 }
2096 else {
2097 top.generate();
2098 top.start_all(gts, mode);
2099 top.ignite();
2100 }
2101 } catch (bpo::unknown_option &ex) {
2102 cerr << ex.what() << endl;
2103 cli.print (cerr);
2104 }
2105 return 0;
2106}
2107
2108
2109//-------------------------------------------------------------
2110// @ignore local_config_file
2112 (ssh_cmd)(scp_cmd)(ssh_identity)(ssh_args) )
2113
2115 (producer_name)(block_signing_key))
2116
2118 (schedule))
2119
2120// @ignore listen_addr, p2p_count, http_count, dot_label_str
2122 (genesis)(ssh_identity)(ssh_args)(sysio_home)
2123 (host_name)(public_name)
2124 (base_p2p_port)(base_http_port)(def_file_size)
2125 (instances) )
2126
2127// @ignore node, dot_label_str
2129 (config_dir_name)(data_dir_name)(p2p_port)
2130 (http_port)(file_size)(name)(host)
2131 (p2p_endpoint) )
2132
2133// @ignore instance, gelf_endpoint
2134FC_REFLECT( tn_node_def, (name)(keys)(peers)(producers)(dont_start) )
2135
2137
2138FC_REFLECT( server_name_def, (ipaddr) (name) (has_bios) (sysio_home) (instances) )
2139
2140FC_REFLECT( server_identities, (producer) (nonprod) (db) (default_sysio_home) (ssh) )
2141
2142FC_REFLECT( node_rt_info, (remote)(pid_file)(kill_cmd) )
2143
2144FC_REFLECT( last_run_def, (running_nodes) )
const mie::Vuint & p
Definition bn.cpp:27
std::string name
void mk_dot_label()
Definition main.cpp:248
string config_dir_name
Definition main.cpp:210
string get_node_num() const
Definition main.cpp:229
uint16_t file_size
Definition main.cpp:214
void set_host(host_def *h, bool is_bios)
Definition main.cpp:266
eosd_def()
Definition main.cpp:197
const string & dot_label()
Definition main.cpp:222
string name
Definition main.cpp:215
string p2p_endpoint
Definition main.cpp:218
string host
Definition main.cpp:217
tn_node_def * node
Definition main.cpp:216
uint16_t http_port
Definition main.cpp:213
uint16_t p2p_port
Definition main.cpp:212
string data_dir_name
Definition main.cpp:211
Used to generate a useful error report when an exception is thrown.
Definition exception.hpp:58
std::string to_detail_string(log_level ll=log_level::all) const
static variant from_file(const fc::path &p, const parse_type ptype=parse_type::legacy_parser, const uint32_t max_depth=DEFAULT_MAX_RECURSION_DEPTH)
Definition json.cpp:797
static bool save_to_file(const T &v, const fc::path &fi, const bool pretty=true, const output_formatting format=output_formatting::stringify_large_ints_and_doubles)
Definition json.hpp:45
static string to_pretty_string(const variant &v, const yield_function_t &yield, const output_formatting format=output_formatting::stringify_large_ints_and_doubles)
Definition json.cpp:775
An order-preserving dictionary of variants.
static constexpr time_point maximum()
Definition time.hpp:46
T as() const
Definition variant.hpp:327
host_def()
Definition main.cpp:118
string sysio_home
Definition main.cpp:138
uint16_t p2p_bios_port()
Definition main.cpp:155
uint16_t http_port()
Definition main.cpp:151
uint16_t base_http_port
Definition main.cpp:143
string host_name
Definition main.cpp:139
uint16_t p2p_port()
Definition main.cpp:147
uint16_t base_p2p_port
Definition main.cpp:142
vector< eosd_def > instances
Definition main.cpp:145
string ssh_args
Definition main.cpp:137
const string & dot_label()
Definition main.cpp:167
bool is_local() const
Definition main.cpp:163
void mk_dot_label()
Definition main.cpp:181
uint16_t def_file_size
Definition main.cpp:144
string genesis
Definition main.cpp:135
string public_name
Definition main.cpp:140
uint16_t http_bios_port()
Definition main.cpp:159
string listen_addr
Definition main.cpp:141
string ssh_identity
Definition main.cpp:136
static string producer_name(unsigned int producer_number, bool shared_producer=false)
Definition main.cpp:354
string name
Definition main.cpp:238
vector< private_key_type > keys
Definition main.cpp:239
string gelf_endpoint
Definition main.cpp:243
bool dont_start
Definition main.cpp:244
eosd_def * instance
Definition main.cpp:242
vector< string > peers
Definition main.cpp:240
vector< string > producers
Definition main.cpp:241
int * count
char ** argv
static const Reg16 bp(Operand::BP)
fc::string to_lower(const fc::string &)
Definition string.cpp:161
Definition name.hpp:106
fc::crypto::public_key public_key_type
Definition types.hpp:76
fc::crypto::private_key private_key_type
Definition types.hpp:77
const CharType(& source)[N]
Definition pointer.h:1204
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1181
#define T(meth, val, expected)
const string shared_mem_dir
Definition main.cpp:49
enum_type & operator|=(enum_type &lhs, const enum_type &rhs)
Definition main.cpp:511
const string block_dir
Definition main.cpp:48
struct local_identity local_id
schedule config_dir_name data_dir_name p2p_port http_port file_size name name keys peers name ipaddr name has_bios producer nonprod db default_sysio_home(ssh)) FC_REFLECT(node_rt_info
schedule config_dir_name data_dir_name p2p_port http_port file_size name name keys peers name ssh_helper(nodes)) FC_REFLECT(server_name_def
schedule config_dir_name data_dir_name p2p_port http_port file_size name name keys peers producers(dont_start)) FC_REFLECT(testnet_def
launch_modes
Definition main.cpp:324
@ LM_NONE
Definition main.cpp:325
@ LM_ALL
Definition main.cpp:329
@ LM_NAMED
Definition main.cpp:328
@ LM_VERIFY
Definition main.cpp:330
@ LM_LOCAL
Definition main.cpp:326
@ LM_REMOTE
Definition main.cpp:327
schedule config_dir_name data_dir_name p2p_port http_port file_size name host(p2p_endpoint)) FC_REFLECT(tn_node_def
void write_default_config(const bfs::path &cfg_file, const options_description &cfg)
Definition main.cpp:1941
allowed_connection
Definition main.cpp:333
@ PC_NONE
Definition main.cpp:334
@ PC_PRODUCERS
Definition main.cpp:335
@ PC_ANY
Definition main.cpp:337
@ PC_SPECIFIED
Definition main.cpp:336
schedule config_dir_name data_dir_name p2p_port http_port file_size name name keys peers name ipaddr name has_bios sysio_home(instances)) FC_REFLECT(server_identities
void retrieve_paired_array_parameters(const variables_map &vmap, const std::string &num_selector, const std::string &paired_selector, std::map< uint, T > &selector_map)
Definition main.cpp:518
producer_name(block_signing_key)) FC_REFLECT(producer_set_def
#define FC_REFLECT(TYPE, MEMBERS)
Specializes fc::reflector for TYPE.
Definition reflect.hpp:311
int add(int a, int b)
unsigned short uint16_t
Definition stdint.h:125
signed __int64 int64_t
Definition stdint.h:135
unsigned int uint32_t
Definition stdint.h:126
signed int int32_t
Definition stdint.h:123
std::vector< string > appenders
std::optional< log_level > level
if not set, then parents level is used.
static logging_config default_config()
vector< node_rt_info > running_nodes
Definition main.cpp:321
bool do_ssh(const string &cmd, const string &host_name)
Definition main.cpp:1488
void down(const string &node_numbers)
Definition main.cpp:1835
bfs::path genesis
Definition main.cpp:395
size_t next_node
Definition main.cpp:392
producer_set_def producer_set
Definition main.cpp:422
pair< host_def, eosd_def > find_node(uint16_t node_num)
Definition main.cpp:1745
bfs::path config_dir_base
Definition main.cpp:402
void do_command(const host_def &host, const string &name, vector< pair< string, string > > env_pairs, const string &cmd)
Definition main.cpp:1791
testnet_def network
Definition main.cpp:408
void make_star()
Definition main.cpp:1379
bool boot
Definition main.cpp:417
void set_options(bpo::options_description &cli)
Definition main.cpp:477
void write_setprods_file()
Definition main.cpp:1254
last_run_def last_run
Definition main.cpp:413
string compose_scp_command(const host_def &host, const bfs::path &source, const bfs::path &destination)
Definition main.cpp:1045
bool force_overwrite
Definition main.cpp:386
int per_host
Definition main.cpp:412
string find_and_remove_arg(string str, string substr)
Definition main.cpp:1546
host_def * find_host_by_name_or_address(const string &name)
Definition main.cpp:935
sysio::chain::genesis_state genesis_from_file
Definition main.cpp:427
void roll(const string &host_names)
Definition main.cpp:1850
std::optional< uint32_t > max_transaction_cpu_usage
Definition main.cpp:426
void bounce(const string &node_numbers)
Definition main.cpp:1815
void write_bios_boot()
Definition main.cpp:1272
bool nogen
Definition main.cpp:416
void write_dot_file()
Definition main.cpp:774
host_def * deploy_config_files(tn_node_def &node)
Definition main.cpp:952
static string get_node_num(uint16_t node_num)
Definition main.cpp:1738
string launch_name
Definition main.cpp:419
void write_logging_config_file(tn_node_def &node)
Definition main.cpp:1140
int start_delay
Definition main.cpp:414
void write_genesis_file(tn_node_def &node)
Definition main.cpp:1240
std::optional< uint32_t > max_block_cpu_usage
Definition main.cpp:425
string eosd_extra_args
Definition main.cpp:405
size_t prod_nodes
Definition main.cpp:389
void ignite()
Definition main.cpp:1862
void load_servers()
Definition main.cpp:673
bfs::path stage
Definition main.cpp:399
vector< string > aliases
Definition main.cpp:410
size_t unstarted_nodes
Definition main.cpp:388
string start_temp
Definition main.cpp:423
bool gelf_enabled
Definition main.cpp:415
vector< pair< host_def, eosd_def > > get_nodes(const string &node_number_list)
Definition main.cpp:1759
void define_network()
Definition main.cpp:789
size_t start_ndx()
Definition main.cpp:1322
void start_all(string &gts, launch_modes mode)
Definition main.cpp:1885
bfs::path data_dir_base
Definition main.cpp:403
void make_mesh()
Definition main.cpp:1431
std::map< uint, string > specific_nodeop_args
Definition main.cpp:406
bfs::path server_ident_file
Definition main.cpp:398
void bind_nodes()
Definition main.cpp:861
std::map< uint, string > specific_nodeop_installation_paths
Definition main.cpp:407
void launch(eosd_def &node, string &gts)
Definition main.cpp:1566
vector< host_def > bindings
Definition main.cpp:411
allowed_connection allowed_connections
Definition main.cpp:394
bool generate()
Definition main.cpp:717
void make_line(bool make_ring=true)
Definition main.cpp:1350
string gelf_endpoint
Definition main.cpp:409
void init_genesis()
Definition main.cpp:1222
size_t shared_producers
Definition main.cpp:391
string start_script
Definition main.cpp:424
bool is_bios_ndx(size_t ndx)
Definition main.cpp:1318
size_t total_nodes
Definition main.cpp:387
bool skip_transaction_signatures
Definition main.cpp:404
void assign_name(eosd_def &node, bool is_bios)
Definition main.cpp:699
bfs::path output
Definition main.cpp:396
string shape
Definition main.cpp:393
size_t skip_ndx(size_t from, size_t offset)
Definition main.cpp:1338
host_def * find_host(const string &name)
Definition main.cpp:918
server_identities servers
Definition main.cpp:421
size_t producers
Definition main.cpp:390
void prep_remote_config_dir(eosd_def &node, host_def *host)
Definition main.cpp:1496
void kill(launch_modes mode, string sig_opt)
Definition main.cpp:1684
string launch_time
Definition main.cpp:420
void make_custom()
Definition main.cpp:1456
void format_ssh(const string &cmd, const string &host_name, string &ssh_cmd_line)
Definition main.cpp:1472
void initialize(const variables_map &vmap)
Definition main.cpp:540
bfs::path host_map_file
Definition main.cpp:397
bool next_ndx(size_t &ndx)
Definition main.cpp:1326
bool add_enable_stale_production
Definition main.cpp:418
void write_config_file(tn_node_def &node)
Definition main.cpp:1064
string erd
Definition main.cpp:401
void initialize()
Definition main.cpp:55
vector< string > names
Definition main.cpp:53
vector< fc::ip::address > addrs
Definition main.cpp:52
bool contains(const string &name) const
Definition main.cpp:94
bool remote
Definition main.cpp:315
string pid_file
Definition main.cpp:316
string kill_cmd
Definition main.cpp:317
public_key_type block_signing_key
Definition main.cpp:290
string producer_name
Definition main.cpp:289
vector< prodkey_def > schedule
Definition main.cpp:294
string ssh_cmd
Definition main.cpp:275
string scp_cmd
Definition main.cpp:276
string ssh_identity
Definition main.cpp:277
bfs::path local_config_file
Definition main.cpp:279
string ssh_args
Definition main.cpp:278
vector< server_name_def > producer
Definition main.cpp:307
string default_sysio_home
Definition main.cpp:310
vector< server_name_def > nonprod
Definition main.cpp:308
remote_deploy ssh
Definition main.cpp:311
vector< string > db
Definition main.cpp:309
string name
Definition main.cpp:299
uint16_t instances
Definition main.cpp:302
string ipaddr
Definition main.cpp:298
string sysio_home
Definition main.cpp:301
uint32_t max_transaction_cpu_usage
the maximum billable cpu usage (in microseconds) that the chain will allow regardless of account limi...
uint32_t max_block_cpu_usage
the maxiumum billable cpu usage (in microseconds) for a block
chain_config_v0 initial_configuration
map< string, tn_node_def > nodes
Definition main.cpp:285
string name
Definition main.cpp:283
remote_deploy ssh_helper
Definition main.cpp:284
void cli()
char * s
uint16_t j
size_t len
int l
CK_BYTE_PTR pubkey