Changeset 3416 for pykota/branches
- Timestamp:
- 10/01/08 18:14:18 (16 years ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
pykota/branches/1.26_fixes/bin/pkturnkey
r3133 r3416 16 16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 17 # GNU General Public License for more details. 18 # 18 # 19 19 # You should have received a copy of the GNU General Public License 20 20 # along with this program; if not, write to the Free Software … … 32 32 import signal 33 33 34 from pkipplib import pkipplib 35 34 36 from pykota.tool import Tool, PyKotaToolError, PyKotaCommandLineError, crashed, N_ 35 37 … … 50 52 -v | --version Prints pkturnkey version number then exits. 51 53 -h | --help Prints this message then exits. 52 54 53 55 -c | --doconf Give hints about what to put into pykota.conf 54 56 55 57 -d | --dousers Manages users accounts as well. 56 58 57 59 -D | --dogroups Manages users groups as well. 58 60 Implies -d | --dousers. 59 61 60 62 -e | --emptygroups Includes empty groups. 61 63 62 64 -f | --force Modifies the database instead of printing what 63 65 it would do. 64 66 65 67 -u | --uidmin uid Only adds users whose uid is greater than or equal to 66 68 uid. You can pass an username there as well, and its … … 68 70 If not set, 0 will be used automatically. 69 71 Implies -d | --dousers. 70 72 71 73 -U | --uidmax uid Only adds users whose uid is lesser than or equal to 72 74 uid. You can pass an username there as well, and its … … 80 82 If not set, 0 will be used automatically. 81 83 Implies -D | --dogroups. 82 84 83 85 -G | --gidmax gid Only adds groups whose gid is lesser than or equal to 84 86 gid. You can pass a groupname there as well, and its … … 87 89 Implies -D | --dogroups. 88 90 89 examples : 91 examples : 90 92 91 93 $ pkturnkey --dousers --uidmin jerome … … 94 96 printers and print accounts for all users whose uid is greater than 95 97 or equal to jerome's one. Won't manage any users group. 96 98 97 99 To REALLY initialize the database instead of simulating it, please 98 100 use the -f | --force command line switch. 99 101 100 102 You can limit the initialization to only a subset of the existing 101 103 printers, by passing their names at the end of the command line. 102 104 """) 103 105 104 106 class PKTurnKey(Tool) : 105 107 """A class for an initialization tool.""" … … 107 109 """Returns a list of tuples (queuename, deviceuri) for all existing print queues.""" 108 110 self.printInfo("Extracting all print queues.") 109 result = os.popen("lpstat -v", "r")110 lines = result.readlines()111 result.close()112 111 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) : 124 130 """Returns a list of users whose uids are between uidmin and uidmax.""" 125 131 self.printInfo("Extracting all users whose uid is between %s and %s." % (uidmin, uidmax)) 126 132 return [(entry[0], entry[3]) for entry in pwd.getpwall() if uidmin <= entry[2] <= uidmax] 127 133 128 134 def listGroups(self, gidmin, gidmax, users) : 129 135 """Returns a list of groups whose gids are between gidmin and gidmax.""" … … 134 140 for u in users : 135 141 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 = {} 139 145 for g in range(len(groups)) : 140 146 (gname, gid, members) = groups[g] … … 144 150 try : 145 151 usernames = gidusers[gid] 146 except KeyError : 152 except KeyError : 147 153 pass 148 else : 154 else : 149 155 for username in usernames : 150 156 if not newmembers.has_key(username) : 151 157 newmembers[username] = username 152 for member in newmembers.keys() : 158 for member in newmembers.keys() : 153 159 if not usersgid.has_key(member) : 154 160 del newmembers[member] 155 161 membership[gname] = newmembers.keys() 156 162 return membership 157 158 def runCommand(self, command, dryrun) : 163 164 def runCommand(self, command, dryrun) : 159 165 """Launches an external command.""" 160 166 self.printInfo("%s" % command) 161 if not dryrun : 167 if not dryrun : 162 168 os.system(command) 163 164 def createPrinters(self, printers, dryrun=0) : 169 170 def createPrinters(self, printers, dryrun=0) : 165 171 """Creates all printers in PyKota's database.""" 166 172 if printers : … … 170 176 args.close() 171 177 self.runCommand("pkprinters --arguments /tmp/pkprinters.args", dryrun) 172 178 173 179 def createUsers(self, users, printers, dryrun=0) : 174 180 """Creates all users in PyKota's database.""" … … 179 185 args.close() 180 186 self.runCommand("pkusers --arguments /tmp/pkusers.users.args", dryrun) 181 187 182 188 printersnames = [p[0] for p in printers] 183 189 args = open("/tmp/edpykota.users.args", "w") … … 187 193 args.close() 188 194 self.runCommand("edpykota --arguments /tmp/edpykota.users.args", dryrun) 189 195 190 196 def createGroups(self, groups, printers, dryrun=0) : 191 197 """Creates all groups in PyKota's database.""" … … 196 202 args.close() 197 203 self.runCommand("pkusers --arguments /tmp/pkusers.groups.args", dryrun) 198 204 199 205 printersnames = [p[0] for p in printers] 200 206 args = open("/tmp/edpykota.groups.args", "w") … … 204 210 args.close() 205 211 self.runCommand("edpykota --arguments /tmp/edpykota.groups.args", dryrun) 206 212 207 213 revmembership = {} 208 214 for (groupname, usernames) in groups.items() : 209 215 for username in usernames : 210 216 revmembership.setdefault(username, []).append(groupname) 211 commands = [] 212 for (username, groupnames) in revmembership.items() : 217 commands = [] 218 for (username, groupnames) in revmembership.items() : 213 219 commands.append('pkusers --ingroups %s "%s"' \ 214 220 % (",".join(['"%s"' % g for g in groupnames]), username)) 215 221 for command in commands : 216 222 self.runCommand(command, dryrun) 217 223 218 224 def supportsSNMP(self, hostname, community) : 219 225 """Returns 1 if the printer accepts SNMP queries, else 0.""" … … 221 227 try : 222 228 from pysnmp.entity.rfc3413.oneliner import cmdgen 223 except ImportError : 229 except ImportError : 224 230 hasV4 = False 225 231 try : … … 227 233 from pysnmp.mapping.udp.role import Manager 228 234 from pysnmp.proto.api import alpha 229 except ImportError : 235 except ImportError : 230 236 sys.stderr.write("pysnmp doesn't seem to be installed. SNMP checks will be ignored !\n") 231 237 return 0 232 else : 238 else : 233 239 hasV4 = True 234 235 if hasV4 : 240 241 if hasV4 : 236 242 def retrieveSNMPValues(hostname, community) : 237 243 """Retrieves a printer's internal page counter and status via SNMP.""" … … 240 246 cmdgen.UdpTransportTarget((hostname, 161)), \ 241 247 tuple([int(i) for i in pageCounterOID.split('.')])) 242 if errorIndication : 248 if errorIndication : 243 249 raise "No SNMP !" 244 elif errorStatus : 250 elif errorStatus : 245 251 raise "No SNMP !" 246 else : 252 else : 247 253 self.SNMPOK = True 248 254 else : 249 def retrieveSNMPValues(hostname, community) : 255 def retrieveSNMPValues(hostname, community) : 250 256 """Retrieves a printer's internal page counter and status via SNMP.""" 251 257 ver = alpha.protoVersions[alpha.protoVersionId1] … … 259 265 (hostname, 161), \ 260 266 (handleAnswer, req)) 261 except : 267 except : 262 268 raise "No SNMP !" 263 269 tsp.close() 264 270 265 271 def handleAnswer(wholemsg, notusedhere, req): 266 272 """Decodes and handles the SNMP answer.""" … … 269 275 try : 270 276 rsp.berDecode(wholemsg) 271 except TypeMismatchError, msg : 277 except TypeMismatchError, msg : 272 278 raise "No SNMP !" 273 279 else : … … 280 286 for varBind in rsp.apiAlphaGetPdu().apiAlphaGetVarBindList(): 281 287 self.values.append(varBind.apiAlphaGetOidVal()[1].rawAsn1Value) 282 try : 288 try : 283 289 pagecounter = self.values[0] 284 290 except : 285 291 raise "No SNMP !" 286 else : 292 else : 287 293 self.SNMPOK = 1 288 294 return 1 289 295 290 296 self.SNMPOK = 0 291 297 try : 292 298 retrieveSNMPValues(hostname, community) 293 except : 299 except : 294 300 self.SNMPOK = 0 295 301 return self.SNMPOK 296 302 297 303 def supportsPJL(self, hostname, port) : 298 304 """Returns 1 if the printer accepts PJL queries over TCP, else 0.""" 299 305 def alarmHandler(signum, frame) : 300 306 raise "Timeout !" 301 307 302 308 pjlsupport = 0 303 309 signal.signal(signal.SIGALRM, alarmHandler) … … 310 316 if not answer.startswith("@PJL") : 311 317 raise "No PJL !" 312 except : 318 except : 313 319 pass 314 else : 320 else : 315 321 pjlsupport = 1 316 322 s.close() … … 318 324 signal.signal(signal.SIGALRM, signal.SIG_IGN) 319 325 return pjlsupport 320 321 def hintConfig(self, printers) : 326 327 def hintConfig(self, printers) : 322 328 """Gives some hints about what to put into pykota.conf""" 323 329 if not printers : 324 330 return 325 sys.stderr.flush() # ensure outputs don't mix 326 print 331 sys.stderr.flush() # ensure outputs don't mix 332 print 327 333 print "--- CUT ---" 328 334 print "# Here are some lines that we suggest you add at the end" … … 337 343 try : 338 344 uri = uri.split("cupspykota:", 2)[-1] 339 except (ValueError, IndexError) : 345 except (ValueError, IndexError) : 340 346 pass 341 else : 347 else : 342 348 while uri and uri.startswith("/") : 343 349 uri = uri[1:] 344 350 try : 345 (backend, destination) = uri.split(":", 1) 351 (backend, destination) = uri.split(":", 1) 346 352 if backend not in ("ipp", "http", "https", "lpd", "socket") : 347 353 raise ValueError 348 except ValueError : 354 except ValueError : 349 355 pass 350 else : 356 else : 351 357 while destination.startswith("/") : 352 358 destination = destination[1:] 353 checkauth = destination.split("@", 1) 359 checkauth = destination.split("@", 1) 354 360 if len(checkauth) == 2 : 355 361 destination = checkauth[1] … … 361 367 except ValueError : 362 368 port = 9100 363 else : 369 else : 364 370 (hostname, port) = parts[0], 9100 365 371 366 372 if self.supportsSNMP(hostname, "public") : 367 373 accounter = "hardware(snmp)" … … 370 376 elif self.supportsPJL(hostname, 9101) : 371 377 accounter = "hardware(pjl:9101)" 372 elif self.supportsPJL(hostname, port) : 378 elif self.supportsPJL(hostname, port) : 373 379 accounter = "hardware(pjl:%s)" % port 374 375 print "preaccounter : software()" 380 381 print "preaccounter : software()" 376 382 print "accounter : %s" % accounter 377 383 print 378 384 print "--- CUT ---" 379 385 380 386 def main(self, names, options) : 381 387 """Intializes PyKota's database.""" … … 383 389 raise PyKotaCommandLineError, "%s : %s" % (pwd.getpwuid(os.geteuid())[0], \ 384 390 _("You're not allowed to use this command.")) 385 391 386 392 if not names : 387 393 names = ["*"] 388 394 389 395 self.printInfo(_("Please be patient...")) 390 396 dryrun = not options["force"] 391 397 if dryrun : 392 398 self.printInfo(_("Don't worry, the database WILL NOT BE MODIFIED.")) 393 else : 399 else : 394 400 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"] : 398 404 self.printInfo(_("System users will have a print account as well !"), "warn") 399 405 uidmin = 0 400 else : 406 else : 401 407 try : 402 408 uidmin = int(options["uidmin"]) 403 except : 409 except : 404 410 try : 405 411 uidmin = pwd.getpwnam(options["uidmin"])[2] 406 except KeyError, msg : 412 except KeyError, msg : 407 413 raise PyKotaCommandLineError, _("Unknown username %s : %s") \ 408 414 % (options["uidmin"], msg) 409 410 if not options["uidmax"] : 415 416 if not options["uidmax"] : 411 417 uidmax = sys.maxint 412 else : 418 else : 413 419 try : 414 420 uidmax = int(options["uidmax"]) 415 except : 421 except : 416 422 try : 417 423 uidmax = pwd.getpwnam(options["uidmax"])[2] 418 except KeyError, msg : 424 except KeyError, msg : 419 425 raise PyKotaCommandLineError, _("Unknown username %s : %s") \ 420 426 % (options["uidmax"], msg) 421 422 if uidmin > uidmax : 427 428 if uidmin > uidmax : 423 429 (uidmin, uidmax) = (uidmax, uidmin) 424 430 users = self.listUsers(uidmin, uidmax) 425 else : 431 else : 426 432 users = [] 427 428 if options["dogroups"] : 429 if not options["gidmin"] : 433 434 if options["dogroups"] : 435 if not options["gidmin"] : 430 436 self.printInfo(_("System groups will have a print account as well !"), "warn") 431 437 gidmin = 0 432 else : 438 else : 433 439 try : 434 440 gidmin = int(options["gidmin"]) 435 except : 441 except : 436 442 try : 437 443 gidmin = grp.getgrnam(options["gidmin"])[2] 438 except KeyError, msg : 444 except KeyError, msg : 439 445 raise PyKotaCommandLineError, _("Unknown groupname %s : %s") \ 440 446 % (options["gidmin"], msg) 441 442 if not options["gidmax"] : 447 448 if not options["gidmax"] : 443 449 gidmax = sys.maxint 444 else : 450 else : 445 451 try : 446 452 gidmax = int(options["gidmax"]) 447 except : 453 except : 448 454 try : 449 455 gidmax = grp.getgrnam(options["gidmax"])[2] 450 except KeyError, msg : 456 except KeyError, msg : 451 457 raise PyKotaCommandLineError, _("Unknown groupname %s : %s") \ 452 458 % (options["gidmax"], msg) 453 454 if gidmin > gidmax : 459 460 if gidmin > gidmax : 455 461 (gidmin, gidmax) = (gidmax, gidmin) 456 462 groups = self.listGroups(gidmin, gidmax, users) … … 459 465 if not members : 460 466 del groups[groupname] 461 else : 467 else : 462 468 groups = [] 463 469 464 470 printers = self.listPrinters(names) 465 471 if printers : … … 467 473 self.createUsers([entry[0] for entry in users], printers, dryrun) 468 474 self.createGroups(groups, printers, dryrun) 469 475 470 476 if dryrun : 471 477 self.printInfo(_("Simulation terminated.")) 472 else : 478 else : 473 479 self.printInfo(_("Database initialized !")) 474 475 if options["doconf"] : 480 481 if options["doconf"] : 476 482 self.hintConfig(printers) 477 478 479 if __name__ == "__main__" : 483 484 485 if __name__ == "__main__" : 480 486 retcode = 0 481 487 try : … … 484 490 "emptygroups", "force", "uidmin=", "uidmax=", \ 485 491 "gidmin=", "gidmax=", "doconf"] 486 492 487 493 # Initializes the command line tool 488 494 manager = PKTurnKey(doc=__doc__) 489 495 manager.deferredInit() 490 496 491 497 # parse and checks the command line 492 498 (options, args) = manager.parseCommandline(sys.argv[1:], \ … … 494 500 long_options, \ 495 501 allownothing=1) 496 502 497 503 # sets long options 498 504 options["help"] = options["h"] or options["help"] … … 507 513 options["gidmax"] = options["G"] or options["gidmax"] 508 514 options["doconf"] = options["c"] or options["doconf"] 509 515 510 516 if options["uidmin"] or options["uidmax"] : 511 517 if not options["dousers"] : 512 518 manager.printInfo(_("The --uidmin or --uidmax command line option implies --dousers as well."), "warn") 513 options["dousers"] = 1 514 519 options["dousers"] = 1 520 515 521 if options["gidmin"] or options["gidmax"] : 516 522 if not options["dogroups"] : 517 523 manager.printInfo(_("The --gidmin or --gidmax command line option implies --dogroups as well."), "warn") 518 524 options["dogroups"] = 1 519 525 520 526 if options["dogroups"] : 521 527 if not options["dousers"] : 522 528 manager.printInfo(_("The --dogroups command line option implies --dousers as well."), "warn") 523 options["dousers"] = 1 524 529 options["dousers"] = 1 530 525 531 if options["help"] : 526 532 manager.display_usage_and_quit() … … 529 535 else : 530 536 retcode = manager.main(args, options) 531 except KeyboardInterrupt : 537 except KeyboardInterrupt : 532 538 sys.stderr.write("\nInterrupted with Ctrl+C !\n") 533 539 retcode = -3 534 except PyKotaCommandLineError, msg : 540 except PyKotaCommandLineError, msg : 535 541 sys.stderr.write("%s : %s\n" % (sys.argv[0], msg)) 536 542 retcode = -2 537 except SystemExit : 543 except SystemExit : 538 544 pass 539 545 except : 540 546 try : 541 547 manager.crashed("pkturnkey failed") 542 except : 548 except : 543 549 crashed("pkturnkey failed") 544 550 retcode = -1 … … 546 552 try : 547 553 manager.storage.close() 548 except (TypeError, NameError, AttributeError) : 554 except (TypeError, NameError, AttributeError) : 549 555 pass 550 551 sys.exit(retcode) 556 557 sys.exit(retcode)