Upload
lethien
View
257
Download
0
Embed Size (px)
Citation preview
Manuel Haim - Hochschulrechenzentrum
CALYPSO – ein Python-Skriptzum generischen Datenabgleich
Manuel Haim, HRZ Uni Marburg
ZKI-Arbeitskreis Verzeichnisdienste12.08.2016 in Ulm
2Manuel Haim - Hochschulrechenzentrum
Datenabgleich per Skript, das heißt...
• Programmiersprache wählen (z.B. Perl, Python, …)
• Quelle und Ziel öffnen (z.B. Datenbank, Datei, …)
• Datensätze durchlaufen (z.B. for-Schleife)
• Vergleich/Fallunterscheidung (z.B. if-then-else-Anweisung)
• Aktion ausführen (z.B. anlegen, aktualisieren, löschen)
3Manuel Haim - Hochschulrechenzentrum
Datenabgleich per Skript, das heißt...
• Programmiersprache wählen (z.B. Perl, Python, …)
• Quelle und Ziel öffnen (z.B. Datenbank, Datei, …)
• Datensätze durchlaufen (z.B. for-Schleife)
• Vergleich/Fallunterscheidung (z.B. if-then-else-Anweisung)
• Aktion ausführen (z.B. anlegen, aktualisieren, löschen)Das läss
t sich
verallg
emeinern!
5Manuel Haim - Hochschulrechenzentrum
CALYPSO ???
• Musikstil und Tanzum 1900 in Trinidad und Tobago entstanden,afrikanische und französische Wurzeln
• Liedtexte dienten als Informationsträgerfür kritische oder anderweitig zensierte Botschaften,waren zuverlässigste Nachrichtenquelle
6Manuel Haim - Hochschulrechenzentrum
CALYPSO
(Common Algorithm LibrarY for the Provisioning and Synchronization of Objects)
CALYPSO ist mehr als nur ein Python-Skript:
• modular aufgebaut (Konnektoren und Algorithmen)
• Funktionsweise angelehnt an gängige IDM-Software
• trotzdem nur wenige hundert Zeilen Python-Code
8Manuel Haim - Hochschulrechenzentrum
Objekte sind Python-Dictionaries, z.B.
obj = { '__id__' : 'uid=triangle,dc=example,dc=net', 'uid' : ['triangle'], 'givenName' : ['Tom'], 'sn' : ['Triangle']}
Attributwerte i.d.R. als Liste(wichtig für LDAP)
10Manuel Haim - Hochschulrechenzentrum
Konnektoren sind Klassen mit Funktionen
Für Quell-Konnektoren (read-only):
• def __init__(self, …): # Konstruktor
• def __iter__(self): # Iterator erzeugen
• def __next__(self): # nächstes Element (Iterator)
Für Ziel-Konnektoren (read/write/search) zusätzlich:
• def correlate(self, source_obj): # Passende(s) Zielobjekt(e) # zum Quellobjekt suchen.
• def id_list(self): # Liste eindeutiger Objekt-IDs
• def add(self, obj): # Objekt hinzufügen
• def update(self, the_id, source_obj, # Objekt aktualisieren target_obj, att_list): # (falls verändert)
• def delete(self, the_id): # Objekt entfernen
11Manuel Haim - Hochschulrechenzentrum
Bislang implementierte Konnektoren
Read-only:• ExcelReader• CsvReader
Read/write:• LdapConnector• LdapIdmConnector (nutzt und pflegt eigene Meta-Attribute
„UniMrIdmSourceCreated“ / „-Updated“ / „-Deleted“)
15Manuel Haim - Hochschulrechenzentrum
Mögliche Situationen beim Datenabgleich
Quelle Ziel
„absent“
„found“
16Manuel Haim - Hochschulrechenzentrum
Mögliche Situationen beim Datenabgleich
Quelle Ziel
„absent“
„found“
„ambiguous“
17Manuel Haim - Hochschulrechenzentrum
Mögliche Situationen beim Datenabgleich
Quelle Ziel
„absent“
„found“
„ambiguous“
„source missing“
18Manuel Haim - Hochschulrechenzentrum
Mögliche Situationen und sinnvolle Aktionen
Quelle Ziel
„absent“
„found“
„ambiguous“
„source missing“
???
19Manuel Haim - Hochschulrechenzentrum
Mögliche Situationen und sinnvolle Aktionen
Quelle Ziel
„absent“
„found“
„ambiguous“
„source missing“
„create“
z.B.
*
20Manuel Haim - Hochschulrechenzentrum
Mögliche Situationen und sinnvolle Aktionen
Quelle Ziel
„absent“
„found“
„ambiguous“
„source missing“
„create“
„update“
z.B.
*←
21Manuel Haim - Hochschulrechenzentrum
Mögliche Situationen und sinnvolle Aktionen
Quelle Ziel
„absent“
„found“
„ambiguous“
„source missing“
„create“
„update“
„ignore“
z.B.
*←
22Manuel Haim - Hochschulrechenzentrum
Mögliche Situationen und sinnvolle Aktionen
Quelle Ziel
„absent“
„found“
„ambiguous“
„source missing“
„create“
„update“
„ignore“
„delete“
z.B.
X
*←
23Manuel Haim - Hochschulrechenzentrum
In CALYPSO sieht das so aus:
source = LdapConnector(…)mapping = { 'uid' : 'uid', 'sn' : 'sn', 'givenName' : 'givenName'}target = LdapConnector(keys = ['uid'], …)actions = { 'absent' : 'create', 'found' : 'update', 'ambiguous' : 'ignore', 'source_missing' : 'delete'}attributes = ['sn', 'givenName']sync(source, mapping, target, actions, attributes)
24Manuel Haim - Hochschulrechenzentrum
In CALYPSO sieht das so aus:
source = LdapConnector(…)mapping = { 'uid' : 'uid', 'sn' : 'sn', 'givenName' : 'givenName'}target = LdapConnector(keys = ['uid'], …)actions = { 'absent' : 'create', 'found' : 'update', 'ambiguous' : 'ignore', 'source_missing' : 'delete'}attributes = ['sn', 'givenName']sync(source, mapping, target, actions, attributes)
Jeder Situation wird eine Aktion zugeordnet.
25Manuel Haim - Hochschulrechenzentrum
In CALYPSO sieht das so aus:
source = LdapConnector(…)mapping = { 'uid' : 'uid', 'sn' : 'sn', 'givenName' : 'givenName'}target = LdapConnector(keys = ['uid'], …)actions = { 'absent' : 'create', 'found' : 'update', 'ambiguous' : 'ignore', 'source_missing' : 'delete'}attributes = ['sn', 'givenName']sync(source, mapping, target, actions, attributes)
Quelle und Ziel (inkl. Suchschlüssel)werden definiert.
26Manuel Haim - Hochschulrechenzentrum
In CALYPSO sieht das so aus:
source = LdapConnector(…)mapping = { 'uid' : 'uid', 'sn' : 'sn', 'givenName' : 'givenName'}target = LdapConnector(keys = ['uid'], …)actions = { 'absent' : 'create', 'found' : 'update', 'ambiguous' : 'ignore', 'source_missing' : 'delete'}attributes = ['sn', 'givenName']sync(source, mapping, target, actions, attributes)
Ein Attribut-Mapping wird festgelegt (links Zielattribut, rechts Quellattribut).
27Manuel Haim - Hochschulrechenzentrum
In CALYPSO sieht das so aus:
source = LdapConnector(…)mapping = { 'uid' : 'uid', … : …, 'cn' : [my_concat,'givenName',': ','sn']}target = LdapConnector(keys = ['uid'], …)actions = { 'absent' : 'create', 'found' : 'update', 'ambiguous' : 'ignore', 'source_missing' : 'delete'}attributes = ['sn', 'givenName']sync(source, mapping, target, actions, attributes)
Auch eigene Funktionen könnenangegeben werden (Präfix-Notation). (String-Konstanten beginnen mit „:“ )
28Manuel Haim - Hochschulrechenzentrum
In CALYPSO sieht das so aus:
source = LdapConnector(…)mapping = { 'uid' : 'uid', … : …, 'cn' : [my_concat,'givenName',': ','sn']}target = LdapConnector(keys = ['uid'], …)actions = { 'absent' : 'create', 'found' : 'update', 'ambiguous' : 'ignore', 'source_missing' : 'delete'}attributes = ['sn', 'givenName']sync(source, mapping, target, actions, attributes)
Die zu überschreibendenZiel-Attribute werden gewählt.
29Manuel Haim - Hochschulrechenzentrum
In CALYPSO sieht das so aus:
source = LdapConnector(…)mapping = { 'uid' : 'uid', … : …, 'cn' : [my_concat,'givenName',': ','sn']}target = LdapConnector(keys = ['uid'], …)actions = { 'absent' : 'create', 'found' : 'update', 'ambiguous' : 'ignore', 'source_missing' : 'delete'}attributes = ['sn', 'givenName']sync(source, mapping, target, actions, attributes)
Die Synchronisationwird gestartet.
30Manuel Haim - Hochschulrechenzentrum
Log-Ausgabe:
20160912 140203 sync started.
create: uid=triangle,dc=example,dc=net data: {'givenName': 'Tom', 'sn': 'Triangle'}
update: uid=circle,dc=example,dc=net data: {'givenName': [('MODIFY_REPLACE', ['Carl'])]}
delete: uid=pentagon,dc=example,dc=net
20160912 140204 sync finished: 5 source entries (1 absent, 1 found, 1 ambiguous), 4 target entries (2 correlated, 0 obsolete). 1 created, 1 updated, 1 deleted.
31Manuel Haim - Hochschulrechenzentrum
Tipp: Delta-Synchronisation verwenden
source = LdapConnector(filt='(createTimestamp>=…)',…)mapping = { 'uid' : 'uid', … : …, 'cn' : [my_concat,'givenName',': ','sn']}target = LdapConnector(keys = ['uid'], …)actions = { 'absent' : 'create', 'found' : 'update', 'ambiguous' : 'ignore', 'source_missing' : 'ignore'}attributes = ['sn', 'givenName']sync(source, mapping, target, actions, attributes)
Wichtig:Bei fehlendem Quelldaten-satz: Nicht löschen!
LDAP-Quell-Konnektorper Filter einschränken
32Manuel Haim - Hochschulrechenzentrum
Tipp: Einstellungen read-only testen
source = LdapConnector(filt='(createTimestamp>=…)',…)mapping = { 'uid' : 'uid', … : …, 'cn' : [my_concat,'givenName',': ','sn']}target = LdapConnector(keys=['uid'],read_only=True,…)actions = { 'absent' : 'create', 'found' : 'update', 'ambiguous' : 'ignore', 'source_missing' : 'ignore'}attributes = ['sn', 'givenName']sync(source, mapping, target, actions, attributes)
LDAP-Ziel-Konnektor auf read_only setzen.
34Manuel Haim - Hochschulrechenzentrum
Vereinigung von Objekten
Quelle Ziel
???
(Zweck: Zusammenführen von Attributen – z.B. Namen, Berechtigungen, ...)
35Manuel Haim - Hochschulrechenzentrum
Vereinigung von Objekten (Sync)
Quelle Ziel
???
„found“
„found“
„found“
„update“
„update“
„update“
→ Zielobjekt 3x überschrieben!
Sync-Algorithmus hilft in der Regel nicht weiter:
36Manuel Haim - Hochschulrechenzentrum
Vereinigung von Objekten (Merge)
Quelle Ziel
„found“
Schritt 1: Ausgehend vom Quellobjekt das Zielobjekt suchen
37Manuel Haim - Hochschulrechenzentrum
Vereinigung von Objekten (Merge)
Quelle Ziel
Schritt 2: Ausgehend vom Zielobjekt passende Quellobjekte suchen
38Manuel Haim - Hochschulrechenzentrum
Vereinigung von Objekten (Merge)
Quelle Ziel
Schritt 3: Über eigene Merge-Funktion die Zielattribute berechnen
39Manuel Haim - Hochschulrechenzentrum
Vereinigung von Objekten (Merge)
Quelle Ziel
Schritt 4: Zielobjekt aktualisieren
„update“
40Manuel Haim - Hochschulrechenzentrum
Vereinigung von Objekten (Merge)
Quelle Ziel
Mit nächstem (unverbrauchtem) Objekt fortfahren...
„found“ ...
41Manuel Haim - Hochschulrechenzentrum
In CALYPSO sieht das so aus:source = LdapConnector(keys = ['uid'], …)source_mapping = { 'uid' : 'uid', 'entitlement' : 'entitlement',}
target = LdapConnector(keys = ['uid'], …)target_mapping = { 'uid' : 'uid', 'entitlement' : 'entitlement',}
actions = { 'found' : 'update', 'source_missing' : 'update'}attributes = ['entitlement']
merge(source, source_mapping, target, target_mapping, actions, attributes, merge_fn = my_merge)
def my_merge(source_objs, target_obj): entitlement = [] for entry in source_objs: entitlement = entitlement + entry.get('entitlement',[]) return {'entitlement' : entitlement}
42Manuel Haim - Hochschulrechenzentrum
In CALYPSO sieht das so aus:source = LdapConnector(keys = ['uid'], …)source_mapping = { 'uid' : 'uid', 'entitlement' : 'entitlement',}
target = LdapConnector(keys = ['uid'], …)target_mapping = { 'uid' : 'uid', 'entitlement' : 'entitlement',}
actions = { 'found' : 'update', 'source_missing' : 'update'}attributes = ['entitlement']
merge(source, source_mapping, target, target_mapping, actions, attributes, merge_fn = my_merge)
def my_merge(source_objs, target_obj): entitlement = [] for entry in source_objs: entitlement = entitlement + entry.get('entitlement',[]) return {'entitlement' : entitlement}
Wir wollen die Summe der Berechtigungen bilden(hier Attribut „entitlement“)
43Manuel Haim - Hochschulrechenzentrum
In CALYPSO sieht das so aus:source = LdapConnector(keys = ['uid'], …)source_mapping = { 'uid' : 'uid', 'entitlement' : 'entitlement',}
target = LdapConnector(keys = ['uid'], …)target_mapping = { 'uid' : 'uid', 'entitlement' : 'entitlement',}
actions = { 'found' : 'update', 'source_missing' : 'update'}attributes = ['entitlement']
merge(source, source_mapping, target, target_mapping, actions, attributes, merge_fn = my_merge)
def my_merge(source_objs, target_obj): entitlement = [] for entry in source_objs: entitlement = entitlement + entry.get('entitlement',[]) return {'entitlement' : entitlement}
Quell-Suchschlüssel undzweites Mapping erforderlich(für die Invers-Suche)
44Manuel Haim - Hochschulrechenzentrum
In CALYPSO sieht das so aus:source = LdapConnector(keys = ['uid'], …)source_mapping = { 'uid' : 'uid', 'entitlement' : 'entitlement',}
target = LdapConnector(keys = ['uid'], …)target_mapping = { 'uid' : 'uid', 'entitlement' : 'entitlement',}
actions = { 'found' : 'update', 'source_missing' : 'update'}attributes = ['entitlement']
merge(source, source_mapping, target, target_mapping, actions, attributes, merge_fn = my_merge)
def my_merge(source_objs, target_obj): entitlement = [] for entry in source_objs: entitlement = entitlement + entry.get('entitlement',[]) return {'entitlement' : entitlement}
Eigene Merge-Funktion
45Manuel Haim - Hochschulrechenzentrum
In CALYPSO sieht das so aus:source = LdapConnector(keys = ['uid'], …)source_mapping = { 'uid' : 'uid', 'entitlement' : 'entitlement',}
target = LdapConnector(keys = ['uid'], …)target_mapping = { 'uid' : 'uid', 'entitlement' : 'entitlement',}
actions = { 'found' : 'update', 'source_missing' : 'update'}attributes = ['entitlement']
merge(source, source_mapping, target, target_mapping, actions, attributes, merge_fn = my_merge)
def my_merge(source_objs, target_obj): entitlement = [] for entry in source_objs: entitlement = entitlement + entry.get('entitlement',[]) return {'entitlement' : entitlement}
Merge-Algorithmuswird gestartet
46Manuel Haim - Hochschulrechenzentrum
Bisherige Einsatzszenarien an der Uni Marburg
• Vorbereitung Forschungs-Informations-System (Converis)→ SAP-Export (Personen, Orgs, Person-zu-Org) nach LDAP importieren→ LDAP-Daten regelm. als CSV exportieren
• Einführung neue Dienstkopierer→ Excel-Tabellen (Person-zu-Kostenstelle) einmalig nach LDAP importieren→ LDAP-Zuordnung (Person-zu-Kostenstelle) regelm. als CSV exportieren→ Kopierberechtigung im LDAP-Account setzen/löschen
• Identity Management→ Personendaten aus Quellsystemen in LDAP-Teilbäume übertragen→ Personendaten aus LDAP-Teilbäumen mit LDAP-Person mergen→ Abgleich von LDAP-Person und LDAP-Account
47Manuel Haim - Hochschulrechenzentrum
Danke für Ihre Aufmerksamkeit!
CALYPSO bei Interesse herunterladen unter:
→ http://www.staff.uni-marburg.de/~haimm/
Noch Fragen?
→ Gern jetzt im Anschluss :-)
→ sonst per E-Mail: Manuel Haim, [email protected]