Bug 678721 - adding errata by errata.clone() api to cloned channel also adds non-relevant packages from that errata
Summary: adding errata by errata.clone() api to cloned channel also adds non-relevant ...
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Red Hat Satellite 5
Classification: Red Hat
Component: API
Version: 540
Hardware: Unspecified
OS: Unspecified
high
high
Target Milestone: ---
Assignee: Milan Zázrivec
QA Contact: Tomas Lestach
URL:
Whiteboard:
Depends On:
Blocks: sat541-blockers 703381
TreeView+ depends on / blocked
 
Reported: 2011-02-19 01:11 UTC by Martin Osvald 🛹
Modified: 2018-11-29 19:46 UTC (History)
7 users (show)

Fixed In Version: spacewalk-java-1.2.39-75
Doc Type: Bug Fix
Doc Text:
Clone Of:
: 703381 (view as bug list)
Environment:
Last Closed: 2011-06-17 02:34:49 UTC
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)
temporary patch which fixes the bug (1.16 KB, patch)
2011-02-19 01:11 UTC, Martin Osvald 🛹
no flags Details | Diff

Description Martin Osvald 🛹 2011-02-19 01:11:08 UTC
Created attachment 479636 [details]
temporary patch which fixes the bug

Description of problem:

If you use errata.clone() api to clone a specific errata to a cloned/custom channel, it adds instead of only packages from cloned channel also packages from different channels which have the same name and architecture as the ones from the cloned channel.

It can lead to adding e.g. RHEL6 packages altogether with RHEL5 ones into channel which was originally cloned from RHEL5 channel. See the 'Actual results'.


Version-Release number of selected component (if applicable):

spacewalk-java-1.2.39-29.el5sat


How reproducible:

Always


Steps to Reproduce:
===================

1. Clone rhel-x86_64-server-5 rhel base channel using the following script (change server, login, pass):

=== <snip clone_channel.py> ===
#!/usr/bin/python

from xmlrpclib import Server
import xmlrpclib

satServer     = "server"
satUser       = "login"
satPasswd     = "pass"
sourceChannel = "rhel-x86_64-server-5"
satClient = Server('https://'+satServer+'/rpc/api')
satAuth = satClient.auth.login(satUser, satPasswd)

print satClient.channel.software.clone(satAuth, sourceChannel , {'name':'testicek', 'label':'testicek', 'summary':'testicek'}, False)
=== </snip> ===

2. Run the following script which clones 'RHSA-2010:0966' into the cloned channel (change server, login, pass):

=== <snip clone_errata.py> ===
#!/usr/bin/python                                                                                                                                                                                              
                                                                                                                                                                                                               
from xmlrpclib import Server                                                                                                                                                                                   
import xmlrpclib                                                                                                                                                                                               
                                                                                                                                                                                                               
errataDict = {}                                                                                                                                                                                                
errataDict['advisory']  = 'RHSA-2010:0966'                                                                                                                                                                     
satServer    = "server"                                                                                                                                                                     
satUser      = "login"                                                                                                                                                                                         
satPasswd    = "pass"
satClient = Server('https://'+satServer+'/rpc/api')                                                                                                                                                            
satAuth = satClient.auth.login(satUser, satPasswd)                                                                                                                                                             
print satClient.errata.clone(satAuth,"testicek",['RHSA-2010:0966'])
=== </snip> ===

  
Actual results:
===============

$ ./clone_channel.py 
426
$

Now, search for RHSA-2010:0966 errata through WebUI and you can see in 'Packages' folder a list of packages belonging to errata and cloned channel ('testicek'), the following output is correct:

testicek 
md5:4864d00fd39cd36741d0f7b8242cac25 firefox-3.6.13-2.el5-i386 
md5:9d986be77ce9a74845cc58855415ccd2 firefox-3.6.13-2.el5-x86_64 
md5:f54552c008aab66135b691e7349fff43 xulrunner-1.9.2.13-3.el5-i386 
md5:587d16fe99016c0d782acfeb83a96765 xulrunner-1.9.2.13-3.el5-x86_64 
md5:63cfc555bc6f52aafa9d7155de062e05 xulrunner-devel-1.9.2.13-3.el5-i386 
md5:edf71edc51ae45cf66eee9561c7c447e xulrunner-devel-1.9.2.13-3.el5-x86_64 

