Skip to content
Merged
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
90 changes: 90 additions & 0 deletions config/runtime/base/pull_labs.jinja2
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{# SPDX-License-Identifier: LGPL-2.1-or-later -#}
{# PULL_LABS job definition template - generates JSON format #}
{# This template creates a job definition according to PULL_LABS protocol Section 3 #}
{
"artifacts": {
{%- if node.artifacts.kernel %}
"kernel": "{{ node.artifacts.kernel }}"
{%- endif %}
{%- if node.artifacts.modules %},
"modules": "{{ node.artifacts.modules }}"
{%- endif %}
{%- if node.artifacts.kselftest %},
"kselftest": "{{ node.artifacts.kselftest }}"
{%- endif %}
{%- if node.artifacts.rootfs %},
"rootfs_type": "{{ node.artifacts.rootfs }}"
{%- endif %}
{%- if node.artifacts.initrd %},
"initrd": "{{ node.artifacts.initrd }}"
{%- endif %}
{%- if node.artifacts.dtb %},
"dtb": "{{ node.artifacts.dtb }}"
{%- endif %}
},
"tests": [
{%- if test_definitions %}
{%- for test in test_definitions %}
{
"id": "{{ test.id }}",
"type": "{{ test.type }}",
"depends": {{ test.depends | tojson }},
"timeout_s": {{ test.timeout_s | default(600) }}
{%- if test.subset %},
"subset": {{ test.subset | tojson }}
{%- endif %}
{%- if test.parameters %},
"parameters": "{{ test.parameters }}"
{%- endif %}
{%- if test.pre_commands %},
"pre-commands": {{ test.pre_commands | tojson }}
{%- else %},
"pre-commands": []
{%- endif %}
{%- if test.post_commands %},
"post-commands": {{ test.post_commands | tojson }}
{%- else %},
"post-commands": []
{%- endif %}
}{{ "," if not loop.last else "" }}
{%- endfor %}
{%- else %}
{
"id": "boot-test-{{ node.id[:8] }}",
"type": "boot",
"depends": [],
"timeout_s": 600,
"pre-commands": [],
"post-commands": []
}
{%- endif %}
],
"environment": {
"platform": "{{ platform_config.name }}",
"arch": "{{ platform_config.arch }}",
"console": {
"method": "{{ platform_config.console_method | default('serial') }}",
"baud": {{ platform_config.console_baud | default(115200) }}
}
{%- if platform_config.params and platform_config.params.requirements %}
,"requirements": {{ platform_config.params.requirements | tojson }}
{%- endif %}
},
"callback": {
"url": "{{ instance_callback }}/node/{{ node.id }}",
"token_name": "{{ callback_token_name | default('kernelci-pipeline-callback') }}"
}
{%- if node.artifacts.metadata %}
,"integrity": {
"sha256": {
{%- if checksums %}
{%- for artifact_name, checksum in checksums.items() %}
"{{ artifact_name }}": "{{ checksum }}"{{ "," if not loop.last else "" }}
{%- endfor %}
{%- else %}
"_comment": "Checksums would be populated from metadata.json if available"
{%- endif %}
}
}
{%- endif %}
}
134 changes: 89 additions & 45 deletions kernelci/config/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#
# Copyright (C) 2019, 2021-2023 Collabora Limited
# Author: Guillaume Tucker <guillaume.tucker@collabora.com>
#
# Copyright (C) 2025 Collabora Limited
# Author: Denys Fedoryshchenko <denys.f@collabora.com>

"""KernelCI Runtime environment configuration"""

Expand All @@ -11,7 +14,7 @@
class Runtime(YAMLConfigObject):
"""Runtime environment configuration"""

yaml_tag = '!Runtime'
yaml_tag = "!Runtime"

def __init__(self, name, lab_type, filters=None, rules=None):
"""A runtime environment configuration object
Expand Down Expand Up @@ -44,25 +47,24 @@ def rules(self):
@classmethod
def _get_yaml_attributes(cls):
attrs = super()._get_yaml_attributes()
attrs.update({'lab_type', 'rules'})
attrs.update({"lab_type", "rules"})
return attrs

@classmethod
def _to_yaml_dict(cls, data):
yaml_dict = {
key: getattr(data, key)
for key in cls._get_yaml_attributes()
}
yaml_dict.update({
# pylint: disable=protected-access
'filters': [{fil.name: fil} for fil in data._filters],
})
yaml_dict = {key: getattr(data, key) for key in cls._get_yaml_attributes()}
yaml_dict.update(
{
# pylint: disable=protected-access
"filters": [{fil.name: fil} for fil in data._filters],
}
)
return yaml_dict

@classmethod
def to_yaml(cls, dumper, data):
return dumper.represent_mapping(
'tag:yaml.org,2002:map', cls._to_yaml_dict(data)
"tag:yaml.org,2002:map", cls._to_yaml_dict(data)
)

def match(self, data):
Expand All @@ -73,19 +75,26 @@ def match(self, data):
class RuntimeLAVA(Runtime):
"""Configuration for LAVA runtime environments"""

yaml_tag = '!RuntimeLAVA'
yaml_tag = "!RuntimeLAVA"

PRIORITIES = {
'low': 0,
'medium': 50,
'high': 100,
"low": 0,
"medium": 50,
"high": 100,
}

# This should be solved by dropping the "priority" attribute
# pylint: disable=too-many-arguments
def __init__(self, url=None, priority=None, priority_min=None,
priority_max=None, queue_timeout=None, notify=None,
**kwargs):
def __init__(
self,
url=None,
priority=None,
priority_min=None,
priority_max=None,
queue_timeout=None,
notify=None,
**kwargs,
):
super().__init__(**kwargs)

def _set_priority_value(value, default):
Expand Down Expand Up @@ -135,24 +144,25 @@ def notify(self):
@classmethod
def _get_yaml_attributes(cls):
attrs = super()._get_yaml_attributes()
attrs.update({
'priority',
'priority_min',
'priority_max',
'queue_timeout',
'url',
'notify',
})
attrs.update(
{
"priority",
"priority_min",
"priority_max",
"queue_timeout",
"url",
"notify",
}
)
return attrs


class RuntimeDocker(Runtime):
"""Configuration for Docker runtime environments"""

yaml_tag = '!RuntimeDocker'
yaml_tag = "!RuntimeDocker"

def __init__(self, env_file=None, volumes=None, user=None, timeout=None,
**kwargs):
def __init__(self, env_file=None, volumes=None, user=None, timeout=None, **kwargs):
super().__init__(**kwargs)
self._env_file = env_file
self._volumes = volumes or []
Expand Down Expand Up @@ -182,14 +192,14 @@ def timeout(self):
@classmethod
def _get_yaml_attributes(cls):
attrs = super()._get_yaml_attributes()
attrs.update({'env_file', 'volumes', 'user', 'timeout'})
attrs.update({"env_file", "volumes", "user", "timeout"})
return attrs


class RuntimeKubernetes(Runtime):
"""Configuration for Kubernetes runtime environments"""

yaml_tag = '!RuntimeKubernetes'
yaml_tag = "!RuntimeKubernetes"

def __init__(self, context=None, **kwargs):
super().__init__(**kwargs)
Expand All @@ -203,43 +213,77 @@ def context(self):
@classmethod
def _get_yaml_attributes(cls):
attrs = super()._get_yaml_attributes()
attrs.update({'context'})
attrs.update({"context"})
return attrs


class RuntimePullLabs(Runtime):
"""Configuration for PULL_LABS runtime environments"""

yaml_tag = "!RuntimePullLabs"

def __init__(self, poll_interval=None, timeout=None, storage_name=None, **kwargs):
super().__init__(**kwargs)
self._poll_interval = poll_interval or 30
self._timeout = timeout or 3600
self._storage_name = storage_name

@property
def poll_interval(self):
"""Polling interval for events in seconds"""
return self._poll_interval

@property
def timeout(self):
"""Job timeout in seconds"""
return self._timeout

@property
def storage_name(self):
"""Storage configuration name for job definitions"""
return self._storage_name

@classmethod
def _get_yaml_attributes(cls):
attrs = super()._get_yaml_attributes()
attrs.update({"poll_interval", "timeout", "storage_name"})
return attrs


class RuntimeFactory: # pylint: disable=too-few-public-methods
"""Factory to create lab objects from YAML data."""

_lab_types = {
'docker': RuntimeDocker,
'kubernetes': RuntimeKubernetes,
'lava': RuntimeLAVA,
'legacy.lava_xmlrpc': RuntimeLAVA,
'legacy.lava_rest': RuntimeLAVA,
'shell': Runtime,
"docker": RuntimeDocker,
"kubernetes": RuntimeKubernetes,
"lava": RuntimeLAVA,
"legacy.lava_xmlrpc": RuntimeLAVA,
"legacy.lava_rest": RuntimeLAVA,
"pull_labs": RuntimePullLabs,
"shell": Runtime,
}

@classmethod
def from_yaml(cls, name, config, default_filters):
"""Load the configuration from YAML data"""
lab_type = config.get('lab_type')
lab_type = config.get("lab_type")
kwargs = {
'name': name,
'lab_type': lab_type,
'filters': FilterFactory.from_data(config, default_filters),
"name": name,
"lab_type": lab_type,
"filters": FilterFactory.from_data(config, default_filters),
}
lab_cls = cls._lab_types[lab_type] if lab_type else Runtime
return lab_cls.load_from_yaml(config, **kwargs)


def from_yaml(data, filters):
"""Load the runtime environment from YAML based on its type"""
runtimes_filters = filters.get('runtimes')
runtimes_filters = filters.get("runtimes")
runtimes = {
name: RuntimeFactory.from_yaml(name, runtime, runtimes_filters)
for name, runtime in data.get('runtimes', {}).items()
for name, runtime in data.get("runtimes", {}).items()
}

return {
'runtimes': runtimes,
"runtimes": runtimes,
}
Loading
Loading