- Timestamp:
- 10/11/09 09:06:43 (15 years ago)
- Location:
- pykota/branches/1.26_fixes/pykota
- Files:
-
- 2 modified
Legend:
- Unmodified
- Added
- Removed
-
pykota/branches/1.26_fixes/pykota/accounters/snmp.py
r3395 r3507 14 14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 15 # GNU General Public License for more details. 16 # 16 # 17 17 # You should have received a copy of the GNU General Public License 18 18 # along with this program; if not, write to the Free Software … … 38 38 try : 39 39 from pysnmp.entity.rfc3413.oneliner import cmdgen 40 except ImportError : 40 except ImportError : 41 41 hasV4 = False 42 42 try : … … 52 52 from pykota import constants 53 53 54 # 54 # 55 55 # Documentation taken from RFC 3805 (Printer MIB v2) and RFC 2790 (Host Resource MIB) 56 56 # … … 69 69 4 : 'testing', 70 70 5 : 'down', 71 } 71 } 72 72 hrPrinterDetectedErrorStateOID = "1.3.6.1.2.1.25.3.5.1.2.1" # SNMPv2-SMI::mib-2.25.3.5.1.2.1 73 73 printerDetectedErrorStateValues = [ { 128 : 'Low Paper', … … 89 89 1 : 'Not Assigned in RFC3805', 90 90 }, 91 ] 92 91 ] 92 93 93 # The default error mask to use when checking error conditions. 94 94 defaultErrorMask = 0x4fcc # [ 'No Paper', … … 102 102 # 'Input Tray Empty', 103 103 # ] 104 105 # WARNING : some printers don't support this one : 104 105 # WARNING : some printers don't support this one : 106 106 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 107 107 class BaseHandler : … … 113 113 try : 114 114 self.community = self.parent.arguments.split(":")[1].strip() 115 except IndexError : 115 except IndexError : 116 116 self.community = "public" 117 117 self.port = 161 118 118 self.initValues() 119 120 def initValues(self) : 119 120 def initValues(self) : 121 121 """Initializes SNMP values.""" 122 122 self.printerInternalPageCounter = None … … 125 125 self.printerDetectedErrorState = None 126 126 self.timebefore = time.time() # resets timer also in case of error 127 128 def retrieveSNMPValues(self) : 127 128 def retrieveSNMPValues(self) : 129 129 """Retrieves a printer's internal page counter and status via SNMP.""" 130 130 raise RuntimeError, "You have to overload this method." 131 132 def extractErrorStates(self, value) : 131 132 def extractErrorStates(self, value) : 133 133 """Returns a list of textual error states from a binary value.""" 134 134 states = [] … … 139 139 if byte & k : 140 140 states.append(v) 141 return states 142 143 def checkIfError(self, errorstates) : 141 return states 142 143 def checkIfError(self, errorstates) : 144 144 """Checks if any error state is fatal or not.""" 145 145 if errorstates is None : … … 148 148 try : 149 149 errormask = self.parent.filter.config.getPrinterSNMPErrorMask(self.parent.filter.PrinterName) 150 except AttributeError : # debug mode 150 except AttributeError : # debug mode 151 151 errormask = defaultErrorMask 152 152 if errormask is None : … … 163 163 return True 164 164 self.parent.filter.logdebug("No error condition matching mask 0x%04x" % errormask) 165 return False 166 165 return False 166 167 167 def waitPrinting(self) : 168 168 """Waits for printer status being 'printing'.""" … … 171 171 if not noprintingmaxdelay : 172 172 self.parent.filter.logdebug("Will wait indefinitely until printer %s is in 'printing' state." % self.parent.filter.PrinterName) 173 else : 173 else : 174 174 self.parent.filter.logdebug("Will wait until printer %s is in 'printing' state or %i seconds have elapsed." % (self.parent.filter.PrinterName, noprintingmaxdelay)) 175 175 previousValue = self.parent.getLastPageCounter() … … 180 180 if statusAsString in ('printing', 'warmup') : 181 181 break 182 if self.printerInternalPageCounter is not None : 182 if self.printerInternalPageCounter is not None : 183 183 if firstvalue is None : 184 184 # first time we retrieved a page counter, save it 185 185 firstvalue = self.printerInternalPageCounter 186 else : 186 else : 187 187 # second time (or later) 188 188 if firstvalue < self.printerInternalPageCounter : … … 207 207 # the printer rejected it for some reason. 208 208 self.parent.filter.printInfo("Printer %s probably won't print this job !!!" % self.parent.filter.PrinterName, "warn") 209 else : 209 else : 210 210 # Here the job has already been entirely printed, and 211 211 # the printer has already passed from 'idle' to 'printing' to 'idle' again. 212 212 self.parent.filter.printInfo("Printer %s has probably already printed this job !!!" % self.parent.filter.PrinterName, "warn") 213 213 break 214 self.parent.filter.logdebug(_("Waiting for printer %s to be printing...") % self.parent.filter.PrinterName) 214 self.parent.filter.logdebug(_("Waiting for printer %s to be printing...") % self.parent.filter.PrinterName) 215 215 time.sleep(statusstabilizationdelay) 216 216 217 217 def waitIdle(self) : 218 218 """Waits for printer status being 'idle'.""" … … 230 230 (dstatusAsString == 'running'))) : 231 231 idle_flag = 1 # Standby / Powersave is considered idle 232 if idle_flag : 232 if idle_flag : 233 233 if (self.printerInternalPageCounter is not None) \ 234 234 and self.skipinitialwait \ 235 235 and (os.environ.get("PYKOTAPHASE") == "BEFORE") : 236 236 self.parent.filter.logdebug("No need to wait for the printer to be idle, it is the case already.") 237 return 237 return 238 238 idle_num += 1 239 239 if idle_num >= statusstabilizationloops : 240 240 # printer status is stable, we can exit 241 241 break 242 else : 242 else : 243 243 idle_num = 0 244 self.parent.filter.logdebug(_("Waiting for printer %s's idle status to stabilize...") % self.parent.filter.PrinterName) 244 self.parent.filter.logdebug(_("Waiting for printer %s's idle status to stabilize...") % self.parent.filter.PrinterName) 245 245 time.sleep(statusstabilizationdelay) 246 246 247 247 def retrieveInternalPageCounter(self) : 248 248 """Returns the page counter from the printer via internal SNMP handling.""" … … 253 253 self.parent.filter.JobSizeBytes : 254 254 self.waitPrinting() 255 self.waitIdle() 256 except : 255 self.waitIdle() 256 except : 257 257 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") 258 258 raise 259 259 return self.printerInternalPageCounter 260 261 if hasV4 : 260 261 if hasV4 : 262 262 class Handler(BaseHandler) : 263 263 """A class for pysnmp v4.x""" 264 def __init__(self, *args): 265 BaseHandler.__init__(self, *args) 266 self.snmpEngine = cmdgen.CommandGenerator() 267 self.snmpAuth = cmdgen.CommunityData("pykota", self.community, 0) 268 self.snmpTarget = cmdgen.UdpTransportTarget((self.printerHostname, self.port)) 269 264 270 def retrieveSNMPValues(self) : 265 271 """Retrieves a printer's internal page counter and status via SNMP.""" 266 272 try : 267 273 errorIndication, errorStatus, errorIndex, varBinds = \ 268 cmdgen.CommandGenerator().getCmd(cmdgen.CommunityData("pykota", self.community, 0), \269 cmdgen.UdpTransportTarget((self.printerHostname, self.port)), \270 271 272 273 274 except socket.gaierror, msg : 274 self.snmpEngine.getCmd(self.snmpAuth, \ 275 self.snmpTarget, \ 276 tuple([int(i) for i in pageCounterOID.split('.')]), \ 277 tuple([int(i) for i in hrPrinterStatusOID.split('.')]), \ 278 tuple([int(i) for i in hrDeviceStatusOID.split('.')]), \ 279 tuple([int(i) for i in hrPrinterDetectedErrorStateOID.split('.')])) 280 except socket.gaierror, msg : 275 281 errorIndication = repr(msg) 276 except : 282 except : 277 283 errorIndication = "Unknown SNMP/Network error. Check your wires." 278 if errorIndication : 284 if errorIndication : 279 285 self.parent.filter.printInfo("SNMP Error : %s" % errorIndication, "error") 280 286 self.initValues() 281 elif errorStatus : 287 elif errorStatus : 282 288 self.parent.filter.printInfo("SNMP Error : %s at %s" % (errorStatus.prettyPrint(), \ 283 289 varBinds[int(errorIndex)-1]), \ 284 290 "error") 285 291 self.initValues() 286 else : 292 else : 287 293 self.printerInternalPageCounter = max(self.printerInternalPageCounter, int(varBinds[0][1].prettyPrint() or "0")) 288 294 self.printerStatus = int(varBinds[1][1].prettyPrint()) … … 297 303 class Handler(BaseHandler) : 298 304 """A class for pysnmp v3.4.x""" 299 def retrieveSNMPValues(self) : 305 def retrieveSNMPValues(self) : 300 306 """Retrieves a printer's internal page counter and status via SNMP.""" 301 307 ver = alpha.protoVersions[alpha.protoVersionId1] … … 312 318 (self.printerHostname, self.port), \ 313 319 (self.handleAnswer, req)) 314 except (SnmpOverUdpError, select.error), msg : 320 except (SnmpOverUdpError, select.error), msg : 315 321 self.parent.filter.printInfo(_("Network error while doing SNMP queries on printer %s : %s") % (self.printerHostname, msg), "warn") 316 322 self.initValues() 317 323 tsp.close() 318 324 319 325 def handleAnswer(self, wholeMsg, notusedhere, req): 320 326 """Decodes and handles the SNMP answer.""" … … 323 329 try : 324 330 rsp.berDecode(wholeMsg) 325 except TypeMismatchError, msg : 331 except TypeMismatchError, msg : 326 332 self.parent.filter.printInfo(_("SNMP message decoding error for printer %s : %s") % (self.printerHostname, msg), "warn") 327 333 self.initValues() … … 335 341 for varBind in rsp.apiAlphaGetPdu().apiAlphaGetVarBindList(): 336 342 self.values.append(varBind.apiAlphaGetOidVal()[1].rawAsn1Value) 337 try : 343 try : 338 344 # keep maximum value seen for printer's internal page counter 339 345 self.printerInternalPageCounter = max(self.printerInternalPageCounter, self.values[0]) … … 346 352 deviceStatusValues.get(self.deviceStatus), \ 347 353 self.printerDetectedErrorState)) 348 except IndexError : 354 except IndexError : 349 355 self.parent.filter.logdebug("SNMP answer is incomplete : %s" % str(self.values)) 350 356 pass 351 else : 357 else : 352 358 return 1 353 359 354 360 def main(hostname) : 355 361 """Tries SNMP accounting for a printer host.""" … … 360 366 self.PrinterName = "FakePrintQueue" 361 367 self.JobSizeBytes = 1 362 368 363 369 def printInfo(self, msg, level="info") : 364 370 """Prints informational message.""" 365 371 sys.stderr.write("%s : %s\n" % (level.upper(), msg)) 366 372 sys.stderr.flush() 367 368 def logdebug(self, msg) : 373 374 def logdebug(self, msg) : 369 375 """Prints debug message.""" 370 376 self.printInfo(msg, "debug") 371 372 class fakeAccounter : 377 378 class fakeAccounter : 373 379 """Fakes an accounter for testing purposes.""" 374 380 def __init__(self) : … … 377 383 self.filter = fakeFilter() 378 384 self.protocolHandler = Handler(self, hostname) 379 380 def getLastPageCounter(self) : 385 386 def getLastPageCounter(self) : 381 387 """Fakes the return of a page counter.""" 382 388 return 0 383 384 acc = fakeAccounter() 389 390 acc = fakeAccounter() 385 391 return acc.protocolHandler.retrieveInternalPageCounter() 386 387 if __name__ == "__main__" : 388 if len(sys.argv) != 2 : 392 393 if __name__ == "__main__" : 394 if len(sys.argv) != 2 : 389 395 sys.stderr.write("Usage : python %s printer_ip_address\n" % sys.argv[0]) 390 else : 396 else : 391 397 def _(msg) : 392 398 return msg 393 399 394 400 pagecounter = main(sys.argv[1]) 395 401 print "Internal page counter's value is : %s" % pagecounter -
pykota/branches/1.26_fixes/pykota/version.py
r3238 r3507 14 14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 15 # GNU General Public License for more details. 16 # 16 # 17 17 # You should have received a copy of the GNU General Public License 18 18 # along with this program; if not, write to the Free Software … … 24 24 """This module defines some application level constants.""" 25 25 26 __version__ = "1.26_ unofficial"26 __version__ = "1.26_fixes_unofficial" 27 27 28 28 __doc__ = "PyKota : a complete Printing Quota Solution for CUPS."