Skip to content
This repository was archived by the owner on Nov 20, 2020. It is now read-only.

Commit e6c57d6

Browse files
authored
Merge pull request #91 from bitbull-team/feature/support-for-web-console
Support for external web console
2 parents c4b29d5 + e002af9 commit e6c57d6

File tree

9 files changed

+145
-6
lines changed

9 files changed

+145
-6
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,6 @@ target/
6363

6464
# Visual Studio code
6565
.vscode/
66+
67+
# Intellij
68+
.idea

Dockerfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ RUN pip install virtualenv
77

88
RUN apk add -U --no-cache git
99

10-
COPY . /app
10+
COPY ./requirements.txt /app/requirements.txt
1111
RUN virtualenv /env && /env/bin/pip install --no-cache-dir -r /app/requirements.txt
1212

13+
COPY . /app
14+
1315
VOLUME ["/opt/docker-compose-projects"]
1416

1517
COPY demo-projects /opt/docker-compose-projects

Dockerfile-dev

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# https://github.com/francescou/docker-compose-ui
2+
# DOCKER-VERSION 1.12.3
3+
FROM python:2.7-alpine
4+
MAINTAINER Francesco Uliana <[email protected]>
5+
6+
RUN pip install virtualenv
7+
8+
RUN apk add -U --no-cache git
9+
10+
COPY ./requirements.txt /app/requirements.txt
11+
RUN virtualenv /env && /env/bin/pip install --no-cache-dir -r /app/requirements.txt
12+
13+
VOLUME /app
14+
15+
VOLUME ["/opt/docker-compose-projects"]
16+
17+
COPY demo-projects /opt/docker-compose-projects
18+
19+
EXPOSE 5000
20+
21+
CMD []
22+
ENTRYPOINT ["/env/bin/python", "/app/main.py"]
23+
24+
WORKDIR /opt/docker-compose-projects/

main.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,12 @@ def host():
388388

389389
return jsonify(host=host_value, workdir=os.getcwd() if YML_PATH == '.' else YML_PATH)
390390

391+
@app.route(API_V1 + "web_console_pattern", methods=['GET'])
392+
def get_web_console_pattern():
393+
"""
394+
forward WEB_CONSOLE_PATTERN env var from server to spa
395+
"""
396+
return jsonify(web_console_pattern=os.getenv('WEB_CONSOLE_PATTERN'))
391397

392398
@app.route(API_V1 + "health", methods=['GET'])
393399
def health():

static/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ <h3>Projects</h3>
9999
<script src="scripts/directives/actions.js"></script>
100100
<script src="scripts/directives/project-detail.js"></script>
101101
<script src="scripts/directives/modal.js"></script>
102+
<script src="scripts/directives/console-modal.js"></script>
102103
<script src="scripts/services/project.js"></script>
103104
<script src="scripts/services/logs.js"></script>
104105
<script async defer src="https://buttons.github.io/buttons.js"></script>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
'use strict';
2+
3+
angular.module('composeUiApp')
4+
.directive('consoleModalShow', function ($parse) {
5+
return {
6+
restrict: 'A',
7+
link: function (scope, element, attrs) {
8+
9+
//Hide or show the modal
10+
scope.showConsoleModal = function (visible, elem) {
11+
if (!elem)
12+
elem = element;
13+
14+
if (visible)
15+
$(elem).modal('show');
16+
else
17+
$(elem).modal('hide');
18+
};
19+
20+
//Watch for changes to the modal-visible attribute
21+
scope.$watch(attrs.consoleModalShow, function (newValue) {
22+
scope.showConsoleModal(newValue, attrs.$$element);
23+
});
24+
25+
//Update the visible value when the dialog is closed through UI actions (Ok, cancel, etc.)
26+
$(element).bind('hide.bs.modal', function () {
27+
$parse(attrs.consoleModalShow).assign(scope, false);
28+
if (!scope.$$phase && !scope.$root.$$phase)
29+
scope.$apply();
30+
});
31+
}
32+
33+
};
34+
});

static/scripts/directives/project-detail.js

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
11
'use strict';
22

33
angular.module('composeUiApp')
4+
.config(function($sceDelegateProvider) {
5+
$.get('/api/v1/web_console_pattern', (response) => {
6+
if (response.web_console_pattern) {
7+
var parser = document.createElement('a'),
8+
whitelistUrlPattern;
9+
10+
parser.href = response.web_console_pattern;
11+
whitelistUrlPattern = parser.protocol + '//' + parser.host + '/**';
12+
13+
$sceDelegateProvider.resourceUrlWhitelist([
14+
'self',
15+
whitelistUrlPattern
16+
]);
17+
}
18+
});
19+
})
420
.directive('projectDetail', function($resource, $log, projectService, $window, $location){
521
return {
622
restrict: 'E',
@@ -18,11 +34,10 @@ angular.module('composeUiApp')
1834
}
1935
});
2036

