PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /opt/dedrads
Viewing File: /opt/dedrads/megaclisas-status
#!/usr/lib/rads/venv/bin/python3 # $Id: megaclisas-status,v 1.68 2016/10/21 14:38:56 root Exp root $ # # Written by Adam Cecile <gandalf@NOSPAM.le-vert.net> # Modified by Vincent S. Cojot <vincent@NOSPAM.cojot.name> # import os import re import sys if sys.platform == 'win32': import ctypes def_megaclipath = "/opt/MegaRAID/MegaCli/MegaCli64" # Non-Nagios Mode defaults nagiosmode = False nagiosoutput = '' nagiosgoodarray = 0 nagiosbadarray = 0 nagiosgooddisk = 0 nagiosbaddisk = 0 # Sane defaults printarray = True printcontroller = True debugmode = False notempmode = False totaldrivenumber = 0 # Hardcode a max of 16 HBA and 128 LDs for now. LDTable must be initialized to accept populating list of LD's into each ctlr's list. MaxNumHBA = 64 MaxNumLD = 128 LDTable = [[] * MaxNumHBA for i in range(MaxNumLD)] NestedLDTable = [[False for i in range(MaxNumHBA)] for j in range(MaxNumLD)] # Outputs is a 'dict' of all MegaCLI outputs so we can re-use them during loops.. Outputs = {} # Startup def print_usage(): print('Usage: megaraid-status [--nagios|--debug|--notemp]') # We need root access to query if __name__ == '__main__': try: root_or_admin = os.geteuid() == 0 except AttributeError: root_or_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0 if not root_or_admin: print('# This script requires Administrator privileges') sys.exit(5) # Check command line arguments to enable nagios or not if len(sys.argv) > 2: print_usage() sys.exit(1) if len(sys.argv) > 1: if sys.argv[1] == '--nagios': nagiosmode = True elif sys.argv[1] == '--debug': debugmode = True elif sys.argv[1] == '--notemp': notempmode = True else: print_usage() sys.exit(1) # Functions def dbgprint(msg): if debugmode: sys.stderr.write(str('# DEBUG : ' + msg + '\n')) def is_exe(fpath): return os.path.isfile(fpath) and os.access(fpath, os.X_OK) def which(program): import os fpath, fname = os.path.split(program) if fpath: if is_exe(program): return program else: # Add some defaults os.environ["PATH"] += os.pathsep + '/opt/MegaRAID/MegaCli' os.environ["PATH"] += os.pathsep + '/ms/dist/hwmgmt/bin' os.environ["PATH"] += os.pathsep + os.path.dirname( os.path.realpath(sys.argv[0]) ) for path in os.environ["PATH"].split(os.pathsep): dbgprint('Looking in PATH ' + str(path)) path = path.strip('"') exe_file = os.path.join(path, program) if is_exe(exe_file): dbgprint('Found "' + program + '" at ' + exe_file) return exe_file return None # Find MegaCli for megabin in "MegaCli64", "MegaCli", "megacli", "MegaCli.exe": dbgprint('Looking for ' + str(megabin) + ' in PATH next..') megaclipath = which(megabin) if megaclipath != None: dbgprint('Will use MegaCLI from here: ' + str(megaclipath)) break # Check binary exists (and +x), if not print an error message if megaclipath != None: if os.path.exists(megaclipath) and os.access(megaclipath, os.X_OK): pass else: if nagiosmode: print('UNKNOWN - Cannot find ' + megaclipath) else: print( 'Cannot find ' + megaclipath + 'in your PATH. Please install it.' ) sys.exit(3) else: print( 'Cannot find "MegaCli64","MegaCli" or "megacli" or "MegaCli.exe" in your PATH. Please install it.' ) sys.exit(3) #### pdb.set_trace() def returnWdthFromArrayCol(glarray, idx): maxwdth = 0 for glrow in glarray: if len(glrow[idx]) > maxwdth: maxwdth = len(glrow[idx]) return maxwdth # Get command output def getOutput(cmd): lines = [] if cmd in Outputs: dbgprint("Got Cached value: " + str(cmd)) lines = Outputs[cmd] else: dbgprint("Not a Cached value: " + str(cmd)) output = os.popen(cmd) for line in output: if not re.match(r'^$', line.strip()): lines.append(line.strip()) Outputs[cmd] = lines return lines def returnControllerNumber(output): for line in output: if re.match(r'^Controller Count.*$', line.strip()): return int(line.split(':')[1].strip().strip('.')) def returnTotalDriveNumber(output): for line in output: if re.match(r'Number of Physical Drives on Adapter.*$', line.strip()): return int(line.split(':')[1].strip()) def returnRebuildProgress(output): percent = 0 tmpstr = '' for line in output: if re.match( r'^Rebuild Progress on Device at Enclosure.*, Slot .* Completed ', line.strip(), ): tmpstr = line.split('Completed')[1].strip() percent = int(tmpstr.split('%')[0].strip()) return percent def returnConfDriveNumber(output): # Count the configured drives confdrives = 0 for line in output: if re.match(r'.*Number of PDs:.*$', line.strip()): confdrives += int(line.split(':')[2].strip()) return int(confdrives) def returnUnConfDriveNumber(output): # Count the configured drives confdrives = 0 for line in output: if re.match(r'^Firmware state: Unconfigured.*$', line.strip()): confdrives += 1 return int(confdrives) def returnControllerModel(output): for line in output: if re.match(r'^Product Name.*$', line.strip()): return line.split(':')[1].strip() def returnMemorySize(output): for line in output: if re.match(r'^Memory Size.*$', line.strip()): return line.split(':')[1].strip() def returnFirmwareVersion(output): for line in output: if re.match(r'^FW Package Build.*$', line.strip()): return line.split(':')[1].strip() def returnROCTemp(output): ROCtemp = '' tmpstr = '' if notempmode: return 'N/A' else: for line in output: if re.match(r'^ROC temperature :.*$', line.strip()): tmpstr = line.split(':')[1].strip() ROCtemp = re.sub(' +.*$', '', tmpstr) if ROCtemp != '': return str(str(ROCtemp) + 'C') else: return 'N/A' def returnBBUPresence(output): BBU = '' tmpstr = '' for line in output: if re.match(r'^BBU +:.*$', line.strip()): tmpstr = line.split(':')[1].strip() BBU = re.sub(' +.*$', '', tmpstr) break if BBU != '': return str(BBU) else: return 'N/A' def returnBBUStatus(output): BBUStatus = '' tmpstr = '' for line in output: if re.match(r'^ *Battery Replacement required +:.*$', line.strip()): tmpstr = line.split(':')[1].strip() BBUStatus = re.sub(' +.*$', '', tmpstr) break if BBUStatus == 'Yes': return 'REPL' else: return 'Good' def returnArrayNumber(output): i = 0 for line in output: if re.match(r'^(CacheCade )?Virtual Drive:.*$', line.strip()): i += 1 return i def returnHBAPCIInfo(output): busprefix = '0000' busid = '' devid = '' functionid = '' pcipath = '' for line in output: if re.match(r'^Bus Number.*:.*$', line.strip()): busid = str(line.strip().split(':')[1].strip()).zfill(2) if re.match(r'^Device Number.*:.*$', line.strip()): devid = str(line.strip().split(':')[1].strip()).zfill(2) if re.match(r'^Function Number.*:.*$', line.strip()): functionid = str(line.strip().split(':')[1].strip()).zfill(1) if busid: pcipath = str(busprefix + ':' + busid + ':' + devid + '.' + functionid) dbgprint("Array PCI path : " + pcipath) return str(pcipath) else: return None def returnHBAInfo(table, output, controllerid): controllermodel = 'Unknown' controllerram = 'Unknown' controllerrev = 'Unknown' controllertemp = '' controllermodel = returnControllerModel(output) controllerram = returnMemorySize(output) controllerrev = returnFirmwareVersion(output) controllertemp = returnROCTemp(output) controllerbbu = returnBBUPresence(output) if controllerbbu == 'Present': cmd = '%s -AdpBbuCmd -GetBbuStatus -a%d -NoLog' % ( megaclipath, controllerid, ) output = getOutput(cmd) controllerbbu = returnBBUStatus(output) if controllermodel != 'Unknown': table.append( [ 'c' + str(controllerid), controllermodel, controllerram, str(controllertemp), str(controllerbbu), str('FW: ' + controllerrev), ] ) def returnArrayInfo(output, controllerid, arrayid, arrayindex): id = 'c' + str(controllerid) + 'u' + str(arrayid) operationlinennumber = False linenumber = 0 targetid = '' raidtype = '' raidlvl = '' size = '' state = 'N/A' strpsz = '' dskcache = 'N/A' properties = '' spandepth = 0 diskperspan = 0 cachecade_info = 'None' for line in output: if re.match( r'^(CacheCade )?Virtual Drive:.*(Target Id: [0-9]+).*$', line.strip(), ): # Extract the SCSI Target ID targetid = line.strip().split(':')[2].split(')')[0].strip() elif re.match(r'^RAID Level.*?:.*$', line.strip()): # Extract the primary raid type, decide on X0 RAID level later when we hit Span Depth raidlvl = int( line.strip().split(':')[1].split(',')[0].split('-')[1].strip() ) elif re.match(r'^Size.*?:.*$', line.strip()): # Size reported in MB if re.match(r'^.*MB$', line.strip().split(':')[1]): size = line.strip().split(':')[1].strip('MB').strip() if float(size) > 1000: size = str(int(round(float(size) / 1000))) + 'G' else: size = str(int(round(float(size)))) + 'M' # Size reported in TB elif re.match(r'^.*TB$', line.strip().split(':')[1]): size = line.strip().split(':')[1].strip('TB').strip() size = str(int(round(float(size) * 1000))) + 'G' # Size reported in GB (default) else: size = line.strip().split(':')[1].strip('GB').strip() size = str(int(round(float(size)))) + 'G' elif re.match(r'^Span Depth.*?:.*$', line.strip()): # If Span Depth is greater than 1 chances are we have a RAID 10, 50 or 60 spandepth = line.strip().split(':')[1].strip() elif re.match(r'^State.*?:.*$', line.strip()): state = line.strip().split(':')[1].strip() elif re.match(r'^Strip Size.*?:.*$', line.strip()): strpsz = line.strip().split(':')[1].strip() elif re.match(r'^Number Of Drives per span.*:.*$', line.strip()): diskperspan = int(line.strip().split(':')[1].strip()) elif re.match(r'^Current Cache Policy.*?:.*$', line.strip()): props = line.strip().split(':')[1].strip() if re.search('ReadAdaptive', props): properties += 'ADRA' if re.search('ReadAhead', props): properties += 'RA' if re.match('ReadAheadNone', props): properties += 'NORA' if re.search('WriteBack', props): properties += ',WB' if re.match('WriteThrough', props): properties += ',WT' elif re.match(r'^Disk Cache Policy.*?:.*$', line.strip()): props = line.strip().split(':')[1].strip() if re.search('Disabled', props): dskcache = 'Disabled' if re.search('Disk.s Default', props): dskcache = 'Default' if re.search('Enabled', props): dskcache = 'Enabled' elif re.match(r'^Ongoing Progresses.*?:.*$', line.strip()): operationlinennumber = linenumber elif re.match(r'Cache Cade Type\s*:.*$', line): cachecade_info = "Type : " + line.strip().split(':')[1].strip() elif re.match(r'^Target Id of the Associated LDs\s*:.*$', line): associated = [] for array in line.split(':')[1].strip().split(','): if array.isdigit(): associated.append('c%du%d' % (controllerid, int(array))) if len(associated) >= 1: cachecade_info = "Associated : %s" % (', '.join(associated)) linenumber += 1 # If there was an ongoing operation, find the relevant line in the previous output if operationlinennumber: inprogress = output[operationlinennumber + 1] else: inprogress = 'None' # Compute the RAID level NestedLDTable[int(controllerid)][int(arrayindex)] = False if raidlvl == '': raidtype = 'N/A' else: if int(spandepth) >= 2: raidtype = str('RAID-' + str(raidlvl) + '0') NestedLDTable[controllerid][int(arrayindex)] = True else: if raidlvl == 1: if diskperspan > 2: raidtype = 'RAID-10' NestedLDTable[controllerid][int(arrayindex)] = True else: raidtype = str('RAID-' + str(raidlvl)) else: raidtype = str('RAID-' + str(raidlvl)) dbgprint( 'RAID Level: ' + str(raidlvl) + ' Span Depth: ' + str(spandepth) + ' Disk Per Span: ' + str(diskperspan) + ' Raid Type: ' + str(raidtype) ) return [ id, raidtype, size, strpsz, properties, dskcache, state, targetid, cachecade_info, inprogress, ] def returnDiskInfo(output, controllerid): arrayid = False arrayindex = -1 sarrayid = 'Unknown' diskid = False oldenclid = False enclid = False spanid = False slotid = False lsidid = 'Unknown' table = [] fstate = 'Offline' substate = 'Unknown' model = 'Unknown' speed = 'Unknown' dsize = 'Unknown' temp = 'Unk0C' percent = 0 for line in output: if re.match(r'^Span: [0-9]+ - Number of PDs:', line.strip()): spanid = line.split(':')[1].strip() spanid = re.sub(' - Number of PDs.*', '', spanid) elif re.match(r'Enclosure Device ID: .*$', line.strip()): # We match here early in the analysis so reset the vars if this is a new disk we're reading.. oldenclid = enclid enclid = line.split(':')[1].strip() if oldenclid != False: fstate = 'Offline' model = 'Unknown' speed = 'Unknown' temp = 'Unk0C' slotid = False lsidid = 'Unknown' elif re.match(r'^Coerced Size: ', line.strip()): dsize = line.split(':')[1].strip() dsize = re.sub(r' \[.*\.*$', '', dsize) dsize = re.sub('[0-9][0-9] GB', ' Gb', dsize) elif re.match( r'^(CacheCade )?Virtual (Disk|Drive): [0-9]+.*$', line.strip() ): arrayindex += 1 arrayid = line.split('(')[0].split(':')[1].strip() elif re.match(r'PD: [0-9]+ Information.*$', line.strip()): diskid = line.split()[1].strip() elif re.match(r'^Device Id: .*$', line.strip()): lsidid = line.split(':')[1].strip() elif re.match(r'Slot Number: .*$', line.strip()): slotid = line.split(':')[1].strip() elif re.match(r'Firmware state: .*$', line.strip()): fstate = line.split(':')[1].strip() subfstate = re.sub(r'\(.*', '', fstate) dbgprint('Firmware State: ' + str(fstate) + ' ' + str(subfstate)) elif re.match(r'Inquiry Data: .*$', line.strip()): model = line.split(':')[1].strip() model = re.sub(' +', ' ', model) # Sub code manuf = re.sub(' .*', '', model) dtype = re.sub(manuf + ' ', '', model) dtype = re.sub(' .*', '', dtype) hwserial = re.sub('.*' + dtype + ' *', '', model) elif re.match(r'^Media Type: .*$', line.strip()): mtype = line.split(':')[1].strip() if mtype == 'Hard Disk Device': mtype = 'HDD' else: if mtype == 'Solid State Device': mtype = 'SSD' else: mtype = 'N/A' elif re.match(r'Device Speed: .*$', line.strip()): speed = line.split(':')[1].strip() elif re.match(r'Drive Temperature :.*$', line.strip()): if notempmode: temp = 'N/A' else: # Drive temp is amongst the last few lines matched, decide here if we add information to the table.. temp = line.split(':')[1].strip() temp = re.sub(r' \(.*\)', '', temp) if model != 'Unknown': dbgprint( 'Disk Info: ' + str(arrayid) + ' ' + str(diskid) + ' ' + str(oldenclid) ) if subfstate == 'Rebuild': cmd = ( r'%s pdrbld -showprog -physdrv\[%s:%s\] -a%d -NoLog' % (megaclipath, enclid, slotid, controllerid) ) output = getOutput(cmd) percent = returnRebuildProgress(output) fstate = str('Rebuilding (%d%%)' % (percent)) if (NestedLDTable[controllerid][int(arrayindex)] == True) and ( spanid != False ): sarrayid = str(arrayid) + "s" + spanid else: sarrayid = str(arrayid) table.append( [ sarrayid, str(diskid), mtype, model, dsize, fstate, speed, temp, enclid, slotid, lsidid, ] ) return table def returnUnconfDiskInfo(output, controllerid): arrayid = False diskid = False olddiskid = False enclid = False slotid = False lsidid = 'Unknown' table = [] fstate = 'Offline' substate = 'Unknown' model = 'Unknown' speed = 'Unknown' mtype = 'Unknown' dsize = 'Unknown' temp = 'Unk0C' for line in output: if re.match(r'Enclosure Device ID: .*$', line.strip()): # We match here early in the analysis so reset the vars if this is a new disk we're reading.. oldenclid = enclid enclid = line.split(':')[1].strip() if oldenclid != False: arrayid = False fstate = 'Offline' model = 'Unknown' speed = 'Unknown' temp = 'Unk0C' slotid = False lsidid = 'Unknown' elif re.match(r'^Coerced Size: ', line.strip()): dsize = line.split(':')[1].strip() dsize = re.sub(r' \[.*\.*$', '', dsize) dsize = re.sub('[0-9][0-9] GB', ' Gb', dsize) elif re.match( r'^Drive.s position: DiskGroup: [0-9]+,.*$', line.strip() ): arrayid = line.split(',')[1].split(':')[1].strip() elif re.match(r'^Device Id: [0-9]+.*$', line.strip()): diskid = line.split(':')[1].strip() elif re.match(r'^Device Id: .*$', line.strip()): lsidid = line.split(':')[1].strip() elif re.match(r'Slot Number: .*$', line.strip()): slotid = line.split(':')[1].strip() elif re.match(r'Firmware state: .*$', line.strip()): fstate = line.split(':')[1].strip() subfstate = re.sub(r'\(.*', '', fstate) dbgprint('Firmware State: ' + str(fstate) + ' ' + str(subfstate)) elif re.match(r'Inquiry Data: .*$', line.strip()): model = line.split(':')[1].strip() model = re.sub(' +', ' ', model) manuf = re.sub(' .*', '', model) dtype = re.sub(manuf + ' ', '', model) dtype = re.sub(' .*', '', dtype) hwserial = re.sub('.*' + dtype + ' *', '', model) elif re.match(r'^Media Type: .*$', line.strip()): mtype = line.split(':')[1].strip() if mtype == 'Hard Disk Device': mtype = 'HDD' else: if mtype == 'Solid State Device': mtype = 'SSD' else: mtype = 'N/A' elif re.match(r'Device Speed: .*$', line.strip()): speed = line.split(':')[1].strip() elif re.match(r'Drive Temperature :.*$', line.strip()): temp = line.split(':')[1].strip() temp = re.sub(r'\(.*\)', '', temp) # Drive temp is amongst the last few lines matched, decide here if we add information to the table.. if arrayid == False: if subfstate == 'Unconfigured': dbgprint( 'Unconfigured Disk: Arrayid: ' + str(arrayid) + ' DiskId: ' + str(diskid) + ' ' + str(olddiskid) + ' ' + str(fstate) ) elif subfstate == 'Online, Spun Up': dbgprint( 'Online Disk: Arrayid: ' + str(arrayid) + ' DiskId: ' + str(diskid) + ' ' + str(olddiskid) + ' ' + str(fstate) ) table.append( [ mtype, model, dsize, fstate, speed, temp, enclid, slotid, lsidid, ] ) return table def returnForeignDisks(controllerid): cmd = "%s -CfgForeign -Dsply -a%d" % (megaclipath, controllerid) foreignout = getOutput(cmd) foreigndisks = [] for line in foreignout: result = re.search(r"Slot Number: (.*)", line) if result: matches = result.groups() foreigndisks.append(matches[0]) return foreigndisks cmd = '%s -adpCount -NoLog' % (megaclipath) output = getOutput(cmd) controllernumber = returnControllerNumber(output) bad = False # List available controller if printcontroller: if controllernumber: if not nagiosmode: print('-- Controller information --') i = 0 controllerid = 0 mlen = 0 hbainfo = [] while controllerid < controllernumber: cmd = '%s -AdpAllInfo -a%d -NoLog' % (megaclipath, controllerid) output = getOutput(cmd) returnHBAInfo(hbainfo, output, controllerid) controllerid += 1 mlen = returnWdthFromArrayCol(hbainfo, 1) controllerid = 0 for hba in hbainfo: hbafmt = str( '%-5s | %-' + str(mlen) + 's | %-6s | %-4s | %-6s | %-12s ' ) # Header if i == 0: if not nagiosmode: print( hbafmt % ( "-- ID", "H/W Model", "RAM", "Temp", "BBU", "Firmware", ) ) if not nagiosmode: print(hbafmt % (hba[0], hba[1], hba[2], hba[3], hba[4], hba[5])) i += 1 if not nagiosmode: print('') else: print("No MegaRAID or PERC adapter detected on your system!") exit(1) if printarray: if not nagiosmode: print('-- Array information --') controllerid = 0 pcipath = '' diskpath = '' i = 0 j = 0 mlen = 0 rlen = 0 clen = 0 while controllerid < controllernumber: arrayindex = 0 cmd = '%s -LDInfo -lall -a%d -NoLog' % (megaclipath, controllerid) output = getOutput(cmd) arraynumber = returnArrayNumber(output) # We need to explore each HBA to look for gaps in LD's ldid = 0 ldcount = 0 while ldcount < arraynumber: cmd = '%s -LDInfo -l%d -a%d -NoLog' % ( megaclipath, ldid, controllerid, ) output = getOutput(cmd) for line in output: if re.match( r'^Adapter.*Virtual Drive .* Does not Exist', line.strip() ): ldid += 1 elif re.match(r'^(CacheCade )?Virtual Drive:', line.strip()): LDTable[controllerid].append(ldid) # NestedLDTable[controllerid][int(arrayindex)] = False ldcount += 1 ldid += 1 while arrayindex < arraynumber: ldid = LDTable[controllerid][arrayindex] cmd = '%s -LDInfo -l%d -a%d -NoLog' % ( megaclipath, ldid, controllerid, ) output = getOutput(cmd) arrayinfo = returnArrayInfo(output, controllerid, ldid, arrayindex) if len(arrayinfo[1]) > rlen: rlen = len(arrayinfo[1]) if len(arrayinfo[4]) > mlen: mlen = len(arrayinfo[4]) if len(arrayinfo[8]) > clen: clen = len(arrayinfo[8]) arrayindex += 1 controllerid += 1 controllerid = 0 while controllerid < controllernumber: arrayindex = 0 cmd = '%s -AdpGetPciInfo -a%d -NoLog' % (megaclipath, controllerid) output = getOutput(cmd) pcipath = returnHBAPCIInfo(output) cmd = '%s -LDInfo -lall -a%d -NoLog' % (megaclipath, controllerid) output = getOutput(cmd) arraynumber = returnArrayNumber(output) while arrayindex < arraynumber: ldid = LDTable[controllerid][arrayindex] cmd = '%s -LDInfo -l%d -a%d -NoLog' % ( megaclipath, ldid, controllerid, ) output = getOutput(cmd) arrayinfo = returnArrayInfo(output, controllerid, ldid, arrayindex) if pcipath: diskprefix = str( '/dev/disk/by-path/pci-' + pcipath + '-scsi-0:' ) for j in range(8): diskpath = ( diskprefix + str(j) + ':' + str(arrayinfo[7]) + ':0' ) if os.path.exists(diskpath): arrayinfo[7] = os.path.realpath(diskpath) else: arrayinfo[7] = 'N/A' # Pad the string length, just to make sure it's aligned with the headers... if rlen < len("Type"): rlen = len("Type") if mlen < len("Flags"): mlen = len("Flags") if clen < len("CacheCade"): clen = len("CacheCade") ldfmt = str( '%-5s | %-' + str(rlen) + 's | %7s | %7s | %' + str(mlen) + 's | %8s | %8s | %8s | %-' + str(clen) + 's |%-12s ' ) # Header if i == 0: if not nagiosmode: print( ldfmt % ( "-- ID", "Type", "Size", "Strpsz", "Flags", "DskCache", "Status", "OS Path", "CacheCade", "InProgress", ) ) if not nagiosmode: print( ldfmt % ( arrayinfo[0], arrayinfo[1], arrayinfo[2], arrayinfo[3], arrayinfo[4], arrayinfo[5], arrayinfo[6], arrayinfo[7], arrayinfo[8], arrayinfo[9], ) ) dbgprint("Array state : " + arrayinfo[6]) if arrayinfo[6] not in ['Optimal', 'N/A']: bad = True nagiosbadarray = nagiosbadarray + 1 else: nagiosgoodarray = nagiosgoodarray + 1 arrayindex += 1 i += 1 controllerid += 1 if not nagiosmode: print('') controllerid = 0 while controllerid < controllernumber: cmd = '%s -PDGetNum -a%d -NoLog' % (megaclipath, controllerid) output = getOutput(cmd) totaldrivenumber += returnTotalDriveNumber(output) controllerid += 1 if totaldrivenumber: if not nagiosmode: print('-- Disk information --') i = 0 dlen = 0 mlen = 0 flen = 0 controllerid = 0 while controllerid < controllernumber: arrayid = 0 cmd = '%s -LDInfo -lall -a%d -NoLog' % (megaclipath, controllerid) output = getOutput(cmd) arraynumber = returnArrayNumber(output) #### BUG: -LdPdInfo shows all PD on the adapter, not just for said LD.. #### while arrayid <= arraynumber: cmd = '%s -LdPdInfo -a%d -NoLog' % (megaclipath, controllerid) output = getOutput(cmd) arraydisk = returnDiskInfo(output, controllerid) for array in arraydisk: dbgprint( 'Disk c' + str(controllerid) + 'u' + array[0] + 'p' + array[1] + ' status : ' + array[5] ) if array[5] not in ['Online', 'Online, Spun Up']: bad = True nagiosbaddisk = nagiosbaddisk + 1 else: nagiosgooddisk = nagiosgooddisk + 1 if returnWdthFromArrayCol(arraydisk, 0) > dlen: dlen = returnWdthFromArrayCol(arraydisk, 0) if returnWdthFromArrayCol(arraydisk, 3) > mlen: mlen = returnWdthFromArrayCol(arraydisk, 3) if returnWdthFromArrayCol(arraydisk, 5) > flen: flen = returnWdthFromArrayCol(arraydisk, 5) controllerid += 1 controllerid = 0 while controllerid < controllernumber: arrayid = 0 cmd = '%s -LDInfo -lall -a%d -NoLog' % (megaclipath, controllerid) output = getOutput(cmd) arraynumber = returnArrayNumber(output) #### BUG: -LdPdInfo shows all PD on the adapter, not just for said LD.. #### while arrayid <= arraynumber: cmd = '%s -LdPdInfo -a%d -NoLog' % (megaclipath, controllerid) output = getOutput(cmd) arraydisk = returnDiskInfo(output, controllerid) # Adjust print format with width computed above drvfmt = ( "%-" + str(dlen + 5) + "s | %-4s | %-" + str(mlen) + "s | %-8s | %-" + str(flen) + "s | %-8s | %-4s | %-8s | %-8s" ) for array in arraydisk: # Header if i == 0: if not nagiosmode: print( drvfmt % ( "-- ID", "Type", "Drive Model", "Size", "Status", "Speed", "Temp", "Slot ID", "LSI Device ID", ) ) # Drive information if not nagiosmode: print( drvfmt % ( str( 'c' + str(controllerid) + 'u' + array[0] + 'p' + array[1] ), # c0p0 array[2], # HDD/SDD array[3], # Model Information (Variable len) array[4], # Size array[5], # Status (Variable len) array[6], # Speed array[7], # Temp str('[' + array[8] + ':' + array[9] + ']'), # Slot ID array[10], ) ) # LSI ID i = i + 1 controllerid += 1 if not nagiosmode: print('') controllerid = 0 totalconfdrivenumber = 0 totalunconfdrivenumber = 0 totaldrivenumber = 0 while controllerid < controllernumber: cmd = '%s -LdPdInfo -a%d -NoLog' % (megaclipath, controllerid) output = getOutput(cmd) totalconfdrivenumber += returnConfDriveNumber(output) cmd = '%s -PDGetNum -a%d -NoLog' % (megaclipath, controllerid) output = getOutput(cmd) totaldrivenumber += returnTotalDriveNumber(output) cmd = '%s -PDList -a%d -NoLog' % (megaclipath, controllerid) output = getOutput(cmd) totalunconfdrivenumber += returnUnConfDriveNumber(output) controllerid += 1 dbgprint('Total Drives in system : ' + str(totaldrivenumber)) dbgprint('Total Configured Drives : ' + str(totalconfdrivenumber)) dbgprint('Total Unconfigured Drives : ' + str(totalunconfdrivenumber)) if totalunconfdrivenumber: if not nagiosmode: print('-- Unconfigured Disk information --') controllerid = 0 while controllerid < controllernumber: foreigndisks = returnForeignDisks(controllerid) arrayid = 0 cmd = '%s -LDInfo -lall -a%d -NoLog' % (megaclipath, controllerid) output = getOutput(cmd) arraynumber = returnArrayNumber(output) #### BUG: -LdPdInfo shows all PD on the adapter, not just for given LD.. #### while arrayid <= arraynumber: cmd = '%s -PDList -a%d -NoLog' % (megaclipath, controllerid) output = getOutput(cmd) arraydisk = returnUnconfDiskInfo(output, controllerid) for array in arraydisk: dbgprint('Disk c' + str(controllerid) + 'uXpY status : ' + array[3]) if array[3] not in [ 'Online', 'Unconfigured(good), Spun Up', 'Unconfigured(good), Spun down', 'JBOD', 'Hotspare, Spun Up', 'Hotspare, Spun down', ]: bad = True nagiosbaddisk = nagiosbaddisk + 1 else: nagiosgooddisk = nagiosgooddisk + 1 if array[7] in foreigndisks: array[3] = array[3] + " (Foreign)" mlen = returnWdthFromArrayCol(arraydisk, 1) flen = returnWdthFromArrayCol(arraydisk, 3) # Adjust print format with widths computed above drvfmt = ( "%-7s | %-4s | %-" + str(mlen) + "s | %-8s | %-" + str(flen + 2) + "s | %-8s | %-4s | %-8s | %-8s" ) i = 0 for array in arraydisk: # Header if i == 0: if not nagiosmode: print( drvfmt % ( "-- ID", "Type", "Drive Model", "Size", "Status", "Speed", "Temp", "Slot ID", "LSI Device ID", ) ) # Drive information if not nagiosmode: print( drvfmt % ( str('c' + str(controllerid) + 'uXpY'), # cXpY array[0], # HDD/SDD array[1], # Model Information (Variable len) array[2], # Size array[3], # Status (Variable len) array[4], # Speed array[5], # Temp str('[' + array[6] + ':' + array[7] + ']'), # Slot ID array[8], ) ) # LSI ID i = i + 1 controllerid += 1 if not nagiosmode: print('') if nagiosmode: if bad: print( 'RAID ERROR - Arrays: OK:' + str(nagiosgoodarray) + ' Bad:' + str(nagiosbadarray) + ' - Disks: OK:' + str(nagiosgooddisk) + ' Bad:' + str(nagiosbaddisk) ) sys.exit(2) else: print( 'RAID OK - Arrays: OK:' + str(nagiosgoodarray) + ' Bad:' + str(nagiosbadarray) + ' - Disks: OK:' + str(nagiosgooddisk) + ' Bad:' + str(nagiosbaddisk) ) else: if bad: print('\nThere is at least one disk/array in a NOT OPTIMAL state.') sys.exit(1)