From b511a02f2010a99c92ae74912c8ed5ff52559050 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Mon, 26 Nov 2018 16:21:31 -0500 Subject: [PATCH] Have correct size on connect for shell session In addition to resize, also support initial size being set --- confluent_client/bin/confetty | 6 ++++- confluent_server/confluent/consoleserver.py | 22 +++++++++++++------ .../confluent/plugins/shell/ssh.py | 10 ++++++++- confluent_server/confluent/shellserver.py | 9 ++++---- confluent_server/confluent/sockapi.py | 8 ++++--- 5 files changed, 39 insertions(+), 16 deletions(-) diff --git a/confluent_client/bin/confetty b/confluent_client/bin/confetty index 48e82d0b..ef6cc61f 100755 --- a/confluent_client/bin/confetty +++ b/confluent_client/bin/confetty @@ -2,7 +2,7 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2014 IBM Corporation -# Copyright 2015-2016 Lenovo +# Copyright 2015-2018 Lenovo # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -435,6 +435,10 @@ def do_command(command, server): currconsole = targpath startrequest = {'operation': 'start', 'path': targpath, 'parameters': {}} + height, width = struct.unpack( + 'hh', fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, b'....'))[:2] + startrequest['parameters']['width'] = width + startrequest['parameters']['height'] = height for param in argv[2:]: (parmkey, parmval) = param.split("=") startrequest['parameters'][parmkey] = parmval diff --git a/confluent_server/confluent/consoleserver.py b/confluent_server/confluent/consoleserver.py index 129455f0..0942f773 100644 --- a/confluent_server/confluent/consoleserver.py +++ b/confluent_server/confluent/consoleserver.py @@ -1,7 +1,7 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2014 IBM Corporation -# Copyright 2017 Lenovo +# Copyright 2017-2018 Lenovo # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -145,8 +145,9 @@ class ConsoleHandler(object): _genwatchattribs = frozenset(('console.method', 'console.logging', 'collective.manager')) - def __init__(self, node, configmanager): + def __init__(self, node, configmanager, width=80, height=24): self.clearpending = False + self.initsize = (width, height) self._dologging = True self._is_local = True self._isondemand = False @@ -384,6 +385,7 @@ class ConsoleHandler(object): self._attribwatcher = self.cfgmgr.watch_attributes( (self.node,), attribstowatch, self._attribschanged) try: + self.resize(width=self.initsize[0], height=self.initsize[1]) self._console.connect(self.get_console_output) except exc.TargetEndpointBadCredentials: self.clearbuffer() @@ -629,17 +631,20 @@ def start_console_sessions(): configmodule.hook_new_configmanagers(_start_tenant_sessions) -def connect_node(node, configmanager, username=None, direct=True): +def connect_node(node, configmanager, username=None, direct=True, width=80, + height=24): attrval = configmanager.get_node_attributes(node, 'collective.manager') myc = attrval.get(node, {}).get('collective.manager', {}).get( 'value', None) myname = collective.get_myname() if myc and myc != collective.get_myname() and direct: minfo = configmodule.get_collective_member(myc) - return ProxyConsole(node, minfo, myname, configmanager, username) + return ProxyConsole(node, minfo, myname, configmanager, username, + width, height) consk = (node, configmanager.tenant) if consk not in _handled_consoles: - _handled_consoles[consk] = ConsoleHandler(node, configmanager) + _handled_consoles[consk] = ConsoleHandler(node, configmanager, width, + height) return _handled_consoles[consk] # A stub console handler that just passes through to a remote confluent @@ -768,7 +773,7 @@ class ConsoleSession(object): """ def __init__(self, node, configmanager, username, datacallback=None, - skipreplay=False, direct=True): + skipreplay=False, direct=True, width=80, height=24): self.registered = False self.tenant = configmanager.tenant if not configmanager.is_node(node): @@ -778,6 +783,8 @@ class ConsoleSession(object): self.configmanager = configmanager self.direct = direct # true if client is directly connected versus # relay + self.width = width + self.height = height self.connect_session() self.registered = True self._evt = None @@ -806,7 +813,8 @@ class ConsoleSession(object): between console and shell. """ self.conshdl = connect_node(self.node, self.configmanager, - self.username, self.direct) + self.username, self.direct, self.width, + self.height) def send_break(self): """Send break to remote system """ diff --git a/confluent_server/confluent/plugins/shell/ssh.py b/confluent_server/confluent/plugins/shell/ssh.py index 8073bdce..7cb83fdb 100644 --- a/confluent_server/confluent/plugins/shell/ssh.py +++ b/confluent_server/confluent/plugins/shell/ssh.py @@ -80,9 +80,16 @@ class SshShell(conapi.Console): self.nodeconfig = config self.username = username self.password = password + self.connected = False + self.width = 80 + self.height = 24 self.inputmode = 0 # 0 = username, 1 = password... def resize(self, width, height): + self.width = width + self.height = height + if not self.connected: + return self.shell.resize_pty(width=width, height=height) def recvdata(self): @@ -149,7 +156,8 @@ class SshShell(conapi.Console): return self.inputmode = 2 self.connected = True - self.shell = self.ssh.invoke_shell() + self.shell = self.ssh.invoke_shell(width=self.width, + height=self.height) self.rxthread = eventlet.spawn(self.recvdata) def write(self, data): diff --git a/confluent_server/confluent/shellserver.py b/confluent_server/confluent/shellserver.py index bb69944e..f0efc85f 100644 --- a/confluent_server/confluent/shellserver.py +++ b/confluent_server/confluent/shellserver.py @@ -1,6 +1,6 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright 2016 Lenovo +# Copyright 2016-2018 Lenovo # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -87,12 +87,13 @@ class ShellSession(consoleserver.ConsoleSession): """ def __init__(self, node, configmanager, username, datacallback=None, - skipreplay=False, sessionid=None): + skipreplay=False, sessionid=None, width=80, height=24): self.sessionid = sessionid self.configmanager = configmanager self.node = node super(ShellSession, self).__init__(node, configmanager, username, - datacallback, skipreplay) + datacallback, skipreplay, + width=width, height=height) def connect_session(self): global activesessions @@ -105,7 +106,7 @@ class ShellSession(consoleserver.ConsoleSession): self.sessionid += 1 self.sessionid = str(self.sessionid) if self.sessionid not in activesessions[(tenant, self.node, self.username)]: - activesessions[(tenant, self.node, self.username)][self.sessionid] = _ShellHandler(self.node, self.configmanager) + activesessions[(tenant, self.node, self.username)][self.sessionid] = _ShellHandler(self.node, self.configmanager, width=self.width, height=self.height) self.conshdl = activesessions[(self.configmanager.tenant, self.node, self.username)][self.sessionid] def destroy(self): diff --git a/confluent_server/confluent/sockapi.py b/confluent_server/confluent/sockapi.py index 3b389508..c5ce3a98 100644 --- a/confluent_server/confluent/sockapi.py +++ b/confluent_server/confluent/sockapi.py @@ -1,7 +1,7 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2014 IBM Corporation -# Copyright 2015 Lenovo +# Copyright 2015-2018 Lenovo # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -239,7 +239,8 @@ def start_proxy_term(connection, cert, request): consession = consoleserver.ConsoleSession( node=request['node'], configmanager=cfm, username=request['user'], datacallback=ccons.sendall, skipreplay=request['skipreplay'], - direct=False) + direct=False, width=request.get('width', 80), height=request.get( + 'height', 24)) term_interact(None, None, ccons, None, connection, consession, None) def start_term(authname, cfm, connection, params, path, authdata, skipauth): @@ -263,7 +264,8 @@ def start_term(authname, cfm, connection, params, path, authdata, skipauth): consession = shellserver.ShellSession( node=node, configmanager=cfm, username=authname, datacallback=ccons.sendall, skipreplay=skipreplay, - sessionid=sessionid) + sessionid=sessionid, width=params.get('width', 80), + height=params.get('height', 24)) else: raise exc.InvalidArgumentException('Invalid path {0}'.format(path)) if consession is None: