DIPLOMAMUNKA
KONFIGURÁCIÓ-MENEDZSMENT VERZIÓKÖVETETT OBJEKTUMOKKAL
Budapesti Műszaki és Gazdaságtudományi Egyetem Irányítástechnika és Informatika Tanszék
Készítette: Fülöp Balázs EIWMWH Konzulens: Dr. Szeberényi Imre
Budapest, 2009
DIPLOMATERV FELADAT Fülöp Balázs szigorló műszaki informatikus hallgató részére Konfiguráció-menedzsment verziókövetett objektumokkal
Összetett, gyakran változó rendszerek konfiguráció-menedzsmentje nem egyszerű feladat. Kis- és nagyvállalatokon belül egyaránt fontos az informatikai szolgáltatásokat nyújtó infrastruktúra konfigurációjának rugalmas, naprakész nyilvántartása, egyszerű módosítása. A diplomaterv feladat során a cél egy rugalmas konfiguráció-menedzsment környezet fő elemeinek objektum orientált megvalósítása, amely verziókövetett módon nyújtja az objektum orientált rendszerek előnyeit. Feladatok: 1. Elemezze a konfiguráció-menedzsmenttel kapcsolatos fő feladatokat egy feltételezett cég belső informatikai infrastruktúra szolgáltatásának szempontjából. 2. Tervezzen meg egy olyan keretrendszert, mely alapját képezheti a konfigurációmenedzsment feladatok verziókövetett megoldásának 3. Válasszon az implementáláshoz megfelelő, lehetőleg gyors fejlesztéshez jól használható nyelvet és implementálja a megtervezett keretrendszert. 4. Demonstrálja az elkészített rendszer működését, és készítse a fejlesztői dokumentációját. A feladat beadási határideje: 2009. május 15. Tanszéki konzulens: Dr. Szeberényi Imre Záróvizsga tárgyak:
Rendszerintegráció (BMEVIFO4367) Operációs rendszerek (BMEVIM3231) Adatbázisok (BMEVIIA3232)
Budapest, 2009. február 20. Dr. Szirmay-Kalos László egyetemi tanár TANSZÉKVEZETŐ
Budapesti Műszaki és Gazdaságtudományi Egyetem Villamosmérnöki és Informatikai Kar Irányítástechnika és Informatika Tanszék
1117 Budapest, Magyar tudósok körútja 2. I. ép. 317. Postacím: 1521 Budapest, Pf.: 91. Tel: 463-2699, Fax: 463-2204, http://www.iit.bme.hu
Konfiguráció-menedzsment verziókövetett objektumokkal
6
Nyilatkozat Alulírott Fülöp Balázs, a Budapesti Műszaki és Gazdaságtudományi Egyetem hallgatója kijelentem, hogy jelen diplomatervet meg nem engedett segítség nélkül, saját magam készítettem, és a diplomatervben csak a megadott forrásokat használtam fel. Minden olyan részt, amelyet szó szerint, vagy azonos értelemben, de átfogalmazva más forrásból átvettem, egyértelműen, a forrás megadásával megjelöltem.
Budapest, 2009. május 14.
...................................... Fülöp Balázs
Konfiguráció-menedzsment verziókövetett objektumokkal
8
Tartalomjegyzék I. Előszó....................................................................................................................................... .....9 II. Abstract........................................................................................................................... ...........10 III. Konfiguráció-menedzsment......................................................................................... ............11 1. A konfiguráció-menedzsment célja.............................................................................. .........11 2. IBM Tivoli platform.................................................................................................... ..........13 3. BMC.................................................................................................................. ....................14 4. Modellezési kihívások........................................................................................................ ...15 5. XML alapú modellezés.................................................................................. .......................16 6. LDAP alapú modellezés.................................................................................................. ......18 7. Objektum-relációs leképezés.......................................................................... ......................20 8. Gyenge sémájú relációs modellezés................................................................. ....................21 9. CM modellezési eljárások összehasonlítása.........................................................................23 IV. Adatmodell gyenge sémájú modellezéshez.............................................................................24 1. Az adatmodell követelményei....................................................................................... ........24 2. Entitás-relációk tervezése.......................................................................... ...........................25 3. Relációs séma tervezése............................................................................................... .........28 4. ActLog tábla........................................................................................................ ..................30 5. ObjTree tábla............................................................................................................ .............30 6. ObjRev tábla..................................................................................................................... .....31 7. ObjType tábla..................................................................................................... ...................32 8. ObjAttr tábla..................................................................................................................... .....32 9. AttrKey tábla.................................................................................................... .....................33 10. AttrVal tábla....................................................................................................................... ..34 V. A Perl nyelv........................................................................................................................... .....35 1. A nyelv eredete........................................................................................................ ..............35 2. A Perl adattípusai................................................................................................................ ...36 3. A Perl és az OOP................................................................................................... ................37 4. Beépített típusok egyedi implementációja..................................................................... .......40 VI. A Calf keretrendszer................................................................................................................. 45 1. A keretrendszer célja......................................................................................... ....................45 2. A keretrendszer áttekintése.................................................................................................... 46 3. Calf csomag.................................................................................................................. .........48 4. Calf::Tie csomagok......................................................................................... ......................48 5. Calf::Object csomagok.................................................................................................... ......49 6. Calf::DB csomagok.................................................................................................... ...........50 7. Calf::Data csomag..................................................................................................... ............51 8. A keretrendszer használatának bemutatása................................................................. ..........51
Konfiguráció-menedzsment verziókövetett objektumokkal
9
I. Előszó Jelen dokumentum a 2008/09. tanév tavaszi félévében, a Budapesti Műszaki és Gazdaságtudományi Egyetem műszaki informatikus szakán írt diplomamunkámat tartalmazza. Önállóan választott témám a Perl 5 programozási környezet objektum-perzisztencia képességeinek feltérképezése és továbbfejlesztése, valamint ezek egyedi konfigurációmenedzsment rendszerekben való alkalmazhatóságának vizsgálata. A téma és a kitűzött feladatok hálás kihívást jelentettek abból a szempontból, hogy egy olyan – jellemzően nagyvállalati környezetben felmerülő – igény problémáit érintik, melyekre magától értetődően jó gyakorlat, tipikus és szélesebb körben elismert megoldás egyelőre nem létezik. Ezért a munka nagy része izgalmas kísérletezésből és kreatív fejlesztésből állt. Másrészről a témaválasztás kevéssé mondható szerencsésnek, mert nem egyértelmű meghúzni azt a határvonalat, ahol a szűkös időkeret szorításában a kutatás-fejlesztés szakasza le kell, hogy záruljon. Mivel a diplomamunka gerincét adó dolgozatnak egy ponton össze kell foglalnia az eredményeket, a szerteágazó problémakör egyes elemei természetszerűleg több hangsúlyt kaptak, mint mások. Végeredményben jelen diplomamunka egyik fő eredménye egy Perl5-höz készült, széles körű felhasználásra alkalmas, verziókövető képességekkel bíró perzisztencia-réteg. E sokrétű feladat meghatározó elemeinek kiemelésében rendkívüli segítséget nyújtott számomra Dr. Szeberényi Imre, akinek támogatásáért ezúton szeretnék köszönetet mondani. Szeretném továbbá megköszönni mindazoknak az együttműködését, akik elolvasták a dolgozatomat, és kritikáikkal, építő megjegyzéseikkel segítették a munkámat: Fülöp Edinának, Hámor Tamásnak, Kornai Tamásnak, Köllő Tamásnak és Székely Gergőnek.
Budapest, 2009. május 14.
...................................... Fülöp Balázs
Konfiguráció-menedzsment verziókövetett objektumokkal
10
II. Abstract This document contains my final thesis for the Faculty of IT Engineering at the Budapest University of Technology and Economics, written in the spring semester of 2008/09. The main topic of the thesis that has been chosen independently is the examination and enhancement of the object persistence capacities of the Perl5 programming environment. The question of the strengths and weaknesses of deploying a custom configuration management system built on top of that has been addressed as well. The topic and the actual tasks imposed a number of exciting challenges concerning enterpriselevel problems, for which apparent best practices, or widely deployed universal solutions are not available. Because of that a great amount of efforts has been spent on experimental development. Defining the actual point where the phase of research and development needs to be closed due to time limitation was a challenge by itself. Since the documentation part of the thesis needs to summarize the results of the work in the end of the day, certain elements of the diversified problem scope have gotten a greater emphasis than others. One of the main accomplishments of the thesis is a fully featured persistence layer for Perl5 with versioning capabilities, intended for general use. I would like to thank Imre Szeberényi, Dr. for his tiredless efforts to help in finding the key points to focus on. I would also like to say thank you to all of those who have read an earlier revision of my thesis and provided feedback: Edina Fülöp, Tamás Hámor, Tamás Kornai, Tamás Köllő and Gergő Székely.
Budapest, 14th May 2009
...................................... Fülöp Balázs
Konfiguráció-menedzsment verziókövetett objektumokkal
11
III. Konfiguráció-menedzsment Mottó: Nehéz úgy érvényes általánosításokat kijelenteni, hogy mondunk is valamit. Ez nincs másként az előző mondat esetében sem.
1.
A konfiguráció-menedzsment célja
Általános értelemben a konfiguráció-menedzsment (a továbbiakban: CM) az informatikában inkább egy koncepció, mint egy valódi szabvány. Pontosabban fogalmazva, a kiadott szabványok nagy, és a referencia implementációk kis száma miatt igen nehéz egy olyan definíciót adni rá, amely minden szervezet CM rendszerére illeszkedne. A Wikipedia Configuration management[1] szócikke az alábbi szabványok listáját tartalmazza: • ANSI/EIA-649-1998 National Consensus Standard for Configuration Management • EIA-649-A 2004 National Consensus Standard for Configuration Management • ISO 10007:2003 Quality management systems - Guidelines for configuration management • Federal Standard 1037C • GEIA Standard 836-2002 Configuration Management Data Exchange and Interoperability • IEEE Std. 828-1998 IEEE Standard for Software Configuration Management Plans • MIL-STD-973 Configuration Management (2000. szeptember 20-án visszavonták) • STANAG 4159 NATO Material Configuration Management Policy and Procedures for Multinational Joint Projects • STANAG 4427 Introduction of Allied Configuration Management Publications (ACMPs) Közös vonásuk, hogy egy informatikai rendszer komponenseinek konfigurációit állapotként kezelik és elsődleges célként a rendszer konzisztens állapotból konzisztens állapotba történő váltását tűzik ki az elérhető legkevesebb tranzienssel. Ez a meghatározó tulajdonság viszont még nem tekinthető definíciónak. Példaként tekintsük egy UNIX rendszer klasszikus felhasználói adatbázisát. Ez a legtöbb UNIX implementációban két fájlban testesül meg: a /etc/passwd tartalmazza a felhasználói fiókokat némi metainformációval, a /etc/shadow pedig a jelszavak hashelt változatát. Mindkét állomány
sima
szöveges
és
soronként
egy
rekordot
tartalmaz.
Csak
fokozott
elővigyázatossággal lehet őket szerkeszteni, mivel egyetlen hibás sor is megjósolhatatlan
Konfiguráció-menedzsment verziókövetett objektumokkal
12
működést eredményezhet, továbbá a két fájl egy-egy sora együttesen ír le egy felhasználói fiókot, ezért módosítások esetén a konzisztencia fenntartása nem triviális. Emiatt minden modern UNIX tartalmaz olyan segédprogramokat, melyekkel a felhasználói adatbázis közvetlen szerkesztés nélkül módosítható. Ilyen a szinte mindenhol elérhető useradd család. Ezek a parancssoros programok garantálják, hogy az adatbázis felhasználók által érzékelhető tranziensek nélkül módosítható. Ha a CM rendszerek fenti tulajdonságát tekintenénk definíciónak, akkor ez alapján a useradd család egy CM megoldás lenne. A gyakorlatban mégsem tekintik annak, mert nem skálázható egy számítógépnél többre, és hiányzik belőle sok olyan fejlett szolgáltatás, ami egy menedzsment megoldás igazi erejét adja. Az esetek többségében egy CM rendszernek része egy általános modellező környezet. Ez egy absztrakciós szintet ad a rendszer elképzelt modellje és a valódi konfiguráció között, ami lehetővé teszi az adminisztrátor számára, hogy modell szinten meghatározott összefüggések alapján dolgozzon. Így a tényleges konfigurációt ez a köztes réteg szolgáltatja, nem pedig valamilyen manuális beállítás. A modellezés jellemzően valamilyen speciális deklaratív nyelvvel történik. Visszatérve a UNIX felhasználói adatbázisának problémájára: egy felhasználó létrehozása a useradd
segítségévél még megoldható magas szinten, viszont egy e-mail alias felvétele
hagyományosan már csak kézzel, a /etc/aliases fájl szerkesztésével valósítható meg. Ha ezek után egy felhasználói fiókhoz tartozó bejelentkezési név megváltozik, azt két helyen kell módosítani: egyrészt a usermod használatával az adatbázisban, másrészt az előbb említett állományban. A CM például az ilyen jellegű helyzetekben nyújt informatikai támogatást, az emberi hibák és a tranziens jelenségek kiküszöbölésének érdekében. Egy CM rendszertől általában elvárhatóak még az alábbiak: • változáskövetés A rendszer lehetőséget biztosít legalább a változások lekérdezésére, azaz az entitások élettörténetének megtekintésére. Fejlettebb rendszerek megvalósítják a rollbacket is, vagyis adott egy korábbi, helyesnek ítélt konfigurációra történő visszaállás lehetősége. • öndokumentáló modell A konfigurációk absztrakt modellje felhasználóbarát leírását adja az elérhető állapotoknak.
Konfiguráció-menedzsment verziókövetett objektumokkal
13
• biztonság A rendszerben tárolt konfigurációhoz a hozzáférés finoman szabályozott. Ez tipikusan Access Control List (ACL) segítségévél történik. • validálás A rendszer garantálja, hogy a modellbe csak érvényes konfiguráció vihető fel. • verifikáció A rendszer ellenőrzi, hogy a valódi konfiguráció a modellnek megfelelő-e. • automatizmus A rendszer kevés ponton igényel felhasználói beavatkozást és legfeljebb annyira időigényes a használata, mintha minden beállítás kézzel történne. • csoportmunka A rendszer támogatja a csoportos adminisztrációt és felkészítették a konkurrens módosítások kezelésére. A lista közel sem teljes – egyes CM rendszerek többet, mások kevesebbet valósítanak meg a fentiekből. A legnagyobb nehézséget ilyen rendszerek vizsgálatakor mégis az jelenti, hogy a szempontok helyenként távolról sem objektívek. Egyetemes megoldás erre a problémakörre egyelőre nem létezik, és az elérhető rendszerek versenyeztetése csak élő, gyakorlati példához viszonyítva lehet releváns. Bár ez jelen dolgozat tárgyán túlmutat, lássuk milyen szolgáltatásokat ígér két nagyobb kereskedelmi CM rendszer.
2.
IBM Tivoli platform
Az IBM Tivoli megoldása egy olyan integrációs platform, amely hardver- és szoftverkonfigurációk, folyamatok és emberi tevékenységek menedzsmentjéhez nyújt nagyvállalati szintű infrastruktúrát. A termék komponenseinek megcélzott előnyei között szerepel az egységesített és átlátható adatmodell, illetve az erre építő automatizmusok – beleértve a validálást és a verifikációt – kialakításának támogatása. A Tivoli platform egyik sarokkövét képező Change and Configuration Management Database (CCMDB) az alábbi szolgáltatásokat biztosítja[2]: • Elosztott konfigurációs adatbázis Az alapértelmezésben szállított, DB2 technológiára építő adatbázisháttér mellett lehetőség van egyedi konfigurációs adatbázis használatára.
Konfiguráció-menedzsment verziókövetett objektumokkal
14
• Kiterjeszthető adatmodell A CCMDB képességei kiterjeszthetőek egyedi CI (configuration item), illetve attribútum elemekkel. • Programozható felület Egy jól definiált API-n keresztül lekérdezhető és menedzselhető a konfiguráció. Erre építve egyedi igényeket kielégítő tooling is létrehozható. • Intelligens jelentések A megoldás teljes mértékben testre szabható és áttekinthető jelentéskészítési funkciókkal bír. • Konfigurálható munkafolyamatok Mélyebb szintű fejlesztési ismeretek nélkül is, fogd-és-vidd jellegű felületeken gyorsan leírhatóak vállalati munkafolyamatok. • Audit napló A konfigurációk
korábbi
változatai
összehasonlíthatóak, a
CI
élettörténetek
megtekinthetőek. • Integrációs pontok külső megoldásokhoz A rendszer mind az adat, mind a funkcionális szinten könnyedén integrálható külső szállító termékeihez.
3.
BMC
A BMC Configuration Manager integrált nagyvállalati megoldás az ismétlődő rendszergazdai feladatok automatizálására. Különleges szolgáltatásai az alábbiak[3]: • Házirend-alapú menedzsment Az aktuális és a modellezett konfiguráció közötti eltérések folyamatos ellenőrzésével a verifikációs folyamatok önműködőek. • Önműködő operációs rendszer migráció Automatikus, best-practice alapú frissítés és migrációs folyamatok jellemzik a rendszert. • Szoftver-használati jelentések A vállalatban alkalmazott szoftverekről jelentések készülnek a licenszek megfelelő kihasználásának felmérése érdekében.
Konfiguráció-menedzsment verziókövetett objektumokkal
15
• Patch-menedzsment megoldások A rendszer megoldást nyújt a hibajavításokat, frissítéseket tartalmazó patchek automatikus csomagolásához. • Egységesített adminisztráció A termékfüggetlen, egységesített felületű telepítési és adminisztrációs segédprogramok elfedik a különböző külső szállítók termékeinek specialitásait.
4.
Modellezési kihívások
A fentiek alapján érezhető, hogy az adatmodell a CM esetén kulcsfontosságú. Egy túlzottan specifikus modell behatárolja a CM alkalmazhatóságának körét, ugyanakkor elengedhetetlen, hogy megkötéseket tartalmazzon, ellenkező esetben a validáció egyáltalán nem, vagy csak nagyon körülményesen oldható meg. Bizonyos modellezési eljárások természetükből adódóan nyújtanak megoldást az előzőekben ismertetett szempontokra, míg másokkal egyes pontok eleve megoldhatatlanok. A kályhától indulva vizsgáljunk meg négyet egy CM rendszer adatmodelljének lehetséges backendjei közül: • XML alapú: a modell entitásai XML dokumentum formátumban kerülnek tárolásra. • LDAP: a modell entitásai LDAP objektumok. • RDBMS objektum-relációs leképezéssel: a modell entitásai egy OOP környezet objektumai, melyeket leképezzük egy rögzített relációs adatbázis sémába. • Gyenge sémájú RDBMS: A modell entitásai egy OOP környezet objektumai, melyek a relációs adatbázis sémájának módosítása nélkül szabadon mutálhatók. A következőkben az alábbi kérdésekre keresünk választ a vázolt backend megoldások összehasonlítási alapjának meghatározása érdekében: • Milyen formátumban kerülnek tárolásra az entitások? Hogyan azonosítja a backend az entitást? Hogyan tárolja az attribútumokat? Mennyire hatékony az adatszervezési eljárás? Van-e lehetőség ezen a szinten típusellenőrzésre, illetve ellenőrzött referenciák létrehozására? • Milyen kommunikációs protokollon érhetőek el az adatok? A használt protokoll sima szöveges vagy bináris, illetve mennyire mondható ipari szabványnak? Eleve adott-e a titkosítás lehetősége, vagy ez csak egyedileg oldható meg?
Konfiguráció-menedzsment verziókövetett objektumokkal
16
A konfiguráció alkalmazási oldalról közvetlenül felhasználható, vagy generálni kell? • Mennyire könnyű a séma kiterjesztése? Mit szükséges megváltoztatni annak érdekében, hogy egy entitás új attribútummal bővüljön? Megoldható-e ez a szolgáltatás megállítása nélkül? • A backend az API-n túl milyen felületeken érhető el? Az adminisztrátornak milyen lehetőségei vannak az adatok közvetlen elérésére? Ezek a módszerek mennyire biztonságosak az adatintegritás szempontjából? • Hogyan oldható meg a verziókövetés? Mennyire körülményes a változások folyamatos követése? Korábbi verzióra vissza lehete állni szolgáltatás-leállítás nélkül? • Hogyan valósítható meg az adatvédelem? Van-e beépített megoldás az adatokhoz való hozzáférés szabályozására? Ha nincs, mennyire körülményes megvalósítani, és milyen fokú biztonság érhető el vele? • Milyen a csoportmunka támogatás? Van-e lehetőség az entitások párhuzamos szerkesztésére? Mi történik konkurrens hozzáférés esetén? A megjósolható működéshez milyen zárolásokat használ a rendszer? Van-e tranzakciókezelés?
5.
XML alapú modellezés
Az első, talán legkézenfekvőbb megoldás az XML[4] (Extensible Markup Language) alapú modellezés. Tekintve, hogy a végcél tetszőleges konfigurációk előállítása, az XML egy természetes általánosítása a problémának. Ugyanakkor, mivel az XML önmagában pusztán egy fájlformátum, a hálózati elérés, a verziókövetés, és egy sor további fejlett szolgáltatás csak egy megfelelő kiszolgáló mellett lehetséges. A továbbiakban feltesszük, hogy ez adott, lévén, hogy egy “XML szerver” egy közönséges fájlkiszolgálóval megvalósítható. Az entitások tárolása ebben az esetben egy vagy több XML dokumentum formájában történik. Ha minden entitás külön dokumentum, az entitások azonosíthatóak egyszerűen a dokumentum mint erőforrás egyértelmű meghatározásával. Ellenkező esetben az entitást a tartalmazó dokumentum megjelölése mellett az azon belüli helye azonosítja, melyhez használható az XPath szabvány. Az attribútumok tárolása az XML strukturált felépítése miatt nem bonyolult, továbbá CDATA
blokkok segítségévél és megfelelően megválasztott kódolás mellett elvileg tetszőleges
értéket vehetnek fel.
Konfiguráció-menedzsment verziókövetett objektumokkal
17
Az adatszervezés hatékonysága megkérdőjelezhető. Legrosszabb esetben minden betöltött entitás külön fájlból származik, ami nagy bonyolultságú rendszereknél komoly teljesítménybeli problémákhoz vezethet. A megoldás ilyen értelemben vett ára elsősorban a használt fájlrendszertől, a fájlszerver gyorsaságától, az egyidejűleg használt objektumok számától és a párhuzamos elérés esetén fellépő zárolások számátólfügg. Típusellenőrzés ebben az esetben backend szinten akkor van, ha az XML dokumentumhoz tartozik előre definiált DTD (Document Type Definition). Ez az XML feldolgozást, ha lehet, még inkább lassítja. További probléma, hogy a DTD módosítása élő rendszerben előre nehezen látható következményekkel jár, ugyanis az ellenőrzés csak a dokumentum betöltésekor történik meg. Így elvileg elképzelhető, hogy a séma módosítása meglévő adatok érvénytelenítésével jár, és ami még rosszabb, ez csak az adatok későbbi felhasználásakor derül ki. Az XML szabvány lehetőséget nyújt referenciák elhelyezésére a dokumentumon belül, viszont ezeknek a feloldása az XML parser felelőssége, és a lehetőség valójában C-szerű terminológiával élve, inkább a makrókra hasonlít. Dokumentumokon átívelő referenciák használatára nincs lehetőség, így általánosságban erre a kérdésre csak alkalmazásszintű válasz adható. A kommunikációs protokoll a használt fájlszervertől függ. Szolgáltatásokban gazdag megoldás érhető el egy alkalmasan megválasztott WebDAV kiszolgálóval. A DAV (Distributed Authoring and Versioning) az ipari szabványnak tekinthető, sima szöveges HTTP protokoll kiterjesztett utasításkészletű változata, amely gond nélkül használható SSL-lel titkosított csatornán is. A konfigurálandó alkalmazások sajnos a legritkább esetben támogatják a beállítások WebDAV szerverről történő letöltését. Ez igaz a többi klasszikus fájlmegosztó szolgáltatásra is, ezért az XML alapú modellezés általános esetben megköveteli a konfiguráció generálását és offline használatát. Az XML létrehozásakor tervezési döntés volt a sima szöveges formátum, így a dokumentumok akár tetszőleges szövegszerkesztővel vagy specifikus segédprogrammal megtekinthetők és szerkeszthetők. Azonban a dokumentumok felépítése elsősorban a CM rendszer igényeit szolgálja, és ebből adódóan a CM rendszer mélyebb ismerete nélkül az XML dokumentumok közvetlen szerkesztése nem csak nehézkes, de adatintegritási szempontból veszélyes művelet is lehet. A verziókövetés lehetősége és az ehhez kapcsolódó szolgáltatások szintén szerverfüggők. A fájlszerver használhat verziókövető fájlrendszert, ennek szolgáltatásai viszont alkalmazási
Konfiguráció-menedzsment verziókövetett objektumokkal
18
oldalról csak nehezen és az esetek többségében komoly biztonsági problémákat felvetve vehetők igénybe. Például a jelenleg elérhető implementációkkal WebDAV használata mellett sem lehet a protokoll verziókövető funkcióit kihasználni. Az, hogy a szerver mögött egy verziókövető motor gondoskodik a változások követéséről, pusztán a szerveren adminisztratív privilégiumokkal rendelkező felhasználók életét segíti, a korábbi verziók megtekintése és visszaállítása csak számukra elérhető. Az
adatok
megvalósítható.
védelme Szervertől
fájlrendszerszintű függően
szóba
jogosultságkezeléssel, jöhet
a
klasszikus
nagy
biztonsággal
UNIX-os
hármas
jogosultságrendszer vagy a POSIX ACL-ek is. A csoportmunka támogatás a választott fájlszerver lehetőségeiből következik. Ha a szerver támogatja a fájlzárolást, a konkurrens hozzáférés megvalósítható, viszont több állomány kezelése mellett ez könnyen dead-lock-hoz vezethet. Ami leginkább megkérdőjelezi a többfelhasználós üzemmódot, az a tranzakciók teljes hiánya, pontosabban, hogy azok kezelése az alkalmazás felelősségi körébe tartozik.
6.
LDAP alapú modellezés
Az LDAP[5] (Lightweight Directory Access Protocol) a címtárszolgáltást biztosító protokollok legnépszerűbb szabványa. Sokkal többet nyújt a hagyományos telefonkönyvszerű szolgáltatásoknál, melyet mi sem bizonyít jobban, mint hogy a Microsoft Windows Serverek Active Directory[6] nevű megoldása LDAP alapú. Az említetten kívül minden nagyobb informatikai szállító rendelkezik saját LDAP implementációval, a Sun Microsystems-től az Oracle-ig. Az LDAP adatbázis fastruktúrában tárolt objektumok halmaza. Fontos hangsúlyozni, hogy a legtöbb LDAP implementáció nem alkalmazásszerver, és az objektumokhoz egyéni műveletek adatbázisszinten nem társíthatóak. Az objektumok egy előre rögzített sémának megfelelő attribútumokat tartalmazó entitások. Azonosítójuk az ún. DN (distinguished name), amely a fa gyökeréből kiindulva az objektumhoz vezető egyértelmű elérési út. Az LDAP szervereket tipikusan keresésre és olvasásra optimalizálják, egyéb műveletekre jellemzően rosszabbul teljesítenek, mint a relációs adatbázisok. Ez konfiguráció tárolása esetén nem feltétlenül jelent gondot, mivel a problémakör természeténél fogva a műveletek döntő többsége olvasás. A legtöbb LDAP szerver legalább read-only replikák felállításának lehetőségével erősíti a skálázhatóságot.
Konfiguráció-menedzsment verziókövetett objektumokkal
19
A típusellenőrzés előre rögzített sémával adatbázisszinten megoldható. A sémában értelmezett az öröklődés, aminek köszönhetően átláthatóan leírható egy objektum attribútumainak halmaza. Az attribútumok lehetnek többértékűek, és tárolhatnak bináris értéket is. Az LDAP fa egyes elemei hivatkozhatnak más objektumokra. Nem minden LDAP szerver támogatja a séma dinamikus frissítését. Az LDAP egy széles körben támogatott bináris protokoll, melynek létezik SSL-el védett változata (LDAPS). Nagyszámú programnyelvhez elérhető megbízható, kliensoldali API, ezért a legtöbb nyílt forrású szerveralkalmazás támogatja a konfiguráció LDAP szerverről történő, dinamikus lekérdezését. Jó példa erre az Apache webszerver, a Postfix SMTP szerver vagy a Bind9 DNS kiszolgáló. Számos jól használható LDAP kliens létezik, amik közül vannak, melyek webes felületet is adnak egy LDAP adatbázis közvetlen eléréséhez. Ezekkel az adatbázis kényelmesen és adatintegritási szempontból biztonságosan szerkeszthető. Verziókövetésre egyetlen nagyobb LDAP szerver sem nyújt támogatást. A változások lekérdezése és visszaállítása integrált módon nem megvalósítható. Mivel az LDAP szabványban definált LDIF (LDAP Interchange Format) sima szöveges dumpját képezi az adatbázisnak, az erről készült rendszeres pillanatképekkel követhetőek a verziók, ez viszont csak a probléma megkerülése; a változások rögzítése így nem folyamatos, a szerver adminisztrátorának kézi beavatkozása szükséges, és a visszaállítás szolgáltatáskimaradással jár. Az LDAP szerverek jellemzően egy nagyon fejlett biztonsági modellt valósítanak meg. Akár attribútumszinten is korlátozható a hozzáférés az objektumokhoz. Többek közt ezért is népszerű az LDAP a központi felhasználó-menedzsment megoldásokban, ahol a felhasználói fiókok LDAP objektumokként tárolódnak, és azok bizonyos attribútumai akár a felhasználó által is szerkeszthetők (pl. a jelszó), mások pedig akár rejtettek is lehetnek megfelelő privilégiumok nélkül. A többfelhasználós üzemmód
korlátokkal
támogatott. Az
LDAP nem
tartalmaz
tranzakciókezelő utasításokat, így az adatbázison végzett műveletek egyik implementációban sem izolálhatóak. Ez komoly gondot jelenthet a konkurens hozzáférések kezelésében, ha ugyanazon logikai művelet több objektum módosításával jár.
Konfiguráció-menedzsment verziókövetett objektumokkal
7.
20
Objektum-relációs leképezés
Ennek a modellezési eljárásnak a lényege, hogy a CM rendszer objektumait még tervezési fázisban leképezzük egy relációs adatbázisháttérre. A leképezés lehet dinamikus olyan értelemben, hogy az objektumok egyfajta leírásából automatikusan generálódik mind a relációs séma, mind az azt használó programkódnak egy része, végeredményben viszont a séma az adatbázisban rögzített lesz és nem frissíthető a kód módosítása nélkül. Az objektumok azonosításának módszere a leképezést végző szoftver megvalósításától függ. A legtöbb esetben az azonosítót természetes módon az objektum osztályát jelképező tábla elsődleges kulcsa adja. Az attribútumok tipikusan az ezen kulccsal jelölt rekord további mezői. Többértékű attribútumok implementációja külső táblában történő tárolással lehetséges. A típusok ez esetben szigorú SQL típusok, melyek adatbázisszinten ellenőrzöttek. A referenciák idegen kulcsként jelentkeznek az adatmodellben, melyek integritásáról szintén az adatbáziskezelő gondoskodik. A relációs adatbáziskezelők az előző két megoldással szemben mind az olvasásra, mind az írásra jól optimalizáltak, ezért egy gondosan megtervezett objektummodellt feltételezve az optimálist megközelítő teljesítmény érhető el. A legtöbb SQL szerver továbbá beépített megoldást nyújt clusterek kialakítására, és így a skálázhatóság csak milliós nagyságrendű objektumszám mellett jelent sématervezési kihívást. A relációs adatbáziskezelők egytől-egyig saját, jellemzően bináris protokollon érhetőek el, amely SSL-lel tehető biztonságossá. Bár ezek mind különbözőek, alkalmazási oldalról minden programozási nyelv alatt elérhető valamilyen szabványos adatelérési könyvtár – C/C++ alatt az ODBC, Java alatt a JDBC, Perl alatt a DBI – aminek köszönhetően a különböző adatbáziskezelők azonos API-n keresztül használhatóak. Ezért sok nyílt forráskódú szerveralkalmazás (az LDAP mellett) relációs adatbáziskezelőből történő dinamikus konfigurálást is támogat. A séma kiterjesztése, mint az a korábbiakban említésre került, nem lehetséges a kód és az adatbázis együttes módosítása nélkül. Ahhoz, hogy ez éles rendszeren leállítás nélkül végbemenjen, gondosan tervezett migrálás szükséges. Egy új attribútum felvétele tehát nem kivitelezhetetlen, de nem is tekinthető mindennapi rutinfeladatnak. Az adatbázis közvetlen szerkesztésére a legtöbb RDBMS egy SQL konzolt nyújt. Ezzel mind a séma, mind az adatok szabadon lekérdezhetőek és szerkeszthetőek. A CM rendszer alapos
Konfiguráció-menedzsment verziókövetett objektumokkal
21
ismerete szükséges ahhoz, hogy ez ne vezessen adatintegritási problémákhoz. A verziókövetésre az adatbázisszerverek nem nyújtanak támogatást, mivel ez nem képezi egyik SQL szabvány részét sem. Így a változatok követése vagy része az objektummodellnek, és ebből adódóan az alkalmazás felelőssége a verziókezelés, vagy az LDAP-ról elmondottak érvényesek ez esetben is. Azaz, az adatbázisról készülhet egy sima szöveges SQL nyelvű dump, amelynek manuális verziókövetését végezheti az adminisztrátor. Az adatvédelem a legtöbb SQL szerverben tábla szintű jogosultságkezeléssel valósítható meg. Ez meglehetősen szegényes biztonsági házirendhez vezetne, ezért komolyabb alkalmazások egyszerűen megtiltják az adatbázis közvetlen elérését, és egyedileg gondoskodnak a hozzáférésszabályozásról. Nem ritka az sem, hogy egy alkalmazás a felhasználók azonosításához és hitelesítéséhez egy másik külső adatforrást (pl. egy LDAP szervert) vesz igénybe. A csoportmunka támogatás SQL szerverek esetén a legkiemelkedőbb. ACID jellegű tranzakciók és ebből következően írásra és olvasásra egyaránt valódi többfelhasználós üzemmód a jellemző. A zárolások megvalósítása szerverenként különböző, de bizonyos esetekben elérhető a sor szintű locking is.
8.
Gyenge sémájú relációs modellezés
Jelen dolgozat gyenge sémájúként hivatkozik arra a relációs adatbázisra, amely a lehetséges entitásokat és azok attribútumainak halmazát nem írja elő, valamint az attribútumok típusait séma szinten nem kényszeríti ki. A megoldás bizonyos értelemben magasabb szabadságfokkal bír az objektum-relációs leképezéshez képest, aminek a nem titkolt árát teljesítményben fizeti meg. Ez a megközelítés röviden összefoglalva egy olyan sémát használ, amely az adatmodell metamodelljét rögzíti. Leegyszerűsítve az entitás és az attribútumok közötti 1-n kapcsolat reprezentálása egy-egy táblával történik. Így az objektum azonosítója az első tábla elsődleges kulcsa, az attribútumok táblája pedig ezt, mint idegen kulcsot használja. Ebből adódóan típusok csak különböző attribútumtáblákkal, vagy ugyanazon táblában tárolt redundáns mezőkkel valósíthatók meg. A referenciák ettől függetlenül idegen kulcsok segítségével lehetnek ellenőrzöttek. A módszer nagy előnye a rugalmas modell, amely éles üzem mellett szabadon módosítható, ami gyengén típusos, dinamikus programozási környezetkben jól kihasználható. Látható viszont
Konfiguráció-menedzsment verziókövetett objektumokkal
22
az is, hogy egy objektum lekérdezése legalább 1 JOIN művelet nélkül nem lehetséges, ami teljesítménykorlátokat hordoz magában. Ezen meghatározó különbségtől eltekintve az előző alfejezetben említettek itt is érvényesek.
Konfiguráció-menedzsment verziókövetett objektumokkal
9.
23
CM modellezési eljárások összehasonlítása
XML
LDAP
RDBMS (ORM)
RDBMS (gyenge séma)
Entitások tárolása
fájlrendszerben
adatbázisban
adatbázisban
adatbázisban
Attribútum típusok
+
+
+
-
Referenciák
-
+
+
+
egyedi, pl. WebDAV
LDAP
egyedi
egyedi
SSL támogatás
+ (ha támogatott)
+
+
+
Séma módosítás
adatintegritásra veszélyes
újraindítást igényel
újrafordítást igényel
szabadon (nincs séma)
Dinamikus konfiguráció
-
+
+
+
Generált konfiguráció
+
+
+
+
Olvasási sebesség
-
++
++
+
Írási sebesség
-
+
++
++
fájlok szerkesztése
LDAP kliens
SQL konzol
SQL konzol
-
-
+ (ha implementált)
+ (ha implementált)
Jogosultságkezelés
fájlrendszer szintű
attribútum szintű
tábla szintű
-
Tranzakciókezelés
-
-
+
+
fájl szintű (ha támogatott)
-
rekord szintű
rekord szintű
Hálózati protokoll
Közvetlen elérés Verziókövetés
Zárak
Konfiguráció-menedzsment verziókövetett objektumokkal
24
IV. Adatmodell gyenge sémájú modellezéshez Mottó: Különböző filozófiájú technológiák házasítása egyszerre egyesítheti azok minden jó és rossz tulajdonságát.
1.
Az adatmodell követelményei
Jelen dolgozat egyik célja egy egyedi CM rendszerben felhasználható adatmodell megtervezése[7]. Az előző fejezetben említett módszerek közül a választás a gyenge sémájú modellezésre esett, melyre megszorításokkal ugyan, de kijelenthető, hogy egy gondosan implementált keretrendszer mellett a gyengén típusos környezetek rugalmasságát ötvözi a relációs adatbáziskezelők teljesítményével. A gyenge sémájú modellezésből származó előnyöket értelemszerűen csak egy gyengén típusos, dinamikus programozási környezetben lehet kamatoztatni. Ezen programozási környezetek közül sok vagy eleve objektum-orientált szemléletű (pl. Python, Ruby), vagy legalábbis kényelmesen alkalmazhatóak bennük az OOP paradigmák (pl. Perl). Egy CM megoldás entitásai természetes módon képezhetők le egy objektum rendszerre, tekintve a valós élet objektumaival vett kapcsolatukat: egy felhasználói fiók egy objektum, amelyen értelmes művelet a bejelentkezési név megváltoztatása. További példák az OOP és a CM kapcsolatára: • adatrejtés UNIX alatt a /etc/passwd fájl rekordjai sorokba rendezettek, és a sorokon belül a mezőhatároló karakter a ':'. Ha ezzel a részletkérdéssel a felhasználói kvótákról jelentést készítő programkód nem kell, hogy foglalkozzon, az nem csak átláthatóbb, de jobban újrafelhasználható megoldást eredményez. • öröklődés Egy webszerver és egy e-mail szerver is egy hálózati kiszolgáló – mindkettőn értelmes művelet az indításuk előtt az általuk használt port foglaltságának ellenőrzése. • polimorfizmus Egy webszervert és egy e-mail szervert jelképező objektum start metódusa azonos programozói felületet kíván, viszont a műveletek megvalósítása természetesen különbözhet.
Konfiguráció-menedzsment verziókövetett objektumokkal
25
A tervezendő adatmodelltől azt várjuk, hogy jól illeszkedjen egy gyengén típusos objektumorientált környezethez. Támogatnia kell az objektum és a műveleteit implementáló osztály összerendelését, a referenciákat, és valamilyen objektum-hierarchiát. Ezeken kívül a következő igényeket támasztjuk a fejlettebb szolgáltatások kialakításához: • objektumfa Az objektumok fastruktúrában tárolódjanak és ugyanazon objektum a fa több csúcspontjához legyen linkelhető. • verziókövetés Az objektumok és attribútumaik legyenek verziókövetés alatt. Legyen lehetőség egy objektum korábbi állapotának megtekintésére – ez adatmodell szinten csak az adattagokra garantálható, a metódusok implementációiban keletkezett változtatásokra nem érvényes. • auditálás Legyen nyomon követhető az adatbázison végzett műveletek listája, időbélyeggel ellátott műveleti napló segítségével.
2.
Entitás-relációk tervezése
Mint az a korábbiakban említésre került, a gyenge sémájú modellezés alapötlete a metamodell implementálása a végleges adatmodell helyett. Ez a következő leegyszerűsített kapcsolatot feltételezi:
Objektum
tartalmaz
Attribútum
Az attribútumok mindig kulcs-érték párok, függetlenül attól, hogy az érték adott esetben egy egyszerű szám, vagy további objektumok kollekciója. A kulcsokat és az értékeket önálló entitásként ábrázolva a következő modellhez jutunk:
Konfiguráció-menedzsment verziókövetett objektumokkal
26
Kulcs
Objektum
attribútum
Érték
Ez az elképzelés egyszerűsége mellett számos pozitív lehetőséget hordoz magában. A verziókövetés megvalósítása az entitás-relációk érintése nélkül implementálható, ha az Objektum entitásra, mint az objektum egy verziójára tekintünk. Ehhez mindössze arra van szükség, hogy a nevezett entitás azonosítóját az objektum azonosítója és a verziószám összetett kulcsként adja. A modellben akár a kulcsok neveinek, akár az értékeknek a változatlansága természetszerűleg leírható, amivel a redundancia elfogadható szintre csökkenthető. A fenti Objektum entitást a valódi objektum egy változataként kezelve felmerül a kérdés, hogy ha egy attribútum értéke egy másik objektum referenciája, akkor a hivatkozás tartalmazza-e a verziószámot. Azaz, amikor egy objektum tartalmazza egy másik referenciáját, azzal egy konkrét, rögzített verzióra hivatkozik vagy annak a legfrissebb állapotára. Az első megközelítésből kiindulva a modell nem veszít általánosságából, és leírhatóak vele olyan különleges esetek is, amikor egy attribútumérték egy időközben frissült objektum régebbi verziójával dolgozik. Ez egy további problémát vet fel. A műveletek nem az adatbázisban tárolódnak, és mivel így nem állnak verziókövetés alatt, a metódusokat megvalósító osztályoknak visszafele kompatibilisnek kellene lenniük minden olyan objektumverzióra, amelyre létezik referencia. A második megközelítés, azon túl, hogy lemond a régebbi objektumok hivatkozásának lehetőségéről, egy kényelmesebben kezelhető adatszerkezetet nyújt. Ha egy objektum frissül, nem szükséges az összes rá hivatkozó objektumot frissíteni annak érdekében, hogy az új változat elérhetővé váljon. Ez a viselkedés programozói szemmel sokkal inkább nevezhető elvártnak az előzőhöz képest.
Konfiguráció-menedzsment verziókövetett objektumokkal
27
Az objektumok fába rendezése egy hasonló, de talán még nehezebben megválaszolható tervezői döntés kérdését veti fel. A fa lehet önmagában verziókövetett, azaz működhet egy modern verziókövető rendszer könyvtárstruktúra-kezelésének mintájára. A másik lehetőség, hogy a fa nem követi a változásokat, csak objektumreferenciákat tartalmaz, ami további két opcióként ismét vonatkozhat az objektum verziójára vagy magára az objektumra. A fa verziókövetése akkor valósítható meg, ha létezik egy globális verziószám a teljes fastruktúrára, és ezt a verziószámot használják az abban szereplő objektumok. Ez azzal járna, hogy a rendszerben lévő bármely objektum bármely attribútumán történő változtatás az objektumrendszer egészének egy új verzióját eredményezné, amit ezen a ponton önkényes választás alapján elkerülünk. A fa tehát nem verziókövetett, és az attribútumértékeknél kifejtett indokok miatt a benne tárolt referenciák objektumokat címeznek és nem verziókat. Mindezt összefoglalva az alábbi ER-diagram adja az objektummodellt:
gyermeke
Objektum
tartalmaz
Kulcs
Objektum verzió
attribútum
Érték
Konfiguráció-menedzsment verziókövetett objektumokkal
3.
28
Relációs séma tervezése
Mielőtt a bemutatott entitás-relációk alapján relációs adatbázisban felhasználható séma készülhetne, a modell még egy kis kiegészítésre szorul. Egyrészt nem esett szó még az audit log megvalósításáról. Erre egy külön tábla fog szolgálni, a modelltől valamilyen szinten függetlenül, kizárólag naplózási célra. Másrészt a modell objektumai – bár gyengén típusos környezetben fognak CM célokat szolgálni – minden esetben tartalmaznak legalább olyan szintű típusinformációt, hogy a műveletek megvalósításai milyen osztályban vagy csomagban keresendők, illetve mi az a befoglaló adatszerkezet, amelyen keresztül a kulcs-érték párok elérhetőek. Ez nyelvspecifikus kérdés, az adott programozási környezet határozza meg ezeknek a tulajdonságoknak a lehetséges értékeit. Itt ismét önkényesen a modellt úgy alakítjuk, hogy az típusosság szempontjából a Perl programozási nyelvnek kedvezzen. A későbbiekben még szó esik a Perl és az OOP kapcsolatáról, egyelőre fogadjuk el, hogy a tervezett rendszer objektumai egy csomagnévvel azonosított osztályból veszik a metódusaikat, és az adataikat egy tetszőleges méretű skalár, tömb vagy asszociatív tömb írja le. A relációs séma tábláit és azok jelentésék a következő alfejezetek tárgyalják. Mivel a fejlesztés MySQL[8] adatbáziskezelővel történt, a táblák DDL leírásai ezen RDBMS SQL dialektusát tükrözik. A mellékelt diagramon vastag betűvel szedettek azok a mezők, amelyek nem vehetnek fel NULL értéket. Az elsődleges kulcsokat a kulcs szimbólum jelzi, összetett kulcsok esetén értelemszerűen több mezőt jelölve. A nyilak az idegen kulcsokat jelentik, egy táblából akkor mutat nyíl egy másikra, ha az első idegen kulcsként használja a második tábla valamely mezőjét.
Konfiguráció-menedzsment verziókövetett objektumokkal
29
Konfiguráció-menedzsment verziókövetett objektumokkal
4.
30
ActLog tábla
Az ActLog (Action Log) tábla az audit logot hivatott megvalósítani. Minden rekordja egy adott időpillanatban egy objektumon végrehajtott műveletet naplóz. Kényszerként nem tartalmaz idegen kulcsokat annak érdekében, hogy az objektumok a naplóbejegyzések érvénytelenítése nélkül törölhetőek legyenek. • act_ts TIMESTAMP típusú
mező a művelet időbélyegének leírásása.
• obj_id INT
típusú mező a művelet tárgyát jelentő objektum azonosításához. Az act_ts mezővel
együtt elsődleges kulcsa a táblának. • role VARCHAR
típusú mező a műveletet végző szerepkör azonosítására. Ez tartalmazhatja
például annak a felhasználónak a belépési nevét, aki az adatbázison dolgozó szkriptet futtatja. • action VARCHAR típusú
mező a művelet leírásása.
• comment TEXT típusú
mező a szabadszöveges megjegyzések tárolásához.
CREATE TABLE `ActLog` ( `act_ts` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, `obj_id` int(11) NOT NULL, `role` varchar(128) NOT NULL, `action` varchar(128) NOT NULL, `comment` text, PRIMARY KEY (`act_ts`,`obj_id`), KEY `ActLog_role` (`role`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
5.
ObjTree tábla
Az ObjTree (Object Tree) tábla az objektumfát valósítja meg. Minden rekordja a fa egy csúcspontja. Az objektumok névvel azonosítottak, és a fában teljes elérési útjuk alapján találhatóak meg.
Konfiguráció-menedzsment verziókövetett objektumokkal
31
• name VARCHAR típusú
mező, az objektum nevét tartalmazza.
• parent típusú mező, az objektum szülőjének azonosítóját tartalmazza. Idegen kulcs
INT
ugyanezen tábla obj_id mezőjére. A name mezővel együtt elsődleges kulcsa a táblának. • obj_id INT típusú
mező az objektum azonosítójának tárolására.
CREATE TABLE `ObjTree` ( `name` varchar(128) NOT NULL default '', `parent` int(11) NOT NULL default '1', `obj_id` int(11) NOT NULL auto_increment, PRIMARY KEY (`name`,`parent`), KEY `Object_ID` (`obj_id`), KEY `Parent object must exist` (`parent`), CONSTRAINT `Parent object must exist` FOREIGN KEY (`parent`) REFERENCES `ObjTree` (`obj_id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
6.
ObjRev tábla
Az ObjRev (Object Revision) tábla az objektumok verzióit tárolja. Minden rekordja egy adott objektum verzióját jelképezi. • obj_id INT
típusú mező az objektum azonosítójának tárolására. Idegen kulcs az ObjTree tábla
azonos nevű mezőjére. • obj_rev INT
típusú mező, az objektum verziószámát tartalmazza. Az obj_id mezővel együtt a
tábla elsődleges kulcsa. • type_id INT típusú
mező, az objektum típusát leíró ObjType rekord idegen kulcsa.
CREATE TABLE `ObjRev` ( `obj_id` int(11) NOT NULL, `obj_rev` int(11) NOT NULL default '0', `type_id` int(11) NOT NULL, PRIMARY KEY (`obj_id`,`obj_rev`), UNIQUE KEY `obj_id` (`obj_id`,`obj_rev`), KEY `Object_type` (`type_id`), CONSTRAINT `Object must exist` FOREIGN KEY (`obj_id`) REFERENCES `ObjTree` (`obj_id`) ON DELETE CASCADE,
Konfiguráció-menedzsment verziókövetett objektumokkal
32
CONSTRAINT `Type must exist` FOREIGN KEY (`type_id`) REFERENCES `ObjType` (`type_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
7.
ObjType tábla
Az ObjType (Object Type) tábla az objektumok típusának leírására szolgál. Minden rekordja egy típusdefiníció. • type_id INT típusú
mező, a típus egyértelmű azonosítója, a tábla elsődleges kulcsa.
• class INT
típusú mező, az objektum osztályát tartalmazó csomag jelölésére szolgál. A csomag
nevét a rendszer egy másik objektumának value nevű attribútuma adja, ezért ez a mező az ObjTree tábla obj_id mezőjére hivatkozó idegen kulcs. Ha ez a mező NULL, akkor az objektum a tie mezőben tárolt információ alapján egy alapértelmezett osztály példánya lesz. • tie ENUM
típusú mező, amely azt az adattípust jelöli, amelyen keresztül később az objektum
attribútumai elérhetőek lesznek. Ha ez SCALAR, az objektum value nevű attribútuma adja a skalár értékét, ha pedig ARRAY vagy HASH, akkor az attribútum kulcs-érték párjai a megfelelő tömbszerkezet kulcsához tartozó értékek lesznek. CREATE TABLE `ObjType` ( `type_id` int(11) NOT NULL auto_increment, `class` int(11) default NULL, `tie` enum('SCALAR','ARRAY','HASH') NOT NULL default 'HASH', PRIMARY KEY (`type_id`), KEY `Object_class` (`class`), CONSTRAINT `Object class must exist` FOREIGN KEY (`class`) REFERENCES `ObjTree` (`obj_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
8.
ObjAttr tábla
Az ObjAttr (Object Attribute) tábla az objektumok attribútumainak kapcsolótáblája. Minden rekordja egy attribútumot jelképez. • obj_id INT típusú
mező az objektum azonosítójának tárolására.
Konfiguráció-menedzsment verziókövetett objektumokkal
33
• obj_rev INT
típusú mező az objektum verziószámának tárolására. Az obj_id mezővel együtt
idegen kulcs az ObjRev tábla azonos nevű mezőire. • attrkey_id INT
típusú mező az attribútum kulcsának jelölésére. Idegen kulcs az AttrKey tábla
azonos nevű mezőjére, továbbá az obj_id és obj_rev mezőkkel együtt képezi a tábla elsődleges kulcsát. • attrval_id INT
típusú mező az attribútum értékenek jelölésére. Idegen kulcs az AttrVal tábla
azonos nevű mezőjére. Ha a mező NULL, az azt jelenti, hogy az objektum attribútumát törölték. CREATE TABLE `ObjRev` ( `obj_id` int(11) NOT NULL, `obj_rev` int(11) NOT NULL default '0', `type_id` int(11) NOT NULL, PRIMARY KEY (`obj_id`,`obj_rev`), UNIQUE KEY `obj_id` (`obj_id`,`obj_rev`), KEY `Object_type` (`type_id`), CONSTRAINT `Object must exist` FOREIGN KEY (`obj_id`) REFERENCES `ObjTree` (`obj_id`) ON DELETE CASCADE, CONSTRAINT `Type must exist` FOREIGN KEY (`type_id`) REFERENCES `ObjType` (`type_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
9.
AttrKey tábla
Az AttrKey (Attribute Key) tábla az attribútumok kulcsát tartalmazza. Minden rekordja egy névvel ellátott kulcs. • attrkey_id INT típusú
mező az attribútumkulcs egyértelmű azonosítására, a tábla elsődleges kulcsa.
• attr_key VARCHAR típusú
mező, az attribútum nevét tartalmazza.
CREATE TABLE `AttrKey` ( `attrkey_id` int(11) NOT NULL auto_increment, `attr_key` varchar(128) NOT NULL, PRIMARY KEY (`attrkey_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Konfiguráció-menedzsment verziókövetett objektumokkal
10.
34
AttrVal tábla
Az AttrVal (Attribute Value) tábla az attribútumok értékét tartalmazza. Minden rekordja egy gyenge típusú érték. • attrval_id INT
típusú mező az attribútum értékének egyértelmű azonosítására, a tábla elsődleges
kulcsa. • attr_type ENUM
típusú mező az attribútum gyenge típusának meghatározására. Ennek jelentését a
későbbiekben tárgyaljuk, a lehetséges értékek: string, delegate és object. Értéke befolyásolja, hogy a további mezők közül melyik szolgáltatja az attribútum értékét. • attr_ref INT
típusú mező objektum-referencia tárolására. Idegen kulcs az ObjTree tábla obj_id
nevű mezőjére. Ha az attr_type értéke delegate vagy object, ez a referencia számít az attribútum értékének meghatározásakor. • attr_val BLOB
típusú mező egyszerű értékek tárolására. Ha az attr_type értéke string, ez a
referencia számít az attribútum értékének meghatározásakor. Az adatbázisban nem tárolt integritási feltétel, hogy az attr_ref és az attr_val mezők közül legfeljebb az egyik vehet fel nem NULL értéket, és a nem NULL értékű mezőt az attr_type jelzi. CREATE TABLE `AttrVal` ( `attrval_id` int(11) NOT NULL auto_increment, `attr_type` enum('string','delegate','object') NOT NULL default 'string', `attr_ref` int(11) default NULL, `attr_val` blob, PRIMARY KEY (`attrval_id`), KEY `AttrVal_ref` (`attr_ref`), CONSTRAINT `Reference must exist` FOREIGN KEY (`attr_ref`) REFERENCES `ObjTree` (`obj_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Konfiguráció-menedzsment verziókövetett objektumokkal
35
V. A Perl nyelv Mottó: A könnyű dolgok legyenek egyszerűek, a nehezebb dolgok pedig megvalósíthatóak. – Larry Wall
1.
A nyelv eredete
A Perl[9] egy általános célú, C-szerű szintaktikával bíró dinamikus, interpretált programozási nyelv, melyet 1987-ben hozott létre az akkor a NASA-nál rendszeradminisztrátorként dolgozó Larry Wall. Eredetileg a ksh-sed-awk klasszikus UNIX-os hármas kiváltására született, elsősorban a mindennapi adminisztrátori feladatok, ezek közül is a riportkészítés egyszerűbbé tétele érdekében. Azóta a nyelv számos verziót megélt, melyek közül a legfontosabb mérföldkő az 1994-ben bemutatott Perl 5. Ebben a változatban jelentek meg azok a fejlett nyelvi elemek, melyek nélkül a Perl a gyakorlatban nehezen volna használható kisebb szkriptelési feladatokon kívül bármire is; így a referenciák, az objektumok, vagy a modulok kezelése mind a Perl 5 sajátja. Ma a Perl egyike a legsikeresebb dinamikus nyelveknek. Elsősorban UNIX adminisztrátorok körében népszerű, de a bioinformatikától a webprogramozásig számos helyen alkalmazzák. Elterjedtségét többek között korlátlan rugalmasságának és a rapid alkalmazásfejlesztés támogatásának köszönheti, továbbá annak a ténynek, hogy a Perl modulok hivatalos gyűjtőhelye, a CPAN[10] az írás pillanatában több, mint 65.000 modult tartalmaz, melyek a jelenlegi stabil 5.10-es változathoz ingyenesen elérhetőek. A Perl megalkotója, Larry Wall eredeti foglalkozása szerint nyelvész, és talán nem véletlen, hogy a programnyelv filozófiáját tekintve sok közös vonást mutat a természetes nyelvekkel. Pl. nem szükségszerű a nyelvet teljes egészében ismerni ahhoz, hogy valaki elkezdjen vele foglalkozni – ugyanúgy, ahogy bizonyos helyzetekben egy angolul társalgási szinten tudó is elboldogul, és nem szükséges felsőfokú nyelvvizsga ahhoz, hogy valaki egy étteremben rendeljen egy steaket. Ez a tulajdonság tette egyszerre híressé és hírhedté a nyelvet. Viszonylag könnyű beletanulni, viszont már a legalapvetőbb programozási feladatokat is rendkívül sokféle módon lehet benne megvalósítani. Ez egy nagyobb projekt esetén megnehezítheti egy programozó csapat feladatát akkor, ha a csapat tagjai különböző szinten “beszélik” a Perlt, és nincsenek szigorú kódolási
Konfiguráció-menedzsment verziókövetett objektumokkal
36
konvenciók. A nyelv maga ugyanis nem kényszerít rá semmilyen – olykor nagyon hasznos – szabályosságra. Azaz, a szabálykövetés egyéni ízlés kérdése. Mindez csak ízelítő ahhoz, hogy egyesek miért svájci bicskaként, míg mások láncfűrészként gondolnak a Perlre. Nekem személyesen egyik nem titkolt célom jelen dolgozattal az, hogy példát mutassak átlátható, robusztus és újrafelhasználható Perl kód írására.
2.
A Perl adattípusai
A Perl beépített típusai az alábbiak[11]: • SCALAR • ARRAY • HASH • CODE • REF • GLOB • LVALUE • FORMAT • IO • VSTRING • Regexp
Ezen primitívek közül a mindennapi gyakorlatban az átlagos programozó az első három típust alkalmazza, a többit pedig vagy egyáltalán nem használja, vagy csak az interpreter dolgozik velük a háttérben. Például a VSTRING használata az 5.8.1-es változat óta ellenjavallt, Regexp pedig implicit módon jön létre a reguláris kifejezést váró operátoroknál. A SCALAR típus az egyszerű skalár – fedi az elterjedt, erősen típusos nyelvek közel összes primitív típusát, így az egész és a lebegőpontos számokat, a karaktert és a sztringet. Egy skalár felveheti az undef értéket (nem definiált) – ez inicializálatlan változók esetén a kezdőérték. Külön boolean típus nincs Perlben. Minden érték, amely nem 0, nem üres sztring és nem undef, igaz, a többi hamis. Egy skalár továbbá értékként felvehet egy referenciát. Az ARRAY egészekkel indexelt, sorrendezett, dinamikus tömb, amelynek értékei skalárok. Értelmezettek rá a következő veremműveletek: push, pop, shift, unshift.
Konfiguráció-menedzsment verziókövetett objektumokkal
37
A HASH sztringekkel indexelt, nem sorrendezett, dinamikus tömb, amelynek értékei skalárok. Az iterátor tervezési mintának megfelelően bejárható. A Perl megköveteli, hogy a változók neveikben prefixumként jelöljék a típusukat (megj.: erre a fogalomra az angol szakirodalom a sigil[12] elnevezést használja). A skalár típust a $, a tömböt a @, a hash tömböt pedig a % jelöli. Minden változóhoz képezhető referencia a \ operátor segítségével. A referencia tárolható skalár változóban, és dereferálható a hivatkozott változó típusának megfelelő sigil használatával. Ez az alábbi táblázatban foglalható össze.
3.
Referenciaképzés
Dereferálás
SCALAR
$ref = \$var
$$ref
ARRAY
$ref = \@var
@$ref
HASH
$ref = \%var
%$ref
A Perl és az OOP
A referenciát tartalmazó skalár változókra értelmes művelet a megáldás[13] (angolul: blessing). Ez az operáció egy névteret definiáló Perl csomagot rendel a változóhoz. Az így létrejövő referencia egy hagyományos Perl objektum. Osztálya az a csomag, amelynek nevével a referencia áldott, adatait pedig a hivatkozott adatstruktúra tárolja. Egy Perl objektum újra megáldható, ebben az értelemben az objektumok típusai dinamikusan módosíthatóak. A metódushívás a nyíl operátorral (->) történik. Akkor, ha ennek bal oldalán egy csomagnév áll, a jobb oldalon álló szubrutint az értelmező az adott névtérben keresi, és meghívásakor átadja a csomag nevét nulladik paraméterként. Ez a működés tükrözi a tisztán objektum-orientált környezetek statikus tagfüggvény-hívásait. Ha a nyíl operátor bal oldalán egy megáldott referencia áll, a jobb oldalon álló szubrutint az értelmező abban a névtérben keresi, amellyel a referencia áldott, és meghívásakor átadja a referenciát nulladik paraméterként. Ez leginkább a C++-os metódushíváshoz hasonlítható, ha a nulladik paraméterre úgy tekintünk, mint a this pointerre. A Perl támogatja a többszörös öröklődést. Ez egy csomag szinten globális változó formájában valósul meg, melynek neve @ISA. Az ISA tömb elemei csomagnevek. Ha a nyíl operátorral egy olyan metódust próbálunk meghívni, amely a bal oldalon álló szimbólumból kikövetkeztetett
Konfiguráció-menedzsment verziókövetett objektumokkal
38
csomagban nem található, az interpreter az @ISA elemeit egyenként végigpróbálva próbálja meg feloldani a hivatkozást. Az eddig ismertetett szabályok összefoglalásaként lássunk egy példát Perl OOP kódra. A példaprogram egy absztrakt állat osztályt, egy tehén osztályt és egy azt felhasználó csomagot mutat be. #!/usr/bin/perl -w package Animal; use strict; use Carp; sub speak($) { my $name = ( caller 0 )[3]; croak "Subroutine $name is abstract and cannot be invoked directly.\n"; } sub DESTROY { warn __PACKAGE__ . " object destroyed.\n"; } package Cow; use strict; use base 'Animal'; sub new($$) { my ( $class, $name ) = @_; my %self = ( name => $name ); return bless \%self, $class; } sub speak($) { my $self = shift; print "$$self{name} says moooo.\n"; } package main; use strict; use Data::Dumper; my $cow = new Cow( 'Dazy' ); warn Data::Dumper->Dump( [ $cow ], [ 'cow' ] ); eval { $cow->speak }; warn "\$cow->speak failed: $@\n" if ( $@ );
Konfiguráció-menedzsment verziókövetett objektumokkal
39
A szkript kimenete a következő (a dőlt betűvel szedett kimenet a STDERR, a többi a STDOUT csatornán jelenik meg): $cow = bless( { 'name' => 'Dazy' }, 'Cow' ); Dazy says moooo. Animal object destroyed.
A fenti kódból látható még a Perl OOP támogatásának néhány további fontos tulajdonsága. Az objektumok legtöbbször hash referenciák, mivel ez az adatstruktúra közelít leginkább a szigorú objektum-orientált környezetek tagváltozóihoz. Egy hash referencia által mutatott adattagok az osztályon kívülről egyszerűen lekérdezhetőek és módosíthatóak. A hagyományos Perl objektumok tehát nem rejtik el az adattagjaikat. Absztrakt metódusok létrehozására szigorú értelemben nincs lehetőség. Pontosabban fogalmazva, az interpreter egy osztály interfészét fordítási időben nem ellenőrzi, ezért csak futásidejű hibák generálásával lehet emulálni a klasszikus absztrakt metódusokat. Az @ISA módosítható a base pragmatikus modul használatával. Ez gyakorlatilag szintaktikai édesítőszer, és itt is tetten érhető az a tulajdonság, hogy az öröklődés megvalósításához az ősosztály neve sztringként tárolódik, vagyis fordítási idejű hibaellenőrzés nincs. A megáldás szintén sztringgel történik, a Cow::new szubrutinban definiált $class változó értéke a 'Cow' karakterlánc lesz. A bless művelettel még futásidőben sem ellenőrzi az interpreter azt, hogy az operációhoz felhasznált csomagnév érvényes-e. Ebből adódik, hogy objektumok konstruktorai elhelyezhetők az osztályokon kívülre is, és még be nem töltött csomagnevekkel is végezhető blessing. Perlben van szemétgyűjtő mechanizmus (garbage collector). Ez az objektum által foglalt memóriaterület felszabadítása előtt meghívja az objektum DESTROY metódusát, ha az létezik. A DESTROY, ahogy bármely
másik metódus, örökölhető és garantáltan lefut.
A metódushívás a nyíl operátor explicit kiírása mellett történhet úgy is, hogy a csomagnév, vagy objektum elé írjuk a metódus nevét. A main csomagban a new Cow kifejezés ismét szintaktikai édesítőszer, és pontosan ugyanazt jelenti, mint a Cow->new. A new tehát nem kulcsszó, és az, hogy a konstruktor szerepét betöltő metódust így hívják, csupán programozói konvenció.
Konfiguráció-menedzsment verziókövetett objektumokkal
40
A kivételkezelésre beépített nyelvi megoldás nincs. Mégis meg lehet valósítani úgy, hogy azt a kifejezést, amely hibát válthat ki, egy eval blokkba helyezzük. Ha a blokkon belül die, vagy ahhoz hasonló, abortálást eredményező művelet történik, akkor a szkript nem lép ki és utána a $@
változó értékének ellenőrzésével elkapható a kivétel. A kivételek ebből adódóan nem
típusosak. Ezek a tulajdonságok első ránézésre veszélyesnek tűnhetnek, sőt, azt is megkockáztatom, hogy egyfajta módosult tudatállapot szükséges a Perl objektummodelljének szeretetéhez. Azt azonban nem szabad figyelmen kívül hagyni, hogy a programnyelv szabadságából adódó lehetséges hibák vagy az első futás során kiderülnek (pl. elírt csomagnév az öröklődésnél), vagy ha nem, akkor a programozó szándékos, rendszerszemléletet nélkülöző munkájának az eredményei (pl. privátnak szánt adattagok módosítása az osztályon kívülről). A Perl egyik legnagyobb hibája és egyúttal igazi ereje az, hogy nem korlátozó.
4.
Beépített típusok egyedi implementációja
A blessing mellett egy másik izgalmas lehetőség Perlben a kötés[14] (tie). Ezzel a programozó a következő primitív típusokhoz adhat egyéni implementációt: • SCALAR • ARRAY • HASH • IO
A kötéshez szükség van egy, az adattípusra értelmes műveletek megvalósításait tartalmazó osztályra. A tie operáció során egy deklarált változóhoz egy megadott osztály példányát rendeljük, és onnantól kezdve a változón végzett beépített műveletekre az objektum metódusai hívódnak meg. Ez hasonló a C++ operátor-túlterheléséhez, azzal a különbséggel, hogy beépített típusokra működik és nem a programozó által létrehozott osztályokra. Példaként lássunk egy olyan szkriptet, amely egy hash kötést implementál az első tíz négyzetszám meghatározásához. #!/usr/bin/perl -w package Pow; use strict; use Carp;
Konfiguráció-menedzsment verziókövetett objektumokkal
sub TIEHASH { my $class = shift; my ( $power ) = @_; my %self = ( pow => defined $power ? $power : 1, first => 1, last => 10 ); return bless \%self, $class; } sub FETCH { my $self = shift; my ( $key ) = @_; $$self{cache}{$key} = $key ** $$self{pow} unless ( exists $$self{cache}{$key} ); return $$self{cache}{$key}; } sub sub sub sub
immutable STORE DELETE CLEAR
sub EXISTS
{ { { {
croak "This hash shift->immutable shift->immutable shift->immutable
is immutable" } } } }
{ return 1 }
sub FIRSTKEY { shift->{first} } sub NEXTKEY { my ( $self, $lastkey ) = @_; if ( $lastkey == $$self{last} ) { undef } else { ++ $lastkey } } sub SCALAR { my $self = shift; return "$$self{first} .. $$self{last}"; } package main; use strict; tie my %square, 'Pow', 2; print scalar( %square ), ":\n";
41
Konfiguráció-menedzsment verziókövetett objektumokkal
42
while ( my ( $key, $val ) = each %square ) { print "$key ^ 2 = $val\n"; } $square{1} = 2;
A szkript kimenete a következő (a dőlt betűvel szedett sor a STDERR, a többi a STDOUT csatornán jelenik meg): 1 .. 10: 1 ^ 2 = 1 2 ^ 2 = 4 3 ^ 2 = 9 4 ^ 2 = 16 5 ^ 2 = 25 6 ^ 2 = 36 7 ^ 2 = 49 8 ^ 2 = 64 9 ^ 2 = 81 10 ^ 2 = 100 This hash is immutable at ./square.pl line 59
Ez az implementáció azt sugallja, hogy a számok négyzeteit egy szótárszerű adatszerkezetben tároljuk, ahol a kulcs a hatványalap, az érték pedig a hatványérték. Ez egy természetes szintaktikát ad a programozó kezébe úgy, hogy a mögöttes bonyolult számítás megvalósítását nem kell ismernie. A tie művelet után a $square{alap} kifejezéssel tetszőleges négyzetszám megkapható. A szintaktika szépségén túl ez a megoldás egy további nagy előnnyel bír. Mivel a hatványraemelés művelete számításigényes, a %square hasht felhasználó programozó joggal várhatja el, hogy az értékek meghatározása a mögöttes implementációt adó objektumban csak egyszer történjen meg, függetlenül attól, hogy az értéket a szkript hányszor használja. Ez a caching mechanizmus a Pow::FETCH szubrutinban néhány sorban implementált, és teljesen transzparens módon, az erre építő kódból észrevétlenül működik. A példaprogram tartalmaz még Perl különlegességeket: • Ha egy szubrutinban nincs explicit return, akkor a visszatérési érték az utoljára kiértékelt kifejezés értéke. Erre jó példa a Pow::FIRSTKEY és a Pow::NEXTKEY. • Egy hashreferencia által mutatott adatstruktúra adott kulcsához tartozó érték nem csak a $$ref{key},
de a $ref->{key} alakú, C-szerű szintaktikával is elérhető. Erre példa a
Pow::FIRSTKEY.
• Blokkok utolsó utasításai esetén elhagyható a pontosvessző – lásd Pow::EXISTS.
Konfiguráció-menedzsment verziókövetett objektumokkal
43
• Függvények visszatérési értéke lehet lista, így az each iterátor két skalárral; egy kulccsal és egy értékkel tér vissza. Ezeken kívül összetett hash természetes módon képezhető és a további dimenziók struktúráit nem szükséges deklarálni, mert az autovivifikációnak nevezett mechanizmus gondoskodik az életre keltésükről. A Pow::FETCH úgy használja a $$self{cache} hashreferenciát, hogy feltételezi annak önműködő létrehozását. Végül érdemes megjegyezni, hogy a Pow osztály egy olyan hashre ad egyedi implementációt, amely értelemszerűen nem módosítható, ezért néhány metódus esetén futásidejű hibát ad. A kimenet utolsó sorában látható hibaüzenet annak köszönhető, hogy a main csomag végső utasításában megkísérli felüldefiniálni az 1 négyzetét, – sajnálatos módon rosszul – amit a Pow osztálypéldány megakadályoz a matematika szabályainak érvényben tartása érdekében.
Konfiguráció-menedzsment verziókövetett objektumokkal
45
VI. A Calf keretrendszer Mottó: Egy keretrendszer nagysága a kiterjeszthetőségben rejlik és nem a korlátoltságban.
1.
A keretrendszer célja
Jelen diplomamunka fő eredménye egy olyan Perlben implementált keretrendszer, amely segítségével verziókövetett objektum-perzisztencia valósítható meg, a korábban bemutatott gyenge sémájú adatmodellt felhasználva. Erre a keretrendszerre építve kialakítható egy egyedi CM rendszer a következő szempontok azonnali teljesülésével: • relációs adatbázisháttér • verziókövetés • könnyű szkriptelhetőség • objektum-orientált szemlélet A Calf alapgondolata egy olyan objektumrendszer, amelyben az objektumok mindig olyan adatstruktúrára mutató referenciák, amelyek belső implementációja a keretrendszer által adott. Perl nyelvi szinten ez azt jelenti, hogy előre elkészített osztályokhoz kötött változók referenciáinak megáldása szolgáltatja az objektumokat. Object Reference Tied variable
Ennek köszönhetően a keretrendszer objektumai szabadon kiterjeszthetőek és azok minden metódusa felüldefiniálható anélkül, hogy a belső adatok integritási szabályai megkerülhetőek lennének. Az ábrán látható folytonos vonalon belül lévő adatok az azokra hivatkozó objektum elől is rejtettek. A kötéshez felhasználásra kerülő osztályok ezeket az adatokat a verziókövetés megkönnyítéséhez Copy-On-Write módon kezelik. A módszer angol nevének rövidítése a COW, melyből sejthető a keretrendszer névválasztásának oka.
Konfiguráció-menedzsment verziókövetett objektumokkal
2.
46
A keretrendszer áttekintése
A Calf Perlben megvalósított objektum-orientált perzisztencia réteg. Az osztályok ebből adódóan Perl csomagok. A forráskód könnyebb kezelhetőségét szem előtt tartva minden csomag önálló fájlban került megvalósításra. A következőkben bemutatott UML osztálydiagram az alábbi egyedi jelöléseket alkalmazza: • Az adattagok csak statikus esetben kerültek feltüntetésre, mivel a Perl objektumok adattagjait minden esetben egy referencia által hivatkozott dinamikusan változó, gyengén típusos struktúra tartalmazza. • A műveletek sztereotípusa <
>, ha a szubrutin felhasználása konstruktor jellegű, <>, ha a szubrutint minden esetben az interpreter hívja, <<sub>>, ha hagyományos Perl szubrutin, és végül <<method>>, ha OOP tagfüggvény. Utóbbi esetben az első átadott paraméter jelzi, hogy statikus ($class), vagy objektumra értelmezett ($self). • A műveletek típusa scalar, array, vagy hash, ha a megfelelő primitív típussal térnek vissza, scalarrref, arrayref, vagy hashref, ha értékük ezekre hivatkozó, nem megáldott referencia, illetve object, ha megáldott referencia. • A műveletek paraméterlistájában a gyenge típusokat sigil jelzi, megáldott referencia esetén a :object jelöléssel
együtt. Az opcionális paraméterek neve mögött ? áll.
• A dőlt betűvel szedett osztályok absztraktnak szánt ősosztályok. • A dőlt betűvel szedett metódusok implementációja nem teljes. • A Calf::Debug csomag az összes többi függősége, ezek a nyilak az áttekinthetőség megtartása érdekében hiányoznak. A metódusok teljes listáját a részletes megjegyzésekkel ellátott forráskódra való tekintettel mellőzöm.
Konfiguráció-menedzsment verziókövetett objektumokkal
47
Konfiguráció-menedzsment verziókövetett objektumokkal
3.
48
Calf csomag
A Calf csomag és az azonos nevű osztály a keretrendszer belépési pontja. Az osztály egy példánya egy, az objektum élettartamán keresztül folyamatos adatbáziskapcsolatot jelent. Legfontosabb metódusa a checkout, amellyel a perzisztált objektumok visszanyerhetőek az adatbázisból. Az így visszaállított objektumok később a Calf objektum nélkül újból perzisztálhatóak, sőt, a mögöttes Calf::DB::Proxy objektum autocommit beállításától függően az akár önműködően is történhet. Felhasználási példa: my $calf = new Calf( 'dsn' => 'DBI:mysql:database=calf;host=localhost;port=3306', 'user' => 'calf', 'pass' => 'secret' ); my $obj = $calf->checkout( 'name' => '/my/object', 'rev' => 2 ); print $obj->value( 'key' );
4.
Calf::Tie csomagok
A Calf::Tie névtér alatt található csomagok nyújtják a korábbiakban bevezetett kötéshez szükséges egyedi típus-implementációkat. A Calf::Tie::Scalar, Calf::Tie::Array, valamint a Calf::Tie::Hash rendre egy Calf::Data objektumot rejtő skalár, tömb, illetve hash implementáció. Ezek absztraktnak szánt ősosztálya a Calf::Tie::Base, amely közvetlenül sehol sem kerül példányosításra. Felhasználására jó példa a Calf::wrap szubrutin vonatkozó része: my $object; my $type = $data->type; my $prefix = $type eq 'Scalar' ? '$' : $type eq 'Array' ? '@' : '%'; eval "tie my ${prefix}var, 'Calf::Tie::$type', \$proxy, \$data; \$object = \\${prefix}var";
A bemutatott kódrészlet két szempontból is érdekes. Egyrészről látható, hogy a típusnak megfelelő Calf::Tie osztály példányosításakor a konstruktor paraméterként kapja a $proxy változót,
amely
egy
Calf::DB::Proxy
objektum.
A
kötés
létrejötte
után
az
adatbázisműveleteket igénylő metódusok erre az objektumra fognak támaszkodni, azaz a fő
Konfiguráció-menedzsment verziókövetett objektumokkal $calf objektum referenciája nélkül, önállóan
49
képesek a megfelelő feladatok végrehajtására.
Másrészről tetten érhető a dinamikus programozási környezet előnyeinek kihasználása. A kód szemantikailag egy var nevű változót köt egy típusának megfelelő osztályhoz. A szintaktika elvárja a statikus sigilt, ami az eval használatával dinamikusan, futásidőben kerül meghatározásra. Az eval beépített függvény használata nélkül ez csupán egy nehezebben átlátható if-else szerkezettel lehetne megvalósítható, mi több, feleslegesen kellene deklarálni a három típusnak megfelelően három különböző változót, melyek közül végül csak egyet használna a program a kötéshez.
5.
Calf::Object csomagok
A Calf::Object nyújtja a keretrendszer kiterjeszthetőségéhez szükséges névteret. A Calf::Object
önmagában egy absztraktnak szánt ősosztály, amely kényelmes metódusokat ad
egy keretrendszerbeli objektum megvalósításához. A három primitív típusnak megfelelően előre adott
három
olyan
osztály,
amelyek
Calf::Object::Array, Calf::Object::Hash).
kiterjesztik
(Calf::Object::Scalar,
Az ősosztály szolgáltatás-gazdagságát jól
mutatja, hogy ezek gyakorlatilag üres Perl csomagok. A Calf::Object csomagban definiált metódusok a verziókövetett objektumok tipikus műveleteit adják, többek között: • type Az objektum, mint referencia által mutatott adatstruktúra típusát adja sztringként. Lehetséges értékei: Scalar, Hash, Array. • value Az objektum értéke, ha az objektum Scalar, vagy az objektum a paraméterben megadott kulcsához tartozó érték. A metódus lehetővé teszi a sigilek egységesítését, ugyanis használatával adattípustól függetlenül alkalmazható a $obj->value jelölés. A metódus balértéket szolgáltat, tehát valóban mindenhol alkalmazható. • commit Az objektumon adatain végzett módosítások perzisztálására szolgál. • copy Másolatot készít az objektumról, és a másolat referenciájával tér vissza. A művelet egy dimenzióig deep copy.
Konfiguráció-menedzsment verziókövetett objektumokkal
50
• attrs Az objektum attribútumainak listáját adja. • children Az objektumfa alapján a gyermekek neveit szolgáltatja. • name Az objektum neve. • id Az objektum belső azonosítója. • class Az objektum osztályának perzisztált azonosítója. Ez nem egy csomagnév, hanem egy másik Calf-beli objektum belső azonosítója, amely értékként szolgáltatja a csomagnevet. • bind Arra szolgál, hogy egy másik objektum adattagja – azonos néven – az adott objektum attribútum-halmazához dinamikusan kötődjön. Azaz, egyszerűen megvalósítható egyfajta szigorú öröklés az objektumok között és a következő állítás mindig igaz: HA $A->bind( 'x', $B->id ) AKKOR $A->value( 'x' ) eq $B->value( 'x' )
6.
Calf::DB csomagok
A Calf::DB::Proxy egy olyan objektumot ad, amelyen keresztül a keretrendszer többi objektuma közvetlen adatbázisműveleteket képes elvégezni. Egy Calf objektum egy példányt hoz belőle létre, melynek referenciáját minden adatbázisból lehívott objektumhoz kötött típusimplementáció példányosításakor átadja. A proxy egy Calf::DB objektumot használ a metódusainak megvalósításához, amely már a közvetlen DBI hívásokat implementálja. A Calf::DB sem tartalmaz viszont SQL utasításokat a keretrendszer hordozhatóságának érdekében. Ez a csomag úgymond a DBI-specifikus kódokat tartalmazza. Minden SQL utasítás egy SQL-dialektusnak megfelelő alcsomagban található. A jelenlegi implementáció a MySQL adatbáziskezelőt támogatja, ezért az ehhez szükséges SQL kódok a Calf::DB:mysql csomagból
érhetőek el.
Konfiguráció-menedzsment verziókövetett objektumokkal
7.
51
Calf::Data csomag
A Calf::Data a keretrendszer lelke. Ez egy olyan osztályt nyújt, amely az adatbáziskezelő rutinoktól teljesen független, és példányai az egyedi típusimplementációkat nyújtó objektumokat segítik. Az összes alacsony szintű, memóriában történő művelet megvalósítása itt található. A Calf::Data szerepének és a többi osztályhoz való viszonyának jobb megértéséhez lássunk egy szekvencia diagramot:
A diagram azt az esetet szemlélteti, amikor egy skalár típust rejtő objektum kap egy value üzenetet. A Calf::Object osztályból örökölt value metódus ebben az esetben a $$self skalárt szolgáltatja balértékként. Ennek elérésekor a Perl értelmező meghívja a változóhoz kötött Calf::Tie::Scalar
objektum megfelelő metódusát, amely az elrejtett Calf::Data objektum
attr metódusának segítségével fogja a hivatkozott értéket lekérdezni vagy módosítani. Utóbbi művelet szükség esetén Copy-On-Write technikával történik.
8.
A keretrendszer használatának bemutatása
A keretrendszer lehetőségeit jól demonstrálja a Calf::CLI csomag. Ez egy parancssoros felületet biztosít a Calf által nyújtott szolgáltatásokhoz. A példa kedvéért tételezzük fel, hogy a modellezendő feladat egy hoszt és egy rajta futó Tomcat kiszolgáló konfigurációjának menedzsmentje.
Konfiguráció-menedzsment verziókövetett objektumokkal
52
Tegyük fel továbbá, hogy az adatbázis lényegében üres, viszont adott egy proto objektum, amelynek gyermekei a scalar, array és hash objektumok, melyek rendre üres skalár, tömb és hash objektumokat adnak. $ bin/calf list / ROOT (1) proto (2) $ bin/calf list /proto scalar (3) hash (5) array (4)
Először hozzunk létre két objektumot az objektumfa gyökerében, amelyekre mint kollekciókra fogunk a későbbiekben tekinteni, attribútumaik érdektelenek (hasonlóan a proto objektumhoz): $ bin/calf copy proto/scalar hosts $ bin/calf copy proto/scalar servers $ bin/calf list / ROOT (1) hosts (6) proto (2) servers (7)
Ezután hozzunk létre egy objektumot a hosts objektum alatt, és állítsuk be: $ bin/calf copy proto/hash hosts/localhost $ bin/calf set hosts/localhost hostname localhost localhost $ bin/calf set hosts/localhost ip 127.0.0.1 127.0.0.1 $ bin/calf set hosts/localhost port_tomcat 8080 8080 $ bin/calf show hosts/localhost 8#3 port_tomcat : string ip : string hostname : string
Ezt követően hozzunk létre egy tomcat objektumot a servers objektum alatt, és konfiguráljuk: $ bin/calf copy proto/hash servers/tomcat $ bin/calf set servers/tomcat name tomcat tomcat $ bin/calf bind servers/tomcat hostname hosts/localhost $ bin/calf set servers/tomcat host hosts/localhost hosts/localhost
Konfiguráció-menedzsment verziókövetett objektumokkal
53
$ bin/calf show servers/tomcat 9#3 name : string hostname : delegate host: string $ bin/calf get servers/tomcat hostname localhost
Az eddigi beállítások eredménye egy olyan modell, amely tartalmaz egy hoszt objektumot, amelynek értelemszerű tulajdonsága a hostname és az ip, továbbá van egy port_tomcat attribútuma, amely a rajta futó szerver portszámát jelképezi. A modellben a port a hoszt tulajdonsága és nem a szerveralkalmazásé, ami pontosan tükrözi a valóságot. Létrehoztunk ezen kívül egy Tomcat objektumot egy egyedi szolgáltatás-azonosítóval, valamint hozzákötöttük a hostname attribútumot a host/localhost objektumhoz. Ennek köszönhetően a tomcat objektum hostname attribútumának értéke mint konfigurációs paraméter mindig a host/localhost objektum azonos nevű attribútumától függ. Beállítottunk továbbá egy host attribútumot, amelynek felhasználására a következőkben láthatunk példát. Adjunk saját implementációt ezeknek az objektumoknak az alábbi osztályokkal: package Calf::Object::Host; use strict; use warnings; use base 'Calf::Object'; sub showip($@) { my $self = shift; my $ip = $self->value( 'ip' ); print "IP: $ip\n"; } sub getport($@) { my $self = shift; my $calf = shift; my $service = shift; my $port = $self->value( "port_$service" ); return $port; }
Konfiguráció-menedzsment verziókövetett objektumokkal
54
package Calf::Object::Tomcat; use strict; use warnings; use base 'Calf::Object'; sub config($@) { my $self = shift; my $calf = shift; my $hostname = $self->value( 'hostname' ); my $host = $calf->checkout( name => $self->value( 'host' ) ); my $port = $host->getport( $calf, $self->value( 'name' ) ); print "host = $hostname\n"; print "port = $port\n"; }
Miután ezek adottak, változtassuk meg a meglévő localhost és tomcat objektumok típusát. Ehhez létrehozunk egy classes kollekciót, és azon belül az objektumoknak megfelelő osztályok neveit adó objektumokat. $ bin/calf copy proto/scalar classes $ bin/calf copy proto/scalar classes/Host $ bin/calf set classes/Host Calf::Object::Host Calf::Object::Host $ bin/calf copy proto/scalar classes/Tomcat $ bin/calf set classes/Tomcat Calf::Object::Tomcat Calf::Object::Tomcat $ bin/calf cast hosts/localhost classes/Host $ bin/calf cast servers/tomcat classes/Tomcat
A modellezés ezzel lényegében kész. Az elkészített objektumok a parancssoros felület által nem definiált metódusaikat a Calf::Object::Host, illetve Calf::Object::Tomcat osztályokból veszik, így a Tomcat szerver konfigurációja a config metódus egyszerű hívásával kapható: $ bin/calf config servers/tomcat host = localhost port = 8080
A portszám valóban dinamikus beállítás, az eredeti hoszt objektumon történő módosítás hatással van a tomcat objektumra is: $ bin/calf set hosts/localhost port_tomcat 4242 4242 $ bin/calf config servers/tomcat host = localhost port = 4242
Konfiguráció-menedzsment verziókövetett objektumokkal
55
Továbbá megtekinthető az eredeti objektum korábbi változatában található attribútum értéke: $ bin/calf get hosts/localhost#4 port_tomcat 8080
Végezetül lássuk a keretrendszer lényeges függvényhívásait és a fontosabb adatszerkezeteket egy attribútum értékének beállításakor: $ bin/calf set servers/tomcat dir /var/www/tomcat -d INFO: Calf::DB::Proxy::lookup: 1/servers is 7 (db) INFO: Calf::DB::Proxy::lookup: 7/tomcat is 9 (db) INFO: Calf::DB::Proxy::head: 9#HEAD is 4 (db) INFO: Calf::DB::Proxy::fetch: fetched 9#4 (db) DEBUG: Calf::DB::Proxy::fetch: fetched object data $data = { 'obj' => { 'obj_id' => '9', 'type_id' => '5', 'tie' => 'HASH', 'class' => '12', 'obj_rev' => '4' }, 'attr' => { 'name' => { 'attr_key' => 'name', 'attr_val' => 'tomcat', 'attr_type' => 'string', 'attr_ref' => undef, 'attrval_id' => '5', 'attrkey_id' => '5' }, 'hostname' => { 'attr_key' => 'hostname', 'attr_val' => undef, 'attr_type' => 'delegate', 'attr_ref' => '8', 'attrval_id' => '6', 'attrkey_id' => '6' }, 'host' => { 'attr_key' => 'host', 'attr_val' => 'hosts/localhost', 'attr_type' => 'string', 'attr_ref' => undef, 'attrval_id' => '7', 'attrkey_id' => '7' } } }; INFO: Calf::DB::Proxy::head: 12#HEAD is 1 (db) INFO: Calf::DB::Proxy::fetch: fetched 12#1 (db)
Konfiguráció-menedzsment verziókövetett objektumokkal
56
DEBUG: Calf::DB::Proxy::fetch: fetched object data $data = { 'obj' => { 'obj_id' => '12', 'type_id' => '1', 'tie' => 'SCALAR', 'class' => undef, 'obj_rev' => '1' }, 'attr' => { 'value' => { 'attr_key' => 'value', 'attr_val' => 'Calf::Object::Tomcat', 'attr_type' => 'string', 'attr_ref' => undef, 'attrval_id' => '9', 'attrkey_id' => '9' } } }; /var/www/tomcat DEBUG: Calf::DB::Proxy::store: store object data $diff = { 'obj' => { 'obj_id' => '9', 'dirty' => 1, 'type_id' => '5', 'tie' => 'HASH', 'class' => '12', 'obj_rev' => '5' }, 'attr' => { 'dir' => { 'attr_key' => 'dir', 'attr_val' => '/var/www/tomcat', 'attr_type' => 'string' } } }; INFO: Calf::DB::Proxy::store: 9#5 stored
A fenti példában a hibakereső módban indított calf szkript egy attribútum értékének frissítése közben meghívott metódusokat és a közben felépített adatszerkezeteket mutatja. Jól látható, hogy először az elérni kívánt objektum nevének rekurzív feloldása történik, majd az objektum belső azonosítójának ismeretében (9) a legfrissebb verziószám (#4) meghatározása. Ezt követi annak az objektumnak a betöltése amely az előző csomagnevét tartalmazza. Végezetül a frissített attribútum egy új objektum-verzióval eltárolódik az adatbázisban.
Konfiguráció-menedzsment verziókövetett objektumokkal
57
A CD mellékleten megtalálható a keretrendszer teljes forráskódja, a használatbavételhez szükséges SQL szkripttel és a bemutatott példakóddal együtt.
Konfiguráció-menedzsment verziókövetett objektumokkal
Irodalomjegyzék
1: http://en.wikipedia.org/wiki/Configuration_management 2: ftp://ftp.software.ibm.com/software/tivoli/datasheets/TID10375-USEN-00.pdf 3: http://documents.bmc.com/products/documents/82/35/48235/48235.pdf 4: http://www.w3.org/XML/ 5: http://tools.ietf.org/html/rfc4511 6: http://www.microsoft.com/windowsserver2008/en/us/active-directory.aspx 7: Gajdos Sándor: Adatbázisok 8: http://mysql.com/ 9: Larry Wall, Tom Christiansen, Jon Orwant: Programming Perl, Third Edition 10: http://search.cpan.org/ 11: http://perldoc.perl.org/functions/ref.html 12: http://en.wikipedia.org/wiki/Sigil_(computer_programming) 13: http://perldoc.perl.org/perlboot.html 14: http://perldoc.perl.org/perltie.html
58