#323 Move ODCS code from ErrataAdvisoryRPPMsSignedhandler to FreshmakerODCSClient.
Merged 8 months ago by jkaluza. Opened 8 months ago by jkaluza.
jkaluza/freshmaker odcs-refactor  into  master

@@ -35,7 +35,7 @@ 

  from freshmaker.models import ArtifactBuild, Event

  from freshmaker.utils import krb_context, get_rebuilt_nvr

  from freshmaker.errors import UnprocessableEntity, ProgrammingError

- from freshmaker.odcsclient import create_odcs_client

+ from freshmaker.odcsclient import create_odcs_client, FreshmakerODCSClient

  from freshmaker.odcsclient import COMPOSE_STATES

  

  

@@ -124,6 +124,7 @@ 

          self._db_artifact_build_id = None

          self._log_prefix = ""

          self._force_dry_run = False

+         self.odcs = FreshmakerODCSClient(self)

  

      def _log(self, log_fnc, msg, *args, **kwargs):

          """

@@ -25,14 +25,12 @@ 

  import json

  import koji

  import requests

- import kobo.rpmlib

  

  from six.moves import cStringIO

  from six.moves import configparser

  

  from freshmaker import conf, db, log

  from freshmaker.events import ErrataAdvisoryRPMsSignedEvent

- from freshmaker.events import ODCSComposeStateChangeEvent

  from freshmaker.events import ManualRebuildWithAdvisoryEvent

  from freshmaker.handlers import ContainerBuildHandler, fail_event_on_handler_exception

  from freshmaker.kojiservice import koji_service

@@ -41,12 +39,7 @@ 

  from freshmaker.errata import Errata

  from freshmaker.types import ArtifactType, ArtifactBuildState, EventState

  from freshmaker.models import Event, Compose

- from freshmaker.consumer import work_queue_put

- from freshmaker.utils import (

-     krb_context, retry, get_rebuilt_nvr)

- from freshmaker.odcsclient import create_odcs_client

- 

- from odcs.common.types import COMPOSE_STATES

+ from freshmaker.utils import get_rebuilt_nvr

  

  

  class ErrataAdvisoryRPMsSignedHandler(ContainerBuildHandler):

@@ -57,9 +50,6 @@ 

  

      name = 'ErrataAdvisoryRPMsSignedHandler'

  

-     # Used to generate incremental compose id in dry run mode.

-     _FAKE_COMPOSE_ID = 0

- 

      def can_handle(self, event):

          return isinstance(event, ErrataAdvisoryRPMsSignedEvent)

  

@@ -129,7 +119,7 @@ 

              # available from official YUM repositories.

              #

              # Generate the ODCS compose with RPMs from the current advisory.

-             repo_urls = self._prepare_yum_repos_for_rebuilds(db_event)

+             repo_urls = self.odcs.prepare_yum_repos_for_rebuilds(db_event)

              self.log_info(

                  "Following repositories will be used for the rebuild:")

              for url in repo_urls:

@@ -146,217 +136,6 @@ 

  

          return []

  

-     def _fake_odcs_new_compose(

-             self, compose_source, tag, packages=None, results=[]):

-         """

-         Fake KojiSession.buildContainer method used dry run mode.

- 

-         Logs the arguments and emits ErrataAdvisoryRPMsSignedHandler of

-         "done" state.

- 

-         :rtype: dict

-         :return: Fake odcs.new_compose dict.

-         """

-         self.log_info("DRY RUN: Calling fake odcs.new_compose with args: %r",

-                       (compose_source, tag, packages, results))

- 

-         # Generate the new_compose dict.

-         ErrataAdvisoryRPMsSignedHandler._FAKE_COMPOSE_ID -= 1

-         new_compose = {}

-         new_compose['id'] = ErrataAdvisoryRPMsSignedHandler._FAKE_COMPOSE_ID

-         new_compose['result_repofile'] = "http://localhost/%d.repo" % (

-             new_compose['id'])

-         new_compose['state'] = COMPOSE_STATES['done']

-         if results:

-             new_compose['results'] = ['boot.iso']

- 

-         # Generate and inject the ODCSComposeStateChangeEvent event.

-         event = ODCSComposeStateChangeEvent(

-             "fake_compose_msg", new_compose)

-         event.dry_run = True

-         self.log_info("Injecting fake event: %r", event)

-         work_queue_put(event)

- 

-         return new_compose

- 

-     def _prepare_yum_repos_for_rebuilds(self, db_event):

-         repo_urls = []

-         db_composes = []

- 

-         compose = self._prepare_yum_repo(db_event)

-         db_composes.append(Compose(odcs_compose_id=compose['id']))

-         db.session.add(db_composes[-1])

-         repo_urls.append(compose['result_repofile'])

- 

-         for dep_event in db_event.find_dependent_events():

-             compose = self._prepare_yum_repo(dep_event)

-             db_composes.append(Compose(odcs_compose_id=compose['id']))

-             db.session.add(db_composes[-1])

-             repo_urls.append(compose['result_repofile'])

- 

-         # commit all new composes

-         db.session.commit()

- 

-         for build in db_event.builds:

-             build.add_composes(db.session, db_composes)

-         db.session.commit()

- 

-         # Remove duplicates from repo_urls.

-         return list(set(repo_urls))

- 

-     def _prepare_yum_repo(self, db_event):

-         """

-         Request a compose from ODCS for builds included in Errata advisory

- 

-         Run a compose in ODCS to contain required RPMs for rebuilding images

-         later.

- 

-         :param Event db_event: current event being handled that contains errata

-             advisory to get builds containing updated RPMs.

-         :return: a mapping returned from ODCS that represents the request

-             compose.

-         :rtype: dict

-         """

-         errata_id = int(db_event.search_key)

- 

-         packages = []

-         errata = Errata()

-         builds = errata.get_builds(errata_id)

-         compose_source = None

-         for nvr in builds:

-             packages += self._get_packages_for_compose(nvr)

-             source = self._get_compose_source(nvr)

-             if compose_source and compose_source != source:

-                 # TODO: Handle this by generating two ODCS composes

-                 db_event.builds_transition(

-                     ArtifactBuildState.FAILED.value, "Packages for errata "

-                     "advisory %d found in multiple different tags."

-                     % (errata_id))

-                 return

-             else:

-                 compose_source = source

- 

-         if compose_source is None:

-             db_event.builds_transition(

-                 ArtifactBuildState.FAILED.value, 'None of builds %s of '

-                 'advisory %d is the latest build in its candidate tag.'

-                 % (builds, errata_id))

-             return

- 

-         self.log_info('Generating new compose for rebuild: '

-                       'source: %s, source type: %s, packages: %s',

-                       compose_source, 'tag', packages)

- 

-         if not self.dry_run:

-             with krb_context():

-                 new_compose = create_odcs_client().new_compose(

-                     compose_source, 'tag', packages=packages,

-                     sigkeys=conf.odcs_sigkeys, flags=["no_deps"])

-         else:

-             new_compose = self._fake_odcs_new_compose(

-                 compose_source, 'tag', packages=packages)

- 

-         return new_compose

- 

-     def _prepare_pulp_repo(self, build, content_sets):

-         """

-         Prepares .repo file containing the repositories matching

-         the content_sets by creating new ODCS compose of PULP type.

- 

-         This currently blocks until the compose is done or failed.

- 

-         :param build: models.ModuleBuild instance associated with this compose.

-         :param list content_sets: List of content sets.

-         :rtype: dict

