Merge branch 'master' into statistics

This commit is contained in:
Ralf Teusner
2015-12-15 15:36:24 +01:00
10 changed files with 113 additions and 75 deletions

View File

@ -5,8 +5,8 @@ gem 'bcrypt', '~> 3.1.7'
gem 'bootstrap-will_paginate' gem 'bootstrap-will_paginate'
gem 'carrierwave' gem 'carrierwave'
gem 'coffee-rails', '~> 4.0.0' gem 'coffee-rails', '~> 4.0.0'
gem 'concurrent-ruby' gem 'concurrent-ruby', '~> 1.0.0'
gem 'concurrent-ruby-ext', platform: :ruby gem 'concurrent-ruby-ext', '~> 1.0.0', platform: :ruby
gem 'docker-api','~> 1.21.1', require: 'docker' gem 'docker-api','~> 1.21.1', require: 'docker'
gem 'factory_girl_rails', '~> 4.0' gem 'factory_girl_rails', '~> 4.0'
gem 'forgery' gem 'forgery'
@ -19,9 +19,9 @@ gem 'kramdown'
gem 'newrelic_rpm' gem 'newrelic_rpm'
gem 'pg', platform: :ruby gem 'pg', platform: :ruby
gem 'pry' gem 'pry'
gem 'puma' gem 'puma', '~> 2.15.3'
gem 'pundit' gem 'pundit'
gem 'rails', '~> 4.1.2' gem 'rails', '~> 4.1.13'
gem 'rails-i18n', '~> 4.0.0' gem 'rails-i18n', '~> 4.0.0'
gem 'ransack' gem 'ransack'
gem 'rubytree' gem 'rubytree'

View File

