337 | | BaseStorage.__init__(self, pykotatool) |
338 | | self.info = pykotatool.config.getLDAPInfo() |
339 | | try : |
340 | | self.database = ldap.initialize(host) |
341 | | self.database.simple_bind_s(user, passwd) |
342 | | self.basedn = dbname |
343 | | except ldap.SERVER_DOWN : |
344 | | raise PyKotaStorageError, "LDAP backend for PyKota seems to be down !" # TODO : translate |
345 | | except ldap.LDAPError : |
346 | | raise PyKotaStorageError, "Unable to connect to LDAP server %s as %s." % (host, user) # TODO : translate |
347 | | else : |
348 | | self.useldapcache = pykotatool.config.getLDAPCache() |
349 | | if self.useldapcache : |
350 | | self.tool.logdebug("Low-Level LDAP Caching enabled.") |
351 | | self.ldapcache = {} # low-level cache specific to LDAP backend |
352 | | self.closed = 0 |
353 | | self.tool.logdebug("Database opened (host=%s, dbname=%s, user=%s)" % (host, dbname, user)) |
| 340 | self.savedtool = pykotatool |
| 341 | self.savedhost = host |
| 342 | self.saveddbname = dbname |
| 343 | self.saveduser = user |
| 344 | self.savedpasswd = passwd |
| 345 | self.secondStageInit() |
| 346 | |
| 347 | def secondStageInit(self) : |
| 348 | """Second stage initialisation.""" |
| 349 | BaseStorage.__init__(self, self.savedtool) |
| 350 | self.info = self.tool.config.getLDAPInfo() |
| 351 | message = "" |
| 352 | for tryit in range(3) : |
| 353 | try : |
| 354 | self.database = ldap.initialize(self.savedhost) |
| 355 | self.database.simple_bind_s(self.saveduser, self.savedpasswd) |
| 356 | self.basedn = self.saveddbname |
| 357 | except ldap.SERVER_DOWN : |
| 358 | message = "LDAP backend for PyKota seems to be down !" |
| 359 | self.tool.printInfo("%s" % message, "error") |
| 360 | self.tool.printInfo("Trying again in 2 seconds...", "warn") |
| 361 | time.sleep(2) |
| 362 | except ldap.LDAPError : |
| 363 | message = "Unable to connect to LDAP server %s as %s." % (self.savedhost, self.saveduser) |
| 364 | self.tool.printInfo("%s" % message, "error") |
| 365 | self.tool.printInfo("Trying again in 2 seconds...", "warn") |
| 366 | time.sleep(2) |
| 367 | else : |
| 368 | self.useldapcache = self.tool.config.getLDAPCache() |
| 369 | if self.useldapcache : |
| 370 | self.tool.logdebug("Low-Level LDAP Caching enabled.") |
| 371 | self.ldapcache = {} # low-level cache specific to LDAP backend |
| 372 | self.closed = 0 |
| 373 | self.tool.logdebug("Database opened (host=%s, dbname=%s, user=%s)" % (self.savedhost, self.saveddbname, self.saveduser)) |
| 374 | return # All is fine here. |
| 375 | raise PyKotaStorageError, message |
393 | | try : |
394 | | base = base or self.basedn |
395 | | if self.useldapcache : |
396 | | # Here we overwrite the fields the app want, to try and |
397 | | # retrieve ALL user defined attributes ("*") |
398 | | # + the createTimestamp attribute, needed by job history |
399 | | # |
400 | | # This may not work with all LDAP servers |
401 | | # but works at least in OpenLDAP (2.1.25) |
402 | | # and iPlanet Directory Server (5.1 SP3) |
403 | | fields = ["*", "createTimestamp"] |
404 | | |
405 | | if self.useldapcache and (not flushcache) and (scope == ldap.SCOPE_BASE) and self.ldapcache.has_key(base) : |
406 | | entry = self.ldapcache[base] |
407 | | self.tool.logdebug("LDAP cache hit %s => %s" % (base, entry)) |
408 | | result = [(base, entry)] |
409 | | else : |
410 | | self.tool.logdebug("QUERY : Filter : %s, BaseDN : %s, Scope : %s, Attributes : %s" % (key, base, scope, fields)) |
411 | | result = self.database.search_s(base, scope, key, fields) |
412 | | except ldap.NO_SUCH_OBJECT, msg : |
413 | | raise PyKotaStorageError, (_("Search base %s doesn't seem to exist. Probable misconfiguration. Please double check /etc/pykota/pykota.conf : %s") % (base, msg)) |
414 | | except ldap.LDAPError, msg : |
415 | | raise PyKotaStorageError, (_("Search for %s(%s) from %s(scope=%s) returned no answer.") % (key, fields, base, scope)) + " : %s" % str(msg) |
416 | | else : |
417 | | self.tool.logdebug("QUERY : Result : %s" % result) |
418 | | if self.useldapcache : |
419 | | for (dn, attributes) in result : |
420 | | self.tool.logdebug("LDAP cache store %s => %s" % (dn, attributes)) |
421 | | self.ldapcache[dn] = attributes |
422 | | return result |
| 415 | message = "" |
| 416 | for tryit in range(3) : |
| 417 | try : |
| 418 | base = base or self.basedn |
| 419 | if self.useldapcache : |
| 420 | # Here we overwrite the fields the app want, to try and |
| 421 | # retrieve ALL user defined attributes ("*") |
| 422 | # + the createTimestamp attribute, needed by job history |
| 423 | # |
| 424 | # This may not work with all LDAP servers |
| 425 | # but works at least in OpenLDAP (2.1.25) |
| 426 | # and iPlanet Directory Server (5.1 SP3) |
| 427 | fields = ["*", "createTimestamp"] |
| 428 | |
| 429 | if self.useldapcache and (not flushcache) and (scope == ldap.SCOPE_BASE) and self.ldapcache.has_key(base) : |
| 430 | entry = self.ldapcache[base] |
| 431 | self.tool.logdebug("LDAP cache hit %s => %s" % (base, entry)) |
| 432 | result = [(base, entry)] |
| 433 | else : |
| 434 | self.tool.logdebug("QUERY : Filter : %s, BaseDN : %s, Scope : %s, Attributes : %s" % (key, base, scope, fields)) |
| 435 | result = self.database.search_s(base, scope, key, fields) |
| 436 | except ldap.NO_SUCH_OBJECT, msg : |
| 437 | raise PyKotaStorageError, (_("Search base %s doesn't seem to exist. Probable misconfiguration. Please double check /etc/pykota/pykota.conf : %s") % (base, msg)) |
| 438 | except ldap.LDAPError, msg : |
| 439 | message = (_("Search for %s(%s) from %s(scope=%s) returned no answer.") % (key, fields, base, scope)) + " : %s" % str(msg) |
| 440 | self.tool.printInfo("LDAP error : %s" % message, "error") |
| 441 | self.tool.printInfo("LDAP connection will be closed and reopened.", "warn") |
| 442 | self.close() |
| 443 | self.secondStageInit() |
| 444 | else : |
| 445 | self.tool.logdebug("QUERY : Result : %s" % result) |
| 446 | if self.useldapcache : |
| 447 | for (dn, attributes) in result : |
| 448 | self.tool.logdebug("LDAP cache store %s => %s" % (dn, attributes)) |
| 449 | self.ldapcache[dn] = attributes |
| 450 | return result |
| 451 | raise PyKotaStorageError, message |
428 | | try : |
429 | | self.tool.logdebug("QUERY : ADD(%s, %s)" % (dn, str(fields))) |
430 | | entry = ldap.modlist.addModlist(fields) |
431 | | self.tool.logdebug("%s" % entry) |
432 | | self.database.add_s(dn, entry) |
433 | | except ldap.LDAPError, msg : |
434 | | raise PyKotaStorageError, (_("Problem adding LDAP entry (%s, %s)") % (dn, str(fields))) + " : %s" % str(msg) |
435 | | else : |
436 | | if self.useldapcache : |
437 | | self.tool.logdebug("LDAP cache add %s => %s" % (dn, fields)) |
438 | | self.ldapcache[dn] = fields |
439 | | return dn |
| 456 | message = "" |
| 457 | for tryit in range(3) : |
| 458 | try : |
| 459 | self.tool.logdebug("QUERY : ADD(%s, %s)" % (dn, str(fields))) |
| 460 | entry = ldap.modlist.addModlist(fields) |
| 461 | self.tool.logdebug("%s" % entry) |
| 462 | self.database.add_s(dn, entry) |
| 463 | except ldap.LDAPError, msg : |
| 464 | message = (_("Problem adding LDAP entry (%s, %s)") % (dn, str(fields))) + " : %s" % str(msg) |
| 465 | self.tool.printInfo("LDAP error : %s" % message, "error") |
| 466 | self.tool.printInfo("LDAP connection will be closed and reopened.", "warn") |
| 467 | self.close() |
| 468 | self.secondStageInit() |
| 469 | else : |
| 470 | if self.useldapcache : |
| 471 | self.tool.logdebug("LDAP cache add %s => %s" % (dn, fields)) |
| 472 | self.ldapcache[dn] = fields |
| 473 | return dn |
| 474 | raise PyKotaStorageError, message |
443 | | # TODO : delete from LDAP specific cache |
444 | | try : |
445 | | self.tool.logdebug("QUERY : Delete(%s)" % dn) |
446 | | self.database.delete_s(dn) |
447 | | except ldap.LDAPError, msg : |
448 | | raise PyKotaStorageError, (_("Problem deleting LDAP entry (%s)") % dn) + " : %s" % str(msg) |
449 | | else : |
450 | | if self.useldapcache : |
451 | | try : |
452 | | self.tool.logdebug("LDAP cache del %s" % dn) |
453 | | del self.ldapcache[dn] |
454 | | except KeyError : |
455 | | pass |
| 478 | message = "" |
| 479 | for tryit in range(3) : |
| 480 | try : |
| 481 | self.tool.logdebug("QUERY : Delete(%s)" % dn) |
| 482 | self.database.delete_s(dn) |
| 483 | except ldap.LDAPError, msg : |
| 484 | message = (_("Problem deleting LDAP entry (%s)") % dn) + " : %s" % str(msg) |
| 485 | self.tool.printInfo("LDAP error : %s" % message, "error") |
| 486 | self.tool.printInfo("LDAP connection will be closed and reopened.", "warn") |
| 487 | self.close() |
| 488 | self.secondStageInit() |
| 489 | else : |
| 490 | if self.useldapcache : |
| 491 | try : |
| 492 | self.tool.logdebug("LDAP cache del %s" % dn) |
| 493 | del self.ldapcache[dn] |
| 494 | except KeyError : |
| 495 | pass |
| 496 | return |
| 497 | raise PyKotaStorageError, message |
459 | | try : |
460 | | # TODO : take care of, and update LDAP specific cache |
461 | | if self.useldapcache and not flushcache : |
462 | | if self.ldapcache.has_key(dn) : |
463 | | old = self.ldapcache[dn] |
464 | | self.tool.logdebug("LDAP cache hit %s => %s" % (dn, old)) |
465 | | oldentry = {} |
466 | | for (k, v) in old.items() : |
467 | | if k != "createTimestamp" : |
468 | | oldentry[k] = v |
469 | | else : |
470 | | self.tool.logdebug("LDAP cache miss %s" % dn) |
471 | | oldentry = self.doSearch("objectClass=*", base=dn, scope=ldap.SCOPE_BASE)[0][1] |
472 | | else : |
473 | | oldentry = self.doSearch("objectClass=*", base=dn, scope=ldap.SCOPE_BASE, flushcache=flushcache)[0][1] |
474 | | for (k, v) in fields.items() : |
475 | | if type(v) == type({}) : |
476 | | try : |
477 | | oldvalue = v["convert"](oldentry.get(k, [0])[0]) |
478 | | except ValueError : |
479 | | self.tool.logdebug("Error converting %s with %s(%s)" % (oldentry.get(k), k, v)) |
480 | | oldvalue = 0 |
481 | | if v["operator"] == '+' : |
482 | | newvalue = oldvalue + v["value"] |
| 501 | for tryit in range(3) : |
| 502 | try : |
| 503 | # TODO : take care of, and update LDAP specific cache |
| 504 | if self.useldapcache and not flushcache : |
| 505 | if self.ldapcache.has_key(dn) : |
| 506 | old = self.ldapcache[dn] |
| 507 | self.tool.logdebug("LDAP cache hit %s => %s" % (dn, old)) |
| 508 | oldentry = {} |
| 509 | for (k, v) in old.items() : |
| 510 | if k != "createTimestamp" : |
| 511 | oldentry[k] = v |
484 | | newvalue = oldvalue - v["value"] |
485 | | fields[k] = str(newvalue) |
486 | | fields = self.normalizeFields(fields) |
487 | | self.tool.logdebug("QUERY : Modify(%s, %s ==> %s)" % (dn, oldentry, fields)) |
488 | | entry = ldap.modlist.modifyModlist(oldentry, fields, ignore_oldexistent=ignoreold) |
489 | | modentry = [] |
490 | | for (mop, mtyp, mval) in entry : |
491 | | if mtyp != "createTimestamp" : |
492 | | modentry.append((mop, mtyp, mval)) |
493 | | self.tool.logdebug("MODIFY : %s ==> %s ==> %s" % (fields, entry, modentry)) |
494 | | if modentry : |
495 | | self.database.modify_s(dn, modentry) |
496 | | except ldap.LDAPError, msg : |
497 | | raise PyKotaStorageError, (_("Problem modifying LDAP entry (%s, %s)") % (dn, fields)) + " : %s" % str(msg) |
498 | | else : |
499 | | if self.useldapcache : |
500 | | cachedentry = self.ldapcache[dn] |
| 513 | self.tool.logdebug("LDAP cache miss %s" % dn) |
| 514 | oldentry = self.doSearch("objectClass=*", base=dn, scope=ldap.SCOPE_BASE)[0][1] |
| 515 | else : |
| 516 | oldentry = self.doSearch("objectClass=*", base=dn, scope=ldap.SCOPE_BASE, flushcache=flushcache)[0][1] |
| 517 | for (k, v) in fields.items() : |
| 518 | if type(v) == type({}) : |
| 519 | try : |
| 520 | oldvalue = v["convert"](oldentry.get(k, [0])[0]) |
| 521 | except ValueError : |
| 522 | self.tool.logdebug("Error converting %s with %s(%s)" % (oldentry.get(k), k, v)) |
| 523 | oldvalue = 0 |
| 524 | if v["operator"] == '+' : |
| 525 | newvalue = oldvalue + v["value"] |
| 526 | else : |
| 527 | newvalue = oldvalue - v["value"] |
| 528 | fields[k] = str(newvalue) |
| 529 | fields = self.normalizeFields(fields) |
| 530 | self.tool.logdebug("QUERY : Modify(%s, %s ==> %s)" % (dn, oldentry, fields)) |
| 531 | entry = ldap.modlist.modifyModlist(oldentry, fields, ignore_oldexistent=ignoreold) |
| 532 | modentry = [] |
502 | | if mop in (ldap.MOD_ADD, ldap.MOD_REPLACE) : |
503 | | cachedentry[mtyp] = mval |
504 | | else : |
505 | | try : |
506 | | del cachedentry[mtyp] |
507 | | except KeyError : |
508 | | pass |
509 | | self.tool.logdebug("LDAP cache update %s => %s" % (dn, cachedentry)) |
510 | | return dn |
| 534 | if mtyp != "createTimestamp" : |
| 535 | modentry.append((mop, mtyp, mval)) |
| 536 | self.tool.logdebug("MODIFY : %s ==> %s ==> %s" % (fields, entry, modentry)) |
| 537 | if modentry : |
| 538 | self.database.modify_s(dn, modentry) |
| 539 | except ldap.LDAPError, msg : |
| 540 | message = (_("Problem modifying LDAP entry (%s, %s)") % (dn, fields)) + " : %s" % str(msg) |
| 541 | self.tool.printInfo("LDAP error : %s" % message, "error") |
| 542 | self.tool.printInfo("LDAP connection will be closed and reopened.", "warn") |
| 543 | self.close() |
| 544 | self.secondStageInit() |
| 545 | else : |
| 546 | if self.useldapcache : |
| 547 | cachedentry = self.ldapcache[dn] |
| 548 | for (mop, mtyp, mval) in entry : |
| 549 | if mop in (ldap.MOD_ADD, ldap.MOD_REPLACE) : |
| 550 | cachedentry[mtyp] = mval |
| 551 | else : |
| 552 | try : |
| 553 | del cachedentry[mtyp] |
| 554 | except KeyError : |
| 555 | pass |
| 556 | self.tool.logdebug("LDAP cache update %s => %s" % (dn, cachedentry)) |
| 557 | return dn |
| 558 | raise PyKotaStorageError, message |