From 6fa9a847fe97a97d8f3e477340bb0b93eadcfe36 Mon Sep 17 00:00:00 2001 From: Ashton South Date: Fri, 15 Nov 2024 10:47:45 -0500 Subject: [PATCH] Pm job management (#3899) Add the ability to delete jobs from the job log as well as the ability to stop a running/queued job. --- .../app/controllers/projects_controller.rb | 49 ++++++++++++++++++- .../app/helpers/application_helper.rb | 2 +- apps/dashboard/app/helpers/projects_helper.rb | 19 ++++++- .../app/models/concerns/job_logger.rb | 13 +++++ apps/dashboard/app/models/project.rb | 9 +++- .../projects/_job_details.turbo_stream.erb | 2 +- .../projects/_job_details_content.html.erb | 3 ++ .../buttons/_completed_buttons.html.erb | 7 +++ .../projects/buttons/_queued_buttons.html.erb | 7 +++ .../buttons/_running_buttons.html.erb | 7 +++ .../app/views/projects/show.html.erb | 6 +-- .../shared/_path_selector_table.html.erb | 2 +- apps/dashboard/config/locales/en.yml | 4 ++ apps/dashboard/config/routes.rb | 2 + 14 files changed, 123 insertions(+), 9 deletions(-) create mode 100644 apps/dashboard/app/views/projects/buttons/_completed_buttons.html.erb create mode 100644 apps/dashboard/app/views/projects/buttons/_queued_buttons.html.erb create mode 100644 apps/dashboard/app/views/projects/buttons/_running_buttons.html.erb diff --git a/apps/dashboard/app/controllers/projects_controller.rb b/apps/dashboard/app/controllers/projects_controller.rb index 0e65d7446c..cb77117e73 100644 --- a/apps/dashboard/app/controllers/projects_controller.rb +++ b/apps/dashboard/app/controllers/projects_controller.rb @@ -110,7 +110,54 @@ def job_details hpc_job = project.job(job_details_params[:jobid].to_s, cluster_str) - render(partial: 'job_details', locals: { job: hpc_job }) + @project = project + + render(partial: 'job_details', locals: { job: hpc_job, project: @project }) + end + + # DELETE /projects/:project_id/jobs/:cluster/:jobid + def delete_job + @project = Project.find(job_details_params[:project_id]) + + cluster_str = job_details_params[:cluster].to_s + + jobid = job_details_params[:jobid] + + if @project.remove_logged_job(jobid.to_s, cluster_str) + redirect_to( + project_path(job_details_params[:project_id]), + notice: I18n.t('dashboard.jobs_project_job_deleted', job_id: jobid) + ) + else + redirect_to( + project_path(job_details_params[:project_id]), + alert: I18n.t('dashboard.jobs_project_job_not_deleted', jobid: jobid) + ) + end + end + + # POST /projects/:project_id/jobs/:cluster/:jobid/stop + def stop_job + @project = Project.find(job_details_params[:project_id]) + cluster_str = job_details_params[:cluster].to_s + cluster = OodAppkit.clusters[cluster_str.to_sym] + + jobid = job_details_params[:jobid] + + hpc_job = @project.job(jobid.to_s, cluster_str) + + begin + cluster.job_adapter.delete(jobid.to_s) unless hpc_job.status.to_s == 'completed' + redirect_to( + project_path(job_details_params[:project_id]), + notice: I18n.t('dashboard.jobs_project_job_stopped', job_id: jobid) + ) + rescue StandardError => e + redirect_to( + project_path(job_details_params[:project_id]), + alert: I18n.t('dashboard.jobs_project_generic_error', error: e.message.to_s) + ) + end end private diff --git a/apps/dashboard/app/helpers/application_helper.rb b/apps/dashboard/app/helpers/application_helper.rb index bb169ef07c..4e99aecb10 100644 --- a/apps/dashboard/app/helpers/application_helper.rb +++ b/apps/dashboard/app/helpers/application_helper.rb @@ -120,7 +120,7 @@ def status_text(status) 'Running' when 'queued' 'Queued' - when 'qued_held' + when 'queued_held' 'Hold' when 'suspended' 'Suspend' diff --git a/apps/dashboard/app/helpers/projects_helper.rb b/apps/dashboard/app/helpers/projects_helper.rb index c725ac7b8b..87df4858d4 100644 --- a/apps/dashboard/app/helpers/projects_helper.rb +++ b/apps/dashboard/app/helpers/projects_helper.rb @@ -14,4 +14,21 @@ def render_readme(readme_location) simple_format(file_content) end end -end \ No newline at end of file + + def job_details_buttons(status, job, project) + locals = { project_id: project.id, id: job.id, cluster: job.cluster } + button_partial = button_category(status) + render(partial: "projects/buttons/#{button_category(status)}_buttons", locals: locals) unless button_partial.nil? + end + + def button_category(status) + case status + when 'queued_held' + 'held' + when 'suspended' + 'held' + else + status + end + end +end diff --git a/apps/dashboard/app/models/concerns/job_logger.rb b/apps/dashboard/app/models/concerns/job_logger.rb index e62d0d0c10..ba235dfae0 100644 --- a/apps/dashboard/app/models/concerns/job_logger.rb +++ b/apps/dashboard/app/models/concerns/job_logger.rb @@ -16,6 +16,19 @@ def upsert_job!(directory, job) JobLoggerHelper.write_log(directory, new_jobs) end + def delete_job!(directory, job) + existing_jobs = jobs(directory) + stored_job = existing_jobs.detect { |j| j.id == job.id && j.cluster == job.cluster } + + return if stored_job.nil? + + new_jobs = existing_jobs.map(&:to_h) + idx = existing_jobs.index(stored_job) + new_jobs.delete_at(idx) + + JobLoggerHelper.write_log(directory, new_jobs) + end + # def write_job_log!(directory, jobs) # JobLoggerHelper.write_log!(directory, jobs) # endd diff --git a/apps/dashboard/app/models/project.rb b/apps/dashboard/app/models/project.rb index e29b7303cd..be2522091b 100644 --- a/apps/dashboard/app/models/project.rb +++ b/apps/dashboard/app/models/project.rb @@ -219,6 +219,13 @@ def job(job_id, cluster) job end + def remove_logged_job(job_id, cluster) + old_job = jobs.detect { |j| j.id == job_id && j.cluster == cluster } + Project.delete_job!(directory, old_job) + + jobs.none? { |j| j.id == job_id && j.cluster == cluster } + end + def adapter(cluster_id) cluster = OodAppkit.clusters[cluster_id] || raise(StandardError, "Job specifies nonexistent '#{cluster_id}' cluster id.") cluster.job_adapter @@ -230,7 +237,7 @@ def readme_path end private - + def update_attrs(attributes) [:name, :description, :icon].each do |attribute| instance_variable_set("@#{attribute}".to_sym, attributes.fetch(attribute, '')) diff --git a/apps/dashboard/app/views/projects/_job_details.turbo_stream.erb b/apps/dashboard/app/views/projects/_job_details.turbo_stream.erb index b85c80f7b8..838f73339e 100644 --- a/apps/dashboard/app/views/projects/_job_details.turbo_stream.erb +++ b/apps/dashboard/app/views/projects/_job_details.turbo_stream.erb @@ -5,6 +5,6 @@ diff --git a/apps/dashboard/app/views/projects/_job_details_content.html.erb b/apps/dashboard/app/views/projects/_job_details_content.html.erb index 3cb30b6821..ac39ff326c 100644 --- a/apps/dashboard/app/views/projects/_job_details_content.html.erb +++ b/apps/dashboard/app/views/projects/_job_details_content.html.erb @@ -19,6 +19,9 @@ <% end %> +
+ <%= job_details_buttons(job.status.to_s, job, project) %> +
diff --git a/apps/dashboard/app/views/projects/buttons/_completed_buttons.html.erb b/apps/dashboard/app/views/projects/buttons/_completed_buttons.html.erb new file mode 100644 index 0000000000..0df5fa9711 --- /dev/null +++ b/apps/dashboard/app/views/projects/buttons/_completed_buttons.html.erb @@ -0,0 +1,7 @@ +<%= button_to( + 'Delete', + project_delete_job_path(project_id: project_id, cluster: cluster, jobid: id), + method: :delete, + data: { confirm: t('dashboard.batch_connect_sessions_delete_confirm') }, + class: 'btn btn-danger' +) %> \ No newline at end of file diff --git a/apps/dashboard/app/views/projects/buttons/_queued_buttons.html.erb b/apps/dashboard/app/views/projects/buttons/_queued_buttons.html.erb new file mode 100644 index 0000000000..8ff57cb0d0 --- /dev/null +++ b/apps/dashboard/app/views/projects/buttons/_queued_buttons.html.erb @@ -0,0 +1,7 @@ +<%= button_to( + 'Stop', + project_stop_job_path(project_id: project_id, cluster: cluster, jobid: id), + method: :post, + data: { confirm: t('dashboard.batch_connect_sessions_delete_confirm') }, + class: 'btn btn-danger' +) %> \ No newline at end of file diff --git a/apps/dashboard/app/views/projects/buttons/_running_buttons.html.erb b/apps/dashboard/app/views/projects/buttons/_running_buttons.html.erb new file mode 100644 index 0000000000..8ff57cb0d0 --- /dev/null +++ b/apps/dashboard/app/views/projects/buttons/_running_buttons.html.erb @@ -0,0 +1,7 @@ +<%= button_to( + 'Stop', + project_stop_job_path(project_id: project_id, cluster: cluster, jobid: id), + method: :post, + data: { confirm: t('dashboard.batch_connect_sessions_delete_confirm') }, + class: 'btn btn-danger' +) %> \ No newline at end of file diff --git a/apps/dashboard/app/views/projects/show.html.erb b/apps/dashboard/app/views/projects/show.html.erb index 8c63227dbf..29d1522dc9 100644 --- a/apps/dashboard/app/views/projects/show.html.erb +++ b/apps/dashboard/app/views/projects/show.html.erb @@ -62,8 +62,8 @@
-

Active Jobs

- <%= render(partial: 'job_details', collection: @project.active_jobs, as: :job) %> +

Active Jobs

+ <%= render(partial: 'job_details', collection: @project.active_jobs, as: :job, locals: { project: @project }) %>
@@ -71,7 +71,7 @@
<%- @project.completed_jobs.each do |job| -%>
"> - <%= render(partial: 'job_details_content', locals: { job: job }) %> + <%= render(partial: 'job_details_content', locals: { job: job, project: @project }) %>
<%- end -%>
diff --git a/apps/dashboard/app/views/shared/_path_selector_table.html.erb b/apps/dashboard/app/views/shared/_path_selector_table.html.erb index 6b91e58be5..127159f2c8 100644 --- a/apps/dashboard/app/views/shared/_path_selector_table.html.erb +++ b/apps/dashboard/app/views/shared/_path_selector_table.html.erb @@ -1,7 +1,7 @@