1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import os
22 import time
23 import glob
24 import cPickle
25 import sys
26 import types
27 from operator import truth
28 import xmlrpclib
29
30
31 from spacewalk.common.rhnLib import parseRPMName
32 from spacewalk.common.rhnLog import log_debug
33 from spacewalk.common.rhnException import rhnFault
34 from spacewalk.common.rhnConfig import CFG
35 from spacewalk.common import rhnRepository
36 from spacewalk.common.rhnTranslate import _
37
38
39 from rhn import rpclib
40
41
42 PKG_LIST_DIR = os.path.join(CFG.PKG_DIR, 'list')
43 PREFIX = "rhn"
48
51
52
53 """ Proxy local package repository lookup and manipulation code. """
54
55 - def __init__(self,
56 channelName, channelVersion, clientInfo,
57 rhnParent=None, rhnParentXMLRPC=None, httpProxy=None, httpProxyUsername=None,
58 httpProxyPassword=None, caChain=None):
59
60 log_debug(3, channelName)
61 rhnRepository.Repository.__init__(self, channelName)
62 self.functions = CFG.PROXY_LOCAL_FLIST
63 self.channelName = channelName
64 self.channelVersion = channelVersion
65 self.clientInfo = clientInfo
66 self.rhnParent = rhnParent
67 self.rhnParentXMLRPC = rhnParentXMLRPC
68 self.httpProxy = httpProxy
69 self.httpProxyUsername = httpProxyUsername
70 self.httpProxyPassword = httpProxyPassword
71 self.caChain = caChain
72
74 """ OVERLOADS getPackagePath in common/rhnRepository.
75 Returns complete path to an RPM file.
76 """
77
78 log_debug(3, pkgFilename)
79 mappingName = "package_mapping:%s:" % self.channelName
80 mapping = self._cacheObj(mappingName, self.channelVersion,
81 self.__channelPackageMapping, ())
82
83
84
85
86 if isinstance(pkgFilename, types.ListType):
87 arch = pkgFilename[3]
88
89
90 if isSolarisArch(arch):
91 pkgFilename = "%s-%s-%s.%s.pkg" % \
92 (pkgFilename[0],
93 pkgFilename[1],
94 pkgFilename[2],
95 pkgFilename[3])
96
97 if not mapping.has_key(pkgFilename):
98 log_debug(3, "Package not in mapping: %s" % pkgFilename)
99 raise NotLocalError
100
101
102
103 filePaths = mapping[pkgFilename]
104
105 for filePath in filePaths:
106 filePath = "%s/%s" % (CFG.PKG_DIR, filePath)
107 log_debug(4, "File path", filePath)
108 if os.access(filePath, os.R_OK):
109 return filePath
110 log_debug(4, "Package not found locally: %s" % pkgFilename)
111 raise NotLocalError(filePaths[0], pkgFilename)
112
114 """ OVERLOADS getSourcePackagePath in common/rhnRepository.
115 snag src.rpm and nosrc.rpm from local repo, after ensuring
116 we are authorized to fetch it.
117 """
118
119 log_debug(3, pkgFilename)
120 if pkgFilename[-8:] != '.src.rpm' and pkgFilename[-10:] != '.nosrc.rpm':
121 raise rhnFault(17, _("Invalid SRPM package requested: %s")
122 % pkgFilename)
123
124
125
126 server = rpclib.Server(self.rhnParentXMLRPC, proxy=self.httpProxy,
127 username=self.httpProxyUsername,
128 password=self.httpProxyPassword)
129 if self.caChain:
130 server.add_trusted_cert(self.caChain)
131
132 try:
133 retval = server.proxy.package_source_in_channel(
134 pkgFilename, self.channelName, self.clientInfo)
135 except xmlrpclib.Fault, e:
136 raise rhnFault(1000,
137 _("Error retrieving source package: %s") % str(e)), None, sys.exc_info()[2]
138 if not retval:
139 raise rhnFault(17, _("Invalid SRPM package requested: %s")
140 % pkgFilename)
141
142 if pkgFilename[-8:] != '.src.rpm':
143
144 nvrea = list(parseRPMName(pkgFilename[:-8]))
145 nvrea.append("src")
146 else:
147
148
149 nvrea = list(parseRPMName(pkgFilename[:-10]))
150 nvrea.append("nosrc")
151
152 filePaths = computePackagePaths(nvrea, source=1, prepend=PREFIX)
153 for filePath in filePaths:
154 filePath = "%s/%s" % (CFG.PKG_DIR, filePath)
155 log_debug(4, "File path", filePath)
156 if os.access(filePath, os.R_OK):
157 return filePath
158 log_debug(4, "Source package not found locally: %s" % pkgFilename)
159 raise NotLocalError(filePaths[0], pkgFilename)
160
161 - def _cacheObj(self, fileName, version, dataProducer, params=None):
162 """ The real workhorse for all flavors of listall
163 It tries to pull data out of a file; if it doesn't work,
164 it calls the data producer with the specified params to generate
165 the data, which is also cached.
166
167 Returns a string from a cache file or, if the cache file is not
168 there, calls dataProducer to generate the object and caches the
169 results
170 """
171
172 log_debug(4, fileName, version, params)
173 fileDir = self._getPkgListDir()
174 filePath = "%s/%s-%s" % (fileDir, fileName, version)
175 if os.access(filePath, os.R_OK):
176 try:
177
178 f = open(filePath, "r")
179 data = f.read()
180 f.close()
181 stringObject = cPickle.loads(data)
182 return stringObject
183 except (IOError, cPickle.UnpicklingError):
184 pass
185
186
187 if params is None:
188 params = ()
189 stringObject = dataProducer(*params)
190
191 cache(cPickle.dumps(stringObject, 1), fileDir, fileName, version)
192
193 return stringObject
194
195 @staticmethod
197 """ Creates and returns the directory for cached lists of packages.
198 Used by _cacheObj.
199
200 XXX: Problem exists here. If PKG_LIST_DIR can't be created
201 due to ownership... this is bad... need to fix.
202 """
203
204 log_debug(3, PKG_LIST_DIR)
205 if not os.access(PKG_LIST_DIR, os.R_OK | os.X_OK):
206 os.makedirs(PKG_LIST_DIR)
207 return PKG_LIST_DIR
208
218
220 """ fetch package list on behalf of the client """
221
222 log_debug(6, self.rhnParentXMLRPC, self.httpProxy, self.httpProxyUsername, self.httpProxyPassword)
223 log_debug(6, self.clientInfo)
224
225 try:
226 packageList = self._listPackages()
227 except xmlrpclib.ProtocolError, e:
228 errcode, errmsg = rpclib.reportError(e.headers)
229 raise rhnFault(1000, "SpacewalkProxy error (xmlrpclib.ProtocolError): "
230 "errode=%s; errmsg=%s" % (errcode, errmsg)), None, sys.exc_info()[2]
231
232
233 _hash = {}
234 for package in packageList:
235 arch = package[4]
236
237 extension = "rpm"
238 if isSolarisArch(arch):
239 extension = "pkg"
240 if isDebianArch(arch):
241 extension = "deb"
242
243 filename = "%s-%s-%s.%s.%s" % (package[0], package[1],
244 package[2], package[4], extension)
245
246 if len(package) > 6:
247 filePaths = computePackagePaths(package, source=0,
248 prepend=PREFIX, checksum=package[7])
249 else:
250 filePaths = computePackagePaths(package, source=0,
251 prepend=PREFIX)
252 _hash[filename] = filePaths
253
254 if CFG.DEBUG > 4:
255 log_debug(5, "Mapping: %s[...snip snip...]%s" % (str(_hash)[:40], str(_hash)[-40:]))
256 return _hash
257
260
261 """ Kickstarts always end up pointing to a channel that they're getting
262 rpms from. Lookup what channel that is and then just use the regular
263 repository """
264
265 - def __init__(self, kickstart, clientInfo, rhnParent=None,
266 rhnParentXMLRPC=None, httpProxy=None, httpProxyUsername=None,
267 httpProxyPassword=None, caChain=None, orgId=None, child=None,
268 session=None, systemId=None):
269 log_debug(3, kickstart)
270
271 self.systemId = systemId
272 self.kickstart = kickstart
273 self.ks_orgId = orgId
274 self.ks_child = child
275 self.ks_session = session
276
277
278
279
280 fileName = "kickstart_mapping:%s-%s-%s-%s:" % (str(kickstart),
281 str(orgId), str(child), str(session))
282
283 mapping = self._lookupKickstart(fileName, rhnParentXMLRPC, httpProxy,
284 httpProxyUsername, httpProxyPassword, caChain)
285 Repository.__init__(self, mapping['channel'], mapping['version'],
286 clientInfo, rhnParent, rhnParentXMLRPC, httpProxy,
287 httpProxyUsername, httpProxyPassword, caChain)
288
289 - def _lookupKickstart(self, fileName, rhnParentXMLRPC, httpProxy,
290 httpProxyUsername, httpProxyPassword, caChain):
291 fileDir = self._getPkgListDir()
292 filePath = "%s/%s-1" % (fileDir, fileName)
293 mapping = None
294 if os.access(filePath, os.R_OK):
295 try:
296
297 f = open(filePath, "r")
298 mapping = cPickle.loads(f.read())
299 f.close()
300 except (IOError, cPickle.UnpicklingError):
301 mapping = None
302
303 now = int(time.time())
304 if not mapping or mapping['expires'] < now:
305
306
307
308 server = rpclib.Server(rhnParentXMLRPC, proxy=httpProxy,
309 username=httpProxyUsername, password=httpProxyPassword)
310 if caChain:
311 server.add_trusted_cert(caChain)
312 try:
313 response = self._getMapping(server)
314 mapping = {'channel': str(response['label']),
315 'version': str(response['last_modified']),
316 'expires': int(time.time()) + 3600}
317 except Exception:
318
319
320 raise NotLocalError
321
322
323 cache(cPickle.dumps(mapping, 1), fileDir, fileName, "1")
324
325 return mapping
326
347
362
365
366
367 """ TinyURL kickstarts have actually already made a HEAD request up to the
368 Satellite to to get the checksum for the rpm, however we can't just use
369 that data because the epoch information is not in the filename so we'd
370 never find files with a non-None epoch. Instead do the same thing we do
371 for non-tiny-urlified kickstarts and look up what channel it maps to."""
372
373 - def __init__(self, tinyurl, clientInfo, rhnParent=None,
374 rhnParentXMLRPC=None, httpProxy=None, httpProxyUsername=None,
375 httpProxyPassword=None, caChain=None, systemId=None):
376 log_debug(3, tinyurl)
377
378 self.systemId = systemId
379 self.tinyurl = tinyurl
380
381
382
383
384 fileName = "tinyurl_mapping:%s:" % (str(tinyurl))
385
386 mapping = self._lookupKickstart(fileName, rhnParentXMLRPC, httpProxy,
387 httpProxyUsername, httpProxyPassword, caChain)
388 Repository.__init__(self, mapping['channel'], mapping['version'],
389 clientInfo, rhnParent, rhnParentXMLRPC, httpProxy,
390 httpProxyUsername, httpProxyPassword, caChain)
391
394
397 """
398 Returns true if the given arch string represents a solaris architecture.
399 """
400 return arch.find("solaris") != -1
401
404 """
405 Returns true if the given arch string represents a Debian architecture..
406 """
407 return arch[-4:] == "-deb"
408
411 """ Finds the appropriate paths, prepending something if necessary """
412 paths = []
413 name = nvrea[0]
414 release = nvrea[2]
415
416 if source:
417 dirarch = 'SRPMS'
418 pkgarch = 'src'
419 else:
420 dirarch = pkgarch = nvrea[4]
421
422 extension = "rpm"
423 if isSolarisArch(pkgarch):
424 extension = "pkg"
425 if isDebianArch(pkgarch):
426 extension = "deb"
427
428 version = nvrea[1]
429 epoch = nvrea[3]
430 if epoch not in [None, '']:
431 version = str(epoch) + ':' + version
432
433
434
435
436
437 if checksum and not source:
438 checksum_template = prepend + "/%s/%s/%s-%s/%s/%s/%s-%s-%s.%s.%s"
439 checksum_template = '/'.join(filter(truth, checksum_template.split('/')))
440 paths.append(checksum_template % (checksum[:3], name, version, release,
441 dirarch, checksum, name, nvrea[1], release, pkgarch, extension))
442 template = prepend + "/%s/%s-%s/%s/%s-%s-%s.%s.%s"
443
444 template = '/'.join(filter(truth, template.split('/')))
445 paths.append(template % (name, version, release, dirarch, name, nvrea[1],
446 release, pkgarch, extension))
447 return paths
448
449
450 -def cache(stringObject, directory, filename, version):
451 """ Caches stringObject into a file and removes older files """
452
453
454 if not os.access(directory, os.R_OK | os.W_OK | os.X_OK):
455 os.makedirs(directory)
456 filePath = "%s/%s-%s" % (directory, filename, version)
457
458 tempfile = "%s-%.20f" % (filePath, time.time())
459
460 tries = 10
461 while tries > 0:
462
463 try:
464 fd = os.open(tempfile, os.O_WRONLY | os.O_CREAT | os.O_EXCL,
465 0644)
466 except OSError, e:
467 if e.errno == 17:
468
469 tries = tries - 1
470 tempfile = tempfile + "%.20f" % time.time()
471 continue
472
473 raise
474 else:
475
476 break
477 else:
478
479 raise Exception("Could not create the file")
480
481 os.write(fd, stringObject)
482 os.close(fd)
483
484 os.rename(tempfile, filePath)
485
486 _list = glob.glob("%s/%s-*" % (directory, filename))
487 for _file in _list:
488 if _file < filePath:
489
490 os.unlink(_file)
491