@ -2,32 +2,32 @@ GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
ZenTest (4.11.0) ZenTest (4.11.0)
actionmailer (4.1.10) actionmailer (4.1.14)
actionpack (= 4.1.10) actionpack (= 4.1.14)
actionview (= 4.1.10) actionview (= 4.1.14)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
actionpack (4.1.10) actionpack (4.1.14)
actionview (= 4.1.10) actionview (= 4.1.14)
activesupport (= 4.1.10) activesupport (= 4.1.14)
rack (~> 1.5.2) rack (~> 1.5.2)
rack-test (~> 0.6.2) rack-test (~> 0.6.2)
actionview (4.1.10) actionview (4.1.14)
activesupport (= 4.1.10) activesupport (= 4.1.14)
builder (~> 3.1) builder (~> 3.1)
erubis (~> 2.7.0) erubis (~> 2.7.0)
activemodel (4.1.10) activemodel (4.1.14)
activesupport (= 4.1.10) activesupport (= 4.1.14)
builder (~> 3.1) builder (~> 3.1)
activerecord (4.1.10) activerecord (4.1.14)
activemodel (= 4.1.10) activemodel (= 4.1.14)
activesupport (= 4.1.10) activesupport (= 4.1.14)
arel (~> 5.0.0) arel (~> 5.0.0)
activerecord-jdbc-adapter (1.3.15) activerecord-jdbc-adapter (1.3.15)
activerecord (>= 2.2) activerecord (>= 2.2)
activerecord-jdbcpostgresql-adapter (1.3.15) activerecord-jdbcpostgresql-adapter (1.3.15)
activerecord-jdbc-adapter (~> 1.3.15) activerecord-jdbc-adapter (~> 1.3.15)
jdbc-postgres (>= 9.1) jdbc-postgres (>= 9.1)
activesupport (4.1.10) activesupport (4.1.14)
i18n (~> 0.6, >= 0.6.9) i18n (~> 0.6, >= 0.6.9)
json (~> 1.7, >= 1.7.7) json (~> 1.7, >= 1.7.7)
minitest (~> 5.1) minitest (~> 5.1)
@ -95,11 +95,10 @@ GEM
execjs execjs
coffee-script-source (1.9.1) coffee-script-source (1.9.1)
colorize (0.7.7) colorize (0.7.7)
concurrent-ruby (0.8.0) concurrent-ruby (1.0.0)
ref (~> 1.0, >= 1.0.5) concurrent-ruby (1.0.0-java)
concurrent-ruby (0.8.0-java) concurrent-ruby-ext (1.0.0)
concurrent-ruby-ext (0.8.0) concurrent-ruby (~> 1.0.0)
concurrent-ruby (~> 0.8.0)
database_cleaner (1.4.1) database_cleaner (1.4.1)
debug_inspector (0.0.2) debug_inspector (0.0.2)
diff-lcs (1.2.5) diff-lcs (1.2.5)
@ -141,17 +140,17 @@ GEM
jquery-turbolinks (2.1.0) jquery-turbolinks (2.1.0)
railties (>= 3.1.0) railties (>= 3.1.0)
turbolinks turbolinks
json (1.8.2) json (1.8.3)
json (1.8.2-java) json (1.8.3-java)
jwt (1.4.1) jwt (1.4.1)
kramdown (1.6.0) kramdown (1.6.0)
mail (2.6.3) mail (2.6.3)
mime-types (>= 1.16, < 3) mime-types (>= 1.16, < 3)
method_source (0.8.2) method_source (0.8.2)
mime-types (2.4.3) mime-types (2.99)
mini_portile (0.6.2) mini_portile (0.6.2)
minitest (5.5.1) minitest (5.8.3)
multi_json (1.11.0) multi_json (1.11.2)
multi_xml (0.5.5) multi_xml (0.5.5)
multipart-post (2.0.0) multipart-post (2.0.0)
net-scp (1.2.1) net-scp (1.2.1)
@ -185,31 +184,29 @@ GEM
method_source (~> 0.8.1) method_source (~> 0.8.1)
slop (~> 3.4) slop (~> 3.4)
spoon (~> 0.0) spoon (~> 0.0)
puma (2.11.1) puma (2.15.3)
rack (>= 1.1, < 2.0) puma (2.15.3-java)
puma (2.11.1-java)
rack (>= 1.1, < 2.0)
pundit (0.3.0) pundit (0.3.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
rack (1.5.2) rack (1.5.5)
rack-test (0.6.3) rack-test (0.6.3)
rack (>= 1.0) rack (>= 1.0)
rails (4.1.10) rails (4.1.14)
actionmailer (= 4.1.10) actionmailer (= 4.1.14)
actionpack (= 4.1.10) actionpack (= 4.1.14)
actionview (= 4.1.10) actionview (= 4.1.14)
activemodel (= 4.1.10) activemodel (= 4.1.14)
activerecord (= 4.1.10) activerecord (= 4.1.14)
activesupport (= 4.1.10) activesupport (= 4.1.14)
bundler (>= 1.3.0, < 2.0) bundler (>= 1.3.0, < 2.0)
railties (= 4.1.10) railties (= 4.1.14)
sprockets-rails (~> 2.0) sprockets-rails (~> 2.0)
rails-i18n (4.0.4) rails-i18n (4.0.4)
i18n (~> 0.6) i18n (~> 0.6)
railties (~> 4.0) railties (~> 4.0)
railties (4.1.10) railties (4.1.14)
actionpack (= 4.1.10) actionpack (= 4.1.14)
activesupport (= 4.1.10) activesupport (= 4.1.14)
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rainbow (2.0.0) rainbow (2.0.0)
@ -221,7 +218,6 @@ GEM
i18n i18n
polyamorous (~> 1.2) polyamorous (~> 1.2)
rdoc (4.2.0) rdoc (4.2.0)
ref (1.0.5)
rspec (3.1.0) rspec (3.1.0)
rspec-core (~> 3.1.0) rspec-core (~> 3.1.0)
rspec-expectations (~> 3.1.0) rspec-expectations (~> 3.1.0)
@ -286,12 +282,12 @@ GEM
spoon (0.0.4) spoon (0.0.4)
ffi ffi
spring (1.3.4) spring (1.3.4)
sprockets (2.12.3) sprockets (2.12.4)
hike (~> 1.2) hike (~> 1.2)
multi_json (~> 1.0) multi_json (~> 1.0)
rack (~> 1.0) rack (~> 1.0)
tilt (~> 1.1, != 1.3.0) tilt (~> 1.1, != 1.3.0)
sprockets-rails (2.2.4) sprockets-rails (2.3.3)
actionpack (>= 3.0) actionpack (>= 3.0)
activesupport (>= 3.0) activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0) sprockets (>= 2.8, < 4.0)
@ -351,8 +347,8 @@ DEPENDENCIES
carrierwave carrierwave
codeclimate-test-reporter codeclimate-test-reporter
coffee-rails (~> 4.0.0) coffee-rails (~> 4.0.0)
concurrent-ruby concurrent-ruby (~> 1.0.0)
concurrent-ruby-ext concurrent-ruby-ext (~> 1.0.0)
database_cleaner database_cleaner
docker-api (~> 1.21.1) docker-api (~> 1.21.1)
factory_girl_rails (~> 4.0) factory_girl_rails (~> 4.0)
@ -368,9 +364,9 @@ DEPENDENCIES
nyan-cat-formatter nyan-cat-formatter
pg pg
pry pry
puma puma (~> 2.15.3)
pundit pundit
rails (~> 4.1.2) rails (~> 4.1.13)
rails-i18n (~> 4.0.0) rails-i18n (~> 4.0.0)
rake rake
ransack ransack

View File

@ -100,12 +100,12 @@ $(function() {
} }
}; };
var confirmSubmission = function(event) { //var confirmSubmission = function(event) {
event.preventDefault(); // event.preventDefault();
if (confirm($(this).data('message-confirm'))) { // if (confirm($(this).data('message-confirm'))) {
submitCode(); // submitCode();
} // }
}; //};
var createSubmission = function(initiator, filter, callback) { var createSubmission = function(initiator, filter, callback) {
showSpinner(initiator); showSpinner(initiator);
@ -637,7 +637,8 @@ $(function() {
var initializeWorkflowButtons = function() { var initializeWorkflowButtons = function() {
$('#start').on('click', showWorkspaceTab); $('#start').on('click', showWorkspaceTab);
$('#submit').on('click', confirmSubmission); //$('#submit').on('click', confirmSubmission);
$('#submit').on('click', submitCode);
}; };
var initializeWorkspaceButtons = function() { var initializeWorkspaceButtons = function() {

View File

@ -33,6 +33,7 @@ function Turtle(pipe, canvas) {
'x': xpos - dx, 'x': xpos - dx,
'y': ypos - dy 'y': ypos - dy
})); }));
pipe.send('\n');
}); });
} }

View File

@ -1,9 +1,6 @@
- unless local_assigns[:modal] - unless local_assigns[:modal]
h1 = t('shared.help.headline') h1 = t('shared.help.headline')
h2 = t('shared.help.general_help')
== Forgery(:lorem_ipsum).paragraphs(10, html: true)
- if local_assigns.has_key?(:execution_environment) - if local_assigns.has_key?(:execution_environment)
h2 = t('shared.help.execution_environment_specific_help', execution_environment: execution_environment) h2 = t('shared.help.execution_environment_specific_help', execution_environment: execution_environment)
= render_markdown(execution_environment.help) = render_markdown(execution_environment.help)

View File

@ -76,8 +76,7 @@
br br
- if session[:lti_parameters].try(:has_key?, 'lis_outcome_service_url') - if session[:lti_parameters].try(:has_key?, 'lis_outcome_service_url')
p.text-center = render('editor_button', classes: 'btn-lg btn-success', data: {:'data-message-confirm' => t('exercises.editor.confirm_submit'), :'data-url' => submit_exercise_path(@exercise)}, icon: 'fa fa-send', id: 'submit', label: t('exercises.editor.submit')) p.text-center = render('editor_button', classes: 'btn-lg btn-success', data: {:'data-url' => submit_exercise_path(@exercise)}, icon: 'fa fa-send', id: 'submit', label: t('exercises.editor.submit'))
- if qa_url - if qa_url
#questions-column #questions-column
#questions-holder data-url="#{qa_url}/qa/index/#{@exercise.id}/#{@user_id}" #questions-holder data-url="#{qa_url}/qa/index/#{@exercise.id}/#{@user_id}"

View File

@ -33,6 +33,8 @@ module CodeOcean
case (RUBY_ENGINE) case (RUBY_ENGINE)
when 'ruby' when 'ruby'
# ... # ...
#this is enabled in prod for testing
config.middleware.use ActiveRecord::ConnectionAdapters::ConnectionManagement
when 'jruby' when 'jruby'
# plattform specific # plattform specific
java.lang.Class.for_name('javax.crypto.JceSecurity').get_declared_field('isRestricted').tap{|f| f.accessible = true; f.set nil, false} java.lang.Class.for_name('javax.crypto.JceSecurity').get_declared_field('isRestricted').tap{|f| f.accessible = true; f.set nil, false}

View File

@ -18,8 +18,8 @@ production:
active: true active: true
refill: refill:
async: false async: false
batch_size: 32 batch_size: 8
interval: 30 interval: 15
timeout: 60 timeout: 60
workspace_root: <%= Rails.root.join('tmp', 'files', Rails.env) %> workspace_root: <%= Rails.root.join('tmp', 'files', Rails.env) %>
ws_host: ws://localhost:4243 ws_host: ws://localhost:4243

View File

@ -88,6 +88,8 @@ class DockerClient
def self.create_container(execution_environment) def self.create_container(execution_environment)
tries ||= 0 tries ||= 0
Rails.logger.info "docker_client: self.create_container with creation options:"
Rails.logger.info(container_creation_options(execution_environment))
container = Docker::Container.create(container_creation_options(execution_environment)) container = Docker::Container.create(container_creation_options(execution_environment))
local_workspace_path = generate_local_workspace_path local_workspace_path = generate_local_workspace_path
# container.start always creates the passed local_workspace_path on disk. Seems like we have to live with that, therefore we can also just create the empty folder ourselves. # container.start always creates the passed local_workspace_path on disk. Seems like we have to live with that, therefore we can also just create the empty folder ourselves.
@ -97,7 +99,7 @@ class DockerClient
container.status = :created container.status = :created
container container
rescue Docker::Error::NotFoundError => error rescue Docker::Error::NotFoundError => error
Rails.logger.info('create_container: Got Docker::Error::NotFoundError: ' + error) Rails.logger.info('create_container: Got Docker::Error::NotFoundError: ' + error.to_s)
destroy_container(container) destroy_container(container)
#(tries += 1) <= RETRY_COUNT ? retry : raise(error) #(tries += 1) <= RETRY_COUNT ? retry : raise(error)
end end
@ -113,6 +115,8 @@ class DockerClient
create_workspace_file(container: container, file: file) create_workspace_file(container: container, file: file)
end end
end end
rescue Docker::Error::NotFoundError => error
Rails.logger.info('create_workspace_files: Rescued from Docker::Error::NotFoundError: ' + error.to_s)
end end
private :create_workspace_files private :create_workspace_files
@ -131,6 +135,9 @@ class DockerClient
if(container) if(container)
container.delete(force: true, v: true) container.delete(force: true, v: true)
end end
rescue Docker::Error::NotFoundError => error
Rails.logger.error('destroy_container: Rescued from Docker::Error::NotFoundError: ' + error.to_s)
Rails.logger.error('No further actions are done concerning that.')
end end
def execute_arbitrary_command(command, &block) def execute_arbitrary_command(command, &block)
@ -297,7 +304,12 @@ class DockerClient
def self.return_container(container, execution_environment) def self.return_container(container, execution_environment)
Rails.logger.debug('returning container ' + container.to_s) Rails.logger.debug('returning container ' + container.to_s)
clean_container_workspace(container) begin
clean_container_workspace(container)
rescue Docker::Error::NotFoundError => error
Rails.logger.info('return_container: Rescued from Docker::Error::NotFoundError: ' + error.to_s)
Rails.logger.info('Nothing is done here additionally. The container will be exchanged upon its next retrieval.')
end
DockerContainerPool.return_container(container, execution_environment) DockerContainerPool.return_container(container, execution_environment)
container.status = :returned container.status = :returned
end end

View File

