Skip to content

Instantly share code, notes, and snippets.

@stefanpejcic
Created September 18, 2024 10:11
Show Gist options
  • Save stefanpejcic/e6010daa77c5d6ef964ef61bfef40bb7 to your computer and use it in GitHub Desktop.
Save stefanpejcic/e6010daa77c5d6ef964ef61bfef40bb7 to your computer and use it in GitHub Desktop.
flask terminal for container - ispired by https://gist.github.com/Humerus/0268c62f359f7ee1ee2d
from flask import Flask, render_template, request
from flask_socketio import SocketIO, emit
import docker
app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins="*")
client = docker.from_env()
@app.route('/terminal/<container_id>')
def terminal(container_id):
try:
client.containers.get(container_id)
except docker.errors.NotFound:
return "Container not found", 404
return render_template('terminal.html', container_id=container_id)
@socketio.on('connect')
def handle_connect():
print('Client connected')
@socketio.on('disconnect')
def handle_disconnect():
print('Client disconnected')
@socketio.on('input')
def handle_input(data):
container_id = data['container_id']
command = data['command'].strip()
try:
container = client.containers.get(container_id)
exec_id = client.api.exec_create(container.id, cmd=['bash', '-c', command], tty=True, stdin=True, stdout=True, stderr=True)
output = client.api.exec_start(exec_id, detach=False, tty=True)
emit('output', {'data': output.decode('utf-8')})
except docker.errors.NotFound:
emit('error', {'message': 'Container not found'})
except Exception as e:
emit('error', {'message': str(e)})
if __name__ == '__main__':
socketio.run(app, host='0.0.0.0', port=5000, debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Web Terminal</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm/css/xterm.css" />
<style>
#terminal {
width: 100%;
height: 500px;
}
</style>
</head>
<body>
<h1>Terminal for Container: {{ container_id }}</h1>
<div id="terminal"></div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/xterm.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/xterm-addon-fit.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/xterm.css" />
<script src="https://cdn.socket.io/4.6.1/socket.io.min.js"></script> <!-- Ensure you use the latest version or the version compatible with your server -->
<script>
const terminal = new Terminal();
const fitAddon = new FitAddon.FitAddon();
terminal.loadAddon(fitAddon);
terminal.open(document.getElementById('terminal'));
fitAddon.fit();
const socket = io.connect('http://165.232.70.181:5000'); // Update this URL if needed
let currentCommand = '';
terminal.onData(data => {
// Handle special keys
if (data === '\r') {
// Enter key pressed, send the command
socket.emit('input', { container_id: '{{ container_id }}', command: currentCommand });
currentCommand = ''; // Reset for the next command
} else if (data === '\x7f') {
// Backspace key pressed
currentCommand = currentCommand.slice(0, -1);
terminal.write('\b \b'); // Erase last character
} else if (data === '\x1b[D') {
// Left arrow key (could be handled differently based on actual escape sequences)
terminal.write(data); // Placeholder for cursor movement
} else if (data === '\x1b[C') {
// Right arrow key (could be handled differently based on actual escape sequences)
terminal.write(data); // Placeholder for cursor movement
} else {
// Append data to command and write to terminal
currentCommand += data;
terminal.write(data);
}
});
socket.on('output', (data) => {
terminal.write(data.data);
});
socket.on('error', (data) => {
terminal.write('\r\nError: ' + data.message);
});
socket.on('connect', () => {
console.log('WebSocket connected');
});
socket.on('disconnect', () => {
terminal.write('\r\nConnection closed.');
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment