[yum-git] Makefile verifytree.py

Seth Vidal skvidal at linux.duke.edu
Mon Jul 7 15:54:07 UTC 2008


 Makefile      |    2 
 verifytree.py |  242 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 243 insertions(+), 1 deletion(-)

New commits:
commit 92dbd80d701a85ef9fd08353db53bdbd778fdb22
Author: Seth Vidal <skvidal at fedoraproject.org>
Date:   Mon Jul 7 11:52:13 2008 -0400

    add verifytree to yum-utils

diff --git a/Makefile b/Makefile
index 25ea61c..80a5673 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 SUBDIRS = docs
 PKGNAME = yum-utils
-UTILS = package-cleanup debuginfo-install repoclosure repomanage repoquery repo-graph repo-rss yumdownloader yum-builddep repotrack reposync repodiff yum-debug-dump
+UTILS = package-cleanup debuginfo-install repoclosure repomanage repoquery repo-graph repo-rss yumdownloader yum-builddep repotrack reposync repodiff yum-debug-dump verifytree
 UTILSROOT = yum-complete-transaction 
 VERSION=$(shell awk '/Version:/ { print $$2 }' ${PKGNAME}.spec)
 RELEASE=$(shell awk '/Release:/ { print $$2 }' ${PKGNAME}.spec)
