Package backend :: Package server :: Package rhnServer :: Module server_token
[hide private]
[frames] | no frames]

Source Code for Module backend.server.rhnServer.server_token

   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  # this module handles the token registration code for a server 
  16  # 
  17   
  18  import sys 
  19   
  20  from spacewalk.common import rhnFlags 
  21  from spacewalk.common.usix import raise_with_tb 
  22  from spacewalk.common.rhnLog import log_debug, log_error 
  23  from spacewalk.common.rhnException import rhnFault, rhnException 
  24  from spacewalk.common.rhnTranslate import _ 
  25  from spacewalk.server import rhnSQL, rhnChannel, rhnAction 
  26   
  27  from server_lib import join_server_group 
  28   
  29  VIRT_ENT_LABEL = 'virtualization_host' 
  30   
31 -def token_channels(server, server_arch, tokens_obj):
32 """ Handle channel subscriptions for the registration token """ 33 assert(isinstance(tokens_obj, ActivationTokens)) 34 35 server_id, server_arch_id = server['id'], server['server_arch_id'] 36 37 # what channels are associated with this token (filter only those 38 # compatible with this server) 39 h = rhnSQL.prepare(""" 40 select 41 rtc.channel_id id, c.name, c.label, c.parent_channel 42 from 43 rhnRegTokenChannels rtc, 44 rhnChannel c, 45 rhnServerChannelArchCompat scac 46 where rtc.token_id = :token_id 47 and rtc.channel_id = c.id 48 and c.channel_arch_id = scac.channel_arch_id 49 and scac.server_arch_id = :server_arch_id 50 """) 51 52 chash = {} 53 base_channel_token = None 54 base_channel_id = None 55 56 for token in tokens_obj.tokens: 57 token_id = token['token_id'] 58 h.execute(token_id=token_id, server_arch_id=server_arch_id) 59 while 1: 60 row = h.fetchone_dict() 61 if not row: 62 break 63 channel_id = row['id'] 64 chash[channel_id] = row 65 if row['parent_channel'] is not None: 66 # Not a base channel 67 continue 68 69 # We only allow for one base channel 70 if base_channel_id is not None and channel_id != base_channel_id: 71 # Base channels conflict - are they coming from the same 72 # token? 73 if base_channel_token == token: 74 log_error("Token has multiple base channels", token_id, 75 base_channel_id) 76 raise rhnFault(62, 77 _("Token `%s' has more than one base channel assigned") 78 % token['note']) 79 raise rhnFault(63, _("Conflicting base channels")) 80 base_channel_id = channel_id 81 base_channel_token = token 82 83 bc = chash.get(base_channel_id) 84 log_debug(4, "base channel", bc) 85 86 # get the base channel for this server 87 # Note that we are hitting this codepath after newserver.__save() has been 88 # run, which means we've already chosen a base channel 89 # from rhnDistChannelMap 90 sbc = rhnChannel.get_base_channel(server_id, none_ok=1) 91 92 # prepare the return value 93 ret = [] 94 95 # now try to figure out which base channel we prefer 96 if bc is None: 97 if sbc is None: 98 # we need at least one base channel definition 99 log_error("Server has invalid release and " 100 "token contains no base channels", server_id, 101 tokens_obj.tokens) 102 ret.append("System registered without a base channel") 103 ret.append("Unsupported release-architecture combination " 104 "(%s, %s)" % (server["release"], server_arch)) 105 return ret 106 else: # do we need to drop the one from sbc? 107 if sbc and sbc["id"] != bc["id"]: # we need to prefer the token one 108 # unsubscribe from old channel(s) 109 rhnChannel.unsubscribe_all_channels(server_id) 110 sbc = None # force true on the next test 111 if sbc is None: 112 # no base channel subscription at this point 113 rhnChannel.subscribe_sql(server_id, bc["id"], commit=0) 114 ret.append("Subscribed to base channel '%s' (%s)" % ( 115 bc["name"], bc["label"])) 116 sbc = bc 117 118 # attempt to subscribe all non-base channels associated with this 119 # token 120 subscribe_channel = rhnSQL.Procedure("rhn_channel.subscribe_server") 121 # Use a set here to ensure uniqueness of the 122 # channel family ids used in the loop below. 123 channel_family_ids = set() 124 125 for c in [a for a in chash.values() if a["parent_channel"]]: 126 # make sure this channel has the right parent 127 if str(c["parent_channel"]) != str(sbc["id"]): 128 ret.append("NOT subscribed to channel '%s' " 129 "(not a child of '%s')" % ( 130 c["name"], sbc["name"])) 131 continue 132 try: 133 # don't run the EC yet 134 # XXX: test return code when this one will start returning 135 # a status 136 subscribe_channel(server_id, c["id"], 0, None) 137 child = rhnChannel.Channel() 138 child.load_by_id(c["id"]) 139 child._load_channel_families() 140 cfamid = child._channel_families[0] 141 channel_family_ids.add(cfamid) 142 except rhnSQL.SQLError: 143 e = sys.exc_info()[1] 144 log_error("Failed channel subscription", server_id, 145 c["id"], c["label"], c["name"]) 146 ret.append("FAILED to subscribe to channel '%s'" % c["name"]) 147 else: 148 ret.append("Subscribed to channel '%s'" % c["name"]) 149 150 log_debug(5, "cf ids: %s" % str(channel_family_ids)) 151 log_debug(5, "Server org_id: %s" % str(server['org_id'])) 152 153 return ret
154 155 _query_token_server_groups = rhnSQL.Statement(""" 156 select rtg.server_group_id, sg.name 157 from rhnRegTokenGroups rtg, rhnServerGroup sg 158 where rtg.token_id = :token_id 159 and sg.id = rtg.server_group_id 160 """) 161 162
163 -def token_server_groups(server_id, tokens_obj):
164 """ Handle server group subscriptions for the registration token """ 165 assert(isinstance(tokens_obj, ActivationTokens)) 166 h = rhnSQL.prepare(_query_token_server_groups) 167 server_groups = {} 168 for token in tokens_obj.tokens: 169 token_id = token['token_id'] 170 h.execute(token_id=token_id) 171 while 1: 172 row = h.fetchone_dict() 173 if not row: 174 break 175 server_group_id = row['server_group_id'] 176 server_groups[server_group_id] = row 177 178 # Now try to subscribe server to group 179 ret = [] 180 for server_group_id, sg in server_groups.items(): 181 log_debug(4, "token server group", sg) 182 183 try: 184 join_server_group(server_id, server_group_id) 185 except rhnSQL.SQLError: 186 e = sys.exc_info()[1] 187 log_error("Failed to add server to group", server_id, 188 server_group_id, sg["name"]) 189 raise_with_tb(rhnFault(80, _("Failed to add server to group %s") % 190 sg["name"]), sys.exc_info()[2]) 191 else: 192 ret.append("Subscribed to server group '%s'" % sg["name"]) 193 return ret
194 195 196 _query_token_packages = rhnSQL.Statement(""" 197 select pn.id as name_id, pa.id as arch_id, pn.name 198 from rhnPackageName pn, rhnRegTokenPackages rtp 199 left outer join rhnPackageArch pa on rtp.arch_id = pa.id 200 where rtp.token_id = :token_id 201 and rtp.name_id = pn.id 202 order by upper(pn.name) 203 """) 204 _query_token_packages_insert = rhnSQL.Statement(""" 205 insert into rhnActionPackage (id, action_id, name_id, parameter) 206 values (sequence_nextval('rhn_act_p_id_seq'), :action_id, :name_id, 'upgrade') 207 """) 208 209
210 -def token_packages(server_id, tokens_obj):
211 assert(isinstance(tokens_obj, ActivationTokens)) 212 213 h = rhnSQL.prepare(_query_token_packages) 214 package_names = {} 215 for token in tokens_obj.tokens: 216 token_id = token['token_id'] 217 h.execute(token_id=token_id) 218 while True: 219 row = h.fetchone_dict() 220 if not row: 221 break 222 pn_id = row['name_id'] 223 pa_id = row['arch_id'] 224 package_names[(pn_id, pa_id)] = row['name'] 225 226 ret = [] 227 if not package_names: 228 return ret 229 230 package_arch_ids = list(package_names.keys()) 231 # Get the latest action scheduled for this token 232 last_action_id = rhnFlags.get('token_last_action_id') 233 234 action_id = rhnAction.schedule_server_packages_update_by_arch(server_id, 235 package_arch_ids, org_id=token['org_id'], 236 prerequisite=last_action_id, 237 action_name="Activation Key Package Auto-Install") 238 239 # This action becomes the latest now 240 rhnFlags.set('token_last_action_id', action_id) 241 242 for p in package_names.values(): 243 ret.append("Scheduled for install: '%s'" % p) 244 245 rhnSQL.commit() 246 247 return ret
248 249 250 # given 2 channels, with one pathname overlap, you'll get 251 # something like: 252 # id=1, '/etc/foo.txt', priority=1 253 # id=27, '/etc/foo.txt', priority=2 254 # id=53, '/var/tmp/baz.log', priority=2 255 _query_token_latest_revisions = rhnSQL.Statement(""" 256 select cf.latest_config_revision_id revision_id, 257 cfn.path 258 from rhnConfigFileName cfn, 259 rhnConfigFile cf, 260 rhnConfigChannelType cct, 261 rhnConfigChannel cc, 262 rhnServerConfigChannel scc 263 where scc.server_id = :server_id 264 and scc.config_channel_id = cc.id 265 and cc.confchan_type_id = cct.id 266 and cct.label != 'server_import' 267 and cc.id = cf.config_channel_id 268 and cf.config_file_name_id = cfn.id 269 -- latest_config_revision_id should always be non-null but 270 -- we should protect ourselves 271 and cf.latest_config_revision_id is not null 272 order by cfn.path, cct.priority, scc.position 273 """) 274 275 _query_add_revision_to_action = rhnSQL.Statement(""" 276 insert into rhnActionConfigRevision (id, action_id, server_id, config_revision_id) 277 values (sequence_nextval('rhn_actioncr_id_seq'), :action_id, :server_id, :config_revision_id) 278 """) 279 280
281 -def deploy_configs_if_needed(server):
282 server_id = server['id'] 283 log_debug(4, server_id) 284 # determine if there are actually any files to be deployed... 285 revisions = {} 286 287 h = rhnSQL.prepare(_query_token_latest_revisions) 288 h.execute(server_id=server_id) 289 290 while 1: 291 row = h.fetchone_dict() 292 if not row: 293 break 294 295 # only care about the 1st revision of a particular path due to 296 # sql ordering... 297 if row['path'] not in revisions: 298 revisions[row['path']] = row['revision_id'] 299 300 if not len(revisions): 301 return None 302 303 # Get the latest action scheduled for this token 304 last_action_id = rhnFlags.get('token_last_action_id') 305 306 action_id = rhnAction.schedule_server_action( 307 server_id, 308 action_type='activation.schedule_deploy', 309 action_name="Activation Key Config File Deployment", 310 delta_time=0, scheduler=None, 311 org_id=server['org_id'], 312 prerequisite=last_action_id, 313 ) 314 315 # This action becomes the latest now 316 rhnFlags.set('token_last_action_id', action_id) 317 318 log_debug(4, "scheduled activation key config deploy") 319 320 h = rhnSQL.prepare(_query_add_revision_to_action) 321 # XXX should use executemany() or execute_bulk 322 for revision_id in revisions.values(): 323 log_debug(5, action_id, revision_id) 324 h.execute(server_id=server_id, 325 action_id=action_id, 326 config_revision_id=revision_id) 327 328 return action_id
329 330 331 _query_token_config_channels = rhnSQL.Statement(""" 332 select rtcc.config_channel_id, 333 rtcc.position, cc.name 334 from rhnConfigChannel cc, 335 rhnRegTokenConfigChannels rtcc 336 where rtcc.token_id = :token_id 337 and rtcc.config_channel_id = cc.id 338 order by rtcc.position 339 """) 340 341 # XXX Same query exists in config/rhn_config_management.py 342 _query_set_server_config_channels = rhnSQL.Statement(""" 343 insert into rhnServerConfigChannel (server_id, config_channel_id, position) 344 values (:server_id, :config_channel_id, :position) 345 """) 346 347
348 -def _get_token_config_channels(token_id):
349 h = rhnSQL.prepare(_query_token_config_channels) 350 h.execute(token_id=token_id) 351 352 return h.fetchall_dict() or []
353 354 _query_current_config_channels = rhnSQL.Statement(""" 355 select config_channel_id 356 from rhnServerConfigChannel 357 where server_id = :server_id 358 and position is not null 359 """) 360 361
362 -def _get_current_config_channels(server_id):
363 h = rhnSQL.prepare(_query_current_config_channels) 364 h.execute(server_id=server_id) 365 366 current_ch = h.fetchall_dict() or [] 367 data = [] 368 for curr in current_ch: 369 data.append(curr['config_channel_id']) 370 return data
371 372
373 -def token_config_channels(server, tokens_obj):
374 assert(isinstance(tokens_obj, ActivationTokens)) 375 server_id = server['id'] 376 377 # If this is a re-registration token, it should not have any config 378 # channel associated with it (and no deploy_configs either). We'll just 379 # keep whatever config files they had on this profile 380 if tokens_obj.is_rereg_token: 381 return [] 382 383 # Activation key order matters; config channels are stacked in order 384 385 config_channels = [] 386 config_channels_hash = {} 387 deployment = 0 388 current_channels = [] 389 if tokens_obj.forget_rereg_token: 390 current_channels = _get_current_config_channels(server_id) 391 392 for token in tokens_obj.tokens: 393 channels = _get_token_config_channels(token['token_id']) 394 # Check every token used and if any of them are set to not deploy configs 395 # then we won't deploy configs for any config channels the system is subscribed to 396 deploy_configs = token['deploy_configs'] 397 log_debug(2, "token_id: ", token['token_id'], " deploy_configs: ", deploy_configs) 398 if deploy_configs == 'Y': 399 log_debug(2, "At least one token set to deploy config files") 400 deployment = 1 401 for c in channels: 402 config_channel_id = c['config_channel_id'] 403 if not c['config_channel_id'] in current_channels and\ 404 config_channel_id not in config_channels_hash: 405 position = len(current_channels) + len(config_channels) + 1 406 # Update the position in the queue 407 c['position'] = position 408 config_channels.append(c) 409 config_channels_hash[config_channel_id] = None 410 411 ret = [] 412 if config_channels: 413 h = rhnSQL.prepare(_query_set_server_config_channels) 414 415 h.execute_bulk({ 416 'server_id': [server_id] * len(config_channels), 417 'config_channel_id': [c['config_channel_id'] for c in config_channels], 418 'position': [c['position'] for c in config_channels], 419 }) 420 421 for channel in config_channels: 422 msg = "Subscribed to config channel %s" % channel['name'] 423 log_debug(4, msg) 424 ret.append(msg) 425 426 # Now that we have the server subscribed to config channels, 427 # determine if we have to deploy the files too 428 # Don't pass tokens_obj, we only need the token that provided the config 429 # channels in the first place 430 if deployment: 431 log_debug(2, "At least one token has deploy_configs == Y, deploying configs") 432 deploy_configs_if_needed(server) 433 434 rhnSQL.commit() 435 436 return ret
437 438 439 _query_server_token_used = rhnSQL.Statement(""" 440 insert into rhnServerTokenRegs (server_id, token_id) 441 values (:server_id, :token_id) 442 """) 443 444 _query_check_server_uses_token = rhnSQL.Statement(""" 445 select 1 from rhnServerTokenRegs 446 where server_id = :server_id 447 and token_id = :token_id 448 """) 449 450
451 -def server_used_token(server_id, token_id):
452 h = rhnSQL.prepare(_query_check_server_uses_token) 453 h.execute(server_id=server_id, token_id=token_id) 454 ret = h.fetchone_dict() 455 if not ret: 456 h = rhnSQL.prepare(_query_server_token_used) 457 h.execute(server_id=server_id, token_id=token_id)
458 459 _query_check_token_limits = rhnSQL.Statement(""" 460 select 461 rt.usage_limit max_nr, 462 ( select count(server_id) from rhnServerTokenRegs 463 where token_id = :token_id ) curr_nr 464 from rhnRegToken rt 465 where rt.id = :token_id 466 """) 467 468
469 -def check_token_limits(server_id, tokens_obj):
470 """ check the token registration limits """ 471 # XXX: would be nice to have those done with triggers in the database 472 # land... 473 assert(isinstance(tokens_obj, ActivationTokens)) 474 rhnSQL.transaction("check_token_limits") 475 for token in tokens_obj.tokens: 476 try: 477 _check_token_limits(server_id, token) 478 except: 479 log_debug(4, "Rolling back transaction") 480 rhnSQL.rollback("check_token_limits") 481 raise 482 return 0
483 484
485 -def _check_token_limits(server_id, token_rec):
486 token_id = token_rec["token_id"] 487 488 # Mark that we used this token 489 server_used_token(server_id, token_id) 490 491 # now check we're not using this token too much 492 h = rhnSQL.prepare(_query_check_token_limits) 493 h.execute(token_id=token_id) 494 ret = h.fetchone_dict() 495 if not ret: 496 raise rhnException("Could not check usage limits for token", 497 server_id, token_rec) 498 # See bug #79095: if usage_limit is NULL, it means unlimited reg tokens 499 if ret["max_nr"] is not None and ret["max_nr"] < ret["curr_nr"]: 500 log_error("Token usage limit exceeded", token_rec, 501 ret["max_nr"], server_id) 502 raise rhnFault(61, _("Maximum usage count of %s reached") % ret["max_nr"]) 503 # all clean, we're below usage limits 504 return 0
505 506
507 -class ActivationTokens:
508 509 """ 510 An aggregation of activation tokens, exposing important information 511 like org_id, user_id etc in a unified manner. 512 """ 513 is_rereg_token = 0 514 forget_rereg_token = 0 515
516 - def __init__(self, tokens, user_id=None, org_id=None, 517 kickstart_session_id=None, entitlements=[], deploy_configs=None):
518 self.tokens = tokens 519 self.user_id = user_id 520 self.org_id = org_id 521 self.kickstart_session_id = kickstart_session_id 522 # Boolean 523 self.deploy_configs = deploy_configs 524 # entitlements is list of tuples [(name, label)] 525 self.entitlements = entitlements
526
527 - def __nonzero__(self):
528 return (len(self.tokens) > 0)
529 530 __bool__ = __nonzero__ 531
532 - def get_server_id(self):
533 if not self: 534 return None 535 # We can have only one re-activation key 536 for token in self.tokens: 537 server_id = token.get('server_id') 538 if server_id: 539 return server_id 540 # We hit this when no re-activation key 541 return None
542
543 - def get_user_id(self):
544 return self.user_id
545
546 - def get_org_id(self):
547 return self.org_id
548
549 - def get_kickstart_session_id(self):
550 return self.kickstart_session_id
551
552 - def get_entitlements(self):
553 return self.entitlements
554
555 - def has_entitlement_label(self, entitlement):
556 if entitlement in [x[0] for x in self.entitlements]: 557 return 1 558 return 0
559
560 - def get_deploy_configs(self):
561 return self.deploy_configs
562
563 - def get_names(self):
564 """ Returns a string of the entitlement names that the token grants. 565 This function is poorly named. 566 """ 567 token_names = [x[0] for x in self.entitlements] 568 if not token_names: 569 return None 570 return ",".join(token_names)
571
572 - def get_tokens(self):
573 tokens = [] 574 for token in self.tokens: 575 tokens.append(token['token']) 576 577 return tokens
578
579 - def entitle(self, server_id, history, virt_type=None):
580 """ 581 Entitle a server according to the entitlements we have configured. 582 """ 583 log_debug(3, self.entitlements) 584 585 entitle_server = rhnSQL.Procedure("rhn_entitlements.entitle_server") 586 # TODO: entitle_server calls can_entitle_server, so we're doing this 587 # twice for each successful call. Is it necessary for external error 588 # handling or can we ditch it? 589 can_entitle_server = rhnSQL.Function( 590 "rhn_entitlements.can_entitle_server", rhnSQL.types.NUMBER()) 591 592 can_ent = None 593 594 history["entitlement"] = "" 595 596 for entitlement in self.entitlements: 597 if virt_type is not None and entitlement[0] == VIRT_ENT_LABEL: 598 continue 599 600 try: 601 can_ent = can_entitle_server(server_id, entitlement[0]) 602 except rhnSQL.SQLSchemaError: 603 e = sys.exc_info()[1] 604 can_ent = 0 605 606 try: 607 # bugzilla #160077, skip attempting to entitle if we cant 608 if can_ent: 609 entitle_server(server_id, entitlement[0]) 610 except rhnSQL.SQLSchemaError: 611 e = sys.exc_info()[1] 612 log_error("Token failed to entitle server", server_id, 613 self.get_names(), entitlement[0], e.errmsg) 614 #No idea what error may be here... 615 raise_with_tb(rhnFault(90, e.errmsg), sys.exc_info()[2]) 616 except rhnSQL.SQLError: 617 e = sys.exc_info()[1] 618 log_error("Token failed to entitle server", server_id, 619 self.get_names(), entitlement[0], e.args) 620 raise_with_tb(rhnFault(90, str(e)), sys.exc_info()[2]) 621 else: 622 history["entitlement"] = "Entitled as a %s member" % entitlement[1]
623 624
625 -class ReRegistrationToken(ActivationTokens):
626 627 """ 628 Subclass for re-registration keys. 629 630 (i.e. used alone and not combined with other regular activation keys) 631 """ 632 is_rereg_token = 1
633 634
635 -class ReRegistrationActivationToken(ReRegistrationToken):
636 637 """ 638 Subclass for re-registration keys and activation keys used together. 639 """ 640 forget_rereg_token = 1 641
642 - def __init__(self, tokens, user_id=None, org_id=None, 643 kickstart_session_id=None, entitlements=[], 644 remove_entitlements=[], deploy_configs=None):
645 ReRegistrationToken.__init__(self, tokens, user_id, org_id, 646 kickstart_session_id, entitlements, deploy_configs) 647 self.remove_entitlements = remove_entitlements # list of labels
648
649 - def entitle(self, server_id, history, virt_type=None):
650 for ent in self.remove_entitlements: 651 unentitle_server = rhnSQL.Procedure( 652 "rhn_entitlements.remove_server_entitlement") 653 try: 654 unentitle_server(server_id, ent) 655 except rhnSQL.SQLSchemaError: 656 e = sys.exc_info()[1] 657 log_error("Failed to unentitle server", server_id, 658 ent, e.errmsg) 659 raise_with_tb(rhnFault(90, e.errmsg), sys.exc_info()[2]) 660 except rhnSQL.SQLError: 661 e = sys.exc_info()[1] 662 log_error("Failed to unentitle server", server_id, 663 ent, e.args) 664 raise_with_tb(rhnFault(90, str(e)), sys.exc_info()[2]) 665 666 # Call parent method: 667 ReRegistrationToken.entitle(self, server_id, history, virt_type)
668 669
670 -def _fetch_token_from_cursor(cursor):
671 """ Fetches a token from a prepared and executed cursor 672 Used by both fetch_token and fetch_org_token 673 """ 674 token_entry = None 675 token_entitlements = {} 676 while 1: 677 row = cursor.fetchone_dict() 678 if not row: 679 break 680 tup = (row['token_type'], row['token_desc'], row['is_base']) 681 token_entitlements[tup] = None 682 if token_entry: 683 # We've seen this token already - the only thing that can be 684 # different is the entitlement level, which we've already 685 # saved 686 687 # Double-check it's the same token 688 assert token_entry['token_id'] == row['token_id'], \ 689 "Query returned different tokens - missing unique constraint" \ 690 " on rhnActivationKey.token?" 691 continue 692 693 # First entry of this type 694 token_entry = row 695 696 return token_entry, token_entitlements
697 698
699 -def _categorize_token_entitlements(token_entitlements, entitlements_base, 700 entitlements_extra):
701 """ Given a hash token_entitlements, splits the base ones and puts them in 702 the entitlements_base hash, and the extras in entitlements_extra 703 """ 704 for tup in token_entitlements.keys(): 705 is_base = tup[2] 706 ent = (tup[0], tup[1]) 707 if is_base == 'Y': 708 entitlements_base[ent] = None 709 else: 710 entitlements_extra[ent] = None 711 712 return entitlements_base, entitlements_extra
713 714
715 -def _validate_entitlements(token_string, rereg_ents, base_entitlements, 716 extra_entitlements, remove_entitlements):
717 """ 718 Perform various checks on the final list of entitlements accumulated after 719 processing all activation keys. 720 721 rereg_ents passed in as a list of entitlement labels. 722 723 Extra/base entitlements passed in as a hash of tuples ('label', 'Friendly 724 Name') mapping to None. (i.e. seems to be used as just a set) 725 726 Remove entitlements being maintained as just a list of labels. 727 """ 728 # Check for exactly one base entitlement: 729 if len(list(base_entitlements.keys())) != 1: 730 log_error("Tokens with different base entitlements", token_string, 731 base_entitlements) 732 raise rhnFault(63, 733 _("Stacking of re-registration tokens with different base entitlements " 734 "is not supported"), explain=0)
735 736 _query_token = rhnSQL.Statement(""" 737 select rt.id as token_id, 738 sgt.label as token_type, 739 sgt.name as token_desc, 740 sgt.is_base, 741 ak.token, 742 rt.user_id, 743 rt.org_id, 744 rt.note, 745 rt.usage_limit, 746 rt.server_id, 747 ak.ks_session_id kickstart_session_id, 748 rt.deploy_configs 749 from rhnActivationKey ak, rhnRegToken rt, rhnRegTokenEntitlement rte, rhnServerGroupType sgt 750 where ak.token = :token 751 and ak.reg_token_id = rt.id 752 and rt.disabled = 0 753 and rt.id = rte.reg_token_id 754 and rte.server_group_type_id = sgt.id 755 """) 756 757
758 -def fetch_token(token_string):
759 """ Fetches a token from the database """ 760 log_debug(3, token_string) 761 # A token should always be passed to this function 762 assert token_string 763 tokens = token_string.split(',') 764 h = rhnSQL.prepare(_query_token) 765 result = [] 766 rereg_token_found = 0 767 num_of_rereg = 0 768 # Global user_id and org_id 769 user_id = None 770 same_user_id = 1 771 org_id = None 772 ks_session_id_token = None 773 deploy_configs = None 774 entitlements_base = {} 775 entitlements_extra = {} 776 777 # List of re-registration entitlements labels (if found): 778 rereg_ents = [] 779 780 for token in tokens: 781 h.execute(token=token) 782 token_entry, token_entitlements = _fetch_token_from_cursor(h) 783 784 if not token_entry: 785 # Unable to find the token 786 log_error("Invalid token '%s'" % token) 787 raise rhnFault(60, _("Could not find token '%s'") % token, explain=0) 788 789 row = token_entry 790 791 if row.get('server_id'): 792 rereg_token_found = row 793 num_of_rereg += 1 794 795 # Store the re-reg ents: 796 for tup in token_entitlements.keys(): 797 rereg_ents.append(tup[0]) 798 799 # Check user_id 800 token_user_id = row.get('user_id') 801 802 # 4/27/05 wregglej - Commented this line out 'cause the token_user_id should 803 # be allowed to be None. This line was causing problems when registering with 804 # an activation key whose creator had been deleted. 805 #assert(token_user_id is not None) 806 807 if same_user_id and user_id is not None and user_id != token_user_id: 808 log_debug(4, "Different user ids: %s, %s" % (same_user_id, user_id)) 809 # This token has a different user id than the rest 810 same_user_id = 0 811 else: 812 user_id = token_user_id 813 814 # Check org_id 815 token_org_id = row.get('org_id') 816 assert(token_org_id is not None) 817 if org_id is not None and org_id != token_org_id: 818 # Cannot use activation keys from different orgs 819 raise rhnFault(63, _("Tokens from mismatching orgs"), explain=0) 820 org_id = token_org_id 821 822 # Check kickstart session ids 823 token_ks_session_id = row.get('kickstart_session_id') 824 if token_ks_session_id is not None: 825 if ks_session_id_token is not None: 826 ks_session_id = ks_session_id_token['kickstart_session_id'] 827 if ks_session_id != token_ks_session_id: 828 # Two tokens with different kickstart sessions 829 raise rhnFault(63, _("Kickstart session mismatch"), 830 explain=0) 831 else: 832 # This token has kickstart session id info 833 ks_session_id_token = row 834 835 # Iterate through the entitlements from this token 836 # and intead of picking one entitlement, create a union of 837 # all the entitlemts as a list of tuples of (name, label) aka 838 # (token_type, token_desc) 839 _categorize_token_entitlements(token_entitlements, entitlements_base, 840 entitlements_extra) 841 842 # Deploy configs? 843 deploy_configs = deploy_configs or (row['deploy_configs'] == 'Y') 844 result.append(row) 845 846 # One should not stack re-activation tokens 847 if num_of_rereg > 1: 848 raise rhnFault(63, 849 _("Stacking of re-registration tokens is not supported"), explain=0) 850 851 entitlements_remove = [] 852 _validate_entitlements(token_string, rereg_ents, entitlements_base, 853 entitlements_extra, entitlements_remove) 854 log_debug(5, "entitlements_base = %s" % entitlements_base) 855 log_debug(5, "entitlements_extra = %s" % entitlements_extra) 856 857 if ks_session_id_token: 858 ks_session_id = ks_session_id_token['kickstart_session_id'] 859 else: 860 ks_session_id = None 861 862 # akl add entitles array constructed above to kwargs 863 kwargs = { 864 'user_id': user_id, 865 'org_id': org_id, 866 'kickstart_session_id': ks_session_id, 867 'entitlements': list(entitlements_base.keys()) + list(entitlements_extra.keys()), 868 'deploy_configs': deploy_configs, 869 } 870 log_debug(4, "Values", kwargs) 871 872 if rereg_token_found and len(result) > 1: 873 log_debug(4, "re-activation stacked with activationkeys") 874 kwargs['remove_entitlements'] = entitlements_remove 875 return ReRegistrationActivationToken(result, **kwargs) 876 elif rereg_token_found: 877 log_debug(4, "simple re-activation") 878 return ReRegistrationToken([rereg_token_found], **kwargs) 879 880 return ActivationTokens(result, **kwargs)
881 882 # always be sure this query has matching columns as _query_token above... 883 _query_org_default_token = rhnSQL.Statement(""" 884 select rt.id as token_id, 885 sgt.label as token_type, 886 sgt.name as token_desc, 887 sgt.is_base, 888 ak.token, 889 rt.user_id, 890 rt.org_id, 891 rt.note, 892 -- Default tokens have no usage limit 893 NULL usage_limit, 894 rt.server_id, 895 NULL kickstart_session_id, 896 rt.deploy_configs 897 from rhnServerGroupType sgt, 898 rhnActivationKey ak, 899 rhnRegToken rt, 900 rhnRegTokenOrgDefault rtod, 901 rhnRegTokenEntitlement rte 902 where rtod.org_id = :org_id 903 and rtod.reg_token_id = rt.id 904 and rt.id = rte.reg_token_id 905 and rt.disabled = 0 906 and rte.server_group_type_id = sgt.id 907 and ak.reg_token_id = rtod.reg_token_id 908 """) 909 910
911 -def fetch_org_token(org_id):
912 log_debug(3, org_id) 913 h = rhnSQL.prepare(_query_org_default_token) 914 h.execute(org_id=org_id) 915 token_entry, token_entitlements = _fetch_token_from_cursor(h) 916 entitlements_base = {} 917 entitlements_extra = {} 918 _categorize_token_entitlements(token_entitlements, entitlements_base, 919 entitlements_extra) 920 921 kwargs = {} 922 tokens = [] 923 if token_entry: 924 kwargs = { 925 'user_id': token_entry['user_id'], 926 'org_id': token_entry['org_id'], 927 'kickstart_session_id': token_entry['kickstart_session_id'], 928 'entitlements': list(entitlements_base.keys()) + list(entitlements_extra.keys()), 929 'deploy_configs': token_entry['deploy_configs'] == 'Y', 930 } 931 tokens.append(token_entry) 932 933 return ActivationTokens(tokens, **kwargs)
934 935 936 _query_disable_token = rhnSQL.Statement(""" 937 update rhnRegToken 938 set disabled = 1 939 where id = :token_id 940 """) 941 942
943 -def disable_token(tokens_obj):
944 assert(isinstance(tokens_obj, ActivationTokens)) 945 h = rhnSQL.prepare(_query_disable_token) 946 for token in tokens_obj.tokens: 947 if token.get("server_id"): 948 # only disable re-activation tokens 949 h.execute(token_id=token["token_id"])
950 951
952 -def process_token(server, server_arch, tokens_obj, virt_type=None):
953 """ perform registration tasks for a server as indicated by a token """ 954 assert(isinstance(tokens_obj, ActivationTokens)) 955 server_id = server['id'] 956 log_debug(1, server_id, tokens_obj.get_names()) 957 958 # Keep track of what we're doing 959 history = {} 960 961 # the tokens are confirmed, mark this server as using it and make 962 # sure we're within limits 963 check_token_limits(server_id, tokens_obj) 964 965 is_reactivation = rhnFlags.test('re_registration_token') 966 967 # channels 968 history["channels"] = token_channels(server, server_arch, tokens_obj) 969 970 if is_reactivation: 971 # If it's a re-registration, the server is already entitled 972 history["entitlement"] = "Re-activation: keeping previous entitlement level" 973 else: 974 tokens_obj.entitle(server_id, history, virt_type) 975 976 is_management_entitled = None 977 978 if tokens_obj.has_entitlement_label('enterprise_entitled'): 979 is_management_entitled = 1 980 981 if is_reactivation: 982 history["groups"] = ["Re-activation: keeping previous server groups"] 983 else: 984 # server groups - allowed for enterprise only 985 if is_management_entitled: 986 history["groups"] = token_server_groups(server_id, tokens_obj) 987 else: 988 # FIXME: better messaging about minimum service level 989 history["groups"] = [ 990 "Not subscribed to any system groups: not entitled for " 991 "Management" 992 ] 993 994 if is_management_entitled: 995 history["packages"] = token_packages(server_id, tokens_obj) 996 history["config_channels"] = token_config_channels(server, 997 tokens_obj) 998 else: 999 history["packages"] = ["Insufficient service level for automatic package installation."] 1000 history["config_channels"] = ["Insufficient service level for config channel subscription."] 1001 1002 # build the report and send it back 1003 return history_report(history)
1004 1005
1006 -def history_report(history):
1007 """ build a mildly html-ized version of the history as a report """ 1008 # header information 1009 report = "Entitlement Information:\n" 1010 report += "<ul><li>%s</li></ul>" % history["entitlement"] 1011 report += "\n" 1012 # print out channels 1013 report += history_subreport(history, "groups", 1014 "Channel Subscription Information:", 1015 "The token does not include default Channel Subscriptions") 1016 1017 # print out the groups 1018 report += history_subreport(history, "groups", 1019 "System Group Membership Information:", 1020 "The token does not include default System Group Membership") 1021 1022 # auto-installed packages... 1023 report += history_subreport(history, "packages", 1024 "Packages Scheduled for Installation:", 1025 "No packages scheduled for automatic installation") 1026 1027 # config channels... 1028 report += history_subreport(history, 'config_channels', 1029 "Config Channel Subscription Information:", 1030 "The token does not include default configuration channels") 1031 1032 return report
1033 1034
1035 -def history_subreport(history, key, title, emptymsg):
1036 if key in history: 1037 subreport = title + "\n" 1038 subreport += "<ul>\n" 1039 1040 for c in history[key]: 1041 subreport += "<li>%s</li>\n" % c 1042 1043 if len(history[key]) == 0: 1044 subreport += "<li>%s</li>\n" % emptymsg 1045 1046 subreport += "</ul>\n" 1047 return subreport
1048