HTML

Bagoj úr blogja

Kíváncsi Bagoj befigyel a Linux belsejébe, illetve különféle Linux terjesztéseket próbál ki. Ha jó napja van, scriptet ír Neked.

Friss topikok

Sorokból oszlopot awk-val

2012.12.14. 12:38 bagoj ur

"Egy kis rendszerfelügyelet" jeligére gondoltam, közzéteszem ezt az apró egysoros szkriptet, amely sorokból oszlopokat gyárt.

Probléma: IPSec VPN kapcsolatokat monitorozó rendszer nagy kieséseket mutat, közben a VPN-t termináló tűzfal szerint csak ezred- vagy tizedmásodperces "megállások" vannak, amíg a Phase2-es kulcsokat újragenerálja. Az első monitorozó rendszer hibájának kizárására egy újabb, független monitorozó rendszert állítottak be, de az egy harmadik értéket mutatott. Arra kértek, hogy zárjam ki a zavaró tényezőket és határozzam meg, mi lehet a hiba.

A megoldáshoz csak SNMP lekérdezés használható, mivel szigorú szabályozás miatt más nem engedélyezett. A tűzfal logjaiban nincs ok kételkednem, de arra gyanakodtam, hogy (bár a teljesítmény-mérések erről nem tanúskodtak) valamivel el van foglalva, ezért csak késve frissíti be az SNMP regisztereit, így a lekérdezés pontatlan.

Feladat: SNMP lekérdezéssel egy tűzfalról lekérni perces intervallummal a VPN kapcsolatok állapotait, ezt egy fájlban rögzíteni, majd utólag a fájlból könnyen értelmezhető táblázatot kell készíteni.

Megoldás

A lekérdezés természetesen nem nehéz:

while true; do
        date +"%Y-%m-%d %H:%M:%S" >> snmp.out
        snmpwalk -v 2c -c <community_string> <OID> >> snmp.out
        sleep 60
done

A community azonosító és az OID, amely végülis a konkrét állapotokat tartalmazza, esetünkben lényegtelen. Még némi átalakítást is végeztem, és csak utána tettem be a fájlba az eredményt. A lényeg, hogy a fájlban ez látható:

2012-12-13 17:46:02
0 active(1)
1 active(1)
2 active(1)
3 active(1)
4 active(1)
5 active(1)
6 active(1)
7 active(1)
8 active(1)
9 active(1)
10 active(1)
11 active(1)
12 active(1)
13 active(1)
14 active(1)
15 active(1)
16 active(1)
17 active(1)
18 active(1)
19 active(1)
20 inactive(0)
21 inactive(0)
22 active(1)
23 active(1)
2012-12-13 17:47:03
0 active(1)
1 active(1)
2 active(1)
3 active(1)
4 active(1)
...

A problémánk tehát az, hogy egymás alatti sorokba vannak rendezve az egyes VPN csatornák állapotai, nekünk pedig úgy lenne jó, ha egy-egy időponthoz tartozó összes VPN állapot egy sorban lenne - magyarul oszlopokat kell gyártanunk sorokból. Szedjük elő hát kedvenc awk-nkat:

awk 'BEGIN{ORS=""} {for ( x = 0; x < 24; x++ ) { sub(/.+active\(/,"");sub(/\)/,""); print $0" "; getline; } print "\n";}' snmp.out > eredmeny.txt

Természetesen a fentiek értelmezése nem okozhat gondot senkinek, aki a bevező írásomon túljutott. :-P Mégis értelmezném a fenti egysorost :-):

A BEGIN részben az output record separator-t, azaz a sorokat elválasztó karaktert (ami nem meglepően alapértelmezetten \n, azaz soremelés) kinullázzuk. Ezzel azt érjük el, hogy a feldolgozott sorok többé nem sorok, hanem egyetlen hosszú adatfolyam.

A for ciklus természetesen arra kell, hogy a formázatlanná tett sorok ismét formázottak legyenek, ezúttal viszont úgy, hogy a dátum és mögötte a VPN státuszok egy egységet kell képezzenek.

