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/syslog_ng.py
""" Module for getting information about syslog-ng :maintainer: Tibor Benke <btibi@sch.bme.hu> :maturity: new :depends: cmd :platform: all This module is capable of managing syslog-ng instances which were installed via a package manager or from source. Users can use a directory as a parameter in the case of most functions, which contains the syslog-ng and syslog-ng-ctl binaries. Syslog-ng can be installed via a package manager or from source. In the latter case, the syslog-ng and syslog-ng-ctl binaries are not available from the PATH, so users should set location of the sbin directory with :mod:`syslog_ng.set_binary_path <salt.modules.syslog_ng.set_binary_path>`. Similarly, users can specify the location of the configuration file with :mod:`syslog_ng.set_config_file <salt.modules.syslog_ng.set_config_file>`, then the module will use it. If it is not set, syslog-ng uses the default configuration file. """ import logging import os import os.path import time import salt import salt.utils.files import salt.utils.path from salt.exceptions import CommandExecutionError __SYSLOG_NG_BINARY_PATH = None __SYSLOG_NG_CONFIG_FILE = "/etc/syslog-ng.conf" __SALT_GENERATED_CONFIG_HEADER = """#Generated by Salt on {0}""" class SyslogNgError(Exception): pass log = logging.getLogger(__name__) log.setLevel(logging.DEBUG) # Don't shadow built-in's. __func_alias__ = {"reload_": "reload"} _INDENT = "" _INDENT_STEP = " " # These are needed during building of the configuration tree _current_statement = None _current_option = None _current_parameter = None _current_parameter_value = None def _increase_indent(): """ Increases the indentation level. """ global _INDENT _INDENT += _INDENT_STEP def _decrease_indent(): """ Decreases the indentation level. """ global _INDENT _INDENT = _INDENT[4:] def _indent(value): """ Returns the indented parameter. """ return f"{_INDENT}{value}" def _indentln(string): """ Return the indented parameter with newline. """ return _indent(string + "\n") class Buildable: """ Base class of most classes, which have a build method. It contains a common build function. Does not need examples. """ def __init__(self, iterable, join_body_on="", append_extra_newline=True): self.iterable = iterable self.join_body_on = join_body_on self.append_extra_newline = append_extra_newline def build_header(self): """ Builds the header of a syslog-ng configuration object. """ return "" def build_tail(self): """ Builds the tail of a syslog-ng configuration object. """ return "" def build_body(self): """ Builds the body of a syslog-ng configuration object. """ _increase_indent() body_array = [x.build() for x in self.iterable] nl = "\n" if self.append_extra_newline else "" if len(self.iterable) >= 1: body = self.join_body_on.join(body_array) + nl else: body = "" _decrease_indent() return body def build(self): """ Builds the textual representation of the whole configuration object with its children. """ header = self.build_header() body = self.build_body() tail = self.build_tail() return header + body + tail class Statement(Buildable): """ It represents a syslog-ng configuration statement, e.g. source, destination, filter. Does not need examples. """ def __init__(self, type, id="", options=None, has_name=True): super().__init__(options, join_body_on="", append_extra_newline=False) self.type = type self.id = id self.options = options if options else [] self.iterable = self.options self.has_name = has_name def build_header(self): if self.has_name: return _indentln(f"{self.type} {self.id} {{") else: return _indentln(f"{self.type} {{") def build_tail(self): return _indentln("};") def add_child(self, option): self.options.append(option) class NamedStatement(Statement): """ It represents a configuration statement, which has a name, e.g. a source. Does not need examples. """ def __init__(self, type, id="", options=None): super().__init__(type, id, options, has_name=True) class UnnamedStatement(Statement): """ It represents a configuration statement, which doesn't have a name, e.g. a log path. Does not need examples. """ def __init__(self, type, options=None): super().__init__(type, id="", options=options, has_name=False) class GivenStatement(Buildable): """ This statement returns a string without modification. It can be used to use existing configuration snippets. Does not need examples. """ def __init__(self, value, add_newline=True): super().__init__(iterable=None) self.value = value self.add_newline = add_newline def build(self): if self.add_newline: return self.value + "\n" else: return self.value class Option(Buildable): """ A Statement class contains Option instances. An instance of Option can represent a file(), tcp(), udp(), etc. option. Does not need examples. """ def __init__(self, type="", params=None): super().__init__(params, ",\n") self.type = type self.params = params if params else [] self.iterable = self.params def build(self): header = _indentln(f"{self.type}(") tail = _indentln(");") body = self.build_body() return header + body + tail def add_parameter(self, param): self.params.append(param) class Parameter(Buildable): """ An Option has one or more Parameter instances. Does not need examples. """ def __init__(self, iterable=None, join_body_on=""): super().__init__(iterable, join_body_on) class SimpleParameter(Parameter): """ A Parameter is a SimpleParameter, if it's just a simple type, like a string. For example: .. code-block:: text destination d_file { file( '/var/log/messages' ); }; ``/var/log/messages`` is a SimpleParameter. Does not need examples. """ def __init__(self, value=""): super().__init__() self.value = value def build(self): return _indent(self.value) class TypedParameter(Parameter): """ A Parameter, which has a type: .. code-block:: text destination d_tcp { tcp( ip(127.0.0.1) ); }; ``ip(127.0.0.1)`` is a TypedParameter. Does not need examples. """ def __init__(self, type="", values=None): super().__init__(values, ",\n") self.type = type self.values = values if values else [] self.iterable = self.values def build(self): header = _indentln(f"{self.type}(") tail = _indent(")") body = self.build_body() return header + body + tail def add_value(self, value): self.values.append(value) class ParameterValue(Buildable): """ A TypedParameter can have one or more values. Does not need examples. """ def __init__(self, iterable=None, join_body_on=""): super().__init__(iterable, join_body_on) class SimpleParameterValue(ParameterValue): """ A ParameterValuem which holds a simple type, like a string or a number. For example in ip(127.0.0.1) 127.0.0.1 is a SimpleParameterValue. Does not need examples. """ def __init__(self, value=""): super().__init__() self.value = value def build(self): return _indent(self.value) class TypedParameterValue(ParameterValue): """ We have to go deeper... A TypedParameter can have a 'parameter', which also have a type. For example key_file and cert_file: .. code-block:: text source demo_tls_source { tcp( ip(0.0.0.0) port(1999) tls( key_file('/opt/syslog-ng/etc/syslog-ng/key.d/syslog-ng.key') cert_file('/opt/syslog-ng/etc/syslog-ng/cert.d/syslog-ng.cert') ) ); }; Does not need examples. """ def __init__(self, type="", arguments=None): super().__init__(arguments, "\n") self.type = type self.arguments = arguments if arguments else [] self.iterable = self.arguments def build(self): header = _indentln(f"{self.type}(") tail = _indent(")") body = self.build_body() return header + body + tail def add_argument(self, arg): self.arguments.append(arg) class Argument: """ A TypedParameterValue has one or more Arguments. For example this can be the value of key_file. Does not need examples. """ def __init__(self, value=""): self.value = value def build(self): return _indent(self.value) def _is_statement_unnamed(statement): """ Returns True, if the given statement is an unnamed statement, like log or junction. """ return statement in ("log", "channel", "junction", "options") def _is_simple_type(value): """ Returns True, if the given parameter value is an instance of either int, str, float or bool. """ return ( isinstance(value, str) or isinstance(value, int) or isinstance(value, float) or isinstance(value, bool) ) def _get_type_id_options(name, configuration): """ Returns the type, id and option of a configuration object. """ # it's in a form of source.name if "." in name: type_, sep, id_ = name.partition(".") options = configuration else: type_ = next(iter(configuration.keys())) id_ = name options = configuration[type_] return type_, id_, options def _expand_one_key_dictionary(_dict): """ Returns the only one key and its value from a dictionary. """ key = next(iter(_dict.keys())) value = _dict[key] return key, value def _parse_typed_parameter_typed_value(values): """ Creates Arguments in a TypedParametervalue. """ type_, value = _expand_one_key_dictionary(values) _current_parameter_value.type = type_ if _is_simple_type(value): arg = Argument(value) _current_parameter_value.add_argument(arg) elif isinstance(value, list): for idx in value: arg = Argument(idx) _current_parameter_value.add_argument(arg) def _parse_typed_parameter(param): """ Parses a TypedParameter and fills it with values. """ global _current_parameter_value type_, value = _expand_one_key_dictionary(param) _current_parameter.type = type_ if _is_simple_type(value) and value != "": _current_parameter_value = SimpleParameterValue(value) _current_parameter.add_value(_current_parameter_value) elif isinstance(value, list): for i in value: if _is_simple_type(i): _current_parameter_value = SimpleParameterValue(i) _current_parameter.add_value(_current_parameter_value) elif isinstance(i, dict): _current_parameter_value = TypedParameterValue() _parse_typed_parameter_typed_value(i) _current_parameter.add_value(_current_parameter_value) def _create_and_add_parameters(params): """ Parses the configuration and creates Parameter instances. """ global _current_parameter if _is_simple_type(params): _current_parameter = SimpleParameter(params) _current_option.add_parameter(_current_parameter) else: # must be a list for i in params: if _is_simple_type(i): _current_parameter = SimpleParameter(i) else: _current_parameter = TypedParameter() _parse_typed_parameter(i) _current_option.add_parameter(_current_parameter) def _create_and_add_option(option): """ Parses the configuration and creates an Option instance. """ global _current_option _current_option = Option() type_, params = _expand_one_key_dictionary(option) _current_option.type = type_ _create_and_add_parameters(params) _current_statement.add_child(_current_option) def _parse_statement(options): """ Parses the configuration and creates options the statement. """ for option in options: _create_and_add_option(option) def _is_reference(arg): """ Return True, if arg is a reference to a previously defined statement. """ return ( isinstance(arg, dict) and len(arg) == 1 and isinstance(next(iter(arg.values())), str) ) def _is_junction(arg): """ Return True, if arg is a junction statement. """ return ( isinstance(arg, dict) and len(arg) == 1 and next(iter(arg.keys())) == "junction" ) def _add_reference(reference, statement): """ Adds a reference to statement. """ type_, value = _expand_one_key_dictionary(reference) opt = Option(type_) param = SimpleParameter(value) opt.add_parameter(param) statement.add_child(opt) def _is_inline_definition(arg): """ Returns True, if arg is an inline definition of a statement. """ return ( isinstance(arg, dict) and len(arg) == 1 and isinstance(next(iter(arg.values())), list) ) def _add_inline_definition(item, statement): """ Adds an inline definition to statement. """ global _current_statement backup = _current_statement type_, options = _expand_one_key_dictionary(item) _current_statement = UnnamedStatement(type=type_) _parse_statement(options) statement.add_child(_current_statement) _current_statement = backup def _add_junction(item): """ Adds a junction to the _current_statement. """ type_, channels = _expand_one_key_dictionary(item) junction = UnnamedStatement(type="junction") for item in channels: type_, value = _expand_one_key_dictionary(item) channel = UnnamedStatement(type="channel") for val in value: if _is_reference(val): _add_reference(val, channel) elif _is_inline_definition(val): _add_inline_definition(val, channel) junction.add_child(channel) _current_statement.add_child(junction) def _parse_log_statement(options): """ Parses a log path. """ for i in options: if _is_reference(i): _add_reference(i, _current_statement) elif _is_junction(i): _add_junction(i) elif _is_inline_definition(i): _add_inline_definition(i, _current_statement) def _build_config_tree(name, configuration): """ Build the configuration tree. The root object is _current_statement. """ type_, id_, options = _get_type_id_options(name, configuration) global _INDENT, _current_statement _INDENT = "" if type_ == "config": _current_statement = GivenStatement(options) elif type_ == "log": _current_statement = UnnamedStatement(type="log") _parse_log_statement(options) else: if _is_statement_unnamed(type_): _current_statement = UnnamedStatement(type=type_) else: _current_statement = NamedStatement(type=type_, id=id_) _parse_statement(options) def _render_configuration(): """ Renders the configuration tree into syslog-ng's configuration syntax. """ text_repr = _current_statement.build() _INDENT = "" return text_repr def config(name, config, write=True): """ Builds syslog-ng configuration. This function is intended to be used from the state module, users should not use it directly! name : the id of the Salt document or it is the format of <statement name>.id config : the parsed YAML code write : if True, it writes the config into the configuration file, otherwise just returns it CLI Example: .. code-block:: bash salt '*' syslog_ng.config name='s_local' config="[{'tcp':[{'ip':'127.0.0.1'},{'port':1233}]}]" """ _build_config_tree(name, config) configs = _render_configuration() if __opts__.get("test", False): comment = "State syslog_ng will write '{}' into {}".format( configs, __SYSLOG_NG_CONFIG_FILE ) return _format_state_result(name, result=None, comment=comment) succ = write if write: succ = _write_config(config=configs) return _format_state_result(name, result=succ, changes={"new": configs, "old": ""}) def set_binary_path(name): """ Sets the path, where the syslog-ng binary can be found. This function is intended to be used from states. If syslog-ng is installed via a package manager, users don't need to use this function. CLI Example: .. code-block:: bash salt '*' syslog_ng.set_binary_path name=/usr/sbin """ global __SYSLOG_NG_BINARY_PATH old = __SYSLOG_NG_BINARY_PATH __SYSLOG_NG_BINARY_PATH = name changes = _format_changes(old, name) return _format_state_result(name, result=True, changes=changes) def set_config_file(name): """ Sets the configuration's name. This function is intended to be used from states. CLI Example: .. code-block:: bash salt '*' syslog_ng.set_config_file name=/etc/syslog-ng """ global __SYSLOG_NG_CONFIG_FILE old = __SYSLOG_NG_CONFIG_FILE __SYSLOG_NG_CONFIG_FILE = name changes = _format_changes(old, name) return _format_state_result(name, result=True, changes=changes) def get_config_file(): """ Returns the configuration directory, which contains syslog-ng.conf. CLI Example: .. code-block:: bash salt '*' syslog_ng.get_config_file """ return __SYSLOG_NG_CONFIG_FILE def _run_command(cmd, options=(), env=None): """ Runs the command cmd with options as its CLI parameters and returns the result as a dictionary. """ params = [cmd] params.extend(options) return __salt__["cmd.run_all"](params, env=env, python_shell=False) def _determine_config_version(syslog_ng_sbin_dir): ret = version(syslog_ng_sbin_dir) full_version = ret["stdout"] dot_count = 0 for idx, part in enumerate(full_version): if part == ".": dot_count = dot_count + 1 if dot_count == 2: return full_version[0:idx] # return first 3 characters return full_version[:3] def set_parameters(version=None, binary_path=None, config_file=None, *args, **kwargs): """ Sets variables. CLI Example: .. code-block:: bash salt '*' syslog_ng.set_parameters version='3.6' salt '*' syslog_ng.set_parameters binary_path=/home/user/install/syslog-ng/sbin config_file=/home/user/install/syslog-ng/etc/syslog-ng.conf """ if binary_path: set_binary_path(binary_path) if config_file: set_config_file(config_file) if version: version = _determine_config_version(__SYSLOG_NG_BINARY_PATH) write_version(version) return _format_return_data(0) def _run_command_in_extended_path(syslog_ng_sbin_dir, command, params): """ Runs the specified command with the syslog_ng_sbin_dir in the PATH """ orig_path = os.environ.get("PATH", "") env = None if syslog_ng_sbin_dir: # Custom environment variables should be str types. This code # normalizes the paths to unicode to join them together, and then # converts back to a str type. env = { "PATH": salt.utils.stringutils.to_str( os.pathsep.join(salt.utils.data.decode((orig_path, syslog_ng_sbin_dir))) ) } return _run_command(command, options=params, env=env) def _format_return_data(retcode, stdout=None, stderr=None): """ Creates a dictionary from the parameters, which can be used to return data to Salt. """ ret = {"retcode": retcode} if stdout is not None: ret["stdout"] = stdout if stderr is not None: ret["stderr"] = stderr return ret def config_test(syslog_ng_sbin_dir=None, cfgfile=None): """ Runs syntax check against cfgfile. If syslog_ng_sbin_dir is specified, it is added to the PATH during the test. CLI Example: .. code-block:: bash salt '*' syslog_ng.config_test salt '*' syslog_ng.config_test /home/user/install/syslog-ng/sbin salt '*' syslog_ng.config_test /home/user/install/syslog-ng/sbin /etc/syslog-ng/syslog-ng.conf """ params = ["--syntax-only"] if cfgfile: params.append(f"--cfgfile={cfgfile}") try: ret = _run_command_in_extended_path(syslog_ng_sbin_dir, "syslog-ng", params) except CommandExecutionError as err: return _format_return_data(retcode=-1, stderr=str(err)) retcode = ret.get("retcode", -1) stderr = ret.get("stderr", None) stdout = ret.get("stdout", None) return _format_return_data(retcode, stdout, stderr) def version(syslog_ng_sbin_dir=None): """ Returns the version of the installed syslog-ng. If syslog_ng_sbin_dir is specified, it is added to the PATH during the execution of the command syslog-ng. CLI Example: .. code-block:: bash salt '*' syslog_ng.version salt '*' syslog_ng.version /home/user/install/syslog-ng/sbin """ try: ret = _run_command_in_extended_path(syslog_ng_sbin_dir, "syslog-ng", ("-V",)) except CommandExecutionError as err: return _format_return_data(retcode=-1, stderr=str(err)) if ret["retcode"] != 0: return _format_return_data( ret["retcode"], stderr=ret["stderr"], stdout=ret["stdout"] ) lines = ret["stdout"].split("\n") # The format of the first line in the output is: # syslog-ng 3.6.0alpha0 version_line_index = 0 version_column_index = 1 line = lines[version_line_index].split()[version_column_index] return _format_return_data(0, stdout=line) def modules(syslog_ng_sbin_dir=None): """ Returns the available modules. If syslog_ng_sbin_dir is specified, it is added to the PATH during the execution of the command syslog-ng. CLI Example: .. code-block:: bash salt '*' syslog_ng.modules salt '*' syslog_ng.modules /home/user/install/syslog-ng/sbin """ try: ret = _run_command_in_extended_path(syslog_ng_sbin_dir, "syslog-ng", ("-V",)) except CommandExecutionError as err: return _format_return_data(retcode=-1, stderr=str(err)) if ret["retcode"] != 0: return _format_return_data(ret["retcode"], ret.get("stdout"), ret.get("stderr")) lines = ret["stdout"].split("\n") for line in lines: if line.startswith("Available-Modules"): label, installed_modules = line.split() return _format_return_data(ret["retcode"], stdout=installed_modules) return _format_return_data(-1, stderr="Unable to find the modules.") def stats(syslog_ng_sbin_dir=None): """ Returns statistics from the running syslog-ng instance. If syslog_ng_sbin_dir is specified, it is added to the PATH during the execution of the command syslog-ng-ctl. CLI Example: .. code-block:: bash salt '*' syslog_ng.stats salt '*' syslog_ng.stats /home/user/install/syslog-ng/sbin """ try: ret = _run_command_in_extended_path( syslog_ng_sbin_dir, "syslog-ng-ctl", ("stats",) ) except CommandExecutionError as err: return _format_return_data(retcode=-1, stderr=str(err)) return _format_return_data(ret["retcode"], ret.get("stdout"), ret.get("stderr")) def _format_changes(old="", new=""): return {"old": old, "new": new} def _format_state_result(name, result, changes=None, comment=""): """ Creates the state result dictionary. """ if changes is None: changes = {"old": "", "new": ""} return {"name": name, "result": result, "changes": changes, "comment": comment} def _add_cli_param(params, key, value): """ Adds key and value as a command line parameter to params. """ if value is not None: params.append(f"--{key}={value}") def _add_boolean_cli_param(params, key, value): """ Adds key as a command line parameter to params. """ if value is True: params.append(f"--{key}") def stop(name=None): """ Kills syslog-ng. This function is intended to be used from the state module. Users shouldn't use this function, if the service module is available on their system. If :mod:`syslog_ng.set_config_file <salt.modules.syslog_ng.set_binary_path>` is called before, this function will use the set binary path. CLI Example: .. code-block:: bash salt '*' syslog_ng.stop """ pids = __salt__["ps.pgrep"](pattern="syslog-ng") if not pids: return _format_state_result( name, result=False, comment="Syslog-ng is not running" ) if __opts__.get("test", False): comment = "Syslog_ng state module will kill {0} pids" return _format_state_result(name, result=None, comment=comment) res = __salt__["ps.pkill"]("syslog-ng") killed_pids = res["killed"] if killed_pids == pids: changes = {"old": killed_pids, "new": []} return _format_state_result(name, result=True, changes=changes) else: return _format_state_result(name, result=False) def start( name=None, user=None, group=None, chroot=None, caps=None, no_caps=False, pidfile=None, enable_core=False, fd_limit=None, verbose=False, debug=False, trace=False, yydebug=False, persist_file=None, control=None, worker_threads=None, ): """ Ensures, that syslog-ng is started via the given parameters. This function is intended to be used from the state module. Users shouldn't use this function, if the service module is available on their system. If :mod:`syslog_ng.set_config_file <salt.modules.syslog_ng.set_binary_path>`, is called before, this function will use the set binary path. CLI Example: .. code-block:: bash salt '*' syslog_ng.start """ params = [] _add_cli_param(params, "user", user) _add_cli_param(params, "group", group) _add_cli_param(params, "chroot", chroot) _add_cli_param(params, "caps", caps) _add_boolean_cli_param(params, "no-capse", no_caps) _add_cli_param(params, "pidfile", pidfile) _add_boolean_cli_param(params, "enable-core", enable_core) _add_cli_param(params, "fd-limit", fd_limit) _add_boolean_cli_param(params, "verbose", verbose) _add_boolean_cli_param(params, "debug", debug) _add_boolean_cli_param(params, "trace", trace) _add_boolean_cli_param(params, "yydebug", yydebug) _add_cli_param(params, "cfgfile", __SYSLOG_NG_CONFIG_FILE) _add_boolean_cli_param(params, "persist-file", persist_file) _add_cli_param(params, "control", control) _add_cli_param(params, "worker-threads", worker_threads) if __SYSLOG_NG_BINARY_PATH: syslog_ng_binary = os.path.join(__SYSLOG_NG_BINARY_PATH, "syslog-ng") command = [syslog_ng_binary] + params if __opts__.get("test", False): comment = f"Syslog_ng state module will start {command}" return _format_state_result(name, result=None, comment=comment) result = __salt__["cmd.run_all"](command, python_shell=False) else: command = ["syslog-ng"] + params if __opts__.get("test", False): comment = f"Syslog_ng state module will start {command}" return _format_state_result(name, result=None, comment=comment) result = __salt__["cmd.run_all"](command, python_shell=False) if result["pid"] > 0: succ = True else: succ = False return _format_state_result( name, result=succ, changes={"new": " ".join(command), "old": ""} ) def reload_(name): """ Reloads syslog-ng. This function is intended to be used from states. If :mod:`syslog_ng.set_config_file <salt.modules.syslog_ng.set_binary_path>`, is called before, this function will use the set binary path. CLI Example: .. code-block:: bash salt '*' syslog_ng.reload """ if __SYSLOG_NG_BINARY_PATH: syslog_ng_ctl_binary = os.path.join(__SYSLOG_NG_BINARY_PATH, "syslog-ng-ctl") command = [syslog_ng_ctl_binary, "reload"] result = __salt__["cmd.run_all"](command, python_shell=False) else: command = ["syslog-ng-ctl", "reload"] result = __salt__["cmd.run_all"](command, python_shell=False) succ = True if result["retcode"] == 0 else False return _format_state_result(name, result=succ, comment=result["stdout"]) def _format_generated_config_header(): """ Formats a header, which is prepended to all appended config. """ now = time.strftime("%Y-%m-%d %H:%M:%S") return __SALT_GENERATED_CONFIG_HEADER.format(now) def write_config(config, newlines=2): """ Writes the given parameter config into the config file. This function is intended to be used from states. If :mod:`syslog_ng.set_config_file <salt.modules.syslog_ng.set_config_file>`, is called before, this function will use the set config file. CLI Example: .. code-block:: bash salt '*' syslog_ng.write_config config='# comment' """ succ = _write_config(config, newlines) changes = _format_changes(new=config) return _format_state_result(name="", result=succ, changes=changes) def _write_config(config, newlines=2): """ Writes the given parameter config into the config file. """ text = config if isinstance(config, dict) and len(list(list(config.keys()))) == 1: key = next(iter(config.keys())) text = config[key] try: with salt.utils.files.fopen(__SYSLOG_NG_CONFIG_FILE, "a") as fha: fha.write(salt.utils.stringutils.to_str(text)) for _ in range(0, newlines): fha.write(salt.utils.stringutils.to_str(os.linesep)) return True except Exception as err: # pylint: disable=broad-except log.error(str(err)) return False def write_version(name): """ Removes the previous configuration file, then creates a new one and writes the name line. This function is intended to be used from states. If :mod:`syslog_ng.set_config_file <salt.modules.syslog_ng.set_config_file>`, is called before, this function will use the set config file. CLI Example: .. code-block:: bash salt '*' syslog_ng.write_version name="3.6" """ line = f"@version: {name}" try: if os.path.exists(__SYSLOG_NG_CONFIG_FILE): log.debug( "Removing previous configuration file: %s", __SYSLOG_NG_CONFIG_FILE ) os.remove(__SYSLOG_NG_CONFIG_FILE) log.debug("Configuration file successfully removed") header = _format_generated_config_header() _write_config(config=header, newlines=1) _write_config(config=line, newlines=2) return _format_state_result(name, result=True) except OSError as err: log.error( "Failed to remove previous configuration file '%s': %s", __SYSLOG_NG_CONFIG_FILE, err, ) return _format_state_result(name, result=False)