mirror of
https://github.com/portainer/portainer.git
synced 2025-08-02 20:35:25 +02:00
feat(global): add container exec support
This commit is contained in:
parent
b0ebbdf68c
commit
5878eed7ec
16 changed files with 438 additions and 75 deletions
|
@ -64,6 +64,7 @@
|
|||
<div class="btn-group" role="group" aria-label="...">
|
||||
<a class="btn btn-default" type="button" ui-sref="stats({id: container.Id})">Stats</a>
|
||||
<a class="btn btn-default" type="button" ui-sref="logs({id: container.Id})">Logs</a>
|
||||
<a class="btn btn-default" type="button" ui-sref="console({id: container.Id})">Console</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="comment">
|
||||
|
|
43
app/components/containerConsole/containerConsole.html
Normal file
43
app/components/containerConsole/containerConsole.html
Normal file
|
@ -0,0 +1,43 @@
|
|||
<rd-header>
|
||||
<rd-header-title title="Container console">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>
|
||||
Containers > <a ui-sref="container({id: container.Id})">{{ container.Name|trimcontainername }}</a> > Console
|
||||
</rd-header-content>
|
||||
</rd-header>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-terminal" title="Console">
|
||||
<div class="pull-right">
|
||||
<i id="loadConsoleSpinner" class="fa fa-cog fa-2x fa-spin" style="margin-top: 5px; display: none;"></i>
|
||||
</div>
|
||||
</rd-widget-header>
|
||||
<rd-widget-body>
|
||||
<form class="form-horizontal">
|
||||
<!-- command-list -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-3">
|
||||
<select class="selectpicker form-control" ng-model="state.command">
|
||||
<option value="bash">/bin/bash</option>
|
||||
<option value="sh">/bin/sh</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-9 pull-left">
|
||||
<button type="button" class="btn btn-primary" ng-click="connect()" ng-disabled="connected">Connect</button>
|
||||
<button type="button" class="btn btn-default" ng-click="disconnect()" ng-disabled="!connected">Disconnect</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<div id="terminal-container" class="terminal-container"></div>
|
||||
</div>
|
||||
</div>
|
104
app/components/containerConsole/containerConsoleController.js
Normal file
104
app/components/containerConsole/containerConsoleController.js
Normal file
|
@ -0,0 +1,104 @@
|
|||
angular.module('containerConsole', [])
|
||||
.controller('ContainerConsoleController', ['$scope', '$stateParams', 'Settings', 'Container', 'Exec', '$timeout', 'Messages', 'errorMsgFilter',
|
||||
function ($scope, $stateParams, Settings, Container, Exec, $timeout, Messages, errorMsgFilter) {
|
||||
$scope.state = {};
|
||||
$scope.state.command = "bash";
|
||||
$scope.connected = false;
|
||||
|
||||
var socket, term;
|
||||
|
||||
// Ensure the socket is closed before leaving the view
|
||||
$scope.$on('$stateChangeStart', function (event, next, current) {
|
||||
if (socket !== null) {
|
||||
socket.close();
|
||||
}
|
||||
});
|
||||
|
||||
Container.get({id: $stateParams.id}, function(d) {
|
||||
$scope.container = d;
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
|
||||
$scope.connect = function() {
|
||||
$('#loadConsoleSpinner').show();
|
||||
var termWidth = Math.round($('#terminal-container').width() / 8.2);
|
||||
var termHeight = 30;
|
||||
var execConfig = {
|
||||
id: $stateParams.id,
|
||||
AttachStdin: true,
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
Tty: true,
|
||||
Cmd: $scope.state.command.replace(" ", ",").split(",")
|
||||
};
|
||||
|
||||
Container.exec(execConfig, function(d) {
|
||||
if (d.Id) {
|
||||
var execId = d.Id;
|
||||
resizeTTY(execId, termHeight, termWidth);
|
||||
var url = window.location.href.split('#')[0].replace('http://', 'ws://') + 'ws/exec?id=' + execId;
|
||||
initTerm(url, termHeight, termWidth);
|
||||
} else {
|
||||
$('#loadConsoleSpinner').hide();
|
||||
Messages.error('Error', errorMsgFilter(d));
|
||||
}
|
||||
}, function (e) {
|
||||
$('#loadConsoleSpinner').hide();
|
||||
Messages.error("Failure", e.data);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.disconnect = function() {
|
||||
$scope.connected = false;
|
||||
if (socket !== null) {
|
||||
socket.close();
|
||||
}
|
||||
if (term !== null) {
|
||||
term.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
function resizeTTY(execId, height, width) {
|
||||
$timeout(function() {
|
||||
Exec.resize({id: execId, height: height, width: width}, function (d) {
|
||||
var error = errorMsgFilter(d);
|
||||
if (error) {
|
||||
Messages.error('Error', 'Unable to resize TTY');
|
||||
}
|
||||
});
|
||||
}, 2000);
|
||||
|
||||
}
|
||||
|
||||
function initTerm(url, height, width) {
|
||||
socket = new WebSocket(url);
|
||||
|
||||
$scope.connected = true;
|
||||
socket.onopen = function(evt) {
|
||||
$('#loadConsoleSpinner').hide();
|
||||
term = new Terminal({
|
||||
cols: width,
|
||||
rows: height,
|
||||
cursorBlink: true
|
||||
});
|
||||
|
||||
term.on('data', function (data) {
|
||||
socket.send(data);
|
||||
});
|
||||
term.open(document.getElementById('terminal-container'));
|
||||
|
||||
socket.onmessage = function (e) {
|
||||
term.write(e.data);
|
||||
};
|
||||
socket.onerror = function (error) {
|
||||
$scope.connected = false;
|
||||
|
||||
};
|
||||
socket.onclose = function(evt) {
|
||||
$scope.connected = false;
|
||||
// term.write("Session terminated");
|
||||
// term.destroy();
|
||||
};
|
||||
};
|
||||
}
|
||||
}]);
|
Loading…
Add table
Add a link
Reference in a new issue