root / pykota / trunk / bin / edpykota @ 2772

Revision 2772, 18.1 kB (checked in by jerome, 19 years ago)

Now does all the changes within a single transaction.

  • 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/python
2# -*- coding: ISO-8859-15 -*-
3
4# PyKota Print Quota Editor
5#
6# PyKota - Print Quotas for CUPS and LPRng
7#
8# (c) 2003, 2004, 2005, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22#
23# $Id$
24#
25#
26
27import sys
28import os
29
30from pykota.tool import PyKotaTool, PyKotaToolError, PyKotaCommandLineError, crashed, N_
31from pykota.config import PyKotaConfigError
32from pykota.storage import PyKotaStorageError, StorageUserPQuota, StorageGroupPQuota
33
34__doc__ = N_("""edpykota v%(__version__)s (c) %(__years__)s %(__author__)s
35
36A Print Quota editor for PyKota.
37
38command line usage :
39
40  edpykota [options] user1 user2 ... userN
41 
42  edpykota [options] group1 group2 ... groupN
43
44options :
45
46  -v | --version       Prints edpykota's version number then exits.
47  -h | --help          Prints this message then exits.
48 
49  -a | --add           Adds users or groups print quota entries if
50                       they don't exist in database.
51                       
52  -d | --delete        Deletes users or groups print quota entries.
53                       Users or groups are never deleted, you have
54                       to use the pkusers command to delete them.
55                       The history will be purge from all matching
56                       jobs, unless -g | --groups is used.
57 
58  -P | --printer p     Edit quotas on printer p only. Actually p can
59                       use wildcards characters to select only
60                       some printers. The default value is *, meaning
61                       all printers.
62                       You can specify several names or wildcards,
63                       by separating them with commas.
64 
65  -g | --groups        Edit groups print quota entries instead of
66                       users print quota entries.
67                         
68  -L | --list          Lists users or groups print quota entries.
69 
70  -n | --noquota       Sets both soft and hard limits to None for users
71                       or groups print quota entries.
72 
73  -r | --reset         Resets the actual page counter for the user
74                       or group to zero on the specified printers.
75                       The life time page counter is kept unchanged.
76                       
77  -R | --hardreset     Resets the actual and life time page counters
78                       for the user or group to zero on the specified
79                       printers. This is a shortcut for '--used 0'.
80                       
81  -s | --skipexisting  In combination with the --add option above, tells
82                       edpykota to not modify existing print quota entries.
83                       
84  -S | --softlimit sl  Sets the quota soft limit to sl pages.                       
85 
86  -H | --hardlimit hl  Sets the quota hard limit to hl pages.
87 
88  -I | --increase v    Increase existing Soft and Hard limits by the value
89                       of v. You can prefix v with + or -, if no sign is
90                       used, + is assumed.
91
92  -U | --used u        Sets the page counters for the user u pages on
93                       the selected printers. Doesn't work for groups, since
94                       their page counters are the sum of all their members'
95                       page counters.
96                       Useful for migrating users from a different system
97                       where they have already used some pages. Actual
98                       and Life Time page counters may be increased or decreased
99                       if u is prefixed with + or -.
100                       WARNING : BOTH page counters are modified in all cases,
101                       so be careful.
102                       NB : if u equals '0', then the action taken is
103                       the same as if --hardreset was used.
104
105  user1 through userN and group1 through groupN can use wildcards
106  if the --add option is not set.
107 
108examples :                             
109
110  $ edpykota --add john paul george ringo
111 
112  This will create print quota entries for users john, paul, george
113  and ringo on all printers. These print quota entries will have no
114  limit set.
115 
116  $ edpykota --printer lp -S 50 -H 60 jerome
117 
118  This will set jerome's print quota on the lp printer to a soft limit
119  of 50 pages, and a hard limit of 60 pages. Both user jerome and
120  printer lp have been previously created with the pkusers and pkprinters
121  commands, respectively.
122
123  $ edpykota -g -S 500 -H 550 financial support           
124 
125  This will set print quota soft limit to 500 pages and hard limit
126  to 550 pages for groups financial and support on all printers.
127 
128  $ edpykota --reset jerome "jo*"
129 
130  This will reset jerome's page counter to zero on all printers, as
131  well as every user whose name begins with 'jo'.
132  Their life time page counter on each printer will be kept unchanged.
133  You can also reset the life time page counters by using the
134  --hardreset | -R command line option.
135 
136  $ edpykota --printer hpcolor --noquota jerome
137 
138  This will tell PyKota to not limit jerome when printing on the
139  hpcolor printer. All his jobs will be allowed on this printer, but
140  accounting of the pages he prints will still be kept.
141  Print Quotas for jerome on other printers are unchanged.
142 
143  $ edpykota --delete --printer "HP*,XER*" jerome rachel
144 
145  This will delete users jerome and rachel's print quota
146  entries on all printers which name begin with 'HP' or
147  'XER'. The jobs printed by these users on these printers
148  will be deleted from the history.
149""") 
150       
151class EdPyKota(PyKotaTool) :       
152    """A class for edpykota."""
153    def modifyPQEntry(self, pqkey, pqentry, noquota, softlimit, hardlimit, increase, reset, hardreset, suffix, used) :
154        """Modifies a print quota entry."""
155        if noquota or ((softlimit is not None) and (hardlimit is not None)) :
156            pqentry.setLimits(softlimit, hardlimit)
157        if increase :
158            newsoft = (pqentry.SoftLimit or 0) + increase         
159            newhard = (pqentry.HardLimit or 0) + increase         
160            if (newsoft >= 0) and (newhard >= 0) :
161                pqentry.setLimits(newsoft, newhard)
162            else :   
163                self.printInfo(_("You can't set negative limits for %s") % pqkey, "error")
164        if reset :
165            pqentry.reset()
166        if hardreset :   
167            pqentry.hardreset()
168        if suffix == "User" :
169            if used :
170                pqentry.setUsage(used)
171   
172    def main(self, names, options) :
173        """Edit user or group quotas."""
174        names = self.sanitizeNames(options, names)
175        suffix = (options["groups"] and "Group") or "User"       
176        printernames = options["printer"].split(",")
177           
178        if not options["list"] :
179            self.display(_("Extracting datas..."))
180        printers = self.storage.getMatchingPrinters(options["printer"])
181        entries = getattr(self.storage, "getMatching%ss" % suffix)(",".join(names))
182       
183        if options["list"] :
184            for printer in printers :
185                for entry in entries :
186                    pqentry = getattr(self.storage, "get%sPQuota" % suffix)(entry, printer)
187                    if pqentry.Exists :
188                        print "%s@%s" % (entry.Name, printer.Name)
189                        print "    %s" % (_("Page counter : %s") % pqentry.PageCounter)
190                        print "    %s" % (_("Lifetime page counter : %s") % pqentry.LifePageCounter)
191                        print "    %s" % (_("Soft limit : %s") % pqentry.SoftLimit)
192                        print "    %s" % (_("Hard limit : %s") % pqentry.HardLimit)
193                        print "    %s" % (_("Date limit : %s") % pqentry.DateLimit)
194                        print "    %s (Not supported yet)" % (_("Maximum job size : %s") % ((pqentry.MaxJobSize and (_("%s pages") % pqentry.MaxJobSize)) or _("Unlimited")))
195                        if hasattr(pqentry, "WarnCount") :
196                            print "    %s" % (_("Warning banners printed : %s") % pqentry.WarnCount)
197                        print
198        elif options["delete"] :   
199            self.display("\n%s..." % _("Deletion"))
200            getattr(self.storage, "deleteMany%sPQuotas" % suffix)(printers, entries)
201            self.display("\n")
202        else :
203            self.display("\n")   
204            skipexisting = options["skipexisting"]
205            used = options["used"]
206            if used :
207                used = used.strip()
208                try :
209                    int(used)
210                except ValueError :
211                    raise PyKotaCommandLineError, _("Invalid used value %s.") % used
212                   
213            increase = options["increase"]
214            if increase :
215                try :
216                    increase = int(increase.strip())
217                except ValueError :
218                    raise PyKotaCommandLineError, _("Invalid increase value %s.") % increase
219           
220            noquota = options["noquota"]
221            reset = options["reset"]       
222            hardreset = options["hardreset"]
223            softlimit = hardlimit = None
224            if not noquota :
225                if options["softlimit"] :
226                    try :
227                        softlimit = int(options["softlimit"].strip())
228                        if softlimit < 0 :
229                            raise ValueError
230                    except ValueError :   
231                        raise PyKotaCommandLineError, _("Invalid softlimit value %s.") % options["softlimit"]
232                if options["hardlimit"] :
233                    try :
234                        hardlimit = int(options["hardlimit"].strip())
235                        if hardlimit < 0 :
236                            raise ValueError
237                    except ValueError :   
238                        raise PyKotaCommandLineError, _("Invalid hardlimit value %s.") % options["hardlimit"]
239                if (softlimit is not None) and (hardlimit is not None) and (hardlimit < softlimit) :       
240                    # error, exchange them
241                    self.printInfo(_("Hard limit %i is less than soft limit %i, values will be exchanged.") % (hardlimit, softlimit))
242                    (softlimit, hardlimit) = (hardlimit, softlimit)
243                if hardlimit is None :   
244                    hardlimit = softlimit
245                    if hardlimit is not None :
246                        self.printInfo(_("Undefined hard limit set to soft limit (%s).") % str(hardlimit))
247                if softlimit is None :   
248                    softlimit = hardlimit
249                    if softlimit is not None :
250                        self.printInfo(_("Undefined soft limit set to hard limit (%s).") % str(softlimit))
251                       
252            self.storage.beginTransaction()           
253            try :
254                if options["add"] :
255                    self.display("%s...\n" % _("Creation"))
256                    dicnames = {}
257                    for m in entries :
258                        dicnames[m.Name] = None
259                    for name in names :
260                        if not dicnames.has_key(name) :
261                            self.printInfo(_("Impossible to create print quota entries if the user or group object '%s' doesn't already exist. Please use pkusers to create it first.") % name, "warn")
262                           
263                    factory = globals()["Storage%sPQuota" % suffix]
264                    nbtotal = len(printers) * len(entries)
265                    i = 0
266                    for printer in printers :
267                        pname = printer.Name
268                        for entry in entries :
269                            ename = entry.Name
270                            pqkey = "%s@%s" % (ename, pname)
271                            pqentry = factory(self.storage, entry, printer)
272                            self.modifyPQEntry(pqkey, pqentry, noquota, \
273                                                        softlimit, hardlimit, \
274                                                        increase, reset, \
275                                                        hardreset, suffix, used)
276                            oldpqentry = getattr(self.storage, "add%sPQuota" % suffix)(pqentry)
277                            if oldpqentry is not None :   
278                                if skipexisting :
279                                    self.logdebug("%s print quota entry %s@%s already exists, skipping." % (suffix, ename, pname))
280                                else :   
281                                    self.logdebug("%s print quota entry %s@%s already exists, will be modified." % (suffix, ename, pname))
282                                    self.modifyPQEntry(pqkey, oldpqentry, noquota, \
283                                                        softlimit, hardlimit, \
284                                                        increase, reset, \
285                                                        hardreset, suffix, used)
286                                    oldpqentry.save()                   
287                            i += 1
288                            percent = 100.0 * float(i) / float(nbtotal)
289                            self.display("\r%.02f%%" % percent)
290                else :       
291                    nbtotal = len(entries) * len(printers)
292                    if nbtotal :
293                        self.display("%s...\n" % _("Modification"))
294                        i = 0
295                        for printer in printers :
296                            for entry in entries :
297                                pqkey = "%s@%s" % (entry.Name, printer.Name)
298                                pqentry = getattr(self.storage, "get%sPQuota" % suffix)(entry, printer)
299                                if pqentry.Exists :     
300                                    self.modifyPQEntry(pqkey, pqentry, noquota, \
301                                                        softlimit, hardlimit, \
302                                                        increase, reset, \
303                                                        hardreset, suffix, used)
304                                    pqentry.save()       
305                                i += 1           
306                                percent = 100.0 * float(i) / float(nbtotal)
307                                self.display("\r%.02f%%" % percent)
308            except :                   
309                self.storage.rollbackTransaction()
310                raise
311            else :   
312                self.storage.commitTransaction()
313                           
314        if not options["list"] :
315            self.done()         
316           
317if __name__ == "__main__" : 
318    retcode = 0
319    try :
320        defaults = { \
321                     "printer" : "*", \
322                   }
323        short_options = "vhdnagrLP:S:H:G:RU:I:s"
324        long_options = ["help", "version", \
325                        "delete", "list", \
326                        "noquota", "add", \
327                        "groups", "reset", "hardreset", \
328                        "printer=", "softlimit=", "hardlimit=", \
329                        "increase=", "used=", "skipexisting"]
330       
331        # Initializes the command line tool
332        manager = EdPyKota(doc=__doc__)
333        manager.deferredInit()
334       
335        # parse and checks the command line
336        (options, args) = manager.parseCommandline(sys.argv[1:], short_options, long_options)
337       
338        # sets long options
339        options["help"] = options["h"] or options["help"]
340        options["version"] = options["v"] or options["version"]
341        options["add"] = options["a"] or options["add"]
342        options["groups"] = options["g"] or options["groups"]
343        options["printer"] = options["P"] or options["printer"] or defaults["printer"]
344        options["softlimit"] = options["S"] or options["softlimit"]
345        options["hardlimit"] = options["H"] or options["hardlimit"] 
346        options["reset"] = options["r"] or options["reset"] 
347        options["noquota"] = options["n"] or options["noquota"]
348        options["delete"] = options["d"] or options["delete"] 
349        options["hardreset"] = options["R"] or options["hardreset"] 
350        options["used"] = options["U"] or options["used"]
351        options["increase"] = options["I"] or options["increase"]
352        options["list"] = options["L"] or options["list"]
353        options["skipexisting"] = options["s"] or options["skipexisting"]
354       
355        if options["help"] :
356            manager.display_usage_and_quit()
357        elif options["version"] :
358            manager.display_version_and_quit()
359        elif (options["add"] and options["delete"]) \
360             or (options["noquota"] and (options["hardlimit"] or options["softlimit"])) \
361             or (options["groups"] and options["used"]) \
362             or (options["skipexisting"] and not options["add"]) :
363            raise PyKotaCommandLineError, _("incompatible options, see help.")
364        elif options["delete"] and not args :
365            raise PyKotaCommandLineError, _("You have to pass user or group names on the command line")
366        else :
367            retcode = manager.main(args, options)
368    except KeyboardInterrupt :       
369        sys.stderr.write("\nInterrupted with Ctrl+C !\n")
370        retcode = -3
371    except PyKotaCommandLineError, msg :     
372        sys.stderr.write("%s : %s\n" % (sys.argv[0], msg))
373        retcode = -2
374    except SystemExit :       
375        pass
376    except :
377        try :
378            manager.crashed("edpykota failed")
379        except :   
380            crashed("edpykota failed")
381        retcode = -1
382
383    try :
384        manager.storage.close()
385    except (TypeError, NameError, AttributeError) :   
386        pass
387       
388    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.