Skip to content

Commit 35a9144

Browse files
authored
adding fixes and GUI for #3323 (#3331)
* adding fixes and GUI * small fixes after deploy * slurm_reservation[0] * jobs special cases * fix test
1 parent 9bcdf46 commit 35a9144

File tree

13 files changed

+158
-45
lines changed

13 files changed

+158
-45
lines changed

qiita_db/analysis.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ def get_by_status(cls, status):
127127

128128
@classmethod
129129
def create(cls, owner, name, description, from_default=False,
130-
merge_duplicated_sample_ids=False, categories=None):
130+
merge_duplicated_sample_ids=False, categories=None,
131+
reservation=None):
131132
"""Creates a new analysis on the database
132133
133134
Parameters
@@ -147,6 +148,8 @@ def create(cls, owner, name, description, from_default=False,
147148
the artifact id
148149
categories : list of str, optional
149150
If not None, use _only_ these categories for the metaanalysis
151+
reservation : str
152+
The slurm reservation to asign to the analysis
150153
151154
Returns
152155
-------
@@ -187,6 +190,8 @@ def create(cls, owner, name, description, from_default=False,
187190
qdb.sql_connection.TRN.add(sql, args, many=True)
188191

189192
instance = cls(a_id)
193+
if reservation is not None:
194+
instance.slurm_reservation = reservation
190195

191196
# Once the analysis is created, we can create the mapping file and
192197
# the initial set of artifacts
@@ -1198,12 +1203,11 @@ def slurm_reservation(self):
11981203
"""
11991204
slurm_reservation = self._slurm_reservation()
12001205

1201-
if slurm_reservation:
1202-
slurm_reservation = slurm_reservation[0]
1203-
cmd = f"scontrol show reservations {slurm_reservation}"
1206+
if slurm_reservation and slurm_reservation[0] != '':
1207+
cmd = f"scontrol show reservations {slurm_reservation[0]}"
12041208
p_out, p_err, rv = qdb.processing_job._system_call(cmd)
1205-
if rv == 0:
1206-
return slurm_reservation
1209+
if rv == 0 and p_out != 'No reservations in the system\n':
1210+
return slurm_reservation[0]
12071211

12081212
return None
12091213

qiita_db/handlers/tests/test_processing_job.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,9 @@ def test_post_job_success(self):
234234
# additionally we can test that job.print_trace is correct
235235
self.assertEqual(job.trace, [
236236
f'{job.id} [Not Available]: Validate | '
237-
'-p qiita -N 1 -n 1 --mem 90gb --time 150:00:00 --nice 10000',
237+
'-p qiita -N 1 -n 1 --mem 90gb --time 150:00:00 --nice=10000',
238238
f' {cj.id} [{cj.external_id}] | '
239-
'-p qiita -N 1 -n 1 --mem 16gb --time 10:00:00 --nice 10000'])
239+
'-p qiita -N 1 -n 1 --mem 16gb --time 10:00:00 --nice=10000'])
240240

