A következő címkéjű bejegyzések mutatása: script. Összes bejegyzés megjelenítése
A következő címkéjű bejegyzések mutatása: script. Összes bejegyzés megjelenítése

2014. szeptember 28., vasárnap

WTF - Megváltozott filerendszer mount pointok migrálás után

Aki már migrált valaha bármilyen régebbi rendszert bármilyen újra, az kb tudhatja hogy változatosabbnál változatosabb csapdákba futhat bele az ember időnként. Ez most se volt másként...

Adott egy régi Power4es szerver amin épp egy 5.2es AIX futkározik. Tekintve hogy ez a HW már jó ideje nem támogatott, sok helyet is foglal, meg amúgy is lassú, így fent az a döntés született, hogy konszolidálni kéne a szervert egy modernebb Power7es infrastruktúrába.
Hogy hogyan is? Hát van több fajta megoldás, csak tudni kell kiválasztani melyik a legcélravezetőbb:
- Live Partition Mobility: Ha a forrás és a cél rendszerek mind szépen virtualizálva vannak, és a szükséges feltételek mind adottak, akkor kiesés nélkül át lehet költöztetni az LPARt 2 fizikai rendszer között
- Lift and Shift: Ha a rendszer és az adatok is külső SAN-on vannak, akkor minimális leállás után át lehet zónázni a LUN-okat egy másik gépre és ott használni őket.
- Backup and restore: Ez esetben minimum a rendszer belsős lemezekre lett telepítve, így annak költöztetése csak egy mksysb backup segítségével megoldható, amit a távoli gépen aztán vissza lehet tölteni (akár WPAR-ba is). Ha mázlink van, akkor az adatok SAN-on helyezkednek el, így a specifikus LUN-okat át lehet simán zónázni a cél géphez; ha viszont nincs mázlink, akkor ezt is hálózaton keresztül valahogy át kell juttatni a cél gép felé (savevg, GLVM, vagy sima tar+ssh pipe)
- Rebuild from scratch: Ebben az esetben az alap rendszert (illetve opcionálisan a Middleware, Applikációt is) teljesen nulláról építjük újra, majd a szolgáltatáshoz szükséges további adatot átemeljük a forrás rendszerről és beillesztjük az újonnan felépített struktúrába.

Lehet meglepő, de régebbi rendszereknél az utóbbi sokszor a legcélravezetőbb, mivel ezeknél valószínű nem csak a rendszer régi, hanem annak komponensei is, így egy-egy ilyen migráció kiváló alkalmat ad arra, hogy az ember végre kidobálja a régi legacy szutykokat, és egy támogatott megoldással helyettesítse őket.

Ebben az esetben a legcélravezetőbbnek az utolsó 2 megoldás keveréke bizonyult a legjobbnak: Az alaprendszert nem volt értelme átköltöztetni, a régi -már nem támogatott- middleware komponenseket egy részét szerencsére volt lehetőség támogatottra cserélni, más komponenseket viszont simán át lehetett emelni a régi rendszerről a szükséges LUN-ok újrazónázásával.

A tényleges lépésekre most nem térek ki, -a bejegyzés szempontjából érdektelenek- egyet kivéve: Miután a LUN-okat az ember átzónázza Volume Groupot ismét be kell importálni a rendszerbe, hogy az adathoz hozzá lehessen férni. A folyamat részeként a teljes LVM struktúra importálódik a fájlrendszerekkel egyetemben. Igen ám, de volt egy kisebb probléma.. Az importálás után a legtöbb fájlrendszer szépen vissza is került a helyére, viszont volt 1-2 aminek a mount pointja megváltozott (ettől eltekintve az adat szépen a helyén volt). A kérdés adott volt: Miért?

No, a technikai része a blog bejegyzésnek kb. innen indul :)) Lássuk mi és hogy zajlik le egy ilyen importálás során:
- Az importálás során az importvg szépen felolvassa a megjelölt diszk VGDA adatait
- A VGDA adatok alapján ellenőrzi a VG-hez szükséges PV-k elérhetőségét (PVID alapján), illetve összeveti azok VGDA adatait (VG_ID) a többi PV-n találhatóakkal.
- Amennyiben az összes PV elérhető, és a VGDA is konzisztensen azonos adatot mutat, úgy felolvassa a teljes LVM struktúrát
- A struktúra része az adott LV-k definiciói (típus, név, méret, upper bound), azok elhelyezkedése (LP/PP-k elhelyezkedése PV-re lebontva), illetve 1-2 további metaadat (létrehozási idő, utolsó módosítási idő, label, vfs specifikus adatok)
- Miután a teljes struktúrát feltérképezte létrehozza a szükséges bejegyzéseket az ODM-ben, illetve a /etc/filesystems-ben, majd ezek alapján aktiválja a VG-t

Nem tudom kinek tűnik fel, de fájlrendszer specifikus adatokat az importvg nem olvas fel, még is módosítja a /etc/filesystems file-t.. Hogy van ez?

Na igen. Itt van a kutya elásva. Igaz, hogy FS specifikus adatot nem olvas fel, viszont nem is kell neki: A metaadatokban ott van minden amire szüksége van ahhoz, hogy egy fájlrendszert mountolni lehessen.

Itt egy pelda a /home FS (hd1 LV) LVM descriptorának elejéről:

3D8220000 41495820 4C564342 00006A66 73320000 |AIX LVCB..jfs2..| # LVM Control Block, LV type 3D8220010 00000000 00000000 00000000 00000000 |................| 3D8220020 00000000 00000000 00003030 63306164 |..........00c0ad| # LV serial ID 3D8220030 31653030 30303463 30303030 30303031 |1e00004c00000001| 3D8220040 34320068 64310000 00000000 00000000 |42.hd1..........| 3D8220050 00000000 00000000 00000000 00000000 |................| 3D8220060 00000000 00000000 00000000 00000000 |................| 3D8220070 00000000 00000000 00000000 00000000 |................| 3D8220080 00000053 756E204E 6F762031 30203231 |...Sun Nov 10 21| # Creation date 3D8220090 3A30393A 34382032 3031330A 00000000 |:09:48 2013.....| 3D82200A0 00576564 204A756C 20323320 30393A31 |.Wed Jul 23 09:1| # Last modification date 3D82200B0 353A3338 20323031 340A0000 00000030 |5:38 2014......0| 3D82200C0 41443145 34433030 00796D63 00790020 |AD1E4C00.ymc.y. | 3D82200D0 00010001 2F686F6D 65000000 00000000 |..../home.......| # Label 3D82200E0 00000000 00000000 00000000 00000000 |................| 3D82200F0 00000000 00000000 00000000 00000000 |................| 3D8220100 00000000 00000000 00000000 00000000 |................| 3D8220110 00000000 00000000 00000000 00000000 |................| 3D8220120 00000000 00000000 00000000 00000000 |................| 3D8220130 00000000 00000000 00000000 00000000 |................| 3D8220140 00000000 00000000 00000000 00000000 |................| 3D8220150 00000000 7666733D 6A667332 3A6C6F67 |....vfs=jfs2:log| # VFS data 3D8220160 3D2F6465 762F6864 383A6D6F 756E743D |=/dev/hd8:mount=| 3D8220170 74727565 3A636865 636B3D74 7275653A |true:check=true:| 3D8220180 766F6C3D 2F686F6D 653A6672 65653D66 |vol=/home:free=f| 3D8220190 616C7365 3A71756F 74613D75 73657271 |alse:quota=userq| 3D82201A0 756F7461 2C67726F 75707175 6F746100 |uota,groupquota.|

Mielőtt valaki nekem ugrik, hogy de ezek fájlrendszer adatok: Nem, az 8000(h) blokkal arrébb van:

3D8228000 4A324653 00000002 00000000 527FF623 |J2FS........R..#| 3D8228010 00000000 00000000 00000000 00002F68 |............../h| 3D8228020 6F6D6500 00000000 00000000 00000000 |ome.............|

Jó. De ha ott megtalálható az adat, akkor miért nem az alapján dolgozik az importvg? A válasz erre nagyon egyszerű: Mert ott az se a mount point :)

De akkor várjunk csak egy pillanatot.. Itt van 2 olyan példa is, ahol egyértelműen látszik, hogy ott van a /home, de ez mégse a mount point? Hülyén hangzik, mi? :)) Nézzünk egy másik példát, és akkor már talán tisztább lesz. Legyen a példa a /var/adm/ras/livedump filerendszer (livedump LV):

LVM descriptor eleje:

1BC220000 41495820 4C564342 00006A66 73320000 |AIX LVCB..jfs2..| # LVM Control Block, LV type 1BC220010 00000000 00000000 00000000 00000000 |................| 1BC220020 00000000 00000000 00003030 63306164 |..........00c0ad| # LV serial ID 1BC220030 31653030 30303463 30303030 30303031 |1e00004c00000001| 1BC220040 3432006C 69766564 756D7000 00000000 |42.livedump.....| 1BC220050 00000000 00000000 00000000 00000000 |................| 1BC220060 00000000 00000000 00000000 00000000 |................| 1BC220070 00000000 00000000 00000000 00000000 |................| 1BC220080 00000053 756E204E 6F762031 30203231 |...Sun Nov 10 21| # Creation date 1BC220090 3A30393A 35302032 3031330A 00000000 |:09:50 2013.....| 1BC2200A0 0053756E 204E6F76 20313020 32313A31 |.Sun Nov 10 21:1| # Last modification date 1BC2200B0 313A3530 20323031 330A0000 00000030 |1:50 2013......0| 1BC2200C0 41443145 34433030 00796D6D 00790020 |AD1E4C00.ymm.y. | 1BC2200D0 00040001 2F766172 2F61646D 2F726173 |..../var/adm/ras| # Label 1BC2200E0 2F6C6976 6564756D 70000000 00000000 |/livedump.......| 1BC2200F0 00000000 00000000 00000000 00000000 |................| 1BC220100 00000000 00000000 00000000 00000000 |................| 1BC220110 00000000 00000000 00000000 00000000 |................| 1BC220120 00000000 00000000 00000000 00000000 |................| 1BC220130 00000000 00000000 00000000 00000000 |................| 1BC220140 00000000 00000000 00000000 00000000 |................| 1BC220150 00000000 7666733D 6A667332 3A6C6F67 |....vfs=jfs2:log| # VFS data 1BC220160 3D2F6465 762F6864 383A6D6F 756E743D |=/dev/hd8:mount=| 1BC220170 74727565 3A616363 6F756E74 3D66616C |true:account=fal| 1BC220180 73653A71 756F7461 3D6E6F00 00000000 |se:quota=no.....| 1BC220190 00000000 00000000 00000000 00000000 |................| 1BC2201A0 00000000 00000000 00000000 00000000 |................| 1BC2201B0 00000000 00000000 00000000 00000000 |................| 1BC2201C0 00000000 00000000 00000000 00000000 |................| 1BC2201D0 00000000 00000000 00003433 64393432 |..........43d942| 1BC2201E0 62342E31 31000000 00000000 00000000 |b4.11...........| 1BC2201F0 00000000 00000000 00000000 00000000 |................|

FS descriptor eleje:

1BC228000 4A324653 00000002 00000000 527FF62C |J2FS........R..,| 1BC228010 00000000 00000000 00000000 00002F76 |............../v| 1BC228020 61722F61 00000000 00000000 00000000 |ar/a............|

Na, ki veszi észre mi a hiba az utóbbi példában? :) Igen, az FS descriptorban lévő adat nem egyezik meg az LVM descriptorban lévő labellel. Hogy miért? Azért mert az FS descriptorban lévő adat csak 6 karakter hosszú minden eseteben.
Jó, következő kérdés: Ennek így mi értelme? Nos, az AIX a boot folyamán ezt a 6 karaktert használja a boot során (Step 2, nem összekeverni az rc2-vel!) hogy visszaellenőrizze az FS-t adatait (felmerült már bárkiben, hogy a rendszer indításához szükséges fájlrendszerek mount pointja miért olyan rövid mindig? :))
Na jó.. Innentől a kérdés már csak az, hogy a mount pointok akkor hol vannak letárolva? Hát ez az.. A /etc/filesystems file alatt. És csak ott. Minden más csak "tájékoztató jellegű", kb. mint a MÁV menetrendje.

Visszatérve az eredeti szálra már látszik, hogy milyen csapdáról beszéltem: Az importálás során ezek a definíciók nem elérhetőek a /etc/filesystems alatt, az FS descriptorra se lehet támaszkodni ilyenkor, így hát marad az LVM descriptorban lévő Label.
Igen ám, de mi van akkor ha valaki megváltoztatja egy FS mount pointját és ehhez nem a megfelelő chfs parancsot használja, hanem manuálisan szerkeszti a /etc/filesystems filet? Pontosan.. Inkonzisztencia.. Minden szépen működni is fog egészen addig, amíg az ember egy ehhez hasonló VG importot nem akar végrehajtani (hisz a rendszer minden boot során ezen file alapján fogja bootolni a filerendszereket), amikor is az importvg/recreatevg neme egyszerűséggel felülvágja a /etc/filesystems-ben található adatokat a Label-ben található adatokkal.

Jó.. már értem.. Azt hiszem.. Hogy tudok meggyőződni arról, hogy nálam ilyen nem fordul elő?
A legegyszerűbben az lslv kimenetéből tudod megnézni a Label-t. Ha abban a szerencsétlen helyzetben találod magad, hogy nem tudod lslv-vel lekérdezni az LV-ket, de a diszkek még elérhetőek (és nem akarsz egy importvg-t megkockáztatni), akkor ezzel a kis scripttel le tudod kérni direktben a diszkekről a label-eket:

Példa kimenet:

# read_labels_directly_from_disk.sh hdisk0 hdisk0 / smallvg / 64 MB PP size ******************* ....primary_bootlv.............................. / hd5 - 64 MB / 1 (220000) / hdisk0 ....None........................................ / hd6 - 512 MB / 104 (19C220000) / hdisk0 ....None........................................ / hd8 - 64 MB / 206 (334220000) / hdisk0 ..../........................................... / hd4 - 192 MB / 207 (338220000) / hdisk0 .#../usr........................................ / hd2 - 2240 MB / 210 (344220000) / hdisk0 ..../var........................................ / hd9var - 256 MB / 241 (3C0220000) / hdisk0 ..../tmp........................................ / hd3 - 768 MB / 245 (3D0220000) / hdisk0 ..../home....................................... / hd1 - 64 MB / 247 (3D8220000) / hdisk0 ..../opt........................................ / hd10opt - 384 MB / 248 (3DC220000) / hdisk0 ..../admin...................................... / hd11admin - 128 MB / 250 (3E4220000) / hdisk0 ..../var/adm/ras/livedump....................... / livedump - 256 MB / 112 (1BC220000) / hdisk0 ....None........................................ / dumplv - 1280 MB / 479 (778220000) / hdisk0 ....None........................................ / dumplv2 - 1280 MB / 269 (430220000) / hdisk0

