root / pykota / trunk / bin / pkhint @ 2203

Revision 2147, 10.8 kB (checked in by jerome, 20 years ago)

Removed all references to $Log$

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#! /usr/bin/env python
2# -*- coding: ISO-8859-15 -*-
3
4# PyKota tool to hint for printer accounters
5#
6# PyKota - Print Quotas for CUPS and LPRng
7#
8# (c) 2003, 2004, 2005 Jerome Alet <alet@librelogiciel.com>
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22#
23# $Id$
24#
25#
26
27import sys
28import os
29
30from pykota.tool import PyKotaTool, PyKotaToolError, crashed, N_
31from pykota.config import PyKotaConfigError
32from pykota.storage import PyKotaStorageError
33try :
34    import pysnmp
35except ImportError :   
36    hasSNMP = 0
37else :   
38    hasSNMP = 1
39
40__doc__ = N_("""pkhint v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels Libres
41A tool to give hints on what accounting method is best for each printer.
42
43command line usage :
44
45  pkhint [options] [printer1 printer2 printer3 ... printerN] <file.conf
46
47options :
48
49  -v | --version       Prints pkhint's version number then exits.
50  -h | --help          Prints this message then exits.
51 
52examples :                             
53
54  $ pkhint "hp*" printer103 </etc/cups/printers.conf
55 
56  Will analyze your printing system to test which accounter
57  is the best for each of the defined printer which
58  name matches one of the parameters.
59 
60  If you don't pass any argument on the command line, all
61  printers will be analyzed.
62 
63This program is free software; you can redistribute it and/or modify
64it under the terms of the GNU General Public License as published by
65the Free Software Foundation; either version 2 of the License, or
66(at your option) any later version.
67
68This program is distributed in the hope that it will be useful,
69but WITHOUT ANY WARRANTY; without even the implied warranty of
70MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
71GNU General Public License for more details.
72
73You should have received a copy of the GNU General Public License
74along with this program; if not, write to the Free Software
75Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
76
77Please e-mail bugs to: %s""")
78       
79SNMPTESTS = [ \
80              'npadmin --pagecount %(printer)s 2>/dev/null', \
81              'snmpget -v1 -c public -Ov %(printer)s mib-2.43.10.2.1.4.1.1 2>/dev/null | cut -f 2,2 -d " "', \
82              'snmpwalk -v 1 -Cc -c public %(printer)s 2>/dev/null | grep mib-2.43.10.2.1.4.1.1 | cut -d " " -f4', \
83              'snmpwalk -v 1 -Cc -c public -Ov %(printer)s 2>/dev/null | grep Counter32 | tail -2 | head -1 | cut -d " " -f2', \
84            ]
85           
86NETPJLTESTS = [ \
87                '/usr/share/pykota/pagecount.pl %(printer)s %(port)s 2>/dev/null', \
88                'nc -w 2 %(printer)s %(port)s </usr/share/pykota/pagecount.pjl 2>/dev/null | tail -2', \
89              ]
90             
91class PKHint(PyKotaTool) :
92    """A class to autodetect the best accounting method for printers."""
93    def extractPrintersInformation(self) :   
94        """Extracts printer information from the printing system.
95         
96           Returns a mapping { queuename : device, ... }
97        """   
98        printers = {}
99        current_printer = None
100        for line in [l.strip() for l in sys.stdin.readlines()] :
101            testline = line.lower()
102            if testline.startswith("<printer ") or testline.startswith("<defaultprinter ") :
103                # beginning of a CUPS printer definition
104                current_printer = line.split()[-1][:-1]
105            elif testline.startswith("</printer ") :
106                # end of a CUPS printer definition
107                current_printer = None
108            elif testline.startswith("deviceuri ") :
109                # CUPS printer device_uri
110                device = testline.split()[-1]
111                if current_printer is not None :
112                    printers[current_printer] = device
113            else :       
114                # LPRng printcap specific code here
115                pass
116        return printers
117       
118    def extractDevices(self) :   
119        """Extracts the list of available CUPS devices.
120       
121           Returns a mapping { device : devicetype, ... }
122           
123           WARNING : CUPS ONLY FOR NOW
124        """   
125        inp = os.popen("lpinfo -v 2>/dev/null")
126        deviceslist = [l.strip() for l in inp.readlines()]
127        inp.close()
128        devicestypes = {}
129        for device in deviceslist :
130            (dtype, dname) = device.split()
131            devicestypes[dname] = dtype
132        return devicestypes
133       
134    def searchDeviceType(self, devicestypes, device) :   
135        """Returns the device type for current device."""
136        if device.startswith("cupspykota:") :
137            fulldevice = device[:]
138            device = fulldevice[len("cupspykota:"):]
139            if device.startswith("//") :
140                device = device[2:]
141        for (k, v) in devicestypes.items() :
142            if device.startswith(k) :
143                return v
144               
145    def extractDeviceFromURI(self, device) :   
146        """Cleans the device URI to remove any trace of PyKota."""
147        if device.startswith("cupspykota:") :
148            fulldevice = device[:]
149            device = fulldevice[len("cupspykota:"):]
150            if device.startswith("//") :
151                device = device[2:]
152        try :
153            (backend, destination) = device.split(":", 1) 
154        except ValueError :   
155            raise PyKotaToolError, _("Invalid DeviceURI : %s") % device
156        while destination.startswith("/") :
157            destination = destination[1:]
158        checkauth = destination.split("@", 1)   
159        if len(checkauth) == 2 :
160            destination = checkauth[1]
161        return destination.split("/")[0]
162       
163    def accepts(self, commands, printer, port=None) :   
164        """Tries to get the printer's internal page counter via SNMP."""
165        for command in commands :
166            inp = os.popen(command % locals())
167            value = inp.readline().strip()
168            inp.close()
169            try :
170                pagecounter = int(value)
171            except :   
172                pass
173            else :   
174                if port is None :
175                    return command
176                else :   
177                    return command.replace("%(port)s", str(port))
178       
179    def main(self, args, options) :
180        """Main work is done here."""
181        os.environ["PATH"] = "%s:/bin:/usr/bin:/usr/local/bin:/opt/bin:/sbin:/usr/sbin" % os.environ.get("PATH", "")
182        sys.stderr.write("BEWARE : This tool doesn't support LPRng's printcap files yet.\n")
183        print _("\nPlease wait while pkhint analyzes your printing system's configuration...")
184        printers = self.extractPrintersInformation()
185        devicestypes = self.extractDevices() # TODO : IT'S CUPS ONLY FOR NOW
186        configuration = []
187        for (printer, deviceuri) in printers.items() :
188            if self.matchString(printer, args) :
189                devicetype = self.searchDeviceType(devicestypes, deviceuri)
190                device = self.extractDeviceFromURI(deviceuri)
191                if devicetype is None :
192                    self.printInfo(_("Unknown device %s for printer %s") % (device, printer))
193                elif devicetype == "network" :
194                    try :
195                        hostname, port = device.split(':')
196                    except ValueError :   
197                        hostname = device
198                        port = 9100             # TODO : may cause problems with other protocols.
199                       
200                    snmpcommand = self.accepts(SNMPTESTS, hostname)
201                    if snmpcommand is not None :
202                        if hasSNMP and snmpcommand.startswith("snmpget ") :
203                            # don't do a more complex test, just consider it will work
204                            accounter = 'hardware(snmp)'
205                        else :   
206                            accounter = 'hardware(/usr/share/pykota/waitprinter.sh %(printer)s && ' + snmpcommand + ')'
207                        configuration.append((printer, accounter))
208                    else :   
209                        netpjlcommand = self.accepts(NETPJLTESTS, hostname, port)
210                        if netpjlcommand is not None :
211                            #accounter = 'hardware(' + netpjlcommand + ')'
212                            accounter = 'hardware(pjl)'
213                            configuration.append((printer, accounter))
214                        else :   
215                            configuration.append((printer, "software()"))
216                else :
217                    configuration.append((printer, "software()"))
218                   
219        if not configuration :           
220            print "\nSorry, pkhint can't help you for now. Please configure PyKota manually."
221        else :
222            print _("\nPut the following lines into your /etc/pykota/pykota.conf file :\n")
223            print _("# BEWARE : if software accounting is suggested, this doesn't mean")
224            print _("# that hardware accounting wouldn't work, this only means that PyKota")
225            print _("# wasn't able to autodetect which hardware accounting method to use.")
226            for (printer, accounter) in configuration :
227                print "[%s]" % printer
228                print "accounter: %s" % accounter
229                print   
230       
231if __name__ == "__main__" : 
232    retcode = 0
233    try :
234        short_options = "hv"
235        long_options = ["help", "version"]
236       
237        # Initializes the command line tool
238        manager = PKHint(doc=__doc__)
239       
240        (options, args) = manager.parseCommandline(sys.argv[1:], short_options, long_options)
241       
242        # sets long options
243        options["help"] = options["h"] or options["help"]
244        options["version"] = options["v"] or options["version"]
245       
246        if options["help"] :
247            manager.display_usage_and_quit()
248        elif options["version"] :
249            manager.display_version_and_quit()
250        else :
251            if not args :
252                args = [ "*" ]
253            retcode = manager.main(args, options)
254    except SystemExit :       
255        pass
256    except :
257        try :
258            manager.crashed("pkhint failed")
259        except :   
260            crashed("pkhint failed")
261        retcode = -1
262
263    try :
264        manager.storage.close()
265    except (TypeError, NameError, AttributeError) :   
266        pass
267       
268    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.