241241
def test_post_job_success_with_archive(self):
242242
pt = npt.assert_warns(

qiita_db/processing_job.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -419,8 +419,15 @@ def resource_allocation_info(self):
419419
if v['artifacts'] is not None:
420420
an_element = list(v['artifacts'].keys())[0]
421421
name = v['artifacts'][an_element]['artifact_type']
422-
ia = ProcessingJob(params['job_id']).input_artifacts
423-
if ia:
422+
# for analysis we have two options, either use the
423+
# input_artifacts or use the parameter 'analysis' of the job
424+
# to complete
425+
job = ProcessingJob(params['job_id'])
426+
params = job.parameters.values
427+
ia = job.input_artifacts
428+
if 'analysis' in params and params['analysis'] is not None:
429+
analysis = qdb.analysis.Analysis(params['analysis'])
430+
elif ia:
424431
analysis = ia[0].analysis
425432
elif self.command.name == 'release_validators':
426433
jtype = 'RELEASE_VALIDATORS_RESOURCE_PARAM'
@@ -440,8 +447,13 @@ def resource_allocation_info(self):
440447
# assume anything else is a command
441448
jtype = 'RESOURCE_PARAMS_COMMAND'
442449
name = self.command.name
450+
# for analysis we have two options, either use the
451+
# input_artifacts or use the parameter 'analysis' of self
452+
params = self.parameters.values
443453
ia = self.input_artifacts
444-
if ia:
454+
if 'analysis' in params and params['analysis'] is not None:
455+
analysis = qdb.analysis.Analysis(params['analysis'])
456+
elif ia:
445457
analysis = ia[0].analysis
446458

447459
# first, query for resources matching name and type

qiita_db/support_files/patches/89.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
-- Nov 1, 2023
22
-- add creation_job_id to qiita.prep_template
33
ALTER TABLE qiita.analysis ADD slurm_reservation VARCHAR DEFAULT '' NOT NULL;
4-
ALTER TABLE qiita.user_level ADD slurm_parameters VARCHAR DEFAULT '--nice 10000' NOT NULL;
4+
ALTER TABLE qiita.user_level ADD slurm_parameters VARCHAR DEFAULT '--nice=10000' NOT NULL;
55

6-
UPDATE qiita.user_level SET slurm_parameters = '--nice 5000' WHERE name = 'admin';
6+
UPDATE qiita.user_level SET slurm_parameters = '--nice=5000' WHERE name = 'admin';
77

88
UPDATE qiita.user_level SET slurm_parameters = '' WHERE name = 'wet-lab admin';

qiita_db/test/test_processing_job.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,7 @@ def test_complete_success(self):
554554
self.assertEqual(validator.parameters.values['artifact_type'], 'BIOM')
555555
self.assertEqual(
556556
validator.resource_allocation_info,
557-
'-p qiita -N 1 -n 1 --mem 90gb --time 150:00:00 --nice 10000')
557+
'-p qiita -N 1 -n 1 --mem 90gb --time 150:00:00 --nice=10000')
558558
self.assertEqual(validator.shape, (27, 53, None))
559559
# Test the output artifact is going to be named based on the
560560
# input parameters
@@ -793,37 +793,37 @@ def test_shape_special_cases(self):
793793
current_allocation = pj.resource_allocation_info
794794
self.assertEqual(current_allocation,
795795
'-p qiita -N 1 -n 1 --mem 120gb --time 80:00:00 '
796-
'--nice 10000')
796+
'--nice=10000')
797797

