1 /*
2 Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25
26 #include <Parser.hpp>
27 #include <NdbOut.hpp>
28 #include <Properties.hpp>
29 #include <socket_io.h>
30
31 #include "APIService.hpp"
32 #include "CPCD.hpp"
33 #include <NdbMutex.h>
34 #include <OutputStream.hpp>
35
36 /**
37 const char * name;
38 const char * realName;
39 const Type type;
40 const ArgType argType;
41 const ArgRequired argRequired;
42 const ArgMinMax argMinMax;
43 const int minVal;
44 const int maxVal;
45 void (T::* function)(const class Properties & args);
46 const char * description;
47 */
48
49 #define CPCD_CMD(name, fun, desc) \
50 { name, \
51 0, \
52 ParserRow<CPCDAPISession>::Cmd, \
53 ParserRow<CPCDAPISession>::String, \
54 ParserRow<CPCDAPISession>::Optional, \
55 ParserRow<CPCDAPISession>::IgnoreMinMax, \
56 0, 0, \
57 fun, \
58 desc, 0 }
59
60 #define CPCD_ARG(name, type, opt, desc) \
61 { name, \
62 0, \
63 ParserRow<CPCDAPISession>::Arg, \
64 ParserRow<CPCDAPISession>::type, \
65 ParserRow<CPCDAPISession>::opt, \
66 ParserRow<CPCDAPISession>::IgnoreMinMax, \
67 0, 0, \
68 0, \
69 desc, 0 }
70
71 #define CPCD_ARG2(name, type, opt, min, max, desc) \
72 { name, \
73 0, \
74 ParserRow<CPCDAPISession>::Arg, \
75 ParserRow<CPCDAPISession>::type, \
76 ParserRow<CPCDAPISession>::opt, \
77 ParserRow<CPCDAPISession>::IgnoreMinMax, \
78 min, max, \
79 0, \
80 desc, 0 }
81
82 #define CPCD_END() \
83 { 0, \
84 0, \
85 ParserRow<CPCDAPISession>::End, \
86 ParserRow<CPCDAPISession>::Int, \
87 ParserRow<CPCDAPISession>::Optional, \
88 ParserRow<CPCDAPISession>::IgnoreMinMax, \
89 0, 0, \
90 0, \
91 0, 0 }
92
93 #define CPCD_CMD_ALIAS(name, realName, fun) \
94 { name, \
95 realName, \
96 ParserRow<CPCDAPISession>::CmdAlias, \
97 ParserRow<CPCDAPISession>::Int, \
98 ParserRow<CPCDAPISession>::Optional, \
99 ParserRow<CPCDAPISession>::IgnoreMinMax, \
100 0, 0, \
101 0, \
102 0, 0 }
103
104 #define CPCD_ARG_ALIAS(name, realName, fun) \
105 { name, \
106 realName, \
107 ParserRow<CPCDAPISession>::ArgAlias, \
108 ParserRow<CPCDAPISession>::Int, \
109 ParserRow<CPCDAPISession>::Optional, \
110 ParserRow<CPCDAPISession>::IgnoreMinMax, \
111 0, 0, \
112 0, \
113 0, 0 }
114
115 const
116 ParserRow<CPCDAPISession> commands[] =
117 {
118 CPCD_CMD("define process" , &CPCDAPISession::defineProcess, ""),
119 CPCD_ARG("id", Int, Optional, "Id of process."),
120 CPCD_ARG("name", String, Mandatory, "Name of process"),
121 CPCD_ARG("group", String, Mandatory, "Group of process"),
122 CPCD_ARG("env", String, Optional, "Environment variables for process"),
123 CPCD_ARG("path", String, Mandatory, "Path to binary"),
124 CPCD_ARG("args", String, Optional, "Arguments to process"),
125 CPCD_ARG("type", String, Mandatory, "Type of process"),
126 CPCD_ARG("cwd", String, Mandatory, "Working directory of process"),
127 CPCD_ARG("owner", String, Mandatory, "Owner of process"),
128 CPCD_ARG("runas", String, Optional, "Run as user"),
129 CPCD_ARG("stdout", String, Optional, "Redirection of stdout"),
130 CPCD_ARG("stderr", String, Optional, "Redirection of stderr"),
131 CPCD_ARG("stdin", String, Optional, "Redirection of stderr"),
132 CPCD_ARG("ulimit", String, Optional, "ulimit"),
133 CPCD_ARG("shutdown", String, Optional, "shutdown options"),
134
135 CPCD_CMD("undefine process", &CPCDAPISession::undefineProcess, ""),
136 CPCD_CMD_ALIAS("undef", "undefine process", 0),
137 CPCD_ARG("id", Int, Mandatory, "Id of process"),
138 CPCD_ARG_ALIAS("i", "id", 0),
139
140 CPCD_CMD("start process", &CPCDAPISession::startProcess, ""),
141 CPCD_ARG("id", Int, Mandatory, "Id of process"),
142
143 CPCD_CMD("stop process", &CPCDAPISession::stopProcess, ""),
144 CPCD_ARG("id", Int, Mandatory, "Id of process"),
145
146 CPCD_CMD("list processes", &CPCDAPISession::listProcesses, ""),
147
148 CPCD_CMD("show version", &CPCDAPISession::showVersion, ""),
149
150 CPCD_END()
151 };
CPCDAPISession(NDB_SOCKET_TYPE sock,CPCD & cpcd)152 CPCDAPISession::CPCDAPISession(NDB_SOCKET_TYPE sock,
153 CPCD & cpcd)
154 : SocketServer::Session(sock)
155 , m_cpcd(cpcd)
156 {
157 m_input = new SocketInputStream(sock, 7*24*60*60000);
158 m_output = new SocketOutputStream(sock);
159 m_parser = new Parser<CPCDAPISession>(commands, *m_input);
160 }
161
CPCDAPISession(FILE * f,CPCD & cpcd)162 CPCDAPISession::CPCDAPISession(FILE * f, CPCD & cpcd)
163 : SocketServer::Session(my_socket_create_invalid())
164 , m_cpcd(cpcd)
165 {
166 m_input = new FileInputStream(f);
167 m_parser = new Parser<CPCDAPISession>(commands, *m_input);
168 m_output = 0;
169 }
170
~CPCDAPISession()171 CPCDAPISession::~CPCDAPISession() {
172 delete m_input;
173 delete m_parser;
174 if (m_output)
175 delete m_output;
176 }
177
178 void
runSession()179 CPCDAPISession::runSession(){
180 Parser_t::Context ctx;
181 while(!m_stop){
182 m_parser->run(ctx, * this);
183 if(ctx.m_currentToken == 0)
184 break;
185
186 m_input->reset_timeout();
187 m_output->reset_timeout();
188
189 switch(ctx.m_status){
190 case Parser_t::Ok:
191 for(unsigned i = 0; i<ctx.m_aliasUsed.size(); i++)
192 ndbout_c("Used alias: %s -> %s",
193 ctx.m_aliasUsed[i]->name, ctx.m_aliasUsed[i]->realName);
194 break;
195 case Parser_t::NoLine:
196 case Parser_t::EmptyLine:
197 break;
198 default:
199 break;
200 }
201 }
202 NDB_CLOSE_SOCKET(m_socket);
203 }
204
205 void
stopSession()206 CPCDAPISession::stopSession(){
207 CPCD::RequestStatus rs;
208 for(unsigned i = 0; i<m_temporaryProcesses.size(); i++){
209 Uint32 id = m_temporaryProcesses[i];
210 m_cpcd.undefineProcess(&rs, id);
211 }
212 }
213
214 void
loadFile()215 CPCDAPISession::loadFile(){
216 Parser_t::Context ctx;
217 while(!m_stop){
218 m_parser->run(ctx, * this);
219 if(ctx.m_currentToken == 0)
220 break;
221
222 switch(ctx.m_status){
223 case Parser_t::Ok:
224 for(unsigned i = 0; i<ctx.m_aliasUsed.size(); i++)
225 ndbout_c("Used alias: %s -> %s",
226 ctx.m_aliasUsed[i]->name, ctx.m_aliasUsed[i]->realName);
227 break;
228 case Parser_t::NoLine:
229 case Parser_t::EmptyLine:
230 break;
231 default:
232 break;
233 }
234 }
235 }
236
237 void
defineProcess(Parser_t::Context &,const class Properties & args)238 CPCDAPISession::defineProcess(Parser_t::Context & /* unused */,
239 const class Properties & args){
240
241 CPCD::Process * p = new CPCD::Process(args, &m_cpcd);
242
243 CPCD::RequestStatus rs;
244
245 bool ret = m_cpcd.defineProcess(&rs, p);
246 if(!m_cpcd.loadingProcessList) {
247 m_output->println("define process");
248 m_output->println("status: %d", rs.getStatus());
249 if(ret == true){
250 m_output->println("id: %d", p->m_id);
251 if(p->m_processType == TEMPORARY){
252 m_temporaryProcesses.push_back(p->m_id);
253 }
254 } else {
255 m_output->println("errormessage: %s", rs.getErrMsg());
256 }
257 m_output->println("%s", "");
258 }
259 }
260
261 void
undefineProcess(Parser_t::Context &,const class Properties & args)262 CPCDAPISession::undefineProcess(Parser_t::Context & /* unused */,
263 const class Properties & args){
264 Uint32 id;
265 CPCD::RequestStatus rs;
266
267 args.get("id", &id);
268 bool ret = m_cpcd.undefineProcess(&rs, id);
269
270 m_output->println("undefine process");
271 m_output->println("id: %d", id);
272 m_output->println("status: %d", rs.getStatus());
273 if(!ret)
274 m_output->println("errormessage: %s", rs.getErrMsg());
275
276 m_output->println("%s", "");
277 }
278
279 void
startProcess(Parser_t::Context &,const class Properties & args)280 CPCDAPISession::startProcess(Parser_t::Context & /* unused */,
281 const class Properties & args){
282 Uint32 id;
283 CPCD::RequestStatus rs;
284
285 args.get("id", &id);
286 const int ret = m_cpcd.startProcess(&rs, id);
287
288 if(!m_cpcd.loadingProcessList) {
289 m_output->println("start process");
290 m_output->println("id: %d", id);
291 m_output->println("status: %d", rs.getStatus());
292 if(!ret)
293 m_output->println("errormessage: %s", rs.getErrMsg());
294 m_output->println("%s", "");
295 }
296 }
297
298 void
stopProcess(Parser_t::Context &,const class Properties & args)299 CPCDAPISession::stopProcess(Parser_t::Context & /* unused */,
300 const class Properties & args){
301 Uint32 id;
302 CPCD::RequestStatus rs;
303
304 args.get("id", &id);
305 int ret = m_cpcd.stopProcess(&rs, id);
306
307 m_output->println("stop process");
308 m_output->println("id: %d", id);
309 m_output->println("status: %d", rs.getStatus());
310 if(!ret)
311 m_output->println("errormessage: %s", rs.getErrMsg());
312
313 m_output->println("%s", "");
314 }
315
316 static const char *
propToString(Properties * prop,const char * key)317 propToString(Properties *prop, const char *key) {
318 static char buf[32];
319 const char *retval = NULL;
320 PropertiesType pt;
321
322 prop->getTypeOf(key, &pt);
323 switch(pt) {
324 case PropertiesType_Uint32:
325 Uint32 val;
326 prop->get(key, &val);
327 BaseString::snprintf(buf, sizeof buf, "%d", val);
328 retval = buf;
329 break;
330 case PropertiesType_char:
331 const char *str;
332 prop->get(key, &str);
333 retval = str;
334 break;
335 default:
336 BaseString::snprintf(buf, sizeof buf, "(unknown)");
337 retval = buf;
338 }
339 return retval;
340 }
341
342 void
printProperty(Properties * prop,const char * key)343 CPCDAPISession::printProperty(Properties *prop, const char *key) {
344 m_output->println("%s: %s", key, propToString(prop, key));
345 }
346
347 void
listProcesses(Parser_t::Context &,const class Properties &)348 CPCDAPISession::listProcesses(Parser_t::Context & /* unused */,
349 const class Properties & /* unused */){
350 m_cpcd.m_processes.lock();
351 MutexVector<CPCD::Process *> *proclist = m_cpcd.getProcessList();
352
353 m_output->println("start processes");
354 m_output->println("%s", "");
355
356
357 for(unsigned i = 0; i < proclist->size(); i++) {
358 CPCD::Process *p = (*proclist)[i];
359
360 m_output->println("process");
361
362 m_output->println("id: %d", p->m_id);
363 m_output->println("name: %s", p->m_name.c_str());
364 m_output->println("path: %s", p->m_path.c_str());
365 m_output->println("args: %s", p->m_args.c_str());
366 m_output->println("type: %s", p->m_type.c_str());
367 m_output->println("cwd: %s", p->m_cwd.c_str());
368 m_output->println("env: %s", p->m_env.c_str());
369 m_output->println("owner: %s", p->m_owner.c_str());
370 m_output->println("group: %s", p->m_group.c_str());
371 m_output->println("runas: %s", p->m_runas.c_str());
372 m_output->println("stdin: %s", p->m_stdin.c_str());
373 m_output->println("stdout: %s", p->m_stdout.c_str());
374 m_output->println("stderr: %s", p->m_stderr.c_str());
375 m_output->println("ulimit: %s", p->m_ulimit.c_str());
376 m_output->println("shutdown: %s", p->m_shutdown_options.c_str());
377 switch(p->m_status){
378 case STOPPED:
379 m_output->println("status: stopped");
380 break;
381 case STARTING:
382 m_output->println("status: starting");
383 break;
384 case RUNNING:
385 m_output->println("status: running");
386 break;
387 case STOPPING:
388 m_output->println("status: stopping");
389 break;
390 }
391
392 m_output->println("%s", "");
393
394 }
395
396 m_output->println("end processes");
397 m_output->println("%s", "");
398
399 m_cpcd.m_processes.unlock();
400 }
401
402 void
showVersion(Parser_t::Context &,const class Properties & args)403 CPCDAPISession::showVersion(Parser_t::Context & /* unused */,
404 const class Properties & args){
405 CPCD::RequestStatus rs;
406
407 m_output->println("show version");
408 m_output->println("compile time: %s %s", __DATE__, __TIME__);
409
410 m_output->println("%s", "");
411 }
412
413 template class Vector<ParserRow<CPCDAPISession> const*>;
414