Changeset 3507

Show
Ignore:
Timestamp:
10/11/09 09:06:43 (12 years ago)
Author:
jerome
Message:

Backported the code that fixed #47.

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  
    1414# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    1515# GNU General Public License for more details. 
    16 #  
     16# 
    1717# You should have received a copy of the GNU General Public License 
    1818# along with this program; if not, write to the Free Software 
     
    3838try : 
    3939    from pysnmp.entity.rfc3413.oneliner import cmdgen 
    40 except ImportError :     
     40except ImportError : 
    4141    hasV4 = False 
    4242    try : 
     
    5252from pykota import constants 
    5353 
    54 #                       
     54# 
    5555# Documentation taken from RFC 3805 (Printer MIB v2) and RFC 2790 (Host Resource MIB) 
    5656# 
     
    6969                       4 : 'testing', 
    7070                       5 : 'down', 
    71                      }   
     71                     } 
    7272hrPrinterDetectedErrorStateOID = "1.3.6.1.2.1.25.3.5.1.2.1" # SNMPv2-SMI::mib-2.25.3.5.1.2.1 
    7373printerDetectedErrorStateValues = [ { 128 : 'Low Paper', 
     
    8989                                        1 : 'Not Assigned in RFC3805', 
    9090                                    }, 
    91                                   ]   
    92                                    
     91                                  ] 
     92 
    9393# The default error mask to use when checking error conditions. 
    9494defaultErrorMask = 0x4fcc # [ 'No Paper', 
     
    102102                          #   'Input Tray Empty', 
    103103                          # ] 
    104                            
    105 # WARNING : some printers don't support this one :                   
     104 
     105# WARNING : some printers don't support this one : 
    106106prtConsoleDisplayBufferTextOID = "1.3.6.1.2.1.43.16.5.1.2.1.1" # SNMPv2-SMI::mib-2.43.16.5.1.2.1.1 
    107107class BaseHandler : 
     
    113113        try : 
    114114            self.community = self.parent.arguments.split(":")[1].strip() 
    115         except IndexError :     
     115        except IndexError : 
    116116            self.community = "public" 
    117117        self.port = 161 
    118118        self.initValues() 
    119          
    120     def initValues(self) :     
     119 
     120    def initValues(self) : 
    121121        """Initializes SNMP values.""" 
    122122        self.printerInternalPageCounter = None 
     
    125125        self.printerDetectedErrorState = None 
    126126        self.timebefore = time.time()   # resets timer also in case of error 
    127          
    128     def retrieveSNMPValues(self) :     
     127 
     128    def retrieveSNMPValues(self) : 
    129129        """Retrieves a printer's internal page counter and status via SNMP.""" 
    130130        raise RuntimeError, "You have to overload this method." 
    131          
    132     def extractErrorStates(self, value) :     
     131 
     132    def extractErrorStates(self, value) : 
    133133        """Returns a list of textual error states from a binary value.""" 
    134134        states = [] 
     
    139139                if byte & k : 
    140140                    states.append(v) 
    141         return states             
    142          
    143     def checkIfError(self, errorstates) :     
     141        return states 
     142 
     143    def checkIfError(self, errorstates) : 
    144144        """Checks if any error state is fatal or not.""" 
    145145        if errorstates is None : 
     
    148148            try : 
    149149                errormask = self.parent.filter.config.getPrinterSNMPErrorMask(self.parent.filter.PrinterName) 
    150             except AttributeError : # debug mode     
     150            except AttributeError : # debug mode 
    151151                errormask = defaultErrorMask 
    152152            if errormask is None : 
     
    163163                    return True 
    164164            self.parent.filter.logdebug("No error condition matching mask 0x%04x" % errormask) 
    165             return False     
    166          
     165            return False 
     166 
    167167    def waitPrinting(self) : 
    168168        """Waits for printer status being 'printing'.""" 
     
    171171        if not noprintingmaxdelay : 
    172172            self.parent.filter.logdebug("Will wait indefinitely until printer %s is in 'printing' state." % self.parent.filter.PrinterName) 
    173         else :     
     173        else : 
    174174            self.parent.filter.logdebug("Will wait until printer %s is in 'printing' state or %i seconds have elapsed." % (self.parent.filter.PrinterName, noprintingmaxdelay)) 
    175175        previousValue = self.parent.getLastPageCounter() 
     
    180180            if statusAsString in ('printing', 'warmup') : 
    181181                break 
    182             if self.printerInternalPageCounter is not None :     
     182            if self.printerInternalPageCounter is not None : 
    183183                if firstvalue is None : 
    184184                    # first time we retrieved a page counter, save it 
    185185                    firstvalue = self.printerInternalPageCounter 
    186                 else :      
     186                else : 
    187187                    # second time (or later) 
    188188                    if firstvalue < self.printerInternalPageCounter : 
     
    207207                                # the printer rejected it for some reason. 
    208208                                self.parent.filter.printInfo("Printer %s probably won't print this job !!!" % self.parent.filter.PrinterName, "warn") 
    209                             else :      
     209                            else : 
    210210                                # Here the job has already been entirely printed, and 
    211211                                # the printer has already passed from 'idle' to 'printing' to 'idle' again. 
    212212                                self.parent.filter.printInfo("Printer %s has probably already printed this job !!!" % self.parent.filter.PrinterName, "warn") 
    213213                            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) 
    215215            time.sleep(statusstabilizationdelay) 
    216          
     216 
    217217    def waitIdle(self) : 
    218218        """Waits for printer status being 'idle'.""" 
     
    230230                          (dstatusAsString == 'running'))) : 
    231231                idle_flag = 1       # Standby / Powersave is considered idle 
    232             if idle_flag :     
     232            if idle_flag : 
    233233                if (self.printerInternalPageCounter is not None) \ 
    234234                   and self.skipinitialwait \ 
    235235                   and (os.environ.get("PYKOTAPHASE") == "BEFORE") : 
    236236                    self.parent.filter.logdebug("No need to wait for the printer to be idle, it is the case already.") 
    237                     return  
     237                    return 
    238238                idle_num += 1 
    239239                if idle_num >= statusstabilizationloops : 
    240240                    # printer status is stable, we can exit 
    241241                    break 
    242             else :     
     242            else : 
    243243                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) 
    245245            time.sleep(statusstabilizationdelay) 
    246              
     246 
    247247    def retrieveInternalPageCounter(self) : 
    248248        """Returns the page counter from the printer via internal SNMP handling.""" 
     
    253253               self.parent.filter.JobSizeBytes : 
    254254                self.waitPrinting() 
    255             self.waitIdle()     
    256         except :     
     255            self.waitIdle() 
     256        except : 
    257257            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") 
    258258            raise 
    259259        return self.printerInternalPageCounter 
    260              
    261 if hasV4 :             
     260 
     261if hasV4 : 
    262262    class Handler(BaseHandler) : 
    263263        """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 
    264270        def retrieveSNMPValues(self) : 
    265271            """Retrieves a printer's internal page counter and status via SNMP.""" 
    266272            try : 
    267273                errorIndication, errorStatus, errorIndex, varBinds = \ 
    268                  cmdgen.CommandGenerator().getCmd(cmdgen.CommunityData("pykota", self.community, 0), \ 
    269                                                   cmdgen.UdpTransportTarget((self.printerHostname, self.port)), \ 
    270                                                   tuple([int(i) for i in pageCounterOID.split('.')]), \ 
    271                                                   tuple([int(i) for i in hrPrinterStatusOID.split('.')]), \ 
    272                                                   tuple([int(i) for i in hrDeviceStatusOID.split('.')]), \ 
    273                                                   tuple([int(i) for i in hrPrinterDetectedErrorStateOID.split('.')])) 
    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 : 
    275281                errorIndication = repr(msg) 
    276             except :                                       
     282            except : 
    277283                errorIndication = "Unknown SNMP/Network error. Check your wires." 
    278             if errorIndication :                                                   
     284            if errorIndication : 
    279285                self.parent.filter.printInfo("SNMP Error : %s" % errorIndication, "error") 
    280286                self.initValues() 
    281             elif errorStatus :     
     287            elif errorStatus : 
    282288                self.parent.filter.printInfo("SNMP Error : %s at %s" % (errorStatus.prettyPrint(), \ 
    283289                                                                        varBinds[int(errorIndex)-1]), \ 
    284290                                             "error") 
    285291                self.initValues() 
    286             else :                                  
     292            else : 
    287293                self.printerInternalPageCounter = max(self.printerInternalPageCounter, int(varBinds[0][1].prettyPrint() or "0")) 
    288294                self.printerStatus = int(varBinds[1][1].prettyPrint()) 
     
    297303    class Handler(BaseHandler) : 
    298304        """A class for pysnmp v3.4.x""" 
    299         def retrieveSNMPValues(self) :     
     305        def retrieveSNMPValues(self) : 
    300306            """Retrieves a printer's internal page counter and status via SNMP.""" 
    301307            ver = alpha.protoVersions[alpha.protoVersionId1] 
     
    312318                                   (self.printerHostname, self.port), \ 
    313319                                   (self.handleAnswer, req)) 
    314             except (SnmpOverUdpError, select.error), msg :     
     320            except (SnmpOverUdpError, select.error), msg : 
    315321                self.parent.filter.printInfo(_("Network error while doing SNMP queries on printer %s : %s") % (self.printerHostname, msg), "warn") 
    316322                self.initValues() 
    317323            tsp.close() 
    318          
     324 
    319325        def handleAnswer(self, wholeMsg, notusedhere, req): 
    320326            """Decodes and handles the SNMP answer.""" 
     
    323329            try : 
    324330                rsp.berDecode(wholeMsg) 
    325             except TypeMismatchError, msg :     
     331            except TypeMismatchError, msg : 
    326332                self.parent.filter.printInfo(_("SNMP message decoding error for printer %s : %s") % (self.printerHostname, msg), "warn") 
    327333                self.initValues() 
     
    335341                        for varBind in rsp.apiAlphaGetPdu().apiAlphaGetVarBindList(): 
    336342                            self.values.append(varBind.apiAlphaGetOidVal()[1].rawAsn1Value) 
    337                         try :     
     343                        try : 
    338344                            # keep maximum value seen for printer's internal page counter 
    339345                            self.printerInternalPageCounter = max(self.printerInternalPageCounter, self.values[0]) 
     
    346352                                    deviceStatusValues.get(self.deviceStatus), \ 
    347353                                    self.printerDetectedErrorState)) 
    348                         except IndexError :     
     354                        except IndexError : 
    349355                            self.parent.filter.logdebug("SNMP answer is incomplete : %s" % str(self.values)) 
    350356                            pass 
    351                         else :     
     357                        else : 
    352358                            return 1 
    353                      
     359 
    354360def main(hostname) : 
    355361    """Tries SNMP accounting for a printer host.""" 
     
    360366            self.PrinterName = "FakePrintQueue" 
    361367            self.JobSizeBytes = 1 
    362              
     368 
    363369        def printInfo(self, msg, level="info") : 
    364370            """Prints informational message.""" 
    365371            sys.stderr.write("%s : %s\n" % (level.upper(), msg)) 
    366372            sys.stderr.flush() 
    367              
    368         def logdebug(self, msg) :     
     373 
     374        def logdebug(self, msg) : 
    369375            """Prints debug message.""" 
    370376            self.printInfo(msg, "debug") 
    371              
    372     class fakeAccounter :         
     377 
     378    class fakeAccounter : 
    373379        """Fakes an accounter for testing purposes.""" 
    374380        def __init__(self) : 
     
    377383            self.filter = fakeFilter() 
    378384            self.protocolHandler = Handler(self, hostname) 
    379              
    380         def getLastPageCounter(self) :     
     385 
     386        def getLastPageCounter(self) : 
    381387            """Fakes the return of a page counter.""" 
    382388            return 0 
    383          
    384     acc = fakeAccounter()             
     389 
     390    acc = fakeAccounter() 
    385391    return acc.protocolHandler.retrieveInternalPageCounter() 
    386          
    387 if __name__ == "__main__" :             
    388     if len(sys.argv) != 2 :     
     392 
     393if __name__ == "__main__" : 
     394    if len(sys.argv) != 2 : 
    389395        sys.stderr.write("Usage :  python  %s  printer_ip_address\n" % sys.argv[0]) 
    390     else :     
     396    else : 
    391397        def _(msg) : 
    392398            return msg 
    393              
     399 
    394400        pagecounter = main(sys.argv[1]) 
    395401        print "Internal page counter's value is : %s" % pagecounter 
  • pykota/branches/1.26_fixes/pykota/version.py

    r3238 r3507  
    1414# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    1515# GNU General Public License for more details. 
    16 #  
     16# 
    1717# You should have received a copy of the GNU General Public License 
    1818# along with this program; if not, write to the Free Software 
     
    2424"""This module defines some application level constants.""" 
    2525 
    26 __version__ = "1.26_unofficial" 
     26__version__ = "1.26_fixes_unofficial" 
    2727 
    2828__doc__ = "PyKota : a complete Printing Quota Solution for CUPS."