35 #include <boost/algorithm/string.hpp>
44 #include <sys/types.h>
55 bool split_command_line(
const string &line, vector<string> &argv) {
56 const char *base = line.c_str();
58 while (*base && isspace(*base))
62 const char *ptr = base;
63 if (*ptr ==
'"' || *ptr ==
'\'') {
66 cout <<
"Invalid command line - missing terminating quote" << endl;
70 argv.push_back(
string(ptr, (end-ptr)-1));
74 while (*ptr && !isspace(*ptr))
76 argv.push_back(
string(base, ptr-base));
83 bool extract_command_line_argument(
const char *base,
const char **end,
string &arg) {
84 const char *ptr = base;
85 while (*ptr && isspace(*ptr))
87 if (*ptr ==
'"' || *ptr ==
'\'') {
89 cout <<
"Invalid command line - missing terminating quote" << endl;
92 arg.append(ptr, (*end)-ptr);
98 while (*ptr && !isspace(*ptr))
100 arg.append(base, ptr-base);
107 const char *help_text[] = {
109 "Shell commands or cluster definition tasks can be run remotely on any",
110 "set of machines using the following syntax. Type 'quit' or 'exit' to",
111 "exit the command interpreter.",
113 "<command> [ <arg> ... ]",
115 " This instructs the interpreter to run the shell command (<command>)",
116 " with optional arguments (<arg> ...) on all hosts specified in all",
117 " the roles in the cluster definition file.",
119 " cluster> echo \"Hello, World!\"",
121 "on <hostspec> <command> [ <arg> ... ]",
123 " This instructs the interpreter to run the shell command (<command>)",
124 " with optional arguments (<arg> ...) on all hosts matching a host",
125 " specification (<hostspec>). The host specification is a compact",
126 " way to specify a large number of host names matching a pattern,",
127 " for example the host specification \"test[01-06] - test02\" expands",
128 " to: test01, test03, test04, test05, test06.",
130 " cluster> on test[02-04]-test03 echo \"Hello, World!\"",
132 "with <roles> <command> [ <arg> ... ]",
134 " This instructs the interpreter to run the shell command (<command>)",
135 " with optional arguments (<arg> ...) on all hosts represented by the",
136 " comma-separated list of role names (<roles>) specified in the cluster",
139 " cluster> with master,slave echo \"Hello, World!\"",
141 "!<task> [ on <hostspec> ] [<arg> ...]",
143 " This instructs the interpreter to run a task (<task>) with optional",
144 " arguments (<arg> ...) using the default roles supplied in the task",
145 " definition or on a specific set of hosts that match a host",
146 " specification pattern by supplying the \"on <hostspec>\" after the",
149 " cluster> !start_hyperspace",
150 " cluster> !start_hyperspace on test02",
159 : m_command_script(script) {
170 string trimmed_line(line);
171 boost::trim(trimmed_line);
173 if (trimmed_line[0] ==
'!') {
175 if (!split_command_line(trimmed_line.substr(1), args) || args.empty())
178 argv =
new char *[args.size()+2];
180 argv[i++] = (
char *)program.c_str();
181 for (
auto & arg : args)
182 argv[i++] = (
char *)arg.c_str();
185 else if (!strcmp(trimmed_line.c_str(),
"help")) {
186 for (
size_t i=0; help_text[i]; i++)
187 cout << help_text[i] <<
"\n";
191 else if (!strncmp(trimmed_line.c_str(),
"on ", 3)) {
193 if (!extract_command_line_argument(trimmed_line.c_str() + 3, &end, target))
197 if (command.empty()) {
198 cout <<
"Invalid command line" << endl;
202 boost::trim_if(target, boost::is_any_of(
"'\""));
205 program.append(
"/bin/ht_ssh");
207 argv =
new char *[4];
208 argv[0] = (
char *)program.c_str();
209 argv[1] = (
char *)target.c_str();
210 argv[2] = (
char *)command.c_str();
216 if (!strncmp(trimmed_line.c_str(),
"with ", 5)) {
217 if (!extract_command_line_argument(trimmed_line.c_str()+5, &end, target))
223 command.append(trimmed_line);
226 if (command.empty()) {
227 cout <<
"Invalid command line" << endl;
231 boost::trim_if(target, boost::is_any_of(
"'\""));
234 argv =
new char *[5];
235 argv[0] = (
char *)program.c_str();
236 argv[1] = (
char *)
"with";
237 argv[2] = (
char *)target.c_str();
238 argv[3] = (
char *)command.c_str();
245 if (execv(program.c_str(), argv) < 0) {
246 cout <<
"execv(" << program <<
") failed - " << strerror(errno) << endl;
251 cout <<
"vfork() failed - " << strerror(errno) << endl;
256 waitpid(pid, &status, 0);
Retrieves system information (hardware, installation directory, etc)
std::string String
A String is simply a typedef to std::string.
string m_command_script
Pathname of command script.
bool status(ContextPtr &context, Timer &timer, Status &status)
Runs a status check on the master.
Compatibility Macros for C/C++.
int execute_line(const string &line) override
Executes a command line.
static String install_dir
The installation directory.
A String class based on std::string.
Declarations for ClusterCommandInterpreter.
Cluster definition file translation definitions.
ClusterCommandInterpreter(const string &script)
Constructor.