Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slurm plugin job submission info #589

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
recursive-include coldfront/core/field_of_science/management/commands/data *
recursive-include coldfront/plugins/iquota/templates *
recursive-include coldfront/plugins/system_monitor/templates *
recursive-include coldfront/plugins/slurm/templates *
recursive-include coldfront/templates *
recursive-include coldfront/static *
recursive-include coldfront/core/portal/templates *
Expand Down
8 changes: 8 additions & 0 deletions coldfront/config/plugins/slurm.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,11 @@
SLURM_NOOP = ENV.bool('SLURM_NOOP', False)
SLURM_IGNORE_USERS = ENV.list('SLURM_IGNORE_USERS', default=['root'])
SLURM_IGNORE_ACCOUNTS = ENV.list('SLURM_IGNORE_ACCOUNTS', default=[])
SLURM_SUBMISSION_INFO = ENV.list('SLURM_SUBMISSION_INFO', default=['account'])
SLURM_DISPLAY_SHORT_OPTION_NAMES = ENV.bool('SLURM_DISPLAY_SHORT_OPTION_NAMES', default=False)
SLURM_SHORT_OPTION_NAMES = ENV.dict('SLURM_SHORT_OPTION_NAMES', default={
'qos': 'q',
'account': 'A',
'clusters': 'M',
'partition': 'p',
})
2 changes: 2 additions & 0 deletions coldfront/config/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
path('research-output/', include('coldfront.core.research_output.urls')),
]

if 'coldfront.plugins.slurm' in settings.INSTALLED_APPS:
urlpatterns.append(path('slurm/', include('coldfront.plugins.slurm.urls')))

if 'coldfront.plugins.iquota' in settings.INSTALLED_APPS:
urlpatterns.append(path('iquota/', include('coldfront.plugins.iquota.urls')))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,10 @@ <h4 class="card-title">{{attribute}}</h4>
</div>
{% endif %}

{% if display_slurm_submission_info %}
{% include "slurm/slurm_submission_info_div.html" %}
{% endif %}

<!-- Start Allocation Change Requests -->
<div class="card mb-3">
<div class="card-header">
Expand Down
2 changes: 2 additions & 0 deletions coldfront/core/allocation/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from dateutil.relativedelta import relativedelta
from django import forms
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import get_user_model
from django.contrib.auth.models import User
Expand Down Expand Up @@ -167,6 +168,7 @@ def get(self, request, *args, **kwargs):
context = self.get_context_data()
context['form'] = form
context['allocation'] = allocation_obj
context['display_slurm_submission_info'] = 'coldfront.plugins.slurm' in settings.INSTALLED_APPS
return self.render_to_response(context)

def post(self, request, *args, **kwargs):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@
{% if 'coldfront.plugins.system_monitor' in EXTRA_APPS %}
{% include "system_monitor/system_monitor_div.html" %}
{% endif %}