# Érdekesség: A módszer kicsit más és más VG típusonként, így aki érdeklődik a tényleges struktúra után, az nyugodtan kukkantson bele a scriptbe :) (kis matek tudás azért nem fog ártani)

2014. június 10., kedd

Amikor RAMBO kifogy a RAMbó..

Egy újabb nap, egy újabb kihívás.. Legalább is ezt mondják a hangok odafent. Gyakorlatilag az irodába beérkezve az alábbi "köszöntő" fogad: "A szerver nem elérhető, csinálj valamit!". Jaj de jó, ismét valami ami elé hulla fáradtan le lehet ülni, hogy aztán még jobban lefárasszam magam. Na mindegy, nézzük miből élünk..

Ránézek a szerverre: pingelni lehet, barmiféle kapcsolatot nyitni viszont nem.
HMC-ről nyitott virtual konzolról megvizsgálva a kérdést se jobb a helyzet, csupán a temérdek "unable to fork" hibaüzenet igazolja az eddigi teóriát, hogy bizony itt elfogyott a gép alól a fizikai memória, és még csak azért van életben, mert a paging space-ből még maradt valami ahova ki lehet lapozni azt a kevés memória területet amit a rendszer képes volt felszabadítani.

Mit lehet ilyenkor tenni? A lehetőségeink lényegében az alábbi 3 opcióra korlátozódnak:
- Imádkozunk, hogy a terhelés egy idő után megszűnik, és felszabadul annyi memória, hogy a szervert ismét életképes állapotba lehessen hozni
- Várni hogy az OOM killer végre működésbe lépjen, vagy hogy a rendszer összeessen magától
- Manuálisan újraindítani az egész mindenséget és behúzni +1 strigulát a service outage rubrika mellé

A kérdés már csak az, hogy a 3 opció közül melyik az, amelyik számunkra ÉS a customer számára is elfogadható. Jó, beszélgessünk el a customerrel, hogy akkor mi és hogyan, illetve próbáljunk meg rájönni, hogy melyik opciót is érdemes választani. Valami ilyesmit képzeljetek el:
- A szerviz számára fontos a szerver?
- Naná hogy az, production szerver, 7x24ben elérhetőnek kéne lennie
- A fontosabb szolgáltatás(ok) elérhető(ek)?
- Hááát ami azt illeti igen, csak épp lassú mint a fene.
/* tehát nincs szerviz kiesés, ami azt jelenti, hogy a fontosabb programok még a memóriában elvannak valahogy és onnan még tudnak úgy-ahogy működni is*/
A fontosabb dolgok hála az égnek mennek, de például az utóbbi 4 beütemezett job failed-re futott /* naná, valószínű el se tudott indulni */
- A nem elérhető részek mennyire business kritikusak?
- Hát.. Kis kiesés még belefér, de hosszútávon már komoly problémákat okoz ha a jobok nem futnak le.
- Tudnak e olyan jobról ami ebbe az idő-ablakba lett ütemezve, és esetleg erősen erőforrás igényes lehet?
- Nem, azok a hétvégére vannak csak beütemezve
- Jó. Tehát a szerviz még elérhető, bár funkcionálisan korlatozott. Mivel jelenleg nem tudunk a rendszerről barmit lekérni, így sajna megbecsülni se tudjuk hogy ez a hibajelenség tartós avagy ideiglenes e. A rendszer teljes újraindításával biztosan vissza tudjuk állítani a rendet, viszont az a szolgáltatás ideiglenes, ám teljes kiesésével is jár. Kérdés hogy ez a szerviz szempontjából elfogadható e, vagy inkább várjunk még egy kis időt, hogy hátha magától megszűnik a magas memória terhelés?
- Hát.. A szolgáltatás szempontjából a helyzet nem kritikus, viszont így nem is lehet a rendszert adminisztrálni. A következő fontos job kb 2 óra múlva indulna. Ha az se tud lefutni, az már komoly pénzbeli veszteség lenne a cégnek. Kb mennyi időt vesz igénybe a teljes rendszer újraindítása?
- Az újraindítás viszonylag gyorsan megvan, a visszaellenőrzések viszont eltartanak egy minimum 20 percig. Számoljunk 30 percet mindenre biztos ami biztos.
- Rendben. Akkor még kb 1 órát tudunk várni, és akkor még lesz 30 percünk az esetleges hibaelhárításra. Ha addig se jön helyre a szerver, akkor indítsák újra.

Ok.. Kapott a szerver 1 óra haladékot, hogy bebizonyítsa milyen fából is faragták. Közben azért érdemes elgondolkodni, hogy mi is mehet épp végbe az AIX mélyebb bugyraiban (kernel szinten):
- A rendszer már kidobált minden nem szükséges adatot a fizikai memóriából (temporary cache már tuti nincs, ami még kell és kilapozható az meg már biztosan a paging space-en található)
- Ettől függetlenül a fizikai memóriában nincs szabad hely, ergo új process-t se lehet nyitni/forkolni. /* épp ezért nem is lehet belépni a gépre, mivel ott is minimum egy új shell-t kéne forkolnia a rendszernek */
- Azok a processek amik már a memóriában vannak még képesek funkcionálni /* ezért is képes a szolgáltatás még úgy ahogy életben maradni */
- A rendszer folyamatosan törekszik kiszolgálni a bejövő memória igényeket, illetve fizikai memóriát felszabadítani további page-ek kilapozásával.
- Amennyiben az egységnyi idő alatt bejövő memória kérések száma magasabb mint amit a rendszer adott idő alatt fel tud szabadítani, akkor lényegében egy meglehetősen kellemetlen hógolyó effektus következik be, mivel a futó program által kért memória terület biztosan valami adat számára lett kikérve, - amit a rendszer viszont ilyen esetekben hajlamos gyorsan ki is lapozni - ami viszont csak tovább rontja a helyzetet, mivel a diszken lévő paging sebessége kb egy kerékbilincses csigáéhoz hasonlítható a fizikai memóriához képest => ilyen helyzetben a nagy paging space csak a haláltusát hosszabbítja meg, de ténylegesen nem segít semmit /* főleg ha a process még később vissza is akar olvasni valamit amit a rendszer ma előzőleg kilapozott */
- Ez az állapot addig fennáll amíg az elérhető virtuális (!) memória le nem csökken egy bizonyos szintig: Amikor az elérhető virtualis memory page-ek száma eléri az VMO npswarn értékét (4k-ban tessek számolni), akkor a rendszer kiküld mindenkinek egy SIGDANGER signalt, hogy lehetőséget adjon a processeknek konzisztensen leállni (már ha fel vannak készítve arra hogy az ilyen signal-al kezdjenek valamit). Amennyiben a memória kihasználtság ez után eléri a VMO npskill értékét (vagy mert a programok ignorálták a signalt, vagy mert nem bírtak időben leállni), akkor a kernel szisztematikusan elkezdi legyilkolászni a legfiatalabb processeket amikre "engedélyé van": Ez kb annyit jelent, hogy a process owner UID-ja nincs felsorolva a VMO nokilluid listáján /* alapból pl a 0as UID van ott, ami annyit jelent, hogy a root neve alatt futó processeket a rendszer nem fogja legyilkolni */
- Amennyiben a rendszer nem képes ezzel a módszerrel se memóriát felszabadítani akkor a paging space teljes felhasználása után egy garantált system crash következik, amit aztán egy automatikus restart követ.

A fenti példából azért látszik, hogy van olyan forgatókönyv is, amikor a szerviz számára fontos programot a rendszer nemes egyszerűséggel legyilkolja (már ha a hozza köthető UID nincs rajta a nokilluid listán), ami kb csak 1 fokkal jobb csak a teljes újraindításnál :)
#Megjegyzés - ez azt is jelenti, hogy a fenti VMO paraméterek finomhangolásával amúgy simán életben is lehet tartani egy gépet restart nélkül, csak akkor készüljünk fel arra, hogy időnként 1-2 programot lehet újra kell majd indítgatni.

Eltelt 1 óra.. Sajnos a rendszer nem volt képes visszarángatni magát a valóságba, így az ügyfél kérésére azt újra kellett indítani. Na jó.. de hogyan? Ne tessek félre érteni, nem az a kérdés, hogy milyen paranccsal, vagy min keresztül (HMC azért jó ha van :)). A kérdés inkább arra irányul, hogy azonnal újra kell e indítani mindent, vagy esetleg adunk a rendszernek még 1-2 percet hogy ha már eddig eljutott akkor dobjon már egy system dumpot is, amiből esetleg később még tudunk vizsgálódni. Ismerve a managementet, az utóbbi garantáltan megfontolandó (még akkor is ha nem azonnal indul újra az LPAR), tekintve, hogy biztosan el fog hangzani az a kérdés, hogy "Jó, de mi tömte tele a memóriát?"

# Jó tanács: Mielőtt a Windows-on nevelkedett adminok nekiállnának azonnal újraindítani 1-1 gépet, inkább tanulják meg az alábbi parancsot használni HMC-ről:
chsysstate -m $MACHINE -r lpar -o dumprestart -n $PARTITION

Kb 5-10 percbe telt mire a gép mindent kidumpolt a memóriából, majd elkezdte szépen újraindítani a rendszert, amit gyors program indítgatások és visszaellenőrzések követtek, így a szerviz ismét teljesen elérhető lett és a customer számára kritikus job is le tudott futni minden gond nélkül.. Éljen.. An other success story, good job, well done, champaign.. Na jó, nem egészen..
További kb 1-1,5 órán át még ment a beszélgetés illetve az összefoglalók írása, miután elhangzott customer oldalról az a kérdés amire előzőleg egy meglehetősen nagy fogadást mertem volna kötni: "Ki tudjuk deríteni, hogy mi okozta ezt? Vagy van valami módszer arra, hogy ezt megelőzzük?"
Látjátok, mondtam én :)

Mázlira a dump device-al, és annak beállításaival semmi gond nem volt (dump compression bekapcsolva, dump device mérete megfelelő) és volt is elég hely ahhoz, hogy a dumpot kimásolva egy fájlrendszerre, majd kitömörítve el lehessen kezdeni analizálni, hogy végül is mi a franc volt a géppel.
Persze ahhoz hogy ezt megválaszoljuk azért nem árt tudni, hogy mi is helyezkedik el a memóriában. A teljesség igénye nélkül itt egy kis összefoglaló:
- A kernel számára lefoglalt memória terület (erre szoktak még System occupied memory néven is hivatkozni, ami magában foglalja magát a kernelt (és annak moduljait), a kernel heap-et, a shared memory szegmenseket, memory buffert, kernel cache-t, és a shared library-knak fenntartott memória területet)
- Fájlrendszer cache /* AIX esetében ez JFS, JFS2, NFS cache-t jelent */
- Különböző HW-ek számára fenntartott caching area
- Processek indító binárisainak (futó process binárisa kötelezően a fizikai memóriában helyezkedik el) és esetleges privát library-knek fenntartott memória terület
- A processek számára fenntartott privát memória területek (minden processnek saját memória terület, saját virtuális memória címzéssel)

Kezdjük is azzal ami a legtöbb problémát szokta okozni: Azok a fránya programok. Csak hogy szemléltessem hogy mennyire (nem)vicces tud egy ilyen nyomozás lenni, már itt leszegezem hogy ennek vizsgálatára nyomban 3 különböző módszer van, amik mind mást-mást néznek (ergo más-más eredményt is produkálnak) ... csak hogy az ember élete egyszerű legyen ...
- a kdb-nek van beépített svmon parancsa, ami meglehetősen jól visszaadja az aktuális állapotot, viszont bizonyos helyzetekben hajlamos nem működni. Naná hogy ez is pont egy olyan helyzet:
(0)> svmon * Pid Command Inuse Pin Pgsp Virtual 64-bit Mthrd LPage [kdb_read_mem] no real storage @ F10013AE4747FF70

- Minden process-től ki lehet kérni az éppen lefoglalt fizikai és paging lapokat (nvpages és npsblks értékek) a proc alparancs segítségével, viszont összehasonlítva egy (működő) svmon kimenetével egyértelműen látható, hogy ez nem a ténylegesen lefoglalt összes virtuális memóriát adja vissza, hanem annak csak egy részét (az svmon kimenetéből csupán a working storage és shared library data összegét vagyunk képesek így megállapítani; a heapet, illetve a kernel segment-eket nem). További kellemetlenség, hogy ezt minden egyes processre meg kell vizsgálni, ami vagy egy script formájában történhet meg, vagy sok, türelmesen beírogatott proc es grep parancsok kombinációjával /* a script lassú, kézzel meg még lassabb - marad a script */
# for i in $(echo 'proc *' |kdb dump_file_copy|awk '{print $1}') > do > echo "proc $i" |kdb dump_file_copy |awk '/ nvpages/ || /^pvproc/ {print $3}' | \ > awk 'NR == 1 { printf("%s", $0); } NR != 1 { printf(" %s", $0); } END { printf("\n") }' > done |sort -r -k2 |sed "s/://g" |head -10 java 000000000001F7FC -> ~ 503.9 MB java 000000000001545D -> ~ 340.3 MB java 0000000000007A43 -> ~ 122.2 MB java 00000000000065F0 -> ~ 101.9 MB kuxagent 00000000000024A1 -> ~ 36.6 MB java 0000000000001951 -> ~ 25.3 MB k07agent 000000000000140F -> ~ 20 MB cimserve 0000000000001088 -> ~ 16.5 MB kulagent 0000000000000C37 -> ~ 12.2 MB aixdp_da 0000000000000C02 -> ~ 12 MB
# Megjegyzés - már itt látható, hogy még így is lesznek később problémáink a processek pontos behatárolásával, tekintve, hogy a "java" process rohadtul nem mondja meg, hogy a JVM-en belül mi futott. Erre később még visszatérünk.