$ ./clone_errata.py 
[{'date': '12/9/10', 'advisory_name': 'CLA-2010:0966', 'advisory_type': 'Security Advisory', 'id': 9306, 'advisory_synopsis': 'Critical: firefox security update'}]
$

Now, again search for RHSA-2010:0966 errata and you can see in 'Packages' the following:

testicek
md5:4864d00fd39cd36741d0f7b8242cac25 firefox-3.6.13-2.el5-i386 
md5:9d986be77ce9a74845cc58855415ccd2 firefox-3.6.13-2.el5-x86_64 
sha256:03ead8549d8fc95b3aab5501f56429d6682c228de5d013f70a60d5824a96c7a2 firefox-3.6.13-2.el6_0-x86_64 
md5:f54552c008aab66135b691e7349fff43 xulrunner-1.9.2.13-3.el5-i386 
md5:587d16fe99016c0d782acfeb83a96765 xulrunner-1.9.2.13-3.el5-x86_64 
sha256:220b0d00e6b0d198b16e31289c580cd0256c5dfb0d733a96c278fe34e4973ff0 xulrunner-1.9.2.13-3.el6_0-x86_64 
md5:63cfc555bc6f52aafa9d7155de062e05 xulrunner-devel-1.9.2.13-3.el5-i386 
md5:edf71edc51ae45cf66eee9561c7c447e xulrunner-devel-1.9.2.13-3.el5-x86_64 


Expected results:
=================

No duplicate packages in cloned channel


Additional info:
================

The problem seems to be in a db call, which gets package list belonging to a chosen errata to add corresponding packages to the cloned channel (you can find a codepath leading to this sql hereinafter):

./spacewalk-java-1.2.39/code/src/com/redhat/rhn/common/db/datasource/xml/Errata_queries.xml:
 655 <mode name="find_packages_for_errata_and_channel" class="com.redhat.rhn.frontend.dto.PackageOverview">
 656   <query params="custom_cid, eid, org_id">
 657         select distinct P.id, PN.name package_name, PA.label as package_arch,
 658                 EVR.version
 659        || '-' || EVR.release || (CASE WHEN EVR.epoch IS NULL THEN '' ELSE ':' || EVR.epoch END)
 660          package_nvre
 661     from
 662         rhnErrata E inner join
 663         rhnErrataPackage EP on E.id = EP.errata_id inner join
 664         rhnPackage P on P.id = EP.package_id inner join
 665         rhnPackageArch PA on PA.id = P.package_arch_id inner join
 666         rhnPackageEvr EVR on Evr.id = P.evr_id inner join
 667     rhnPackage P2 on P2.name_id = P.name_id inner join <<<---
 668     rhnChannelPackage CP on CP.package_id = P2.id      <<<---
 669     inner join rhnPackageName PN on  PN.id = P.name_id
 670     inner join rhnChannel CN on CP.channel_id = CN.id
 671     where E.id = :eid
 672          and CP.channel_id = :custom_cid
 673          and P2.Package_arch_id = P.package_arch_id   <<<---
 674          and CN.org_id = :org_id and
 675          (E.org_id is NULL or E.org_id = :org_id)
 676   </query>
 677 </mode>

Problematic are lines #673 and related conditions at line #667,#668 which lead to returning also packages from unrelated channels. It happens because we iterate through all packages belonging to errata from all channels (#663) ...:

=== <snip> ===
SQL> select * from rhnErrataPackage where errata_id = 68;  <<<--- 'RHSA-2010:0966'

 ERRATA_ID PACKAGE_ID CREATED   MODIFIED
