Make init handler idempotent.

This fixes the issue when module build is cancelled in init state.
This commit is contained in:
Jan Kaluza
2019-02-14 08:48:01 +01:00
parent 486d644d68
commit 7052ea0a11
5 changed files with 47 additions and 1 deletions

View File

@@ -43,6 +43,7 @@ RUN yum -y install \
python-mock \
python-tox \
rpm-build \
python2-pyyaml \
&& yum clean all
# We currently require newer versions of these Python packages for the tests.
# more-itertools is required by pytest, but versions 6.0.0 and up aren't Python 2 compatible

View File

@@ -33,6 +33,7 @@ RUN dnf -y install \
python3-mock \
python3-tox \
rpm-build \
python3-PyYAML \
&& dnf clean all
VOLUME /src
WORKDIR /src

View File

@@ -159,6 +159,11 @@ def format_mmd(mmd, scmurl):
xmd['mbs']['rpms'] = {}
# Add missing data in RPM components
for pkgname, pkg in mmd.get_rpm_components().items():
# In case of resubmit of existing module which have been
# cancelled/failed during the init state, the package
# was maybe already handled by MBS, so skip it in this case.
if pkgname in xmd['mbs']['rpms']:
continue
if pkg.get_repository() and not conf.rpms_allow_repository:
raise Forbidden(
"Custom component repositories aren't allowed. "
@@ -193,7 +198,11 @@ def format_mmd(mmd, scmurl):
# by real SCM hash and store the result to our private xmd place in modulemd.
pool = ThreadPool(20)
try:
pkg_dicts = pool.map(_scm_get_latest, mmd.get_rpm_components().values())
# Filter out the packages which we have already resolved in possible
# previous runs of this method (can be caused by module build resubmition).
pkgs_to_resolve = [pkg for pkg in mmd.get_rpm_components().values()
if pkg.get_name() not in xmd['mbs']['rpms']]
pkg_dicts = pool.map(_scm_get_latest, pkgs_to_resolve)
finally:
pool.close()
@@ -355,6 +364,22 @@ def record_component_builds(mmd, module, initial_batch=1,
component_ref = mmd.get_xmd()['mbs']['rpms'][component.get_name()]['ref']
full_url = component.get_repository() + "?#" + component_ref
# Skip the ComponentBuild if it already exists in database. This can happen
# in case of module build resubmition.
existing_build = models.ComponentBuild.from_component_name(
db.session, component.get_name(), module.id)
if existing_build:
# Check that the existing build has the same most important attributes.
# This should never be a problem, but it's good to be defensive here so
# we do not mess things during resubmition.
if (existing_build.batch != batch or existing_build.scmurl != full_url or
existing_build.ref != component_ref):
raise ValidationError(
"Module build %s already exists in database, but its attributes "
" are different from resubmitted one." % component.get_name())
continue
build = models.ComponentBuild(
module_id=module.id,
package=component.get_name(),

View File

@@ -4,3 +4,4 @@ mock
pytest
flake8
tox
pyyaml

View File

@@ -20,6 +20,7 @@
#
import os
import yaml
from mock import patch, PropertyMock
from gi.repository import GLib
@@ -93,6 +94,23 @@ class TestModuleInit:
assert type(xmd_mbs) is GLib.Variant
assert xmd_mbs["buildrequires"]["platform"]["filtered_rpms"] == [
'foo-0:2.4.48-3.el8+1308+551bfa71', 'bar-0:2.5.48-3.el8+1308+551bfa71']
return build
def test_init_called_twice(self):
build = self.test_init_basic()
old_component_builds = len(build.component_builds)
old_mmd = yaml.load(build.modulemd)
build.state = 4
db.session.commit()
build = self.test_init_basic()
db.session.refresh(build)
assert build.state == 1
assert old_component_builds == len(build.component_builds)
new_mmd = yaml.load(build.modulemd)
assert old_mmd == new_mmd
@patch('module_build_service.scm.SCM')
def test_init_scm_not_available(self, mocked_scm):