Skip to content

Commit

Permalink
rpmbuild: specify snippets to mock config via copr-rpmbuild config file
Browse files Browse the repository at this point in the history
This allows us to specify tpm fs size to rpmbuild in order to be able to
automatically generate its size for performance builders.

See fedora-copr#3268
  • Loading branch information
nikromen committed Sep 24, 2024
1 parent 2bdec45 commit e869d2a
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 3 deletions.
4 changes: 4 additions & 0 deletions rpmbuild/copr-rpmbuild.spec
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ BuildRequires: %{python}-requests
BuildRequires: %{python_pfx}-jinja2
BuildRequires: %{python_pfx}-specfile >= 0.21.0
BuildRequires: python3-backoff >= 1.9.0
BuildRequires: python3-pyyaml

BuildRequires: /usr/bin/argparse-manpage
BuildRequires: python-rpm-macros
Expand All @@ -57,6 +58,7 @@ Requires: %{python_pfx}-munch
Requires: %{python}-requests
Requires: %{python_pfx}-specfile >= 0.21.0
Requires: python3-backoff >= 1.9.0
Requires: python3-pyyaml

Requires: mock >= 5.0
Requires: git
Expand Down Expand Up @@ -213,6 +215,7 @@ install -m 644 mock.cfg.j2 %{buildroot}%{_sysconfdir}/copr-rpmbuild/mock.cfg.j2
install -m 644 rpkg.conf.j2 %{buildroot}%{_sysconfdir}/copr-rpmbuild/rpkg.conf.j2
install -m 644 mock-source-build.cfg.j2 %{buildroot}%{_sysconfdir}/copr-rpmbuild/
install -m 644 mock-custom-build.cfg.j2 %{buildroot}%{_sysconfdir}/copr-rpmbuild/
install -m 644 copr-rpmbuild.yml %{buildroot}%{_sysconfdir}/copr-rpmbuild/copr-rpmbuild.yml

cat <<EOF > %buildroot%mock_config_overrides/README
Contents of this directory is used by %_bindir/copr-update-builder script.
Expand Down Expand Up @@ -264,6 +267,7 @@ install -p -m 755 copr-update-builder %buildroot%_bindir
%config(noreplace) %{_sysconfdir}/copr-rpmbuild/rpkg.conf.j2
%config(noreplace) %{_sysconfdir}/copr-rpmbuild/mock-source-build.cfg.j2
%config(noreplace) %{_sysconfdir}/copr-rpmbuild/mock-custom-build.cfg.j2
%config(noreplace) %{_sysconfdir}/copr-rpmbuild/copr-rpmbuild.yml

%files -n copr-builder
%license LICENSE
Expand Down
6 changes: 6 additions & 0 deletions rpmbuild/copr-rpmbuild.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
# Configure special mock configuration snippets per given set of tags.
# job_tag_to_mock_snippets:
# on_demand_powerful: config_opts['plugin_conf']['tmpfs_opts']['max_fs_size'] = '280g'
# # specify more tags as 'and' condition with '+' sign
# x86_64+on_demand_powerful: some_other_tag_for_x86_64_and_on_demand_powerful_tags
11 changes: 10 additions & 1 deletion rpmbuild/copr_rpmbuild/builders/mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
import subprocess

from jinja2 import Environment, FileSystemLoader
from ..helpers import (
from copr_rpmbuild.config import Config
from copr_rpmbuild.helpers import (
locate_spec,
CONF_DIRS,
get_mock_uniqueext,
GentlyTimeoutedPopen,
macros_for_task,
mock_snippet_for_tags,
)

log = logging.getLogger("__main__")
Expand Down Expand Up @@ -42,6 +44,10 @@ def __init__(self, task, sourcedir, resultdir, config):
self.macros = macros_for_task(task, config)
self.uniqueext = get_mock_uniqueext()
self.allow_user_ssh = task.get("allow_user_ssh")
self.tags = task.get("tags", [])

self.copr_rpmbuild_config = Config()
self.copr_rpmbuild_config.load_config()

def run(self):
open(self.logfile, 'w').close() # truncate logfile
Expand Down Expand Up @@ -82,6 +88,9 @@ def render_config_template(self):
copr_build_id=self.build_id,
isolation=self.isolation,
macros=self.macros,
mock_snippet=mock_snippet_for_tags(
self.copr_rpmbuild_config.job_tag_to_mock_snippets, self.tags
),
)

