Package backend :: Package common :: Module rhnRepository
[hide private]
[frames] | no frames]

Source Code for Module backend.common.rhnRepository

  1  # 
  2  # Copyright (c) 2008--2016 Red Hat, Inc. 
  3  # 
  4  # This software is licensed to you under the GNU General Public License, 
  5  # version 2 (GPLv2). There is NO WARRANTY for this software, express or 
  6  # implied, including the implied warranties of MERCHANTABILITY or FITNESS 
  7  # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 
  8  # along with this software; if not, see 
  9  # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 
 10  # 
 11  # Red Hat trademarks are not licensed under GPLv2. No permission is 
 12  # granted to use or replicate Red Hat trademarks that are incorporated 
 13  # in this software or its documentation. 
 14  # 
 15  # 
 16   
 17  import os 
 18  import stat 
 19  try: 
 20      #  python 2 
 21      import cStringIO 
 22  except ImportError: 
 23      #  python3 
 24      import io as cStringIO 
 25  import sys 
 26  from rhn import rpclib 
 27   
 28  from spacewalk.common import usix 
 29  from spacewalk.common import rhn_rpm 
 30   
 31  # local imports 
 32  from spacewalk.common import rhnFlags 
 33  from spacewalk.common.rhnLog import log_debug 
 34  from spacewalk.common.rhnLib import rfc822time 
 35  from spacewalk.common.rhnException import rhnException, rhnFault, rhnNotFound 
 36  from spacewalk.common.RPC_Base import RPC_Base 
