1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 """\
21 X2goControlSessionSTDOUT class - core functions for handling your individual X2go sessions.
22
23 This backend handles X2go server implementations that respond via server-side STDOUT.
24
25 """
26 __NAME__ = 'x2gocontrolsession-pylib'
27
28
29 import os
30 import types
31 import paramiko
32 import gevent
33
34 import copy
35 import binascii
36
37 import string
38 import random
39
40
41 import x2go.sshproxy as sshproxy
42 import x2go.log as log
43 import x2go.utils as utils
44 import x2go.x2go_exceptions as x2go_exceptions
45 import x2go.defaults as defaults
46 import x2go.checkhosts as checkhosts
47
48 from x2go.backends.terminal import X2goTerminalSession as _X2goTerminalSession
49 from x2go.backends.info import X2goServerSessionInfo as _X2goServerSessionInfo
50 from x2go.backends.info import X2goServerSessionList as _X2goServerSessionList
51 from x2go.backends.proxy import X2goProxy as _X2goProxy
54
55 if cmd:
56 cmd = cmd.replace("X2GO_SPACE_CHAR", " ")
57 return cmd
58
60
61
62
63 if cmd and user:
64 cmd = cmd.replace('X2GO_USER', user)
65
66
67 if cmd and password:
68 cmd = cmd.replace('X2GO_PASSWORD', password)
69 return cmd
70
73 """\
74 STILL UNDOCUMENTED
75
76 @param logger: you can pass an L{X2goLogger} object to the
77 L{X2goControlSessionSTDOUT} constructor
78 @type logger: L{X2goLogger} instance
79 @param loglevel: if no L{X2goLogger} object has been supplied a new one will be
80 constructed with the given loglevel
81 @type loglevel: int
82
83 """
84 associated_terminals = None
85
86 - def __init__(self,
87 profile_name='UNKNOWN',
88 add_to_known_hosts=False,
89 known_hosts=None,
90 terminal_backend=_X2goTerminalSession,
91 info_backend=_X2goServerSessionInfo,
92 list_backend=_X2goServerSessionList,
93 proxy_backend=_X2goProxy,
94 client_rootdir=os.path.join(defaults.LOCAL_HOME, defaults.X2GO_CLIENT_ROOTDIR),
95 sessions_rootdir=os.path.join(defaults.LOCAL_HOME, defaults.X2GO_SESSIONS_ROOTDIR),
96 ssh_rootdir=os.path.join(defaults.LOCAL_HOME, defaults.X2GO_SSH_ROOTDIR),
97 logger=None, loglevel=log.loglevel_DEFAULT,
98 *args, **kwargs):
99 """\
100 Initialize an X2go session. With the L{X2goControlSessionSTDOUT} class you can start
101 new X2go sessions, resume suspended sessions or suspend resp. terminate
102 currently running sessions on a connected X2go server.
103
104 """
105 self.associated_terminals = {}
106 self.terminated_terminals = []
107
108 self.profile_name = profile_name
109 self.add_to_known_hosts = add_to_known_hosts
110 self.known_hosts = known_hosts
111
112 self.hostname = None
113 self.port = None
114
115 self.sshproxy_session = None
116
117 self._session_auth_rsakey = None
118 self._remote_home = None
119 self._remote_group = {}
120
121 self.locked = False
122
123 if logger is None:
124 self.logger = log.X2goLogger(loglevel=loglevel)
125 else:
126 self.logger = copy.deepcopy(logger)
127 self.logger.tag = __NAME__
128
129 self._terminal_backend = terminal_backend
130 self._info_backend = info_backend
131 self._list_backend = list_backend
132 self._proxy_backend = proxy_backend
133
134 self.client_rootdir = client_rootdir
135 self.sessions_rootdir = sessions_rootdir
136 self.ssh_rootdir = ssh_rootdir
137
138 paramiko.SSHClient.__init__(self, *args, **kwargs)
139 if self.add_to_known_hosts:
140 self.set_missing_host_key_policy(paramiko.AutoAddPolicy())
141
142 self.session_died = False
143
145 if self.known_hosts is not None:
146 utils.touch_file(self.known_hosts)
147 self.load_host_keys(self.known_hosts)
148
152
154
155 self.logger('sFTP-put: %s -> %s:%s' % (os.path.normpath(local_path), self.get_transport().getpeername(), remote_path), loglevel=log.loglevel_DEBUG)
156 self.sftp_client.put(os.path.normpath(local_path), remote_path)
157
159
160 self.logger('sFTP-write: opening remote file %s on host %s for writing' % (remote_path, self.get_transport().getpeername()), loglevel=log.loglevel_DEBUG)
161 remote_fileobj = self.sftp_client.open(remote_path, 'w')
162 self.logger('sFTP-write: writing content: %s' % content, loglevel=log.loglevel_DEBUG_SFTPXFER)
163 remote_fileobj.write(content)
164 remote_fileobj.close()
165
167
168 self.logger('sFTP-write: removing remote file %s on host %s' % (remote_path, self.get_transport().getpeername()), loglevel=log.loglevel_DEBUG)
169 self.sftp_client.remove(remote_path)
170
172
173 while self.locked:
174 gevent.sleep(.1)
175
176 self.locked = True
177 _retval = None
178
179 if type(cmd_line) == types.ListType:
180 cmd = " ".join(cmd_line)
181 else:
182 cmd = cmd_line
183 if self.get_transport() is not None:
184
185 timeout = gevent.Timeout(20)
186 timeout.start()
187 try:
188 self.logger("executing command on X2go server ,,%s'': %s" % (self.profile_name, _rerewrite_blanks(cmd)), loglevel)
189 _retval = self.exec_command(_rewrite_password(cmd, user=self.get_transport().get_username(), password=self._session_password), **kwargs)
190 except AttributeError:
191 self.session_died = True
192 if self.sshproxy_session:
193 self.sshproxy_session.stop_thread()
194 self.locked = False
195 raise x2go_exceptions.X2goControlSessionException('the X2go control session has died unexpectedly')
196 except EOFError:
197 self.session_died = True
198 if self.sshproxy_session:
199 self.sshproxy_session.stop_thread()
200 self.locked = False
201 raise x2go_exceptions.X2goControlSessionException('the X2go control session has died unexpectedly')
202 except x2go_exceptions.SSHException:
203 self.session_died = True
204 if self.sshproxy_session:
205 self.sshproxy_session.stop_thread()
206 self.locked = False
207 raise x2go_exceptions.X2goControlSessionException('the X2go control session has died unexpectedly')
208 except gevent.timeout.Timeout:
209 self.session_died = True
210 if self.sshproxy_session:
211 self.sshproxy_session.stop_thread()
212 self.locked = False
213 raise x2go_exceptions.X2goControlSessionException('the X2go control session command timed out')
214 finally:
215 self.locked = False
216 timeout.cancel()
217
218 else:
219 self.locked = False
220 raise x2go_exceptions.X2goControlSessionException('the X2go control session is not connected')
221 return _retval
222
223 @property
225
226 if self._remote_home is None:
227 (stdin, stdout, stderr) = self._x2go_exec_command('echo $HOME')
228 self._remote_home = stdout.read().split()[0]
229 self.logger('remote user\' home directory: %s' % self._remote_home, loglevel=log.loglevel_DEBUG)
230 return self._remote_home
231 else:
232 return self._remote_home
233
235
236 if not self._remote_group.has_key(group):
237 (stdin, stdout, stderr) = self._x2go_exec_command('getent group %s | cut -d":" -f4' % group)
238 self._remote_group[group] = stdout.read().split('\n')[0].split(',')
239 self.logger('remote %s group: %s' % (group, self._remote_group[group]), loglevel=log.loglevel_DEBUG)
240 return self._remote_group[group]
241 else:
242 return self._remote_group[group]
243
245
246
247
248
249
250
251 return True
252
254 """\
255 Returns the control session's remote username.
256
257 """
258 if self.get_transport() is not None:
259 return self.get_transport().get_username()
260 else:
261 return None
262
263 @property
265 if self._session_auth_rsakey is None:
266 self._session_auth_rsakey = paramiko.RSAKey.generate(defaults.RSAKEY_STRENGTH)
267 return self._session_auth_rsakey
268
270 self.profile_name = profile_name
271
278
279 - def connect(self, hostname, port=22, username='', password='', pkey=None,
280 use_sshproxy=False, sshproxy_host='', sshproxy_user='', sshproxy_password='',
281 sshproxy_key_filename='', sshproxy_tunnel='',
282 key_filename=None, timeout=None, allow_agent=False, look_for_keys=False,
283 session_instance=None,
284 add_to_known_hosts=False, force_password_auth=False):
285 """\
286 Connect to an X2go server and authenticate to it. This method is directly
287 inherited from the paramiko.SSHClient module. The features of the Paramiko
288 SSH client connect method are recited here. The parameters C{add_to_known_hosts}
289 and C{force_password_auth} have been added as a parameter for X2go.
290
291 The server's host key
292 is checked against the system host keys (see C{load_system_host_keys})
293 and any local host keys (C{load_host_keys}). If the server's hostname
294 is not found in either set of host keys, the missing host key policy
295 is used (see C{set_missing_host_key_policy}). The default policy is
296 to reject the key and raise an C{SSHException}.
297
298 Authentication is attempted in the following order of priority:
299
300 - The C{pkey} or C{key_filename} passed in (if any)
301 - Any key we can find through an SSH agent
302 - Any "id_rsa" or "id_dsa" key discoverable in C{~/.ssh/}
303 - Plain username/password auth, if a password was given
304
305 If a private key requires a password to unlock it, and a password is
306 passed in, that password will be used to attempt to unlock the key.
307
308 @param hostname: the server to connect to
309 @type hostname: str
310 @param port: the server port to connect to
311 @type port: int
312 @param username: the username to authenticate as (defaults to the
313 current local username)
314 @type username: str
315 @param password: a password to use for authentication or for unlocking
316 a private key
317 @type password: str
318 @param pkey: an optional private key to use for authentication
319 @type pkey: C{PKey}
320 @param key_filename: the filename, or list of filenames, of optional
321 private key(s) to try for authentication
322 @type key_filename: str or list(str)
323 @param timeout: an optional timeout (in seconds) for the TCP connect
324 @type timeout: float
325 @param allow_agent: set to False to disable connecting to the SSH agent
326 @type allow_agent: C{bool}
327 @param look_for_keys: set to False to disable searching for discoverable
328 private key files in C{~/.ssh/}
329 @type look_for_keys: C{bool}
330 @param add_to_known_hosts: non-paramiko option, if C{True} paramiko.AutoAddPolicy()
331 is used as missing-host-key-policy. If set to C{False} paramiko.RejectPolicy()
332 is used
333 @type add_to_known_hosts: C{bool}
334 @param force_password_auth: non-paramiko option, disable pub/priv key authentication
335 completely, even if the C{pkey} or the C{key_filename} parameter is given
336 @type force_password_auth: C{bool}
337 @param session_instance: an instance L{X2goSession} using this L{X2goControlSessionSTDOUT}
338 instance.
339 @type session_instance: C{instance}
340
341 @raise BadHostKeyException: if the server's host key could not be
342 verified
343 @raise AuthenticationException: if authentication failed
344 @raise SSHException: if there was any other error connecting or
345 establishing an SSH session
346 @raise socket.error: if a socket error occurred while connecting
347
348 """
349 if use_sshproxy and sshproxy_host and sshproxy_user:
350 try:
351 self.sshproxy_session = sshproxy.X2goSSHProxy(known_hosts=self.known_hosts,
352 sshproxy_host=sshproxy_host,
353 sshproxy_user=sshproxy_user,
354 sshproxy_password=sshproxy_password,
355 sshproxy_key_filename=sshproxy_key_filename,
356 sshproxy_tunnel=sshproxy_tunnel,
357 session_instance=session_instance,
358 logger=self.logger,
359 )
360
361 except:
362 if self.sshproxy_session:
363 self.sshproxy_session.stop_thread()
364 self.sshproxy_session = None
365 raise
366
367 if self.sshproxy_session is not None:
368 self.sshproxy_session.start()
369
370
371
372 gevent.sleep(.1)
373 port = self.sshproxy_session.get_local_proxy_port()
374
375 if not add_to_known_hosts and session_instance:
376 self.set_missing_host_key_policy(checkhosts.X2goInteractiveAddPolicy(caller=self, session_instance=session_instance))
377
378 if add_to_known_hosts:
379 self.set_missing_host_key_policy(paramiko.AutoAddPolicy())
380
381
382 if force_password_auth:
383 key_filename = None
384 pkey = None
385
386 self.logger('connecting to [%s]:%s' % (hostname, port), loglevel=log.loglevel_NOTICE)
387
388 self.load_session_host_keys()
389
390 _hostname = hostname
391
392 if _hostname == 'localhost':
393 _hostname = '127.0.0.1'
394
395 if (key_filename and os.path.exists(os.path.normpath(key_filename))) or pkey:
396 try:
397 self.logger('trying SSH pub/priv key authentication with server', loglevel=log.loglevel_DEBUG)
398 paramiko.SSHClient.connect(self, _hostname, port=port, username=username, pkey=pkey,
399 key_filename=key_filename, timeout=timeout, allow_agent=allow_agent,
400 look_for_keys=look_for_keys)
401
402 except paramiko.AuthenticationException, e:
403 self.close()
404 if password:
405 self.logger('next auth mechanism we\'ll try is keyboard-interactive authentication', loglevel=log.loglevel_DEBUG)
406 try:
407 paramiko.SSHClient.connect(self, _hostname, port=port, username=username, password=password,
408 timeout=timeout, allow_agent=allow_agent,
409 look_for_keys=look_for_keys)
410 except paramiko.AuthenticationException, e:
411 self.close()
412 if self.sshproxy_session:
413 self.sshproxy_session.stop_thread()
414 raise e
415 except:
416 self.close()
417 if self.sshproxy_session:
418 self.sshproxy_session.stop_thread()
419 raise
420 else:
421 self.close()
422 if self.sshproxy_session:
423 self.sshproxy_session.stop_thread()
424 raise(e)
425
426 except:
427 self.close()
428 if self.sshproxy_session:
429 self.sshproxy_session.stop_thread()
430 raise
431
432
433 else:
434
435 if not password:
436 password = "".join([random.choice(string.letters+string.digits) for x in range(1, 20)])
437 self.logger('performing SSH keyboard-interactive authentication with server', loglevel=log.loglevel_DEBUG)
438 try:
439 paramiko.SSHClient.connect(self, _hostname, port=port, username=username, password=password,
440 timeout=timeout, allow_agent=allow_agent, look_for_keys=look_for_keys)
441 except paramiko.AuthenticationException, e:
442 self.close()
443 if self.sshproxy_session:
444 self.sshproxy_session.stop_thread()
445 raise e
446 except:
447 self.close()
448 if self.sshproxy_session:
449 self.sshproxy_session.stop_thread()
450 raise
451
452 self.set_missing_host_key_policy(paramiko.RejectPolicy())
453
454 self.hostname = hostname
455 self.port = port
456
457
458 try:
459 self.sftp_client = self.open_sftp()
460 except:
461 raise x2go_exceptions.X2goControlSessionException('could not invoke server-side SFTP subsystem')
462
463
464 ssh_transport = self.get_transport()
465 ssh_transport.reverse_tunnels = {}
466
467
468 ssh_transport._x2go_session_marker = True
469 self._session_password = password
470
471 if self.get_transport():
472 self.session_died = False
473 return (self.get_transport() is not None)
474
485
525
526
528 if self._x2go_exec_command('echo', loglevel=log.loglevel_DEBUG):
529 return True
530 return False
531
532 - def start(self, **kwargs):
533 """\
534 Start a new X2go session.
535
536 The L{X2goControlSessionSTDOUT.start()} method accepts any parameter
537 that can be passed to any of the C{X2goTerminalSession} backend class
538 constructors.
539
540 """
541 return self.resume(**kwargs)
542
543 - def resume(self, session_name=None, session_instance=None, **kwargs):
544 """\
545 Resume a running/suspended X2go session.
546
547 The L{X2goControlSessionSTDOUT.resume()} method accepts any parameter
548 that can be passed to any of the C{X2goTerminalSession} backend class constructors.
549
550 @return: True if the session could be successfully resumed
551 @rtype: C{bool}
552
553 """
554 if not self.is_x2gouser(self.get_transport().get_username()):
555 raise x2go_exceptions.X2goUserException('remote user %s is not allowed to run X2go commands' % self.get_transport().get_username())
556
557 if session_name is not None:
558 session_info = self.list_sessions()[session_name]
559 else:
560 session_info = None
561
562 _terminal = self._terminal_backend(self,
563 profile_name=self.profile_name,
564 session_info=session_info,
565 info_backend=self._info_backend,
566 list_backend=self._list_backend,
567 proxy_backend=self._proxy_backend,
568 client_rootdir=self.client_rootdir,
569 session_instance=session_instance,
570 sessions_rootdir=self.sessions_rootdir,
571 **kwargs)
572
573 _success = False
574 if session_name is not None:
575 try:
576 _success = _terminal.resume()
577 except x2go_exceptions.X2goFwTunnelException:
578 pass
579
580 else:
581 try:
582 _success = _terminal.start()
583 except x2go_exceptions.X2goFwTunnelException:
584 pass
585
586 if _success:
587 while not _terminal.ok():
588 gevent.sleep(.2)
589
590 if _terminal.ok():
591 self.associated_terminals[_terminal.get_session_name()] = _terminal
592 self.get_transport().reverse_tunnels[_terminal.get_session_name()] = {
593 'sshfs': (0, None),
594 'snd': (0, None),
595 }
596
597 return _terminal or None
598
599 return None
600
601 - def share_desktop(self, desktop=None, user=None, display=None, share_mode=0, **kwargs):
602 """\
603 Share another already running desktop session. Desktop sharing can be run
604 in two different modes: view-only and full-access mode.
605
606 @param desktop: desktop ID of a sharable desktop in format <user>@<display>
607 @type desktop: C{str}
608 @param user: user name and display number can be given separately, here give the
609 name of the user who wants to share a session with you.
610 @type user: C{str}
611 @param display: user name and display number can be given separately, here give the
612 number of the display that a user allows you to be shared with.
613 @type display: C{str}
614 @param share_mode: desktop sharing mode, 0 is VIEW-ONLY, 1 is FULL-ACCESS.
615 @type share_mode: C{int}
616
617 @return: True if the session could be successfully shared.
618 @rtype: C{bool}
619
620 """
621 if desktop:
622 user = desktop.split('@')[0]
623 display = desktop.split('@')[1]
624 if not (user and display):
625 raise x2go_exceptions.X2goDesktopSharingException('Need user name and display number of sharable desktop.')
626
627 cmd = '%sXSHAD%sXSHAD%s' % (share_mode, user, display)
628
629 kwargs['cmd'] = cmd
630 kwargs['session_type'] = 'shared'
631
632 return self.start(**kwargs)
633
635 """\
636 List all desktop-like sessions of current user (or of users that have
637 granted desktop sharing) on the connected server.
638
639 @param raw: if C{True}, the raw output of the server-side X2go command
640 C{x2godesktopsharing} is returned.
641 @type raw: C{bool}
642
643 @return: a list of X2go desktops available for sharing
644 @rtype: C{list}
645
646 """
647 if raw:
648 (stdin, stdout, stderr) = self._x2go_exec_command("export HOSTNAME && x2golistdesktops")
649 return stdout.read(), stderr.read()
650
651 else:
652
653
654
655
656 timeout = gevent.Timeout(maxwait)
657 timeout.start()
658 try:
659 (stdin, stdout, stderr) = self._x2go_exec_command("export HOSTNAME && x2golistdesktops")
660 _stdout_read = stdout.read()
661 _listdesktops = _stdout_read.split('\n')
662 except gevent.timeout.Timeout:
663
664
665
666 raise x2go_exceptions.X2goTimeOutException('x2golistdesktop command timed out')
667 finally:
668 timeout.cancel()
669
670 return _listdesktops
671
673 """\
674 List all sessions of current user on the connected server.
675
676 @param raw: if C{True}, the raw output of the server-side X2go command
677 C{x2golistsessions} is returned.
678 @type raw: C{bool}
679
680 @return: normally an instance of a C{X2goServerSessionList} backend Bis returned. However,
681 if the raw argument is set, the plain text output of the x2golistsessions
682 command is returned
683 @rtype: C{X2goServerSessionList} instance or str
684
685 """
686 if raw:
687 (stdin, stdout, stderr) = self._x2go_exec_command("export HOSTNAME && x2golistsessions")
688 return stdout.read(), stderr.read()
689
690 else:
691
692
693
694 _listsessions = {}
695 _success = False
696 _count = 0
697 _maxwait = 20
698
699
700
701 while not _success and _count < _maxwait:
702 _count += 1
703 try:
704 (stdin, stdout, stderr) = self._x2go_exec_command("export HOSTNAME && x2golistsessions")
705 _stdout_read = stdout.read()
706 _listsessions = self._list_backend(_stdout_read, info_backend=self._info_backend).sessions
707 _success = True
708 except KeyError:
709 gevent.sleep(1)
710 except IndexError:
711 gevent.sleep(1)
712 except ValueError:
713 gevent.sleep(1)
714
715 if _count >= _maxwait:
716 raise x2go_exceptions.X2goControlSessionException('x2golistsessions command failed after we have tried 20 times')
717
718
719 for _session_name, _session_info in self.associated_terminals.items():
720 if _session_name not in _listsessions.keys():
721 del self.associated_terminals[_session_name]
722 self.terminated_terminals.append(_session_name)
723 elif _session_info.is_suspended():
724 del self.associated_terminals[_session_name]
725
726 return _listsessions
727
729 """\
730 Find X2go terminals that have previously been started by the
731 connected user on the remote X2go server and terminate them.
732
733 """
734 session_list = self.list_sessions()
735 for session_name in session_list.keys():
736 self.terminate(session_name=session_name)
737
739 """\
740 Returns C{True} if this X2go session is connected to the remote server (that
741 is if it has a valid Paramiko Transport object).
742
743 @return: X2go session connected?
744 @rtype: C{bool}
745
746 """
747 return self.get_transport() is not None and self.get_transport().is_authenticated()
748
750 """\
751 Returns C{True} if the given X2go session is in running state,
752 C{False} else.
753
754 @param session_name: X2go name of the session to be queried
755 @type session_name: str
756
757 @return: X2go session running?
758 @rtype: C{bool}
759
760 """
761 session_infos = self.list_sessions()
762 if session_name in session_infos.keys():
763 return session_infos[session_name].is_running()
764 return None
765
767 """\
768 Returns C{True} if the given X2go session is in suspended state,
769 C{False} else.
770
771 @return: X2go session suspended?
772 @rtype: C{bool}
773
774 """
775 session_infos = self.list_sessions()
776 if session_name in session_infos.keys():
777 return session_infos[session_name].is_suspended()
778 return None
779
781 """\
782 Returns C{True} if this X2go session is not in the session list on the
783 connected server, C{False} else.
784
785 Of course, if this command is called before session startup, it will also
786 return C{True}.
787
788 @return: X2go session has terminate?
789 @rtype: C{bool}
790
791 """
792 session_infos = self.list_sessions()
793
794 if session_name not in session_infos.keys():
795 if session_name in self.terminated_terminals:
796 return True
797 else:
798
799 if session_name in self.associated_terminals.keys():
800 self.terminate(session_name)
801 return True
802
803 return False
804
806 """\
807 Suspend either this or another available X2go session on the connected
808 server.
809
810 If L{session_name} is given, L{X2goControlSessionSTDOUT.suspend()} tries to suspend the
811 corresponding session.
812
813 @param session_name: X2go name of the session to be suspended
814 @type session_name: str
815
816 @return: True if the session could be successfully suspended
817 @rtype: C{bool}
818
819 """
820 _ret = False
821 _session_names = [ t.get_session_name() for t in self.associated_terminals.values() ]
822 if session_name in _session_names:
823
824 self.logger('suspending associated terminal session: %s' % session_name, loglevel=log.loglevel_DEBUG)
825 (stdin, stdout, stderr) = self._x2go_exec_command("x2gosuspend-session %s" % session_name, loglevel=log.loglevel_DEBUG)
826 dummy_stdout = stdout.read()
827 dummy_stderr = stderr.read()
828 if self.associated_terminals.has_key(session_name):
829 if self.associated_terminals[session_name] is not None:
830 self.associated_terminals[session_name].__del__()
831 try: del self.associated_terminals[session_name]
832 except KeyError: pass
833 _ret = True
834
835 else:
836
837 self.logger('suspending non-associated terminal session: %s' % session_name, loglevel=log.loglevel_DEBUG)
838 (stdin, stdout, stderr) = self._x2go_exec_command("x2gosuspend-session %s" % session_name, loglevel=log.loglevel_DEBUG)
839 dummy_stdout = stdout.read()
840 dummy_stderr = stderr.read()
841 _ret = True
842
843 return _ret
844
846 """\
847 Terminate either this or another available X2go session on the connected
848 server.
849
850 If L{session_name} is given, L{X2goControlSessionSTDOUT.terminate()} tries to terminate the
851 corresponding session.
852
853 @param session_name: X2go name of the session to be terminated
854 @type session_name: str
855
856 @return: True if the session could be successfully terminate
857 @rtype: C{bool}
858
859 """
860
861 _ret = False
862 _session_names = [ t.get_session_name() for t in self.associated_terminals.values() ]
863 if session_name in _session_names:
864
865 self.logger('terminating associated session: %s' % session_name, loglevel=log.loglevel_DEBUG)
866 (stdin, stdout, stderr) = self._x2go_exec_command("x2goterminate-session %s" % session_name, loglevel=log.loglevel_DEBUG)
867 dummy_stdout = stdout.read()
868 dummy_stderr = stderr.read()
869 if self.associated_terminals.has_key(session_name):
870 if self.associated_terminals[session_name] is not None:
871 self.associated_terminals[session_name].__del__()
872 try: del self.associated_terminals[session_name]
873 except KeyError: pass
874 self.terminated_terminals.append(session_name)
875 _ret = True
876
877 else:
878
879 self.logger('terminating non-associated session: %s' % session_name, loglevel=log.loglevel_DEBUG)
880 (stdin, stdout, stderr) = self._x2go_exec_command("x2goterminate-session %s" % session_name, loglevel=log.loglevel_DEBUG)
881 dummy_stdout = stdout.read()
882 dummy_stderr = stderr.read()
883 _ret = True
884
885 return _ret
886