---------- ---------- --------- ---------
        68       3644 30-JAN-11 30-JAN-11  <<<--- firefox-3.6.13-2.el6_0.x86_64.rpm
        68       3645 30-JAN-11 30-JAN-11  <<<--- xulrunner-1.9.2.13-3.el6_0.i686.rpm (note this wasn't added)
        68       3646 30-JAN-11 30-JAN-11  <<<--- xulrunner-1.9.2.13-3.el6_0.x86_64.rpm
        68      14319 09-FEB-11 09-FEB-11
        68      14320 09-FEB-11 09-FEB-11  <<<--- firefox-3.6.13-2.el5.x86_64.rpm
        68      14321 09-FEB-11 09-FEB-11
        68      14322 09-FEB-11 09-FEB-11
        68      14323 09-FEB-11 09-FEB-11  <<<--- xulrunner-1.9.2.13-3.el5.x86_64.rpm
        68      14324 09-FEB-11 09-FEB-11

9 rows selected.
=== </snip> ===

... and P can contain a package from one channel (#664, in our case firefox-3.6.13-2.el6_0.x86_64.rpm) and the destination channel can contain a package with the same name (#667, in our case firefox-3.6.13-2.el5.x86_64.rpm) in destination channel (#668) so that it prints the same package from both RHEL5 and RHEL6 channel (correct packages were removed from output):

=== <snip> ===
SQL> select distinct P.id, PN.name package_name, PA.label as package_arch, EVR.version || '-' || EVR.release || (CASE WHEN EVR.epoch IS NULL THEN '' ELSE ':' || EVR.epoch END) package_nvre
 from rhnErrata E inner join
  rhnErrataPackage EP on E.id = EP.errata_id inner join
  rhnPackage P on P.id = EP.package_id inner join                                                                                                                                                              
  rhnPackageArch PA on PA.id = P.package_arch_id inner join                                                                                                                                                    
  rhnPackageEvr EVR on Evr.id = P.evr_id inner join                                                                                                                                                            
  rhnPackage P2 on P2.name_id = P.name_id inner join                                                                                                                                                           
  rhnChannelPackage CP on CP.package_id = P2.id                                                                                                                                                                
  inner join rhnPackageName PN on  PN.id = P.name_id                                                                                                                                                           
  inner join rhnChannel CN on CP.channel_id = CN.id                                                                                                                                                            
 where E.id = 68                                                                                                                                                                                               
  and CP.channel_id = 426                                                                                                                                                                                      
  and P2.Package_arch_id = P.package_arch_id                                                                                                                                                                   
  and CN.org_id = 1 and                                                                                                                                                                                        
  (E.org_id is NULL or E.org_id = 1);  2    3    4    5    6    7    8    9   10   11   12   13   14   15                                                                                                      
                                                                                                                                                                                                               
        ID                                                                                                                                                                                                     
----------                                                                                                                                                                                                     
PACKAGE_NAME                                                                                                                                                                                                   
--------------------------------------------------------------------------------                                                                                                                               
PACKAGE_ARCH
----------------------------------------------------------------
PACKAGE_NVRE
--------------------------------------------------------------------------------
      3646
xulrunner
x86_64
1.9.2.13-3.el6_0

...snip...

        ID
----------
PACKAGE_NAME
--------------------------------------------------------------------------------
PACKAGE_ARCH
----------------------------------------------------------------
PACKAGE_NVRE
--------------------------------------------------------------------------------
      3644
firefox
x86_64
3.6.13-2.el6_0

8 rows selected.
=== </snip> ===


I cannot find out a background reason/intention of lines #667 and #673, but without them it works correctly, see the attached temporary patch (actually I didn't test it enough to be sure it doesn't break something).

The following is a correct output, the changes in the patch won't fix cases where the channel was already corrupted by cloning an errata before applying the patch.

SQL> select distinct P.id, PN.name package_name, PA.label as package_arch, EVR.version || '-' || EVR.release || (CASE WHEN EVR.epoch IS NULL THEN '' ELSE ':' || EVR.epoch END) package_nvre
 from rhnErrata E inner join
  rhnErrataPackage EP on E.id = EP.errata_id inner join
  rhnPackage P on P.id = EP.package_id inner join
  rhnPackageArch PA on PA.id = P.package_arch_id inner join
  rhnPackageEvr EVR on Evr.id = P.evr_id inner join
  rhnChannelPackage CP on CP.package_id = P.id
  inner join rhnPackageName PN on  PN.id = P.name_id
  inner join rhnChannel CN on CP.channel_id = CN.id
 where E.id = 68
  and CP.channel_id = 465
  and CN.org_id = 1 and
  (E.org_id is NULL or E.org_id = 1);  2    3    4    5    6    7    8    9   10   11   12   13  

        ID
----------
PACKAGE_NAME
--------------------------------------------------------------------------------
PACKAGE_ARCH
----------------------------------------------------------------
PACKAGE_NVRE
--------------------------------------------------------------------------------
     14321
xulrunner
i386
1.9.2.13-3.el5


        ID
----------
PACKAGE_NAME
--------------------------------------------------------------------------------
PACKAGE_ARCH
----------------------------------------------------------------
PACKAGE_NVRE
--------------------------------------------------------------------------------
     14320
firefox
x86_64
3.6.13-2.el5


        ID
----------
PACKAGE_NAME
--------------------------------------------------------------------------------
PACKAGE_ARCH
----------------------------------------------------------------
PACKAGE_NVRE
--------------------------------------------------------------------------------
     14319
firefox
i386
3.6.13-2.el5


        ID
----------
PACKAGE_NAME
--------------------------------------------------------------------------------
PACKAGE_ARCH
----------------------------------------------------------------
PACKAGE_NVRE
--------------------------------------------------------------------------------
     14322
xulrunner-devel
i386
1.9.2.13-3.el5


        ID
----------
PACKAGE_NAME
--------------------------------------------------------------------------------
PACKAGE_ARCH
----------------------------------------------------------------
PACKAGE_NVRE
--------------------------------------------------------------------------------
     14324
xulrunner-devel
x86_64
1.9.2.13-3.el5


        ID
----------
PACKAGE_NAME
--------------------------------------------------------------------------------
PACKAGE_ARCH
----------------------------------------------------------------
PACKAGE_NVRE
--------------------------------------------------------------------------------
     14323
xulrunner
x86_64
1.9.2.13-3.el5


6 rows selected.

SQL>


errata.clone() codepath leading to the responsible sql:
=======================================================

./spacewalk-java-1.2.39/code/src/com/redhat/rhn/frontend/xmlrpc/handler-manifest.xml:
...
  5   <template name="errata" classname="com.redhat.rhn.frontend.xmlrpc.errata.ErrataHandler" />
...

./spacewalk-java-1.2.39/code/src/com/redhat/rhn/frontend/xmlrpc/errata/ErrataHandler.java:
 855     public Object[] clone(String sessionKey, String channelLabel,
 856             List advisoryNames) throws InvalidChannelRoleException {
...
 879         for (Iterator itr = errataToClone.iterator(); itr.hasNext();) {
 880             Errata cloned = ErrataManager.createClone(loggedInUser, (Errata)itr.next());
 881             Errata publishedClone = ErrataManager.publish(cloned);
 882 
 883             publishedClone = ErrataFactory.publishToChannel(publishedClone, channel, <<<--- 1.
 884                     loggedInUser, false);
 885             ErrataFactory.save(publishedClone);
 886 
 887             toReturn.add(publishedClone);
 888         }
...

spacewalk-java-1.2.39/code/src/com/redhat/rhn/domain/errata/ErrataFactory.java:
 268     public static Errata publishToChannel(Errata errata, Channel chan, User user,
 269             boolean inheritPackages) {
...
 277         if (inheritPackages) {
...
 284         }
 285         else { 
 286             packs = ErrataManager.lookupPacksFromErrataForChannel(chan, errata, user);  <<<---- 2.
 287         }
 288         for (PackageOverview packOver : packs) {
 289             //lookup the Package object
 290             Package pack = PackageFactory.lookupByIdAndUser(
 291                     packOver.getId().longValue(), user);
 292             packagesToPush.add(pack);
 293         } 
 294         return publishErrataPackagesToChannel(errata, chan, user, packagesToPush);
 295     }

spacewalk-java-1.2.39/code/src/com/redhat/rhn/manager/errata/ErrataManager.java:
1184    public static DataResult<PackageOverview> lookupPacksFromErrataForChannel(
1185                Channel customChan, Errata errata, User user) {
1186        Map params = new HashMap();
1187        //params.put("uid", user.getId());
1188        params.put("eid" , errata.getId());
1189        params.put("org_id" , user.getOrg().getId());
1190        params.put("custom_cid", customChan.getId());
1191        SelectMode m = ModeFactory.getMode(
1192                "Errata_queries",  "find_packages_for_errata_and_channel");  <<<--- 3. the query
1193        return m.execute(params);
1194     
1195    }


Related problem:
================

* I found out during investigation that the same problem happens also when cloning a channel with 'Current state of the channel (all errata)' through WebUI, it creates cloned erratas (with a name in a form CLA-XXXX:XXXX-X) which contains also duplicated packages. I will create a BZ for it soon (currently investigating related perl code, I see the sql responsible for inserting package ids into rhnChannelPackage table, but don't see the culprit yet)


BZ related to this bug:
=======================

BZ #500128 (adding errata to clone channels also adds non-relevant packages from that errata)


Workaround:
===========

* It currently works correctly only when cloning an individual erratas through WebUI and the destination channel was originally created by copying erratas and related packages through channel.software.clone() api as done in first script in 'Steps to Reproduce' instead of cloning the channel which creates a new/cloned errata with a new name in a form CLA-XXXX:XXXX-X which doesn't work:

Cloned RHEL5 64 bit Channel -> Errata -> Add -> Add Red hat Errata -> select 2010:431 Errata -> Confirm -> Clone

The above works because the code in a background simply gathers package list from source channel and compares it with package ids stored in related rhnErrataPackage table (which holds errata and related package ids) and these packages are then copied to destination (cloned) channel.

Also probably good to mention that errata.clone() api was intended to be used only on channels which already contain all the packages related to errata. It means that one has to find out all the packages related to specific errata, then add them to the channel and then call the errata.clone() api to add erratas and connect them with packages.

Comment 2 Milan Zázrivec 2011-05-11 10:45:55 UTC
The behavior of errata.clone() this bug report is showing is perfectly
OK and expected: you clone a RHEL errata spanning RHEL-5 and RHEL-6 channels,
you get RHEL-5 and RHEL-6 packages in the target channel.

I created a new API call just for this purpose errata.cloneAsOriginal():
* same prototype as errata.clone()
* works with cloned channels only
* publishes the cloned errata according to the original channels.

spacewalk.git master: 4e0eb25dae25047378066affd966eec0c376390c
satellite.git SATELLITE-5.4: 4096d3b2d216e580a4e698adf6942ae5e063613c

Comment 6 Tomas Lestach 2011-05-18 13:25:42 UTC
When cloning RHBA-2010:10260 into the cloned channel:

- using errata.cloneAsOriginal, following package lands in the target channel:
   * spacewalk-koan-0.2.7-7.el6sat.noarch

- using errata.clone, following packages lands in the target channel:
   * spacewalk-koan-0.2.7-7.el5sat.noarch
   * spacewalk-koan-0.2.7-7.el6sat.noarch

API looks good (also if using user that cannot manage the target channel, using non-cloned channel, cloning several errata, ...).

VERIFIED with spacewalk-java-1.2.39-76.el6sat.noarch.

Notes:
 - the API call clones an erratum also if another errata clone is already associated with the target channel
 - when cloning more than 8 errata within the API, the API times out with: 503 Service Temporarily Unavailable

Comment 7 Pavel Novotny 2011-06-07 14:35:43 UTC
Moving to RELEASE_PENDING.
Re-verified with spacewalk-java-1.2.39-82.

Clone channel 'rhn-tools-rhel-x86_64-server-5' as channel 'testicek'.
Clone errata RHBA-2010:10260 into channel 'testicek'...

- using errata.clone():

Packages in target channel:
* spacewalk-koan-0.2.7-7.el5sat-noarch
* spacewalk-koan-0.2.7-7.el6sat-noarch

- using errata.cloneAsOriginal():

Packages in target channel:
* spacewalk-koan-0.2.7-7.el5sat-noarch

Comment 8 Clifford Perry 2011-06-17 02:34:49 UTC
An advisory has been issued which should help the problem
described in this bug report. This report is therefore being
closed with a resolution of ERRATA. For more information
on therefore solution and/or where to find the updated files,
please follow the link below. You may reopen this bug report
if the solution does not work for you.

https://rhn.redhat.com/errata/RHSA-2011-0879.html


Note You need to log in before you can comment on or make changes to this bug.