mirror of
https://pagure.io/fm-orchestrator.git
synced 2026-04-05 03:38:12 +08:00
Move get_session and retry to separate modules to reduce circular imports
This commit is contained in:
@@ -22,6 +22,7 @@ import koji
|
||||
import pungi.arch
|
||||
|
||||
from module_build_service import conf, log, build_logs, Modulemd
|
||||
from module_build_service.common.koji import get_session, koji_retrying_multicall_map
|
||||
from module_build_service.db_session import db_session
|
||||
from module_build_service.scm import SCM
|
||||
from module_build_service.utils import to_text_type, load_mmd, mmd_to_str
|
||||
@@ -29,12 +30,6 @@ from module_build_service.utils import to_text_type, load_mmd, mmd_to_str
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
|
||||
def get_session(config, login=True):
|
||||
from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder
|
||||
|
||||
return KojiModuleBuilder.get_session(config, login=login)
|
||||
|
||||
|
||||
def strip_suffixes(s, suffixes):
|
||||
"""
|
||||
Helper function to remove suffixes from given string.
|
||||
@@ -54,17 +49,6 @@ def strip_suffixes(s, suffixes):
|
||||
return s
|
||||
|
||||
|
||||
def koji_retrying_multicall_map(*args, **kwargs):
|
||||
"""
|
||||
Wrapper around KojiModuleBuilder.koji_retrying_multicall_map, because
|
||||
we cannot import that method normally because of import loop.
|
||||
"""
|
||||
from module_build_service.builder.KojiModuleBuilder import (
|
||||
koji_retrying_multicall_map as multicall,)
|
||||
|
||||
return multicall(*args, **kwargs)
|
||||
|
||||
|
||||
class KojiContentGenerator(object):
|
||||
""" Class for handling content generator imports of module builds into Koji """
|
||||
|
||||
|
||||
@@ -13,8 +13,7 @@ import random
|
||||
import string
|
||||
import kobo.rpmlib
|
||||
import threading
|
||||
import six.moves.xmlrpc_client as xmlrpclib
|
||||
import munch
|
||||
|
||||
import locale
|
||||
from itertools import chain
|
||||
from OpenSSL.SSL import SysCallError
|
||||
@@ -24,114 +23,19 @@ from module_build_service import log, conf, models
|
||||
import module_build_service.scm
|
||||
import module_build_service.utils
|
||||
from module_build_service.builder.utils import execute_cmd
|
||||
from module_build_service.common.retry import retry
|
||||
from module_build_service.db_session import db_session
|
||||
from module_build_service.errors import ProgrammingError
|
||||
|
||||
from module_build_service.builder import GenericBuilder
|
||||
from module_build_service.builder.KojiContentGenerator import KojiContentGenerator
|
||||
from module_build_service.common.koji import (
|
||||
get_session, koji_multicall_map, koji_retrying_multicall_map,
|
||||
)
|
||||
from module_build_service.scheduler import events
|
||||
from module_build_service.utils import get_reusable_components, get_reusable_module, set_locale
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
|
||||
def koji_multicall_map(koji_session, koji_session_fnc, list_of_args=None, list_of_kwargs=None):
|
||||
"""
|
||||
Calls the `koji_session_fnc` using Koji multicall feature N times based on the list of
|
||||
arguments passed in `list_of_args` and `list_of_kwargs`.
|
||||
Returns list of responses sorted the same way as input args/kwargs. In case of error,
|
||||
the error message is logged and None is returned.
|
||||
|
||||
For example to get the package ids of "httpd" and "apr" packages:
|
||||
ids = koji_multicall_map(session, session.getPackageID, ["httpd", "apr"])
|
||||
# ids is now [280, 632]
|
||||
|
||||
:param KojiSessions koji_session: KojiSession to use for multicall.
|
||||
:param object koji_session_fnc: Python object representing the KojiSession method to call.
|
||||
:param list list_of_args: List of args which are passed to each call of koji_session_fnc.
|
||||
:param list list_of_kwargs: List of kwargs which are passed to each call of koji_session_fnc.
|
||||
"""
|
||||
if list_of_args is None and list_of_kwargs is None:
|
||||
raise ProgrammingError("One of list_of_args or list_of_kwargs must be set.")
|
||||
|
||||
if (
|
||||
type(list_of_args) not in [type(None), list]
|
||||
or type(list_of_kwargs) not in [type(None), list]
|
||||
):
|
||||
raise ProgrammingError("list_of_args and list_of_kwargs must be list or None.")
|
||||
|
||||
if list_of_kwargs is None:
|
||||
list_of_kwargs = [{}] * len(list_of_args)
|
||||
if list_of_args is None:
|
||||
list_of_args = [[]] * len(list_of_kwargs)
|
||||
|
||||
if len(list_of_args) != len(list_of_kwargs):
|
||||
raise ProgrammingError("Length of list_of_args and list_of_kwargs must be the same.")
|
||||
|
||||
koji_session.multicall = True
|
||||
for args, kwargs in zip(list_of_args, list_of_kwargs):
|
||||
if type(args) != list:
|
||||
args = [args]
|
||||
if type(kwargs) != dict:
|
||||
raise ProgrammingError("Every item in list_of_kwargs must be a dict")
|
||||
koji_session_fnc(*args, **kwargs)
|
||||
|
||||
try:
|
||||
responses = koji_session.multiCall(strict=True)
|
||||
except Exception:
|
||||
log.exception(
|
||||
"Exception raised for multicall of method %r with args %r, %r:",
|
||||
koji_session_fnc, args, kwargs,
|
||||
)
|
||||
return None
|
||||
|
||||
if not responses:
|
||||
log.error("Koji did not return response for multicall of %r", koji_session_fnc)
|
||||
return None
|
||||
if type(responses) != list:
|
||||
log.error(
|
||||
"Fault element was returned for multicall of method %r: %r", koji_session_fnc, responses
|
||||
)
|
||||
return None
|
||||
|
||||
results = []
|
||||
|
||||
# For the response specification, see
|
||||
# https://web.archive.org/web/20060624230303/http://www.xmlrpc.com/discuss/msgReader$1208?mode=topic
|
||||
# Relevant part of this:
|
||||
# Multicall returns an array of responses. There will be one response for each call in
|
||||
# the original array. The result will either be a one-item array containing the result value,
|
||||
# or a struct of the form found inside the standard <fault> element.
|
||||
for response, args, kwargs in zip(responses, list_of_args, list_of_kwargs):
|
||||
if type(response) == list:
|
||||
if not response:
|
||||
log.error(
|
||||
"Empty list returned for multicall of method %r with args %r, %r",
|
||||
koji_session_fnc, args, kwargs
|
||||
)
|
||||
return None
|
||||
results.append(response[0])
|
||||
else:
|
||||
log.error(
|
||||
"Unexpected data returned for multicall of method %r with args %r, %r: %r",
|
||||
koji_session_fnc, args, kwargs, response
|
||||
)
|
||||
return None
|
||||
|
||||
return results
|
||||
|
||||
|
||||
@module_build_service.utils.retry(wait_on=(xmlrpclib.ProtocolError, koji.GenericError))
|
||||
def koji_retrying_multicall_map(*args, **kwargs):
|
||||
"""
|
||||
Retrying version of koji_multicall_map. This tries to retry the Koji call
|
||||
in case of koji.GenericError or xmlrpclib.ProtocolError.
|
||||
|
||||
Please refer to koji_multicall_map for further specification of arguments.
|
||||
"""
|
||||
return koji_multicall_map(*args, **kwargs)
|
||||
|
||||
|
||||
class KojiModuleBuilder(GenericBuilder):
|
||||
""" Koji specific builder class """
|
||||
|
||||
@@ -159,7 +63,7 @@ class KojiModuleBuilder(GenericBuilder):
|
||||
log.debug("Using koji profile %r" % config.koji_profile)
|
||||
log.debug("Using koji_config: %s" % config.koji_config)
|
||||
|
||||
self.koji_session = self.get_session(config)
|
||||
self.koji_session = get_session(config)
|
||||
self.arches = sorted(arch.name for arch in self.module.arches)
|
||||
|
||||
# Allow KojiModuleBuilder to be initialized if no arches are set but the module is in
|
||||
@@ -183,7 +87,7 @@ class KojiModuleBuilder(GenericBuilder):
|
||||
def getPerms(self):
|
||||
return dict([(p["name"], p["id"]) for p in self.koji_session.getAllPerms()])
|
||||
|
||||
@module_build_service.utils.retry(wait_on=(IOError, koji.GenericError))
|
||||
@retry(wait_on=(IOError, koji.GenericError))
|
||||
def buildroot_ready(self, artifacts=None):
|
||||
"""
|
||||
:param artifacts=None - list of nvrs
|
||||
@@ -234,7 +138,7 @@ class KojiModuleBuilder(GenericBuilder):
|
||||
reusable_module = get_reusable_module(module_build)
|
||||
if not reusable_module:
|
||||
return filtered_rpms
|
||||
koji_session = KojiModuleBuilder.get_session(conf, login=False)
|
||||
koji_session = get_session(conf, login=False)
|
||||
# Get all the RPMs and builds of the reusable module in Koji
|
||||
rpms, builds = koji_session.listTaggedRPMS(reusable_module.koji_tag, latest=True)
|
||||
# Convert the list to a dict where each key is the build_id
|
||||
@@ -468,59 +372,6 @@ class KojiModuleBuilder(GenericBuilder):
|
||||
log.debug("Wrote srpm into %s" % srpm_paths[0])
|
||||
return srpm_paths[0]
|
||||
|
||||
@staticmethod
|
||||
@module_build_service.utils.retry(wait_on=(xmlrpclib.ProtocolError, koji.GenericError))
|
||||
def get_session(config, login=True):
|
||||
"""Create and return a koji.ClientSession object
|
||||
|
||||
:param config: the config object returned from :meth:`init_config`.
|
||||
:type config: :class:`Config`
|
||||
:param bool login: whether to log into the session. To login if True
|
||||
is passed, otherwise not to log into session.
|
||||
:return: the Koji session object.
|
||||
:rtype: :class:`koji.ClientSession`
|
||||
"""
|
||||
koji_config = munch.Munch(
|
||||
koji.read_config(profile_name=config.koji_profile, user_config=config.koji_config))
|
||||
# Timeout after 10 minutes. The default is 12 hours.
|
||||
koji_config["timeout"] = 60 * 10
|
||||
|
||||
address = koji_config.server
|
||||
log.info("Connecting to koji %r.", address)
|
||||
koji_session = koji.ClientSession(address, opts=koji_config)
|
||||
|
||||
if not login:
|
||||
return koji_session
|
||||
|
||||
authtype = koji_config.authtype
|
||||
log.info("Authenticate session with %r.", authtype)
|
||||
if authtype == "kerberos":
|
||||
try:
|
||||
import krbV
|
||||
# We want to create a context per thread to avoid Kerberos cache corruption
|
||||
ctx = krbV.Context()
|
||||
except ImportError:
|
||||
# If no krbV, we can assume GSSAPI auth is available
|
||||
ctx = None
|
||||
keytab = getattr(config, "krb_keytab", None)
|
||||
principal = getattr(config, "krb_principal", None)
|
||||
if not keytab and principal:
|
||||
raise ValueError(
|
||||
"The Kerberos keytab and principal aren't set for Koji authentication")
|
||||
log.debug(" keytab: %r, principal: %r" % (keytab, principal))
|
||||
# We want to use the thread keyring for the ccache to ensure we have one cache per
|
||||
# thread to avoid Kerberos cache corruption
|
||||
ccache = "KEYRING:thread:mbs"
|
||||
koji_session.krb_login(principal=principal, keytab=keytab, ctx=ctx, ccache=ccache)
|
||||
elif authtype == "ssl":
|
||||
koji_session.ssl_login(
|
||||
os.path.expanduser(koji_config.cert), None, os.path.expanduser(koji_config.serverca)
|
||||
)
|
||||
else:
|
||||
raise ValueError("Unrecognized koji authtype %r" % authtype)
|
||||
|
||||
return koji_session
|
||||
|
||||
def buildroot_connect(self, groups):
|
||||
log.info("%r connecting buildroot." % self)
|
||||
|
||||
@@ -552,7 +403,7 @@ class KojiModuleBuilder(GenericBuilder):
|
||||
if "blocked_packages" in mbs_opts:
|
||||
self._koji_block_packages(mbs_opts["blocked_packages"])
|
||||
|
||||
@module_build_service.utils.retry(wait_on=SysCallError, interval=5)
|
||||
@retry(wait_on=SysCallError, interval=5)
|
||||
def add_groups():
|
||||
return self._koji_add_groups_to_tag(dest_tag=self.module_build_tag, groups=groups)
|
||||
|
||||
@@ -683,7 +534,7 @@ class KojiModuleBuilder(GenericBuilder):
|
||||
|
||||
timeout = 60 * 60 # 60 minutes
|
||||
|
||||
@module_build_service.utils.retry(timeout=timeout, wait_on=koji.GenericError)
|
||||
@retry(timeout=timeout, wait_on=koji.GenericError)
|
||||
def get_result():
|
||||
log.debug("Waiting for task_id=%s to finish" % task_id)
|
||||
task = self.koji_session.getTaskResult(task_id)
|
||||
@@ -1169,7 +1020,7 @@ class KojiModuleBuilder(GenericBuilder):
|
||||
"""
|
||||
# If the component has not been built before, then None is returned. Instead, let's
|
||||
# return 0.0 so the type is consistent
|
||||
koji_session = KojiModuleBuilder.get_session(conf, login=False)
|
||||
koji_session = get_session(conf, login=False)
|
||||
return koji_session.getAverageBuildDuration(component) or 0.0
|
||||
|
||||
@classmethod
|
||||
@@ -1184,8 +1035,7 @@ class KojiModuleBuilder(GenericBuilder):
|
||||
:rtype: dict
|
||||
:return: {component_name: weight_as_float, ...}
|
||||
"""
|
||||
|
||||
koji_session = KojiModuleBuilder.get_session(conf)
|
||||
koji_session = get_session(conf)
|
||||
|
||||
# Get our own userID, so we can limit the builds to only modular builds
|
||||
user_info = koji_session.getLoggedInUser()
|
||||
@@ -1280,7 +1130,7 @@ class KojiModuleBuilder(GenericBuilder):
|
||||
mmd.get_version(),
|
||||
mmd.get_context()
|
||||
)
|
||||
koji_session = KojiModuleBuilder.get_session(conf, login=False)
|
||||
koji_session = get_session(conf, login=False)
|
||||
rpms = koji_session.listTaggedRPMS(build.koji_tag, latest=True)[0]
|
||||
nvrs = set(kobo.rpmlib.make_nvr(rpm, force_epoch=True) for rpm in rpms)
|
||||
return list(nvrs)
|
||||
@@ -1307,7 +1157,7 @@ class KojiModuleBuilder(GenericBuilder):
|
||||
:return: koji tag
|
||||
"""
|
||||
|
||||
session = KojiModuleBuilder.get_session(conf, login=False)
|
||||
session = get_session(conf, login=False)
|
||||
rpm_md = session.getRPM(rpm)
|
||||
if not rpm_md:
|
||||
return None
|
||||
@@ -1333,7 +1183,7 @@ class KojiModuleBuilder(GenericBuilder):
|
||||
if not module.koji_tag:
|
||||
log.warning("No Koji tag associated with module %r", module)
|
||||
return []
|
||||
koji_session = KojiModuleBuilder.get_session(conf, login=False)
|
||||
koji_session = get_session(conf, login=False)
|
||||
tag = koji_session.getTag(module.koji_tag)
|
||||
if not tag:
|
||||
raise ValueError("Unknown Koji tag %r." % module.koji_tag)
|
||||
|
||||
@@ -11,10 +11,10 @@ import subprocess
|
||||
import threading
|
||||
|
||||
from module_build_service import conf, log
|
||||
from module_build_service.common.koji import get_session
|
||||
import module_build_service.scm
|
||||
import module_build_service.utils
|
||||
import module_build_service.scheduler
|
||||
|
||||
from module_build_service.builder import GenericBuilder
|
||||
from module_build_service.builder.utils import (
|
||||
create_local_repo_from_koji_tag,
|
||||
@@ -579,7 +579,7 @@ class MockModuleBuilder(GenericBuilder):
|
||||
# Modules from local repository have already the RPMs filled in mmd.
|
||||
return mmd.get_rpm_artifacts()
|
||||
else:
|
||||
koji_session = KojiModuleBuilder.get_session(conf, login=False)
|
||||
koji_session = get_session(conf, login=False)
|
||||
rpms = koji_session.listTaggedRPMS(build.koji_tag, latest=True)[0]
|
||||
nvrs = set(kobo.rpmlib.make_nvr(rpm, force_epoch=True) for rpm in rpms)
|
||||
return list(nvrs)
|
||||
@@ -663,7 +663,7 @@ class SCMBuilder(BaseBuilder):
|
||||
if not self.koji_session:
|
||||
# If Koji is not configured on the system, then just return 0.0 for components
|
||||
try:
|
||||
self.koji_session = KojiModuleBuilder.get_session(self.config, login=False)
|
||||
self.koji_session = get_session(self.config, login=False)
|
||||
# If the component has not been built before, then None is returned. Instead,
|
||||
# let's return 0.0 so the type is consistent
|
||||
return self.koji_session.getAverageBuildDuration(component.package) or 0.0
|
||||
|
||||
@@ -12,9 +12,7 @@ from abc import ABCMeta, abstractmethod
|
||||
from requests.exceptions import ConnectionError
|
||||
|
||||
from module_build_service import conf, log
|
||||
import module_build_service.resolver
|
||||
import module_build_service.scm
|
||||
import module_build_service.utils
|
||||
from module_build_service.common.retry import retry
|
||||
from module_build_service.models import BUILD_STATES
|
||||
from module_build_service.resolver import GenericResolver
|
||||
from module_build_service.utils import create_dogpile_key_generator_func
|
||||
@@ -285,7 +283,7 @@ class GenericBuilder(six.with_metaclass(ABCMeta)):
|
||||
"default_buildroot_groups_" + str(module_build.id))
|
||||
|
||||
@classmethod
|
||||
@module_build_service.utils.retry(wait_on=(ConnectionError))
|
||||
@retry(wait_on=(ConnectionError))
|
||||
@default_buildroot_groups_cache.cache_on_arguments()
|
||||
def default_buildroot_groups(cls, db_session, module):
|
||||
try:
|
||||
|
||||
0
module_build_service/common/__init__.py
Normal file
0
module_build_service/common/__init__.py
Normal file
162
module_build_service/common/koji.py
Normal file
162
module_build_service/common/koji.py
Normal file
@@ -0,0 +1,162 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
|
||||
import koji
|
||||
import munch
|
||||
import six.moves.xmlrpc_client as xmlrpclib
|
||||
|
||||
from module_build_service import log
|
||||
from module_build_service.common.retry import retry
|
||||
from module_build_service.errors import ProgrammingError
|
||||
|
||||
|
||||
def koji_multicall_map(koji_session, koji_session_fnc, list_of_args=None, list_of_kwargs=None):
|
||||
"""
|
||||
Calls the `koji_session_fnc` using Koji multicall feature N times based on the list of
|
||||
arguments passed in `list_of_args` and `list_of_kwargs`.
|
||||
Returns list of responses sorted the same way as input args/kwargs. In case of error,
|
||||
the error message is logged and None is returned.
|
||||
|
||||
For example to get the package ids of "httpd" and "apr" packages:
|
||||
ids = koji_multicall_map(session, session.getPackageID, ["httpd", "apr"])
|
||||
# ids is now [280, 632]
|
||||
|
||||
:param KojiSessions koji_session: KojiSession to use for multicall.
|
||||
:param object koji_session_fnc: Python object representing the KojiSession method to call.
|
||||
:param list list_of_args: List of args which are passed to each call of koji_session_fnc.
|
||||
:param list list_of_kwargs: List of kwargs which are passed to each call of koji_session_fnc.
|
||||
"""
|
||||
if list_of_args is None and list_of_kwargs is None:
|
||||
raise ProgrammingError("One of list_of_args or list_of_kwargs must be set.")
|
||||
|
||||
if (
|
||||
type(list_of_args) not in [type(None), list]
|
||||
or type(list_of_kwargs) not in [type(None), list]
|
||||
):
|
||||
raise ProgrammingError("list_of_args and list_of_kwargs must be list or None.")
|
||||
|
||||
if list_of_kwargs is None:
|
||||
list_of_kwargs = [{}] * len(list_of_args)
|
||||
if list_of_args is None:
|
||||
list_of_args = [[]] * len(list_of_kwargs)
|
||||
|
||||
if len(list_of_args) != len(list_of_kwargs):
|
||||
raise ProgrammingError("Length of list_of_args and list_of_kwargs must be the same.")
|
||||
|
||||
koji_session.multicall = True
|
||||
for args, kwargs in zip(list_of_args, list_of_kwargs):
|
||||
if type(args) != list:
|
||||
args = [args]
|
||||
if type(kwargs) != dict:
|
||||
raise ProgrammingError("Every item in list_of_kwargs must be a dict")
|
||||
koji_session_fnc(*args, **kwargs)
|
||||
|
||||
try:
|
||||
responses = koji_session.multiCall(strict=True)
|
||||
except Exception:
|
||||
log.exception(
|
||||
"Exception raised for multicall of method %r with args %r, %r:",
|
||||
koji_session_fnc, args, kwargs,
|
||||
)
|
||||
return None
|
||||
|
||||
if not responses:
|
||||
log.error("Koji did not return response for multicall of %r", koji_session_fnc)
|
||||
return None
|
||||
if type(responses) != list:
|
||||
log.error(
|
||||
"Fault element was returned for multicall of method %r: %r", koji_session_fnc, responses
|
||||
)
|
||||
return None
|
||||
|
||||
results = []
|
||||
|
||||
# For the response specification, see
|
||||
# https://web.archive.org/web/20060624230303/http://www.xmlrpc.com/discuss/msgReader$1208?mode=topic
|
||||
# Relevant part of this:
|
||||
# Multicall returns an array of responses. There will be one response for each call in
|
||||
# the original array. The result will either be a one-item array containing the result value,
|
||||
# or a struct of the form found inside the standard <fault> element.
|
||||
for response, args, kwargs in zip(responses, list_of_args, list_of_kwargs):
|
||||
if type(response) == list:
|
||||
if not response:
|
||||
log.error(
|
||||
"Empty list returned for multicall of method %r with args %r, %r",
|
||||
koji_session_fnc, args, kwargs
|
||||
)
|
||||
return None
|
||||
results.append(response[0])
|
||||
else:
|
||||
log.error(
|
||||
"Unexpected data returned for multicall of method %r with args %r, %r: %r",
|
||||
koji_session_fnc, args, kwargs, response
|
||||
)
|
||||
return None
|
||||
|
||||
return results
|
||||
|
||||
|
||||
@retry(wait_on=(xmlrpclib.ProtocolError, koji.GenericError))
|
||||
def koji_retrying_multicall_map(*args, **kwargs):
|
||||
"""
|
||||
Retrying version of koji_multicall_map. This tries to retry the Koji call
|
||||
in case of koji.GenericError or xmlrpclib.ProtocolError.
|
||||
|
||||
Please refer to koji_multicall_map for further specification of arguments.
|
||||
"""
|
||||
return koji_multicall_map(*args, **kwargs)
|
||||
|
||||
|
||||
@retry(wait_on=(xmlrpclib.ProtocolError, koji.GenericError))
|
||||
def get_session(config, login=True):
|
||||
"""Create and return a koji.ClientSession object
|
||||
|
||||
:param config: the config object returned from :meth:`init_config`.
|
||||
:type config: :class:`Config`
|
||||
:param bool login: whether to log into the session. To login if True
|
||||
is passed, otherwise not to log into session.
|
||||
:return: the Koji session object.
|
||||
:rtype: :class:`koji.ClientSession`
|
||||
"""
|
||||
koji_config = munch.Munch(
|
||||
koji.read_config(profile_name=config.koji_profile, user_config=config.koji_config))
|
||||
# Timeout after 10 minutes. The default is 12 hours.
|
||||
koji_config["timeout"] = 60 * 10
|
||||
|
||||
address = koji_config.server
|
||||
log.info("Connecting to koji %r.", address)
|
||||
koji_session = koji.ClientSession(address, opts=koji_config)
|
||||
|
||||
if not login:
|
||||
return koji_session
|
||||
|
||||
authtype = koji_config.authtype
|
||||
log.info("Authenticate session with %r.", authtype)
|
||||
if authtype == "kerberos":
|
||||
try:
|
||||
import krbV
|
||||
# We want to create a context per thread to avoid Kerberos cache corruption
|
||||
ctx = krbV.Context()
|
||||
except ImportError:
|
||||
# If no krbV, we can assume GSSAPI auth is available
|
||||
ctx = None
|
||||
keytab = getattr(config, "krb_keytab", None)
|
||||
principal = getattr(config, "krb_principal", None)
|
||||
if not keytab and principal:
|
||||
raise ValueError(
|
||||
"The Kerberos keytab and principal aren't set for Koji authentication")
|
||||
log.debug(" keytab: %r, principal: %r" % (keytab, principal))
|
||||
# We want to use the thread keyring for the ccache to ensure we have one cache per
|
||||
# thread to avoid Kerberos cache corruption
|
||||
ccache = "KEYRING:thread:mbs"
|
||||
koji_session.krb_login(principal=principal, keytab=keytab, ctx=ctx, ccache=ccache)
|
||||
elif authtype == "ssl":
|
||||
koji_session.ssl_login(
|
||||
os.path.expanduser(koji_config.cert), None, os.path.expanduser(koji_config.serverca)
|
||||
)
|
||||
else:
|
||||
raise ValueError("Unrecognized koji authtype %r" % authtype)
|
||||
|
||||
return koji_session
|
||||
31
module_build_service/common/retry.py
Normal file
31
module_build_service/common/retry.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
import functools
|
||||
import time
|
||||
|
||||
from module_build_service import conf, log
|
||||
|
||||
|
||||
def retry(timeout=conf.net_timeout, interval=conf.net_retry_interval, wait_on=Exception):
|
||||
""" A decorator that allows to retry a section of code...
|
||||
...until success or timeout.
|
||||
"""
|
||||
|
||||
def wrapper(function):
|
||||
@functools.wraps(function)
|
||||
def inner(*args, **kwargs):
|
||||
start = time.time()
|
||||
while True:
|
||||
try:
|
||||
return function(*args, **kwargs)
|
||||
except wait_on as e:
|
||||
log.warning(
|
||||
"Exception %r raised from %r. Retry in %rs" % (e, function, interval)
|
||||
)
|
||||
time.sleep(interval)
|
||||
if (time.time() - start) >= timeout:
|
||||
raise # This re-raises the last exception.
|
||||
|
||||
return inner
|
||||
|
||||
return wrapper
|
||||
@@ -2,6 +2,7 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
from itertools import groupby
|
||||
|
||||
from module_build_service.common.koji import get_session, koji_multicall_map
|
||||
from module_build_service.resolver.DBResolver import DBResolver
|
||||
from module_build_service import conf, models, log
|
||||
|
||||
@@ -76,9 +77,6 @@ class KojiResolver(DBResolver):
|
||||
:param str stream: The requested stream name.
|
||||
:return list: Filtered list of builds.
|
||||
"""
|
||||
# We need to import here because of circular dependencies.
|
||||
from module_build_service.builder.KojiModuleBuilder import koji_multicall_map
|
||||
|
||||
# Return early if there are no module builds.
|
||||
if not module_builds:
|
||||
return []
|
||||
@@ -128,9 +126,7 @@ class KojiResolver(DBResolver):
|
||||
if not tag:
|
||||
return []
|
||||
|
||||
# Create KojiSession. We need to import here because of circular dependencies.
|
||||
from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder
|
||||
koji_session = KojiModuleBuilder.get_session(conf, login=False)
|
||||
koji_session = get_session(conf, login=False)
|
||||
event = koji_session.getLastEvent()
|
||||
|
||||
# List all the modular builds in the modular Koji tag.
|
||||
|
||||
@@ -11,13 +11,11 @@ import koji
|
||||
import six.moves.xmlrpc_client as xmlrpclib
|
||||
|
||||
from module_build_service import conf, log, models, Modulemd, scm
|
||||
from module_build_service.builder.KojiModuleBuilder import (
|
||||
koji_retrying_multicall_map, KojiModuleBuilder,
|
||||
)
|
||||
from module_build_service.common.koji import get_session, koji_retrying_multicall_map
|
||||
from module_build_service.common.retry import retry
|
||||
from module_build_service.db_session import db_session
|
||||
from module_build_service.errors import UnprocessableEntity
|
||||
from module_build_service.resolver.base import GenericResolver
|
||||
from module_build_service.utils import retry
|
||||
from module_build_service.utils.mse import (
|
||||
get_compatible_base_module_mmds, expand_single_mse_streams)
|
||||
|
||||
@@ -209,7 +207,7 @@ def _get_rawhide_version():
|
||||
:return: the rawhide version (e.g. "f32")
|
||||
:rtype: str
|
||||
"""
|
||||
koji_session = KojiModuleBuilder.get_session(conf, login=False)
|
||||
koji_session = get_session(conf, login=False)
|
||||
build_target = koji_session.getBuildTarget("rawhide")
|
||||
if build_target:
|
||||
return build_target["build_tag_name"].partition("-build")[0]
|
||||
@@ -252,7 +250,7 @@ def handle_collisions_with_base_module_rpms(mmd, arches):
|
||||
"Querying Koji for the latest RPMs from the buildrequired base modules from the tags: %s",
|
||||
", ".join(bm_tags),
|
||||
)
|
||||
koji_session = KojiModuleBuilder.get_session(conf, login=False)
|
||||
koji_session = get_session(conf, login=False)
|
||||
bm_rpms = _get_rpms_from_tags(koji_session, list(bm_tags), arches)
|
||||
# The keys are base module RPM names and the values are sets of RPM NEVRAs with that name
|
||||
name_to_nevras = {}
|
||||
|
||||
@@ -7,7 +7,7 @@ import koji
|
||||
|
||||
from module_build_service import celery_app, conf, models, log
|
||||
from module_build_service.builder import GenericBuilder
|
||||
from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder
|
||||
from module_build_service.common.koji import get_session
|
||||
from module_build_service.utils.general import mmd_to_str
|
||||
from module_build_service.db_session import db_session
|
||||
from module_build_service.scheduler import events
|
||||
@@ -90,7 +90,7 @@ def build_task_finalize(
|
||||
and conf.system in ["koji", "test"]
|
||||
and build_new_state == koji.BUILD_STATES["COMPLETE"]
|
||||
):
|
||||
koji_session = KojiModuleBuilder.get_session(conf)
|
||||
koji_session = get_session(conf)
|
||||
rpms = koji_session.listBuildRPMs(component_build.nvr)
|
||||
mmd = parent.mmd()
|
||||
for artifact in rpms:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
from module_build_service import celery_app, conf, log
|
||||
from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder
|
||||
from module_build_service.common.koji import get_session
|
||||
from module_build_service.db_session import db_session
|
||||
from module_build_service.models import ModuleBuild, BUILD_STATES
|
||||
from module_build_service.scheduler import events
|
||||
@@ -17,7 +17,7 @@ def get_corresponding_module_build(nvr):
|
||||
``nvr``, None will be returned.
|
||||
:rtype: :class:`ModuleBuild` or None
|
||||
"""
|
||||
koji_session = KojiModuleBuilder.get_session(conf, login=False)
|
||||
koji_session = get_session(conf, login=False)
|
||||
build_info = koji_session.getBuild(nvr)
|
||||
if build_info is None:
|
||||
return None
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
""" Handlers for module change events on the message bus. """
|
||||
|
||||
from module_build_service import celery_app, conf, models, log, build_logs
|
||||
from module_build_service.common.retry import retry
|
||||
import module_build_service.resolver
|
||||
import module_build_service.utils
|
||||
from module_build_service.utils import (
|
||||
@@ -257,7 +258,7 @@ def generate_module_build_koji_tag(build):
|
||||
return "-".join(["module", build.name, build.stream, build.version])
|
||||
|
||||
|
||||
@module_build_service.utils.retry(
|
||||
@retry(
|
||||
interval=10, timeout=120, wait_on=(ValueError, RuntimeError, ConnectionError)
|
||||
)
|
||||
def get_module_build_dependencies(build):
|
||||
@@ -336,7 +337,7 @@ def wait(msg_id, module_build_id, module_build_state):
|
||||
# Wait for the db on the frontend to catch up to the message, otherwise the
|
||||
# xmd information won't be present when we need it.
|
||||
# See https://pagure.io/fm-orchestrator/issue/386
|
||||
@module_build_service.utils.retry(interval=10, timeout=120, wait_on=RuntimeError)
|
||||
@retry(interval=10, timeout=120, wait_on=RuntimeError)
|
||||
def _get_build_containing_xmd_for_mbs():
|
||||
build = models.ModuleBuild.get_by_id(db_session, module_build_id)
|
||||
if "mbs" in build.mmd().get_xmd():
|
||||
|
||||
@@ -11,7 +11,7 @@ import module_build_service.scheduler
|
||||
import module_build_service.scheduler.consumer
|
||||
from module_build_service import celery_app, conf, models, log
|
||||
from module_build_service.builder import GenericBuilder
|
||||
from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder
|
||||
from module_build_service.common.koji import get_session
|
||||
from module_build_service.utils.greenwave import greenwave
|
||||
from module_build_service.db_session import db_session
|
||||
from module_build_service.scheduler.consumer import ON_MODULE_CHANGE_HANDLERS
|
||||
@@ -100,7 +100,7 @@ def fail_lost_builds():
|
||||
|
||||
if conf.system == "koji":
|
||||
# We don't do this on behalf of users
|
||||
koji_session = KojiModuleBuilder.get_session(conf, login=False)
|
||||
koji_session = get_session(conf, login=False)
|
||||
log.info("Querying tasks for statuses:")
|
||||
res = db_session.query(models.ComponentBuild).filter_by(
|
||||
state=koji.BUILD_STATES["BUILDING"]
|
||||
@@ -219,7 +219,7 @@ def retrigger_new_repo_on_failure():
|
||||
if conf.system != "koji":
|
||||
return
|
||||
|
||||
koji_session = KojiModuleBuilder.get_session(conf)
|
||||
koji_session = get_session(conf)
|
||||
module_builds = db_session.query(models.ModuleBuild).filter(
|
||||
models.ModuleBuild.state == models.BUILD_STATES["build"],
|
||||
models.ModuleBuild.new_repo_task_id.isnot(None),
|
||||
@@ -251,7 +251,7 @@ def delete_old_koji_targets():
|
||||
|
||||
now = datetime.utcnow()
|
||||
|
||||
koji_session = KojiModuleBuilder.get_session(conf)
|
||||
koji_session = get_session(conf)
|
||||
for target in koji_session.getBuildTargets():
|
||||
module = db_session.query(models.ModuleBuild).filter(
|
||||
models.ModuleBuild.koji_tag == target["dest_tag_name"],
|
||||
@@ -389,7 +389,7 @@ def sync_koji_build_tags():
|
||||
if conf.system != "koji":
|
||||
return
|
||||
|
||||
koji_session = KojiModuleBuilder.get_session(conf, login=False)
|
||||
koji_session = get_session(conf, login=False)
|
||||
|
||||
threshold = datetime.utcnow() - timedelta(minutes=10)
|
||||
module_builds = db_session.query(models.ModuleBuild).filter(
|
||||
|
||||
@@ -10,13 +10,14 @@ import shutil
|
||||
import datetime
|
||||
|
||||
from module_build_service import log, conf
|
||||
from module_build_service.common.retry import retry
|
||||
from module_build_service.errors import (
|
||||
Forbidden,
|
||||
ValidationError,
|
||||
UnprocessableEntity,
|
||||
ProgrammingError,
|
||||
)
|
||||
from module_build_service.utils.general import scm_url_schemes, retry
|
||||
from module_build_service.utils.general import scm_url_schemes
|
||||
|
||||
|
||||
class SCM(object):
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
import os
|
||||
import functools
|
||||
import inspect
|
||||
import hashlib
|
||||
import time
|
||||
import locale
|
||||
import contextlib
|
||||
from datetime import datetime
|
||||
@@ -118,31 +116,6 @@ def scm_url_schemes(terse=False):
|
||||
return list(set(scheme_list))
|
||||
|
||||
|
||||
def retry(timeout=conf.net_timeout, interval=conf.net_retry_interval, wait_on=Exception):
|
||||
""" A decorator that allows to retry a section of code...
|
||||
...until success or timeout.
|
||||
"""
|
||||
|
||||
def wrapper(function):
|
||||
@functools.wraps(function)
|
||||
def inner(*args, **kwargs):
|
||||
start = time.time()
|
||||
while True:
|
||||
try:
|
||||
return function(*args, **kwargs)
|
||||
except wait_on as e:
|
||||
log.warning(
|
||||
"Exception %r raised from %r. Retry in %rs" % (e, function, interval)
|
||||
)
|
||||
time.sleep(interval)
|
||||
if (time.time() - start) >= timeout:
|
||||
raise # This re-raises the last exception.
|
||||
|
||||
return inner
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def module_build_state_from_msg(msg):
|
||||
state = int(msg.module_build_state)
|
||||
# TODO better handling
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import re
|
||||
|
||||
from module_build_service import conf, log
|
||||
from module_build_service.common.koji import get_session
|
||||
from module_build_service.db_session import db_session
|
||||
from module_build_service.resolver import GenericResolver
|
||||
|
||||
@@ -109,11 +110,9 @@ def get_modulemds_from_ursine_content(tag):
|
||||
modules metadata is found.
|
||||
:rtype: list[Modulemd.Module]
|
||||
"""
|
||||
from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder
|
||||
|
||||
resolver = GenericResolver.create(db_session, conf)
|
||||
|
||||
koji_session = KojiModuleBuilder.get_session(conf, login=False)
|
||||
koji_session = get_session(conf, login=False)
|
||||
repos = koji_session.getExternalRepoList(tag)
|
||||
build_tags = find_build_tags_from_external_repos(koji_session, repos)
|
||||
if not build_tags:
|
||||
@@ -252,12 +251,10 @@ def find_module_built_rpms(modules_nsvc):
|
||||
:rtype: list[str]
|
||||
"""
|
||||
import kobo.rpmlib
|
||||
from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder
|
||||
|
||||
resolver = GenericResolver.create(db_session, conf)
|
||||
|
||||
built_rpms = []
|
||||
koji_session = KojiModuleBuilder.get_session(conf, login=False)
|
||||
koji_session = get_session(conf, login=False)
|
||||
|
||||
for nsvc in modules_nsvc:
|
||||
name, stream, version, context = nsvc.split(":")
|
||||
|
||||
@@ -555,7 +555,7 @@ class TestBuild(BaseTestBuild):
|
||||
assert module_build.module_builds_trace[4].state == models.BUILD_STATES["ready"]
|
||||
assert len(module_build.module_builds_trace) == 5
|
||||
|
||||
@patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session")
|
||||
@patch("module_build_service.builder.KojiModuleBuilder.get_session")
|
||||
@patch("module_build_service.auth.get_user", return_value=user)
|
||||
@patch("module_build_service.scm.SCM")
|
||||
def test_submit_build_buildonly(
|
||||
|
||||
@@ -1,86 +1,84 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
from collections import OrderedDict
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
import mock
|
||||
import koji
|
||||
|
||||
import six.moves.xmlrpc_client as xmlrpclib
|
||||
from collections import OrderedDict
|
||||
import mock
|
||||
from mock import patch, MagicMock
|
||||
import pytest
|
||||
|
||||
import module_build_service.messaging
|
||||
import module_build_service.scheduler.handlers.repos
|
||||
import module_build_service.models
|
||||
from module_build_service import conf, Modulemd
|
||||
from module_build_service.db_session import db_session
|
||||
from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder
|
||||
from module_build_service.builder import GenericBuilder
|
||||
from module_build_service.scheduler import events
|
||||
from module_build_service.utils.general import mmd_to_str
|
||||
|
||||
import pytest
|
||||
from mock import patch, MagicMock
|
||||
|
||||
from tests import init_data, clean_database, make_module_in_db
|
||||
|
||||
from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def mock_get_session():
|
||||
koji_session = MagicMock()
|
||||
koji_session.getRepo.return_value = {"create_event": "fake event"}
|
||||
|
||||
FakeKojiModuleBuilder.tags = {
|
||||
"module-foo": {
|
||||
"name": "module-foo",
|
||||
"id": 1,
|
||||
"arches": "x86_64",
|
||||
"locked": False,
|
||||
"perm": "admin",
|
||||
},
|
||||
"module-foo-build": {
|
||||
"name": "module-foo-build",
|
||||
"id": 2,
|
||||
"arches": "x86_64",
|
||||
"locked": False,
|
||||
"perm": "admin",
|
||||
},
|
||||
}
|
||||
|
||||
def _get_tag(name):
|
||||
return FakeKojiModuleBuilder.tags.get(name, {})
|
||||
|
||||
koji_session.getTag = _get_tag
|
||||
|
||||
def _createTag(name):
|
||||
FakeKojiModuleBuilder.tags[name] = {
|
||||
"name": name,
|
||||
"id": len(FakeKojiModuleBuilder.tags) + 1,
|
||||
"arches": "x86_64",
|
||||
"locked": False,
|
||||
"perm": "admin",
|
||||
}
|
||||
|
||||
koji_session.createTag = _createTag
|
||||
|
||||
def _getBuildTarget(name):
|
||||
return {
|
||||
"build_tag_name": "module-foo-build",
|
||||
"dest_tag_name": "module-foo",
|
||||
}
|
||||
|
||||
koji_session.getBuildTarget = _getBuildTarget
|
||||
|
||||
def _getAllPerms(*args, **kwargs):
|
||||
return [{"id": 1, "name": "admin"}]
|
||||
|
||||
koji_session.getAllPerms = _getAllPerms
|
||||
|
||||
with patch("module_build_service.builder.KojiModuleBuilder.get_session") as mock_get_session:
|
||||
mock_get_session.return_value = koji_session
|
||||
yield
|
||||
|
||||
|
||||
class FakeKojiModuleBuilder(KojiModuleBuilder):
|
||||
@module_build_service.utils.retry(wait_on=(xmlrpclib.ProtocolError, koji.GenericError))
|
||||
def get_session(self, config, login=True):
|
||||
koji_session = MagicMock()
|
||||
koji_session.getRepo.return_value = {"create_event": "fake event"}
|
||||
|
||||
FakeKojiModuleBuilder.tags = {
|
||||
"module-foo": {
|
||||
"name": "module-foo",
|
||||
"id": 1,
|
||||
"arches": "x86_64",
|
||||
"locked": False,
|
||||
"perm": "admin",
|
||||
},
|
||||
"module-foo-build": {
|
||||
"name": "module-foo-build",
|
||||
"id": 2,
|
||||
"arches": "x86_64",
|
||||
"locked": False,
|
||||
"perm": "admin",
|
||||
},
|
||||
}
|
||||
|
||||
def _get_tag(name):
|
||||
return FakeKojiModuleBuilder.tags.get(name, {})
|
||||
|
||||
koji_session.getTag = _get_tag
|
||||
|
||||
def _createTag(name):
|
||||
FakeKojiModuleBuilder.tags[name] = {
|
||||
"name": name,
|
||||
"id": len(FakeKojiModuleBuilder.tags) + 1,
|
||||
"arches": "x86_64",
|
||||
"locked": False,
|
||||
"perm": "admin",
|
||||
}
|
||||
|
||||
koji_session.createTag = _createTag
|
||||
|
||||
def _getBuildTarget(name):
|
||||
return {
|
||||
"build_tag_name": self.module_build_tag["name"],
|
||||
"dest_tag_name": self.module_tag["name"],
|
||||
}
|
||||
|
||||
koji_session.getBuildTarget = _getBuildTarget
|
||||
|
||||
def _getAllPerms(*args, **kwargs):
|
||||
return [{"id": 1, "name": "admin"}]
|
||||
|
||||
koji_session.getAllPerms = _getAllPerms
|
||||
|
||||
return koji_session
|
||||
|
||||
@classmethod
|
||||
def get_module_build_arches(cls, module):
|
||||
return ["x86_64"]
|
||||
@@ -102,7 +100,7 @@ class TestKojiBuilder:
|
||||
"server": "http://koji.example.com/",
|
||||
},
|
||||
)
|
||||
self.mock_read_config = self.p_read_config.start()
|
||||
self.p_read_config.start()
|
||||
|
||||
def teardown_method(self, test_method):
|
||||
self.p_read_config.stop()
|
||||
@@ -120,7 +118,7 @@ class TestKojiBuilder:
|
||||
"/module-base-runtime-0.25-9/latest/x86_64"
|
||||
)
|
||||
|
||||
def test_recover_orphaned_artifact_when_tagged(self):
|
||||
def test_recover_orphaned_artifact_when_tagged(self, mock_get_session):
|
||||
""" Test recover_orphaned_artifact when the artifact is found and tagged in both tags
|
||||
"""
|
||||
module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2)
|
||||
@@ -171,7 +169,7 @@ class TestKojiBuilder:
|
||||
assert component_build.state_reason == "Found existing build"
|
||||
assert builder.koji_session.tagBuild.call_count == 0
|
||||
|
||||
def test_recover_orphaned_artifact_when_untagged(self):
|
||||
def test_recover_orphaned_artifact_when_untagged(self, mock_get_session):
|
||||
""" Tests recover_orphaned_artifact when the build is found but untagged
|
||||
"""
|
||||
module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2)
|
||||
@@ -216,7 +214,7 @@ class TestKojiBuilder:
|
||||
assert component_build.state_reason == "Found existing build"
|
||||
builder.koji_session.tagBuild.assert_called_once_with(2, "foo-1.0-1.{0}".format(dist_tag))
|
||||
|
||||
def test_recover_orphaned_artifact_when_module_build_macros_untagged(self):
|
||||
def test_recover_orphaned_artifact_when_module_build_macros_untagged(self, mock_get_session):
|
||||
""" Tests recover_orphaned_artifact when module-build-macros is found but untagged
|
||||
"""
|
||||
module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2)
|
||||
@@ -272,7 +270,7 @@ class TestKojiBuilder:
|
||||
[mock.call(2, "srpm-build", "module-build-macros"),
|
||||
mock.call(2, "build", "module-build-macros")])
|
||||
|
||||
def test_recover_orphaned_artifact_when_nothing_exists(self):
|
||||
def test_recover_orphaned_artifact_when_nothing_exists(self, mock_get_session):
|
||||
""" Test recover_orphaned_artifact when the build is not found
|
||||
"""
|
||||
module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2)
|
||||
@@ -309,7 +307,7 @@ class TestKojiBuilder:
|
||||
assert builder.koji_session.tagBuild.call_count == 0
|
||||
|
||||
@patch("koji.util")
|
||||
def test_buildroot_ready(self, mocked_kojiutil):
|
||||
def test_buildroot_ready(self, mocked_kojiutil, mock_get_session):
|
||||
module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2)
|
||||
|
||||
attrs = {"checkForBuilds.return_value": None, "checkForBuilds.side_effect": IOError}
|
||||
@@ -329,7 +327,7 @@ class TestKojiBuilder:
|
||||
assert mocked_kojiutil.checkForBuilds.call_count == 3
|
||||
|
||||
@pytest.mark.parametrize("blocklist", [False, True])
|
||||
def test_tagging_already_tagged_artifacts(self, blocklist):
|
||||
def test_tagging_already_tagged_artifacts(self, blocklist, mock_get_session):
|
||||
"""
|
||||
Tests that buildroot_add_artifacts and tag_artifacts do not try to
|
||||
tag already tagged artifacts
|
||||
@@ -386,9 +384,8 @@ class TestKojiBuilder:
|
||||
builder.module_tag["id"], "new-1.0-1.module_e0095747"
|
||||
)
|
||||
|
||||
@patch.object(FakeKojiModuleBuilder, "get_session")
|
||||
@patch.object(FakeKojiModuleBuilder, "_get_tagged_nvrs")
|
||||
def test_untagged_artifacts(self, mock_get_tagged_nvrs, mock_get_session):
|
||||
def test_untagged_artifacts(self, mock_get_tagged_nvrs,):
|
||||
"""
|
||||
Tests that only tagged artifacts will be untagged
|
||||
"""
|
||||
@@ -399,18 +396,20 @@ class TestKojiBuilder:
|
||||
{"name": "foobar", "id": 1},
|
||||
{"name": "foobar-build", "id": 2},
|
||||
]
|
||||
mock_get_session.return_value = mock_session
|
||||
mock_get_tagged_nvrs.side_effect = [["foo", "bar"], ["foo"]]
|
||||
builder = FakeKojiModuleBuilder(
|
||||
db_session=db_session,
|
||||
owner=module_build.owner,
|
||||
module=module_build,
|
||||
config=conf,
|
||||
tag_name="module-foo",
|
||||
components=[],
|
||||
)
|
||||
path = "module_build_service.builder.KojiModuleBuilder.get_session"
|
||||
with patch(path) as mock_get_session:
|
||||
mock_get_session.return_value = mock_session
|
||||
builder = FakeKojiModuleBuilder(
|
||||
db_session=db_session,
|
||||
owner=module_build.owner,
|
||||
module=module_build,
|
||||
config=conf,
|
||||
tag_name="module-foo",
|
||||
components=[],
|
||||
)
|
||||
builder.untag_artifacts(["foo", "bar"])
|
||||
|
||||
builder.untag_artifacts(["foo", "bar"])
|
||||
assert mock_session.untagBuild.call_count == 3
|
||||
expected_calls = [mock.call(1, "foo"), mock.call(2, "foo"), mock.call(1, "bar")]
|
||||
assert mock_session.untagBuild.mock_calls == expected_calls
|
||||
@@ -534,7 +533,7 @@ class TestKojiBuilder:
|
||||
@pytest.mark.parametrize("custom_whitelist", [False, True])
|
||||
@pytest.mark.parametrize("repo_include_all", [False, True])
|
||||
def test_buildroot_connect(
|
||||
self, custom_whitelist, blocklist, repo_include_all
|
||||
self, custom_whitelist, blocklist, repo_include_all, mock_get_session
|
||||
):
|
||||
module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2)
|
||||
db_session.refresh(module_build)
|
||||
@@ -650,7 +649,7 @@ class TestKojiBuilder:
|
||||
assert session.editTag2.mock_calls == expected_calls
|
||||
|
||||
@pytest.mark.parametrize("blocklist", [False, True])
|
||||
def test_buildroot_connect_create_tag(self, blocklist):
|
||||
def test_buildroot_connect_create_tag(self, blocklist, mock_get_session):
|
||||
module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2)
|
||||
db_session.refresh(module_build)
|
||||
|
||||
@@ -688,7 +687,7 @@ class TestKojiBuilder:
|
||||
assert session.packageListBlock.mock_calls == expected_calls
|
||||
|
||||
@pytest.mark.parametrize("scratch", [False, True])
|
||||
def test_buildroot_connect_create_target(self, scratch):
|
||||
def test_buildroot_connect_create_target(self, scratch, mock_get_session):
|
||||
module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2)
|
||||
|
||||
if scratch:
|
||||
@@ -870,7 +869,7 @@ class TestKojiBuilder:
|
||||
"cg_enabled,cg_devel_enabled", [(False, False), (True, False), (True, True)]
|
||||
)
|
||||
@mock.patch("module_build_service.builder.KojiModuleBuilder.KojiContentGenerator")
|
||||
def test_finalize(self, mock_koji_cg_cls, cg_enabled, cg_devel_enabled):
|
||||
def test_finalize(self, mock_koji_cg_cls, cg_enabled, cg_devel_enabled, mock_get_session):
|
||||
module_build = module_build_service.models.ModuleBuild.get_by_id(db_session, 2)
|
||||
db_session.refresh(module_build)
|
||||
module_build.state = 2
|
||||
@@ -906,13 +905,6 @@ class TestKojiBuilder:
|
||||
else:
|
||||
mock_koji_cg.koji_import.assert_not_called()
|
||||
|
||||
@patch("koji.ClientSession")
|
||||
def test_get_anonymous_session(self, ClientSession):
|
||||
mbs_config = mock.Mock(koji_profile="koji", koji_config="conf/koji.conf")
|
||||
session = KojiModuleBuilder.get_session(mbs_config, login=False)
|
||||
assert ClientSession.return_value == session
|
||||
assert ClientSession.return_value.krb_login.assert_not_called
|
||||
|
||||
@patch.dict("sys.modules", krbV=MagicMock())
|
||||
@patch("koji.ClientSession")
|
||||
def test_ensure_builder_use_a_logged_in_koji_session(self, ClientSession):
|
||||
|
||||
0
tests/test_common/__init__.py
Normal file
0
tests/test_common/__init__.py
Normal file
13
tests/test_common/test_koji.py
Normal file
13
tests/test_common/test_koji.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
import mock
|
||||
|
||||
from module_build_service.common.koji import get_session
|
||||
|
||||
|
||||
@mock.patch("koji.ClientSession")
|
||||
def test_get_anonymous_session(mock_session):
|
||||
mbs_config = mock.Mock(koji_profile="koji", koji_config="conf/koji.conf")
|
||||
session = get_session(mbs_config, login=False)
|
||||
assert mock_session.return_value == session
|
||||
assert mock_session.return_value.krb_login.assert_not_called
|
||||
@@ -230,7 +230,7 @@ class TestLocalResolverModule:
|
||||
"testmodule-master-20170110091357.7c29193d",
|
||||
"testmodule-2-20180109091357.7c29193d"}
|
||||
|
||||
@patch("module_build_service.builder.KojiModuleBuilder.koji_multicall_map")
|
||||
@patch("module_build_service.resolver.KojiResolver.koji_multicall_map")
|
||||
def test_filter_based_on_real_stream_name(self, koji_multicall_map):
|
||||
koji_session = MagicMock()
|
||||
koji_multicall_map.return_value = [
|
||||
|
||||
@@ -256,18 +256,18 @@ def test_get_default_modules_invalid_branch(
|
||||
mock_scm.return_value.checkout_ref.assert_called_once_with("f32")
|
||||
|
||||
|
||||
@patch("module_build_service.scheduler.default_modules.KojiModuleBuilder")
|
||||
def test_get_rawhide_version(mock_koji_builder):
|
||||
@patch("module_build_service.scheduler.default_modules.get_session")
|
||||
def test_get_rawhide_version(mock_get_session):
|
||||
"""
|
||||
Test that _get_rawhide_version will return rawhide Fedora version.
|
||||
"""
|
||||
mock_koji_builder.get_session.return_value.getBuildTarget.return_value = {
|
||||
mock_get_session.return_value.getBuildTarget.return_value = {
|
||||
"build_tag_name": "f32-build",
|
||||
}
|
||||
assert default_modules._get_rawhide_version() == "f32"
|
||||
|
||||
|
||||
@patch("module_build_service.scheduler.default_modules.KojiModuleBuilder.get_session")
|
||||
@patch("module_build_service.scheduler.default_modules.get_session")
|
||||
@patch("module_build_service.scheduler.default_modules._get_rpms_from_tags")
|
||||
def test_handle_collisions_with_base_module_rpms(mock_grft, mock_get_session):
|
||||
"""
|
||||
|
||||
@@ -42,7 +42,7 @@ class TestRepoDone:
|
||||
"module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.buildroot_ready",
|
||||
return_value=True,
|
||||
)
|
||||
@mock.patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session")
|
||||
@mock.patch("module_build_service.builder.KojiModuleBuilder.get_session")
|
||||
@mock.patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.build")
|
||||
@mock.patch(
|
||||
"module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.buildroot_connect"
|
||||
@@ -87,7 +87,7 @@ class TestRepoDone:
|
||||
"module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.buildroot_ready",
|
||||
return_value=True,
|
||||
)
|
||||
@mock.patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session")
|
||||
@mock.patch("module_build_service.builder.KojiModuleBuilder.get_session")
|
||||
@mock.patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.build")
|
||||
@mock.patch(
|
||||
"module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.buildroot_connect"
|
||||
@@ -141,7 +141,7 @@ class TestRepoDone:
|
||||
"module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.buildroot_ready",
|
||||
return_value=True,
|
||||
)
|
||||
@mock.patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session")
|
||||
@mock.patch("module_build_service.builder.KojiModuleBuilder.get_session")
|
||||
@mock.patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.build")
|
||||
@mock.patch(
|
||||
"module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.buildroot_connect"
|
||||
@@ -203,7 +203,7 @@ class TestRepoDone:
|
||||
"module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.buildroot_ready",
|
||||
return_value=True,
|
||||
)
|
||||
@mock.patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session")
|
||||
@mock.patch("module_build_service.builder.KojiModuleBuilder.get_session")
|
||||
@mock.patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.build")
|
||||
@mock.patch(
|
||||
"module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.buildroot_connect"
|
||||
|
||||
@@ -43,7 +43,7 @@ class TestTagTagged:
|
||||
"module_build_service.builder.GenericBuilder.default_buildroot_groups",
|
||||
return_value={"build": [], "srpm-build": []},
|
||||
)
|
||||
@patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session")
|
||||
@patch("module_build_service.builder.KojiModuleBuilder.get_session")
|
||||
@patch("module_build_service.builder.GenericBuilder.create_from_module")
|
||||
def test_newrepo(self, create_builder, koji_get_session, dbg):
|
||||
"""
|
||||
@@ -132,7 +132,7 @@ class TestTagTagged:
|
||||
"module_build_service.builder.GenericBuilder.default_buildroot_groups",
|
||||
return_value={"build": [], "srpm-build": []},
|
||||
)
|
||||
@patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session")
|
||||
@patch("module_build_service.builder.KojiModuleBuilder.get_session")
|
||||
@patch("module_build_service.builder.GenericBuilder.create_from_module")
|
||||
def test_newrepo_still_building_components(
|
||||
self, create_builder, koji_get_session, dbg
|
||||
@@ -184,7 +184,7 @@ class TestTagTagged:
|
||||
"module_build_service.builder.GenericBuilder.default_buildroot_groups",
|
||||
return_value={"build": [], "srpm-build": []},
|
||||
)
|
||||
@patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session")
|
||||
@patch("module_build_service.builder.KojiModuleBuilder.get_session")
|
||||
@patch("module_build_service.builder.GenericBuilder.create_from_module")
|
||||
def test_newrepo_failed_components(self, create_builder, koji_get_session, dbg):
|
||||
"""
|
||||
@@ -256,7 +256,7 @@ class TestTagTagged:
|
||||
"module_build_service.builder.GenericBuilder.default_buildroot_groups",
|
||||
return_value={"build": [], "srpm-build": []},
|
||||
)
|
||||
@patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session")
|
||||
@patch("module_build_service.builder.KojiModuleBuilder.get_session")
|
||||
@patch("module_build_service.builder.GenericBuilder.create_from_module")
|
||||
def test_newrepo_multiple_batches_tagged(
|
||||
self, create_builder, koji_get_session, dbg
|
||||
@@ -358,7 +358,7 @@ class TestTagTagged:
|
||||
"module_build_service.builder.GenericBuilder.default_buildroot_groups",
|
||||
return_value={"build": [], "srpm-build": []},
|
||||
)
|
||||
@patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session")
|
||||
@patch("module_build_service.builder.KojiModuleBuilder.get_session")
|
||||
@patch("module_build_service.builder.GenericBuilder.create_from_module")
|
||||
def test_newrepo_build_time_only(self, create_builder, koji_get_session, dbg):
|
||||
"""
|
||||
@@ -450,7 +450,7 @@ class TestTagTagged:
|
||||
"module_build_service.builder.GenericBuilder.default_buildroot_groups",
|
||||
return_value={"build": [], "srpm-build": []},
|
||||
)
|
||||
@patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder.get_session")
|
||||
@patch("module_build_service.builder.KojiModuleBuilder.get_session")
|
||||
@patch("module_build_service.builder.GenericBuilder.create_from_module")
|
||||
def test_newrepo_not_duplicated(
|
||||
self, create_builder, koji_get_session, dbg, task_state, expect_new_repo
|
||||
|
||||
Reference in New Issue
Block a user