Improve docker HTTP console

Fix #816
This commit is contained in:
Julien Duponchelle 2016-12-09 16:41:15 +01:00
parent 846041a59c
commit c4327ec74c
No known key found for this signature in database
GPG Key ID: CE8B29639E07F5E8
2 changed files with 22 additions and 7 deletions

View File

@ -434,15 +434,20 @@ class DockerVM(BaseNode):
@asyncio.coroutine @asyncio.coroutine
def _start_http(self): def _start_http(self):
""" """
Start an HTTP tunnel to container localhost Start an HTTP tunnel to container localhost. It's not perfect
but the only way we have to inject network packet is using nc.
""" """
log.debug("Forward HTTP for %s to %d", self.name, self._console_http_port) log.debug("Forward HTTP for %s to %d", self.name, self._console_http_port)
command = ["docker", "exec", "-i", self._cid, "/gns3/bin/busybox", "nc", "127.0.0.1", str(self._console_http_port)] command = ["docker", "exec", "-i", self._cid, "/gns3/bin/busybox", "nc", "127.0.0.1", str(self._console_http_port)]
# We replace the port in the server answer otherwise some link could be broken # We replace host and port in the server answer otherwise some link could be broken
server = AsyncioRawCommandServer(command, replaces=[ server = AsyncioRawCommandServer(command, replaces=[
( (
'{}'.format(self._console_http_port).encode(), '://127.0.0.1'.encode(), # {{HOST}} mean client host
'{}'.format(self.console).encode(), '://{{HOST}}'.encode(),
),
(
':{}'.format(self._console_http_port).encode(),
':{}'.format(self.console).encode(),
) )
]) ])
self._telnet_servers.append((yield from asyncio.start_server(server.run, self._manager.port_manager.console_host, self.console))) self._telnet_servers.append((yield from asyncio.start_server(server.run, self._manager.port_manager.console_host, self.console)))

View File

@ -16,6 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import re import re
import copy
import asyncio import asyncio
import asyncio.subprocess import asyncio.subprocess
@ -59,6 +60,15 @@ class AsyncioRawCommandServer:
@asyncio.coroutine @asyncio.coroutine
def _process(self, network_reader, network_writer, process_reader, process_writer): def _process(self, network_reader, network_writer, process_reader, process_writer):
replaces = []
# Server host from the client point of view
host = network_writer.transport.get_extra_info("sockname")[0]
for replace in self._replaces:
if b'{{HOST}}' in replace[1]:
replaces.append((replace[0], replace[1].replace(b'{{HOST}}', host.encode()), ))
else:
replaces.append((replace[0], replace[1], ))
network_read = asyncio.async(network_reader.read(READ_SIZE)) network_read = asyncio.async(network_reader.read(READ_SIZE))
reader_read = asyncio.async(process_reader.read(READ_SIZE)) reader_read = asyncio.async(process_reader.read(READ_SIZE))
timeout = 30 timeout = 30
@ -89,7 +99,7 @@ class AsyncioRawCommandServer:
reader_read = asyncio.async(process_reader.read(READ_SIZE)) reader_read = asyncio.async(process_reader.read(READ_SIZE))
for replace in self._replaces: for replace in replaces:
data = data.replace(replace[0], replace[1]) data = data.replace(replace[0], replace[1])
timeout = 2 # We reduce the timeout when the process start to return stuff to avoid problem with server not closing the connection timeout = 2 # We reduce the timeout when the process start to return stuff to avoid problem with server not closing the connection
@ -102,8 +112,8 @@ if __name__ == '__main__':
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
command = ["nc", "localhost", "80"] command = ["nc", "localhost", "80"]
server = AsyncioRawCommandServer(command) server = AsyncioRawCommandServer(command, replaces=[(b"work", b"{{HOST}}", )])
coro = asyncio.start_server(server.run, '127.0.0.1', 4444, loop=loop) coro = asyncio.start_server(server.run, '0.0.0.0', 4444, loop=loop)
s = loop.run_until_complete(coro) s = loop.run_until_complete(coro)
try: try: