From 518016d37594996a674f1b1f39f78258236b9974 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Wed, 8 Apr 2015 18:19:33 +0200 Subject: [PATCH 01/95] Smaller buttons --- app/views/exercises/_editor_file_tree.html.slim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/exercises/_editor_file_tree.html.slim b/app/views/exercises/_editor_file_tree.html.slim index cad3c845..c5fe9384 100644 --- a/app/views/exercises/_editor_file_tree.html.slim +++ b/app/views/exercises/_editor_file_tree.html.slim @@ -2,8 +2,8 @@ hr -= render('editor_button', classes: 'btn-block btn-primary btn-sm', data: {:'data-cause' => 'file'}, icon: 'fa fa-plus', id: 'create-file', label: t('exercises.editor.create_file')) -= render('editor_button', classes: 'btn-block btn-warning btn-sm', data: {:'data-cause' => 'file', :'data-message-confirm' => t('shared.confirm_destroy')}, icon: 'fa fa-times', id: 'destroy-file', label: t('exercises.editor.destroy_file')) -= render('editor_button', classes: 'btn-block btn-primary btn-sm', icon: 'fa fa-download', id: 'download', label: t('exercises.editor.download')) += render('editor_button', classes: 'btn-block btn-primary btn-xs', data: {:'data-cause' => 'file'}, icon: 'fa fa-plus', id: 'create-file', label: t('exercises.editor.create_file')) += render('editor_button', classes: 'btn-block btn-warning btn-xs', data: {:'data-cause' => 'file', :'data-message-confirm' => t('shared.confirm_destroy')}, icon: 'fa fa-times', id: 'destroy-file', label: t('exercises.editor.destroy_file')) += render('editor_button', classes: 'btn-block btn-primary btn-xs', icon: 'fa fa-download', id: 'download', label: t('exercises.editor.download')) = render('shared/modal', id: 'modal-file', template: 'code_ocean/files/_form', title: t('exercises.editor.create_file')) From 6ee3218ee6aacae8d6379105047b2c7b919b3686 Mon Sep 17 00:00:00 2001 From: Hauke Klement Date: Wed, 8 Apr 2015 21:47:59 +0200 Subject: [PATCH 02/95] updated Underscore to 1.8.3 --- app/views/layouts/application.html.slim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim index ee780de7..c527bc8b 100644 --- a/app/views/layouts/application.html.slim +++ b/app/views/layouts/application.html.slim @@ -9,7 +9,7 @@ html lang='en' = stylesheet_link_tag('//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css') = stylesheet_link_tag('application', media: 'all', 'data-turbolinks-track' => true) = javascript_include_tag('application', 'data-turbolinks-track' => true) - = javascript_include_tag('//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.2/underscore-min.js') + = javascript_include_tag('//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js') = javascript_include_tag('//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js') = yield(:head) = csrf_meta_tags From 1f4f290de43f4847b7d9eb0ccbaff5d2caa75a2e Mon Sep 17 00:00:00 2001 From: Hauke Klement Date: Wed, 8 Apr 2015 21:48:52 +0200 Subject: [PATCH 03/95] updated bundle --- Gemfile.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index cbebab3f..55123c4c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -50,7 +50,7 @@ GEM bootstrap-will_paginate (0.0.10) will_paginate builder (3.2.2) - byebug (4.0.3) + byebug (4.0.5) columnize (= 0.9.0) capistrano (3.3.5) capistrano-stats (~> 1.1.0) @@ -83,7 +83,7 @@ GEM activesupport (>= 3.2.0) json (>= 1.7) mime-types (>= 1.16) - childprocess (0.5.5) + childprocess (0.5.6) ffi (~> 1.0, >= 1.0.11) codeclimate-test-reporter (0.4.7) simplecov (>= 0.7.1, < 1.0.0) @@ -91,7 +91,7 @@ GEM coffee-rails (4.0.1) coffee-script (>= 2.2.0) railties (>= 4.0.0, < 5.0) - coffee-script (2.3.0) + coffee-script (2.4.1) coffee-script-source execjs coffee-script-source (1.9.1) @@ -106,12 +106,12 @@ GEM debug_inspector (0.0.2) diff-lcs (1.2.5) docile (1.1.5) - docker-api (1.20.0) + docker-api (1.21.0) excon (>= 0.38.0) json erubis (2.7.0) - excon (0.45.0) - execjs (2.4.0) + excon (0.45.1) + execjs (2.5.0) factory_girl (4.5.0) activesupport (>= 3.0.0) factory_girl_rails (4.5.0) @@ -169,7 +169,7 @@ GEM parser (2.2.0.3) ast (>= 1.1, < 3.0) pg (0.18.1) - polyamorous (1.1.0) + polyamorous (1.2.0) activerecord (>= 3.0) powerpack (0.1.0) pry (0.10.1) @@ -210,12 +210,12 @@ GEM thor (>= 0.18.1, < 2.0) rainbow (2.0.0) rake (10.4.2) - ransack (1.6.4) + ransack (1.6.6) actionpack (>= 3.0) activerecord (>= 3.0) activesupport (>= 3.0) i18n - polyamorous (~> 1.1) + polyamorous (~> 1.2) rdoc (4.2.0) ref (1.0.5) rspec (3.1.0) @@ -240,7 +240,7 @@ GEM rspec-mocks (~> 3.1.0) rspec-support (~> 3.1.0) rspec-support (3.1.2) - rubocop (0.29.1) + rubocop (0.30.0) astrolabe (~> 1.3) parser (>= 2.2.0.1, < 3.0) powerpack (~> 0.1) @@ -275,13 +275,13 @@ GEM temple (~> 0.7.3) tilt (>= 1.3.3, < 2.1) slop (3.6.0) - sorcery (0.9.0) + sorcery (0.9.1) bcrypt (~> 3.1) oauth (~> 0.4, >= 0.4.4) oauth2 (>= 0.8.0) spoon (0.0.4) ffi - spring (1.3.3) + spring (1.3.4) sprockets (2.12.3) hike (~> 1.2) multi_json (~> 1.0) From 4a6e8c7c0af8c1583658b0f13bcda51953543521 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Thu, 9 Apr 2015 09:50:39 +0200 Subject: [PATCH 04/95] Minor style changes --- app/assets/stylesheets/base.css.scss | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/base.css.scss b/app/assets/stylesheets/base.css.scss index bbd74a94..e6e0e92c 100644 --- a/app/assets/stylesheets/base.css.scss +++ b/app/assets/stylesheets/base.css.scss @@ -1,5 +1,10 @@ h1 { - margin-bottom: 1em; + font-size: 25px; + margin-bottom: 0.5em; +} + +.lead { + font-size: 16px; } i.fa { From 6b025aeda94c29ea1da716959a456fed43913f57 Mon Sep 17 00:00:00 2001 From: Hauke Klement Date: Sat, 11 Apr 2015 16:54:48 +0200 Subject: [PATCH 05/95] added New Relic --- Gemfile | 1 + Gemfile.lock | 2 + config/deploy.rb | 2 +- config/newrelic.yml.example | 220 ++++++++++++++++++++++++++++++++++++ 4 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 config/newrelic.yml.example diff --git a/Gemfile b/Gemfile index 19a51b8b..f9f6e208 100644 --- a/Gemfile +++ b/Gemfile @@ -16,6 +16,7 @@ gem 'jquery-rails' gem 'jquery-turbolinks' gem 'ims-lti' gem 'kramdown' +gem 'newrelic_rpm' gem 'pg', platform: :ruby gem 'pry' gem 'puma' diff --git a/Gemfile.lock b/Gemfile.lock index 55123c4c..968c04bd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -154,6 +154,7 @@ GEM net-scp (1.2.1) net-ssh (>= 2.6.5) net-ssh (2.9.2) + newrelic_rpm (3.11.2.286) nokogiri (1.6.6.2) mini_portile (~> 0.6.0) nokogiri (1.6.6.2-java) @@ -351,6 +352,7 @@ DEPENDENCIES jquery-rails jquery-turbolinks kramdown + newrelic_rpm nyan-cat-formatter pg pry diff --git a/config/deploy.rb b/config/deploy.rb index fac4c4d7..a1567cb7 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -4,7 +4,7 @@ set :default_env, 'PATH' => '/usr/java/jdk1.8.0_40/bin:$PATH' set :deploy_to, '/var/www/app' set :keep_releases, 3 set :linked_dirs, %w(bin log public/uploads tmp/cache tmp/files tmp/pids tmp/sockets) -set :linked_files, %w(config/action_mailer.yml config/code_ocean.yml config/database.yml config/secrets.yml config/sendmail.yml config/smtp.yml) +set :linked_files, %w(config/action_mailer.yml config/code_ocean.yml config/database.yml config/newrelic.yml config/secrets.yml config/sendmail.yml config/smtp.yml) set :log_level, :info set :puma_threads, [0, 16] set :repo_url, 'git@github.com:openHPI/codeocean.git' diff --git a/config/newrelic.yml.example b/config/newrelic.yml.example new file mode 100644 index 00000000..bcff3c2a --- /dev/null +++ b/config/newrelic.yml.example @@ -0,0 +1,220 @@ +# +# This file configures the New Relic Agent. New Relic monitors Ruby, Java, +# .NET, PHP, Python and Node applications with deep visibility and low +# overhead. For more information, visit www.newrelic.com. + + +# Here are the settings that are common to all environments +common: &default_settings + # ============================== LICENSE KEY =============================== + + # You must specify the license key associated with your New Relic + # account. This key binds your Agent's data to your account in the + # New Relic service. + license_key: 'CHANGE_ME' + + # Agent Enabled (Ruby/Rails Only) + # Use this setting to force the agent to run or not run. + # Default is 'auto' which means the agent will install and run only + # if a valid dispatcher such as Mongrel is running. This prevents + # it from running with Rake or the console. Set to false to + # completely turn the agent off regardless of the other settings. + # Valid values are true, false and auto. + # + # agent_enabled: auto + + # Application Name Set this to be the name of your application as + # you'd like it show up in New Relic. The service will then auto-map + # instances of your application into an "application" on your + # dashboard page. If you want to map this instance into multiple + # apps, like "AJAX Requests" and "All UI" then specify a semicolon + # separated list of up to three distinct names, or a yaml list. + # Defaults to the capitalized RAILS_ENV or RACK_ENV (i.e., + # Production, Staging, etc) + # + # Example: + # + # app_name: + # - Ajax Service + # - All Services + # + # Caution: If you change this name, a new application will appear in the New + # Relic user interface with the new name, and data will stop reporting to the + # app with the old name. + # + # See https://newrelic.com/docs/site/renaming-applications for more details + # on renaming your New Relic applications. + # + app_name: Code Ocean + + # When "true", the agent collects performance data about your + # application and reports this data to the New Relic service at + # newrelic.com. This global switch is normally overridden for each + # environment below. (formerly called 'enabled') + monitor_mode: true + + # Developer mode should be off in every environment but + # development as it has very high overhead in memory. + developer_mode: false + + # The newrelic agent generates its own log file to keep its logging + # information separate from that of your application. Specify its + # log level here. + log_level: info + + # Optionally set the path to the log file This is expanded from the + # root directory (may be relative or absolute, e.g. 'log/' or + # '/var/log/') The agent will attempt to create this directory if it + # does not exist. + # log_file_path: 'log' + + # Optionally set the name of the log file, defaults to 'newrelic_agent.log' + # log_file_name: 'newrelic_agent.log' + + # The newrelic agent communicates with the service via https by default. This + # prevents eavesdropping on the performance metrics transmitted by the agent. + # The encryption required by SSL introduces a nominal amount of CPU overhead, + # which is performed asynchronously in a background thread. If you'd prefer + # to send your metrics over http uncomment the following line. + # ssl: false + + #============================== Browser Monitoring =============================== + # New Relic Real User Monitoring gives you insight into the performance real users are + # experiencing with your website. This is accomplished by measuring the time it takes for + # your users' browsers to download and render your web pages by injecting a small amount + # of JavaScript code into the header and footer of each page. + browser_monitoring: + # By default the agent automatically injects the monitoring JavaScript + # into web pages. Set this attribute to false to turn off this behavior. + auto_instrument: true + + # Proxy settings for connecting to the New Relic server. + # + # If a proxy is used, the host setting is required. Other settings + # are optional. Default port is 8080. + # + # proxy_host: hostname + # proxy_port: 8080 + # proxy_user: + # proxy_pass: + + # The agent can optionally log all data it sends to New Relic servers to a + # separate log file for human inspection and auditing purposes. To enable this + # feature, change 'enabled' below to true. + # See: https://newrelic.com/docs/ruby/audit-log + audit_log: + enabled: false + + # Tells transaction tracer and error collector (when enabled) + # whether or not to capture HTTP params. When true, frameworks can + # exclude HTTP parameters from being captured. + # Rails: the RoR filter_parameter_logging excludes parameters + # Java: create a config setting called "ignored_params" and set it to + # a comma separated list of HTTP parameter names. + # ex: ignored_params: credit_card, ssn, password + capture_params: false + + # Transaction tracer captures deep information about slow + # transactions and sends this to the New Relic service once a + # minute. Included in the transaction is the exact call sequence of + # the transactions including any SQL statements issued. + transaction_tracer: + + # Transaction tracer is enabled by default. Set this to false to + # turn it off. This feature is only available at the Professional + # and above product levels. + enabled: true + + # Threshold in seconds for when to collect a transaction + # trace. When the response time of a controller action exceeds + # this threshold, a transaction trace will be recorded and sent to + # New Relic. Valid values are any float value, or (default) "apdex_f", + # which will use the threshold for an dissatisfying Apdex + # controller action - four times the Apdex T value. + transaction_threshold: apdex_f + + # When transaction tracer is on, SQL statements can optionally be + # recorded. The recorder has three modes, "off" which sends no + # SQL, "raw" which sends the SQL statement in its original form, + # and "obfuscated", which strips out numeric and string literals. + record_sql: obfuscated + + # Threshold in seconds for when to collect stack trace for a SQL + # call. In other words, when SQL statements exceed this threshold, + # then capture and send to New Relic the current stack trace. This is + # helpful for pinpointing where long SQL calls originate from. + stack_trace_threshold: 0.500 + + # Determines whether the agent will capture query plans for slow + # SQL queries. Only supported in mysql and postgres. Should be + # set to false when using other adapters. + # explain_enabled: true + + # Threshold for query execution time below which query plans will + # not be captured. Relevant only when `explain_enabled` is true. + # explain_threshold: 0.5 + + # Error collector captures information about uncaught exceptions and + # sends them to New Relic for viewing + error_collector: + + # Error collector is enabled by default. Set this to false to turn + # it off. This feature is only available at the Professional and above + # product levels. + enabled: true + + # To stop specific errors from reporting to New Relic, set this property + # to comma-separated values. Default is to ignore routing errors, + # which are how 404's get triggered. + ignore_errors: "ActionController::RoutingError,Sinatra::NotFound" + + # If you're interested in capturing memcache keys as though they + # were SQL uncomment this flag. Note that this does increase + # overhead slightly on every memcached call, and can have security + # implications if your memcached keys are sensitive + # capture_memcache_keys: true + +# Application Environments +# ------------------------------------------ +# Environment-specific settings are in this section. +# For Rails applications, RAILS_ENV is used to determine the environment. +# For Java applications, pass -Dnewrelic.environment to set +# the environment. + +# NOTE if your application has other named environments, you should +# provide newrelic configuration settings for these environments here. + +development: + <<: *default_settings + # Turn on communication to New Relic service in development mode + monitor_mode: true + app_name: Code Ocean (Development) + + # Rails Only - when running in Developer Mode, the New Relic Agent will + # present performance information on the last 100 transactions you have + # executed since starting the mongrel. + # NOTE: There is substantial overhead when running in developer mode. + # Do not use for production or load testing. + developer_mode: true + +test: + <<: *default_settings + # It almost never makes sense to turn on the agent when running + # unit, functional or integration tests or the like. + monitor_mode: false + +# Turn on the agent in production for 24x7 monitoring. NewRelic +# testing shows an average performance impact of < 5 ms per +# transaction, you can leave this on all the time without +# incurring any user-visible performance degradation. +production: + <<: *default_settings + monitor_mode: true + +# Many applications have a staging environment which behaves +# identically to production. Support for that environment is provided +# here. By default, the staging environment has the agent turned on. +staging: + <<: *default_settings + monitor_mode: true + app_name: Code Ocean (Staging) From 51d93ae8c9e687bc25ba8ff02442e333812e2fb6 Mon Sep 17 00:00:00 2001 From: Hauke Klement Date: Sat, 11 Apr 2015 21:36:59 +0200 Subject: [PATCH 06/95] updated bundle --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 968c04bd..bde8fa1b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -111,7 +111,7 @@ GEM json erubis (2.7.0) excon (0.45.1) - execjs (2.5.0) + execjs (2.5.2) factory_girl (4.5.0) activesupport (>= 3.0.0) factory_girl_rails (4.5.0) @@ -128,7 +128,7 @@ GEM ims-lti (1.1.8) builder oauth (~> 0.4.5) - jbuilder (2.2.12) + jbuilder (2.2.13) activesupport (>= 3.0.0, < 5) multi_json (~> 1.2) jdbc-postgres (9.4.1200) From b8284a7a2624600c743ff682ecc15f3b9625a57a Mon Sep 17 00:00:00 2001 From: Hauke Klement Date: Sun, 12 Apr 2015 13:45:45 +0200 Subject: [PATCH 07/95] fixed issue of default test feedback message not being localized correctly --- app/controllers/concerns/submission_scoring.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/concerns/submission_scoring.rb b/app/controllers/concerns/submission_scoring.rb index ea20a483..34d17cf9 100644 --- a/app/controllers/concerns/submission_scoring.rb +++ b/app/controllers/concerns/submission_scoring.rb @@ -20,6 +20,7 @@ module SubmissionScoring private :execute_test_file def feedback_message(file, score) + set_locale score == Assessor::MAXIMUM_SCORE ? I18n.t('exercises.implement.default_feedback') : file.feedback_message end From d06e9a476acf607137cabc0b998fbe0705762dac Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Sun, 12 Apr 2015 23:16:58 +0200 Subject: [PATCH 08/95] if we use this for cheching then there should be a valid false or nil return --- app/helpers/exercise_helper.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/helpers/exercise_helper.rb b/app/helpers/exercise_helper.rb index cab90c21..7dcbb6f4 100644 --- a/app/helpers/exercise_helper.rb +++ b/app/helpers/exercise_helper.rb @@ -13,6 +13,8 @@ module ExerciseHelper if enabled config.read[:code_pilot][:url] + else + return nil end end end From 7e28a6c045abcf9d1fbe609eeec1dbe818ff3ff1 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Mon, 13 Apr 2015 15:21:34 +0200 Subject: [PATCH 09/95] Add docker config for prod --- config/docker.yml.erb | 1 + 1 file changed, 1 insertion(+) diff --git a/config/docker.yml.erb b/config/docker.yml.erb index ea234022..1c38c5d6 100644 --- a/config/docker.yml.erb +++ b/config/docker.yml.erb @@ -11,6 +11,7 @@ development: production: <<: *default + host: unix:///var/run/docker.sock pool: active: true refill: From cb98ef50fbb3d4239c170bfc1601442f84f5c689 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Mon, 13 Apr 2015 16:25:48 +0200 Subject: [PATCH 10/95] Disable average count as this breaks on some exercises... --- app/views/sessions/destroy_through_lti.html.slim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/sessions/destroy_through_lti.html.slim b/app/views/sessions/destroy_through_lti.html.slim index 623badba..8f1e89a8 100644 --- a/app/views/sessions/destroy_through_lti.html.slim +++ b/app/views/sessions/destroy_through_lti.html.slim @@ -10,6 +10,6 @@ h2 = t('shared.statistics') p == t('shared.out_of', maximum_value: @submission.exercise.maximum_score, value: @submission.score) p = progress_bar(@submission.percentage) = row(label: '.final_submissions', value: @submission.exercise.submissions.final.distinct.count(:user_id, :user_type) - 1) -= row(label: '.average_score') do - p == t('shared.out_of', maximum_value: @submission.exercise.maximum_score, value: @submission.exercise.average_score.round(2)) - p = progress_bar(@submission.exercise.average_percentage) +/= row(label: '.average_score') do +/ p == t('shared.out_of', maximum_value: @submission.exercise.maximum_score, value: @submission.exercise.average_score.round(2)) +/ p = progress_bar(@submission.exercise.average_percentage) From c0fde51f6cea3bbbace3274d4626dd9145ab7c2a Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Mon, 13 Apr 2015 22:36:27 +0200 Subject: [PATCH 11/95] Backup commit --- Gemfile | 2 +- Gemfile.lock | 2 +- app/models/exercise.rb | 2 +- lib/docker_client.rb | 7 ++++++- lib/docker_container_pool.rb | 5 +++++ 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index f9f6e208..8ff54445 100644 --- a/Gemfile +++ b/Gemfile @@ -60,7 +60,7 @@ group :test do gem 'nyan-cat-formatter' gem 'rake' gem 'rspec-autotest' - gem 'rspec-rails', '~> 3.1.0' + gem 'rspec-rails' gem 'selenium-webdriver' gem 'simplecov', require: false end diff --git a/Gemfile.lock b/Gemfile.lock index bde8fa1b..ef54d806 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -363,7 +363,7 @@ DEPENDENCIES rake ransack rspec-autotest - rspec-rails (~> 3.1.0) + rspec-rails rubocop rubocop-rspec rubytree diff --git a/app/models/exercise.rb b/app/models/exercise.rb index 6e7e090a..152d79bf 100644 --- a/app/models/exercise.rb +++ b/app/models/exercise.rb @@ -23,7 +23,7 @@ class Exercise < ActiveRecord::Base validates :token, presence: true, uniqueness: true def average_percentage - (average_score / maximum_score * 100).round if average_score + (average_score/ maximum_score * 100).round if average_score end def average_score diff --git a/lib/docker_client.rb b/lib/docker_client.rb index e5224236..f0799d8f 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -172,7 +172,12 @@ class DockerClient rescue Timeout::Error {status: :timeout} ensure - Concurrent::Future.execute { self.class.destroy_container(container) } + Concurrent::Future.execute { + #self.class.destroy_container(container) + FileUtils.rm_rf(local_workspace_path(container)) if local_workspace_path(container) + FileUtils.mkdir(local_workspace_path) + DockerContainerPool.return_container(container, @execution_environment) + } end private :send_command diff --git a/lib/docker_container_pool.rb b/lib/docker_container_pool.rb index c1d16c0a..3ca644df 100644 --- a/lib/docker_container_pool.rb +++ b/lib/docker_container_pool.rb @@ -20,6 +20,11 @@ class DockerContainerPool DockerClient.create_container(execution_environment) end + def self.return_container(container, execution_environment) + #container.start() + @containers[execution_environment.id].push(container) + end + def self.get_container(execution_environment) if config[:active] @containers[execution_environment.id].try(:shift) || create_container(execution_environment) From 40aa3e1494b04100e0e55fb72ca15fcfc8b1edd1 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Tue, 14 Apr 2015 14:43:06 +0200 Subject: [PATCH 12/95] lets assume we are stable soon.. --- config/environments/production.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/environments/production.rb b/config/environments/production.rb index 47d3553b..3c3fe0c5 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -43,7 +43,7 @@ Rails.application.configure do # config.force_ssl = true # Set to :debug to see everything in the log. - config.log_level = :info + config.log_level = :error # Prepend all log lines with the following tags. # config.log_tags = [ :subdomain, :uuid ] From 0c8e93fb95e726b24df8c6c10dbd47d5f5fbe910 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Tue, 14 Apr 2015 14:55:43 +0200 Subject: [PATCH 13/95] use latest api version --- Gemfile | 2 +- Gemfile.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 8ff54445..9d8a302f 100644 --- a/Gemfile +++ b/Gemfile @@ -7,7 +7,7 @@ gem 'carrierwave' gem 'coffee-rails', '~> 4.0.0' gem 'concurrent-ruby' gem 'concurrent-ruby-ext', platform: :ruby -gem 'docker-api', require: 'docker' +gem 'docker-api','~> 1.21.0', require: 'docker' gem 'factory_girl_rails', '~> 4.0' gem 'forgery' gem 'highline' diff --git a/Gemfile.lock b/Gemfile.lock index ef54d806..858774f3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -343,7 +343,7 @@ DEPENDENCIES concurrent-ruby concurrent-ruby-ext database_cleaner - docker-api + docker-api (~> 1.21.0) factory_girl_rails (~> 4.0) forgery highline From a28b80b083132ba39b65eb8f046966fb451cba0a Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Tue, 14 Apr 2015 16:31:22 +0200 Subject: [PATCH 14/95] deactiveate stuff that breaks for now --- app/views/exercises/implement.html.slim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/exercises/implement.html.slim b/app/views/exercises/implement.html.slim index 47cac7c1..0b464df0 100644 --- a/app/views/exercises/implement.html.slim +++ b/app/views/exercises/implement.html.slim @@ -73,7 +73,7 @@ .progress-bar role='progressbar' br 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')) - - if qa_url - #questions-column - #questions-holder data-url="#{qa_url}/qa/index/#{@exercise.id}/#{@user_id}" - = qa_js_tag \ No newline at end of file + //- if qa_url + // #questions-column + // #questions-holder data-url="#{qa_url}/qa/index/#{@exercise.id}/#{@user_id}" + // = qa_js_tag \ No newline at end of file From 168df58cc70feb7301df64e24e22353160f62466 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Tue, 14 Apr 2015 16:45:56 +0200 Subject: [PATCH 15/95] debugging --- lib/docker_client.rb | 11 ++++++++++- lib/docker_container_pool.rb | 1 - 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/docker_client.rb b/lib/docker_client.rb index f0799d8f..1c02f379 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -155,11 +155,16 @@ class DockerClient `docker pull #{docker_image}` if docker_image end + #this sends the command to run whatever is defined in the backend def send_command(command, container, &block) Timeout.timeout(@execution_environment.permitted_execution_time.to_i) do stderr = [] stdout = [] - container.attach(stdin: StringIO.new(command)) do |stream, chunk| + # map command in a shell call, maybe add -c + command = ['bash', '-c', command] + # lets call the command, but we do not want the container to stop afterwards + # thats why we use exec. If its ok do stop the container this could be assign instead + container.exec(command) do |stream, chunk| block.call(stream, chunk) if block_given? if stream == :stderr stderr.push(chunk) @@ -173,7 +178,11 @@ class DockerClient {status: :timeout} ensure Concurrent::Future.execute { + # If you do not want to reuse running container you could use: #self.class.destroy_container(container) + # This could be moved to an execution environment specific setting + + # we may need to stop the exec call here..!!! FileUtils.rm_rf(local_workspace_path(container)) if local_workspace_path(container) FileUtils.mkdir(local_workspace_path) DockerContainerPool.return_container(container, @execution_environment) diff --git a/lib/docker_container_pool.rb b/lib/docker_container_pool.rb index 3ca644df..7d58f138 100644 --- a/lib/docker_container_pool.rb +++ b/lib/docker_container_pool.rb @@ -21,7 +21,6 @@ class DockerContainerPool end def self.return_container(container, execution_environment) - #container.start() @containers[execution_environment.id].push(container) end From a410696438ae168d3239776ef3f222f23b47d9ef Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Tue, 14 Apr 2015 16:53:56 +0200 Subject: [PATCH 16/95] debugging --- lib/docker_client.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/docker_client.rb b/lib/docker_client.rb index 1c02f379..c617bca7 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -162,9 +162,12 @@ class DockerClient stdout = [] # map command in a shell call, maybe add -c command = ['bash', '-c', command] + command.join(' ') # lets call the command, but we do not want the container to stop afterwards # thats why we use exec. If its ok do stop the container this could be assign instead - container.exec(command) do |stream, chunk| + #container.exec(command) do |stream, chunk| + container.attach(stdin: StringIO.new(command)) do |stream, chunk| +end block.call(stream, chunk) if block_given? if stream == :stderr stderr.push(chunk) From 0b7ae86a6976d126a4955394ba13b80ea301cc8f Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Tue, 14 Apr 2015 16:54:23 +0200 Subject: [PATCH 17/95] debugging --- lib/docker_client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/docker_client.rb b/lib/docker_client.rb index c617bca7..aac180d0 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -167,7 +167,7 @@ class DockerClient # thats why we use exec. If its ok do stop the container this could be assign instead #container.exec(command) do |stream, chunk| container.attach(stdin: StringIO.new(command)) do |stream, chunk| -end + block.call(stream, chunk) if block_given? if stream == :stderr stderr.push(chunk) From 91ac7e8e371a9780cd5b60964b926d68df6c4844 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Tue, 14 Apr 2015 17:10:05 +0200 Subject: [PATCH 18/95] debugging --- lib/docker_client.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/docker_client.rb b/lib/docker_client.rb index aac180d0..62e84032 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -162,11 +162,11 @@ class DockerClient stdout = [] # map command in a shell call, maybe add -c command = ['bash', '-c', command] - command.join(' ') + #command.join!(' ') # lets call the command, but we do not want the container to stop afterwards # thats why we use exec. If its ok do stop the container this could be assign instead - #container.exec(command) do |stream, chunk| - container.attach(stdin: StringIO.new(command)) do |stream, chunk| + container.exec(command) do |stream, chunk| + #container.attach(stdin: StringIO.new(command)) do |stream, chunk| block.call(stream, chunk) if block_given? if stream == :stderr From 9187596f18aaed0d2442b9e2d04afa664182436c Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Tue, 14 Apr 2015 19:47:01 +0200 Subject: [PATCH 19/95] Do not create container if pooling is on and all containers are gone --- lib/docker_client.rb | 12 ++++++++---- lib/docker_container_pool.rb | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/docker_client.rb b/lib/docker_client.rb index 62e84032..77c7544a 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -90,10 +90,14 @@ class DockerClient def execute_command(command, before_execution_block, output_consuming_block) tries ||= 0 @container = DockerContainerPool.get_container(@execution_environment) - before_execution_block.try(:call) - send_command(command, @container, &output_consuming_block) + if @container + before_execution_block.try(:call) + send_command(command, @container, &output_consuming_block) + else + raise('Alle Slots belegt. Versuche es später nochmal.') + end rescue Excon::Errors::SocketError => error - (tries += 1) <= RETRY_COUNT ? retry : raise(error) + #(tries += 1) <= RETRY_COUNT ? retry : raise(error) end [:run, :test].each do |cause| @@ -187,7 +191,7 @@ class DockerClient # we may need to stop the exec call here..!!! FileUtils.rm_rf(local_workspace_path(container)) if local_workspace_path(container) - FileUtils.mkdir(local_workspace_path) + FileUtils.mkdir(local_workspace_path(container)) DockerContainerPool.return_container(container, @execution_environment) } end diff --git a/lib/docker_container_pool.rb b/lib/docker_container_pool.rb index 7d58f138..0dc536f5 100644 --- a/lib/docker_container_pool.rb +++ b/lib/docker_container_pool.rb @@ -17,7 +17,7 @@ class DockerContainerPool end def self.create_container(execution_environment) - DockerClient.create_container(execution_environment) + DockerClient.create_container(execution_environment) end def self.return_container(container, execution_environment) @@ -26,7 +26,7 @@ class DockerContainerPool def self.get_container(execution_environment) if config[:active] - @containers[execution_environment.id].try(:shift) || create_container(execution_environment) + @containers[execution_environment.id].try(:shift) || nil else create_container(execution_environment) end @@ -49,6 +49,7 @@ class DockerContainerPool def self.refill_for_execution_environment(execution_environment) refill_count = [execution_environment.pool_size - @containers[execution_environment.id].length, config[:refill][:batch_size]].min @containers[execution_environment.id] += refill_count.times.map { create_container(execution_environment) } + #refill_count.times.map { create_container(execution_environment) } end def self.start_refill_task From 7f7e538af2d09c4e5687365ded0f2bdde03fd183 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Tue, 14 Apr 2015 19:49:46 +0200 Subject: [PATCH 20/95] Added comment to explain commented stuff --- lib/docker_client.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/docker_client.rb b/lib/docker_client.rb index 77c7544a..ccc7e40d 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -97,6 +97,8 @@ class DockerClient raise('Alle Slots belegt. Versuche es später nochmal.') end rescue Excon::Errors::SocketError => error + # socket errors seems to be normal when using exec + # so lets ignore them for now #(tries += 1) <= RETRY_COUNT ? retry : raise(error) end From b46055eca3a27788681eb6bf974a39e34a47c9e2 Mon Sep 17 00:00:00 2001 From: Hauke Klement Date: Tue, 14 Apr 2015 19:59:11 +0200 Subject: [PATCH 21/95] added option to recycle Docker containers --- lib/docker_client.rb | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/lib/docker_client.rb b/lib/docker_client.rb index 62e84032..cae78534 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -5,6 +5,7 @@ class DockerClient DEFAULT_MEMORY_LIMIT = 256 LOCAL_WORKSPACE_ROOT = Rails.root.join('tmp', 'files', Rails.env) MINIMUM_MEMORY_LIMIT = 4 + RECYCLE_CONTAINERS = true RETRY_COUNT = 2 attr_reader :container @@ -155,19 +156,19 @@ class DockerClient `docker pull #{docker_image}` if docker_image end - #this sends the command to run whatever is defined in the backend + def return_container(container) + local_workspace_path = self.class.local_workspace_path(container) + FileUtils.rm_rf(local_workspace_path) if local_workspace_path + FileUtils.mkdir(local_workspace_path) + DockerContainerPool.return_container(container, @execution_environment) + end + private :return_container + def send_command(command, container, &block) Timeout.timeout(@execution_environment.permitted_execution_time.to_i) do stderr = [] stdout = [] - # map command in a shell call, maybe add -c - command = ['bash', '-c', command] - #command.join!(' ') - # lets call the command, but we do not want the container to stop afterwards - # thats why we use exec. If its ok do stop the container this could be assign instead - container.exec(command) do |stream, chunk| - #container.attach(stdin: StringIO.new(command)) do |stream, chunk| - + container.exec(['bash', '-c', command]) do |stream, chunk| block.call(stream, chunk) if block_given? if stream == :stderr stderr.push(chunk) @@ -180,16 +181,7 @@ class DockerClient rescue Timeout::Error {status: :timeout} ensure - Concurrent::Future.execute { - # If you do not want to reuse running container you could use: - #self.class.destroy_container(container) - # This could be moved to an execution environment specific setting - - # we may need to stop the exec call here..!!! - FileUtils.rm_rf(local_workspace_path(container)) if local_workspace_path(container) - FileUtils.mkdir(local_workspace_path) - DockerContainerPool.return_container(container, @execution_environment) - } + RECYCLE_CONTAINERS ? return_container(container) : self.class.destroy_container(container) end private :send_command From 366f2b8ef0c08a29bd4eefb21b8d72c816115788 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Tue, 14 Apr 2015 20:17:36 +0200 Subject: [PATCH 22/95] backup --- lib/docker_client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/docker_client.rb b/lib/docker_client.rb index ccc7e40d..1bb4ebd2 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -88,7 +88,7 @@ class DockerClient end def execute_command(command, before_execution_block, output_consuming_block) - tries ||= 0 + #tries ||= 0 @container = DockerContainerPool.get_container(@execution_environment) if @container before_execution_block.try(:call) From 95923a137e59f196332fb7a342354c156bbb8e97 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Tue, 14 Apr 2015 20:23:41 +0200 Subject: [PATCH 23/95] Do not create more containers as the pool count --- lib/docker_container_pool.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/docker_container_pool.rb b/lib/docker_container_pool.rb index 0dc536f5..8823d989 100644 --- a/lib/docker_container_pool.rb +++ b/lib/docker_container_pool.rb @@ -4,7 +4,8 @@ require 'concurrent/utilities' class DockerContainerPool @containers = ThreadSafe::Hash[ExecutionEnvironment.all.map { |execution_environment| [execution_environment.id, ThreadSafe::Array.new] }] - + #as containers are not containing containers in use + @all_containers = ThreadSafe::Hash[ExecutionEnvironment.all.map { |execution_environment| [execution_environment.id, ThreadSafe::Array.new] }] def self.clean_up @refill_task.try(:shutdown) @containers.values.each do |containers| @@ -47,8 +48,10 @@ class DockerContainerPool end def self.refill_for_execution_environment(execution_environment) - refill_count = [execution_environment.pool_size - @containers[execution_environment.id].length, config[:refill][:batch_size]].min - @containers[execution_environment.id] += refill_count.times.map { create_container(execution_environment) } + refill_count = [execution_environment.pool_size - @all_containers[execution_environment.id].length, config[:refill][:batch_size]].min + c = refill_count.times.map { create_container(execution_environment) } + @containers[execution_environment.id] += c + @all_containers[execution_environment.id] += c #refill_count.times.map { create_container(execution_environment) } end From 69bac3fe20528902dea78b773495f9769441d607 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Tue, 14 Apr 2015 20:26:43 +0200 Subject: [PATCH 24/95] Avoid utf-8 trouble --- lib/docker_client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/docker_client.rb b/lib/docker_client.rb index 420ad917..859306d2 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -95,7 +95,7 @@ class DockerClient before_execution_block.try(:call) send_command(command, @container, &output_consuming_block) else - raise('Alle Slots belegt. Versuche es später nochmal.') + raise('Alle Slots belegt. Versuche es nachher nochmal.') end rescue Excon::Errors::SocketError => error # socket errors seems to be normal when using exec From 48c9bbcea5a86a44f6e3d151c063390671f87d20 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Wed, 15 Apr 2015 08:17:26 +0200 Subject: [PATCH 25/95] Changed the way we empty the working dir after continaer is returnned in pool --- lib/docker_client.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/docker_client.rb b/lib/docker_client.rb index 859306d2..692198a7 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -1,4 +1,5 @@ require 'concurrent' +require 'pathname' class DockerClient CONTAINER_WORKSPACE_PATH = '/workspace' @@ -55,7 +56,7 @@ class DockerClient container rescue Docker::Error::NotFoundError => error destroy_container(container) - (tries += 1) <= RETRY_COUNT ? retry : raise(error) + #(tries += 1) <= RETRY_COUNT ? retry : raise(error) end def create_workspace_files(container, submission) @@ -164,8 +165,9 @@ class DockerClient def return_container(container) local_workspace_path = self.class.local_workspace_path(container) - FileUtils.rm_rf(local_workspace_path) if local_workspace_path - FileUtils.mkdir(local_workspace_path) + #FileUtils.rm_rf(local_workspace_path) if local_workspace_path + Pathname.new(local_workspace_path).children.each{ |p| p.rmtree} + #FileUtils.mkdir(local_workspace_path) DockerContainerPool.return_container(container, @execution_environment) end private :return_container From 2146089a2bbedfb0dbf32e496f9d15f599ec41b0 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Wed, 15 Apr 2015 12:12:26 +0200 Subject: [PATCH 26/95] Change deploy username --- config/deploy/production.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/deploy/production.rb b/config/deploy/production.rb index 06929397..83110aff 100644 --- a/config/deploy/production.rb +++ b/config/deploy/production.rb @@ -1 +1 @@ -server 'codeocean.openhpi.de', roles: [:app, :db, :puma_nginx, :web], user: 'hklement' +server 'codeocean.openhpi.de', roles: [:app, :db, :puma_nginx, :web], user: 'codeocean' From 940eee5856e64c3df23acb2dfa9a5ee68bc8f4ce Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Wed, 15 Apr 2015 17:17:39 +0200 Subject: [PATCH 27/95] Show warning if all containers are depleted. --- app/assets/javascripts/editor.js | 12 ++++++++++++ app/views/exercises/_editor.html.slim | 2 +- config/locales/de.yml | 1 + config/locales/en.yml | 1 + lib/docker_client.rb | 2 +- 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/editor.js b/app/assets/javascripts/editor.js index 09c23bba..7aa32fc0 100644 --- a/app/assets/javascripts/editor.js +++ b/app/assets/javascripts/editor.js @@ -651,6 +651,11 @@ $(function() { })) { showTimeoutMessage(); } + if (_.some(response, function(result) { + return result.status === 'container_depleted'; + })) { + showContainerDepletedMessage(); + } if (qa_api) { // send test response to QA qa_api.executeCommand('syncOutput', [response]); @@ -828,6 +833,13 @@ $(function() { } }; + var showContainerDepletedMessage = function() { + $.flash.danger({ + icon: ['fa', 'fa-clock-o'], + text: $('#editor').data('message-depleted') + }); + }; + var showTab = function(index) { $('a[data-toggle="tab"]').eq(index || 0).tab('show'); }; diff --git a/app/views/exercises/_editor.html.slim b/app/views/exercises/_editor.html.slim index b8450c29..09d07190 100644 --- a/app/views/exercises/_editor.html.slim +++ b/app/views/exercises/_editor.html.slim @@ -1,4 +1,4 @@ -#editor.row data-exercise-id=exercise.id data-message-timeout=t('exercises.editor.timeout', permitted_execution_time: @exercise.execution_environment.permitted_execution_time) data-errors-url=execution_environment_errors_path(exercise.execution_environment) data-submissions-url=submissions_path data-user-id=@current_user.id +#editor.row data-exercise-id=exercise.id data-message-depleted=t('exercises.editor.depleted') data-message-timeout=t('exercises.editor.timeout', permitted_execution_time: @exercise.execution_environment.permitted_execution_time) data-errors-url=execution_environment_errors_path(exercise.execution_environment) data-submissions-url=submissions_path data-user-id=@current_user.id .col-sm-3 = render('editor_file_tree', files: @files) #frames.col-sm-9 - @files.each do |file| diff --git a/config/locales/de.yml b/config/locales/de.yml index fa725fde..a58493c3 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -166,6 +166,7 @@ de: confirm_start_over: Wollen Sie wirklich von vorne anfangen? confirm_submit: Wollen Sie Ihren Code wirklich zur Bewertung abgeben? create_file: Neue Datei + depleted: Alle Ausführungsausgebungen sind momentan in Benutzung. Probiere es später nochmal. destroy_file: Datei löschen download: Herunterladen dummy: Keine Aktion diff --git a/config/locales/en.yml b/config/locales/en.yml index 64cd0eda..d27552bf 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -166,6 +166,7 @@ en: confirm_start_over: Do you really want to start over? confirm_submit: Do you really want to submit your code for grading? create_file: New File + depleted: All execution environments are busy. Please try again later. destroy_file: Delete File download: Download dummy: No Action diff --git a/lib/docker_client.rb b/lib/docker_client.rb index 692198a7..284a66fe 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -96,7 +96,7 @@ class DockerClient before_execution_block.try(:call) send_command(command, @container, &output_consuming_block) else - raise('Alle Slots belegt. Versuche es nachher nochmal.') + {status: :container_depleted} end rescue Excon::Errors::SocketError => error # socket errors seems to be normal when using exec From 635900b3cc0af5b1f5345a62c0c18e6457a23c6c Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Wed, 15 Apr 2015 19:54:15 +0200 Subject: [PATCH 28/95] Restart container on timeout --- lib/docker_client.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/docker_client.rb b/lib/docker_client.rb index 284a66fe..95b89e50 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -187,6 +187,7 @@ class DockerClient {status: :ok, stderr: stderr.join, stdout: stdout.join} end rescue Timeout::Error + container.restart if RECYCLE_CONTAINERS {status: :timeout} ensure RECYCLE_CONTAINERS ? return_container(container) : self.class.destroy_container(container) From ac113ec717d13dfd603a50a049f7b72aeb7a4751 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Thu, 16 Apr 2015 09:23:59 +0200 Subject: [PATCH 29/95] Restart container on timeout --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 23c6e67f..0b6bda13 100644 --- a/README.md +++ b/README.md @@ -34,3 +34,15 @@ In order to execute code submissions using Docker, source code files are written - customize *config/deploy/production.rb* if you want to deploy using [Capistrano](http://capistranorb.com/) The application is compatible with MRI and JRuby. Due to superior parallelism, we recommend using JRuby. + +## Useful service maintance commands + +- delete all containers (include running ones) `docker rm -f $(docker ps -aq)` +- if the application is run as a service restart it by using `service codeocean restart` +- if deployed via capistrano you will find the logs at `/var/www/app/shared/log/` -> `production.log` + + + + + + From 68ab935e12825c7fd6bca28d098fb943ceeac641 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Thu, 16 Apr 2015 09:44:27 +0200 Subject: [PATCH 30/95] Fixed typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b6bda13..04cc90e4 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ In order to execute code submissions using Docker, source code files are written The application is compatible with MRI and JRuby. Due to superior parallelism, we recommend using JRuby. -## Useful service maintance commands +## Useful service maintenance commands - delete all containers (include running ones) `docker rm -f $(docker ps -aq)` - if the application is run as a service restart it by using `service codeocean restart` From 04891167c358322a8e6147b0355f5d0bc0be6b64 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Thu, 16 Apr 2015 10:06:48 +0200 Subject: [PATCH 31/95] Adapt test to new pooling --- spec/lib/docker_container_pool_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/lib/docker_container_pool_spec.rb b/spec/lib/docker_container_pool_spec.rb index 8c7c3335..f820a49b 100644 --- a/spec/lib/docker_container_pool_spec.rb +++ b/spec/lib/docker_container_pool_spec.rb @@ -53,8 +53,8 @@ describe DockerContainerPool do expect(described_class.instance_variable_get(:@containers)[@execution_environment.id]).to be_empty end - it 'creates a new container' do - expect(described_class).to receive(:create_container).with(@execution_environment) + it 'not creates a new container' do + expect(described_class).not_to receive(:create_container).with(@execution_environment) described_class.get_container(@execution_environment) end end From bbf28fc202f70ef2d9af271cdaf6d58f145c60bb Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Thu, 16 Apr 2015 17:36:33 +0200 Subject: [PATCH 32/95] add db restart manual --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 04cc90e4..a1dafb00 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ The application is compatible with MRI and JRuby. Due to superior parallelism, w - delete all containers (include running ones) `docker rm -f $(docker ps -aq)` - if the application is run as a service restart it by using `service codeocean restart` +- `/etc/init.d/postgresql restart` - if deployed via capistrano you will find the logs at `/var/www/app/shared/log/` -> `production.log` From ba50ed0b811cd22191b4592ab7de98a0e0e91bd7 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Fri, 17 Apr 2015 12:50:48 +0200 Subject: [PATCH 33/95] Working on non streaming output mode --- app/assets/javascripts/editor.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/editor.js b/app/assets/javascripts/editor.js index 7aa32fc0..56ea1a83 100644 --- a/app/assets/javascripts/editor.js +++ b/app/assets/javascripts/editor.js @@ -17,6 +17,7 @@ $(function() { var active_frame = undefined; var running = false; var qa_api = undefined; + var output_mode_is_streaming = true; var flowrResultHtml = '
' @@ -615,6 +616,10 @@ $(function() { var printOutput = function(output, colorize, index) { var element = findOrCreateOutputElement(index); + // disable streaming if desired + if (output.stdout && output.stdout.length >= 20 && output.stdout.substr(0,20) == "##DISABLESTREAMING##"){ + output_mode_is_streaming = false; + } if (!colorize) { var stream = _.sortBy([output.stderr || '', output.stdout || ''], function(stream) { return stream.length; @@ -623,7 +628,14 @@ $(function() { } else if (output.stderr) { element.addClass('text-warning').append(output.stderr); } else if (output.stdout) { - element.addClass('text-success').append(output.stdout); + if (output_mode_is_streaming){ + element.addClass('text-success').append(output.stdout); + }else{ + element.addClass('text-success'); + element.data('content_buffer' , element.data('content_buffer') + output.stdout); + } + } else if (output.code && output.code == '200' && output_mode_is_streaming === false){ + element.append( element.data('content_buffer')); } else { element.addClass('text-muted').text($('#output').data('message-no-output')); } From 99226207a3944af17fd9339b29c4ae447e86c4e1 Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Fri, 17 Apr 2015 12:57:29 +0200 Subject: [PATCH 34/95] fix indention --- app/assets/javascripts/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/editor.js b/app/assets/javascripts/editor.js index 56ea1a83..766b3ee2 100644 --- a/app/assets/javascripts/editor.js +++ b/app/assets/javascripts/editor.js @@ -635,7 +635,7 @@ $(function() { element.data('content_buffer' , element.data('content_buffer') + output.stdout); } } else if (output.code && output.code == '200' && output_mode_is_streaming === false){ - element.append( element.data('content_buffer')); + element.append( element.data('content_buffer')); } else { element.addClass('text-muted').text($('#output').data('message-no-output')); } From 5cb8ae68b0414984e73f79d33ff7e0dbf1276a5d Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Mon, 20 Apr 2015 16:51:50 +0200 Subject: [PATCH 35/95] Added tests --- spec/controllers/exercises_controller_spec.rb | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/spec/controllers/exercises_controller_spec.rb b/spec/controllers/exercises_controller_spec.rb index 6082004e..f9fcf621 100644 --- a/spec/controllers/exercises_controller_spec.rb +++ b/spec/controllers/exercises_controller_spec.rb @@ -200,11 +200,26 @@ describe ExercisesController do end describe 'GET #show' do - before(:each) { get :show, id: exercise.id } - - expect_assigns(exercise: :exercise) - expect_status(200) - expect_template(:show) + context 'as admin' do + before(:each) { get :show, id: exercise.id } + expect_assigns(exercise: :exercise) + expect_status(200) + expect_template(:show) + end + context 'as internal user' do + let(:user) { FactoryGirl.create(:internal_user) } + before(:each) { get :show, id: exercise.id } + expect_assigns(exercise: :exercise) + expect_status(200) + expect_template(:show) + end + context 'as external user' do + let(:user) { FactoryGirl.create(:external_user) } + before(:each) { get :show, id: exercise.id } + expect_assigns(exercise: :exercise) + expect_status(200) + expect_template(:show) + end end describe 'GET #statistics' do From 36b8542710b76e4532f4f57c61129f6234bded1e Mon Sep 17 00:00:00 2001 From: Jan Renz Date: Mon, 20 Apr 2015 17:02:57 +0200 Subject: [PATCH 36/95] Nicer error text part I of II --- public/500.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/500.html b/public/500.html index 061abc58..a592f052 100644 --- a/public/500.html +++ b/public/500.html @@ -1,7 +1,7 @@ - We're sorry, but something went wrong (500) + Momentan nehmen wir Wartungs- und Optimierungsarbeiten vor. Probieren Sie es in Kürze noch einmal.