@ -1,6 +1,6 @@
require 'concurrent/future' require 'concurrent/future'
require 'concurrent/timer_task' require 'concurrent/timer_task'
require 'concurrent/utilities'
class DockerContainerPool class DockerContainerPool
@ -18,10 +18,19 @@ class DockerContainerPool
@config ||= CodeOcean::Config.new(:docker).read(erb: true)[:pool] @config ||= CodeOcean::Config.new(:docker).read(erb: true)[:pool]
end end
def self.containers
@containers
end
def self.all_containers
@all_containers
end
def self.remove_from_all_containers(container, execution_environment) def self.remove_from_all_containers(container, execution_environment)
@all_containers[execution_environment.id]-=[container] @all_containers[execution_environment.id]-=[container]
if(@containers[execution_environment.id].include?(container)) if(@containers[execution_environment.id].include?(container))
@containers[execution_environment.id]-=[container] @containers[execution_environment.id]-=[container]
Rails.logger.debug('Removed container ' + container.to_s + ' from all_pool for execution environment ' + execution_environment.to_s + '. Remaining containers in all_pool ' + @all_containers[execution_environment.id].size.to_s)
end end
end end
@ -29,6 +38,7 @@ class DockerContainerPool
@all_containers[execution_environment.id]+=[container] @all_containers[execution_environment.id]+=[container]
if(!@containers[execution_environment.id].include?(container)) if(!@containers[execution_environment.id].include?(container))
@containers[execution_environment.id]+=[container] @containers[execution_environment.id]+=[container]
Rails.logger.debug('Added container ' + container.to_s + ' to all_pool for execution environment ' + execution_environment.to_s + '. Containers in all_pool: ' + @all_containers[execution_environment.id].size.to_s)
else else
Rails.logger.info('failed trying to add existing container ' + container.to_s + ' to execution_environment ' + execution_environment.to_s) Rails.logger.info('failed trying to add existing container ' + container.to_s + ' to execution_environment ' + execution_environment.to_s)
end end
@ -57,9 +67,28 @@ class DockerContainerPool
Rails.logger.debug('get_container fetched container ' + container.to_s + ' for execution environment ' + execution_environment.to_s) Rails.logger.debug('get_container fetched container ' + container.to_s + ' for execution environment ' + execution_environment.to_s)
# just access and the following if we got a container. Otherwise, the execution_environment might be just created and not fully exist yet. # just access and the following if we got a container. Otherwise, the execution_environment might be just created and not fully exist yet.
if(container) if(container)
Rails.logger.debug('get_container remaining avail. containers: ' + @containers[execution_environment.id].size.to_s) begin
Rails.logger.debug('get_container all container count: ' + @all_containers[execution_environment.id].size.to_s) # check whether the container is running. exited containers go to the else part.
# Dead containers raise a NotFOundError on the container.json call. This is handled in the rescue block.
if(container.json['State']['Running'])
Rails.logger.debug('get_container remaining avail. containers: ' + @containers[execution_environment.id].size.to_s)
Rails.logger.debug('get_container all container count: ' + @all_containers[execution_environment.id].size.to_s)
else
Rails.logger.error('docker_container_pool.get_container retrieved a container not running. Container will be removed from list: ' + container.to_s)
remove_from_all_containers(container, execution_environment)
Rails.logger.error('Creating a new container and returning that.')
container = create_container(execution_environment)
DockerContainerPool.add_to_all_containers(container, execution_environment)
end
rescue Docker::Error::NotFoundError => error
Rails.logger.error('docker_container_pool.get_container rescued from Docker::Error::NotFoundError. Most likely, the container is not there any longer. Removing faulty entry from list: ' + container.to_s)
remove_from_all_containers(container, execution_environment)
Rails.logger.error('Creating a new container and returning that.')
container = create_container(execution_environment)
DockerContainerPool.add_to_all_containers(container, execution_environment)
end
end end
# returning nil is no problem. then the pool is just depleted.
container container
else else
create_container(execution_environment) create_container(execution_environment)
@ -71,7 +100,7 @@ class DockerContainerPool
end end
def self.refill def self.refill
ExecutionEnvironment.where('pool_size > 0').each do |execution_environment| ExecutionEnvironment.where('pool_size > 0').order(pool_size: :desc).each do |execution_environment|
if config[:refill][:async] if config[:refill][:async]
Concurrent::Future.execute { refill_for_execution_environment(execution_environment) } Concurrent::Future.execute { refill_for_execution_environment(execution_environment) }
else else
@ -85,18 +114,19 @@ class DockerContainerPool
if refill_count > 0 if refill_count > 0
Rails.logger.info('Adding ' + refill_count.to_s + ' containers for execution_environment ' + execution_environment.name ) Rails.logger.info('Adding ' + refill_count.to_s + ' containers for execution_environment ' + execution_environment.name )
c = refill_count.times.map { create_container(execution_environment) } c = refill_count.times.map { create_container(execution_environment) }
Rails.logger.debug('Created containers: ' + c.to_s ) Rails.logger.info('Created containers: ' + c.to_s )
#c.each { |container| return_container(container, execution_environment) }
@containers[execution_environment.id] += c @containers[execution_environment.id] += c
@all_containers[execution_environment.id] += c @all_containers[execution_environment.id] += c
Rails.logger.debug('@containers ' + @containers.object_id.to_s + ' has:'+ @containers[execution_environment.id].to_s) Rails.logger.debug('@containers for ' + execution_environment.name.to_s + ' (' + @containers.object_id.to_s + ') has the following content: '+ @containers[execution_environment.id].to_s)
Rails.logger.debug('@all_containers ' + @containers.object_id.to_s + ' has:'+ @all_containers[execution_environment.id].to_s) Rails.logger.debug('@all_containers for ' + execution_environment.name.to_s + ' (' + @all_containers.object_id.to_s + ') has the following content: ' + @all_containers[execution_environment.id].to_s)
#refill_count.times.map { create_container(execution_environment) } #refill_count.times.map { create_container(execution_environment) }
end end
end end
def self.start_refill_task def self.start_refill_task
@refill_task = Concurrent::TimerTask.new(execution_interval: config[:refill][:interval], run_now: false, timeout_interval: config[:refill][:timeout]) { refill } @refill_task = Concurrent::TimerTask.new(execution_interval: config[:refill][:interval], run_now: true, timeout_interval: config[:refill][:timeout]) { refill }
@refill_task.execute @refill_task.execute
end end
end end