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

Source Code for Module backend.server.rhnServer.server_hardware

   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  # This file contains all the logic necessary to manipulate Hardware 
  17  # items - load, reload, instanciate and save 
  18  # 
  19   
  20  import string 
  21  import sys 
  22   
  23  from rhn.UserDictCase import UserDictCase 
  24  from spacewalk.common.usix import raise_with_tb 
  25  from spacewalk.common.rhnLog import log_debug, log_error 
  26  from spacewalk.common.rhnException import rhnFault 
  27  from spacewalk.common.rhnTB import Traceback 
  28  from spacewalk.server import rhnSQL 
  29   
  30   
31 -def kudzu_mapping(dict=None):
32 """ this is a class we use to get the mapping for a kudzu entry """ 33 # This is the generic mapping we need 34 mapping = { 35 'desc': 'description', 36 } 37 # error handling if we get passed weird stuff. 38 if not dict: 39 return mapping 40 if not type(dict) == type({}) and not isinstance(dict, UserDictCase): 41 return mapping 42 hw_bus = dict.get("bus") 43 # we need to have a bus type to be able to continue 44 if not hw_bus: 45 return mapping 46 hw_bus = string.lower(hw_bus) 47 extra = {} 48 if hw_bus == "ddc": 49 extra = { 50 "id": None, 51 "horizsyncmin": "prop1", 52 "horizsyncmax": "prop2", 53 "vertrefreshmin": "prop3", 54 "vertrefreshmax": "prop4", 55 "modes": None, 56 "mem": None, 57 } 58 elif hw_bus == "ide": 59 extra = { 60 "physical": "prop1", 61 "logical": "prop2", 62 } 63 elif hw_bus in ["isapnp", "isa"]: 64 extra = { 65 "pdeviceid": "prop1", 66 "deviceid": "prop2", 67 "compat": "prop3", 68 "native": None, 69 "active": None, 70 "cardnum": None, # XXX: fix me 71 "logdev": "prop4", 72 "io": "prop2", 73 "irq": "prop1", 74 "dma": "prop3", 75 "mem": "prop4", 76 } 77 elif hw_bus == "keyboard": 78 extra = {} 79 elif hw_bus == "psaux": 80 extra = {} 81 elif hw_bus == "parallel": 82 extra = { 83 'pnpmfr': 'prop1', 84 'pnpdesc': 'prop2', 85 'pnpmodel': 'prop3', 86 'pnpmodes': 'prop4', 87 'pinfo': None, 88 'pinfo.xres': None, 89 'pinfo.yres': None, 90 'pinfo.color': None, 91 'pinfo.ascii': None, 92 } 93 elif hw_bus == "pci": 94 extra = { 95 'vendorid': 'prop1', 96 'deviceid': 'prop2', 97 'subvendorid': 'prop3', 98 'subdeviceid': 'prop4', 99 'network.hwaddr': None, 100 'pcibus': None, 101 'pcidev': None, 102 'pcifn': None, 103 'pcidom': None, 104 } 105 elif hw_bus == "sbus": 106 extra = { 107 "monitor": "prop1", 108 "width": "prop2", 109 "height": "prop3", 110 "freq": "prop4", 111 } 112 elif hw_bus == "scsi": 113 extra = { 114 'host': 'prop1', 115 'id': 'prop2', 116 'channel': 'prop3', 117 'lun': 'prop4', 118 'generic': None, 119 } 120 elif hw_bus == "serial": 121 extra = { 122 'pnpmfr': 'prop1', 123 'pnpdesc': 'prop2', 124 'pnpmodel': 'prop3', 125 'pnpcompat': "prop4", 126 } 127 elif hw_bus == "usb": 128 extra = { 129 "vendorid": "prop1", 130 "deviceid": "prop2", 131 "usbclass": "prop3", 132 "usbbus": "prop4", 133 "usblevel": "pciType", 134 "usbdev": None, 135 "usbprod": None, 136 "usbsubclass": None, 137 "usbprotocol": None, 138 "usbport": None, 139 "usbmfr": None, 140 "productname": None, 141 "productrevision": None, 142 'network.hwaddr': None, 143 } 144 elif hw_bus == "firewire": 145 extra = { 146 'vendorid': 'prop1', 147 'deviceid': 'prop2', 148 'subvendorid': 'prop3', 149 'subdeviceid': 'prop4', 150 } 151 elif hw_bus == 'pcmcia': 152 extra = { 153 'vendorid': 'prop1', 154 'deviceid': 'prop2', 155 'function': 'prop3', 156 'slot': 'prop4', 157 'network.hwaddr': None, 158 } 159 mapping.update(extra) 160 return mapping
161 162
163 -def cleanse_ip_addr(ip_addr):
164 """ Cleans up things like 127.00.00.01 """ 165 if ip_addr is None: 166 return None 167 # Make sure it's a string 168 ip_addr = str(ip_addr) 169 # If the ipaddr is empty, jus return empty str 170 if not len(ip_addr): 171 return '' 172 arr = ip_addr.split('.') 173 # lstrip will remove all leading zeros; if multiple zeros are present, it 174 # would remove too much, hence the or '0' here. 175 return '.'.join([x.lstrip('0') or '0' for x in arr])
176 177
178 -class GenericDevice:
179 180 """ A generic device class """ 181 table = "override-GenericDevice" 182
183 - def __init__(self):
184 self.id = 0 185 self.status = 1 # just added 186 self.data = {} 187 # default to the hardware seq... 188 self.sequence = "rhn_hw_dev_id_seq" 189 self._autonull = ("description", "board")
190
191 - def getid(self):
192 if self.id == 0: 193 self.id = rhnSQL.Sequence(self.sequence)() 194 return self.id
195
196 - def must_save(self):
197 if self.id == 0 and self.status == 2: # deleted new item 198 return 0 199 if self.status == 0: # original item, unchanged 200 return 0 201 return 1
202
203 - def save(self, sysid):
204 """ save data in the rhnDevice table """ 205 log_debug(4, self.table, self.status, self.data) 206 if not self.must_save(): 207 return 0 208 t = rhnSQL.Table(self.table, "id") 209 # check if we have to delete 210 if self.status == 2 and self.id: 211 # delete the entry 212 del t[self.id] 213 return 0 214 # set description to null if empty 215 self._null_columns([self.data], self._autonull) 216 # make sure we have a device id 217 devid = self.getid() 218 for k in self.data.keys(): 219 if self.data[k] is None: 220 del self.data[k] 221 self.data["server_id"] = sysid 222 t[devid] = self.data 223 self.status = 0 # now it is saved 224 return 0
225
226 - def reload(self, devid):
227 """ reload from rhnDevice table based on devid """ 228 if not devid: 229 return -1 230 t = rhnSQL.Table(self.table, "id") 231 self.data = t[devid] 232 # clean up fields we don't want 233 if self.data: 234 for k in ["created", "modified"]: 235 if self.data.has_key(k): 236 del self.data[k] 237 self.id = devid 238 self.status = 0 239 return 0
240
241 - def _null_columns(self, params, names=()):
242 """ Method searches for empty string in params dict with names 243 defined in names list and replaces them with None value which 244 is translated to NULL in SQL. 245 246 We do not allow empty strings in database for compatibility 247 reasons between Oracle and PostgreSQL. 248 """ 249 # list of dicts 250 for param in params: 251 for name in names: 252 if name in param and param[name] == '': 253 param[name] = None
254 255
256 -class Device(GenericDevice):
257 258 """ This is the base Device class that supports instantiation from a 259 dictionarry. the __init__ takes the dictionary as its argument, 260 together with a list of valid fields to recognize and with a mapping 261 for dictionary keys into valid field names for self.data 262 263 The fields are required to know what fields we have in the 264 table. The mapping allows transformation from whatever comes in to 265 valid fields in the table Looks complicated but it isn't -- gafton 266 """ 267
268 - def __init__(self, fields, dict=None, mapping=None):
269 GenericDevice.__init__(self) 270 x = {} 271 for k in fields: 272 x[k] = None 273 self.data = UserDictCase(x) 274 if not dict: 275 return 276 # make sure we get a UserDictCase to work with 277 if type(dict) == type({}): 278 dict = UserDictCase(dict) 279 if mapping is None or type(mapping) == type({}): 280 mapping = UserDictCase(mapping) 281 if not isinstance(dict, UserDictCase) or \ 282 not isinstance(mapping, UserDictCase): 283 log_error("Argument passed is not a dictionary", dict, mapping) 284 raise TypeError("Argument passed is not a dictionary", 285 dict, mapping) 286 # make sure we have a platform 287 for k in dict.keys(): 288 if dict[k] == '': 289 dict[k] = None 290 if self.data.has_key(k): 291 self.data[k] = dict[k] 292 continue 293 if mapping.has_key(k): 294 # the mapping dict might tell us to lose some fields 295 if mapping[k] is not None: 296 self.data[mapping[k]] = dict[k] 297 else: 298 log_error("Unknown HW key =`%s'" % k, 299 dict.dict(), mapping.dict()) 300 # The try-except is added just so that we can send e-mails 301 try: 302 raise KeyError("Don't know how to parse key `%s''" % k, 303 dict.dict()) 304 except: 305 Traceback(mail=1) 306 # Ignore this key 307 continue 308 # clean up this data 309 try: 310 for k in self.data.keys(): 311 if type(self.data[k]) == type("") and len(self.data[k]): 312 self.data[k] = string.strip(self.data[k]) 313 if not len(self.data[k]): 314 continue 315 if self.data[k][0] == '"' and self.data[k][-1] == '"': 316 self.data[k] = self.data[k][1:-1] 317 except IndexError: 318 raise_with_tb(IndexError("Can not process data = %s, key = %s" % ( 319 repr(self.data), k)), sys.exc_info()[2])
320 321
322 -class HardwareDevice(Device):
323 324 """ A more specific device based on the Device class """ 325 table = "rhnDevice" 326
327 - def __init__(self, dict=None):
328 fields = ['class', 'bus', 'device', 'driver', 'detached', 329 'description', 'pcitype', 'prop1', 'prop2', 330 'prop3', 'prop4'] 331 # get a processed mapping 332 mapping = kudzu_mapping(dict) 333 # ... and do little to no work 334 Device.__init__(self, fields, dict, mapping) 335 # use the hardware id sequencer 336 self.sequence = "rhn_hw_dev_id_seq"
337 338
339 -class CPUDevice(Device):
340 341 """ A class for handling CPU - mirrors the rhnCPU structure """ 342 table = "rhnCPU" 343
344 - def __init__(self, dict=None):
345 fields = ['cpu_arch_id', 'architecture', 'bogomips', 'cache', 346 'family', 'mhz', 'stepping', 'flags', 'model', 347 'version', 'vendor', 'nrcpu', 'acpiVersion', 348 'apic', 'apmVersion', 'chipset', 'nrsocket'] 349 mapping = { 350 "bogomips": "bogomips", 351 "cache": "cache", 352 "model": "model", 353 "platform": "architecture", 354 "type": "vendor", 355 "model_rev": "stepping", 356 "model_number": "family", 357 "model_ver": "version", 358 "model_version": "version", 359 "speed": "mhz", 360 "count": "nrcpu", 361 "socket_count": "nrsocket", 362 "other": "flags", 363 "desc": None, 364 'class': None, 365 } 366 # now instantiate this class 367 Device.__init__(self, fields, dict, mapping) 368 self.sequence = "rhn_cpu_id_seq" 369 if not dict: 370 return 371 if self.data.get("cpu_arch_id") is not None: 372 return # all fine, we have the arch 373 # if we don't have an architecture, guess it 374 if not self.data.has_key("architecture"): 375 log_error("hash does not have a platform member: %s" % dict) 376 raise AttributeError("Expected a hash value for member `platform'") 377 # now extract the arch field, which has to come out of rhnCpuArch 378 arch = self.data["architecture"] 379 row = rhnSQL.Table("rhnCpuArch", "label")[arch] 380 if row is None or not row.has_key("id"): 381 log_error("Can not find arch %s in rhnCpuArch" % arch) 382 raise AttributeError("Invalid architecture for CPU: `%s'" % arch) 383 self.data["cpu_arch_id"] = row["id"] 384 del self.data["architecture"] 385 if self.data.has_key("nrcpu"): # make sure this is a number 386 try: 387 self.data["nrcpu"] = int(self.data["nrcpu"]) 388 except: 389 self.data["nrcpu"] = 1 390 if self.data["nrcpu"] == 0: 391 self.data["nrcpu"] = 1
392 393
394 -class NetworkInformation(Device):
395 396 """ This is a wrapper class for the Network Information (rhnServerNetwork) """ 397 table = "rhnServerNetwork" 398
399 - def __init__(self, dict=None):
400 fields = ["hostname", "ipaddr", "ip6addr"] 401 mapping = {'class': None} 402 Device.__init__(self, fields, dict, mapping) 403 self._autonull = ('ipaddr', 'ip6addr') 404 # use our own sequence 405 self.sequence = "rhn_server_net_id_seq" 406 # bugzilla: 129840 kudzu (rhpl) will sometimes pad octets 407 # with leading zeros, causing confusion; clean those up 408 self.data['ipaddr'] = cleanse_ip_addr(self.data['ipaddr'])
409 410
411 -class NetIfaceInformation(Device):
412 key_mapping = { 413 'hwaddr': 'hw_addr', 414 'module': 'module', 415 } 416
417 - def __init__(self, dict=None):
418 log_debug(4, dict) 419 self.ifaces = {} 420 self.db_ifaces = [] 421 # parameters which are not allowed to be empty and set to NULL 422 self._autonull = ('hw_addr', 'module') 423 if not dict: 424 return 425 for name, info in dict.items(): 426 if name == 'class': 427 # Ignore it 428 continue 429 if not isinstance(info, type({})): 430 raise rhnFault(53, "Unexpected format for interface %s" % 431 name) 432 vdict = {} 433 for key, mapping in self.key_mapping.items(): 434 # Look at the mapping first; if not found, look for the key 435 if mapping in info: 436 k = mapping 437 else: 438 k = key 439 if k not in info: 440 raise rhnFault(53, "Unable to find required field %s" 441 % key) 442 val = info[k] 443 vdict[mapping] = val 444 if 'ipaddr' in info and info['ipaddr']: 445 vdict['ipv4'] = NetIfaceAddress4( 446 [{'ipaddr': info['ipaddr'], 'broadcast': info['broadcast'], 'netmask': info['netmask']}]) 447 if 'ipv6' in info and info['ipv6']: 448 vdict['ipv6'] = NetIfaceAddress6(info["ipv6"]) 449 self.ifaces[name] = vdict
450
451 - def __str__(self):
452 return "<%s Class at %d: %s>\n" % ( 453 self.__class__.__name__, 454 id(self), { 455 "self.ifaces": self.ifaces, 456 "self.db_ifaces": self.db_ifaces, 457 })
458 __repr__ = __str__ 459
460 - def save(self, server_id):
461 log_debug(4, self.ifaces) 462 self.reload(server_id) 463 log_debug(4, "Interfaces in DB", self.db_ifaces) 464 465 # Compute updates, deletes and inserts 466 inserts = [] 467 updates = [] 468 deletes = [] 469 470 ifaces = self.ifaces.copy() 471 for iface in self.db_ifaces: 472 name = iface['name'] 473 if name not in self.ifaces: 474 # To be deleted 475 deletes.append({'server_id': server_id, 'name': name}) 476 continue 477 478 uploaded_iface = ifaces[name].copy() 479 del ifaces[name] 480 if _hash_eq(uploaded_iface, iface): 481 # Same value 482 continue 483 uploaded_iface.update({'name': name, 'server_id': server_id}) 484 if 'ipv4' in uploaded_iface: 485 del(uploaded_iface['ipv4']) 486 if 'ipv6' in uploaded_iface: 487 del(uploaded_iface['ipv6']) 488 updates.append(uploaded_iface) 489 490 # Everything else in self.ifaces has to be inserted 491 for name, info in ifaces.items(): 492 iface = {} 493 iface['name'] = name 494 iface['server_id'] = server_id 495 iface['hw_addr'] = info['hw_addr'] 496 iface['module'] = info['module'] 497 inserts.append(iface) 498 499 log_debug(4, "Deletes", deletes) 500 log_debug(4, "Updates", updates) 501 log_debug(4, "Inserts", inserts) 502 503 self._update(updates) 504 self._insert(inserts) 505 ifaces = self.ifaces.copy() 506 for name, info in ifaces.items(): 507 if not 'ipv6' in info: 508 info['ipv6'] = NetIfaceAddress6() 509 info['ipv6'].save(self.get_server_id(server_id, name)) 510 if not 'ipv4' in info: 511 info['ipv4'] = NetIfaceAddress4() 512 info['ipv4'].save(self.get_server_id(server_id, name)) 513 # delete address (if any) of deleted interaces 514 for d in deletes: 515 interface = NetIfaceAddress6() 516 interface.save(self.get_server_id(server_id, d['name'])) 517 interface = NetIfaceAddress4() 518 interface.save(self.get_server_id(server_id, d['name'])) 519 self._delete(deletes) 520 return 0
521
522 - def get_server_id(self, server_id, name):
523 """ retrieve id for given server_id and name """ 524 h = rhnSQL.prepare("select id from rhnServerNetInterface where server_id=:server_id and name=:name") 525 h.execute(server_id=server_id, name=name) 526 row = h.fetchone_dict() 527 if row: 528 return row['id'] 529 else: 530 return None
531
532 - def _insert(self, params):
533 q = """insert into rhnServerNetInterface 534 (%s) values (%s)""" 535 self._null_columns(params, self._autonull) 536 537 columns = list(self.key_mapping.values()) + ['server_id', 'name'] 538 columns.sort() 539 bind_params = string.join([':' + x for x in columns], ", ") 540 h = rhnSQL.prepare(q % (string.join(columns, ", "), bind_params)) 541 return _dml(h, params)
542
543 - def _delete(self, params):
544 q = """delete from rhnServerNetInterface 545 where %s""" 546 547 columns = ['server_id', 'name'] 548 wheres = ['%s = :%s' % (x, x) for x in columns] 549 h = rhnSQL.prepare(q % string.join(wheres, " and ")) 550 return _dml(h, params)
551
552 - def _update(self, params):
553 q = """update rhnServerNetInterface 554 set %s 555 where %s""" 556 self._null_columns(params, self._autonull) 557 558 wheres = ['server_id', 'name'] 559 wheres = ['%s = :%s' % (x, x) for x in wheres] 560 wheres = string.join(wheres, " and ") 561 562 updates = list(self.key_mapping.values()) 563 updates.sort() 564 updates = ['%s = :%s' % (x, x) for x in updates] 565 updates = string.join(updates, ", ") 566 567 h = rhnSQL.prepare(q % (updates, wheres)) 568 return _dml(h, params)
569
570 - def reload(self, server_id):
571 h = rhnSQL.prepare(""" 572 select * 573 from rhnServerNetInterface 574 where server_id = :server_id 575 """) 576 h.execute(server_id=server_id) 577 self.db_ifaces = [] 578 while 1: 579 row = h.fetchone_dict() 580 if not row: 581 break 582 hval = {'primary_id': row['id'], 'name': row['name'], 'server_id': server_id} 583 for key in self.key_mapping.values(): 584 hval[key] = row[key] 585 hval['ipv4'] = NetIfaceAddress4() 586 hval['ipv4'].reload(hval['primary_id']) 587 hval['ipv6'] = NetIfaceAddress6() 588 hval['ipv6'].reload(hval['primary_id']) 589 self.db_ifaces.append(hval) 590 591 self.status = 0 592 return 0
593 594
595 -class NetIfaceAddress(Device):
596 key_mapping = { 597 'netmask': 'netmask', 598 'address': 'address', 599 } 600 unique = ['address'] # to be overriden by child 601 table = 'rhnServerNetAddress' # to be overriden by child 602
603 - def __init__(self, list_ifaces=None):
604 log_debug(4, list_ifaces) 605 self.ifaces = {} 606 self.db_ifaces = [] 607 # parameters which are not allowed to be empty and set to NULL 608 self._autonull = ('address', 'netmask') 609 self.sequence = "rhn_srv_net_iface_id_seq" 610 if not list_ifaces: 611 return 612 for info in list_ifaces: 613 if not isinstance(info, type({})): 614 raise rhnFault(53, "Unexpected format for interface %s" % 615 info) 616 vdict = {} 617 for key, mapping in self.key_mapping.items(): 618 # Look at the mapping first; if not found, look for the key 619 if mapping in info: 620 k = mapping 621 else: 622 k = key 623 if k not in info: 624 raise rhnFault(53, "Unable to find required field %s" 625 % (key)) 626 val = info[k] 627 if mapping in ['ip_addr', 'netmask', 'broadcast', 'address']: 628 # bugzilla: 129840 kudzu (rhpl) will sometimes pad octets 629 # with leading zeros, causing confusion; clean those up 630 val = self.cleanse_ip_addr(val) 631 vdict[mapping] = val 632 self.ifaces[vdict['address']] = vdict
633
634 - def __str__(self):
635 return "<%s Class at %d: %s>\n" % ( 636 self.__class__.__name__, 637 id(self), { 638 "self.ifaces": self.ifaces, 639 "self.db_ifaces": self.db_ifaces, 640 })
641 __repr__ = __str__ 642
643 - def cleanse_ip_addr(self, val):
644 """ to be overriden by child """ 645 return val
646
647 - def save(self, interface_id):
648 log_debug(4, self.ifaces) 649 self.reload(interface_id) 650 log_debug(4, "Net addresses in DB", self.db_ifaces) 651 652 # Compute updates, deletes and inserts 653 inserts = [] 654 updates = [] 655 deletes = [] 656 ifaces = self.ifaces.copy() 657 for iface in self.db_ifaces: 658 address = iface['address'] 659 if iface['address'] not in self.ifaces: 660 # To be deleted 661 # filter out params, which are not used in query 662 iface = dict((column, iface[column]) for column in self.unique) 663 deletes.append(iface) 664 continue 665 uploaded_iface = ifaces[address] 666 del ifaces[address] 667 # FIXME this is inefficient for IPv4 as it row is present it will be always update 668 if _hash_eq(uploaded_iface, iface): 669 # Same value 670 continue 671 uploaded_iface.update({'interface_id': interface_id}) 672 updates.append(uploaded_iface) 673 674 # Everything else in self.ifaces has to be inserted 675 for name, iface in ifaces.items(): 676 iface['address'] = iface['address'] 677 iface['interface_id'] = interface_id 678 inserts.append(iface) 679 680 log_debug(4, "Deletes", deletes) 681 log_debug(4, "Updates", updates) 682 log_debug(4, "Inserts", inserts) 683 684 self._delete(deletes) 685 self._update(updates) 686 self._insert(inserts)
687
688 - def _insert(self, params):
689 q = """insert into %s 690 (%s) values (%s)""" 691 self._null_columns(params, self._autonull) 692 693 columns = list(self.key_mapping.values()) + ['interface_id'] 694 columns.sort() 695 bind_params = string.join([':' + x for x in columns], ", ") 696 h = rhnSQL.prepare(q % (self.table, string.join(columns, ", "), bind_params)) 697 return _dml(h, params)
698
699 - def _delete(self, params):
700 q = """delete from %s 701 where %s""" 702 703 columns = self.unique 704 wheres = ['%s = :%s' % (x, x) for x in columns] 705 h = rhnSQL.prepare(q % (self.table, string.join(wheres, " and "))) 706 return _dml(h, params)
707
708 - def _update(self, params):
709 q = """update %s 710 set %s 711 where %s""" 712 self._null_columns(params, self._autonull) 713 714 wheres = self.unique 715 wheres = ['%s = :%s' % (x, x) for x in wheres] 716 wheres = string.join(wheres, " and ") 717 718 updates = list(self.key_mapping.values()) 719 updates.sort() 720 updates = ['%s = :%s' % (x, x) for x in updates] 721 updates = string.join(updates, ", ") 722 723 h = rhnSQL.prepare(q % (self.table, updates, wheres)) 724 return _dml(h, params)
725
726 - def reload(self, interface_id):
727 h = rhnSQL.prepare(""" 728 select * 729 from %s 730 where interface_id = :interface_id 731 order by interface_id 732 """ % self.table) 733 h.execute(interface_id=interface_id) 734 self.db_ifaces = [] 735 while 1: 736 row = h.fetchone_dict() 737 if not row: 738 break 739 hval = {'interface_id': row['interface_id']} 740 for key in self.key_mapping.values(): 741 hval[key] = row[key] 742 self.db_ifaces.append(hval) 743 744 self.status = 0 745 return 0
746 747
748 -class NetIfaceAddress6(NetIfaceAddress):
749 750 """ IPv6 Network interface """ 751 key_mapping = { 752 'netmask': 'netmask', 753 'addr': 'address', 754 'scope': 'scope', 755 } 756 table = 'rhnServerNetAddress6' 757 unique = ['interface_id', 'address', 'scope'] 758
759 - def __init__(self, addr_dict=None):
760 NetIfaceAddress.__init__(self, addr_dict) 761 self._autonull = ('address', 'netmask', 'scope')
762 763
764 -class NetIfaceAddress4(NetIfaceAddress):
765 766 """ IPv4 Network interface """ 767 key_mapping = { 768 'netmask': 'netmask', 769 'ipaddr': 'address', 770 'broadcast': 'broadcast', 771 } 772 table = 'rhnServerNetAddress4' 773 unique = ['interface_id'] 774
775 - def __init__(self, addr_dict=None):
776 NetIfaceAddress.__init__(self, addr_dict) 777 self._autonull = ('address', 'netmask', 'broadcast')
778
779 - def cleanse_ip_addr(self, val):
780 return cleanse_ip_addr(val)
781 782
783 -def _hash_eq(h1, h2):
784 """ Compares two hashes and return 1 if the first is a subset of the second """ 785 log_debug(5, h1, h2) 786 for k, v in h1.items(): 787 if k not in h2: 788 return 0 789 if h2[k] != v: 790 return 0 791 return 1
792 793
794 -def _dml(statement, params):
795 log_debug(5, params) 796 if not params: 797 return 0 798 params = _transpose(params) 799 rowcount = statement.executemany(**params) 800 log_debug(5, "Affected rows", rowcount) 801 return rowcount
802 803
804 -def _transpose(hasharr):
805 """ Transpose the array of hashes into a hash of arrays """ 806 if not hasharr: 807 return {} 808 keys = list(hasharr[0].keys()) 809 result = {} 810 for k in keys: 811 result[k] = [] 812 813 for hval in hasharr: 814 for k in keys: 815 if k in hval: 816 result[k].append(hval[k]) 817 else: 818 result[k].append(None) 819 820 return result
821 822
823 -class MemoryInformation(Device):
824 825 """ Memory information """ 826 table = "rhnRAM" 827
828 - def __init__(self, dict=None):
829 fields = ["ram", "swap"] 830 mapping = {"class": None} 831 Device.__init__(self, fields, dict, mapping) 832 # use our own sequence 833 self.sequence = "rhn_ram_id_seq" 834 if not dict: 835 return 836 # Sometimes we get sent a NNNNL number and we need to strip the L 837 for k in fields: 838 if not self.data.has_key(k): 839 continue 840 if self.data[k] in [None, "None", ""]: 841 self.data[k] = -1 842 self.data[k] = str(self.data[k]) 843 if self.data[k][-1] == 'L': 844 self.data[k] = self.data[k][:-1]
845 846
847 -class DMIInformation(Device):
848 849 """ DMI information """ 850 table = "rhnServerDMI" 851
852 - def __init__(self, dict=None):
853 fields = ["vendor", "system", "product", "asset", "board", 854 "bios_vendor", "bios_version", "bios_release"] 855 mapping = {"class": None} 856 Device.__init__(self, fields, dict, mapping) 857 # use our own sequence 858 self.sequence = "rhn_server_dmi_id_seq" 859 self._autonull = ("vendor", "system", "product", "asset", "board", 860 "bios_vendor", "bios_version", "bios_release") 861 if not dict: 862 return 863 864 # deal with hardware with insanely long dmi strings... 865 for key, value in self.data.items(): 866 # Some of the values may be None 867 if value and isinstance(value, type("")): 868 self.data[key] = value[:256]
869 870
871 -class InstallInformation(Device):
872 873 """ Install information """ 874 table = "rhnServerInstallInfo" 875
876 - def __init__(self, dict=None):
877 fields = ['install_method', 'iso_status', 'mediasum'] 878 mapping = { 879 'class': None, 880 'installmethod': 'install_method', 881 'isostatus': 'iso_status', 882 'mediasum': 'mediasum', 883 } 884 Device.__init__(self, fields, dict, mapping) 885 self.sequence = 'rhn_server_install_info_id_seq'
886 887
888 -class Hardware:
889 890 """ Support for the hardware items """ 891
892 - def __init__(self):
893 self.__hardware = {} 894 self.__loaded = 0 895 self.__changed = 0
896
897 - def hardware_by_class(self, device_class):
898 return self.__hardware[device_class]
899
900 - def add_hardware(self, hardware):
901 """ add new hardware """ 902 log_debug(4, hardware) 903 if not hardware: 904 return -1 905 if type(hardware) == type({}): 906 hardware = UserDictCase(hardware) 907 if not isinstance(hardware, UserDictCase): 908 log_error("argument type is not hash: %s" % hardware) 909 raise TypeError("This function requires a hash as an argument") 910 # validation is important 911 hw_class = hardware.get("class") 912 if hw_class is None: 913 return -1 914 hw_class = string.lower(hw_class) 915 916 class_type = None 917 918 if hw_class in ["video", "audio", "audio_hd", "usb", "other", "hd", "floppy", 919 "mouse", "modem", "network", "cdrom", "scsi", 920 "unspec", "scanner", "tape", "capture", "raid", 921 "socket", "keyboard", "printer", "firewire", "ide"]: 922 class_type = HardwareDevice 923 elif hw_class == "cpu": 924 class_type = CPUDevice 925 elif hw_class == "netinfo": 926 class_type = NetworkInformation 927 elif hw_class == "memory": 928 class_type = MemoryInformation 929 elif hw_class == "dmi": 930 class_type = DMIInformation 931 elif hw_class == "installinfo": 932 class_type = InstallInformation 933 elif hw_class == "netinterfaces": 934 class_type = NetIfaceInformation 935 else: 936 log_error("UNKNOWN CLASS TYPE `%s'" % hw_class) 937 # Same trick: try-except and raise the exception so that Traceback 938 # can send the e-mail 939 try: 940 raise KeyError("Unknwon class type `%s' for hardware '%s'" % ( 941 hw_class, hardware)) 942 except: 943 Traceback(mail=1) 944 return 945 946 # create the new device 947 new_dev = class_type(hardware) 948 949 if class_type in self.__hardware: 950 _l = self.__hardware[class_type] 951 else: 952 _l = self.__hardware[class_type] = [] 953 _l.append(new_dev) 954 self.__changed = 1 955 return 0
956
957 - def delete_hardware(self, sysid=None):
958 """ This function deletes all hardware. """ 959 log_debug(4, sysid) 960 if not self.__loaded: 961 self.reload_hardware_byid(sysid) 962 hardware = self.__hardware 963 if hardware == {}: 964 # nothing to delete 965 return 0 966 self.__changed = 1 967 968 for device_type in hardware.keys(): 969 for hw in hardware[device_type]: 970 hw.status = 2 # deleted 971 972 # filter out the hardware that was just added and then 973 # deleted before saving 974 hardware[device_type] = [a for a in hardware[device_type] if not (a.status == 2 and hasattr(a, "id") and a.id == 0)] 975 return 0
976
977 - def save_hardware_byid(self, sysid):
978 """Save the hardware list """ 979 log_debug(3, sysid, "changed = %s" % self.__changed) 980 hardware = self.__hardware 981 if hardware == {}: # nothing loaded 982 return 0 983 if not self.__changed: 984 return 0 985 for device_type, hw_list in hardware.items(): 986 for hw in hw_list: 987 hw.save(sysid) 988 self.__changed = 0 989 return 0
990
991 - def __load_from_db(self, DevClass, sysid):
992 """ Load a certain hardware class from the database """ 993 if DevClass not in self.__hardware: 994 self.__hardware[DevClass] = [] 995 996 h = rhnSQL.prepare("select id from %s where server_id = :sysid" % DevClass.table) 997 h.execute(sysid=sysid) 998 rows = h.fetchall_dict() or [] 999 1000 for device in rows: 1001 dev_id = device['id'] 1002 dev = DevClass() 1003 dev.reload(dev_id) 1004 self.__hardware[DevClass].append(dev)
1005
1006 - def reload_hardware_byid(self, sysid):
1007 """ load all hardware devices for a server """ 1008 log_debug(4, sysid) 1009 if not sysid: 1010 return -1 1011 self.__hardware = {} # discard what was already loaded 1012 # load from all hardware databases 1013 self.__load_from_db(HardwareDevice, sysid) 1014 self.__load_from_db(CPUDevice, sysid) 1015 self.__load_from_db(DMIInformation, sysid) 1016 self.__load_from_db(NetworkInformation, sysid) 1017 self.__load_from_db(MemoryInformation, sysid) 1018 self.__load_from_db(InstallInformation, sysid) 1019 1020 net_iface_info = NetIfaceInformation() 1021 net_iface_info.reload(sysid) 1022 self.__hardware[NetIfaceInformation] = [net_iface_info] 1023 1024 # now set the flag 1025 self.__changed = 0 1026 self.__loaded = 1 1027 return 0
1028