root / pykota / trunk / bin / pkhint @ 1475

Revision 1475, 11.1 kB (checked in by jalet, 20 years ago)

Code simplifications

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