37 38 # bare-except and broad-except 39 # pylint: disable=W0702,W0703 40 41 -class Repository(RPC_Base):
42 43 """ Shared repository class, inherited by both the proxy and server specific 44 Repository classes. 45 """ 46
47 - def __init__(self, channelName=None):
48 log_debug(2, channelName) 49 RPC_Base.__init__(self) 50 self.channelName = channelName 51 # Default visible functions. 52 self.compress_headers = 1 53 self.functions = [ 54 'getPackage', 55 'getPackageHeader', 56 'getPackageSource', 57 'i18n', 58 'media_1' 59 ]
60
61 - def set_compress_headers(self, val):
62 self.compress_headers = val
63
64 - def __del__(self):
65 self.channelName = None 66 self.functions = None
67
68 - def getPackagePath(self, pkgFilename, redirect=0):
69 """Returns the path to a package. 70 OVERLOAD this in server and proxy rhnRepository. 71 I.e.: they construct the path differently. 72 """ 73 # pylint: disable=R0201,W0613 74 raise rhnException("This function should be overloaded.")
75 76 @staticmethod
77 - def getPackagePathNVRA(_nvra):
78 """OVERLOAD this in server and proxy rhnRepository. 79 I.e.: they construct the path differently. 80 """ 81 raise rhnException("This function should be overloaded.")
82
83 - def getSourcePackagePath(self, _pkgFilename):
84 """Returns the path to a package. 85 OVERLOAD this in server and proxy rhnRepository. 86 I.e.: they construct the path differently. 87 """ 88 # pylint: disable=R0201 89 raise rhnException("This function should be overloaded.")
90
91 - def getPackage(self, pkgFilename, *args):
92 """ Get rpm package. """ 93 log_debug(3, pkgFilename) 94 if args: 95 pkg_spec = [pkgFilename] + list(args) 96 else: 97 pkg_spec = pkgFilename 98 99 redirectsSupported = 0 100 101 # If we are talking to a proxy, determine whether it's a version that 102 # supports redirects. 103 proxyVersionString = rhnFlags.get('x-rhn-proxy-version') 104 if proxyVersionString: 105 redirectsSupported = 1 106 else: 107 # Must be a client. We'll determine the redirect capability via 108 # the x-rhn-transport-capability header instead. 109 transport_cap = rhnFlags.get('x-rhn-transport-capability') 110 if transport_cap: 111 transport_cap_list = transport_cap.split('=') 112 redirectsSupported = transport_cap_list[0] == 'follow-redirects' and transport_cap_list[1] >= 2 113 114 if redirectsSupported: 115 log_debug(3, "Client supports redirects.") 116 filePath = self.getPackagePath(pkg_spec, 1) 117 else: 118 # older clients just return the hosted url and download the package 119 filePath = self.getPackagePath(pkg_spec) 120 121 return self._getFile(filePath)
122 123 @staticmethod
124 - def i18n(_translation, *_args):
125 """ Translations files for Ubuntu. E.g. Translation-en_US.bz2 126 127 We do not support it so just return 404. But do not fail with 128 traceback. 129 """ 130 raise rhnNotFound()
131 132 @staticmethod
133 - def media_1(filePath):
134 """SUSE File 135 136 We do not support it so just return 404. But do not fail with 137 traceback. 138 """ 139 log_debug(3, filePath) 140 raise rhnNotFound()
141
142 - def getPackageSource(self, pkgFilename):
143 """ Get srpm packrge. """ 144 log_debug(3, pkgFilename) 145 # Sanity check: 146 l = pkgFilename.split('.') 147 # 6/23/05 wregglej 154248, Don't mangle the filename if it's a nosrc package. 148 if l[-2] != "nosrc": 149 l[-2] = 'src' 150 pkgFilename = '.'.join(l) 151 filePath = self.getSourcePackagePath(pkgFilename) 152 return self._getFile(filePath)
153
154 - def getPackageHeader(self, pkgFilename):
155 """ Get rpm header. 156 XXX: stock 8.0 clients could not compress headers, we need to either 157 change the function name, or version the protocol 158 """ 159 log_debug(3, pkgFilename) 160 pkg = pkgFilename.split('.') 161 # Basic sanity checks: 162 if pkg[-1] not in ["hdr", 'rpm']: 163 raise rhnFault(21, "'%s' not a valid RPM header name" % pkgFilename) 164 165 pkgFilename = ".".join(pkg[:-1]) + '.rpm' 166 filePath = self.getPackagePath(pkgFilename) 167 data = self._getHeaderFromFile(filePath) 168 # XXX: Interesting. Found that if returned just data, this 169 # function works fine. Investigate later. 170 return rpclib.transports.File(cStringIO.StringIO(data), len(data))
171 172 # The real workhorse for all flavors of listall 173 # It tries to pull data out of a file; if it doesn't work, 174 # it calls the data producer with the specified params to generate the 175 # data, which is also cached 176 177 # --- PRIVATE METHODS --- 178
179 - def _getFile(self, filePath):
180 """ Returns xmlrpclib file object to any file given a path to it. 181 IN: filePath: path to any file. 182 OUT: XMLed rpm or source rpm, or an xmlrpc file object. 183 """ 184 log_debug(3, filePath) 185 features = self._fileFeatures(filePath) 186 filePath = features['path'] 187 length = features['length'] 188 lastModified = features['lastModified'] 189 self._set_last_modified(lastModified) 190 return rpclib.transports.File(open(filePath, "rb"), length, name=filePath)
191
192 - def _getHeaderFromFile(self, filePath, stat_info=None):
193 """ Utility function to extract a header from an rpm. 194 If stat_info was already passed, don't re-stat the file 195 """ 196 log_debug(3, filePath) 197 if stat_info: 198 s = stat_info 199 else: 200 s = None 201 try: 202 s = os.stat(filePath) 203 except: 204 usix.raise_with_tb(rhnFault(17, "Unable to read package %s" 205 % os.path.basename(filePath)), sys.exc_info()[2]) 206 207 lastModified = s[stat.ST_MTIME] 208 del s # XXX: not neccessary? 209 210 # Get the package header from the file 211 # since we stat()ed the file, we know it's there already 212 fd = os.open(filePath, os.O_RDONLY) 213 h = rhn_rpm.get_package_header(fd=fd) 214 os.close(fd) 215 if h is None: 216 raise rhnFault(17, "Invalid RPM %s" % os.path.basename(filePath)) 217 stringIO = cStringIO.StringIO() 218 # Put the result in stringIO 219 stringIO.write(h.unload()) 220 del h # XXX: not neccessary? 221 222 pkgFilename = os.path.basename(filePath) 223 pkg = pkgFilename.split('.') 224 # Replace .rpm with .hdr 225 pkg[-1] = "hdr" 226 pkgFilename = ".".join(pkg) 227 extra_headers = { 228 'X-RHN-Package-Header': pkgFilename, 229 } 230 self._set_last_modified(lastModified, extra_headers=extra_headers) 231 rhnFlags.set("AlreadyEncoded", 1) 232 return stringIO.getvalue()
233 234 @staticmethod
235 - def _set_last_modified(last_modified, extra_headers=None):
236 log_debug(4, last_modified) 237 if not last_modified: 238 return None 239 # Set a field with the name of the header 240 transport = rhnFlags.get('outputTransportOptions') 241 if last_modified: 242 # Put the last-modified info too 243 if isinstance(last_modified, (usix.IntType, usix.FloatType)): 244 last_modified = rfc822time(last_modified) 245 transport['Last-Modified'] = last_modified 246 if extra_headers: 247 for k, v in extra_headers.items(): 248 transport[str(k)] = str(v) 249 return transport
250 251 @staticmethod
252 - def _fileFeatures(filePath):
253 """ From a filepath, construct a dictionary of file features. """ 254 # pylint: disable=W0702 255 log_debug(3, filePath) 256 if not filePath: 257 raise rhnFault(17, "While looking for file: `%s'" 258 % os.path.basename(filePath)) 259 try: 260 s = os.stat(filePath) 261 except: 262 s = None 263 if not s: 264 l = 0 265 lastModified = 0 266 else: 267 l = s[stat.ST_SIZE] 268 lastModified = s[stat.ST_MTIME] 269 del s 270 271 # Build the result hash 272 result = {} 273 result['name'] = os.path.basename(filePath) 274 result['length'] = l 275 result['path'] = filePath 276 if lastModified: 277 result['lastModified'] = rfc822time(lastModified) 278 else: 279 result['lastModified'] = None 280 return result
281