A két sub() függvény egyszerű cserét végez el annak érdekében, hogy csak a zárójelek közötti 1-est vagy 0-t tegyük az adott oszlopba. Ezután a print $0 kiírja a maradékot (itt szerintem elég lenne egy sima print is, de nem próbáltam, így jött ki a kezemen, most már így marad). A getline; új sort olvas be, hiszen különben minden sornál kiírnánk ugyanazt az értéket 24x, magyarul nem a kívánt eredményt kapnánk. Ha a dátum és a státuszok megvannak, akkor vége a ciklusnak, ezért kézzel hozzáadunk egy soremelést, tehát mi vezéreljük azt, hogy mi számítson egy rekordnak.

A végeredmény egy szöveges fájl, ami Excelbe beolvasható szóközzel elválasztott fájlként, és olyan színes kimutatást gyárthatunk belőle, hogy a vezetőink csak pislognak.

2012-12-13 17:46:02 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1
2012-12-13 17:47:03 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1
...

Ha valakit érdekel a megoldás: mint kiderült, az SNMP lekérdezés tényleg csak ennyire megbízható. A riasztások elkerülésére a monitoring alkalmazást állították át úgy, hogy 2 vagy több kiesésre jelezzen csak.

5 komment

Címkék: linux sorok tűzfal awk szkript rendszerfelügyelet vpn snmp oszlopok lekérdezés

A bejegyzés trackback címe:

http://bagojur.blog.hu/api/trackback/id/tr54965006

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben.

csarlee 2012.12.25. 08:34:13

Az egysoros vakmeleg! Amúgy egyetértek, az SNMP már csak ilyen...

atomgape 2013.01.05. 16:58:25

Hajrá, Bagoj úr, kiváló írás! :-)

0sm 2016.02.04. 10:25:43

Szia Bagoj úr!
Segítségre van szükségem, mert nem tudom, mit kezdjek a problémámmal.
Kapok egy tonna ügyféladatot, amit javítani kell, mert eltérés mutatkozik az adat rögzítése pillanatában felvett adat a jelenlegivel. - tudom, hülyén hangzik, de ha tudnád, mi folyik itt...
Konkrétan:
Kapok csomó xml-t és egy listát. A lista tartalmazza azokat az adatokat, melyek az xml-ekben duplán fordulnak elő. Példa kedvéért legyen a duplikáció: AAAAAAAAA
Az xml-ben 22 sor tartalmaz minden ügyféladatot, de a hibásak duplikálva vannak az alábbi rendszer szerint:
<1>
<2>
<3></3>
<!-- AAAAAAAAA: BBBBBBB - CCCC - DDDDDDDDDDDD - EEEEEEEEEEEEE -->
<4>BBBBBBB</4>
<5></5>
<6></6>
<7>DDDDDDDDDDDD</7>
<8>EEEEEEEEEEEEE</8>
<9>CCCC</9>
<10>FFFFFFFFFFFFF</10>
<11>GGGGGGGGGGGGG</11>
</2>
<12>
<13>20150503</13>
<14>HHHHHHHHH</14>
<15>AAAAAAAAA</15>
<16>---</16>
<17>JJJJJJJJJJ</17>
<18>KKKKKKKKKK</18>
</12>
</1>
Ez a 22 sor még egyszer előfordul az xml-ben, mégpedig így:
<1>
<2>
<3></3>
<!-- AAAAAAAAA: BBBBBBB - CCCC - DDDDDDDDDDDD - EEEEEEEEEEEEE -->
<4>BBBBBBB</4>
<5></5>
<6></6>
<7>DDDDDDDDDDDD</7>
<8>EEEEEEEEEEEEE</8>
<9>MMMM</9>
<10>FFFFFFFFFFFFF</10>
<11>GGGGGGGGGGGGG</11>
</2>
<12>
<13>20150503</13>
<14>HHHHHHHHH</14>
<15>AAAAAAAAA</15>
<16>---</16>
<17>JJJJJJJJJJ</17>
<18>KKKKKKKKKK</18>
</12>
</1>

A <9>-es tag eltér, az egyiket az ügyfél dadogása során rögzítették (kb. úgy képzeld el, mint az egyszeri vájárt a lottószám sorsoláskor: a következő nyerőszám a hatos. Ja nem, a kilences.)
A kiemelt sor <!-- mindkét 22-es blokkban tartalmazza a helyes adatokat, ami a példában a CCCC
Az első blokk a helyes: <9>CCCC</9>
a második a hibás: <9>MMMM</9>

Hogyan lehetne ezt megoldani shell-ben, akár awk-kal, akár ed-del, bármivel?

