Loading ccserver/clients/cli.py +75 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ import logging from collections import defaultdict from sjrpc.core import RpcError from sjrpc.core.protocols import TunnelProtocol from ccserver.orderedset import OrderedSet from ccserver.conf import CCConf Loading Loading @@ -666,6 +667,52 @@ class CliHandler(RegisteredCCHandler): 'hv_dest': dest['id'], 'author': self.client.login}) @listed def rshell(self, tql): """ Start a remote shell on object matching the provided tql. """ objects = self.server.list(tql, show=('r', 'p')) if len(objects) != 1: raise NotImplementedError('Rshell only support one tunnel at time for now') errs = Reporter() for obj in objects: if obj['r'] in ('host', 'hv'): client = self.server.get_client(obj['id']) srv_to_host_tun = client.rshell() cli_tun = self.client.register_tunnel('rshell', client, srv_to_host_tun) errs.success(obj['id'], 'tunnel started.', output=cli_tun.label) elif obj['r'] in ('vm', ): raise NotImplementedError('rshell on vm not implemented') else: errs.error(obj['id'], 'bad role') return errs.get_dict() @listed def rshell_resize(self, label, row, col, xpixel, ypixel): """ Resize the shell. """ ttype, client, ctun, stun = self.client.get_tunnel(label) if ttype != 'rshell': raise ValueError('Label does not refers on a rshell') client.rshell_resize(stun.label, row, col, xpixel, ypixel) @listed def rshell_wait(self, label): """ Wait for a remote shell termination. """ ttype, client, ctun, stun = self.client.get_tunnel(label) if ttype != 'rshell': raise ValueError('Label does not refers on a rshell') try: rcode = client.rshell_wait(stun.label) except Exception as err: rcode = -1 logging.warning('Unexpected exit of tunnel: %s', err) self.client.unregister_tunnel(ctun.label) ctun.close() stun.close() return rcode def forward_call(self, login, func, *args, **kwargs): """ Forward a call to a connected client and return result. Loading @@ -686,5 +733,33 @@ class CliClient(Client): ROLE = 'cli' RPC_HANDLER = CliHandler def __init__(self, *args, **kwargs): super(CliClient, self).__init__(*args, **kwargs) self._tunnels = {} # Running tunnels for this client (as client) def register_tunnel(self, ttype, client, tun, label=None): """ Create and register a tunnel for this client. :param ttype: type of tunnel :param client: client where the tunnel go :param tun: the tunnel of this client :param label: label of the tunnel to create """ def cb_on_close(tun): # Call the default callback: tun.cb_default_on_close(tun) # Delete the tunnel from the current running tunnels: self.unregister_tunnel(tun.label) ctun = self.conn.create_tunnel(label=label, endpoint=tun.socket, on_close=cb_on_close) self._tunnels[ctun.label] = (ttype, client, ctun, tun) return ctun def get_tunnel(self, label): return self._tunnels[label] def unregister_tunnel(self, label): del self._tunnels[label] Client.register_client_class(CliClient) ccserver/clients/host.py +18 −0 Original line number Diff line number Diff line Loading @@ -7,8 +7,26 @@ class HostClient(Client): ROLE = 'host' def __init__(self, *args, **kwargs): super(HostClient, self).__init__(*args, **kwargs) def execute(self, command): return self.conn.call('execute_command', command) def rshell(self): """ Start a remote shell on the host. """ label = self.proxy.rshell() tun = self.conn.create_tunnel(label=label) return tun def rshell_resize(self, label, *args, **kwargs): return self.proxy.rshell_resize(label, *args, **kwargs) def rshell_wait(self, label): """ Wait for a remote shell termination. """ return self.proxy.rshell_wait(label, _timeout=None) Client.register_client_class(HostClient) Loading
ccserver/clients/cli.py +75 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ import logging from collections import defaultdict from sjrpc.core import RpcError from sjrpc.core.protocols import TunnelProtocol from ccserver.orderedset import OrderedSet from ccserver.conf import CCConf Loading Loading @@ -666,6 +667,52 @@ class CliHandler(RegisteredCCHandler): 'hv_dest': dest['id'], 'author': self.client.login}) @listed def rshell(self, tql): """ Start a remote shell on object matching the provided tql. """ objects = self.server.list(tql, show=('r', 'p')) if len(objects) != 1: raise NotImplementedError('Rshell only support one tunnel at time for now') errs = Reporter() for obj in objects: if obj['r'] in ('host', 'hv'): client = self.server.get_client(obj['id']) srv_to_host_tun = client.rshell() cli_tun = self.client.register_tunnel('rshell', client, srv_to_host_tun) errs.success(obj['id'], 'tunnel started.', output=cli_tun.label) elif obj['r'] in ('vm', ): raise NotImplementedError('rshell on vm not implemented') else: errs.error(obj['id'], 'bad role') return errs.get_dict() @listed def rshell_resize(self, label, row, col, xpixel, ypixel): """ Resize the shell. """ ttype, client, ctun, stun = self.client.get_tunnel(label) if ttype != 'rshell': raise ValueError('Label does not refers on a rshell') client.rshell_resize(stun.label, row, col, xpixel, ypixel) @listed def rshell_wait(self, label): """ Wait for a remote shell termination. """ ttype, client, ctun, stun = self.client.get_tunnel(label) if ttype != 'rshell': raise ValueError('Label does not refers on a rshell') try: rcode = client.rshell_wait(stun.label) except Exception as err: rcode = -1 logging.warning('Unexpected exit of tunnel: %s', err) self.client.unregister_tunnel(ctun.label) ctun.close() stun.close() return rcode def forward_call(self, login, func, *args, **kwargs): """ Forward a call to a connected client and return result. Loading @@ -686,5 +733,33 @@ class CliClient(Client): ROLE = 'cli' RPC_HANDLER = CliHandler def __init__(self, *args, **kwargs): super(CliClient, self).__init__(*args, **kwargs) self._tunnels = {} # Running tunnels for this client (as client) def register_tunnel(self, ttype, client, tun, label=None): """ Create and register a tunnel for this client. :param ttype: type of tunnel :param client: client where the tunnel go :param tun: the tunnel of this client :param label: label of the tunnel to create """ def cb_on_close(tun): # Call the default callback: tun.cb_default_on_close(tun) # Delete the tunnel from the current running tunnels: self.unregister_tunnel(tun.label) ctun = self.conn.create_tunnel(label=label, endpoint=tun.socket, on_close=cb_on_close) self._tunnels[ctun.label] = (ttype, client, ctun, tun) return ctun def get_tunnel(self, label): return self._tunnels[label] def unregister_tunnel(self, label): del self._tunnels[label] Client.register_client_class(CliClient)
ccserver/clients/host.py +18 −0 Original line number Diff line number Diff line Loading @@ -7,8 +7,26 @@ class HostClient(Client): ROLE = 'host' def __init__(self, *args, **kwargs): super(HostClient, self).__init__(*args, **kwargs) def execute(self, command): return self.conn.call('execute_command', command) def rshell(self): """ Start a remote shell on the host. """ label = self.proxy.rshell() tun = self.conn.create_tunnel(label=label) return tun def rshell_resize(self, label, *args, **kwargs): return self.proxy.rshell_resize(label, *args, **kwargs) def rshell_wait(self, label): """ Wait for a remote shell termination. """ return self.proxy.rshell_wait(label, _timeout=None) Client.register_client_class(HostClient)