21-
22-
2337
var Host = $resource('api/v1/host');
2438
var Yml = $resource('api/v1/projects/yml/:id');
2539
var Readme = $resource('api/v1/projects/readme/:id');
40+
var WebConsolePattern = $resource('api/v1/web_console_pattern');
2641

2742
$scope.$watch('projectId', function (val) {
2843
if (val) {
@@ -57,7 +72,24 @@ angular.module('composeUiApp')
5772
$scope.logs = data.logs;
5873
});
5974
};
75+
76+
$scope.containerConsolePattern = null;
77+
WebConsolePattern.get(function(data) {
78+
if (data.web_console_pattern) {
79+
$scope.containerConsolePattern = data.web_console_pattern;
80+
}
81+
});
6082

83+
$scope.openConsole = function(containerName, shell) {
84+
if ($scope.containerConsolePattern) {
85+
console.log('Opening console for ' + containerName + ' with shell ' + shell);
86+
87+
$scope.containerConsoleUrl = $scope.containerConsolePattern.replace('{containerName}', containerName).replace('{command}', shell);
88+
$scope.containerName = containerName;
89+
$scope.showConsoleDialog = true;
90+
}
91+
};
92+
6193
$scope.rebuild = function(serviceName) {
6294
$scope.working = true;
6395
Project.save({id: $scope.projectId, service_names: [serviceName], do_build: true},

static/styles/main.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,4 +168,8 @@ header {
168168

169169
.btn {
170170
padding: 6px 9px;
171+
}
172+
173+
.shell-selector-list a {
174+
cursor: pointer;
171175
}

static/views/project-detail.html

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,28 @@ <h5>
5454

5555
<div class="panel" ng-class="{'active': container.is_running, 'off': !container.is_running}">
5656
<div class="panel-heading">
57+
5758
<span ng-class="{'text-muted': !container.is_running}">
5859
{{container.name_without_project}}
5960
</span>
60-
<button class="btn btn-xs btn-default" ng-click="displayLogs(container.name)">logs</button>
61-
<a class="btn btn-xs btn-default" ng-href="#/project/{{projectId}}/{{container.name}}">details</a>
62-
<button class="btn btn-xs btn-default" ng-click="rebuild(id)">rebuild</button>
61+
<br/>
62+
63+
<div class="btn-group" role="group" >
64+
<button class="btn btn-xs btn-default" ng-click="displayLogs(container.name)">logs</button>
65+
<a class="btn btn-xs btn-default" ng-href="#/project/{{projectId}}/{{container.name}}">details</a>
66+
<button class="btn btn-xs btn-default" ng-click="rebuild(id)">rebuild</button>
67+
68+
<div class="btn-group" role="group" ng-show="containerConsolePattern">
69+
<button class="btn btn-xs btn-default dropdown-toggle" type="button" id="shellSelector" data-toggle="dropdown">
70+
console <span class="caret"></span>
71+
</button>
72+
<ul class="dropdown-menu shell-selector-list">
73+
<li><a ng-click="openConsole(container.name, '/bin/bash')">/bin/bash</a></li>
74+
<li><a ng-click="openConsole(container.name, '/bin/sh')">/bin/sh</a></li>
75+
</ul>
76+
</div>
77+
</div>
78+
6379
</div>
6480
<div class="panel-body">
6581

@@ -103,6 +119,23 @@ <h4 class="modal-title">{{containerLogs}} logs</h4>
103119
</div>
104120
</div>
105121
</div>
122+
123+
<div console-modal-show="showConsoleDialog" class="modal fade" tabindex="-1">
124+
<div class="modal-dialog modal-lg" role="document">
125+
<div class="modal-content">
126+
<div class="modal-header">
127+
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
128+
<h4 class="modal-title">{{containerName}} console</h4>
129+
</div>
130+
<div class="modal-body">
131+
<iframe ng-if="containerConsoleUrl" src="{{containerConsoleUrl}}" style="width: 800px; height: 450px; border: none;"></iframe>
132+
</div>
133+
<div class="modal-footer">
134+
</div>
135+
</div>
136+
</div>
137+
</div>
138+
106139
<span ng-show="isEmpty(services)">no containers found</span>
107140
</div>
108141

0 commit comments

Comments
 (0)