1 /* $Id: adm_cmds.cpp 574016 2018-11-05 16:55:15Z sadyrovr $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Authors: Dmitry Kazimirov
27 *
28 * File Description: Miscellaneous commands of the grid_cli application
29 * (the ones that are not specific to NetCache, NetSchedule,
30 * or worker nodes).
31 *
32 */
33
34 #include <ncbi_pch.hpp>
35
36 #include "util.hpp"
37 #include "ns_cmd_impl.hpp"
38
39 USING_NCBI_SCOPE;
40
SetUp_AdminCmd(CGridCommandLineInterfaceApp::EAdminCmdSeverity cmd_severity)41 void CGridCommandLineInterfaceApp::SetUp_AdminCmd(
42 CGridCommandLineInterfaceApp::EAdminCmdSeverity cmd_severity)
43 {
44 // For commands that accept only one type of server.
45 switch (IsOptionAccepted(eNetCache, OPTION_N(0)) |
46 IsOptionAccepted(eNetSchedule, OPTION_N(1)) |
47 IsOptionAccepted(eWorkerNode, OPTION_N(2)) |
48 IsOptionAccepted(eNetStorage, OPTION_N(3))) {
49 case OPTION_N(0): // eNetCache
50 SetUp_NetCacheAdminCmd(cmd_severity);
51 return;
52
53 case OPTION_N(1): // eNetSchedule
54 SetUp_NetScheduleCmd(eNetScheduleAdmin, cmd_severity, false);
55 return;
56
57 case OPTION_N(2): // eWorkerNode
58 SetUp_NetScheduleCmd(eWorkerNodeAdmin, cmd_severity, false);
59 return;
60
61 case OPTION_N(3): // eNetStorage
62 SetUp_NetStorageCmd(eNetStorageAdmin, cmd_severity);
63 return;
64
65 default:
66 break;
67 }
68
69 // For commands that accept multiple types of servers.
70 switch (IsOptionExplicitlySet(eNetCache, OPTION_N(0)) |
71 IsOptionExplicitlySet(eNetSchedule, OPTION_N(1)) |
72 IsOptionExplicitlySet(eWorkerNode, OPTION_N(2)) |
73 IsOptionExplicitlySet(eNetStorage, OPTION_N(3))) {
74 case OPTION_N(0): // eNetCache
75 SetUp_NetCacheAdminCmd(cmd_severity);
76 return;
77
78 case OPTION_N(1): // eNetSchedule
79 SetUp_NetScheduleCmd(eNetScheduleAdmin, cmd_severity, false);
80 return;
81
82 case OPTION_N(2): // eWorkerNode
83 SetUp_NetScheduleCmd(eWorkerNodeAdmin, cmd_severity, false);
84 return;
85
86 case OPTION_N(3): // eNetStorage
87 SetUp_NetStorageCmd(eNetStorageAdmin, cmd_severity);
88 return;
89
90 case 0: // No options specified
91 NCBI_THROW(CArgException, eNoValue, "this command requires "
92 "a service name or a server address");
93
94 default: // A combination of options
95 NCBI_THROW(CArgException, eNoValue, "this command works "
96 "with only one type of server at a time");
97 }
98 }
99
Cmd_ServerInfo()100 int CGridCommandLineInterfaceApp::Cmd_ServerInfo()
101 {
102 CNetService service;
103
104 SetUp_AdminCmd(eReadOnlyAdminCmd);
105
106 bool server_version_key = true;
107
108 switch (m_APIClass) {
109 case eNetCacheAdmin:
110 service = m_NetCacheAPI.GetService();
111 break;
112
113 case eNetScheduleAdmin:
114 case eWorkerNodeAdmin:
115 server_version_key = false;
116 service = m_NetScheduleAPI.GetService();
117 break;
118
119 case eNetStorageAdmin:
120 return PrintNetStorageServerInfo();
121
122 default:
123 return 2;
124 }
125
126 if (m_Opts.output_format == eJSON)
127 g_PrintJSON(stdout, g_ServerInfoToJson(service,
128 server_version_key));
129 else if (m_Opts.output_format == eRaw)
130 service.PrintCmdOutput("VERSION", NcbiCout,
131 CNetService::eSingleLineOutput,
132 CNetService::eIncludePenalized);
133 else {
134 bool print_server_address = service.IsLoadBalanced();
135
136 for (CNetServiceIterator it =
137 service.Iterate(CNetService::eIncludePenalized); it; ++it) {
138 if (print_server_address)
139 printf("[%s]\n", (*it).GetServerAddress().c_str());
140
141 CNetServerInfo server_info((*it).GetServerInfo());
142
143 string attr_name, attr_value;
144
145 while (server_info.GetNextAttribute(attr_name, attr_value))
146 printf("%s: %s\n", attr_name.c_str(), attr_value.c_str());
147
148 if (print_server_address)
149 printf("\n");
150 }
151 }
152
153 return 0;
154 }
155
Cmd_Stats()156 int CGridCommandLineInterfaceApp::Cmd_Stats()
157 {
158 SetUp_AdminCmd(eReadOnlyAdminCmd);
159
160 switch (m_APIClass) {
161 case eNetCacheAdmin:
162 m_NetCacheAdmin.PrintStat(NcbiCout, m_Opts.aggregation_interval,
163 !IsOptionSet(ePreviousInterval) ?
164 CNetCacheAdmin::eReturnCurrentPeriod :
165 CNetCacheAdmin::eReturnCompletePeriod);
166 return 0;
167
168 case eNetScheduleAdmin:
169 return PrintNetScheduleStats();
170
171 case eWorkerNodeAdmin:
172 if (m_Opts.output_format == eJSON)
173 g_PrintJSON(stdout, g_WorkerNodeInfoToJson(
174 m_NetScheduleAPI.GetService().Iterate().GetServer()));
175 else
176 m_NetScheduleAdmin.PrintServerStatistics(NcbiCout);
177 return 0;
178
179 default:
180 return 2;
181 }
182 }
183
Cmd_Health()184 int CGridCommandLineInterfaceApp::Cmd_Health()
185 {
186 SetUp_AdminCmd(eReadOnlyAdminCmd);
187
188 switch (m_APIClass) {
189 case eNetCacheAdmin:
190 m_NetCacheAdmin.PrintHealth(NcbiCout);
191 return 0;
192
193 case eNetScheduleAdmin:
194 m_NetScheduleAdmin.PrintHealth(NcbiCout);
195 return 0;
196
197 default:
198 return 2;
199 }
200 }
201
202 #define CHECK_FAILED_RETVAL 10
203
NetCacheSanityCheck()204 int CGridCommandLineInterfaceApp::NetCacheSanityCheck()
205 {
206 // functionality test
207
208 const char test_data[] = "A quick brown fox, jumps over lazy dog.";
209 const char test_data2[] = "Test 2.";
210 string key = m_NetCacheAPI.PutData(test_data, sizeof(test_data));
211
212 if (key.empty()) {
213 NcbiCerr << "Failed to put data. " << NcbiEndl;
214 return CHECK_FAILED_RETVAL;
215 }
216 NcbiCout << key << NcbiEndl;
217
218 char data_buf[1024];
219
220 size_t blob_size = m_NetCacheAPI.GetBlobSize(key);
221
222 if (blob_size != sizeof(test_data)) {
223 NcbiCerr << "Failed to retrieve data size." << NcbiEndl;
224 return CHECK_FAILED_RETVAL;
225 }
226
227 unique_ptr<IReader> reader(m_NetCacheAPI.GetData(key, &blob_size,
228 nc_caching_mode = CNetCacheAPI::eCaching_Disable));
229
230 if (reader.get() == 0) {
231 NcbiCerr << "Failed to read data." << NcbiEndl;
232 return CHECK_FAILED_RETVAL;
233 }
234
235 reader->Read(data_buf, 1024);
236 int res = strcmp(data_buf, test_data);
237 if (res != 0) {
238 NcbiCerr << "Could not read data." << NcbiEndl <<
239 "Server returned:" << NcbiEndl << data_buf << NcbiEndl <<
240 "Expected:" << NcbiEndl << test_data << NcbiEndl;
241
242 return CHECK_FAILED_RETVAL;
243 }
244 reader.reset(0);
245
246 {{
247 unique_ptr<IEmbeddedStreamWriter> wrt(m_NetCacheAPI.PutData(&key));
248 size_t bytes_written;
249 wrt->Write(test_data2, sizeof(test_data2), &bytes_written);
250 wrt->Close();
251 }}
252
253 memset(data_buf, 0xff, sizeof(data_buf));
254 reader.reset(m_NetCacheAPI.GetReader(key, &blob_size,
255 nc_caching_mode = CNetCacheAPI::eCaching_Disable));
256 reader->Read(data_buf, 1024);
257 res = strcmp(data_buf, test_data2);
258 if (res != 0) {
259 NcbiCerr << "Could not read updated data." << NcbiEndl <<
260 "Server returned:" << NcbiEndl << data_buf << NcbiEndl <<
261 "Expected:" << NcbiEndl << test_data2 << NcbiEndl;
262
263 return CHECK_FAILED_RETVAL;
264 }
265
266 return 0;
267 }
268
NetScheduleSanityCheck()269 int CGridCommandLineInterfaceApp::NetScheduleSanityCheck()
270 {
271 if (!IsOptionSet(eQueue)) {
272 if (!IsOptionSet(eQueueClass)) {
273 fprintf(stderr, GRID_APP_NAME ": '--" QUEUE_OPTION
274 "' or '--" QUEUE_CLASS_OPTION
275 "' (or both) must be specified.\n");
276 return 2;
277 }
278 m_Opts.queue = NETSCHEDULE_CHECK_QUEUE;
279 }
280 if (IsOptionSet(eQueueClass))
281 m_NetScheduleAdmin.CreateQueue(m_Opts.queue, m_Opts.queue_class);
282
283 CNetScheduleAdmin::TQueueList server_queues;
284
285 m_NetScheduleAdmin.GetQueueList(server_queues);
286
287 ITERATE(CNetScheduleAdmin::TQueueList, it, server_queues) {
288 list<string>::const_iterator queue(it->queues.begin());
289 for (;;) {
290 if (queue == it->queues.end()) {
291 fprintf(stderr, "The queue '%s' is not available on '%s'.\n",
292 m_Opts.queue.c_str(),
293 it->server.GetServerAddress().c_str());
294 return 4;
295 }
296 if (*queue == m_Opts.queue)
297 break;
298 ++queue;
299 }
300 }
301
302 SetUp_NetScheduleCmd(eNetScheduleExecutor, eReadOnlyAdminCmd, false);
303
304 const string input = "Hello ";
305 const string output = "DONE ";
306 CNetScheduleJob job(input);
307 m_NetScheduleSubmitter.SubmitJob(job);
308
309 for (;;) {
310 CNetScheduleJob job1;
311 bool job_exists = m_NetScheduleExecutor.GetJob(job1, 5);
312 if (job_exists) {
313 if (job1.job_id != job.job_id)
314 m_NetScheduleExecutor.ReturnJob(job1);
315 else {
316 if (job1.input != job.input) {
317 job1.error_msg = "Job's (" + job1.job_id +
318 ") input does not match.(" + job.input +
319 ") ["+ job1.input +"]";
320 m_NetScheduleExecutor.PutFailure(job1);
321 } else {
322 job1.output = output;
323 job1.ret_code = 0;
324 m_NetScheduleExecutor.PutResult(job1);
325 }
326 break;
327 }
328 }
329 }
330
331 bool check_again = true;
332 int ret = 0;
333 string err;
334 while (check_again) {
335 check_again = false;
336
337 CNetScheduleAPI::EJobStatus status = m_NetScheduleSubmitter.GetJobDetails(job);
338 switch(status) {
339
340 case CNetScheduleAPI::eJobNotFound:
341 ret = 10;
342 err = "Job (" + job.job_id +") is lost.";
343 break;
344 case CNetScheduleAPI::eCanceled:
345 ret = 12;
346 err = "Job (" + job.job_id +") is canceled.";
347 break;
348 case CNetScheduleAPI::eFailed:
349 ret = 13;
350 break;
351 case CNetScheduleAPI::eDone:
352 if (job.ret_code != 0) {
353 ret = job.ret_code;
354 err = "Job (" + job.job_id +") is done, but retcode is not zero.";
355 } else if (job.output != output) {
356 err = "Job (" + job.job_id + ") is done, output does not match.("
357 + output + ") ["+ job.output +"]";
358 ret = 14;
359 } else if (job.input != input) {
360 err = "Job (" + job.job_id +") is done, input does not match.("
361 + input + ") ["+ job.input +"]";
362 ret = 15;
363 }
364 break;
365 case CNetScheduleAPI::ePending:
366 case CNetScheduleAPI::eRunning:
367 default:
368 check_again = true;
369 }
370 }
371
372 if (ret != 0)
373 ERR_POST(err);
374
375 if (IsOptionSet(eQueueClass))
376 m_NetScheduleAdmin.DeleteQueue(m_Opts.queue);
377
378 return ret;
379 }
380
Cmd_SanityCheck()381 int CGridCommandLineInterfaceApp::Cmd_SanityCheck()
382 {
383 SetUp_AdminCmd(eAdminCmdWithSideEffects);
384
385 switch (m_APIClass) {
386 case eNetCacheAdmin:
387 return NetCacheSanityCheck();
388
389 case eNetScheduleAdmin:
390 return NetScheduleSanityCheck();
391
392 default:
393 return 2;
394 }
395 }
396
Cmd_GetConf()397 int CGridCommandLineInterfaceApp::Cmd_GetConf()
398 {
399 SetUp_AdminCmd(eReadOnlyAdminCmd);
400
401 switch (m_APIClass) {
402 case eNetCacheAdmin:
403 m_NetCacheAdmin.PrintConfig(NcbiCout);
404 return 0;
405
406 case eNetScheduleAdmin:
407 case eWorkerNodeAdmin:
408 m_NetScheduleAdmin.PrintConf(NcbiCout);
409 return 0;
410
411 case eNetStorageAdmin:
412 return PrintNetStorageServerConfig();
413
414 default:
415 return 2;
416 }
417 }
418
Cmd_Reconf()419 int CGridCommandLineInterfaceApp::Cmd_Reconf()
420 {
421 SetUp_AdminCmd(eAdminCmdWithSideEffects);
422
423 switch (m_APIClass) {
424 case eNetCacheAdmin:
425 m_NetCacheAdmin.ReloadServerConfig(IsOptionExplicitlySet(eMirror) ?
426 CNetCacheAdmin::eMirrorReload : CNetCacheAdmin::eCompleteReload);
427 return 0;
428
429 case eNetScheduleAdmin:
430 g_PrintJSON(stdout, g_ReconfAndReturnJson(m_NetScheduleAPI));
431 return 0;
432
433 case eNetStorageAdmin:
434 return ReconfigureNetStorageServer();
435
436 default:
437 return 2;
438 }
439 }
440
Cmd_Drain()441 int CGridCommandLineInterfaceApp::Cmd_Drain()
442 {
443 SetUp_AdminCmd(eAdminCmdWithSideEffects);
444
445 switch (m_APIClass) {
446 case eNetScheduleAdmin:
447 m_NetScheduleAdmin.SwitchToDrainMode(m_Opts.on_off_switch);
448 return 0;
449
450 default:
451 return 2;
452 }
453 return 0;
454 }
455
NetSchedule_SuspendResume(bool suspend)456 void CGridCommandLineInterfaceApp::NetSchedule_SuspendResume(bool suspend)
457 {
458 if (IsOptionAcceptedAndSetImplicitly(eQueue)) {
459 NCBI_THROW(CArgException, eNoValue,
460 "missing option '--" QUEUE_OPTION "'");
461 }
462
463 if (suspend)
464 g_SuspendNetSchedule(m_NetScheduleAPI, IsOptionSet(ePullback));
465 else
466 g_ResumeNetSchedule(m_NetScheduleAPI);
467 }
468
Cmd_Suspend()469 int CGridCommandLineInterfaceApp::Cmd_Suspend()
470 {
471 SetUp_AdminCmd(eAdminCmdWithSideEffects);
472
473 switch (m_APIClass) {
474 case eNetScheduleAdmin:
475 NetSchedule_SuspendResume(true);
476 return 0;
477
478 case eWorkerNodeAdmin:
479 {
480 CNetServer worker_node =
481 m_NetScheduleAPI.GetService().Iterate().GetServer();
482 g_SuspendWorkerNode(worker_node,
483 IsOptionSet(ePullback), m_Opts.timeout);
484 if (IsOptionSet(eWaitForJobCompletion)) {
485 string output_line;
486 for (;;) {
487 unsigned jobs_running = 0;
488 CNetServerMultilineCmdOutput stat_output(
489 worker_node.ExecWithRetry("STAT", true));
490 while (stat_output.ReadLine(output_line))
491 if (NStr::StartsWith(output_line, "Jobs Running: "))
492 jobs_running = NStr::StringToUInt(
493 output_line.c_str() +
494 sizeof("Jobs Running: ") - 1);
495 if (jobs_running == 0)
496 break;
497 SleepMilliSec(500);
498 }
499 }
500 }
501 return 0;
502
503 default:
504 return 2;
505 }
506 }
507
Cmd_Resume()508 int CGridCommandLineInterfaceApp::Cmd_Resume()
509 {
510 SetUp_AdminCmd(eAdminCmdWithSideEffects);
511
512 switch (m_APIClass) {
513 case eNetScheduleAdmin:
514 NetSchedule_SuspendResume(false);
515 return 0;
516
517 case eWorkerNodeAdmin:
518 g_ResumeWorkerNode(m_NetScheduleAPI.GetService().Iterate().GetServer());
519 return 0;
520
521 default:
522 return 2;
523 }
524 }
525
Cmd_Shutdown()526 int CGridCommandLineInterfaceApp::Cmd_Shutdown()
527 {
528 SetUp_AdminCmd(eAdminCmdWithSideEffects);
529
530 switch (m_APIClass) {
531 case eNetCacheAdmin:
532 m_NetCacheAdmin.ShutdownServer(IsOptionSet(eDrain) ?
533 CNetCacheAdmin::eDrain : CNetCacheAdmin::eNormalShutdown);
534 return 0;
535
536 case eNetScheduleAdmin:
537 case eWorkerNodeAdmin:
538 switch (IsOptionSet(eNow, OPTION_N(0)) |
539 IsOptionSet(eDie, OPTION_N(1)) |
540 IsOptionSet(eDrain, OPTION_N(2))) {
541 case 0: // No additional options.
542 m_NetScheduleAdmin.ShutdownServer();
543 return 0;
544
545 case OPTION_N(0): // eNow is set.
546 m_NetScheduleAdmin.ShutdownServer(
547 CNetScheduleAdmin::eShutdownImmediate);
548 return 0;
549
550 case OPTION_N(1): // eDie is set.
551 m_NetScheduleAdmin.ShutdownServer(CNetScheduleAdmin::eDie);
552 return 0;
553
554 case OPTION_N(2): // eDrain is set.
555 m_NetScheduleAdmin.ShutdownServer(CNetScheduleAdmin::eDrain);
556 return 0;
557
558 default: // A combination of the above options.
559 fprintf(stderr, GRID_APP_NAME ": options '--" NOW_OPTION "', '--"
560 DIE_OPTION "', and '--" DRAIN_OPTION
561 "' are mutually exclusive.\n");
562 return 2;
563 }
564
565 case eNetStorageAdmin:
566 return ShutdownNetStorageServer();
567
568 default:
569 return 2;
570 }
571 }
572
573 namespace {
574 class CAdjustableTableColumn {
575 public:
576 enum {
577 fAlignRight = 1,
578 fLastColumn = 2
579 };
CAdjustableTableColumn(int min_width=0,int spacing=1,unsigned mode=0)580 CAdjustableTableColumn(int min_width = 0,
581 int spacing = 1,
582 unsigned mode = 0) :
583 m_Width(min_width),
584 m_Spacing(spacing),
585 m_Mode(mode)
586 {
587 }
AddCell(const string & text)588 void AddCell(const string& text)
589 {
590 int length = (int)text.length();
591 if (m_Width < length)
592 m_Width = length;
593 m_Cells.push_back(text);
594 }
PrintCell(size_t row)595 void PrintCell(size_t row)
596 {
597 switch (m_Mode & (fAlignRight | fLastColumn)) {
598 default:
599 printf("%-*s", m_Width + m_Spacing, m_Cells[row].c_str());
600 break;
601 case fAlignRight:
602 printf("%*s%*s", m_Width, m_Cells[row].c_str(), m_Spacing, "");
603 break;
604 case fLastColumn:
605 printf("%s\n", m_Cells[row].c_str());
606 break;
607 case fAlignRight | fLastColumn:
608 printf("%*s\n", m_Width, m_Cells[row].c_str());
609 }
610 }
PrintRule()611 void PrintRule()
612 {
613 const static char eight_dashes[] = "--------";
614
615 int width = m_Width;
616 while (width > 8) {
617 printf("%s", eight_dashes);
618 width -= 8;
619 }
620
621 if ((m_Mode & fLastColumn) == 0)
622 printf("%-*.*s", width + m_Spacing, width, eight_dashes);
623 else
624 printf("%.*s\n", width, eight_dashes);
625 }
GetHeight() const626 size_t GetHeight() const {return m_Cells.size();}
627
628 private:
629 int m_Width;
630 int m_Spacing;
631 unsigned m_Mode;
632 vector<string> m_Cells;
633 };
634 }
635
636 #define NCBI_DOMAIN ".ncbi.nlm.nih.gov"
637
Cmd_Discover()638 int CGridCommandLineInterfaceApp::Cmd_Discover()
639 {
640 CNetService service = CNetService::Create("discovery", m_Opts.service_name, m_Opts.auth);
641
642 CAdjustableTableColumn ipv4_column(0, 2);
643 ipv4_column.AddCell("IPv4 Address");
644
645 CAdjustableTableColumn hostname_column(0, 2);
646 if (!IsOptionSet(eNoDNSLookup))
647 hostname_column.AddCell("Hostname");
648
649 CAdjustableTableColumn port_column(0, 2,
650 CAdjustableTableColumn::fAlignRight);
651 port_column.AddCell("Port");
652
653 CAdjustableTableColumn rating_column(7, 0,
654 CAdjustableTableColumn::fAlignRight |
655 CAdjustableTableColumn::fLastColumn);
656 rating_column.AddCell("Rating");
657
658 for (CNetServiceIterator it =
659 service.Iterate(CNetService::eIncludePenalized); it; ++it) {
660 CNetServer server(it.GetServer());
661 unsigned ipv4 = server.GetHost();
662 string ipv4_str = CSocketAPI::ntoa(ipv4);
663 ipv4_column.AddCell(ipv4_str);
664 if (!IsOptionSet(eNoDNSLookup)) {
665 string hostname = CSocketAPI::gethostbyaddr(ipv4, eOff);
666 if (hostname.empty() || hostname == ipv4_str)
667 hostname = "***DNS lookup failed***";
668 else if (NStr::EndsWith(hostname, NCBI_DOMAIN))
669 hostname.erase(hostname.length() - (sizeof(NCBI_DOMAIN) - 1));
670 hostname_column.AddCell(hostname);
671 }
672 port_column.AddCell(NStr::UIntToString(server.GetPort()));
673 rating_column.AddCell(NStr::DoubleToString(it.GetRate(), 3));
674 }
675
676 for (unsigned row = 0; row < ipv4_column.GetHeight(); ++row) {
677 ipv4_column.PrintCell(row);
678 if (!IsOptionSet(eNoDNSLookup))
679 hostname_column.PrintCell(row);
680 port_column.PrintCell(row);
681 rating_column.PrintCell(row);
682 if (row == 0) {
683 ipv4_column.PrintRule();
684 if (!IsOptionSet(eNoDNSLookup))
685 hostname_column.PrintRule();
686 port_column.PrintRule();
687 rating_column.PrintRule();
688 }
689 }
690
691 return 0;
692 }
693
Cmd_Exec()694 int CGridCommandLineInterfaceApp::Cmd_Exec()
695 {
696 SetUp_AdminCmd(eAdminCmdWithSideEffects);
697
698 CNetService service;
699
700 switch (m_APIClass) {
701 case eNetCacheAdmin:
702 service = m_NetCacheAPI.GetService();
703 break;
704
705 case eNetScheduleAdmin:
706 service = m_NetScheduleAPI.GetService();
707 break;
708
709 default:
710 return 2;
711 }
712
713 if (m_Opts.output_format == eRaw)
714 service.PrintCmdOutput(m_Opts.command, NcbiCout,
715 IsOptionSet(eMultiline) ? CNetService::eMultilineOutput :
716 CNetService::eSingleLineOutput);
717 else // Output format is eJSON.
718 g_PrintJSON(stdout, g_ExecAnyCmdToJson(service,
719 m_Opts.command, IsOptionSet(eMultiline)));
720
721 return 0;
722 }
723