root / pykota / trunk / bin / pkhint @ 1606

Revision 1606, 11.8 kB (checked in by jalet, 20 years ago)

Sanitized a bit + use of gettext

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