798798
# now, let's update that job allocation and make sure that things
799799
# work as expected
800800
tests = [
801801
# (resource allocation, specific allocation)
802802
# 1. tests that nlog works
803803
('-p qiita -N 1 -n 1 --mem nlog({samples})*100 --time {columns}',
804-
'-p qiita -N 1 -n 1 --mem 329B --time 0:00:53 --nice 10000'),
804+
'-p qiita -N 1 -n 1 --mem 329B --time 0:00:53 --nice=10000'),
805805
# 2. days in time works fine
806806
('-p qiita -N 1 -n 1 --mem 10g --time {columns}*10000',
807-
'-p qiita -N 1 -n 1 --mem 10g --time 6-3:13:20 --nice 10000'),
807+
'-p qiita -N 1 -n 1 --mem 10g --time 6-3:13:20 --nice=10000'),
808808
('-p qiita -N 1 -n 1 --mem 20g --time {columns}*1631',
809-
'-p qiita -N 1 -n 1 --mem 20g --time 1-0:00:43 --nice 10000'),
809+
'-p qiita -N 1 -n 1 --mem 20g --time 1-0:00:43 --nice=10000'),
810810
# 3. conditionals work
811811
('-p qiita -N 1 -n 1 --mem 10g --time {columns}*1631 '
812812
'if {columns}*1631 < 86400 else 86400',
813-
'-p qiita -N 1 -n 1 --mem 10g --time 1-0:00:00 --nice 10000'),
813+
'-p qiita -N 1 -n 1 --mem 10g --time 1-0:00:00 --nice=10000'),
814814
('-p qiita -N 1 -n 1 --mem 10g --time {columns}*1631 '
815815
'if {columns}*1631 > 86400 else 86400',
816-
'-p qiita -N 1 -n 1 --mem 10g --time 1-0:00:43 --nice 10000'),
816+
'-p qiita -N 1 -n 1 --mem 10g --time 1-0:00:43 --nice=10000'),
817817
# --qos=qiita_prio
818818
('-p qiita -N 1 -n 1 --mem 10g --time 1:00:00 --qos=qiita_prio',
819819
'-p qiita -N 1 -n 1 --mem 10g --time 1:00:00 --qos=qiita_prio '
820-
'--nice 10000'),
820+
'--nice=10000'),
821821
# all the combinations
822822
('-p qiita -N 1 -n 1 --mem nlog({samples})*100000 --time '
823823
'{columns}*1631 if {columns}*1631 > 86400 else 86400 '
824824
'--qos=qiita_prio',
825825
'-p qiita -N 1 -n 1 --mem 322K --time 1-0:00:43 '
826-
'--qos=qiita_prio --nice 10000'),
826+
'--qos=qiita_prio --nice=10000'),
827827
]
828828
for ra, sra in tests:
829829
sql = ("UPDATE qiita.processing_job_resource_allocation "
@@ -842,17 +842,17 @@ def test_get_resource_allocation_info(self):
842842
jids = {
843843
# Split libraries FASTQ
844844
'6d368e16-2242-4cf8-87b4-a5dc40bb890b':
845-
'-p qiita -N 1 -n 1 --mem 120gb --time 80:00:00 --nice 10000',
845+
'-p qiita -N 1 -n 1 --mem 120gb --time 80:00:00 --nice=10000',
846846
# Pick closed-reference OTUs
847847
'80bf25f3-5f1d-4e10-9369-315e4244f6d5':
848-
'-p qiita -N 1 -n 5 --mem 120gb --time 130:00:00 --nice 10000',
848+
'-p qiita -N 1 -n 5 --mem 120gb --time 130:00:00 --nice=10000',
849849
# Single Rarefaction / Analysis
850850
'8a7a8461-e8a1-4b4e-a428-1bc2f4d3ebd0':
851851
'-p qiita -N 1 -n 5 --mem-per-cpu 8gb --time 168:00:00 '
852-
'--nice 10000',
852+
'--nice=10000',
853853
# Split libraries
854854
'bcc7ebcd-39c1-43e4-af2d-822e3589f14d':
855-
'-p qiita -N 1 -n 1 --mem 60gb --time 25:00:00 --nice 10000'}
855+
'-p qiita -N 1 -n 1 --mem 60gb --time 25:00:00 --nice=10000'}
856856

857857
for jid, allocation in jids.items():
858858
job = qdb.processing_job.ProcessingJob(jid)
@@ -877,27 +877,27 @@ def _set_allocation(memory):
877877
_set_allocation('{samples}*1000')
878878
self.assertEqual(
879879
job_not_changed.resource_allocation_info,
880-
'-p qiita -N 1 -n 5 --mem 120gb --time 130:00:00 --nice 10000')
880+
'-p qiita -N 1 -n 5 --mem 120gb --time 130:00:00 --nice=10000')
881881
self.assertEqual(job_changed.resource_allocation_info,
882-
'-p qiita --mem 26K --nice 10000')
882+
'-p qiita --mem 26K --nice=10000')
883883

884884
# a little more complex ((samples+columns)*1000000)+4000000
885885
# (( 27 + 31 )*1000000)+4000000 ~ 62000000
886886
_set_allocation('(({samples}+{columns})*1000000)+4000000')
887887
self.assertEqual(
888888
job_not_changed.resource_allocation_info,
889-
'-p qiita -N 1 -n 5 --mem 120gb --time 130:00:00 --nice 10000')
889+
'-p qiita -N 1 -n 5 --mem 120gb --time 130:00:00 --nice=10000')
890890
self.assertEqual(job_changed.resource_allocation_info,
891-
'-p qiita --mem 80M --nice 10000')
891+
'-p qiita --mem 80M --nice=10000')
892892