Gondoltam már arra, hogy egyszerűen beolvasom a kiemelt sort és a megfelelő tageket kicserélem, akár jó, akár nem... mert a cserével mindenféleképpen jók lesznek az adatok... de a fő gondom az, hogy ahány hiba van az xml-ben, annyiszor 22-sorral több lesz az xml.

Hogyan kéne ezt a problémát megoldani szerinted?
Évek óta kézzel javítom ezeket, tehát vi, duplikált adat megkeres, szemmel adatellenőrzés, kurzor megfelelő helyre mozgatás, majd 22 dd, mentés és ez ismétlődik többszázszor.
Ezt kellene gépesítenem, mert lassan homokot szórok a fejemre és elkezdek magamba beszélni.

Előre is kösz, a rám szánt idődet.

0sm 2016.02.04. 10:28:53

Visszaolvasva még kiegészíteném... hátha nem világos:
Tehát a második blokkot...

<1>
<2>
<3></3>
<!-- AAAAAAAAA: BBBBBBB - CCCC - DDDDDDDDDDDD - EEEEEEEEEEEEE -->
<4>BBBBBBB</4>
<5></5>
<6></6>
<7>DDDDDDDDDDDD</7>
<8>EEEEEEEEEEEEE</8>
<9>MMMM</9>
<10>FFFFFFFFFFFFF</10>
<11>GGGGGGGGGGGGG</11>
</2>
<12>
<13>20150503</13>
<14>HHHHHHHHH</14>
<15>AAAAAAAAA</15>
<16>---</16>
<17>JJJJJJJJJJ</17>
<18>KKKKKKKKKK</18>
</12>
</1>

...törölnöm kell az xml-ből.
És ilyen hibás blokkokkal van tele az xml.

0sm 2016.06.07. 15:33:04

Nah... csak összehoztam.
Ideírom a kódot, mert látom, nem megy neked sem és hátha van valami hozzám hasonló nemnormális. (tudom, hogy menne neked, csak nem érdekel... ;)
Szóval awk-kal oldottam meg... bár nem nagyon értek hozzá:

Megírja az első két taget, majd adott tagek esetén memóriába pakol, kisbetűsít, összehasonlít és ha arra érdemesnek találja az adatokat, kiír.
Egyszerű, mint a csapbakakálás.

Köszi a figyelmet!

BEGIN{
FS="<|>";
nr = 0;
}
/Document_Name/{ dname = $3; printf ("<?xml version=\"1.0\" encoding=\"ISO-8859-2\"?>\n<Document>\n <Document_Name>%s</Document_Name>", dname) }
/Document_Date/{ ddate = $3; printf ("\n <Document_Date>%s</Document_Date>", ddate) }
/Sorszam/ {
getline;
comment = $0;
}
/HN/{ name = $3; }
/HD1/{ d1 = $3; }
/HD2/{ d2 = $3; }
/HA/{ aes = $3; }
/HC/{ cy = $3; }
/HZ/{ zapp = $3; }
/MT/{ mte = $3; }
/MC/{ mc = $3; }
/Ld/{ ld = $3; }
/Lt/{ lt = $3; }
/Ll/{ ll = $3; }
/CdN/{ cdn = $3; gsub(" ","",cdn); }
/<\/DocumentData>/{
s1 = tolower(sprintf("%s", cmt));
gsub(" ","",s1);
s2 = tolower(sprintf(" <!-- %s: %s - %s - %s - %s -->", cardno, name, zip, city, address));
gsub(" ","",s2);
if ( s1 == s2 ) {
nr = nr + 1;
printf ("\n <DocumentData>\n <Header>\n <Sorszam>%s</Sorszam>\n%s\n <HN>%s</HN>\n <HD1>%s</HD1>\n <HD2>%s</HD2>\n <HA>%s</HA>\n <HC>%s</HC>\n <HZ>%s</HZ>\n <MT>%s</MT>\n <MC>%s<MC>\n </Header>\n <Letter>\n <Ld>%s</Ld>\n <LetterCity>Budapest</LetterCity>\n <CdN>%s</CdN>\n <TelNumber>-</TelNumber>\n <Lt>%s</Lt>\n <Ll>%s</Ll>\n </Letter>\n </DocumentData>", nr, cmt, name, d1, d2, aes, cy, zapp, mt, mc, ld, cdn, lt, ll);
}
#else if {
# s1 = "
#}
}
END{
printf ("\n</Document>\n");
}