Skip to content

Commit 8db3957

Browse files
author
Staging script
committed
Staging PR 3038
1 parent fe827ff commit 8db3957

File tree

3 files changed

+113
-9
lines changed

3 files changed

+113
-9
lines changed

kernelci/config/build.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ class BuildConfig(YAMLConfigObject):
370370

371371
def __init__( # pylint: disable=too-many-arguments
372372
self, name, tree, branch, variants, *, reference=None,
373-
architectures=None, frequency=None
373+
architectures=None, frequency=None, priority=None
374374
):
375375
"""A build configuration defines the actual kernels to be built.
376376
@@ -388,6 +388,8 @@ def __init__( # pylint: disable=too-many-arguments
388388
389389
*frequency* is an optional string that limits how often a checkout node
390390
can be created. Format: [Nd][Nh][Nm]
391+
392+
*priority* is an optional string (high/medium/low) for tree priority.
391393
"""
392394
self._name = name
393395
self._tree = tree
@@ -396,6 +398,7 @@ def __init__( # pylint: disable=too-many-arguments
396398
self._reference = reference
397399
self._architectures = architectures
398400
self._frequency = frequency
401+
self._priority = priority
399402

400403
@classmethod
401404
# pylint: disable=arguments-differ,too-many-arguments,too-many-positional-arguments
@@ -419,6 +422,7 @@ def load_from_yaml(cls, config, name, trees, fragments, b_envs, defaults):
419422

420423
kw['architectures'] = config.get('architectures')
421424
kw['frequency'] = config.get('frequency')
425+
kw['priority'] = config.get('priority')
422426
return cls(**kw)
423427

424428
@property
@@ -460,6 +464,11 @@ def frequency(self):
460464
"""Return the checkout frequency."""
461465
return self._frequency
462466

467+
@property
468+
def priority(self):
469+
"""Return the tree priority."""
470+
return self._priority
471+
463472
@classmethod
464473
def to_yaml(cls, dumper, data):
465474
result = {

kernelci/runtime/lava.py

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -325,27 +325,61 @@ class LAVA(Runtime):
325325
API_VERSION = 'v0.2'
326326
RestAPIServer = namedtuple('RestAPIServer', ['url', 'session'])
327327

328+
# LAVA supports 'high'/'medium'/'low' (100/50/0), but we define our own
329+
# values to allow scaling across labs with different priority ranges.
330+
PRIORITY_HIGHEST = 80
331+
PRIORITY_HIGH = 60
332+
PRIORITY_MEDIUM = 40
333+
PRIORITY_LOW = 20
334+
335+
SERVICE_PIPELINE = 'service:pipeline'
336+
328337
def __init__(self, configs, kcictx=None, **kwargs):
329338
super().__init__(configs, **kwargs)
330339
self._context = kcictx
331340
self._server = self._connect()
332341

333342
def _get_priority(self, job):
334-
# Scale the job priority (from 0-100) within the available levels
335-
# for the lab, or use the lowest by default.
336-
priority = job.config.priority if job.config.priority else 20
343+
node = job.node
344+
submitter = node.get('submitter')
345+
346+
priority_map = {
347+
'high': self.PRIORITY_HIGH,
348+
'medium': self.PRIORITY_MEDIUM,
349+
'low': self.PRIORITY_LOW,
350+
}
351+
352+
if submitter and submitter != self.SERVICE_PIPELINE:
353+
# Human submission - check for user-specified priority
354+
user_priority = node.get('data', {}).get('priority')
355+
if user_priority:
356+
if isinstance(user_priority, str):
357+
priority = priority_map.get(user_priority.lower(), self.PRIORITY_HIGHEST)
358+
elif isinstance(user_priority, (int, float)):
359+
priority = max(0, min(100, user_priority))
360+
else:
361+
priority = self.PRIORITY_HIGHEST
362+
else:
363+
priority = self.PRIORITY_HIGHEST
364+
else:
365+
# Pipeline submission - use tree priority
366+
tree_priority = node.get('data', {}).get('tree_priority')
367+
368+
if tree_priority and isinstance(tree_priority, str):
369+
priority = priority_map.get(tree_priority.lower(), self.PRIORITY_LOW)
370+
elif tree_priority and isinstance(tree_priority, (int, float)):
371+
priority = max(0, min(100, tree_priority))
372+
else:
373+
job_priority = job.config.priority
374+
priority = job_priority if job_priority is not None else self.PRIORITY_LOW
375+
337376
if self.config.priority:
338377
priority = int(priority * self.config.priority / 100)
339378
elif (self.config.priority_max is not None and
340379
self.config.priority_min is not None):
341380
prio_range = self.config.priority_max - self.config.priority_min
342381
prio_min = self.config.priority_min
343382
priority = int((priority * prio_range / 100) + prio_min)
344-
# Increase the priority for jobs submitted by humans
345-
node = job.node
346-
submitter = node.get('submitter')
347-
if submitter and submitter != 'service:pipeline':
348-
priority = min(priority + 1, self.config.priority_max)
349383
return priority
350384

351385
def get_params(self, job, api_config=None):

tests/test_runtime.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,67 @@ def test_runtimes_init():
6868
kernelci.runtime.get_runtime(runtime_config)
6969

7070

71+
def test_lava_priority_hierarchy():
72+
"""Test LAVA priority: human=highest, tree=high/medium/low"""
73+
config = kernelci.config.load('tests/configs/lava-runtimes.yaml')
74+
runtimes = config['runtimes']
75+
runtime_config = runtimes['lab-min-12-max-40-new-runtime']
76+
lab = kernelci.runtime.get_runtime(runtime_config)
77+
78+
job_config_no_priority = type('JobConfig', (), {'priority': None})()
79+
80+
job_human_high_tree = type('Job', (), {
81+
'node': {'data': {'tree_priority': 'high'}, 'submitter': '[email protected]'},
82+
'config': job_config_no_priority
83+
})()
84+
expected_priority = int(12 + (40 - 12) * 80 / 100)
85+
assert lab._get_priority(job_human_high_tree) == expected_priority
86+
87+
job_pipeline_high_tree = type('Job', (), {
88+
'node': {'data': {'tree_priority': 'high'}, 'submitter': 'service:pipeline'},
89+
'config': job_config_no_priority
90+
})()
91+
expected_priority = int(12 + (40 - 12) * 60 / 100)
92+
assert lab._get_priority(job_pipeline_high_tree) == expected_priority
93+
94+
job_medium_tree = type('Job', (), {
95+
'node': {'data': {'tree_priority': 'medium'}, 'submitter': 'service:pipeline'},
96+
'config': job_config_no_priority
97+
})()
98+
expected_priority = int(12 + (40 - 12) * 40 / 100)
99+
assert lab._get_priority(job_medium_tree) == expected_priority
100+
101+
job_low_tree = type('Job', (), {
102+
'node': {'data': {'tree_priority': 'low'}, 'submitter': 'service:pipeline'},
103+
'config': job_config_no_priority
104+
})()
105+
expected_priority = int(12 + (40 - 12) * 20 / 100)
106+
assert lab._get_priority(job_low_tree) == expected_priority
107+
108+
job_default = type('Job', (), {
109+
'node': {'data': {}, 'submitter': 'service:pipeline'},
110+
'config': job_config_no_priority
111+
})()
112+
expected_priority = int(12 + (40 - 12) * 20 / 100)
113+
assert lab._get_priority(job_default) == expected_priority
114+
115+
# Human submission with user-specified string priority
116+
job_human_set_high = type('Job', (), {
117+
'node': {'data': {'priority': 'high'}, 'submitter': '[email protected]'},
118+
'config': job_config_no_priority
119+
})()
120+
expected_priority = int(12 + (40 - 12) * 60 / 100)
121+
assert lab._get_priority(job_human_set_high) == expected_priority
122+
123+
# Human submission with user-specified numeric priority
124+
job_human_set_numeric = type('Job', (), {
125+
'node': {'data': {'priority': 50}, 'submitter': '[email protected]'},
126+
'config': job_config_no_priority
127+
})()
128+
expected_priority = int(12 + (40 - 12) * 50 / 100)
129+
assert lab._get_priority(job_human_set_numeric) == expected_priority
130+
131+
71132
def test_lava_priority_scale():
72133
"""Test the logic for determining the priority of LAVA jobs"""
73134
config = kernelci.config.load('tests/configs/lava-runtimes.yaml')

0 commit comments

Comments
 (0)