backend/common/rhnRepository.py | 2 backend/satellite_tools/reposync.py | 4 backend/satellite_tools/satCerts.py | 2 backend/satellite_tools/satComputePkgHeaders.py | 2 backend/satellite_tools/satsync.py | 2 backend/satellite_tools/updatePackages.py | 2 backend/server/handlers/app/rhn_mpm.py | 2 backend/server/handlers/applet/applet.py | 2 backend/server/handlers/xmlrpc/up2date.py | 2 backend/server/handlers/xp/rhnlint.py | 2 backend/server/importlib/backend.py | 2 backend/server/importlib/packageUpload.py | 2 backend/server/rhnChannel.py | 2 backend/server/rhnPackageUpload.py | 2 backend/server/rhnServer/server_class.py | 2 backend/server/rhnServer/server_packages.py | 2 backend/setup.py | 17 backend/spacewalk-backend.spec | 28 + backend/spacewalk/common/rhn_mpm.py | 283 ++++++++++++++ backend/spacewalk/common/rhn_rpm.py | 462 +++++++++++++++++++++++ client/rhel/rhnlib/rhn/common/rhn_mpm.py | 283 -------------- client/rhel/rhnlib/rhn/common/rhn_rpm.py | 462 ----------------------- client/rhel/rhnlib/setup.py.in | 2 client/tools/rhnpush/rhnpush.spec | 3 rel-eng/packages/spacewalk-backend | 2 spacewalk/certs-tools/spacewalk-certs-tools.spec | 2 26 files changed, 810 insertions(+), 768 deletions(-)
New commits: commit 30efa10c87fd46087fb8e40031930ef3a5d4acab Author: Michael Mraka michael.mraka@redhat.com Date: Mon Dec 7 16:58:59 2009 +0100
Automatic commit of package [spacewalk-backend] release [0.8.3-1].
diff --git a/backend/spacewalk-backend.spec b/backend/spacewalk-backend.spec index 9ec125a..666f2ad 100644 --- a/backend/spacewalk-backend.spec +++ b/backend/spacewalk-backend.spec @@ -8,7 +8,7 @@ Name: spacewalk-backend Summary: Common programs needed to be installed on the Spacewalk servers/proxies Group: Applications/Internet License: GPLv2 -Version: 0.8.2 +Version: 0.8.3 Release: 1%{?dist} URL: https://fedorahosted.org/spacewalk Source0: https://fedorahosted.org/releases/s/p/spacewalk/%%7Bname%7D-%%7Bversion%7D.t... @@ -598,6 +598,10 @@ rm -f %{rhnconf}/rhnSecret.py*
# $Id$ %changelog +* Mon Dec 07 2009 Michael Mraka michael.mraka@redhat.com 0.8.3-1 +- moved code from rhnlib to spacewalk-backend-libs +- 543509 - do not fail if machine has not uuid set (like qemu) + * Fri Dec 4 2009 Miroslav Suchý msuchy@redhat.com 0.8.2-1 - sha256 support
diff --git a/rel-eng/packages/spacewalk-backend b/rel-eng/packages/spacewalk-backend index ce9e292..77b6c0e 100644 --- a/rel-eng/packages/spacewalk-backend +++ b/rel-eng/packages/spacewalk-backend @@ -1 +1 @@ -0.8.2-1 backend/ +0.8.3-1 backend/
commit 40ea2292cd2cc20ff4414998addbcb606e9f75ac Author: Michael Mraka michael.mraka@redhat.com Date: Mon Dec 7 16:57:43 2009 +0100
updated namespace of common/rhn_rpm
diff --git a/backend/common/rhnRepository.py b/backend/common/rhnRepository.py index e112c1f..a52edda 100644 --- a/backend/common/rhnRepository.py +++ b/backend/common/rhnRepository.py @@ -21,7 +21,7 @@ import string import cStringIO from rhn import rpclib
-from rhn.common import rhn_rpm +from spacewalk.common import rhn_rpm
# local imports import rhnFlags diff --git a/backend/satellite_tools/reposync.py b/backend/satellite_tools/reposync.py index 7640fcd..8006b08 100644 --- a/backend/satellite_tools/reposync.py +++ b/backend/satellite_tools/reposync.py @@ -18,8 +18,8 @@ from optparse import OptionParser from common import rhnLib from server import rhnPackage, rhnSQL, rhnChannel, rhnPackageUpload from common import CFG, initCFG, rhnLog, fetchTraceback -from rhn.common import rhn_rpm -from rhn.common.rhn_mpm import InvalidPackageError +from spacewalk.common import rhn_rpm +from spacewalk.common.rhn_mpm import InvalidPackageError from server.importlib.importLib import IncompletePackage from server.importlib.backendOracle import OracleBackend from server.importlib.packageImport import ChannelPackageSubscription diff --git a/backend/satellite_tools/satCerts.py b/backend/satellite_tools/satCerts.py index daaf741..554023b 100644 --- a/backend/satellite_tools/satCerts.py +++ b/backend/satellite_tools/satCerts.py @@ -28,7 +28,7 @@ from server import rhnSQL from server.rhnServer import satellite_cert from common.rhnTB import fetchTraceback from common.rhnConfig import RHNOptions -from rhn.common.rhn_rpm import getInstalledHeader +from spacewalk.common.rhn_rpm import getInstalledHeader
# # RHN certificate section diff --git a/backend/satellite_tools/satComputePkgHeaders.py b/backend/satellite_tools/satComputePkgHeaders.py index 54d1ff7..7751a2d 100644 --- a/backend/satellite_tools/satComputePkgHeaders.py +++ b/backend/satellite_tools/satComputePkgHeaders.py @@ -55,7 +55,7 @@ sys.modules["_apache"] = sys.modules["__main__"]
from server import rhnSQL -from rhn.common import rhn_rpm +from spacewalk.common import rhn_rpm
options_table = [ Option("-v", "--verbose", action="count", diff --git a/backend/satellite_tools/satsync.py b/backend/satellite_tools/satsync.py index 106468d..4e5112a 100644 --- a/backend/satellite_tools/satsync.py +++ b/backend/satellite_tools/satsync.py @@ -31,7 +31,7 @@ from optparse import Option, OptionParser # __rhn imports__ from common import CFG, initCFG, initLOG, Traceback, rhnMail, \ rhnLib, rhnFlags -from rhn.common import rhn_rpm +from spacewalk.common import rhn_rpm
from server import rhnSQL from server.rhnSQL import SQLError, SQLSchemaError, SQLConnectError diff --git a/backend/satellite_tools/updatePackages.py b/backend/satellite_tools/updatePackages.py index be6c0a5..af57b3f 100644 --- a/backend/satellite_tools/updatePackages.py +++ b/backend/satellite_tools/updatePackages.py @@ -26,7 +26,7 @@ sys.path.append('/usr/share/rhn')
from optparse import Option, OptionParser from common import rhnLib, rhnLog, initLOG, CFG, initCFG -from rhn.common import rhn_rpm +from spacewalk.common import rhn_rpm from server.rhnLib import parseRPMFilename from server import rhnSQL from server.rhnServer import server_packages diff --git a/backend/server/handlers/app/rhn_mpm.py b/backend/server/handlers/app/rhn_mpm.py index d1a2859..63d75ea 100644 --- a/backend/server/handlers/app/rhn_mpm.py +++ b/backend/server/handlers/app/rhn_mpm.py @@ -63,7 +63,7 @@ def load_rpm(stream, seekable=1): # Hmm, maybe an rpm
try: - from rhn.common import rhn_rpm + from spacewalk.common import rhn_rpm except ImportError: raise InvalidPackageError
diff --git a/backend/server/handlers/applet/applet.py b/backend/server/handlers/applet/applet.py index 956ae2f..a485eb3 100644 --- a/backend/server/handlers/applet/applet.py +++ b/backend/server/handlers/applet/applet.py @@ -21,7 +21,7 @@ import random # common modules imports from common import rhnCache, rhnFlags, log_debug, CFG, rhnFault from common.rhnTranslate import _ -from rhn.common import rhn_rpm +from spacewalk.common import rhn_rpm
# server modules imports from server import rhnChannel, rhnSQL, rhnHandler, rhnLib diff --git a/backend/server/handlers/xmlrpc/up2date.py b/backend/server/handlers/xmlrpc/up2date.py index 5f09b87..dae8fd6 100644 --- a/backend/server/handlers/xmlrpc/up2date.py +++ b/backend/server/handlers/xmlrpc/up2date.py @@ -26,7 +26,7 @@ from types import ListType, TupleType, StringType, IntType # common module imports from common import CFG, rhnFlags, rhnFault, log_debug, log_error from common.rhnTranslate import _ -from rhn.common import rhn_rpm +from spacewalk.common import rhn_rpm
# local module imports from server.rhnLib import computeSignature diff --git a/backend/server/handlers/xp/rhnlint.py b/backend/server/handlers/xp/rhnlint.py index 236da62..b20ff1c 100644 --- a/backend/server/handlers/xp/rhnlint.py +++ b/backend/server/handlers/xp/rhnlint.py @@ -19,7 +19,7 @@ import time import string
from common import RPC_Base, log_debug -from rhn.common import rhn_rpm +from spacewalk.common import rhn_rpm
from server import rhnSQL
diff --git a/backend/server/importlib/backend.py b/backend/server/importlib/backend.py index c3e1b58..1975a86 100644 --- a/backend/server/importlib/backend.py +++ b/backend/server/importlib/backend.py @@ -23,7 +23,7 @@ import re import sys
from common import rhnFault, CFG -from rhn.common import rhn_rpm +from spacewalk.common import rhn_rpm from server import rhnSQL, rhnChannel, taskomatic from importLib import Diff, Package, IncompletePackage, Erratum, \ AlreadyUploadedError, InvalidPackageError, TransactionError, \ diff --git a/backend/server/importlib/packageUpload.py b/backend/server/importlib/packageUpload.py index 1accd58..61c8b5b 100644 --- a/backend/server/importlib/packageUpload.py +++ b/backend/server/importlib/packageUpload.py @@ -18,7 +18,7 @@ #
from common import rhnFault, log_debug -from rhn.common import rhn_rpm +from spacewalk.common import rhn_rpm
from server import rhnChannel, taskomatic, rhnSQL from server.importlib.headerSource import createPackage diff --git a/backend/server/rhnChannel.py b/backend/server/rhnChannel.py index e8d875f..e38d3ea 100644 --- a/backend/server/rhnChannel.py +++ b/backend/server/rhnChannel.py @@ -25,7 +25,7 @@ from types import IntType, ListType, DictType from common import log_debug, log_error, rhnFault, rhnException, rhnCache, rhnFlags, CFG from common.rhnTranslate import _ from common.rhnLib import startswith -from rhn.common import rhn_rpm +from spacewalk.common import rhn_rpm from rhnServer import server_lib from rhnDependency import MakeEvrError
diff --git a/backend/server/rhnPackageUpload.py b/backend/server/rhnPackageUpload.py index 6161a54..547bbf4 100644 --- a/backend/server/rhnPackageUpload.py +++ b/backend/server/rhnPackageUpload.py @@ -19,7 +19,7 @@ import os import tempfile
from common import CFG, log_debug, rhnFault, rhn_mpm, rhnLib, UserDictCase -from rhn.common.rhn_rpm import get_header_byte_range +from spacewalk.common.rhn_rpm import get_header_byte_range
from server import rhnSQL from server.importlib import importLib, userAuth, mpmSource, backendOracle, \ diff --git a/backend/server/rhnServer/server_class.py b/backend/server/rhnServer/server_class.py index dead358..3083b1a 100644 --- a/backend/server/rhnServer/server_class.py +++ b/backend/server/rhnServer/server_class.py @@ -23,7 +23,7 @@ import string from common import rhnException, rhnFault, log_debug, log_error, CFG from common import rhnFlags from common.rhnTranslate import _ -from rhn.common import rhn_rpm +from spacewalk.common import rhn_rpm
# from the server stuff... from server import rhnChannel, rhnUser, rhnSQL, rhnLib, rhnAction, \ diff --git a/backend/server/rhnServer/server_packages.py b/backend/server/rhnServer/server_packages.py index 2e71f64..327a342 100644 --- a/backend/server/rhnServer/server_packages.py +++ b/backend/server/rhnServer/server_packages.py @@ -23,7 +23,7 @@ import time from types import DictType, TupleType
from common import log_debug, rhnFault -from rhn.common import rhn_rpm +from spacewalk.common import rhn_rpm from server import rhnSQL, rhnLib from server_lib import snapshot_server, check_entitlement
commit 68c4f75bc0f3cec80c6066f5a6bc0dc4ef6d0d28 Author: Michael Mraka michael.mraka@redhat.com Date: Mon Dec 7 16:56:21 2009 +0100
create setup.py to properly setup & install things from backend/spacewalk
diff --git a/backend/setup.py b/backend/setup.py new file mode 100644 index 0000000..ecb8896 --- /dev/null +++ b/backend/setup.py @@ -0,0 +1,17 @@ +#!/usr/bin/python +# +# setup of spacewalk-backend-libs +# + +from distutils.core import setup +import os + +setup(name = os.environ["PYTHON_MODULE_NAME"], + version = os.environ["PYTHON_MODULE_VERSION"], + description = "Python libraries for the Spacewalk project", + long_description = """A collection of python modules used by the +Spacewalk (http://spacewalk.redhat.com) software.""", + url = 'http://spacewalk.redhat.com', + packages = ["spacewalk/common"], + license = "GPL", + ) diff --git a/backend/spacewalk-backend.spec b/backend/spacewalk-backend.spec index 4a81558..9ec125a 100644 --- a/backend/spacewalk-backend.spec +++ b/backend/spacewalk-backend.spec @@ -2,6 +2,7 @@ %define rhnconf %{_sysconfdir}/rhn %define httpdconf %{rhnconf}/satellite-httpd/conf %define apacheconfd %{_sysconfdir}/httpd/conf.d +%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
Name: spacewalk-backend Summary: Common programs needed to be installed on the Spacewalk servers/proxies @@ -237,12 +238,18 @@ XXX To be determined if the proper location is under backend
%build make -f Makefile.backend all +export PYTHON_MODULE_NAME=%{name} +export PYTHON_MODULE_VERSION=%{version} +%{__python} setup.py build
%install rm -rf $RPM_BUILD_ROOT install -d $RPM_BUILD_ROOT/%{rhnroot} make -f Makefile.backend install PREFIX=$RPM_BUILD_ROOT ROOT=%{rhnroot} \ MANDIR=%{_mandir} +export PYTHON_MODULE_NAME=%{name} +export PYTHON_MODULE_VERSION=%{version} +%{__python} setup.py install -O1 --root $RPM_BUILD_ROOT --prefix=%{_prefix}
%clean rm -rf $RPM_BUILD_ROOT @@ -455,8 +462,8 @@ rm -f %{rhnconf}/rhnSecret.py*
%files libs %defattr(-,root,root) -%dir %{rhnroot}/spacewalk/ - +%{python_sitelib}/spacewalk/ +%{python_sitelib}/spacewalk*egg-info
%files config-files-common %defattr(-,root,root)
commit 370ca2d811ffc369839325cc1e9f0ff9fe839915 Author: Michael Mraka michael.mraka@redhat.com Date: Mon Dec 7 16:50:25 2009 +0100
moved code from rhnlib to spacewalk-backend-libs
well, one more move of rhn_rpm/rhn_mpm - this code is shared between server and tools so it's better to put them into some spacewalk driven repo/package instead of rhnlib which is part of RHEL/Fedora
diff --git a/backend/spacewalk-backend.spec b/backend/spacewalk-backend.spec index 0fbf099..4a81558 100644 --- a/backend/spacewalk-backend.spec +++ b/backend/spacewalk-backend.spec @@ -16,7 +16,8 @@ BuildArch: noarch Requires: python, rpm-python # /etc/rhn is provided by spacewalk-proxy-common or by spacewalk-config Requires: /etc/rhn -Requires: rhnlib >= 2.5.16 +Requires: rhnlib >= 1.8 +Requires: %{name}-libs = %{version}-%{release} BuildRequires: /usr/bin/msgfmt BuildRequires: /usr/bin/docbook2man BuildRequires: docbook-utils @@ -139,6 +140,13 @@ receivers and get them enabled automatically.
This package contains listener for the Server XML dumper.
+%package libs +Summary: Spacewalk server and client tools libraries +Group: Applications/Internet + +%description libs +Libraries required by both Spacewalk server and Spacewalk client tools. + %package config-files-common Summary: Common files for the Configuration Management project Group: Applications/Internet @@ -445,6 +453,11 @@ rm -f %{rhnconf}/rhnSecret.py* %attr(640,root,apache) %{rhnconf}/default/rhn_server_satexport_internal.conf
+%files libs +%defattr(-,root,root) +%dir %{rhnroot}/spacewalk/ + + %files config-files-common %defattr(-,root,root) %{rhnroot}/server/configFilesHandler.py* diff --git a/backend/spacewalk/common/rhn_mpm.py b/backend/spacewalk/common/rhn_mpm.py new file mode 100644 index 0000000..0d339d8 --- /dev/null +++ b/backend/spacewalk/common/rhn_mpm.py @@ -0,0 +1,283 @@ +# +# Copyright (c) 2008 Red Hat, Inc. +# +# This software is licensed to you under the GNU General Public License, +# version 2 (GPLv2). There is NO WARRANTY for this software, express or +# implied, including the implied warranties of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 +# along with this software; if not, see +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. +# +# Red Hat trademarks are not licensed under GPLv2. No permission is +# granted to use or replicate Red Hat trademarks that are incorporated +# in this software or its documentation. +# + +import os +import gzip +import cStringIO +import tempfile +from rhn.rpclib import xmlrpclib + +import struct + +from types import ListType, TupleType, DictType + +def labelCompare(l1, l2): + try: + import rhn_rpm + except ImportError: + # rhn_rpm not avalable; return a dummy comparison function + return -1 + return rhn_rpm.labelCompare(l1, l2) + +def get_package_header(filename=None, file=None, fd=None): + return load(filename=filename, file=file, fd=fd)[0] + +# Loads an MPM and returns its header and its payload +def load(filename=None, file=None, fd=None): + if (filename is None and file is None and fd is None): + raise ValueError, "No parameters passed" + + if filename is not None: + f = open(filename) + elif file is not None: + f = file + else: # fd is not None + f = os.fdopen(os.dup(fd), "r") + + f.seek(0, 0) + + p = MPM_Package() + try: + p.load(f) + except InvalidPackageError, e: + try: + return load_rpm(f) + except InvalidPackageError: + raise e + + return p.header, p.payload_stream + +def load_rpm(stream): + # Hmm, maybe an rpm + + try: + import rhn_rpm + except ImportError: + raise InvalidPackageError + + # Dup the file descriptor, we don't want it to get closed before we read + # the payload + newfd = os.dup(stream.fileno()) + stream = os.fdopen(newfd, "r") + + stream.flush() + stream.seek(0, 0) + + try: + header = rhn_rpm.get_package_header(file=stream) + except rhn_rpm.InvalidPackageError, e: + raise apply(InvalidPackageError, e.args) + except rhn_rpm.error, e: + raise InvalidPackageError(e) + stream.seek(0, 0) + + return header, stream + +class MPM_Header: + "Wrapper class for an mpm header - we need to store a flag is_source" + def __init__(self, hdr): + self.hdr = hdr + self.is_source = hdr.get('is_source') + self.packaging = 'mpm' + self.signatures = [] + + def __getitem__(self, name): + return self.hdr.get(name) + + def __setitem__(self, name, item): + self.hdr[name] = item + + def __delitem__(self, name): + del self.hdr[name] + + def __getattr__(self, name): + return getattr(self.hdr, name) + + def is_signed(self): + return 0 + +class InvalidPackageError(Exception): + pass + +MPM_HEADER_COMPRESSED_GZIP = 1 +MPM_PAYLOAD_COMPRESSED_GZIP = 1 + +class MPM_Package: + _lead_format = '!16sB3s4L92s' + _magic = 'mpmpackage012345' + def __init__(self): + self.header = None + self.payload_stream = None + self.header_flags = MPM_HEADER_COMPRESSED_GZIP + self.payload_flags = 0 + assert(len(self._magic) == 16) + self._buffer_size = 16384 + + def _read_lead(self, stream): + # Lead has the following format: + # 16 bytes magic + # 1 bytes version + # 3 bytes unused + # 4 bytes header flags + # 4 bytes payload flags + # 4 bytes header length + # 4 bytes payload length + # 92 bytes padding to 128 bytes + lead = self._read_bytes(stream, 128) + if len(lead) != 128: + raise InvalidPackageError() + + arr = struct.unpack(self._lead_format, lead) + return arr + + def load(self, input_stream): + # Clean up + self.__init__() + arr = self._read_lead(input_stream) + magic = arr[0] + if magic != self._magic: + raise InvalidPackageError() + header_len, payload_len = int(arr[5]), int(arr[6]) + header_flags, payload_flags = arr[3], arr[4] + file_size = 128 + header_len + payload_len + input_stream.seek(file_size) + if file_size != input_stream.tell(): + raise InvalidPackageError() + # Read the header + input_stream.seek(128, 0) + header_data = self._read_bytes(input_stream, header_len) + payload_stream = tempfile.TemporaryFile() + self.stream_copy(input_stream, payload_stream) + + self._read_header(header_data, header_flags) + self._read_payload(payload_stream, payload_flags) + + def _read_bytes(self, stream, amt): + ret = "" + while amt: + buf = stream.read(min(amt, self._buffer_size)) + if not buf: + return ret + ret = ret + buf + amt = amt - len(buf) + return ret + + def _read_header(self, header_data, header_flags): + if header_flags & MPM_HEADER_COMPRESSED_GZIP: + t = cStringIO.StringIO(header_data) + g = gzip.GzipFile(None, "r", 0, t) + header_data = g.read() + g.close() + t.close() + + try: + params, foo = xmlrpclib.loads(header_data) + except: + # XXX + raise + + self.header = MPM_Header(params[0]) + + def _read_payload(self, payload_stream, payload_flags): + payload_stream.seek(0, 0) + if payload_flags & MPM_PAYLOAD_COMPRESSED_GZIP: + g = gzip.GzipFile(None, "r", 0, payload_stream) + t = tempfile.TemporaryFile() + self.stream_copy(g, t) + g.close() + payload_stream = t + + self.payload_stream = payload_stream + + def write(self, output_stream): + if self.header is None: + raise Exception() + + header_stream, header_size = self._encode_header() + payload_stream, payload_size = self._encode_payload() + + lead_arr = (self._magic, 1, "\0" * 3, self.header_flags, + self.payload_flags, header_size, payload_size, '\0' * 92) + # lead + lead = apply(struct.pack, (self._lead_format, ) + lead_arr) + output_stream.write(lead) + self.stream_copy(header_stream, output_stream) + self.stream_copy(payload_stream, output_stream) + + def add_header_flag(self, flag): + self.header_flags = self.header_flags | flag + + def add_payload_flag(self, flag): + self.payload_flags = self.payload_flags | flag + + def reset_header_flags(self): + self.header_flags = 0 + + def reset_payload_flags(self): + self.payload_flags = 0 + + def _encode_header(self): + assert(self.header is not None) + stream = tempfile.TemporaryFile() + data = xmlrpclib.dumps((_replace_null(self.header), )) + if self.header_flags & MPM_HEADER_COMPRESSED_GZIP: + f = gzip.GzipFile(None, "wb", 9, stream) + f.write(data) + f.close() + else: + stream.write(data) + stream.flush() + stream.seek(0, 2) + size = stream.tell() + stream.seek(0, 0) + return stream, size + + def _encode_payload(self): + assert(self.payload_stream is not None) + stream = tempfile.TemporaryFile() + if self.payload_flags & MPM_PAYLOAD_COMPRESSED_GZIP: + f = gzip.GzipFile(None, "wb", 9, stream) + self.stream_copy(self.payload_stream, f) + f.close() + else: + stream = self.payload_stream + stream.flush() + stream.seek(0, 2) + size = stream.tell() + stream.seek(0, 0) + return stream, size + + def stream_copy(self, source, dest): + "Copies data from the source stream to the destination stream" + while 1: + buf = source.read(self._buffer_size) + if not buf: + break + dest.write(buf) + + +def _replace_null(obj): + if obj is None: + return '' + if isinstance(obj, ListType): + return map(_replace_null, obj) + if isinstance(obj, TupleType): + return tuple(_replace_null(list(obj))) + if hasattr(obj, 'items'): + dict = {} + for k, v in obj.items(): + dict[_replace_null(k)] = _replace_null(v) + return dict + return obj diff --git a/backend/spacewalk/common/rhn_rpm.py b/backend/spacewalk/common/rhn_rpm.py new file mode 100644 index 0000000..349388a --- /dev/null +++ b/backend/spacewalk/common/rhn_rpm.py @@ -0,0 +1,462 @@ +# +# Copyright (c) 2008 Red Hat, Inc. +# +# This software is licensed to you under the GNU General Public License, +# version 2 (GPLv2). There is NO WARRANTY for this software, express or +# implied, including the implied warranties of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 +# along with this software; if not, see +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. +# +# Red Hat trademarks are not licensed under GPLv2. No permission is +# granted to use or replicate Red Hat trademarks that are incorporated +# in this software or its documentation. +# + +import os +import sys +import rpm +import struct + +import exceptions +if not hasattr(exceptions, 'StopIteration'): + # Presumably python 1.5.2 + class StopIteration(Exception): + pass + +# Expose a bunch of useful constants from rpm +error = rpm.error +for sym, val in rpm.__dict__.items(): + if sym[:3] == 'RPM': + # A constant, probably - import it into our namespace + globals()[sym] = val +del sym, val + +# need this for rpm-pyhon < 4.6 (e.g. on RHEL5) +rpm.RPMTAG_FILEDIGESTALGO = 5011 + +# these values are taken from /usr/include/rpm/rpmpgp.h +# PGPHASHALGO_MD5 = 1, /*!< MD5 */ +# PGPHASHALGO_SHA1 = 2, /*!< SHA1 */ +# PGPHASHALGO_RIPEMD160 = 3, /*!< RIPEMD160 */ +# PGPHASHALGO_MD2 = 5, /*!< MD2 */ +# PGPHASHALGO_TIGER192 = 6, /*!< TIGER192 */ +# PGPHASHALGO_HAVAL_5_160 = 7, /*!< HAVAL-5-160 */ +# PGPHASHALGO_SHA256 = 8, /*!< SHA256 */ +# PGPHASHALGO_SHA384 = 9, /*!< SHA384 */ +# PGPHASHALGO_SHA512 = 10, /*!< SHA512 */ +PGPHASHALGO = { + 1: 'md5', + 2: 'sha1', + 3: 'ripemd160', + 5: 'md2', + 6: 'tiger192', + 7: 'haval-5-160', + 8: 'sha256', + 9: 'sha384', + 10: 'sha512', +} + + +class InvalidPackageError(Exception): + pass + +# wrapper/proxy class for rpm.Transaction so we can +# instrument it, etc easily +class RPMTransaction: + read_only = 0 + def __init__(self): + if hasattr(rpm, 'opendb'): + db = getattr(rpm, 'opendb')(not self.read_only) + self.ts = rpm.TransactionSet('/', db) + else: + self.ts = rpm.TransactionSet() + self.tsflags = [] + # For rpm 4.0.4 + self._flags = 0 + self._prob_filter = 0 + + def __getattr__(self, attr): + return getattr(self.ts, attr) + + def getMethod(self, method): + # in theory, we can override this with + # profile/etc info + return getattr(self.ts, method) + + # push/pop methods so we don't lose the previous + # set value, and we can potentially debug a bit + # easier + def pushVSFlags(self, flags): + self.tsflags.append(flags) + if hasattr(self.ts, 'setVSFlags'): + f = getattr(self.ts, 'setVSFlags') + f(self.tsflags[-1]) + + def popVSFlags(self): + del self.tsflags[-1] + if hasattr(self.ts, 'setVSFlags'): + f = getattr(self.ts, 'setVSFlags') + f(self.tsflags[-1]) + + def addInstall(self, arg1, arg2, mode): + """Install a package""" + hdr = arg1.hdr + if hasattr(self.ts, 'addInstall'): + f = getattr(self.ts, 'addInstall') + return f(hdr, arg2, mode) + return self.ts.add(hdr, arg2, mode) + + def addErase(self, arg1): + """Erase a package""" + hdr = arg1.hdr + if hasattr(self.ts, 'addErase'): + f = getattr(self.ts, 'addErase') + return f(hdr) + return self.ts.add(hdr, hdr, "e") + + def check(self): + """Check dependencies""" + if hasattr(self.ts, 'check'): + f = getattr(self.ts, 'check') + else: + f = getattr(self.ts, 'depcheck') + return f() + + def setFlags(self, flag): + """Set transaction flags""" + if hasattr(rpm, 'headerFromPackage'): + # Old style rpm + old_flags = self._flags + self._flags = flag + return old_flags + return self.ts.setFlags(flag) + + def setProbFilter(self, flag): + """Set problem flags""" + if hasattr(rpm, 'headerFromPackage'): + # Old style rpm + old_flags = self._prob_filter + self._prob_filter = flag + return old_flags + return self.ts.setProbFilter(flag) + + def run(self, callback, user_data): + if hasattr(rpm, 'headerFromPackage'): + # Old style rpm + return self.ts.run(self._flags, self._prob_filter, callback, + user_data) + return self.ts.run(callback, user_data) + + + + +class SharedStateTransaction: + _shared_state = {} + + def __init__(self): + self.__dict__ = self._shared_state + +class RPMReadOnlyTransaction(SharedStateTransaction, RPMTransaction): + read_only = 1 + def __init__(self): + SharedStateTransaction.__init__(self) + if not hasattr(self, 'ts'): + RPMTransaction.__init__(self) + # FIXME: replace with macro defination + self.pushVSFlags(8) + +class RPM_Header: + "Wrapper class for an rpm header - we need to store a flag is_source" + def __init__(self, hdr, is_source=None): + self.hdr = hdr + self.is_source = is_source + self.packaging = 'rpm' + self.signatures = [] + self._extract_signatures() + + def __getitem__(self, name): + return self.hdr[name] + + def __getattr__(self, name): + return getattr(self.hdr, name) + + def checksum_type(self): + if self.hdr[rpm.RPMTAG_FILEDIGESTALGO] \ + and PGPHASHALGO.has_key(self.hdr[rpm.RPMTAG_FILEDIGESTALGO]): + checksum_type = PGPHASHALGO[self.hdr[rpm.RPMTAG_FILEDIGESTALGO]] + else: + checksum_type = 'md5' + return checksum_type + + def is_signed(self): + if hasattr(rpm, "RPMTAG_DSAHEADER"): + dsaheader = self.hdr["dsaheader"] + else: + dsaheader = 0 + if self.hdr["siggpg"] or self.hdr["sigpgp"] or dsaheader: + return 1 + return 0 + + def _extract_signatures(self): + header_tags = [ + [rpm.RPMTAG_DSAHEADER, "dsa"], + [rpm.RPMTAG_RSAHEADER, "rsa"], + [rpm.RPMTAG_SIGGPG, "gpg"], + [rpm.RPMTAG_SIGPGP, 'pgp'], + ] + for ht, sig_type in header_tags: + ret = self.hdr[ht] + if not ret or len(ret) < 17: + continue + # Get the key id - hopefully we get it right + key_id = ret[9:17] + key_id_len = len(key_id) + format = "%dB" % key_id_len + t = struct.unpack(format, key_id) + format = "%02x" * key_id_len + key_id = format % t + self.signatures.append({ + 'signature_type' : sig_type, + 'key_id' : key_id, + 'signature' : ret, + }) + +def get_header_byte_range(package_file): + """ + Return the start and end bytes of the rpm header object. + + For details of the rpm file format, see: + http://www.rpm.org/max-rpm/s1-rpm-file-format-rpm-file-format.html + """ + + lead_size = 96 + + # Move past the rpm lead + package_file.seek(lead_size) + + sig_size = get_header_struct_size(package_file) + + # Now we can find the start of the actual header. + header_start = lead_size + sig_size + + package_file.seek(header_start) + + header_size = get_header_struct_size(package_file) + + header_end = header_start + header_size + + return (header_start, header_end) + +def get_header_struct_size(package_file): + """ + Compute the size in bytes of the rpm header struct starting at the current + position in package_file. + """ + # Move past the header preamble + package_file.seek(8, 1) + + # Read the number of index entries + header_index = package_file.read(4) + (header_index_value, ) = struct.unpack('>I', header_index) + + # Read the the size of the header data store + header_store = package_file.read(4) + (header_store_value, ) = struct.unpack('>I', header_store) + + # The total size of the header. Each index entry is 16 bytes long. + header_size = 8 + 4 + 4 + header_index_value * 16 + header_store_value + + # Headers end on an 8-byte boundary. Round out the extra data. + round_out = header_size % 8 + if round_out != 0: + header_size = header_size + (8 - round_out) + + return header_size + +# Loads the package header from a file / stream / file descriptor +# Raises rpm.error if an error is found, or InvalidPacageError if package is +# busted +# XXX Deal with exceptions better +def get_package_header(filename=None, file=None, fd=None): + if (filename is None and file is None and fd is None): + raise ValueError, "No parameters passed" + + if filename is not None: + f = open(filename) + elif file is not None: + f = file + f.seek(0, 0) + else: # fd is not None + f = None + + if f is None: + os.lseek(fd, 0, 0) + file_desc = fd + else: + file_desc = f.fileno() + + if hasattr(rpm, 'headerFromPackage'): + hdr, is_source = rpm.headerFromPackage(file_desc) + if hdr is None: + raise InvalidPackageError + else: + if hasattr(rpm, 'readHeaderFromFD'): + header_start, header_end = \ + get_header_byte_range(os.fdopen(os.dup(file_desc))) + os.lseek(file_desc, header_start, 0) + hdr, offset = rpm.readHeaderFromFD(file_desc) + else: + # RHEL-4 and older, do the old way + ts = RPMReadOnlyTransaction() + nomd5 = getattr(rpm, 'RPMVSF_NOMD5') + needpayload = getattr(rpm, 'RPMVSF_NEEDPAYLOAD') + ts.pushVSFlags(~(nomd5 | needpayload)) + hdr = RPMReadOnlyTransaction().hdrFromFdno(file_desc) + ts.popVSFlags() + if hdr is None: + raise InvalidPackageError + is_source = hdr[getattr(rpm, 'RPMTAG_SOURCEPACKAGE')] + + return RPM_Header(hdr, is_source) + +class MatchIterator: + def __init__(self, tag_name=None, value=None): + # Query by name, by default + if not tag_name: + tag_name = "name" + + if hasattr(rpm, "headerFromPackage"): + # rpm 4.0.4 or earlier + self.db = rpm.opendb() + method = self.db.match + else: + # rpm 4.1 or later + self.ts = rpm.TransactionSet() + self.ts.setVSFlags(8) + method = self.ts.dbMatch + + if value: + self.mi = method(tag_name, value) + else: + self.mi = method(tag_name) + + def pattern(self, tag_name, mode, pattern): + self.mi.pattern(tag_name, mode, pattern) + + def next(self): + try: + hdr = self.mi.next() + except StopIteration: + hdr = None + + if hdr is None: + return None + if hasattr(rpm, "headerFromPackage"): + is_source = not hdr[rpm.RPMTAG_SOURCERPM] + else: + is_source = hdr[getattr(rpm, 'RPMTAG_SOURCEPACKAGE')] + return RPM_Header(hdr, is_source) + + +def headerLoad(data): + hdr = rpm.headerLoad(data) + if hasattr(rpm, "headerFromPackage"): + is_source = not hdr[rpm.RPMTAG_SOURCERPM] + else: + is_source = hdr[getattr(rpm, 'RPMTAG_SOURCEPACKAGE')] + return RPM_Header(hdr, is_source) + +def labelCompare(t1, t2): + return rpm.labelCompare(t1, t2) + +def nvre_compare(t1, t2): + def build_evr(p): + evr = [p[3], p[1], p[2]] + evr = map(str, evr) + if evr[0] == "": + evr[0] = None + return evr + if t1[0] != t2[0]: + raise ValueError("You should only compare packages with the same name") + evr1, evr2 = (build_evr(t1), build_evr(t2)) + return rpm.labelCompare(evr1, evr2) + + +def hdrLabelCompare(hdr1, hdr2): + """ take two RPMs or headers and compare them for order """ + + if hdr1['name'] == hdr2['name']: + hdr1 = [hdr1['epoch'] or None, hdr1['version'], hdr1['release']] + hdr2 = [hdr2['epoch'] or None, hdr2['version'], hdr2['release']] + if hdr1[0]: + hdr1[0] = str(hdr1[0]) + if hdr2[0]: + hdr2[0] = str(hdr2[0]) + return rpm.labelCompare(hdr1, hdr2) + elif hdr1['name'] < hdr2['name']: + return -1 + return 1 + + +def rpmLabelCompare(rpmFilename1, rpmFilename2): + """ take two RPMs and compare them for order """ + return hdrLabelCompare(get_package_header(rpmFilename1), + get_package_header(rpmFilename2)) + + +def sortHeaders(hdrs): + """ Sorts a list of RPM headers (or RPMs). + Assertion: they *must* exist. + """ + + assert isinstance(hdrs, type([])) + + sorted = hdrs[:] + sorted.sort(hdrLabelCompare) + return sorted + + +def sortRPMs(rpms): + """ Sorts a list of RPM files. They *must* exist. """ + + assert isinstance(rpms, type([])) + + # We don't want to use rpmLabelCompare as a sorting mechanism, it would + # extract the rpm header for each comparison. + # Build a list of (header, rpm) + helper = map(lambda x: (get_package_header(x), x), rpms) + + # Sort the list using the headers as a comparison + helper.sort(lambda x, y: hdrLabelCompare(x[0], y[0])) + + # Extract the rpm names now + return map(lambda x: x[1], helper) + + +def getInstalledHeader(rpmName): + """ quieries the RPM DB for a header matching rpmName. """ + + mi = MatchIterator("name") + mi.pattern("name", rpm.RPMMIRE_STRCMP, rpmName) + return mi.next() + + +if __name__ == '__main__': + mi = MatchIterator("name") + mi.pattern("name", rpm.RPMMIRE_GLOB, "*ker*") + while 1: + h = mi.next() + if not h: + break + print h['name'] + sys.exit(1) + hdr = get_package_header(filename="/tmp/python-1.5.2-42.72.i386.rpm") + print dir(hdr) + # Sources + hdr = get_package_header(filename="/tmp/python-1.5.2-42.72.src.rpm") + hdr2 = headerLoad(hdr.unload()) + print hdr2 + print len(hdr2.keys()) + + diff --git a/client/rhel/rhnlib/rhn/common/rhn_mpm.py b/client/rhel/rhnlib/rhn/common/rhn_mpm.py deleted file mode 100644 index 0d339d8..0000000 --- a/client/rhel/rhnlib/rhn/common/rhn_mpm.py +++ /dev/null @@ -1,283 +0,0 @@ -# -# Copyright (c) 2008 Red Hat, Inc. -# -# This software is licensed to you under the GNU General Public License, -# version 2 (GPLv2). There is NO WARRANTY for this software, express or -# implied, including the implied warranties of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 -# along with this software; if not, see -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. -# -# Red Hat trademarks are not licensed under GPLv2. No permission is -# granted to use or replicate Red Hat trademarks that are incorporated -# in this software or its documentation. -# - -import os -import gzip -import cStringIO -import tempfile -from rhn.rpclib import xmlrpclib - -import struct - -from types import ListType, TupleType, DictType - -def labelCompare(l1, l2): - try: - import rhn_rpm - except ImportError: - # rhn_rpm not avalable; return a dummy comparison function - return -1 - return rhn_rpm.labelCompare(l1, l2) - -def get_package_header(filename=None, file=None, fd=None): - return load(filename=filename, file=file, fd=fd)[0] - -# Loads an MPM and returns its header and its payload -def load(filename=None, file=None, fd=None): - if (filename is None and file is None and fd is None): - raise ValueError, "No parameters passed" - - if filename is not None: - f = open(filename) - elif file is not None: - f = file - else: # fd is not None - f = os.fdopen(os.dup(fd), "r") - - f.seek(0, 0) - - p = MPM_Package() - try: - p.load(f) - except InvalidPackageError, e: - try: - return load_rpm(f) - except InvalidPackageError: - raise e - - return p.header, p.payload_stream - -def load_rpm(stream): - # Hmm, maybe an rpm - - try: - import rhn_rpm - except ImportError: - raise InvalidPackageError - - # Dup the file descriptor, we don't want it to get closed before we read - # the payload - newfd = os.dup(stream.fileno()) - stream = os.fdopen(newfd, "r") - - stream.flush() - stream.seek(0, 0) - - try: - header = rhn_rpm.get_package_header(file=stream) - except rhn_rpm.InvalidPackageError, e: - raise apply(InvalidPackageError, e.args) - except rhn_rpm.error, e: - raise InvalidPackageError(e) - stream.seek(0, 0) - - return header, stream - -class MPM_Header: - "Wrapper class for an mpm header - we need to store a flag is_source" - def __init__(self, hdr): - self.hdr = hdr - self.is_source = hdr.get('is_source') - self.packaging = 'mpm' - self.signatures = [] - - def __getitem__(self, name): - return self.hdr.get(name) - - def __setitem__(self, name, item): - self.hdr[name] = item - - def __delitem__(self, name): - del self.hdr[name] - - def __getattr__(self, name): - return getattr(self.hdr, name) - - def is_signed(self): - return 0 - -class InvalidPackageError(Exception): - pass - -MPM_HEADER_COMPRESSED_GZIP = 1 -MPM_PAYLOAD_COMPRESSED_GZIP = 1 - -class MPM_Package: - _lead_format = '!16sB3s4L92s' - _magic = 'mpmpackage012345' - def __init__(self): - self.header = None - self.payload_stream = None - self.header_flags = MPM_HEADER_COMPRESSED_GZIP - self.payload_flags = 0 - assert(len(self._magic) == 16) - self._buffer_size = 16384 - - def _read_lead(self, stream): - # Lead has the following format: - # 16 bytes magic - # 1 bytes version - # 3 bytes unused - # 4 bytes header flags - # 4 bytes payload flags - # 4 bytes header length - # 4 bytes payload length - # 92 bytes padding to 128 bytes - lead = self._read_bytes(stream, 128) - if len(lead) != 128: - raise InvalidPackageError() - - arr = struct.unpack(self._lead_format, lead) - return arr - - def load(self, input_stream): - # Clean up - self.__init__() - arr = self._read_lead(input_stream) - magic = arr[0] - if magic != self._magic: - raise InvalidPackageError() - header_len, payload_len = int(arr[5]), int(arr[6]) - header_flags, payload_flags = arr[3], arr[4] - file_size = 128 + header_len + payload_len - input_stream.seek(file_size) - if file_size != input_stream.tell(): - raise InvalidPackageError() - # Read the header - input_stream.seek(128, 0) - header_data = self._read_bytes(input_stream, header_len) - payload_stream = tempfile.TemporaryFile() - self.stream_copy(input_stream, payload_stream) - - self._read_header(header_data, header_flags) - self._read_payload(payload_stream, payload_flags) - - def _read_bytes(self, stream, amt): - ret = "" - while amt: - buf = stream.read(min(amt, self._buffer_size)) - if not buf: - return ret - ret = ret + buf - amt = amt - len(buf) - return ret - - def _read_header(self, header_data, header_flags): - if header_flags & MPM_HEADER_COMPRESSED_GZIP: - t = cStringIO.StringIO(header_data) - g = gzip.GzipFile(None, "r", 0, t) - header_data = g.read() - g.close() - t.close() - - try: - params, foo = xmlrpclib.loads(header_data) - except: - # XXX - raise - - self.header = MPM_Header(params[0]) - - def _read_payload(self, payload_stream, payload_flags): - payload_stream.seek(0, 0) - if payload_flags & MPM_PAYLOAD_COMPRESSED_GZIP: - g = gzip.GzipFile(None, "r", 0, payload_stream) - t = tempfile.TemporaryFile() - self.stream_copy(g, t) - g.close() - payload_stream = t - - self.payload_stream = payload_stream - - def write(self, output_stream): - if self.header is None: - raise Exception() - - header_stream, header_size = self._encode_header() - payload_stream, payload_size = self._encode_payload() - - lead_arr = (self._magic, 1, "\0" * 3, self.header_flags, - self.payload_flags, header_size, payload_size, '\0' * 92) - # lead - lead = apply(struct.pack, (self._lead_format, ) + lead_arr) - output_stream.write(lead) - self.stream_copy(header_stream, output_stream) - self.stream_copy(payload_stream, output_stream) - - def add_header_flag(self, flag): - self.header_flags = self.header_flags | flag - - def add_payload_flag(self, flag): - self.payload_flags = self.payload_flags | flag - - def reset_header_flags(self): - self.header_flags = 0 - - def reset_payload_flags(self): - self.payload_flags = 0 - - def _encode_header(self): - assert(self.header is not None) - stream = tempfile.TemporaryFile() - data = xmlrpclib.dumps((_replace_null(self.header), )) - if self.header_flags & MPM_HEADER_COMPRESSED_GZIP: - f = gzip.GzipFile(None, "wb", 9, stream) - f.write(data) - f.close() - else: - stream.write(data) - stream.flush() - stream.seek(0, 2) - size = stream.tell() - stream.seek(0, 0) - return stream, size - - def _encode_payload(self): - assert(self.payload_stream is not None) - stream = tempfile.TemporaryFile() - if self.payload_flags & MPM_PAYLOAD_COMPRESSED_GZIP: - f = gzip.GzipFile(None, "wb", 9, stream) - self.stream_copy(self.payload_stream, f) - f.close() - else: - stream = self.payload_stream - stream.flush() - stream.seek(0, 2) - size = stream.tell() - stream.seek(0, 0) - return stream, size - - def stream_copy(self, source, dest): - "Copies data from the source stream to the destination stream" - while 1: - buf = source.read(self._buffer_size) - if not buf: - break - dest.write(buf) - - -def _replace_null(obj): - if obj is None: - return '' - if isinstance(obj, ListType): - return map(_replace_null, obj) - if isinstance(obj, TupleType): - return tuple(_replace_null(list(obj))) - if hasattr(obj, 'items'): - dict = {} - for k, v in obj.items(): - dict[_replace_null(k)] = _replace_null(v) - return dict - return obj diff --git a/client/rhel/rhnlib/rhn/common/rhn_rpm.py b/client/rhel/rhnlib/rhn/common/rhn_rpm.py deleted file mode 100644 index 349388a..0000000 --- a/client/rhel/rhnlib/rhn/common/rhn_rpm.py +++ /dev/null @@ -1,462 +0,0 @@ -# -# Copyright (c) 2008 Red Hat, Inc. -# -# This software is licensed to you under the GNU General Public License, -# version 2 (GPLv2). There is NO WARRANTY for this software, express or -# implied, including the implied warranties of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 -# along with this software; if not, see -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. -# -# Red Hat trademarks are not licensed under GPLv2. No permission is -# granted to use or replicate Red Hat trademarks that are incorporated -# in this software or its documentation. -# - -import os -import sys -import rpm -import struct - -import exceptions -if not hasattr(exceptions, 'StopIteration'): - # Presumably python 1.5.2 - class StopIteration(Exception): - pass - -# Expose a bunch of useful constants from rpm -error = rpm.error -for sym, val in rpm.__dict__.items(): - if sym[:3] == 'RPM': - # A constant, probably - import it into our namespace - globals()[sym] = val -del sym, val - -# need this for rpm-pyhon < 4.6 (e.g. on RHEL5) -rpm.RPMTAG_FILEDIGESTALGO = 5011 - -# these values are taken from /usr/include/rpm/rpmpgp.h -# PGPHASHALGO_MD5 = 1, /*!< MD5 */ -# PGPHASHALGO_SHA1 = 2, /*!< SHA1 */ -# PGPHASHALGO_RIPEMD160 = 3, /*!< RIPEMD160 */ -# PGPHASHALGO_MD2 = 5, /*!< MD2 */ -# PGPHASHALGO_TIGER192 = 6, /*!< TIGER192 */ -# PGPHASHALGO_HAVAL_5_160 = 7, /*!< HAVAL-5-160 */ -# PGPHASHALGO_SHA256 = 8, /*!< SHA256 */ -# PGPHASHALGO_SHA384 = 9, /*!< SHA384 */ -# PGPHASHALGO_SHA512 = 10, /*!< SHA512 */ -PGPHASHALGO = { - 1: 'md5', - 2: 'sha1', - 3: 'ripemd160', - 5: 'md2', - 6: 'tiger192', - 7: 'haval-5-160', - 8: 'sha256', - 9: 'sha384', - 10: 'sha512', -} - - -class InvalidPackageError(Exception): - pass - -# wrapper/proxy class for rpm.Transaction so we can -# instrument it, etc easily -class RPMTransaction: - read_only = 0 - def __init__(self): - if hasattr(rpm, 'opendb'): - db = getattr(rpm, 'opendb')(not self.read_only) - self.ts = rpm.TransactionSet('/', db) - else: - self.ts = rpm.TransactionSet() - self.tsflags = [] - # For rpm 4.0.4 - self._flags = 0 - self._prob_filter = 0 - - def __getattr__(self, attr): - return getattr(self.ts, attr) - - def getMethod(self, method): - # in theory, we can override this with - # profile/etc info - return getattr(self.ts, method) - - # push/pop methods so we don't lose the previous - # set value, and we can potentially debug a bit - # easier - def pushVSFlags(self, flags): - self.tsflags.append(flags) - if hasattr(self.ts, 'setVSFlags'): - f = getattr(self.ts, 'setVSFlags') - f(self.tsflags[-1]) - - def popVSFlags(self): - del self.tsflags[-1] - if hasattr(self.ts, 'setVSFlags'): - f = getattr(self.ts, 'setVSFlags') - f(self.tsflags[-1]) - - def addInstall(self, arg1, arg2, mode): - """Install a package""" - hdr = arg1.hdr - if hasattr(self.ts, 'addInstall'): - f = getattr(self.ts, 'addInstall') - return f(hdr, arg2, mode) - return self.ts.add(hdr, arg2, mode) - - def addErase(self, arg1): - """Erase a package""" - hdr = arg1.hdr - if hasattr(self.ts, 'addErase'): - f = getattr(self.ts, 'addErase') - return f(hdr) - return self.ts.add(hdr, hdr, "e") - - def check(self): - """Check dependencies""" - if hasattr(self.ts, 'check'): - f = getattr(self.ts, 'check') - else: - f = getattr(self.ts, 'depcheck') - return f() - - def setFlags(self, flag): - """Set transaction flags""" - if hasattr(rpm, 'headerFromPackage'): - # Old style rpm - old_flags = self._flags - self._flags = flag - return old_flags - return self.ts.setFlags(flag) - - def setProbFilter(self, flag): - """Set problem flags""" - if hasattr(rpm, 'headerFromPackage'): - # Old style rpm - old_flags = self._prob_filter - self._prob_filter = flag - return old_flags - return self.ts.setProbFilter(flag) - - def run(self, callback, user_data): - if hasattr(rpm, 'headerFromPackage'): - # Old style rpm - return self.ts.run(self._flags, self._prob_filter, callback, - user_data) - return self.ts.run(callback, user_data) - - - - -class SharedStateTransaction: - _shared_state = {} - - def __init__(self): - self.__dict__ = self._shared_state - -class RPMReadOnlyTransaction(SharedStateTransaction, RPMTransaction): - read_only = 1 - def __init__(self): - SharedStateTransaction.__init__(self) - if not hasattr(self, 'ts'): - RPMTransaction.__init__(self) - # FIXME: replace with macro defination - self.pushVSFlags(8) - -class RPM_Header: - "Wrapper class for an rpm header - we need to store a flag is_source" - def __init__(self, hdr, is_source=None): - self.hdr = hdr - self.is_source = is_source - self.packaging = 'rpm' - self.signatures = [] - self._extract_signatures() - - def __getitem__(self, name): - return self.hdr[name] - - def __getattr__(self, name): - return getattr(self.hdr, name) - - def checksum_type(self): - if self.hdr[rpm.RPMTAG_FILEDIGESTALGO] \ - and PGPHASHALGO.has_key(self.hdr[rpm.RPMTAG_FILEDIGESTALGO]): - checksum_type = PGPHASHALGO[self.hdr[rpm.RPMTAG_FILEDIGESTALGO]] - else: - checksum_type = 'md5' - return checksum_type - - def is_signed(self): - if hasattr(rpm, "RPMTAG_DSAHEADER"): - dsaheader = self.hdr["dsaheader"] - else: - dsaheader = 0 - if self.hdr["siggpg"] or self.hdr["sigpgp"] or dsaheader: - return 1 - return 0 - - def _extract_signatures(self): - header_tags = [ - [rpm.RPMTAG_DSAHEADER, "dsa"], - [rpm.RPMTAG_RSAHEADER, "rsa"], - [rpm.RPMTAG_SIGGPG, "gpg"], - [rpm.RPMTAG_SIGPGP, 'pgp'], - ] - for ht, sig_type in header_tags: - ret = self.hdr[ht] - if not ret or len(ret) < 17: - continue - # Get the key id - hopefully we get it right - key_id = ret[9:17] - key_id_len = len(key_id) - format = "%dB" % key_id_len - t = struct.unpack(format, key_id) - format = "%02x" * key_id_len - key_id = format % t - self.signatures.append({ - 'signature_type' : sig_type, - 'key_id' : key_id, - 'signature' : ret, - }) - -def get_header_byte_range(package_file): - """ - Return the start and end bytes of the rpm header object. - - For details of the rpm file format, see: - http://www.rpm.org/max-rpm/s1-rpm-file-format-rpm-file-format.html - """ - - lead_size = 96 - - # Move past the rpm lead - package_file.seek(lead_size) - - sig_size = get_header_struct_size(package_file) - - # Now we can find the start of the actual header. - header_start = lead_size + sig_size - - package_file.seek(header_start) - - header_size = get_header_struct_size(package_file) - - header_end = header_start + header_size - - return (header_start, header_end) - -def get_header_struct_size(package_file): - """ - Compute the size in bytes of the rpm header struct starting at the current - position in package_file. - """ - # Move past the header preamble - package_file.seek(8, 1) - - # Read the number of index entries - header_index = package_file.read(4) - (header_index_value, ) = struct.unpack('>I', header_index) - - # Read the the size of the header data store - header_store = package_file.read(4) - (header_store_value, ) = struct.unpack('>I', header_store) - - # The total size of the header. Each index entry is 16 bytes long. - header_size = 8 + 4 + 4 + header_index_value * 16 + header_store_value - - # Headers end on an 8-byte boundary. Round out the extra data. - round_out = header_size % 8 - if round_out != 0: - header_size = header_size + (8 - round_out) - - return header_size - -# Loads the package header from a file / stream / file descriptor -# Raises rpm.error if an error is found, or InvalidPacageError if package is -# busted -# XXX Deal with exceptions better -def get_package_header(filename=None, file=None, fd=None): - if (filename is None and file is None and fd is None): - raise ValueError, "No parameters passed" - - if filename is not None: - f = open(filename) - elif file is not None: - f = file - f.seek(0, 0) - else: # fd is not None - f = None - - if f is None: - os.lseek(fd, 0, 0) - file_desc = fd - else: - file_desc = f.fileno() - - if hasattr(rpm, 'headerFromPackage'): - hdr, is_source = rpm.headerFromPackage(file_desc) - if hdr is None: - raise InvalidPackageError - else: - if hasattr(rpm, 'readHeaderFromFD'): - header_start, header_end = \ - get_header_byte_range(os.fdopen(os.dup(file_desc))) - os.lseek(file_desc, header_start, 0) - hdr, offset = rpm.readHeaderFromFD(file_desc) - else: - # RHEL-4 and older, do the old way - ts = RPMReadOnlyTransaction() - nomd5 = getattr(rpm, 'RPMVSF_NOMD5') - needpayload = getattr(rpm, 'RPMVSF_NEEDPAYLOAD') - ts.pushVSFlags(~(nomd5 | needpayload)) - hdr = RPMReadOnlyTransaction().hdrFromFdno(file_desc) - ts.popVSFlags() - if hdr is None: - raise InvalidPackageError - is_source = hdr[getattr(rpm, 'RPMTAG_SOURCEPACKAGE')] - - return RPM_Header(hdr, is_source) - -class MatchIterator: - def __init__(self, tag_name=None, value=None): - # Query by name, by default - if not tag_name: - tag_name = "name" - - if hasattr(rpm, "headerFromPackage"): - # rpm 4.0.4 or earlier - self.db = rpm.opendb() - method = self.db.match - else: - # rpm 4.1 or later - self.ts = rpm.TransactionSet() - self.ts.setVSFlags(8) - method = self.ts.dbMatch - - if value: - self.mi = method(tag_name, value) - else: - self.mi = method(tag_name) - - def pattern(self, tag_name, mode, pattern): - self.mi.pattern(tag_name, mode, pattern) - - def next(self): - try: - hdr = self.mi.next() - except StopIteration: - hdr = None - - if hdr is None: - return None - if hasattr(rpm, "headerFromPackage"): - is_source = not hdr[rpm.RPMTAG_SOURCERPM] - else: - is_source = hdr[getattr(rpm, 'RPMTAG_SOURCEPACKAGE')] - return RPM_Header(hdr, is_source) - - -def headerLoad(data): - hdr = rpm.headerLoad(data) - if hasattr(rpm, "headerFromPackage"): - is_source = not hdr[rpm.RPMTAG_SOURCERPM] - else: - is_source = hdr[getattr(rpm, 'RPMTAG_SOURCEPACKAGE')] - return RPM_Header(hdr, is_source) - -def labelCompare(t1, t2): - return rpm.labelCompare(t1, t2) - -def nvre_compare(t1, t2): - def build_evr(p): - evr = [p[3], p[1], p[2]] - evr = map(str, evr) - if evr[0] == "": - evr[0] = None - return evr - if t1[0] != t2[0]: - raise ValueError("You should only compare packages with the same name") - evr1, evr2 = (build_evr(t1), build_evr(t2)) - return rpm.labelCompare(evr1, evr2) - - -def hdrLabelCompare(hdr1, hdr2): - """ take two RPMs or headers and compare them for order """ - - if hdr1['name'] == hdr2['name']: - hdr1 = [hdr1['epoch'] or None, hdr1['version'], hdr1['release']] - hdr2 = [hdr2['epoch'] or None, hdr2['version'], hdr2['release']] - if hdr1[0]: - hdr1[0] = str(hdr1[0]) - if hdr2[0]: - hdr2[0] = str(hdr2[0]) - return rpm.labelCompare(hdr1, hdr2) - elif hdr1['name'] < hdr2['name']: - return -1 - return 1 - - -def rpmLabelCompare(rpmFilename1, rpmFilename2): - """ take two RPMs and compare them for order """ - return hdrLabelCompare(get_package_header(rpmFilename1), - get_package_header(rpmFilename2)) - - -def sortHeaders(hdrs): - """ Sorts a list of RPM headers (or RPMs). - Assertion: they *must* exist. - """ - - assert isinstance(hdrs, type([])) - - sorted = hdrs[:] - sorted.sort(hdrLabelCompare) - return sorted - - -def sortRPMs(rpms): - """ Sorts a list of RPM files. They *must* exist. """ - - assert isinstance(rpms, type([])) - - # We don't want to use rpmLabelCompare as a sorting mechanism, it would - # extract the rpm header for each comparison. - # Build a list of (header, rpm) - helper = map(lambda x: (get_package_header(x), x), rpms) - - # Sort the list using the headers as a comparison - helper.sort(lambda x, y: hdrLabelCompare(x[0], y[0])) - - # Extract the rpm names now - return map(lambda x: x[1], helper) - - -def getInstalledHeader(rpmName): - """ quieries the RPM DB for a header matching rpmName. """ - - mi = MatchIterator("name") - mi.pattern("name", rpm.RPMMIRE_STRCMP, rpmName) - return mi.next() - - -if __name__ == '__main__': - mi = MatchIterator("name") - mi.pattern("name", rpm.RPMMIRE_GLOB, "*ker*") - while 1: - h = mi.next() - if not h: - break - print h['name'] - sys.exit(1) - hdr = get_package_header(filename="/tmp/python-1.5.2-42.72.i386.rpm") - print dir(hdr) - # Sources - hdr = get_package_header(filename="/tmp/python-1.5.2-42.72.src.rpm") - hdr2 = headerLoad(hdr.unload()) - print hdr2 - print len(hdr2.keys()) - - diff --git a/client/rhel/rhnlib/setup.py.in b/client/rhel/rhnlib/setup.py.in index 99a8c59..35d5028 100644 --- a/client/rhel/rhnlib/setup.py.in +++ b/client/rhel/rhnlib/setup.py.in @@ -15,7 +15,7 @@ Red Hat Network (http://rhn.redhat.com) software.""", author = 'Mihai Ibanescu', author_email = 'misa@redhat.com', url = 'http://rhn.redhat.com', - packages = ["rhn", "rhn/common"], + packages = ["rhn"], license = "GPL",
) diff --git a/client/tools/rhnpush/rhnpush.spec b/client/tools/rhnpush/rhnpush.spec index 26efa29..9cd1d58 100644 --- a/client/tools/rhnpush/rhnpush.spec +++ b/client/tools/rhnpush/rhnpush.spec @@ -10,7 +10,8 @@ Release: 1%{?dist} Source0: https://fedorahosted.org/releases/s/p/spacewalk/%%7Bname%7D-%%7Bversion%7D.t... BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildArch: noarch -Requires: rpm-python, rhnlib >= 2.5.16 +Requires: rpm-python, rhnlib +Requires: spacewalk-backend-libs >= 0.8.3 BuildRequires: docbook-utils, gettext
Summary: Package uploader for the Red Hat Network Satellite Server diff --git a/spacewalk/certs-tools/spacewalk-certs-tools.spec b/spacewalk/certs-tools/spacewalk-certs-tools.spec index 3f882d1..76477aa 100644 --- a/spacewalk/certs-tools/spacewalk-certs-tools.spec +++ b/spacewalk/certs-tools/spacewalk-certs-tools.spec @@ -10,7 +10,7 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildArch: noarch Requires: openssl rpm-build Requires: rhn-client-tools -Requires: rhnlib >= 2.5.16 +Requires: spacewalk-backend-libs >= 0.8.3 BuildRequires: docbook-utils BuildRequires: python Obsoletes: rhns-certs < 5.3.0