-         :return: ODCS compose dictionary.

-         """

-         self.log_info('Generating new PULP type compose for content_sets: %r',

-                       content_sets)

- 

-         odcs = create_odcs_client()

-         if not self.dry_run:

-             with krb_context():

-                 new_compose = odcs.new_compose(

-                     ' '.join(content_sets), 'pulp')

- 

-                 # Pulp composes in ODCS takes just few seconds, because ODCS

-                 # only generates the .repo file after single query to Pulp.

-                 # TODO: Freshmaker is currently not designed to handle

-                 # multiple ODCS composes per rebuild Event and since these

-                 # composes are done in no-time normally, it is OK here to

-                 # block. It would still be nice to redesign that part of

-                 # Freshmaker to do things "right".

-                 # This is tracked here: https://pagure.io/freshmaker/issue/114

-                 @retry(timeout=60, interval=2)

-                 def wait_for_compose(compose_id):

-                     ret = odcs.get_compose(compose_id)

-                     if ret["state_name"] == "done":

-                         return True

-                     elif ret["state_name"] == "failed":

-                         return False

-                     self.log_info("Waiting for Pulp compose to finish: %r",

-                                   ret)

-                     raise Exception("ODCS compose not finished.")

- 

-                 done = wait_for_compose(new_compose["id"])

-                 if not done:

-                     build.transition(

-                         ArtifactBuildState.FAILED.value, "Cannot generate "

-                         "ODCS PULP compose %s for content_sets %r"

-                         % (str(new_compose["id"]), content_sets))

-         else:

-             new_compose = self._fake_odcs_new_compose(

-                 content_sets, 'pulp')

- 

-         return new_compose

- 

-     def _prepare_odcs_compose_with_image_rpms(self, image):

-         """

-         Request a compose from ODCS for builds included in Errata advisory

- 

-         Run a compose in ODCS to contain required RPMs for rebuilding images

-         later.

- 

-         :param dict image: Container image representation as returned by

-             LightBlue class.

-         :return: a mapping returned from ODCS that represents the request

-             compose.

-         :rtype: dict

-         """

- 

-         if not image.get('rpm_manifest'):

-             self.log_warn('"rpm_manifest" not set in image.')

-             return

- 

-         rpm_manifest = image["rpm_manifest"][0]

-         if not rpm_manifest.get('rpms'):

-             return

- 

-         builds = set()

-         packages = set()

-         for rpm in rpm_manifest["rpms"]:

-             parsed_nvr = kobo.rpmlib.parse_nvra(rpm["srpm_nevra"])

-             srpm_nvr = "%s-%s-%s" % (parsed_nvr["name"], parsed_nvr["version"],

-                                      parsed_nvr["release"])

-             builds.add(srpm_nvr)

-             parsed_nvr = kobo.rpmlib.parse_nvra(rpm["nvra"])

-             packages.add(parsed_nvr["name"])

- 

-         if not self.dry_run:

-             with krb_context():

-                 new_compose = create_odcs_client().new_compose(

-                     "", 'build', packages=packages, builds=builds,

-                     sigkeys=conf.odcs_sigkeys, flags=["no_deps"])

-         else:

-             new_compose = self._fake_odcs_new_compose(

-                 "", 'build', packages=packages,

-                 builds=builds)

- 

-         self.log_info("Started generating ODCS 'build' type compose %d." % (

-             new_compose["id"]))

- 

-         return new_compose

- 

      def _get_base_image_build_target(self, image):

          dockerfile = image.dockerfile

          image_build_conf_url = dockerfile['content_url'].replace(

@@ -383,88 +162,6 @@ 

              log.exception('image-build.conf does not have option target.')

              return None

  

-     def _get_base_image_build_tag(self, build_target):

-         with koji_service(

-                 conf.koji_profile, log, dry_run=self.dry_run) as session:

-             target_info = session.get_build_target(build_target)

-             if target_info is None:

-                 return target_info

-             else:

-                 return target_info['build_tag_name']

- 

-     def _request_boot_iso_compose(self, image):

-         """Request boot.iso compose for base image"""

-         target = self._get_base_image_build_target(image)

-         if not target:

-             return None

-         build_tag = self._get_base_image_build_tag(target)

-         if not build_tag:

-             return None

- 

-         if self.dry_run:

-             new_compose = self._fake_odcs_new_compose(

-                 build_tag, 'tag', results=['boot.iso'])

-         else:

-             with krb_context():

-                 new_compose = create_odcs_client().new_compose(

-                     build_tag, 'tag', results=['boot.iso'])

-         return new_compose

- 

-     def _get_packages_for_compose(self, nvr):

-         """Get RPMs of current build NVR

- 

-         :param str nvr: build NVR.

-         :return: list of RPM names built from given build.

-         :rtype: list

-         """

-         with koji_service(

-                 conf.koji_profile, log, dry_run=self.dry_run) as session:

-             rpms = session.get_build_rpms(nvr)

-         return list(set([rpm['name'] for rpm in rpms]))

- 

-     def _get_compose_source(self, nvr):

-         """Get tag from which to collect packages to compose

-         :param str nvr: build NVR used to find correct tag.

-         :return: found tag. None is returned if build is not the latest build

-             of found tag.

-         :rtype: str

-         """

-         with koji_service(

-                 conf.koji_profile, log, dry_run=self.dry_run) as service:

-             # Get the list of *-candidate tags, because packages added into

-             # Errata should be tagged into -candidate tag.

-             tags = service.session.listTags(nvr)

-             candidate_tags = [tag['name'] for tag in tags

-                               if tag['name'].endswith('-candidate')]

- 

-             # Candidate tags may include unsigned packages and ODCS won't

-             # allow generating compose from them, so try to find out final

-             # version of candidate tag (without the "-candidate" suffix).

-             final_tags = []

-             for candidate_tag in candidate_tags:

-                 final = candidate_tag[:-len("-candidate")]

-                 final_tags += [tag['name'] for tag in tags

-                                if tag['name'] == final]

- 

-             # Prefer final tags over candidate tags.

-             tags_to_try = final_tags + candidate_tags

-             for tag in tags_to_try:

-                 latest_build = service.session.listTagged(

-                     tag,

-                     latest=True,

-                     package=koji.parse_NVR(nvr)['name'])

-                 if latest_build and latest_build[0]['nvr'] == nvr:

-                     self.log_info("Package %r is latest version in tag %r, "

-                                   "will use this tag", nvr, tag)

-                     return tag

-                 elif not latest_build:

-                     self.log_info("Could not find package %r in tag %r, "

-                                   "skipping this tag", nvr, tag)

-                 else:

-                     self.log_info("Package %r is not he latest in the tag %r ("

-                                   "latest is %r), skipping this tag",

-                                   nvr, tag, latest_build[0]['nvr'])

- 

      def _check_images_to_rebuild(self, db_event, builds):

          """

          Checks the images to rebuild and logs them using self.log_info(...).

@@ -616,7 +313,7 @@ 

                          if cache_key in odcs_cache:

                              db_compose = odcs_cache[cache_key]

                          else:

