47
Manuel Haim - Hochschulrechenzentrum CALYPSO – ein Python-Skript zum generischen Datenabgleich Manuel Haim, HRZ Uni Marburg ZKI-Arbeitskreis Verzeichnisdienste 12.08.2016 in Ulm

CALYPSO – ein Python-Skript zum generischen … · Manuel Haim - Hochschulrechenzentrum 10 Konnektoren sind Klassen mit Funktionen ... → Excel-Tabellen (Person-zu-Kostenstelle)

  • 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!

4Manuel Haim - Hochschulrechenzentrum

Ein Python-Skript zum generischen Datenabgleich:

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

7Manuel Haim - Hochschulrechenzentrum

Objekte

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)

9Manuel Haim - Hochschulrechenzentrum

Konnektoren

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“)

12Manuel Haim - Hochschulrechenzentrum

Sync-Algorithmus

13Manuel Haim - Hochschulrechenzentrum

Mögliche Situationen beim Datenabgleich

Quelle Ziel

14Manuel Haim - Hochschulrechenzentrum

Mögliche Situationen beim Datenabgleich

Quelle Ziel

„absent“

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.

33Manuel Haim - Hochschulrechenzentrum

Merge-Algorithmus

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]