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/boto_elasticache.py
""" Connection module for Amazon Elasticache .. versionadded:: 2014.7.0 :configuration: This module accepts explicit elasticache credentials but can also utilize IAM roles assigned to the instance through Instance Profiles. Dynamic credentials are then automatically obtained from AWS API and no further configuration is necessary. More Information available at: .. code-block:: text http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html If IAM roles are not used you need to specify them either in a pillar or in the minion's config file: .. code-block:: yaml elasticache.keyid: GKTADJGHEIQSXMKKRBJ08H elasticache.key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs A region may also be specified in the configuration: .. code-block:: yaml elasticache.region: us-east-1 If a region is not specified, the default is us-east-1. It's also possible to specify key, keyid and region via a profile, either as a passed in dict, or as a string to pull from pillars or minion config: .. code-block:: yaml myprofile: keyid: GKTADJGHEIQSXMKKRBJ08H key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs region: us-east-1 :depends: boto """ # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 import logging import time import salt.utils.odict as odict import salt.utils.versions from salt.exceptions import SaltInvocationError log = logging.getLogger(__name__) try: # pylint: disable=unused-import import boto import boto.elasticache # pylint: enable=unused-import import boto.utils logging.getLogger("boto").setLevel(logging.CRITICAL) HAS_BOTO = True except ImportError: HAS_BOTO = False def __virtual__(): """ Only load if boto libraries exist. """ has_boto_reqs = salt.utils.versions.check_boto_reqs(check_boto3=False) if has_boto_reqs is True: __utils__["boto.assign_funcs"](__name__, "elasticache", pack=__salt__) return has_boto_reqs def exists(name, region=None, key=None, keyid=None, profile=None): """ Check to see if a cache cluster exists. CLI Example: .. code-block:: bash salt myminion boto_elasticache.exists myelasticache """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) try: conn.describe_cache_clusters(name) return True except boto.exception.BotoServerError as e: log.debug(e) return False def group_exists(name, region=None, key=None, keyid=None, profile=None): """ Check to see if a replication group exists. CLI Example: .. code-block:: bash salt myminion boto_elasticache.group_exists myelasticache """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) try: conn.describe_replication_groups(name) return True except boto.exception.BotoServerError as e: log.debug(e) return False def create_replication_group( name, primary_cluster_id, replication_group_description, wait=None, region=None, key=None, keyid=None, profile=None, ): """ Create replication group. CLI Example: .. code-block:: bash salt myminion boto_elasticache.create_replication_group myelasticache myprimarycluster description """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) if not conn: return None try: cc = conn.create_replication_group( name, primary_cluster_id, replication_group_description ) if not wait: log.info("Created cache cluster %s.", name) return True while True: time.sleep(3) config = describe_replication_group(name, region, key, keyid, profile) if not config: return True if config["status"] == "available": return True except boto.exception.BotoServerError as e: msg = f"Failed to create replication group {name}." log.error(msg) log.debug(e) return {} def delete_replication_group(name, region=None, key=None, keyid=None, profile=None): """ Delete an ElastiCache replication group. CLI Example: .. code-block:: bash salt myminion boto_elasticache.delete_replication_group my-replication-group \ region=us-east-1 """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) if not conn: return False try: conn.delete_replication_group(name) msg = f"Deleted ElastiCache replication group {name}." log.info(msg) return True except boto.exception.BotoServerError as e: log.debug(e) msg = f"Failed to delete ElastiCache replication group {name}" log.error(msg) return False def describe_replication_group( name, region=None, key=None, keyid=None, profile=None, parameter=None ): """ Get replication group information. CLI Example: .. code-block:: bash salt myminion boto_elasticache.describe_replication_group mygroup """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) if not conn: return None try: cc = conn.describe_replication_groups(name) except boto.exception.BotoServerError as e: msg = f"Failed to get config for cache cluster {name}." log.error(msg) log.debug(e) return {} ret = odict.OrderedDict() cc = cc["DescribeReplicationGroupsResponse"]["DescribeReplicationGroupsResult"] cc = cc["ReplicationGroups"][0] attrs = [ "status", "description", "primary_endpoint", "member_clusters", "replication_group_id", "pending_modified_values", "primary_cluster_id", "node_groups", ] for key, val in cc.items(): _key = boto.utils.pythonize_name(key) if _key == "status": if val: ret[_key] = val else: ret[_key] = None if _key == "description": if val: ret[_key] = val else: ret[_key] = None if _key == "replication_group_id": if val: ret[_key] = val else: ret[_key] = None if _key == "member_clusters": if val: ret[_key] = val else: ret[_key] = None if _key == "node_groups": if val: ret[_key] = val else: ret[_key] = None if _key == "pending_modified_values": if val: ret[_key] = val else: ret[_key] = None return ret def get_config(name, region=None, key=None, keyid=None, profile=None): """ Get the configuration for a cache cluster. CLI Example: .. code-block:: bash salt myminion boto_elasticache.get_config myelasticache """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) if not conn: return None try: cc = conn.describe_cache_clusters(name, show_cache_node_info=True) except boto.exception.BotoServerError as e: msg = f"Failed to get config for cache cluster {name}." log.error(msg) log.debug(e) return {} cc = cc["DescribeCacheClustersResponse"]["DescribeCacheClustersResult"] cc = cc["CacheClusters"][0] ret = odict.OrderedDict() attrs = [ "engine", "cache_parameter_group", "cache_cluster_id", "cache_security_groups", "replication_group_id", "auto_minor_version_upgrade", "num_cache_nodes", "preferred_availability_zone", "security_groups", "cache_subnet_group_name", "engine_version", "cache_node_type", "notification_configuration", "preferred_maintenance_window", "configuration_endpoint", "cache_cluster_status", "cache_nodes", ] for key, val in cc.items(): _key = boto.utils.pythonize_name(key) if _key not in attrs: continue if _key == "cache_parameter_group": if val: ret[_key] = val["CacheParameterGroupName"] else: ret[_key] = None elif _key == "cache_nodes": if val: ret[_key] = [k for k in val] else: ret[_key] = [] elif _key == "cache_security_groups": if val: ret[_key] = [k["CacheSecurityGroupName"] for k in val] else: ret[_key] = [] elif _key == "configuration_endpoint": if val: ret["port"] = val["Port"] ret["address"] = val["Address"] else: ret["port"] = None ret["address"] = None elif _key == "notification_configuration": if val: ret["notification_topic_arn"] = val["TopicArn"] else: ret["notification_topic_arn"] = None else: ret[_key] = val return ret def get_node_host(name, region=None, key=None, keyid=None, profile=None): """ Get hostname from cache node CLI Example: .. code-block:: bash salt myminion boto_elasticache.get_node_host myelasticache """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) if not conn: return None try: cc = conn.describe_cache_clusters(name, show_cache_node_info=True) except boto.exception.BotoServerError as e: msg = f"Failed to get config for cache cluster {name}." log.error(msg) log.debug(e) return {} cc = cc["DescribeCacheClustersResponse"]["DescribeCacheClustersResult"] host = cc["CacheClusters"][0]["CacheNodes"][0]["Endpoint"]["Address"] return host def get_group_host(name, region=None, key=None, keyid=None, profile=None): """ Get hostname from replication cache group CLI Example: .. code-block:: bash salt myminion boto_elasticache.get_group_host myelasticachegroup """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) if not conn: return None try: cc = conn.describe_replication_groups(name) except boto.exception.BotoServerError as e: msg = f"Failed to get config for cache cluster {name}." log.error(msg) log.debug(e) return {} cc = cc["DescribeReplicationGroupsResponse"]["DescribeReplicationGroupsResult"] cc = cc["ReplicationGroups"][0]["NodeGroups"][0]["PrimaryEndpoint"] host = cc["Address"] return host def get_all_cache_subnet_groups( name=None, region=None, key=None, keyid=None, profile=None ): """ Return a list of all cache subnet groups with details CLI Example: .. code-block:: bash salt myminion boto_elasticache.get_all_subnet_groups region=us-east-1 """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) try: marker = "" groups = [] while marker is not None: ret = conn.describe_cache_subnet_groups( cache_subnet_group_name=name, marker=marker ) trimmed = ret.get("DescribeCacheSubnetGroupsResponse", {}).get( "DescribeCacheSubnetGroupsResult", {} ) groups += trimmed.get("CacheSubnetGroups", []) marker = trimmed.get("Marker", None) if not groups: log.debug("No ElastiCache subnet groups found.") return groups except boto.exception.BotoServerError as e: log.error(e) return [] def list_cache_subnet_groups( name=None, region=None, key=None, keyid=None, profile=None ): """ Return a list of all cache subnet group names CLI Example: .. code-block:: bash salt myminion boto_elasticache.list_subnet_groups region=us-east-1 """ return [ g["CacheSubnetGroupName"] for g in get_all_cache_subnet_groups(name, region, key, keyid, profile) ] def subnet_group_exists( name, tags=None, region=None, key=None, keyid=None, profile=None ): """ Check to see if an ElastiCache subnet group exists. CLI Example: .. code-block:: bash salt myminion boto_elasticache.subnet_group_exists my-param-group \ region=us-east-1 """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) if not conn: return False try: ec = conn.describe_cache_subnet_groups(cache_subnet_group_name=name) if not ec: msg = f"ElastiCache subnet group does not exist in region {region}" log.debug(msg) return False return True except boto.exception.BotoServerError as e: log.debug(e) return False def create_subnet_group( name, description, subnet_ids=None, subnet_names=None, tags=None, region=None, key=None, keyid=None, profile=None, ): """ Create an ElastiCache subnet group CLI example to create an ElastiCache subnet group:: salt myminion boto_elasticache.create_subnet_group my-subnet-group \ "group description" subnet_ids='[subnet-12345678, subnet-87654321]' \ region=us-east-1 """ if not _exactly_one((subnet_ids, subnet_names)): raise SaltInvocationError( "Exactly one of either 'subnet_ids' or 'subnet_names' must be provided." ) conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) if not conn: return False if subnet_group_exists(name, tags, region, key, keyid, profile): return True if subnet_names: subnet_ids = [] for n in subnet_names: r = __salt__["boto_vpc.get_resource_id"]( "subnet", n, region=region, key=key, keyid=keyid, profile=profile ) if "id" not in r: log.error("Couldn't resolve subnet name %s to an ID.", subnet_name) return False subnet_ids += [r["id"]] try: ec = conn.create_cache_subnet_group(name, description, subnet_ids) if not ec: msg = f"Failed to create ElastiCache subnet group {name}" log.error(msg) return False log.info("Created ElastiCache subnet group %s", name) return True except boto.exception.BotoServerError as e: log.debug(e) msg = f"Failed to create ElastiCache subnet group {name}" log.error(msg) return False def get_cache_subnet_group(name, region=None, key=None, keyid=None, profile=None): """ Get information about a cache subnet group. CLI Example: .. code-block:: bash salt myminion boto_elasticache.get_cache_subnet_group mycache_subnet_group """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) try: csg = conn.describe_cache_subnet_groups(name) csg = csg["DescribeCacheSubnetGroupsResponse"] csg = csg["DescribeCacheSubnetGroupsResult"]["CacheSubnetGroups"][0] except boto.exception.BotoServerError as e: msg = f"Failed to get cache subnet group {name}." log.error(msg) log.debug(e) return False except (IndexError, TypeError, KeyError): msg = f"Failed to get cache subnet group {name} (2)." log.error(msg) return False ret = {} for key, val in csg.items(): if key == "CacheSubnetGroupName": ret["cache_subnet_group_name"] = val elif key == "CacheSubnetGroupDescription": ret["cache_subnet_group_description"] = val elif key == "VpcId": ret["vpc_id"] = val elif key == "Subnets": ret["subnets"] = [] for subnet in val: _subnet = {} _subnet["subnet_id"] = subnet["SubnetIdentifier"] _az = subnet["SubnetAvailabilityZone"]["Name"] _subnet["subnet_availability_zone"] = _az ret["subnets"].append(_subnet) else: ret[key] = val return ret def delete_subnet_group(name, region=None, key=None, keyid=None, profile=None): """ Delete an ElastiCache subnet group. CLI Example: .. code-block:: bash salt myminion boto_elasticache.delete_subnet_group my-subnet-group \ region=us-east-1 """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) if not conn: return False try: conn.delete_cache_subnet_group(name) msg = f"Deleted ElastiCache subnet group {name}." log.info(msg) return True except boto.exception.BotoServerError as e: log.debug(e) msg = f"Failed to delete ElastiCache subnet group {name}" log.error(msg) return False def create( name, num_cache_nodes=None, engine=None, cache_node_type=None, replication_group_id=None, engine_version=None, cache_parameter_group_name=None, cache_subnet_group_name=None, cache_security_group_names=None, security_group_ids=None, snapshot_arns=None, preferred_availability_zone=None, preferred_maintenance_window=None, port=None, notification_topic_arn=None, auto_minor_version_upgrade=None, wait=None, region=None, key=None, keyid=None, profile=None, ): """ Create a cache cluster. CLI Example: .. code-block:: bash salt myminion boto_elasticache.create myelasticache 1 redis cache.t1.micro cache_security_group_names='["myelasticachesg"]' """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) try: conn.create_cache_cluster( name, num_cache_nodes, cache_node_type, engine, replication_group_id, engine_version, cache_parameter_group_name, cache_subnet_group_name, cache_security_group_names, security_group_ids, snapshot_arns, preferred_availability_zone, preferred_maintenance_window, port, notification_topic_arn, auto_minor_version_upgrade, ) if not wait: log.info("Created cache cluster %s.", name) return True while True: time.sleep(3) config = get_config(name, region, key, keyid, profile) if not config: return True if config["cache_cluster_status"] == "available": return True log.info("Created cache cluster %s.", name) except boto.exception.BotoServerError as e: msg = f"Failed to create cache cluster {name}." log.error(msg) log.debug(e) return False def delete(name, wait=False, region=None, key=None, keyid=None, profile=None): """ Delete a cache cluster. CLI Example: .. code-block:: bash salt myminion boto_elasticache.delete myelasticache """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) try: conn.delete_cache_cluster(name) if not wait: log.info("Deleted cache cluster %s.", name) return True while True: config = get_config(name, region, key, keyid, profile) if not config: return True if config["cache_cluster_status"] == "deleting": return True time.sleep(2) log.info("Deleted cache cluster %s.", name) return True except boto.exception.BotoServerError as e: msg = f"Failed to delete cache cluster {name}." log.error(msg) log.debug(e) return False def create_cache_security_group( name, description, region=None, key=None, keyid=None, profile=None ): """ Create a cache security group. CLI Example: .. code-block:: bash salt myminion boto_elasticache.create_cache_security_group myelasticachesg 'My Cache Security Group' """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) created = conn.create_cache_security_group(name, description) if created: log.info("Created cache security group %s.", name) return True else: msg = f"Failed to create cache security group {name}." log.error(msg) return False def delete_cache_security_group(name, region=None, key=None, keyid=None, profile=None): """ Delete a cache security group. CLI Example: .. code-block:: bash salt myminion boto_elasticache.delete_cache_security_group myelasticachesg 'My Cache Security Group' """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) deleted = conn.delete_cache_security_group(name) if deleted: log.info("Deleted cache security group %s.", name) return True else: msg = f"Failed to delete cache security group {name}." log.error(msg) return False def authorize_cache_security_group_ingress( name, ec2_security_group_name, ec2_security_group_owner_id, region=None, key=None, keyid=None, profile=None, ): """ Authorize network ingress from an ec2 security group to a cache security group. CLI Example: .. code-block:: bash salt myminion boto_elasticache.authorize_cache_security_group_ingress myelasticachesg myec2sg 879879 """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) try: added = conn.authorize_cache_security_group_ingress( name, ec2_security_group_name, ec2_security_group_owner_id ) if added: msg = "Added {0} to cache security group {1}." msg = msg.format(name, ec2_security_group_name) log.info(msg) return True else: msg = "Failed to add {0} to cache security group {1}." msg = msg.format(name, ec2_security_group_name) log.error(msg) return False except boto.exception.EC2ResponseError as e: log.debug(e) msg = "Failed to add {0} to cache security group {1}." msg = msg.format(name, ec2_security_group_name) log.error(msg) return False def revoke_cache_security_group_ingress( name, ec2_security_group_name, ec2_security_group_owner_id, region=None, key=None, keyid=None, profile=None, ): """ Revoke network ingress from an ec2 security group to a cache security group. CLI Example: .. code-block:: bash salt myminion boto_elasticache.revoke_cache_security_group_ingress myelasticachesg myec2sg 879879 """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) try: removed = conn.revoke_cache_security_group_ingress( name, ec2_security_group_name, ec2_security_group_owner_id ) if removed: msg = "Removed {0} from cache security group {1}." msg = msg.format(name, ec2_security_group_name) log.info(msg) return True else: msg = "Failed to remove {0} from cache security group {1}." msg = msg.format(name, ec2_security_group_name) log.error(msg) return False except boto.exception.EC2ResponseError as e: log.debug(e) msg = "Failed to remove {0} from cache security group {1}." msg = msg.format(name, ec2_security_group_name) log.error(msg) return False