Package backend :: Package server :: Package handlers :: Package app :: Module packages
[hide private]
[frames] | no frames]

Source Code for Module backend.server.handlers.app.packages

  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  # Package uploading functions. 
 17  # Package info checking routines. 
 18  # 
 19   
 20  import os 
 21  import string 
 22  import sys 
 23  from spacewalk.common.usix import TupleType 
 24   
 25  from spacewalk.common.usix import raise_with_tb 
 26   
 27  from spacewalk.common.rhnLog import log_debug, log_error 
 28  from spacewalk.common.rhnConfig import CFG 
 29  from spacewalk.common.rhnException import rhnFault 
 30  from spacewalk.common.RPC_Base import RPC_Base 
 31   
 32  from spacewalk.server import rhnSQL, rhnPackageUpload, rhnUser, rhnSession 
 33   
 34  from spacewalk.server.importlib.backendOracle import SQLBackend 
 35  from spacewalk.server.importlib.importLib import Collection, IncompatibleArchError,\ 
 36      Channel, IncompletePackage, InvalidChannelError 
 37  from spacewalk.server.importlib.packageImport import ChannelPackageSubscription 
 38   
 39  from spacewalk.server.importlib.packageUpload import uploadPackages, listChannels, listChannelsSource, listChannelsChecksum 
 40  from spacewalk.server.importlib.userAuth import UserAuth 
 41  from spacewalk.server.importlib.errataCache import schedule_errata_cache_update 
 42   
 43  # 12/22/05 wregglej 173287 
 44  # I made a decent number of changes to this file to implement session authentication. 
 45  # One of the requirements for this was to maintain backwards compatibility, so older 
 46  # versions of rhnpush can still talk to a newer satellite. This meant that I had to 
 47  # add new versions of each XMLRPC call that did authentication by sessions rather than 
 48  # username/password. I noticed that the only real difference between the two was the 
 49  # authentication scheme that the functions used, so rather than copy-n-paste a bunch of code, 
 50  # I separated the functionality from the authentication and just pass a authentication object 
 51  # to the function that actually does stuff. 
 52   
 53   
