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/mine.py
""" The function cache system allows for data to be stored on the master so it can be easily read by other minions """ import logging import time import traceback import salt.channel.client import salt.crypt import salt.payload import salt.transport import salt.utils.args import salt.utils.dictupdate import salt.utils.event import salt.utils.functools import salt.utils.mine import salt.utils.minions import salt.utils.network from salt.exceptions import SaltClientError MINE_INTERNAL_KEYWORDS = frozenset( [ "__pub_user", "__pub_arg", "__pub_fun", "__pub_jid", "__pub_tgt", "__pub_tgt_type", "__pub_ret", ] ) __proxyenabled__ = ["*"] log = logging.getLogger(__name__) def _auth(): """ Return the auth object """ if "auth" not in __context__: try: __context__["auth"] = salt.crypt.SAuth(__opts__) except SaltClientError: log.error( "Could not authenticate with master. Mine data will not be transmitted." ) return __context__["auth"] def _mine_function_available(func): if func not in __salt__: log.error("Function %s in mine_functions not available", func) return False return True def _mine_send(load, opts): eventer = salt.utils.event.MinionEvent(opts, listen=False) event_ret = eventer.fire_event(load, "_minion_mine") # We need to pause here to allow for the decoupled nature of # events time to allow the mine to propagate time.sleep(0.5) return event_ret def _mine_get(load, opts): with salt.channel.client.ReqChannel.factory(opts) as channel: return channel.send(load) def _mine_store(mine_data, clear=False): """ Helper function to store the provided mine data. This will store either locally in the cache (for masterless setups), or in the master's cache. :param dict mine_data: Dictionary with function_name: function_data to store. :param bool clear: Whether or not to clear (`True`) the mine data for the function names present in ``mine_data``, or update it (`False`). """ # Store in the salt-minion's local cache if __opts__["file_client"] == "local": if not clear: old = __salt__["data.get"]("mine_cache") if isinstance(old, dict): old.update(mine_data) mine_data = old return __salt__["data.update"]("mine_cache", mine_data) # Store on the salt master load = { "cmd": "_mine", "data": mine_data, "id": __opts__["id"], "clear": clear, } return _mine_send(load, __opts__) def update(clear=False, mine_functions=None): """ Call the configured functions and send the data back up to the master. The functions to be called are merged from the master config, pillar and minion config under the option `mine_functions`: .. code-block:: yaml mine_functions: network.ip_addrs: - eth0 disk.usage: [] This function accepts the following arguments: :param bool clear: Default: ``False`` Specifies whether updating will clear the existing values (``True``), or whether it will update them (``False``). :param dict mine_functions: Update (or clear, see ``clear``) the mine data on these functions only. This will need to have the structure as defined on https://docs.saltproject.io/en/latest/topics/mine/index.html#mine-functions This feature can be used when updating the mine for functions that require a refresh at different intervals than the rest of the functions specified under `mine_functions` in the minion/master config or pillar. A potential use would be together with the `scheduler`, for example: .. code-block:: yaml schedule: lldp_mine_update: function: mine.update kwargs: mine_functions: net.lldp: [] hours: 12 In the example above, the mine for `net.lldp` would be refreshed every 12 hours, while `network.ip_addrs` would continue to be updated as specified in `mine_interval`. The function cache will be populated with information from executing these functions CLI Example: .. code-block:: bash salt '*' mine.update """ if not mine_functions: mine_functions = __salt__["config.merge"]("mine_functions", {}) # If we don't have any mine functions configured, then we should just bail out if not mine_functions: return elif isinstance(mine_functions, list): mine_functions = {fun: {} for fun in mine_functions} elif isinstance(mine_functions, dict): pass else: return mine_data = {} for function_alias, function_data in mine_functions.items(): ( function_name, function_args, function_kwargs, minion_acl, ) = salt.utils.mine.parse_function_definition(function_data) if not _mine_function_available(function_name or function_alias): continue try: res = salt.utils.functools.call_function( __salt__[function_name or function_alias], *function_args, **function_kwargs, ) except Exception: # pylint: disable=broad-except trace = traceback.format_exc() log.error( "Function %s in mine.update failed to execute", function_name or function_alias, ) log.debug("Error: %s", trace) continue if minion_acl.get("allow_tgt"): mine_data[function_alias] = salt.utils.mine.wrap_acl_structure( res, **minion_acl ) else: mine_data[function_alias] = res return _mine_store(mine_data, clear) def send(name, *args, **kwargs): """ Send a specific function and its result to the salt mine. This gets stored in either the local cache, or the salt master's cache. :param str name: Name of the function to add to the mine. The following pameters are extracted from kwargs if present: :param str mine_function: The name of the execution_module.function to run and whose value will be stored in the salt mine. Defaults to ``name``. :param str allow_tgt: Targeting specification for ACL. Specifies which minions are allowed to access this function. Please note both your master and minion need to be on, at least, version 3000 for this to work properly. :param str allow_tgt_type: Type of the targeting specification. This value will be ignored if ``allow_tgt`` is not specified. Please note both your master and minion need to be on, at least, version 3000 for this to work properly. Remaining args and kwargs will be passed on to the function to run. :rtype: bool :return: Whether executing the function and storing the information was successful. .. versionchanged:: 3000 Added ``allow_tgt``- and ``allow_tgt_type``-parameters to specify which minions are allowed to access this function. See :ref:`targeting` for more information about targeting. CLI Example: .. code-block:: bash salt '*' mine.send network.ip_addrs interface=eth0 salt '*' mine.send eth0_ip_addrs mine_function=network.ip_addrs interface=eth0 salt '*' mine.send eth0_ip_addrs mine_function=network.ip_addrs interface=eth0 allow_tgt='G@grain:value' allow_tgt_type=compound """ kwargs = salt.utils.args.clean_kwargs(**kwargs) mine_function = kwargs.pop("mine_function", None) allow_tgt = kwargs.pop("allow_tgt", None) allow_tgt_type = kwargs.pop("allow_tgt_type", None) mine_data = {} try: res = salt.utils.functools.call_function( __salt__[mine_function or name], *args, **kwargs ) except Exception as exc: # pylint: disable=broad-except trace = traceback.format_exc() log.error("Function %s in mine.send failed to execute", mine_function or name) log.debug("Error: %s", trace) return False if allow_tgt: mine_data[name] = salt.utils.mine.wrap_acl_structure( res, allow_tgt=allow_tgt, allow_tgt_type=allow_tgt_type ) else: mine_data[name] = res return _mine_store(mine_data) def get(tgt, fun, tgt_type="glob", exclude_minion=False): """ Get data from the mine. :param str tgt: Target whose mine data to get. :param fun: Function to get the mine data of. You can specify multiple functions to retrieve using either a list or a comma-separated string of functions. :type fun: str or list :param str tgt_type: Default ``glob``. Target type to use with ``tgt``. See :ref:`targeting` for more information. Note that all pillar matches, whether using the compound matching system or the pillar matching system, will be exact matches, with globbing disabled. :param bool exclude_minion: Excludes the current minion from the result set. CLI Example: .. code-block:: bash salt '*' mine.get '*' network.interfaces salt '*' mine.get 'os:Fedora' network.interfaces grain salt '*' mine.get 'G@os:Fedora and S@192.168.5.0/24' network.ipaddrs compound .. seealso:: Retrieving Mine data from Pillar and Orchestrate This execution module is intended to be executed on minions. Master-side operations such as Pillar or Orchestrate that require Mine data should use the :py:mod:`Mine Runner module <salt.runners.mine>` instead; it can be invoked from a Pillar SLS file using the :py:func:`saltutil.runner <salt.modules.saltutil.runner>` module. For example: .. code-block:: jinja {% set minion_ips = salt.saltutil.runner('mine.get', tgt='*', fun='network.ip_addrs', tgt_type='glob') %} """ # Load from local minion's cache if __opts__["file_client"] == "local": ret = {} is_target = __salt__[f"match.{tgt_type}"](tgt) if not is_target: return ret data = __salt__["data.get"]("mine_cache") if not isinstance(data, dict): return ret if isinstance(fun, str): functions = list(set(fun.split(","))) _ret_dict = len(functions) > 1 elif isinstance(fun, list): functions = fun _ret_dict = True else: return ret for function in functions: if function not in data: continue # If this is a mine item with minion_side_ACL, get its data if salt.utils.mine.MINE_ITEM_ACL_ID in data[function]: res = data[function][salt.utils.mine.MINE_ITEM_ACL_DATA] else: # Backwards compatibility with non-ACL mine data. res = data[function] if _ret_dict: ret.setdefault(function, {})[__opts__["id"]] = res else: ret[__opts__["id"]] = res return ret # Load from master load = { "cmd": "_mine_get", "id": __opts__["id"], "tgt": tgt, "fun": fun, "tgt_type": tgt_type, } ret = _mine_get(load, __opts__) if exclude_minion and __opts__["id"] in ret: del ret[__opts__["id"]] return ret def delete(fun): """ Remove specific function contents of minion. :param str fun: The name of the function. :rtype: bool :return: True on success. CLI Example: .. code-block:: bash salt '*' mine.delete 'network.interfaces' """ if __opts__["file_client"] == "local": data = __salt__["data.get"]("mine_cache") if isinstance(data, dict) and fun in data: del data[fun] return __salt__["data.update"]("mine_cache", data) load = { "cmd": "_mine_delete", "id": __opts__["id"], "fun": fun, } return _mine_send(load, __opts__) def flush(): """ Remove all mine contents of minion. :rtype: bool :return: True on success CLI Example: .. code-block:: bash salt '*' mine.flush """ if __opts__["file_client"] == "local": return __salt__["data.update"]("mine_cache", {}) load = { "cmd": "_mine_flush", "id": __opts__["id"], } return _mine_send(load, __opts__) def get_docker(interfaces=None, cidrs=None, with_container_id=False): """ .. versionchanged:: 2017.7.8,2018.3.3 When :conf_minion:`docker.update_mine` is set to ``False`` for a given minion, no mine data will be populated for that minion, and thus none will be returned for it. .. versionchanged:: 2019.2.0 :conf_minion:`docker.update_mine` now defaults to ``False`` Get all mine data for :py:func:`docker.ps <salt.modules.dockermod.ps_>` and run an aggregation routine. The ``interfaces`` parameter allows for specifying the network interfaces from which to select IP addresses. The ``cidrs`` parameter allows for specifying a list of subnets which the IP address must match. with_container_id Boolean, to expose container_id in the list of results .. versionadded:: 2015.8.2 CLI Example: .. code-block:: bash salt '*' mine.get_docker salt '*' mine.get_docker interfaces='eth0' salt '*' mine.get_docker interfaces='["eth0", "eth1"]' salt '*' mine.get_docker cidrs='107.170.147.0/24' salt '*' mine.get_docker cidrs='["107.170.147.0/24", "172.17.42.0/24"]' salt '*' mine.get_docker interfaces='["eth0", "eth1"]' cidrs='["107.170.147.0/24", "172.17.42.0/24"]' """ # Enforce that interface and cidr are lists if interfaces: interface_ = [] interface_.extend(interfaces if isinstance(interfaces, list) else [interfaces]) interfaces = interface_ if cidrs: cidr_ = [] cidr_.extend(cidrs if isinstance(cidrs, list) else [cidrs]) cidrs = cidr_ # Get docker info cmd = "docker.ps" docker_hosts = get("*", cmd) proxy_lists = {} # Process docker info for containers in docker_hosts.values(): host = containers.pop("host") host_ips = [] # Prepare host_ips list if not interfaces: for info in host["interfaces"].values(): if "inet" in info: for ip_ in info["inet"]: host_ips.append(ip_["address"]) else: for interface in interfaces: if interface in host["interfaces"]: if "inet" in host["interfaces"][interface]: for item in host["interfaces"][interface]["inet"]: host_ips.append(item["address"]) host_ips = list(set(host_ips)) # Filter out ips from host_ips with cidrs if cidrs: good_ips = [] for cidr in cidrs: for ip_ in host_ips: if salt.utils.network.in_subnet(cidr, [ip_]): good_ips.append(ip_) host_ips = list(set(good_ips)) # Process each container for container in containers.values(): container_id = container["Info"]["Id"] if container["Image"] not in proxy_lists: proxy_lists[container["Image"]] = {} for dock_port in container["Ports"]: # IP exists only if port is exposed ip_address = dock_port.get("IP") # If port is 0.0.0.0, then we must get the docker host IP if ip_address == "0.0.0.0": for ip_ in host_ips: containers = ( proxy_lists[container["Image"]] .setdefault("ipv4", {}) .setdefault(dock_port["PrivatePort"], []) ) container_network_footprint = "{}:{}".format( ip_, dock_port["PublicPort"] ) if with_container_id: value = (container_network_footprint, container_id) else: value = container_network_footprint if value not in containers: containers.append(value) elif ip_address: containers = ( proxy_lists[container["Image"]] .setdefault("ipv4", {}) .setdefault(dock_port["PrivatePort"], []) ) container_network_footprint = "{}:{}".format( dock_port["IP"], dock_port["PublicPort"] ) if with_container_id: value = (container_network_footprint, container_id) else: value = container_network_footprint if value not in containers: containers.append(value) return proxy_lists def valid(): """ List valid entries in mine configuration. CLI Example: .. code-block:: bash salt '*' mine.valid """ mine_functions = __salt__["config.merge"]("mine_functions", {}) # If we don't have any mine functions configured, then we should just bail out if not mine_functions: return mine_data = {} for function_alias, function_data in mine_functions.items(): ( function_name, function_args, function_kwargs, minion_acl, ) = salt.utils.mine.parse_function_definition(function_data) if not _mine_function_available(function_name or function_alias): continue if function_name: mine_data[function_alias] = { function_name: function_args + [{key: value} for key, value in function_kwargs.items()] } else: mine_data[function_alias] = function_data return mine_data