- az scb alparancs segítségével is ki lehet kérni az nvpage-eket (process azonosítóra szűrve), itt viszont már a rendszerhez rendelt page-ek is listázva lesznek, ergo szerintem ez a leghasználhatóbb módszer (már ha az svmon valamiért nem működne), plusz az előzőhöz képest jóval gyorsabb is az alap vizsgalat (mivel a page-eket egy körben le tudjuk kérni), viszont itt az is bejön, hogy 1 process több page-et is használhat (már ha többszálusított programról beszélünk), így ezt a vizsgálat során külön figyelembe kell venni. Ezen felül a szűrt processekre (mondjuk top10) így is kell egy extra fork a proc alparanccsal, szóval hiába gyorsabb, attól még azért eléggé macerás így is:
# PVPROC_=""; VPGS_="0" # echo "scb -c 6 0" |kdb dump_file_copy |grep -v 0000000000000000 |grep -w W |awk '{print $10,$7}' |sort | \ > awk '{gsub ("MB","")}{if ($2 ~ "GB") {sub ("GB","");print $1,$2*1024,$3} else {print}}' | while read PVPROC VPGS > do > if [ "${PVPROC}" == "${PVPROC_}" ] > then > VPGS="$(echo ${VPGS_}+${VPGS} |bc)" > else > echo "${PVPROC_} ${VPGS_} ${PGSP_}" > fi > PVPROC_="${PVPROC}" > VPGS_="${VPGS}" > done| sort -rn -k2 |head -10|while read PROC VPGS PGSP > do > printf "%-15s %-15s %-15s\n" \ > $(echo "proc $PROC"|kdb dump_file_copy |awk '/^pvproc/ {printf ("%d %s", "0x"$5, $3)}') "${VPGS} MB" > done 15597570 java 571.6 MB 7274716 java 374.1 MB 4653250 java 271.1 MB 14745724 java 102.9 MB 0 swapper 83.7 MB 3866808 rmcd 61.6 MB 6094860 java 50.3 MB 10354744 kuxagent 38.0 MB 8192024 cimserve 31.5 MB 6946818 k07agent 22.5 MB

Szupi.. akkor most már van valami hozzávetőleges fogalmunk is arról, hogy mi mennyit zabált. nézzük mennyi memória is alt rendelkezésre:
(0)> vmstat |grep "total lru frames" total lru frames (4K units) : 00000000000E53E0 3.6GB
Őőőőőő.. Állj.. A számok valahogy nem stimmelnek: Ha megnézzük, akkor az top10 process is csak kb 1.6 GB-ot volt képes lefoglalni, ami közel sincs a teljes 3.6 GB-hoz (HW cache nélkül). Ami azt jelenti, hogy valamit vagy nagyon sikerült benézni, vagy máshol van Lessie elásva. 1 lépés előre, 3 lépés vissza, kezdjük elölről, de most inkább kezdjük a vizsgálódást magasabb szintről és csak utána menjünk alacsonyabb szintekre:

Fizikai memória (poolonként lebontva - mázlira itt csak 1 pool volt)
(0)> memp * VMP MEMP NB_PAGES FRAMESETS NUMFRB F1000F0009540000 00 000 000E7440 000 001 002 003 000008D4 ^^^^^^^^ ^^^^^^^^ 3700.25 MB 8.8 MB
3700 MB (3.6 GB) fizikai memória összesen, ebből 8,8 MB szabad a dump pillanatában. Eddig stimmt. Nézzük a paginget
(0)> vmker |grep pgsp |egrep "^total|^free" total pgsp blks (numpsblks) : 001A8000 -> 6784 MB free pgsp blks (psfreeblks) : 0010DDE4 -> 4317.8 MB
6.625 GB paging, ebből közel 4.2 GB szabad. Eddig is klappol a történet.
(0)> vmstat |egrep "total perm frames|wlm_hw_pages|vm_nonsys|total perm frames|vm_syspgs" # 'system' pages (vm_syspgs) : 00000000000E2844 3.5GB # non-'system' pages (vm_nonsys) : 00000000000041F8 66.0MB total perm frames (4K units) : 0000000000000187 1.5MB Total unmanaged mem (wlm_hw_pages): 00018BC0 395.8MB
Na jó, itt kicsit sok dolog van, beismerem. Nézzük őket szépen sorjában
- 'system' pages / vm_syspgs - Emlékeztek még a fent említett "kernel-számára fenntartott memória terület"-re? Na ez az :)
- non-'system' pages / vm_nonsys - Fizikai memórián belül azon processekhez tartozó lapok mennyisége amik nem lettek kilapozva a paging space-re
- total perm frames - fájlrendszer cache (JFS, JFS2, NFS)
- Total unmanaged mem / wlm_hw_pages - A szinten fent emlegetett HW cache area.

Na itt már látszik, hogy nem mi vagyunk a hülyék, hanem a rendszer tényleg nagyon élszált, tekintve hogy a fizikai memóriában szinte csak system lapok voltak, a többi meg vagy HW cache, vagy applikáció, egy nagyon kevés FS cache, illetve 1 kis rész ami ezen a query-n nem látszik. Továbbá az is simán látszik, hogy a fenti svmon/proc/scb mérésünk semmit nem ér, ha nem látjuk, hogy mennyi memória terület is lett kilapozva abból amit az applikáció tényleg lefoglalt. Az viszont tuti, hogy a kernelnek nem kéne ennyit lefoglalnia, szóval nézzünk már rá, hogy mi a franc is zabált annyit:
(0)> scb -c 6 100 |grep 0000000000000000 |sort -rn -k4 |head -15 00A14A W 64K 256.0MB 256.0MB 0.0MB 256.0MB 0.0MB 0000 0000000000000000 KHEAP SYS 00A148 W 64K 256.0MB 256.0MB 0.0MB 256.0MB 0.0MB 0000 0000000000000000 KHEAP SYS 00A147 W 64K 256.0MB 256.0MB 0.0MB 256.0MB 0.0MB 0000 0000000000000000 KHEAP SYS 00A146 W 64K 256.0MB 256.0MB 0.0MB 256.0MB 0.0MB 0000 0000000000000000 KHEAP SYS 00A145 W 64K 256.0MB 256.0MB 0.0MB 256.0MB 0.0MB 0000 0000000000000000 KHEAP SYS 00A144 W 64K 256.0MB 256.0MB 0.0MB 256.0MB 0.0MB 0000 0000000000000000 KHEAP SYS 00A143 W 64K 256.0MB 256.0MB 0.0MB 256.0MB 0.0MB 0000 0000000000000000 KHEAP SYS 00A142 W 64K 256.0MB 256.0MB 0.0MB 256.0MB 0.0MB 0000 0000000000000000 KHEAP SYS 00A149 W 64K 255.8MB 255.7MB 0.0MB 255.8MB 0.0MB 0000 0000000000000000 KHEAP SYS 00A023 W 64K 206.7MB 203.4MB 0.0MB 206.8MB 0.1MB 0000 0000000000000000 KHEAP SYS 00A00E W 64K 187.8MB 53.8MB 0.0MB 188.0MB 0.2MB 0000 0000000000000000 KHEAP SYS 00A14B W 64K 154.1MB 153.9MB 0.0MB 154.1MB 0.0MB 0000 0000000000000000 KHEAP SYS 00E000 W 64K 130.0MB 130.0MB 0.0MB 130.0MB 0.0MB 0000 0000000000000000 MBUF SYS 00A111 W 64K 122.8MB 0.8MB 0.0MB 122.9MB 0.1MB 0000 0000000000000000 KHEAP SYS 00A01C W 64K 87.3MB 86.9MB 0.0MB 87.3MB 0.1MB 0000 0000000000000000 KHEAP SYS
Hat én itt 2 dolgot latok: Rohadt sok Kernel heap-et, meg egy kevéske memory buffert.. Ami azt jelenti, hogy az elején valóban nem benézés esete forgott fent, hanem a rendszer tényleg "Mind megette" játékot játszott, ami viszont némi kis keresgélés után nyomban ki is derül miért:
IV53587: XMGC NOT TRAVERSING ALL KERNEL HEAPS. APPLIES TO AIX 7100-03 14/04/17 PTF PECHANGE

És igen... Persze hogy a rendszer pont ezen az szinten fut:
# oslevel -s 7100-03-01-1341
Customer értesít, állapot elmagyaráz (csak amolyan konyhanyelven, mert az halál biztos, hogy nem akarok 2 órán keresztül arról magyarázkodni -egy jó esetben félig technikus emberkének - hogy az AIX hogyan is manageli a memóriát a motorháztető alatt), következő maintenance window lefoglal, change előkészít, rendszer frissítés a hétvégére beütemez, hátradől, virtuális vállveregetés, a rendszergazda megpihen.
Megpihenne.. Legalább is ha nem baxná az ideg, hogy mi a jó büdös francért kellett kb 2-3 órán át a kernel dumpot túrnia és a fejét vakarnia amikor különböző okoknál fogva valami vagy nem működött, vagy nem azt az eredményt adta amit az ember várna tőle. Mit csinál ilyenkor a (jó)rendszer gazda? Füles be, elkezd valami kódolós zenét hallgatni majd elkezdi az egész francos memória checket lescriptelni, hogy legközelebb már 5 perc alatt meglegyen az, amivel most órákat szívott.
És mivel jófej rendszergazda tudja milyen xar amikor mások is ilyenekkel szívnak, így inkább úgy dönt, hogy szabadon elérhetővé teszi az egészet, szóval ha ne adj isten más is hasonló aljasságokra adná a fejet, az használja szeretettel az alábbi kis scriptecskét arra hogy valami támpontot kapjon a rendszer állapotáról egy sikeres dump után:
https://drive.google.com/file/d/0BzMqRqSWTAToNjdCbUNXd1ZGeVU

A gyengébbek kedvéért azért azt kiemelném hogy az ilyen jellegű outputot is a helyén kell kezelni, ergo akinek nincs tapasztalata ilyen jellegű debugolásokban, annak inkább azt ajánlom, hogy max a scriptet olvasgassa, és próbálja meg megérteni hogy mi és hogy működik mielőtt teljesen vakon megbízna egy netről letöltött scriptben/parancsban :D

Csak úgy a hova tartás végett: a script jelenlegi verziója ilyen outputot generált a fent említett dumpból:
# kdb_memory_check.sh -d dump_file_copy -t 10 Available physical memory: 0.215% (8.828 from 4096 MB ) HW pages: 395.750 MB (9.661% of total memory) FS cache: 1.527 MB (.037% of total memory) Processes occupied memory: 64.441 MB (1.573% of total memory) System occupied memory: 3624.265 MB (88.483% of total memory) Kernel Heap: 3320 MB (91.606% of system memory) Available paging space: 63.648% (4317.890 from 6784 MB) Additional details: SIGDANGER level: 54272 SIGKILL level: 13568 minperm percent: 3.0% maxperm percent: 90.0% maxclient percent: 90.0% Top 10 memory consumer(s) (based on nvpages) Process Name PID Virtual Pages Paged pages java 15597570 571.6 569.9 java 7274716 374.1 372.2 java 4653250 271.1 270.7 java 14745724 102.9 102.3 swapper 0 83.7 24.8 rmcd 3866808 61.6 61.1 java 6094860 50.3 49.8 kuxagent 10354744 38.0 36.8 cimserve 8192024 31.5 31.3 k07agent 6946818 22.5 20.6
Ami a process neveket illeti.. Hát az tényleg a szívás kategóriába tartozik: logikus lenne, hogy a parancs argumentumait is megtaláljuk a memóriában (hisz itt van a /proc alatt, ami meg teljesen memória rezidens), a probléma viszont az, hogy ezt minden process saját maga manageli a saját kis memória területen belül (pontosabban mondva a process-nek fenntartott Guardpage-en belül; a procfs-en belül a psargs meg erre a memória címre mutat), így azt a kernel dumpból nem fogjuk tudni kinyerni direktben...
Viszont ha mázlink van és megmaradt a process név+PID páros valamelyik bufferban/cache-benm akkor simán megpróbálhatunk ezekre rá-greppelni a dumpon belül és megszerezni a teljes process nevet, annak minden argumentumával együtt :)

Na és ezzel tényleg ennyi.. It's Now Safe to Turn Off Your Computer. Legalább is amíg a következő nagy "kihívás" nem köszön be..

2014. január 29., szerda

Solaris - Emulex HBA WWPN check

Régen blogoltam ide, de úgy gondoltam hogy ez még jól jöhet az utókornak, szóval ...

.. Adott egy ősrégi Solaris szerver (az a fajta ami a múzeumba se való már, olyan régi), aminél azt a feladatot kaptam, hogy a Storage szerverek zónázásakor használt WWPN numbert kinézzem. Tekintve hogy ez számomra alap feladatnak hangzott (AIX adminként), így gondoltam gyorsan végzek is a feladattal.. Hát a francokat..

Na nézzük miért is.
1) Mint mondtam a gép meglehetősen régi:
root@server[] # uname -a SunOS server 5.6 Generic_105181-39 sun4u sparc SUNW,Ultra-Enterprise
/* Csak a miheztartás végett - az 5.6ot (aka Solaris 2.6) 1997ben adták ki (bár 2006ig támogatott maradt) */

2) A google jelen esetben nem a barátod
Hiába akad google-n 1-2 használhatónak tűnő tipp*, attól még sajna ez kevés a boldogsághoz ha a tippek közül egyik se működik, mert vagy nem elérhető a parancs amire hivatkozik, vagy nem kapok kimenetet, vagy amit kapok az láthatóan hülyeség.
-> scli, fcinfo, prtpicl, lputil64 nem létezik
-> 'prtconf -vp | grep -i wwn' hülyeséget dob vissza
-> /var/adm/messages* alatt egy bejegyzes sincs amiben a wwn vagy wwpn benne lenne
-> 'luxadm -e port' szerint az összes adapter not-connected state-ben van ami abszolút hülyeség, viszont ez miatt a 'luxadm -e dump_map' se működik.
-> 'iostat -XMzxn' közli, hogy a -X, -z kapcsoló nem értelmezhető

* A leghasználhatóbb talán ez: http://www.sunsolarisadmin.com/hardware/how-to-find-the-wwn-world-wide-name-in-sun-solaris/

3) Nem mindegy hogy milyen adapter van a gépben és hogy milyen driver hajtja
Az egy dolog, hogy csak 1-2 hivatalosan támogatott kártya elérhető, de mocskos módon még az se mindegy, hogy azt a kártyát milyen Storage megvalósításhoz szeretnéd használni, mert mindegyik megvalósításnak más-más driver kell, azok meg hajlamosak meglehetősen válogatósak lenni a támogatott kártyák között. Ehhez jön még hozzá, hogy nincs egységes tool a HBA-k kezelésére, hanem minden driverhez külön-külön utility set van ami így vagy úgy valósítja meg kb ugyan azokat a feladatokat (lscfg, de hiányoltalak én téged..)

4) Az se mindegy, hogy melyik verziójú drivered van fent
Mint utólag kiderült a 2. pontban leírt problémámba ay is erősen közrejátszott, hogz az idők során kiadott különböző driverek/toolok telepítési útvonala hajlamos volt időről időre változni, így ha nincs bent a $PATH-ban az adott tool akkor vagy tudod mi és hol van, vagy keresgélhetsz amíg meg nem találod (már ha tudod mit is kéne pontosan keresni)

Na szóval.. Ha tudni akarod, hogy hogy is kell megtekinteni egy HBA WWPN-jét, akkor:
- Tudnod kell, hogy pontosan milyen kártyáról van szó
- Tudnod kell, hogy az adott kártyát milyen driver hajtja
- Tudnod kell, hogy az adott driver tooljai hol találhatóak
- Tudnod kell, hogz a toolok közül melyik is alkalmazható a te általad megálmodott feladatra, és azt is hogyan.

Hát gyerekek. Aki a Linux alatt sír hogy mennyire össze van gányolva, és hogy mennyire de nem egységes, azt isten bizony odaültetném egy ilyen elé.

Na de vissza térve az én esetemre.
- Milyen HBA van a gépben?
root@server[] # prtdiag -v |grep SBus |grep sd 1 SBus 25 0 lpfs/sd (block) LP9002S 1 SBus 25 3 SUNW,fas/sd (block) 3 SBus 25 1 QLGC,isp/sd (block) QLGC,ISP1000U 3 SBus 25 2 lpfs/sd (block) LP9002S 3 SBus 25 3 SUNW,fas/sd (block) 5 SBus 25 1 QLGC,isp/sd (block) QLGC,ISP1000U 5 SBus 25 2 QLGC,isp/sd (block) QLGC,ISP1000U 5 SBus 25 3 SUNW,fas/sd (block)
- Lehet is nyomban válogatni, tekintve, hogy 2 is van. Az 1ik ránézésre valami QLogic cucc (sd driver-rel), a másik meg csak annyit mond magáról, hogy LP9002S. Kis google után utóbbiról kiderül, hogy 2Gbps Emulex Fibre channel adapter, míg az első egy sima SCSI vezérlő (így azzal most nem foglalkozok). Annyi segítséget a gép adott, hogy az Emulex kártyát az lpfs driver hajtja, így már csak azt kell kitalálni, a driverhez tartozó segédprogramok hol is találhatóak
- Első körben tudni kell a csomag nevét:
root@server[] # pkginfo |grep lpfs system lpfs Emulex LightPulse FC SCSI/IP Host Bus Adapter driver
- Ebből kiindulva aztán érdemes megnézni, hogy mi is van a csomagban:
root@server[] # pkgchk -l lpfs|grep Pathname |egrep "bin|sbin" Pathname: /usr/sbin Pathname: /usr/sbin/lpfs Pathname: /usr/sbin/lpfs/QS_fmw Pathname: /usr/sbin/lpfs/REV_fmw Pathname: /usr/sbin/lpfs/dfc Pathname: /usr/sbin/lpfs/dfc32 Pathname: /usr/sbin/lpfs/dfc64 Pathname: /usr/sbin/lpfs/download_fmw_lpfs Pathname: /usr/sbin/lpfs/lpsutil Pathname: /usr/sbin/lpfs/lpsutil32 Pathname: /usr/sbin/lpfs/lpsutil64 Pathname: /usr/sbin/lpfs/resetqdepth
- Oksi. Akkor a /usr/sbin/lpfs mappában kéne körbenézni. Kérdés, hogy mi is használható ezek közül.

Az mondjuk kb tiszta, hogy a QS_fmw és a REV_fmw valami firmware féleség lehet, így azokhoz inkább nem nyúlok. A download_fmw_lpfs hasonló okok miatt esik ki (lekérdezni akarok, nem módosítani). A dfc-ből, illetve az lpsutil-ból a jelek szerint 3-3 file is elérhető: 1 központi, illetve 1-1 32/64 bit specifikus (Ránézésre a fő bináris feladata, hogy megítélje, hogy a rendszer 32 vagy 64 bites rendszeren fut e, és az alapján meghívja a szükséges binárist). Ezen felül van még a resetqdepth, ami a nevéből illetően piszkálni akar valamit, viszont mint kiderül lényegében csak egy script:
root@server[] # cat /usr/sbin/lpfs/resetqdepth #!/bin/sh # $Id: resetqdepth.sh 1.6 2001/03/07 00:12:00 mks Exp $ case $1 in [0123456789]*) ;; *) echo Usage: resetqdepth adapter_number exit 1 ;; esac /usr/sbin/lpfs/dfc > /dev/null <<! set board $1 rqdepth exit ! exit 0
Természetesen ezt lefuttatni nem akarom, viszont a tény hogy a fentebb említett dfc parancsra támaszkodik egy EOF here tag-el ad némi reményt arra hogy esetleg valami belső parancs készletre támaszkodó programmal van dolgunk.

Így hát elindítva a dfc programot az alábbi kimenetben gyönyörködhetünk:
root@server[] # /usr/sbin/lpfs/dfc LightPulse Engineering Debug Utility Copyright (c) 1999, 2000 Emulex Network Systems, Inc. Do not run this utility unless instructed by Emulex Technical Support Found 0 PCI 2 SBUS adapters: onmask 3f58f offmask 1e7 Driver:4.21x1 Adapter 0: lpfs1 SBUS id df1095f0 Firmware:3.90A7 (R2F3.90A7) Adapter 1: lpfs0 SBUS id df1095f0 Firmware:3.90A7 (R2F3.90A7) cmd>

Szupi.. Szóval kapunk egy belső command line-t.. Nézzük mit lehet benne mókólni (és lehetőleg nem elszúrni :))
cmd> help rdallpci wrpci wrhc wrhs wrha wrca rdpci rdhc rdhs rdha rdca rdmb exit set rring rslim riocb rrpi rbp rmemseg mbox reset rbinfo nddstat fcstat wslim wffreg rffreg sdiag dbg rnode rdevp instance lip linkinfo ioinfo nodeinfo getcfg setcfg failio outfcpio rqdepth ct hbaattr portattr portstat dportattr wportattr iportattr fcpmap fcpbind setmgmt getmgmt rnid getevent resetstat sendscsi refresh els getmpulse setmpulse listn trace help p
Sajna a fejlesztők arra már nem szánták rá magukat, hogy a help parancsot kibővítsék az alparancsok leírásával is, így némi kis próbálkozás után sikerül eljutnom csak az alábbi kimenethez:
cmd> linkinfo Event 0x0 Up 0x1 Down 0x0 Multi 0x0 PortID 0x0 alpa 0x0 topology 0x4 state 0x1 ALPAmap 0: Portname 10:00:00:00:ab:cd:ef:01 Nodename 20:00:00:00:ab:cd:ef:01
Na ez már végre az amit akartam.. Az egyedüli bajom csak az, hogy a parancs ismételt kiadásával ugyan ezt az eredményt kapom vissza, viszont ebben a gépben (ahogy fentebb is látható volt) 2 HBA kártya van.. Valahogy rá kéne venni a programot, hogy a másik kártya adatait is le lehessen kérdezni.

