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/aixpkg.py
""" Package support for AIX .. important:: If you feel that Salt should be using this module to manage filesets or rpm packages on a minion, and it is using a different module (or gives an error similar to *'pkg.install' is not available*), see :ref:`here <module-provider-override>`. """ import copy import logging import os import pathlib import salt.utils.data import salt.utils.functools import salt.utils.path import salt.utils.pkg from salt.exceptions import CommandExecutionError log = logging.getLogger(__name__) # Define the module's virtual name __virtualname__ = "pkg" def __virtual__(): """ Set the virtual pkg module if the os is AIX """ if __grains__["os_family"] == "AIX": return __virtualname__ return (False, "Did not load AIX module on non-AIX OS.") def _check_pkg(target): """ Return name, version and if rpm package for specified target """ ret = {} cmd = ["/usr/bin/lslpp", "-Lc", target] result = __salt__["cmd.run_all"](cmd, python_shell=False) if 0 == result["retcode"]: name = "" version_num = "" rpmpkg = False lines = result["stdout"].splitlines() for line in lines: if line.startswith("#"): continue comps = line.split(":") if len(comps) < 7: raise CommandExecutionError( "Error occurred finding fileset/package", info={"errors": comps[1].strip()}, ) # handle first matching line if "R" in comps[6]: name = comps[0] rpmpkg = True else: name = comps[1] # use fileset rather than rpm package version_num = comps[2] break return name, version_num, rpmpkg else: raise CommandExecutionError( "Error occurred finding fileset/package", info={"errors": result["stderr"].strip()}, ) def _is_installed_rpm(name): """ Returns True if the rpm package is installed. Otherwise returns False. """ cmd = ["/usr/bin/rpm", "-q", name] return __salt__["cmd.retcode"](cmd) == 0 def _list_pkgs_from_context(versions_as_list): """ Use pkg list from __context__ """ if versions_as_list: return __context__["pkg.list_pkgs"] else: ret = copy.deepcopy(__context__["pkg.list_pkgs"]) __salt__["pkg_resource.stringify"](ret) return ret def list_pkgs(versions_as_list=False, **kwargs): """ List the filesets/rpm packages currently installed as a dict: .. code-block:: python {'<package_name>': '<version>'} CLI Example: .. code-block:: bash salt '*' pkg.list_pkgs """ ret = {} versions_as_list = salt.utils.data.is_true(versions_as_list) # not yet implemented or not applicable if any( [salt.utils.data.is_true(kwargs.get(x)) for x in ("removed", "purge_desired")] ): return ret if "pkg.list_pkgs" in __context__ and kwargs.get("use_context", True): return _list_pkgs_from_context(versions_as_list) # cmd returns information colon delimited in a single linei, format # Package Name:Fileset:Level:State:PTF Id:Fix State:Type:Description: # Destination Dir.:Uninstaller:Message Catalog:Message Set: # Message Number:Parent:Automatic:EFIX Locked:Install Path:Build Date # Example: # xcursor:xcursor-1.1.7-3:1.1.7-3: : :C:R:X Cursor library: :\ # /bin/rpm -e xcursor: : : : :0: :(none):Mon May 8 15:18:35 CDT 2017 # bos:bos.rte.libcur:7.1.5.0: : :C:F:libcurses Library: : : : : : :0:0:/:1731 # # where Type codes: F -- Installp Fileset, P -- Product, C -- Component, # T -- Feature, R -- RPM Package cmd = "/usr/bin/lslpp -Lc" lines = __salt__["cmd.run"](cmd, python_shell=False).splitlines() for line in lines: if line.startswith("#"): continue comps = line.split(":") if len(comps) < 7: continue if "R" in comps[6]: name = comps[0] else: name = comps[1] # use fileset rather than rpm package version_num = comps[2] __salt__["pkg_resource.add_pkg"](ret, name, version_num) __salt__["pkg_resource.sort_pkglist"](ret) __context__["pkg.list_pkgs"] = copy.deepcopy(ret) if not versions_as_list: __salt__["pkg_resource.stringify"](ret) return ret def version(*names, **kwargs): """ Return the current installed version of the named fileset/rpm package If more than one fileset/rpm package name is specified a dict of name/version pairs is returned. .. versionchanged:: 3005 CLI Example: .. code-block:: bash salt '*' pkg.latest_version <package name> salt '*' pkg.latest_version <package1> <package2> <package3> ... """ kwargs.pop("refresh", True) ret = {} if not names: return "" for name in names: # AIX packaging includes info on filesets and rpms version_found = "" cmd = f"lslpp -Lq {name}" aix_info = __salt__["cmd.run_all"](cmd, python_shell=False) if 0 == aix_info["retcode"]: aix_info_list = aix_info["stdout"].split("\n") log.debug( "Returned AIX packaging information aix_info_list %s for name %s", aix_info_list, name, ) for aix_line in aix_info_list: if name in aix_line: aix_ver_list = aix_line.split() log.debug( "Processing name %s with AIX packaging version information %s", name, aix_ver_list, ) version_found = aix_ver_list[1] if version_found: log.debug( "Found name %s in AIX packaging information, version %s", name, version_found, ) break else: log.debug("Could not find name %s in AIX packaging information", name) ret[name] = version_found # Return a string if only one package name passed if len(names) == 1: return ret[names[0]] return ret def _is_installed(name, **kwargs): """ Returns True if the fileset/rpm package is installed. Otherwise returns False. CLI Example: .. code-block:: bash salt '*' pkg._is_installed bash """ cmd = ["/usr/bin/lslpp", "-Lc", name] return __salt__["cmd.retcode"](cmd) == 0 def install(name=None, refresh=False, pkgs=None, version=None, test=False, **kwargs): """ Install the named fileset(s)/rpm package(s). .. versionchanged:: 3005 preference to install rpm packages are to use in the following order: /opt/freeware/bin/dnf /opt/freeware/bin/yum /usr/bin/yum /usr/bin/rpm .. note: use of rpm to install implies that rpm's dependencies must have been previously installed. dnf and yum automatically install rpm's dependencies as part of the install process Alogrithm to install filesets or rpms is as follows: if ends with '.rte' or '.bff' process as fileset if ends with '.rpm' process as rpm if unrecognised or no file extension attempt process with dnf | yum failure implies attempt process as fileset Fileset needs to be available as a single path and filename compound filesets are not handled and are not supported. An example is bos.adt.insttools which is part of bos.adt.other and is installed as follows /usr/bin/installp -acXYg /cecc/repos/aix72/TL4/BASE/installp/ppc/bos.adt.other bos.adt.insttools name The name of the fileset or rpm package to be installed. refresh Whether or not to update the yum database before executing. pkgs A list of filesets and/or rpm packages to install. Must be passed as a python list. The ``name`` parameter will be ignored if this option is passed. version Install a specific version of a fileset/rpm package. (Unused at present). .. note:: Remember that versions that contain a single `.` will be interpreted as numbers and must be double-quoted. For example, version ``3006.10`` will be rendered as ``3006.1``. To pass ``3006.10`` you'll need to use double-quotes. ``version="'3006.10'"`` test Verify that command functions correctly. Returns a dict containing the new fileset(s)/rpm package(s) names and versions: {'<package>': {'old': '<old-version>', 'new': '<new-version>'}} CLI Example: .. code-block:: bash salt '*' pkg.install /stage/middleware/AIX/bash-4.2-3.aix6.1.ppc.rpm salt '*' pkg.install /stage/middleware/AIX/bash-4.2-3.aix6.1.ppc.rpm refresh=True salt '*' pkg.install /stage/middleware/AIX/VIOS2211_update/tpc_4.1.1.85.bff salt '*' pkg.install /cecc/repos/aix72/TL3/BASE/installp/ppc/bos.rte.printers_7.2.2.0.bff salt '*' pkg.install /stage/middleware/AIX/Xlc/usr/sys/inst.images/xlC.rte salt '*' pkg.install /stage/middleware/AIX/Firefox/ppc-AIX53/Firefox.base salt '*' pkg.install /cecc/repos/aix72/TL3/BASE/installp/ppc/bos.net salt '*' pkg.install pkgs='["foo", "bar"]' salt '*' pkg.install libxml2 """ targets = salt.utils.args.split_input(pkgs) if pkgs else [name] if not targets: return {} if pkgs: log.debug("Installing these fileset(s)/rpm package(s) %s: %s", name, targets) # Get a list of the currently installed pkgs. old = list_pkgs() # Install the fileset (normally ends with bff or rte) or rpm package(s) errors = [] for target in targets: filename = os.path.basename(target) flag_fileset = False flag_actual_rpm = False flag_try_rpm_failed = False cmd = "" out = {} if filename.endswith(".bff") or filename.endswith(".rte"): flag_fileset = True log.debug("install identified %s as fileset", filename) else: if filename.endswith(".rpm"): flag_actual_rpm = True log.debug("install identified %s as rpm", filename) else: log.debug("install filename %s trying install as rpm", filename) # assume use dnf or yum cmdflags = "install " libpathenv = {"LIBPATH": "/opt/freeware/lib:/usr/lib"} if pathlib.Path("/opt/freeware/bin/dnf").is_file(): cmdflags += "--allowerasing " cmdexe = "/opt/freeware/bin/dnf" if test: cmdflags += "--assumeno " else: cmdflags += "--assumeyes " if refresh: cmdflags += "--refresh " cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True, ) elif pathlib.Path("/usr/bin/yum").is_file(): # check for old yum first, removed if new dnf or yum cmdexe = "/usr/bin/yum" if test: cmdflags += "--assumeno " else: cmdflags += "--assumeyes " cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True, ) elif pathlib.Path("/opt/freeware/bin/yum").is_file(): cmdflags += "--allowerasing " cmdexe = "/opt/freeware/bin/yum" if test: cmdflags += "--assumeno " else: cmdflags += "--assumeyes " if refresh: cmdflags += "--refresh " cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True, ) else: cmdexe = "/usr/bin/rpm" cmdflags = "-Uivh " if test: cmdflags += "--test" cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"](cmd, python_shell=False) if "retcode" in out and not (0 == out["retcode"] or 100 == out["retcode"]): if not flag_actual_rpm: flag_try_rpm_failed = True log.debug( "install tried filename %s as rpm and failed, trying as fileset", filename, ) else: errors.append(out["stderr"]) log.debug( "install error rpm path, returned result %s, resultant errors %s", out, errors, ) if flag_fileset or flag_try_rpm_failed: # either identified as fileset, or failed trying install as rpm, try as fileset cmd = "/usr/sbin/installp -acYXg" if test: cmd += "p" cmd += " -d " dirpath = os.path.dirname(target) cmd += dirpath + " " + filename log.debug("install fileset commanda to attempt %s", cmd) out = __salt__["cmd.run_all"](cmd, python_shell=False) if 0 != out["retcode"]: errors.append(out["stderr"]) log.debug( "install error fileset path, returned result %s, resultant errors %s", out, errors, ) # Get a list of the packages after the uninstall __context__.pop("pkg.list_pkgs", None) new = list_pkgs() ret = salt.utils.data.compare_dicts(old, new) if errors: raise CommandExecutionError( "Problems encountered installing filesets(s)/package(s)", info={"changes": ret, "errors": errors}, ) # No error occurred if test: return "Test succeeded." return ret def remove(name=None, pkgs=None, **kwargs): """ Remove specified fileset(s)/rpm package(s). name The name of the fileset or rpm package to be deleted. .. versionchanged:: 3005 preference to install rpm packages are to use in the following order: /opt/freeware/bin/dnf /opt/freeware/bin/yum /usr/bin/yum /usr/bin/rpm pkgs A list of filesets and/or rpm packages to delete. Must be passed as a python list. The ``name`` parameter will be ignored if this option is passed. Returns a list containing the removed packages. CLI Example: .. code-block:: bash salt '*' pkg.remove <fileset/rpm package name> salt '*' pkg.remove tcsh salt '*' pkg.remove xlC.rte salt '*' pkg.remove Firefox.base.adt salt '*' pkg.remove pkgs='["foo", "bar"]' """ targets = salt.utils.args.split_input(pkgs) if pkgs else [name] if not targets: return {} if pkgs: log.debug("Removing these fileset(s)/rpm package(s) %s: %s", name, targets) errors = [] # Get a list of the currently installed pkgs. old = list_pkgs() # Remove the fileset or rpm package(s) for target in targets: cmd = "" out = {} try: named, versionpkg, rpmpkg = _check_pkg(target) except CommandExecutionError as exc: if exc.info: errors.append(exc.info["errors"]) continue if rpmpkg: # assume use dnf or yum cmdflags = "-y remove" libpathenv = {"LIBPATH": "/opt/freeware/lib:/usr/lib"} if pathlib.Path("/opt/freeware/bin/dnf").is_file(): cmdexe = "/opt/freeware/bin/dnf" cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True, ) elif pathlib.Path("/opt/freeware/bin/yum").is_file(): cmdexe = "/opt/freeware/bin/yum" cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True, ) elif pathlib.Path("/usr/bin/yum").is_file(): cmdexe = "/usr/bin/yum" cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True, ) else: cmdexe = "/usr/bin/rpm" cmdflags = "-e" cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"](cmd, python_shell=False) else: cmd = ["/usr/sbin/installp", "-u", named] out = __salt__["cmd.run_all"](cmd, python_shell=False) log.debug("result of removal command %s, returned result %s", cmd, out) # Get a list of the packages after the uninstall __context__.pop("pkg.list_pkgs", None) new = list_pkgs() ret = salt.utils.data.compare_dicts(old, new) if errors: raise CommandExecutionError( "Problems encountered removing filesets(s)/package(s)", info={"changes": ret, "errors": errors}, ) return ret def latest_version(*names, **kwargs): """ Return the latest available version of the named fileset/rpm package available for upgrade or installation. If more than one fileset/rpm package name is specified, a dict of name/version pairs is returned. If the latest version of a given fileset/rpm package is already installed, an empty string will be returned for that package. .. versionchanged:: 3005 CLI Example: .. code-block:: bash salt '*' pkg.latest_version <package name> salt '*' pkg.latest_version <package1> <package2> <package3> ... Note: currently only functional for rpm packages due to filesets do not have a specific location to check Requires yum of dnf available in order to query a repository This function will always return an empty string for unfound fileset/rpm package. """ kwargs.pop("refresh", True) ret = {} if not names: return "" for name in names: # AIX packaging includes info on filesets and rpms version_found = "" libpathenv = {"LIBPATH": "/opt/freeware/lib:/usr/lib"} if pathlib.Path("/opt/freeware/bin/dnf").is_file(): cmdexe = "/opt/freeware/bin/dnf" cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) elif pathlib.Path("/opt/freeware/bin/yum").is_file(): cmdexe = "/opt/freeware/bin/yum" cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) elif pathlib.Path("/usr/bin/yum").is_file(): cmdexe = "/usr/bin/yum" cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) else: # no yum found implies no repository support available_info = None log.debug( "latest_version dnf|yum check-update command returned information %s", available_info, ) if available_info and ( 0 == available_info["retcode"] or 100 == available_info["retcode"] ): available_output = available_info["stdout"] if available_output: available_list = available_output.split() flag_found = False for name_chk in available_list: # have viable check, note .ppc or .noarch if name_chk.startswith(name): # check full name pkg_label = name_chk.split(".") if name == pkg_label[0]: flag_found = True elif flag_found: # version comes after name found version_found = name_chk break if version_found: log.debug( "latest_version result for name %s found version %s", name, version_found, ) else: log.debug("Could not find AIX / RPM packaging version for %s", name) ret[name] = version_found # Return a string if only one package name passed if len(names) == 1: return ret[names[0]] return ret # available_version is being deprecated available_version = salt.utils.functools.alias_function( latest_version, "available_version" ) def upgrade_available(name, **kwargs): """ Check whether or not an upgrade is available for a given package .. versionchanged:: 3005 CLI Example: .. code-block:: bash salt '*' pkg.upgrade_available <package name> Note: currently only functional for rpm packages due to filesets do not have a specific location to check Requires yum of dnf available in order to query a repository """ # AIX packaging includes info on filesets and rpms rpm_found = False version_found = "" libpathenv = {"LIBPATH": "/opt/freeware/lib:/usr/lib"} if pathlib.Path("/opt/freeware/bin/dnf").is_file(): cmdexe = "/opt/freeware/bin/dnf" cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) elif pathlib.Path("/opt/freeware/bin/yum").is_file(): cmdexe = "/opt/freeware/bin/yum" cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) elif pathlib.Path("/usr/bin/yum").is_file(): cmdexe = "/usr/bin/yum" cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) else: # no yum found implies no repository support return False log.debug( "upgrade_available yum check-update command %s, returned information %s", cmd, available_info, ) if 0 == available_info["retcode"] or 100 == available_info["retcode"]: available_output = available_info["stdout"] if available_output: available_list = available_output.split() flag_found = False for name_chk in available_list: # have viable check, note .ppc or .noarch if name_chk.startswith(name): # check full name pkg_label = name_chk.split(".") if name == pkg_label[0]: flag_found = True elif flag_found: # version comes after name found version_found = name_chk break current_version = version(name) log.debug( "upgrade_available result for name %s, found current version %s, available version %s", name, current_version, version_found, ) if version_found: return current_version != version_found else: log.debug("upgrade_available information for name %s was not found", name) return False