Coverage for /home/agp/Documents/me/code/gutools/gutools/controllers/session.py : 0%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import os
2import random
3import time
4import sys
5import psutil
6from logging import debug, warn, error
8from cement import App, Controller, ex
10from gutools.controllers.arguments import *
11from gutools.tools import update_context, _call, prepare_call, expandpath
12from gutools.tools import parse_uri
13from gutools.system import get_fingerprint, test_alive
14from gutools.session import USession, UProcess, codenamize
15from gutools.bash_completer import CompletableController, find_process_by_cmdline
17class SessionController(CompletableController):
18 handled_uris = ['session', 'exec']
19 class Meta:
20 label = 'session'
21 stacked_on = 'base'
22 stacked_type = 'nested'
23 description = 'session manager'
24 arguments = []
25 hide = False
27 @classmethod
28 def can_handle(cls, uri):
29 uri_ = parse_uri(uri)
30 return uri_['scheme'] in cls.handled_uris
32 def __init__(self, *args, **kw):
33 super().__init__(*args, **kw)
35 # add custom expansor from some commands
36 self._add_expander('stop', 'pid', self._exp_from_db)
37 self._add_expander('stop', 'name', self._exp_from_db)
40 @ex(arguments=[ARGS, PATH], help='Init a session')
41 def init(self):
42 """Create a session in curent folder."""
43 pargs = self.app.pargs
44 data = {
45 'foo' : 'bar',
46 }
47 pargs.path = pargs.path or (pargs.args and pargs.args[0]) or expandpath(os.path.curdir)
48 update_context(data, self.app.pargs)
49 session = _call(USession, **data)
50 session.init()
52 update_context(data, session)
53 self.app.render(data, 'session.init.jinja2')
55 @ex(arguments=[ARGS, PATH], help='activate a session')
56 def activate(self):
57 """Activate session"""
58 pargs = self.app.pargs
59 data = {
60 'foo' : 'bar',
61 }
62 pargs.path = pargs.path or (pargs.args and pargs.args[0]) or expandpath(os.path.curdir)
63 update_context(data, self.app.pargs)
64 session = _call(USession, **data)
66 self.app.render(data, 'default.jinja2')
68 session.activate()
70 @ex(arguments=[ARGS, PATH], help='deactivate a session')
71 def deactivate(self):
72 """Deactivate running session"""
73 pargs = self.app.pargs
74 data = {
75 'foo' : 'bar',
76 }
77 pargs.path = pargs.path or (pargs.args and pargs.args[0]) or expandpath(os.path.curdir)
78 update_context(data, pargs)
79 session = _call(USession, **data)
80 # TODO: isolate session daemon task in Controllers or Session
81 # TODO: it seems has more sense in Session as gather all info in fodler
82 self.app.render(data, 'default.jinja2')
84 session.deactivate()
88 @ex()
89 def status(self):
90 """Show session status."""
91 data = {
92 'foo' : 'bar',
93 }
94 self.app.render(data, 'session.status.jinja2')
96 @ex()
97 def list(self):
98 """Show session status."""
99 pargs = self.app.pargs
100 data = {
101 'path' : '.',
102 }
103 update_context(data, self.app.pargs)
105 session = _call(USession, **data)
106 results = list(session.workspace.find_process())
107 data['results'] = results
109 self.app.render(data, 'session.list.jinja2')
111 foo = 1
113 @ex()
114 def exit(self):
115 """Show session status."""
116 data = {
117 'foo' : 'bar',
118 }
119 self.app.render(data, 'session.exit.jinja2')
122 @ex(arguments=[URI, NAME, ALIAS, RESTART, SHUTDOWN])
123 def start(self):
124 """Start a subnode task based on uri.
125 Example:
127 $ atlas session start --uri "exec://localhost/home/agp/Jts/tws?username=myuser&password=mypassword" --alias master.tws --restart 1 --shutdown 1
128 $ atlas session start --uri=atlas://localhost:9090
129 $ atlas session start --uri=ib://localhost:7496?account=DU123456
131 You need to enclose in "" if any parameter contains characteres like:
133 &,
135 atlas session start --uri "ib://sync:9090?master&account=1" --alias
136 """
137 pargs = self.app.pargs
138 data = {
139 'path' : '.',
140 }
141 update_context(data, pargs)
143 session = _call(USession, **data)
144 self.app.render(data, 'session.start.jinja2')
145 if self.can_handle(pargs.uri):
146 uri = parse_uri(pargs.uri)
147 if uri['scheme'] in ('exec', ):
148 session._launch_process(**data)
149 else:
150 assert uri['scheme'] in ('session', )
151 pass
152 else:
153 self._delegate_controller_dispatch()
155 print('-End-2-')
157 @ex(arguments=[ARGS, URI, NAME])
158 def stop(self):
159 """Stop a subnode task.
160 Example:
162 atlas stop --uri=atlas://localhost:9090
163 atlas stop --name=atlas://localhost:9090
165 """
166 pargs = self.app.pargs
167 data = {
168 'path' : '.',
169 }
170 pargs.name = pargs.name or pargs.args[0]
171 update_context(data, self.app.pargs)
173 session = _call(USession, **data)
174 self.app.render(data, 'default.jinja2')
176 context = session.stop(**data)
178 @ex(arguments=[ARGS, URI, PID, NAME, ALIAS, TIMEOUT, CONDITION])
179 def wait(self):
180 """Wait until a condition over a process is true.
181 Example:
183 atlas session wait --alias master.tws --condition "len(fp['listen'])>0 --timeout 60"
185 """
186 pargs = self.app.pargs
187 data = {
188 'path': '.',
189 }
190 update_context(data, pargs)
191 session = _call(USession, **data)
193 timeout = pargs.timeout or 0
194 t1 = time.time() + timeout
196 while timeout <= 0 or time.time() < t1:
197 try:
198 score, proc, state, fp = session.locate_process(**data)
199 update_context(data, fp=fp, proc=proc, state=state)
201 result = eval(pargs.condition, data, data)
202 if result:
203 break
204 except Exception as why:
205 print(f"{RED}{why}{RESET}")
206 time.sleep(1)
207 else:
208 raise TimeoutError(f"waiting for {pargs.condition}")
210 foo = 1
212 @ex(arguments=[ARGS, PATH], help='deactivate a session')
213 def random_process(self):
214 """Deactivate running session"""
215 pargs = self.app.pargs
216 data = {
217 'foo' : 'bar',
218 }
219 pargs.path = pargs.path or (pargs.args and pargs.args[0]) or expandpath(os.path.curdir)
220 update_context(data, self.app.pargs)
221 session = _call(USession, **data)
223 n = random.randint(100, 2000)
224 uri = f'session://random?n={n}'
225 self.app.render(data, 'default.jinja2')
227 session.start(
228 target=session._demo_task,
229 uri=uri,
230 n=n)
235 def _delegate_controller_dispatch(self):
236 pargs = self.app.pargs
237 for c in self._available_session_controllers():
238 print(c)
239 if c.can_handle(pargs.uri):
240 funcname = sys._getframe(1).f_code.co_name
241 func = getattr(c, funcname)
242 func()
243 foo = 1
245 def _exp_from_db(self, attr):
246 "Expand attrs from session database"
247 candidates = set([])
249 path = '.'
250 session = _call(USession, path=path)
251 candidates = set([])
252 for process in session.workspace.find_process():
253 if process.pid is None:
254 continue
255 value = getattr(process, attr, '')
256 if value.startswith(partial):
257 candidates.add(value.lstrip(prefix))
259 return candidates
261 def _available_session_controllers(self):
262 for c in self.app.controller._controllers:
263 if isinstance(c, self.__class__) and c != self:
264 yield c
266 # @ex(arguments=[NAME])
267 # def launch_process(self):
268 # """Launch a previous captured process"""
269 # pargs = self.app.pargs
270 # data = {
271 # 'path' : '.',
272 # }
273 # update_context(data, self.app.pargs)
275 # session = _call(USession, **data)
277 # result, proc, fp = session.launch_process(name=pargs.name)
279 # update_context(data, fp, result=result, proc=proc)
280 # self.app.render(data, 'session.launch-process.jinja2')
282 @ex(arguments=[PID, URI, CMDLINE, ALIAS, STATE, RESTART, SHUTDOWN])
283 def attach(self):
284 pargs = self.app.pargs
285 data = {
286 'path' : '.',
287 }
288 update_context(data, self.app.pargs)
289 if pargs.pid:
290 assert not pargs.uri
291 assert not pargs.cmdline
292 proc = psutil.Process(pargs.pid)
293 update_context(data, proc=proc)
295 elif pargs.cmdline:
296 assert not pargs.uri
297 assert not pargs.pid
298 proc = find_process_by_cmdline(pargs.cmdline)
299 lproc = len(proc)
300 if lproc > 1:
301 print(f"too many matching processes ({lproc})")
302 elif lproc < 1:
303 print(f"process not found")
304 else:
305 proc = proc.pop()
306 update_context(data, proc=proc)
308 elif pargs.uri:
309 assert not pargs.pid
310 assert not pargs.cmdline
311 data['cmdline'] = sys.argv
313 session = _call(USession, **data)
314 info = _call(session.attach, **data)
315 update_context(data, info)
316 # self.app.render(data, 'session.attach-process.jinja2')
318 foo = 1
321 @ex(arguments=[PID, CMDLINE, ALIAS, LABEL])
322 def fooo(self):
323 pargs = self.app.pargs
324 data = {
325 'path' : '.',
326 }
327 import uuid
328 update_context(data, self.app.pargs)
329 node = uuid.getnode()
330 foo = 1
333class SessionDependenceController(CompletableController):
334 class Meta:
335 label = 'dependence'
336 stacked_on = 'session'
337 stacked_type = 'nested'
338 description = 'session dependence manager'
339 arguments = []
340 hide = False
342 @ex(arguments=[PARENT, CHILD, ])
343 def add(self):
344 """Add a process dependence within session
345 Example:
347 atlas session dependence add --parent foo --child bar
348 """
349 pargs = self.app.pargs
350 data = {
351 'path' : '.',
352 }
353 pargs.path = expandpath(os.path.curdir)
354 update_context(data, self.app.pargs)
355 session = _call(USession, **data)
357 session.add_dependence(pargs.parent, pargs.child)
359 self.app.render(data, 'default.jinja2')
362 @ex(arguments=[PARENT, CHILD, ])
363 def remove(self):
364 """Remove a process dependence within session
365 Example:
367 atlas session dependence remove --parent foo --child bar
368 """
369 pargs = self.app.pargs
370 data = {
371 'path' : '.',
372 }
373 pargs.path = expandpath(os.path.curdir)
374 update_context(data, self.app.pargs)
375 session = _call(USession, **data)
377 session.remove_dependence(pargs.parent, pargs.child)
379 self.app.render(data, 'default.jinja2')