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/saltstack/salt/lib/python3.10/site-packages/salt/modules
Viewing File: /opt/saltstack/salt/lib/python3.10/site-packages/salt/modules/dracr.py
""" Manage Dell DRAC. .. versionadded:: 2015.8.2 """ import logging import os import re import salt.utils.path from salt.exceptions import CommandExecutionError log = logging.getLogger(__name__) __proxyenabled__ = ["fx2"] try: run_all = __salt__["cmd.run_all"] except (NameError, KeyError): import salt.modules.cmdmod __salt__ = {"cmd.run_all": salt.modules.cmdmod.run_all} def __virtual__(): if salt.utils.path.which("racadm"): return True return ( False, "The drac execution module cannot be loaded: racadm binary not in path.", ) def __parse_drac(output): """ Parse Dell DRAC output """ drac = {} section = "" for i in output.splitlines(): if i.strip().endswith(":") and "=" not in i: section = i[0:-1] drac[section] = {} if i.rstrip() and "=" in i: if section in drac: drac[section].update(dict([[prop.strip() for prop in i.split("=")]])) else: section = i.strip() if section not in drac and section: drac[section] = {} return drac def __execute_cmd( command, host=None, admin_username=None, admin_password=None, module=None ): """ Execute rac commands """ if module: # -a takes 'server' or 'switch' to represent all servers # or all switches in a chassis. Allow # user to say 'module=ALL_SERVER' or 'module=ALL_SWITCH' if module.startswith("ALL_"): modswitch = "-a " + module[module.index("_") + 1 : len(module)].lower() else: modswitch = f"-m {module}" else: modswitch = "" if not host: # This is a local call cmd = __salt__["cmd.run_all"](f"racadm {command} {modswitch}") else: cmd = __salt__["cmd.run_all"]( "racadm -r {} -u {} -p {} {} {}".format( host, admin_username, admin_password, command, modswitch ), output_loglevel="quiet", ) if cmd["retcode"] != 0: log.warning("racadm returned an exit code of %s", cmd["retcode"]) return False return True def __execute_ret( command, host=None, admin_username=None, admin_password=None, module=None ): """ Execute rac commands """ if module: if module == "ALL": modswitch = "-a " else: modswitch = f"-m {module}" else: modswitch = "" if not host: # This is a local call cmd = __salt__["cmd.run_all"](f"racadm {command} {modswitch}") else: cmd = __salt__["cmd.run_all"]( "racadm -r {} -u {} -p {} {} {}".format( host, admin_username, admin_password, command, modswitch ), output_loglevel="quiet", ) if cmd["retcode"] != 0: log.warning("racadm returned an exit code of %s", cmd["retcode"]) else: fmtlines = [] for l in cmd["stdout"].splitlines(): if l.startswith("Security Alert"): continue if l.startswith("RAC1168:"): break if l.startswith("RAC1169:"): break if l.startswith("Continuing execution"): continue if not l.strip(): continue fmtlines.append(l) if "=" in l: continue cmd["stdout"] = "\n".join(fmtlines) return cmd def get_dns_dracname(host=None, admin_username=None, admin_password=None): ret = __execute_ret( "get iDRAC.NIC.DNSRacName", host=host, admin_username=admin_username, admin_password=admin_password, ) parsed = __parse_drac(ret["stdout"]) return parsed def set_dns_dracname(name, host=None, admin_username=None, admin_password=None): ret = __execute_ret( f"set iDRAC.NIC.DNSRacName {name}", host=host, admin_username=admin_username, admin_password=admin_password, ) return ret def system_info(host=None, admin_username=None, admin_password=None, module=None): """ Return System information CLI Example: .. code-block:: bash salt dell dracr.system_info """ cmd = __execute_ret( "getsysinfo", host=host, admin_username=admin_username, admin_password=admin_password, module=module, ) if cmd["retcode"] != 0: log.warning("racadm returned an exit code of %s", cmd["retcode"]) return cmd return __parse_drac(cmd["stdout"]) def set_niccfg( ip=None, netmask=None, gateway=None, dhcp=False, host=None, admin_username=None, admin_password=None, module=None, ): cmdstr = "setniccfg " if dhcp: cmdstr += "-d " else: cmdstr += "-s " + ip + " " + netmask + " " + gateway return __execute_cmd( cmdstr, host=host, admin_username=admin_username, admin_password=admin_password, module=module, ) def set_nicvlan( vlan=None, host=None, admin_username=None, admin_password=None, module=None ): cmdstr = "setniccfg -v " if vlan: cmdstr += vlan ret = __execute_cmd( cmdstr, host=host, admin_username=admin_username, admin_password=admin_password, module=module, ) return ret def network_info(host=None, admin_username=None, admin_password=None, module=None): """ Return Network Configuration CLI Example: .. code-block:: bash salt dell dracr.network_info """ inv = inventory( host=host, admin_username=admin_username, admin_password=admin_password ) if inv is None: cmd = {} cmd["retcode"] = -1 cmd["stdout"] = "Problem getting switch inventory" return cmd if module not in inv.get("switch") and module not in inv.get("server"): cmd = {} cmd["retcode"] = -1 cmd["stdout"] = f"No module {module} found." return cmd cmd = __execute_ret( "getniccfg", host=host, admin_username=admin_username, admin_password=admin_password, module=module, ) if cmd["retcode"] != 0: log.warning("racadm returned an exit code of %s", cmd["retcode"]) cmd["stdout"] = "Network:\n" + "Device = " + module + "\n" + cmd["stdout"] return __parse_drac(cmd["stdout"]) def nameservers(ns, host=None, admin_username=None, admin_password=None, module=None): """ Configure the nameservers on the DRAC CLI Example: .. code-block:: bash salt dell dracr.nameservers [NAMESERVERS] salt dell dracr.nameservers ns1.example.com ns2.example.com admin_username=root admin_password=calvin module=server-1 host=192.168.1.1 """ if len(ns) > 2: log.warning("racadm only supports two nameservers") return False for i in range(1, len(ns) + 1): if not __execute_cmd( f"config -g cfgLanNetworking -o cfgDNSServer{i} {ns[i - 1]}", host=host, admin_username=admin_username, admin_password=admin_password, module=module, ): return False return True def syslog( server, enable=True, host=None, admin_username=None, admin_password=None, module=None, ): """ Configure syslog remote logging, by default syslog will automatically be enabled if a server is specified. However, if you want to disable syslog you will need to specify a server followed by False CLI Example: .. code-block:: bash salt dell dracr.syslog [SYSLOG IP] [ENABLE/DISABLE] salt dell dracr.syslog 0.0.0.0 False """ if enable and __execute_cmd( "config -g cfgRemoteHosts -o cfgRhostsSyslogEnable 1", host=host, admin_username=admin_username, admin_password=admin_password, module=None, ): return __execute_cmd( f"config -g cfgRemoteHosts -o cfgRhostsSyslogServer1 {server}", host=host, admin_username=admin_username, admin_password=admin_password, module=module, ) return __execute_cmd( "config -g cfgRemoteHosts -o cfgRhostsSyslogEnable 0", host=host, admin_username=admin_username, admin_password=admin_password, module=module, ) def email_alerts(action, host=None, admin_username=None, admin_password=None): """ Enable/Disable email alerts CLI Example: .. code-block:: bash salt dell dracr.email_alerts True salt dell dracr.email_alerts False """ if action: return __execute_cmd( "config -g cfgEmailAlert -o cfgEmailAlertEnable -i 1 1", host=host, admin_username=admin_username, admin_password=admin_password, ) else: return __execute_cmd("config -g cfgEmailAlert -o cfgEmailAlertEnable -i 1 0") def list_users(host=None, admin_username=None, admin_password=None, module=None): """ List all DRAC users CLI Example: .. code-block:: bash salt dell dracr.list_users """ users = {} _username = "" for idx in range(1, 17): cmd = __execute_ret( f"getconfig -g cfgUserAdmin -i {idx}", host=host, admin_username=admin_username, admin_password=admin_password, ) if cmd["retcode"] != 0: log.warning("racadm returned an exit code of %s", cmd["retcode"]) for user in cmd["stdout"].splitlines(): if not user.startswith("cfg"): continue (key, val) = user.split("=") if key.startswith("cfgUserAdminUserName"): _username = val.strip() if val: users[_username] = {"index": idx} else: break else: if _username: users[_username].update({key: val}) return users def delete_user( username, uid=None, host=None, admin_username=None, admin_password=None ): """ Delete a user CLI Example: .. code-block:: bash salt dell dracr.delete_user [USERNAME] [UID - optional] salt dell dracr.delete_user diana 4 """ if uid is None: user = list_users() uid = user[username]["index"] if uid: return __execute_cmd( f"config -g cfgUserAdmin -o cfgUserAdminUserName -i {uid} ", host=host, admin_username=admin_username, admin_password=admin_password, ) else: log.warning("User '%s' does not exist", username) return False def change_password( username, password, uid=None, host=None, admin_username=None, admin_password=None, module=None, ): """ Change user's password CLI Example: .. code-block:: bash salt dell dracr.change_password [USERNAME] [PASSWORD] uid=[OPTIONAL] host=<remote DRAC> admin_username=<DRAC user> admin_password=<DRAC PW> salt dell dracr.change_password diana secret Note that if only a username is specified then this module will look up details for all 16 possible DRAC users. This is time consuming, but might be necessary if one is not sure which user slot contains the one you want. Many late-model Dell chassis have 'root' as UID 1, so if you can depend on that then setting the password is much quicker. Raises an error if the supplied password is greater than 20 chars. """ if len(password) > 20: raise CommandExecutionError("Supplied password should be 20 characters or less") if uid is None: user = list_users( host=host, admin_username=admin_username, admin_password=admin_password, module=module, ) uid = user[username]["index"] if uid: return __execute_cmd( "config -g cfgUserAdmin -o cfgUserAdminPassword -i {} {}".format( uid, password ), host=host, admin_username=admin_username, admin_password=admin_password, module=module, ) else: log.warning("racadm: user '%s' does not exist", username) return False def deploy_password( username, password, host=None, admin_username=None, admin_password=None, module=None ): """ Change the QuickDeploy password, used for switches as well CLI Example: .. code-block:: bash salt dell dracr.deploy_password [USERNAME] [PASSWORD] host=<remote DRAC> admin_username=<DRAC user> admin_password=<DRAC PW> salt dell dracr.change_password diana secret Note that if only a username is specified then this module will look up details for all 16 possible DRAC users. This is time consuming, but might be necessary if one is not sure which user slot contains the one you want. Many late-model Dell chassis have 'root' as UID 1, so if you can depend on that then setting the password is much quicker. """ return __execute_cmd( f"deploy -u {username} -p {password}", host=host, admin_username=admin_username, admin_password=admin_password, module=module, ) def deploy_snmp(snmp, host=None, admin_username=None, admin_password=None, module=None): """ Change the QuickDeploy SNMP community string, used for switches as well CLI Example: .. code-block:: bash salt dell dracr.deploy_snmp SNMP_STRING host=<remote DRAC or CMC> admin_username=<DRAC user> admin_password=<DRAC PW> salt dell dracr.deploy_password diana secret """ return __execute_cmd( f"deploy -v SNMPv2 {snmp} ro", host=host, admin_username=admin_username, admin_password=admin_password, module=module, ) def create_user( username, password, permissions, users=None, host=None, admin_username=None, admin_password=None, ): """ Create user accounts CLI Example: .. code-block:: bash salt dell dracr.create_user [USERNAME] [PASSWORD] [PRIVILEGES] salt dell dracr.create_user diana secret login,test_alerts,clear_logs DRAC Privileges * login : Login to iDRAC * drac : Configure iDRAC * user_management : Configure Users * clear_logs : Clear Logs * server_control_commands : Execute Server Control Commands * console_redirection : Access Console Redirection * virtual_media : Access Virtual Media * test_alerts : Test Alerts * debug_commands : Execute Debug Commands """ _uids = set() if users is None: users = list_users() if username in users: log.warning("racadm: user '%s' already exists", username) return False for idx in users.keys(): _uids.add(users[idx]["index"]) uid = sorted(list(set(range(2, 12)) - _uids), reverse=True).pop() # Create user account first if not __execute_cmd( f"config -g cfgUserAdmin -o cfgUserAdminUserName -i {uid} {username}", host=host, admin_username=admin_username, admin_password=admin_password, ): delete_user(username, uid) return False # Configure users permissions if not set_permissions(username, permissions, uid): log.warning("unable to set user permissions") delete_user(username, uid) return False # Configure users password if not change_password(username, password, uid): log.warning("unable to set user password") delete_user(username, uid) return False # Enable users admin if not __execute_cmd(f"config -g cfgUserAdmin -o cfgUserAdminEnable -i {uid} 1"): delete_user(username, uid) return False return True def set_permissions( username, permissions, uid=None, host=None, admin_username=None, admin_password=None ): """ Configure users permissions CLI Example: .. code-block:: bash salt dell dracr.set_permissions [USERNAME] [PRIVILEGES] [USER INDEX - optional] salt dell dracr.set_permissions diana login,test_alerts,clear_logs 4 DRAC Privileges * login : Login to iDRAC * drac : Configure iDRAC * user_management : Configure Users * clear_logs : Clear Logs * server_control_commands : Execute Server Control Commands * console_redirection : Access Console Redirection * virtual_media : Access Virtual Media * test_alerts : Test Alerts * debug_commands : Execute Debug Commands """ privileges = { "login": "0x0000001", "drac": "0x0000002", "user_management": "0x0000004", "clear_logs": "0x0000008", "server_control_commands": "0x0000010", "console_redirection": "0x0000020", "virtual_media": "0x0000040", "test_alerts": "0x0000080", "debug_commands": "0x0000100", } permission = 0 # When users don't provide a user ID we need to search for this if uid is None: user = list_users() uid = user[username]["index"] # Generate privilege bit mask for i in permissions.split(","): perm = i.strip() if perm in privileges: permission += int(privileges[perm], 16) return __execute_cmd( "config -g cfgUserAdmin -o cfgUserAdminPrivilege -i {} 0x{:08X}".format( uid, permission ), host=host, admin_username=admin_username, admin_password=admin_password, ) def set_snmp(community, host=None, admin_username=None, admin_password=None): """ Configure CMC or individual iDRAC SNMP community string. Use ``deploy_snmp`` for configuring chassis switch SNMP. CLI Example: .. code-block:: bash salt dell dracr.set_snmp [COMMUNITY] salt dell dracr.set_snmp public """ return __execute_cmd( f"config -g cfgOobSnmp -o cfgOobSnmpAgentCommunity {community}", host=host, admin_username=admin_username, admin_password=admin_password, ) def set_network( ip, netmask, gateway, host=None, admin_username=None, admin_password=None ): """ Configure Network on the CMC or individual iDRAC. Use ``set_niccfg`` for blade and switch addresses. CLI Example: .. code-block:: bash salt dell dracr.set_network [DRAC IP] [NETMASK] [GATEWAY] salt dell dracr.set_network 192.168.0.2 255.255.255.0 192.168.0.1 admin_username=root admin_password=calvin host=192.168.1.1 """ return __execute_cmd( "setniccfg -s {} {} {}".format( ip, netmask, gateway, host=host, admin_username=admin_username, admin_password=admin_password, ) ) def server_power( status, host=None, admin_username=None, admin_password=None, module=None ): """ status One of 'powerup', 'powerdown', 'powercycle', 'hardreset', 'graceshutdown' host The chassis host. admin_username The username used to access the chassis. admin_password The password used to access the chassis. module The element to reboot on the chassis such as a blade. If not provided, the chassis will be rebooted. CLI Example: .. code-block:: bash salt dell dracr.server_reboot salt dell dracr.server_reboot module=server-1 """ return __execute_cmd( f"serveraction {status}", host=host, admin_username=admin_username, admin_password=admin_password, module=module, ) def server_reboot(host=None, admin_username=None, admin_password=None, module=None): """ Issues a power-cycle operation on the managed server. This action is similar to pressing the power button on the system's front panel to power down and then power up the system. host The chassis host. admin_username The username used to access the chassis. admin_password The password used to access the chassis. module The element to reboot on the chassis such as a blade. If not provided, the chassis will be rebooted. CLI Example: .. code-block:: bash salt dell dracr.server_reboot salt dell dracr.server_reboot module=server-1 """ return __execute_cmd( "serveraction powercycle", host=host, admin_username=admin_username, admin_password=admin_password, module=module, ) def server_poweroff(host=None, admin_username=None, admin_password=None, module=None): """ Powers down the managed server. host The chassis host. admin_username The username used to access the chassis. admin_password The password used to access the chassis. module The element to power off on the chassis such as a blade. If not provided, the chassis will be powered off. CLI Example: .. code-block:: bash salt dell dracr.server_poweroff salt dell dracr.server_poweroff module=server-1 """ return __execute_cmd( "serveraction powerdown", host=host, admin_username=admin_username, admin_password=admin_password, module=module, ) def server_poweron(host=None, admin_username=None, admin_password=None, module=None): """ Powers up the managed server. host The chassis host. admin_username The username used to access the chassis. admin_password The password used to access the chassis. module The element to power on located on the chassis such as a blade. If not provided, the chassis will be powered on. CLI Example: .. code-block:: bash salt dell dracr.server_poweron salt dell dracr.server_poweron module=server-1 """ return __execute_cmd( "serveraction powerup", host=host, admin_username=admin_username, admin_password=admin_password, module=module, ) def server_hardreset(host=None, admin_username=None, admin_password=None, module=None): """ Performs a reset (reboot) operation on the managed server. host The chassis host. admin_username The username used to access the chassis. admin_password The password used to access the chassis. module The element to hard reset on the chassis such as a blade. If not provided, the chassis will be reset. CLI Example: .. code-block:: bash salt dell dracr.server_hardreset salt dell dracr.server_hardreset module=server-1 """ return __execute_cmd( "serveraction hardreset", host=host, admin_username=admin_username, admin_password=admin_password, module=module, ) def server_powerstatus( host=None, admin_username=None, admin_password=None, module=None ): """ return the power status for the passed module CLI Example: .. code-block:: bash salt dell drac.server_powerstatus """ ret = __execute_ret( "serveraction powerstatus", host=host, admin_username=admin_username, admin_password=admin_password, module=module, ) result = {"retcode": 0} if ret["stdout"] == "ON": result["status"] = True result["comment"] = "Power is on" if ret["stdout"] == "OFF": result["status"] = False result["comment"] = "Power is on" if ret["stdout"].startswith("ERROR"): result["status"] = False result["comment"] = ret["stdout"] return result def server_pxe(host=None, admin_username=None, admin_password=None): """ Configure server to PXE perform a one off PXE boot CLI Example: .. code-block:: bash salt dell dracr.server_pxe """ if __execute_cmd( "config -g cfgServerInfo -o cfgServerFirstBootDevice PXE", host=host, admin_username=admin_username, admin_password=admin_password, ): if __execute_cmd( "config -g cfgServerInfo -o cfgServerBootOnce 1", host=host, admin_username=admin_username, admin_password=admin_password, ): return server_reboot else: log.warning("failed to set boot order") return False log.warning("failed to configure PXE boot") return False def list_slotnames(host=None, admin_username=None, admin_password=None): """ List the names of all slots in the chassis. host The chassis host. admin_username The username used to access the chassis. admin_password The password used to access the chassis. CLI Example: .. code-block:: bash salt-call --local dracr.list_slotnames host=111.222.333.444 admin_username=root admin_password=secret """ slotraw = __execute_ret( "getslotname", host=host, admin_username=admin_username, admin_password=admin_password, ) if slotraw["retcode"] != 0: return slotraw slots = {} stripheader = True for l in slotraw["stdout"].splitlines(): if l.startswith("<"): stripheader = False continue if stripheader: continue fields = l.split() slots[fields[0]] = {} slots[fields[0]]["slot"] = fields[0] if len(fields) > 1: slots[fields[0]]["slotname"] = fields[1] else: slots[fields[0]]["slotname"] = "" if len(fields) > 2: slots[fields[0]]["hostname"] = fields[2] else: slots[fields[0]]["hostname"] = "" return slots def get_slotname(slot, host=None, admin_username=None, admin_password=None): """ Get the name of a slot number in the chassis. slot The number of the slot for which to obtain the name. host The chassis host. admin_username The username used to access the chassis. admin_password The password used to access the chassis. CLI Example: .. code-block:: bash salt-call --local dracr.get_slotname 0 host=111.222.333.444 admin_username=root admin_password=secret """ slots = list_slotnames( host=host, admin_username=admin_username, admin_password=admin_password ) # The keys for this dictionary are strings, not integers, so convert the # argument to a string slot = str(slot) return slots[slot]["slotname"] def set_slotname(slot, name, host=None, admin_username=None, admin_password=None): """ Set the name of a slot in a chassis. slot The slot number to change. name The name to set. Can only be 15 characters long. host The chassis host. admin_username The username used to access the chassis. admin_password The password used to access the chassis. CLI Example: .. code-block:: bash salt '*' dracr.set_slotname 2 my-slotname host=111.222.333.444 admin_username=root admin_password=secret """ return __execute_cmd( f"config -g cfgServerInfo -o cfgServerName -i {slot} {name}", host=host, admin_username=admin_username, admin_password=admin_password, ) def set_chassis_name(name, host=None, admin_username=None, admin_password=None): """ Set the name of the chassis. name The name to be set on the chassis. host The chassis host. admin_username The username used to access the chassis. admin_password The password used to access the chassis. CLI Example: .. code-block:: bash salt '*' dracr.set_chassis_name my-chassis host=111.222.333.444 admin_username=root admin_password=secret """ return __execute_cmd( f"setsysinfo -c chassisname {name}", host=host, admin_username=admin_username, admin_password=admin_password, ) def get_chassis_name(host=None, admin_username=None, admin_password=None): """ Get the name of a chassis. host The chassis host. admin_username The username used to access the chassis. admin_password The password used to access the chassis. CLI Example: .. code-block:: bash salt '*' dracr.get_chassis_name host=111.222.333.444 admin_username=root admin_password=secret """ return bare_rac_cmd( "getchassisname", host=host, admin_username=admin_username, admin_password=admin_password, ) def inventory(host=None, admin_username=None, admin_password=None): def mapit(x, y): return {x: y} fields = {} fields["server"] = ["name", "idrac_version", "blade_type", "gen", "updateable"] fields["switch"] = ["name", "model_name", "hw_version", "fw_version"] fields["cmc"] = ["name", "cmc_version", "updateable"] fields["chassis"] = ["name", "fw_version", "fqdd"] rawinv = __execute_ret( "getversion", host=host, admin_username=admin_username, admin_password=admin_password, ) if rawinv["retcode"] != 0: return rawinv in_server = False in_switch = False in_cmc = False in_chassis = False ret = {} ret["server"] = {} ret["switch"] = {} ret["cmc"] = {} ret["chassis"] = {} for l in rawinv["stdout"].splitlines(): if l.startswith("<Server>"): in_server = True in_switch = False in_cmc = False in_chassis = False continue if l.startswith("<Switch>"): in_server = False in_switch = True in_cmc = False in_chassis = False continue if l.startswith("<CMC>"): in_server = False in_switch = False in_cmc = True in_chassis = False continue if l.startswith("<Chassis Infrastructure>"): in_server = False in_switch = False in_cmc = False in_chassis = True continue if not l: continue line = re.split(" +", l.strip()) if in_server: ret["server"][line[0]] = { k: v for d in map(mapit, fields["server"], line) for (k, v) in d.items() } if in_switch: ret["switch"][line[0]] = { k: v for d in map(mapit, fields["switch"], line) for (k, v) in d.items() } if in_cmc: ret["cmc"][line[0]] = { k: v for d in map(mapit, fields["cmc"], line) for (k, v) in d.items() } if in_chassis: ret["chassis"][line[0]] = { k: v for d in map(mapit, fields["chassis"], line) for k, v in d.items() } return ret def set_chassis_location(location, host=None, admin_username=None, admin_password=None): """ Set the location of the chassis. location The name of the location to be set on the chassis. host The chassis host. admin_username The username used to access the chassis. admin_password The password used to access the chassis. CLI Example: .. code-block:: bash salt '*' dracr.set_chassis_location location-name host=111.222.333.444 admin_username=root admin_password=secret """ return __execute_cmd( f"setsysinfo -c chassislocation {location}", host=host, admin_username=admin_username, admin_password=admin_password, ) def get_chassis_location(host=None, admin_username=None, admin_password=None): """ Get the location of the chassis. host The chassis host. admin_username The username used to access the chassis. admin_password The password used to access the chassis. CLI Example: .. code-block:: bash salt '*' dracr.set_chassis_location host=111.222.333.444 admin_username=root admin_password=secret """ return system_info( host=host, admin_username=admin_username, admin_password=admin_password )["Chassis Information"]["Chassis Location"] def set_chassis_datacenter( location, host=None, admin_username=None, admin_password=None ): """ Set the location of the chassis. location The name of the datacenter to be set on the chassis. host The chassis host. admin_username The username used to access the chassis. admin_password The password used to access the chassis. CLI Example: .. code-block:: bash salt '*' dracr.set_chassis_datacenter datacenter-name host=111.222.333.444 admin_username=root admin_password=secret """ return set_general( "cfgLocation", "cfgLocationDatacenter", location, host=host, admin_username=admin_username, admin_password=admin_password, ) def get_chassis_datacenter(host=None, admin_username=None, admin_password=None): """ Get the datacenter of the chassis. host The chassis host. admin_username The username used to access the chassis. admin_password The password used to access the chassis. CLI Example: .. code-block:: bash salt '*' dracr.set_chassis_location host=111.222.333.444 admin_username=root admin_password=secret """ return get_general( "cfgLocation", "cfgLocationDatacenter", host=host, admin_username=admin_username, admin_password=admin_password, ) def set_general( cfg_sec, cfg_var, val, host=None, admin_username=None, admin_password=None ): return __execute_cmd( f"config -g {cfg_sec} -o {cfg_var} {val}", host=host, admin_username=admin_username, admin_password=admin_password, ) def get_general(cfg_sec, cfg_var, host=None, admin_username=None, admin_password=None): ret = __execute_ret( f"getconfig -g {cfg_sec} -o {cfg_var}", host=host, admin_username=admin_username, admin_password=admin_password, ) if ret["retcode"] == 0: return ret["stdout"] else: return ret def idrac_general( blade_name, command, idrac_password=None, host=None, admin_username=None, admin_password=None, ): """ Run a generic racadm command against a particular blade in a chassis. Blades are usually named things like 'server-1', 'server-2', etc. If the iDRAC has a different password than the CMC, then you can pass it with the idrac_password kwarg. :param blade_name: Name of the blade to run the command on :param command: Command like to pass to racadm :param idrac_password: Password for the iDRAC if different from the CMC :param host: Chassis hostname :param admin_username: CMC username :param admin_password: CMC password :return: stdout if the retcode is 0, otherwise a standard cmd.run_all dictionary CLI Example: .. code-block:: bash salt fx2 chassis.cmd idrac_general server-1 'get BIOS.SysProfileSettings' """ module_network = network_info(host, admin_username, admin_password, blade_name) if idrac_password is not None: password = idrac_password else: password = admin_password idrac_ip = module_network["Network"]["IP Address"] ret = __execute_ret( command, host=idrac_ip, admin_username="root", admin_password=password ) if ret["retcode"] == 0: return ret["stdout"] else: return ret def _update_firmware(cmd, host=None, admin_username=None, admin_password=None): if not admin_username: admin_username = __pillar__["proxy"]["admin_username"] if not admin_username: admin_password = __pillar__["proxy"]["admin_password"] ret = __execute_ret( cmd, host=host, admin_username=admin_username, admin_password=admin_password ) if ret["retcode"] == 0: return ret["stdout"] else: return ret def bare_rac_cmd(cmd, host=None, admin_username=None, admin_password=None): ret = __execute_ret( f"{cmd}", host=host, admin_username=admin_username, admin_password=admin_password, ) if ret["retcode"] == 0: return ret["stdout"] else: return ret def update_firmware(filename, host=None, admin_username=None, admin_password=None): """ Updates firmware using local firmware file .. code-block:: bash salt dell dracr.update_firmware firmware.exe This executes the following command on your FX2 (using username and password stored in the pillar data) .. code-block:: bash racadm update –f firmware.exe -u user –p pass """ if os.path.exists(filename): return _update_firmware( f"update -f {filename}", host=None, admin_username=None, admin_password=None, ) else: raise CommandExecutionError(f"Unable to find firmware file {filename}") def update_firmware_nfs_or_cifs( filename, share, host=None, admin_username=None, admin_password=None ): """ Executes the following for CIFS (using username and password stored in the pillar data) .. code-block:: bash racadm update -f <updatefile> -u user –p pass -l //IP-Address/share Or for NFS (using username and password stored in the pillar data) .. code-block:: bash racadm update -f <updatefile> -u user –p pass -l IP-address:/share Salt command for CIFS: .. code-block:: bash salt dell dracr.update_firmware_nfs_or_cifs \ firmware.exe //IP-Address/share Salt command for NFS: .. code-block:: bash salt dell dracr.update_firmware_nfs_or_cifs \ firmware.exe IP-address:/share """ if os.path.exists(filename): return _update_firmware( f"update -f {filename} -l {share}", host=None, admin_username=None, admin_password=None, ) else: raise CommandExecutionError(f"Unable to find firmware file {filename}") # def get_idrac_nic()