Ekkor ugrott be a fenti script, ami képes volt tetszőleges adapterre lefuttatni az rqdepth parancsot. Mindezt a set board $1 parancsal, úgy hogy nyomban mentem is vissza az újonnan megismert subshellem alá további tesztelésre:
root@server[lpfs] # ./dfc LightPulse Engineering Debug Utility Copyright (c) 1999, 2000 Emulex Network Systems, Inc. Do not run this utility unless instructed by Emulex Technical Support Found 0 PCI 2 SBUS adapters: onmask 3f58f offmask 1e7 Driver:4.21x1 Adapter 0: lpfs1 SBUS id df1095f0 Firmware:3.90A7 (R2F3.90A7) Adapter 1: lpfs0 SBUS id df1095f0 Firmware:3.90A7 (R2F3.90A7) cmd> set board 0 cmd> linkinfo Event 0x1 Up 0x1 Down 0x0 Multi 0x0 PortID 0x633613 alpa 0x13 topology 0x3 state 0x6 ALPAmap 0: Portname 10:00:00:00:ab:fd:08:04 Nodename 20:00:00:00:ab:fd:08:04 cmd> set board 1 cmd> linkinfo Event 0x0 Up 0x1 Down 0x0 Multi 0x0 PortID 0x0 alpa 0x0 topology 0x4 state 0x1 ALPAmap 0: Portname 10:00:00:00:ab:cd:ef:01 Nodename 20:00:00:00:ab:cd:ef:01 cmd> exit
Buli.. Igy mar szepen megy is minden, mint a karika csapás. Akkor már csak az maradt, hogy le is scriptljük a dolgot:
root@server[] # cat /tmp/emulex_wwpn_query.sh #!/usr/bin/ksh PACKAGE_NAME=`pkginfo |grep SCSI |egrep "lpfc|lpfs" |cut -d ' ' -f2` DFC_PATH=`pkgchk -l $PACKAGE_NAME |grep Pathname |grep dfc$ |cut -d ' ' -f2` while true do $DFC_PATH 2>&1 << ! exit ! break done |grep Adapter |cut -d ' ' -f 2 |sed "s/://g" |while read ID do $DFC_PATH 2>&1 << ! set board $ID linkinfo exit ! done |grep Portname |cut -d ' ' -f 2 |sed "s/://g" |tr 'a-z' 'A-Z' root@server[] # sh /tmp/emulex_wwpn_query.sh 10000000ABCDEF01 10000000ABFD0804
Trolloknak előre megjegyzem: ezen az ősrégi vackon a pipe feldolgozási sorrendje nem tudom miért de valahogy eltér a megszokottól; a $() nem működik, helyette van backtick (`), az viszont valamiért nem szeret több parancsot 1 soron belül látni; Talán pont a pipe-olás miatt az awk se működik úgy ahogy azt elvárnám, így fallbackeltem az ódivatú parancsokra, mint cut, grep, sed, tr (amit amúgy egy awk simán ki tudna váltani, viszont ha nincs ló, jó lesz a szamár is.. ). Amúgy ha valakinek van ötlete, hogy while; do ... done módszeren kívül hogy lehet még greppelni egy here tag (jelen esetben !) után az ne fogja vissza magát :)

2012. február 14., kedd

fuser - némileg másként

A múltkor blogbejegyzés után kedvet kaptam némi kis turkászásban a kernel térben, úgy hogy íme egy újabb szösszenet arról, hogy a rendszernek mit is kell csinálnia amikor mi csak úgy dobálózunk a parancsokkal :)

Na szóval.. A mostani alkalomra a fuser nevű parancsot néztem ki magamnak.. Sokat nem kell róla mondani: Általános ismérve, hogy ha egy FS nyitva van, akkor ezt szoktuk meghívni, hogy megnézzük mi is fogja. Nézzük, hogy ezt a funkciót a kernel térből hogy is lehetne elérni:

Első körben kell nekünk egy mount point.. Az én esetemben ez a /opt/IBM lesz, mert miért ne :)

Első körben a kontroll teszt: Nézzük, hogy a rendszer mit is tud róla:
test_server@root:/ # fuser -cux /opt/IBM
/opt/IBM:  1130574c(root) 1253494c(root)
Szupi.. Na akkor nézzük ugyan ezt a kernel térben. A módszer az alábbi dióhéjban:
- Meg kell keresni az adott mount point memória pointerjét
- Ezt a pointert használva megnézni az elérhető I-node bejegyzések pointereit, majd leválogatni amire van bármiféle hivatkozás
- A leválogatott hivatkozásokat alapul véve meg kell nézni, hogy melyiknek mi a Gnode (generic node structure) szegmense
- Ezen segmensekből már le tudjuk válogatni, hogy melyiknek milyen thread a szülője, amiből meg direkt megtalálhatjuk a thread-hez rendelt PID-et.

A valóságban:
Első körben ugye a mount-hoz tartozó cím kell. Annyi probléma van, hogy a mount-ot kikérve ilyen összevisszaságot kapunk:
(0)> mount
                           GFS             DATA TYPE    FLAGS
  1 F10001001D6868B0 014D4D60 F1000100206D2080 JFS2    DEVMOUNT
... /dev/hd4 mounted over /
  2 F10001001D686950 014D4D60 F1000100206A4480 JFS2    DEVMOUNT
... /dev/hd2 mounted over /usr
  3 F10001001D6869F0 014D4D60 F1000100206FB080 JFS2    DEVMOUNT
... /dev/hd9var mounted over /var
  4 F10001001D686810 014D4D60 F1000100206FC880 JFS2    DEVMOUNT
... /dev/hd3 mounted over /tmp
És így tovább.. Ez persze felvet 2 gondot:
- Komolyan végig kell mindent böngésszek, úgy hogy közben kifolyik a szemem?
- Miért nem lehet ezt 1 sorban kirakni, hogy legalább greppelni lehessen rá?

Persze azért annyira mégse rossz a helyzet, csak kicsit bűvészkedni kell az awk-al, és nyomban meglesz az ami nekünk kell:
(0)> mount |awk '{a[NR]=$0} /\/opt\/IBM$/ {print a[NR],a[NR-1]}'
... /dev/IBMlv mounted over /opt/IBM  14 F100010020684550 014D4D60 F1000100226C2C80 JFS2    DEVMOUNT

Ugye hogy így szebb.. Na szóval megvan a pointerünk (F100010020684550). Akkor kérjük le milyen i-node bejegyzések vannak alatta:
(0)> mount F100010020684550 |grep -E "DIR|REG|SOCK" |tail -5
 648 F1000100241643E8     0 F1000100241640B0 F100010020684550 DIR
 649 F1000100240E03E8     0 F1000100240E00B0 F100010020684550 DIR
 650 F100010024092FE8     1 F100010024092CB0 F100010020684550 REG
 651 F10001002411B7E8     2 F10001002411B4B0 F100010020684550 DIR
 652 F1000100226D2FE8     1 F1000100226D2CB0 F100010020684550 DIR  ROOT
Na itt egy újabb probléma.. Mi ez a sok szám, és mit jelentenek? Nos A válasz a következő:
- Az első és második oszlop lényegében ugyan azt takarja. Az első az index-szám, a második pedig a VFS_VNODE pointer.
- A 3. szám egy úgy nevezett counter. Ez mutatja, hogy hány kernel thread használja éppen az adott VFS_VNODE-ot.
- A 4. lesz a VFS_VNODE-hoz tartozó GNODE.
- Az 5.-et most bocs de kihagyom, mert érdektelen jelen szempontból

Ami nekünk ezek közül kell, az azok a GNODE regiszterek, amelyeknek COUNT-ja nagyobb mint 0. Ezt kb az alábbi scriptelési módszerrel tudjuk előhozni:
(0)> mount F100010020684550|grep -E "DIR|REG|SOCK" |awk ' { if ($3 != "0") print }'
 154 F100010036F6A3E8     1 F100010036F6A0B0 F100010020684550 REG
 157 F100010036F3A3E8     1 F100010036F3A0B0 F100010020684550 REG
 160 F100010036F99FE8     1 F100010036F99CB0 F100010020684550 REG
 163 F100010036F69FE8     1 F100010036F69CB0 F100010020684550 REG
 266 F100010036FA6FE8     1 F100010036FA6CB0 F100010020684550 REG
 556 F1000100244D2FE8     1 F1000100244D2CB0 F100010020684550 REG
 557 F1000100243B57E8     1 F1000100243B54B0 F100010020684550 REG
 558 F1000100244CC3E8     1 F1000100244CC0B0 F100010020684550 REG
 559 F1000100244EBBE8     1 F1000100244EB8B0 F100010020684550 REG
 560 F1000100243B0BE8     1 F1000100243B08B0 F100010020684550 REG
 561 F1000100244CB7E8     1 F1000100244CB4B0 F100010020684550 REG
 562 F1000100244A93E8     1 F1000100244A90B0 F100010020684550 REG
 563 F1000100244C8BE8     1 F1000100244C88B0 F100010020684550 REG
 652 F1000100226D2FE8     1 F1000100226D2CB0 F100010020684550 DIR  ROOT

Egy baj van - Ez a lista helyenként iszonyat nagy.. Itt se épp rövid.. A problémám meg az, hogy az itt található GNODE ID-kat kéne mind végigjárjam az alábbi módon:
(0)> gnode F1000100243B08B0 |grep gn_seg
gn_seg........ 00000000000086A6
(0)> scb 2 00000000000086A6 |grep pvproc
pvproc pointer           (pvproc)   : 0000000000000000

(0)> gnode F1000100244C88B0 |grep gn_seg
gn_seg........ 00000000000246AD
(0)> scb 2 00000000000246AD |grep pvproc
pvproc pointer           (pvproc)   : 0000000000000000

(0)> gnode F100010036F99CB0 |grep gn_seg
gn_seg........ 00000000000732D8
(0)> scb 2 00000000000732D8 |grep pvproc
pvproc pointer           (pvproc)   : F100070F00045000
3.-ra csak ráhibáztam az egyikre, de persze ezt így egyesével végigjátszani valami halál.. Mindenesetre ha megvan a pvproc cím, akkor abból már az egyik process-t meg is találhatjuk:
(0)> proc F100070F00045000 |grep ^pvproc
pvproc+045000  276 java     ACTIVE 011404E 0132076 0000000030588400   0 0013
(0)> hcal 011404E
Value hexa: 0011404E          Value decimal: 1130574
Bingo.. 1130574 az egyik PID amint fentebb is láttunk.. Na de akkor hogy is lehet ezt normálisan végignézni, úgy hogy az összes GNODE ID-t végigjátsszuk? Hát, a szomorú hír, hogy a kdb nem tud belső scriptelést, így a shell-re kell támaszkodjunk, ami meg egy részről iszonyat erőforrás zabáló, más részről meg a sok fork miatt ágyúval verébre módszer is. Annyi segítségünk mondjuk van, hogy a kdbnek van '-script' kapcsolója, ami pont az ilyen munkákat igyekszik megkönnyíteni, de azért ez még mindig kevés az optimális működéshez.
test_server@root:/ # for GN_SEG in $(
>       for GNODE_ID in $(echo mount F100010020684550|kdb -script |grep -E "DIR|REG|SOCK" |awk ' { if ($3 != "0") print }')
>       do
>               echo gnode $GNODE_ID|kdb -script|awk '/gn_seg/ {print $NF}'
>       done)
> do
>       echo scb 2 $GN_SEG |kdb -script|awk '/pvproc/ {print}'
> done|sort -u|grep -v 0000000000000000
pvproc pointer           (pvproc)   : F100070F00045000
pvproc pointer           (pvproc)   : F100070F0004C800
Ebből kiindulva már nem nehéz megtalálni azt amire végső soron pályázunk (viszalépés kdb-be, majd.. )
(0)> proc F100070F00045000 |grep ^pvproc
pvproc+045000  276 java     ACTIVE 011404E 0132076 0000000030588400   0 000E
(0)> hcal 011404E
Value hexa: 0011404E          Value decimal: 1130574

(0)> proc F100070F0004C800 |grep ^pvproc
pvproc+04C800  306 sh       ACTIVE 0132076 0000001 0000000008466400   0 0001
(0)> hcal 0132076
Value hexa: 00132076          Value decimal: 1253494

1130574, 1253494. Amiket fentebb is láttunk.. Sőt, még azt is tudjuk, hogy egy sh, meg egy java processről van szó :)
Ha ne adj isten lusták vagyunk visszamenni a fenti script után a kdb-be, akkor némi kis módosítással nyomban ki is lehet kérni az ID-ket:

test_server@root:/ # MOUNT=$(echo mount |kdb -script|awk '{a[NR]=$0} /\/opt\/IBM$/ {print a[NR-1]}'|awk '{print $2}')
test_server@root:/ # for PVPROC in $(
>       for GN_SEG in $(
>               for GNODE_ID in $(echo "mount $MOUNT" |kdb -script|grep -E "DIR|REG|SOCK" |awk ' { if ($3 != "0") print $4}')
>               do
>                       echo gnode $GNODE_ID|kdb -script|awk '/gn_seg/ {print $NF}'
>               done)
>       do
>               echo scb 2 $GN_SEG |kdb -script|awk '/pvproc/ {print $NF}'
>       done|sort -u|grep -v 0000000000000000)
> do
>       echo proc $PVPROC|kdb -script|grep ^pvproc
> done
pvproc+045000  276 java     ACTIVE 011404E 0132076 0000000030588400   0 0017
pvproc+04C800  306 sh       ACTIVE 0132076 0000001 0000000008466400   0 0001

# Mint fent említettem: A módszer csak azokra a GNODE-okra működik aminek a countere (aktív thread-je) nagyobb mint 0. Ez azért problémás, mert ha egy process használ egy file-t, de az épp nem aktív (írás nélküli file, pl tail esetén), akkor ez a módszer is hibádzik. További probléma, hogy a submount-okat (amik szintén fogják az FS-t umount esetén) szintén nem képes kijelezni, szóval nyugodtan tekintsétek ezt is amolyan érdekességnek, tekintve, hogy mind a fuser, mind az lsof bőven alkalmasabb ezeknek a megkeresésére (általában - volt amikor ez a módszer talált meg nekem egy olyan thread-et, amiről más program sose hallott)

2011. október 9., vasárnap

AIX mounting issue

Kicsit régebbi eset(2009.08), de gondoltam inkább lebloggolom, mintsem az enyészeté legyen, mert annál azért többet ér :)

Nos hát.. Alapvető probléma a következő: A rendszer indulásakor egy csomó filerendszer nem jön fel normálisan, holott a /etc/filesystems alatt szépen be van állítva, hogy azoknak bizony fel kell jönniük. A Volume Group szépen aktiválódik, de az alatta lévő FS-ek a rendszer indulásakor nem jönnek fel (Ha manuálisan mountoljuk őket, akkor viszont igen)

Kiegészítő információk:
- Az AIX kicsit régi a gépen (5300-10-01-0921) de ez nem indokolja a rendszer hibáját.
- A bootolás után a console log ilyen randaságokat tartalmaz:
0 Sun Aug 16 16:43:35 BST 2009 mount: 0506-324 Cannot mount /dev/lv_ap02n8log on /vfs=jfs2log=/dev/loglv27: A file or directory in the path name does not exist.
0 Sun Aug 16 16:43:35 BST 2009 mount: 0506-324 Cannot mount /dev/lv_ap02n2temp01 on /dev=/dev/lv_ap02n2data02log=/dev/loglv20: A file or directory in the path name does not exist.
0 Sun Aug 16 16:43:35 BST 2009 mount: 0506-324 Cannot mount /dev/lv_ap02n3data02 on /dev=/dev/lv_ap02n2temp02log=/dev/loglv20check=false: A file or directory in the path name does not exist.
0 Sun Aug 16 16:43:35 BST 2009 mount: 0506-324 Cannot mount /dev/lv_ap03n9log on /vfs=jfs2: A file or directory in the path name does not exist.

Mint az látszik a console logból a rendszer össze vissza kavarva próbál valami mount félét össze hozni, de nagyon kevés sikerrel.
Na de a kérdés.. Miért, és hogy?
Ehhez első körben vizsgáljuk meg, hogy mi (és hogy) is lenne a felelős ennek folyamatnak a lezongorázásáért:

A folyamat alapvetően egyszerű: a rendszer IPL-je során amint átvált a rendszer rc2-be nyomban elkezdi a /etc/inittab-ot feldolgozni, illetve az ott feltüntetett parancsokat/scripteket végrehajtani. Az egyik ilyen alap script a /etc/rc, ami a mountolásért is felel. Az akkor rendszeren az alábbi kód volt ezért a felelős (megjegyzés - a kód verziószáma 1.20.1.7 - ez még később fontos lesz)

# Perform file system checks
# The -f flag skips the check if the log has been replayed successfully
fsck -fp

# Perform all auto mounts
dspmsg rc.cat 4 ' Performing all automatic mounts \n'

cat /etc/filesystems | tr -d ' ' | tr -d '\t' | grep -vp "vfs=nfs" | grep -vp "vfs=cachefs"> /tmp/fs1.$$

# Collecting entries except nfs
lines=`wc -l /tmp/fs1.$$ | awk '{print $1}'`

# Calculate the number of lines
cnt=1

# Remove the file 'fs2.$$' if it already exists
if [ -f /tmp/fs2.$$ ]
then
        rm -f /tmp/fs2.$$
fi

# Compare each line in the file '/tmp/fs1.$$'
# If it is a comment line or just having the filesystem name,
# just write it to '/tmp/fs2.$$'
# Otherwise, add a tab before that line and write it to '/tmp/fs2.$$'

while [ $cnt -le $lines ]
do
        cat /tmp/fs1.$$ | head -$cnt | tail -1 | grep "^[\*/]"  1> /dev/null
        if [ $? -eq 0 ]
        then
                cat /tmp/fs1.$$ | head -$cnt | tail -1 >> /tmp/fs2.$$
        else
                param=`cat /tmp/fs1.$$ | head -$cnt | tail -1`
                echo "\t"$param >> /tmp/fs2.$$
        fi
        cnt=`expr $cnt + 1`
done
mount /tmp/fs2.$$ /etc/filesystems
mount all
umount /etc/filesystems
rm -f /tmp/fs1.$$ /tmp/fs2.$$

Nah.. mit is látunk itt...
- Első körben a rendszer létrehoz egy /tmp/fs1.$$ file-t ($$ a PID szám, amivel maga a /etc/rc fut), amit aztán majd alapnak fog használni. A file-ból minden tab és szóköz hiányzik, illetve a cachefs-eket is kikapja belőle a grep -vp.
- Aztán egy $lines változót használva a rendszer megnézi, hogy az így keletkezett file hány soros (bár sztem kicsit undorítóan csinálja, de hát ízlés kérdése).
- Mindezek után egy counter-t használva ($lines értékéig) egy teljes while ciklus indul, ami egy (szerintem szintén undorító módon) sorról-sorra végigmegy, és megnézi, hogy az adott sor '*'-al, avagy '/'-el kezdődik e (grep visszatérési értéke). Amennyiben igen, úgy az adott sor átkerül egy /tmp/fs2.$$ file-ba. Amennyiben mégse így történne akkor is, csak az adott sor kap maga elé egy tabulátort.
- Amint a ciklus lefut egy meglehetősen furcsa módszerrel a /tmp/fs2.$$-ban lévő FS-eket mountolja a rendszer (figyelem - a /etc/filesystems helyére felülmountolódik a /tmp/fs2.$$ ), majd a standard mount all parancsal minden a file-ban szereplő FS mountolódik (aminek a mount paramétere nem 'false').
- Amint ezzel is kész feloldja az előző mountot, majd törli a temporary file-okat.

A módszer kicsit tényleg furcsán néz ki (nekem főleg a sorról-sorra végigmenős módszertől borsódzik a hátam), viszont elméletben működnie kellett volna.. Akkor hol volt a probléma?? Nos.. végeztem pár tesztet, majd a szemem fennakadt, amikor nem az általam várt eredmények jöttek ki:

A használt script a következő volt:
#!/bin/ksh
set -x
lines=`wc -l /tmp/fs1.temp | awk '{print $1}'`
cnt=1

while [ $cnt -le $lines ]
do
        cat /tmp/fs1.temp | head -$cnt | tail -1 | grep "^[\*/]"  1> /dev/null
        if [ $? -eq 0 ]
        then
                cat /tmp/fs1.temp | head -$cnt | tail -1 >> /tmp/fs2.temp
        else
                param=`cat /tmp/fs1.temp | head -$cnt | tail -1`
                echo "\t"$param >> /tmp/fs2.temp
        fi
        cnt=`expr $cnt + 1`
done
Lényegében azonos a standard scriptel, az eredmény (/tmp/fs2.temp) viszont nem az volt amit vártam:
/var:
dev=/dev/hd9var
vfs=jfs2
    log=/dev/hd8
    mount=automatic
check=false
type=bootfs
    vol=/var
    free=false
quota=no

/tmp:
    dev=/dev/hd3
    vfs=jfs2
log=/dev/hd8
mount=automatic
check=false
vol=/tmp
free=false
quota=no

/proc:
    dev=/proc
    vol="/proc"
    mount=true
    check=false
    free=false
    vfs=procfs
Mit látható.. A TAB-ok egy csomó helyen nem kerültek a helyükre.. Na akkor nézzük meg azt az elágazást kicsit közelebbről:
cat /tmp/fs1.temp | head -$cnt | tail -1 | grep "^[\*/]"  1> /dev/null
if [ $? -eq 0 ]
then
        cat /tmp/fs1.temp | head -$cnt | tail -1 >> /tmp/fs2.temp
else
        param=`cat /tmp/fs1.temp | head -$cnt | tail -1`
        echo "\t"$param >> /tmp/fs2.temp
fi
Tehát.. Ha a $? (előző parancs (grep) Return Code-ja) 0 akkor csak rakja bele, ha meg nem akkor toldja meg egy tabbal.. Hát jó. csináljunk egy kis tesztet:
server:root # while true;do cat /tmp/fs1.temp | head -172| tail -1 | grep "^[\*/]"  1>/dev/null;echo $?;done
1
2
13
13
13
13
13
13
És kb itt nyomtam Ctrl+C-t..

Mit is csináltam? - egy végelenített ciklust, amikor is folyamatosan ugyan azt az adatot kértem ki (head+tail) majd megnéztem a grep return code-ját.. Az viszont azonos adat esetén (172. sor) különböző eredményt produkált! Wattafák???

Nos.. Mint kiderült sikerült belefutni egy meglehetősen érdekes issue-ba. Ennek az issue-nak neve is volt: IZ43276: KSH MAY RETURN INCORRECT RETURN CODE FOR PIPED COMMANDS APPLIES TO AIX 5300-11

Aha... Hogy úgy... Én is üdvözöllek.. A problémámon ez a tudás akkor viszont még nem segített.. A patch-et csak 2010ben adták ki, ami azt jelentette, hogy én 2009ben még csak feliratkozhattam a fix "hírlevél mondóra" és várhattam, hogy javítják a hibát..

Viszont mint kiderült azért volt kerülőút: Az AIX 5.3 TL6-tól (TL10-en van a rendszer, emlékeztek? :) a /etc/rc file már a 1.20.1.9 verzión volt, ami ugyen ezt a problémát (FS-ek mountolása) sokkal szebben oldotta meg:

# Remove the file 'fs1.$$' if it already exists
rm -f /tmp/fs1.$$

# handle the egrep line carefully: between each pair of brackets is a tab
# followed by a space, and the tab may get lost if you copy and paste the line
egrep -vp "^[ ]*vfs[ ]*=[ ]*(cachefs|nfs|cifs)[ ]*$" \
/etc/filesystems > /tmp/fs1.$$

mount /tmp/fs1.$$ /etc/filesystems
mount all
umount /etc/filesystems
rm -f /tmp/fs1.$$

Éljenek a Reguláris kifejezések.. Ennek a kódnak köszönhetően pedig (mivel nem használ hülye visszatérési értékeket) a mount problémám megoldódott (persze a rendszeren lévő további scriptek amik erre támaszkodtak ettől még szívhatták).

Egy kérdés maradt csak nyitva - Ha ez TL6tól elérhető volt, akkor miért nem ez a verzió volt elérhető a TL10-es AIX alatt is?

A válasz persze "prózai" - A fejlesztők szerint a /etc/rc file-t a customer (ha nem is nyugodtan, de.. ) bármikor szerkesztheti, így úgy gondolták, hogy az upgrade során ezt a file-t inkább ne piszkálják (hisz új funkciót amúgy se hoz) upgrade során. Ergo ha a rendszer egy régebbi szintről ( < TL6 ) lett felhúzva TL10-re, akkor az upgrade véletlenül se fogja a frissebb file-t a helyére pakolni. Max akkor ha a rendszert már az elejétől fogva TL6, vagy afölötti verzióval telepítették (ergo az újabb /etc/rc már alapból része a telepítő csomagnak)..

Igen.. Én is örültem amikor megtudtam :)

2011. szeptember 15., csütörtök

Dual Network VIO - SEA adapter buktatók

Normálisabb helyeken ugyebár a az ember minimum 2 VIO szervert használ (ha másért nem, hát a redundancia végett), ami meg nyomban meg is követeli a SEA (Shared Ethernet Adapter) használatát control chanellel (plusz persze a megfelelő trunk priority beállításával). Ezzel nincs is semmi gond..
Aztán amikor az embernek valami baja van az egyik VIO-val, akkor meg pont örül, hogy milyen jó is a redundancia, majd teljes lelki nyugalommal nekiáll a hibás dolgot megjavítani.. Az általam tapasztalt esetben a hiba épp egy SEA adapter alatt lévő fizikai adaptereknél jelentkezett. Ebben az esetben az ember 2 dolgot tehet:

- Lebontja a SEA-t (illetve jelen esetben az ether channel-t is), majd elkezdi szépen darabonként szétcincálni az alatta lévő eszközöket, hogy vajon merre is lehet a probléma
- Azt mondja az ember, hogy a végén úgy is újra kell inicializálni az egészet, úgy is redundáns a rendszer, gyorsabb ha újraindítom (amúgy tényleg)

Mind2 esetben persze meg kell bizonyosodni róla, hogy a másik VIO átvette az összes hálózat vezérlését, amit az entstat -all [SEA]-val meg is lehet tenni (padmin alól; root alól standard entstat -d [SEA]).. Amennyiben a másik VIO átvette, akkor az összes hálózaton a SEA-nak a 'PRIMARY' állapotot kell mutatnia. Amint ez a helyzet már nyugodtabbak lehetünk, mert a másik VIO-n kedvünkre lehet matatni, az nem fog kihatni a kliensekre..

Mind emellett persze még van egy dolog amire figyelnünk kell, miszerint hogy az éppen hibás VIO-n a ha_mode hogy is áll.. Nyomban 3 lehetőségünk is van chdev-el ezt megpiszkálni:
chdev -dev [SEA]-attr ha_mode=auto -> ezt használjuk ha azt akarjuk, hogy a Trunk Priority alapján döntse el a 2 VIO egymás között, hogy épp ki szolgálja ki az adott hálózatot. Amennyiben az éppen aktuális VIO ezt mégse tudja megtenni, akkor nyomban átpasszolja a másik VIO-nak a hálózatot.

chdev -dev [SEA]-attr ha_mode=standby -> Ez amolyan "illedelmes (gently)" kérés a VIO felé, hogy hagyjon fel a hálózat kiszolgálásával (ha netán nála lenne). Amennyiben át akarjuk adni a másik VIO-nak a hálózatot, úgy illik ezt használni

chdev -dev [SEA]-attr ha_mode=disable -> Ez a módszer meg azt mondja, hogy a SEA adapter mostantól nincs HA módban, ergo bármiféle hálózati failoverre esély sincs.

Az utóbbi esetben viszont van 1-2 érdekes viselkedés, ami ha jól láttam sehol se volt dokumentálva (kb ezért is született ez a bejegyzés):

Amennyiben egy már bekonfigurált dual-network VIO-s környezet alól szedjük ki a HA módot a chdev-el, úgy attól még az entstat alatt láthatjuk, hogy a VIO még tud a primary VIO-ról, viszont persze nem fogja tudni átvenni a hálózatot, viszont a vicc az, hogy amíg újra nem indítjuk a gépet, addig nem is fog a hálózat átvételére kísérletet tenni. Ergo itt még el lehet játszani, hogy:
chdev -dev [SEA] -attr ha_mode=disable
chdev -dev [SEA] -attr ha_mode=standby ctl_chan=[Control_channel_adapter]
Majd ez után olyan szépen visszaáll a HA módba, hogy öröm nézni. Mellékesen felhívnám a figyelmet arra, hogy ebben az esetben a 2 VIO között használt (dedikált VLAN-al rendelkező) Control Channel adaptert újra kell konfigurálni, mivel a disable azt teljesen kitörli a beállítások közül! (Ez szintén nincs ledokumentálva sehol se)

A másik dolog ami ilyenkor problémát okozhat, ha olyan okosak vagyunk, hogy restartoljuk a gépet.. Ekkor ugyan is a SEA már nem fog semmit tudni arról, hogy ő eredetileg egy HA módban lévő dual network VIO volt, és annak rendje és módja szerint ő is "magáévá" szeretné tenni az adott VLAN taggelt hálózat irányítását.. Ez persze felvet egy olyan alapvető problémát, hogy mi van akkor ha már az adott hálózatot a switch-en használja valaki (tekintve, hogy dual VIO esetén a fentebb sorolt módon nagy eséllyel épp átadtuk a restart előtt a hálózatot a másik VIO-nak így szinte biztos, hogy ez a helyzet)?

Nos.. A helyzet koránt sem vicces -> A HA módból leválasztott SEA egy kisebb ARP tornádót fog a switch felé indítani (network storm) ami miatt meg a switch nem lesz képes kiszolgálni a kéréseket, ergo az a hálózat innentől nem elérhető, aminek a legtöbb customer csak ritkán örül, szóval dual network VIO-s környezetben mindenki felejtse el a ha_mode esetében a disable módot!!

Járulékosan az elmúlt pár napban felmerült részemről az igény egy kis network VIO monitoring scriptre, szóval ha valaki úgy érzi, hogy ez egy háztartásból se hiányozhat, úgy nyugodtan használja egészséggel :))

#!/usr/bin/ksh
# Script created by Gabor Lukacs
# Note - please use the script only on a dual-network VIO environment!
# Version 0.2

# Run as root pls :)
if [ "$(id -u)" != "0" ]; 
then
 echo "You must have root rights to run this script!"
 exit 1
fi

export ODMDIR=/etc/objrepos
NEED_MAIL=0
MAIL_SUBJECT="Warning! Some error(s) detected on $(hostname) VIO server!"
MAIL_ADDRESS=    # Fill this out before use :)

# Checking SEA adapters
if [ $(lsdev -Cc adapter |grep "Shared Ethernet Adapter" |grep -c Defined) -ne 0 ]
then
 echo "Warning! - There are one or more non-available SEA adapters:"
 lsdev -Cc adapter |grep "Shared Ethernet Adapter" |grep Defined
 NEED_MAIL=1
fi

for SEA in $(lsdev -Cc adapter |awk '/Shared Ethernet Adapter/ && /Available/ {print $1}')
do
 echo "\nChecking ${SEA} SEA adapter"
 USED_VLAN=$(odmget -q "name=${SEA} and attribute=pvid" CuAt|awk -F "\"" '/value/ {print $2}')
 SEA_STATE=$(entstat -d ${SEA} 2>&1|grep -E "ETHERNET STATISTICS|State|Priority" |awk '{ gsub("ETH", "\nETH"); print }' |grep -p ${SEA} |grep State)
 SEA_USED_TRUNK_PRIORITY=$(entstat -d ${SEA} 2>&1|grep -E "ETHERNET STATISTICS|State|Priority" |awk '{ gsub("ETH", "\nETH"); print }' |grep -p ${SEA} |grep Priority)
 SEA_USED_CTL_CHAN=$(odmget -q "name=${SEA} and attribute=ctl_chan" CuAt |awk -F "\"" '/value/ {print $2}')
 SEA_HA_MODE=$(odmget -q "name=${SEA} and attribute=ha_mode" CuAt |awk -F "\"" '/value/ {print $2}')
 echo "\tVLAN ID: $USED_VLAN"
 echo "\t${SEA_STATE}"
 echo "\t${SEA_USED_TRUNK_PRIORITY}"
 
 # In case the SEA adapter's state isn't Primary or backup send a mail
 if [[ $(echo "${SEA_STATE}"|awk '{print $NF}') != "BACKUP" && $(echo "${SEA_STATE}"|awk '{print $NF}') != "PRIMARY" ]]
 then
  NEED_MAIL=1
 fi
 
 if [ ${SEA_USED_CTL_CHAN} ]
 then
  echo "\tSEA used control channel adapter: ${SEA_USED_CTL_CHAN}"
 else
  echo "\tSEA used control channel adapter: No adapter defined (Please check in case it's a dual network-VIO setup!)"
 fi
 echo "\tSEA HA mode: ${SEA_HA_MODE}"
 
 REAL_ADAPTER=$(odmget -q "name=${SEA} and attribute=real_adapter" CuAt |awk -F "\"" '/value/ {print $2}')
 
 # Is the adapter in defined state?
 if [ $(lsdev -l ${REAL_ADAPTER} |grep -c Defined) -eq 1 ]
 then
  echo "\WARNING - The ${REAL_ADAPTER} adapter is in defined state!"
  NEED_MAIL=1
 # Ok.. It's not defined.. Move forward
 else
  if [ $(lsdev -l ${REAL_ADAPTER} |grep -c EtherChannel) -eq 1 ]
  # In case SEA using link aggregation
  then
   echo "\tSEA used real adapter: ${REAL_ADAPTER} (Etherchannel)"
   ETH_CHAN_ADAPTERS=$(odmget -q "name=${REAL_ADAPTER} and attribute=adapter_names" CuAt|awk -F "\"" '/value/ {print $2}' |sed "s/,/ /g")
   echo "\tUsed physical adapters under ${REAL_ADAPTER} Etherchannel adapters:"
   for ETH_CHAN_ADAPTER in ${ETH_CHAN_ADAPTERS}
   do
    # 2nd check - is any of the etherchannel used physical adapter in defined state?
    if [ $(lsdev -l ${ETH_CHAN_ADAPTER} |grep -c Defined) -eq 1 ]
    then
     echo "WARNING - The ${ETH_CHAN_ADAPTER} adapter is in Defined state!"
    # No.. Grand.. move forward
    else
     echo "\t\t${ETH_CHAN_ADAPTER}"
     ADAPTER_STATUS=$(entstat -d ${SEA} 2>&1|grep -E "ETHERNET STATISTICS|Link Status|Media Speed Running" |awk '{ gsub("ETH", "\nETH"); print }' |grep -p ${ETH_CHAN_ADAPTER} |awk '/Link Status/ {print $NF}')
     ADAPTER_MEDIA_SPEED=$(entstat -d ${SEA} 2>&1|grep -E "ETHERNET STATISTICS|Link Status :|Media Speed Running" |awk '{ gsub("ETH", "\nETH"); print }' |grep -p ${ETH_CHAN_ADAPTER} |grep Media)
     echo "\t\t\tStatus: ${ADAPTER_STATUS}"
     echo "\t\t\t${ADAPTER_MEDIA_SPEED}"
     # If adapter Status isn't up, send a mail
     if [ ${ADAPTER_STATUS} != "Up" ]
     then
      NEED_MAIL=1
     fi
    fi
   done
  # In case it not using Link aggregation
  else
   echo "\tSEA used real adapter: ${REAL_ADAPTER} (physical adapter)"
   ADAPTER_STATUS=$(entstat -d ${SEA} 2>&1|grep -E "ETHERNET STATISTICS|Link Status|Media Speed Running" |awk '{ gsub("ETH", "\nETH"); print }' |grep -p ${REAL_ADAPTER} |awk '/Link Status/ {print $NF}')
   ADAPTER_MEDIA_SPEED=$(entstat -d ${SEA} 2>&1|grep -E "ETHERNET STATISTICS|Link Status|Media Speed Running" |awk '{ gsub("ETH", "\nETH"); print }' |grep -p ${REAL_ADAPTER} |grep Media)
   echo "\t\tStatus: ${ADAPTER_STATUS}"
   echo "\t\t${ADAPTER_MEDIA_SPEED}"
   # If adapter Status isn't up, send a mail
   if [ ${ADAPTER_STATUS} != "Up" ]
   then
    NEED_MAIL=1
   fi
  fi
 fi
done > /tmp/vio_status.output

if [ ${NEED_MAIL} -eq 1 ]
then
 mail -s "${MAIL_SUBJECT}" "${MAIL_ADDRESS}" < /tmp/vio_status.output
fi

2011. augusztus 19., péntek

CPU usage monitoring by processes

Kaptam egy érdekes feladatot mostanság: Kéne valahogy monitorozni a gépen futó alkalmazások által használt CPU időt, de mindezt úgy, hogy az adatokat később diagram-ban ábrázolni lehessen processekre lebontva.
Első gondolatom az nmon volt, de sajna az nem képes a processenkénti lebontásra ahogy néztem.. topasrec detto nem.
Aztán próbáltam a ps listából kiszedni az adatokat ('ps -o ruser,pid,ppid,pcpu,args') de ott is bajba ütköztem, mivel sokszor a ps által reportolt eredmény durván eltért a topas/nmon által visszaadottól.
Aztán jó kis kutatás után kikötöttem a tprof-nál.. Ennek azonban alapvetően 1 nagy baja van: eredetileg csak arra készítették fel, hogy egy alatta futó alkalmazást monitorozzon és annak minden kis forkolását és mozgását kövesse, majd a végén reportot generáljon belőle. Viszont mint kiderült a tprof tud offline módban is dolgozni, bár elég hülye megkötésekkel.
A módszer kb így néz ki:
- Generáljunk a trace parancsal egy tracefile-t
- Hagyjuk kicsit futni a trace-t, majd állítsuk le (nálam ez 30 sec volt)
- Ez után a gensyms-el generáljuk le az address mappingot
- Majd futtassuk a kinyert adatokra a tprof-ot offline módban

Ez nálam a script-ben így nézett ki:

#!/usr/bin/ksh
mkdir /tmp/cpucheck 2>/dev/null
cd /tmp/cpucheck
DATE=$(date +"%Y.%m.%d. %H:%M:%S")
echo $DATE >> cpu_check_output_total
echo $DATE >> cpu_check_output
trace -af -T 1000000 -L 10000000 -o trace1.trc -j 000,001,002,003,005,006,234,106,10C,134,139,00A,465
sleep 30
trcoff
gensyms > trace1.syms
trcstop
tprof -skjue -R -P all -r trace1
grep -p Freq trace1.prof >> cpu_check_output_total
grep -p TID trace1.prof >> cpu_check_output
rm trace1*

Nem mondom, hogy szép megoldás, viszont a célnak bőven megtette. Annyi extrát adtam hozzá, hogy mivel a trace1.[trc|sysms] file-ok sok helyet igényeltek, így azokat a ciklus végén töröltem, miután kinyertem belőlük a számomra szükséges adatokat.
A scriptet crontabba belerakva és 10 percenként futtatva már egy egész szép kis kimutatást lehetett kapni arról, hogy mikor mi is folyik a rendszeren.
Valami ilyesfélét:

2011.08.14. 02:20:00
Process                          Freq  Total Kernel   User Shared  Other   Java
=======                          ====  ===== ======   ==== ======  =====   ====
dsapi_slave                         4  50.69  10.17  27.66  12.86   0.00   0.00
kuxagent                            2  22.34   0.06   0.00  22.28   0.00   0.00
/usr/bin/sh                       150   7.72   6.28   0.70   0.75   0.00   0.00
/usr/bin/echo                     129   5.24   5.16   0.00   0.08   0.00   0.00
/usr/bin/awk                      116   5.04   4.45   0.46   0.13   0.00   0.00
/usr/bin/sed                      106   4.37   4.25   0.00   0.13   0.00   0.00
wait                                4   2.39   2.39   0.00   0.00   0.00   0.00
dscs                                2   1.01   0.84   0.00   0.17   0.00   0.00
/usr/sbin/syncd                     1   0.35   0.35   0.00   0.00   0.00   0.00
l/DataStage/DSEngine/bin/dsjob      2   0.35   0.19   0.00   0.16   0.00   0.00
/db2gpsp1/sqllib/bin/db2usrinf      3   0.13   0.13   0.00   0.00   0.00   0.00
/bin/sh                             3   0.12   0.12   0.00   0.00   0.00   0.00
xmgc                                1   0.09   0.09   0.00   0.00   0.00   0.00
kulagent                            2   0.07   0.00   0.00   0.07   0.00   0.00
/usr/bin/vmstat                     1   0.03   0.03   0.00   0.00   0.00   0.00
/usr/bin/ksh                        1   0.03   0.03   0.00   0.00   0.00   0.00
/usr/bin/lparstat                   1   0.02   0.02   0.00   0.00   0.00   0.00
=======                          ====  ===== ======   ==== ======  =====   ====
Total                             528 100.00  34.57  28.83  36.61   0.00   0.00

Amit erről az ábráról le lehetett olvasni:
- A gépet a különböző scriptek elég durván meghajtják (jelen esetben a gépnek van 0.3 EC-je :))
- A legtöbb CPU időt a dsapi_slave nevű bináris viszi (mellesleg ez hívogatja a scripteket is)
- Szépen processekre lehet nézni, hogy a 30 sec-es mérésen belül mi és mennyiszer hívódott meg, az CPU kihasználtság viszont összesítve (Kernel, User,Shared-re lebontva) látható, ami nekem most nagyon is kapóra jött

Egy dologra viszont mindenképp felhívnám a figyelmet: Ez a report nem azt mutatja, hogy a gép 100%-ban ki volt hajtva, ahogy a Total mutatja! Csupán annyit mutat, hogy a felhasznált CPU mennyiség (!) mekkora része mely processek által lett kihasználva! Ergo ha valaki szeretne ez alapján egy átfogó képet készíteni, annak szüksége lesz egy külön log-ra, amely a global CPU usage-et nézi! Erre viszont már könnyű szerrel használhatóak a normal toolok (nmon/topasrec/sar). Ezt a kis "apróságot" leszámítva viszont szerintem nagyon is jól használható ez a kis módszer az esetleges bottleneck-ek kiderítésére (jelen esetben, hogy a gépen futó applikáció iszonyat sokat forkol (szerintem feleslegesen)

2011. június 9., csütörtök

xivpath - pre-release

Ahogy az előző postomban is említettem dolgoztam egy kicsit egy 'xivpath' nevű datapath/pcmpath szerű programon, hogy egy kicsit megkönnyítsem a saját életemet az XIV adminisztráció kapcsán.
Nos.. A fejlesztés elérkezett a "pre-release" fázisba. Ebben a fázisban az általam megtalált hibák/bugok már javítva lettek, és nem tudok további olyan bugról, ami ténylegesen problémát tudna okozni, így elérkezettnek láttam az időt, hogy publikáljam a kódot (tekintve, hogy semmi confidential dolgot nem tartalmaz).
Amennyiben van XIV-s rendszere bárkinek, azt megkérném, hogy tesztelje a kódot, és amennyiben hibát talál bárhol, úgy vegye fel velem a kapcsolatot, hogy javíthassam azt.

Jah igen.. felhívnám a figyelmet arra, hogy a script csak Fibre Channel adapterekre lett felkészítve, mivel nem áll rendelkezésemre iSCSI-t használó kliens. Továbbá -remélem feleslegesen- kiemelném, hogy ez a script az XIV-s kliensekre lett készítve, így ha pl DS8K-n akarná valaki használni, akkor ne csodálkozzon ha nem azt kapja amit várt :)
Illetve a szokásos játék itt is fennáll: Ezt a scriptet én a saját kis szabadidőmben csináltam, ergo hivatalos support nincs rá, illetve az esetlegesen keletkezett kárért se tudok felelősséget vállalni, így tessék tisztességesen egy teszt környezeten tesztelgetni első körben (azért arra felhívnám a figyelmet, hogy a scriptnek elvileg nem szabadna semmiféle kárt okoznia, de sose lehet tudni :))

Update: Kicsit hivatalos formába öntöttem a dolgot, és felraktam a csomagot az alábbi címre:
https://www.ibm.com/developerworks/mydeveloperworks/blogs/glukacs/resource/xivpath.tar.zip

2011. május 29., vasárnap

SDD,SDDPCM,XIV - Connection azonosítók..

Elkezdtem dolgozni az XIV-s scriptemen (amit még az előző postomnál megemlítettem) és úgy gondoltam, hogy milyen jó is lenne, ha kb úgy működne a script, mint az SDD/SDDPCM pcmpath/datapath parancsa (egy vezérlő parancs, amivel mindent administrative taskot szépen meg lehet csinálni).
Megyeget is szépen a fejlesztés (első körben még csak a query parancsok), és el is jutottam a 'query essmap' részhez, ahol is le lehet kérni a connection detaileket (az adott LUN melyik SAN Rack, melyik Module, melyik portján közlekedik felénk - hasznos kis információ hibakeresés esetén)..
Ez ugye pcmpath/datapath alatt valahogy így néz ki:
test_server@root:/ # datapath query essmap|head -3
Disk Path P Location adapter LUN SN Type Size LSS Vol Rank C/A S Connection port RaidMode
------- ----- - ----------- ------ ----------- ------------ ---- ---- --- ----- ---- - ----------- ---- --------
vpath0 hdisk6 6p-08-02[FC] fscsi3 xxxxxxx0400 IBM 2107-900 32.8GB 4 0 0004 29 Y R1-B3-H1-ZA 200 RAID5
Ami nekem ebből kellett az az 'R1-B3-H1-ZA'. Ugyan ezt akarom én is megvalósítani az XIV-s scriptem 'query essmap' részénél.. Na de nézzük hogyan...
Mint kiderült - ezt is ki lehet bányászni ODM-ből (CuPath alatt connection attributum utolsó 3 karaktere), de sajna ezt már nem lehet 1 az 1ben konvertálni ahogy néztem (vagy csak még nem jöttem rá pontosan hogyan).
Sebaj mondom, az XIV is nagyban épít az MPIO-ra, ahogy az SDDPCM is, annak meg van pcmpath parancsa, ami ezeket az infókat gyönyörűen kiadja, úgy hogy akkor induljak ki abból, nézzük össze az adatokat, és akkor az alapján dolgozzunk.

Némi kis keresgélés után kiderült, hogy SDDPCM alatt ugyan úgy a CuPath alatt kell keresni az adatokat, csak ott nem a végén, hanem kicsit máshol, de ugyan úgy megvan. Így aztán elkezdtem írni egy kis scriptet ami ezeket összegyűjti nekem, és amiből aztán majd egy kedves kis mátrixot csinálhatok, hogy mi és merre..
Aztán ahogy gyűltek az adatok észrevettem, hogy ugyan ezen kiosztás érvényes az SDD esetében is és ott meg a datapath alatt ugyan úgy elérhetőek ezek a Connection infók, szóval kicsit kibővítettem a scriptem, hogy lekezelje az SDD-os ODM bejegyzéseket is (ez kivételesen már a CuAt alatt van) és összeszedtem amit tudtam.

Az eredmény: Egy egész kellemes kis script:
#!usr/bin/ksh
SDDPCM=0
SDD=0
export ODMDIR=/etc/objrepos
if [ `lslpp -l |grep -wc devices.sddpcm` -gt 0 ]
then
SDDPCM=1
MAIN_COMMAND="pcmpath"
fi

if [ `lslpp -l |grep -wc devices.sdd` -gt 0 ]
then
SDD=1
MAIN_COMMAND="datapath"
fi

$MAIN_COMMAND query essmap > /tmp/$MAIN_COMMAND.query.essmap
for i in $(awk '{print $14}' /tmp/$MAIN_COMMAND.query.essmap |sort|uniq |grep ^R);do grep -w $i /tmp/$MAIN_COMMAND.query.essmap |head -1;done |awk '{ sub("path", ""); print $1,$2,$14}' > /tmp/connection.check

while read LINE
do
if [ $SDDPCM -eq 1 ]
then
set -A array $LINE
DISK=$(print ${array[0]})
CONN_PATH=$(print ${array[1]})
CONNECTION=$(print ${array[2]})
# In case of SDDPCM 11-13 contain the right identifiers in CuPath
CONN_IDENTIFIER=$(odmget -q "name=$DISK and path_id=$CONN_PATH" CuPath|awk -F "\"" '/connection/ {print $2}'|cut -c 11-13)
elif [ $SDD -eq 1 ]
then
set -A array $LINE
DISK=$(print ${array[1]})
CONNECTION=$(print ${array[2]})
# In case of SDD
CONN_IDENTIFIER=$(odmget -q "name=$DISK and attribute=ww_name" CuAt|awk -F "\"" '/value/ {print $2}' |cut -c 13-15)
fi

echo "$CONN_IDENTIFIER - $CONNECTION"
done < /tmp/connection.check



Illetve egy kellemes kis mátrix, amit használni tudok:
000 - R1-B1-H1-ZA
004 - R1-B1-H1-ZB
008 - R1-B1-H1-ZC
030 - R1-B1-H3-ZA
034 - R1-B1-H3-ZB
038 - R1-B1-H3-ZC
080 - R1-B2-H1-ZA
084 - R1-B2-H1-ZB
088 - R1-B2-H1-ZC
0b0 - R1-B2-H3-ZA
0b4 - R1-B2-H3-ZB
0b8 - R1-B2-H3-ZC
100 - R1-B3-H1-ZA
104 - R1-B3-H1-ZB
108 - R1-B3-H1-ZC
130 - R1-B3-H3-ZA
134 - R1-B3-H3-ZC
138 - R1-B3-H3-ZC
180 - R1-B4-H1-ZA
184 - R1-B4-H1-ZB
188 - R1-B4-H1-ZC
1b0 - R1-B4-H3-ZA
1b4 - R1-B4-H3-ZB
1b8 - R1-B4-H3-ZC
200 - R1-B5-H1-ZA
204 - R1-B5-H1-ZB
208 - R1-B5-H1-ZC
230 - R1-B5-H3-ZA
234 - R1-B5-H3-ZB
238 - R1-B5-H3-ZC
280 - R1-B6-H1-ZA
284 - R1-B6-H1-ZB
288 - R1-B6-H1-ZC
2b0 - R1-B6-H3-ZA
2b4 - R1-B6-H3-ZB
2b8 - R1-B6-H3-ZC
300 - R1-B7-H1-ZA
304 - R1-B7-H1-ZB
308 - R1-B7-H1-ZC
330 - R1-B7-H3-ZA
334 - R1-B7-H3-ZB
338 - R1-B7-H3-ZC
380 - R1-B8-H1-ZA
384 - R1-B8-H1-ZB
388 - R1-B8-H1-ZC
3b0 - R1-B8-H3-ZA
3b4 - R1-B8-H3-ZB
3b8 - R1-B8-H3-ZC
Na mondom éljen.. Megvan minden szépen ahogy kell.. Nézzük ezt össze az XIV-s kapcsolatokkal.. És kopp - XIV alatt jóvolta több kapcsolat van, mint amiket én kigyűjtöttem, ami azt jelenti, hogy ez a mátrix max részben használható jelenleg..
Most bújom a DS8000 és az XIV Architecture guide-jait, hogy megnézzem milyen durva különbségek vannak még amiről tudnom kéne :)))

Stay tooned :)

Szerk:
na végül erre is fény derült :))
- > DS8000 series alatt a Bay1-8 az a DS hátán elhelyezett I/O enclosure-öknek felelnek meg (SG246452 PDF 44. oldal), míg XIV esetében ez kicsit másként néz ki: Igaz, hogy jóvolta több kapcsolódási lehetősége van, viszont Fibre kapcsolatra csupán 6 I/O module-ja van (SG247659 PDF 81. oldal) amelyek számozása Module 4-9ig tart (ergo Bay1-4 variáció itt totál kiesik). Minden module rendelkezik 4-4 portal kapásból, amiket aztán rá lehet kötni a közeli Fibre switchre.
Ez után viszont akkor ez azt jelenti, hogy az SDD/SDDPCM-nél megszokott konnekciós ábrázolás bukott, helyette valami ilyesmi használható XIV esetén:
test_server@root:/ # odmget -q name=hdisk3 CuPath |awk -F "\"" '/connection/ {print $2}' |cut -c 14-16 |sort|uniq |head -1
140
Ergo jelen esetben akkor ez a kapcsolat a Rack 1, Module 4 1. portjáról jön ( az ODM-ben a számozás 0-3ig van, az XIV-n meg 1-4ig, ergo ott azt 1el kell növelni), tehát a nevezéktan valami ilyesmi lehetne:
R1-M3-C1
(Az SDD/SDDPCM query essmap outputja végén lévő ZA/ZB/ZC/ZD(?) elvileg a Fabric-et jelöli. Annak még megpróbálok utánajárni, hogy kinyerhető e valahogy :)

2011. május 17., kedd

XIV_ID-k és XIV_LUNID-k

Te hogy kérdezed le egy XiV-ról kapott LUN ID-ját, illetve, hogy melyik XiV-ról is jön az adott LUN?
Nos.. Az alapvető válasz egyszerű: A HAK csomagon belül elérhető az xiv_devlist parancs, amit megfelelően felparaméterezve ('xiv_devlist -o all', vagy 'xiv_devlist -v') kidobja nekünk az összes XIV-hez csatolt LUN információját, abból meg kedvünk szerint szűrhetünk grep-el, awk-al, akármivel.. Nincs is ezzel baj.. Na jó... egy kicsi még is - ez a módszer iszonyat de lassú (de legalább színes),főleg ha scripteléshez is szeretnénk valamely adatot használni, arról ne is beszéljünk mi van akkor, ha sok diszkünk van az XiV-hez csatolva (lassú == csiga)
Úgy hogy kicsit elkezdtem turni, hogy hogy is lehetne ezt sokkal gyorsabban megvalósítani.. Nos.. VAN MEGOLDÁS.. Bár jól eldugták..
Az utat ahogy eddig eljutottam nem írom le (legyen elég annyi, hogy szívatós, főleg ha rászámolom, hogy a nyomozás egyik szakaszában a teljes rootvg-t végiggreppeltem az adott string után kutatva :)), úgy is inkább az eredmény érdekli az embereket..
Akkor lássuk hát:
Alapjáraton megszoktam, hogy mind SDD,SDDPCM,MPIO drivereknél az adott LUN ID-ja kinyerhető az ODM-ből.. Erre szolgál ugyan is az unique_id attributum (odmget-el, vagy lsattr-al lekérhető). XiV-s diszknél (hiába támaszkodik félig meddig az MPIO-ra) ez mintha mégse lenne így meg (az elején legalább is nagyon nem így tünt). De nézzük meg közelebbről ezt a stringet..
# odmget -q "name=hdisk10 and attribute=unique_id" CuAt |awk -F "=" '/value/{print $2}'
"261120017380005660F32072810XIV03IBMfcp"
Annyit tudtam alapjáraton is, hogy a LUN-om a 6001382-ös XiV-ről jön, illetve hogy a LUN ID-ja 3890:
# xiv_devlist |grep -w hdisk10
/dev/hdisk10 34.4GB 18/18 Vol1 3890 6001382 test_server
Az adott ODM attributumban persze semmi hasonló nincs.. Egészen addig amíg az ember el nem kezdi boncolgatni.. Mint kiderült: Ott van az.. Csak nézzük kicsit másként azt a stringet:
261120017380005660F32072810XIV03IBMfcp
Na akkor mit is bányászhatunk ki:
0566 - Ez az XiV boxunk azonosítójának utolsó 4 jegye (jelen esetben) hexában tárolva -> 1382
0F32 - Ez pedig a LUNID-nk szintén hexában tárolva -> 3890
/* Azt majd még meg kéne nézni, hogy a 0-ák a string elején mennyire konstansak, de jelen esetben nálam erre nem volt szükség */
Ergo akkor némi kis scripteléssek ki lehet szedni az aktuális azonosítókat, immár kifejezetten gyorsabban:
#!/usr/bin/ksh
DISK=hdisk10
UNIQUE_ID=$(odmget -q "name=$DISK and attribute=unique_id" CuAt |awk -F "=" '/value/{print $2}')
XIV_ID=$(echo "600$(echo "ibase=16; $(echo $UNIQUE_ID|cut -c 15-18)"|bc)")
XIV_LUNID=$(echo "ibase=16; $(echo $UNIQUE_ID|cut -c 19-22)"|bc)

#Edit:
Az ODM entry-ben lévő '2810XIV' utal arra, hogy XiV-s LUN-ról van szó. Ugyan ez DS8k box esetében is megtalálható, csak akkor a '2107900'-es stringre kell figyeljünk

2011. március 31., csütörtök

AIX - Rootvg költöztetés - csak óvatosan!!

Történt az a vicces eset, hogy a rootvg-t át kellett költöztetni egy AIX gépen.. Ez alapvetően nem is nagy nehézség:
- extendvg rootvg [new_disk]
- mirrorvg rootvg [new_disk]
- syncvg rootvg # Menjünk biztosra
- unmirrorvg rootvg [old_disk]
- reducevg rootvg [old_disk]
- bosboot -ad /dev/new_disk
- bootlist -m normal [new_disk]
Ez szépen is megy.. De sajna van egy bökkenő, ha mksysb-t is szeretnénk futtatni a gépen ezek után - az elég durván elhasal, ilyesmi hibaüzenettel:
0301-168 bosboot: The current boot logical volume, /dev/hd5,
does not exist on /dev/hdisk0.
Mint kiderül: A szituáció az, hogy az mksysb-nk meghívja az mkszfile parancsot, ami pedig hív egy 'bosboot -qv'-t.
A szerencsétlen bosboot-unk pedig nagyon nem is törődik a rendszer állapotával, őt csak az érdekli, hogy mi van az NVRAM-ban, ergo ez így csak restart után menne neki..
Kivétel persze, ha kicsit megszeghetjük a szabályokat =>
Az IBM már egy ideje tisztában van az adott problémával, sőt hibajegyet is adtak ki rá: IZ90977. Ez alapján már nem nehéz kicsit áttúrni az mkszfile-t, hogy azt csinálja ami nekünk kell: A /usr/bin/mkszfile file-an a 399. sor környékén írjuk át a számunkra szükséges sort az alábbiak alapján:
+399 BOOT_BLKS=`LC_MESSAGES=C ${bosboot} -qv | ${tail} -1l | ${awk} '{print $2 * 2}'`
=>
+399 BOOT_BLKS=`LC_MESSAGES=C ${bosboot} -qvd /dev/ipldevice | ${tail} -1l | ${awk} '{print $2 * 2}'`
Ezek után még figyeljünk arra, hogy a /dev/ipldevice-unk a megfelelő rhdisk-re mutasson:
# Test_server:root > ls -l /dev/rhdisk5
crw------- 2 root system 17, 5 Feb 18 15:01 /dev/rhdisk1
# Test_server:root > ls -l /dev/ipldevice
crw------- 2 root system 17, 5 Feb 18 15:01 /dev/ipldevice
Innen pedig már az mkszfile-unk is jól lefut, illetve az mksysb se fog kardjába dőlni..

2010. november 29., hétfő

AIX - VG varyon failed.. - Avagy amikor Murphy nagyot mosolyog..

Na de vajon miért.. (költői kérdés).. avagy - ez az a helyzet, amibe nem szívesen kerülök, mint system admin (amúgy sikerült megoldani, csak gondoltam postolom ezt is :))
# > lspv |grep -w hdisk10
hdisk10 00c3f43e8eff2532 None
# > readvgda hdisk10 |grep pv_id
pv_id: 00c3f42e99549e58
pv_id: 00c3f42e99549fef
pv_id: 00c3f42e9954a259
pv_id: 00c3f42e9954a3ee
pv_id: 00c3f42e9954a587
pv_id: 00c3f42e9954a716
pv_id: 00c3f42e9954a982
pv_id: 00c3f42e9954ab07
pv_id: 00c3f42e9954ad78
pv_id: 00c3f42e9954aeff
pv_id: 00c3f42e9954b162
pv_id: 00c3f42e9954b2f1
pv_id: 00c3f42e9954b47c
A szitu az volt, hogy kb 150 diszk keringőzött a gépen, amiből mint fentebb látható 13 egy VG-hez tartozott.. Sajna a gépen -nem részeletezem miért - az összes diszk PVID-ja törölve lett (kiv a rootvg-hez tartozók), ergo a VG-ket a VGDA adatok alapján kellett helyrevágni.
A dolog pikantériáját az adta, hogy a readvgda/lqueryvg segítségével meg tudod nézni melyik diszk mely diszkkel volt közös VG-n belül (vgda-n belül a vg_id sokat tud ebben segíteni), viszont ez után még 2 problémával szembe kell nézz:
- Az 1ik az, hogy a PVID-kat attól még vissza kéne rakni (VGDA-ba nem írunk), különben a VG-t az istennek se lehet varyon-olni
- A másik az, hogy az embernek figyelnie kell arra is, hogy a megfelelő PVID-t a megfelelő diszkre írja vissza (az, hogy még mondjuk fél napja -hasraütök- a hdisk10es az XY PVID-t bírtokolta, az még nem jelenti azt, hogy az a hdisk10 ugyan az a hdisk10 amit most látsz, ergo nem lehet benne biztos, hogy az XY PVID-t erre a diszkre kell visszaírd..
Az első problémára a megoldás kicsit vicces... A PVID fizikailag tárolódik a diszken, így azt felül lehet vágni egy mókásan felparaméterezett dd-vel .. a módszer kb így néz ki:
#!/usr/bin/ksh
pvid=$1
disk=$2
set -A a `echo $pvid|\
awk ' {
for (f=1; f <= length($0); f=f+2) {
print "ibase=16\nobase=8\n"toupper(substr($0,f,2))
}
}'|\
bc 2>/dev/null`
/usr/bin/echo "\0"${a[0]}"\0"${a[1]}"\0"${a[2]}"\0"${a[3]}"\0"\
${a[4]}"\0"${a[5]}"\0"${a[6]}"\0"${a[7]}"\0\0\0\0\0\0\0\0\c"|\
dd bs=1 seek=128 of=/dev/$disk
A 2. probléma már gázosabb.. megvan, hogy mely 13 diszk van benne a VG-ben (sőt még a VG nevét is tudjuk valahonnan), de attól még nem tudjuk melyik diszk melyik PVID-t kéne birtokolja.. Nos.. ez az a pont, ahol a jól dokumentált rendszer csak a jó rendszer - előkaptam a régi doksikat, és a LUNID-k alapján (vagy lokál diszk esetén lokációs adat alapján) összerendezhető, hogy minden diszk az e akiről tudjuk.. Ha ez megvan, akkor a fentebb leírt módszerrel a megfelelő PVID-k visszavarázsolhatók a megfelelő diszkekre, és ismét lehet varyon-olni..

