root / pykota / trunk / bin / pkhint @ 1526

Revision 1526, 11.3 kB (checked in by jalet, 20 years ago)

Fixed over-verbose exits when displaying help or version number

  • 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 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# $Log$
26# Revision 1.10  2004/06/07 18:43:40  jalet
27# Fixed over-verbose exits when displaying help or version number
28#
29# Revision 1.9  2004/06/03 21:50:34  jalet
30# Improved error logging.
31# crashrecipient directive added.
32# Now exports the job's size in bytes too.
33#
34# Revision 1.8  2004/05/18 14:48:47  jalet
35# Big code changes to completely remove the need for "requester" directives,
36# jsut use "hardware(... your previous requester directive's content ...)"
37#
38# Revision 1.7  2004/05/13 13:59:27  jalet
39# Code simplifications
40#
41# Revision 1.6  2004/03/30 12:59:47  jalet
42# Fixed path problem
43#
44# Revision 1.5  2004/02/09 13:07:06  jalet
45# Should now be able to handle network + pjl printers
46#
47# Revision 1.4  2004/02/09 12:35:19  jalet
48# De-uglyfication.
49# Now works with older CUPS (1.14) which don't detect the cupspykota backend but accept it anyway.
50#
51# Revision 1.3  2004/02/07 13:56:03  jalet
52# Help
53#
54# Revision 1.2  2004/02/07 13:47:55  jalet
55# More warnings
56#
57# Revision 1.1  2004/02/07 13:45:51  jalet
58# Preliminary work on the pkhint command
59#
60#
61#
62
63import sys
64import os
65
66from pykota import version
67from pykota.tool import PyKotaTool,PyKotaToolError
68from pykota.config import PyKotaConfigError
69from pykota.storage import PyKotaStorageError
70
71__doc__ = """pkhint v%s (c) 2003-2004 C@LL - Conseil Internet & Logiciels Libres
72A tool to give hints on what accounting method is best for each printer.
73
74command line usage :
75
76  pkhint [options] [printer1 printer2 printer3 ... printerN] <file.conf
77
78options :
79
80  -v | --version       Prints pkhint's version number then exits.
81  -h | --help          Prints this message then exits.
82 
83examples :                             
84
85  $ pkhint "hp*" printer103 </etc/cups/printers.conf
86 
87  Will analyze your printing system to test which accounter
88  is the best for each of the defined printer which
89  name matches one of the parameters.
90 
91  If you don't pass any argument on the command line, all
92  printers will be analyzed.
93 
94This program is free software; you can redistribute it and/or modify
95it under the terms of the GNU General Public License as published by
96the Free Software Foundation; either version 2 of the License, or
97(at your option) any later version.
98
99This program is distributed in the hope that it will be useful,
100but WITHOUT ANY WARRANTY; without even the implied warranty of
101MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
102GNU General Public License for more details.
103
104You should have received a copy of the GNU General Public License
105along with this program; if not, write to the Free Software
106Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
107
108Please e-mail bugs to: %s""" % (version.__version__, version.__author__)
109       
110SNMPTESTS = [ \
111              '/usr/bin/npadmin --pagecount %(printer)s 2>/dev/null', \
112              '/usr/bin/snmpget -v1 -c public -Ov %(printer)s mib-2.43.10.2.1.4.1.1 2>/dev/null | cut -f 2,2 -d " "', \
113              '/usr/bin/snmpwalk -v 1 -Cc -c public %(printer)s 2>/dev/null | grep mib-2.43.10.2.1.4.1.1 | cut -d " " -f4', \
114              '/usr/bin/snmpwalk -v 1 -Cc -c public -Ov %(printer)s 2>/dev/null | grep Counter32 | tail -2 | head -1 | cut -d " " -f2', \
115            ]
116           
117NETPJLTESTS = [ \
118                '/usr/share/pykota/pagecount.pl %(printer)s %(port)s 2>/dev/null', \
119                '/bin/nc -w 2 %(printer)s %(port)s </usr/share/pykota/pagecount.pjl 2>/dev/null | /usr/bin/tail -2', \
120              ]
121
122class PKHint(PyKotaTool) :
123    """A class to autodetect the best accounting method for printers."""
124    def extractPrintersInformation(self) :   
125        """Extracts printer information from the printing system.
126         
127           Returns a mapping { queuename : device, ... }
128        """   
129        printers = {}
130        current_printer = None
131        for line in [l.strip() for l in sys.stdin.readlines()] :
132            testline = line.lower()
133            if testline.startswith("<printer ") or testline.startswith("<defaultprinter ") :
134                # beginning of a CUPS printer definition
135                current_printer = line.split()[-1][:-1]
136            elif testline.startswith("</printer ") :
137                # end of a CUPS printer definition
138                current_printer = None
139            elif testline.startswith("deviceuri ") :
140                # CUPS printer device_uri
141                device = testline.split()[-1]
142                if current_printer is not None :
143                    printers[current_printer] = device
144            else :       
145                # LPRng printcap specific code here
146                pass
147        return printers
148       
149    def extractDevices(self) :   
150        """Extracts the list of available CUPS devices.
151       
152           Returns a mapping { device : devicetype, ... }
153           
154           WARNING : CUPS ONLY FOR NOW
155        """   
156        inp = os.popen("/usr/sbin/lpinfo -v 2>/dev/null")
157        deviceslist = [l.strip() for l in inp.readlines()]
158        inp.close()
159        devicestypes = {}
160        for device in deviceslist :
161            (dtype, dname) = device.split()
162            devicestypes[dname] = dtype
163        return devicestypes
164       
165    def searchDeviceType(self, devicestypes, device) :   
166        """Returns the device type for current device."""
167        if device.startswith("cupspykota:") :
168            fulldevice = device[:]
169            device = fulldevice[len("cupspykota:"):]
170            if device.startswith("//") :
171                device = device[2:]
172        for (k, v) in devicestypes.items() :
173            if device.startswith(k) :
174                return v
175               
176    def extractDeviceFromURI(self, device) :   
177        """Cleans the device URI to remove any trace of PyKota."""
178        if device.startswith("cupspykota:") :
179            fulldevice = device[:]
180            device = fulldevice[len("cupspykota:"):]
181            if device.startswith("//") :
182                device = device[2:]
183        try :
184            (backend, destination) = device.split(":", 1) 
185        except ValueError :   
186            raise PyKotaToolError, "Invalid DEVICE_URI : %s\n" % device
187        while destination.startswith("/") :
188            destination = destination[1:]
189        checkauth = destination.split("@", 1)   
190        if len(checkauth) == 2 :
191            destination = checkauth[1]
192        return destination.split("/")[0]
193       
194    def accepts(self, commands, printer, port=None) :   
195        """Tries to get the printer's internal page counter via SNMP."""
196        for command in commands :
197            inp = os.popen(command % locals())
198            value = inp.readline().strip()
199            inp.close()
200            try :
201                pagecounter = int(value)
202            except :   
203                pass
204            else :   
205                return command
206       
207    def main(self, args, options) :
208        """Main work is done here."""
209        print "\nPlease wait while pkhint analyzes your printing system's configuration..."
210        printers = self.extractPrintersInformation()
211        devicestypes = self.extractDevices() # TODO : IT'S CUPS ONLY FOR NOW
212        configuration = []
213        for (printer, deviceuri) in printers.items() :
214            if self.matchString(printer, args) :
215                devicetype = self.searchDeviceType(devicestypes, deviceuri)
216                device = self.extractDeviceFromURI(deviceuri)
217                if devicetype is None :
218                    sys.stderr.write("Unknown device %s for printer %s\n" % (device, printer))
219                elif devicetype == "network" :
220                    try :
221                        hostname, port = device.split(':')
222                    except ValueError :   
223                        hostname = device
224                        port = 9100             # TODO : may cause problems with other protocols.
225                       
226                    snmpcommand = self.accepts(SNMPTESTS, hostname)
227                    if snmpcommand is not None :
228                        accounter = 'hardware(/usr/share/pykota/waitprinter.sh %(printer)s && ' + snmpcommand + ')'
229                        configuration.append((printer, accounter))
230                    else :   
231                        netpjlcommand = self.accepts(NETPJLTESTS, hostname, port)
232                        if netpjlcommand is not None :
233                            accounter = 'hardware(' + netpjlcommand + ')'
234                            configuration.append((printer, accounter))
235                elif devicetype == "direct" : 
236                    sys.stderr.write("Can't currently handle device %s for printer %s\n" % (device, printer))
237                elif devicetype == "serial" : 
238                    sys.stderr.write("Can't currently handle device %s for printer %s\n" % (device, printer))
239                else :
240                    sys.stderr.write("Can't currently handle device %s for printer %s\n" % (device, printer))
241                   
242        if not configuration :           
243            print "\nSorry, pkhint can't help you for now. Please configure PyKota manually."
244        else :
245            print "\nPut the following lines into your /etc/pykota/pykota.conf file :\n"
246            for (printer, accounter) in configuration :
247                print "[%s]" % printer
248                print "accounter: %s" % accounter
249                print   
250       
251if __name__ == "__main__" : 
252    sys.stderr.write("BEWARE : This tool doesn't support LPRng's printcap files yet.\n")
253    sys.stderr.write("This tool is currently highly experimental, so don't rely on it.\n")
254    retcode = 0
255    try :
256        short_options = "hv"
257        long_options = ["help", "version"]
258       
259        # Initializes the command line tool
260        manager = PKHint(doc=__doc__)
261       
262        (options, args) = manager.parseCommandline(sys.argv[1:], short_options, long_options)
263       
264        # sets long options
265        options["help"] = options["h"] or options["help"]
266        options["version"] = options["v"] or options["version"]
267       
268        if options["help"] :
269            manager.display_usage_and_quit()
270        elif options["version"] :
271            manager.display_version_and_quit()
272        else :
273            if not args :
274                args = [ "*" ]
275            retcode = manager.main(args, options)
276    except SystemExit :       
277        pass
278    except :
279        try :
280            manager.crashed("pkhint failed")
281        except :   
282            pass
283        retcode = -1
284
285    try :
286        manager.storage.close()
287    except (TypeError, NameError, AttributeError) :   
288        pass
289       
290    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.