Changeset 3413 for pykota/trunk/pykota/accounters/snmp.py
- Timestamp:
- 09/27/08 22:02:37 (16 years ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
pykota/trunk/pykota/accounters/snmp.py
r3411 r3413 8 8 # the Free Software Foundation, either version 3 of the License, or 9 9 # (at your option) any later version. 10 # 10 # 11 11 # This program is distributed in the hope that it will be useful, 12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 14 # GNU General Public License for more details. 15 # 15 # 16 16 # You should have received a copy of the GNU General Public License 17 17 # along with this program. If not, see <http://www.gnu.org/licenses/>. … … 36 36 try : 37 37 from pysnmp.entity.rfc3413.oneliner import cmdgen 38 except ImportError : 38 except ImportError : 39 39 hasV4 = False 40 40 try : … … 50 50 from pykota import constants 51 51 52 # 52 # 53 53 # Documentation taken from RFC 3805 (Printer MIB v2) and RFC 2790 (Host Resource MIB) 54 54 # … … 67 67 4 : 'testing', 68 68 5 : 'down', 69 } 69 } 70 70 hrPrinterDetectedErrorStateOID = "1.3.6.1.2.1.25.3.5.1.2.1" # SNMPv2-SMI::mib-2.25.3.5.1.2.1 71 71 printerDetectedErrorStateValues = [ { 128 : 'Low Paper', … … 87 87 1 : 'Not Assigned in RFC3805', 88 88 }, 89 ] 90 89 ] 90 91 91 # The default error mask to use when checking error conditions. 92 92 defaultErrorMask = 0x4fcc # [ 'No Paper', … … 100 100 # 'Input Tray Empty', 101 101 # ] 102 103 # WARNING : some printers don't support this one : 102 103 # WARNING : some printers don't support this one : 104 104 prtConsoleDisplayBufferTextOID = "1.3.6.1.2.1.43.16.5.1.2.1.1" # SNMPv2-SMI::mib-2.43.16.5.1.2.1.1 105 105 class BaseHandler : … … 111 111 try : 112 112 self.community = self.parent.arguments.split(":")[1].strip() 113 except IndexError : 113 except IndexError : 114 114 self.community = "public" 115 115 self.port = 161 116 116 self.initValues() 117 118 def initValues(self) : 117 118 def initValues(self) : 119 119 """Initializes SNMP values.""" 120 120 self.printerInternalPageCounter = None … … 123 123 self.printerDetectedErrorState = None 124 124 self.timebefore = time.time() # resets timer also in case of error 125 126 def retrieveSNMPValues(self) : 125 126 def retrieveSNMPValues(self) : 127 127 """Retrieves a printer's internal page counter and status via SNMP.""" 128 128 raise RuntimeError, "You have to overload this method." 129 130 def extractErrorStates(self, value) : 129 130 def extractErrorStates(self, value) : 131 131 """Returns a list of textual error states from a binary value.""" 132 132 states = [] … … 137 137 if byte & k : 138 138 states.append(v) 139 return states 140 141 def checkIfError(self, errorstates) : 139 return states 140 141 def checkIfError(self, errorstates) : 142 142 """Checks if any error state is fatal or not.""" 143 143 if errorstates is None : … … 146 146 try : 147 147 errormask = self.parent.filter.config.getPrinterSNMPErrorMask(self.parent.filter.PrinterName) 148 except AttributeError : # debug mode 148 except AttributeError : # debug mode 149 149 errormask = defaultErrorMask 150 150 if errormask is None : … … 161 161 return True 162 162 self.parent.filter.logdebug("No error condition matching mask 0x%04x" % errormask) 163 return False 164 163 return False 164 165 165 def waitPrinting(self) : 166 166 """Waits for printer status being 'printing'.""" … … 169 169 if not noprintingmaxdelay : 170 170 self.parent.filter.logdebug("Will wait indefinitely until printer %s is in 'printing' state." % self.parent.filter.PrinterName) 171 else : 171 else : 172 172 self.parent.filter.logdebug("Will wait until printer %s is in 'printing' state or %i seconds have elapsed." % (self.parent.filter.PrinterName, noprintingmaxdelay)) 173 173 previousValue = self.parent.getLastPageCounter() … … 178 178 if statusAsString in ('printing', 'warmup') : 179 179 break 180 if self.printerInternalPageCounter is not None : 180 if self.printerInternalPageCounter is not None : 181 181 if firstvalue is None : 182 182 # first time we retrieved a page counter, save it 183 183 firstvalue = self.printerInternalPageCounter 184 else : 184 else : 185 185 # second time (or later) 186 186 if firstvalue < self.printerInternalPageCounter : … … 205 205 # the printer rejected it for some reason. 206 206 self.parent.filter.printInfo("Printer %s probably won't print this job !!!" % self.parent.filter.PrinterName, "warn") 207 else : 207 else : 208 208 # Here the job has already been entirely printed, and 209 209 # the printer has already passed from 'idle' to 'printing' to 'idle' again. 210 210 self.parent.filter.printInfo("Printer %s has probably already printed this job !!!" % self.parent.filter.PrinterName, "warn") 211 211 break 212 self.parent.filter.logdebug(_("Waiting for printer %s to be printing...") % self.parent.filter.PrinterName) 212 self.parent.filter.logdebug(_("Waiting for printer %s to be printing...") % self.parent.filter.PrinterName) 213 213 time.sleep(statusstabilizationdelay) 214 214 215 215 def waitIdle(self) : 216 216 """Waits for printer status being 'idle'.""" … … 228 228 (dstatusAsString == 'running'))) : 229 229 idle_flag = 1 # Standby / Powersave is considered idle 230 if idle_flag : 230 if idle_flag : 231 231 if (self.printerInternalPageCounter is not None) \ 232 232 and self.skipinitialwait \ 233 233 and (os.environ.get("PYKOTAPHASE") == "BEFORE") : 234 234 self.parent.filter.logdebug("No need to wait for the printer to be idle, it is the case already.") 235 return 235 return 236 236 idle_num += 1 237 237 if idle_num >= statusstabilizationloops : 238 238 # printer status is stable, we can exit 239 239 break 240 else : 240 else : 241 241 idle_num = 0 242 self.parent.filter.logdebug(_("Waiting for printer %s's idle status to stabilize...") % self.parent.filter.PrinterName) 242 self.parent.filter.logdebug(_("Waiting for printer %s's idle status to stabilize...") % self.parent.filter.PrinterName) 243 243 time.sleep(statusstabilizationdelay) 244 244 245 245 def retrieveInternalPageCounter(self) : 246 246 """Returns the page counter from the printer via internal SNMP handling.""" … … 251 251 self.parent.filter.JobSizeBytes : 252 252 self.waitPrinting() 253 self.waitIdle() 254 except : 253 self.waitIdle() 254 except : 255 255 self.parent.filter.printInfo(_("SNMP querying stage interrupted. Using latest value seen for internal page counter (%s) on printer %s.") % (self.printerInternalPageCounter, self.parent.filter.PrinterName), "warn") 256 256 raise 257 257 return self.printerInternalPageCounter 258 259 if hasV4 : 258 259 if hasV4 : 260 260 class Handler(BaseHandler) : 261 261 """A class for pysnmp v4.x""" … … 270 270 tuple([int(i) for i in hrDeviceStatusOID.split('.')]), \ 271 271 tuple([int(i) for i in hrPrinterDetectedErrorStateOID.split('.')])) 272 except socket.gaierror, msg : 272 except socket.gaierror, msg : 273 273 errorIndication = repr(msg) 274 except : 274 except : 275 275 errorIndication = "Unknown SNMP/Network error. Check your wires." 276 if errorIndication : 276 if errorIndication : 277 277 self.parent.filter.printInfo("SNMP Error : %s" % errorIndication, "error") 278 278 self.initValues() 279 elif errorStatus : 279 elif errorStatus : 280 280 self.parent.filter.printInfo("SNMP Error : %s at %s" % (errorStatus.prettyPrint(), \ 281 281 varBinds[int(errorIndex)-1]), \ 282 282 "error") 283 283 self.initValues() 284 else : 284 else : 285 285 self.printerInternalPageCounter = max(self.printerInternalPageCounter, int(varBinds[0][1].prettyPrint() or "0")) 286 286 self.printerStatus = int(varBinds[1][1].prettyPrint()) … … 295 295 class Handler(BaseHandler) : 296 296 """A class for pysnmp v3.4.x""" 297 def retrieveSNMPValues(self) : 297 def retrieveSNMPValues(self) : 298 298 """Retrieves a printer's internal page counter and status via SNMP.""" 299 299 ver = alpha.protoVersions[alpha.protoVersionId1] … … 310 310 (self.printerHostname, self.port), \ 311 311 (self.handleAnswer, req)) 312 except (SnmpOverUdpError, select.error), msg : 312 except (SnmpOverUdpError, select.error), msg : 313 313 self.parent.filter.printInfo(_("Network error while doing SNMP queries on printer %s : %s") % (self.printerHostname, msg), "warn") 314 314 self.initValues() 315 315 tsp.close() 316 316 317 317 def handleAnswer(self, wholeMsg, notusedhere, req): 318 318 """Decodes and handles the SNMP answer.""" … … 321 321 try : 322 322 rsp.berDecode(wholeMsg) 323 except TypeMismatchError, msg : 323 except TypeMismatchError, msg : 324 324 self.parent.filter.printInfo(_("SNMP message decoding error for printer %s : %s") % (self.printerHostname, msg), "warn") 325 325 self.initValues() … … 333 333 for varBind in rsp.apiAlphaGetPdu().apiAlphaGetVarBindList(): 334 334 self.values.append(varBind.apiAlphaGetOidVal()[1].rawAsn1Value) 335 try : 335 try : 336 336 # keep maximum value seen for printer's internal page counter 337 337 self.printerInternalPageCounter = max(self.printerInternalPageCounter, self.values[0]) … … 344 344 deviceStatusValues.get(self.deviceStatus), \ 345 345 self.printerDetectedErrorState)) 346 except IndexError : 346 except IndexError : 347 347 self.parent.filter.logdebug("SNMP answer is incomplete : %s" % str(self.values)) 348 348 pass 349 else : 349 else : 350 350 return 1 351 351 352 352 def main(hostname) : 353 353 """Tries SNMP accounting for a printer host.""" … … 358 358 self.PrinterName = "FakePrintQueue" 359 359 self.JobSizeBytes = 1 360 360 361 361 def printInfo(self, msg, level="info") : 362 362 """Prints informational message.""" 363 363 sys.stderr.write("%s : %s\n" % (level.upper(), msg)) 364 364 sys.stderr.flush() 365 366 def logdebug(self, msg) : 365 366 def logdebug(self, msg) : 367 367 """Prints debug message.""" 368 368 self.printInfo(msg, "debug") 369 370 class fakeAccounter : 369 370 class fakeAccounter : 371 371 """Fakes an accounter for testing purposes.""" 372 372 def __init__(self) : … … 375 375 self.filter = fakeFilter() 376 376 self.protocolHandler = Handler(self, hostname) 377 378 def getLastPageCounter(self) : 377 378 def getLastPageCounter(self) : 379 379 """Fakes the return of a page counter.""" 380 380 return 0 381 382 acc = fakeAccounter() 381 382 acc = fakeAccounter() 383 383 return acc.protocolHandler.retrieveInternalPageCounter() 384 385 if __name__ == "__main__" : 386 if len(sys.argv) != 2 : 384 385 if __name__ == "__main__" : 386 if len(sys.argv) != 2 : 387 387 sys.stderr.write("Usage : python %s printer_ip_address\n" % sys.argv[0]) 388 else : 388 else : 389 389 def _(msg) : 390 390 return msg 391 391 392 392 pagecounter = main(sys.argv[1]) 393 393 print "Internal page counter's value is : %s" % pagecounter