Changeset 3416

Show
Ignore:
Timestamp:
10/01/08 18:14:18 (16 years ago)
Author:
jerome
Message:

Fixes #25 using the third way. Needs to be ported to trunk if pkturnkey
still makes it in 1.27 final, which I'm really not sure about,
considering how it's easy, and probably more versatile, to do the same with
some shell scripting.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • pykota/branches/1.26_fixes/bin/pkturnkey

    r3133 r3416  
    1616# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    1717# GNU General Public License for more details. 
    18 #  
     18# 
    1919# You should have received a copy of the GNU General Public License 
    2020# along with this program; if not, write to the Free Software 
     
    3232import signal 
    3333 
     34from pkipplib import pkipplib 
     35 
    3436from pykota.tool import Tool, PyKotaToolError, PyKotaCommandLineError, crashed, N_ 
    3537 
     
    5052  -v | --version       Prints pkturnkey version number then exits. 
    5153  -h | --help          Prints this message then exits. 
    52    
     54 
    5355  -c | --doconf        Give hints about what to put into pykota.conf 
    54    
     56 
    5557  -d | --dousers       Manages users accounts as well. 
    56    
     58 
    5759  -D | --dogroups      Manages users groups as well. 
    5860                       Implies -d | --dousers. 
    59    
     61 
    6062  -e | --emptygroups   Includes empty groups. 
    61    
     63 
    6264  -f | --force         Modifies the database instead of printing what 
    6365                       it would do. 
    64                         
     66 
    6567  -u | --uidmin uid    Only adds users whose uid is greater than or equal to 
    6668                       uid. You can pass an username there as well, and its 
     
    6870                       If not set, 0 will be used automatically. 
    6971                       Implies -d | --dousers. 
    70                         
     72 
    7173  -U | --uidmax uid    Only adds users whose uid is lesser than or equal to 
    7274                       uid. You can pass an username there as well, and its 
     
    8082                       If not set, 0 will be used automatically. 
    8183                       Implies -D | --dogroups. 
    82                         
     84 
    8385  -G | --gidmax gid    Only adds groups whose gid is lesser than or equal to 
    8486                       gid. You can pass a groupname there as well, and its 
     
    8789                       Implies -D | --dogroups. 
    8890 
    89 examples :                               
     91examples : 
    9092 
    9193  $ pkturnkey --dousers --uidmin jerome 
     
    9496  printers and print accounts for all users whose uid is greater than 
    9597  or equal to jerome's one. Won't manage any users group. 
    96    
     98 
    9799  To REALLY initialize the database instead of simulating it, please 
    98100  use the -f | --force command line switch. 
    99    
     101 
    100102  You can limit the initialization to only a subset of the existing 
    101103  printers, by passing their names at the end of the command line. 
    102104""") 
    103          
     105 
    104106class PKTurnKey(Tool) : 
    105107    """A class for an initialization tool.""" 
     
    107109        """Returns a list of tuples (queuename, deviceuri) for all existing print queues.""" 
    108110        self.printInfo("Extracting all print queues.") 
    109         result = os.popen("lpstat -v", "r") 
    110         lines = result.readlines() 
    111         result.close() 
    112111        printers = [] 
    113         for line in lines : 
    114             (begin, end) = line.split(':', 1) 
    115             deviceuri = end.strip() 
    116             queuename = begin.split()[-1] 
    117             if self.matchString(queuename, namestomatch) : 
    118                 printers.append((queuename, deviceuri)) 
    119             else :     
    120                 self.printInfo("Print queue %s skipped." % queuename) 
    121         return printers     
    122          
    123     def listUsers(self, uidmin, uidmax) :     
     112        server = pkipplib.CUPS() 
     113        for queuename in server.getPrinters() : 
     114            req = server.newRequest(pkipplib.IPP_GET_PRINTER_ATTRIBUTES) 
     115            req.operation["printer-uri"] = ("uri", server.identifierToURI("printers", queuename)) 
     116            req.operation["requested-attributes"] = ("keyword", "device-uri") 
     117            result = server.doRequest(req) 
     118            try : 
     119                deviceuri = result.printer["device-uri"][0][1] 
     120            except (AttributeError, IndexError) : 
     121                deviceuri = None 
     122            if deviceuri is not None : 
     123                if self.matchString(queuename, namestomatch) : 
     124                    printers.append((queuename, deviceuri)) 
     125                else : 
     126                    self.printInfo("Print queue %s skipped." % queuename) 
     127        return printers 
     128 
     129    def listUsers(self, uidmin, uidmax) : 
    124130        """Returns a list of users whose uids are between uidmin and uidmax.""" 
    125131        self.printInfo("Extracting all users whose uid is between %s and %s." % (uidmin, uidmax)) 
    126132        return [(entry[0], entry[3]) for entry in pwd.getpwall() if uidmin <= entry[2] <= uidmax] 
    127          
     133 
    128134    def listGroups(self, gidmin, gidmax, users) : 
    129135        """Returns a list of groups whose gids are between gidmin and gidmax.""" 
     
    134140        for u in users : 
    135141            gidusers.setdefault(u[1], []).append(u[0]) 
    136             usersgid.setdefault(u[0], []).append(u[1])  
    137              
    138         membership = {}     
     142            usersgid.setdefault(u[0], []).append(u[1]) 
     143 
     144        membership = {} 
    139145        for g in range(len(groups)) : 
    140146            (gname, gid, members) = groups[g] 
     
    144150            try : 
    145151                usernames = gidusers[gid] 
    146             except KeyError :     
     152            except KeyError : 
    147153                pass 
    148             else :     
     154            else : 
    149155                for username in usernames : 
    150156                    if not newmembers.has_key(username) : 
    151157                        newmembers[username] = username 
    152             for member in newmembers.keys() :             
     158            for member in newmembers.keys() : 
    153159                if not usersgid.has_key(member) : 
    154160                    del newmembers[member] 
    155161            membership[gname] = newmembers.keys() 
    156162        return membership 
    157          
    158     def runCommand(self, command, dryrun) :     
     163 
     164    def runCommand(self, command, dryrun) : 
    159165        """Launches an external command.""" 
    160166        self.printInfo("%s" % command) 
    161         if not dryrun :     
     167        if not dryrun : 
    162168            os.system(command) 
    163              
    164     def createPrinters(self, printers, dryrun=0) :     
     169 
     170    def createPrinters(self, printers, dryrun=0) : 
    165171        """Creates all printers in PyKota's database.""" 
    166172        if printers : 
     
    170176            args.close() 
    171177            self.runCommand("pkprinters --arguments /tmp/pkprinters.args", dryrun) 
    172          
     178 
    173179    def createUsers(self, users, printers, dryrun=0) : 
    174180        """Creates all users in PyKota's database.""" 
     
    179185            args.close() 
    180186            self.runCommand("pkusers --arguments /tmp/pkusers.users.args", dryrun) 
    181              
     187 
    182188            printersnames = [p[0] for p in printers] 
    183189            args = open("/tmp/edpykota.users.args", "w") 
     
    187193            args.close() 
    188194            self.runCommand("edpykota --arguments /tmp/edpykota.users.args", dryrun) 
    189              
     195 
    190196    def createGroups(self, groups, printers, dryrun=0) : 
    191197        """Creates all groups in PyKota's database.""" 
     
    196202            args.close() 
    197203            self.runCommand("pkusers --arguments /tmp/pkusers.groups.args", dryrun) 
    198              
     204 
    199205            printersnames = [p[0] for p in printers] 
    200206            args = open("/tmp/edpykota.groups.args", "w") 
     
    204210            args.close() 
    205211            self.runCommand("edpykota --arguments /tmp/edpykota.groups.args", dryrun) 
    206              
     212 
    207213            revmembership = {} 
    208214            for (groupname, usernames) in groups.items() : 
    209215                for username in usernames : 
    210216                    revmembership.setdefault(username, []).append(groupname) 
    211             commands = []         
    212             for (username, groupnames) in revmembership.items() :         
     217            commands = [] 
     218            for (username, groupnames) in revmembership.items() : 
    213219                commands.append('pkusers --ingroups %s "%s"' \ 
    214220                    % (",".join(['"%s"' % g for g in groupnames]), username)) 
    215221            for command in commands : 
    216222                self.runCommand(command, dryrun) 
    217          
     223 
    218224    def supportsSNMP(self, hostname, community) : 
    219225        """Returns 1 if the printer accepts SNMP queries, else 0.""" 
     
    221227        try : 
    222228            from pysnmp.entity.rfc3413.oneliner import cmdgen 
    223         except ImportError :     
     229        except ImportError : 
    224230            hasV4 = False 
    225231            try : 
     
    227233                from pysnmp.mapping.udp.role import Manager 
    228234                from pysnmp.proto.api import alpha 
    229             except ImportError :     
     235            except ImportError : 
    230236                sys.stderr.write("pysnmp doesn't seem to be installed. SNMP checks will be ignored !\n") 
    231237                return 0 
    232         else :         
     238        else : 
    233239            hasV4 = True 
    234              
    235         if hasV4 :     
     240 
     241        if hasV4 : 
    236242            def retrieveSNMPValues(hostname, community) : 
    237243                """Retrieves a printer's internal page counter and status via SNMP.""" 
     
    240246                                                      cmdgen.UdpTransportTarget((hostname, 161)), \ 
    241247                                                      tuple([int(i) for i in pageCounterOID.split('.')])) 
    242                 if errorIndication :                                                   
     248                if errorIndication : 
    243249                    raise "No SNMP !" 
    244                 elif errorStatus :     
     250                elif errorStatus : 
    245251                    raise "No SNMP !" 
    246                 else :                                  
     252                else : 
    247253                    self.SNMPOK = True 
    248254        else : 
    249             def retrieveSNMPValues(hostname, community) :     
     255            def retrieveSNMPValues(hostname, community) : 
    250256                """Retrieves a printer's internal page counter and status via SNMP.""" 
    251257                ver = alpha.protoVersions[alpha.protoVersionId1] 
     
    259265                                       (hostname, 161), \ 
    260266                                       (handleAnswer, req)) 
    261                 except :     
     267                except : 
    262268                    raise "No SNMP !" 
    263269                tsp.close() 
    264              
     270 
    265271            def handleAnswer(wholemsg, notusedhere, req): 
    266272                """Decodes and handles the SNMP answer.""" 
     
    269275                try : 
    270276                    rsp.berDecode(wholemsg) 
    271                 except TypeMismatchError, msg :     
     277                except TypeMismatchError, msg : 
    272278                    raise "No SNMP !" 
    273279                else : 
     
    280286                            for varBind in rsp.apiAlphaGetPdu().apiAlphaGetVarBindList(): 
    281287                                self.values.append(varBind.apiAlphaGetOidVal()[1].rawAsn1Value) 
    282                             try :     
     288                            try : 
    283289                                pagecounter = self.values[0] 
    284290                            except : 
    285291                                raise "No SNMP !" 
    286                             else :     
     292                            else : 
    287293                                self.SNMPOK = 1 
    288294                                return 1 
    289              
     295 
    290296        self.SNMPOK = 0 
    291297        try : 
    292298            retrieveSNMPValues(hostname, community) 
    293         except :     
     299        except : 
    294300            self.SNMPOK = 0 
    295301        return self.SNMPOK 
    296          
     302 
    297303    def supportsPJL(self, hostname, port) : 
    298304        """Returns 1 if the printer accepts PJL queries over TCP, else 0.""" 
    299305        def alarmHandler(signum, frame) : 
    300306            raise "Timeout !" 
    301          
     307 
    302308        pjlsupport = 0 
    303309        signal.signal(signal.SIGALRM, alarmHandler) 
     
    310316            if not answer.startswith("@PJL") : 
    311317                raise "No PJL !" 
    312         except :     
     318        except : 
    313319            pass 
    314         else :     
     320        else : 
    315321            pjlsupport = 1 
    316322        s.close() 
     
    318324        signal.signal(signal.SIGALRM, signal.SIG_IGN) 
    319325        return pjlsupport 
    320              
    321     def hintConfig(self, printers) :     
     326 
     327    def hintConfig(self, printers) : 
    322328        """Gives some hints about what to put into pykota.conf""" 
    323329        if not printers : 
    324330            return 
    325         sys.stderr.flush() # ensure outputs don't mix     
    326         print      
     331        sys.stderr.flush() # ensure outputs don't mix 
     332        print 
    327333        print "--- CUT ---" 
    328334        print "# Here are some lines that we suggest you add at the end" 
     
    337343            try : 
    338344                uri = uri.split("cupspykota:", 2)[-1] 
    339             except (ValueError, IndexError) :     
     345            except (ValueError, IndexError) : 
    340346                pass 
    341             else :     
     347            else : 
    342348                while uri and uri.startswith("/") : 
    343349                    uri = uri[1:] 
    344350                try : 
    345                     (backend, destination) = uri.split(":", 1)  
     351                    (backend, destination) = uri.split(":", 1) 
    346352                    if backend not in ("ipp", "http", "https", "lpd", "socket") : 
    347353                        raise ValueError 
    348                 except ValueError :     
     354                except ValueError : 
    349355                    pass 
    350                 else :         
     356                else : 
    351357                    while destination.startswith("/") : 
    352358                        destination = destination[1:] 
    353                     checkauth = destination.split("@", 1)     
     359                    checkauth = destination.split("@", 1) 
    354360                    if len(checkauth) == 2 : 
    355361                        destination = checkauth[1] 
     
    361367                        except ValueError : 
    362368                            port = 9100 
    363                     else :     
     369                    else : 
    364370                        (hostname, port) = parts[0], 9100 
    365                          
     371 
    366372                    if self.supportsSNMP(hostname, "public") : 
    367373                        accounter = "hardware(snmp)" 
     
    370376                    elif self.supportsPJL(hostname, 9101) : 
    371377                        accounter = "hardware(pjl:9101)" 
    372                     elif self.supportsPJL(hostname, port) :     
     378                    elif self.supportsPJL(hostname, port) : 
    373379                        accounter = "hardware(pjl:%s)" % port 
    374                      
    375             print "preaccounter : software()"  
     380 
     381            print "preaccounter : software()" 
    376382            print "accounter : %s" % accounter 
    377383            print 
    378384        print "--- CUT ---" 
    379          
     385 
    380386    def main(self, names, options) : 
    381387        """Intializes PyKota's database.""" 
     
    383389            raise PyKotaCommandLineError, "%s : %s" % (pwd.getpwuid(os.geteuid())[0], \ 
    384390                                   _("You're not allowed to use this command.")) 
    385              
     391 
    386392        if not names : 
    387393            names = ["*"] 
    388              
     394 
    389395        self.printInfo(_("Please be patient...")) 
    390396        dryrun = not options["force"] 
    391397        if dryrun : 
    392398            self.printInfo(_("Don't worry, the database WILL NOT BE MODIFIED.")) 
    393         else :     
     399        else : 
    394400            self.printInfo(_("Please WORRY NOW, the database WILL BE MODIFIED.")) 
    395              
    396         if options["dousers"] :     
    397             if not options["uidmin"] :     
     401 
     402        if options["dousers"] : 
     403            if not options["uidmin"] : 
    398404                self.printInfo(_("System users will have a print account as well !"), "warn") 
    399405                uidmin = 0 
    400             else :     
     406            else : 
    401407                try : 
    402408                    uidmin = int(options["uidmin"]) 
    403                 except :     
     409                except : 
    404410                    try : 
    405411                        uidmin = pwd.getpwnam(options["uidmin"])[2] 
    406                     except KeyError, msg :     
     412                    except KeyError, msg : 
    407413                        raise PyKotaCommandLineError, _("Unknown username %s : %s") \ 
    408414                                                   % (options["uidmin"], msg) 
    409                          
    410             if not options["uidmax"] :     
     415 
     416            if not options["uidmax"] : 
    411417                uidmax = sys.maxint 
    412             else :     
     418            else : 
    413419                try : 
    414420                    uidmax = int(options["uidmax"]) 
    415                 except :     
     421                except : 
    416422                    try : 
    417423                        uidmax = pwd.getpwnam(options["uidmax"])[2] 
    418                     except KeyError, msg :     
     424                    except KeyError, msg : 
    419425                        raise PyKotaCommandLineError, _("Unknown username %s : %s") \ 
    420426                                                   % (options["uidmax"], msg) 
    421              
    422             if uidmin > uidmax :             
     427 
     428            if uidmin > uidmax : 
    423429                (uidmin, uidmax) = (uidmax, uidmin) 
    424430            users = self.listUsers(uidmin, uidmax) 
    425         else :     
     431        else : 
    426432            users = [] 
    427              
    428         if options["dogroups"] :     
    429             if not options["gidmin"] :     
     433 
     434        if options["dogroups"] : 
     435            if not options["gidmin"] : 
    430436                self.printInfo(_("System groups will have a print account as well !"), "warn") 
    431437                gidmin = 0 
    432             else :     
     438            else : 
    433439                try : 
    434440                    gidmin = int(options["gidmin"]) 
    435                 except :     
     441                except : 
    436442                    try : 
    437443                        gidmin = grp.getgrnam(options["gidmin"])[2] 
    438                     except KeyError, msg :     
     444                    except KeyError, msg : 
    439445                        raise PyKotaCommandLineError, _("Unknown groupname %s : %s") \ 
    440446                                                   % (options["gidmin"], msg) 
    441                          
    442             if not options["gidmax"] :     
     447 
     448            if not options["gidmax"] : 
    443449                gidmax = sys.maxint 
    444             else :     
     450            else : 
    445451                try : 
    446452                    gidmax = int(options["gidmax"]) 
    447                 except :     
     453                except : 
    448454                    try : 
    449455                        gidmax = grp.getgrnam(options["gidmax"])[2] 
    450                     except KeyError, msg :     
     456                    except KeyError, msg : 
    451457                        raise PyKotaCommandLineError, _("Unknown groupname %s : %s") \ 
    452458                                                   % (options["gidmax"], msg) 
    453              
    454             if gidmin > gidmax :             
     459 
     460            if gidmin > gidmax : 
    455461                (gidmin, gidmax) = (gidmax, gidmin) 
    456462            groups = self.listGroups(gidmin, gidmax, users) 
     
    459465                    if not members : 
    460466                        del groups[groupname] 
    461         else :     
     467        else : 
    462468            groups = [] 
    463              
     469 
    464470        printers = self.listPrinters(names) 
    465471        if printers : 
     
    467473            self.createUsers([entry[0] for entry in users], printers, dryrun) 
    468474            self.createGroups(groups, printers, dryrun) 
    469          
     475 
    470476        if dryrun : 
    471477            self.printInfo(_("Simulation terminated.")) 
    472         else :     
     478        else : 
    473479            self.printInfo(_("Database initialized !")) 
    474         
    475         if options["doconf"] :     
     480 
     481        if options["doconf"] : 
    476482            self.hintConfig(printers) 
    477                      
    478                       
    479 if __name__ == "__main__" :  
     483 
     484 
     485if __name__ == "__main__" : 
    480486    retcode = 0 
    481487    try : 
     
    484490                        "emptygroups", "force", "uidmin=", "uidmax=", \ 
    485491                        "gidmin=", "gidmax=", "doconf"] 
    486          
     492 
    487493        # Initializes the command line tool 
    488494        manager = PKTurnKey(doc=__doc__) 
    489495        manager.deferredInit() 
    490          
     496 
    491497        # parse and checks the command line 
    492498        (options, args) = manager.parseCommandline(sys.argv[1:], \ 
     
    494500                                                   long_options, \ 
    495501                                                   allownothing=1) 
    496          
     502 
    497503        # sets long options 
    498504        options["help"] = options["h"] or options["help"] 
     
    507513        options["gidmax"] = options["G"] or options["gidmax"] 
    508514        options["doconf"] = options["c"] or options["doconf"] 
    509          
     515 
    510516        if options["uidmin"] or options["uidmax"] : 
    511517            if not options["dousers"] : 
    512518                manager.printInfo(_("The --uidmin or --uidmax command line option implies --dousers as well."), "warn") 
    513             options["dousers"] = 1     
    514              
     519            options["dousers"] = 1 
     520 
    515521        if options["gidmin"] or options["gidmax"] : 
    516522            if not options["dogroups"] : 
    517523                manager.printInfo(_("The --gidmin or --gidmax command line option implies --dogroups as well."), "warn") 
    518524            options["dogroups"] = 1 
    519          
     525 
    520526        if options["dogroups"] : 
    521527            if not options["dousers"] : 
    522528                manager.printInfo(_("The --dogroups command line option implies --dousers as well."), "warn") 
    523             options["dousers"] = 1     
    524              
     529            options["dousers"] = 1 
     530 
    525531        if options["help"] : 
    526532            manager.display_usage_and_quit() 
     
    529535        else : 
    530536            retcode = manager.main(args, options) 
    531     except KeyboardInterrupt :         
     537    except KeyboardInterrupt : 
    532538        sys.stderr.write("\nInterrupted with Ctrl+C !\n") 
    533539        retcode = -3 
    534     except PyKotaCommandLineError, msg :     
     540    except PyKotaCommandLineError, msg : 
    535541        sys.stderr.write("%s : %s\n" % (sys.argv[0], msg)) 
    536542        retcode = -2 
    537     except SystemExit :         
     543    except SystemExit : 
    538544        pass 
    539545    except : 
    540546        try : 
    541547            manager.crashed("pkturnkey failed") 
    542         except :     
     548        except : 
    543549            crashed("pkturnkey failed") 
    544550        retcode = -1 
     
    546552    try : 
    547553        manager.storage.close() 
    548     except (TypeError, NameError, AttributeError) :     
     554    except (TypeError, NameError, AttributeError) : 
    549555        pass 
    550          
    551     sys.exit(retcode)     
     556 
     557    sys.exit(retcode)