0.9.8.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
ht_ssh.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2014 Hypertable, Inc.
3  *
4  * This file is part of Hypertable.
5  *
6  * Hypertable is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; version 3 of the
9  * License, or any later version.
10  *
11  * Hypertable is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301, USA.
20  */
21 
26 
27 #include <Common/Compat.h>
28 
29 #include "SshSocketHandler.h"
30 #include "SshThreadsCallbacks.h"
31 #include "SshOutputCollector.h"
32 
33 #include <AsyncComm/Comm.h>
35 
36 #include <Common/Error.h>
38 #include <Common/Init.h>
39 #include <Common/Logger.h>
40 #include <Common/Random.h>
41 #include <Common/System.h>
42 #include <Common/Timer.h>
43 
44 #include <algorithm>
45 #include <cctype>
46 #include <chrono>
47 #include <cstdlib>
48 #include <fstream>
49 #include <iostream>
50 #include <map>
51 #include <mutex>
52 #include <sstream>
53 #include <thread>
54 #include <vector>
55 
56 using namespace Hypertable;
57 using namespace std;
58 
59 namespace {
60 
61  std::mutex g_mutex;
62  bool g_handlers_created {};
63  bool g_cancelled {};
64  vector<SshSocketHandlerPtr> g_handlers;
65 
66  void sig(int i) {
67  lock_guard<mutex> lock(g_mutex);
68  g_cancelled = true;
69  if (g_handlers_created) {
70  for (auto & handler : g_handlers)
71  handler->cancel();
72  }
73  }
74 
75  void dump_usage_and_exit() {
76  cout << "\n";
77  cout << "ht_ssh version " << version_string() << "\n";
78  cout << "\n";
79  cout << "This application uses libssh 0.6.4 (https://www.libssh.org/)\n";
80  cout << "libssh is licensed under the GNU Lesser General Public License\n";
81  cout << "\n";
82  cout << "usage: ht_ssh [options] <hosts-specification> <command>\n";
83  cout << "\n";
84  cout << "options:\n";
85  cout << " --debug Turn on verbose debugging output\n";
86  cout << " --random-start-delay <millis>\n";
87  cout << " Wait a random amount of time between 0 and <millis>\n";
88  cout << " prior to starting each command\n";
89  cout << " --libssh-verbosity <level>\n";
90  cout << " Set libssh verbosity level to <level>. Valid values\n";
91  cout << " are: none, warning, protocol, packet, and functions.\n";
92  cout << " Default value is protocol.\n";
93  cout << endl;
94  quick_exit(EXIT_FAILURE);
95  }
96 }
97 
101 
102 int main(int argc, char **argv) {
103 
105  Config::properties = make_shared<Properties>();
107 
108  string host_spec;
109  string command;
110 
111  int start_delay {};
112  for (int i=1; i<argc; i++) {
113  if (!strcmp(argv[i], "--debug"))
115  else if (!strcmp(argv[i], "--libssh-verbosity")) {
116  i++;
117  if (i == argc)
118  dump_usage_and_exit();
120  }
121  else if (!strcmp(argv[i], "--random-start-delay")) {
122  i++;
123  if (i == argc)
124  dump_usage_and_exit();
125  start_delay = atoi(argv[i]);
126  }
127  else if (host_spec.empty())
128  host_spec = argv[i];
129  else if (command.empty())
130  command.append(argv[i]);
131  else {
132  command.append(" ");
133  command.append(argv[i]);
134  }
135  }
136 
137  if (command.empty())
138  dump_usage_and_exit();
139 
140  vector<string> hosts;
141  try {
142  hosts = HostSpecification(host_spec);
143  }
144  catch (Exception &e) {
145  cout << "Invalid host specification: " << e.what() << endl;
146  quick_exit(EXIT_FAILURE);
147  }
148 
149  (void)signal(SIGINT, sig);
150  (void)signal(SIGQUIT, sig);
151 
152  ssh_threads_set_callbacks(SshThreadsCallbacks::get());
153  ssh_init();
154 
155  g_handlers.reserve(hosts.size());
156 
157  for (auto & host : hosts)
158  g_handlers.push_back(make_shared<SshSocketHandler>(host));
159 
160  auto now = chrono::system_clock::now();
161  auto deadline = now + std::chrono::seconds(30);
162 
163  {
164  lock_guard<mutex> lock(g_mutex);
165  g_handlers_created = true;
166  if (g_cancelled)
167  quick_exit(EXIT_FAILURE);
168  }
169 
170  // Wait for connections
171  for (auto & handler : g_handlers) {
172  if (!handler->wait_for_connection(deadline)) {
173  handler->dump_log(cerr);
174  quick_exit(EXIT_FAILURE);
175  }
176  }
177 
178  {
179  lock_guard<mutex> lock(g_mutex);
180  if (g_cancelled)
181  quick_exit(EXIT_FAILURE);
182  }
183 
184  vector<string> failed_hosts;
185 
186  // Issue commands
187 
188  if (start_delay) {
189  map<chrono::time_point<chrono::steady_clock>, SshSocketHandlerPtr> start_map;
190  chrono::time_point<chrono::steady_clock> start_time;
191  for (auto & handler : g_handlers) {
192  start_time = chrono::steady_clock::now()
193  + std::chrono::milliseconds(Random::number32() % start_delay);
194  start_map[start_time] = handler;
195  }
196  chrono::time_point<chrono::steady_clock> now;
197  for (auto & entry : start_map) {
198  now = chrono::steady_clock::now();
199  this_thread::sleep_for(chrono::duration_cast<std::chrono::milliseconds>(entry.first-now));
200  if (!entry.second->issue_command(command)) {
201  entry.second->dump_log(cerr);
202  failed_hosts.push_back(entry.second->hostname());
203  entry.second.reset();
204  }
205  }
206  }
207  else {
208  for (auto & handler : g_handlers) {
209  if (!handler->issue_command(command)) {
210  handler->dump_log(cerr);
211  failed_hosts.push_back(handler->hostname());
212  handler.reset();
213  }
214  }
215  }
216 
217  // Wait for commands to complete
218  for (auto & handler : g_handlers) {
219  if (handler) {
220  handler->set_terminal_output(true);
221  if (!handler->wait_for_command_completion()) {
222  handler->dump_log(cerr);
223  failed_hosts.push_back(handler->hostname());
224  }
225  handler->set_terminal_output(false);
226  }
227  }
228 
229  if (!failed_hosts.empty()) {
230  cerr << "Command failed on hosts: ";
231  bool first = true;
232  for (auto & host : failed_hosts) {
233  if (first)
234  first = false;
235  else
236  cerr << ",";
237  cerr << host;
238  }
239  cerr << endl << flush;
240  quick_exit(2);
241  }
242 
243  cout << flush;
244 
245  quick_exit(EXIT_SUCCESS);
246 }
Retrieves system information (hardware, installation directory, etc)
static std::mutex mutex
Definition: Logger.cc:43
std::shared_ptr< SshSocketHandler > SshSocketHandlerPtr
Smart pointer to SshSocketHandler.
static struct ssh_threads_callbacks_struct * get()
Gets libssh threads callbacks structure.
Declarations for HostSpecification.
PropertiesPtr properties
This singleton map stores all options.
Definition: Config.cc:47
static void initialize(uint16_t reactor_count)
Initializes I/O reactors.
Converts host specification pattern to list of host names.
static void initialize(const String &install_directory=String())
Initializes the static class members; checks header version vs.
Definition: System.h:72
STL namespace.
static int32_t get_processor_count()
The processor count.
Definition: System.cc:103
static uint32_t number32(uint32_t maximum=0)
Returns a random 32-bit unsigned integer.
Definition: Random.cc:55
Declarations for SshThreadsCallbacks.
A timer class to keep timeout states across AsyncComm related calls.
Logging routines and macros.
int main(int argc, char **argv)
Definition: ht_ssh.cc:102
Compatibility Macros for C/C++.
Initialization helper for applications.
Declarations for SshOutputCollector.
static void set_libssh_verbosity(const std::string &value)
Sets libssh logging verbosity level.
Hypertable definitions
static void enable_debug()
Enables debug logging output.
Declarations for Comm.
Random number generator for int32, int64, double and ascii arrays.
Declarations for ReactorFactory.
This is a generic exception class for Hypertable.
Definition: Error.h:314
Error codes, Exception handling, error logging.
const char * version_string()
Definition: Version.cc:37
Declarations for SshSocketHandler.