Package backend :: Package satellite_tools :: Module contentRemove
[hide private]
[frames] | no frames]

Source Code for Module backend.satellite_tools.contentRemove

  1  # Copyright (c) 2016--2018 Red Hat, Inc. 
  2  # 
  3  # This software is licensed to you under the GNU General Public License, 
  4  # version 2 (GPLv2). There is NO WARRANTY for this software, express or 
  5  # implied, including the implied warranties of MERCHANTABILITY or FITNESS 
  6  # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 
  7  # along with this software; if not, see 
  8  # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 
  9  # 
 10  # Red Hat trademarks are not licensed under GPLv2. No permission is 
 11  # granted to use or replicate Red Hat trademarks that are incorporated 
 12  # in this software or its documentation. 
 13  # 
 14   
 15  import os 
 16  import shutil 
 17  import sys 
 18  from spacewalk.common.rhnConfig import CFG 
 19  from spacewalk.common.rhnLog import log_debug, log_error 
 20  from spacewalk.satellite_tools.progress_bar import ProgressBar 
 21  from spacewalk.server.rhnPackage import unlink_package_file 
 22  from spacewalk.server import rhnSQL 
 23   
 24   
25 -def __serverCheck(labels, unsubscribe):
26 sql = """ 27 select distinct S.org_id, S.id, S.name 28 from rhnChannel c inner join 29 rhnServerChannel sc on c.id = sc.channel_id inner join 30 rhnServer s on s.id = sc.server_id 31 where c.label in (%s) 32 """ 33 params, bind_params = _bind_many(labels) 34 bind_params = ', '.join(bind_params) 35 h = rhnSQL.prepare(sql % (bind_params)) 36 h.execute(**params) 37 server_list = h.fetchall_dict() 38 if not server_list: 39 return 0 40 41 if unsubscribe: 42 return __unsubscribeServers(labels) 43 44 print("\nCurrently there are systems subscribed to one or more of the specified channels.") 45 print("If you would like to automatically unsubscribe these systems, simply use the --unsubscribe flag.\n") 46 print("The following systems were found to be subscribed:") 47 48 print("%-8s %-14s name" % ('org_id', 'id')) 49 print("-" * 32) 50 for server in server_list: 51 print("%-8s %-14s %s" % (server['org_id'], server['id'], server['name'])) 52 53 return len(server_list)
54 55
56 -def __unsubscribeServers(labels):
57 sql = """ 58 select distinct sc.server_id as server_id, C.id as channel_id, c.parent_channel, c.label 59 from rhnChannel c inner join 60 rhnServerChannel sc on c.id = sc.channel_id 61 where c.label in (%s) order by C.parent_channel 62 """ 63 params, bind_params = _bind_many(labels) 64 bind_params = ', '.join(bind_params) 65 h = rhnSQL.prepare(sql % (bind_params)) 66 h.execute(**params) 67 server_channel_list = h.fetchall_dict() 68 69 channel_counts = {} 70 for i in server_channel_list: 71 if i['label'] in channel_counts: 72 channel_counts[i['label']] = channel_counts[i['label']] + 1 73 else: 74 channel_counts[i['label']] = 1 75 print("\nThe following channels will have their systems unsubscribed:") 76 channel_list = channel_counts.keys() 77 channel_list.sort() 78 for i in channel_list: 79 print("%-40s %-8s" % (i, channel_counts[i])) 80 81 pb = ProgressBar(prompt='Unsubscribing: ', endTag=' - complete', 82 finalSize=len(server_channel_list), finalBarLength=40, stream=sys.stdout) 83 pb.printAll(1) 84 85 unsubscribe_server_proc = rhnSQL.Procedure("rhn_channel.unsubscribe_server") 86 for i in server_channel_list: 87 unsubscribe_server_proc(i['server_id'], i['channel_id']) 88 pb.addTo(1) 89 pb.printIncrement() 90 pb.printComplete()
91 92
93 -def __kickstartCheck(labels):
94 sql = """ 95 select K.org_id, K.label 96 from rhnKSData K inner join 97 rhnKickstartDefaults KD on KD.kickstart_id = K.id inner join 98 rhnKickstartableTree KT on KT.id = KD.kstree_id inner join 99 rhnChannel c on c.id = KT.channel_id 100 where c.label in (%s) 101 """ 102 params, bind_params = _bind_many(labels) 103 bind_params = ', '.join(bind_params) 104 h = rhnSQL.prepare(sql % (bind_params)) 105 h.execute(**params) 106 kickstart_list = h.fetchall_dict() 107 108 if not kickstart_list: 109 return 0 110 111 print("The following kickstarts are associated with one of the specified channels. " + 112 "Please remove these or change their associated base channel.\n") 113 print("%-8s label" % 'org_id') 114 print("-" * 20) 115 for kickstart in kickstart_list: 116 print("%-8s %s" % (kickstart['org_id'], kickstart['label'])) 117 118 return len(kickstart_list)
119 120
121 -def __listChannels():
122 sql = """ 123 select c1.label, c2.label parent_channel 124 from rhnChannel c1 left outer join rhnChannel c2 on c1.parent_channel = c2.id 125 order by c2.label desc, c1.label asc 126 """ 127 h = rhnSQL.prepare(sql) 128 h.execute() 129 labels = {} 130 parents = {} 131 while 1: 132 row = h.fetchone_dict() 133 if not row: 134 break 135 parent_channel = row['parent_channel'] 136 labels[row['label']] = parent_channel 137 if not parent_channel: 138 parents[row['label']] = [] 139 140 if parent_channel: 141 parents[parent_channel].append(row['label']) 142 143 return labels, parents
144 145
146 -def delete_outside_channels(org):
147 rpms_ids = list_packages_without_channels(org, sources=0) 148 rpms_paths = _get_package_paths(rpms_ids, sources=0) 149 srpms_ids = list_packages_without_channels(org, sources=1) 150 srpms_paths = _get_package_paths(srpms_ids, sources=1) 151 152 _delete_srpms(srpms_ids) 153 _delete_rpms(rpms_ids) 154 155 _delete_files(rpms_paths + srpms_paths)
156 157
158 -def delete_channels(channelLabels, force=0, justdb=0, skip_packages=0, skip_channels=0, 159 skip_kickstart_trees=0, just_kickstart_trees=0):
160 # Get the package ids 161 if not channelLabels: 162 return 163 164 rpms_ids = list_packages(channelLabels, force=force, sources=0) 165 rpms_paths = _get_package_paths(rpms_ids, sources=0) 166 srpms_ids = list_packages(channelLabels, force=force, sources=1) 167 srpms_paths = _get_package_paths(srpms_ids, sources=1) 168 169 if not skip_packages and not just_kickstart_trees: 170 _delete_srpms(srpms_ids) 171 _delete_rpms(rpms_ids) 172 173 if not skip_kickstart_trees and not justdb: 174 _delete_ks_files(channelLabels) 175 176 if not justdb and not skip_packages and not just_kickstart_trees: 177 _delete_files(rpms_paths + srpms_paths) 178 179 # Get the channel ids 180 h = rhnSQL.prepare(""" 181 select id, parent_channel 182 from rhnChannel 183 where label = :label 184 order by parent_channel""") 185 channel_ids = [] 186 for label in channelLabels: 187 h.execute(label=label) 188 row = h.fetchone_dict() 189 if not row: 190 break 191 channel_id = row['id'] 192 if row['parent_channel']: 193 # Subchannel, we have to remove it first 194 channel_ids.insert(0, channel_id) 195 else: 196 channel_ids.append(channel_id) 197 198 if not channel_ids: 199 return 200 201 indirect_tables = [ 202 ['rhnKickstartableTree', 'channel_id', 'rhnKSTreeFile', 'kstree_id'], 203 ] 204 query = """ 205 delete from %(table_2)s where %(link_field)s in ( 206 select id 207 from %(table_1)s 208 where %(channel_field)s = :channel_id 209 ) 210 """ 211 for e in indirect_tables: 212 args = { 213 'table_1': e[0], 214 'channel_field': e[1], 215 'table_2': e[2], 216 'link_field': e[3], 217 } 218 h = rhnSQL.prepare(query % args) 219 h.executemany(channel_id=channel_ids) 220 221 tables = [ 222 ['rhnErrataFileChannel', 'channel_id'], 223 ['rhnErrataNotificationQueue', 'channel_id'], 224 ['rhnChannelErrata', 'channel_id'], 225 ['rhnChannelPackage', 'channel_id'], 226 ['rhnRegTokenChannels', 'channel_id'], 227 ['rhnServerProfile', 'base_channel'], 228 ['rhnKickstartableTree', 'channel_id'], 229 ] 230 231 if not skip_channels: 232 tables.extend([ 233 ['rhnChannelFamilyMembers', 'channel_id'], 234 ['rhnDistChannelMap', 'channel_id'], 235 ['rhnReleaseChannelMap', 'channel_id'], 236 ['rhnChannel', 'id'], 237 ]) 238 239 if just_kickstart_trees: 240 tables = [['rhnKickstartableTree', 'channel_id']] 241 242 query = "delete from %s where %s = :channel_id" 243 for table, field in tables: 244 log_debug(3, "Processing table %s" % table) 245 h = rhnSQL.prepare(query % (table, field)) 246 h.executemany(channel_id=channel_ids) 247 248 if not justdb and not just_kickstart_trees: 249 __deleteRepoData(channelLabels)
250 251
252 -def __deleteRepoData(labels):
253 directory = '/var/cache/' + CFG.repomd_path_prefix 254 for label in labels: 255 if os.path.isdir(directory + '/' + label): 256 shutil.rmtree(directory + '/' + label)
257 258
259 -def list_packages_without_channels(org_id, sources=0):
260 """List packages in given org outside any channel""" 261 262 if sources: 263 query = """ 264 select ps.id from rhnPackage p inner join 265 rhnPackageSource ps on p.source_rpm_id = ps.source_rpm_id left join 266 rhnChannelPackage cp on cp.package_id = p.id 267 where cp.channel_id is null 268 """ 269 else: 270 query = """ 271 select p.id from rhnPackage p left join 272 rhnChannelPackage cp on cp.package_id = p.id 273 where cp.channel_id is null 274 """ 275 276 if org_id: 277 query += """ 278 and p.org_id = :org_id 279 """ 280 if sources: 281 query += """ 282 and p.org_id = ps.org_id 283 """ 284 else: 285 query += """ 286 and p.org_id is null 287 """ 288 if sources: 289 query += """ 290 and ps.org_id is null 291 """ 292 293 h = rhnSQL.prepare(query) 294 h.execute(org_id=org_id) 295 296 return [x['id'] for x in h.fetchall_dict() or []]
297 298
299 -def list_packages(channelLabels, sources=0, force=0):
300 "List the source ids for the channels" 301 if sources: 302 packages = "srpms" 303 else: 304 packages = "rpms" 305 log_debug(3, "Listing %s" % packages) 306 if not channelLabels: 307 return [] 308 309 params, bind_params = _bind_many(channelLabels) 310 bind_params = ', '.join(bind_params) 311 312 if sources: 313 templ = _templ_srpms() 314 else: 315 templ = _templ_rpms() 316 317 if force: 318 query = templ % ("", bind_params) 319 else: 320 if CFG.DB_BACKEND == 'oracle': 321 minus_op = 'MINUS' # ORA syntax 322 else: 323 minus_op = 'EXCEPT' # ANSI syntax 324 query = """ 325 %s 326 %s 327 %s 328 """ % ( 329 templ % ("", bind_params), 330 minus_op, 331 templ % ("not", bind_params), 332 ) 333 h = rhnSQL.prepare(query) 334 h.execute(**params) 335 return [x['id'] for x in h.fetchall_dict() or []]
336 337
338 -def _templ_rpms():
339 "Returns a template for querying rpms" 340 log_debug(4, "Generating template for querying rpms") 341 return """\ 342 select cp.package_id id 343 from rhnChannel c, rhnChannelPackage cp 344 where c.label %s in (%s) 345 and cp.channel_id = c.id"""
346 347
348 -def _templ_srpms():
349 "Returns a template for querying srpms" 350 log_debug(4, "Generating template for querying srpms") 351 return """\ 352 select ps.id id 353 from rhnPackage p, 354 rhnPackageSource ps, 355 rhnChannelPackage cp, 356 rhnChannel c 357 where c.label %s in (%s) 358 and c.id = cp.channel_id 359 and cp.package_id = p.id 360 and p.source_rpm_id = ps.source_rpm_id 361 and ((p.org_id is null and ps.org_id is null) or 362 p.org_id = ps.org_id)"""
363 364
365 -def _delete_srpms(srcPackageIds):
366 """Blow away rhnPackageSource and rhnFile entries. 367 """ 368 if not srcPackageIds: 369 return 370 # nuke the rhnPackageSource entry 371 h = rhnSQL.prepare(""" 372 delete 373 from rhnPackageSource 374 where id = :id 375 """) 376 count = h.executemany(id=srcPackageIds) 377 if not count: 378 count = 0 379 log_debug(2, "Successfully deleted %s/%s source package ids" % ( 380 count, len(srcPackageIds)))
381 382
383 -def _delete_rpms(packageIds):
384 if not packageIds: 385 return 386 group = 300 387 toDel = packageIds[:] 388 print "Deleting package metadata (" + str(len(toDel)) + "):" 389 pb = ProgressBar(prompt='Removing: ', endTag=' - complete', 390 finalSize=len(packageIds), finalBarLength=40, stream=sys.stdout) 391 pb.printAll(1) 392 393 while toDel: 394 _delete_rpm_group(toDel[:group]) 395 del toDel[:group] 396 pb.addTo(group) 397 pb.printIncrement() 398 pb.printComplete()
399 400
401 -def _delete_rpm_group(packageIds):
402 403 references = [ 404 'rhnChannelPackage', 405 'rhnErrataPackage', 406 'rhnErrataPackageTMP', 407 'rhnPackageChangelogRec', 408 'rhnPackageConflicts', 409 'rhnPackageFile', 410 'rhnPackageObsoletes', 411 'rhnPackageProvides', 412 'rhnPackageRequires', 413 'rhnPackageRecommends', 414 'rhnPackageSuggests', 415 'rhnPackageSupplements', 416 'rhnPackageEnhances', 417 'rhnPackageBreaks', 418 'rhnPackagePredepends', 419 'rhnServerNeededCache', 420 ] 421 deleteStatement = "delete from %s where package_id = :package_id" 422 for table in references: 423 h = rhnSQL.prepare(deleteStatement % table) 424 count = h.executemany(package_id=packageIds) 425 log_debug(3, "Deleted from %s: %d rows" % (table, count)) 426 deleteStatement = "delete from rhnPackage where id = :package_id" 427 h = rhnSQL.prepare(deleteStatement) 428 count = h.executemany(package_id=packageIds) 429 if count: 430 log_debug(2, "DELETED package id %s" % str(packageIds)) 431 else: 432 log_error("No such package id %s" % str(packageIds)) 433 rhnSQL.commit()
434 435
436 -def _delete_files(relpaths):
437 for relpath in relpaths: 438 path = os.path.join(CFG.MOUNT_POINT, relpath) 439 if not os.path.exists(path): 440 log_debug(1, "Not removing %s: no such file" % path) 441 continue 442 unlink_package_file(path)
443 444
445 -def _bind_many(l):
446 h = {} 447 lr = [] 448 for i, item in enumerate(l): 449 key = 'p_%s' % i 450 h[key] = item 451 lr.append(':' + key) 452 return h, lr
453 454
455 -def _get_package_paths(package_ids, sources=0):
456 if sources: 457 table = "rhnPackageSource" 458 else: 459 table = "rhnPackage" 460 h = rhnSQL.prepare("select path from %s where id = :package_id" % table) 461 pdict = {} 462 for package_id in package_ids: 463 h.execute(package_id=package_id) 464 row = h.fetchone_dict() 465 if not row: 466 continue 467 if not row['path']: 468 continue 469 pdict[row['path']] = None 470 471 return pdict.keys()
472 473
474 -def _delete_ks_files(channel_labels):
475 sql = """ 476 select kt.base_path 477 from rhnChannel c 478 join rhnKickstartableTree kt on c.id = kt.channel_id 479 where c.label in (%s) and not exists ( 480 select 1 481 from rhnKickstartableTree ktx 482 join rhnChannel cx on cx.id = ktx.channel_id 483 where replace(ktx.base_path, :mnt_point, '') = 484 replace(kt.base_path, :mnt_point, '') 485 and cx.label not in (%s)) 486 """ 487 488 params, bind_params = _bind_many(channel_labels) 489 params['mnt_point'] = CFG.MOUNT_POINT + '/' 490 bind_params = ', '.join(bind_params) 491 h = rhnSQL.prepare(sql % (bind_params, bind_params)) 492 h.execute(**params) 493 kickstart_list = h.fetchall_dict() or [] 494 495 for kickstart in kickstart_list: 496 path = os.path.join(CFG.MOUNT_POINT, str(kickstart['base_path'])) 497 if not os.path.exists(path): 498 log_debug(1, "Not removing %s: no such file" % path) 499 continue 500 shutil.rmtree(path)
501