def produce_srpm(self, spec, sources, resultdir):
Expand Down
37 changes: 37 additions & 0 deletions rpmbuild/copr_rpmbuild/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""
Configuration class for copr-rpmbuild
"""


import os
import yaml


CONFIG_PATH = "/etc/copr-rpmbuild/copr-rpmbuild"
ALLOWED_FILE_TYPES = ["yaml", "yml"]


class Config:
"""
Configuration class for copr-rpmbuild
"""
def __init__(self):
self.job_tag_to_mock_snippets = {}

def load_config(self):
"""
Load configuration from the config file
"""
config_path = None
for file_type in ALLOWED_FILE_TYPES:
if os.path.exists(f"{CONFIG_PATH}.{file_type}"):
config_path = f"{CONFIG_PATH}.{file_type}"
break

if config_path is None:
return

with open(config_path, "r", encoding="utf-8") as file:
config_data = yaml.safe_load(file) or {}

self.job_tag_to_mock_snippets = config_data.get('job_tag_to_mock_snippets', {})
17 changes: 17 additions & 0 deletions rpmbuild/copr_rpmbuild/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,3 +469,20 @@ def package_version(name):
return pkg_resources.require(name)[0].version
except pkg_resources.DistributionNotFound:
return "git"


def mock_snippet_for_tags(job_tag_to_mock_snippets, tags):
"""
Return mock snippets as string separated by newlines for a given
list of tags.
"""
if not tags or not job_tag_to_mock_snippets:
return ""

tags_set = set(tags)
mock_snippets = []
for tag, snippet in job_tag_to_mock_snippets.items():
if set(tag.split("+")).issubset(tags_set):
mock_snippets.append(snippet)

return "\n".join(mock_snippets)
15 changes: 13 additions & 2 deletions rpmbuild/copr_rpmbuild/providers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

from copr_common.request import SafeRequest
from copr_rpmbuild.helpers import CONF_DIRS
from copr_rpmbuild.helpers import run_cmd
from copr_rpmbuild.helpers import run_cmd, mock_snippet_for_tags
from copr_rpmbuild.config import Config


log = logging.getLogger("__main__")
Expand Down Expand Up @@ -51,6 +52,16 @@ def __init__(self, source_dict, config, macros=None, task=None):
if e.errno != errno.EEXIST:
raise

self.copr_rpmbuild_config = Config()
self.copr_rpmbuild_config.load_config()

# Mock snippets to render in the mock config
self.mock_snippet = ""
if self.task is not None:
self.mock_snippet = mock_snippet_for_tags(
self.copr_rpmbuild_config.job_tag_to_mock_snippets, self.task.get("tags")
)

# Change home directory to workdir and create .rpmmacros there
os.environ["HOME"] = self.workdir
self.create_rpmmacros()
Expand Down Expand Up @@ -130,7 +141,7 @@ def render_mock_config_template(self, template_name):
"""
jinja_env = Environment(loader=FileSystemLoader(CONF_DIRS))
template = jinja_env.get_template(template_name)
return template.render(macros=self.macros)
return template.render(macros=self.macros, mock_snippet=self.mock_snippet)

def produce_srpm(self):
"""
Expand Down
1 change: 1 addition & 0 deletions rpmbuild/copr_rpmbuild/providers/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def render_mock_config_template(self, *_args):
chroot=self.chroot,
repos=self.repos,
macros=self.macros,
mock_snippet=self.mock_snippet,
)

def produce_srpm(self):
Expand Down
3 changes: 3 additions & 0 deletions rpmbuild/mock-custom-build.cfg.j2
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ config_opts["root"] = "copr-custom-" + config_opts["root"]
# /bin/mock calls (when tmpfs_enable is on).
config_opts['plugin_conf']['tmpfs_opts']['keep_mounted'] = True

# Custom mock snippets configured in copr-crpmbuild config file - can be empty
{{ mock_snippet }}

{%- for key, value in macros.items() %}
config_opts['macros']['{{ key }}'] = '{{ value }}'
{%- endfor %}
Expand Down
3 changes: 3 additions & 0 deletions rpmbuild/mock.cfg.j2
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ config_opts.setdefault('plugin_conf', {})
config_opts['plugin_conf'].setdefault('tmpfs_opts', {})
config_opts['plugin_conf']['tmpfs_opts']['keep_mounted'] = True

# Custom mock snippets configured in copr-crpmbuild config file - can be empty
{{ mock_snippet }}

{% if buildroot_pkgs %}
config_opts['chroot_additional_packages'] = '{{ buildroot_pkgs| join(" ") }}'
{% endif %}
Expand Down
24 changes: 24 additions & 0 deletions rpmbuild/tests/test_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ def test_mock_config(self, call, f_mock_calls):
config_opts['plugin_conf'].setdefault('tmpfs_opts', {})
config_opts['plugin_conf']['tmpfs_opts']['keep_mounted'] = True
# Custom mock snippets configured in copr-crpmbuild config file - can be empty
config_opts['chroot_additional_packages'] = 'pkg1 pkg2 pkg3'
Expand All @@ -164,6 +167,27 @@ def test_mock_config(self, call, f_mock_calls):
""" # TODO: make the output nicer

@mock.patch("copr_rpmbuild.builders.mock.subprocess.call")
# pylint: disable-next=unused-argument, redefined-outer-name
def test_mock_config_hp_fs_size(self, call, f_mock_calls):
""" test that fs_size for performance builders is correctly set """
self.task["tags"] = ["blabla_tag", "on_demand_powerful"]
builder = MockBuilder(
self.task, self.sourcedir, self.resultdir, self.config
)
mock_snippet = "config_opts['plugin_conf']['tmpfs_opts']['max_fs_size'] = '280g'"
builder.copr_rpmbuild_config.job_tag_to_mock_snippets = {
"on_demand_powerful": mock_snippet
}
builder.run()

with open(self.child_config, "r", encoding="utf-8") as f:
config = f.readlines()

config = ''.join(config)
assert mock_snippet in config


@mock.patch("copr_rpmbuild.builders.mock.MockBuilder.prepare_configs")
@mock.patch("copr_rpmbuild.builders.mock.MockBuilder.archive_configs")
def test_mock_options(self, archive_configs, prep_configs, f_mock_calls):
Expand Down

0 comments on commit e869d2a

Please sign in to comment.