{% if 'coldfront.plugins.slurm' in EXTRA_APPS and user.is_authenticated %}
{% include "slurm/all_slurm_submission_info_div.html" %}
{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{% load slurm_tags %}

{% if slurm_submission_info %}
<div class="col">
<div class="card mb-3">
<div class="card-header">
Submitting Slurm Jobs
</div>
<div class="card-body">
{% for project_pk, allocations in slurm_submission_info.items %}
<hr>
<h3><strong>{{ project_titles|dictitem:project_pk }}</strong></h3>
<hr>
<h4>Interactive Jobs</h4>
<hr>
<div class="table-responsive">
<table class="table table-bordered table-sm">
{% for resources in allocations %}
{% for resources_name, submit_info in resources.items %}
{% if submit_info %}
<tr>
<th scope="row" class="text-nowrap">{{ resources_name }}</th>
<td>
srun
{% for slurm_submit_option, slurm_submit_option_value in submit_info.items %}
{{ slurm_submit_option }} {{ slurm_submit_option_value }}
{% endfor %}
&lt;other options&gt;
</td>
</tr>
{% endif %}
{% endfor %}
{% endfor %}
</table>
</div>
<hr>
<h4>Batch Jobs</h4>
<div class="row">
{% for resources in allocations %}
{% for resources_name, submit_info in resources.items %}
{% if submit_info %}
<div class="col-4">
<hr>
<strong>{{ resources_name }}</strong>
<hr>
<ul style="list-style-type: none; padding: 0; margin: 0;">
{% for slurm_submit_option, slurm_submit_option_value in submit_info.items %}
<li>
#SBATCH {{ slurm_submit_option }} {{ slurm_submit_option_value }}
</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% endfor %}
{% endfor %}
</div>
{% endfor %}
</div>
</div>
</div>
{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

<div id="all_slurm_submission_info">
</div>

<script>
$(document).ready(function () {
$.ajax({
url: "{% url 'all-slurm-submission-info' %}",
method: "POST",
data: {
csrfmiddlewaretoken: "{{ csrf_token }}",
},
success: function(data) {
$('#all_slurm_submission_info').before(data);
$('#all_slurm_submission_info').remove();
}
})
})
</script>
42 changes: 42 additions & 0 deletions coldfront/plugins/slurm/templates/slurm/slurm_submission_info.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{% if slurm_submission_info %}
<div class="card mb-3">
<div class="card-header">
<h3 class="d-inline"><i class="fas fa-info-circle" aria-hidden="true"></i> Submitting Slurm Jobs</h3>
</div>
<div class="card-body">
<h4 class="d-inline">Interactive Jobs</h4>
<hr>
<ul style="list-style-type: none; padding: 0; margin: 0;">
{% for resources_name, submit_info in slurm_submission_info.items %}
{% if submit_info %}
<li>
srun
{% for slurm_submit_option, submit_info_value in submit_info.items %}
{{ slurm_submit_option }} {{ submit_info_value }}
{% endfor %}
&lt;other options&gt;
</li>
{% endif %}
{% endfor %}
</ul>
<hr>
<h4 class="d-inline">Batch Jobs</h4>
<hr>
<div class="row">
{% for resources_name, submit_info in slurm_submission_info.items %}
{% if submit_info %}
<div class="col">
<ul style="list-style-type: none; padding: 0; margin: 0;">
{% for slurm_submit_option, submit_info_value in submit_info.items %}
<li>
#SBATCH {{ slurm_submit_option }} {{ submit_info_value }}
</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% endfor %}
</div>
</div>
</div>
{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

<div id="slurm_submission_info">
</div>

<script>
$(document).ready(function () {
$.ajax({
url: "{% url 'slurm-submission-info' %}",
method: "POST",
data: {
csrfmiddlewaretoken: "{{ csrf_token }}",
allocation_pk: "{{ allocation.pk }}"
},
success: function(data) {
$('#slurm_submission_info').html(data);
}
})
})
</script>
Empty file.
7 changes: 7 additions & 0 deletions coldfront/plugins/slurm/templatetags/slurm_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django import template

register = template.Library()

@register.filter
def dictitem(dictionary, key):
return dictionary.get(key)
8 changes: 8 additions & 0 deletions coldfront/plugins/slurm/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.urls import path

from coldfront.plugins.slurm.views import get_all_slurm_submission_info, get_slurm_submission_info

urlpatterns = [
path('all-slurm-submission-info/', get_all_slurm_submission_info, name='all-slurm-submission-info'),
path('slurm-submission-info/', get_slurm_submission_info, name='slurm-submission-info')
]
103 changes: 103 additions & 0 deletions coldfront/plugins/slurm/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
from django.shortcuts import render
from django.http import HttpResponse
from coldfront.core.allocation.models import Allocation
from coldfront.core.allocation.models import Project
from coldfront.core.utils.common import import_from_settings

SLURM_SUBMISSION_INFO = import_from_settings('SLURM_SUBMISSION_INFO', ['account'])
SLURM_DISPLAY_SHORT_OPTION_NAMES = import_from_settings('SLURM_DISPLAY_SHORT_OPTION_NAMES', False)
SLURM_SHORT_OPTION_NAMES = import_from_settings('SLURM_SHORT_OPTION_NAMES', {})


def get_all_slurm_submission_info(request):
if not request.user.is_authenticated:
return HttpResponse('401 Unauthorized', status=401)

project_list = Project.objects.filter(
status__name='Active',
projectuser__user=request.user,
projectuser__status__name='Active',
)

project_titles = {}
slurm_submission_info = {}
for project_obj in project_list:
project_titles[project_obj.pk] = project_obj.title
slurm_submission_info[project_obj.pk] = []
allocation_list = project_obj.allocation_set.filter(
status__name__in=['Active', 'Renewal Requested', ],
allocationuser__user=request.user,
allocationuser__status__name='Active',
)
for allocation_obj in allocation_list:
slurm_submission_info[project_obj.pk].append(get_slurm_submission_info_from_allocation(allocation_obj))

context = {}
context['slurm_submission_info'] = slurm_submission_info
context['project_titles'] = project_titles
return render(request, 'slurm/all_slurm_submission_info.html', context)


def get_slurm_submission_info(request):
allocation_obj = Allocation.objects.get(pk=request.POST.get('allocation_pk'))
slurm_submission_info = get_slurm_submission_info_from_allocation(allocation_obj)
return render(request, 'slurm/slurm_submission_info.html', {'slurm_submission_info': slurm_submission_info})


def get_slurm_submission_info_from_allocation(allocation_obj):
submit_options = {}
resource_obj = allocation_obj.get_parent_resource
resource_type = resource_obj.resource_type.name
if resource_type == 'Cluster Partition':
cluster_obj = resource_obj.parent_resource
if 'clusters' in SLURM_SUBMISSION_INFO:
submit_options['clusters'] = cluster_obj.resourceattribute_set.get(resource_attribute_type__name='slurm_cluster').value
if 'partition' in SLURM_SUBMISSION_INFO:
submit_options['partition'] = resource_obj.name.lower()
elif resource_type != 'Cluster':
return {}

slurm_account = allocation_obj.allocationattribute_set.filter(allocation_attribute_type__name='slurm_account_name')
if slurm_account.exists():
if 'account' in SLURM_SUBMISSION_INFO:
submit_options['account'] = slurm_account[0].value

slurm_specs = resource_obj.resourceattribute_set.filter(resource_attribute_type__name='slurm_specs')
submit_options = get_slurm_submission_info_from_slurm_specs(slurm_specs, submit_options)
slurm_specs = allocation_obj.allocationattribute_set.filter(allocation_attribute_type__name='slurm_specs')
submit_options = get_slurm_submission_info_from_slurm_specs(slurm_specs, submit_options)

if SLURM_DISPLAY_SHORT_OPTION_NAMES:
submit_short_options = {}
for option, value in submit_options.items():
short_option = SLURM_SHORT_OPTION_NAMES.get(option)
if short_option:
submit_short_options['-' + short_option] = value
else:
submit_short_options['--' + option] = value

slurm_submission_info = submit_short_options
else:
submit_long_options = {}
for option, value in submit_options.items():
submit_long_options['--' + option] = value

slurm_submission_info = submit_long_options

return {resource_obj.name: slurm_submission_info}


def get_slurm_submission_info_from_slurm_specs(slurm_specs, submit_options):
if slurm_specs.exists():
specs = slurm_specs[0].value.replace('+', '').split(':')
for spec in specs:
spec_split = spec.split('=')
# Expanded attributes should be skipped
if len(spec_split) > 2:
continue
option, value = spec_split
option = option.lower()
if option in SLURM_SUBMISSION_INFO:
submit_options[option] = value

return submit_options