0.9.8.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
ht_cluster.cc
Go to the documentation of this file.
1 /* -*- c++ -*-
2  * Copyright (C) 2007-2015 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 
22 #include <Common/Compat.h>
23 
25 
26 #include <Tools/Lib/CommandShell.h>
27 
28 #include <Hypertable/Lib/Config.h>
29 
33 #include <Common/Config.h>
34 #include <Common/FileUtils.h>
35 #include <Common/Init.h>
36 #include <Common/System.h>
37 #include <Common/Version.h>
38 
39 #include <cerrno>
40 #include <iostream>
41 #include <string>
42 #include <vector>
43 
44 extern "C" {
45 #include <pwd.h>
46 #include <sys/types.h>
47 #include <unistd.h>
48 }
49 
50 using namespace Hypertable;
51 using namespace Hypertable::ClusterDefinitionFile;
52 using namespace Hypertable::Config;
53 using namespace std;
54 
58 
59 namespace {
60 
61  void clear_cache() {
62  string cache_dir;
63  struct passwd *pw = getpwuid(getuid());
64  cache_dir.append(pw->pw_dir);
65  cache_dir.append("/.cluster");
66  if (!FileUtils::exists(cache_dir))
67  return;
68  string cmd = (string)"/bin/rm -rf " + cache_dir;
69  if (system(cmd.c_str()) != 0) {
70  cout << "Failed execution: " << cmd << endl;
71  quick_exit(EXIT_FAILURE);
72  }
73  }
74 
75  const string locate_definition_file() {
76  string fname;
77 
78  // CWD
79  fname.clear();
80  char cwd[1024];
81  if (getcwd(cwd, 1024) == nullptr) {
82  cout << "getcwd() - " << strerror(errno) << endl;
83  quick_exit(EXIT_FAILURE);
84  }
85  fname.append(cwd);
86  fname.append("/cluster.def");
87  if (FileUtils::exists(fname))
88  return fname;
89 
90  // conf dir
91  fname = System::install_dir + "/conf/cluster.def";
92  if (FileUtils::exists(fname))
93  return fname;
94 
95  cout << "Unable to locate 'cluster.def' in '.' or '" << System::install_dir
96  << "/conf'" << endl;
97  quick_exit(EXIT_FAILURE);
98  return string();
99  }
100 
101  bool is_environment_setting(const string &arg) {
102  HT_ASSERT(!arg.empty());
104  return false;
105  const char *ptr = arg.c_str();
107  ptr++;
108  return *ptr == '=';
109  }
110 
111  void exec_command(const string &script, vector<string> environment,
112  vector<string> arguments) {
113  char **argv = new char *[environment.size() + arguments.size() + 3];
114 
115  if (environment.empty()) {
116  argv[0] = (char *)script.c_str();
117  size_t i=1;
118  for (auto & arg : arguments)
119  argv[i++] = (char *)arg.c_str();
120  argv[i] = nullptr;
121  if (execv(script.c_str(), argv) < 0) {
122  cout << "execv() failed - " << strerror(errno) << endl;
123  quick_exit(EXIT_FAILURE);
124  }
125  }
126  else {
127  argv[0] = (char *)"env";
128  size_t i=1;
129  for (auto & setting : environment)
130  argv[i++] = (char *)setting.c_str();
131  argv[i++] = (char *)script.c_str();
132  for (auto & arg : arguments)
133  argv[i++] = (char *)arg.c_str();
134  argv[i] = nullptr;
135  if (execvp("env", argv) < 0) {
136  cout << "execv() failed - " << strerror(errno) << endl;
137  quick_exit(EXIT_FAILURE);
138  }
139  }
140  HT_FATAL("Should not reach here!");
141  }
142 
143  const char *usage[] = {
144  "",
145  "usage: ht_cluster [-f <fname>] [<environment>] <task> [<arg> ...]",
146  "usage: ht_cluster <options>",
147  "usage: ht_cluster",
148  "",
149  "options:",
150  " --clear-cache Clear command script cache directory (~/.cluster)",
151  " --display-json Display JSON representation of cluster definition",
152  " file",
153  " --display-script Display script compiled from cluster definition",
154  " file",
155  " -e, --explain <task> Display long description for <task>",
156  " -f <fname> Use <fname> for the cluster definition file",
157  " --help Display this help message",
158  " -T, --tasks List all tasks with short description of each",
159  " --version Display version string",
160  "",
161  "This program is used to run tasks defined in the cluster definition file.",
162  "The default name of the cluster definition file is \"cluster.def\" and is",
163  "expected to be located in the current working directory, or if not found",
164  "there, in the directory ../conf relative to the directory containing the",
165  "ht_cluster executable file. The location of the cluster definition file",
166  "can also be specified explicitly with the -f option.",
167  "",
168  "If a task name (with optional arguments) is supplied on the command line,",
169  "the corresponding task will be run. Optionally, environment variables",
170  "can be set by supplying a list of space-separated <name>=<value> variable",
171  "specifications where <name> is the name of the environment variable to set",
172  "and <value> is the value you would like to set it to prior to running the",
173  "task. The environment variables must appear before the task name on the",
174  "command line.",
175  "",
176  "If ht_cluster is run with no arguments, it will enter interactive mode.",
177  "In this mode tasks or any shell command can be run interactively. Tasks",
178  "can be run on their default roles or any set of machines matching a host",
179  "specification. Shell commands can be run on any set of roles or on any",
180  "set of machines matching a host specification. Type 'help' at the",
181  "interactive command prompt for details on the format of interactive",
182  "commands.",
183  "",
184  nullptr
185  };
186 
187 }
188 
189 
190 int main(int argc, char **argv) {
191 
192  CommandShellPtr shell;
193  CommandInterpreterPtr interp;
194  int status = 0;
195 
196  try {
197  vector<string> environment;
198  string definition_file;
199  vector<string> arguments;
200  bool display_script {};
201  bool display_json {};
202 
204  Config::properties = make_shared<Properties>();
206 
207  // environment settings and cluster options
208  int i = 1;
209  while (i<argc) {
210  if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) {
211  for (size_t i=0; usage[i]; i++)
212  cout << usage[i] << "\n";
213  cout << flush;
214  quick_exit(EXIT_SUCCESS);
215  }
216  else if (!strcmp(argv[1], "--version")) {
217  cout << version_string() << endl;
218  quick_exit(EXIT_SUCCESS);
219  }
220  else if (!strcmp(argv[1], "--clear-cache")) {
221  clear_cache();
222  quick_exit(EXIT_SUCCESS);
223  }
224  else if (!strcmp(argv[i], "-f")) {
225  if (!definition_file.empty()) {
226  cout << "error: -f option supplied multiple times" << endl;
227  quick_exit(EXIT_FAILURE);
228  }
229  i++;
230  if (i == argc) {
231  cout << "error: missing argument to -f option" << endl;
232  quick_exit(EXIT_FAILURE);
233  }
234  definition_file.append(argv[i]);
235  i++;
236  continue;
237  }
238  else if (!strcmp(argv[i], "--display-script")) {
239  display_script = true;
240  }
241  else if (!strcmp(argv[i], "--display-json")) {
242  display_json = true;
243  }
244  else if (!is_environment_setting(argv[i]))
245  break;
246  environment.push_back(argv[i]);
247  i++;
248  }
249 
250  // load command arguments
251  while (i<argc) {
252  arguments.push_back(argv[i]);
253  i++;
254  }
255 
256  if (definition_file.empty())
257  definition_file = locate_definition_file();
258 
259  if (display_script) {
260  Compiler compiler(definition_file);
261  string cmd = (string)"cat " + compiler.output_script();
262  if (system(cmd.c_str()) != 0) {
263  cout << "Failed execution: " << cmd << endl;
264  quick_exit(EXIT_FAILURE);
265  }
266  quick_exit(EXIT_SUCCESS);
267  }
268  else if (display_json) {
269  cout << ToJson(definition_file).str() << endl;
270  _exit(0);
271  }
272 
273  Compiler compiler(definition_file);
274 
275  if (!arguments.empty())
276  exec_command(compiler.output_script(), environment, arguments);
277 
278  interp = make_shared<ClusterCommandInterpreter>(compiler.output_script());
279  shell = make_shared<CommandShell>("cluster", "Cluster", interp, properties);
280 
281  // Entire line is command
282  shell->set_line_command_mode(true);
283 
284  interp->set_silent(shell->silent());
285  interp->set_test_mode(shell->test_mode());
286 
287  status = shell->run();
288  }
289  catch(Exception &e) {
290  cout << Error::get_text(e.code()) << " - " << e.what() << endl;
291  status = e.code();
292  }
293  quick_exit(status);
294 }
Retrieves system information (hardware, installation directory, etc)
string str()
Returns pathname of output script.
Definition: ToJson.h:62
PropertiesPtr properties
This singleton map stores all options.
Definition: Config.cc:47
static void initialize(uint16_t reactor_count)
Initializes I/O reactors.
static void initialize(const String &install_directory=String())
Initializes the static class members; checks header version vs.
Definition: System.h:72
static bool exists(const String &fname)
Checks if a file or directory exists.
Definition: FileUtils.cc:420
STL namespace.
#define HT_FATAL(msg)
Definition: Logger.h:339
static int32_t get_processor_count()
The processor count.
Definition: System.cc:103
Declarations for ToJson.
#define HT_ASSERT(_e_)
Definition: Logger.h:396
string output_script()
Returns pathname of output script.
Definition: Compiler.h:62
File system utility functions.
Compiles a cluster definition file into an executable bash script.
Definition: ToJson.h:45
const char * get_text(int error)
Returns a descriptive error message.
Definition: Error.cc:330
bool status(ContextPtr &context, Timer &timer, Status &status)
Runs a status check on the master.
Definition: Utility.cc:408
Compatibility Macros for C/C++.
Initialization helper for applications.
std::shared_ptr< CommandInterpreter > CommandInterpreterPtr
std::shared_ptr< CommandShell > CommandShellPtr
Definition: CommandShell.h:91
Hypertable definitions
Declarations for Compiler.
static String install_dir
The installation directory.
Definition: System.h:114
Compiles a cluster definition file into an executable bash script.
Definition: Compiler.h:45
int main(int argc, char **argv)
Definition: ht_cluster.cc:190
This is a generic exception class for Hypertable.
Definition: Error.h:314
Declarations for TokenizerTools.
Declarations for ClusterCommandInterpreter.
bool is_identifier_character(char c)
Checks if character is valid bash identifier character.
Configuration settings.
Cluster definition file translation definitions.
Definition: Compiler.h:35
bool is_identifier_start_character(char c)
Checks if character is valid bash identifier start character.
const char * version_string()
Definition: Version.cc:37
int code() const
Returns the error code.
Definition: Error.h:391