Commit 1ec4aa7e authored by Antoine Millet's avatar Antoine Millet
Browse files

Implemented rshell tunnels

parent dabc9579
Loading
Loading
Loading
Loading
+75 −0
Original line number Diff line number Diff line
@@ -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
@@ -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.

@@ -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)
+18 −0
Original line number Diff line number Diff line
@@ -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)