(nettipäiväkirja 06.11.2014) Olen työskennellyt viime aikoina aika paljon LDAPin kanssa (LDAP tietokantana), ja ajattelin jakaa vähän vihjeitä työkaluista. Ensinnäkin LDIF on kiva olemassa; SQL-tietokannoissa on usein harmittanut juuri se, ettei tiedolla ole vakioitua siirtoformaattia (tietenkin LDIF on yksi mahdollinen sellainen). CSV on ihan OK siirtoformaatti muuten, mutta sen verran standardoimaton, ettei voi esim. vain ottaa CSV-tiedostoa ja viedä sitä tietokantaan, vaan pitää tietää, mitä on tekemässä ja millainen taulu CSV-tietoja varten pitää perustaa.
Mutta asiaan. Ensinnäkin LDIF:ssä on muutamia ominaisuuksia, jotka hankaloittavat sen käyttöä. Ensinnäkin se voi olla melkein missä vain järjestyksessä ja toisekseen siinä voi olla kommentteja ja jatkettuja rivejä, ja myös kommenttirivit voivat olla jatkettuja(!). Useimpien raakatekstityökalujen käyttöä helpottaa, jos yhden olion kaikki tiedot ovat yhdellä rivillä. Tässä on kaksi shell-funktiota, ldif-linify ja ldif-normalise. ldif-linify siivoaa syötteensä ja muuttaa sen kappalepohjaisesta rivipohjaiseksi. ldif-normalise käyttää tätä tuottaakseen uudestaan siivottua, deterministisessä järjestyksessä olevaa LDIF:a (jota voi sitten vaikka vertailla diff:llä).
ldif-linify() { sed '$!{;/./{;H;d;};};$H;x;s/\n //g;s/ */ /g;s/\n#[^\n]*//g;s/\n/||/g' } ldif-normalise() { ldif-linify | grep '||dn::* ' | sort | sed 's/||/\n/g' | \ sed 's/^dn::* /00&/' | awk '/^$/{n++};{printf "%05d %s\n", n, $0}' | \ sort | cut -c7- | sed 's/^00\(dn::* \)/\1/' }
LDIF:ssä on luettavuuden kannalta ongelma, että erilaiset kentät voivat olla base64-koodattuja. Usein koodauksen pystyy avaamaan ilman, että LDIF varsinaisesti kärsii, mutta jos koodattu merkkijono sisältää esimerkiksi rivinvaihtoja tai huonossa paikassa olevia välilyöntejä, tulos ei välttämättä ole enää ehjää LDIFiä. Mutta jos LDIF on tarkoitettu vain ihmisten luettavaksi, voi käyttää tätä Perl-komentoa koodausten avaamiseksi:
ldif-decode() { perl -MMIME::Base64 -n -00 -e \ 's/\n //g;s/(?<=:: )(\S+)/"<<<".decode_base64($1).">>>"/eg;print' }
LDIF on aika runsassanainen formaatti. Jos haluaa lukea tiedot mieluummin CSV:nä ja tietää valmiiksi, mitkä kentät haluaa, voi käyttää tätä gawk-skriptiä. Varoitus: skripti ei piittaa siitä, että jokin kenttä voi olla multivalue, vaan ottaa raa'asti viimeisen arvon.
ldif2csv() { awk -F '::* ' 'BEGIN { fcount=split("'"$*"'", fields, " "); } NF==2 { obj[$1] = $2; next; } NF==0 && "dn" in obj { line=obj[fields[1]]; for(i = 2; i <= fcount; i++) line = line "|" obj[fields[i]]; print line; delete obj; next; } 1' }
Sitten on varsinaisia työvälineitä. OpenLDAP:n ldap-utils on tietenkin aika korvaamaton, sillä sillä pystyy tekemään kaiken, mikä olisi muuten hankalaa. ldapsearch on yleinen kyselytyökalu ja ldapmodifylla voi tehdä haluamansa muutokset. Mutta! Huomaa, että muutosten kuvaamiseen tarkoitettu LDIF on erilaista kuin sisältö-LDIF, eli ldapsearch tuottaa eri LDIFia kuin ldapmodify ottaa syötteekseen. Sen sijaan, jos haluaa vain lisätä entryjä, ldapadd ottaa syötteekseen samaa LDIF-formaattia kuin ldapsearch tuottaa. Muutenkin kannattaa muistaa nämä "helpommat" ldapmodify:n versiot, eritoten ldapdelete -r on kätevä (ja vaarallinen).
Yleensä, kun tekee LDIF:lla muutoksia, pitää tietää, mikä on lähtötilanne. Esimerkiksi oliota ei voi lisätä, jos se on jo olemassa (siis jos sen DN on jo jonkin muun olion DN). Samoin poisto tuottaa virheilmoituksen, jos poistettavaa oliota ei ole. ldapmodify:n valitsimet -c ja -S <lokitiedosto> ovat mielettömän käteviä tällöin.
Mutta yleisesti ottaen, jos sinulla on LDIF-dumppi ja haluat viedä sen hakemistoon, niin joko hakemisto pitää tyhjätä ensin ja viedä dumppi sinne vasta sitten, tai sitten asiaankuuluvat muutokset pitää syntetisoida vertaamalla nykytilannetta toivottuun. Skeemamuutoksille minulla on Makefile-automaatio, mutta tätä ei voi soveltaa sellaisenaan mihin tahansa tilanteeseen. Se olettaa, että haluttu skeema on tiedostossa master-schema.ldif ja tuottaa esim. tiedostosta myserver-schema.ldif tiedoston myserver-update.ldif, joka sisältää tarvitut komennot skeeman päivittämiseksi master-schema.ldif:n mukaiseksi:
%-schema-ordered.ldif: %-schema.ldif ldif-normalise < $< > $@ %-oid-list.txt: %-schema-ordered.ldif cut -d' ' -f3 -s $< >$@ %-name-list.txt: %-schema-ordered.ldif grep -o "NAME '[^']*'" $< | cut -d"'" -f2 >$@ %-schema-selected.ldif: %-schema-ordered.ldif master-oid-list.txt master-name-list.txt egrep "^dn:|NAME '(`cat master-name-list.txt | tr \\\\012 '|'`)'|\\<(`cat master-oid-list.txt | tr \\\\012 '|'`)\\>" $< >$@ %-updates.txt: %-schema-selected.ldif master-schema-ordered.ldif ( sed 's/^/d /' $<; sed 's/^/a /' master-schema-ordered.ldif ) >$@ %-updates-combined.txt: %-updates.txt combine-updates.awk sort -f -k6,6 -k4,4 -k1,1 $< | awk -f combine-updates.awk | \ sed 's/^d object/d 1object/' | sort | sed 's/^d 1object/d object/' >$@ %-update.ldif: %-updates-combined.txt sed 's/||a \([^:]*\)/\n-\nadd: \1\n\1/g;\ s/||d \([^:]*\)/\n-\ndelete: \1\n\1/g;\ s/^\n-/\ndn: cn=schema\nchangetype: modify/' $< >$@
combine-updates.awk näyttää tältä:
#!/bin/awk -f END { if (oldrecord) print oldrecord; } ($4 == oldoid) || ($6 == oldname) { oldrecord = "c " $0 "||" oldrecord; next; } oldrecord { print oldrecord; } { oldrecord = $0; oldoid = $4; oldname = $6; }
Hakemistojen sisällön muokkaamiseen on kaikenlaisia työkaluja. Niille, jotka tykkäävät shellistä, shelldap on todennäköisesti mieleen. Se on komentoriviohjelma, jossa on unixmaiset komennot (kuten muokkaa = vi, näytä = cat, luo = touch jne). Shelldapilla pystyy myös tekemään joitain käsin vähän työläitä asioita kuten vaihtamaan käyttäjäolion salasanaa. Tähän on työkalu myös ldaptor-utilsissa, jota en ole testannut, mutta vaikuttaa hyvältä: