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/timezone.py
""" Module for managing timezone on POSIX-like systems. """ import errno import filecmp import logging import os import re import string import salt.utils.files import salt.utils.hashutils import salt.utils.itertools import salt.utils.path import salt.utils.platform import salt.utils.stringutils from salt.config import DEFAULT_HASH_TYPE from salt.exceptions import CommandExecutionError, SaltInvocationError log = logging.getLogger(__name__) __virtualname__ = "timezone" def __virtual__(): """ Only work on POSIX-like systems """ if salt.utils.platform.is_windows(): return ( False, "The timezone execution module failed to load: " "win_timezone.py should replace this module on Windows." "There was a problem loading win_timezone.py.", ) if salt.utils.platform.is_darwin(): return ( False, "The timezone execution module failed to load: " "mac_timezone.py should replace this module on macOS." "There was a problem loading mac_timezone.py.", ) return __virtualname__ def _timedatectl(): """ get the output of timedatectl """ ret = __salt__["cmd.run_all"](["timedatectl"], python_shell=False) if ret["retcode"] != 0: msg = "timedatectl failed: {}".format(ret["stderr"]) raise CommandExecutionError(msg) return ret def _get_zone_solaris(): tzfile = "/etc/TIMEZONE" with salt.utils.files.fopen(tzfile, "r") as fp_: for line in fp_: line = salt.utils.stringutils.to_unicode(line) if "TZ=" in line: zonepart = line.rstrip("\n").split("=")[-1] return zonepart.strip("'\"") or "UTC" raise CommandExecutionError("Unable to get timezone from " + tzfile) def _get_adjtime_timezone(): """ Return the timezone in /etc/adjtime of the system clock """ adjtime_file = "/etc/adjtime" if os.path.exists(adjtime_file): cmd = ["tail", "-n", "1", adjtime_file] return __salt__["cmd.run"](cmd, python_shell=False) elif os.path.exists("/dev/rtc"): raise CommandExecutionError( "Unable to get hwclock timezone from " + adjtime_file ) else: # There is no RTC. return None def _get_zone_sysconfig(): tzfile = "/etc/sysconfig/clock" with salt.utils.files.fopen(tzfile, "r") as fp_: for line in fp_: line = salt.utils.stringutils.to_unicode(line) if re.match(r"^\s*#", line): continue if "ZONE" in line and "=" in line: zonepart = line.rstrip("\n").split("=")[-1] return zonepart.strip("'\"") or "UTC" raise CommandExecutionError("Unable to get timezone from " + tzfile) def _get_zone_etc_localtime(): tzfile = _get_localtime_path() tzdir = "/usr/share/zoneinfo/" tzdir_len = len(tzdir) try: olson_name = os.path.normpath(os.path.join("/etc", os.readlink(tzfile))) if olson_name.startswith(tzdir): return olson_name[tzdir_len:] except OSError as exc: if exc.errno == errno.ENOENT: if "FreeBSD" in __grains__["os_family"]: return get_zonecode() raise CommandExecutionError(tzfile + " does not exist") elif exc.errno == errno.EINVAL: if "FreeBSD" in __grains__["os_family"]: return get_zonecode() log.warning( "%s is not a symbolic link. Attempting to match it to zoneinfo files.", tzfile, ) # Regular file. Try to match the hash. hash_type = __opts__.get("hash_type", DEFAULT_HASH_TYPE) tzfile_hash = salt.utils.hashutils.get_hash(tzfile, hash_type) # Not a link, just a copy of the tzdata file for root, dirs, files in salt.utils.path.os_walk(tzdir): for filename in files: full_path = os.path.join(root, filename) olson_name = full_path[tzdir_len:] if olson_name[0] in string.ascii_lowercase: continue if tzfile_hash == salt.utils.hashutils.get_hash( full_path, hash_type ): return olson_name raise CommandExecutionError("Unable to determine timezone") def _get_zone_etc_timezone(): tzfile = "/etc/timezone" try: with salt.utils.files.fopen(tzfile, "r") as fp_: return salt.utils.stringutils.to_unicode(fp_.read()).strip() except OSError as exc: raise CommandExecutionError( f"Problem reading timezone file {tzfile}: {exc.strerror}" ) def _get_zone_aix(): tzfile = "/etc/environment" with salt.utils.files.fopen(tzfile, "r") as fp_: for line in fp_: line = salt.utils.stringutils.to_unicode(line) if "TZ=" in line: zonepart = line.rstrip("\n").split("=")[-1] return zonepart.strip("'\"") or "UTC" raise CommandExecutionError("Unable to get timezone from " + tzfile) def get_zone(): """ Get current timezone (i.e. America/Denver) .. versionchanged:: 2016.11.4 .. note:: On AIX operating systems, Posix values can also be returned 'CST6CDT,M3.2.0/2:00:00,M11.1.0/2:00:00' CLI Example: .. code-block:: bash salt '*' timezone.get_zone """ if salt.utils.path.which("timedatectl"): ret = _timedatectl() for line in ( x.strip() for x in salt.utils.itertools.split(ret["stdout"], "\n") ): try: return re.match(r"Time ?zone:\s+(\S+)", line).group(1) except AttributeError: pass raise CommandExecutionError( "Failed to parse timedatectl output: {}\n" "Please file an issue with SaltStack".format(ret["stdout"]) ) else: if __grains__["os"].lower() == "centos": return _get_zone_etc_localtime() os_family = __grains__["os_family"] for family in ("RedHat", "Suse"): if family in os_family: return _get_zone_sysconfig() for family in ("Debian", "Gentoo"): if family in os_family: return _get_zone_etc_timezone() if os_family in ("FreeBSD", "OpenBSD", "NetBSD", "NILinuxRT", "Slackware"): return _get_zone_etc_localtime() elif "Solaris" in os_family: return _get_zone_solaris() elif "AIX" in os_family: return _get_zone_aix() raise CommandExecutionError("Unable to get timezone") def get_zonecode(): """ Get current timezone (i.e. PST, MDT, etc) CLI Example: .. code-block:: bash salt '*' timezone.get_zonecode """ return __salt__["cmd.run"](["date", "+%Z"], python_shell=False) def get_offset(): """ Get current numeric timezone offset from UTC (i.e. -0700) CLI Example: .. code-block:: bash salt '*' timezone.get_offset """ if "AIX" not in __grains__["os_family"]: return __salt__["cmd.run"](["date", "+%z"], python_shell=False) salt_path = "/opt/salt/bin/date" if not os.path.exists(salt_path): return f"date in salt binaries does not exist: {salt_path}" return __salt__["cmd.run"]([salt_path, "+%z"], python_shell=False) def set_zone(timezone): """ Unlinks, then symlinks /etc/localtime to the set timezone. The timezone is crucial to several system processes, each of which SHOULD be restarted (for instance, whatever you system uses as its cron and syslog daemons). This will not be automagically done and must be done manually! CLI Example: .. code-block:: bash salt '*' timezone.set_zone 'America/Denver' .. versionchanged:: 2016.11.4 .. note:: On AIX operating systems, Posix values are also allowed, see below .. code-block:: bash salt '*' timezone.set_zone 'CST6CDT,M3.2.0/2:00:00,M11.1.0/2:00:00' """ if salt.utils.path.which("timedatectl"): try: __salt__["cmd.run"](f"timedatectl set-timezone {timezone}") except CommandExecutionError: pass if "Solaris" in __grains__["os_family"] or "AIX" in __grains__["os_family"]: zonepath = f"/usr/share/lib/zoneinfo/{timezone}" else: zonepath = f"/usr/share/zoneinfo/{timezone}" if not os.path.exists(zonepath) and "AIX" not in __grains__["os_family"]: return f"Zone does not exist: {zonepath}" tzfile = _get_localtime_path() if os.path.exists(tzfile): os.unlink(tzfile) if "Solaris" in __grains__["os_family"]: __salt__["file.sed"]("/etc/default/init", "^TZ=.*", f"TZ={timezone}") elif "AIX" in __grains__["os_family"]: # timezone could be Olson or Posix curtzstring = get_zone() cmd = ["chtz", timezone] result = __salt__["cmd.retcode"](cmd, python_shell=False) if result == 0: return True # restore orig timezone, since AIX chtz failure sets UTC cmd = ["chtz", curtzstring] __salt__["cmd.retcode"](cmd, python_shell=False) return False else: os.symlink(zonepath, tzfile) if "RedHat" in __grains__["os_family"]: __salt__["file.sed"]("/etc/sysconfig/clock", "^ZONE=.*", f'ZONE="{timezone}"') elif "Suse" in __grains__["os_family"]: __salt__["file.sed"]( "/etc/sysconfig/clock", "^TIMEZONE=.*", f'TIMEZONE="{timezone}"' ) elif "Debian" in __grains__["os_family"] or "Gentoo" in __grains__["os_family"]: with salt.utils.files.fopen("/etc/timezone", "w") as ofh: ofh.write(salt.utils.stringutils.to_str(timezone).strip()) ofh.write("\n") return True def zone_compare(timezone): """ Compares the given timezone name with the system timezone name. Checks the hash sum between the given timezone, and the one set in /etc/localtime. Returns True if names and hash sums match, and False if not. Mostly useful for running state checks. .. versionchanged:: 2016.3.0 .. note:: On Solaris-like operating systems only a string comparison is done. .. versionchanged:: 2016.11.4 .. note:: On AIX operating systems only a string comparison is done. CLI Example: .. code-block:: bash salt '*' timezone.zone_compare 'America/Denver' """ if "Solaris" in __grains__["os_family"] or "AIX" in __grains__["os_family"]: return timezone == get_zone() if "Arch" in __grains__["os_family"] or "FreeBSD" in __grains__["os_family"]: if not os.path.isfile(_get_localtime_path()): return timezone == get_zone() tzfile = _get_localtime_path() zonepath = _get_zone_file(timezone) try: return filecmp.cmp(tzfile, zonepath, shallow=False) except OSError as exc: problematic_file = exc.filename if problematic_file == zonepath: raise SaltInvocationError(f'Can\'t find a local timezone "{timezone}"') elif problematic_file == tzfile: raise CommandExecutionError( "Failed to read {} to determine current timezone: {}".format( tzfile, exc.strerror ) ) raise def _get_localtime_path(): if ( "NILinuxRT" in __grains__["os_family"] and "nilrt" in __grains__["lsb_distrib_id"] ): return "/etc/natinst/share/localtime" return "/etc/localtime" def _get_zone_file(timezone): return f"/usr/share/zoneinfo/{timezone}" def get_hwclock(): """ Get current hardware clock setting (UTC or localtime) CLI Example: .. code-block:: bash salt '*' timezone.get_hwclock """ if salt.utils.path.which("timedatectl"): ret = _timedatectl() for line in (x.strip() for x in ret["stdout"].splitlines()): if "rtc in local tz" in line.lower(): try: if line.split(":")[-1].strip().lower() == "yes": return "localtime" else: return "UTC" except IndexError: pass raise CommandExecutionError( "Failed to parse timedatectl output: {}\n" "Please file an issue with SaltStack".format(ret["stdout"]) ) else: os_family = __grains__["os_family"] for family in ("RedHat", "Suse", "NILinuxRT"): if family in os_family: return _get_adjtime_timezone() if "Debian" in __grains__["os_family"]: # Original way to look up hwclock on Debian-based systems try: with salt.utils.files.fopen("/etc/default/rcS", "r") as fp_: for line in fp_: line = salt.utils.stringutils.to_unicode(line) if re.match(r"^\s*#", line): continue if "UTC=" in line: is_utc = line.rstrip("\n").split("=")[-1].lower() if is_utc == "yes": return "UTC" else: return "localtime" except OSError as exc: pass # Since Wheezy return _get_adjtime_timezone() if "Gentoo" in __grains__["os_family"]: if not os.path.exists("/etc/adjtime"): offset_file = "/etc/conf.d/hwclock" try: with salt.utils.files.fopen(offset_file, "r") as fp_: for line in fp_: line = salt.utils.stringutils.to_unicode(line) if line.startswith("clock="): line = line.rstrip("\n") line = line.split("=")[-1].strip("'\"") if line == "UTC": return line if line == "local": return "LOCAL" raise CommandExecutionError( f"Correct offset value not found in {offset_file}" ) except OSError as exc: raise CommandExecutionError( "Problem reading offset file {}: {}".format( offset_file, exc.strerror ) ) return _get_adjtime_timezone() if "Solaris" in __grains__["os_family"]: offset_file = "/etc/rtc_config" try: with salt.utils.files.fopen(offset_file, "r") as fp_: for line in fp_: line = salt.utils.stringutils.to_unicode(line) if line.startswith("zone_info=GMT"): return "UTC" return "localtime" except OSError as exc: if exc.errno == errno.ENOENT: # offset file does not exist return "UTC" raise CommandExecutionError( "Problem reading offset file {}: {}".format( offset_file, exc.strerror ) ) if "AIX" in __grains__["os_family"]: offset_file = "/etc/environment" try: with salt.utils.files.fopen(offset_file, "r") as fp_: for line in fp_: line = salt.utils.stringutils.to_unicode(line) if line.startswith("TZ=UTC"): return "UTC" return "localtime" except OSError as exc: if exc.errno == errno.ENOENT: # offset file does not exist return "UTC" raise CommandExecutionError( "Problem reading offset file {}: {}".format( offset_file, exc.strerror ) ) if "Slackware" in __grains__["os_family"]: if not os.path.exists("/etc/adjtime"): offset_file = "/etc/hardwareclock" try: with salt.utils.files.fopen(offset_file, "r") as fp_: for line in fp_: line = salt.utils.stringutils.to_unicode(line) if line.startswith("UTC"): return "UTC" return "localtime" except OSError as exc: if exc.errno == errno.ENOENT: return "UTC" return _get_adjtime_timezone() def set_hwclock(clock): """ Sets the hardware clock to be either UTC or localtime CLI Example: .. code-block:: bash salt '*' timezone.set_hwclock UTC """ if salt.utils.path.which("timedatectl"): cmd = [ "timedatectl", "set-local-rtc", "true" if clock == "localtime" else "false", ] return __salt__["cmd.retcode"](cmd, python_shell=False) == 0 else: os_family = __grains__["os_family"] if os_family in ("AIX", "NILinuxRT"): if clock.lower() != "utc": raise SaltInvocationError("UTC is the only permitted value") return True timezone = get_zone() if "Solaris" in __grains__["os_family"]: if clock.lower() not in ("localtime", "utc"): raise SaltInvocationError( "localtime and UTC are the only permitted values" ) if "sparc" in __grains__["cpuarch"]: raise SaltInvocationError( "UTC is the only choice for SPARC architecture" ) cmd = ["rtc", "-z", "GMT" if clock.lower() == "utc" else timezone] return __salt__["cmd.retcode"](cmd, python_shell=False) == 0 zonepath = f"/usr/share/zoneinfo/{timezone}" if not os.path.exists(zonepath): raise CommandExecutionError(f"Zone '{zonepath}' does not exist") os.unlink("/etc/localtime") os.symlink(zonepath, "/etc/localtime") if "Arch" in __grains__["os_family"]: cmd = [ "timezonectl", "set-local-rtc", "true" if clock == "localtime" else "false", ] return __salt__["cmd.retcode"](cmd, python_shell=False) == 0 elif "RedHat" in __grains__["os_family"]: __salt__["file.sed"]( "/etc/sysconfig/clock", "^ZONE=.*", f'ZONE="{timezone}"' ) elif "Suse" in __grains__["os_family"]: __salt__["file.sed"]( "/etc/sysconfig/clock", "^TIMEZONE=.*", f'TIMEZONE="{timezone}"', ) elif "Debian" in __grains__["os_family"]: if clock == "UTC": __salt__["file.sed"]("/etc/default/rcS", "^UTC=.*", "UTC=yes") elif clock == "localtime": __salt__["file.sed"]("/etc/default/rcS", "^UTC=.*", "UTC=no") elif "Gentoo" in __grains__["os_family"]: if clock not in ("UTC", "localtime"): raise SaltInvocationError("Only 'UTC' and 'localtime' are allowed") if clock == "localtime": clock = "local" __salt__["file.sed"]("/etc/conf.d/hwclock", "^clock=.*", f'clock="{clock}"') elif "Slackware" in os_family: if clock not in ("UTC", "localtime"): raise SaltInvocationError("Only 'UTC' and 'localtime' are allowed") __salt__["file.sed"]("/etc/hardwareclock", "^(UTC|localtime)", f"{clock}") return True