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/zcbuildout.py
""" Management of zc.buildout .. versionadded:: 2014.1.0 .. _`minitage's buildout maker`: https://github.com/minitage/minitage/blob/master/src/minitage/core/makers/buildout.py This module is inspired by `minitage's buildout maker`_ .. note:: The zc.buildout integration is still in beta; the API is subject to change General notes ------------- You have those following methods: * upgrade_bootstrap * bootstrap * run_buildout * buildout """ import copy import logging import os import re import sys import traceback import urllib.request import salt.utils.files import salt.utils.path import salt.utils.stringutils from salt.exceptions import CommandExecutionError INVALID_RESPONSE = "Unexpected response from buildout" VALID_RESPONSE = "" NOTSET = object() HR = "{}\n".format("-" * 80) RE_F = re.S | re.M | re.U BASE_STATUS = { "status": None, "logs": [], "comment": "", "out": None, "logs_by_level": {}, "outlog": None, "outlog_by_level": None, } _URL_VERSIONS = { 1: "http://downloads.buildout.org/1/bootstrap.py", 2: "http://downloads.buildout.org/2/bootstrap.py", } DEFAULT_VER = 2 _logger = logging.getLogger(__name__) # Define the module's virtual name __virtualname__ = "buildout" def __virtual__(): """ Only load if buildout libs are present """ return __virtualname__ def _salt_callback(func, **kwargs): LOG.clear() def _call_callback(*a, **kw): # cleanup the module kwargs before calling it from the # decorator kw = copy.deepcopy(kw) for k in [ar for ar in kw if "__pub" in ar]: kw.pop(k, None) st = BASE_STATUS.copy() directory = kw.get("directory", ".") onlyif = kw.get("onlyif", None) unless = kw.get("unless", None) runas = kw.get("runas", None) env = kw.get("env", ()) status = BASE_STATUS.copy() try: # may rise _ResultTransmission status = _check_onlyif_unless( onlyif, unless, directory=directory, runas=runas, env=env ) # if onlyif/unless returns, we are done if status is None: status = BASE_STATUS.copy() comment, st = "", True out = func(*a, **kw) # we may have already final statuses not to be touched # merged_statuses flag is there to check that ! if not isinstance(out, dict): status = _valid(status, out=out) else: if out.get("merged_statuses", False): status = out else: status = _set_status( status, status=out.get("status", True), comment=out.get("comment", ""), out=out.get("out", out), ) except Exception: # pylint: disable=broad-except trace = traceback.format_exc() LOG.error(trace) _invalid(status) LOG.clear() # before returning, trying to compact the log output for k in ["comment", "out", "outlog"]: if status[k] and isinstance(status[k], str): status[k] = "\n".join( [log for log in status[k].split("\n") if log.strip()] ) return status _call_callback.__doc__ = func.__doc__ return _call_callback class _Logger: levels = ("info", "warn", "debug", "error") def __init__(self): self._msgs = [] self._by_level = {} def _log(self, level, msg): if not isinstance(msg, str): msg = msg.decode("utf-8") if level not in self._by_level: self._by_level[level] = [] self._msgs.append((level, msg)) self._by_level[level].append(msg) def debug(self, msg): self._log("debug", msg) def info(self, msg): self._log("info", msg) def error(self, msg): self._log("error", msg) def warn(self, msg): self._log("warn", msg) warning = warn def clear(self): for i in self._by_level: self._by_level[i] = [] for i in self._msgs[:]: self._msgs.pop() def get_logs(self, level): return self._by_level.get(level, []) @property def messages(self): return self._msgs @property def by_level(self): return self._by_level LOG = _Logger() def _encode_status(status): if status["out"] is None: status["out"] = None else: status["out"] = salt.utils.stringutils.to_unicode(status["out"]) status["outlog_by_level"] = salt.utils.stringutils.to_unicode( status["outlog_by_level"] ) if status["logs"]: for i, data in enumerate(status["logs"][:]): status["logs"][i] = (data[0], salt.utils.stringutils.to_unicode(data[1])) for logger in "error", "warn", "info", "debug": logs = status["logs_by_level"].get(logger, [])[:] if logs: for i, log in enumerate(logs): status["logs_by_level"][logger][i] = ( salt.utils.stringutils.to_unicode(log) ) return status def _set_status(m, comment=INVALID_RESPONSE, status=False, out=None): """ Assign status data to a dict. """ m["out"] = out m["status"] = status m["logs"] = LOG.messages[:] m["logs_by_level"] = LOG.by_level.copy() outlog, outlog_by_level = "", "" m["comment"] = comment if out and isinstance(out, str): outlog += HR outlog += "OUTPUT:\n" outlog += f"{salt.utils.stringutils.to_unicode(out)}\n" outlog += HR if m["logs"]: outlog += HR outlog += "Log summary:\n" outlog += HR outlog_by_level += HR outlog_by_level += "Log summary by level:\n" outlog_by_level += HR for level, msg in m["logs"]: outlog += "\n{}: {}\n".format( level.upper(), salt.utils.stringutils.to_unicode(msg) ) for logger in "error", "warn", "info", "debug": logs = m["logs_by_level"].get(logger, []) if logs: outlog_by_level += f"\n{logger.upper()}:\n" for idx, log in enumerate(logs[:]): logs[idx] = salt.utils.stringutils.to_unicode(log) outlog_by_level += "\n".join(logs) outlog_by_level += "\n" outlog += HR m["outlog"] = outlog m["outlog_by_level"] = outlog_by_level return _encode_status(m) def _invalid(m, comment=INVALID_RESPONSE, out=None): """ Return invalid status. """ return _set_status(m, status=False, comment=comment, out=out) def _valid(m, comment=VALID_RESPONSE, out=None): """ Return valid status. """ return _set_status(m, status=True, comment=comment, out=out) def _Popen( command, output=False, directory=".", runas=None, env=(), exitcode=0, use_vt=False, loglevel=None, ): """ Run a command. output return output if true directory directory to execute in runas user used to run buildout as env environment variables to set when running exitcode fails if cmd does not return this exit code (set to None to disable check) use_vt Use the new salt VT to stream output [experimental] """ ret = None directory = os.path.abspath(directory) if isinstance(command, list): command = " ".join(command) LOG.debug(f"Running {command}") if not loglevel: loglevel = "debug" ret = __salt__["cmd.run_all"]( command, cwd=directory, output_loglevel=loglevel, runas=runas, env=env, use_vt=use_vt, python_shell=False, ) out = ret["stdout"] + "\n\n" + ret["stderr"] if (exitcode is not None) and (ret["retcode"] != exitcode): raise _BuildoutError(out) ret["output"] = out if output: ret = out return ret class _BuildoutError(CommandExecutionError): """ General Buildout Error. """ def _has_old_distribute(python=sys.executable, runas=None, env=()): old_distribute = False try: cmd = [ python, "-c", "'import pkg_resources;" "print pkg_resources." 'get_distribution("distribute").location\'', ] ret = _Popen(cmd, runas=runas, env=env, output=True) if "distribute-0.6" in ret: old_distribute = True except Exception: # pylint: disable=broad-except old_distribute = False return old_distribute def _has_setuptools7(python=sys.executable, runas=None, env=()): new_st = False try: cmd = [ python, "-c", "'import pkg_resources;" "print not pkg_resources." 'get_distribution("setuptools").version.startswith("0.6")\'', ] ret = _Popen(cmd, runas=runas, env=env, output=True) if "true" in ret.lower(): new_st = True except Exception: # pylint: disable=broad-except new_st = False return new_st def _find_cfgs(path, cfgs=None): """ Find all buildout configs in a subdirectory. only buildout.cfg and etc/buildout.cfg are valid in:: path directory where to start to search cfg a optional list to append to . ├── buildout.cfg ├── etc │   └── buildout.cfg ├── foo │   └── buildout.cfg └── var └── buildout.cfg """ ignored = ["var", "parts"] dirs = [] if not cfgs: cfgs = [] for i in os.listdir(path): fi = os.path.join(path, i) if fi.endswith(".cfg") and os.path.isfile(fi): cfgs.append(fi) if os.path.isdir(fi) and (i not in ignored): dirs.append(fi) for fpath in dirs: for p, ids, ifs in salt.utils.path.os_walk(fpath): for i in ifs: if i.endswith(".cfg"): cfgs.append(os.path.join(p, i)) return cfgs def _get_bootstrap_content(directory="."): """ Get the current bootstrap.py script content """ try: with salt.utils.files.fopen( os.path.join(os.path.abspath(directory), "bootstrap.py") ) as fic: oldcontent = salt.utils.stringutils.to_unicode(fic.read()) except OSError: oldcontent = "" return oldcontent def _get_buildout_ver(directory="."): """Check for buildout versions. In any cases, check for a version pinning Also check for buildout.dumppickedversions which is buildout1 specific Also check for the version targeted by the local bootstrap file Take as default buildout2 directory directory to execute in """ directory = os.path.abspath(directory) buildoutver = 2 try: files = _find_cfgs(directory) for f in files: with salt.utils.files.fopen(f) as fic: buildout1re = re.compile(r"^zc\.buildout\s*=\s*1", RE_F) dfic = salt.utils.stringutils.to_unicode(fic.read()) if ("buildout.dumppick" in dfic) or (buildout1re.search(dfic)): buildoutver = 1 bcontent = _get_bootstrap_content(directory) if ( "--download-base" in bcontent or "--setup-source" in bcontent or "--distribute" in bcontent ): buildoutver = 1 except OSError: pass return buildoutver def _get_bootstrap_url(directory): """ Get the most appropriate download URL for the bootstrap script. directory directory to execute in """ v = _get_buildout_ver(directory) return _URL_VERSIONS.get(v, _URL_VERSIONS[DEFAULT_VER]) def _dot_buildout(directory): """ Get the local marker directory. directory directory to execute in """ return os.path.join(os.path.abspath(directory), ".buildout") @_salt_callback def upgrade_bootstrap( directory=".", onlyif=None, unless=None, runas=None, env=(), offline=False, buildout_ver=None, ): """ Upgrade current bootstrap.py with the last released one. Indeed, when we first run a buildout, a common source of problem is to have a locally stale bootstrap, we just try to grab a new copy directory directory to execute in offline are we executing buildout in offline mode buildout_ver forcing to use a specific buildout version (1 | 2) onlyif Only execute cmd if statement on the host return 0 unless Do not execute cmd if statement on the host return 0 CLI Example: .. code-block:: bash salt '*' buildout.upgrade_bootstrap /srv/mybuildout """ if buildout_ver: booturl = _URL_VERSIONS[buildout_ver] else: buildout_ver = _get_buildout_ver(directory) booturl = _get_bootstrap_url(directory) LOG.debug(f"Using {booturl}") # try to download an up-to-date bootstrap # set defaulttimeout # and add possible content directory = os.path.abspath(directory) b_py = os.path.join(directory, "bootstrap.py") comment = "" try: oldcontent = _get_bootstrap_content(directory) dbuild = _dot_buildout(directory) data = oldcontent updated = False dled = False if not offline: try: if not os.path.isdir(dbuild): os.makedirs(dbuild) # only try to download once per buildout checkout with salt.utils.files.fopen( os.path.join(dbuild, f"{buildout_ver}.updated_bootstrap") ): pass except OSError: LOG.info("Bootstrap updated from repository") data = urllib.request.urlopen(booturl).read() updated = True dled = True if "socket.setdefaulttimeout" not in data: updated = True ldata = data.splitlines() ldata.insert(1, "import socket;socket.setdefaulttimeout(2)") data = "\n".join(ldata) if updated: comment = "Bootstrap updated" with salt.utils.files.fopen(b_py, "w") as fic: fic.write(salt.utils.stringutils.to_str(data)) if dled: with salt.utils.files.fopen( os.path.join(dbuild, f"{buildout_ver}.updated_bootstrap"), "w" ) as afic: afic.write("foo") except OSError: if oldcontent: with salt.utils.files.fopen(b_py, "w") as fic: fic.write(salt.utils.stringutils.to_str(oldcontent)) return {"comment": comment} @_salt_callback def bootstrap( directory=".", config="buildout.cfg", python=sys.executable, onlyif=None, unless=None, runas=None, env=(), distribute=None, buildout_ver=None, test_release=False, offline=False, new_st=None, use_vt=False, loglevel=None, ): """ Run the buildout bootstrap dance (python bootstrap.py). directory directory to execute in config alternative buildout configuration file to use runas User used to run buildout as env environment variables to set when running buildout_ver force a specific buildout version (1 | 2) test_release buildout accept test release offline are we executing buildout in offline mode distribute Forcing use of distribute new_st Forcing use of setuptools >= 0.7 python path to a python executable to use in place of default (salt one) onlyif Only execute cmd if statement on the host return 0 unless Do not execute cmd if statement on the host return 0 use_vt Use the new salt VT to stream output [experimental] CLI Example: .. code-block:: bash salt '*' buildout.bootstrap /srv/mybuildout """ directory = os.path.abspath(directory) dbuild = _dot_buildout(directory) bootstrap_args = "" has_distribute = _has_old_distribute(python=python, runas=runas, env=env) has_new_st = _has_setuptools7(python=python, runas=runas, env=env) if has_distribute and has_new_st and not distribute and new_st: new_st = True distribute = False if has_distribute and has_new_st and not distribute and new_st: new_st = True distribute = False if has_distribute and has_new_st and distribute and not new_st: new_st = True distribute = False if has_distribute and has_new_st and not distribute and not new_st: new_st = True distribute = False if not has_distribute and has_new_st and not distribute and new_st: new_st = True distribute = False if not has_distribute and has_new_st and not distribute and new_st: new_st = True distribute = False if not has_distribute and has_new_st and distribute and not new_st: new_st = True distribute = False if not has_distribute and has_new_st and not distribute and not new_st: new_st = True distribute = False if has_distribute and not has_new_st and not distribute and new_st: new_st = True distribute = False if has_distribute and not has_new_st and not distribute and new_st: new_st = True distribute = False if has_distribute and not has_new_st and distribute and not new_st: new_st = False distribute = True if has_distribute and not has_new_st and not distribute and not new_st: new_st = False distribute = True if not has_distribute and not has_new_st and not distribute and new_st: new_st = True distribute = False if not has_distribute and not has_new_st and not distribute and new_st: new_st = True distribute = False if not has_distribute and not has_new_st and distribute and not new_st: new_st = False distribute = True if not has_distribute and not has_new_st and not distribute and not new_st: new_st = True distribute = False if new_st and distribute: distribute = False if new_st: distribute = False LOG.warning("Forcing to use setuptools as we have setuptools >= 0.7") if distribute: new_st = False if buildout_ver == 1: LOG.warning("Using distribute !") bootstrap_args += " --distribute" if not os.path.isdir(dbuild): os.makedirs(dbuild) upgrade_bootstrap(directory, offline=offline, buildout_ver=buildout_ver) # be sure which buildout bootstrap we have b_py = os.path.join(directory, "bootstrap.py") with salt.utils.files.fopen(b_py) as fic: content = salt.utils.stringutils.to_unicode(fic.read()) if (test_release is not False) and " --accept-buildout-test-releases" in content: bootstrap_args += " --accept-buildout-test-releases" if config and '"-c"' in content: bootstrap_args += f" -c {config}" # be sure that the bootstrap belongs to the running user try: if runas: uid = __salt__["user.info"](runas)["uid"] gid = __salt__["user.info"](runas)["gid"] os.chown("bootstrap.py", uid, gid) except OSError as exc: # don't block here, try to execute it if can pass _logger.error( "BUILDOUT bootstrap permissions error: %s", exc, exc_info=_logger.isEnabledFor(logging.DEBUG), ) cmd = f"{python} bootstrap.py {bootstrap_args}" ret = _Popen( cmd, directory=directory, runas=runas, loglevel=loglevel, env=env, use_vt=use_vt ) output = ret["output"] return {"comment": cmd, "out": output} @_salt_callback def run_buildout( directory=".", config="buildout.cfg", parts=None, onlyif=None, unless=None, offline=False, newest=True, runas=None, env=(), verbose=False, debug=False, use_vt=False, loglevel=None, ): """ Run a buildout in a directory. directory directory to execute in config alternative buildout configuration file to use offline are we executing buildout in offline mode runas user used to run buildout as env environment variables to set when running onlyif Only execute cmd if statement on the host return 0 unless Do not execute cmd if statement on the host return 0 newest run buildout in newest mode force run buildout unconditionally verbose run buildout in verbose mode (-vvvvv) use_vt Use the new salt VT to stream output [experimental] CLI Example: .. code-block:: bash salt '*' buildout.run_buildout /srv/mybuildout """ directory = os.path.abspath(directory) bcmd = os.path.join(directory, "bin", "buildout") installed_cfg = os.path.join(directory, ".installed.cfg") argv = [] if verbose: LOG.debug("Buildout is running in verbose mode!") argv.append("-vvvvvvv") if not newest and os.path.exists(installed_cfg): LOG.debug("Buildout is running in non newest mode!") argv.append("-N") if newest: LOG.debug("Buildout is running in newest mode!") argv.append("-n") if offline: LOG.debug("Buildout is running in offline mode!") argv.append("-o") if debug: LOG.debug("Buildout is running in debug mode!") argv.append("-D") cmds, outputs = [], [] if parts: for part in parts: LOG.info(f"Installing single part: {part}") cmd = "{} -c {} {} install {}".format(bcmd, config, " ".join(argv), part) cmds.append(cmd) outputs.append( _Popen( cmd, directory=directory, runas=runas, env=env, output=True, loglevel=loglevel, use_vt=use_vt, ) ) else: LOG.info("Installing all buildout parts") cmd = "{} -c {} {}".format(bcmd, config, " ".join(argv)) cmds.append(cmd) outputs.append( _Popen( cmd, directory=directory, runas=runas, loglevel=loglevel, env=env, output=True, use_vt=use_vt, ) ) return {"comment": "\n".join(cmds), "out": "\n".join(outputs)} def _merge_statuses(statuses): status = BASE_STATUS.copy() status["status"] = None status["merged_statuses"] = True status["out"] = "" for st in statuses: if status["status"] is not False: status["status"] = st["status"] out = st["out"] comment = salt.utils.stringutils.to_unicode(st["comment"]) logs = st["logs"] logs_by_level = st["logs_by_level"] outlog_by_level = st["outlog_by_level"] outlog = st["outlog"] if out: if not status["out"]: status["out"] = "" status["out"] += "\n" status["out"] += HR out = salt.utils.stringutils.to_unicode(out) status["out"] += f"{out}\n" status["out"] += HR if comment: if not status["comment"]: status["comment"] = "" status["comment"] += "\n{}\n".format( salt.utils.stringutils.to_unicode(comment) ) if outlog: if not status["outlog"]: status["outlog"] = "" outlog = salt.utils.stringutils.to_unicode(outlog) status["outlog"] += f"\n{HR}" status["outlog"] += outlog if outlog_by_level: if not status["outlog_by_level"]: status["outlog_by_level"] = "" status["outlog_by_level"] += f"\n{HR}" status["outlog_by_level"] += salt.utils.stringutils.to_unicode( outlog_by_level ) status["logs"].extend( [(a[0], salt.utils.stringutils.to_unicode(a[1])) for a in logs] ) for log in logs_by_level: if log not in status["logs_by_level"]: status["logs_by_level"][log] = [] status["logs_by_level"][log].extend( [salt.utils.stringutils.to_unicode(a) for a in logs_by_level[log]] ) return _encode_status(status) @_salt_callback def buildout( directory=".", config="buildout.cfg", parts=None, runas=None, env=(), buildout_ver=None, test_release=False, distribute=None, new_st=None, offline=False, newest=False, python=sys.executable, debug=False, verbose=False, onlyif=None, unless=None, use_vt=False, loglevel=None, ): """ Run buildout in a directory. directory directory to execute in config buildout config to use parts specific buildout parts to run runas user used to run buildout as env environment variables to set when running buildout_ver force a specific buildout version (1 | 2) test_release buildout accept test release new_st Forcing use of setuptools >= 0.7 distribute use distribute over setuptools if possible offline does buildout run offline python python to use debug run buildout with -D debug flag onlyif Only execute cmd if statement on the host return 0 unless Do not execute cmd if statement on the host return 0 newest run buildout in newest mode verbose run buildout in verbose mode (-vvvvv) use_vt Use the new salt VT to stream output [experimental] CLI Example: .. code-block:: bash salt '*' buildout.buildout /srv/mybuildout """ LOG.info(f"Running buildout in {directory} ({config})") boot_ret = bootstrap( directory, config=config, buildout_ver=buildout_ver, test_release=test_release, offline=offline, new_st=new_st, env=env, runas=runas, distribute=distribute, python=python, use_vt=use_vt, loglevel=loglevel, ) buildout_ret = run_buildout( directory=directory, config=config, parts=parts, offline=offline, newest=newest, runas=runas, env=env, verbose=verbose, debug=debug, use_vt=use_vt, loglevel=loglevel, ) # signal the decorator or our return return _merge_statuses([boot_ret, buildout_ret]) def _check_onlyif_unless(onlyif, unless, directory, runas=None, env=()): ret = None status = BASE_STATUS.copy() if os.path.exists(directory): directory = os.path.abspath(directory) status["status"] = False retcode = __salt__["cmd.retcode"] if onlyif is not None: if not isinstance(onlyif, str): if not onlyif: _valid(status, "onlyif condition is false") elif isinstance(onlyif, str): if retcode(onlyif, cwd=directory, runas=runas, env=env) != 0: _valid(status, "onlyif condition is false") if unless is not None: if not isinstance(unless, str): if unless: _valid(status, "unless condition is true") elif isinstance(unless, str): if ( retcode( unless, cwd=directory, runas=runas, env=env, python_shell=False ) == 0 ): _valid(status, "unless condition is true") if status["status"]: ret = status return ret