893893
# now something real input_size+(2*1e+9)
894894
# 116 +(2*1e+9) ~ 2000000116
895895
_set_allocation('{input_size}+(2*1e+9)')
896896
self.assertEqual(
897897
job_not_changed.resource_allocation_info,
898-
'-p qiita -N 1 -n 5 --mem 120gb --time 130:00:00 --nice 10000')
898+
'-p qiita -N 1 -n 5 --mem 120gb --time 130:00:00 --nice=10000')
899899
self.assertEqual(job_changed.resource_allocation_info,
900-
'-p qiita --mem 2G --nice 10000')
900+
'-p qiita --mem 2G --nice=10000')
901901

902902
# restore allocation
903903
sql = ("UPDATE qiita.processing_job_resource_allocation "

qiita_db/test/test_user.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,9 +515,9 @@ def test_update_email(self):
515515

516516
def test_slurm_parameters(self):
517517
self.assertEqual(qdb.user.User('shared@foo.bar').slurm_parameters,
518-
'--nice 10000')
518+
'--nice=10000')
519519
self.assertEqual(qdb.user.User('admin@foo.bar').slurm_parameters,
520-
'--nice 5000')
520+
'--nice=5000')
521521

522522

523523
@qiita_test_checker()

qiita_pet/handlers/analysis_handlers/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
# -----------------------------------------------------------------------------
88