-                             compose = self._prepare_pulp_repo(

+                             compose = self.odcs.prepare_pulp_repo(

                                  build, image["content_sets"])

  

                              if build.state != ArtifactBuildState.FAILED.value:

@@ -635,7 +332,7 @@ 

                      # the ODCS compose with all the RPMs in the image to allow

                      # installation of possibly unreleased RPMs.

                      if not image["published"]:

-                         compose = self._prepare_odcs_compose_with_image_rpms(image)

+                         compose = self.odcs.prepare_odcs_compose_with_image_rpms(image)

                          if compose:

                              db_compose = Compose(odcs_compose_id=compose['id'])

                              db.session.add(db_compose)

@@ -643,25 +340,6 @@ 

                              build.add_composes(db.session, [db_compose])

                              db.session.commit()

  

-                     # TODO: uncomment following code after boot.iso compose is

-                     # deployed in ODCS server.

- #                    if image.is_base_image:

- #                        compose = self._request_boot_iso_compose(image)

- #                        if compose is None:

- #                            log.error(

- #                                'Failed to request boot.iso compose for base '

- #                                'image %s.', nvr)

- #                            build.transition(

- #                                ArtifactBuildState.FAILED.value,

- #                                'Cannot rebuild this base image because failed to '

- #                                'requeset boot.iso compose.')

- #                            # FIXME: mark all builds associated with build.event FAILED?

- #                        else:

- #                            db_compose = Compose(odcs_compose_id=compose['id'])

- #                            db.session.add(db_compose)

- #                            db.session.commit()

- #                            build.add_composes(db.session, [db_compose])

- 

                  builds[nvr] = build

  

          # Reset context to db_event.

file modified
+1 -1

@@ -35,7 +35,6 @@ 

  

  from freshmaker import db, log

  from freshmaker import messaging

- from freshmaker.odcsclient import create_odcs_client

  from freshmaker.utils import get_url_for, krb_context

  from freshmaker.types import ArtifactType, ArtifactBuildState, EventState

  from freshmaker.events import (

@@ -589,6 +588,7 @@ 

  

      @property

      def finished(self):

+         from freshmaker.odcsclient import create_odcs_client

          with krb_context():

              return 'done' == create_odcs_client().get_compose(

                  self.odcs_compose_id)['state_name']

file modified
+303 -2

@@ -30,12 +30,22 @@ 

  # it would import freshmaker.handlers.odcs, so instead, we import it here

  # and in freshmaker.handler do "from freshmaker.odcsclient import ODCS".

  

+ import koji

  import os

+ import kobo.rpmlib

+ 

  from odcs.client.odcs import AuthMech, ODCS

- from odcs.common.types import COMPOSE_STATES  # noqa

+ from odcs.common.types import COMPOSE_STATES

  from requests.exceptions import HTTPError

  

- from freshmaker import conf, log

+ from freshmaker import conf, log, db

+ from freshmaker.models import Compose

+ from freshmaker.errata import Errata

+ from freshmaker.kojiservice import koji_service

+ from freshmaker.consumer import work_queue_put

+ from freshmaker.types import ArtifactBuildState

+ from freshmaker.utils import krb_context, retry

+ from freshmaker.events import ODCSComposeStateChangeEvent

  

  

  class RetryingODCS(ODCS):

@@ -71,3 +81,294 @@ 

          raise ValueError(

              'Authentication mechanism {0} is not supported yet.'.format(

                  conf.odcs_auth_mech))

+ 

+ 

+ class FreshmakerODCSClient(object):

+     """

+     Class wrapping ODCS providing high-level methods to generate ODCS composes.

+     This class is intended to be used in the BaseHandler scope.

+     """

+ 

+     # Used to generate incremental compose id in dry run mode.

+     _FAKE_COMPOSE_ID = 0

+ 

+     def __init__(self, handler):

+         """

+         Creates new FreshmakerODCSClient.

+ 

+         :param BaseHandler handler: Handler with which is the newly created

+             instance associated.

+         """

+         self.handler = handler

+ 

+     def _fake_odcs_new_compose(

+             self, compose_source, tag, packages=None, results=[]):

+         """

+         Fake odcs.new_compose(...) method used in the dry run mode.

+ 

+         Logs the arguments and emits fake ODCSComposeStateChangeEvent

+ 

+         :rtype: dict

+         :return: Fake odcs.new_compose dict.

+         """

+         self.handler.log_info(

+             "DRY RUN: Calling fake odcs.new_compose with args: %r",

+             (compose_source, tag, packages, results))

+ 

+         # Generate the new_compose dict.

+         FreshmakerODCSClient._FAKE_COMPOSE_ID -= 1

+         new_compose = {}

+         new_compose['id'] = FreshmakerODCSClient._FAKE_COMPOSE_ID

+         new_compose['result_repofile'] = "http://localhost/%d.repo" % (

+             new_compose['id'])

+         new_compose['state'] = COMPOSE_STATES['done']

+         if results:

+             new_compose['results'] = ['boot.iso']

+ 

+         # Generate and inject the ODCSComposeStateChangeEvent event.

+         event = ODCSComposeStateChangeEvent(

+             "fake_compose_msg", new_compose)

+         event.dry_run = True

+         self.handler.log_info("Injecting fake event: %r", event)

+         work_queue_put(event)

+ 

+         return new_compose

+ 

+     def _get_packages_for_compose(self, nvr):

+         """Get RPMs of current build NVR

+ 

+         :param str nvr: build NVR.

+         :return: list of RPM names built from given build.

+         :rtype: list

+         """

+         with koji_service(

+                 conf.koji_profile, log, dry_run=self.handler.dry_run) as session:

+             rpms = session.get_build_rpms(nvr)

+         return list(set([rpm['name'] for rpm in rpms]))

+ 

+     def _get_compose_source(self, nvr):

+         """Get tag from which to collect packages to compose

+         :param str nvr: build NVR used to find correct tag.

+         :return: found tag. None is returned if build is not the latest build

+             of found tag.

+         :rtype: str

+         """

+         with koji_service(

+                 conf.koji_profile, log, dry_run=self.handler.dry_run) as service:

+             # Get the list of *-candidate tags, because packages added into

+             # Errata should be tagged into -candidate tag.

+             tags = service.session.listTags(nvr)

+             candidate_tags = [tag['name'] for tag in tags

+                               if tag['name'].endswith('-candidate')]

+ 

+             # Candidate tags may include unsigned packages and ODCS won't

+             # allow generating compose from them, so try to find out final

+             # version of candidate tag (without the "-candidate" suffix).

+             final_tags = []

+             for candidate_tag in candidate_tags:

+                 final = candidate_tag[:-len("-candidate")]

+                 final_tags += [tag['name'] for tag in tags

+                                if tag['name'] == final]

+ 

+             # Prefer final tags over candidate tags.

+             tags_to_try = final_tags + candidate_tags

+             for tag in tags_to_try:

+                 latest_build = service.session.listTagged(

+                     tag,

+                     latest=True,

+                     package=koji.parse_NVR(nvr)['name'])

+                 if latest_build and latest_build[0]['nvr'] == nvr:

+                     self.handler.log_info(

+                         "Package %r is latest version in tag %r, "

+                         "will use this tag", nvr, tag)

+                     return tag

+                 elif not latest_build:

+                     self.handler.log_info(

+                         "Could not find package %r in tag %r, "

+                         "skipping this tag", nvr, tag)

+                 else:

+                     self.handler.log_info(

+                         "Package %r is not he latest in the tag %r ("

+                         "latest is %r), skipping this tag",

+                         nvr, tag, latest_build[0]['nvr'])

+ 

+     def prepare_yum_repos_for_rebuilds(self, db_event):

+         repo_urls = []

+         db_composes = []

+ 

+         compose = self.prepare_yum_repo(db_event)

+         db_composes.append(Compose(odcs_compose_id=compose['id']))

+         db.session.add(db_composes[-1])

+         repo_urls.append(compose['result_repofile'])

+ 

+         for dep_event in db_event.find_dependent_events():

+             compose = self.prepare_yum_repo(dep_event)

+             db_composes.append(Compose(odcs_compose_id=compose['id']))

+             db.session.add(db_composes[-1])

+             repo_urls.append(compose['result_repofile'])

+ 

+         # commit all new composes

+         db.session.commit()

+ 

+         for build in db_event.builds:

+             build.add_composes(db.session, db_composes)

+         db.session.commit()

+ 

+         # Remove duplicates from repo_urls.

+         return list(set(repo_urls))

+ 

+     def prepare_yum_repo(self, db_event):

+         """

+         Request a compose from ODCS for builds included in Errata advisory

+ 

+         Run a compose in ODCS to contain required RPMs for rebuilding images

+         later.

+ 

+         :param Event db_event: current event being handled that contains errata

+             advisory to get builds containing updated RPMs.

+         :return: a mapping returned from ODCS that represents the request

+             compose.

+         :rtype: dict

+         """

+         errata_id = int(db_event.search_key)

+ 

+         packages = []

+         errata = Errata()

+         builds = errata.get_builds(errata_id)

+         compose_source = None

+         for nvr in builds:

+             packages += self._get_packages_for_compose(nvr)

+             source = self._get_compose_source(nvr)

+             if compose_source and compose_source != source:

+                 # TODO: Handle this by generating two ODCS composes

+                 db_event.builds_transition(

+                     ArtifactBuildState.FAILED.value, "Packages for errata "

+                     "advisory %d found in multiple different tags."

+                     % (errata_id))

+                 return

+             else:

+                 compose_source = source

+ 

+         if compose_source is None:

+             db_event.builds_transition(

+                 ArtifactBuildState.FAILED.value, 'None of builds %s of '

+                 'advisory %d is the latest build in its candidate tag.'

+                 % (builds, errata_id))

+             return

+ 

+         self.handler.log_info(

+             'Generating new compose for rebuild: '

+             'source: %s, source type: %s, packages: %s',

+             compose_source, 'tag', packages)

+ 

+         if not self.handler.dry_run:

+             with krb_context():

+                 new_compose = create_odcs_client().new_compose(

+                     compose_source, 'tag', packages=packages,

+                     sigkeys=conf.odcs_sigkeys, flags=["no_deps"])

+         else:

+             new_compose = self._fake_odcs_new_compose(

+                 compose_source, 'tag', packages=packages)

+ 

+         return new_compose

+ 

+     def prepare_pulp_repo(self, build, content_sets):

+         """

+         Prepares .repo file containing the repositories matching

+         the content_sets by creating new ODCS compose of PULP type.

+ 

+         This currently blocks until the compose is done or failed.

+ 

+         :param build: models.ModuleBuild instance associated with this compose.

+         :param list content_sets: List of content sets.

+         :rtype: dict

+         :return: ODCS compose dictionary.

+         """

+         self.handler.log_info(

+             'Generating new PULP type compose for content_sets: %r',

+             content_sets)

+ 

+         odcs = create_odcs_client()

+         if not self.handler.dry_run:

+             with krb_context():

+                 new_compose = odcs.new_compose(

+                     ' '.join(content_sets), 'pulp')

+ 

+                 # Pulp composes in ODCS takes just few seconds, because ODCS

+                 # only generates the .repo file after single query to Pulp.

+                 # TODO: Freshmaker is currently not designed to handle

+                 # multiple ODCS composes per rebuild Event and since these

+                 # composes are done in no-time normally, it is OK here to

+                 # block. It would still be nice to redesign that part of

+                 # Freshmaker to do things "right".

+                 # This is tracked here: https://pagure.io/freshmaker/issue/114

+                 @retry(timeout=60, interval=2)

+                 def wait_for_compose(compose_id):

+                     ret = odcs.get_compose(compose_id)

+                     if ret["state_name"] == "done":

+                         return True

+                     elif ret["state_name"] == "failed":

+                         return False

+                     self.handler.log_info(

+                         "Waiting for Pulp compose to finish: %r", ret)

+                     raise Exception("ODCS compose not finished.")

+ 

+                 done = wait_for_compose(new_compose["id"])

+                 if not done:

+                     build.transition(

+                         ArtifactBuildState.FAILED.value, "Cannot generate "

+                         "ODCS PULP compose %s for content_sets %r"

+                         % (str(new_compose["id"]), content_sets))

+         else:

+             new_compose = self._fake_odcs_new_compose(

+                 content_sets, 'pulp')

+ 

+         return new_compose

+ 

+     def prepare_odcs_compose_with_image_rpms(self, image):

+         """

+         Request a compose from ODCS for builds included in Errata advisory

+ 

+         Run a compose in ODCS to contain required RPMs for rebuilding images

+         later.

+ 

+         :param dict image: Container image representation as returned by

+             LightBlue class.

+         :return: a mapping returned from ODCS that represents the request

+             compose.

+         :rtype: dict

+         """

+ 

+         if not image.get('rpm_manifest'):

+             self.handler.log_warn('"rpm_manifest" not set in image.')

+             return

+ 

+         rpm_manifest = image["rpm_manifest"][0]

+         if not rpm_manifest.get('rpms'):

+             return

+ 

+         builds = set()

+         packages = set()

+         for rpm in rpm_manifest["rpms"]:

+             parsed_nvr = kobo.rpmlib.parse_nvra(rpm["srpm_nevra"])

+             srpm_nvr = "%s-%s-%s" % (parsed_nvr["name"], parsed_nvr["version"],

+                                      parsed_nvr["release"])

+             builds.add(srpm_nvr)

+             parsed_nvr = kobo.rpmlib.parse_nvra(rpm["nvra"])

+             packages.add(parsed_nvr["name"])

+ 

+         if not self.handler.dry_run:

+             with krb_context():

+                 new_compose = create_odcs_client().new_compose(

+                     "", 'build', packages=packages, builds=builds,

+                     sigkeys=conf.odcs_sigkeys, flags=["no_deps"])

+         else:

+             new_compose = self._fake_odcs_new_compose(

+                 "", 'build', packages=packages,

+                 builds=builds)

+ 

+         self.handler.log_info(

+             "Started generating ODCS 'build' type compose %d." % (

+                 new_compose["id"]))

+ 

+         return new_compose

@@ -19,8 +19,6 @@ 

  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE

  # SOFTWARE.

  

- import requests

- 

  from mock import patch

  

  import freshmaker

@@ -56,19 +54,12 @@ 

              'freshmaker.messaging.publish')

  

          self.mock_prepare_pulp_repo = self.patcher.patch(

-             '_prepare_pulp_repo',

+             'freshmaker.odcsclient.FreshmakerODCSClient.prepare_pulp_repo',

              side_effect=[{'id': compose_id} for compose_id in range(1, 7)])

  

          self.mock_find_images_to_rebuild = self.patcher.patch(

              '_find_images_to_rebuild')

  

-         # boot.iso composes IDs should be different from pulp composes IDs as

-         # when each time to request a compose from ODCS, new compose ID will

-         # be returned along with new comopse.

-         self.mock_request_boot_iso_compose = self.patcher.patch(

-             '_request_boot_iso_compose',

-             side_effect=[{'id': 100}, {'id': 101}])

- 

          # Fake images found to rebuild has these relationships

          #

          # Batch 1  |         Batch 2            |          Batch 3

@@ -370,8 +361,7 @@ 

  

      @patch('freshmaker.handlers.errata.ErrataAdvisoryRPMsSignedHandler.'

             'allow_build', return_value=True)

-     @patch('freshmaker.handlers.errata.ErrataAdvisoryRPMsSignedHandler.'

-            '_prepare_yum_repos_for_rebuilds')

+     @patch('freshmaker.odcsclient.FreshmakerODCSClient.prepare_yum_repos_for_rebuilds')

      @patch('freshmaker.handlers.errata.ErrataAdvisoryRPMsSignedHandler.'

             'start_to_build_images')

      def test_rebuild_if_errata_state_is_prior_to_SHIPPED_LIVE(

@@ -388,8 +378,7 @@ 

  

      @patch('freshmaker.handlers.errata.ErrataAdvisoryRPMsSignedHandler.'

             'allow_build', return_value=True)

-     @patch('freshmaker.handlers.errata.ErrataAdvisoryRPMsSignedHandler.'

-            '_prepare_yum_repos_for_rebuilds')

+     @patch('freshmaker.odcsclient.FreshmakerODCSClient.prepare_yum_repos_for_rebuilds')

      @patch('freshmaker.handlers.errata.ErrataAdvisoryRPMsSignedHandler.'

             'start_to_build_images')

      @patch('freshmaker.models.Event.get_image_builds_in_first_batch')

@@ -412,201 +401,6 @@ 

          self.assertEqual(EventState.BUILDING.value, db_event.state)

  

  

- class TestGetBaseImageBuildTarget(helpers.FreshmakerTestCase):

-     """Test ErrataAdvisoryRPMsSignedHandler._get_base_image_build_target"""

- 

-     def setUp(self):

-         super(TestGetBaseImageBuildTarget, self).setUp()

- 

-         self.image = ContainerImage({

-             'repository': 'repo_1',

-             'commit': '1234567',

-             'target': 'docker-container-candidate',

-             'git_branch': 'rhel-7.4',

-             'content_sets': ['image_a_content_set_1', 'image_a_content_set_2'],

-             'brew': {

-                 'build': 'image-a-1.0-2',

-             },

-             'parent': None,

-             'parsed_data': {

-                 'layers': [

-                     'sha512:7890',

-                     'sha512:5678',

-                 ],

-                 'files': [

-                     {

-                         'filename': 'Dockerfile',

-                         'content_url': 'http://pkgs.localhost/cgit/rpms/'

-                                        'image-a/plain/Dockerfile?id=fa521323',

-                         'key': 'buildfile'

-                     }

-                 ]

-             },

-         })

-         self.handler = ErrataAdvisoryRPMsSignedHandler()

- 

-     @patch('requests.get')

-     def test_get_target_from_image_build_conf(self, get):

-         get.return_value.content = '''\

- [image-build]

- name = image-a

- arches = x86_64

- format = docker

- disk_size = 10

- ksurl = git://git.localhost/spin-kickstarts.git?rhel7#HEAD

- kickstart = rhel-7.4-server-docker.ks

- version = 7.4

- target = guest-rhel-7.4-docker

- distro = RHEL-7.4

- ksversion = RHEL7'''

- 

-         result = self.handler._get_base_image_build_target(self.image)

-         self.assertEqual('guest-rhel-7.4-docker', result)

- 

-     @patch('requests.get')

-     def test_image_build_conf_is_unavailable_in_distgit(self, get):

-         get.return_value.raise_for_status.side_effect = \

-             requests.exceptions.HTTPError('error')

- 

-         result = self.handler._get_base_image_build_target(self.image)

-         self.assertIsNone(result)

- 

-     @patch('requests.get')

-     def test_image_build_conf_is_empty(self, get):

-         get.return_value.content = ''

- 

-         result = self.handler._get_base_image_build_target(self.image)

-         self.assertIsNone(result)

- 

-     @patch('requests.get')

-     def test_image_build_conf_is_not_INI(self, get):

-         get.return_value.content = 'abc'

- 

-         result = self.handler._get_base_image_build_target(self.image)

-         self.assertIsNone(result)

- 

- 

- class TestGetBaseImageBuildTag(helpers.FreshmakerTestCase):

-     """Test ErrataAdvisoryRPMsSignedHandler._get_base_image_build_tag"""

- 

-     def setUp(self):

-         super(TestGetBaseImageBuildTag, self).setUp()

- 

-         self.image = ContainerImage({

-             'repository': 'repo_1',

-             'commit': '1234567',

-             'target': 'docker-container-candidate',

-             'git_branch': 'rhel-7.4',

-             'content_sets': ['image_a_content_set_1', 'image_a_content_set_2'],

-             'brew': {

-                 'build': 'image-a-1.0-2',

-             },

-             'parent': None,

-             'parsed_data': {

-                 'layers': [

-                     'sha512:7890',

-                     'sha512:5678',

-                 ],

-                 'files': [

-                     {

-                         'filename': 'Dockerfile',

-                         'content_url': 'http://pkgs.localhost/cgit/rpms/'

-                                        'image-a/plain/Dockerfile?id=fa521323',

-                         'key': 'buildfile'

-                     }

-                 ]

-             },

-         })

-         self.handler = ErrataAdvisoryRPMsSignedHandler()

- 

-     @helpers.mock_koji

-     def test_get_build_tag_name(self, mocked_koji):

-         result = self.handler._get_base_image_build_tag(

-             'guest-rhel-7.4-docker')

-         self.assertEqual('guest-rhel-7.4-docker-build', result)

- 

-     @helpers.mock_koji

-     def test_no_target_is_returned(self, mocked_koji):

-         result = self.handler._get_base_image_build_tag(

-             'guest-rhel-7.4-docker-unknown')

-         self.assertIsNone(result)

- 

- 

- class TestRequestBootISOCompose(helpers.FreshmakerTestCase):

-     """Test ErrataAdvisoryRPMsSignedHandler._request_boot_iso_compose"""

- 

-     def setUp(self):

-         super(TestRequestBootISOCompose, self).setUp()

- 

-         self.image = ContainerImage({

-             'repository': 'repo_1',

-             'commit': '1234567',

-             'target': 'docker-container-candidate',

-             'git_branch': 'rhel-7.4',

-             'content_sets': ['image_a_content_set_1', 'image_a_content_set_2'],

-             'brew': {

-                 'build': 'image-a-1.0-2',

-             },

-             'parent': None,

-             'parsed_data': {

-                 'layers': [

-                     'sha512:7890',

-                     'sha512:5678',

-                 ],

-                 'files': [

-                     {

-                         'filename': 'Dockerfile',

-                         'content_url': 'http://pkgs.localhost/cgit/rpms/'

-                                        'image-a/plain/Dockerfile?id=fa521323',

-                         'key': 'buildfile'

-                     }

-                 ]

-             },

-         })

-         self.handler = ErrataAdvisoryRPMsSignedHandler()

- 

-     @patch('freshmaker.handlers.errata.errata_advisory_rpms_signed.'

-            'create_odcs_client')

-     @patch('freshmaker.handlers.errata.ErrataAdvisoryRPMsSignedHandler.'

-            '_get_base_image_build_target')

-     @patch('freshmaker.handlers.errata.ErrataAdvisoryRPMsSignedHandler.'

-            '_get_base_image_build_tag')

-     def test_get_boot_iso_compose(

-             self, get_base_image_build_tag, get_base_image_build_target,

-             create_odcs_client):

-         odcs = create_odcs_client.return_value

-         odcs.new_compose.return_value = {'id': 1}

- 

-         get_base_image_build_target.return_value = 'build-target'

-         get_base_image_build_tag.return_value = 'build-tag'

- 

-         result = self.handler._request_boot_iso_compose(self.image)

- 

-         self.assertEqual(odcs.new_compose.return_value, result)

-         odcs.new_compose.assert_called_once_with(

-             'build-tag', 'tag', results=['boot.iso'])

- 

-     @patch('freshmaker.handlers.errata.ErrataAdvisoryRPMsSignedHandler.'

-            '_get_base_image_build_target')

-     def test_cannot_get_image_build_target(self, get_base_image_build_target):

-         get_base_image_build_target.return_value = None

- 

-         result = self.handler._request_boot_iso_compose(self.image)

-         self.assertIsNone(result)

- 

-     @patch('freshmaker.handlers.errata.ErrataAdvisoryRPMsSignedHandler.'

-            '_get_base_image_build_target')

-     @patch('freshmaker.handlers.errata.ErrataAdvisoryRPMsSignedHandler.'

-            '_get_base_image_build_tag')

-     def test_cannot_get_build_tag_from_target(

-             self, get_base_image_build_tag, get_base_image_build_target):

-         get_base_image_build_target.return_value = 'build-target'

-         get_base_image_build_tag.return_value = None

- 

-         result = self.handler._request_boot_iso_compose(self.image)

-         self.assertIsNone(result)

- 

- 

  class TestFindImagesToRebuild(helpers.FreshmakerTestCase):

  

      def setUp(self):

@@ -21,7 +21,6 @@ 

  #

  # Written by Chenxiong Qi <cqi@redhat.com>

  

- import unittest

  import json

  

  from mock import patch, PropertyMock, Mock, call

@@ -326,7 +325,7 @@ 

              "published": False,

          })

  

