From 53a3fa048e1dca98c1ffa34e95b98b7f086daa42 Mon Sep 17 00:00:00 2001 From: Jay Kumar <70096901+35C4n0r@users.noreply.github.com> Date: Mon, 13 Jan 2025 18:47:00 +0530 Subject: [PATCH] feat: Amazon SQS Provider (#3002) Signed-off-by: 35C4n0r Co-authored-by: Tal --- README.md | 30 +- docs/mint.json | 1 + .../documentation/amazonsqs-provider.mdx | 64 ++++ docs/providers/overview.mdx | 8 + keep-ui/public/icons/amazonsqs-icon.png | Bin 0 -> 15248 bytes keep/providers/amazonsqs_provider/__init__.py | 0 .../amazonsqs_provider/amazonsqs_provider.py | 359 ++++++++++++++++++ pyproject.toml | 2 +- 8 files changed, 451 insertions(+), 13 deletions(-) create mode 100644 docs/providers/documentation/amazonsqs-provider.mdx create mode 100644 keep-ui/public/icons/amazonsqs-icon.png create mode 100644 keep/providers/amazonsqs_provider/__init__.py create mode 100644 keep/providers/amazonsqs_provider/amazonsqs_provider.py diff --git a/README.md b/README.md index f36a8593a..60039ab21 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,12 @@ + + + - - + + - - - + + + - -
+ + AmazonSQS
+ Amazon SQS +
+
AppDynamics
@@ -96,14 +102,14 @@ Checkmk
Cilium
Cilium
CloudWatch
@@ -134,14 +140,14 @@ Elastic
GCP Monitoring
GCP Monitoring
Grafana
@@ -172,12 +178,6 @@ New Relic
- - OpenObserve
- OpenObserve -
-
@@ -218,6 +218,12 @@
+ + OpenObserve
+ OpenObserve +
+
Site24x7
@@ -248,14 +254,14 @@ UptimeKuma
VictoriaMetrics
VictoriaMetrics
Zabbix
diff --git a/docs/mint.json b/docs/mint.json index 373398997..1ee51f5c0 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -111,6 +111,7 @@ "group": "Supported Providers", "pages": [ "providers/documentation/aks-provider", + "providers/documentation/amazonsqs-provider", "providers/documentation/appdynamics-provider", "providers/documentation/argocd-provider", "providers/documentation/auth0-provider", diff --git a/docs/providers/documentation/amazonsqs-provider.mdx b/docs/providers/documentation/amazonsqs-provider.mdx new file mode 100644 index 000000000..c636cf766 --- /dev/null +++ b/docs/providers/documentation/amazonsqs-provider.mdx @@ -0,0 +1,64 @@ +--- +title: "AmazonSQS Provider" +sidebarTitle: "AmazonSQS Provider" +description: "The AmazonSQS provider enables you to pull & push alerts to the Amazon SQS Queue." +--- + +## Overview + +The **AmazonSQS Provider** facilitates +Consuming SQS messages as alerts +Notifying/Pushing messages to SQS Queue + +## Authentication Parameters + +- **Access Key Id** (required): Access Key ID generated from your IAM. +- **Secret Access Key** (required): The secret corresponding to the above key-id. +- **Region Name** (required): The region of your data center eg. us-east-1, ap-sout-1, etc. +- **SQS Queue URL** (required): The url for the SQS Queue. + + +## Scopes + +- **authenticated**: Mandatory for all operations, ensures the user is authenticated. +- **sqs::read**: Mandatory for getting alerts, ensures user can read from the Queue. +- **sqs::write**: Mandatory **only** for Notifying/Pushing messages to queue, ensures user can write to Queue. + +If you only want to give read scope to your key-secret pair the permission policy: AmazonSQSReadOnlyAccess +If you only want to give read & write scope to your key-secret pair the permission policy: AmazonSQSFullAccess +Both are the policies are prebuilt in AWS. + +## Inputs for AmazonSQS Action + +- `message`: str: Body/Message for the notification +- `group_id`: str | None: Mandatory only if Queue is of type FIFO, ignored incase of a normal Queue. +- `dedup_id`: str | None: Mandatory only if Queue is of type FIFO, ignored incase of a normal Queue. +- **kwargs: dict | None: You can pass additional key-value pairs, that will be sent as MessageAttributes in the notification. + +## Output for AmazonSQS Action +For more detail, visit [sqs-documentation](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sqs/client/send_message.html#). + ```json + { + 'MD5OfMessageBody': 'string', + 'MD5OfMessageAttributes': 'string', + 'MD5OfMessageSystemAttributes': 'string', + 'MessageId': 'string', + 'SequenceNumber': 'string' + } + ``` + + + - When using the AmazonSQS action, if your queue is fifo, then it is **mandatory** to pass a dedup_id & group_id. + - All the extra fields present in the MessageAttribute is stored in alert.label as a key-value pair dictionary. + - You can pass these attributes in the SQS Queue message and keep will extract and use these field for the alert + - name + - status: Possible values 'firing' | 'resolved' | 'acknowledged' | 'suppressed' | 'pending' defaults to 'firing'. + - severity: Possible values 'critical' | 'high' | 'warning' | 'info' | 'low' defaults to 'high' + - description + + + +## Useful Links + +- [AmazonSQS Boto3 Examples](https://docs.aws.amazon.com/code-library/latest/ug/python_3_sqs_code_examples.html) +- [Boto3 SQS Documentation](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sqs.html) diff --git a/docs/providers/overview.mdx b/docs/providers/overview.mdx index 30c9b523e..8d8b0d7de 100644 --- a/docs/providers/overview.mdx +++ b/docs/providers/overview.mdx @@ -116,6 +116,14 @@ By leveraging Keep Providers, users are able to deeply integrate Keep with the t } /> + + } +> + XDn+SLQE5`d z0!TS@kuC_RlpwwL-tOV|-1oiDpZAY^PIh;8cIG?VXZDe?kuEdSVI}|on9u3ym;wL_ z`HKP=(8#Ceoyd0pKm*1GW@q;I_h&WzJ476&)qQ)!Z#D2)b{=#3E$Q-C%C%p{?U&fC zCX!9vVT)0vd&3HzZNheq0+e}j;GmrQq^kFjock{^rxszmN>1}C?rXzJo-HJs9&wkB zV-ABdZZ!mp8p5@4W$z&c_cjr`#Zy7$hc5R^xps;zVd=T|$`yoN75ZkKgkEoj{8AD{GoJ(*Opl3Cj#=CnPxvKaSe$Rc{Z z@z0n|+* zTqiC?jYIDTRqwZnIdw?6Op^T0R{z0364`4+N4@2mn9=&gp2IdHstjo^>kp+T)tnXUluA(~zh# zow&o*cD=1%qV?OM(CL$vKK)t5gPk{-s6EmZu#)>CoRcP)f*Lq<5srmp$Y3S!k~NJ!2YRr+^ZgQ>Udy>4 z7$jJUYKOpEL^h#1$muv%B-WPvdJezwnG2~3!3@HJvlrg`{A2Jm-X6LRi2rXMd^fOV+0o!>gy_{P`~m}+AH8)>mUQYd*kN4* zS>@Qm*G=&R8!>bl%D4gONTtxUN!3uuf;H4@WSsPW>oJmNjf@qzBVujHp1m?~1Nip; zHfROhB9gwaMkLsgGo9Kk@WvIa1mQY}mDwJcdV2}XmOsU4T@7#*{-1`7rEfE_#b8d! z!_|e5)7gmAfGq*?y=h7g3Cnd0_OcD4vdH`=Q6H*(i<2!9b4nKeSqMoB)Xtza72-g# zt3{}-b2<-A@p=XBl5BmGuA3$7+0R&F1fkW}E#-CZ?2Gm(O;OKpJ6Nm{Laz&GN zNpTwz62B16h~$cLP@n{JlEo63Z37niLwE6RII=uiSm9EHi1|rw!t2sgAq2EK9qA*h zF)uFUf+o481ZMk#Utpp}T1v8MZUUFaQFl5VpcsJDHfZ4oJzF#5;ToV4$gD#l&3ngF zjM@oUItH>VH^X~>Xvzb;whdALD~)3{4v-?B5dAI$jGB}Dr_g4pxc0}GViff-(og`D z?E&6W(Ix}gg=FPXv_Tw42#QL;g`elR2xQej)xk@ zp|iWq;RyXPhyMkFsw&!Dm0CBknNR-TLQfo-72CTCX18IY`suyt$Z6mgEAnayRHdSw z4{XVE;>-u6DK3&U4nVCC8r?-<$LV%a6jAPiGAp>(pG*dFYf%a7I6?{so(W3*uMu01 zU_P+m5YD_$n&M^@D*=450ncw^qM8^{U;)DLk2Hm1#Kt_8FM)Qc1cnE!6`W$z@CCal z7r*fR5pHM>Uoed(tg*b&-d%NoW_c*T)n<-C0|yj%zi^EhAb?2O#+a|M_%X^v44K2# zf#4DM;0j&fTOky>iwYZ|+ohwN@%Kcm?5z-3$TuQb)xh)o^U8-;PHgwj;B^?(H11Ho6C=obXQnR-;h8gAkRhfV;N z_yhPW4ZpZgSe>*LIZ(oRz`E;wOx1yi20r2as0rH{O?VAgFv7pa0J|Lk-0U4*j%0_K z!)ek~U88nUfTIq@y^f2G#_XVE3=bp(7E>r>;N7DG(~weG8JJ*^La1&RReONv3y}kb zAWsBONOMe?N3Wo~hK>l(QJx)eB+H00U?`9O`zt5wLh*kPl}bSOI-WpgMhaxQ)njwaFIpqK$zrTV}!umSxlpw}rRU0{eE*Sm~~8>K5jF(m$HLXs#09h*QQq+vxqXT-)tNPrxP?8mCPBfSqmNCU6!pcubSOLf_iMkPEppa1FqTQi_G!wxLt zjfuFF)X%y4N(>MDW6 zg-c2QCXFE$pAE1g96KO=&T0EP0JtaWou$N2EdThv-w01XUyuyQj{T;m*aST|{!RAO zWPh^iF~^;O@(XF|SIfK?qeL&P&Gmm(cm8A(;$lv~4p_5-26e!ICT&IY_hi~9S;Z?! zQ$~rYdTbz1>V~Y{wvjR?!OxRfHR-f ze0%9ndf!{nxhFj*^^1kTWp019s=fhhLGYOY0&9ZDcBg2!uWLZ2xNP8)_T|5WR-4+` z8$T=4DGu{8j~Aso>rk)mR32Hc?(^#C7%w?v^W#!2!$De@>cvyO(v7Sx<{z<7b{2;VlcW{uHvooz$j=XM{D; z-MQQ`Z4IuaBO1h|z0;zDw6))g|NaI^Ot*~jk1@b_d?vTXqDNN>I{cyU7WPgXn<2MD zcT%%jvnbGsH}^O_^DWWWns#x%_;i92%~sd+r^MK~bK8 z^!I7f%kl4bo!W>=G91z^Dcm03;fr*XDDdmTc%Y)aK{N5z%djVg@1zt$?-PyyV}t^Z zjW%W5Y23H8MGfL}oY-v{g+TaEuMKR0Kc+E{J&3m-f+U(uw5 zW^siR>=V6;6df}$+p-Tfc$ddf6aDwEI*`{pO^Q9f=4|G+5VuBY`EG9~FFvr_wSZ3m zVZ`3 zS>|tLuw2+U{&Q4=80Aj@vXpUhG>W6Q^6Fjoqy_DKTichf8I)94Y~veHVsg(eVL7dh z0>*cFhdsjn#Zbf}67%<&i;#8Vk==8!|D?>XH0GH$;$aIhJVPbnbJ}ln_%whew)cyd z?Q^guS+^Sd|1%isK6-z5I;tKefGTK!(peer?1tDPk62yh)gktC8^>?+fl@~SGdDU|ocszE&pM9I`bQbT*v z_EM&C@kLf_|DuO@j47$(Yuu4goxZ$=FqaDsFKKQC}OY%wg-k)MG4ojzmf z$1_Tsii`!>9y}egd1-I<>q7(po-skwvNf7 zDtnm4_>*mR=Gb5VMK-Ju9f-Fh3*>j`j{}G%Udy=J!I7IgC|->-vM4GH44|pEj>f-y zQ#yt|H0*Q6CR*_2#PP?kg(u}HEb~7VOkb#EKhUJ0@;g1d1Gs%3zs?lkN0LkHp|9loL<;Zi{el^QQf1fz#n#b6b^ha2hN=N=|EOAh<6;2^Bl{3 zwFwL;QAad)H&L#rc6+kBRGIklGv*YPTW*?ACG!jI2Nh5<;7N2NSU$I{Z{d3z%UaCL zF%W&E%kha1Bl#)Ff2qLc)>~_N-J2ume-2A)YX7GoafqwLwyW7he-oyQUk3!!x2 z6QLb{AL7a9mG_9V)TAjHFiMMOs5|4&sN9sJZE1RAy_;fRzTsR3?=H%}m9IYAfYL@8 zTf-+8Zl#pE!p$Z>5WDnl$&E7fm(;j|?Y3k&zT((bgZ-CpR(4TkdK3{P-vUKwgYGdv zDrcMd-&qQ>eI@MuDx&X9QJdicj$$ps!+}(!!~vF;0TZQ@Fy=dT0^WTG73yPtAQ4LAI!;mKn(%75Tu`$ zH7C(mUNliZmf9b-g;`V3cxiI~lp>nRdJuYf_b%ren3hVq0@TaVRO!gyrYfo{9)0Z0 zd9sY-^nD`maxljMXr?zR7v$m573GH6VFETc_=!S(&a6aP=f1jOvSXYT?H)D4r|25i zrHxG((wBrROyUSYOx>SfYh10#KW>UzM_7@pS;tRY$gu|$qNHB1=>~ywsepUQgbanr z040j>YMvFJFxTjV%xQe<>iK7HOBV3Aaw!vaAA$m?;!GJzyNNmdyVCrHBZ22lQf-5l z3yA(du6{0r&-Gr=lxp?HZZMET!Da1}vANUPev!-dkDuJ=`QR++c2ByER%Ccvlcq8w zRv{D3gtlB|fKX_P7ENsmp}YO{_x+V9i~}RKnlrnV9u{6q8do6DjzEj}2|(ac);EF7 zxf4<;lI|1FEDPcOx?pVk-vH^Y~jr*XNur!m7d~PNDP6{nJ zq}>A8(ReoE9J@N3oiHgBUKFmqjImk zY`xg%)Zd4+lr=ltu*gB&R>#SO*j=v2VV-E9XfImBRz53FUli&TTMeV+; z<@URroRd~*#r{F3_i$#Zq*0y?@U66FwPMV%!%aXs;3PvjuCx}qne)AwmoGM@FE-dL zPdaX2pI^2TuI}F%TdJ2sW(QR~N!4RTPR`|tM!uDn_Cq2Y8^DESOHolJsocr7Mk#-A z*3v#rL}r9dqRj8i?aB*-fx%&N&=H_Wp0r7GdPrBGyS|C4mqiYOo$@qs{LaO5{R^BE z*2H{2Ep7C{!S)`OkM65~N0m?b&rgE^4NHa>s)jI0_TS629})lzQVgp;Oucc#XI5A7 zF6qO&dpC4yFH+x_)Hm}gM1bnxL<5wu)o?!YvVrP7C)4Y73HEQdWN6&qF?_4u;oo?9 zV!Sd-w{5SD53GuW50Q)Vy(R^Xiwo}6Z>01+d)8+%obJE<%l8cd=7BWvFCJ_-apfm{ z`CP7$ppFJ|bVoM(hkdN10u@fNujB6dmrJ?H(TNjyQbh-}Xq(kU^(U%)TI!oq73_F6 z21p&PAEQ-kH4=GVjX|EuRd%i&=emHf`F zKFc#Y_qVV#Z!v4zPE0U`rACxY{2dsKbIwS+@Ww%Osu_p^^yH|477-11emrJ*jR*e1 zU9N=!!uX)$gM3g07$Xluk=aF(z+WzpB8)j1U1mH=D>F zW-ky(js@F2%Zhk{0)rEQ>RSPCt3|dLxs9F|sr9$N7DX4JNVQO!?9x38mE}fR3g9+x zajgA9!C((%_+zV;RCY-^O}fqg`!~(3lU{a!C7?ra(_hLfOTfvkqE;C(MLBmVek9dv6UpkJSwPIBYVW#No+o)Ik$D0{s; zzUnJWHUO>>jRQ@t{v4gqIEA11F@g!chHx6L1NQ#re@LfTM}M5YxO6fVnGV;wAA&vZ z@$dRo=hGRX-tDE1T*+chu6ntP_$mWQgiY|sSLo(ub&3Sr`|H1ml&BxZ?&EC zdlBwP-p3X&ZXkD+K+d!`9fKUrRqE80xgSmRDO?g1!#R!FID zyv^xGY3_=pfq~EN$Km0EU)LM#8&HE8LMz5mAXPHsn)8+4iZr}+veQ1Y#_q4kUEPF4 zd$;|p*Jg{-o(Co5bH`MlVHoD{qCmPp2(f_9w&iN!Q$J0<<^JI})g;;5ZwxU0!<#o` zu@L%|;WfX=#GqSl9ebcxMP-rESxt)4G2Sm5_h?Q|v(o$Pw2g#!XR7yay<^z~@_`6B zs-+t${qkKyb0N70;pEYy{2w_No?K89#shDI)IQxy$V1mbHX1rVP>wi`wy+=cE*uu= zGcW(j<`rH8k9FRA-p05^M}7tdGsA_x20?nw`PelEBgVfYDY#sw0(2YDt|+GKeCMvr z;M;Q<;ool<<$ui85LyC*>EN){4W_5nH-j5=gzsWEFyv@(ho1ar$j0SAE}CNhwBZg8 zUQ;kfx$>bsd>Ov{VHpEkd@B*w(8+_eyr0`?Ql$2`{P&+bJ!yB*l)S}pPM$;pO!1ip z;~M=5<&h^2Eq5~t&}QibLe=@hDue8S3H}n(VSmsqtpgGz^Uo{IY6zvVDmOVRCTzYj zi|>6}xwJREn$d>skPdrh58t)qO&zoGkAIPGv>+=z@si{9DLa7}qB0hezHR%!5N}=+ zP&wo8BKS&9n|Ar5u7co##(ebL(>xBBp@4Mm=Xva>DmO4DSk9X655IXM3oqH63%WLR zX(2i~E|=Z6{b^%mHvtR8^zs|ZpIy?vEX1?DTN!!NB<`}GKsxJ&nz|5wp_&~Jv6!n_ zQpDm&NZ=ywHNF=mUHh#4bG5owTb%hhtU;9ofNTdAa=VorokaC6+iWwWRt9O*X$7^= z`?tuy49nxPWT+I9r+hP4+j+K z@fMc6Ebf{Wu+XGp@6pE(^FaM{MGQSmesqX+Ru>MNaW^gCx*l$o&G-r33Oy}P!}rYh zXWi~5IBA-RcAt0QopX^Mo$}Gvq_X*^>ZW^N4YQ)C`Pa@IyDow3WRGK&h1wEpb$%@3 ztE{eZRZFw+A}9Bf{XFvDTv=${q)pzFb;ct)%rlC@S->R&MaGHWUdFOk*#I3C)$AU38+dUJi%TGlQ!L5H+|LI zx)t75LlF}Z%Z9}bWJ4iQK^a`c8{@n?3o6RAvU8sj&5Z#%0xcI9-(D)Op$6vm`^`^R zJ~clRj7x2@hGpj}i{IWH6Fd3g=~ND9ZW^w;C&&xK!@9TXDI>UWLb*SFo*z5jARply zu7YZBhQ4Ro?(jhdSm-w8=@lS{v-|l7a;82<3dp%RCv%cm311OYHlesL@3Y*(TAKaTg0|_6E=d3i4Ob*AgrtB_ zJa9a8v;r+Wiqcy?N>{8+E`7EKQgb$ZpK0iLquT2s)47I}jEr!GuL>fDpMhgOjIsFY zAE`nPG3Ui;Qp%a8CjhhYmnz9{05!_==V?2%G>b?BPyu|BA>Go{Vu)=4*s$ux5|BkY z0H-aTpZq=ilc|_47dM3|=tV;uWFvjw2x#LUL!;&?6zF74mKU2x*wFDY^z&w#0+V4h%goc?i9-S(}_(U3Gtz0vjNTmQ(SJ$alxuwEA0P{-MLs^UTelc z?bihcjulk;Vj)A?o4{L)GN>X(Nt2(tP9m-xdLf`Pn0X1xImBlnF>z#t|74)S`n~5D zrJ!KPf$jY^5@OiqdBQVzkkGpIw{d?z>&}5>vYDZx3#8(k6KxvuR ze*F+H15@MWOb&QL9vl}dKJA#{5EE_&k+^bGfa5u6CGZ7P!r=KC2}|)8lnW*+*Pk%~ zD!scVAN?K$o%ijNfPNmGJL*nQxEkx7ugbB)^6qsnSKDuh4&xg%SYjT& zJ&*%XXW?F9o#>I)s@^YhDD=E!?CH58`9dJ>@A(;(4UapAW+jk2bXg4i3>GNarDKJr zmq>P2Lk>ZA<=(uU7NExn^&EAK2{#2K8J;GoMoKf39B!Eva_3QIxHY=Q5u#{)LT8)F z4@1@mTcg+-DU#?ti3J8r{O{|0%e!~5b9Y@oDPHrPa}z@vkXd~6d~eqAV#!(|_<^$(H{ z&cC+hj|{#+d|Sk}vo+BBrN3&0bwM3-`0P+L;QVHDmu~+ifA2B7l=#jIZnK`|+(!2* z5NDtrCy)+0JxU1-E)e&(iyG93zC!-KJ^117_j&*zh#$lPyk}Ji3rSIv%!2Mw@a&VK z$~-5ZQ|&HPjPKQ0+7zfXGplHvaTFfnfcVhC2cpG>p2=E$MJ!;SOZ}?XN_fPT@Gv2F z`iOnQ<$}1L~hl!8kQSN{ec^tw5v50O#K%u4lLch;Y)bf%!U)Z$;3Ln{aG*aAF#c$f@8J{35JqX71j_xLx?izpSHr?nc#+;NXSWN*wvO z*FPrn?}Lkhycc}C30v|vF=k75Zms>a+3BhL7@V%w@>JegG7}2^srf=muHal;SxL=5 zCP25zP&hTC+bvlq{!GN`p=ELESvPZUR6bOMYPi|$@vo@9J^h>ntf*UX)VH|#xDNSe zkf-*)PrBV@+LfqxiT_H!t1H(0&m_9zN`51vvVku zx!=Xu1BAmMYbOuqf5DB{|f!oWzczi(XN%B+a7MCL=KX=4W(?t!_V2Xn>OVGDdFvfWs{z- zu7IKrExA?9e>1P<)HIv0f(X+J{bthBr}3ALD(PiVE%ur_jvi-KtElk{*A`Z`Pn`KZ zY{LYE``_0=P9BYCGFS65{rF^PdA$Wt*Rw*~2D`^QO|qfB&3vnx2NH^2_c=2j?0eKB zTrl!p{0$}njU~sJNLfI={aT%xzLH(n>Tn9nc{y6G=V*`Un=^?eHJYf{%kW3ew-2lw zmsPsPRx|(F0S=Tm)h}CcNk zw%-0n4-BxG9kZ>Ez+-nhRYQ*)kz1Qk@KYxPKbf3bjhEKB;^^ z`l z_4W0~9n zFyQhzR`$<$vUGWdJX-w_BAr^rzt=ovzb8{~H~5LC8Vzi^W!%Fy(+~bSm)5ngTL0RD z-n8iF_3=@kgSp>IB1uCk986;#>igAsb}S*PRkHC$p#50SUrV3S_gCUp*i4#$m7nLg zheAN;cH~n(oToX;L%Mj;czjl0K!XX{${^G<~3IPdll8FPKzH*4kv4_jW?V7U_ zwEQeipkH&~ZJ-OlSvmL($WLJN`$64qI|EdiBX)a8pz%Oe+kgh4{pqbZpxp?WkB)T7 zk!{wLuVU%wC?s@-V@!?%Y+o~{b@=ZIkG0}I=A^0ubCMV!ju*S}PoxeS;~b`g=2qf& zIT_e-&Dr%@m_v9QKoOUuAETk6q#X z94%==rDlI{=VBA*ei8jqDUp$L;j#55kO$!H$(spA7Xn?go;Pb!vU1hZ68K*m-CbQwu~>&QA`v4v3j%UHSae6q%R#m=n-F99pE?`WV@ID_q6af#4~kz4v?=; zz4oOkK!)wLChcm^OSKPIg}B^|9-(T91xJj_KKb&-`vaViEIyN-v2@c2RS4hbIXZuN zt+=MeV&84z@T>UQ4?ji2Bc&QILpqXfi8+5wJdTf`y-_m3V4gG0yZFdzlY!0xMPL>*cA0nO=dLEsXbQ&KLM~->XN|t*{!`LnC0h>y3J~ z{*UkRJp`O&*gKB@D$v)JgcO6&)cKiP{3*D<(pmf z#Tbe@I)!Saux%NK#nOB~X(b8E`dq`H`=+^F4aikhQmchz1u=O&KmE6w@Dap=SAe;P z?Ql~nHYh%mT&i#x85OEnk@Z`(I-xn=x*AY2*glE7av8Roumn&;G-gZ-#6A9%&ddb5 zeNyOJ@wtSb(4YJBON8O%`O;Fe22?@Sf`Fx!^}{7l6C|_(<`pGp0s;VJ@z7v<{Q%;| zu4D_;T!G(8ox#&)(C`Ywr#?Sbigy5H1)P_2aFzhXMQ;=_UJmpgmSz{PGrwoW@(6pa*^&` zegXR?5Di4xLmZlAi7J=msOsiSDId?c3JMwGClrrvBt+L&{NQAZz_eDuqf&YQ(dQxb zFi0rT&CcZ#C~i)FMJ&__6g_?$?_>@?LB)&1H9`KF`z;$4)mX%sk%GoH5XN#QBdm!t= zzN6|YdYCT}7#9-)tCR7%kwuC=6p1IC}XMniT8}ULF z9zzRuWX(G+Gs;`LbPo|)NMOJ_*SWR8p3ITo(R>lfRY6f}fkbEeJ5Z*)0TI?hla~n- zqTjiI6WBOMrcUjl@6h=&OEkyT2_*W991cqDJthCy$#k=W+m37+I+!Eb81f^q)hKQB z<4VT@r#OyoS4;13B+r{##^j%CU9g1{trqsqB1NAMisoftVDB_=!Yk~r zCN=8)A|{bxjk_n7l{{ZogSZC=#X|Ua-&99}7kmWj<8B2bwMLMuVM-7; z(F2o-dTm5ge%uBf44_kXZVs!xt_}t7vpJy2o~^N4{>ZrQBGTM%49Dzbxt$5cpeshc z%Brs3sU62>wbE022CPHC>f1>8p^F1{rN8lxq~|BWMU~T2%izT4o?dI9aN0`|ty4^Xyuo~zw?lGxAvAjqFf9+^vi5I+5RI=3tp#i@qLRhmU`X}!t zWmV9J-!1Xt6TK!?Jj@m~f%0{M^Z4TW`PQ^AwO#lZa!GBUQcGL;E~Ozzl{c`VE%MS7 zsxHE{g%Gswbn*VzJb7KN2Gm4(8xkktoH<=cUCp^^8`)l2(?lsaN=~9Y%pKt(dD{@d zZ)4Q3ypO8e7$jKs5BP zn1okh+&Qf049xsu&(y>5X234$6smv=7pGNy2M;L%bN#%+uZ>4PX{nJRBe9 z{d-gVyFDg}XbbBDyBDz zy?+Pg4;IuzucUg~?JpJQB=5Z-VhtLr0^m49I>)GqF&?sDWrG4*UA#E#F9T^MGn^5d zYY}v&EBIEmN7%|DjvAxokPHgol_d(8$j|dS9N^U(?>`m_-X78ah!8CON01ImB|0;% z2}OPsy<%z)udd-|#`Uwj&jxnCkV4jie8HkN;J$*}2M*St?8f*mg3Lsd1=AkwClJf)VB^o7&K*A-a{{m|459 zYx>paq3Q;vo%ha*5O7ZQm2mj?GZ#)|pNs>2p3CcKGOB(t?RohoV;42?WWBitNX*%M z+UvFduh+JQAhYlOrMKbxi}%ybCP+x|NwB#F8ju>l+u6b6miq9w)ypQ2&ZEzKqZWf5eWfBpTuD9rTPJ#x&VvlfbO*cN;n;+vT3 z)5DBV^&U_)B2=U9CvYdgke{Obb6I9p(0tO@88Nqzz+KtpJXSgPHD&8cAQ2d|fpk$C zse0YlWL)=y#`H^&ZT!9B+anBDr7eC2?gqUoYB;xzDW;R*MfWke-R2u7%O%i$38eY z=VWFU_jN1X{8{`IbBQHX`kA}u4|I)V497YS*&(_kvv~aZ^RYihjkhDSZZ98i77(51 zp>e=*c(;<2n3#7YbkFy-8)gnM&)0F@7>X}KpXYa7;IQYq{Ntp_W`Uj>X_5$Zj>tCp z`0-SU#oO)vHci!W?HQ74QN!v2ZUaLJ#1`XDS+u6T#;6YLvWK(8btY@%MOq=}lOj3N zkDQ<DojZa0Ms*+QJso4FM|fZkxC`+V zxR+X(#5aix9Ad(M{F4yZnXZxd+zOI_koP3vXp`0-X>XrrD+De_CV0xo`dLU@iK%5|_gWXa`L!0tHjPzz){ zFl57lKq=2nzO(0OE>E)ChxFDEjSu6fCkH<%p>28*6`dua0sqcF_z1hewc?6Gz;~J1 zS)LTO`g>Tl0f{~{PXeF1vuf+-R4=|jPm;t5wE*YqQ2!2yADIK92X!A~+C}gD!6T1uAkEEM2PobaTxk?l zLg(@wbl3l$^XMWX=JMjG>sp0G%BVR|zF*M-NFb~8?)q)4xe7OVzVfC#{G$+=W)Ri> zzj}!WN#28AEDwMDzltM0R33g^NRB-yCF1A~lFtf}VTvRPIJbjja3LUqh}u+#GCs)V z!7UtsWmAaQ7)f&D7!H!Ah0uScTsRs7l03Byq#OX}BnXKf)Rh4afJ?9jwpId?!OITF z_u~Kl{s+8dGZ1r7DG{^;5r`y_=LHBfmk^IM!tphpfdRo!kqBvSbs@kUe82ziFA@&b z0^sD4qg*oBZ4X^J5bhuj2Vocw1|BdJL!%BD8e;!POFZp>Ar}$mI;bcI9HdqcB4XrW zcRY;|N&PyAT4@0yWyz!irZ)ehVjU9yfiQi9cz+P4Z0PoJ!Qc1-IpmxE_kVx;4jQvY zLXZ%KrO3l3grPl=#(^-*If(p0tZk3n^drV>L>?|744;8~2MmSL#RnC&vA{t}0Nrk- w`IShq$5JbI>i*MrZ;9ssy8l0rZS3zh{QO*hcj685tPnVN#z-gc6ealo0W17)8vp dict[str, bool | str]: + self.logger.info("Validating user scopes for AmazonSQS provider") + scopes = { + "authenticated": False, + "sqs::read": False, + "sqs::write": False, + } + sts = boto3.client( + "sts", + region_name=self.authentication_config.region_name, + aws_access_key_id=self.authentication_config.access_key_id, + aws_secret_access_key=self.authentication_config.secret_access_key, + ) + try: + sts.get_caller_identity() + self.logger.info( + "User identity fetched successfully, user is authenticated." + ) + scopes["authenticated"] = True + except botocore.exceptions.ClientError as e: + self.logger.error( + "Error while getting user identity, authentication failed", + extra={"exception": str(e)}, + ) + scopes["authenticated"] = str(e) + return scopes + + try: + self.__write_to_queue( + message="KEEP_SCOPE_TEST_MSG_PLEASE_IGNORE", + dedup_id=str(uuid.uuid4()), + group_id="keep", + ) + self.logger.info("All scopes verified successfully") + scopes["sqs::write"] = True + scopes["sqs::read"] = True + except botocore.exceptions.ClientError as e: + self.logger.error( + "User does not have permission to write to SQS queue", + extra={"exception": str(e)}, + ) + scopes["sqs::write"] = str(e) + try: + self.__read_from_queue() + self.logger.info("User has permission to read from SQS Queue") + scopes["sqs::read"] = True + except botocore.exceptions.ClientError as e: + self.logger.error( + "User does not have permission to read from SQS queue", + extra={"exception": str(e)}, + ) + scopes["sqs::read"] = str(e) + return scopes + + def __read_from_queue(self): + self.logger.info("Getting messages from SQS Queue") + try: + return self.__get_sqs_client.receive_message( + QueueUrl=self.authentication_config.sqs_queue_url, + MessageAttributeNames=["All"], + MessageSystemAttributeNames=["All"], + MaxNumberOfMessages=10, + WaitTimeSeconds=10, + ) + except Exception as e: + self.logger.error( + "Error while reading from SQS Queue", extra={"exception": str(e)} + ) + + def __write_to_queue(self, message, group_id, dedup_id, **kwargs): + try: + self.logger.info("Sending message to SQS Queue") + message = str(message) + group_id = str(group_id) + dedup_id = str(dedup_id) + is_fifo = self.authentication_config.sqs_queue_url.endswith(".fifo") + self.logger.info("Building MessageAttributes") + msg_attrs = { + key: {"StringValue": kwargs[key], "DataType": "String"} + for key in kwargs + } + if is_fifo: + if not dedup_id or not group_id: + self.logger.error( + "Mandatory to provide dedup_id (Message deduplication ID) & group_id (Message group ID) when pushing to fifo queue" + ) + raise Exception( + "Mandatory to provide dedup_id (Message deduplication ID) & group_id (Message group ID) when pushing to fifo queue" + ) + response = self.__get_sqs_client.send_message( + QueueUrl=self.authentication_config.sqs_queue_url, + MessageAttributes=msg_attrs, + MessageBody=message, + MessageDeduplicationId=dedup_id, + MessageGroupId=group_id, + ) + else: + response = self.__get_sqs_client.send_message( + QueueUrl=self.authentication_config.sqs_queue_url, + MessageAttributes=msg_attrs, + MessageBody=message, + ) + + self.logger.info( + "Successfully pushed the message to SQS", + extra={"response": str(response)}, + ) + return response + except Exception as e: + self.logger.error( + "Error while writing to SQS queue", extra={"exception": str(e)} + ) + raise e + + def __delete_from_queue(self, receipt: str): + self.logger.info("Deleting message from SQS Queue") + try: + self.__get_sqs_client.delete_message( + QueueUrl=self.authentication_config.sqs_queue_url, ReceiptHandle=receipt + ) + self.logger.info("Successfully deleted message from SQS Queue") + except Exception as e: + self.logger.error( + "Error while deleting message from SQS queue", + extra={"exception": str(e)}, + ) + raise e + + @staticmethod + def get_status_or_default(status_value): + try: + # Check if status_value is a valid member of AlertStatus + return AlertStatus(status_value) + except ValueError: + # If not, return the default AlertStatus.FIRING + return AlertStatus.FIRING + + def _notify(self, message, group_id, dedup_id, **kwargs): + return self.__write_to_queue( + message=message, group_id=group_id, dedup_id=dedup_id, **kwargs + ) + + def start_consume(self): + self.consume = True + while self.consume: + response = self.__read_from_queue() + messages = response.get("Messages", []) + if not messages: + self.logger.info("No messages found. Queue is empty!") + + for message in messages: + try: + labels = {} + attrs = message.get("MessageAttributes", {}) + for msg_attr in attrs: + labels[msg_attr.lower()] = attrs[msg_attr].get( + "StringValue", attrs[msg_attr].get("BinaryValue", "") + ) + + alert_dict = { + "id": message["MessageId"], + "name": labels.get("name", message["Body"]), + "description": labels.get("description", message["Body"]), + "message": message["Body"], + "status": AmazonsqsProvider.get_status_or_default( + labels.get("status", "firing") + ), + "severity": self.alert_severity_dict.get( + labels.get("severity", "high"), AlertSeverity.HIGH + ), + "lastReceived": datetime.fromtimestamp( + float(message["Attributes"]["SentTimestamp"]) / 1000 + ).isoformat(), + "firingStartTime": datetime.fromtimestamp( + float(message["Attributes"]["SentTimestamp"]) / 1000 + ).isoformat(), + "labels": labels, + "source": ["amazonsqs"], + } + self._push_alert(alert_dict) + self.__delete_from_queue(receipt=message["ReceiptHandle"]) + except Exception as e: + self.logger.error(f"Error processing message: {e}") + + time.sleep(0.1) + self.logger.info("Consuming stopped") + + def stop_consume(self): + self.consume = False diff --git a/pyproject.toml b/pyproject.toml index 67edc18de..73ee56ac1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "keep" -version = "0.34.1" +version = "0.34.2" description = "Alerting. for developers, by developers." authors = ["Keep Alerting LTD"] packages = [{include = "keep"}]