def powerState(self): """ Get the power state for all slots """ walkAttr = 'remoteControlBladePowerState' oid = 'BLADE-MIB::%s' % walkAttr # Start async snmpwalk. This call returns immediately # and spawns a background thread to perform the SNMPWalk snmpWalk = SNMPWalk.withConfigFile(self.host, oid) state = [] # While the snmpwalk is running while not snmpWalk.eof: # Get snmp oid/value pairs off the queue while not snmpWalk.queue.empty(): (oid, value) = snmpWalk.queue.get() (mibName, attr, lastOctet) = snmpWalk.extractOidParts(oid) if attr == walkAttr: if value == 'on(1)': state.append(1) else: state.append(0) snmpWalk.join() Log.debug(100, 'ch %03d power state: %s' % (self.num, state)) return state
def walk(self, oid): """ Perform an SNMP walk Params ----- oid : string The starting OID """ version = '-v1' if self.version == 2: version = '-v2' args = [ snmpwalk_cmd, '-t', '120', version, '-c', self.readCommunity, self.host, oid ] Log.debug(100, ' '.join(args)) (output, exitcode) = Command.run(args) values = None if exitcode == 0 and output: values = [] for line in output: line.rstrip('\n') if len(line) > 0: values.append(self.parseSNMPLine(line)) return values
def powerState(self): """ Get the power state for all slots """ walkAttr = 'remoteControlBladePowerState' oid = 'BLADE-MIB::%s' % walkAttr # Start async snmpwalk. This call returns immediately # and spawns a background thread to perform the SNMPWalk snmpWalk = SNMPWalk.withConfigFile(self.host, oid) state = [] # While the snmpwalk is running while not snmpWalk.eof: # Get snmp oid/value pairs off the queue while not snmpWalk.queue.empty(): (oid, value) = snmpWalk.queue.get() (mibName, attr, lastOctet) = snmpWalk.extractOidParts(oid) if attr == walkAttr: if value == 'on(1)': state.append(1) else: state.append(0) snmpWalk.join() Log.debug(100, 'ch %03d power state: %s' % (self.num, state)) return state
def putDocument(self, docId, params): """ PUT a document on the CouchDB server. If the document already exists, you will need to pass in a _rev param with the revision you would like to update. The saveDocument() method handles this for you, if all you want to do is save a document, regardless of whether or not it already exists. Params ------ docId : string The unique ID of the document params : dictionary A dictionary of parameters that define the document """ path = '/%s/%s' % (self.db, docId.replace(' ', '+')) Log.debug(100, 'Putting %s' % path) connection = httplib.HTTPConnection(self.host, self.port) connection.connect() params['updatedAt'] = CouchDB.now() connection.request('PUT', path, json.dumps(params), { 'Content-Type': 'application/json' }) result = json.loads(connection.getresponse().read()) if result.has_key(u'error'): Log.error('PUT %s: %s' % (path, result)) return result
def retrieveWithMac(cls, couch, mac): """ Find a slot that matches the specified mac address Params ------ couch: object couch database connection mac: string The mac address for which to search Returns ------- Dictionary of key/value pairs for the slot that matches the specified mac address """ if mac == 'not available' or mac == 'not installed': return None output = couch.getView('slot', 'mac_to_slot', mac) Log.debug(200, output) if output and len(output) > 0: key, value = output.popitem() if value: return value return None
def getViewDict(self, design, view, params = {}): """ Get a view, return the results as a dictionary of key => values. If the particular key occurs multiple times, then the value will be an array of values for that key Params ------ design: string The design document name view: string The view name params: dictv Dictionary of parameters: key: The key to which results will be limited start: The starting key for the range to which results will be limited end: The ending key for the range to which results will be limited includeDocs: Set this to anything, and the entire document will be returned as the value Returns ------- A dictionary of view key/value pairs. If no results were returned, then None is returned """ path = self.getViewPath(design, view, params) Log.debug(10, 'Getting view path %s' % path) output = self.getDocument(path) results = {} if output.has_key(u'total_rows'): Log.debug(10, '%s returned %s rows' % (path, output[u'total_rows'])) if output.has_key(u'rows'): for row in output[u'rows']: key = row[u'key'] value = row.get(u'value', None) if params.has_key('includeDocs'): value = row.get(u'doc', None) # If this key is already in the results, then append this value # to the list if results.has_key(key): storedValue = results[key] # If the stored value is a dict, change to an array of dicts if isinstance(storedValue, (frozenset, list, set, tuple)): storedValue.append(value) value = storedValue else: value = [storedValue, value] results[key] = value # If no results, then return a None object if len(results) <= 0: results = {} return results
def walk(self, oid): """ Perform an SNMP walk Params ----- oid : string The starting OID """ version = '-v1' if self.version == 2: version = '-v2' args = [snmpwalk_cmd, '-t', '120', version, '-c', self.readCommunity, self.host, oid] Log.debug(100, ' '.join(args)) (output, exitcode) = Command.run(args) values = None if exitcode == 0 and output: values = [] for line in output: line.rstrip('\n') if len(line) > 0: values.append(self.parseSNMPLine(line)) return values
def retrieveWithMac(cls, couch, mac): """ Find a slot that matches the specified mac address Params ------ couch: object couch database connection mac: string The mac address for which to search Returns ------- Dictionary of key/value pairs for the slot that matches the specified mac address """ if mac == 'not available' or mac == 'not installed': return None output = couch.getView('slot', 'mac_to_slot', mac) Log.debug(200, output) if output and len(output) > 0: key, value = output.popitem() if value: return value return None
def collectChassisInfo(self, snmp): """ Retrieve chassis information """ for (attr, oid) in self.chassisOidDict.items(): values = snmp.walk(oid) if values: Log.debug(10, '%s: %s' % (attr, values[0][1])) setattr(self, attr, values[0][1])
def collectChassisInfo(self, snmp): """ Retrieve chassis information """ for (attr, oid) in self.chassisOidDict.items(): values = snmp.walk(oid) if values: Log.debug(10, '%s: %s' % (attr, values[0][1])) setattr(self, attr, values[0][1])
def run(cls, args): output = None exitCode = 0 try: Log.debug(100, ' '.join(args)) proc = Popen(args, stdout=PIPE) output = proc.communicate()[0].split('\n') exitCode = proc.returncode except (OSError) as e: Log.error(str(e)) return (output, exitCode)
def run(cls, args): output = None exitCode = 0 try: Log.debug(100, " ".join(args)) proc = Popen(args, stdout=PIPE) output = proc.communicate()[0].split("\n") exitCode = proc.returncode except (OSError) as e: Log.error(str(e)) return (output, exitCode)
def getView(self, design, view, key = None): """ Get a view Params ------ design: string The design document name view: string The view name key: string (optional) a key to select Returns ------- A dictionary of view key/value pairs. If no results were returned, then None is returned """ path = '_design/%s/_view/%s' % (design, view) if key: path = '%s?key="%s"' % (path, key) output = self.getDocument(path) results = {} if output.has_key(u'total_rows'): Log.debug(10, '%s returned %s rows' % (path, output[u'total_rows'])) if output.has_key(u'rows'): for row in output[u'rows']: value = row[u'value'] key = row[u'key'] if results.has_key(key): storedValue = results[key] # If the stored value is a dict, change to an array of dicts if isinstance(storedValue, (frozenset, list, set, tuple)): storedValue.append(value) value = storedValue else: value = [storedValue, value] results[key] = value # If no results, then return a None object if len(results) <= 0: results = {} return results
def run(self): """ Perform an SNMP walk """ version = '-v1' if self.version == 2: version = '-v2' command = [ snmpwalk_cmd, '-t', '120', version, '-c', self.readCommunity, self.host, self.oid ] Log.debug(100, ' '.join(command)) # Launch the command as subprocess. process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Launch the asynchronous readers of the process' stdout and stderr. stdoutQueue = Queue.Queue() stdoutReader = AsynchronousFileReader(process.stdout, stdoutQueue) stdoutReader.start() stderrQueue = Queue.Queue() stderrReader = AsynchronousFileReader(process.stderr, stderrQueue) stderrReader.start() # Check the queues if we received some output (until there is nothing more to get). while not stdoutReader.eof() or not stderrReader.eof(): # Show what we received from standard output. while not stdoutQueue.empty(): line = stdoutQueue.get() self.queue.put(self.split(line)) # Show what we received from standard error. while not stderrQueue.empty(): line = stderrQueue.get() print 'Received line on standard error: ' + repr(line) # Sleep a bit before asking the readers again. time.sleep(.1) # Let's be tidy and join the threads we've started. stdoutReader.join() stderrReader.join() # Close subprocess' file descriptors. process.stdout.close() process.stderr.close()
def delete(self, params): """ Delete a document. Params must have an _id and _rev param """ path = '/%s/%s?rev=%s' % (self.db, params['_id'].replace(' ', '+'), params['_rev'].replace(' ', '+')) Log.debug(10, 'DELETE %s' % path) connection = httplib.HTTPConnection(self.host, self.port) connection.connect() connection.request('DELETE', path) result = json.loads(connection.getresponse().read()) if result.has_key(u'error'): if result[u'error'] != u'not_found': Log.error('GET %s: %s' % (path, result)) return result
def allBladesFailToNetboot(cls, couch): """ Find a list of chassis where all blades failed to netboot Params ------ couch: object A CouchDB object Returns ------- A list of chassis docId """ results = couch.getView('blade', 'failed_netboot') chassis = {} failedChassis = [] for bladeDocId in results: slotInfo = Slot.retrieveWithMac(couch, bladeDocId) chassisDocId = None slotNum = None if slotInfo: Log.debug(200, 'slotInfo: %s' % slotInfo) if slotInfo.has_key(u'chassisDocId'): chassisDocId = slotInfo[u'chassisDocId'] if slotInfo.has_key(u'num'): slotNum = slotInfo[u'num'] if chassisDocId and slotInfo: if chassis.has_key(chassisDocId): chassis[chassisDocId].append(slotNum) else: chassis[chassisDocId] = [slotNum] for chassisDocId in sorted(chassis.iterkeys()): slots = chassis[chassisDocId] if len(slots) >= 14: failedChassis.append(chassisDocId) return failedChassis
def allBladesFailToNetboot(cls, couch): """ Find a list of chassis where all blades failed to netboot Params ------ couch: object A CouchDB object Returns ------- A list of chassis docId """ results = couch.getView('blade', 'failed_netboot') chassis = {} failedChassis = [] for bladeDocId in results: slotInfo = Slot.retrieveWithMac(couch, bladeDocId) chassisDocId = None slotNum = None if slotInfo: Log.debug(200, 'slotInfo: %s' % slotInfo) if slotInfo.has_key(u'chassisDocId'): chassisDocId = slotInfo[u'chassisDocId'] if slotInfo.has_key(u'num'): slotNum = slotInfo[u'num'] if chassisDocId and slotInfo: if chassis.has_key(chassisDocId): chassis[chassisDocId].append(slotNum) else: chassis[chassisDocId] = [slotNum] for chassisDocId in sorted(chassis.iterkeys()): slots = chassis[chassisDocId] if len(slots) >= 14: failedChassis.append(chassisDocId) return failedChassis
def run(self): """ Perform an SNMP walk """ version = '-v1' if self.version == 2: version = '-v2' command = [snmpwalk_cmd, '-t', '120', version, '-c', self.readCommunity, self.host, self.oid] Log.debug(100, ' '.join(command)) # Launch the command as subprocess. process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Launch the asynchronous readers of the process' stdout and stderr. stdoutQueue = Queue.Queue() stdoutReader = AsynchronousFileReader(process.stdout, stdoutQueue) stdoutReader.start() stderrQueue = Queue.Queue() stderrReader = AsynchronousFileReader(process.stderr, stderrQueue) stderrReader.start() # Check the queues if we received some output (until there is nothing more to get). while not stdoutReader.eof() or not stderrReader.eof(): # Show what we received from standard output. while not stdoutQueue.empty(): line = stdoutQueue.get() self.queue.put(self.split(line)) # Show what we received from standard error. while not stderrQueue.empty(): line = stderrQueue.get() print 'Received line on standard error: ' + repr(line) # Sleep a bit before asking the readers again. time.sleep(.1) # Let's be tidy and join the threads we've started. stdoutReader.join() stderrReader.join() # Close subprocess' file descriptors. process.stdout.close() process.stderr.close()
def getViewTuple(self, design, view, params = None): """ Get a view, return a list of key/value tuples Params ------ design: string The design document name view: string The view name key: string (optional) a key to select Returns ------- An array of 2-tuples. The first element in the tuple is the key, the second element is the value. If no results were returned, then the array will be empty """ path = self.getViewPath(design, view, params) Log.debug(10, 'Getting view path %s' % path) output = self.getDocument(path) results = [] if output.has_key(u'total_rows'): Log.debug(10, '%s returned %s rows' % (path, output[u'total_rows'])) if output.has_key(u'rows'): for row in output[u'rows']: key = row[u'key'] value = row.get(u'value', None) if params is not None and params.has_key('includeDocs'): value = row.get(u'doc', None) results.append((key, value)) return results
def collectInfoAndPersist(self, couch): """ Collect blade info for this chassis via SNMP, and persist those blades and slots and this Chassis object to CouchDB when done """ if not self.ping(): Log.info('%s not pingable, not collecting SNMP info' % self.host) else: Log.debug(5, '%s is pingable' % self.host) self.isPingable = 1 snmp = SNMP.withConfigFile(self.host) self.collectChassisInfo(snmp) self.collectFanPackInfo() bladesCommunicating = bitarray(self.bladesCommunicating) bladesInstalled = bitarray(self.bladesInstalled) oids = { 'mac0': 'BLADE-MIB::bladeMACAddress1Vpd', 'mac1': 'BLADE-MIB::bladeMACAddress2Vpd', 'biosVersion': 'BLADE-MIB::bladeBiosVpdRevision', 'bmcVersion': 'BLADE-MIB::bladeSysMgmtProcVpdRevision', 'diagVersion': 'BLADE-MIB::bladeDiagsVpdRevision', 'serialNumber': 'BLADE-MIB::bladeBiosVpdName', 'healthState': 'BLADE-MIB::bladeHealthState', 'healthSummarySeverity': 'BLADE-MIB::bladeHealthSummarySeverity', 'healthSummaryDescription': 'BLADE-MIB::bladeHealthSummaryDescription', } blade = {} for (attr, oid) in oids.items(): values = self.bladeInfo(snmp, oid) if values: for (slot, value) in values: if not blade.has_key(slot): blade[slot] = {} blade[slot][attr] = value if len(blade) > 0: self.collectedSNMP = 1 for (slotNum, params) in blade.items(): Log.debug( 10, 'chassis %d slot %s blade params: %s' % (self.num, slotNum, params)) nodeNum = (int(slotNum) - 1) + self.firstNode nodeName = self.nodeNameFormat % nodeNum blade = Blade(params) slotInt = int(slotNum) slotParams = { 'num': slotInt, 'nodeName': nodeName, 'chassisDocId': self.docId, 'bladeDocId': blade.mac0, 'bladeInstalled': bladesInstalled[slotInt - 1], 'bladeCommunicating': bladesCommunicating[slotInt - 1], } slot = Slot(slotParams) # This appears to be pointless. We shouldn't save any information about blades that # are not available # if blade.mac0 == 'not available': # blade.mac0 = '%s-%s' % (blade.mac0, slot.docId) slot.persist(couch) if blade.validMac0: blade.persist(couch) self.persist(couch)
def collectInfoAndPersist(self, couch): """ Collect blade info for this chassis via SNMP, and persist those blades and slots and this Chassis object to CouchDB when done """ if not self.ping(): Log.info('%s not pingable, not collecting SNMP info' % self.host) else: Log.debug(5, '%s is pingable' % self.host) self.isPingable = 1 snmp = SNMP.withConfigFile(self.host) self.collectChassisInfo(snmp) self.collectFanPackInfo() bladesCommunicating = bitarray(self.bladesCommunicating) bladesInstalled = bitarray(self.bladesInstalled) oids = {'mac0': 'BLADE-MIB::bladeMACAddress1Vpd', 'mac1': 'BLADE-MIB::bladeMACAddress2Vpd', 'biosVersion': 'BLADE-MIB::bladeBiosVpdRevision', 'bmcVersion': 'BLADE-MIB::bladeSysMgmtProcVpdRevision', 'diagVersion': 'BLADE-MIB::bladeDiagsVpdRevision', 'serialNumber': 'BLADE-MIB::bladeBiosVpdName', 'healthState': 'BLADE-MIB::bladeHealthState', 'healthSummarySeverity': 'BLADE-MIB::bladeHealthSummarySeverity', 'healthSummaryDescription': 'BLADE-MIB::bladeHealthSummaryDescription', } blade = {} for (attr, oid) in oids.items(): values = self.bladeInfo(snmp, oid) if values: for (slot, value) in values: if not blade.has_key(slot): blade[slot] = {} blade[slot][attr] = value if len(blade) > 0: self.collectedSNMP = 1 for (slotNum, params) in blade.items(): Log.debug(10, 'chassis %d slot %s blade params: %s' % (self.num, slotNum, params)) nodeNum = (int(slotNum) - 1) + self.firstNode nodeName = self.nodeNameFormat % nodeNum blade = Blade(params) slotInt = int(slotNum) slotParams = {'num': slotInt, 'nodeName': nodeName, 'chassisDocId': self.docId, 'bladeDocId': blade.mac0, 'bladeInstalled': bladesInstalled[slotInt - 1], 'bladeCommunicating': bladesCommunicating[slotInt - 1], } slot = Slot(slotParams) # This appears to be pointless. We shouldn't save any information about blades that # are not available # if blade.mac0 == 'not available': # blade.mac0 = '%s-%s' % (blade.mac0, slot.docId) slot.persist(couch) if blade.validMac0: blade.persist(couch) self.persist(couch)