99
from .util import check_analysis_access
10-
from .base_handlers import (CreateAnalysisHandler, AnalysisDescriptionHandler,
10+
from .base_handlers import (CreateAnalysisHandler, AnalysisHandler,
1111
AnalysisGraphHandler, AnalysisJobsHandler)
1212
from .listing_handlers import (ListAnalysesHandler, AnalysisSummaryAJAX,
1313
SelectedSamplesHandler)
1414
from .sharing_handlers import ShareAnalysisAJAX
1515

16-
__all__ = ['CreateAnalysisHandler', 'AnalysisDescriptionHandler',
16+
__all__ = ['CreateAnalysisHandler', 'AnalysisHandler',
1717
'AnalysisGraphHandler', 'AnalysisJobsHandler',
1818
'ListAnalysesHandler', 'AnalysisSummaryAJAX',
1919
'SelectedSamplesHandler', 'check_analysis_access',

qiita_pet/handlers/analysis_handlers/base_handlers.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def post(self):
2727
desc = self.get_argument('description')
2828
mdsi = self.get_argument('merge_duplicated_sample_ids', False)
2929
metadata = self.request.arguments.get('analysis-metadata', None)
30+
reservation = self.get_argument('reservation', None)
3031
# we need to change from bytes to strings
3132
if metadata is not None:
3233
metadata = [m.decode('utf-8') for m in metadata]
@@ -35,7 +36,7 @@ def post(self):
3536
mdsi = True
3637
analysis = Analysis.create(
3738
self.current_user, name, desc, merge_duplicated_sample_ids=mdsi,
38-
from_default=True, categories=metadata)
39+
from_default=True, categories=metadata, reservation=reservation)
3940

4041
self.redirect(u"%s/analysis/description/%s/"
4142
% (qiita_config.portal_dir, analysis.id))
@@ -86,10 +87,11 @@ def analysis_description_handler_get_request(analysis_id, user):
8687
'analysis_mapping_id': analysis.mapping_file,
8788
'alert_type': alert_type,
8889
'artifacts': artifacts,
90+
'analysis_reservation': analysis._slurm_reservation()[0],
8991
'alert_msg': alert_msg}
9092

9193

92-
class AnalysisDescriptionHandler(BaseHandler):
94+
class AnalysisHandler(BaseHandler):
9395
@authenticated
9496
@execute_as_transaction
9597
def get(self, analysis_id):
@@ -119,6 +121,26 @@ def post(self, analysis_id):
119121

120122
self.render("analysis_description.html", **res)
121123

124+
@authenticated
125+
@execute_as_transaction
126+
def patch(self, analysis_id):
127+
"""Patches a analysis
128+
129+
Follows the JSON PATCH specification:
130+
https://tools.ietf.org/html/rfc6902
131+
"""
132+
req_op = self.get_argument('op')
133+
req_path = self.get_argument('path')
134+
req_value = self.get_argument('value', None)
135+
136+
if req_op == 'replace' and req_path == 'reservation':
137+
Analysis(analysis_id).slurm_reservation = req_value
138+
response = {'status': 'success', 'message': ''}
139+
else:
140+
response = {'status': 'error', 'message': 'Not implemented'}
141+
142+
self.write(response)
143+
122144

123145
def analyisis_graph_handler_get_request(analysis_id, user):
124146
"""Returns the graph information of the analysis

qiita_pet/handlers/analysis_handlers/tests/test_base_handlers.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ def test_analysis_description_handler_get_request(self):
5656
'libraries FASTQ', 'QIIME v1.9.1'), [
5757
'1.SKB7.640196', '1.SKB8.640193', '1.SKD8.640184',
5858
'1.SKM4.640180', '1.SKM9.640192'], {'1'})},
59+
'analysis_reservation': '',
5960
'alert_msg': ''}
60-
6161
self.assertEqual(obs, exp)
6262

6363
r_client.set('analysis_1', dumps({'job_id': 'job_id'}))
@@ -85,7 +85,8 @@ def test_analysis_description_handler_get_request(self):
8585
'libraries FASTQ', 'QIIME v1.9.1'), [
8686
'1.SKB7.640196', '1.SKB8.640193', '1.SKD8.640184',
8787
'1.SKM4.640180', '1.SKM9.640192'], {'1'})},
88-
'alert_msg': 'An artifact is being deleted from this analysis'}
88+
'alert_msg': 'An artifact is being deleted from this analysis',
89+
'analysis_reservation': ''}
8990
self.assertEqual(obs, exp)
9091

9192
r_client.set('job_id', dumps(
@@ -115,7 +116,8 @@ def test_analysis_description_handler_get_request(self):
115116
'libraries FASTQ', 'QIIME v1.9.1'), [
116117
'1.SKB7.640196', '1.SKB8.640193', '1.SKD8.640184',
117118
'1.SKM4.640180', '1.SKM9.640192'], {'1'})},
118-
'alert_msg': 'Error deleting artifact'}
119+
'alert_msg': 'Error deleting artifact',
120+
'analysis_reservation': ''}
119121
self.assertEqual(obs, exp)
120122

121123
def test_analyisis_graph_handler_get_request(self):
@@ -199,6 +201,25 @@ def test_get_analysis_jobs_handler(self):
199201
exp = {job_id: {'status': 'queued', 'step': None, 'error': ""}}
200202
self.assertEqual(obs, exp)
201203

204+
def test_patch(self):
205+
# first let's check that the reservation is not set
206+
analysis = Analysis(1)
207+
self.assertEqual(analysis._slurm_reservation(), [''])
208+
209+
# now, let's change it to something different
210+
reservation = 'my-reservation'
211+
arguments = {
212+
'op': 'replace', 'path': 'reservation', 'value': reservation}
213+
self.patch(f'/analysis/description/{analysis.id}/', data=arguments)
214+
self.assertEqual(analysis._slurm_reservation(), [reservation])
215+
216+
# then bring it back
217+
reservation = ''
218+
arguments = {
219+
'op': 'replace', 'path': 'reservation', 'value': reservation}
220+
self.patch(f'/analysis/description/{analysis.id}/', data=arguments)
221+
self.assertEqual(analysis._slurm_reservation(), [reservation])
222+
202223

203224
class TestAnalysisGraphHandler(TestHandlerBase):
204225
def test_get_analysis_graph_handler(self):

0 commit comments

Comments
 (0)