root / pykota / trunk / bin / pkhint @ 1814

Revision 1814, 12.8 kB (checked in by jalet, 20 years ago)

More complete PATH.
pkhint doesn't use absolute path to search for helper commands anymore.

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