diff --git a/verifytree.py b/verifytree.py
new file mode 100755
index 0000000..cebb039
--- /dev/null
+++ b/verifytree.py
@@ -0,0 +1,242 @@
+#!/usr/bin/python -tt
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# copyright (c) 2008 Red Hat, Inc - written by Seth Vidal and Will Woods
+
+import yum
+import sys
+import os
+from yum.misc import getCacheDir, checksum
+import urlparse
+from yum import Errors
+from optparse import OptionParser
+
+####
+# take a file path to a repo as an option, verify all the metadata vs repomd.xml
+# optionally go through packages and verify them vs the checksum in the primary
+
+# Error values
+BAD_REPOMD = 1
+BAD_METADATA = 2
+BAD_COMPS = 4
+BAD_PACKAGES = 8
+BAD_IMAGES = 16
+
+# Testopia case/plan numbers
+plan_number = 13
+case_numbers = {'REPODATA': 56, 'CORE_PACKAGES': 57, 'COMPS': 58, 
+                'BOOT_IMAGES': 59}
+
+# URL for the RELAX NG schema for comps
+SCHEMA='http://cvs.fedoraproject.org/viewcvs/*checkout*/comps/comps.rng'
+
+def testopia_create_run(plan):
+    '''Create a run of the given test plan. Returns the run ID.'''
+    run_id = 49 # STUB actually create the run
+    print "Testopia: created run %i of plan %i" % (run_id,plan)
+    return run_id
+
+def testopia_report(run,case,result):
+    print "  testopia: reporting %s for case %s in run %i" % (result,
+                                                              str(case),run)
+    if type(case) == str:
+        case = case_numbers[case]
+    # STUB actually do the reporting
+
+def checkfileurl(pkg):
+    pkg_path = pkg.remote_url
+    pkg_path = pkg_path.replace('file://', '')
+    (csum_type, csum) = pkg.returnIdSum()
+    
+    try:
+        filesum = checksum(csum_type, pkg_path)
+    except Errors.MiscError:
+        return False
+    
+    if filesum != csum:
+        return False
+    
+    return True
+
+
+def main():
+    parser = OptionParser()
+    parser.usage = """
+    verifytree - verify that a local yum repository is consistent
+    
+    verifytree /path/to/repo"""
+    
+    parser.add_option("-a","--checkall",action="store_true",default=False,
+            help="Check all packages in the repo")
+    parser.add_option("-t","--testopia",action="store",type="int",
+            help="Report results to the given testopia run number")
+    opts, args = parser.parse_args()
+    if not args: 
+        print "Must provide a file url to the repo"
+        sys.exit(1)
+    # FIXME: check that "args" is a valid dir before proceeding 
+    # (exists, isdir, contains .treeinfo, etc)
+
+    url = args[0]
+    if url[0] == '/':
+        url = 'file://' + url
+
+    s = urlparse.urlsplit(url)[0]
+    h,d = urlparse.urlsplit(url)[1:3]
+    if s != 'file':
+        print "Must be a file:// url or you will not like this"
+        sys.exit(1)
+    repoid = '%s/%s' % (h, d)
+    repoid = repoid.replace('/', '_')
+    # Bad things happen if we're missing a trailing slash here
+    if url[-1] != '/':
+        url += '/'
+
+    my = yum.YumBase()
+    my.conf.cachedir = getCacheDir()
+    my.repos.disableRepo('*')
+    newrepo = yum.yumRepo.YumRepository(repoid)
+    newrepo.name = repoid
+    newrepo.baseurl = [url]
+    newrepo.basecachedir = my.conf.cachedir
+    newrepo.metadata_expire = 0
+    newrepo.enablegroups = 1
+    # we want *all* metadata
+    newrepo.mdpolicy='group:all'
+
+    # add our new repo
+    my.repos.add(newrepo)
+    # enable that repo
+    my.repos.enableRepo(repoid)
+    # setup the repo dirs/etc
+    my.doRepoSetup(thisrepo=repoid)
+
+    # Initialize results and reporting
+    retval = 0 
+    if opts.testopia:
+        run_id = testopia_create_run(opts.testopia)
+        report = lambda case,result: testopia_report(run_id,case,result)
+    else:
+        report = lambda case,result: None
+
+    # Check boot images (independent of metadata)
+    print "Checking boot images:"
+    images_ok = True
+    basedir = url.replace('file://', '')
+    imagedir = basedir + 'images/'
+    for filename in ("boot.iso", "stage2.img"):
+        fullpath = imagedir + filename
+        try:
+            f = open(fullpath)
+            data = f.read(1024)
+            f.close()
+            if len(data) < 1024:
+                raise IOError
+            print "  verifying %s is a non-empty file" % filename
+        except IOError, OSError:
+            print "  verifying %s FAILED: missing or unreadable" % filename
+            images_ok = False
+
+    if images_ok:
+        report('BOOT_IMAGES','PASSED')
+    else:
+        report('BOOT_IMAGES','FAILED')
+        retval = retval | BAD_IMAGES
+
+
+    # Check the metadata
+    print "Checking repodata:"
+    try:
+        md_types = newrepo.repoXML.fileTypes()
+        print "  verifying repomd.xml with yum"
+    except yum.Errors.RepoError:
+        print "  failed to load repomd.xml."
+        report('REPODATA','FAILED')
+        report('CORE_PACKAGES','BLOCKED')
+        report('COMPS','BLOCKED')
+        return retval | BAD_REPOMD
+
+    for md_type in md_types:
+        try:
+            print "  verifying %s checksum" % md_type
+            newrepo.retrieveMD(md_type)
+        except Errors.RepoError, e:
+            print "  %s metadata missing or does not match checksum" % md_type
+            retval = retval | BAD_METADATA
+    if retval & BAD_METADATA:
+        report('REPODATA','FAILED')
+    else:
+        report('REPODATA','PASSED')
+
+    print "Checking groups (comps.xml):"
+    try:
+        print "  verifying comps.xml with yum"
+        b = my.comps.compscount
+    except Errors.GroupsError, e:
+        print '  comps file missing or unparseable'
+        report('COMPS','FAILED')
+        retval = retval | BAD_COMPS
+
+    if not (retval & BAD_COMPS):
+        print "  verifying comps.xml grammar with xmllint"
+        comps=newrepo.getGroups()
+        r = os.system("xmllint --noout --nowarning --relaxng %s %s" % 
+            (SCHEMA,comps))
+        if r != 0:
+            retval = retval | BAD_COMPS
+            report('COMPS','FAILED')
+        else:
+            report('COMPS','PASSED')
+
+    sack = []
+    packages_ok = True
+    if opts.checkall:
+        print "Checking all packages"
+        sack = my.pkgSack
+    elif not (retval & BAD_COMPS):
+        print "Checking mandatory @core packages"
+        group = my.comps.return_group('core')
+        for pname in group.mandatory_packages:
+            # FIXME: this pulls from pkgSack, which (I guess) is populated 
+            # based on the arch etc. of the current host.. so you can't check
+            # the x86_64 repo from an i386 machine, f'rinstance.
+            try:
+                sack.extend(my.pkgSack.searchNevra(name=pname))
+            except yum.Errors.RepoError:
+                print "  something went wrong with the repodata."
+                sack = []
+                break
+    for pkg in sack:
+        if checkfileurl(pkg):
+            print "  verifying %s checksum" % pkg
+        else:
+            print "  verifying %s checksum FAILED" % pkg
+            packages_ok = False
+    if sack:
+        if packages_ok is True:
+            report('CORE_PACKAGES','PASSED')
+        else:
+            report('CORE_PACKAGES','FAILED')
+            retval = retval | BAD_PACKAGES
+    else: 
+        # we couldn't test anything
+        report('CORE_PACKAGES','BLOCKED')
+    # All done!
+    if retval == 0:
+        print "Tree verified."
+    return retval
+
+if __name__ == "__main__":
+    r = main()
+    sys.exit(r)



More information about the Yum-cvs-commits mailing list