1 /* $Id: ns_automation.cpp 572261 2018-10-10 19:24:55Z 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: NetSchedule automation implementation.
29 *
30 */
31
32 #include <ncbi_pch.hpp>
33
34 #include "ns_automation.hpp"
35
36 USING_NCBI_SCOPE;
37
38 using namespace NAutomation;
39
40 const string SNetScheduleService::kName = "nssvc";
41 const string SNetScheduleServer::kName = "nssrv";
42
SNetScheduleService(CAutomationProc * automation_proc,CNetScheduleAPI ns_api)43 SNetScheduleService::SNetScheduleService(
44 CAutomationProc* automation_proc,
45 CNetScheduleAPI ns_api) :
46 SNetService(automation_proc),
47 m_NetScheduleAPI(ns_api)
48 {
49 auto warning_handler = [&](const string& m, CNetServer s) {
50 auto o = m_AutomationProc->ReturnNetScheduleServerObject(m_NetScheduleAPI, s);
51 m_AutomationProc->SendWarning(m, o);
52 return true;
53 };
54
55 GetService().SetWarningHandler(warning_handler);
56 }
57
SNetScheduleServer(CAutomationProc * automation_proc,CNetScheduleAPIExt ns_api,CNetServer::TInstance server)58 SNetScheduleServer::SNetScheduleServer(
59 CAutomationProc* automation_proc,
60 CNetScheduleAPIExt ns_api, CNetServer::TInstance server) :
61 SNetScheduleService(automation_proc, ns_api.GetServer(server))
62 {
63 if (GetService().IsLoadBalanced()) {
64 NCBI_THROW(CAutomationException, eCommandProcessingError,
65 "NetScheduleServer constructor: "
66 "'server_address' must be a host:port combination");
67 }
68 }
69
NewCommand()70 CCommand SNetScheduleService::NewCommand()
71 {
72 return CCommand(kName, ExecNew<TSelf>, {
73 { "service_name", "", },
74 { "queue_name", "", },
75 { "client_name", "", },
76 });
77 }
78
Create(const TArguments & args,CAutomationProc * automation_proc)79 CAutomationObject* SNetScheduleService::Create(const TArguments& args, CAutomationProc* automation_proc)
80 {
81 _ASSERT(args.size() == 3);
82
83 const auto service_name = args["service_name"].AsString();
84 const auto queue_name = args["queue_name"].AsString();
85 const auto client_name = args["client_name"].AsString();
86
87 CNetScheduleAPIExt ns_api(CNetScheduleAPIExt::CreateNoCfgLoad(
88 service_name, client_name, queue_name));
89
90 return new SNetScheduleService(automation_proc, ns_api);
91 }
92
NewCommand()93 CCommand SNetScheduleServer::NewCommand()
94 {
95 return CCommand(kName, ExecNew<TSelf>, {
96 { "service_name", "", },
97 { "queue_name", "", },
98 { "client_name", "", },
99 });
100 }
101
Create(const TArguments & args,CAutomationProc * automation_proc)102 CAutomationObject* SNetScheduleServer::Create(const TArguments& args, CAutomationProc* automation_proc)
103 {
104 _ASSERT(args.size() == 3);
105
106 const auto service_name = args["service_name"].AsString();
107 const auto queue_name = args["queue_name"].AsString();
108 const auto client_name = args["client_name"].AsString();
109
110 CNetScheduleAPIExt ns_api(CNetScheduleAPIExt::CreateNoCfgLoad(
111 service_name, client_name, queue_name));
112
113 CNetServer server = ns_api.GetService().Iterate().GetServer();
114 return new SNetScheduleServer(automation_proc, ns_api, server);
115 }
116
ReturnNetScheduleServerObject(CNetScheduleAPI::TInstance ns_api,CNetServer::TInstance server)117 TAutomationObjectRef CAutomationProc::ReturnNetScheduleServerObject(
118 CNetScheduleAPI::TInstance ns_api,
119 CNetServer::TInstance server)
120 {
121 TAutomationObjectRef object(new SNetScheduleServer(this, ns_api, server));
122 AddObject(object);
123 return object;
124 }
125
CallCommand()126 CCommand SNetScheduleServer::CallCommand()
127 {
128 return CCommand(kName, TCommandGroup(CallCommands(), CheckCall<TSelf>));
129 }
130
CallCommands()131 TCommands SNetScheduleServer::CallCommands()
132 {
133 TCommands cmds =
134 {
135 { "server_status", ExecMethod<TSelf, &TSelf::ExecServerStatus>, {
136 { "verbose", false, },
137 }},
138 { "job_group_info", ExecMethod<TSelf, &TSelf::ExecJobGroupInfo>, {
139 { "verbose", false, },
140 }},
141 { "client_info", ExecMethod<TSelf, &TSelf::ExecClientInfo>, {
142 { "verbose", false, },
143 }},
144 { "notification_info", ExecMethod<TSelf, &TSelf::ExecNotificationInfo>, {
145 { "verbose", false, },
146 }},
147 { "affinity_info", ExecMethod<TSelf, &TSelf::ExecAffinityInfo>, {
148 { "verbose", false, },
149 }},
150 { "change_preferred_affinities", ExecMethod<TSelf, &TSelf::ExecChangePreferredAffinities>, {
151 { "affs_to_add", CJsonNode::eArray, },
152 { "affs_to_del", CJsonNode::eArray, },
153 }},
154 };
155
156 TCommands base_cmds = SNetScheduleService::CallCommands();
157 cmds.insert(cmds.end(), base_cmds.begin(), base_cmds.end());
158
159 return cmds;
160 }
161
ExecServerStatus(const TArguments & args,SInputOutput & io)162 void SNetScheduleServer::ExecServerStatus(const TArguments& args, SInputOutput& io)
163 {
164 _ASSERT(args.size() == 1);
165
166 auto& reply = io.reply;
167 const auto verbose = args["verbose"].AsBoolean();
168 reply.Append(g_LegacyStatToJson(GetServer(), verbose));
169 }
170
ExecJobGroupInfo(const TArguments & args,SInputOutput & io)171 void SNetScheduleServer::ExecJobGroupInfo(const TArguments& args, SInputOutput& io)
172 {
173 _ASSERT(args.size() == 1);
174
175 auto& reply = io.reply;
176 const auto verbose = args["verbose"].AsBoolean();
177 reply.Append(g_GenericStatToJson(GetServer(), eNetScheduleStatJobGroups, verbose));
178 }
179
ExecClientInfo(const TArguments & args,SInputOutput & io)180 void SNetScheduleServer::ExecClientInfo(const TArguments& args, SInputOutput& io)
181 {
182 _ASSERT(args.size() == 1);
183
184 auto& reply = io.reply;
185 const auto verbose = args["verbose"].AsBoolean();
186 reply.Append(g_GenericStatToJson(GetServer(), eNetScheduleStatClients, verbose));
187 }
188
ExecNotificationInfo(const TArguments & args,SInputOutput & io)189 void SNetScheduleServer::ExecNotificationInfo(const TArguments& args, SInputOutput& io)
190 {
191 _ASSERT(args.size() == 1);
192
193 auto& reply = io.reply;
194 const auto verbose = args["verbose"].AsBoolean();
195 reply.Append(g_GenericStatToJson(GetServer(), eNetScheduleStatNotifications, verbose));
196 }
197
ExecAffinityInfo(const TArguments & args,SInputOutput & io)198 void SNetScheduleServer::ExecAffinityInfo(const TArguments& args, SInputOutput& io)
199 {
200 _ASSERT(args.size() == 1);
201
202 auto& reply = io.reply;
203 const auto verbose = args["verbose"].AsBoolean();
204 reply.Append(g_GenericStatToJson(GetServer(), eNetScheduleStatAffinities, verbose));
205 }
206
s_ExtractVectorOfStrings(CJsonNode & arg)207 vector<string> s_ExtractVectorOfStrings(CJsonNode& arg)
208 {
209 vector<string> result;
210
211 if (!arg.IsNull()) {
212 for (CJsonIterator it = arg.Iterate(); it; ++it) {
213 CArgument affinity("affinity", CJsonNode::eString);
214 affinity.Exec("change_preferred_affinities", it);
215 result.push_back(affinity.AsString());
216 }
217 }
218
219 return result;
220 }
221
ExecChangePreferredAffinities(const TArguments & args,SInputOutput &)222 void SNetScheduleServer::ExecChangePreferredAffinities(const TArguments& args, SInputOutput&)
223 {
224 _ASSERT(args.size() == 2);
225
226 auto affs_to_add = args["affs_to_add"].Value();
227 auto affs_to_del = args["affs_to_del"].Value();
228
229 auto to_add = s_ExtractVectorOfStrings(affs_to_add);
230 auto to_del = s_ExtractVectorOfStrings(affs_to_del);
231
232 m_NetScheduleAPI.GetExecutor().ChangePreferredAffinities(&to_add, &to_del);
233 }
234
CallCommand()235 CCommand SNetScheduleService::CallCommand()
236 {
237 return CCommand(kName, TCommandGroup(CallCommands(), CheckCall<TSelf>));
238 }
239
CallCommands()240 TCommands SNetScheduleService::CallCommands()
241 {
242 TCommands cmds =
243 {
244 { "set_client_type", ExecMethod<TSelf, &TSelf::ExecSetClientType>, {
245 { "client_type", 0, },
246 }},
247 { "set_node_session", ExecMethod<TSelf, &TSelf::ExecSetNodeSession>, {
248 { "node", "", },
249 { "session", "", },
250 }},
251 { "queue_info", ExecMethod<TSelf, &TSelf::ExecQueueInfo>, {
252 { "queue_name", "", },
253 }},
254 { "queue_class_info", ExecMethod<TSelf, &TSelf::ExecQueueClassInfo>, },
255 { "reconf", ExecMethod<TSelf, &TSelf::ExecReconf>, },
256 { "suspend", ExecMethod<TSelf, &TSelf::ExecSuspend>, {
257 { "pullback_mode", false, },
258 }},
259 { "resume", ExecMethod<TSelf, &TSelf::ExecResume>, },
260 { "shutdown", ExecMethod<TSelf, &TSelf::ExecShutdown>, {
261 { "do_not_drain", false, },
262 }},
263 { "parse_key", ExecMethod<TSelf, &TSelf::ExecParseKey>, {
264 { "job_key", CJsonNode::eString, },
265 }},
266 { "job_info", ExecMethod<TSelf, &TSelf::ExecJobInfo>, {
267 { "job_key", CJsonNode::eString, },
268 { "verbose", true, },
269 }},
270 { "job_counters", ExecMethod<TSelf, &TSelf::ExecJobCounters>, {
271 { "affinity", "", },
272 { "job_group", "", },
273 }},
274 { "get_servers", ExecMethod<TSelf, &TSelf::ExecGetServers>, },
275 };
276
277 TCommands base_cmds = SNetService::CallCommands();
278 cmds.insert(cmds.end(), base_cmds.begin(), base_cmds.end());
279
280 return cmds;
281 }
282
ExecSetClientType(const TArguments & args,SInputOutput &)283 void SNetScheduleService::ExecSetClientType(const TArguments& args, SInputOutput&)
284 {
285 _ASSERT(args.size() == 1);
286
287 const auto client_type = args["client_type"].AsInteger<CNetScheduleAPI::EClientType>();
288 m_NetScheduleAPI.SetClientType(client_type);
289 }
290
ExecSetNodeSession(const TArguments & args,SInputOutput &)291 void SNetScheduleService::ExecSetNodeSession(const TArguments& args, SInputOutput&)
292 {
293 _ASSERT(args.size() == 2);
294
295 const auto node = args["node"].AsString();
296 const auto session = args["session"].AsString();
297 m_NetScheduleAPI.ReSetClientNode(node);
298 m_NetScheduleAPI.ReSetClientSession(session);
299 }
300
ExecQueueInfo(const TArguments & args,SInputOutput & io)301 void SNetScheduleService::ExecQueueInfo(const TArguments& args, SInputOutput& io)
302 {
303 _ASSERT(args.size() == 1);
304
305 auto& reply = io.reply;
306 const auto queue_name = args["queue_name"].AsString();
307 reply.Append(g_QueueInfoToJson(m_NetScheduleAPI, queue_name));
308 }
309
ExecQueueClassInfo(const TArguments &,SInputOutput & io)310 void SNetScheduleService::ExecQueueClassInfo(const TArguments&, SInputOutput& io)
311 {
312 auto& reply = io.reply;
313 reply.Append(g_QueueClassInfoToJson(m_NetScheduleAPI));
314 }
315
ExecReconf(const TArguments &,SInputOutput & io)316 void SNetScheduleService::ExecReconf(const TArguments&, SInputOutput& io)
317 {
318 auto& reply = io.reply;
319 reply.Append(g_ReconfAndReturnJson(m_NetScheduleAPI));
320 }
321
ExecSuspend(const TArguments & args,SInputOutput &)322 void SNetScheduleService::ExecSuspend(const TArguments& args, SInputOutput&)
323 {
324 _ASSERT(args.size() == 1);
325
326 const auto pullback_mode = args["pullback_mode"].AsBoolean();
327 g_SuspendNetSchedule(m_NetScheduleAPI, pullback_mode);
328 }
329
ExecResume(const TArguments &,SInputOutput &)330 void SNetScheduleService::ExecResume(const TArguments&, SInputOutput&)
331 {
332 g_ResumeNetSchedule(m_NetScheduleAPI);
333 }
334
ExecShutdown(const TArguments & args,SInputOutput &)335 void SNetScheduleService::ExecShutdown(const TArguments& args, SInputOutput&)
336 {
337 _ASSERT(args.size() == 1);
338
339 const auto do_not_drain = args["do_not_drain"].AsBoolean();
340 auto level = do_not_drain ? CNetScheduleAdmin::eNormalShutdown : CNetScheduleAdmin::eDrain;
341 m_NetScheduleAPI.GetAdmin().ShutdownServer(level);
342 }
343
ExecParseKey(const TArguments & args,SInputOutput & io)344 void SNetScheduleService::ExecParseKey(const TArguments& args, SInputOutput& io)
345 {
346 _ASSERT(args.size() == 1);
347
348 auto& reply = io.reply;
349 const auto job_key = args["job_key"].AsString();
350 CJobInfoToJSON job_key_to_json;
351 job_key_to_json.ProcessJobMeta(CNetScheduleKey(job_key, m_NetScheduleAPI.GetCompoundIDPool()));
352 reply.Append(job_key_to_json.GetRootNode());
353 }
354
ExecJobInfo(const TArguments & args,SInputOutput & io)355 void SNetScheduleService::ExecJobInfo(const TArguments& args, SInputOutput& io)
356 {
357 _ASSERT(args.size() == 2);
358
359 auto& reply = io.reply;
360 const auto job_key = args["job_key"].AsString();
361 const auto verbose = args["verbose"].AsBoolean();
362 CJobInfoToJSON job_info_to_json;
363 g_ProcessJobInfo(m_NetScheduleAPI, job_key, &job_info_to_json, verbose, m_NetScheduleAPI.GetCompoundIDPool());
364 reply.Append(job_info_to_json.GetRootNode());
365 }
366
ExecJobCounters(const TArguments & args,SInputOutput & io)367 void SNetScheduleService::ExecJobCounters(const TArguments& args, SInputOutput& io)
368 {
369 _ASSERT(args.size() == 2);
370
371 auto& reply = io.reply;
372 const auto affinity = args["affinity"].AsString();
373 const auto job_group = args["job_group"].AsString();
374 CNetScheduleAdmin::TStatusMap status_map;
375 m_NetScheduleAPI.GetAdmin().StatusSnapshot(status_map, affinity, job_group);
376 CJsonNode jobs_by_status(CJsonNode::NewObjectNode());
377
378 ITERATE(CNetScheduleAdmin::TStatusMap, it, status_map) {
379 jobs_by_status.SetInteger(it->first, it->second);
380 }
381 reply.Append(jobs_by_status);
382 }
383
ExecGetServers(const TArguments &,SInputOutput & io)384 void SNetScheduleService::ExecGetServers(const TArguments&, SInputOutput& io)
385 {
386 auto& reply = io.reply;
387
388 CJsonNode object_ids(CJsonNode::NewArrayNode());
389 for (CNetServiceIterator it = m_NetScheduleAPI.GetService().Iterate(
390 CNetService::eIncludePenalized); it; ++it)
391 object_ids.AppendInteger(m_AutomationProc->
392 ReturnNetScheduleServerObject(m_NetScheduleAPI, *it)->
393 GetID());
394 reply.Append(object_ids);
395 }
396