From 81aa5d5d8f410c81f873ad603f80d98a9e97bf61 Mon Sep 17 00:00:00 2001 From: Alexander Kastius Date: Wed, 16 Sep 2015 18:34:04 +0200 Subject: [PATCH] Fixed submission-scoring. Added parsing of exit cmd. --- app/controllers/submissions_controller.rb | 41 +++++++++++++++++------ lib/docker_client.rb | 33 +++++++++--------- webpython/Dockerfile | 1 - 3 files changed, 49 insertions(+), 26 deletions(-) diff --git a/app/controllers/submissions_controller.rb b/app/controllers/submissions_controller.rb index a84f069e..b246de80 100644 --- a/app/controllers/submissions_controller.rb +++ b/app/controllers/submissions_controller.rb @@ -93,20 +93,40 @@ class SubmissionsController < ApplicationController Thread.new { EventMachine.run } unless EventMachine.reactor_running? && EventMachine.reactor_thread.alive? result = @docker_client.execute_run_command(@submission, params[:filename]) - socket = result[:socket] - socket.on :message do |event| - Rails.logger.info("Docker sending: " + event.data) - handle_message(event.data, tubesock) - end - - socket.on :close do |event| + if result[:status] == :container_depleted + tubesock.send_data JSON.dump({'cmd' => 'container_depleted'}) kill_socket(tubesock) end - tubesock.onmessage do |data| - Rails.logger.info("Client sending: " + data) - socket.send data + if result[:status] == :container_running + socket = result[:socket] + + socket.on :message do |event| + Rails.logger.info("Docker sending: " + event.data) + handle_message(event.data, tubesock) + end + + socket.on :close do |event| + kill_socket(tubesock) + end + + tubesock.onmessage do |data| + Rails.logger.info("Client sending: " + data) + # Check wether the client send a JSON command and kill container + # if the command is 'exit', send it to docker otherwise. + begin + parsed = JSON.parse(data) + if parsed['cmd'] == 'exit' + Rails.logger.info("Client killed container.") + @docker_client.kill_container(result[:container]) + else + socket.send data + end + rescue JSON::ParserError + socket.send data + end + end end end end @@ -134,6 +154,7 @@ class SubmissionsController < ApplicationController parsed = JSON.parse(message) socket.send_data message rescue JSON::ParserError => e + # Check wether the message contains multiple lines, if true try to parse each line if ((recursive == true) && (message.include? "\n")) for part in message.split("\n") self.parse_message(part,output_stream,socket,false) diff --git a/lib/docker_client.rb b/lib/docker_client.rb index 3b39c71b..1c0de144 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -155,7 +155,7 @@ class DockerClient @socket ||= create_socket(@container) # Newline required to flush @socket.send command + "\n" - {status: :container_running, socket: @socket} + {status: :container_running, socket: @socket, container: @container} else {status: :container_depleted} end @@ -170,22 +170,25 @@ class DockerClient timeout = @execution_environment.permitted_execution_time.to_i # seconds sleep(timeout) Rails.logger.info("Killing container after timeout of " + timeout.to_s + " seconds.") - # if we use pooling and recylce the containers, put it back. otherwise, destroy it. - # (DockerContainerPool.config[:active] && RECYCLE_CONTAINERS) ? self.class.return_container(container, @execution_environment) : self.class.destroy_container(container) + kill_container(container) + end + end - # todo won't this always create a new container? - # remove container from pool, then destroy it - (DockerContainerPool.config[:active]) ? DockerContainerPool.remove_from_all_containers(container, @execution_environment) : + def kill_container(container) - # destroy container - self.class.destroy_container(container) + # todo won't this always create a new container? + # It does, because it's impossible to determine wether a programm is still running or not while using ws to run. + # remove container from pool, then destroy it + (DockerContainerPool.config[:active]) ? DockerContainerPool.remove_from_all_containers(container, @execution_environment) : - # if we recylce containers, we start a fresh one - if(DockerContainerPool.config[:active] && RECYCLE_CONTAINERS) - # create new container and add it to @all_containers and @containers. - container = self.class.create_container(@execution_environment) - DockerContainerPool.add_to_all_containers(container, @execution_environment) - end + #destroy container + self.class.destroy_container(container) + + # if we recylce containers, we start a fresh one + if(DockerContainerPool.config[:active] && RECYCLE_CONTAINERS) + # create new container and add it to @all_containers and @containers. + container = self.class.create_container(@execution_environment) + DockerContainerPool.add_to_all_containers(container, @execution_environment) end end @@ -198,7 +201,7 @@ class DockerClient execute_websocket_command(command, create_workspace_files, block) end - def execute_test_command(subbmission, filename, &block) + def execute_test_command(submission, filename, &block) """ Stick to existing Docker API with exec command. """ diff --git a/webpython/Dockerfile b/webpython/Dockerfile index 978d68b0..54f1b014 100644 --- a/webpython/Dockerfile +++ b/webpython/Dockerfile @@ -5,7 +5,6 @@ ENV LANG en_US.UTF-8 ADD webpython.py /usr/lib/python3.4/webpython.py RUN rm /usr/lib/python3.4/turtle.py ADD turtle.py /usr/lib/python3.4/turtle.py -ADD assess /usr/lib/python3.4/assess RUN adduser --disabled-password --gecos Python python USER python WORKDIR /home/python