diff --git a/main.py b/main.py index 52e9f3a..11ba14e 100644 --- a/main.py +++ b/main.py @@ -12,7 +12,7 @@ import requests from flask import Flask, jsonify, request from scripts.git_repo import git_pull, git_repo, GIT_YML_PATH -from scripts.bridge import ps_, get_project, get_container_from_id, get_yml_path, containers, project_config, info +from scripts.bridge import ps_, get_project, get_container_from_id, get_yml_path, containers, project_config, info, client from scripts.find_files import find_yml_files, get_readme_file, get_logo_file from scripts.requires_auth import requires_auth, authentication_enabled, \ disable_authentication, set_authentication @@ -79,6 +79,55 @@ def project_containers(name): project = get_project_with_name(name) return jsonify(containers=ps_(project)) +@app.route(API_V1 + "exec/", methods=['POST']) +@requires_auth +def run_exec(container_id): + """ + Run a one-off exec command in a specific container specified by the + "container_id" param. + """ + + json = loads(request.data) + + if 'command' not in json: + raise Exception('run_exec expects command to be set in JSON body') + + command = json['command'] + container = get_container_from_id(client(), container_id) + + r = container.create_exec(command) + + if 'Id' not in r: + raise Exception('Unable to create exec for command "%s"' % command) + + container.start_exec(r['Id'], detach=True) + + return jsonify(\ + id=r['Id'], \ + command=command, \ + container=container.name, \ + container_id=container.id \ + ) + +@app.route(API_V1 + "exec//", methods=['GET']) +@requires_auth +def inspect_exec(container_id, exec_id): + """ + Inspect a one-off exec command ran with `run_exec`. + """ + + container = get_container_from_id(client(), container_id) + r = client().exec_inspect(exec_id) + + return jsonify(\ + id=exec_id, \ + running=r.get('Running'), \ + code=r.get('ExitCode'), \ + pid=r.get('Pid'), \ + container_id=r.get('ContainerID') \ + ) + + @app.route(API_V1 + "projects//", methods=['POST']) @requires_auth def run_service(project, service_id): diff --git a/static/scripts/directives/project-detail.js b/static/scripts/directives/project-detail.js index d98a41d..8017ed1 100644 --- a/static/scripts/directives/project-detail.js +++ b/static/scripts/directives/project-detail.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('composeUiApp') - .directive('projectDetail', function($resource, $log, projectService, $window, $location){ + .directive('projectDetail', function($resource, $log, projectService, $window, $location, $timeout){ return { restrict: 'E', scope: { @@ -19,7 +19,6 @@ angular.module('composeUiApp') }); - var Host = $resource('api/v1/host'); var Yml = $resource('api/v1/projects/yml/:id'); var Readme = $resource('api/v1/projects/readme/:id'); @@ -58,6 +57,45 @@ angular.module('composeUiApp') }); }; + var Exec = $resource('api/v1/exec/:container/:id'); + + $scope.showRunCommand = function (container) { + $scope.container = container; + $scope.showRunDialog = true; + }; + $scope.runCommand = function (container_id, command) { + Exec.save({ + container: container_id + }, { + command: command + }, function(r) { + alertify.success('`' + r.command + '` running in ' + r.container + '.'); + + // repeatedly check exec command exit code + var checkExec = function() { + // check for successful exit code + Exec.get({ + container: container_id, + id: r.id + }, function (exec) { + if (exec.running) { + // keep checking until the command is finished + return $timeout(checkExec, 5000); + } + + if (exec.code === 0) { + alertify.success('`' + r.command + '` successfully completed in ' + r.container + '.'); + } else { + alertify.error('`' + r.command + '` exited with non-zero exit code'); + } + }); + }; + checkExec(); + }, function() { + alertify.error('Error running `' + command + '`'); + }); + }; + $scope.rebuild = function(serviceName) { $scope.working = true; Project.save({id: $scope.projectId, service_names: [serviceName], do_build: true}, diff --git a/static/views/project-detail.html b/static/views/project-detail.html index e0f318a..720aeac 100644 --- a/static/views/project-detail.html +++ b/static/views/project-detail.html @@ -60,6 +60,7 @@
details +
@@ -103,6 +104,26 @@
+ no containers found