Loading cccli/command.py +47 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,10 @@ import ConfigParser import os import shlex import imp import sys import termios import threading import tty from cccli.exception import * from sjrpc.core import RpcError Loading Loading @@ -410,3 +414,46 @@ class TqlCommand(RemoteCommand): args2[self.options.tql_index] = "id=%s"%obj["id"] # now we can make call self._unsecure_rpccall(args2, **kwargs) class ConsoleCommand(TqlCommand): def __init__(self, cli, argv0): TqlCommand.__init__(self, cli, argv0) def start_console(self, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr): self.stdin = stdin.fileno() self.stdout = stdout.fileno() self.stderr = stderr.fileno() if self.stdin == sys.stdin.fileno(): sys.stdin.flush() if self.stdout == sys.stdout.fileno(): sys.stdout.flush() if self.stderr == sys.stderr.fileno(): sys.stderr.flush() self._old_settings = termios.tcgetattr(self.stdout) tty.setraw(self.stdin) self.running = True def stop_console(self): # Reset terminal attributes. termios.tcsetattr(sys.stdout, termios.TCSADRAIN, self._old_settings) self.running = False def recv(self, size): return os.read(self.stdin, 1024) def send(self, data): return os.write(self.stdout, data) def fileno(self): return self.stdin def setblocking(self, blocking): # Do NOT be in non-blocking mode : non-blocking mode # causes rshell to get EAGAIN errors when having to # output loads of data, causing the TTY to break. return def close(self): # Reset terminal attributes. termios.tcsetattr(sys.stdout, termios.TCSADRAIN, self._old_settings) cccli/commands/rshell.py 0 → 100644 +95 −0 Original line number Diff line number Diff line #!/usr/bin/env python #coding=utf8 ''' Connection to a remote shell ''' import os import sys import tty import fcntl import signal import struct import termios from cccli.exception import * from sjrpc.core.exceptions import * from cccli.printer import Printer, color from cccli.command import ConsoleCommand from sjrpc.core.protocols import TunnelProtocol from sjrpc.core import AsyncWatcher class Command_rshell(ConsoleCommand): '''Start a remote shell on the provided host''' def __init__(self, cli, argv0): ConsoleCommand.__init__(self, cli, argv0) self.tql_filter = "&con" def __call__(self, argv): # args parse self.parse_args(argv) if len(self.args) != 1: raise cmdBadArgument() # rpccall self.rpccall("rshell", self.args[0], _callback=self._cb_open_shell, _status=True, _direct=True) def _cb_open_shell(self, response): tun = None if not 'objects' in response: return response = response['objects'][0] if not 'status' in response: return if response['status'] == 'success': label = response['output'] try: # Create terminal self.start_console(sys.stdin, sys.stdout, sys.stderr) # Connect to remote end using sjrpc tun = self.rpc.create_tunnel(endpoint=self) # Terminal resizing event handler def sig_resize(signum, frame): size = struct.pack('HHHH', 0, 0, 0, 0) size = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, size) size = struct.unpack('HHHH', size) self.rpc.call('rshell_resize', label, *size) signal.signal(signal.SIGWINCH, sig_resize) # Init size for term size = struct.pack('HHHH', 0, 0, 0, 0) size = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, size) size = struct.unpack('HHHH', size) self.rpc.call('rshell_resize', label, *size) # Setup and run event loop watcher = AsyncWatcher() watcher.register(self.rpc.rpc, 'rshell_wait', label) while self.running: returned = watcher.wait(1) if returned: if 'return' in returned[0]: rcode = returned[0]['return'] break elif 'error' in returned[0]: raise RpcError(Exception(returned[0]['error']['message']), Exception(returned[0]['error']['message'])) # Clear signal handlers signal.signal(signal.SIGWINCH, signal.SIG_IGN) except Exception: # Cleanup self.stop_console() if tun: tun.shutdown() tun.close() raise else: # Cleanup self.stop_console() if tun: tun.shutdown() tun.close() def remote_functions(self): return set(("rshell",)) Loading
cccli/command.py +47 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,10 @@ import ConfigParser import os import shlex import imp import sys import termios import threading import tty from cccli.exception import * from sjrpc.core import RpcError Loading Loading @@ -410,3 +414,46 @@ class TqlCommand(RemoteCommand): args2[self.options.tql_index] = "id=%s"%obj["id"] # now we can make call self._unsecure_rpccall(args2, **kwargs) class ConsoleCommand(TqlCommand): def __init__(self, cli, argv0): TqlCommand.__init__(self, cli, argv0) def start_console(self, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr): self.stdin = stdin.fileno() self.stdout = stdout.fileno() self.stderr = stderr.fileno() if self.stdin == sys.stdin.fileno(): sys.stdin.flush() if self.stdout == sys.stdout.fileno(): sys.stdout.flush() if self.stderr == sys.stderr.fileno(): sys.stderr.flush() self._old_settings = termios.tcgetattr(self.stdout) tty.setraw(self.stdin) self.running = True def stop_console(self): # Reset terminal attributes. termios.tcsetattr(sys.stdout, termios.TCSADRAIN, self._old_settings) self.running = False def recv(self, size): return os.read(self.stdin, 1024) def send(self, data): return os.write(self.stdout, data) def fileno(self): return self.stdin def setblocking(self, blocking): # Do NOT be in non-blocking mode : non-blocking mode # causes rshell to get EAGAIN errors when having to # output loads of data, causing the TTY to break. return def close(self): # Reset terminal attributes. termios.tcsetattr(sys.stdout, termios.TCSADRAIN, self._old_settings)
cccli/commands/rshell.py 0 → 100644 +95 −0 Original line number Diff line number Diff line #!/usr/bin/env python #coding=utf8 ''' Connection to a remote shell ''' import os import sys import tty import fcntl import signal import struct import termios from cccli.exception import * from sjrpc.core.exceptions import * from cccli.printer import Printer, color from cccli.command import ConsoleCommand from sjrpc.core.protocols import TunnelProtocol from sjrpc.core import AsyncWatcher class Command_rshell(ConsoleCommand): '''Start a remote shell on the provided host''' def __init__(self, cli, argv0): ConsoleCommand.__init__(self, cli, argv0) self.tql_filter = "&con" def __call__(self, argv): # args parse self.parse_args(argv) if len(self.args) != 1: raise cmdBadArgument() # rpccall self.rpccall("rshell", self.args[0], _callback=self._cb_open_shell, _status=True, _direct=True) def _cb_open_shell(self, response): tun = None if not 'objects' in response: return response = response['objects'][0] if not 'status' in response: return if response['status'] == 'success': label = response['output'] try: # Create terminal self.start_console(sys.stdin, sys.stdout, sys.stderr) # Connect to remote end using sjrpc tun = self.rpc.create_tunnel(endpoint=self) # Terminal resizing event handler def sig_resize(signum, frame): size = struct.pack('HHHH', 0, 0, 0, 0) size = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, size) size = struct.unpack('HHHH', size) self.rpc.call('rshell_resize', label, *size) signal.signal(signal.SIGWINCH, sig_resize) # Init size for term size = struct.pack('HHHH', 0, 0, 0, 0) size = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, size) size = struct.unpack('HHHH', size) self.rpc.call('rshell_resize', label, *size) # Setup and run event loop watcher = AsyncWatcher() watcher.register(self.rpc.rpc, 'rshell_wait', label) while self.running: returned = watcher.wait(1) if returned: if 'return' in returned[0]: rcode = returned[0]['return'] break elif 'error' in returned[0]: raise RpcError(Exception(returned[0]['error']['message']), Exception(returned[0]['error']['message'])) # Clear signal handlers signal.signal(signal.SIGWINCH, signal.SIG_IGN) except Exception: # Cleanup self.stop_console() if tun: tun.shutdown() tun.close() raise else: # Cleanup self.stop_console() if tun: tun.shutdown() tun.close() def remote_functions(self): return set(("rshell",))