From 563e14a44adfb512e7ac6d8fb09098048ed16d8e Mon Sep 17 00:00:00 2001 From: Sebastian Serth Date: Mon, 6 Dec 2021 23:56:31 +0100 Subject: [PATCH] Adapt dashboard to show idle and used runners --- app/assets/javascripts/dashboard.js | 17 ++++++++-------- app/helpers/admin/dashboard_helper.rb | 13 +++++++++++- app/views/admin/dashboard/show.html.slim | 21 ++++++++++++-------- config/locales/de.yml | 6 ++++-- config/locales/en.yml | 6 ++++-- lib/runner/strategy/docker_container_pool.rb | 2 +- lib/runner/strategy/poseidon.rb | 18 ++++++++++++++++- spec/helpers/admin/dashboard_helper_spec.rb | 12 +++++++---- 8 files changed, 68 insertions(+), 27 deletions(-) diff --git a/app/assets/javascripts/dashboard.js b/app/assets/javascripts/dashboard.js index 6ae38079..38504849 100644 --- a/app/assets/javascripts/dashboard.js +++ b/app/assets/javascripts/dashboard.js @@ -68,7 +68,7 @@ $(document).on('turbolinks:load', function() { _.each(response.docker, function(data) { groups.update({ id: data.id, - visible: data.pool_size > 0 + visible: data.prewarmingPoolSize > 0 }); }); }; @@ -78,26 +78,27 @@ $(document).on('turbolinks:load', function() { dataset.add({ group: data.id, x: vis.moment(), - y: data.quantity + y: data.usedRunners }); }); }; var updateProgressBar = function(progress_bar, data) { - var percentage = Math.min(Math.round(data.quantity / data.pool_size * 100), 100); + var percentage = Math.min(Math.round(data.idleRunners / data.prewarmingPoolSize * 100), 100); progress_bar.attr({ - 'aria-valuemax': data.pool_size, - 'aria-valuenow': data.quantity, + 'aria-valuemax': data.prewarmingPoolSize, + 'aria-valuenow': data.idleRunners, style: 'width: ' + percentage + '%' }); - progress_bar.html(data.quantity); + progress_bar.html(data.idleRunners); }; var updateTable = function(response) { _.each(response.docker, function(data) { var row = $('tbody tr[data-id=' + data.id + ']'); - $('.pool-size', row).html(data.pool_size); - var progress_bar = $('.quantity .progress .progress-bar', row); + $('.prewarming-pool-size', row).html(data.prewarmingPoolSize); + $('.used-runners', row).html(`+ ${data.usedRunners}`); + var progress_bar = $('.idle-runners .progress .progress-bar', row); updateProgressBar(progress_bar, data); }); }; diff --git a/app/helpers/admin/dashboard_helper.rb b/app/helpers/admin/dashboard_helper.rb index 1b209fb8..0cb02797 100644 --- a/app/helpers/admin/dashboard_helper.rb +++ b/app/helpers/admin/dashboard_helper.rb @@ -15,7 +15,18 @@ module Admin end ExecutionEnvironment.order(:id).select(:id, :pool_size).map do |execution_environment| - execution_environment.attributes.merge(quantity: pool_size[execution_environment.id]) + # Fetch the actual values (ID is stored as a symbol) or get an empty hash for merge + actual = pool_size[execution_environment.id.to_s.to_sym] || {} + + template = { + id: execution_environment.id, + prewarmingPoolSize: execution_environment.pool_size, + idleRunners: 0, + usedRunners: 0, + } + + # Existing values in the template get replaced with actual values + template.merge(actual) end end end diff --git a/app/views/admin/dashboard/show.html.slim b/app/views/admin/dashboard/show.html.slim index 9bf07936..a87284e5 100644 --- a/app/views/admin/dashboard/show.html.slim +++ b/app/views/admin/dashboard/show.html.slim @@ -10,33 +10,38 @@ h1 = t('breadcrumbs.dashboard.show') h2 Version div.mb-4 - = "CodeOcean Release:" + = application_name + =< t("admin.dashboard.show.release") + | : pre = Sentry.configuration.release - if Runner.management_active? div.mb-4 = Runner.strategy_class.name.demodulize - =< "Release:" + =< t("admin.dashboard.show.release") + | : pre = Runner.strategy_class.release h2 Docker - if Runner.management_active? - h3 = t('.current') + h3 = t('admin.dashboard.show.current') .table-responsive table.table thead tr th = t('activerecord.models.execution_environment.one') th = t('activerecord.attributes.execution_environment.pool_size') - th = t('.quantity') + th = t('admin.dashboard.show.idleRunners') + th = t('admin.dashboard.show.usedRunners') tbody - ExecutionEnvironment.order(:name).each do |execution_environment| tr data-id=execution_environment.id td.name = link_to_if(policy(execution_environment).show?, execution_environment, execution_environment) - td.pool-size - td.quantity = progress_bar(0) - h3 = t('.history') + td.prewarming-pool-size + td.idle-runners = progress_bar(0) + td.used-runners + h3 = t('admin.dashboard.show.history') #graph - else - p = t('.inactive') + p = t('admin.dashboard.show.inactive') diff --git a/config/locales/de.yml b/config/locales/de.yml index ba767d3a..4d8a602d 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -241,10 +241,12 @@ de: admin: dashboard: show: + release: Release current: Aktuelle Verfügbarkeit - history: Verfügbarkeitsverlauf + history: Nutzungsverlauf inactive: Es ist kein Runner Management aktiv. - quantity: Verfügbare Container + idleRunners: Freie Runner + usedRunners: Reservierte Runner application: not_authorized: Sie Sind nicht berechtigt, diese Aktion auszuführen. welcome: diff --git a/config/locales/en.yml b/config/locales/en.yml index 33eb6adc..4f93be50 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -241,10 +241,12 @@ en: admin: dashboard: show: + release: Release current: Current Availability - history: Availability History + history: Usage History inactive: No runner management is currently enabled. - quantity: Available Containers + idleRunners: Idle Runners + usedRunners: Reserved Runners application: not_authorized: You are not authorized to perform this action. welcome: diff --git a/lib/runner/strategy/docker_container_pool.rb b/lib/runner/strategy/docker_container_pool.rb index be79bcc2..526a7c76 100644 --- a/lib/runner/strategy/docker_container_pool.rb +++ b/lib/runner/strategy/docker_container_pool.rb @@ -166,7 +166,7 @@ class Runner::Strategy::DockerContainerPool < Runner::Strategy url = "#{config[:url]}/docker_container_pool/quantities" response = Faraday.get(url) pool_size = JSON.parse(response.body) - pool_size.transform_keys(&:to_i) + pool_size.deep_symbolize_keys rescue Faraday::Error => e raise Runner::Error::FaradayError.new("Request to DockerContainerPool failed: #{e.inspect}") rescue JSON::ParserError => e diff --git a/lib/runner/strategy/poseidon.rb b/lib/runner/strategy/poseidon.rb index 879aa7d3..fb3cbd9a 100644 --- a/lib/runner/strategy/poseidon.rb +++ b/lib/runner/strategy/poseidon.rb @@ -176,7 +176,23 @@ class Runner::Strategy::Poseidon < Runner::Strategy end def self.pool_size - {} + url = "#{config[:url]}/statistics/execution-environments" + Rails.logger.debug { "#{Time.zone.now.getutc.inspect}: Getting statistics from #{url}" } + response = http_connection.get url + case response.status + when 200 + response_body = parse response + response_body + else + handle_error response + end + rescue Faraday::Error => e + raise Runner::Error::FaradayError.new("Request to Poseidon failed: #{e.inspect}") + rescue JSON::ParserError => e + # Poseidon should not send invalid json + raise Runner::Error::UnexpectedResponse.new("Error parsing response from Poseidon: #{e.message}") + ensure + Rails.logger.debug { "#{Time.zone.now.getutc.inspect}: Finished getting statistics" } end def self.websocket_header diff --git a/spec/helpers/admin/dashboard_helper_spec.rb b/spec/helpers/admin/dashboard_helper_spec.rb index 22307561..643bd08f 100644 --- a/spec/helpers/admin/dashboard_helper_spec.rb +++ b/spec/helpers/admin/dashboard_helper_spec.rb @@ -14,7 +14,7 @@ describe Admin::DashboardHelper do FactoryBot.create(:ruby) dcp = instance_double 'docker_container_pool' allow(Runner).to receive(:strategy_class).and_return dcp - allow(dcp).to receive(:pool_size).and_return([]) + allow(dcp).to receive(:pool_size).and_return({}) end it 'contains an entry for every execution environment' do @@ -22,11 +22,15 @@ describe Admin::DashboardHelper do end it 'contains the pool size for every execution environment' do - expect(docker_data.first.symbolize_keys).to include(:pool_size) + expect(docker_data.first.symbolize_keys).to include(:prewarmingPoolSize) end - it 'contains the number of available containers for every execution environment' do - expect(docker_data.first).to include(:quantity) + it 'contains the number of idle runners for every execution environment' do + expect(docker_data.first).to include(:idleRunners) + end + + it 'contains the number of used runners for every execution environment' do + expect(docker_data.first).to include(:usedRunners) end end end