2010. május 19., szerda

Tiny script - Putty settings converter

Windows-Linux migráció során született nálam az igény, hogy a Windows alatt használt putty-s beállításaimat valahogy át kéne pakolni linux alá ( tekintve, hogy elég sok szerver volt felvéve, így mindet manual ismét felpakolni elég nagy macera lett volna ). Ezen igény kielégítésére született az alábbi kis scriptecske. Gondoltam publikálom hátha még valakinek jól jön:
http://pastebin.com/TYxfLXFL
A folyamat kb a következőképp néz ki:
- Windows alól első körben ki kell exportáljuk a putty-s beállításainkat a registryből ( regedit.exe /e putty_settings.reg HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\Sessions )
- A kiexportált .reg file-t át kell konvertáljuk UTF16ról valami emberibb formátumba ( UTF-8, CP-1250 ). Ehhez én a lokális gépen notepad++-t használtam, de ha cygwin alá felrakjuk az iconv-t azzal is megy ( megoldható lett volna egy perl alatti iconv modul include-olása, de mivel az is külső modult igényelt volna, így azt elvetettem )
- A scriptben megadjuk a .reg file helyét ( éljen a hardcoding :D (Jó tudom.. Lusta voltam megírni, hogy megkérdezze :))
- A scriptet futtatva ( nálam épp cygwinből, de elvileg activeperl is használható ) az aktuális mappába legenerálja nekünk a linux alatt használható file-okat
- A generált file-okat a ~user/.putty/sessions mappa alá bepakolva már is a helyükön lesznek a session-ök :)
Amire figyelni kell:
- Ha van beállítva logolás, akkor linux alatt azt ildomos átlőni ( egy sed szerintem totál megteszi erre a célra )
- A használt kulcsfile-t érdemes szintén átlőni
For the trolls:
Nem mondom, hogy szép, vagy hogy nem lehetne rajta fejleszteni, csupán egy szerintem elégséges alap az adott feladat ellátására. Viszont ha van bárkinek bármilyen javaslata ( kódolás során megejtett hibák főként ) amiből érdemes tanulni azt most is szívesen fogadom.