54 -class Packages(RPC_Base):
55
56 - def __init__(self):
57 log_debug(3) 58 RPC_Base.__init__(self) 59 self.functions.append('uploadPackageInfo') 60 self.functions.append('uploadPackageInfoBySession') 61 self.functions.append('uploadSourcePackageInfo') 62 self.functions.append('uploadSourcePackageInfoBySession') 63 self.functions.append('listChannel') 64 self.functions.append('listChannelBySession') 65 self.functions.append('listChannelChecksum') 66 self.functions.append('listChannelChecksumBySession') 67 self.functions.append('listChannelSource') 68 self.functions.append('listChannelSourceBySession') 69 self.functions.append('listMissingSourcePackages') 70 self.functions.append('listMissingSourcePackagesBySession') 71 self.functions.append('channelPackageSubscription') 72 self.functions.append('channelPackageSubscriptionBySession') 73 self.functions.append('no_op') 74 self.functions.append('test_login') 75 self.functions.append('test_new_login') 76 self.functions.append('test_check_session') 77 self.functions.append('login') 78 self.functions.append('check_session') 79 self.functions.append('getPackageChecksum') 80 self.functions.append('getPackageChecksumBySession') 81 self.functions.append('getSourcePackageChecksum') 82 self.functions.append('getSourcePackageChecksumBySession') 83 # old MD5 compatibility functions 84 self.functions.append('getPackageMD5sum') 85 self.functions.append('getPackageMD5sumBySession') 86 self.functions.append('getSourcePackageMD5sum') 87 self.functions.append('getSourcePackageMD5sumBySession')
88
89 - def no_op(self):
90 """ This is so the client can tell if the satellite supports session tokens or not. 91 92 This was used in rhnpush-5.5.26 and older. When there will be no such version of rhnpush in wild, 93 then this function can be safely removed.""" 94 return 1
95
96 - def uploadPackageInfo(self, username, password, info):
97 """ Upload a collection of binary packages. """ 98 log_debug(5, username, info) 99 authobj = auth(username, password) 100 return self._uploadPackageInfo(authobj, info)
101
102 - def uploadPackageInfoBySession(self, session_string, info):
103 log_debug(5, session_string) 104 authobj = auth_session(session_string) 105 return self._uploadPackageInfo(authobj, info)
106
107 - def _uploadPackageInfo(self, authobj, info):
108 # Authorize the org id passed 109 authobj.authzOrg(info) 110 # Get the channels 111 channels = info.get('channels') 112 if channels: 113 authobj.authzChannels(channels) 114 force = 0 115 if 'force' in info: 116 force = info['force'] 117 return uploadPackages(info, force=force, 118 caller="server.app.uploadPackageInfo")
119
120 - def uploadSourcePackageInfo(self, username, password, info):
121 """ Upload a collection of source packages. """ 122 log_debug(5, username, info) 123 authobj = auth(username, password) 124 return self._uploadSourcePackageInfo(authobj, info)
125
126 - def uploadSourcePackageInfoBySession(self, session_string, info):
127 log_debug(5, session_string) 128 authobj = auth_session(session_string) 129 return self._uploadSourcePackageInfo(authobj, info)
130
131 - def _uploadSourcePackageInfo(self, authobj, info):
132 # Authorize the org id passed 133 authobj.authzOrg(info) 134 force = 0 135 if 'force' in info: 136 force = info['force'] 137 return uploadPackages(info, source=1, force=force, 138 caller="server.app.uploadSourcePackageInfo")
139
140 - def listChannelSource(self, channelList, username, password):
141 log_debug(5, channelList, username) 142 authobj = auth(username, password) 143 return self._listChannelSource(authobj, channelList)
144
145 - def listChannelSourceBySession(self, channelList, session_string):
146 log_debug(5, channelList, session_string) 147 authobj = auth_session(session_string) 148 return self._listChannelSource(authobj, channelList)
149
150 - def _listChannelSource(self, authobj, channelList):
151 authobj.authzChannels(channelList) 152 ret = listChannelsSource(channelList) 153 return ret
154
155 - def listChannel(self, channelList, username, password):
156 """ List packages of a specified channel. """ 157 log_debug(5, channelList, username) 158 authobj = auth(username, password) 159 return self._listChannel(authobj, channelList)
160
161 - def listChannelBySession(self, channelList, session_string):
162 log_debug(5, channelList, session_string) 163 authobj = auth_session(session_string) 164 return self._listChannel(authobj, channelList)
165
166 - def _listChannel(self, authobj, channelList):
167 authobj.authzChannels(channelList) 168 return listChannels(channelList)
169
170 - def listChannelChecksum(self, channelList, username, password):
171 """ List packages of a specified channel. """ 172 log_debug(5, channelList, username) 173 authobj = auth(username, password) 174 return self._listChannelChecksum(authobj, channelList)
175
176 - def listChannelChecksumBySession(self, channelList, session_string):
177 log_debug(5, channelList, session_string) 178 authobj = auth_session(session_string) 179 return self._listChannelChecksum(authobj, channelList)
180
181 - def _listChannelChecksum(self, authobj, channelList):
182 authobj.authzChannels(channelList) 183 return listChannelsChecksum(channelList)
184
185 - def login(self, username, password):
186 """ This function that takes in the username 187 and password and returns a session string if they are correct. It raises a 188 rhnFault if the user/pass combo is not acceptable. 189 """ 190 log_debug(5, username) 191 user = rhnUser.search(username) 192 if not user or not user.check_password(password): 193 raise rhnFault(2) 194 if rhnUser.is_user_read_only(user.username): 195 raise rhnFault(702) 196 session = user.create_session() 197 return session.get_session()
198
199 - def check_session(self, session):
200 """ Checks a session string to make sure it is authentic expired. """ 201 try: 202 user = rhnUser.session_reload(session) 203 except (rhnSession.InvalidSessionError, rhnSession.ExpiredSessionError): 204 return 0 205 return 1
206
207 - def test_login(self, username, password):
208 log_debug(5, username) 209 try: 210 authobj = auth(username, password) 211 except: 212 return 0 213 return 1
214
215 - def test_new_login(self, username, password, session=None):
216 """ rhnpush's --extended-test will call this function. """ 217 log_debug(5, "testing new login") 218 return self.login(username, password)
219
220 - def test_check_session(self, session):
221 """ rhnpush's --extended-test will call this function. """ 222 log_debug(5, "testing check session") 223 return self.check_session(session)
224 225 ###listMissingSourcePackages###
226 - def listMissingSourcePackages(self, channelList, username, password):
227 """ List source packages for a list of channels. """ 228 log_debug(5, channelList, username) 229 authobj = auth(username, password) 230 return self._listMissingSourcePackages(authobj, channelList)
231
232 - def listMissingSourcePackagesBySession(self, channelList, session_string):
233 log_debug(5, channelList, session_string) 234 authobj = auth_session(session_string) 235 return self._listMissingSourcePackages(authobj, channelList)
236
237 - def _listMissingSourcePackages(self, authobj, channelList):
238 authobj.authzChannels(channelList) 239 240 h = rhnSQL.prepare(""" 241 select distinct sr.name source_rpm 242 from rhnChannel c 243 join rhnChannelNewestPackage cnp 244 on cnp.channel_id = c.id 245 join rhnPackage p 246 on cnp.package_id = p.id 247 join rhnSourceRPM sr 248 on p.source_rpm_id = sr.id 249 left join rhnPackageSource ps 250 on p.source_rpm_id = ps.source_rpm_id 251 and (p.org_id = ps.org_id or 252 (p.org_id is null and ps.org_id is null) 253 ) 254 where c.label = :channel_label 255 and ps.source_rpm_id is null 256 """) 257 missing_packages = [] 258 for c in channelList: 259 h.execute(channel_label=c) 260 while 1: 261 row = h.fetchone_dict() 262 if not row: 263 break 264 265 missing_packages.append([row['source_rpm'], c]) 266 267 return missing_packages
268
269 - def channelPackageSubscription(self, username, password, info):
270 """ Uploads an RPM package. """ 271 log_debug(3) 272 authobj = auth(username, password) 273 return self._channelPackageSubscription(authobj, info)
274
275 - def channelPackageSubscriptionBySession(self, session_string, info):
276 log_debug(3, info) 277 authobj = auth_session(session_string) 278 return self._channelPackageSubscription(authobj, info)
279
280 - def _channelPackageSubscription(self, authobj, info):
281 # Authorize the org id passed 282 authobj.authzOrg(info) 283 284 packageList = info.get('packages') or [] 285 if not packageList: 286 log_debug(1, "No packages found; done") 287 return 0 288 289 if 'channels' not in info or not info['channels']: 290 log_debug(1, "No channels found; done") 291 return 0 292 293 channelList = info['channels'] 294 authobj.authzChannels(channelList) 295 296 # Have to turn the channel list into a list of Channel objects 297 channelList = [Channel().populate({'label': x}) for x in channelList] 298 299 # Since we're dealing with superusers, we allow them to change the org 300 # id 301 # XXX check if we don't open ourselves too much (misa 20030422) 302 org_id = info.get('orgId') 303 if org_id == '': 304 org_id = None 305 306 batch = Collection() 307 package_keys = ['name', 'version', 'release', 'epoch', 'arch'] 308 for package in packageList: 309 for k in package_keys: 310 if k not in package: 311 raise Exception("Missing key %s" % k) 312 if k == 'epoch': 313 if package[k] is not None: 314 if package[k] == '': 315 package[k] = None 316 else: 317 package[k] = str(package[k]) 318 else: 319 package[k] = str(package[k]) 320 321 if package['arch'] == 'src' or package['arch'] == 'nosrc': 322 # Source package - no reason to continue 323 continue 324 _checksum_sql_filter = "" 325 if 'md5sum' in package: # for old rhnpush compatibility 326 package['checksum_type'] = 'md5' 327 package['checksum'] = package['md5sum'] 328 329 exec_args = { 330 'name': package['name'], 331 'pkg_epoch': package['epoch'], 332 'pkg_version': package['version'], 333 'pkg_rel': package['release'], 334 'pkg_arch': package['arch'], 335 'orgid': org_id 336 } 337 338 if 'checksum' in package and CFG.ENABLE_NVREA: 339 _checksum_sql_filter = """and c.checksum = :checksum 340 and c.checksum_type = :checksum_type""" 341 exec_args.update({'checksum_type': package['checksum_type'], 342 'checksum': package['checksum']}) 343 344 h = rhnSQL.prepare(self._get_pkg_info_query % 345 _checksum_sql_filter) 346 h.execute(**exec_args) 347 row = h.fetchone_dict() 348 349 package['checksum_type'] = row['checksum_type'] 350 package['checksum'] = row['checksum'] 351 package['org_id'] = org_id 352 package['channels'] = channelList 353 batch.append(IncompletePackage().populate(package)) 354 355 caller = "server.app.channelPackageSubscription" 356 357 backend = SQLBackend() 358 importer = ChannelPackageSubscription(batch, backend, caller=caller) 359 try: 360 importer.run() 361 except IncompatibleArchError: 362 e = sys.exc_info()[1] 363 raise_with_tb(rhnFault(50, string.join(e.args), explain=0), sys.exc_info()[2]) 364 except InvalidChannelError: 365 e = sys.exc_info()[1] 366 raise_with_tb(rhnFault(50, str(e), explain=0), sys.exc_info()[2]) 367 368 affected_channels = importer.affected_channels 369 370 log_debug(3, "Computing errata cache for systems affected by channels", 371 affected_channels) 372 373 schedule_errata_cache_update(affected_channels) 374 rhnSQL.commit() 375 376 return 0
377
378 - def getAnyChecksum(self, info, username=None, password=None, session=None, is_source=0):
379 """ returns checksum info of available packages 380 also does an existance check on the filesystem. 381 """ 382 log_debug(3) 383 384 pkg_infos = info.get('packages') 385 channels = info.get('channels', []) 386 force = info.get('force', 0) 387 orgid = info.get('org_id') 388 389 if orgid == 'null': 390 null_org = 1 391 else: 392 null_org = None 393 394 if not session: 395 org_id, force = rhnPackageUpload.authenticate(username, password, 396 channels=channels, 397 null_org=null_org, 398 force=force) 399 else: 400 try: 401 org_id, force = rhnPackageUpload.authenticate_session( 402 session, channels=channels, null_org=null_org, force=force) 403 except rhnSession.InvalidSessionError: 404 raise_with_tb(rhnFault(33), sys.exc_info()[2]) 405 except rhnSession.ExpiredSessionError: 406 raise_with_tb(rhnFault(34), sys.exc_info()[2]) 407 408 if is_source: 409 ret = self._getSourcePackageChecksum(org_id, pkg_infos) 410 else: 411 ret = self._getPackageChecksum(org_id, pkg_infos) 412 return ret
413
414 - def getPackageChecksum(self, username, password, info):
416
417 - def getPackageMD5sum(self, username, password, info):
418 """ bug#177762 gives md5sum info of available packages. 419 also does an existance check on the filesystem. 420 """ 421 log_debug(3) 422 self._MD5sum2Checksum_info(info) 423 return self._Checksum2MD5sum_list( 424 self.getPackageChecksum(username, password, info))
425
426 - def getPackageChecksumBySession(self, session_string, info):
427 return self.getAnyChecksum(info, session=session_string)
428
429 - def getPackageMD5sumBySession(self, session_string, info):
430 log_debug(3) 431 self._MD5sum2Checksum_info(info) 432 return self._Checksum2MD5sum_list( 433 self.getPackageChecksumBySession(session_string, info))
434 435 _get_pkg_info_query = """ 436 select 437 c.checksum_type, 438 c.checksum, 439 p.path path 440 from 441 rhnPackageEVR pe, 442 rhnPackageName pn, 443 rhnPackage p, 444 rhnPackageArch pa, 445 rhnChecksumView c 446 where 447 pn.name = :name 448 and ( pe.epoch = :pkg_epoch or 449 ( pe.epoch is null and :pkg_epoch is null ) 450 ) 451 and pe.version = :pkg_version 452 and pe.release = :pkg_rel 453 and ( p.org_id = :orgid or 454 ( p.org_id is null and :orgid is null ) 455 ) 456 and p.name_id = pn.id 457 and p.evr_id = pe.id 458 and p.package_arch_id = pa.id 459 and pa.label = :pkg_arch 460 and p.checksum_id = c.id 461 %s 462 """ 463
464 - def _getPackageChecksum(self, org_id, pkg_infos):
465 log_debug(3) 466 row_list = {} 467 checksum_exists = 0 468 for pkg in pkg_infos.keys(): 469 470 pkg_info = pkg_infos[pkg] 471 pkg_epoch = pkg_info['epoch'] 472 if pkg_epoch is not None: 473 # Force empty strings to None (NULLs in database) 474 if pkg_epoch == '': 475 pkg_epoch = None 476 # and force numbers to strings 477 else: 478 pkg_epoch = str(pkg_epoch) 479 480 query_args = { 481 'name': pkg_info['name'], 482 'pkg_epoch': pkg_epoch, 483 'pkg_version': str(pkg_info['version']), 484 'pkg_rel': str(pkg_info['release']), 485 'pkg_arch': pkg_info['arch'], 486 'orgid': org_id, 487 } 488 489 _checksum_sql_filter = "" 490 if 'checksum' in pkg_info and CFG.ENABLE_NVREA: 491 _checksum_sql_filter = """and c.checksum = :checksum 492 and c.checksum_type = :checksum_type""" 493 query_args.update({ 494 'checksum_type': pkg_info['checksum_type'], 495 'checksum': pkg_info['checksum'], 496 }) 497 498 h = rhnSQL.prepare(self._get_pkg_info_query % _checksum_sql_filter) 499 row_list[pkg] = self._get_package_checksum(h, query_args) 500 501 return row_list
502
503 - def _get_package_checksum(self, h, query_args):
504 h.execute(**query_args) 505 row = h.fetchone_dict() 506 if not row: 507 ret = '' 508 elif row.get('path'): 509 filePath = os.path.join(CFG.MOUNT_POINT, row['path']) 510 if os.access(filePath, os.R_OK): 511 if 'checksum' in row: 512 ret = (row['checksum_type'], row['checksum']) 513 else: 514 ret = 'on-disk' 515 else: 516 # Package not found on the filesystem 517 log_error("Package not found", filePath) 518 ret = '' 519 else: 520 log_error("Package path null for package", query_args['name']) 521 ret = '' 522 return ret
523
524 - def _MD5sum2Checksum_info(self, info):
525 log_debug(5) 526 pkg_infos = info.get('packages') 527 for pkg in pkg_infos.keys(): 528 if 'md5sum' in pkg_infos[pkg]: 529 pkg_infos[pkg]['checksum_type'] = 'md5' 530 pkg_infos[pkg]['checksum'] = pkg_infos[pkg]['md5sum'] 531 del(pkg_infos[pkg]['md5sum'])
532
533 - def _Checksum2MD5sum_list(self, checksum_list):
534 log_debug(5) 535 row_list = {} 536 for k in checksum_list.keys(): 537 if checksum_list[k] == '' or checksum_list[k] == 'on-disk': 538 row_list[k] = checksum_list[k] 539 elif type(checksum_list[k]) == TupleType and checksum_list[k][0] == 'md5': 540 row_list[k] = checksum_list[k][1] 541 else: 542 row_list[k] = '' 543 return row_list
544
545 - def getSourcePackageChecksum(self, username, password, info):
546 return self.getAnyChecksum(info, username=username, password=password, is_source=1)
547
548 - def getSourcePackageMD5sum(self, username, password, info):
553
554 - def getSourcePackageChecksumBySession(self, session_string, info):
555 return self.getAnyChecksum(info, session=session_string, is_source=1)
556
557 - def getSourcePackageMD5sumBySession(self, session_string, info):
558 log_debug(3) 559 self._MD5sum2Checksum_info(info) 560 return self._Checksum2MD5sum_list( 561 self.getSourcePackageChecksumBySession(session_string, info))
562
563 - def _getSourcePackageChecksum(self, org_id, pkg_infos):
564 """ Gives checksum info of available source packages. 565 Also does an existance check on the filesystem. 566 """ 567 568 log_debug(3) 569 570 statement = """ 571 select 572 ps.path path, 573 c.checksum, 574 c.checksum_type 575 from 576 rhnSourceRpm sr, 577 rhnPackageSource ps, 578 rhnChecksumView c 579 where 580 sr.name = :name 581 and ps.source_rpm_id = sr.id 582 and ( ps.org_id = :orgid or 583 ( ps.org_id is null and :orgid is null ) 584 ) 585 and ps.checksum_id = c.id 586 """ 587 h = rhnSQL.prepare(statement) 588 row_list = {} 589 for pkg in pkg_infos.keys(): 590 row_list[pkg] = self._get_package_checksum(h, 591 {'name': pkg, 'orgid': org_id}) 592 return row_list
593 594
595 -def auth(login, password):
596 """ Authorize this user. """ 597 authobj = UserAuth() 598 authobj.auth(login, password) 599 return authobj
600 601
602 -def auth_session(session_string):
603 """ Authenticate based on a session. """ 604 authobj = UserAuth() 605 authobj.auth_session(session_string) 606 return authobj
607