-     @patch('freshmaker.handlers.errata.errata_advisory_rpms_signed.create_odcs_client')

+     @patch('freshmaker.odcsclient.create_odcs_client')

      def test_batches_records(self, create_odcs_client):

          """

          Tests that batches are properly recorded in DB.

@@ -478,243 +477,6 @@ 

              self.assertEqual(build.state, ArtifactBuildState.FAILED.value)

  

  

- class TestGetPackagesForCompose(helpers.FreshmakerTestCase):

-     """Test ErrataAdvisoryRPMsSignedHandler._get_packages_for_compose"""

- 

-     @helpers.mock_koji

-     def test_get_packages(self, mocked_koji):

-         build_nvr = 'chkconfig-1.7.2-1.el7_3.1'

-         mocked_koji.add_build(build_nvr)

-         mocked_koji.add_build_rpms(

-             build_nvr,

-             [build_nvr, "chkconfig-debuginfo-1.7.2-1.el7_3.1"])

- 

-         handler = ErrataAdvisoryRPMsSignedHandler()

-         packages = handler._get_packages_for_compose(build_nvr)

- 

-         self.assertEqual(set(['chkconfig', 'chkconfig-debuginfo']),

-                          set(packages))

- 

- 

- class TestGetComposeSource(helpers.FreshmakerTestCase):

-     """Test ErrataAdvisoryRPMsSignedHandler._get_compose_source"""

- 

-     @helpers.mock_koji

-     def test_get_tag(self, mocked_koji):

-         mocked_koji.add_build("rh-postgresql96-3.0-9.el6")

-         handler = ErrataAdvisoryRPMsSignedHandler()

-         tag = handler._get_compose_source('rh-postgresql96-3.0-9.el6')

-         self.assertEqual('tag-candidate', tag)

- 

-     @helpers.mock_koji

-     def test_get_None_if_tag_has_new_build(self, mocked_koji):

-         mocked_koji.add_build("rh-postgresql96-3.0-9.el6")

-         mocked_koji.add_build("rh-postgresql96-3.0-10.el6")

-         handler = ErrataAdvisoryRPMsSignedHandler()

-         tag = handler._get_compose_source('rh-postgresql96-3.0-9.el6')

-         self.assertEqual(None, tag)

- 

-     @helpers.mock_koji

-     def test_get_tag_prefer_final_over_candidate(self, mocked_koji):

-         mocked_koji.add_build("rh-postgresql96-3.0-9.el6",

-                               ["tag-candidate", "tag"])

-         handler = ErrataAdvisoryRPMsSignedHandler()

-         tag = handler._get_compose_source('rh-postgresql96-3.0-9.el6')

-         self.assertEqual('tag', tag)

- 

-     @helpers.mock_koji

-     def test_get_tag_fallback_to_second_tag(self, mocked_koji):

-         mocked_koji.add_build("rh-postgresql96-3.0-10.el6",

-                               ["tag"])

-         mocked_koji.add_build("rh-postgresql96-3.0-9.el6",

-                               ["tag", "tag-candidate"])

-         handler = ErrataAdvisoryRPMsSignedHandler()

-         tag = handler._get_compose_source('rh-postgresql96-3.0-9.el6')

-         self.assertEqual('tag-candidate', tag)

- 

- 

- class TestPrepareYumRepo(helpers.ModelsTestCase):

-     """Test ErrataAdvisoryRPMsSignedHandler._prepare_yum_repo"""

- 

-     def setUp(self):

-         super(TestPrepareYumRepo, self).setUp()

- 

-         self.ev = Event.create(db.session, 'msg-id', '123', 100)

-         ArtifactBuild.create(

-             db.session, self.ev, "parent", "image",

-             state=ArtifactBuildState.PLANNED)

-         db.session.commit()

- 

-     @patch('freshmaker.handlers.errata.errata_advisory_rpms_signed.'

-            'create_odcs_client')

-     @patch('freshmaker.handlers.errata.errata_advisory_rpms_signed.'

-            'ErrataAdvisoryRPMsSignedHandler._get_packages_for_compose')

-     @patch('freshmaker.handlers.errata.errata_advisory_rpms_signed.'

-            'ErrataAdvisoryRPMsSignedHandler._get_compose_source')

-     @patch('time.sleep')

-     @patch('freshmaker.handlers.errata.errata_advisory_rpms_signed.Errata')

-     def test_get_repo_url_when_succeed_to_generate_compose(

-             self, errata, sleep, _get_compose_source,

-             _get_packages_for_compose, create_odcs_client):

-         odcs = create_odcs_client.return_value

-         _get_packages_for_compose.return_value = ['httpd', 'httpd-debuginfo']

-         _get_compose_source.return_value = 'rhel-7.2-candidate'

-         odcs.new_compose.return_value = {

-             "id": 3,

-             "result_repo": "http://localhost/composes/latest-odcs-3-1/compose/Temporary",

-             "result_repofile": "http://localhost/composes/latest-odcs-3-1/compose/Temporary/odcs-3.repo",

-             "source": "f26",

-             "source_type": 1,

-             "state": 0,

-             "state_name": "wait",

-         }

- 

-         errata.return_value.get_builds.return_value = set(["httpd-2.4.15-1.f27"])

- 

-         handler = ErrataAdvisoryRPMsSignedHandler()

-         compose = handler._prepare_yum_repo(self.ev)

- 

-         db.session.refresh(self.ev)

-         self.assertEqual(3, compose['id'])

- 

-         _get_compose_source.assert_called_once_with("httpd-2.4.15-1.f27")

-         _get_packages_for_compose.assert_called_once_with("httpd-2.4.15-1.f27")

- 

-         # Ensure new_compose is called to request a new compose

-         odcs.new_compose.assert_called_once_with(

-             'rhel-7.2-candidate', 'tag', packages=['httpd', 'httpd-debuginfo'],

-             sigkeys=[], flags=["no_deps"])

- 

-         # We should get the right repo URL eventually

-         self.assertEqual(

-             "http://localhost/composes/latest-odcs-3-1/compose/Temporary/odcs-3.repo",

-             compose['result_repofile'])

- 

-     @patch('freshmaker.handlers.errata.errata_advisory_rpms_signed.'

-            'create_odcs_client')

-     @patch('freshmaker.handlers.errata.errata_advisory_rpms_signed.'

-            'ErrataAdvisoryRPMsSignedHandler._get_packages_for_compose')

-     @patch('freshmaker.handlers.errata.errata_advisory_rpms_signed.'

-            'ErrataAdvisoryRPMsSignedHandler._get_compose_source')

-     @patch('time.sleep')

-     @patch('freshmaker.handlers.errata.errata_advisory_rpms_signed.Errata')

-     def test_get_repo_url_packages_in_multiple_tags(

-             self, errata, sleep, _get_compose_source,

-             _get_packages_for_compose, create_odcs_client):

-         _get_packages_for_compose.return_value = ['httpd', 'httpd-debuginfo']

-         _get_compose_source.side_effect = [

-             'rhel-7.2-candidate', 'rhel-7.7-candidate']

- 

-         errata.return_value.get_builds.return_value = [

-             set(["httpd-2.4.15-1.f27"]), set(["foo-2.4.15-1.f27"])]

- 

-         handler = ErrataAdvisoryRPMsSignedHandler()

-         repo_url = handler._prepare_yum_repo(self.ev)

- 

-         create_odcs_client.return_value.new_compose.assert_not_called()

-         self.assertEqual(repo_url, None)

- 

-         db.session.refresh(self.ev)

-         for build in self.ev.builds:

-             self.assertEqual(build.state, ArtifactBuildState.FAILED.value)

-             self.assertEqual(build.state_reason, "Packages for errata "

-                              "advisory 123 found in multiple different tags.")

- 

-     @patch('freshmaker.handlers.errata.errata_advisory_rpms_signed.'

-            'create_odcs_client')

-     @patch('freshmaker.handlers.errata.errata_advisory_rpms_signed.'

-            'ErrataAdvisoryRPMsSignedHandler._get_packages_for_compose')

-     @patch('freshmaker.handlers.errata.errata_advisory_rpms_signed.'

-            'ErrataAdvisoryRPMsSignedHandler._get_compose_source')

-     @patch('time.sleep')

-     @patch('freshmaker.handlers.errata.errata_advisory_rpms_signed.Errata')

-     def test_get_repo_url_packages_not_found_in_tag(

-             self, errata, sleep, _get_compose_source,

-             _get_packages_for_compose, create_odcs_client):

-         _get_packages_for_compose.return_value = ['httpd', 'httpd-debuginfo']

-         _get_compose_source.return_value = None

- 

-         errata.return_value.get_builds.return_value = [

-             set(["httpd-2.4.15-1.f27"]), set(["foo-2.4.15-1.f27"])]

- 

-         handler = ErrataAdvisoryRPMsSignedHandler()

-         repo_url = handler._prepare_yum_repo(self.ev)

- 

-         create_odcs_client.return_value.new_compose.assert_not_called()

-         self.assertEqual(repo_url, None)

- 

-         db.session.refresh(self.ev)

-         for build in self.ev.builds:

-             self.assertEqual(build.state, ArtifactBuildState.FAILED.value)

-             self.assertTrue(build.state_reason.endswith(

-                 "of advisory 123 is the latest build in its candidate tag."))

- 

-     def _get_fake_container_image(self):

-         return {

-             u'rpm_manifest': [

-                 {u'rpms': [{u'architecture': u'noarch',

-                             u'gpg': u'199e2f91fd431d51',

-                             u'name': u'apache-commons-lang',

-                             u'nvra': u'apache-commons-lang-2.6-15.el7.noarch',

-                             u'release': u'15.el7',

-                             u'srpm_name': u'apache-commons-lang',

-                             u'srpm_nevra': u'apache-commons-lang-0:2.6-15.el7.src',

-                             u'summary': u'Provides a host of helper utilities for the java.lang API',

-                             u'version': u'2.6'},

-                            {u'architecture': u'noarch',

-                             u'gpg': u'199e2f91fd431d51',

-                             u'name': u'avalon-logkit',

-                             u'nvra': u'avalon-logkit-2.1-14.el7.noarch',

-                             u'release': u'14.el7',

-                             u'srpm_name': u'avalon-logkit',

-                             u'srpm_nevra': u'avalon-logkit-0:2.1-14.el7.src',

-                             u'summary': u'Java logging toolkit',

-                             u'version': u'2.1'}]}]}

- 

-     @patch('freshmaker.handlers.errata.errata_advisory_rpms_signed.'

-            'create_odcs_client')

-     @patch('time.sleep')

-     def test_prepare_odcs_compose_with_image_rpms(

-             self, sleep, create_odcs_client):

-         odcs = create_odcs_client.return_value

-         odcs.new_compose.return_value = {

-             "id": 3,

-             "result_repo": "http://localhost/composes/latest-odcs-3-1/compose/Temporary",

-             "result_repofile": "http://localhost/composes/latest-odcs-3-1/compose/Temporary/odcs-3.repo",

-             "source": "f26",

-             "source_type": 1,

-             "state": 0,

-             "state_name": "wait",

-         }

- 

-         image = self._get_fake_container_image()

- 

-         handler = ErrataAdvisoryRPMsSignedHandler()

-         compose = handler._prepare_odcs_compose_with_image_rpms(image)

- 

-         db.session.refresh(self.ev)

-         self.assertEqual(3, compose['id'])

- 

-         # Ensure new_compose is called to request a new compose

-         odcs.new_compose.assert_called_once_with(

-             '', 'build', builds=set(['avalon-logkit-2.1-14.el7', 'apache-commons-lang-2.6-15.el7']),

-             flags=['no_deps'], packages=set([u'avalon-logkit', u'apache-commons-lang']), sigkeys=[])

- 

-     def test_prepare_odcs_compose_with_image_rpms_no_rpm_manifest(self):

-         handler = ErrataAdvisoryRPMsSignedHandler()

- 

-         compose = handler._prepare_odcs_compose_with_image_rpms({})

-         self.assertEqual(compose, None)

- 

-         compose = handler._prepare_odcs_compose_with_image_rpms(

-             {"rpm_manifest": []})

-         self.assertEqual(compose, None)

- 

-         compose = handler._prepare_odcs_compose_with_image_rpms(

-             {"rpm_manifest": [{"rpms": []}]})

-         self.assertEqual(compose, None)

- 

- 

  class TestErrataAdvisoryStateChangedHandler(helpers.ModelsTestCase):

  

      @patch('freshmaker.errata.Errata.advisories_from_event')

@@ -923,11 +685,8 @@ 

              'freshmaker.handlers.errata.ErrataAdvisoryRPMsSignedHandler.')

  

          self.mock_prepare_pulp_repo = self.patcher.patch(

-             '_prepare_pulp_repo', side_effect=[{'id': 1}, {'id': 2}])

- 

-         self.mock_request_boot_iso_compose = self.patcher.patch(

-             '_request_boot_iso_compose',

-             side_effect=[{'id': 100}, {'id': 200}])

+             'freshmaker.odcsclient.FreshmakerODCSClient.prepare_pulp_repo',

+             side_effect=[{'id': 1}, {'id': 2}])

  

          self.patcher.patch_dict(

              'freshmaker.models.EVENT_TYPES', {self.mock_event.__class__: 0})

@@ -1067,100 +826,6 @@ 

          self.assertEqual(ArtifactBuildState.PLANNED.value, parent_image.state)

          self.mock_prepare_pulp_repo.assert_not_called()

  

-     @unittest.skip('Enable again when enable to request boot.iso compose')

-     def test_pulp_compose_is_stored_for_each_build(self):

-         batches = [

-             [ContainerImage({

-                 "brew": {

-                     "completion_date": "20170420T17:05:37.000-0400",

-                     "build": "rhel-server-docker-7.3-82",

-                     "package": "rhel-server-docker"

-                 },

-                 'parsed_data': {

-                     'layers': [

-                         'sha512:12345678980',

-                         'sha512:10987654321'

-                     ]

-                 },

-                 "parent": None,

-                 "content_sets": ["content-set-1"],

-                 "repository": "repo-1",

-                 "commit": "123456789",

-                 "target": "target-candidate",

-                 "git_branch": "rhel-7",

-                 "error": None,

-                 "published": False,

-             })],

-             [ContainerImage({

-                 "brew": {

-                     "build": "rh-dotnetcore10-docker-1.0-16",

-                     "package": "rh-dotnetcore10-docker",

-                     "completion_date": "20170511T10:06:09.000-0400"

-                 },

-                 'parsed_data': {

-                     'layers': [

-                         'sha512:2345af2e293',

-                         'sha512:12345678980',

-                         'sha512:10987654321'

-                     ]

-                 },

-                 "parent": ContainerImage({

-                     "brew": {

-                         "completion_date": "20170420T17:05:37.000-0400",

-                         "build": "rhel-server-docker-7.3-82",

-                         "package": "rhel-server-docker"

-                     },

-                     'parsed_data': {

-                         'layers': [

-                             'sha512:12345678980',

-                             'sha512:10987654321'

-                         ]

-                     },

-                     "parent": None,

-                     "content_sets": ["content-set-1"],

-                     "repository": "repo-1",

-                     "commit": "123456789",

-                     "target": "target-candidate",

-                     "git_branch": "rhel-7",

-                     "error": None

-                 }),

-                 "content_sets": ["content-set-1"],

-                 "repository": "repo-1",

-                 "commit": "987654321",

-                 "target": "target-candidate",

-                 "git_branch": "rhel-7",

-                 "error": None,

-                 "published": False,

-             })]

-         ]

- 

-         handler = ErrataAdvisoryRPMsSignedHandler()

-         handler._record_batches(batches, self.mock_event)

- 

-         query = db.session.query(ArtifactBuild)

-         parent_build = query.filter(

-             ArtifactBuild.original_nvr == 'rhel-server-docker-7.3-82'

-         ).first()

-         self.assertEqual(2, len(parent_build.composes))

-         compose_ids = sorted([rel.compose.odcs_compose_id

-                               for rel in parent_build.composes])

-         # Ensure both pulp compose id and boot.iso compose id are stored

-         self.assertEqual([1, 100], compose_ids)

- 

-         child_build = query.filter(

-             ArtifactBuild.original_nvr == 'rh-dotnetcore10-docker-1.0-16'

-         ).first()

-         self.assertEqual(1, len(child_build.composes))

-         self.assertEqual(2, child_build.composes[0].compose.odcs_compose_id)

- 

-         self.mock_prepare_pulp_repo.assert_has_calls([

-             call(child_build.event, ["content-set-1"]),

-             call(child_build.event, ["content-set-1"])

-         ])

- 

-         self.mock_request_boot_iso_compose.assert_called_once_with(

-             batches[0][0])

- 

      def test_pulp_compose_generated_just_once(self):

          batches = [

              [ContainerImage({

@@ -1449,76 +1114,6 @@ 

          self.mock_prepare_pulp_repo.assert_not_called()

  

  

- class TestPrepareYumReposForRebuilds(helpers.ModelsTestCase):

-     """Test ErrataAdvisoryRPMsSignedHandler._prepare_yum_repos_for_rebuilds"""

- 

-     def setUp(self):

-         super(TestPrepareYumReposForRebuilds, self).setUp()

- 

-         self.patcher = helpers.Patcher(

-             'freshmaker.handlers.errata.errata_advisory_rpms_signed.'

-             'ErrataAdvisoryRPMsSignedHandler.')

- 

-         self.mock_prepare_yum_repo = self.patcher.patch(

-             '_prepare_yum_repo',

-             side_effect=[

-                 {'id': 1, 'result_repofile': 'http://localhost/repo/1'},

-                 {'id': 2, 'result_repofile': 'http://localhost/repo/2'},

-                 {'id': 3, 'result_repofile': 'http://localhost/repo/3'},

-                 {'id': 4, 'result_repofile': 'http://localhost/repo/4'},

-             ])

- 

-         self.mock_find_dependent_event = self.patcher.patch(

-             'freshmaker.models.Event.find_dependent_events')

- 

-         self.db_event = Event.create(

-             db.session, 'msg-1', 'search-key-1',

-             EVENT_TYPES[ErrataAdvisoryRPMsSignedEvent],

-             state=EventState.INITIALIZED,

-             released=False)

-         self.build_1 = ArtifactBuild.create(

-             db.session, self.db_event, 'build-1', ArtifactType.IMAGE)

-         self.build_2 = ArtifactBuild.create(

-             db.session, self.db_event, 'build-2', ArtifactType.IMAGE)

- 

-         db.session.commit()

- 

-     def tearDown(self):

-         super(TestPrepareYumReposForRebuilds, self).tearDown()

-         self.patcher.unpatch_all()

- 

-     def test_prepare_without_dependent_events(self):

-         self.mock_find_dependent_event.return_value = []

- 

-         handler = ErrataAdvisoryRPMsSignedHandler()

-         urls = handler._prepare_yum_repos_for_rebuilds(self.db_event)

- 

-         self.assertEqual(1, self.build_1.composes[0].compose.id)

-         self.assertEqual(1, self.build_2.composes[0].compose.id)

-         self.assertEqual(['http://localhost/repo/1'], urls)

- 

-     def test_prepare_with_dependent_events(self):

-         self.mock_find_dependent_event.return_value = [

-             Mock(), Mock(), Mock()

-         ]

- 

-         handler = ErrataAdvisoryRPMsSignedHandler()

-         urls = handler._prepare_yum_repos_for_rebuilds(self.db_event)

- 

-         odcs_compose_ids = [rel.compose.id for rel in self.build_1.composes]

-         self.assertEqual([1, 2, 3, 4], sorted(odcs_compose_ids))

- 

-         odcs_compose_ids = [rel.compose.id for rel in self.build_2.composes]

-         self.assertEqual([1, 2, 3, 4], sorted(odcs_compose_ids))

- 

-         self.assertEqual([

-             'http://localhost/repo/1',

-             'http://localhost/repo/2',

-             'http://localhost/repo/3',

-             'http://localhost/repo/4',

-         ], sorted(urls))

- 

- 

  class TestSkipNonRPMAdvisory(helpers.FreshmakerTestCase):

  

      def test_ensure_to_handle_rpm_adivsory(self):

file modified
+311 -2

@@ -23,14 +23,29 @@ 

  

  import six

  

- from mock import patch

+ from mock import patch, Mock

  from odcs.client.odcs import AuthMech