From d6b85d9467b9387f6b3c3cb18b53fcb8862079c5 Mon Sep 17 00:00:00 2001 From: arbulu89 Date: Wed, 11 Oct 2023 08:30:18 +0000 Subject: [PATCH] deploy: 937367d99d003474c8a7bff851f8ddb0bfeae568 --- .build | 2 +- Wanda.DataCase.html | 6 +- Wanda.epub | Bin 511132 -> 512451 bytes ...ta-4FC63431.js => search_data-EE7CC24E.js} | 2 +- gatherers.html | 146 +++++++++++++++++- hack_on_wanda.html | 2 +- readme.html | 8 +- search.html | 2 +- specification.html | 6 +- 9 files changed, 157 insertions(+), 17 deletions(-) rename dist/{search_data-4FC63431.js => search_data-EE7CC24E.js} (77%) diff --git a/.build b/.build index e360ecd1..60a78f0f 100644 --- a/.build +++ b/.build @@ -96,7 +96,7 @@ dist/merriweather-latin-ext-300-normal-K6L27CZ5.woff2 dist/merriweather-vietnamese-300-italic-EHHNZPUO.woff2 dist/merriweather-vietnamese-300-normal-U376L4Z4.woff2 dist/remixicon-NKANDIL5.woff2 -dist/search_data-4FC63431.js +dist/search_data-EE7CC24E.js dist/sidebar_items-E53B19A0.js expression_language.html gatherers.html diff --git a/Wanda.DataCase.html b/Wanda.DataCase.html index c9e8160b..9f1ee828 100644 --- a/Wanda.DataCase.html +++ b/Wanda.DataCase.html @@ -186,9 +186,9 @@

errors_on(changeset)

-

A helper that transforms changeset errors into a map of messages.

assert {:error, changeset} = Accounts.create_user(%{password: "short"})
-assert "password is too short" in errors_on(changeset).password
-assert %{password: ["password is too short"]} = errors_on(changeset)
+

A helper that transforms changeset errors into a map of messages.

assert {:error, changeset} = Accounts.create_user(%{password: "short"})
+assert "password is too short" in errors_on(changeset).password
+assert %{password: ["password is too short"]} = errors_on(changeset)
diff --git a/Wanda.epub b/Wanda.epub index 42b8c4c5ec7ea7e14e3a43e3ed0138a15e35a822..edce3584b00b07549e8f0e0947efe8ee70e70464 100644 GIT binary patch delta 21624 zcmY(qQ*@wR(*>AxY}-c1PCB-2+w7Q6Y};1HX2(g#wr$(Vy#F_AF6P`+t-9a))UK+X zok28EM1-Iy0|t%`@_%naL?!`&6YRfGFOd%l^Iz21-Wt-;Z@dAWB?Yz}<|UE+t__&) z!1jtc=nq{^h?@uDP#LL;JJI4S_XwzdUTm7V=TM>oysT~;9od|06nxqvBAa99Ioqt; zoFS)Hj+S?Scnivzf}r;22jxbx*{^ zuCkK&ENbBT(eztYR2d)&tUeWq5Zj<9c1JKS!zyYyvVbwe>kBa0MjM&$r`zZY&pxTIgi?g9F7RhTm1YKX1RZF(<+7Mu3zjVJP2I`F zZp~o7A~?Y=r=_}?4y2fVOk|W~$){u^jRkY{?Zkq$)O5f6n{u5KgD)9_Q5kt~`*VBi zei*uTyDLZ5;*0HD2mI`&A;vnZsNkC2ulOIRnpcT0tvNR|#DHa;b2vRM{=Rvb*0RfyG3y6=QRDvzB6AK~Gk3bG zt*)_u@?PDZ(OVnC)j_o5?N7t)@_soX?Y@iI`R|Nx2w^LgUUf1dFIP!^k62M>Wv$?^ zA@(5Rdu##Bk7%p(Yfv4*-w%~P$L)O>Tru*Sx)%x8&hY?fi@H?2=&42RiMzqj#X)d! z0x*`rVH-9~0k4~u9Gx629?f~78@wf|MDDj{#p|StsNK% zB-yoW+LT0B?dRC4WYGO`q;KrVVvt_%g-+ek(`Xxo(W_>JMT%0Xrz)ijkX z_;te7nomQ#rlYo&65mR`aenWFc<+U@vN^6eJ`?ufyoC|;1Oz;{1btg~O|yGieiE&| zAvH6#t@;J_do;1y^&V_lN$`bSaqEPbZ|!79D4TT9gQOl5F{EQuhy2!Itcp6#usxmV z^*{pBm7+iF{{+o2tcxxWp2z6T28a=8s{T&4@9Z=6+b~qbzBRqF+m~& znx2~e;_^&AR6z6Mr+PS%d}PpQ0XL5-Pfqh%816zqmH$jqh>58c9ynKdKGq9-TaUHB z^>Ae2a?3SzAA5VHZ}@@$0r~#ER9m-SXMzWOpEZ!ZuzB)pbjmd6*k+O7R~X?V2ib(p zq~^`+0{nbVn+TLupUy~DR1D~{Ngm6*zGqwKtI{Gb&vfQchz8qo$bgS3c zVTr!H3#+}DKY6kPg$tI>Y4Aw*4gAc~Y8b&ZT*1R zT%c0tUyuC4qfYvVgeF;zu(nTr*|9qV9t56lVo0~Q$@NV~Ct7PdU;gYf50j+OilwM< zq>TTyXqsA*?cZnWB+0c^&D4oBu#75@F{cPYKALx@mvD)jFj%?{M1b%Fx9Gcd5I<;c zguruG(OgKmMYwdYJ{o;-sT~l)ivr54-&S1PvKcX>+&HpYA0hUsR2qc1c#PbODOpji zB}*8rdHtdyR!!39OtvUpt>aGD=|hX_H6^|~Y1dBGZn?eq6BqYma$}tCT8`_9LwXM{L>E+MT0q6rFDwvpAfi^G}KcXQZAMf11iT zHggJ-y2zhar%tn;CC5jA^82GNb%>&&{(UN+dU9^yHr>XSi?j7mQ}gw7$oASzlWIVlN{pkXt6xV zA8gTsE40LFG1}0m)3NGr-7Ro8t3}%XJb+n#LZ&ODu{KcDC5r(IMNv$Z4;e$?=~kXm zuJo!7R@yI)mTwxbk+12u;-D zD5e==3o=Q_tiP22`gaj zPWuqd(q`F0v<=X-mnmfa2t{ns^iB79P_&76^mo4FPDzZFmlhP;ggtr#!#u*>AI&Il zKX-mUJIZyWy$xMrrt0^9mh`ZrZkSN@hi#d-c}zK7Uko6a6)>3L+sPmVakcg=e?F?(>Dm41x$6BU_6*30u!b4rs-k6BaM!1k@NAT^K8*! zX+eIx(f6Zu-_r+;_j+jyP&!H+jGKMIC2I?(UVc9(an#cC3;u2cG;e`HZ@M!ASP#<> zpUy(x?&uHeo!5IrP{%h`6rn(6p#I>B&jxtTqiTv;LKeKI#8u4{r05|A?Y)sY+gMyu6EK4W6D)ArD+0xA7iA8 zIAW&mbF3WnfsF*ki<0OBbJ1o(~_3b@nO}7=j%y!X05Pn@jqOFpl zO{PtgRaV^72Pce_$nXINYfwAT&WX&-ElLY_L$(MMv_c!h?Y6{=5-K^u(vHWafW78;C0K~s8L)Qu!#_{ zs{bHL@l^%T+>@BmZ6I`*wKHGt#HMdE+2?|ootrsc_cX3;b=w-BeF7i9dOn3eFj$EVl=xY&n_~mgGiA+gHkY75-PqJ%oC_uS|k2 zzv>cN36wY8ow+)HVsuT_AB;tcW>7gHk-k8T4NL@JeQ$upNhO~U?bKR=xG`aFfb8Hn z;zJqzH6a)%)olW5Z`)|M=447yH*0j+X6$Sl2<-G< z`OMDOJ0BTNa&1Zrjc&1ezU}l)V+~t#`4JJk=e}#YL5C0s+Z`ZnSKrFdk?gy#akIqs zItK&MvwG^SyIgQcL&_u}9miH-9Yw)9%(((-hv|88uKb6%(?Msljm?@ru4kMd{NfP< zU*Ucqw*+ib#jtUQtS8poj5PFUc${%AMo9J3s4w2L>xp`sxM)~U-gKIH+^Y1=1y+fv znA=I!ssHxqdC!`h<#{$x;c|n`)@pnFL;n*%w5QMDkO-ki&FfA$_g`7{w+j++E{@&qDMd)$A6^}g%>@S*cCf+7Hy*gd#;7K>gOESUJ%(BAbaF;K9=3lzf2wiU7 z{(vd{=6+gR@Z`5qI2yPy<^LE;Rrg4UzBOJIh-)9l|G3!z^`b9{pFZYLm)}Z0>TEpX*oao{nj51!o;Jvl>rG8FuKTE?L*;2jS+W1`bvAmu#;H+98SsK>x z?g3we97~&Qj1iCr|3B5#xFv!I@xPDt)pOt|2~>&&xQwEazLlDP8OfGHYn959_rZ6c zdO#u7Ah$*}1XWDqz61n1LCR(5TT>|~W$7Y%8J_Mgub|}fx;|fyuF|q>%JtR{EL6Vy z)z+!KQx>LN)3jQ286?J|5;)X2JRi^0TK4#096D@+D{4?xVQjl|0=|#cbd8s%pB_dU zvb^Ph>EZpfj4Rv3q~0cRr6c{{YlUcv3;mid8dBFsr<^dRPP0Jxri&BfIMFHd3DJ@3;asUL8C*n&)*cXBn~oL8tb+#w z38d9#T7`wgnS`sXIN8Oe*&rw(a78u@Y&klB#)66@1_i_p%SY+h0v0gKM9 z=#T}M)j>Fcs!I{2eRsbzU0+o>xha^p(#%hS ze?j^D?R@nX62Y`ba?$4Gh+3k2rKkS_nj@95+(dz^*=X2JbBqqQ5At7IZ;Zn<`QJG$ zTq||6KOFk|)ph>$~TQ(#Mm&kmHpShN(a3|G^R zM&;6`=3Um(CE+9TQ6Zcb92fuLeb~U1`Z~nIs{KOvy0+l4=I2(PJwXuz@Gr@xw~mhT zSFYp2tAqa_j%Dw3^NPpeR(w(?fGnF#(;yl9Qy@mVz$EuaG_iDCD_@OI_u%y4_joul zduGTdegI|ApUlu^y66wPaK+;S1z@yr3}goJ<(PApLn`mi3$rlHvGiB@T?wH)v1`CUaEsrL8)EYv-)Dpr`(TK7I-5VKEi_WfS&MgS)#1isX2bvCw8s@sS-! zh@MCh+}ZlCn&=(*FvN?b_M)8))+%3XvEgRXb_M~7*zpmCSlXqS9toqOYkqf)FBR^M zMf6MTY-BmOKx{rG2(?2_Hj|%08+H9)2F|Q~jVVtKoLiBrvK@JV-@5%nxjIDdKtrn7 zq*O@)KB~2qEwis7fsb3QDG4wA?P)}QSrn?;Q)0v&T0r+tC(<^7`pC&iW1^XDQk*yv z>F7TryVdp?e`JOS`?EmgSG><@W|=-=s`=-V(Mcr=%PC0OgI6=_D>T;y!j{!*VuN#@ z_h`aTXB1_%;b7r_CiQgJhs`Gl*2RFHdKn70a_XZHQE$W$ph22o3|ax6F5Z=!G#_yWu@I@$yufu z6+w6`=~J4UY|TrSt#{w#MO}3l1nNH}5S%`3gmuf2*lq&A{lOy6nZK7K?fp>vWcV)& z`kZVOO!2k`LiCRzmGO4+)G372(JJ`rdCSXu@)OJn=G7(wNTS(`!xw#q^f~Dv#hX9I zv0r5_5*qyt2;iBy&ZS_+AM~V4P|w$nSi2%X;?MNQ2AWUbeO^Q;eT=Wn*?h8b)7_W; zCI{+GVjo=K2@ej-(Gu;CDvg~&gdC@W9ZQ^K-kReFcoYp%K~Gor>rMWvZK&P_kIkma ztP%HL#h2r?u)(6W;Uban8j!r$3z1>>ni_uUTda-kLM_{}SCS_R*eg5cLpPcVSUJW# z=roC71<`SvTKfLO`TR>z&8->eQswik8LsJ8`Vf2IBx~x7My*W|Efcf$N*YL zH=@rieh@}~`!CcUAK!hY;s9F*W}qIRItN^_X+g!G3ctp6LA#X@6bD&+2sG(tzQc=>MlmHNvFQE~cqLK%Oc=Krlek z9Gal8fQbw(=XDNb|LxD8EfXS%8Szc~x^5IxToy^Ca+&6(mq}1Rgiv6hnLwzuzPsUW z;*-NU=;h2$pk($4HGMikq%IE9(unkZzOMIwj@XeT7Dc@KR|-qABK)=)zvt3tNSnQ5 zQ}!av%g)Ie(vYWels*m|d1W(X@xNL}c@enY1F};VZO4%m#wWbJJbXUb)JtGc+0qZ9 ziz8aI(I-&zxo1OHtrS=3d@uz!py^u!DICHlGtAcnp}&zcP&Knfsb+7Z$!S*D z(pg8@>ZPFsQ<`K8k2N$HF+zr%T)go4wBm@{K49I{3RBE9I7Wjy38M(?kh0z_k4e{y#I$(XUIoWhn9Lnh715+9%*2R~R}zrx%!q3s>UD$&Q?qor+x=|{;_s%a~Y zW0=?6+N6IIbO^O)FME<^MrVOSwKG!}VV^I3=?8>GE{IrB%1n<__uv!>*a!v1bBRJ8Cy-5-({ zq&AbxKJio|PWC?fYSCrYv5F{#Bc*);kuYVd9gtjB;iM?y-A``YB{O(;XA!190?yg} z+O!tzO|Vo?8F9H~vslBn5bC{;_U4mIOzt7r=tia@F;=b(-2 z(MyD5OGQ~?XemkVi#ns$3(ewtYtB!Mz3_bT3kwR|BgR3LjitDjD`-VD)Q1%m2>H0Z zA6_1`JW$D>y?k0uSB8&2m#E!VfSUm_+lov&Xe?7o&6Q9)NX%!3aXy=mLRW|^ILFQf zU|`%GK^;s@cp;#jHcw5r%?v>g8Odm?5-E8sze;~Y*e9(?}7GGmVUPGx#$Csdk$_-Cc`e$Pz`tyAi zl1dROcg}3xTDUiLtzFUpkP*^EOwqgtXLE)(RwP3TzdLD#$H z0hzd_xJ{&F?wEGDyKiO^upfjYS-QAM6xCypMaahDB`qhwyVMS0f>+Ri{7UnZ@iV^E%uE*p8{4r-qGoIauT?yd;cnX>&xrx>)?V8AT zdPq5k(AiqY>~c!>o|B7cii{f;zZ{%f)YnrO&5 z+Y@c~3)mrb6Rl!+mG*Ae#;45V82`28; zu#TSiGk4n^@;}~(y~_vI&z3Bg7YB;9RU57h{}P*J|IWiN)acGxUd1_-W1SL>BxdTr zdgbf)H9qw${xbjy$T7XnwzxxewIowj{D8e2_Ju_6(91 za;!d=57UBuW{C~g?G3L)pI|}W(0qv~OFo~!{B=#l2Z!punR4tK*Dwkuqlc+W9S(IL zS_z*NoHinSi>{n&W=V-cN9Rnr3*5YBy_(7cuV6;`^;8(6h0;g#XCi9{CL_6<{)IQ#Nv%Nr*sqL+#Oi6Ysj*>~ZJS)GW3 z$ZHfMi7*d*Poz~ENv9P^qch2@E+>+$L&=q|lP^WfAud^_>B6@5s^y!@G@B}(3$KEf z8Ko;JhZMr71MAcNk?8ZoP9eu6L#$>fZeG|5pe@pk%$DwoMPKyWxmS}P{L;jpOJ z8}SHqK1pusx?vwxuA_@+#zjKDL#DzZAgdEuXaIX4X(G5f82QRes=|uUmGIJ>#5RJ^6ba7FeQS*>e5RJfV@Efn< z%>1KidLX(6&kzdK%QJgZ97b-GXKV!U#oC@SYF&Hea`DM(2re-^dRmiCmos4iE%+0Yeq&iEwL zmca|S|NNMz#)jzA@;Hh^#Z?iOk8nQ=BNKRVdt8>W@xHi2U+BjECk)$sRBr+N_0#mE zs+zOBqNkCsy(usO$wk#!9KlN=1Lt>o~hS9Q2;4!KozQ?nlDQB7WnVPo8-I_7ii zce78i`3Foc2)EzsVBOCOxX~Pqwq3IX>N2P1y|%sbkkX9WA^OAjWgg1}MZMnm9G+w4 zlg6JdDrZrKwUShbb~Gw$oJe2ms(D#q;kUtCJ$fh3>r;su6*phjI4A>nih~z$ z&{iS=Q5q;_I}7f|v}Pw_ORQu`pxS7FD^oVcnTT^uyl5Y2yj>Wq^tUHEKQAu753D`` z+$W2V<*;8KB&ON12GsP{C!WLwr<;0^<30W(=5H8o zmHx{sd#9-AgL-+SQmm2{RvhsVXY^6c0WDJ?Rf*?UvE2O<0DEbv=Jn&ELDKgjOuS;m znS^A&A0A_lUM~yYc1&O)Vimw;w%afkpIr`=7DxLA`0qSuCRzHEES8nE9Fr2qM2fz7 zQs|l!gMaQz)=D<&-}lusj1h+tkCtl`+qBX-D8JjN-8G-Nj$E#SX8K}vTj|Xu#1V*= zE6F|WWRwg`NbFxtaRu2mSH=rSKWclxwc->o=KI3cFlSI$3YmgU4g#x2Dwna#)!Y+x z7XC34BYs9(7x%8=`UTQaxaS4@#kIdmFm=t&6we4B?x6VG zv|H=gwynKex$QNH3d`=vc$D@A-X5+{-irFSDP6yI#1;BuI2;%444tF4eMI8sKM@hv zoGw$DaQ>v<@XR z19zC}jbTjP3eT8spz=ssm&0Rsg*hwiiH_(XxVR99WF&m#=*y8W>ELK0@v&eBvm~hM zV#9HmQ^3)S$@R6X^mtc8)Dq;WXwDg}m_i044_@Bp-jDx%fCF3aZvtPAkEd%K>3Lq` z2rKe}&co?Z52;p+gAM*6Z!lZ_9(fD`Pg93>|6bIq*a|GVY&6 zst(BYiEl|<>{9*+NO74qM$#g=G`)K~X3bJSuM?qfWVP+9wm@upwmH+R^du*JJuT8bvRKGDok1l$&<(-Js?QDY6%whSE}&IT)_Xkd0o&t zk6RnV_?|LgCRNT_)UzdyTSvvDsdzIIc%Y3e+(H6oVG*AE%WS5(SWTcS?s}fHJ+WgtY>>q zWY16+uXg1uqC-d%hI*?-vJ1qJBdlcMC2A$2!jU0NQ!bH($c!j@-DRl#+T4>|O{Jm- zGid{Ge%+f;l$^FS3s7g!tvLS}=+0_g9->(3E>*MtxWtN8Ll+AQL%QcmpwXGwSMIZT z3cY!-Z&PZZeT*mPUVO7J*9u&UVG&nh;23~#oTeE?*V#re@Z1YY;XMwJx>cGQ+AqgO zt>7Xs$xjs+-`(0wYr0gD`iJ2OA>?5MdhZNz;57%(rtWTDN z*hOxU4A@W;O<_FZHu%V8R@8&?7c7^iXyt|AfHgvGUeKxRirtSDA#&8~Q=$Rt^lC;w z%Pw`=68`0*clS`S$@MAK5k^CXG%J%JK@wTx52Cd?%ci&8DGqZE*Mu1$>@ms}wDr+h-Ht$v+wCUpc0K%J)ndwfHqQ_pgEd>jKT2(Ib2k@sww^Ort?TVYNWR zg}JBqAZ9-_$WKwOv`5_JCF`aA*kaB0$br`f8y+`%KJ&hI-tz8?arOY%teq{6!quy1 zUFNHdDq*K()OOT~s!MHMjhn=FZ;+j?$G7Rb{V4M0O{*K3L(s7|S^}%9!JoFPv4}lR zO}Cgl>bmSF7|_x%qrr#<8k4wa&|piJ(lzix=bh-)jG`iEFnXtA;j=U1&C_+Z*kbG; z^6()GIKP-8P_>e|E@^<(8+v$(Y1l5IRXukRrK*%fm4PO1wIJ;u-YVTh%+LMPb`Td^ zG&|5S3N>F4p7UH_o7n?6Z37<2;z<(%R4}rfy6qU_tErJS)QYnfn|%!72e32W;ew5e z?|8a+DEtlZ>X0*-luf#LjtRbDmbi)_<0}2Vd9V+coveax4P$`HhFCEOZoCE*zuCWt zQ^~BwIM`b{NF;UdM3x+;fO16mDW`#YJ&1|N5=pd?#%V!>fi-k37Kk~)CiG+0%Yuz9 zLOt_yNl%iK!PNPyYGzfGr%#HfjoN)EgY&j(yyY!HnT)o3A+(`L9#;b?|vNb zS9v0Qh4GWvnC@_%z$e*PS=9cv?W`01P$eUdPDO)12$dL&o);O$#HMkZ;D?DxyOrU6 z5hr@@Do&wOIEj0TL2W~IM`%O9ez$$W5>y*y=-VChn>qkW-0?O{5hR}UlU}&(7{uKj zWVLTN541U@zY#B4-tOSBA}?R7E@z&O!KUTKy8nE&z+<(#@uBJ|I zxg^9JCBk>Pp537mNgFIa-*c_meLdJCU>+>1$S%(jzEEdWMUiR=0~duomR}KN(R{#G zqh+)ES3KY+PA9@^gkJmVelCH>4Aryo&!Z(ah?fbi0y*jIg}ZS2R?#Wf$3?bw*ICMy=<+3;4gP{h9YMhwv(;-&u(LL(&uLaKM`xJLIR)=A zA+hsUTvIufszqYg0dDzf!xKDa6yl~`3ll?;A`KMYn~4kly&A4Pqus|YYzqSt6)n|2 zep>(!bi(e__qhD~T?3`h!bqnGsTXg_2S5)C;!EY0K29tKTeiUYA@hi(iAi&Cat}? zyLb62L&5q%z_+{a&$pR=ZT3otfZK}!fi3_%Q?dgtTvy*OtbIYgVZSpoZAxN_T6<)N z=Wky=4}96=wEC%iMHJ9=r59Y!C}%rwjzaxsx=l9dQRaH5q9nL9lRtJb+zol3)|8Ba zl6LvshrtYe%V_VdBg-zCTE7UBh`i4$$o6lE9zq^7;AA?ixo0wQFiWAb;r~P}@cn(D zb?$&Gh5BEQF#EfBzQ!~i2mYTq4C-;6R^AmV5qT$(I*PS9Z0TWv_uM9!xcBRJt(QI% zBi^sh%E=tF)!v1Bjkp>HVVM1dpS;BOf+=3UrHiXC%b0z68a+eb6Vu!L62jj*0lz8W z*wJ`j4b%BG8yM^qR<&VAPcy{%cSO`$ybZ7!XM1bc*1mK;~TaWww(Y zF8vHHyFipij`65Q{g+GvQPG7bXQ_-xJoQh}?Fg)#+$&bFXYDjPf?i)UI?$)3ZUn0v zq__@s#@x-1R}_pw(H*>a-l!n~zpptEZWf)`4EFDOJ&RSC;y)yL5<1dp;q>90nZXPQ z1)}_ie;d<^2d<3A~+5$rpTPn5_}%Jor&URVZI!IQqHueG3&~CmK+qv%6C>}(LRlvI8_d2XYo>c0?NCIW9JYVGu6ybD z%RH(g<7=00q1{3Jnz@c9Y{`qwIWptjEw*coyK_%#8sh=$Eq2592Ckbzc)UE0Cl%LR zKi6&_A@9v|e@XZSP-FycuwaeQFB5AlKqR4)FC)J*0|M=2Nu4_VEQQWKr;rI)U?||s zYShWbG7layLD1-+KqLuDCHjB!cd!jETK>&Ke{z?JK?{XCo&h!V_>_2Xu8LGuxIdD; zS9r(|>B2YVv8se*`U{H4o$|{V$ktg+ zhBiX|pB9)h01rEn2^3Lv!@W_Qo6gNJ(Y=L)CUBDnHD&0DyO0n@_@b|Gm^@{~J)Mg+ zui+YRgRL>oETuX+?)6~A`*~c?jWE@G@L+!;3W6~wD^`!!H_83qBk86KM=g~cFEuUW zB(Z`#iOLsuAhbC$B;|&1DpjDa@Rmp9kE5i{EOP8iptbSzK@Uv;eC4rkzUo5%`R=!+ z0YZ)+ngs^R4yt1MhHz2)u2C?KOQ(Dah;Ks2Kip1lp$nV2u75oPxj{X0v~0X5Jfh|( zoK%Oig6K$MrC%< zodA#xaKPMz%&9HcY2D~as*zzK;=(zLo7(!~lQEo~s)p2QP*lN$ZpQmXDYB4cY^4>d z%jet+5V?zbaddgZEKIU%g{*O7SRbpF=U5oqxxY9lG1k=s+vNWqX$*og zZpY+aI^0(s7VNLE)D){ErQlR%gkP$$N#F>3BN_3q0gBcb3y8%U19UgLb-9H*eR@ZH zG0GNGP|5{TfBIyG)tE5I%*HmT(Q){oFR^`Y6?aMQ^wYu9BzyOhhfu6(8=P;(dV_1A z_*nqgr8CS4a668~)7X8wnS89i2wn47*&TnHe0LYv>i*=)@@ezk_PELTMWK%;O`SBl zeY=!rz!wfxs+i9lhf8&igF*hKHN&UO%l>@QV+;YPwaoDA?TF>rIXm6b{%z2nD#yfk=q-t;i*}z% zq@T28kB{MncPlgG>?rV8qZPf#moiX`*TJ{1HRjZjE?L4Bi^W@S;E9xZ9W8{?L% z?zM&O@#uUh!abdo%IHh4k* zF?qYyG1U02QlhK|1r=^LM~yttGu7<7c)jQYrtLnzWgnlnmJ-nDF_s*AJm#pw3jG{= zJ^gy4ovr6&T|F~+URl`Pxtdj^{(hLi2qss{>D2|TJwdgqpFKJCP2^_6&nl&si)18huH%v#3)@gn)w;t!E>-?6B5Cm+!F0wpV zztZ3pcz?G-uwWvIM=U8_M7-r(k2sBmGcHQ;7tBGUC@rWki(#B)UT1b zX=c3FGzM1;+G%&x0q}b8`-UO;xW;I~bulzoB`Yx7y~j*8*T(A2n}m^)3)B}=vk>Pg zjhId*1{Fmwaq~CS0OO~FhDzC?F3`@Bh`iq!0TC5pG006X6T>ZZuoc(f4=#VH{Hkou zs}Z7_9gvjoC^@2)8kpFK@gpe3gh@Mb5wLekMsW$#Sb87u2Jp*zg^LHvoX zDTA9_iveH-Xuf6C*q{Eayqw&LKVTTz3#d*qpq$@bR{B1#``cXS;heV5HB?JPL`zw5 zlkB+?9PCnc$8r@klhV4f2723KzCq8?90|#I^R#pKuQT0?b6ec(RiH=X=Kz4vm38ak zl@G{=F5lSk-gd_@F#ZeL{bxd5dhzx3F!+mm>)3PvxY=88`hK-;li4`5WVwuE2! zr$VZ4@5TYzef)xDuST8 zS9r_==v*0(*Gt^6$`Gi#&B$s777E+y^MwRaPd0eL_G)AvAshATU7Tu{T(Kl>h_t`Z z6bB;1srn)F93za1U+7|um@;R(yl<>SE(S}iX=xyWgWi}pt9gj0tc$@<0@^D!>C1aG zRU#n9Nz*&Q&3-^%V}iSYT=vE&B-B)AiA@*)6_!Uqzrpize73NTwq~hWB#8}>PrW0LlPSo_c=Z`tMw zfPEPLy-vl*HnkdS1256m89KIwWDi9YrkM_gJZ$1J6 zkkBO6!dbEX(el_nAa2t_Z-tiCU@z1H#k6uyTZ2WI3`$~*LZqv5X$1;}yCWVD#N$Tf ziM<>QTaEAOvYgv%n>o`u>?$i+7%m^5>u5`|E2OE(VTPhaQ#oTj)m2me?1$HvK)#^9 z$sHpIIoFJH=yFt}V3e3jZG-T4)?jo3pv3^DA|o?{0xr8YPtCb`V5c#t1@dzFk+t=1 zOLnR6kyUA|{%=*EB{Vqz%*4L6^m;3?=8A*wZ@(cGO?%m#ikr^fk{5j_^nP8W1Zm+QMi+rM-eU z^7i4*xQ)3F=>5L_?}|h_9hl?)wWc{@t_TUIFh|?VWlKoNo@o)Ij@P_K@aTTgG(A;8 zxG!p|gyD_RW-C7c51FgMG9pb~z!2n|&k#};CZ*`sL}5kHnn@HV&td!7ofgEY+(k+3VS%aTT`Z!0Vp3v zmS)UyKl)p_q5B>F^e}`-qX;@xtZ1-{AFfq*3^PEf+KLvz+E^7o>**5AAfpZLevJF+DoWcpr)Dw{GSd zMf-MfOcKC;t4UHEqK#(!jAQICg?q+fp7)bJPLl*WMc7&@%!5xOIeQ>hu=9 zl$F#|cw6zwXx*vc^=#6~ASo=J*fmrLIZd|}k;TUW>O@RCwg^wSa9egH-J_oHwz59BI z5M+`>t8CNNK{Qs|DxJmvqZ5beD@yajNdDLbF;V@=O@dn(!~oY94308I{bqcg31U|#^JT1s@%zF zylkzB1N9DpM@35W)X}1IJXXhjk!8olD3+YS<)mqent!zGs=htVn?Qa2^0DHKC))eR z-z}lbrCl#T>}ww5E+c6|P(Y0#3(!XwD;|tl|5XYa+rH1sRKLqT@wmp8)BRV@DWBVb&0MRSk`nMuuWp zv0+ycTCCNHfYcvBIM(s(%2NxARd6^dlCD8K&L;jqJcAthuH%-=y)6k0K1#Tavv7HL ze&F#RZwM;W$1Qoc*hV1Add9PGMG2HoLR^6WJ@bXzWDodXr?aUp=djO#+;y&jtetNe zuwq>=h!jg|sMIv{Lkwwsi$EJ+D@d_8m8fO0@ViSyxdCH%tJq5ZJm`_#hc(;tTFO%m z6VNn^_H(OiPIA%4{5v*Q=&SJUtEO$yw5CopvE-hQ&w8_31geC&pM-(e%P<~j{C=i! zrOiZ!J-_w1MZYRBj1Pc}zdRg(LjF7T5g5R0KGs6j}BS<4mx8D;Rfn5p+|Jh7Z z9QzE9$8*~5G=fH{y@b~#0%}ZqdJJ~$1;7mJx?vD;btedhVYcN5!IVvO2=(h-?d)Lc z?x|O&2mjkVTD<-n)Zlo@YLvGJseDQE7kXwW*}Q0o$sEnVpT>sXe=$+VJFO_OoVeC) zbMDG>dp@Mu3`O`yg9l{g(m(&pX4LW)6AhKTKUrBu*^)mZhq`NcK=FEfJ=LuIngR9L zBG?con*Cy{$ke5fjJZud<<4uer@JpdbyMb+2JGV%JP+OF-d`CS2(?x_gJ%#bY<(E( zuIDOfWVfve4TkDeFm+^F{efD`jX275XB5zJztG_L>RF_MeWN0Mt-1ZuMqW)hr;gN= zWEab{{XV`p#!t*?4>q@xpR%U)I{_W8g_&Oq*1PbvB%8YRME0>LNaTqKDNvW{MueDp z^7O*pmP*iyO(OddV$Q!{$G4~Ae&F82>Y1hmok%BbI}R};?;(th=Jw)Xz#A`vQCxe;xvm_ki8bbgC%3Tqyi}z-eGagD>1HG1t2CFZBCj zv!%H-shbFzU(9Hym!<*yCN4LywR8?UFWJ#MrW6{M*9v#?Z2W=l8;f=y96Vcvt6|7e zxhR@I>XiO%La2=QMBzZolckY$9}(ZeiXlN)?gw?lq`uKIMs?HQR3KNSUa1A++bb}TYK?nAC^;^%>!V=7!g z!JSiqL2dk|0M$nIH3PawiDrD|Cd~4=R*C@%bjJC`nxtMrI-j%Sm#9_ z-oB?P{G0RpG$f#+1;gxV)y8vQleTL7M3j0fvuRL1*?pvlu3j;5JjVx59jkWckF>@&9Og+#daSS>&BszFH=k^ z%Ra-2W1L0W{AEGF``eGlsq{tlljq(SYIk&ydsDV-pXQ~g@!o3oqq_^}k_gs}|I?@Q z<0sqWaguVP`-1WmjpJ)u9ZYJk33HShimJ$L0JmJpkNY(MlS|30N;Wd#OCqauNa{2GB8H0?Rpe0B&kLcl1`ScInOHh- ztP0WcPA2`}fg#EI$5LucI-v$3X-BBun9xC^VwDrLWQ`a!@wt+p_&u%J)h;THAv?^N zI&FMVe(vpxyR+Wp(pVQ&Nf?PB3wTZH&{#X-3GSsL{hiHXtzA9v#@9{={`inAn62ve z`gs0OJ6x{0w5ecS@>jI5=EO)<0ZS&X5(?c+j8)@5=aSgW)ERlZlqzdn*q51X**Ryk zjyvQRP5CmX+*;{rC9io<$`2kPO+Ej6Eqs z$#`8enU&`uM8nhgDv<`fUOoSP&$(&c{%5VT*3a+z?eF{cc=lb+*%9NaJ}+}8nIg@L z``mX&=2j|L8l{-vT5o(@KSsTC%b-a+LHNdQEH$m#fV=rPj9IO8w4?IbmnI z`nQM2oUEEJpt)lE()Ny!!tB8sD)^Y8$4gul~5B#R2_A3=y06Uzt@MGmkg! z?Ea%y(&wc^Z;F2{m7!+%uZKarT4MV}=H>2p8Flym0}eyeQ&x-~fmS==;gE>6zr(+l zVkMVu4A6)r;9!C2A}%! z5d)xyv~GNhRpdjLuGE}w-9Z=3KRiyadUev~>!V)y zit)Jil!c#@Y`aEzUE5Wi-xPZvvfk)KzWf-t(rnJPluf6vU%&omV|vzP_s)ikTV`6$w?~f>wropL(~x{sU)*HbqPoDMCsk9-+vd=6F-0e- z6<5w*p~jmfx9yltlndxGycAj?=vOm;>|E8c=MtYwg|;=ay4Hp6w$QS2)D)fLJac%$ zIp_H)8Id1M3WrY%J5Y;g4UrzG1PI0Wj-99-|( z?{rmV_}#i-wrLs5kCMVtn3KcIyVd5bwR;^s#yRr-y{0uU?=Q^~oY}Wz zL)~rPq|C;Zc~X5d+xoNjc3K!G_cyM(ZYeHY5HEDeWrGFFO-su@<*0#6M`h7Nty5is z+L15BN1XN#`o{O|uAfV9c0A$NWjkhcbCLAJVYz!@p`OywUAH`HYZuGUO=Y$|YJ?t2n;v#=T&kd?N zbzT`VKls5M2!04Hw+fOmR+oQW?^r*u_;twc{`3yjr}P~iJ?En(T%3X_^G0q)JRJ+N zcf2dGe|=Yps6hNeuOiXs`DdWJ+mlmGrxe#%G|SbEDNIotY$;PFksrV1EWF*%92r|| zo6gRN5$mgcA{7)Pr25K@^>%VahLHC`!QhBBRhfy-U#ud1Vs|^}XNh>>t3Tt&{NUfQ3 zWkqv8yYfTu_+Uj&zv0dFq7?rm&%Fz{SrwZOwiRbdYKQi>AB zY03<$}M`_IF z&7X>vXS8H7&a)4j2u;Xdh;Gc?h+mE$m;B=6TbSeH*k_DW$LhPXuRlwIti@pJ{jEvd|Yp%KH>RE|%7zD+>+G0L|w{mQ7Q z8Q(pk>*7sA=&O5TUBWo{_{+$EYo5sA z#e4P-hn{&8GHnlySwM-&QGM8uaz{+BJbUB7HFnG2M>7LVqxOf>>KQj?Y-N5e{AcLz z=|2aQn=O`JJn&&4IBDoe%YU^ZTRqC-Lbh6F1YL+XeSNu^puTRPGPi1m<2Cek zI;-eK(?9KNUR=4ddZ4zncDg(8=oedwv|XmgK)Y&c(l2MA+9a*u+tf8_nNKtO|C8YR zp}~H``o6wrrhy^yi4dFxu98Uk8n{EEzi)sR5)~ByWn$5X{kOpr?n4Y#6oCc;1Qmnj z1Sl>BYk!0<5%w(Oogw2Q6!ux1qOs$<+U+0&yY2Of?;$%)ld?&F9Vun6P5uwbrQnlGN4Ehm0Uvb zYQncvdHAIXh!VbtpL_tr^w(n8Ts~hpxo}}QAa;e&tQ-~ntq8i70~MlJi<$1Lh8#hR zd&}?@Ywm^_NTtMW`k5C`^_0*NL9Gigj66V$lx9;nzv8ga4{aQ$%Xx|X*imAbDxXKu zV5n39=D{d75Q1orDGaUAZj-2z3mfHiFKpJXO7ysS!qj9i8XJSCyZKu&7A~#;3NRy# z=Y*(>9vYisNM0_DVVZoAZKJrJiSy3jt_nb>WyRv~SQfqj7DnQ9SWv-Bql#vx+72ifkjcs8`76^C{lUO9KJ%`J^*JH)~j;O+0WIqt!r{h^kU?75)_W*~PeYghntlJvu)KUfbwGOBgL02(cUM15oEK&%= z&;*;kvMK(H0X#$pa?q{*`}n9wg*PsN7wUl~F-I<*j;}O9Q}bWcASjX9E1N=tN)4!} zqzVv)a;WWzSTuD7-P35fIY<3@j)dw07`+Ur!YvJ8E|I8f14`X|DUZ(J{>5F}Yq+3c zIY}oq@>oR#s7c0fO(R%G$U?ZpwKXuT2_;e52<8%VbSc~OPBW^j6I$;1(@oewO8;vF z^9d;@SN^mN>WkZ`xA|v3Ycna`dWSce4%|Vp#;i#;;|`clWWeFFJMBq!{0>ke8cf>! z#F0_t7NAvv-|aaV+63ewQsU6A2}luHL=Bpa7NLY~P{RE3Vi&GwawVTwwo63<^@5xN zhN;c=0r%OI?M}vj+r(=qp=OlT)E<&GYvxTqcP=}zk7Q>&!F-tC%uIbDH()1qv zK~zq>1+ivFNcPfRAON?t04c)c#x?03BTeHiKm?|@@EVH4H7)Uf$LrIsf&YZAWy)cw&=I#KJJ2WQ3HL{95$e#BvKS`M=YY-vaBc#i>;C-A zuNNr1!bAgW5IrH~_=*Um1K3aiWS~Sc5QJ_W-{*1%>dVTjJX=P`_hHMWVGfTT?Etbw zMn2|Sn$Mytb)!{+|GBz0kEdPP2^JFCr6St*B9Qhy(yH*KLcK+3WubU35GVSQ7&5t? zC}w97VO#uvyBXQCl83jDo3H3b?J;|0Q{IAPSF;bZk()P_CfaQj_gh9|PoUIhCe DuYHv5 delta 20355 zcmY(qb8u$Q)409i9ox2Td*ftd+tx-K-LY-kcCxXtv2EMdyWh_~?;pQYH8ofDO!Z8i zIj4Kj(_cWCnMMe&AOi-D_U(TUs<3n%JSW)StWF{q1p05TZcP*+rqgf@GD8BCv0vjt z>N-+~bEeWFawK>I)shfmguSn)s%<~6!-^oyC>5(GJ6IM1zE4W3u;_8%iAo0zZlGx-0r6Ra*xoqq<#q!r4ifwWZ z*(Di0lg3>1tAwc|xWz$fXyGOhpgs47649zHbcs74&nRv?5rguF!yl}>iz2opNOhn) zGsV2SEe*;=`Ma*ADAP0}&=W>jWZZv)UKnUtHGzk5oK&hb zt;!A?*h-Z8XKa(rR_tDGr=?lgfIt60dieWmbUw;T>!(s#nNluTEVT`A&v7!n2|7-} zkG_|k*^bqEop+j9K~;V`2SO(Mj9fp~L`cp;3=eR6=*oyTU3Y1!{iB6nB9`LUhaeT__5y{9gJEE?)wbCUQXP5M|>hE#Haw z^Q_l$f-uXXxagQ4PL?jvX?Rt)v9@q*OqXGvXAH=Vd*PO%zY@G=BK}5Q`v$s5N>^pw zDqUi3t*IMRP}6eg3M$CCdu-@?gIF>$wsh?p3%?TZ~^qRH?BC zR4}{sw5q-(#jhUqE7b%}atw;3n>3O z5<)&?n^#(6_V_TMNB6HYONB4=f)a5jNE!DMG`+tRkrq4XwsphCDR zhTpSZY>3qsiZM_589lURPD?(`NBl4^!!S2zdJOyd-QUfQ3EkcyAqAEZJ{ukcmiF@= zy3Nl77yGu&-augXMkgCV5<&3&_ta$USv?1kIm=;^AEAkwU8t+VEZFj|~6m-X+-O(2#oG&O_PToq(`+ zU4b?qK_*;u7Ugnhy^mu^lw+ivOZl#vHN5m6^nj4&! zZsiIqB;K2E{-pBWe{ zIt3Hh(45Ws>5^Z))wkc>hjW59y9>t8-~DriYI!%D?tTN;GbCjrt99@kB&uu4PZ*|8 zoD@Y#2lQRSS(ANq$TNl|tS~FebkvJIb`&NTF9m8op`I`##vL43+LM2FeH2&C{Ay2r zh?XdRIl>yk0vlhC%7PwaT3G5j=?!j6m){IL&05OS)ni~-HEl1|9_p4Ih1@v~+z3k_ zmn8KBF;t5Al{8<*Uu@rk6+dKz|8Z5G`lBX%YUVDxGTZLnCMuzYKc*k6 zt=I)Z5Q*Oc7C(!-uv2oHQ*+sr7BK1Ny5b^HDQAJZOFpIq`#v4bj>vp*qMeS1`lZ9R>E2{vd@&hU!M6b83DOcd{u-z zYxEwE&a#$n!tvyc;Y9|;KLH*$T}&#m@vP#;`jZ3*5dCR%U35@E~sZr!?cwH5Ca zzA>>)>CgmLG%2~NLiOP^E~r!^=TGF*nK!1j&%v?W@av_tBK z_((KBYk>sC+flPM9ks#{({FEYxMDT4uDp|UUW8uU1nDmCpoIu6o)T9u$}sEwdj;}dBJv(9%Fwu<8b;7D`nvS5;M zoxO^33)J9wpbLhiu(K>ubhBn{OvQW#?T@#)z$IO@H61kO%8Q1!)v!CwW-zA8Thk?g z6QBX!OPKK?=O!ccEW}E3H{S9Bjf;p2IPVex(vQAky0|HA2AAYXEhqF7(qA8Vr{AN> z50M4Vci)L*!2K|Rc0i@P7@1m~%THidA@|Du_*zK)E@#r<1i@@oR1Lt|=rf3G zswXi#Mm;)O>)wpB*C%VZlCH`)qbe5@rxo3NaOc7kZ#10oK;yQ~x78{ip(sKp`|7E( zOXO2QU!4uW{lie82^rNz(P&ANtQdget>CZke>XMBigr>E--e3SXwkamdagvx=8S=r$p?)(Wwh)5YbFvo{yc0-1T zxyP0{p(o$(s5Gv`^G8qaZlKCbc33IAnY-`DZGP%OKN;R!2h?x^c;AXiVqgu06sRMg z^qk^5+dD%i|NGX|^{;4a#3PweAXszB-i-}gfuTS~?u3*8!kpJFix+f1Tb3M%-o#K$ zTKn7%%O^F)m5F%5iGJ~q*&XtsgsYN-{Wvt{ug_nH7inm(C;}ml0vSb)$Ow5O{Wn~r zBIy(LOkw)b!BUxMbMDXGqvlub0%bp%^KJCo0-$A@%H}3^)zVqZ%Y;N-fZgi%5P*lK zTp<0iKJ4p~|L2$DwEdNjtPi$sUrAEvmkLCuZ0$=cG}9M*GtEwQ+$4y0+G!cQd-uCJ z$L`OfqV2IkUO>lEs$0)-l(yr1-WIfx2Wbm}EN#$+tSu~aUYW&%q4Mc!qKHb;GL~Eo z(B}#_NzE2F>xg%5v-6_^NO~dla6jd?ng z5G7x!A6RUhwwPleym+xki4Tq*)ir~J{kka>X655sddTw z1VSMzt_^|M5J96vD)DSnOdz{bj9+WLNdM}31t4h-deVLHocmw}&M}c@gVSG0we-_@ z90_nd1KKj3okuPh6!fQuW6M~W)BUKV>)h4X(D1o#MHCnOa5=#E3Afj0rC>6sTgOyr z6~zL@|OL^f}oWbEb2rt>Hu4;S{aTBNk4_QzBAc@TvIA*{>sikGOIE`oo?LcnC7Ht^?gH zINJXp!i9*y+@G`sYyY8T=>*e4uDcg!3aq)Fx354=2vn{tPqA(bM;JP;o=@L#o4Vdz ziZ>-+32pw<9&b>!f9?3inUUafX6-tPB0Yu9Y|CV}L)aoz`OSQGnlSNqE^D}uH5yC?bz z=g^0niC#v(X1`n0yM`D+dGP`sr)BM&+3_Kk1U9*{ne)9&s1Pp~}(K+B%ZlLAfKB z5~Z-9>QCeM(1LpX)e$ap{(2Hkpy|q5a{_!>Ss9ac;~14PP%5DM$;fRv15IURNY_?T z=+PcyZR?#{-9D$GE^@)<%>Wva zrpy)+>U~^aAZ`Jl?ncHC!fg#rj(XCKwD%8ycKTbLUpHR&xZjQAgXCUDp#c=QB&=zt zP7vQo>BuQ~Vx_+eD1rw(dcf7|FwX8}aRu>f@*k23KJmhTZpsAEUr>-1*hK^-Xcc+Y zs;G{{g!=e2k)m|Q2b9K9hcMWpA_2w281tHW)$DQYnAy&ZErq)HU0-IY9ilLM=Dbpdx#-tVxP&f7y2fS=Kz@||^ zjh(P62m+;iE^=z26C%kUrI_tzY+zpquXipFuOQ$xTe+t#HGb+k$F-#?$~nc6CoW;AbvONAn!TQ###D_dRtd zGc*vPf^&m5J+NFgM$!rq{DDKWX0RTRSu;t%Ef=2tXVB zwLrEN*Njl6VsF@0j)>!pI)}Q&UwuAOlTh;vw%7Ggmyv78oW51Km-c!oS*#*EE{1!a z^FnnJgO~@_M>)*DCsAasL>m#dl#?-flxz4jx7SNLEk9+l6~1LB6gzGG)FylB?&9fw zW_<3}KQ3K)7W!Twfd+JJMC9{K$mlcz@{u&76|d6%41Bvq;0dsRO_Iy%(R#?kX4DzbQho1@K`bdEkChbxyLLBNTna|Kws7QG4f=MKhomkOPl zlHbsxWRNMPvwbaGNGlud=cy|>yFD1yISh`j!q%pfDYzStvq8={Jw!>i;e`?{Pc``; zmltv;9dREgg}Ukwekfe;r=s>-$^!>=o3gcb%nWse=Ox8Xh6~N~ZL(+0y zekvx)1vMIE5bnEP!5<9v<~}gvP#M}VH>X)!F^Swu_L&tGS(mF>Nm^z52h_aV(&xC= zUox*fX8{?xj6ypgieGw?--DD%zV{3L0AbdlDk|w=HEN1*zj{(sW7V8t&n-;GSij!! z=+UD!TK)jeC#aj3f}Qr3jbn;(kY8ptIXj7KVC~F$C|qOypf``#;NjGuXkclSFK7yg z&(&rcHkoV2@)B!E+4KBuAWe%d+FKIN{YrTfT^(qO3&qBNBnudL))uQoyxiJh=nMHI zOJTY&RepUNvcyB^pm}F65SBkLuBVz1!vIY&5+O*sAOZx-AqZDGx}EB~ ztm|9(Y4*i00*~Y{m$u9YuEgaqa*R1pDH4G(Vq>&5^nC|=xfdWBdUH_4N@p32QsF$!G!r`q0`sVZE-g1JHUK9bmis{C5=!{cLTA@pie0=1Yt% zSByVgJuIMTZRGb`Dp0;YDwU2r^zd|4(-I5X5ef{sgkPtb!OG9&-G0}%kyWK?_ z=vp>tdOlq~VwUzp~=%JL&# zA9uBb&AI-)z2UNQSvJuC%U(&2yX3ieP0&W7RVGh@1&){;u~^8w1GU-}Ya`g=G!CTx zEip6jWXe$~Cq6mcmt;~YX;%XJRFia#BGO!GEsB}Du?o!azFV#|JW4@(aU>ldkoM~7 zKlQX3O2#D9vY8S?)ex)@#?4tk<2+3t0@L;7c{w&Se|<;%?r!(D^NTZeAjM|0i%sca z5=6mC^XT4O%#>i~n{B+8ILch3VmdxPHji zH%`N)aV3LcGMAz?gGCE86=er7teEdOhrnSw1qMtxJ;~I)Ec^r}(#>?B6#=h}BR0rP z<^aSL3k7m+by^0xJ=~_v%k>>8mXa3Vz}JGBJartCxdE&yBMdAJz=)`(sD;&ht}$KC znz>(gV%h{ALX*XUg|Fgg-rfFp8@#~|4*QLby`)E*c>@ByQeQHiw2vaNk&;l zxMKEC>GkWdnh##?Jd8Ww1B~E09ZpLbZ22uFJlmXbw1VaLH0GWS$@*puVUcGkmGp^X z71PQCjd;e&>Rjpqs7i`iD5E;GB9Z7~5f)+egxI&4jX~WRn)F_mrJ2DO+k3}QAyIwG zYLbyq@*9zgws2j|ECC*VA2#kRK7pto`750SIkr5HH@~{srSUm{@7GYGstM#f{^Jl4 zYqb+SyIqq`Q#jogy1kE}>+}!$H@CV03qnaqat76Zj@U8nG(|B7z%(4S4G#9DQ@TEV z$5n0f6liNBA&H>dl<|3=4HpW;wD={AiE0 z)TNv{Un!h_oO6UGs+rMKUmpD;EY6MR%9^QN4fmv~(M{+FrVTcdp*QV9+EuL{PqQ0t zB<7B6fNMs(|E5HLhJ z&>5s#K*paWK1nE38Ox2+J?MKN{aVq0dNFWfSQe68dwu&^4)x(b$(V9H+ik1^drDhX zM+9paR0`cAOav!R!*E5snB2ZyS?+x|8{j`89)A3WPcq4#nW*Y*vq%HI-bfrh= za|!EjJy>tiw5^DQ(!iZ{Fwn*TfHXAq&kp~Qk_a3PV#QOO7Wg*B*Y5n|(Q8JcR2d7t z@MZdmXoSL+x?nF2GsL zL5HjV1pMOTW?LD3YANLtMC3$3R^KuTLLF5NcR|Q%3(FgV5k9Jo?H)Qp>Zj2($6j!g zG-qe~$7?~=hnlkUZbrVcaZ`N6%6ALI0JEgFVJpsR#xs!D|PqKl`DQW5skD6z-IR4ET{L5JmJ+6WT3`0_(z z20?v-bO{}iGDogIdN1^Qku>B5wS@1gM2eNa4SX(ISi z+okh0KlbGT9`bKrWOedXQ=-R-k`?+*~W5Kc~>(7b2)W)^txZ~|=~hUlAQxL$qn34O(CkHdI5dV?G)GWv3f zP$weG+07VF%Ga`}5aIccaIBphPI)M&c|Jjym34zdjsnA1tH_?r)C}vY8Q~j79Z6Eq zcX+r@GDg1s9)*2vStf@m0<&x zO=iP);wqkd;>I3>+``#M<9Oz!$b)>Qp;fc)s>Pm0)Bw%eNXzDY0Lg1Sjp9fkO?U8Z z|AphL8oetlVSA9^yswzq!RoU&FyJ}w>iWY1CABEHs&1@n1xxX`WBM2{H1mMcKC_)Y1wr}Bq1tR-Km*ZU{v zgyo}5V=)Kl(c4RjA{R`5#Bm=Xa=Jp~RGr(U1gYSy>%)?=wdeUQ-nb8^Y#^G|1nQLg zNA0bAYEj*~wvsHCK3s_ba1y+rsPN9MU)?sVjNPS=Mt8I$@rIWXSEP{noF1DvF<^Mi zAHmT15RC>2*B4TtXRen_BfB3R6cR(>dhotHQkCo^#a~LALU@H$T<4jgxi}|Tc3~#k zAw9eXW(WK>6!gsY(A0~;#4G?W_z;Ix9=b7KO@#%aI3NjRK}tarh}9^&QE9|_T9KKr z)0%RkmGKZDXlWNWdzRS8GhLN_L+K8>|9pUIw4{O=&s*cLYZ^xt;@H#|El%Kfl2wP1 zZq|k2mbk>qW_qkhW)Y{LYe3BFGFdb&PV5<`m;=E}oWa#tBx|{~{#>K%ZE0sT1laI7Pep%L3+*}}jx>t~6@Br+5aPoT@vmK)15k*<&i)1FQFYlhwF0ID|+P@#C=zmZ-+aj7<6tH_J z(b6>8F}7Dcw8xH6_^ajlJHbB4M#x?0T4hx@BGLI8q6c@FA$itf_kkrFfwK3&y2F{3 zr9xn%{r0_yKUiMQ_X3e3E`3yAXqvFGhr5@3g9Qm|L7aQanPw$lzr4g~8F9!ycDDCW zEbojpRN(>u<09EJzh_UeNSlW=T4sC9IWCpYq8g-pKP?bsQ~I6_3yqB_UK)FOylP^g z{Fx^|z8Gq`hrt@&g{HzH{r>ebvRA}5#ze_jT~xnKL7o&M{>2tWR~4U1yC+F$qIq@O zTgNa-6ihT)idx^Koy=MGp%TTX+KzK29c{Vdwv(|4B*%YQ77oN&*vIB;xPN{&Sl_@l zueEhWzXhb}(c15DklsTrwrt}BX!>Iear~V*UU1G|x^Lk0hjxDR^2PC8cq3Z#Y3-Eo z$Xa%8fHc3n>l1fd^2C#&m(*)*FIKU>6DRLkoJ?Bhyx$6R*e`Xr7hSgV^Y%P!lNQkJ zE?8#*I=(IUSMV+e+@kBRw1e5*ldW5TsdvKL*xgjvA3L^f^$PRqwIfp)CmDRoO6x=r zN(Rw>1W;XX6*F9!_4J6sH)4Yw68T2a+@nWRLKQ${iYP=kar+T*$yQ?djYq5ELw;_f z?myzpFzXzPFRX=d%YYz6i;m7B>np?3i1GdbiiDFO!a$r(6rff{OJZ>(fx{JYX=+vK z@~s4^#>rDspD|i81;U|C24v7)%M0B_Gh?3M&*`C! zfKr?$7=Z11cf3yXCbz`hRB2ha_Q>v1HP!C0O>`_;ZSJ!kUAf=PH%ZDXYR*SH0)}Tk?Liq^1dp{>H5D<7T{A%QEnEBS zbXo)TDOn}?#~wJ-r0y;AZwcVCr?tZ7!}TZIm9pH2?{?8^Oo0>n?m?PX7UX?x?+)!* zyn0Al3pN>!rfbni@L3wAcz)C9GHstg$S6N8TB>tDG!Zw!n%_sV-@HSA_O@P@K8!`GZ$}gpuz>tMG^gpj(80u%8IMu1mv zQc}ruE1R~>0J(26v=dRRTRM_b4C6UnNwZ!WNN(`TX{>IZyd4fgk z{s#BghS=gPW)-FyRL^o-KqP{#C{*$>kr=5&#j2~J^zRlMWTtF~B-k~+o>Eff%a3;N ze^6^G_sMHg(Q-_5_~dVy^TOw({_LfOwbv<<;|2&^V&QSZz@1n%!p(7BYgZ<(Qc=e* zNF*h4qXttwR_%umj!k!KA`yczc|y$VD^*L0$o)Z64m3+!w-zY~1zO5Ql3iy8j*I1~ ziZh9~5KSja_c+C7`@#%jGhI+k9a9(w;*5n1B&Bx)OMZdWIQNot9Uy18#X^ z`9v2x){`}ye58CFZFW8wITR_(R30Qp?Ryvj`86gwpuPl94+Ob)0wIqZA`AZhoq{*k zpT@Szx@5VtY>^aV-{1g2a#t?PjgCUek2g?GiO3CG@$a||sdtyasVpH7ZI_FT;>Y+! z`DcjHKP+0+e6$`Z0CZFxRA6jUw4J^zpD+jph^d0!o&txM>Ch?x1;U0^DkDSNq*X`r zv6&dx1BFqYK!ZI}-rT&p24PND#d|MmdWi z)H)*UwRFV21$%=(ENmwb^;35Eyy;2Vd}1?(MP{UX0ZSM;$a4|>vf^x_E%Vs6yRc3y z)lsl%j}9ST4ql7ZN7y9WE9Wts`5@{+m1nj*erf$nz>gBh?-Cfn0(N__@Xz2_hL{wwYJ0h)yD41l+6@A^VI1CKs(4Yy@4S@gvR2_jImBx98IZep#~** z!;x0iE+KpxzGt!-?mP|2>{xq~Ey@&Pi!Evzcgs0n@({w+QyQf!pm<+1kAsT$i~?;? ziyE6kVq2sZuTuLYW9&OvX`Qmf+9E$;|iW$3#s3h-JrBL3TCGKo?*X`_tKd?-7r@ z_0kQv+Ra%;o8){h>>BeU6!@`}g)xD@-L#SfDfBDeVOf4EhG76)H+b}{xqPmkRX zPI7Yg;^_#c^?D5&7+VZK9Lc0W&(D#5U<{2kF)fCE;kfhj%bZ{zkVo)yf&za@spB=i zzKO=k!66Y-p$N4s_v&yDeU}h+Ob#}Kuru%5q#mXmEumA&%LCQgsI?^S^5q$VRcC;; z(Fo&Jfj#-R{2CvfzndcMvm}9@kPdFRvHb7v*b3S->+Qm)^Wu6nuh8ibYrGS?z>AHgyeBW^u(_WZv`A*@QJzVjx~~jpXUS` zc(yNrwn!UN1OYsC^fRHkO%HyNR0)AAivYDx6!SEgNz{9&}}Z) zg;XtOUw959`Vka=j)8B-%LP&Y6o&@O!W zHM1mIa*p`nrBTz875{vFAV9dQ7_|Ec=7LL)%aHvkT=U|p2b3pFEKp81#W#YV&x=iy z4Q~Adn}Z6#V7_O+0}B2(V;I-;v|p9R_{#agoUg7*t7~H+GN%wO=66}2Ap&mVR&y!7 zXn^R>;NxN@+o$)?eueG%&H>Fix?vY+w3l}Gnl+qh+!fUIY=LaYf&+ExS<^iV;78M! z;JE7q!!h2akP+mJeU0e0FH4%v)OQ}MXugUkk@1d6yPO6#*@<_Yr8#AA$%om=@p}j0 z%b!a1br2jSsmg1_>FaqlzIe*soj#$QC_2cC9c)0SIxt;2lkMAW+~ET~BWb*ZywG82 z%_Sj&iY=qoV!Su*=~<4?KmxuVvGW&8D2Dwmej36Yvc;VkOzvPalZ(-37({ri9e&fe zXRgOy@v;JT{ZWP^!S+s9U|Dr4ZL$6>7l=JbpP_|uBft&;D}_onmr67&QoneUJF|4b z`b-G-s^iPq5BPK$AI9UOyE0J8lLL}K+gM$gMiV{Kd!t|8j z5JROnLx!^Cb)lQ8C;SQK|`-+XyhuX<_s= zYICX>!8U1gD~cQl+UX~$znt2|ZKM%YY=Rhd|l{;Ztn1fytlAy zA*SW(#p?zLMsZd)MV4z3)t-Sws>E!c*9?EfIk$uGdVa^*AeX)=Aytid&pW&elwc>Y z%Z%&?V=Z+IrK-l1U|r82t33nZR-v&Sb|n!-GVJg~%EE69UYb02kdK$2It& zzfYbYFc8ECCH>0T)rcq|`I0fVN^W)h`Bhh!me>7inG~eOf^yX^-EU3Ze>TnXtUjbv z6!txzOTq^i2=uC)nUE(EIob2%K@4^RnbFHpZlF>~uoSA4g_;%0!4#alg$!!JAq()i z-#ufpVsm-DruC{Vl8o|HTxN?fspu8)L-ASPj$Gmy%XvzjRc7M{^;OGNWh5h2!lZlv zfosoq`bT4`%*?#D7oxa2tK77hfp|Om)rUDD>Z(TH2HFF_UO;9K7{?a&&upH7E=pu_ z^pnb?L$trY^cZLt`clBj0{3RD%rK?m*FkQiCXdlMqT(Tc2zm19VihFSwWgsTeBFyz z%YL#mW8A%*+P=GR{|;_{nQcvzleoJfd%}vR?&$uy-gF20z?lp>I5*(r!`BfMCH=?NRJL-Aq$e9#>t2P!sXwoAI!5I3jdeIAcra>ln>&i65OA-rl*rHF=o~ z&Ume+haK*2EGI$N*%+6y=CN|NL%_ZN>Qv@<(y|We2Wp6yqvK6soP^AerH5G7tTm>9 zV`+B&&54KTMfq%OW@UQ4*+O7FDt#B2@nh25lZA9jnJPRZbLoaO@Uo1laO1?&&t?Jw zanJTQp;UWRUvWMi9)5_<+G{7`1_4gBTEdDIPtLHTLCJl2qh3W`Ee(cIK zp*r+6GF-H*Aho8rK+14Cgp_xVe?)J#>q;;C0Hcq+(9ag?Z*ci$(^gi~YD$$nrb`?D z3-?l6N{Z@UnBZ%SNtH3CENkZOIK%g@MaN&+>ay?wHF6@}z|@pVIO= zW)Er$>>GBPdh#FICS$d#;5-ltFy(ntuVjkktI8B2=hI)?r&sFjof$mm$7prUk*y|~ zJd!5hKeEV`fC#`{F5^3@E_1lfY?2+{*^RY+Cl-#Za)`7MYWMX06-3ok8;~EVaoVKauSW zgrg~#K`kf;Rn6k>B^{ z(Q<)8QK8wz31Z=q2hl>RdMQNXpgZxu0^-TJyuv0Oy{$=g3HM3bmZVG!dU zUk-O)5BG9X)X!#>QtS4G^BHPBKd(Qn@W?Gh_@Zfowp6`bB*wzQ;+o2=MD>`2t6~4> zMaP1jB##mhL6>NCpW$xA6pT=pTY!=`ZTr6~oT{PaP^NKgDW2OG#40J`N9qen;CH0T@`T3$qT2}Z ztG=%0YP$pAdQi44{*ctaCMSNo-QBHc^3FtwYQtl>vjw>`$a&!`xC3NXsDY$)l0&`) zokqMsaEh>d5ziasbj(RjT#Ia4p($Xl4@BFcxb}h4HG~hysD)AAg`gCe1qQo-qBTJb zcSMj)0)cLME-F-^7D93!1zO5)UQG#$#Ia|PJb3|-qC%2!Edwj^zL^oL(p?!oUxwd7 zK@^P5o7cffM7HD;Wm4fPhm0Ax1U65SWBR9F@@cb0Szmzw*#t)46$WOt7`DK zYjer3h8H6|8quqrsd8MVPs#RCiRQxV&A)iOD~@-!#0!a6V}jrm60oVxLXf!$2=E)l zb~*&&RtA3ImzkT(lz+!Bqrd@n3Xqsf49kSy^kyxSNGuWmf{l~Wj2fAt$Qy+!#J58c z^~f6{udCMNvATRcz1TU)NNAA=*k3p~>pi*OcNRkYaZKdt?Vg@RK6-Prf;)8*4ZQLe z)JN>C(SUX^M;jCyEu_)Cu47^u7aFg|(1bOn;SbNxOv}$kKvp6tsD%U`BEhJ`|dNh=WiwgHJVc9I~bY#fBZ?SLln!#=Dhv`6Q}yA&`2StXaYKo8{( zzFMQ=yE9%3fV#3I-S6GME~~K|l*65pjX_tZq%SoE~!v#y(&N zA8F8<`A#qZ1(_NjuQmYOB`K@bWj!?|0nKkQrwek%ht&#wD6%+CG;YH>lX)*VC!I0t z1=JiHyU(r@P5dPUebACi9E*S`rsl*dW5 z-N5itDz+6U#>hvSQVPqZEX?|q#=#q0;Bt~heF+RPl#_7IasbvkfWTJe;*L>%3pCqf z#nraV@ZHc7zhrln3<*_kQeaceSUQrE9JC-6o@M$dGl?`L%Vi?z& zDq3whU;4pc|GqTvP6t=XP(!_qrLKiUeg}#tq!3@g3(kP`th8-nDzi%vCc@R7^f^drSSXj>q;XgZW_ zp`AIpqzMGN@7K!-+ECJ1^jXVVu?u7F^u;T#yZ+s!DE=~oYB!w@U*+gr8v`tYbxTdb zn)UF2D`Ap#Q?&y{iDcuSn(9aDgJ!g<)fX?SCf6EE8U(-UNRgf*2CrW2GDe1z-uOXk zEt|E*JF{u=0a48!vZH&O!2c&4s6qMH1=4>pwxZ#AaR0$kGB(J60G0{|^Bq9oU(P0XHoH*{r8=mkB#d9^#z24Jx0JA52@u!Y5vhcfM5|NQ;FpSgC0N!ft5 z!;9uyG%q`Tq43A~^w-+OViDO!D>Pz9-Br#nskXWwm8XnA<9mBZ1o9rT4TbHWya%I% zJ+r^RN9G1MilobsizFVDk+7IeA9loy4hyd>Zr7Gu*5jmO;BK@=_Xj7bc+(!mLH^YeW{p;KA}_RTaO{k zTamC&p*X>Z_nN|-RlT)fw}JgUoU6CRW|>jUc*~4id5_?b+(M$oUcG0wz7ZjWFUcU< zNO?I`lCso3J96^h@vdJaKNPGVwpaoOG41&0J0`x z>~)GqI`;614RN8|O>r_eHhN8em=-g>6+MfzLm3#7cUveNT@s;58;QKpdvseX<8-yd z-&nvV`3&a1XZZvjMqKQKhZ7Uk4Qjp z0-XJWL&9BekGoL?ER(ZwR|&6_kC%CHUVTP6C9>#g;oE;~$D}5OgC=eClsqkzt7Sug z|6qgngU-G*%uiz$o@NzBP~yR^7KTD|Ztmi-8CdHik}Uh}q0#y2$|~kWfiMk6KnB6aTY+E%IxSb^m0b+mIpuy^5B|JxJhx z_Ob=x9uo1NjOYo{<6ph3H^^?t|1|4^0`zhIqh35f*S~uHM1b*sq(}zn_(w=o0FQq? zjiLv1|7-ULBf#sQzDZWV?7w;ioB+6gvU*;?8Q?$7xuO8jf3hM8fbu_jlL1)#BQpg6 zH3Y){E={0{INP3sfBObNO{tXt;HNl@0^nMPQ~{6wDt2oDuKqPrrw91I5d=2@JpJp; zrzs%%UuldbpzR;Y+5*o15w9cQ?jJF`06zYYegRY z2n8VgBg#ks;Xjg!1t9$+okYMW*ngKP-L6HBQs`3wf6vN|>#86~sIM$pG=-K@40U~* zW$N;+u*tl@mK|?Ur8NLH3-KkgDOl`?egC8?-pq^(J zfbWdM@dZ-hQzh~0*TyDkG7du!DxIksCS3xx<;8XjM|cD_O+>}M?IioNa%>$nrfk3{ zwgIsG6sB0o&v4Zu@YHysYB{u+dd^+4?Pp^-OtzBswFEr&YmiHW2~A`Hjqt~n2|T$j zN1LG*>``WLCbe0TEY^IwsnCUzB6E>n#EjBn)PdRzEQ5t2oty8EEW>u_vO!-`j_~5+ z{mhJYTP;C~))v-uRs(-|CZ2Ymn?pP{5-wm|1pf3aMp3HaKpI+QRA~~vqO(FBZE>W_ zRI3~XORREjh0Ku%RJS}xCxmC)B1Z0#QbwAQh4t`7p^63wNI6EpZ)ZcSKnx zPx4Q!QfQhrb)131FPb?|-BY977Q{_8P3rR86teEY+mpF}CMRD*%61XjO4F0K9Eswu zwkT77x>De++n1M=o{_@NbZ*|_^xNB_yc4HO>K8{@PsvvIt`r|}Sd^pjX2IBYmmgYJ z6)p*rcV5?cqJOb}=B!AA5>2-@fy%PzpS$K)?@O5z!-EN`MM2hqT_DC zRo51YN^OHS-aZ)rB&=*Zy0JT=z-nm%r+2H5{LQ}nG2T9Q_x5rAC^{(K8hzR`mscU! zn31%4aOKf$@q9Pe^W%5q^o(;#2SL{S2ygc%hacO$<(shF0qgu-*~`-Ar`iX2 zM0@yqth^Yz!e;N86rs9FUUbddOBECBwl2?omwh#?)5_xNm5mn4d}W^LXBFiL!JiLe zo=59f<{m4GeR(t5aMF9#;P#3v!Qv@vc6B&Z_oRPTOnT-1vEAu$u+Kcr=EWV417mv5 zc^nZ~`VQU*3VOfbQ_KX`o(}>1N12C2<;#tILS8#49XP_jv`bKYwW)W#dzNX7!Ugv! z_EEil*^|tatXubX+--IV5ycHRPi(V|2#(?X=Z}Y$1L8L+*~a=E1}EJtldIwW_Afg< zaqn*$%M}+MSyp53d*7;Yx4Y98g9GIoTE<)X#-ZnqpC_kqFP(|pf8)zizcb5Fk6x;{ zTkd((4ab+7^LsCHUQjWO`?}0)T3<)LtA20xu74nMup!&VX;RyLCWD{hyHO$K`*@f4E-J@W zRN`Iar`6f?917B2QMX}!kGqjoYe8iA92G@Nm?xH)WB=$9A%CpTZK-xRD{fOrJ=EdcbUkf;A~g}lcn&+zNuYlIU;sRKIFgsg|Sp#bUY(Wm2FUh$@WI2{{xC`x67 z0iQxv16C_Ux`ZVA?(i#1$m+u@3X#baTGH2-6%?iUl>?IOTod`O9GqQ<$Q28hz`I2` zgHZgq5X~f3j4J{_{U>Zxgys;ylLqom;yp!ZIuTAO)^NMWQB(kzqEuysHzwfQMM#%S z>!zo5rzYyBYh$fqq~uNOMQ&~IXmYkSMXAY5jTTari@lxes#!jP0ijz0Ld^q%{6>3G zY37(?6Z9ym_vg`OZOlqMm&?JYVIi{mm10;u?S5i+JqNdsfUjsUAq0;rK?a0nUIM_g zJvgldev51?LEjNHibgZSXmlX~S^$vW7RAO{vFvG>TPj(@v=m^YSORO~Lvd_X+;$f! z5g%nO&+Oj_TWJSY&XqBA|52P%h9=>HQe;f1c@uUI@PN7(;=(|NY8=l{wQeB}p|YH! z*RBBSDWDq4P%kDj)NQwrHlc10pB`!tR4v${c`{UsQw+8EmLymG@^1H^!j=7DvM2+-GX)4!2EFD7@GGYgQ zWvH%&Y(1ieJ{@+a?By1SJ9oSW>l)xOk{w`Zt zWmFjAb3l=csK%vtkOk2v=~R~OUeKok#qAM@`b4!&K_R>UUd61Qk@4;B~# z{~^2`mfc64dYV6vXdSwi@3xXfQ8VNy%2+Csc6Q7oHWoc*n~-=TF6_ArT5C74u~#b? zE?sEzD@PA!Fq{MFsxKp=t_80yN3+O6hnFRUI6|Cg1j1V^8J0%}8>c>H>we>chH`L0 z%WM3)9GMaYxD}wlt9~|~{ef+S`4tjx2Ga2M_XO6&=@n=)S@G7xCx4r3Q`DGe6a_wz zHX+M&h>g1{&{RTOy2wxaD5!sL0{zDNYZJ1LaS(3cB5lm89Ep@l&}fAY-cgB+$fh)3 zUN{&FlWV|s*-f9Uhgl+|g{v!(8d1KDp4(=?plVe}i=bvzfUYy4Q6n5!h17`HD_K1P zI;8!fn#(4Z&J3Drj73$F9IW^^%i$1cprkmOdfJ?(E+zu|S~*o^z*?m|x>N+tW!C<$ zNFs1mM7`<_D4!1?XrTB?n~)W5fzRKEs?sWwnA9f%<#+NJ)UX!Q)Q&I}5dHa6zogN=pU!i%6I=jAFLVtf}zqjByGdgq?Rqir;L za2u0d0Ylx|we zdS3?R+($Y@fK5m*&H({iU>{_&Kx-RA^}mn4Bh;KuPs2>0ssUBDz@eQq)tW5R1(M~4 z0%>3x_T7y%%|?}owaQDKS*0MS9OTTE?h~E6Lq9UpVrwPEY=@fj&=LqJLnt0bGE~LA zG*t(`i9%y>&_SetU)D;Z{ZlPykPs#v*Z4+*m3qaQ!5}sZ5?i);$Zt5&6%Cl*P_N3>Kc0g{ zEWxL;RW?z8a~?>3zjV>lgU*xbns{Qp1op0%SQTCW+%LH}yaCy;cU^~MrTzgk{a+pc diff --git a/dist/search_data-4FC63431.js b/dist/search_data-EE7CC24E.js similarity index 77% rename from dist/search_data-4FC63431.js rename to dist/search_data-EE7CC24E.js index f17ddce4..4162a455 100644 --- a/dist/search_data-4FC63431.js +++ b/dist/search_data-EE7CC24E.js @@ -1 +1 @@ -searchData={"content_type":"text/markdown","items":[{"doc":"This module defines the setup for tests requiring\naccess to the application's data layer.\n\nYou may define functions here to be used as helpers in\nyour tests.\n\nFinally, if the test case interacts with the database,\nwe enable the SQL sandbox, so changes done to the database\nare reverted at the end of every test. If you are using\nPostgreSQL, you can even run database tests asynchronously\nby setting `use Wanda.DataCase, async: true`, although\nthis option is not recommended for other databases.","ref":"Wanda.DataCase.html","title":"Wanda.DataCase","type":"module"},{"doc":"A helper that transforms changeset errors into a map of messages.\n\n assert {:error, changeset} = Accounts.create_user(%{password: \"short\"})\n assert \"password is too short\" in errors_on(changeset).password\n assert %{password: [\"password is too short\"]} = errors_on(changeset)","ref":"Wanda.DataCase.html#errors_on/1","title":"Wanda.DataCase.errors_on/1","type":"function"},{"doc":"Sets up the sandbox based on the test tags.","ref":"Wanda.DataCase.html#setup_sandbox/1","title":"Wanda.DataCase.setup_sandbox/1","type":"function"},{"doc":"This module wraps the Rhai engine and provides a simple interface for\nevaluating expressions.\nIt also sets some default options for the engine.","ref":"Wanda.EvaluationEngine.html","title":"Wanda.EvaluationEngine","type":"module"},{"doc":"","ref":"Wanda.EvaluationEngine.html#eval/3","title":"Wanda.EvaluationEngine.eval/3","type":"function"},{"doc":"","ref":"Wanda.EvaluationEngine.html#new/0","title":"Wanda.EvaluationEngine.new/0","type":"function"},{"doc":"Handles integration events.","ref":"Wanda.Policy.html","title":"Wanda.Policy","type":"module"},{"doc":"","ref":"Wanda.Policy.html#handle_event/1","title":"Wanda.Policy.handle_event/1","type":"function"},{"doc":"Used for executing DB release tasks when run in production without Mix\ninstalled.","ref":"Wanda.Release.html","title":"Wanda.Release","type":"module"},{"doc":"","ref":"Wanda.Release.html#init/0","title":"Wanda.Release.init/0","type":"function"},{"doc":"","ref":"Wanda.Release.html#migrate/0","title":"Wanda.Release.migrate/0","type":"function"},{"doc":"","ref":"Wanda.Release.html#rollback/2","title":"Wanda.Release.rollback/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html","title":"Wanda.Repo","type":"module"},{"doc":"","ref":"Wanda.Repo.html#aggregate/3","title":"Wanda.Repo.aggregate/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#aggregate/4","title":"Wanda.Repo.aggregate/4","type":"function"},{"doc":"","ref":"Wanda.Repo.html#all/2","title":"Wanda.Repo.all/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#checked_out?/0","title":"Wanda.Repo.checked_out?/0","type":"function"},{"doc":"","ref":"Wanda.Repo.html#checkout/2","title":"Wanda.Repo.checkout/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#child_spec/1","title":"Wanda.Repo.child_spec/1","type":"function"},{"doc":"","ref":"Wanda.Repo.html#config/0","title":"Wanda.Repo.config/0","type":"function"},{"doc":"","ref":"Wanda.Repo.html#default_options/1","title":"Wanda.Repo.default_options/1","type":"function"},{"doc":"","ref":"Wanda.Repo.html#delete/2","title":"Wanda.Repo.delete/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#delete!/2","title":"Wanda.Repo.delete!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#delete_all/2","title":"Wanda.Repo.delete_all/2","type":"function"},{"doc":"A convenience function for SQL-based repositories that forces all connections in the\npool to disconnect within the given interval.\n\nSee `Ecto.Adapters.SQL.disconnect_all/3` for more information.","ref":"Wanda.Repo.html#disconnect_all/2","title":"Wanda.Repo.disconnect_all/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#exists?/2","title":"Wanda.Repo.exists?/2","type":"function"},{"doc":"A convenience function for SQL-based repositories that executes an EXPLAIN statement or similar\ndepending on the adapter to obtain statistics for the given query.\n\nSee `Ecto.Adapters.SQL.explain/4` for more information.","ref":"Wanda.Repo.html#explain/3","title":"Wanda.Repo.explain/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#get/3","title":"Wanda.Repo.get/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#get!/3","title":"Wanda.Repo.get!/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#get_by/3","title":"Wanda.Repo.get_by/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#get_by!/3","title":"Wanda.Repo.get_by!/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#get_dynamic_repo/0","title":"Wanda.Repo.get_dynamic_repo/0","type":"function"},{"doc":"","ref":"Wanda.Repo.html#in_transaction?/0","title":"Wanda.Repo.in_transaction?/0","type":"function"},{"doc":"","ref":"Wanda.Repo.html#insert/2","title":"Wanda.Repo.insert/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#insert!/2","title":"Wanda.Repo.insert!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#insert_all/3","title":"Wanda.Repo.insert_all/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#insert_or_update/2","title":"Wanda.Repo.insert_or_update/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#insert_or_update!/2","title":"Wanda.Repo.insert_or_update!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#load/2","title":"Wanda.Repo.load/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#one/2","title":"Wanda.Repo.one/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#one!/2","title":"Wanda.Repo.one!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#preload/3","title":"Wanda.Repo.preload/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#prepare_query/3","title":"Wanda.Repo.prepare_query/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#put_dynamic_repo/1","title":"Wanda.Repo.put_dynamic_repo/1","type":"function"},{"doc":"A convenience function for SQL-based repositories that executes the given query.\n\nSee `Ecto.Adapters.SQL.query/4` for more information.","ref":"Wanda.Repo.html#query/3","title":"Wanda.Repo.query/3","type":"function"},{"doc":"A convenience function for SQL-based repositories that executes the given query.\n\nSee `Ecto.Adapters.SQL.query!/4` for more information.","ref":"Wanda.Repo.html#query!/3","title":"Wanda.Repo.query!/3","type":"function"},{"doc":"A convenience function for SQL-based repositories that executes the given multi-result query.\n\nSee `Ecto.Adapters.SQL.query_many/4` for more information.","ref":"Wanda.Repo.html#query_many/3","title":"Wanda.Repo.query_many/3","type":"function"},{"doc":"A convenience function for SQL-based repositories that executes the given multi-result query.\n\nSee `Ecto.Adapters.SQL.query_many!/4` for more information.","ref":"Wanda.Repo.html#query_many!/3","title":"Wanda.Repo.query_many!/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#reload/2","title":"Wanda.Repo.reload/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#reload!/2","title":"Wanda.Repo.reload!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#rollback/1","title":"Wanda.Repo.rollback/1","type":"function"},{"doc":"","ref":"Wanda.Repo.html#start_link/1","title":"Wanda.Repo.start_link/1","type":"function"},{"doc":"","ref":"Wanda.Repo.html#stop/1","title":"Wanda.Repo.stop/1","type":"function"},{"doc":"","ref":"Wanda.Repo.html#stream/2","title":"Wanda.Repo.stream/2","type":"function"},{"doc":"A convenience function for SQL-based repositories that translates the given query to SQL.\n\nSee `Ecto.Adapters.SQL.to_sql/3` for more information.","ref":"Wanda.Repo.html#to_sql/2","title":"Wanda.Repo.to_sql/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#transaction/2","title":"Wanda.Repo.transaction/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#update/2","title":"Wanda.Repo.update/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#update!/2","title":"Wanda.Repo.update!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#update_all/3","title":"Wanda.Repo.update_all/3","type":"function"},{"doc":"This module exposes functionalities to interact with the historycal log of executions.","ref":"Wanda.Executions.html","title":"Wanda.Executions","type":"module"},{"doc":"Marks a previously started execution as completed","ref":"Wanda.Executions.html#complete_execution!/2","title":"Wanda.Executions.complete_execution!/2","type":"function"},{"doc":"Counts executions in the database.","ref":"Wanda.Executions.html#count_executions/1","title":"Wanda.Executions.count_executions/1","type":"function"},{"doc":"Create a new execution.\n\nIf the execution already exists, it will be returned.","ref":"Wanda.Executions.html#create_execution!/3","title":"Wanda.Executions.create_execution!/3","type":"function"},{"doc":"Get an execution by execution_id.","ref":"Wanda.Executions.html#get_execution!/1","title":"Wanda.Executions.get_execution!/1","type":"function"},{"doc":"Get the last execution of a group by group_id.","ref":"Wanda.Executions.html#get_last_execution_by_group_id!/1","title":"Wanda.Executions.get_last_execution_by_group_id!/1","type":"function"},{"doc":"Get a paginated list of executions.\n\nCan be filtered by group_id.","ref":"Wanda.Executions.html#list_executions/1","title":"Wanda.Executions.list_executions/1","type":"function"},{"doc":"Represents the result of a check on a specific agent.","ref":"Wanda.Executions.AgentCheckError.html","title":"Wanda.Executions.AgentCheckError","type":"module"},{"doc":"","ref":"Wanda.Executions.AgentCheckError.html#t:t/0","title":"Wanda.Executions.AgentCheckError.t/0","type":"type"},{"doc":"Represents the result of a check on a specific agent.","ref":"Wanda.Executions.AgentCheckResult.html","title":"Wanda.Executions.AgentCheckResult","type":"module"},{"doc":"","ref":"Wanda.Executions.AgentCheckResult.html#t:t/0","title":"Wanda.Executions.AgentCheckResult.t/0","type":"type"},{"doc":"Represents the result of a check.","ref":"Wanda.Executions.CheckResult.html","title":"Wanda.Executions.CheckResult","type":"module"},{"doc":"","ref":"Wanda.Executions.CheckResult.html#t:t/0","title":"Wanda.Executions.CheckResult.t/0","type":"type"},{"doc":"Evaluation functional core.","ref":"Wanda.Executions.Evaluation.html","title":"Wanda.Executions.Evaluation","type":"module"},{"doc":"","ref":"Wanda.Executions.Evaluation.html#execute/7","title":"Wanda.Executions.Evaluation.execute/7","type":"function"},{"doc":"","ref":"Wanda.Executions.Evaluation.html#has_some_fact_gathering_error?/1","title":"Wanda.Executions.Evaluation.has_some_fact_gathering_error?/1","type":"function"},{"doc":"Schema of a persisted execution.","ref":"Wanda.Executions.Execution.html","title":"Wanda.Executions.Execution","type":"module"},{"doc":"","ref":"Wanda.Executions.Execution.html#changeset/2","title":"Wanda.Executions.Execution.changeset/2","type":"function"},{"doc":"","ref":"Wanda.Executions.Execution.html#t:t/0","title":"Wanda.Executions.Execution.t/0","type":"type"},{"doc":"","ref":"Wanda.Executions.Execution.Target.html","title":"Wanda.Executions.Execution.Target","type":"module"},{"doc":"Represents the evaluation of an expectation.","ref":"Wanda.Executions.ExpectationEvaluation.html","title":"Wanda.Executions.ExpectationEvaluation","type":"module"},{"doc":"","ref":"Wanda.Executions.ExpectationEvaluation.html#t:t/0","title":"Wanda.Executions.ExpectationEvaluation.t/0","type":"type"},{"doc":"Represents an error occurred during the evaluation of an expectation.","ref":"Wanda.Executions.ExpectationEvaluationError.html","title":"Wanda.Executions.ExpectationEvaluationError","type":"module"},{"doc":"","ref":"Wanda.Executions.ExpectationEvaluationError.html#t:t/0","title":"Wanda.Executions.ExpectationEvaluationError.t/0","type":"type"},{"doc":"Represents the result of an expectation.","ref":"Wanda.Executions.ExpectationResult.html","title":"Wanda.Executions.ExpectationResult","type":"module"},{"doc":"","ref":"Wanda.Executions.ExpectationResult.html#t:t/0","title":"Wanda.Executions.ExpectationResult.t/0","type":"type"},{"doc":"A fact is a piece of information that was gathered from a target.","ref":"Wanda.Executions.Fact.html","title":"Wanda.Executions.Fact","type":"module"},{"doc":"","ref":"Wanda.Executions.Fact.html#t:t/0","title":"Wanda.Executions.Fact.t/0","type":"type"},{"doc":"Fact with an error.","ref":"Wanda.Executions.FactError.html","title":"Wanda.Executions.FactError","type":"module"},{"doc":"","ref":"Wanda.Executions.FactError.html#t:t/0","title":"Wanda.Executions.FactError.t/0","type":"type"},{"doc":"Module responsible to generate the fake gathered facts from targets","ref":"Wanda.Executions.FakeGatheredFacts.html","title":"Wanda.Executions.FakeGatheredFacts","type":"module"},{"doc":"","ref":"Wanda.Executions.FakeGatheredFacts.html#get_demo_gathered_facts/2","title":"Wanda.Executions.FakeGatheredFacts.get_demo_gathered_facts/2","type":"function"},{"doc":"Execution server implementation that does not actually execute anything and just\nreturns (fake) random results.","ref":"Wanda.Executions.FakeServer.html","title":"Wanda.Executions.FakeServer","type":"module"},{"doc":"Facts gathering functional core.","ref":"Wanda.Executions.Gathering.html","title":"Wanda.Executions.Gathering","type":"module"},{"doc":"Check if all the agents have sent the facts","ref":"Wanda.Executions.Gathering.html#all_agents_sent_facts?/2","title":"Wanda.Executions.Gathering.all_agents_sent_facts?/2","type":"function"},{"doc":"Adds gathered facts of an agent.","ref":"Wanda.Executions.Gathering.html#put_gathered_facts/3","title":"Wanda.Executions.Gathering.put_gathered_facts/3","type":"function"},{"doc":"Adds timeout data to gathered facts.","ref":"Wanda.Executions.Gathering.html#put_gathering_timeouts/2","title":"Wanda.Executions.Gathering.put_gathering_timeouts/2","type":"function"},{"doc":"Check if an agent is a target of an execution","ref":"Wanda.Executions.Gathering.html#target?/2","title":"Wanda.Executions.Gathering.target?/2","type":"function"},{"doc":"Represents the result of an execution.","ref":"Wanda.Executions.Result.html","title":"Wanda.Executions.Result","type":"module"},{"doc":"","ref":"Wanda.Executions.Result.html#t:t/0","title":"Wanda.Executions.Result.t/0","type":"type"},{"doc":"Represents the execution of the CheckSelection(s) on the target nodes/agents of a cluster\nOrchestrates facts gathering on the targets - issuing execution and receiving back facts - and following check evaluations.","ref":"Wanda.Executions.Server.html","title":"Wanda.Executions.Server","type":"module"},{"doc":"Returns a specification to start this module under a supervisor.\n\nSee `Supervisor`.","ref":"Wanda.Executions.Server.html#child_spec/1","title":"Wanda.Executions.Server.child_spec/1","type":"function"},{"doc":"Starts a check execution.\n\nThe checks are filtered leveraging the `env` and evaluating the `when` condition using a best-effort approach.\nIf non-existing check IDs are provided inside a target, they will get filtered away.","ref":"Wanda.Executions.Server.html#start_execution/6","title":"Wanda.Executions.Server.start_execution/6","type":"function"},{"doc":"","ref":"Wanda.Executions.Server.html#start_link/1","title":"Wanda.Executions.Server.start_link/1","type":"function"},{"doc":"Execution server API behaviour.","ref":"Wanda.Executions.ServerBehaviour.html","title":"Wanda.Executions.ServerBehaviour","type":"behaviour"},{"doc":"","ref":"Wanda.Executions.ServerBehaviour.html#c:receive_facts/4","title":"Wanda.Executions.ServerBehaviour.receive_facts/4","type":"callback"},{"doc":"","ref":"Wanda.Executions.ServerBehaviour.html#c:start_execution/5","title":"Wanda.Executions.ServerBehaviour.start_execution/5","type":"callback"},{"doc":"","ref":"Wanda.Executions.ServerBehaviour.html#c:start_execution/6","title":"Wanda.Executions.ServerBehaviour.start_execution/6","type":"callback"},{"doc":"State of an execution.","ref":"Wanda.Executions.State.html","title":"Wanda.Executions.State","type":"module"},{"doc":"","ref":"Wanda.Executions.State.html#t:t/0","title":"Wanda.Executions.State.t/0","type":"type"},{"doc":"Execution targets.","ref":"Wanda.Executions.Target.html","title":"Wanda.Executions.Target","type":"module"},{"doc":"","ref":"Wanda.Executions.Target.html#get_checks_from_targets/1","title":"Wanda.Executions.Target.get_checks_from_targets/1","type":"function"},{"doc":"","ref":"Wanda.Executions.Target.html#map_targets/1","title":"Wanda.Executions.Target.map_targets/1","type":"function"},{"doc":"","ref":"Wanda.Executions.Target.html#t:t/0","title":"Wanda.Executions.Target.t/0","type":"type"},{"doc":"Represents a Value used in expectation evaluation.\nThis value has been already determined given the conditions in check definition.","ref":"Wanda.Executions.Value.html","title":"Wanda.Executions.Value","type":"module"},{"doc":"","ref":"Wanda.Executions.Value.html#t:t/0","title":"Wanda.Executions.Value.t/0","type":"type"},{"doc":"Function to interact with the checks catalog.","ref":"Wanda.Catalog.html","title":"Wanda.Catalog","type":"module"},{"doc":"Get the checks catalog with all checks","ref":"Wanda.Catalog.html#get_catalog/1","title":"Wanda.Catalog.get_catalog/1","type":"function"},{"doc":"Get a check from the catalog.","ref":"Wanda.Catalog.html#get_check/1","title":"Wanda.Catalog.get_check/1","type":"function"},{"doc":"Get specific checks from the catalog.","ref":"Wanda.Catalog.html#get_checks/2","title":"Wanda.Catalog.get_checks/2","type":"function"},{"doc":"Represents a check.","ref":"Wanda.Catalog.Check.html","title":"Wanda.Catalog.Check","type":"module"},{"doc":"","ref":"Wanda.Catalog.Check.html#t:t/0","title":"Wanda.Catalog.Check.t/0","type":"type"},{"doc":"Represents a condition.","ref":"Wanda.Catalog.Condition.html","title":"Wanda.Catalog.Condition","type":"module"},{"doc":"","ref":"Wanda.Catalog.Condition.html#t:t/0","title":"Wanda.Catalog.Condition.t/0","type":"type"},{"doc":"Represents an expectation.","ref":"Wanda.Catalog.Expectation.html","title":"Wanda.Catalog.Expectation","type":"module"},{"doc":"","ref":"Wanda.Catalog.Expectation.html#t:t/0","title":"Wanda.Catalog.Expectation.t/0","type":"type"},{"doc":"Represents a fact.","ref":"Wanda.Catalog.Fact.html","title":"Wanda.Catalog.Fact","type":"module"},{"doc":"","ref":"Wanda.Catalog.Fact.html#t:t/0","title":"Wanda.Catalog.Fact.t/0","type":"type"},{"doc":"Represents a value.","ref":"Wanda.Catalog.Value.html","title":"Wanda.Catalog.Value","type":"module"},{"doc":"","ref":"Wanda.Catalog.Value.html#t:t/0","title":"Wanda.Catalog.Value.t/0","type":"type"},{"doc":"Publishes messages to the message bus","ref":"Wanda.Messaging.html","title":"Wanda.Messaging","type":"module"},{"doc":"","ref":"Wanda.Messaging.html#publish/2","title":"Wanda.Messaging.publish/2","type":"function"},{"doc":"AMQP adapter","ref":"Wanda.Messaging.Adapters.AMQP.html","title":"Wanda.Messaging.Adapters.AMQP","type":"module"},{"doc":"AMQP consumer.","ref":"Wanda.Messaging.Adapters.AMQP.Consumer.html","title":"Wanda.Messaging.Adapters.AMQP.Consumer","type":"module"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Consumer.html#child_spec/1","title":"Wanda.Messaging.Adapters.AMQP.Consumer.child_spec/1","type":"function"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Consumer.html#start_link/1","title":"Wanda.Messaging.Adapters.AMQP.Consumer.start_link/1","type":"function"},{"doc":"AMQP processor.","ref":"Wanda.Messaging.Adapters.AMQP.Processor.html","title":"Wanda.Messaging.Adapters.AMQP.Processor","type":"module"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Processor.html#process/1","title":"Wanda.Messaging.Adapters.AMQP.Processor.process/1","type":"function"},{"doc":"AMQP publisher.","ref":"Wanda.Messaging.Adapters.AMQP.Publisher.html","title":"Wanda.Messaging.Adapters.AMQP.Publisher","type":"module"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Publisher.html#child_spec/1","title":"Wanda.Messaging.Adapters.AMQP.Publisher.child_spec/1","type":"function"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Publisher.html#init/0","title":"Wanda.Messaging.Adapters.AMQP.Publisher.init/0","type":"function"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Publisher.html#publish_message/2","title":"Wanda.Messaging.Adapters.AMQP.Publisher.publish_message/2","type":"function"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Publisher.html#start_link/1","title":"Wanda.Messaging.Adapters.AMQP.Publisher.start_link/1","type":"function"},{"doc":"Maps domain structures to integration events.","ref":"Wanda.Messaging.Mapper.html","title":"Wanda.Messaging.Mapper","type":"module"},{"doc":"","ref":"Wanda.Messaging.Mapper.html#from_execution_requested/1","title":"Wanda.Messaging.Mapper.from_execution_requested/1","type":"function"},{"doc":"","ref":"Wanda.Messaging.Mapper.html#from_facts_gathererd/1","title":"Wanda.Messaging.Mapper.from_facts_gathererd/1","type":"function"},{"doc":"","ref":"Wanda.Messaging.Mapper.html#to_execution_completed/2","title":"Wanda.Messaging.Mapper.to_execution_completed/2","type":"function"},{"doc":"","ref":"Wanda.Messaging.Mapper.html#to_execution_started/3","title":"Wanda.Messaging.Mapper.to_execution_started/3","type":"function"},{"doc":"","ref":"Wanda.Messaging.Mapper.html#to_facts_gathering_requested/4","title":"Wanda.Messaging.Mapper.to_facts_gathering_requested/4","type":"function"},{"doc":"The entrypoint for defining your web interface, such\nas controllers, views, channels and so on.\n\nThis can be used in your application as:\n\n use WandaWeb, :controller\n use WandaWeb, :view\n\nThe definitions below will be executed for every view,\ncontroller, etc, so keep them short and clean, focused\non imports, uses and aliases.\n\nDo NOT define functions inside the quoted expressions\nbelow. Instead, define any helper function in modules\nand import those modules here.","ref":"WandaWeb.html","title":"WandaWeb","type":"module"},{"doc":"When used, dispatch to the appropriate controller/view/etc.","ref":"WandaWeb.html#__using__/1","title":"WandaWeb.__using__/1","type":"macro"},{"doc":"","ref":"WandaWeb.html#channel/0","title":"WandaWeb.channel/0","type":"function"},{"doc":"","ref":"WandaWeb.html#controller/0","title":"WandaWeb.controller/0","type":"function"},{"doc":"","ref":"WandaWeb.html#router/0","title":"WandaWeb.router/0","type":"function"},{"doc":"","ref":"WandaWeb.html#view/0","title":"WandaWeb.view/0","type":"function"},{"doc":"Jwt Token is the module responsible for creating a proper jwt access token.\n Uses Joken as jwt base library","ref":"WandaWeb.Auth.AccessToken.html","title":"WandaWeb.Auth.AccessToken","type":"module"},{"doc":"Combines `generate_claims/1` and `encode_and_sign/2`","ref":"WandaWeb.Auth.AccessToken.html#generate_and_sign/2","title":"WandaWeb.Auth.AccessToken.generate_and_sign/2","type":"function"},{"doc":"Same as `generate_and_sign/2` but raises if error","ref":"WandaWeb.Auth.AccessToken.html#generate_and_sign!/2","title":"WandaWeb.Auth.AccessToken.generate_and_sign!/2","type":"function"},{"doc":"Combines `verify/2` and `validate/2`","ref":"WandaWeb.Auth.AccessToken.html#verify_and_validate/3","title":"WandaWeb.Auth.AccessToken.verify_and_validate/3","type":"function"},{"doc":"Same as `verify_and_validate/2` but raises if error","ref":"WandaWeb.Auth.AccessToken.html#verify_and_validate!/3","title":"WandaWeb.Auth.AccessToken.verify_and_validate!/3","type":"function"},{"doc":"Plug responsible for reading the JWT from the authorization header and\n validating it.\n\n If the token is valid, the user_id is added to the private section of the\n connection.\n If the token is invalid, the connection is halted with a 401 response.","ref":"WandaWeb.Auth.JWTAuthPlug.html","title":"WandaWeb.Auth.JWTAuthPlug","type":"module"},{"doc":"Read, validate and decode the JWT from authorization header at each call","ref":"WandaWeb.Auth.JWTAuthPlug.html#call/2","title":"WandaWeb.Auth.JWTAuthPlug.call/2","type":"function"},{"doc":"","ref":"WandaWeb.Auth.JWTAuthPlug.html#init/1","title":"WandaWeb.Auth.JWTAuthPlug.init/1","type":"function"},{"doc":"This module defines the test case to be used by\ntests that require setting up a connection.\n\nSuch tests rely on `Phoenix.ConnTest` and also\nimport other functionality to make it easier\nto build common data structures and query the data layer.\n\nFinally, if the test case interacts with the database,\nwe enable the SQL sandbox, so changes done to the database\nare reverted at the end of every test. If you are using\nPostgreSQL, you can even run database tests asynchronously\nby setting `use WandaWeb.ConnCase, async: true`, although\nthis option is not recommended for other databases.","ref":"WandaWeb.ConnCase.html","title":"WandaWeb.ConnCase","type":"module"},{"doc":"","ref":"WandaWeb.Endpoint.html","title":"WandaWeb.Endpoint","type":"module"},{"doc":"","ref":"WandaWeb.Endpoint.html#broadcast/3","title":"WandaWeb.Endpoint.broadcast/3","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#broadcast!/3","title":"WandaWeb.Endpoint.broadcast!/3","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#broadcast_from/4","title":"WandaWeb.Endpoint.broadcast_from/4","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#broadcast_from!/4","title":"WandaWeb.Endpoint.broadcast_from!/4","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#call/2","title":"WandaWeb.Endpoint.call/2","type":"function"},{"doc":"Returns the child specification to start the endpoint\nunder a supervision tree.","ref":"WandaWeb.Endpoint.html#child_spec/1","title":"WandaWeb.Endpoint.child_spec/1","type":"function"},{"doc":"Returns the endpoint configuration for `key`\n\nReturns `default` if the key does not exist.","ref":"WandaWeb.Endpoint.html#config/2","title":"WandaWeb.Endpoint.config/2","type":"function"},{"doc":"Reloads the configuration given the application environment changes.","ref":"WandaWeb.Endpoint.html#config_change/2","title":"WandaWeb.Endpoint.config_change/2","type":"function"},{"doc":"Returns the host for the given endpoint.","ref":"WandaWeb.Endpoint.html#host/0","title":"WandaWeb.Endpoint.host/0","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#init/1","title":"WandaWeb.Endpoint.init/1","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#local_broadcast/3","title":"WandaWeb.Endpoint.local_broadcast/3","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#local_broadcast_from/4","title":"WandaWeb.Endpoint.local_broadcast_from/4","type":"function"},{"doc":"Generates the path information when routing to this endpoint.","ref":"WandaWeb.Endpoint.html#path/1","title":"WandaWeb.Endpoint.path/1","type":"function"},{"doc":"Generates the script name.","ref":"WandaWeb.Endpoint.html#script_name/0","title":"WandaWeb.Endpoint.script_name/0","type":"function"},{"doc":"Starts the endpoint supervision tree.","ref":"WandaWeb.Endpoint.html#start_link/1","title":"WandaWeb.Endpoint.start_link/1","type":"function"},{"doc":"* `:log_access_url` - if the access url should be logged\n once the endpoint starts\n\nAll other options are merged into the endpoint configuration.","ref":"WandaWeb.Endpoint.html#start_link/1-options","title":"Options - WandaWeb.Endpoint.start_link/1","type":"function"},{"doc":"Generates a base64-encoded cryptographic hash (sha512) to a static file\nin `priv/static`. Meant to be used for Subresource Integrity with CDNs.","ref":"WandaWeb.Endpoint.html#static_integrity/1","title":"WandaWeb.Endpoint.static_integrity/1","type":"function"},{"doc":"Returns a two item tuple with the first item being the `static_path`\nand the second item being the `static_integrity`.","ref":"WandaWeb.Endpoint.html#static_lookup/1","title":"WandaWeb.Endpoint.static_lookup/1","type":"function"},{"doc":"Generates a route to a static file in `priv/static`.","ref":"WandaWeb.Endpoint.html#static_path/1","title":"WandaWeb.Endpoint.static_path/1","type":"function"},{"doc":"Generates the static URL without any path information.\n\nIt uses the configuration under `:static_url` to generate\nsuch. It falls back to `:url` if `:static_url` is not set.","ref":"WandaWeb.Endpoint.html#static_url/0","title":"WandaWeb.Endpoint.static_url/0","type":"function"},{"doc":"Generates the endpoint base URL but as a `URI` struct.\n\nIt uses the configuration under `:url` to generate such.\nUseful for manipulating the URL data and passing it to\nURL helpers.","ref":"WandaWeb.Endpoint.html#struct_url/0","title":"WandaWeb.Endpoint.struct_url/0","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#subscribe/2","title":"WandaWeb.Endpoint.subscribe/2","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#unsubscribe/1","title":"WandaWeb.Endpoint.unsubscribe/1","type":"function"},{"doc":"Generates the endpoint base URL without any path information.\n\nIt uses the configuration under `:url` to generate such.","ref":"WandaWeb.Endpoint.html#url/0","title":"WandaWeb.Endpoint.url/0","type":"function"},{"doc":"Conveniences for translating and building error messages.","ref":"WandaWeb.ErrorHelpers.html","title":"WandaWeb.ErrorHelpers","type":"module"},{"doc":"Translates an error message.","ref":"WandaWeb.ErrorHelpers.html#translate_error/1","title":"WandaWeb.ErrorHelpers.translate_error/1","type":"function"},{"doc":"","ref":"WandaWeb.ErrorView.html","title":"WandaWeb.ErrorView","type":"module"},{"doc":"The resource name, as an atom, for this view","ref":"WandaWeb.ErrorView.html#__resource__/0","title":"WandaWeb.ErrorView.__resource__/0","type":"function"},{"doc":"Renders the given template locally.","ref":"WandaWeb.ErrorView.html#render/2","title":"WandaWeb.ErrorView.render/2","type":"function"},{"doc":"Callback invoked when no template is found.\nBy default it raises but can be customized\nto render a particular template.","ref":"WandaWeb.ErrorView.html#template_not_found/2","title":"WandaWeb.ErrorView.template_not_found/2","type":"function"},{"doc":"","ref":"WandaWeb.FallbackController.html","title":"WandaWeb.FallbackController","type":"module"},{"doc":"","ref":"WandaWeb.HealthController.html","title":"WandaWeb.HealthController","type":"module"},{"doc":"","ref":"WandaWeb.HealthController.html#health/2","title":"WandaWeb.HealthController.health/2","type":"function"},{"doc":"","ref":"WandaWeb.HealthController.html#open_api_operation/1","title":"WandaWeb.HealthController.open_api_operation/1","type":"function"},{"doc":"","ref":"WandaWeb.HealthController.html#ready/2","title":"WandaWeb.HealthController.ready/2","type":"function"},{"doc":"","ref":"WandaWeb.HealthController.html#shared_security/0","title":"WandaWeb.HealthController.shared_security/0","type":"function"},{"doc":"","ref":"WandaWeb.HealthController.html#shared_tags/0","title":"WandaWeb.HealthController.shared_tags/0","type":"function"},{"doc":"","ref":"WandaWeb.HealthView.html","title":"WandaWeb.HealthView","type":"module"},{"doc":"The resource name, as an atom, for this view","ref":"WandaWeb.HealthView.html#__resource__/0","title":"WandaWeb.HealthView.__resource__/0","type":"function"},{"doc":"Renders the given template locally.","ref":"WandaWeb.HealthView.html#render/2","title":"WandaWeb.HealthView.render/2","type":"function"},{"doc":"Callback invoked when no template is found.\nBy default it raises but can be customized\nto render a particular template.","ref":"WandaWeb.HealthView.html#template_not_found/2","title":"WandaWeb.HealthView.template_not_found/2","type":"function"},{"doc":"This Plug is responsible for redirecting api requests without a specific version\n to the latest version, when the requested path exists\n\n For example:\n Requesting /api/test, will redirect to /api/ Note: `api-key` value is not used if the unique goal is to run checks, so setting it as `--api-key 0` does the work.\n\nKeep in mind that the `agent_id` of the targets must match with values provided in the `targets` field of the execution request.\n\nThe ID can be obtained running:\n\n```\n./trento-agent id\n```\n\nIf the execution is run in a development/testing environment, [faking the agent id](https://github.com/trento-project/agent#fake-agent-id) might come handy.\n\n### **Consulting the catalog**\n\nAvailable Checks are part of the **Catalog**, and they can be retrieved by accessing the dedicated API\n\n```bash\ncurl -X 'GET' \\\n 'http://localhost:4000/api/v1/checks/catalog' \\\n -H 'accept: application/json'\n```\n\n### **Starting a Checks Execution**\n\nA Checks Execution can be started by calling the Start Execution endpoint, as follows\n\n```bash\ncurl --request POST 'http://localhost:4000/api/v1/checks/executions/start' \\\n--header 'accept: application/json' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n \"env\": {\n \"provider\": \"azure\"\n },\n \"execution_id\": \"205e326d-0c25-4f4b-9976-43f9ba1c86d3\",\n \"group_id\": \"3dff9d03-4adf-453e-9513-8533e221bb12\",\n \"targets\": [\n {\n \"agent_id\": \"a644919a-d953-43d4-bd57-7e0bb96ee894\",\n \"checks\": [\n \"156F64\"\n ]\n },\n {\n \"agent_id\": \"02d99b2f-0efd-443c-ac9c-32710323f620\",\n \"checks\": [\n \"OTH3R1\"\n ]\n }\n ]\n}'\n```\n\n> **execution_id** must be new and unique for every new execution. If an already used **execution_id** is provided, starting the execution fails.\n\nIn order to get detailed information for an execution, see [Getting Execution details](#getting-execution-details).\n\n> Note that execution is _eventually started_, meaning that a successful response to the previous API call does not guarantee that the execution is running, but that it has been accepted by the system to start.\n\n#","ref":"readme.html#testing-executions","title":"Testing Executions - Wanda","type":"extras"},{"doc":"An execution target is a target host where the checks are executed. This requires to have the `trento-agent` executable running in the host. In order to specify an execution order, its `agent_id` and a list of checks to be executed are provided. Once the execution is started, a facts gathering request is sent to these targets, facts are gathered and sent back to Wanda, where the checks result is evaluated using the gathered facts.\n\nThe `agent_id` can be obtained just issuing `trento-agent id` command in the target host.\n\nEach target _must_ specify a list of checks, that can be empty. These are the selected checks for each agent, that are executed.\n\nGiven two different targets, the same checks can be selected:\n\n```bash\ncurl --request POST 'http://localhost:4000/api/v1/checks/executions/start' \\\n--header 'accept: application/json' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n \"env\": {\n \"provider\": \"azure\"\n },\n \"execution_id\": \"205e326d-0c25-4f4b-9976-43f9ba1c86d3\",\n \"group_id\": \"3dff9d03-4adf-453e-9513-8533e221bb12\",\n \"targets\": [\n {\n \"agent_id\": \"a644919a-d953-43d4-bd57-7e0bb96ee894\",\n \"checks\": [\n \"156F64\",\n \"45B653\"\n ]\n },\n {\n \"agent_id\": \"02d99b2f-0efd-443c-ac9c-32710323f620\",\n \"checks\": [\n \"156F64\",\n \"45B653\"\n ]\n }\n ]\n}'\n```\n\nOr completely different ones:\n\n```bash\ncurl --request POST 'http://localhost:4000/api/v1/checks/executions/start' \\\n--header 'accept: application/json' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n \"env\": {\n \"provider\": \"azure\"\n },\n \"execution_id\": \"205e326d-0c25-4f4b-9976-43f9ba1c86d3\",\n \"group_id\": \"3dff9d03-4adf-453e-9513-8533e221bb12\",\n \"targets\": [\n {\n \"agent_id\": \"a644919a-d953-43d4-bd57-7e0bb96ee894\",\n \"checks\": [\n \"156F64\",\n \"45B653\"\n ]\n },\n {\n \"agent_id\": \"02d99b2f-0efd-443c-ac9c-32710323f620\",\n \"checks\": [\n \"OTH3R1\",\n \"OTH3R2\"\n ]\n }\n ]\n}'\n```\n\n### **Getting Execution details**\n\nTo get detailed information about the execution, the following API can be used.\n\n```bash\ncurl --request GET 'http://localhost:4000/api/v1/checks/executions/205e326d-0c25-4f4b-9976-43f9ba1c86d3' \\\n--header 'accept: application/json' \\\n--header 'Content-Type: application/json'\n```\n\n> **Note** that calling the execution detail API right after [starting an execution](#starting-a-checks-execution) might result in a `404 not found`, because the execution, as mentioned, is _eventually started_.\n>\n> In this case retry getting the detail of the execution.\n\nRefer to the [API doc](http://localhost:4000/swaggerui) for more information about requests and responses.\n\n### **Debugging gathered facts**\n\nOften times knowing the returned value of the gathered facts is not a trivial thing, more during the implementation of new checks.\n\nTo better debug the fact gathering process and the returned values, the `facts` subcommand of `trento-agent` is a really useful tool. This command helps to see in the target itself what the gathered fact looks like. This is specially interesting when the returned value is a complex object or the target under test is modified and the check developer wants to see how this affects the gathered fact.\n\nThe command can be used as:\n\n```\n./trento-agent facts gather --gatherer corosync.conf --argument totem.token\n# To see the currently available gatherers and their names\n# ./trento-agent facts list\n```\n\nWhich would return the next where the `Value` is the available value in the written check:\n\n```\n{\n \"Name\": \"totem.token\",\n \"CheckID\": \"\",\n \"Value\": {\n \"Value\": 30000\n },\n \"Error\": null\n}\n```","ref":"readme.html#execution-targets","title":"Execution Targets - Wanda","type":"extras"},{"doc":"Built-in Checks can be found in the Catalog directory at `./priv/catalog/`\n\nTo implement new checks and test them:\n\n- write a new [Check Specification](./guides/specification.md) file\n- locate the newly created Check in the Catalog directory `./priv/catalog/`\n- test the execution as [previously described](#testing-executions)\n\n# Running a local Wanda instance","ref":"readme.html#adding-new-checks","title":"Adding new Checks - Wanda","type":"extras"},{"doc":"To set up a local development environment for Wanda, follow the instructions provided in [how to hack on wanda](./guides/development/hack_on_wanda.md).\n\nThis guide walks through the process of installing and configuring the necessary dependencies, as well as setting up a local development environment.","ref":"readme.html#running-a-development-environment","title":"Running a Development Environment - Wanda","type":"extras"},{"doc":"The demo mode of Wanda allows to showcase checks evaluation without the full setup with actual agents on the host. To run a demo instance, follow the instructions provided in [how to run wanda demo guide](./guides/development/demo.md).\n\n# Support\n\nPlease only report bugs via [GitHub issues](https://github.com/trento-project/wanda/issues) and\nfor any other inquiry or topic use [GitHub discussion](https://github.com/trento-project/wanda/discussions).\n\n# Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md)\n\n# License\n\nCopyright 2021-2023 SUSE LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use\nany of the source code in this project except in compliance with the License. You may obtain a copy of the\nLicense at\n\nhttps://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed\nunder the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\nCONDITIONS OF ANY KIND, either express or implied. See the License for the\nspecific language governing permissions and limitations under the License.","ref":"readme.html#running-a-demo-environment","title":"Running a Demo Environment - Wanda","type":"extras"},{"doc":"# Changelog\n\n## [1.1.0](https://github.com/trento-project/wanda/tree/1.1.0) (2023-08-02)\n\n[Full Changelog](https://github.com/trento-project/wanda/compare/1.0.0...1.1.0)\n\n**Implemented enhancements:**\n\n- Refactor demo server [\\#271](https://github.com/trento-project/wanda/pull/271) ([EMaksy](https://github.com/EMaksy))\n- initial checks for VMware vSphere \\(jsc\\#TRNT-1682\\) [\\#259](https://github.com/trento-project/wanda/pull/259) ([yeoldegrove](https://github.com/yeoldegrove))\n- update reference section to clarify the package version decision [\\#255](https://github.com/trento-project/wanda/pull/255) ([angelabriel](https://github.com/angelabriel))\n- Add when conditions for resource types, propagate the resource type in the ExecutionCompleted event [\\#253](https://github.com/trento-project/wanda/pull/253) ([dottorblaster](https://github.com/dottorblaster))\n- Add user friendly failure message \\(jsc\\#TRNT-1825\\) [\\#237](https://github.com/trento-project/wanda/pull/237) ([angelabriel](https://github.com/angelabriel))\n\n**Fixed bugs:**\n\n- Fix formatting in demo guide [\\#275](https://github.com/trento-project/wanda/pull/275) ([EMaksy](https://github.com/EMaksy))\n- fixes found by checks-checker [\\#260](https://github.com/trento-project/wanda/pull/260) ([yeoldegrove](https://github.com/yeoldegrove))\n- Add default failure message for expect\\_same expectations [\\#243](https://github.com/trento-project/wanda/pull/243) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n**Merged pull requests:**\n\n- Bump rhai\\_rustler to v1.0.2 [\\#276](https://github.com/trento-project/wanda/pull/276) ([fabriziosestito](https://github.com/fabriziosestito))\n- Bump rhai\\_rustler from 1.0.0 to 1.0.1 [\\#270](https://github.com/trento-project/wanda/pull/270) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump ex\\_doc from 0.30.2 to 0.30.3 [\\#269](https://github.com/trento-project/wanda/pull/269) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump jason from 1.4.0 to 1.4.1 [\\#266](https://github.com/trento-project/wanda/pull/266) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump ex\\_doc from 0.29.4 to 0.30.2 [\\#265](https://github.com/trento-project/wanda/pull/265) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump rhai\\_rustler to v1.0.0 [\\#264](https://github.com/trento-project/wanda/pull/264) ([fabriziosestito](https://github.com/fabriziosestito))\n- Update contracts usage [\\#258](https://github.com/trento-project/wanda/pull/258) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Document target\\_type inside env [\\#256](https://github.com/trento-project/wanda/pull/256) ([dottorblaster](https://github.com/dottorblaster))\n- Bump phoenix\\_ecto from 4.4.0 to 4.4.2 [\\#252](https://github.com/trento-project/wanda/pull/252) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump docker/login-action from 2.1.0 to 2.2.0 [\\#251](https://github.com/trento-project/wanda/pull/251) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Document cluster type support [\\#248](https://github.com/trento-project/wanda/pull/248) ([arbulu89](https://github.com/arbulu89))\n- Bump open\\_api\\_spex from 3.16.1 to 3.17.3 [\\#246](https://github.com/trento-project/wanda/pull/246) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Update copyright year to 2023 [\\#240](https://github.com/trento-project/wanda/pull/240) ([EMaksy](https://github.com/EMaksy))\n- Bump docker/metadata-action from 4.3.0 to 4.4.0 [\\#234](https://github.com/trento-project/wanda/pull/234) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump dialyxir from 1.2.0 to 1.3.0 [\\#232](https://github.com/trento-project/wanda/pull/232) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump excoveralls from 0.16.0 to 0.16.1 [\\#231](https://github.com/trento-project/wanda/pull/231) ([dependabot[bot]](https://github.com/apps/dependabot))\n\n## [1.0.0](https://github.com/trento-project/wanda/tree/1.0.0) (2023-04-26)\n\n[Full Changelog](https://github.com/trento-project/wanda/compare/0.1.0...1.0.0)\n\n**Implemented enhancements:**\n\n- Make cors optional on production [\\#206](https://github.com/trento-project/wanda/pull/206) ([arbulu89](https://github.com/arbulu89))\n- Build wanda with premium checks, if available [\\#179](https://github.com/trento-project/wanda/pull/179) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n**Fixed bugs:**\n\n- Expectation results result to false when some agent evaluation is missing [\\#224](https://github.com/trento-project/wanda/pull/224) ([arbulu89](https://github.com/arbulu89))\n\n**Merged pull requests:**\n\n- enhance remediation section to clarify the value setting [\\#235](https://github.com/trento-project/wanda/pull/235) ([angelabriel](https://github.com/angelabriel))\n- Add failure message documentation [\\#230](https://github.com/trento-project/wanda/pull/230) ([dottorblaster](https://github.com/dottorblaster))\n- Bump ex\\_doc from 0.29.2 to 0.29.4 [\\#229](https://github.com/trento-project/wanda/pull/229) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Rename `health_test.exs` -\\> `health_controller_test.exs` [\\#228](https://github.com/trento-project/wanda/pull/228) ([jamie-suse](https://github.com/jamie-suse))\n- Rename `HealthcheckViewTest` -\\> `HealthViewTest` [\\#227](https://github.com/trento-project/wanda/pull/227) ([jamie-suse](https://github.com/jamie-suse))\n- add api versioning to the readme examples [\\#226](https://github.com/trento-project/wanda/pull/226) ([angelabriel](https://github.com/angelabriel))\n- Add healthcheck and readiness endpoints [\\#225](https://github.com/trento-project/wanda/pull/225) ([jamie-suse](https://github.com/jamie-suse))\n- Add dev.local.exs usage [\\#223](https://github.com/trento-project/wanda/pull/223) ([arbulu89](https://github.com/arbulu89))\n- Bump credo from 1.6.7 to 1.7.0 [\\#222](https://github.com/trento-project/wanda/pull/222) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Fix execution of SBD related checks \\(jsc\\#CFSA-1961\\) [\\#220](https://github.com/trento-project/wanda/pull/220) ([angelabriel](https://github.com/angelabriel))\n- Bump plug\\_cowboy from 2.6.0 to 2.6.1 [\\#218](https://github.com/trento-project/wanda/pull/218) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Refactor API errors [\\#217](https://github.com/trento-project/wanda/pull/217) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add failure message [\\#216](https://github.com/trento-project/wanda/pull/216) ([dottorblaster](https://github.com/dottorblaster))\n- Bump excoveralls from 0.15.3 to 0.16.0 [\\#213](https://github.com/trento-project/wanda/pull/213) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Fixed broken web URLs [\\#212](https://github.com/trento-project/wanda/pull/212) ([ksanjeet](https://github.com/ksanjeet))\n- Compile and test with --warnings-as-errors flag [\\#210](https://github.com/trento-project/wanda/pull/210) ([fabriziosestito](https://github.com/fabriziosestito))\n- Update the hack on wanda guide [\\#209](https://github.com/trento-project/wanda/pull/209) ([EMaksy](https://github.com/EMaksy))\n- Bump ex\\_doc from 0.29.1 to 0.29.2 [\\#208](https://github.com/trento-project/wanda/pull/208) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Remove jwt enablement flag usage from jwt plug tests [\\#207](https://github.com/trento-project/wanda/pull/207) ([arbulu89](https://github.com/arbulu89))\n- Enrich the faker by using catalog data [\\#205](https://github.com/trento-project/wanda/pull/205) ([rtorrero](https://github.com/rtorrero))\n- Facts schema value lists maps [\\#204](https://github.com/trento-project/wanda/pull/204) ([arbulu89](https://github.com/arbulu89))\n- Bump actions/checkout from 2 to 3 [\\#203](https://github.com/trento-project/wanda/pull/203) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump excoveralls from 0.15.0 to 0.15.3 [\\#200](https://github.com/trento-project/wanda/pull/200) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump open\\_api\\_spex from 3.13.0 to 3.16.1 [\\#198](https://github.com/trento-project/wanda/pull/198) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump ecto\\_sql from 3.8.3 to 3.9.2 [\\#197](https://github.com/trento-project/wanda/pull/197) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump joken from 2.5.0 to 2.6.0 [\\#196](https://github.com/trento-project/wanda/pull/196) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump ex\\_doc from 0.29.0 to 0.29.1 [\\#195](https://github.com/trento-project/wanda/pull/195) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump credo from 1.6.6 to 1.6.7 [\\#194](https://github.com/trento-project/wanda/pull/194) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump phoenix from 1.6.12 to 1.6.16 [\\#193](https://github.com/trento-project/wanda/pull/193) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump docker/build-push-action from 3 to 4 [\\#192](https://github.com/trento-project/wanda/pull/192) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Add dependabot [\\#191](https://github.com/trento-project/wanda/pull/191) ([fabriziosestito](https://github.com/fabriziosestito))\n- Filter out non-existing checks on the faker [\\#189](https://github.com/trento-project/wanda/pull/189) ([rtorrero](https://github.com/rtorrero))\n- Remotely trigger demo deploy on new wanda image [\\#188](https://github.com/trento-project/wanda/pull/188) ([rtorrero](https://github.com/rtorrero))\n- Add new demo env that uses faked execution server [\\#187](https://github.com/trento-project/wanda/pull/187) ([rtorrero](https://github.com/rtorrero))\n- Fix warning in api redirector test [\\#186](https://github.com/trento-project/wanda/pull/186) ([fabriziosestito](https://github.com/fabriziosestito))\n- Fix execution flaky test [\\#185](https://github.com/trento-project/wanda/pull/185) ([arbulu89](https://github.com/arbulu89))\n- Api version v1 [\\#183](https://github.com/trento-project/wanda/pull/183) ([CDimonaco](https://github.com/CDimonaco))\n- Update package\\_version gatherer doc [\\#182](https://github.com/trento-project/wanda/pull/182) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Run CI `test` step on different versions of Elixir & OTP [\\#181](https://github.com/trento-project/wanda/pull/181) ([jamie-suse](https://github.com/jamie-suse))\n- Add information on how to install wanda directly for development [\\#178](https://github.com/trento-project/wanda/pull/178) ([EMaksy](https://github.com/EMaksy))\n- Bump BCI base image to 15.4 for dev Dockerfile [\\#177](https://github.com/trento-project/wanda/pull/177) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Fix JWT plug runtime config [\\#176](https://github.com/trento-project/wanda/pull/176) ([fabriziosestito](https://github.com/fabriziosestito))\n- Use new `trento-wanda` image name for check development environment [\\#175](https://github.com/trento-project/wanda/pull/175) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- rewrite trento community checks regarding 'package version' [\\#124](https://github.com/trento-project/wanda/pull/124) ([angelabriel](https://github.com/angelabriel))\n\n## [0.1.0](https://github.com/trento-project/wanda/tree/0.1.0) (2023-01-23)\n\n[Full Changelog](https://github.com/trento-project/wanda/compare/a8b788751fe90542ed0d2541a816b3a148dedfd0...0.1.0)\n\n**Implemented enhancements:**\n\n- Build in obs [\\#173](https://github.com/trento-project/wanda/pull/173) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add JWT auth [\\#168](https://github.com/trento-project/wanda/pull/168) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add premium flag option to catalog loading code [\\#163](https://github.com/trento-project/wanda/pull/163) ([arbulu89](https://github.com/arbulu89))\n- Add check DA114A: Corosync has at least 2 rings configured [\\#141](https://github.com/trento-project/wanda/pull/141) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add SBD dump gatherer documentation [\\#137](https://github.com/trento-project/wanda/pull/137) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add last execution by group [\\#108](https://github.com/trento-project/wanda/pull/108) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add targets execution view [\\#106](https://github.com/trento-project/wanda/pull/106) ([arbulu89](https://github.com/arbulu89))\n- Fix protobuf message mapping [\\#94](https://github.com/trento-project/wanda/pull/94) ([arbulu89](https://github.com/arbulu89))\n- Ordered Execution list [\\#93](https://github.com/trento-project/wanda/pull/93) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add cargo to dockerfile and build rustler [\\#74](https://github.com/trento-project/wanda/pull/74) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Start execution api [\\#73](https://github.com/trento-project/wanda/pull/73) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add Checks Specification Documentation [\\#72](https://github.com/trento-project/wanda/pull/72) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Refactor executions api [\\#66](https://github.com/trento-project/wanda/pull/66) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Store execution state [\\#60](https://github.com/trento-project/wanda/pull/60) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add support for values computation based on environment [\\#46](https://github.com/trento-project/wanda/pull/46) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Use env values [\\#42](https://github.com/trento-project/wanda/pull/42) ([arbulu89](https://github.com/arbulu89))\n- Serve the execution results through an endpoint [\\#40](https://github.com/trento-project/wanda/pull/40) ([dottorblaster](https://github.com/dottorblaster))\n- Some needed improvements to make the code runnable on prod environment [\\#38](https://github.com/trento-project/wanda/pull/38) ([arbulu89](https://github.com/arbulu89))\n- Store execution result on Check execution completion [\\#36](https://github.com/trento-project/wanda/pull/36) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add a storable Wanda.Result.ExecutionResult entity [\\#35](https://github.com/trento-project/wanda/pull/35) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n**Fixed bugs:**\n\n- Fix default value when getting system env for JWT\\_AUTHENTICATION\\_ENABLED [\\#172](https://github.com/trento-project/wanda/pull/172) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Set critical state on agent timeout and warning severity [\\#166](https://github.com/trento-project/wanda/pull/166) ([arbulu89](https://github.com/arbulu89))\n- Fix get last execution by group id [\\#110](https://github.com/trento-project/wanda/pull/110) ([fabriziosestito](https://github.com/fabriziosestito))\n- Improve Execution open api doc [\\#109](https://github.com/trento-project/wanda/pull/109) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Init before start [\\#101](https://github.com/trento-project/wanda/pull/101) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Fix flaky evaluation test [\\#96](https://github.com/trento-project/wanda/pull/96) ([arbulu89](https://github.com/arbulu89))\n- Load checks properly for the execution [\\#61](https://github.com/trento-project/wanda/pull/61) ([arbulu89](https://github.com/arbulu89))\n- Fixed items definition for expectation\\_results in ExecutionComplete event [\\#14](https://github.com/trento-project/wanda/pull/14) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n**Closed issues:**\n\n- Bad links in README.md [\\#126](https://github.com/trento-project/wanda/issues/126)\n\n**Merged pull requests:**\n\n- Fix cors plug integration [\\#174](https://github.com/trento-project/wanda/pull/174) ([CDimonaco](https://github.com/CDimonaco))\n- Execution started event [\\#171](https://github.com/trento-project/wanda/pull/171) ([CDimonaco](https://github.com/CDimonaco))\n- Chore: move tests in subfolder [\\#170](https://github.com/trento-project/wanda/pull/170) ([fabriziosestito](https://github.com/fabriziosestito))\n- Remove ssh-address flag reference from docs [\\#169](https://github.com/trento-project/wanda/pull/169) ([arbulu89](https://github.com/arbulu89))\n- rewrite trento community check regarding 'running corosync rings' [\\#167](https://github.com/trento-project/wanda/pull/167) ([angelabriel](https://github.com/angelabriel))\n- Add list & map examples for `corosync-cmapctl` docs [\\#165](https://github.com/trento-project/wanda/pull/165) ([jamie-suse](https://github.com/jamie-suse))\n- Force rhai\\_rustler build [\\#164](https://github.com/trento-project/wanda/pull/164) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add doc for the new package\\_version comparisons [\\#162](https://github.com/trento-project/wanda/pull/162) ([rtorrero](https://github.com/rtorrero))\n- add when condition to decide where to run a check [\\#161](https://github.com/trento-project/wanda/pull/161) ([angelabriel](https://github.com/angelabriel))\n- Improve gatherers documentation and add rhai example outputs [\\#160](https://github.com/trento-project/wanda/pull/160) ([fabriziosestito](https://github.com/fabriziosestito))\n- Clean up doc saying that expectation evaluation has access to the env [\\#159](https://github.com/trento-project/wanda/pull/159) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Document the trento-agent facts command [\\#158](https://github.com/trento-project/wanda/pull/158) ([arbulu89](https://github.com/arbulu89))\n- Fix integer mapping [\\#157](https://github.com/trento-project/wanda/pull/157) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add starting the targets section on the docs [\\#156](https://github.com/trento-project/wanda/pull/156) ([arbulu89](https://github.com/arbulu89))\n- Document best practices [\\#155](https://github.com/trento-project/wanda/pull/155) ([arbulu89](https://github.com/arbulu89))\n- Implement when condition [\\#154](https://github.com/trento-project/wanda/pull/154) ([dottorblaster](https://github.com/dottorblaster))\n- rewrite trento community check regarding 'hacluster' password change [\\#153](https://github.com/trento-project/wanda/pull/153) ([angelabriel](https://github.com/angelabriel))\n- Fix external links in ExDocs [\\#152](https://github.com/trento-project/wanda/pull/152) ([fabriziosestito](https://github.com/fabriziosestito))\n- Chore: remove unusued fixture [\\#151](https://github.com/trento-project/wanda/pull/151) ([fabriziosestito](https://github.com/fabriziosestito))\n- Bump to rhai\\_rustler to v0.1.3 [\\#149](https://github.com/trento-project/wanda/pull/149) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add documentation for verify\\_password gatherer [\\#147](https://github.com/trento-project/wanda/pull/147) ([rtorrero](https://github.com/rtorrero))\n- rewrite trento community checks regarding 'cibadmin' configuration [\\#146](https://github.com/trento-project/wanda/pull/146) ([angelabriel](https://github.com/angelabriel))\n- Improve table format and add req argument info [\\#145](https://github.com/trento-project/wanda/pull/145) ([rtorrero](https://github.com/rtorrero))\n- Add saphostctrl gatherer to gatherers.md [\\#144](https://github.com/trento-project/wanda/pull/144) ([rtorrero](https://github.com/rtorrero))\n- Add a cheat sheet for Rhai [\\#143](https://github.com/trento-project/wanda/pull/143) ([dottorblaster](https://github.com/dottorblaster))\n- rewrite trento community checks regarding 'sbd dump' configuration [\\#142](https://github.com/trento-project/wanda/pull/142) ([angelabriel](https://github.com/angelabriel))\n- Document cibadmin gatherer [\\#136](https://github.com/trento-project/wanda/pull/136) ([arbulu89](https://github.com/arbulu89))\n- Add a ref to target to README [\\#133](https://github.com/trento-project/wanda/pull/133) ([dottorblaster](https://github.com/dottorblaster))\n- rewrite trento community checks regarding 'sbd' configuration [\\#123](https://github.com/trento-project/wanda/pull/123) ([angelabriel](https://github.com/angelabriel))\n- rewriting checks for Wanda gatherer corosync-cmapctl [\\#119](https://github.com/trento-project/wanda/pull/119) ([pirat013](https://github.com/pirat013))\n- Add severity to the JSON schema [\\#116](https://github.com/trento-project/wanda/pull/116) ([dottorblaster](https://github.com/dottorblaster))\n- Gatherer.corosyncconf [\\#115](https://github.com/trento-project/wanda/pull/115) ([pirat013](https://github.com/pirat013))\n- Refactor factories [\\#112](https://github.com/trento-project/wanda/pull/112) ([fabriziosestito](https://github.com/fabriziosestito))\n- Use Kernel.-- instead of Enum.filter [\\#111](https://github.com/trento-project/wanda/pull/111) ([fabriziosestito](https://github.com/fabriziosestito))\n- add license [\\#107](https://github.com/trento-project/wanda/pull/107) ([stefanotorresi](https://github.com/stefanotorresi))\n- Use specific compose ports for wanda dev/test docker-compose [\\#105](https://github.com/trento-project/wanda/pull/105) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add critical, warning and passing counts to the execution view [\\#104](https://github.com/trento-project/wanda/pull/104) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add ability to handle non-existent & malformed Checks supplied to catalog [\\#103](https://github.com/trento-project/wanda/pull/103) ([jamie-suse](https://github.com/jamie-suse))\n- Add corosynccmapctl to gatherers.md [\\#102](https://github.com/trento-project/wanda/pull/102) ([rtorrero](https://github.com/rtorrero))\n- Bump contracts [\\#99](https://github.com/trento-project/wanda/pull/99) ([fabriziosestito](https://github.com/fabriziosestito))\n- Generate and push swagger-ui to gh-pages [\\#98](https://github.com/trento-project/wanda/pull/98) ([fabriziosestito](https://github.com/fabriziosestito))\n- Re-add accidentaly removed headers [\\#97](https://github.com/trento-project/wanda/pull/97) ([rtorrero](https://github.com/rtorrero))\n- Add test for policy handling Fact error [\\#95](https://github.com/trento-project/wanda/pull/95) ([jamie-suse](https://github.com/jamie-suse))\n- Remove installation section from README.md [\\#92](https://github.com/trento-project/wanda/pull/92) ([fabriziosestito](https://github.com/fabriziosestito))\n- Update CONTRIBUTING.md [\\#91](https://github.com/trento-project/wanda/pull/91) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add documentation for the package\\_version gatherer [\\#90](https://github.com/trento-project/wanda/pull/90) ([rtorrero](https://github.com/rtorrero))\n- Document systemd gatherer [\\#89](https://github.com/trento-project/wanda/pull/89) ([arbulu89](https://github.com/arbulu89))\n- Add Documentation for SBD Gatherer [\\#88](https://github.com/trento-project/wanda/pull/88) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add badges to readme [\\#87](https://github.com/trento-project/wanda/pull/87) ([fabriziosestito](https://github.com/fabriziosestito))\n- Use correct remediation text for check 156F64 [\\#85](https://github.com/trento-project/wanda/pull/85) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Support no args gatherers [\\#84](https://github.com/trento-project/wanda/pull/84) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add coveralls [\\#83](https://github.com/trento-project/wanda/pull/83) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add /etc/hosts file gatherer documentation [\\#82](https://github.com/trento-project/wanda/pull/82) ([rtorrero](https://github.com/rtorrero))\n- Add ExDoc config in mix.exs and supporting file to generate the doc [\\#81](https://github.com/trento-project/wanda/pull/81) ([fabriziosestito](https://github.com/fabriziosestito))\n- Minor tweaks to the specs doc [\\#80](https://github.com/trento-project/wanda/pull/80) ([rtorrero](https://github.com/rtorrero))\n- Fix Checks Specification doc link [\\#79](https://github.com/trento-project/wanda/pull/79) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Use strict module ordering [\\#77](https://github.com/trento-project/wanda/pull/77) ([fabriziosestito](https://github.com/fabriziosestito))\n- Integrate TLint into CI [\\#76](https://github.com/trento-project/wanda/pull/76) ([dottorblaster](https://github.com/dottorblaster))\n- Do not raise if an execution already exists [\\#75](https://github.com/trento-project/wanda/pull/75) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add ex doc gh pages [\\#71](https://github.com/trento-project/wanda/pull/71) ([fabriziosestito](https://github.com/fabriziosestito))\n- Bump erlang version to 24.3.4 [\\#70](https://github.com/trento-project/wanda/pull/70) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Change Abacus to Rhai [\\#69](https://github.com/trento-project/wanda/pull/69) ([fabriziosestito](https://github.com/fabriziosestito))\n- Handle CORS in dev environment [\\#68](https://github.com/trento-project/wanda/pull/68) ([arbulu89](https://github.com/arbulu89))\n- Refactor context [\\#65](https://github.com/trento-project/wanda/pull/65) ([fabriziosestito](https://github.com/fabriziosestito))\n- Abstract RabbitMQ processing logic [\\#64](https://github.com/trento-project/wanda/pull/64) ([jamie-suse](https://github.com/jamie-suse))\n- Detect already running execution for group\\_id [\\#63](https://github.com/trento-project/wanda/pull/63) ([arbulu89](https://github.com/arbulu89))\n- Remove restart directive from container definitions [\\#62](https://github.com/trento-project/wanda/pull/62) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Chore: remove unused miss dep [\\#59](https://github.com/trento-project/wanda/pull/59) ([fabriziosestito](https://github.com/fabriziosestito))\n- Use google protobuf value [\\#58](https://github.com/trento-project/wanda/pull/58) ([fabriziosestito](https://github.com/fabriziosestito))\n- Chore: rename/refactor schemas [\\#56](https://github.com/trento-project/wanda/pull/56) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add get check result [\\#55](https://github.com/trento-project/wanda/pull/55) ([fabriziosestito](https://github.com/fabriziosestito))\n- Rename controllers context [\\#54](https://github.com/trento-project/wanda/pull/54) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add Result OpenAPI Schema and cleanup [\\#53](https://github.com/trento-project/wanda/pull/53) ([fabriziosestito](https://github.com/fabriziosestito))\n- More prod fixes [\\#52](https://github.com/trento-project/wanda/pull/52) ([arbulu89](https://github.com/arbulu89))\n- Add initialization tasks for a release [\\#51](https://github.com/trento-project/wanda/pull/51) ([arbulu89](https://github.com/arbulu89))\n- Enable phoenix server usage in prod [\\#50](https://github.com/trento-project/wanda/pull/50) ([arbulu89](https://github.com/arbulu89))\n- Catalog controller [\\#49](https://github.com/trento-project/wanda/pull/49) ([arbulu89](https://github.com/arbulu89))\n- Cleanup execution controller [\\#48](https://github.com/trento-project/wanda/pull/48) ([fabriziosestito](https://github.com/fabriziosestito))\n- Refactor evaluation tests [\\#47](https://github.com/trento-project/wanda/pull/47) ([arbulu89](https://github.com/arbulu89))\n- Switch to Views for JSON rendering [\\#45](https://github.com/trento-project/wanda/pull/45) ([dottorblaster](https://github.com/dottorblaster))\n- Add CI step to check for unused dependencies [\\#44](https://github.com/trento-project/wanda/pull/44) ([jamie-suse](https://github.com/jamie-suse))\n- Load check values from yaml [\\#43](https://github.com/trento-project/wanda/pull/43) ([arbulu89](https://github.com/arbulu89))\n- Check severity [\\#41](https://github.com/trento-project/wanda/pull/41) ([arbulu89](https://github.com/arbulu89))\n- Enable single pipe check on credo [\\#39](https://github.com/trento-project/wanda/pull/39) ([arbulu89](https://github.com/arbulu89))\n- Add dockerfile [\\#37](https://github.com/trento-project/wanda/pull/37) ([fabriziosestito](https://github.com/fabriziosestito))\n- Map ExecutionCompleted event [\\#34](https://github.com/trento-project/wanda/pull/34) ([arbulu89](https://github.com/arbulu89))\n- Phoenix lift off [\\#33](https://github.com/trento-project/wanda/pull/33) ([arbulu89](https://github.com/arbulu89))\n- Message content\\_type from Contracts [\\#32](https://github.com/trento-project/wanda/pull/32) ([CDimonaco](https://github.com/CDimonaco))\n- Add amqp consumer integration tests [\\#31](https://github.com/trento-project/wanda/pull/31) ([fabriziosestito](https://github.com/fabriziosestito))\n- Handle fact gathering errors [\\#30](https://github.com/trento-project/wanda/pull/30) ([arbulu89](https://github.com/arbulu89))\n- Update contracts dep to trento-projects/contracts [\\#29](https://github.com/trento-project/wanda/pull/29) ([fabriziosestito](https://github.com/fabriziosestito))\n- Set execution GenServer restart policy as transient [\\#28](https://github.com/trento-project/wanda/pull/28) ([arbulu89](https://github.com/arbulu89))\n- Do not requeue amqp message on error [\\#26](https://github.com/trento-project/wanda/pull/26) ([arbulu89](https://github.com/arbulu89))\n- Fix amqp message consumption [\\#25](https://github.com/trento-project/wanda/pull/25) ([arbulu89](https://github.com/arbulu89))\n- Publish facts gathering requested [\\#24](https://github.com/trento-project/wanda/pull/24) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add checks to execution server state [\\#23](https://github.com/trento-project/wanda/pull/23) ([fabriziosestito](https://github.com/fabriziosestito))\n- Map FactsGatheringRequested event [\\#22](https://github.com/trento-project/wanda/pull/22) ([fabriziosestito](https://github.com/fabriziosestito))\n- Timeout business logic implementation [\\#21](https://github.com/trento-project/wanda/pull/21) ([dottorblaster](https://github.com/dottorblaster))\n- Remove JSON schema, add new protobuf contracts [\\#20](https://github.com/trento-project/wanda/pull/20) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add timeout logic to Wanda.Execution.Server [\\#19](https://github.com/trento-project/wanda/pull/19) ([dottorblaster](https://github.com/dottorblaster))\n- Revert \"Adds cache version to pipeline\" [\\#18](https://github.com/trento-project/wanda/pull/18) ([fabriziosestito](https://github.com/fabriziosestito))\n- fix execution requested event schema [\\#15](https://github.com/trento-project/wanda/pull/15) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Adds cache version to pipeline [\\#12](https://github.com/trento-project/wanda/pull/12) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Serialize an ExecutionCompleted json cloud event [\\#11](https://github.com/trento-project/wanda/pull/11) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Adds json schema for emitted ExecutionCompletedV1 [\\#10](https://github.com/trento-project/wanda/pull/10) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Receive Execution Requested event [\\#9](https://github.com/trento-project/wanda/pull/9) ([fabriziosestito](https://github.com/fabriziosestito))\n- Refactor Wanda.Execution in Wanda.Execution.Server, create execution API module [\\#8](https://github.com/trento-project/wanda/pull/8) ([fabriziosestito](https://github.com/fabriziosestito))\n- Receive facts gathered event [\\#6](https://github.com/trento-project/wanda/pull/6) ([fabriziosestito](https://github.com/fabriziosestito))\n- Setup amqp [\\#5](https://github.com/trento-project/wanda/pull/5) ([fabriziosestito](https://github.com/fabriziosestito))\n- Group expectations evaluation [\\#4](https://github.com/trento-project/wanda/pull/4) ([fabriziosestito](https://github.com/fabriziosestito))\n- Refactor execution pt1 [\\#3](https://github.com/trento-project/wanda/pull/3) ([fabriziosestito](https://github.com/fabriziosestito))\n- Expectations eval pt 1 [\\#2](https://github.com/trento-project/wanda/pull/2) ([fabriziosestito](https://github.com/fabriziosestito))\n- proof of concept of check execution orchestration, step 1 [\\#1](https://github.com/trento-project/wanda/pull/1) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n\n\n\\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*","ref":"changelog.html","title":"Changelog","type":"extras"},{"doc":"# How to contribute\n\nThanks for showing interest and sharing your time to contribute to this project!\n\nThis guide is meant to be used as a general guideline for creating issues or\npull requests. We encourage all first-time contributors to give this a read to avoid\ncommon mistakes and improve the quality of all contributions.","ref":"contributing.html","title":"How to contribute","type":"extras"},{"doc":"Before creating a new issue make sure you use the search functionality to confirm\nthat a similar issue doesn't already exist. Next, make sure you properly label\nthe issue as per our [labels](https://github.com/trento-project/wanda/labels)\n\nIf you are reporting a `bug`, please share a file generated using the\n`trento-support.sh` script with the following params:\n\n```\n# trento-support.sh --collect all --output file-tgz\n```\n\nand include the output in your issue. The script should remove sensitive data\nautomatically but please make sure you are not sharing any sensitive data of your own.","ref":"contributing.html#opening-issues","title":"Opening issues - How to contribute","type":"extras"},{"doc":"Always refer to the [docs repository](https://github.com/trento-project/docs) for coding standards and general guidelines.\n\n#","ref":"contributing.html#submitting-changes","title":"Submitting changes - How to contribute","type":"extras"},{"doc":"Reviews are hard. These few points will help us to reduce the time and effort required and allow us to merge your changes faster.\n\n1. Only touch relevant files.\n2. We have a PR template to aid you in completing the required details. Be\n sure to complete it and remove the non-relevant parts.\n3. Keep PRs as small as possible. When the PR gets too big, consider splitting it into multiple parts. A PR should ideally be between 100 and 500 additions.\n4. Check that the tests are passing.\n5. Check that your code is not generating new warnings.\n6. Check that any dependent changes have been merged and published in downstream modules\n7. Commit history should be short and group changes that otherwise wouldn't\n make sense on their own.\n8. Always write a clear log message for your commits. One-line messages are\n fine for small changes, but bigger changes should look like this:\n\n ```\n git commit -m \"A brief summary of the commit\n\n A paragraph describing what changed and its impact.\"\n ```\n\n9. Write a detailed description that gives context and explains why you are\n creating the PR.\n10. If the PR adds functionality, please add some tests and documentation\n to support it.\n11. Each PR needs 1 approval to be merged. Select a reviewer in particular if\n you are looking for specific feedback from someone.\n\n#","ref":"contributing.html#pull-requests-guideline","title":"Pull Requests guideline - How to contribute","type":"extras"},{"doc":"1. Opinionated comments are welcome but don't expect them always to be\n addressed. Be ready for discussion but also open to conceding.\n To avoid scope creep, consider proposing subsequent PRs\n rather than requesting changes for the current PR you are reviewing.\n2. Short, concise comments with examples are the most valuable.","ref":"contributing.html#reviewers-guideline","title":"Reviewers guideline - How to contribute","type":"extras"},{"doc":"# Rhai expressions cheatsheet\n\nIn this cheatsheet are grouped the most frequent manipulations that can be done through Rhai, for convenience.","ref":"rhai_expressions_cheat_sheet.html","title":"Rhai expressions cheatsheet","type":"extras"},{"doc":"{: .col-2}\n\n#","ref":"rhai_expressions_cheat_sheet.html#cheatsheet","title":"Cheatsheet - Rhai expressions cheatsheet","type":"extras"},{"doc":"##","ref":"rhai_expressions_cheat_sheet.html#arrays","title":"Arrays - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n[1, 2, 3].filter(|value| value % 2 == 0)\n=> [2]\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#filtering-an-array","title":"Filtering an array - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n[\"wow\", \"check\"].index_of(|value| value == \"check\")\n=> 1\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#finding-the-index-of-an-element-inside-an-array","title":"Finding the index of an element inside an array - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\nlet nodelist = [\n #{resource_id: 5, name: \"foo\"},\n #{resource_id: 12, name: \"bar\"}\n];\n\nnodelist.find(|value| value.resource_id == 5)\n=> #{\"name\": \"foo\", \"resource_id\": 5}\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#finding-an-element-inside-an-array","title":"Finding an element inside an array - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n[2, 4, 6].all(|value| value % 2 == 0)\n=> true\n```\n\n#","ref":"rhai_expressions_cheat_sheet.html#checking-if-an-expression-is-true-for-every-element-of-an-array","title":"Checking if an expression is true for every element of an array - Rhai expressions cheatsheet","type":"extras"},{"doc":"##","ref":"rhai_expressions_cheat_sheet.html#maps","title":"Maps - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n#{a: 1, b: 2}.keys()\n=> [\"a\", \"b\"]\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#get-only-keys-returns-an-array","title":"Get only keys (returns an array) - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n#{a: 1, b: 2}.values()\n=> [1, 2]\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#get-only-values-returns-an-array","title":"Get only values (returns an array) - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\nlet map = #{\n ring_one: 12,\n ring_two: 34,\n ring_three: 90,\n ring_four: 234,\n ring_five: 908\n};\n\nmap.keys().filter(|prop| prop.starts_with(\"ring\")).len() >= 5\n=> true\n```\n\n#","ref":"rhai_expressions_cheat_sheet.html#check-if-a-map-has-more-than-5-keys-which-name-starts-with-ring","title":"Check if a map has more than 5 keys which name starts with \"ring\" - Rhai expressions cheatsheet","type":"extras"},{"doc":"##","ref":"rhai_expressions_cheat_sheet.html#strings","title":"Strings - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n\"a;b;c\".split(\";\")\n=> [\"a\", \"b\", \"c\"]\n```","ref":"rhai_expressions_cheat_sheet.html#splitting-a-string","title":"Splitting a string - Rhai expressions cheatsheet","type":"extras"},{"doc":"# Checks Specification\n\nA language allowing to declare best practices to be adhered on target SAP Infrastructures.","ref":"specification.html","title":"Checks Specification","type":"extras"},{"doc":"The need this Specification aims to fulfill is to provide users a simple way to declare what we (the Trento Team) often refer to as \"Checks\".\n\nChecks are, in Trento's domain, the crystallization of SUSE's best practices when it comes to SAP workloads in a form that both a user ([Spec](#anatomy-of-a-check)) and a machine ([Execution](#checks-execution)) can read.\n\n[^1]: The Trento Team from now on.","ref":"specification.html#introduction","title":"Introduction - Checks Specification","type":"extras"},{"doc":"_Checks Execution_ is the process that determines whether the best practices defined in the [Checks Specifications](#anatomy-of-a-check) are being followed on a target infrastructure.\n\n> [Requesting an Execution](#requesting-an-execution) -> [Facts Gathering](#facts-gathering) -> [Expectation Evaluation](#expectation-evaluation)\n\n#","ref":"specification.html#checks-execution","title":"Checks Execution - Checks Specification","type":"extras"},{"doc":"An Execution can be requested to start by providing Wanda the following information:\n\n- an execution identifier\n- an execution Group identifier\n- the Checks Selection for the targets (a list of checks to be executed on the targets)\n\nWhen the Execution starts running, its current state is stored in the Database and the targets are notified - via the message broker - about Facts to be gathered.\n\nThen the _Execution_ waits for the [Facts Gathering](#facts-gathering) to complete.\n\n#","ref":"specification.html#requesting-an-execution","title":"Requesting an Execution - Checks Specification","type":"extras"},{"doc":"After an _Execution Request_ the targets are notified about the facts they need to [gather](./gatherers.md).\n\nWhenever a target has gathered all the needed facts for an _Execution_, it notifies Wanda - via the message broker - about the _Gathered Facts_.\n\n#","ref":"specification.html#facts-gathering","title":"Facts Gathering - Checks Specification","type":"extras"},{"doc":"_Expectation Evaluation_ is the process of [evaluating](#expression-language) the [Expectations](#expectations)\nusing the received _Gathered Facts_ to obtain the result of a check.\n\nThis will only happen once _Gathered Facts_ are received **from all the targets**.\n\nAfter the result has been determined, the currently `running` Execution transitions to `completed` and its new state is tracked on the Database.\n\nAt this point the Execution is considered **Completed** and interested parties are notified about the Execution Completion.\n\n#","ref":"specification.html#expectation-evaluation","title":"Expectation Evaluation - Checks Specification","type":"extras"},{"doc":"Once an execution is completed, a checks result should give feedback on what aspects of a target infrastructure adhere to the best practices and which don't.\n\nPossible results:\n\n- `passing`, everything ok\n- `warning`, best practice not followed, should fix\n- `critical`, best practice not followed, must fix\n\nSee also [Check Severity](#severity).","ref":"specification.html#checks-results","title":"Checks Results - Checks Specification","type":"extras"},{"doc":"A Check declaration comes in the form of a `yaml` file and all the Checks together build up the **Checks Catalog**\n\nHere's an example:\n\n```yaml\nid: \"156F64\"\nname: Corosync `token` timeout\ngroup: Corosync\ndescription: Corosync `token` timeout is set to the correct value\nremediation: |","ref":"specification.html#anatomy-of-a-check","title":"Anatomy of a Check - Checks Specification","type":"extras"},{"doc":"The value of the Corosync `token` timeout is not set as recommended.","ref":"specification.html#abstract","title":"Abstract - Checks Specification","type":"extras"},{"doc":"Adjust the corosync `token` timeout as recommended...\n\nfacts:\n - name: corosync_token_timeout\n gatherer: corosync.conf\n argument: totem.token\n\nvalues:\n - name: expected_token_timeout\n default: 5000\n conditions:\n - value: 30000\n when: env.provider == \"azure\" || env.provider == \"aws\"\n - value: 20000\n when: env.provider == \"gcp\"\n\nexpectations:\n - name: token_timeout\n expect: facts.corosync_token_timeout == values.expected_token_timeout\n```\n\n#","ref":"specification.html#remediation","title":"Remediation - Checks Specification","type":"extras"},{"doc":"**Note** that a Check's filename **MUST** be in the form ` .yaml` (ie: `156F64.yaml`)\n\n#","ref":"specification.html#filename-convention","title":"Filename Convention - Checks Specification","type":"extras"},{"doc":"Following are listed the top level properties of a Check definition yaml.\n\n| Key | Required/Not Required | Details |\n| -------------- | --------------------- | ------------------------- |\n| `id` | required | [see more](#id) |\n| `name` | required | [see more](#name) |\n| `group` | required | [see more](#group) |\n| `description` | required | [see more](#description) |\n| `remediation` | required | [see more](#remediation) |\n| `severity` | not required | [see more](#severity) |\n| `facts` | required | [see more](#facts) |\n| `values` | not required | [see more](#values) |\n| `expectations` | required | [see more](#expectations) |\n\n---\n\n##","ref":"specification.html#structure","title":"Structure - Checks Specification","type":"extras"},{"doc":"Uniquely identifies a Check in the Catalog\n\nie:\n\n```yaml\nid: \"156F64\"\nid: \"845CC9\"\nid: \"B089BE\"\n```\n\n##","ref":"specification.html#id","title":"id - Checks Specification","type":"extras"},{"doc":"A, preferably one-line, string representing the name for the Check being declared.\n\nie:\n\n```yaml\nname: Corosync `token` timeout\nname: Corosync `consensus` timeout\nname: SBD Startmode\n```\n\n##","ref":"specification.html#name","title":"name - Checks Specification","type":"extras"},{"doc":"A, preferably one-line, string representing the group where the Check being declared belongs.\n\nExample:\n\n```yaml\ngroup: Corosync\ngroup: Pacemaker\ngroup: SBD\n```\n\n##","ref":"specification.html#group","title":"group - Checks Specification","type":"extras"},{"doc":"A text providing a description for the Check being declared.\n\ncan be a one-liner\n\n```yaml\ndescription: Some plain description\n```\n\ncan be a multiline text\n\n```yaml\ndescription: |\n Some plain multiline\n description that carries a lot\n of information\n```\n\nformat is **markdown**\n\n```yaml\ndescription: |\n A `description` is a **markdown**\n```\n\n##","ref":"specification.html#description","title":"description - Checks Specification","type":"extras"},{"doc":"A text providing an comprehensive description about the remediation to apply for the Check being declared.\n\nIt has the same properties of the `description`\n\n- can be a one-liner (it usually is not)\n- can be a multiline (it usually is)\n- format is **markdown**\n\nExample:\n\n```yaml\nremediation: |","ref":"specification.html#remediation","title":"remediation - Checks Specification","type":"extras"},{"doc":"The value of the Corosync `token` timeout is not set as recommended.","ref":"specification.html#abstract","title":"Abstract - Checks Specification","type":"extras"},{"doc":"Adjust the corosync `token` timeout as recommended on the best \n ...\n 2. Reload the corosync configuration:\n ...\n```\n\n##","ref":"specification.html#remediation","title":"Remediation - Checks Specification","type":"extras"},{"doc":"A string determining the severity of the Check being declared, in case the check is not passing, so that the appropriate result is reported.\n\nAllowed values: `warning`, `critical`\n\n**Default:** if no severity is provided, the system would default to `critical`\n\nExample:\n\nReports a `warning` When the Check expectations do not pass\n\n```yaml\nseverity: warning\n```\n\nReports a `critical` When the Check expectations do not pass\n\n```yaml\nseverity: critical\n```\n\n##","ref":"specification.html#severity","title":"severity - Checks Specification","type":"extras"},{"doc":"A boolean determining whether the check is premium or not. It doesn't have any real impact in the check execution itself, it is only an informative field, mostly used by the web frontend.\n\n**Default:** if no premium flag is provided, the system would default to `false`\n\nExample:\n\nSets the check as premium\n\n```yaml\npremium: true\n```\n\n##","ref":"specification.html#premium","title":"premium - Checks Specification","type":"extras"},{"doc":"See main sections [Facts](#facts), [Values](#values), [Expectations](#expectations)","ref":"specification.html#facts-values-expectations","title":"Facts, Values, Expectations - Checks Specification","type":"extras"},{"doc":"Facts are the core data on which the engine evaluates the state of the target infrastructure.\nExamples include (but are not limited to) installed packages, cluster state, and configuration files content.\n\nThe process of determining the value of a declared fact during Check execution is referred to as _Facts Gathering_ and it is the responsibility of the [_Gatherers_](./gatherers.md).\nGatherers could be seen as functions that have a name and accept argument(s).\n\nThat said, a fact declaration contains:\n\n- the fact name\n- the gatherer used to retrieve the fact\n- the argument(s) to be provided to the gatherer\n\n**Note:**\n\n- many facts can be declared\n- all the declared facts would be registered in the [`facts`](#facts-1) namespaced evaluation scope.\n\n```yaml\nfacts:\n - name: \n gatherer: \n argument: \n\n - name: \n gatherer: \n argument: \n```\n\nThe following example declares a **fact** named `corosync_token_timeout`, retrievable via the built-in `corosync.conf` **gatherer** to which will be provided the **argument** `totem.token`\n\n```yaml\nfacts:\n - name: corosync_token_timeout\n gatherer: corosync.conf\n argument: totem.token\n\n # other facts maybe\n```\n\nFinally, gathered facts, are used in Check's [Expectations](#expectations) to determine whether expected conditions are met for the best practice to be adhered.","ref":"specification.html#facts","title":"Facts - Checks Specification","type":"extras"},{"doc":"Values are named variables that may evaluate differently based on the execution context and are used with Facts for _Contextual_ [Expectations](#expectations) Evaluation.\n\n> When contextual expectations is not needed, there's the following options available:\n>\n> - use [**hardcoded**](#hardcoded-values) values\n> - define `values` as [**constants**](#constant-values)\n>\n> Scenario:\n>\n> No matter what the context is, the fact `awesome_fact` MUST always be `wanda`\n\n#","ref":"specification.html#values","title":"Values - Checks Specification","type":"extras"},{"doc":"Direct usage of a simple hardcoded value\n\n```yaml\nexpectations:\n - name: awesome_expectation\n expect: facts.awesome_fact == \"wanda\"\n```\n\n#","ref":"specification.html#hardcoded-values","title":"Hardcoded Values - Checks Specification","type":"extras"},{"doc":"Define a Value with only the `default` specified (**omitting** `conditions`) for **constants** regardless of the context.\n\n```yaml\nvalues:\n - name: awesome_constant_value\n default: \"wanda\"\n\nexpectations:\n - name: awesome_expectation\n expect: facts.awesome_fact == values.awesome_constant_value\n```\n\n#","ref":"specification.html#constant-values","title":"Constant Values - Checks Specification","type":"extras"},{"doc":"This is needed because the same check might expect facts to be treated differently based on the context.\n\n> Let's clarify with an example:\n>\n> A Check might define a fact named `awesome_fact` which is expected to be different given the _color_ of the execution.\n>\n> - it has to be `cat` when the `color` in the execution context is `red`\n> - it has to be `dog` when the `color` in the execution context is `blue`\n> - it has to be `rabbit` in all other cases, regardless of the execution context\n>\n> so we define a named variable `awesome_expectation` that resolves to `cat|dog|rabbit` when proper conditions are met\n>\n> allowing us to have an expectation like this\n>\n> `expect: facts.awesome_fact == values.awesome_expectation`\n\nA Value declaration contains:\n\n- the value name\n- the default value\n- a list of conditions that determine the value given the context (optional, see [constant values](#constant-values))\n\n```yaml\nvalues:\n - name: \n default: \n conditions:\n - value: \n when: \n - value: \n when: \n```\n\nIt could read as:\n\nthe value named ` ` resolves to\n\n- ` ` when ` ` is true\n- ` ` when ` ` is true\n- ` ` in all other cases\n\nExample:\n\n> Check `156F64 Corosync token timeout is set to expected value` defines a fact `corosync_token_timeout` which is expected to be different given the platform (aws/azure/gcp), so we define a named variable `expected_token_timeout` resolving to the appropriate value.\n>\n> `expected_token_timeout` resolves to:\n>\n> - `30000` when `azure`/`aws` are detected\n> - `20000` on `gcp`\n> - `5000` in all other cases (ie: bare metal, VMs...)\n\n```yaml\nvalues:\n - name: expected_token_timeout\n default: 5000\n conditions:\n - value: 30000\n when: env.provider == \"azure\" || env.provider == \"aws\"\n - value: 20000\n when: env.provider == \"gcp\"\n\nexpectations:\n - name: corosync_token_timeout_is_correct\n expect: facts.corosync_token_timeout == values.expected_token_timeout\n```\n\nNote that `conditions` is a cascading chain of contextual inspection to determine which is the resolved value.\n\n- there may be many conditions\n- first condition that passes determines the value, following are not evaluated\n- `when` entry [Expression](#expression-language) has [access](#evaluation-scope) to gathered [facts](#facts-1) and [env](#env) evaluation scopes\n\nAll the _resolved_ declared values would be registered in the [`values`](#values-1) namespaced evaluation scope.","ref":"specification.html#contextual-values","title":"Contextual Values - Checks Specification","type":"extras"},{"doc":"Expectations are assertions on the state of a target infrastructure for a given scenario. By using fact and values they are able to determine if a check passes or not.\n\nAn Expectation declaration contains:\n\n- the expectation name\n- the expectation expression itself with [access](#evaluation-scope) to gathered [facts](#facts-1) and [resolved values](#values-1)\n- an optional [failure message](#failure-message)\n\n```yaml\nexpectations:\n - name: \n expect: \n\n - name: \n expect: \n failure_message: \n\n - name: \n expect_same: \n```\n\nExtra considerations:\n\n- there can be many expectations for a single Check\n- an expectation can be one of two types [`expect`](#expect) or [`expect_same`](#expect_same)\n- a Check passes when all the expectations are satisfied\n\nExample\n\n```yaml\nexpectations:\n - name: token_timeout\n expect: facts.corosync_token_timeout == values.expected_token_timeout\n\n - name: awesome_expectation\n expect: facts.awesome_fact == values.awesome_expected_value\n```\n\nIn the previous example a Checks passes (is successful) if all expectations are met, meaning that\n\n```\nfacts.corosync_token_timeout == values.expected_token_timeout\nAND\nfacts.awesome_fact == values.awesome_expected_value\n```\n\n#","ref":"specification.html#expectations","title":"Expectations - Checks Specification","type":"extras"},{"doc":"This type of expectation is satisfied when, after facts gathering, the expression is `true` for all the targets involved in the current execution.\n\n> Execution Scenario:\n>\n> - 2 targets [`A`, `B`]\n> - selected Checks [`corosync_check`]\n> - some environment (context)\n>\n> ```yaml\n> facts:\n> - name: corosync_token_timeout\n> gatherer: corosync.conf\n> argument: totem.token\n>\n> values: ...\n>\n> expectations:\n> - name: corosync_token_timeout_is_correct\n> expect: facts.corosync_token_timeout == values.expected_token_timeout\n> ```\n\nConsidering the previous scenario what happens is that:\n\n- the fact `corosync_token_timeout` is gathered on all targets (`A` and `B` in this case)\n- the expectation expression gets executed against the `corosync_token_timeout` fact gathered on every targets.\n - `targetA.corosync_token_timeout == values.expected_token_timeout`\n - `targetB.corosync_token_timeout == values.expected_token_timeout`\n- every evaluation has to be `true`\n\n#","ref":"specification.html#expect","title":"expect - Checks Specification","type":"extras"},{"doc":"This type of expectation is satisfied when, after facts gathering, the expression's return value is the same for all the targets involved in the current execution, regardless of the value itself.\n\n> Execution Scenario:\n>\n> - 2 targets [`A`, `B`, `C`]\n> - selected Checks [`some_check`]\n> - some environment (context)\n>\n> ```yaml\n> expectations:\n> - name: awesome_expectation\n> expect_same: facts.awesome_fact\n> ```\n\nConsidering the previous scenario what happens is that:\n\n- the fact `awesome_fact` is gathered on all targets (`A`, `B` and `C` in this case)\n- the expectation expression gets executed for every target involved.\n - `targetA.facts.awesome_fact`\n - `targetB.facts.awesome_fact`\n - `targetC.facts.awesome_fact`\n- the expressions results has to be the same for every target\n - `targetA.facts.awesome_fact == targetB.facts.awesome_fact == targetC.facts.awesome_fact`\n\n> Example:\n>\n> RPM version must be the same on all the targets, regardless of what version it is\n>\n> ```yaml\n> facts:\n> - name: installed_rpm_version\n> gatherer: package_version\n> argument: rpm\n>\n> expectations:\n> - name: installed_rpm_version_must_be_the_same_on_all_targets\n> expect_same: facts.installed_rpm_version\n> ```\n\n#","ref":"specification.html#expect_same","title":"expect_same - Checks Specification","type":"extras"},{"doc":"An optional failure message can be declared for every expectation.\n\nIn case of an `expect` one, the failure message can interpolate `facts` and `values` present in the check definition to provide more meaningful insights:\n\n```yaml\nexpectations:\n - name: awesome_expectation\n expect: values.awesome_constant_value == facts.awesome_fact\n failure_message: The expectation did not match ${values.awesome_constant_value}\n```\n\nThe outcome of the interpolation is available in `ExpectationEvaluation` inside the API response.\n\nIn case of an `expect_same` one, the failure message has to be a plain string:\n\n```yaml\nexpectations:\n - name: awesome_expectation\n expect_same: facts.awesome_fact\n failure_message: Boom!\n```\n\nThis plain string is available in `ExpectationResult` inside the API response.","ref":"specification.html#failure_message","title":"failure_message - Checks Specification","type":"extras"},{"doc":"Different parts of the Check declaration are places where an evaluation is needed.\n\n> Determine to what a [value](#values) resolves during execution\n>\n> `when: ` part of a Value's condition\n\n```yaml\nvalues:\n - name: expected_token_timeout\n default: 5000\n conditions:\n - value: 30000\n when: env.provider == \"azure\" || env.provider == \"aws\"\n - value: 20000\n when: env.provider == \"gcp\"\n```\n\n> Defining the [Expectation](#expectations) of a Check\n>\n> `expect|expect_same: `\n\n```yaml\nexpectations:\n - name: token_timeout\n expect: facts.corosync_token_timeout == values.expected_token_timeout\n```\n\nSee [reference for the Expression Language](./expression_language.md).\n\n#","ref":"specification.html#expression-language","title":"Expression Language - Checks Specification","type":"extras"},{"doc":"Every expression has access to an evaluation scope, allowing to access relevant piece of information to run the expression.\n\nScopes are namespaced and access to items in the scope is name based.\n\n#### **env**\n\n`env` is a map of information about the context of the running execution, it is set by the system on each execution/check compilation.\n\nExamples of entries in the scope. What is actually available during the execution depends on the scenario. Find the updated values in the reference column link.\n\n| name | Type | Reference\n| ---- | -----| ----------\n| `env.provider` | one of `azure`, `aws`, `gcp`,`kvm`,`nutanix`, `vmware`, `unknown` | [Providers](https://github.com/trento-project/web/blob/main/lib/trento/domain/enums/provider.ex)\n| `env.cluster_type` | one of `hana_scale_up`, `hana_scale_out`, `ascs_ers`, `unknown` | [Cluster types](https://github.com/trento-project/web/blob/main/lib/trento/domain/enums/cluster_type.ex)\n| `env.target_type` | one of `cluster`, `host` | No enum available\n\n#### **facts**\n\n`facts` is the map of the gathered facts, thus the scope varies based on which facts have been declared in the [relative section](#facts), and are accessible in other sections by fact name.\n\n```yaml\nfacts:\n - name: an_interesting_fact\n gatherer: \n argument: \n\n - name: another_interesting_fact\n gatherer: \n argument: \n```\n\nAvailable entries in scope, the value is what has been gathered on the targets\n| name \n| -----------------------------\n| `facts.an_interesting_fact` \n| `facts.another_interesting_fact`\n\n#### **values**\n\n`values` is the map of resolved variable names defined in the [relative section](#values)\n\n```yaml\nvalues:\n - name: expected_token_timeout\n default: 5000\n conditions:\n - value: 30000\n when: env.provider == \"azure\" || env.provider == \"aws\"\n - value: 20000\n when: env.provider == \"gcp\"\n\n - name: another_variable_value\n default: \"blue\"\n conditions:\n - value: \"red\"\n when: env.should_be_red == true\n```\n\nAvailable entries in scope\n| name | Resolved to \n| ------------------------------- | -------------------------------------------------------\n| `values.expected_token_timeout` | `5000`, `30000`, `20000` based on the conditions\n| `values.another_variable_value` | `blue`, `red` based on the conditions","ref":"specification.html#evaluation-scope","title":"Evaluation Scope - Checks Specification","type":"extras"},{"doc":"To have a standardized format for writing checks, follow the next best practices and conventions as much as possible:\n\n- The `id` field must be wrapped in double quotes to avoid any type of ambiguity, as this field must be of string format.\n- The remaining `name`, `description`, `group`, and `remediation` fields must not be wrapped in quotes, as they are text-based values always.\n- Take advantage of markdown tags in the `name`, `description`, and `remediation` fields to make the text easy and compelling to read.\n- The `name` field of `facts`, `values`, and `expectations` must follow `camel_case` format. \n For example:\n ```\n facts:\n - name: some_fact\n ...\n values:\n - name: expected_some_fact\n ...\n expectations:\n - name: some_expectation\n ...\n ```\n- Use 2 spaces to indent multiline expectation expressions.\n- Naming hardcoded values in the `values` section with the `default` field is encouraged instead of putting hardcoded values in the expectation expression itself. This gives some meaning to the expected value and improves potential interaction with the Wanda API. \n So this:\n\n ```\n expectations:\n - name: some_expectation\n expect: facts.foo == 30\n ```\n\n would be:\n\n ```\n values:\n - name: expected_foo\n default: 30\n\n expectations:\n - name: some_expectation\n expect: facts.foo == values.expected_foo\n ```\n\n- If the gathered fact is compared to a value, using `value` and `expected_value` names for facts and values respectively is recommended, as it improves the meaning of the comparison. \n For example:\n ```\n facts:\n - name: some_fact\n ...\n values:\n - name: expected_some_fact\n ...\n ```\n- Avoid adding prefixes such as `facts` or `values` to the entries of these sections, as they already use this as a namespace.\n For example, the next example should be avoided, as the `facts` prefix would be redundant in the expectation expression:\n ```\n facts:\n - name: facts_some_fact\n ```\n- If the implemented expectation expression contains any kind of `&&` to combine multiple operations, consider adding them as individual expectations, as the final result is the combination of all of them. \n So this:\n ```\n expectations:\n - name: some_expectation\n expect: facts.foo == values.expected_foo && facts.bar == values.expected_bar\n ```\n would be:\n ```\n expectations:\n - name: foo_expectation\n expect: facts.foo == values.expected_foo\n - name: bar_expectation\n expect: facts.bar == values.expected_bar\n ```\n- Pipe the expression language functions vertically in order to provide a better visual output of the code. \n So this:\n ```\n expectations:\n - name: some_expectation\n expect: facts.foo.find(|item| item.id == \"super\").properties.find(|prop| prop.name == \"good\").value\n ```\n would be:\n ```\n expectations:\n - name: some_expectation\n expect: |\n facts.foo\n .find(|item| item.id == \"super\").properties\n .find(|prop| prop.name == \"good\").value\n ```\n > Note: Keep in mind that some functions such as `sort` and `drain` run in-place modifications, so they cannot be piped.","ref":"specification.html#best-practices-and-conventions","title":"Best practices and conventions - Checks Specification","type":"extras"},{"doc":"# Expression Language\n\nA small, fast, easy-to-use scripting language and evaluation engine.","ref":"expression_language.html","title":"Expression Language","type":"extras"},{"doc":"An embedded scripting language and evaluation engine for Trento Checks Expressions that gives a safe and easy way to script specific steps during Checks Execution.","ref":"expression_language.html#introduction","title":"Introduction - Expression Language","type":"extras"},{"doc":"| Type | Example |\n| ------------------------------ | ------------------------ |\n| **Nothing/void/nil/null/Unit** | `()` |\n| **Integer** | `42`, `123` |\n| **Float** | `123.4567` |\n| **Boolean** | `true` or `false` |\n| **String** | `\"hello\"` |\n| **Array** | `[ 1, 2, 3, \"foobar\" ]` |\n| **Map** | `#{ \"a\": 1, \"b\": true }` |","ref":"expression_language.html#types","title":"Types - Expression Language","type":"extras"},{"doc":"| Operator | Description (`x` _operator_ `y`) | `x`, `y` same type or are numeric | `x`, `y` different types |\n| :------: | ------------------------------------ | :-------------------------------: | :----------------------: |\n| `==` | `x` is equals to `y` | error if not defined | `false` if not defined |\n| `!=` | `x` is not equals to `y` | error if not defined | `true` if not defined |\n| `>` | `x` is greater than `y` | error if not defined | `false` if not defined |\n| `>=` | `x` is greater than or equals to `y` | error if not defined | `false` if not defined |\n| `<` | `x` is less than `y` | error if not defined | `false` if not defined |\n| `<=` | `x` is less than or equals to `y` | error if not defined | `false` if not defined |\n\n#","ref":"expression_language.html#logic-operators-and-boolean","title":"Logic Operators and Boolean - Expression Language","type":"extras"},{"doc":"Comparing two values of _different_ data types defaults to `false`.\n\nThe exception is `!=` (not equals) which defaults to `true`. This is in line with intuition.\n\n```ts\n42 > \"42\"; // false: i64 cannot be compared with string\n42 <= \"42\"; // false: i64 cannot be compared with string\nts == 42; // false: different types cannot be compared\nts != 42; // true: different types cannot be compared\n```\n\n#","ref":"expression_language.html#comparing-different-types-defaults-to-false","title":"Comparing different types defaults to `false` - Expression Language","type":"extras"},{"doc":"| Operator | Description | Arity | Short-circuits? |\n| :---------------: | :---------: | :----: | :-------------: |\n| `!` _(prefix)_ | _NOT_ | unary | no |\n| `&&` | _AND_ | binary | yes |\n| `&` | _AND_ | binary | no |\n| \\|\\| | _OR_ | binary | yes |\n| \\| | _OR_ | binary | no |\n\nDouble boolean operators `&&` and `||` _short-circuit_ – meaning that the second operand will not be evaluated\nif the first one already proves the condition wrong.\n\nSingle boolean operators `&` and `|` always evaluate both operands.\n\n```ts\na() || b(); // b() is not evaluated if a() is true\na() && b(); // b() is not evaluated if a() is false\na() | b(); // both a() and b() are evaluated\na() & b(); // both a() and b() are evaluated\n```","ref":"expression_language.html#boolean-operators","title":"Boolean Operators - Expression Language","type":"extras"},{"doc":"`if` statements follow C syntax.\n\n```ts\nif foo(x) {\n print(\"It's true!\");\n} else if bar == baz {\n print(\"It's true again!\");\n} else if baz.is_foo() {\n print(\"Yet again true.\");\n} else if foo(bar - baz) {\n print(\"True again... this is getting boring.\");\n} else {\n print(\"It's finally false!\");\n}\n```\n\n> Unlike C, the condition expression does _not_ need to be enclosed in parentheses `(`...`)`, but all\n> branches of the `if` statement must be enclosed within braces `{`...`}`, even when there is only\n> one statement inside the branch.\n> Like Rust, there is no ambiguity regarding which `if` clause a branch belongs to.\n>\n> ```ts\n> // not C!\n> if (decision) print(42);\n> // ^ syntax error, expecting '{'\n> ```\n\n#","ref":"expression_language.html#if-statement","title":"If Statement - Expression Language","type":"extras"},{"doc":"`if` statements can also be used as _expressions_, replacing the `? :` conditional\noperators in other C-like languages.\n\n```ts\n// The following is equivalent to C: int x = 1 + (decision ? 42 : 123) / 2;\nlet x = 1 + if decision { 42 } else { 123 } / 2;\nx == 22;\nlet x = if decision { 42 }; // no else branch defaults to '()'\nx == ();\n```","ref":"expression_language.html#if-expression","title":"If Expression - Expression Language","type":"extras"},{"doc":"All elements stored in an array are dynamic, and the array can freely grow or shrink with elements\nadded or removed.\n\nArray literals are built within square brackets `[` ... `]` and separated by commas `,`:\n\n> `[` _value_`,` _value_`,` ... `,` _value_ `]`\n>\n> `[` _value_`,` _value_`,` ... `,` _value_ `,` `]` `// trailing comma is OK`\n\n```ts\nlet some_list = [1, 2, 3];\n\nlet another_list = [\"foo\", \"bar\", 42];\n```\n\n#","ref":"expression_language.html#arrays","title":"Arrays - Expression Language","type":"extras"},{"doc":"Like C, arrays are accessed with zero-based, non-negative integer indices:\n\n> _array_ `[` _index position from 0 to length−1_ `]`\n\n```ts\nlet some_list = [\"foo\", \"bar\", 42];\n\nlet second_element = some_list[1];\n\n// second_element is \"bar\"\n```\n\n#","ref":"expression_language.html#access-element-from-beginning","title":"Access Element From beginning - Expression Language","type":"extras"},{"doc":"A _negative_ position accesses an element in the array counting from the _end_, with −1 being the\n_last_ element.\n\n> _array_ `[` _index position from −1 to −length_ `]`\n\n```ts\nlet some_list = [\"foo\", \"bar\", 42];\n\nlet second_element = some_list[-2];\nlet last_element = some_list[-1];\n\n// second_element is \"bar\"\n// last_element is 42\n```\n\n| Function | Parameter(s) | Description |\n| -------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `get` | position, counting from end if array item _(optional)_ offset position |\n| `all` | predicate (usually a closure) | returns `true` if all items return `true` when called with the predicate function taking the following parameters: array item _(optional)_ offset position |\n\nExamples\n\n```ts\nlet some_list = [1, 2, 3, 4, \"foo\", \"bar\"];\n\nlet foo = some_list.get(4); // \"foo\"\n\nlet items_count = some_list.len(); // 6\n\nlet only_foo_and_bar = some_list.filter(|item| item == \"foo\" || item == \"bar\"); // [\"foo\", \"bar\"]\n// let only_foo_and_bar = some_list.filter(|item, idex_in_array| item == \"foo\" || item == \"bar\");\n\nlet another_list = [3, 5, 7, 9, 10, 20, 30];\n\nlet all_greater_than_2 = another_list.all(|item| item > 2); // true\nlet all_greater_than_10 = another_list.all(|item| item > 10); // false\n// let all_greater_than_10 = another_list.all(|item, idex_in_array| item > 10);\n```","ref":"expression_language.html#access-element-from-end","title":"Access Element From end - Expression Language","type":"extras"},{"doc":"Maps are hash dictionaries. Properties are all dynamic values and can be freely added and retrieved.\n\nMap literals are built within braces `#{` ... `}` with _name_`:`_value_ pairs separated by\ncommas `,`:\n\n> `#{` _property_ `:` _value_`,` ... `,` _property_ `:` _value_ `}`\n>\n> `#{` _property_ `:` _value_`,` ... `,` _property_ `:` _value_ `,` `}` `// trailing comma is OK`\n\n```ts\nlet some_map = #{ // map literal with 2 properties\n foo: 42,\n bar: \"hello\",\n};\n```\n\n#","ref":"expression_language.html#maps","title":"Maps - Expression Language","type":"extras"},{"doc":"The _dot notation_ allows to access properties by name.\n\n> _object_ `.` _property_\n\n```ts\nlet some_map = #{ // map literal with 2 properties\n foo: 42,\n bar: \"hello\",\n};\n\nsome_map.foo // 42\nsome_map.bar // \"hello\"\n\n```\n\n#","ref":"expression_language.html#dot-notation","title":"Dot notation - Expression Language","type":"extras"},{"doc":"Trying to read a non-existing property returns an error.\n\n```ts\nlet some_map = #{ // map literal with 2 properties\n foo: 42,\n bar: \"hello\",\n};\n\nsome_map.another_property // returns \"Property not found: another_property (line X, position Y)\"\n```\n\n#","ref":"expression_language.html#non-existing-property","title":"Non-existing property - Expression Language","type":"extras"},{"doc":"```ts\nlet some_map = #{ // map literal with 2 properties\n foo: 42,\n bar: \"hello\",\n rabbits: [\n #{\n name: \"wanda\",\n power: 9001\n },\n #{\n name: \"tonio\",\n power: 9002\n },\n #{\n name: \"weak_rabbit\",\n power: 8999\n }\n ]\n};\n\n// Tell me how many strong rabbits are there\nlet strong_rabbits = some_map.rabbits.filter(|rabbit| rabbit.power > 9000).len() // 2\n\nlet rabbits = some_map.rabbits\n\nlet all_rabbits_are_strong = rabbits.all(|rabbit| rabbit.power > 9000) // false, unfortunately\n\n```","ref":"expression_language.html#a-more-complex-example","title":"A more complex example - Expression Language","type":"extras"},{"doc":"For extra information about the underlying scripting language see [Rhai](https://rhai.rs/book/language/).","ref":"expression_language.html#rhai","title":"Rhai - Expression Language","type":"extras"},{"doc":"# Gatherers","ref":"gatherers.html","title":"Gatherers","type":"extras"},{"doc":"Gatherers can be thought of as functions:\n\n- they have a name\n- they accept argument(s)\n- they return a value, the gathered [Fact](./specification.md#facts)\n\nFacts Gathering process in a nutshell\n\n```\nfact = gatherer(argument)\n```","ref":"gatherers.html#introduction","title":"Introduction - Gatherers","type":"extras"},{"doc":"Here's a collection of built-in gatherers, with information about how to use them.\n\n| Name | Implementation |\n| :-------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| [`cibadmin`](#cibadmin) | [trento-project/agent/../gatherers/cibadmin.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/cibadmin.go) |\n| [`corosync.conf`](#corosyncconf) | [trento-project/agent/../gatherers/corosyncconf.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/corosyncconf.go) |\n| [`corosync-cmapctl`](#corosync-cmapctl) | [trento-project/agent/../gatherers/corosynccmapctl.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/corosynccmapctl.go) |\n| [`dir_scan`](#dir_scan) | [trento-project/agent/../gatherers/dir_scan.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/dir_scan.go) |\n| [`fstab`](#fstab) | [trento-project/agent/../gatherers/fstab.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/fstab.go) |\n| [`groups`](#groups) | [trento-project/agent/../gatherers/groups.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/groups.go) |\n| [`hosts`](#hosts-etchosts) | [trento-project/agent/../gatherers/hostsfile.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/hostsfile.go) |\n| [`package_version`](#package_version) | [trento-project/agent/../gatherers/packageversion.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/packageversion.go) |\n| [`passwd`](#passwd) | [trento-project/agent/../gatherers/passwd.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/passwd.go) |\n| [`saphostctrl`](#saphostctrl) | [trento-project/agent/../gatherers/saphostctrl.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/saphostctrl.go) |\n| [`sap_profiles`](#sap_profiles) | [trento-project/agent/../gatherers/sapprofiles.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sapprofiles.go) |\n| [`saptune`](#saptune) | [trento-project/agent/../gatherers/saptune.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/saptune.go) |\n| [`sbd_config`](#sbd_config) | [trento-project/agent/../gatherers/sbd.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sbd.go) |\n| [`sbd_dump`](#sbd_dump) | [trento-project/agent/../gatherers/sbddump.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sbddump.go) |\n| [`sysctl`](#sysctl) | [trento-project/agent/../gatherers/sysctl.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sysctl.go) |\n| [`systemd`](#systemd) | [trento-project/agent/../gatherers/systemd.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/systemd.go) |\n| [`verify_password`](#verify_password) | [trento-project/agent/../gatherers/verifypassword.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/verifypassword.go) |\n\n#","ref":"gatherers.html#available-gatherers","title":"Available Gatherers - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows accessing Pacemaker's CIB information, the output of the `cibadmin` command more precisely.\nAs the `cibadmin` command output is in XML format, the gatherer converts it to map/dictionary type format, so the fields are available with the normal dot access way.\nSome specific fields, such as `primitive`, `clone`, `master`, etc (find the complete list [here](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/cibadmin.go#L48)) are converted to lists, in order to avoid differences when the field appears one or multiple times.\n\nExample arguments:\n\n| Name | Return value |\n| :------------------------------------------------------------- | :----------------------------------------------------------------- |\n| `cib.configuration` | complete cib configuration entry as a map |\n| `cib.configuration.resources.primitive.0` | first available primitive resource |\n| `cib.configuration.crm_config.cluster_property_set.0.nvpair.1` | second nvpair value from the first element of cluster_property_set |\n\nExample specification:\n\n```yaml\nfacts:\n - name: cib_configuration\n gatherer: cibadmin\n argument: cib.configuration\n\n - name: first_primitive\n gatherer: cibadmin\n argument: cib.configuration.resources.primitive.0\n\n - name: first_cluster_property_set_second_nvpair\n gatherer: cibadmin\n argument: cib.configuration.crm_config.cluster_property_set.0.nvpair.1\n```\n\nExample output (in Rhai):\n\n```ts\n// first_primitive\n#{\n class: \"stonith\",\n id: \"stonith-sbd\",\n instance_attributes: #{\n id: \"stonith-sbd-instance_attributes\",\n nvpair: [#{\n id: \"stonith-sbd-instance_attributes-pcmk_delay_max\",\n name: \"pcmk_delay_max\",\n value: \"30s\"\n }]\n },\n type: \"external/sbd\"\n};\n\n// first_cluster_property_set_second_nvpair\n#{\n id: \"cib-bootstrap-options-dc-version\",\n name: \"dc-version\",\n value: \"2.0.4+20200616.2deceaa3a-3.12.1-2.0.4+20200616.2deceaa3a\"\n};\n```\n\n#","ref":"gatherers.html#cibadmin","title":"cibadmin - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows accessing the information contained in `/etc/corosync/corosync.conf`\n\nExample arguments:\n\n| Name | Return value |\n| :---------------------------------- | -------------------------------------- |\n| `totem.token` | extracted value from the config |\n| `totem.join` | extracted value from the config |\n| `nodelist.node. .nodeid` | extracted value from the config |\n| `nodelist.node` | list of objects representing the nodes |\n\nExample specification:\n\n```yaml\nfacts:\n - name: corosync_token_timeout\n gatherer: corosync.conf\n argument: totem.token\n\n - name: corosync_join\n gatherer: corosync.conf\n argument: totem.join\n\n - name: corosync_node_id_0\n gatherer: corosync.conf\n argument: nodelist.node.0.nodeid\n\n - name: corosync_node_id_1\n gatherer: corosync.conf\n argument: nodelist.node.1.nodeid\n\n - name: corosync_nodes\n gatherer: corosync.conf\n argument: nodelist.node\n```\n\nExample output (in Rhai):\n\n```ts\n// corosync_token_timeout\n30000;\n\n// corosync_join\n60;\n\n// corosync_node_id_0\n1;\n\n// corosync_node_id_1\n2;\n\n// corosync_nodes\n[#{nodeid: 1, ring0_addr: \"192.168.157.10\"}, #{nodeid: 2, ring0_addr: \"192.168.157.11\"}];\n```\n\nFor extra information refer to [trento-project/agent/../gatherers/corosyncconf_test.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/corosyncconf_test.go)\n\n#","ref":"gatherers.html#corosync-conf","title":"corosync.conf - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nThis gatherer allows accessing the output of the `corosync-cmapctl` tool. It supports all of the keys returned by it to be queried.\n\nExample arguments:\n\n| Name | Return value |\n| :---------------------------------- | :------------------------------- |\n| `totem.token` | extracted value from the command |\n| `runtime.config.totem.token` | extracted value from the command |\n| `totem.transport` | extracted value from the command |\n| `runtime.config.totem.max_messages` | extracted value from the command |\n| `nodelist.node.0.ring0_addr` | extracted value from the command |\n| `nodelist.node` | extracted value from the command |\n| `nodelist.node.1` | extracted value from the command |\n\nExample specification:\n\n```yaml\nfacts:\n - name: totem_token\n gatherer: corosync-cmapctl\n argument: totem.token\n\n - name: runtime_totem_token\n gatherer: corosync-cmapctl\n argument: runtime.config.totem.token\n\n - name: totem_transport\n gatherer: corosync-cmapctl\n argument: totem.transport\n\n - name: totem_max_messages\n gatherer: corosync-cmapctl\n argument: runtime.config.totem.max_messages\n\n - name: node_0_ring0addr\n gatherer: corosync-cmapctl\n argument: nodelist.node.0.ring0_addr\n\n - name: node_list\n gatherer: corosync-cmapctl\n argument: nodelist.node\n \n - name: second_node\n gatherer: corosync-cmapctl\n argument: nodelist.node.1\n```\n\nExample output (in Rhai):\n\n```ts\n// totem_token\n30000;\n\n// runtime_totem_token\n30000;\n\n// totem_transport\n\"udpu\";\n\n// totem_max_messages\n20;\n\n// node_0_ring0addr\n\"10.80.1.11\";\n\n// node_list\n#{\n \"0\": #{\n nodeid: 1,\n ring0_addr: \"10.80.1.11\"\n },\n \"1\": #{\n nodeid: 2,\n ring0_addr: \"10.80.1.12\"\n }\n};\n\n// second_node\n#{ nodeid: 2, ring0_addr: \"10.80.1.12\" };\n```\n\n#","ref":"gatherers.html#corosync-cmapctl","title":"corosync-cmapctl - Gatherers","type":"extras"},{"doc":"**Argument required**: Yes\n\nThis gatherer allows to scan directories with a glob pattern provided as argument.\nThe gatherer returns a list of files matched by the pattern with group/user information associated to each file.\n\nExample argument:\n\n- `/usr/sap/[A-Z][A-Z0-9][A-Z0-9]/ERS[0-9][0-9]`\n- `/etc/polkit-1/rules.d/[0-9][0-9]-SAP[A-Z][A-Z0-9][A-Z0-9]-[0-9][0-9].rules`\n\nExample specification:\n\n```yaml\nfacts:\n - name: dir_scan\n gatherer: dir_scan\n argument: \"/usr/sap/[A-Z][A-Z0-9][A-Z0-9]/ERS[0-9][0-9]\"\n```\n\nExample output (in Rhai):\n\n```ts\n [\n #{\n \"name\": \"/usr/sap/PRD/ERS01\",\n \"owner\": \"trento\",\n \"group\": \"trento\"\n },\n #{\n \"name\": \"/usr/sap/QAS/ERS02\",\n \"owner\": \"trento\",\n \"group\": \"trento\"\n },\n ]\n```\n\n#","ref":"gatherers.html#dir_scan","title":"dir_scan - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows access to the /etc/fstab file, returning all entries available at the file.\n\nExample specification:\n\n```yaml\nfacts:\n - name: fstab\n gatherer: fstab\n```\n\nExample output (in Rhai):\n\n```ts\n[\n #{\n \"device\": \"/dev/system/root\",\n \"mount_point\": \"/\",\n \"file_system_type\": \"btrfs\",\n \"options\": [],\n \"backup\": 0,\n \"check_order\": 1,\n },\n #{\n \"device\": \"/dev/system/root\",\n \"mount_point\": \"/home\",\n \"file_system_type\": \"ext4\",\n \"options\": [\"defaults\"],\n \"backup\": 0,\n \"check_order\": 1,\n },\n ...\n];\n```\n\n#","ref":"gatherers.html#fstab","title":"fstab - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows access to the /etc/group file, returning all entries available at the file.\n\nExample specification:\n\n```yaml\nfacts:\n - name: groups\n gatherer: groups\n```\n\nExample output (in Rhai):\n\n```ts\n[\n #{\n \"name\": \"root\",\n \"gid\": 0,\n \"users\": [],\n },\n #{\n \"name\": \"adm\",\n \"gid\": 1,\n \"users\": [\"trento\"],\n }\n ...\n];\n```\n\n#","ref":"gatherers.html#groups","title":"groups - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows accessing the hostnames that are resolvable through `/etc/hosts`. It\ndoes **not** use domain resolution in any way but instead directly parses the file.\n\nIt allows one argument to be specified or none at all:\n\n- When a hostname is provided as an argument, the gatherer will return an array of IPv4 and/or IPv6 addresses.\n- When no argument is provided, the gatherer will return a map with hostname as keys and arrays with IPv4 and/or IPv6 addresses.\n\nExample arguments:\n\n| Name | Return value |\n| :--------------------- | :---------------------------------- |\n| `localhost` | list of IPs resolving |\n| `node1` | list of IPs resolving |\n| `no argument provided` | map with hostnames and IP addresses |\n\nExample specification:\n\n```yaml\nfacts:\n - name: hosts_node1\n gatherer: hosts\n argument: node1\n\n - name: hosts_node2\n gatherer: hosts\n argument: node2\n\n - name: hosts_all\n gatherer: hosts\n```\n\nExample output (in Rhai):\n\n```ts\n// hosts_node1\n[\"127.0.0.1\", \"::1\"];\n\n// hosts_node2\n[\"192.168.157.11\"];\n\n// hosts_all\n#{\n \"localhost\": [\"127.0.0.1\", \"::1\"],\n \"node1\": [\"192.168.157.10\"],\n \"node2\": [\"192.168.157.11\"],\n ...\n};\n```\n\n#","ref":"gatherers.html#hosts-etc-hosts","title":"hosts (/etc/hosts) - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nThis gatherer supports two usecases:\n\n- get information about the installed versions of the specified package.\n- compare a given version string against the latest installed version of a given package.\n\nIn the first usecase a list of objects is returned, where each object carries relevant information about an installed version of a package.\n\n> Note:\n>\n> - a list of one element is often expected since usually the installed version would be only one\n> - detected installed versions list is ordered by descending installation time: **latest installed versions come first**\n> - operating on the latest installed version requires accessing the first element in the list via `package_fact_name[0]` or `package_fact_name.first()`\n\nIn the second usecase, the return value is as follows (see additional details [here](https://fedoraproject.org/wiki/Archive:Tools/RPM/VersionComparison#The_rpmvercmp_algorithm)):\n\n- A value of `0` if the provided version string matches the installed package version for the requested package.\n- A value of `-1` if the provided version string is older that what's currently installed.\n- A value of `1` if the provided version string is newer than what's currently installed.\n\n> The latest detected installed version is used for comparison\n\nNaming the facts / expectations accordingly is specially important here to avoid confusion.\n\n- We suggest using a `compare_` prefix for package version comparisons and `package_` to retrieve\n a package version\n\nAdditionally, when using the version comparison, it increases readability to explicitly mention\nthe values to compare against:\n\n```yaml\nfacts:\n - name: compare_package_corosync\n gatherer: package_version\n argument: corosync,2.4.5\n\n - name: package_corosync\n gatherer: package_version\n argument: corosync\n\n - name: package_sbd\n gatherer: package_version\n argument: sbd\n\nvalues:\n - name: greater_than_installed\n default: 1\n - name: lesser_than_installed\n default: -1\n - name: same_as_installed\n default: 0\n - name: expected_corosync_version\n default: \"2.4.5\"\n\nexpectations:\n - name: compare_package_corosync\n expect: facts.compare_package_corosync == values.greater_than_installed\n\n - name: package_corosync_is_the_expected_one\n expect: facts.package_corosync.first().version == values.expected_corosync_version\n\n - name: sbd_version_same_on_all_hosts\n expect_same: facts.package_sbd.first().version\n```\n\nExample arguments:\n\n| Name | Return value |\n| :------------------- | :---------------------------------------------------------------------------- |\n| `package_name` | a list containing information about the installed versions of the rpm package |\n| `package_name,2.4.5` | an integer with a value of `-1`, `0` or `1` (see above) |\n\nExample specification:\n\n```yaml\nfacts:\n - name: package_corosync\n gatherer: package_version\n argument: corosync\n\n - name: package_pacemaker\n gatherer: package_version\n argument: pacemaker\n\n - name: multiple_sbd_versions_installed\n gatherer: package_version\n argument: sbd\n\n - name: compare_package_corosync\n gatherer: package_version\n argument: corosync,2.4.5\n\n ...\n```\n\nExample output (in Rhai):\n\n```ts\n// package_corosync\n[\n #{\n \"version\": \"2.4.5\"\n }\n]\n\n// package_pacemaker\n[\n #{\n \"version\": \"2.0.4+20200616.2deceaa3a\"\n }\n]\n\n// multiple_sbd_versions_installed\n[\n #{\n \"version\": \"1.5.1\" // latest installed version, not necessarily the newest one\n },\n #{\n \"version\": \"1.5.2\"\n }\n]\n\n// compare_package_corosync\n0\n```\n\n#","ref":"gatherers.html#package_version","title":"package_version - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows access to the /etc/passwd file, returning all entries available at the file.\n\nExample specification:\n\n```yaml\nfacts:\n - name: passwd\n gatherer: passwd\n```\n\nExample output (in Rhai):\n\n```ts\n[\n #{\n \"description\": \"bin\",\n \"gid\": 1,\n \"home\": \"/bin\",\n \"shell\": \"/sbin/nologin\",\n \"uid\": 1,\n \"user\": \"bin\"\n },\n #{\n \"description\": \"Chrony Daemon\",\n \"gid\": 475,\n \"home\": \"/var/lib/chrony\",\n \"shell\": \"/bin/false\",\n \"uid\": 474,\n \"user\": \"chrony\"\n },\n #{\n \"description\": \"Daemon\",\n \"gid\": 2,\n \"home\": \"/sbin\",\n \"shell\": \"/sbin/nologin\",\n \"uid\": 2,\n \"user\": \"daemon\"\n },\n ...\n];\n```\n\n#","ref":"gatherers.html#passwd","title":"passwd - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nThis gatherer allows access to certain webmethods that `saphostctrl` implements. An argument is required to specify\nwhich webmethod should be called. This webmethod is passed to the `saphostctrl` command-line tool through the `-function` argument.\n\nSupported webmethods:\n\n- `Ping`\n- `ListInstances`\n\nA `Ping` call with a successful return should look like this:\n\nExample specification:\n\n```yaml\nfacts:\n - name: ping\n gatherer: saphostctrl\n argument: Ping\n\n - name: list_instances\n gatherer: saphostctrl\n argument: ListInstances\n```\n\nExample output (in Rhai):\n\n```ts\n// ping\n#{elapsed: 579770.0, status: \"SUCCESS\"}\n\n// list_instances\n[\n #{\n \"changelist\": 1908545,\n \"hostname\": \"vmhana01\",\n \"instance\": \"00\",\n \"patch\": 410,\n \"sapkernel\": 753,\n \"system\": \"PRD\"\n }\n];\n```\n\n#","ref":"gatherers.html#saphostctrl","title":"saphostctrl - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows access to the latest SAP profile files content stored in `/sapmnt/ /profile`.\nThe \"latest\" profile means that backed up files like `DEFAULT.1.PFL` or `some_profile.1` are excluded.\nIt returns the profile files and content grouped by SID in a key\\value way.\n\nExample specification:\n\n```yaml\nfacts:\n - name: sap_profiles\n gatherer: sap_profiles\n```\n\nExample output (in Rhai):\n\n```ts\n#{\n \"NWP\": #{\n \"profiles\": [\n #{\n \"content\": #{\n \"SAPDBHOST\": \"10.80.1.13\",\n \"SAPGLOBALHOST\": \"sapnwpas\",\n \"SAPSYSTEMNAME\": \"NWP\",\n ...\n },\n \"name\": \"DEFAULT.PFL\",\n \"path\": \"/sapmnt/NWP/profile/DEFAULT.PFL\"\n },\n #{\n \"content\": #{\n \"DIR_CT_RUN\": \"$(DIR_EXE_ROOT)$(DIR_SEP)$(OS_UNICODE)$(DIR_SEP)linuxx86_64\",\n \"DIR_EXECUTABLE\": \"$(DIR_INSTANCE)/exe\",\n \"DIR_PROFILE\": \"$(DIR_INSTALL)$(DIR_SEP)profile\",\n ...\n },\n \"name\": \"NWP_ASCS00_sapnwpas\",\n \"path\": \"/sapmnt/NWP/profile/NWP_ASCS00_sapnwpas\"\n },\n ...\n ]\n },\n \"NWD\": #{\n \"profiles\": [\n #{\n \"content\": #{\n \"SAPDBHOST\": \"10.85.1.13\",\n \"SAPGLOBALHOST\": \"sapnwdas\",\n \"SAPSYSTEMNAME\": \"NWD\",\n ...\n },\n \"name\": \"DEFAULT.PFL\",\n \"path\": \"/sapmnt/NWD/profile/DEFAULT.PFL\"\n },\n ...\n ]\n }\n}\n```\n\n#","ref":"gatherers.html#sap_profiles","title":"sap_profiles - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nThis gatherer allows access to certain commands that `saptune` implements. An argument is required to specify\nwhich argument should be used when calling `saptune`.\n\n> Note: the gatherer will return the same JSON objects returned by saptune. The only transformation it applies is the snake casing of the keys.\n\nSupported arguments:\n\n- `status` (maps to `saptune --format json status --non-compliance-check`)\n- `solution-verify` (maps to `saptune --format json solution verify`)\n- `solution-list` (maps to `saptune --format json solution list`)\n- `note-verify` (maps to `saptune --format json note verify`)\n- `note-list` (maps to `saptune --format json note list`)\n\nA `status` call with a successful return should look like this:\n\nExample specification:\n\n```yaml\nfacts:\n - name: status\n gatherer: saptune\n argument: status\n```\n\nExample output (in Rhai):\n\n```ts\n// status\n#{\n \"$schema\": \"file:///usr/share/saptune/schemas/1.0/saptune_status.schema.json\",\n \"argv\": \"saptune --format json status\",\n \"command\": \"status\",\n \"exit_code\": 1,\n \"messages\": [\n #{\n \"message\": \"actions.go:85: ATTENTION: You are running a test version\",\n \"priority\": \"NOTICE\"\n }\n ],\n \"pid\": 6593,\n \"publish_time\": \"2023-09-15 15:15:14.599\",\n \"result\": #{\n \"configured_version\": \"3\",\n \"notes_applied\": [\n \"1410736\"\n ],\n \"notes_applied_by_solution\": [],\n \"notes_enabled\": [\n \"1410736\"\n ],\n \"notes_enabled_additionally\": [\n \"1410736\"\n ],\n \"notes_enabled_by_solution\": [],\n \"package_version\": \"3.1.0\",\n \"remember_message\": \"This is a reminder\",\n \"services\": #{\n \"sapconf\": [],\n \"saptune\": [\n \"disabled\",\n \"inactive\"\n ],\n \"tuned\": []\n },\n \"solution_applied\": [],\n \"solution_enabled\": [],\n \"staging\": #{\n \"notes_staged\": [],\n \"solutions_staged\": [],\n \"staging_enabled\": false\n },\n \"systemd_system_state\": \"degraded\",\n \"tuning_state\": \"compliant\",\n \"virtualization\": \"kvm\"\n }\n}\n```\n\n#","ref":"gatherers.html#saptune","title":"saptune - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nThis gatherer allows accessing the information contained in `/etc/sysconfig/sbd`\n\nExample arguments:\n\n| Name | Return value |\n| :-------------- | :------------------------------ |\n| `SBD_PACEMAKER` | extracted value from the config |\n| `SBD_STARTMODE` | extracted value from the config |\n| `SBD_DEVICE` | extracted value from the config |\n\nExample specification:\n\n```yaml\nfacts:\n - name: sbd_pacemaker\n gatherer: sbd_config\n argument: SBD_PACEMAKER\n\n - name: sbd_startmode\n gatherer: sbd_config\n argument: SBD_STARTMODE\n\n - name: sbd_device\n gatherer: sbd_config\n argument: SBD_DEVICE\n```\n\nExample output (in Rhai):\n\n```ts\n// sbd_pacemaker\n\"yes\";\n\n// sbd_startmode\n\"always\";\n\n// sbd_device\n\"/dev/vdc;/dev/vdb\";\n```\n\n#","ref":"gatherers.html#sbd_config","title":"sbd_config - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows accessing the sbd dump command output data.\n\nIt executes the `sbd -d dump` command in all devices configured in the `SBD_DEVICE` field on `/etc/sysconfig/sbd` and aggregates results in only one fact.\n\nNote that:\n\n- no arguments are required\n- if any of the dumps fail, a fact error is returned\n\nDumped keys (`Timeout (watchdog)`, `Timeout (msgwait)`, `Number of slots`, etc) are sanitized to simplify their access and usage in the expression language.\n\nExample specification:\n\n```yaml\nfacts:\n - name: sbd_devices_dump\n gatherer: sbd_dump\n```\n\nExample output (in Rhai):\n\n```ts\n// sbd_devices_dump\n#{\n \"/dev/vdc\": #{\n header_version: 2.1,\n number_of_slots: 255,\n sector_size: 512,\n timeout_allocate: 2,\n timeout_loop: 1,\n timeout_msgwait: 10,\n timeout_watchdog: 5,\n uuid: \"69048391-c647-4b34-a03a-f704f5cc2258\"\n }\n};\n```\n\nFor extra information refer to [trento-project/agent/../gatherers/sbddump_test.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sbddump_test.go)\n\n#","ref":"gatherers.html#sbd_dump","title":"sbd_dump - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nGather sysctl output. It takes a sysctl key as argument and it returns the value of the requested key or a map if a partial key is provided.\n\nExample arguments:\n\n| Name | Return value |\n| :-------------- | :---------------------------------------------------- |\n| `vm.swappiness` | corresponding value returned by sysctl |\n| `debug` | a map containing all the keys starting with `debug.`` |\n\n```yaml\nfacts:\n - name: vm_swappiness\n gatherer: sysctl\n argument: vm.swappiness\n\n - name: debug\n gatherer: sysctl\n argument: debug\n```\n\nExample output (in Rhai):\n\n```ts\n// vm_swapiness\n60;\n\n// debug\n#{\n \"exception-trace\": 1,\n \"kprobes-optimization\": 1\n};\n```\n\n#","ref":"gatherers.html#sysctl","title":"sysctl - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nGather systemd units state. It returns an `active/inactive` string.\nIf the service is disabled or it does not exist, `inactive` is returned.\n\nExample arguments:\n\n| Name | Return value |\n| :------------- | :------------------------ |\n| `trento-agent` | state of the systemd unit |\n\n```yaml\nfacts:\n - name: sbd_state\n gatherer: systemd\n argument: sbd\n\n - name: corosync_state\n gatherer: systemd\n argument: corosync\n```\n\nExample output (in Rhai):\n\n```ts\n// sbd_state\n\"active\";\n\n// corosync_state\n\"inactive\";\n```\n\n#","ref":"gatherers.html#systemd","title":"systemd - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nThis gatherer determines whether a given user has its password still set to an unsafe password.\nIt returns `true` if the password matches a password in the list of unsafe passwords, `false` otherwise.\n\nSpecification examples:\n\n```yaml\nfacts:\n - name: hacluster_has_default_password\n gatherer: verify_password\n argument: hacluster\n```\n\nFor the argument, only whitelisted users are allowed. Currently whitelisted usernames:\n\n- `hacluster`\n\nList of unsafe passwords:\n\n- `linux`\n\nExample output (in Rhai):\n\n```ts\n// hacluster_has_default_password\ntrue;\n```","ref":"gatherers.html#verify_password","title":"verify_password - Gatherers","type":"extras"},{"doc":"# Hack on Wanda","ref":"hack_on_wanda.html","title":"Hack on Wanda","type":"extras"},{"doc":"In order to run Wanda, the following software must be installed:\n\n1. [Elixir](https://elixir-lang.org/)\n2. [Erlang OTP](https://www.erlang.org/)\n3. [Rust](https://www.rust-lang.org/tools/install)\n4. [Docker](https://docs.docker.com/get-docker/)\n5. [Docker Compose](https://docs.docker.com/compose/install/)\n\n#","ref":"hack_on_wanda.html#requirements","title":"Requirements - Hack on Wanda","type":"extras"},{"doc":"[asdf](https://asdf-vm.com/guide/introduction.html) allows using specific versions of programming language tools that are known to be compatible with the project, rather than relying on the version that's installed globally on the host system.\n\nIn order to use asdf, follow the official [asdf getting started guide](https://asdf-vm.com/guide/getting-started.html).\n\nInstall all required asdf plugins from [.tool-versions](/.tool-versions) inside the web repository.\n\n```\ncut -d' ' -f1 .tool-versions|xargs -i asdf plugin add {}\n```\n\nSet up the asdf environment\n\n```\nasdf install\n```","ref":"hack_on_wanda.html#ensure-compatibility-with-asdf","title":"Ensure Compatibility with asdf - Hack on Wanda","type":"extras"},{"doc":"A `docker-compose` environment is provided for easy local development. To start the environment, run the following command:\n\n```\ndocker-compose up -d\n```\n\nThis command starts a **Postgres** database and a **RabbitMq** instance, which is used for storage and communication.","ref":"hack_on_wanda.html#development-environment","title":"Development environment - Hack on Wanda","type":"extras"},{"doc":"Before starting Wanda, some initial setup tasks are required. This can be achieved by running the following command:\n\n```\nmix setup\n```\n\nThis command performs necessary tasks such as installing dependencies, creating the database schema and running migrations.\n\n#","ref":"hack_on_wanda.html#setup-wanda","title":"Setup Wanda - Hack on Wanda","type":"extras"},{"doc":"Gain a deeper understanding of how Wanda is configured, reading the [mix.exs](https://github.com/trento-project/wanda/blob/main/mix.exs) file located in the root directory of the project. This file contains information on dependencies, configuration settings, and tasks that can be run using the Mix build tool, providing a complete picture of the project's setup.","ref":"hack_on_wanda.html#hint-about-project-setup","title":"Hint about Project setup - Hack on Wanda","type":"extras"},{"doc":"To start Wanda, you need to run the following command:\n\n```\niex -S mix phx.server\n```","ref":"hack_on_wanda.html#start-wanda-in-the-repl","title":"Start Wanda in the REPL - Hack on Wanda","type":"extras"},{"doc":"Congratulations, Wanda is now running locally on your machine! You can access its API documentation by visiting the following URL:\n[localhost:4001/swaggerui](http://localhost:4001/swaggerui).\n\nThe Swagger UI provides a user-friendly interface for exploring and testing the various API endpoints of Wanda.\n\nHappy Hacking!","ref":"hack_on_wanda.html#access-wanda-swaggerui","title":"Access Wanda Swaggerui - Hack on Wanda","type":"extras"},{"doc":"# Wanda Demo","ref":"demo.html","title":"Wanda Demo","type":"extras"},{"doc":"Wanda's demo mode provides a simulated environment where targets' gathered facts are faked via a configuration yaml file. This empowers showcasing Trento's capabilities, and eases the development of the platform. The user is able to run check executions from the web, and wanda's fake server returns faked gathered facts.","ref":"demo.html#introduction","title":"Introduction - Wanda Demo","type":"extras"},{"doc":"First set up the [local environment](./hack_on_wanda.md) and run the following command to start Wanda in demo mode, instead of the usual `iex -S mix phx.server`\n\n```bash\n$ DATABASE_URL=ecto://postgres:postgres@localhost:5434/wanda_dev \\\n AMQP_URL=amqp://wanda:wanda@localhost:5674 \\\n SECRET_KEY_BASE=Tbp26GilFTZOXafb7FNVqt4dFQdeb7FAJ++am7ItYx2sMzYaPSB9SwUczdJu6AhQ \\\n CORS_ORIGIN=http://localhost:4000 \\\n ACCESS_TOKEN_ENC_SECRET=s2ZdE+3+ke1USHEJ5O45KT364KiXPYaB9cJPdH3p60t8yT0nkLexLBNw8TFSzC7k \\\n PORT=4001 \\\n MIX_ENV=demo \\\n iex -S mix phx.server\n```\n\n#","ref":"demo.html#how-to-setup-wanda-in-demo-mode","title":"How to setup Wanda in demo mode? - Wanda Demo","type":"extras"},{"doc":"- DATABASE_URL: The URL to connect to the Postgres database running in the Docker container.\n- AMQP_URL: The URL for RabbitMQ, used for message exchange.\n- SECRET_KEY_BASE: The secret key for Wanda.\n- CORS_ORIGIN: The origin URL from where API requests are allowed (pointing to web).\n- ACCESS_TOKEN_ENC_SECRET: Secret key for encrypting access tokens.\n- PORT: The port on which Wanda will run (4001 in this case).\n- MIX_ENV: The environment in which Wanda will run (set to \"demo\" for the demo environment).","ref":"demo.html#explanation-of-environment-variables","title":"Explanation of environment variables: - Wanda Demo","type":"extras"},{"doc":"In the Wanda demo environment, configure fake facts by editing the [fake_facts configuration](https://github.com/trento-project/wanda/blob/main/priv/demo/fake_facts.yaml). Define or modify custom facts for different targets and checks.\n\n#","ref":"demo.html#modify-demo-facts-configuration","title":"Modify demo facts configuration - Wanda Demo","type":"extras"},{"doc":"The Configuration is saved in [fake_facts.yaml](https://github.com/trento-project/wanda/blob/main/priv/demo/fake_facts.yaml) file, which follows a specific structure with two main sections: `targets` and `facts`.\n\nExample:\n\n```yaml\ntargets:\n target1: 0a055c90-4cb6-54ce-ac9c-ae3fedaf40d4\n target2: 13e8c25c-3180-5a9a-95c8-51ec38e50cfc\nfacts:\n check_1:\n fact_name1:\n target1: 2\n target2: 3\n```\n\n#","ref":"demo.html#yaml-structure","title":"YAML Structure - Wanda Demo","type":"extras"},{"doc":"The targets section allows defining handles for targets' UUIDs, providing a reference that can be used through the configuration.\n\nFormat:\n\n```yaml\ntargets:\n : \n```\n\n` `: A user-defined handle or reference for a target.\n\n` `: The UUID or identifier of the target.\n\nAdd as many new target entries as required:\n\n```yaml\ntargets:\n target1: 0a055c90-4cb6-54ce-ac9c-ae3fedaf40d4\n target2: 13e8c25c-3180-5a9a-95c8-51ec38e50cfc\n : \n```\n\n#","ref":"demo.html#targets","title":"Targets - Wanda Demo","type":"extras"},{"doc":"The facts section allows specifying what fact value a target should return for a specific check.\n\nThe format for the facts section is as follows:\n\n```yaml\nfacts:\n :\n :\n : \n : \n```\n\n- There can be as many as needed.\n- Each there can be as many configured as needed.\n- Each can be instrumented to have a specific on a .\n\nExample:\n\n```yaml\ntargets:\n target1: 0a055c90-4cb6-54ce-ac9c-ae3fedaf40d4\n target2: 13e8c25c-3180-5a9a-95c8-51ec38e50cfc\n target3: 3f16cb32-57fb-46cc-9bf1-cd8d72d7eb9a\n\nfacts:\n.......existing facts..........\n new_check_id:\n new_fact_name:\n target1: \n target2: \n target3: \n```","ref":"demo.html#facts","title":"Facts: - Wanda Demo","type":"extras"},{"doc":"#","ref":"demo.html#faq","title":"FAQ - Wanda Demo","type":"extras"},{"doc":"Wanda will still evaluate and return a default fallback fact value \"some fact value\" for a check's execution. This means when a new check is added to wanda, changing the the configuration is optional.\n\n#","ref":"demo.html#what-happens-with-unmapped-targets-facts-or-checks","title":"What happens with unmapped targets, facts or checks? - Wanda Demo","type":"extras"},{"doc":"Every Fact Gatherer has specific return values. To get an overview of all gatherers, refer to [Wanda's gatherers guide](../gatherers.md).\nDetermining the correct return value of a fact requires inspecting the specific check itself.\nVisit the [Checks Catalog](https://github.com/trento-project/wanda/blob/main/priv/catalog) to find out which gatherer is used for the specific check and which values are expected.","ref":"demo.html#how-to-know-what-s-the-correct-return-value-of-a-fact","title":"How to know what's the correct return value of a fact? - Wanda Demo","type":"extras"}]} \ No newline at end of file +searchData={"content_type":"text/markdown","items":[{"doc":"This module defines the setup for tests requiring\naccess to the application's data layer.\n\nYou may define functions here to be used as helpers in\nyour tests.\n\nFinally, if the test case interacts with the database,\nwe enable the SQL sandbox, so changes done to the database\nare reverted at the end of every test. If you are using\nPostgreSQL, you can even run database tests asynchronously\nby setting `use Wanda.DataCase, async: true`, although\nthis option is not recommended for other databases.","ref":"Wanda.DataCase.html","title":"Wanda.DataCase","type":"module"},{"doc":"A helper that transforms changeset errors into a map of messages.\n\n assert {:error, changeset} = Accounts.create_user(%{password: \"short\"})\n assert \"password is too short\" in errors_on(changeset).password\n assert %{password: [\"password is too short\"]} = errors_on(changeset)","ref":"Wanda.DataCase.html#errors_on/1","title":"Wanda.DataCase.errors_on/1","type":"function"},{"doc":"Sets up the sandbox based on the test tags.","ref":"Wanda.DataCase.html#setup_sandbox/1","title":"Wanda.DataCase.setup_sandbox/1","type":"function"},{"doc":"This module wraps the Rhai engine and provides a simple interface for\nevaluating expressions.\nIt also sets some default options for the engine.","ref":"Wanda.EvaluationEngine.html","title":"Wanda.EvaluationEngine","type":"module"},{"doc":"","ref":"Wanda.EvaluationEngine.html#eval/3","title":"Wanda.EvaluationEngine.eval/3","type":"function"},{"doc":"","ref":"Wanda.EvaluationEngine.html#new/0","title":"Wanda.EvaluationEngine.new/0","type":"function"},{"doc":"Handles integration events.","ref":"Wanda.Policy.html","title":"Wanda.Policy","type":"module"},{"doc":"","ref":"Wanda.Policy.html#handle_event/1","title":"Wanda.Policy.handle_event/1","type":"function"},{"doc":"Used for executing DB release tasks when run in production without Mix\ninstalled.","ref":"Wanda.Release.html","title":"Wanda.Release","type":"module"},{"doc":"","ref":"Wanda.Release.html#init/0","title":"Wanda.Release.init/0","type":"function"},{"doc":"","ref":"Wanda.Release.html#migrate/0","title":"Wanda.Release.migrate/0","type":"function"},{"doc":"","ref":"Wanda.Release.html#rollback/2","title":"Wanda.Release.rollback/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html","title":"Wanda.Repo","type":"module"},{"doc":"","ref":"Wanda.Repo.html#aggregate/3","title":"Wanda.Repo.aggregate/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#aggregate/4","title":"Wanda.Repo.aggregate/4","type":"function"},{"doc":"","ref":"Wanda.Repo.html#all/2","title":"Wanda.Repo.all/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#checked_out?/0","title":"Wanda.Repo.checked_out?/0","type":"function"},{"doc":"","ref":"Wanda.Repo.html#checkout/2","title":"Wanda.Repo.checkout/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#child_spec/1","title":"Wanda.Repo.child_spec/1","type":"function"},{"doc":"","ref":"Wanda.Repo.html#config/0","title":"Wanda.Repo.config/0","type":"function"},{"doc":"","ref":"Wanda.Repo.html#default_options/1","title":"Wanda.Repo.default_options/1","type":"function"},{"doc":"","ref":"Wanda.Repo.html#delete/2","title":"Wanda.Repo.delete/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#delete!/2","title":"Wanda.Repo.delete!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#delete_all/2","title":"Wanda.Repo.delete_all/2","type":"function"},{"doc":"A convenience function for SQL-based repositories that forces all connections in the\npool to disconnect within the given interval.\n\nSee `Ecto.Adapters.SQL.disconnect_all/3` for more information.","ref":"Wanda.Repo.html#disconnect_all/2","title":"Wanda.Repo.disconnect_all/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#exists?/2","title":"Wanda.Repo.exists?/2","type":"function"},{"doc":"A convenience function for SQL-based repositories that executes an EXPLAIN statement or similar\ndepending on the adapter to obtain statistics for the given query.\n\nSee `Ecto.Adapters.SQL.explain/4` for more information.","ref":"Wanda.Repo.html#explain/3","title":"Wanda.Repo.explain/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#get/3","title":"Wanda.Repo.get/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#get!/3","title":"Wanda.Repo.get!/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#get_by/3","title":"Wanda.Repo.get_by/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#get_by!/3","title":"Wanda.Repo.get_by!/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#get_dynamic_repo/0","title":"Wanda.Repo.get_dynamic_repo/0","type":"function"},{"doc":"","ref":"Wanda.Repo.html#in_transaction?/0","title":"Wanda.Repo.in_transaction?/0","type":"function"},{"doc":"","ref":"Wanda.Repo.html#insert/2","title":"Wanda.Repo.insert/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#insert!/2","title":"Wanda.Repo.insert!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#insert_all/3","title":"Wanda.Repo.insert_all/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#insert_or_update/2","title":"Wanda.Repo.insert_or_update/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#insert_or_update!/2","title":"Wanda.Repo.insert_or_update!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#load/2","title":"Wanda.Repo.load/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#one/2","title":"Wanda.Repo.one/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#one!/2","title":"Wanda.Repo.one!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#preload/3","title":"Wanda.Repo.preload/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#prepare_query/3","title":"Wanda.Repo.prepare_query/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#put_dynamic_repo/1","title":"Wanda.Repo.put_dynamic_repo/1","type":"function"},{"doc":"A convenience function for SQL-based repositories that executes the given query.\n\nSee `Ecto.Adapters.SQL.query/4` for more information.","ref":"Wanda.Repo.html#query/3","title":"Wanda.Repo.query/3","type":"function"},{"doc":"A convenience function for SQL-based repositories that executes the given query.\n\nSee `Ecto.Adapters.SQL.query!/4` for more information.","ref":"Wanda.Repo.html#query!/3","title":"Wanda.Repo.query!/3","type":"function"},{"doc":"A convenience function for SQL-based repositories that executes the given multi-result query.\n\nSee `Ecto.Adapters.SQL.query_many/4` for more information.","ref":"Wanda.Repo.html#query_many/3","title":"Wanda.Repo.query_many/3","type":"function"},{"doc":"A convenience function for SQL-based repositories that executes the given multi-result query.\n\nSee `Ecto.Adapters.SQL.query_many!/4` for more information.","ref":"Wanda.Repo.html#query_many!/3","title":"Wanda.Repo.query_many!/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#reload/2","title":"Wanda.Repo.reload/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#reload!/2","title":"Wanda.Repo.reload!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#rollback/1","title":"Wanda.Repo.rollback/1","type":"function"},{"doc":"","ref":"Wanda.Repo.html#start_link/1","title":"Wanda.Repo.start_link/1","type":"function"},{"doc":"","ref":"Wanda.Repo.html#stop/1","title":"Wanda.Repo.stop/1","type":"function"},{"doc":"","ref":"Wanda.Repo.html#stream/2","title":"Wanda.Repo.stream/2","type":"function"},{"doc":"A convenience function for SQL-based repositories that translates the given query to SQL.\n\nSee `Ecto.Adapters.SQL.to_sql/3` for more information.","ref":"Wanda.Repo.html#to_sql/2","title":"Wanda.Repo.to_sql/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#transaction/2","title":"Wanda.Repo.transaction/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#update/2","title":"Wanda.Repo.update/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#update!/2","title":"Wanda.Repo.update!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#update_all/3","title":"Wanda.Repo.update_all/3","type":"function"},{"doc":"This module exposes functionalities to interact with the historycal log of executions.","ref":"Wanda.Executions.html","title":"Wanda.Executions","type":"module"},{"doc":"Marks a previously started execution as completed","ref":"Wanda.Executions.html#complete_execution!/2","title":"Wanda.Executions.complete_execution!/2","type":"function"},{"doc":"Counts executions in the database.","ref":"Wanda.Executions.html#count_executions/1","title":"Wanda.Executions.count_executions/1","type":"function"},{"doc":"Create a new execution.\n\nIf the execution already exists, it will be returned.","ref":"Wanda.Executions.html#create_execution!/3","title":"Wanda.Executions.create_execution!/3","type":"function"},{"doc":"Get an execution by execution_id.","ref":"Wanda.Executions.html#get_execution!/1","title":"Wanda.Executions.get_execution!/1","type":"function"},{"doc":"Get the last execution of a group by group_id.","ref":"Wanda.Executions.html#get_last_execution_by_group_id!/1","title":"Wanda.Executions.get_last_execution_by_group_id!/1","type":"function"},{"doc":"Get a paginated list of executions.\n\nCan be filtered by group_id.","ref":"Wanda.Executions.html#list_executions/1","title":"Wanda.Executions.list_executions/1","type":"function"},{"doc":"Represents the result of a check on a specific agent.","ref":"Wanda.Executions.AgentCheckError.html","title":"Wanda.Executions.AgentCheckError","type":"module"},{"doc":"","ref":"Wanda.Executions.AgentCheckError.html#t:t/0","title":"Wanda.Executions.AgentCheckError.t/0","type":"type"},{"doc":"Represents the result of a check on a specific agent.","ref":"Wanda.Executions.AgentCheckResult.html","title":"Wanda.Executions.AgentCheckResult","type":"module"},{"doc":"","ref":"Wanda.Executions.AgentCheckResult.html#t:t/0","title":"Wanda.Executions.AgentCheckResult.t/0","type":"type"},{"doc":"Represents the result of a check.","ref":"Wanda.Executions.CheckResult.html","title":"Wanda.Executions.CheckResult","type":"module"},{"doc":"","ref":"Wanda.Executions.CheckResult.html#t:t/0","title":"Wanda.Executions.CheckResult.t/0","type":"type"},{"doc":"Evaluation functional core.","ref":"Wanda.Executions.Evaluation.html","title":"Wanda.Executions.Evaluation","type":"module"},{"doc":"","ref":"Wanda.Executions.Evaluation.html#execute/7","title":"Wanda.Executions.Evaluation.execute/7","type":"function"},{"doc":"","ref":"Wanda.Executions.Evaluation.html#has_some_fact_gathering_error?/1","title":"Wanda.Executions.Evaluation.has_some_fact_gathering_error?/1","type":"function"},{"doc":"Schema of a persisted execution.","ref":"Wanda.Executions.Execution.html","title":"Wanda.Executions.Execution","type":"module"},{"doc":"","ref":"Wanda.Executions.Execution.html#changeset/2","title":"Wanda.Executions.Execution.changeset/2","type":"function"},{"doc":"","ref":"Wanda.Executions.Execution.html#t:t/0","title":"Wanda.Executions.Execution.t/0","type":"type"},{"doc":"","ref":"Wanda.Executions.Execution.Target.html","title":"Wanda.Executions.Execution.Target","type":"module"},{"doc":"Represents the evaluation of an expectation.","ref":"Wanda.Executions.ExpectationEvaluation.html","title":"Wanda.Executions.ExpectationEvaluation","type":"module"},{"doc":"","ref":"Wanda.Executions.ExpectationEvaluation.html#t:t/0","title":"Wanda.Executions.ExpectationEvaluation.t/0","type":"type"},{"doc":"Represents an error occurred during the evaluation of an expectation.","ref":"Wanda.Executions.ExpectationEvaluationError.html","title":"Wanda.Executions.ExpectationEvaluationError","type":"module"},{"doc":"","ref":"Wanda.Executions.ExpectationEvaluationError.html#t:t/0","title":"Wanda.Executions.ExpectationEvaluationError.t/0","type":"type"},{"doc":"Represents the result of an expectation.","ref":"Wanda.Executions.ExpectationResult.html","title":"Wanda.Executions.ExpectationResult","type":"module"},{"doc":"","ref":"Wanda.Executions.ExpectationResult.html#t:t/0","title":"Wanda.Executions.ExpectationResult.t/0","type":"type"},{"doc":"A fact is a piece of information that was gathered from a target.","ref":"Wanda.Executions.Fact.html","title":"Wanda.Executions.Fact","type":"module"},{"doc":"","ref":"Wanda.Executions.Fact.html#t:t/0","title":"Wanda.Executions.Fact.t/0","type":"type"},{"doc":"Fact with an error.","ref":"Wanda.Executions.FactError.html","title":"Wanda.Executions.FactError","type":"module"},{"doc":"","ref":"Wanda.Executions.FactError.html#t:t/0","title":"Wanda.Executions.FactError.t/0","type":"type"},{"doc":"Module responsible to generate the fake gathered facts from targets","ref":"Wanda.Executions.FakeGatheredFacts.html","title":"Wanda.Executions.FakeGatheredFacts","type":"module"},{"doc":"","ref":"Wanda.Executions.FakeGatheredFacts.html#get_demo_gathered_facts/2","title":"Wanda.Executions.FakeGatheredFacts.get_demo_gathered_facts/2","type":"function"},{"doc":"Execution server implementation that does not actually execute anything and just\nreturns (fake) random results.","ref":"Wanda.Executions.FakeServer.html","title":"Wanda.Executions.FakeServer","type":"module"},{"doc":"Facts gathering functional core.","ref":"Wanda.Executions.Gathering.html","title":"Wanda.Executions.Gathering","type":"module"},{"doc":"Check if all the agents have sent the facts","ref":"Wanda.Executions.Gathering.html#all_agents_sent_facts?/2","title":"Wanda.Executions.Gathering.all_agents_sent_facts?/2","type":"function"},{"doc":"Adds gathered facts of an agent.","ref":"Wanda.Executions.Gathering.html#put_gathered_facts/3","title":"Wanda.Executions.Gathering.put_gathered_facts/3","type":"function"},{"doc":"Adds timeout data to gathered facts.","ref":"Wanda.Executions.Gathering.html#put_gathering_timeouts/2","title":"Wanda.Executions.Gathering.put_gathering_timeouts/2","type":"function"},{"doc":"Check if an agent is a target of an execution","ref":"Wanda.Executions.Gathering.html#target?/2","title":"Wanda.Executions.Gathering.target?/2","type":"function"},{"doc":"Represents the result of an execution.","ref":"Wanda.Executions.Result.html","title":"Wanda.Executions.Result","type":"module"},{"doc":"","ref":"Wanda.Executions.Result.html#t:t/0","title":"Wanda.Executions.Result.t/0","type":"type"},{"doc":"Represents the execution of the CheckSelection(s) on the target nodes/agents of a cluster\nOrchestrates facts gathering on the targets - issuing execution and receiving back facts - and following check evaluations.","ref":"Wanda.Executions.Server.html","title":"Wanda.Executions.Server","type":"module"},{"doc":"Returns a specification to start this module under a supervisor.\n\nSee `Supervisor`.","ref":"Wanda.Executions.Server.html#child_spec/1","title":"Wanda.Executions.Server.child_spec/1","type":"function"},{"doc":"Starts a check execution.\n\nThe checks are filtered leveraging the `env` and evaluating the `when` condition using a best-effort approach.\nIf non-existing check IDs are provided inside a target, they will get filtered away.","ref":"Wanda.Executions.Server.html#start_execution/6","title":"Wanda.Executions.Server.start_execution/6","type":"function"},{"doc":"","ref":"Wanda.Executions.Server.html#start_link/1","title":"Wanda.Executions.Server.start_link/1","type":"function"},{"doc":"Execution server API behaviour.","ref":"Wanda.Executions.ServerBehaviour.html","title":"Wanda.Executions.ServerBehaviour","type":"behaviour"},{"doc":"","ref":"Wanda.Executions.ServerBehaviour.html#c:receive_facts/4","title":"Wanda.Executions.ServerBehaviour.receive_facts/4","type":"callback"},{"doc":"","ref":"Wanda.Executions.ServerBehaviour.html#c:start_execution/5","title":"Wanda.Executions.ServerBehaviour.start_execution/5","type":"callback"},{"doc":"","ref":"Wanda.Executions.ServerBehaviour.html#c:start_execution/6","title":"Wanda.Executions.ServerBehaviour.start_execution/6","type":"callback"},{"doc":"State of an execution.","ref":"Wanda.Executions.State.html","title":"Wanda.Executions.State","type":"module"},{"doc":"","ref":"Wanda.Executions.State.html#t:t/0","title":"Wanda.Executions.State.t/0","type":"type"},{"doc":"Execution targets.","ref":"Wanda.Executions.Target.html","title":"Wanda.Executions.Target","type":"module"},{"doc":"","ref":"Wanda.Executions.Target.html#get_checks_from_targets/1","title":"Wanda.Executions.Target.get_checks_from_targets/1","type":"function"},{"doc":"","ref":"Wanda.Executions.Target.html#map_targets/1","title":"Wanda.Executions.Target.map_targets/1","type":"function"},{"doc":"","ref":"Wanda.Executions.Target.html#t:t/0","title":"Wanda.Executions.Target.t/0","type":"type"},{"doc":"Represents a Value used in expectation evaluation.\nThis value has been already determined given the conditions in check definition.","ref":"Wanda.Executions.Value.html","title":"Wanda.Executions.Value","type":"module"},{"doc":"","ref":"Wanda.Executions.Value.html#t:t/0","title":"Wanda.Executions.Value.t/0","type":"type"},{"doc":"Function to interact with the checks catalog.","ref":"Wanda.Catalog.html","title":"Wanda.Catalog","type":"module"},{"doc":"Get the checks catalog with all checks","ref":"Wanda.Catalog.html#get_catalog/1","title":"Wanda.Catalog.get_catalog/1","type":"function"},{"doc":"Get a check from the catalog.","ref":"Wanda.Catalog.html#get_check/1","title":"Wanda.Catalog.get_check/1","type":"function"},{"doc":"Get specific checks from the catalog.","ref":"Wanda.Catalog.html#get_checks/2","title":"Wanda.Catalog.get_checks/2","type":"function"},{"doc":"Represents a check.","ref":"Wanda.Catalog.Check.html","title":"Wanda.Catalog.Check","type":"module"},{"doc":"","ref":"Wanda.Catalog.Check.html#t:t/0","title":"Wanda.Catalog.Check.t/0","type":"type"},{"doc":"Represents a condition.","ref":"Wanda.Catalog.Condition.html","title":"Wanda.Catalog.Condition","type":"module"},{"doc":"","ref":"Wanda.Catalog.Condition.html#t:t/0","title":"Wanda.Catalog.Condition.t/0","type":"type"},{"doc":"Represents an expectation.","ref":"Wanda.Catalog.Expectation.html","title":"Wanda.Catalog.Expectation","type":"module"},{"doc":"","ref":"Wanda.Catalog.Expectation.html#t:t/0","title":"Wanda.Catalog.Expectation.t/0","type":"type"},{"doc":"Represents a fact.","ref":"Wanda.Catalog.Fact.html","title":"Wanda.Catalog.Fact","type":"module"},{"doc":"","ref":"Wanda.Catalog.Fact.html#t:t/0","title":"Wanda.Catalog.Fact.t/0","type":"type"},{"doc":"Represents a value.","ref":"Wanda.Catalog.Value.html","title":"Wanda.Catalog.Value","type":"module"},{"doc":"","ref":"Wanda.Catalog.Value.html#t:t/0","title":"Wanda.Catalog.Value.t/0","type":"type"},{"doc":"Publishes messages to the message bus","ref":"Wanda.Messaging.html","title":"Wanda.Messaging","type":"module"},{"doc":"","ref":"Wanda.Messaging.html#publish/2","title":"Wanda.Messaging.publish/2","type":"function"},{"doc":"AMQP adapter","ref":"Wanda.Messaging.Adapters.AMQP.html","title":"Wanda.Messaging.Adapters.AMQP","type":"module"},{"doc":"AMQP consumer.","ref":"Wanda.Messaging.Adapters.AMQP.Consumer.html","title":"Wanda.Messaging.Adapters.AMQP.Consumer","type":"module"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Consumer.html#child_spec/1","title":"Wanda.Messaging.Adapters.AMQP.Consumer.child_spec/1","type":"function"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Consumer.html#start_link/1","title":"Wanda.Messaging.Adapters.AMQP.Consumer.start_link/1","type":"function"},{"doc":"AMQP processor.","ref":"Wanda.Messaging.Adapters.AMQP.Processor.html","title":"Wanda.Messaging.Adapters.AMQP.Processor","type":"module"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Processor.html#process/1","title":"Wanda.Messaging.Adapters.AMQP.Processor.process/1","type":"function"},{"doc":"AMQP publisher.","ref":"Wanda.Messaging.Adapters.AMQP.Publisher.html","title":"Wanda.Messaging.Adapters.AMQP.Publisher","type":"module"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Publisher.html#child_spec/1","title":"Wanda.Messaging.Adapters.AMQP.Publisher.child_spec/1","type":"function"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Publisher.html#init/0","title":"Wanda.Messaging.Adapters.AMQP.Publisher.init/0","type":"function"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Publisher.html#publish_message/2","title":"Wanda.Messaging.Adapters.AMQP.Publisher.publish_message/2","type":"function"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Publisher.html#start_link/1","title":"Wanda.Messaging.Adapters.AMQP.Publisher.start_link/1","type":"function"},{"doc":"Maps domain structures to integration events.","ref":"Wanda.Messaging.Mapper.html","title":"Wanda.Messaging.Mapper","type":"module"},{"doc":"","ref":"Wanda.Messaging.Mapper.html#from_execution_requested/1","title":"Wanda.Messaging.Mapper.from_execution_requested/1","type":"function"},{"doc":"","ref":"Wanda.Messaging.Mapper.html#from_facts_gathererd/1","title":"Wanda.Messaging.Mapper.from_facts_gathererd/1","type":"function"},{"doc":"","ref":"Wanda.Messaging.Mapper.html#to_execution_completed/2","title":"Wanda.Messaging.Mapper.to_execution_completed/2","type":"function"},{"doc":"","ref":"Wanda.Messaging.Mapper.html#to_execution_started/3","title":"Wanda.Messaging.Mapper.to_execution_started/3","type":"function"},{"doc":"","ref":"Wanda.Messaging.Mapper.html#to_facts_gathering_requested/4","title":"Wanda.Messaging.Mapper.to_facts_gathering_requested/4","type":"function"},{"doc":"The entrypoint for defining your web interface, such\nas controllers, views, channels and so on.\n\nThis can be used in your application as:\n\n use WandaWeb, :controller\n use WandaWeb, :view\n\nThe definitions below will be executed for every view,\ncontroller, etc, so keep them short and clean, focused\non imports, uses and aliases.\n\nDo NOT define functions inside the quoted expressions\nbelow. Instead, define any helper function in modules\nand import those modules here.","ref":"WandaWeb.html","title":"WandaWeb","type":"module"},{"doc":"When used, dispatch to the appropriate controller/view/etc.","ref":"WandaWeb.html#__using__/1","title":"WandaWeb.__using__/1","type":"macro"},{"doc":"","ref":"WandaWeb.html#channel/0","title":"WandaWeb.channel/0","type":"function"},{"doc":"","ref":"WandaWeb.html#controller/0","title":"WandaWeb.controller/0","type":"function"},{"doc":"","ref":"WandaWeb.html#router/0","title":"WandaWeb.router/0","type":"function"},{"doc":"","ref":"WandaWeb.html#view/0","title":"WandaWeb.view/0","type":"function"},{"doc":"Jwt Token is the module responsible for creating a proper jwt access token.\n Uses Joken as jwt base library","ref":"WandaWeb.Auth.AccessToken.html","title":"WandaWeb.Auth.AccessToken","type":"module"},{"doc":"Combines `generate_claims/1` and `encode_and_sign/2`","ref":"WandaWeb.Auth.AccessToken.html#generate_and_sign/2","title":"WandaWeb.Auth.AccessToken.generate_and_sign/2","type":"function"},{"doc":"Same as `generate_and_sign/2` but raises if error","ref":"WandaWeb.Auth.AccessToken.html#generate_and_sign!/2","title":"WandaWeb.Auth.AccessToken.generate_and_sign!/2","type":"function"},{"doc":"Combines `verify/2` and `validate/2`","ref":"WandaWeb.Auth.AccessToken.html#verify_and_validate/3","title":"WandaWeb.Auth.AccessToken.verify_and_validate/3","type":"function"},{"doc":"Same as `verify_and_validate/2` but raises if error","ref":"WandaWeb.Auth.AccessToken.html#verify_and_validate!/3","title":"WandaWeb.Auth.AccessToken.verify_and_validate!/3","type":"function"},{"doc":"Plug responsible for reading the JWT from the authorization header and\n validating it.\n\n If the token is valid, the user_id is added to the private section of the\n connection.\n If the token is invalid, the connection is halted with a 401 response.","ref":"WandaWeb.Auth.JWTAuthPlug.html","title":"WandaWeb.Auth.JWTAuthPlug","type":"module"},{"doc":"Read, validate and decode the JWT from authorization header at each call","ref":"WandaWeb.Auth.JWTAuthPlug.html#call/2","title":"WandaWeb.Auth.JWTAuthPlug.call/2","type":"function"},{"doc":"","ref":"WandaWeb.Auth.JWTAuthPlug.html#init/1","title":"WandaWeb.Auth.JWTAuthPlug.init/1","type":"function"},{"doc":"This module defines the test case to be used by\ntests that require setting up a connection.\n\nSuch tests rely on `Phoenix.ConnTest` and also\nimport other functionality to make it easier\nto build common data structures and query the data layer.\n\nFinally, if the test case interacts with the database,\nwe enable the SQL sandbox, so changes done to the database\nare reverted at the end of every test. If you are using\nPostgreSQL, you can even run database tests asynchronously\nby setting `use WandaWeb.ConnCase, async: true`, although\nthis option is not recommended for other databases.","ref":"WandaWeb.ConnCase.html","title":"WandaWeb.ConnCase","type":"module"},{"doc":"","ref":"WandaWeb.Endpoint.html","title":"WandaWeb.Endpoint","type":"module"},{"doc":"","ref":"WandaWeb.Endpoint.html#broadcast/3","title":"WandaWeb.Endpoint.broadcast/3","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#broadcast!/3","title":"WandaWeb.Endpoint.broadcast!/3","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#broadcast_from/4","title":"WandaWeb.Endpoint.broadcast_from/4","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#broadcast_from!/4","title":"WandaWeb.Endpoint.broadcast_from!/4","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#call/2","title":"WandaWeb.Endpoint.call/2","type":"function"},{"doc":"Returns the child specification to start the endpoint\nunder a supervision tree.","ref":"WandaWeb.Endpoint.html#child_spec/1","title":"WandaWeb.Endpoint.child_spec/1","type":"function"},{"doc":"Returns the endpoint configuration for `key`\n\nReturns `default` if the key does not exist.","ref":"WandaWeb.Endpoint.html#config/2","title":"WandaWeb.Endpoint.config/2","type":"function"},{"doc":"Reloads the configuration given the application environment changes.","ref":"WandaWeb.Endpoint.html#config_change/2","title":"WandaWeb.Endpoint.config_change/2","type":"function"},{"doc":"Returns the host for the given endpoint.","ref":"WandaWeb.Endpoint.html#host/0","title":"WandaWeb.Endpoint.host/0","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#init/1","title":"WandaWeb.Endpoint.init/1","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#local_broadcast/3","title":"WandaWeb.Endpoint.local_broadcast/3","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#local_broadcast_from/4","title":"WandaWeb.Endpoint.local_broadcast_from/4","type":"function"},{"doc":"Generates the path information when routing to this endpoint.","ref":"WandaWeb.Endpoint.html#path/1","title":"WandaWeb.Endpoint.path/1","type":"function"},{"doc":"Generates the script name.","ref":"WandaWeb.Endpoint.html#script_name/0","title":"WandaWeb.Endpoint.script_name/0","type":"function"},{"doc":"Starts the endpoint supervision tree.","ref":"WandaWeb.Endpoint.html#start_link/1","title":"WandaWeb.Endpoint.start_link/1","type":"function"},{"doc":"* `:log_access_url` - if the access url should be logged\n once the endpoint starts\n\nAll other options are merged into the endpoint configuration.","ref":"WandaWeb.Endpoint.html#start_link/1-options","title":"Options - WandaWeb.Endpoint.start_link/1","type":"function"},{"doc":"Generates a base64-encoded cryptographic hash (sha512) to a static file\nin `priv/static`. Meant to be used for Subresource Integrity with CDNs.","ref":"WandaWeb.Endpoint.html#static_integrity/1","title":"WandaWeb.Endpoint.static_integrity/1","type":"function"},{"doc":"Returns a two item tuple with the first item being the `static_path`\nand the second item being the `static_integrity`.","ref":"WandaWeb.Endpoint.html#static_lookup/1","title":"WandaWeb.Endpoint.static_lookup/1","type":"function"},{"doc":"Generates a route to a static file in `priv/static`.","ref":"WandaWeb.Endpoint.html#static_path/1","title":"WandaWeb.Endpoint.static_path/1","type":"function"},{"doc":"Generates the static URL without any path information.\n\nIt uses the configuration under `:static_url` to generate\nsuch. It falls back to `:url` if `:static_url` is not set.","ref":"WandaWeb.Endpoint.html#static_url/0","title":"WandaWeb.Endpoint.static_url/0","type":"function"},{"doc":"Generates the endpoint base URL but as a `URI` struct.\n\nIt uses the configuration under `:url` to generate such.\nUseful for manipulating the URL data and passing it to\nURL helpers.","ref":"WandaWeb.Endpoint.html#struct_url/0","title":"WandaWeb.Endpoint.struct_url/0","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#subscribe/2","title":"WandaWeb.Endpoint.subscribe/2","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#unsubscribe/1","title":"WandaWeb.Endpoint.unsubscribe/1","type":"function"},{"doc":"Generates the endpoint base URL without any path information.\n\nIt uses the configuration under `:url` to generate such.","ref":"WandaWeb.Endpoint.html#url/0","title":"WandaWeb.Endpoint.url/0","type":"function"},{"doc":"Conveniences for translating and building error messages.","ref":"WandaWeb.ErrorHelpers.html","title":"WandaWeb.ErrorHelpers","type":"module"},{"doc":"Translates an error message.","ref":"WandaWeb.ErrorHelpers.html#translate_error/1","title":"WandaWeb.ErrorHelpers.translate_error/1","type":"function"},{"doc":"","ref":"WandaWeb.ErrorView.html","title":"WandaWeb.ErrorView","type":"module"},{"doc":"The resource name, as an atom, for this view","ref":"WandaWeb.ErrorView.html#__resource__/0","title":"WandaWeb.ErrorView.__resource__/0","type":"function"},{"doc":"Renders the given template locally.","ref":"WandaWeb.ErrorView.html#render/2","title":"WandaWeb.ErrorView.render/2","type":"function"},{"doc":"Callback invoked when no template is found.\nBy default it raises but can be customized\nto render a particular template.","ref":"WandaWeb.ErrorView.html#template_not_found/2","title":"WandaWeb.ErrorView.template_not_found/2","type":"function"},{"doc":"","ref":"WandaWeb.FallbackController.html","title":"WandaWeb.FallbackController","type":"module"},{"doc":"","ref":"WandaWeb.HealthController.html","title":"WandaWeb.HealthController","type":"module"},{"doc":"","ref":"WandaWeb.HealthController.html#health/2","title":"WandaWeb.HealthController.health/2","type":"function"},{"doc":"","ref":"WandaWeb.HealthController.html#open_api_operation/1","title":"WandaWeb.HealthController.open_api_operation/1","type":"function"},{"doc":"","ref":"WandaWeb.HealthController.html#ready/2","title":"WandaWeb.HealthController.ready/2","type":"function"},{"doc":"","ref":"WandaWeb.HealthController.html#shared_security/0","title":"WandaWeb.HealthController.shared_security/0","type":"function"},{"doc":"","ref":"WandaWeb.HealthController.html#shared_tags/0","title":"WandaWeb.HealthController.shared_tags/0","type":"function"},{"doc":"","ref":"WandaWeb.HealthView.html","title":"WandaWeb.HealthView","type":"module"},{"doc":"The resource name, as an atom, for this view","ref":"WandaWeb.HealthView.html#__resource__/0","title":"WandaWeb.HealthView.__resource__/0","type":"function"},{"doc":"Renders the given template locally.","ref":"WandaWeb.HealthView.html#render/2","title":"WandaWeb.HealthView.render/2","type":"function"},{"doc":"Callback invoked when no template is found.\nBy default it raises but can be customized\nto render a particular template.","ref":"WandaWeb.HealthView.html#template_not_found/2","title":"WandaWeb.HealthView.template_not_found/2","type":"function"},{"doc":"This Plug is responsible for redirecting api requests without a specific version\n to the latest version, when the requested path exists\n\n For example:\n Requesting /api/test, will redirect to /api/ Note: `api-key` value is not used if the unique goal is to run checks, so setting it as `--api-key 0` does the work.\n\nKeep in mind that the `agent_id` of the targets must match with values provided in the `targets` field of the execution request.\n\nThe ID can be obtained running:\n\n```\n./trento-agent id\n```\n\nIf the execution is run in a development/testing environment, [faking the agent id](https://github.com/trento-project/agent#fake-agent-id) might come handy.\n\n### **Consulting the catalog**\n\nAvailable Checks are part of the **Catalog**, and they can be retrieved by accessing the dedicated API\n\n```bash\ncurl -X 'GET' \\\n 'http://localhost:4000/api/v1/checks/catalog' \\\n -H 'accept: application/json'\n```\n\n### **Starting a Checks Execution**\n\nA Checks Execution can be started by calling the Start Execution endpoint, as follows\n\n```bash\ncurl --request POST 'http://localhost:4000/api/v1/checks/executions/start' \\\n--header 'accept: application/json' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n \"env\": {\n \"provider\": \"azure\"\n },\n \"execution_id\": \"205e326d-0c25-4f4b-9976-43f9ba1c86d3\",\n \"group_id\": \"3dff9d03-4adf-453e-9513-8533e221bb12\",\n \"targets\": [\n {\n \"agent_id\": \"a644919a-d953-43d4-bd57-7e0bb96ee894\",\n \"checks\": [\n \"156F64\"\n ]\n },\n {\n \"agent_id\": \"02d99b2f-0efd-443c-ac9c-32710323f620\",\n \"checks\": [\n \"OTH3R1\"\n ]\n }\n ]\n}'\n```\n\n> **execution_id** must be new and unique for every new execution. If an already used **execution_id** is provided, starting the execution fails.\n\nIn order to get detailed information for an execution, see [Getting Execution details](#getting-execution-details).\n\n> Note that execution is _eventually started_, meaning that a successful response to the previous API call does not guarantee that the execution is running, but that it has been accepted by the system to start.\n\n#","ref":"readme.html#testing-executions","title":"Testing Executions - Wanda","type":"extras"},{"doc":"An execution target is a target host where the checks are executed. This requires to have the `trento-agent` executable running in the host. In order to specify an execution order, its `agent_id` and a list of checks to be executed are provided. Once the execution is started, a facts gathering request is sent to these targets, facts are gathered and sent back to Wanda, where the checks result is evaluated using the gathered facts.\n\nThe `agent_id` can be obtained just issuing `trento-agent id` command in the target host.\n\nEach target _must_ specify a list of checks, that can be empty. These are the selected checks for each agent, that are executed.\n\nGiven two different targets, the same checks can be selected:\n\n```bash\ncurl --request POST 'http://localhost:4000/api/v1/checks/executions/start' \\\n--header 'accept: application/json' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n \"env\": {\n \"provider\": \"azure\"\n },\n \"execution_id\": \"205e326d-0c25-4f4b-9976-43f9ba1c86d3\",\n \"group_id\": \"3dff9d03-4adf-453e-9513-8533e221bb12\",\n \"targets\": [\n {\n \"agent_id\": \"a644919a-d953-43d4-bd57-7e0bb96ee894\",\n \"checks\": [\n \"156F64\",\n \"45B653\"\n ]\n },\n {\n \"agent_id\": \"02d99b2f-0efd-443c-ac9c-32710323f620\",\n \"checks\": [\n \"156F64\",\n \"45B653\"\n ]\n }\n ]\n}'\n```\n\nOr completely different ones:\n\n```bash\ncurl --request POST 'http://localhost:4000/api/v1/checks/executions/start' \\\n--header 'accept: application/json' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n \"env\": {\n \"provider\": \"azure\"\n },\n \"execution_id\": \"205e326d-0c25-4f4b-9976-43f9ba1c86d3\",\n \"group_id\": \"3dff9d03-4adf-453e-9513-8533e221bb12\",\n \"targets\": [\n {\n \"agent_id\": \"a644919a-d953-43d4-bd57-7e0bb96ee894\",\n \"checks\": [\n \"156F64\",\n \"45B653\"\n ]\n },\n {\n \"agent_id\": \"02d99b2f-0efd-443c-ac9c-32710323f620\",\n \"checks\": [\n \"OTH3R1\",\n \"OTH3R2\"\n ]\n }\n ]\n}'\n```\n\n### **Getting Execution details**\n\nTo get detailed information about the execution, the following API can be used.\n\n```bash\ncurl --request GET 'http://localhost:4000/api/v1/checks/executions/205e326d-0c25-4f4b-9976-43f9ba1c86d3' \\\n--header 'accept: application/json' \\\n--header 'Content-Type: application/json'\n```\n\n> **Note** that calling the execution detail API right after [starting an execution](#starting-a-checks-execution) might result in a `404 not found`, because the execution, as mentioned, is _eventually started_.\n>\n> In this case retry getting the detail of the execution.\n\nRefer to the [API doc](http://localhost:4000/swaggerui) for more information about requests and responses.\n\n### **Debugging gathered facts**\n\nOften times knowing the returned value of the gathered facts is not a trivial thing, more during the implementation of new checks.\n\nTo better debug the fact gathering process and the returned values, the `facts` subcommand of `trento-agent` is a really useful tool. This command helps to see in the target itself what the gathered fact looks like. This is specially interesting when the returned value is a complex object or the target under test is modified and the check developer wants to see how this affects the gathered fact.\n\nThe command can be used as:\n\n```\n./trento-agent facts gather --gatherer corosync.conf --argument totem.token\n# To see the currently available gatherers and their names\n# ./trento-agent facts list\n```\n\nWhich would return the next where the `Value` is the available value in the written check:\n\n```\n{\n \"Name\": \"totem.token\",\n \"CheckID\": \"\",\n \"Value\": {\n \"Value\": 30000\n },\n \"Error\": null\n}\n```","ref":"readme.html#execution-targets","title":"Execution Targets - Wanda","type":"extras"},{"doc":"Built-in Checks can be found in the Catalog directory at `./priv/catalog/`\n\nTo implement new checks and test them:\n\n- write a new [Check Specification](./guides/specification.md) file\n- locate the newly created Check in the Catalog directory `./priv/catalog/`\n- test the execution as [previously described](#testing-executions)\n\n# Running a local Wanda instance","ref":"readme.html#adding-new-checks","title":"Adding new Checks - Wanda","type":"extras"},{"doc":"To set up a local development environment for Wanda, follow the instructions provided in [how to hack on wanda](./guides/development/hack_on_wanda.md).\n\nThis guide walks through the process of installing and configuring the necessary dependencies, as well as setting up a local development environment.","ref":"readme.html#running-a-development-environment","title":"Running a Development Environment - Wanda","type":"extras"},{"doc":"The demo mode of Wanda allows to showcase checks evaluation without the full setup with actual agents on the host. To run a demo instance, follow the instructions provided in [how to run wanda demo guide](./guides/development/demo.md).\n\n# Support\n\nPlease only report bugs via [GitHub issues](https://github.com/trento-project/wanda/issues) and\nfor any other inquiry or topic use [GitHub discussion](https://github.com/trento-project/wanda/discussions).\n\n# Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md)\n\n# License\n\nCopyright 2021-2023 SUSE LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use\nany of the source code in this project except in compliance with the License. You may obtain a copy of the\nLicense at\n\nhttps://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed\nunder the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\nCONDITIONS OF ANY KIND, either express or implied. See the License for the\nspecific language governing permissions and limitations under the License.","ref":"readme.html#running-a-demo-environment","title":"Running a Demo Environment - Wanda","type":"extras"},{"doc":"# Changelog\n\n## [1.1.0](https://github.com/trento-project/wanda/tree/1.1.0) (2023-08-02)\n\n[Full Changelog](https://github.com/trento-project/wanda/compare/1.0.0...1.1.0)\n\n**Implemented enhancements:**\n\n- Refactor demo server [\\#271](https://github.com/trento-project/wanda/pull/271) ([EMaksy](https://github.com/EMaksy))\n- initial checks for VMware vSphere \\(jsc\\#TRNT-1682\\) [\\#259](https://github.com/trento-project/wanda/pull/259) ([yeoldegrove](https://github.com/yeoldegrove))\n- update reference section to clarify the package version decision [\\#255](https://github.com/trento-project/wanda/pull/255) ([angelabriel](https://github.com/angelabriel))\n- Add when conditions for resource types, propagate the resource type in the ExecutionCompleted event [\\#253](https://github.com/trento-project/wanda/pull/253) ([dottorblaster](https://github.com/dottorblaster))\n- Add user friendly failure message \\(jsc\\#TRNT-1825\\) [\\#237](https://github.com/trento-project/wanda/pull/237) ([angelabriel](https://github.com/angelabriel))\n\n**Fixed bugs:**\n\n- Fix formatting in demo guide [\\#275](https://github.com/trento-project/wanda/pull/275) ([EMaksy](https://github.com/EMaksy))\n- fixes found by checks-checker [\\#260](https://github.com/trento-project/wanda/pull/260) ([yeoldegrove](https://github.com/yeoldegrove))\n- Add default failure message for expect\\_same expectations [\\#243](https://github.com/trento-project/wanda/pull/243) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n**Merged pull requests:**\n\n- Bump rhai\\_rustler to v1.0.2 [\\#276](https://github.com/trento-project/wanda/pull/276) ([fabriziosestito](https://github.com/fabriziosestito))\n- Bump rhai\\_rustler from 1.0.0 to 1.0.1 [\\#270](https://github.com/trento-project/wanda/pull/270) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump ex\\_doc from 0.30.2 to 0.30.3 [\\#269](https://github.com/trento-project/wanda/pull/269) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump jason from 1.4.0 to 1.4.1 [\\#266](https://github.com/trento-project/wanda/pull/266) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump ex\\_doc from 0.29.4 to 0.30.2 [\\#265](https://github.com/trento-project/wanda/pull/265) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump rhai\\_rustler to v1.0.0 [\\#264](https://github.com/trento-project/wanda/pull/264) ([fabriziosestito](https://github.com/fabriziosestito))\n- Update contracts usage [\\#258](https://github.com/trento-project/wanda/pull/258) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Document target\\_type inside env [\\#256](https://github.com/trento-project/wanda/pull/256) ([dottorblaster](https://github.com/dottorblaster))\n- Bump phoenix\\_ecto from 4.4.0 to 4.4.2 [\\#252](https://github.com/trento-project/wanda/pull/252) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump docker/login-action from 2.1.0 to 2.2.0 [\\#251](https://github.com/trento-project/wanda/pull/251) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Document cluster type support [\\#248](https://github.com/trento-project/wanda/pull/248) ([arbulu89](https://github.com/arbulu89))\n- Bump open\\_api\\_spex from 3.16.1 to 3.17.3 [\\#246](https://github.com/trento-project/wanda/pull/246) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Update copyright year to 2023 [\\#240](https://github.com/trento-project/wanda/pull/240) ([EMaksy](https://github.com/EMaksy))\n- Bump docker/metadata-action from 4.3.0 to 4.4.0 [\\#234](https://github.com/trento-project/wanda/pull/234) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump dialyxir from 1.2.0 to 1.3.0 [\\#232](https://github.com/trento-project/wanda/pull/232) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump excoveralls from 0.16.0 to 0.16.1 [\\#231](https://github.com/trento-project/wanda/pull/231) ([dependabot[bot]](https://github.com/apps/dependabot))\n\n## [1.0.0](https://github.com/trento-project/wanda/tree/1.0.0) (2023-04-26)\n\n[Full Changelog](https://github.com/trento-project/wanda/compare/0.1.0...1.0.0)\n\n**Implemented enhancements:**\n\n- Make cors optional on production [\\#206](https://github.com/trento-project/wanda/pull/206) ([arbulu89](https://github.com/arbulu89))\n- Build wanda with premium checks, if available [\\#179](https://github.com/trento-project/wanda/pull/179) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n**Fixed bugs:**\n\n- Expectation results result to false when some agent evaluation is missing [\\#224](https://github.com/trento-project/wanda/pull/224) ([arbulu89](https://github.com/arbulu89))\n\n**Merged pull requests:**\n\n- enhance remediation section to clarify the value setting [\\#235](https://github.com/trento-project/wanda/pull/235) ([angelabriel](https://github.com/angelabriel))\n- Add failure message documentation [\\#230](https://github.com/trento-project/wanda/pull/230) ([dottorblaster](https://github.com/dottorblaster))\n- Bump ex\\_doc from 0.29.2 to 0.29.4 [\\#229](https://github.com/trento-project/wanda/pull/229) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Rename `health_test.exs` -\\> `health_controller_test.exs` [\\#228](https://github.com/trento-project/wanda/pull/228) ([jamie-suse](https://github.com/jamie-suse))\n- Rename `HealthcheckViewTest` -\\> `HealthViewTest` [\\#227](https://github.com/trento-project/wanda/pull/227) ([jamie-suse](https://github.com/jamie-suse))\n- add api versioning to the readme examples [\\#226](https://github.com/trento-project/wanda/pull/226) ([angelabriel](https://github.com/angelabriel))\n- Add healthcheck and readiness endpoints [\\#225](https://github.com/trento-project/wanda/pull/225) ([jamie-suse](https://github.com/jamie-suse))\n- Add dev.local.exs usage [\\#223](https://github.com/trento-project/wanda/pull/223) ([arbulu89](https://github.com/arbulu89))\n- Bump credo from 1.6.7 to 1.7.0 [\\#222](https://github.com/trento-project/wanda/pull/222) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Fix execution of SBD related checks \\(jsc\\#CFSA-1961\\) [\\#220](https://github.com/trento-project/wanda/pull/220) ([angelabriel](https://github.com/angelabriel))\n- Bump plug\\_cowboy from 2.6.0 to 2.6.1 [\\#218](https://github.com/trento-project/wanda/pull/218) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Refactor API errors [\\#217](https://github.com/trento-project/wanda/pull/217) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add failure message [\\#216](https://github.com/trento-project/wanda/pull/216) ([dottorblaster](https://github.com/dottorblaster))\n- Bump excoveralls from 0.15.3 to 0.16.0 [\\#213](https://github.com/trento-project/wanda/pull/213) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Fixed broken web URLs [\\#212](https://github.com/trento-project/wanda/pull/212) ([ksanjeet](https://github.com/ksanjeet))\n- Compile and test with --warnings-as-errors flag [\\#210](https://github.com/trento-project/wanda/pull/210) ([fabriziosestito](https://github.com/fabriziosestito))\n- Update the hack on wanda guide [\\#209](https://github.com/trento-project/wanda/pull/209) ([EMaksy](https://github.com/EMaksy))\n- Bump ex\\_doc from 0.29.1 to 0.29.2 [\\#208](https://github.com/trento-project/wanda/pull/208) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Remove jwt enablement flag usage from jwt plug tests [\\#207](https://github.com/trento-project/wanda/pull/207) ([arbulu89](https://github.com/arbulu89))\n- Enrich the faker by using catalog data [\\#205](https://github.com/trento-project/wanda/pull/205) ([rtorrero](https://github.com/rtorrero))\n- Facts schema value lists maps [\\#204](https://github.com/trento-project/wanda/pull/204) ([arbulu89](https://github.com/arbulu89))\n- Bump actions/checkout from 2 to 3 [\\#203](https://github.com/trento-project/wanda/pull/203) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump excoveralls from 0.15.0 to 0.15.3 [\\#200](https://github.com/trento-project/wanda/pull/200) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump open\\_api\\_spex from 3.13.0 to 3.16.1 [\\#198](https://github.com/trento-project/wanda/pull/198) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump ecto\\_sql from 3.8.3 to 3.9.2 [\\#197](https://github.com/trento-project/wanda/pull/197) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump joken from 2.5.0 to 2.6.0 [\\#196](https://github.com/trento-project/wanda/pull/196) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump ex\\_doc from 0.29.0 to 0.29.1 [\\#195](https://github.com/trento-project/wanda/pull/195) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump credo from 1.6.6 to 1.6.7 [\\#194](https://github.com/trento-project/wanda/pull/194) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump phoenix from 1.6.12 to 1.6.16 [\\#193](https://github.com/trento-project/wanda/pull/193) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump docker/build-push-action from 3 to 4 [\\#192](https://github.com/trento-project/wanda/pull/192) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Add dependabot [\\#191](https://github.com/trento-project/wanda/pull/191) ([fabriziosestito](https://github.com/fabriziosestito))\n- Filter out non-existing checks on the faker [\\#189](https://github.com/trento-project/wanda/pull/189) ([rtorrero](https://github.com/rtorrero))\n- Remotely trigger demo deploy on new wanda image [\\#188](https://github.com/trento-project/wanda/pull/188) ([rtorrero](https://github.com/rtorrero))\n- Add new demo env that uses faked execution server [\\#187](https://github.com/trento-project/wanda/pull/187) ([rtorrero](https://github.com/rtorrero))\n- Fix warning in api redirector test [\\#186](https://github.com/trento-project/wanda/pull/186) ([fabriziosestito](https://github.com/fabriziosestito))\n- Fix execution flaky test [\\#185](https://github.com/trento-project/wanda/pull/185) ([arbulu89](https://github.com/arbulu89))\n- Api version v1 [\\#183](https://github.com/trento-project/wanda/pull/183) ([CDimonaco](https://github.com/CDimonaco))\n- Update package\\_version gatherer doc [\\#182](https://github.com/trento-project/wanda/pull/182) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Run CI `test` step on different versions of Elixir & OTP [\\#181](https://github.com/trento-project/wanda/pull/181) ([jamie-suse](https://github.com/jamie-suse))\n- Add information on how to install wanda directly for development [\\#178](https://github.com/trento-project/wanda/pull/178) ([EMaksy](https://github.com/EMaksy))\n- Bump BCI base image to 15.4 for dev Dockerfile [\\#177](https://github.com/trento-project/wanda/pull/177) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Fix JWT plug runtime config [\\#176](https://github.com/trento-project/wanda/pull/176) ([fabriziosestito](https://github.com/fabriziosestito))\n- Use new `trento-wanda` image name for check development environment [\\#175](https://github.com/trento-project/wanda/pull/175) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- rewrite trento community checks regarding 'package version' [\\#124](https://github.com/trento-project/wanda/pull/124) ([angelabriel](https://github.com/angelabriel))\n\n## [0.1.0](https://github.com/trento-project/wanda/tree/0.1.0) (2023-01-23)\n\n[Full Changelog](https://github.com/trento-project/wanda/compare/a8b788751fe90542ed0d2541a816b3a148dedfd0...0.1.0)\n\n**Implemented enhancements:**\n\n- Build in obs [\\#173](https://github.com/trento-project/wanda/pull/173) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add JWT auth [\\#168](https://github.com/trento-project/wanda/pull/168) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add premium flag option to catalog loading code [\\#163](https://github.com/trento-project/wanda/pull/163) ([arbulu89](https://github.com/arbulu89))\n- Add check DA114A: Corosync has at least 2 rings configured [\\#141](https://github.com/trento-project/wanda/pull/141) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add SBD dump gatherer documentation [\\#137](https://github.com/trento-project/wanda/pull/137) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add last execution by group [\\#108](https://github.com/trento-project/wanda/pull/108) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add targets execution view [\\#106](https://github.com/trento-project/wanda/pull/106) ([arbulu89](https://github.com/arbulu89))\n- Fix protobuf message mapping [\\#94](https://github.com/trento-project/wanda/pull/94) ([arbulu89](https://github.com/arbulu89))\n- Ordered Execution list [\\#93](https://github.com/trento-project/wanda/pull/93) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add cargo to dockerfile and build rustler [\\#74](https://github.com/trento-project/wanda/pull/74) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Start execution api [\\#73](https://github.com/trento-project/wanda/pull/73) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add Checks Specification Documentation [\\#72](https://github.com/trento-project/wanda/pull/72) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Refactor executions api [\\#66](https://github.com/trento-project/wanda/pull/66) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Store execution state [\\#60](https://github.com/trento-project/wanda/pull/60) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add support for values computation based on environment [\\#46](https://github.com/trento-project/wanda/pull/46) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Use env values [\\#42](https://github.com/trento-project/wanda/pull/42) ([arbulu89](https://github.com/arbulu89))\n- Serve the execution results through an endpoint [\\#40](https://github.com/trento-project/wanda/pull/40) ([dottorblaster](https://github.com/dottorblaster))\n- Some needed improvements to make the code runnable on prod environment [\\#38](https://github.com/trento-project/wanda/pull/38) ([arbulu89](https://github.com/arbulu89))\n- Store execution result on Check execution completion [\\#36](https://github.com/trento-project/wanda/pull/36) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add a storable Wanda.Result.ExecutionResult entity [\\#35](https://github.com/trento-project/wanda/pull/35) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n**Fixed bugs:**\n\n- Fix default value when getting system env for JWT\\_AUTHENTICATION\\_ENABLED [\\#172](https://github.com/trento-project/wanda/pull/172) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Set critical state on agent timeout and warning severity [\\#166](https://github.com/trento-project/wanda/pull/166) ([arbulu89](https://github.com/arbulu89))\n- Fix get last execution by group id [\\#110](https://github.com/trento-project/wanda/pull/110) ([fabriziosestito](https://github.com/fabriziosestito))\n- Improve Execution open api doc [\\#109](https://github.com/trento-project/wanda/pull/109) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Init before start [\\#101](https://github.com/trento-project/wanda/pull/101) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Fix flaky evaluation test [\\#96](https://github.com/trento-project/wanda/pull/96) ([arbulu89](https://github.com/arbulu89))\n- Load checks properly for the execution [\\#61](https://github.com/trento-project/wanda/pull/61) ([arbulu89](https://github.com/arbulu89))\n- Fixed items definition for expectation\\_results in ExecutionComplete event [\\#14](https://github.com/trento-project/wanda/pull/14) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n**Closed issues:**\n\n- Bad links in README.md [\\#126](https://github.com/trento-project/wanda/issues/126)\n\n**Merged pull requests:**\n\n- Fix cors plug integration [\\#174](https://github.com/trento-project/wanda/pull/174) ([CDimonaco](https://github.com/CDimonaco))\n- Execution started event [\\#171](https://github.com/trento-project/wanda/pull/171) ([CDimonaco](https://github.com/CDimonaco))\n- Chore: move tests in subfolder [\\#170](https://github.com/trento-project/wanda/pull/170) ([fabriziosestito](https://github.com/fabriziosestito))\n- Remove ssh-address flag reference from docs [\\#169](https://github.com/trento-project/wanda/pull/169) ([arbulu89](https://github.com/arbulu89))\n- rewrite trento community check regarding 'running corosync rings' [\\#167](https://github.com/trento-project/wanda/pull/167) ([angelabriel](https://github.com/angelabriel))\n- Add list & map examples for `corosync-cmapctl` docs [\\#165](https://github.com/trento-project/wanda/pull/165) ([jamie-suse](https://github.com/jamie-suse))\n- Force rhai\\_rustler build [\\#164](https://github.com/trento-project/wanda/pull/164) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add doc for the new package\\_version comparisons [\\#162](https://github.com/trento-project/wanda/pull/162) ([rtorrero](https://github.com/rtorrero))\n- add when condition to decide where to run a check [\\#161](https://github.com/trento-project/wanda/pull/161) ([angelabriel](https://github.com/angelabriel))\n- Improve gatherers documentation and add rhai example outputs [\\#160](https://github.com/trento-project/wanda/pull/160) ([fabriziosestito](https://github.com/fabriziosestito))\n- Clean up doc saying that expectation evaluation has access to the env [\\#159](https://github.com/trento-project/wanda/pull/159) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Document the trento-agent facts command [\\#158](https://github.com/trento-project/wanda/pull/158) ([arbulu89](https://github.com/arbulu89))\n- Fix integer mapping [\\#157](https://github.com/trento-project/wanda/pull/157) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add starting the targets section on the docs [\\#156](https://github.com/trento-project/wanda/pull/156) ([arbulu89](https://github.com/arbulu89))\n- Document best practices [\\#155](https://github.com/trento-project/wanda/pull/155) ([arbulu89](https://github.com/arbulu89))\n- Implement when condition [\\#154](https://github.com/trento-project/wanda/pull/154) ([dottorblaster](https://github.com/dottorblaster))\n- rewrite trento community check regarding 'hacluster' password change [\\#153](https://github.com/trento-project/wanda/pull/153) ([angelabriel](https://github.com/angelabriel))\n- Fix external links in ExDocs [\\#152](https://github.com/trento-project/wanda/pull/152) ([fabriziosestito](https://github.com/fabriziosestito))\n- Chore: remove unusued fixture [\\#151](https://github.com/trento-project/wanda/pull/151) ([fabriziosestito](https://github.com/fabriziosestito))\n- Bump to rhai\\_rustler to v0.1.3 [\\#149](https://github.com/trento-project/wanda/pull/149) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add documentation for verify\\_password gatherer [\\#147](https://github.com/trento-project/wanda/pull/147) ([rtorrero](https://github.com/rtorrero))\n- rewrite trento community checks regarding 'cibadmin' configuration [\\#146](https://github.com/trento-project/wanda/pull/146) ([angelabriel](https://github.com/angelabriel))\n- Improve table format and add req argument info [\\#145](https://github.com/trento-project/wanda/pull/145) ([rtorrero](https://github.com/rtorrero))\n- Add saphostctrl gatherer to gatherers.md [\\#144](https://github.com/trento-project/wanda/pull/144) ([rtorrero](https://github.com/rtorrero))\n- Add a cheat sheet for Rhai [\\#143](https://github.com/trento-project/wanda/pull/143) ([dottorblaster](https://github.com/dottorblaster))\n- rewrite trento community checks regarding 'sbd dump' configuration [\\#142](https://github.com/trento-project/wanda/pull/142) ([angelabriel](https://github.com/angelabriel))\n- Document cibadmin gatherer [\\#136](https://github.com/trento-project/wanda/pull/136) ([arbulu89](https://github.com/arbulu89))\n- Add a ref to target to README [\\#133](https://github.com/trento-project/wanda/pull/133) ([dottorblaster](https://github.com/dottorblaster))\n- rewrite trento community checks regarding 'sbd' configuration [\\#123](https://github.com/trento-project/wanda/pull/123) ([angelabriel](https://github.com/angelabriel))\n- rewriting checks for Wanda gatherer corosync-cmapctl [\\#119](https://github.com/trento-project/wanda/pull/119) ([pirat013](https://github.com/pirat013))\n- Add severity to the JSON schema [\\#116](https://github.com/trento-project/wanda/pull/116) ([dottorblaster](https://github.com/dottorblaster))\n- Gatherer.corosyncconf [\\#115](https://github.com/trento-project/wanda/pull/115) ([pirat013](https://github.com/pirat013))\n- Refactor factories [\\#112](https://github.com/trento-project/wanda/pull/112) ([fabriziosestito](https://github.com/fabriziosestito))\n- Use Kernel.-- instead of Enum.filter [\\#111](https://github.com/trento-project/wanda/pull/111) ([fabriziosestito](https://github.com/fabriziosestito))\n- add license [\\#107](https://github.com/trento-project/wanda/pull/107) ([stefanotorresi](https://github.com/stefanotorresi))\n- Use specific compose ports for wanda dev/test docker-compose [\\#105](https://github.com/trento-project/wanda/pull/105) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add critical, warning and passing counts to the execution view [\\#104](https://github.com/trento-project/wanda/pull/104) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add ability to handle non-existent & malformed Checks supplied to catalog [\\#103](https://github.com/trento-project/wanda/pull/103) ([jamie-suse](https://github.com/jamie-suse))\n- Add corosynccmapctl to gatherers.md [\\#102](https://github.com/trento-project/wanda/pull/102) ([rtorrero](https://github.com/rtorrero))\n- Bump contracts [\\#99](https://github.com/trento-project/wanda/pull/99) ([fabriziosestito](https://github.com/fabriziosestito))\n- Generate and push swagger-ui to gh-pages [\\#98](https://github.com/trento-project/wanda/pull/98) ([fabriziosestito](https://github.com/fabriziosestito))\n- Re-add accidentaly removed headers [\\#97](https://github.com/trento-project/wanda/pull/97) ([rtorrero](https://github.com/rtorrero))\n- Add test for policy handling Fact error [\\#95](https://github.com/trento-project/wanda/pull/95) ([jamie-suse](https://github.com/jamie-suse))\n- Remove installation section from README.md [\\#92](https://github.com/trento-project/wanda/pull/92) ([fabriziosestito](https://github.com/fabriziosestito))\n- Update CONTRIBUTING.md [\\#91](https://github.com/trento-project/wanda/pull/91) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add documentation for the package\\_version gatherer [\\#90](https://github.com/trento-project/wanda/pull/90) ([rtorrero](https://github.com/rtorrero))\n- Document systemd gatherer [\\#89](https://github.com/trento-project/wanda/pull/89) ([arbulu89](https://github.com/arbulu89))\n- Add Documentation for SBD Gatherer [\\#88](https://github.com/trento-project/wanda/pull/88) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add badges to readme [\\#87](https://github.com/trento-project/wanda/pull/87) ([fabriziosestito](https://github.com/fabriziosestito))\n- Use correct remediation text for check 156F64 [\\#85](https://github.com/trento-project/wanda/pull/85) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Support no args gatherers [\\#84](https://github.com/trento-project/wanda/pull/84) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add coveralls [\\#83](https://github.com/trento-project/wanda/pull/83) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add /etc/hosts file gatherer documentation [\\#82](https://github.com/trento-project/wanda/pull/82) ([rtorrero](https://github.com/rtorrero))\n- Add ExDoc config in mix.exs and supporting file to generate the doc [\\#81](https://github.com/trento-project/wanda/pull/81) ([fabriziosestito](https://github.com/fabriziosestito))\n- Minor tweaks to the specs doc [\\#80](https://github.com/trento-project/wanda/pull/80) ([rtorrero](https://github.com/rtorrero))\n- Fix Checks Specification doc link [\\#79](https://github.com/trento-project/wanda/pull/79) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Use strict module ordering [\\#77](https://github.com/trento-project/wanda/pull/77) ([fabriziosestito](https://github.com/fabriziosestito))\n- Integrate TLint into CI [\\#76](https://github.com/trento-project/wanda/pull/76) ([dottorblaster](https://github.com/dottorblaster))\n- Do not raise if an execution already exists [\\#75](https://github.com/trento-project/wanda/pull/75) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add ex doc gh pages [\\#71](https://github.com/trento-project/wanda/pull/71) ([fabriziosestito](https://github.com/fabriziosestito))\n- Bump erlang version to 24.3.4 [\\#70](https://github.com/trento-project/wanda/pull/70) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Change Abacus to Rhai [\\#69](https://github.com/trento-project/wanda/pull/69) ([fabriziosestito](https://github.com/fabriziosestito))\n- Handle CORS in dev environment [\\#68](https://github.com/trento-project/wanda/pull/68) ([arbulu89](https://github.com/arbulu89))\n- Refactor context [\\#65](https://github.com/trento-project/wanda/pull/65) ([fabriziosestito](https://github.com/fabriziosestito))\n- Abstract RabbitMQ processing logic [\\#64](https://github.com/trento-project/wanda/pull/64) ([jamie-suse](https://github.com/jamie-suse))\n- Detect already running execution for group\\_id [\\#63](https://github.com/trento-project/wanda/pull/63) ([arbulu89](https://github.com/arbulu89))\n- Remove restart directive from container definitions [\\#62](https://github.com/trento-project/wanda/pull/62) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Chore: remove unused miss dep [\\#59](https://github.com/trento-project/wanda/pull/59) ([fabriziosestito](https://github.com/fabriziosestito))\n- Use google protobuf value [\\#58](https://github.com/trento-project/wanda/pull/58) ([fabriziosestito](https://github.com/fabriziosestito))\n- Chore: rename/refactor schemas [\\#56](https://github.com/trento-project/wanda/pull/56) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add get check result [\\#55](https://github.com/trento-project/wanda/pull/55) ([fabriziosestito](https://github.com/fabriziosestito))\n- Rename controllers context [\\#54](https://github.com/trento-project/wanda/pull/54) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add Result OpenAPI Schema and cleanup [\\#53](https://github.com/trento-project/wanda/pull/53) ([fabriziosestito](https://github.com/fabriziosestito))\n- More prod fixes [\\#52](https://github.com/trento-project/wanda/pull/52) ([arbulu89](https://github.com/arbulu89))\n- Add initialization tasks for a release [\\#51](https://github.com/trento-project/wanda/pull/51) ([arbulu89](https://github.com/arbulu89))\n- Enable phoenix server usage in prod [\\#50](https://github.com/trento-project/wanda/pull/50) ([arbulu89](https://github.com/arbulu89))\n- Catalog controller [\\#49](https://github.com/trento-project/wanda/pull/49) ([arbulu89](https://github.com/arbulu89))\n- Cleanup execution controller [\\#48](https://github.com/trento-project/wanda/pull/48) ([fabriziosestito](https://github.com/fabriziosestito))\n- Refactor evaluation tests [\\#47](https://github.com/trento-project/wanda/pull/47) ([arbulu89](https://github.com/arbulu89))\n- Switch to Views for JSON rendering [\\#45](https://github.com/trento-project/wanda/pull/45) ([dottorblaster](https://github.com/dottorblaster))\n- Add CI step to check for unused dependencies [\\#44](https://github.com/trento-project/wanda/pull/44) ([jamie-suse](https://github.com/jamie-suse))\n- Load check values from yaml [\\#43](https://github.com/trento-project/wanda/pull/43) ([arbulu89](https://github.com/arbulu89))\n- Check severity [\\#41](https://github.com/trento-project/wanda/pull/41) ([arbulu89](https://github.com/arbulu89))\n- Enable single pipe check on credo [\\#39](https://github.com/trento-project/wanda/pull/39) ([arbulu89](https://github.com/arbulu89))\n- Add dockerfile [\\#37](https://github.com/trento-project/wanda/pull/37) ([fabriziosestito](https://github.com/fabriziosestito))\n- Map ExecutionCompleted event [\\#34](https://github.com/trento-project/wanda/pull/34) ([arbulu89](https://github.com/arbulu89))\n- Phoenix lift off [\\#33](https://github.com/trento-project/wanda/pull/33) ([arbulu89](https://github.com/arbulu89))\n- Message content\\_type from Contracts [\\#32](https://github.com/trento-project/wanda/pull/32) ([CDimonaco](https://github.com/CDimonaco))\n- Add amqp consumer integration tests [\\#31](https://github.com/trento-project/wanda/pull/31) ([fabriziosestito](https://github.com/fabriziosestito))\n- Handle fact gathering errors [\\#30](https://github.com/trento-project/wanda/pull/30) ([arbulu89](https://github.com/arbulu89))\n- Update contracts dep to trento-projects/contracts [\\#29](https://github.com/trento-project/wanda/pull/29) ([fabriziosestito](https://github.com/fabriziosestito))\n- Set execution GenServer restart policy as transient [\\#28](https://github.com/trento-project/wanda/pull/28) ([arbulu89](https://github.com/arbulu89))\n- Do not requeue amqp message on error [\\#26](https://github.com/trento-project/wanda/pull/26) ([arbulu89](https://github.com/arbulu89))\n- Fix amqp message consumption [\\#25](https://github.com/trento-project/wanda/pull/25) ([arbulu89](https://github.com/arbulu89))\n- Publish facts gathering requested [\\#24](https://github.com/trento-project/wanda/pull/24) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add checks to execution server state [\\#23](https://github.com/trento-project/wanda/pull/23) ([fabriziosestito](https://github.com/fabriziosestito))\n- Map FactsGatheringRequested event [\\#22](https://github.com/trento-project/wanda/pull/22) ([fabriziosestito](https://github.com/fabriziosestito))\n- Timeout business logic implementation [\\#21](https://github.com/trento-project/wanda/pull/21) ([dottorblaster](https://github.com/dottorblaster))\n- Remove JSON schema, add new protobuf contracts [\\#20](https://github.com/trento-project/wanda/pull/20) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add timeout logic to Wanda.Execution.Server [\\#19](https://github.com/trento-project/wanda/pull/19) ([dottorblaster](https://github.com/dottorblaster))\n- Revert \"Adds cache version to pipeline\" [\\#18](https://github.com/trento-project/wanda/pull/18) ([fabriziosestito](https://github.com/fabriziosestito))\n- fix execution requested event schema [\\#15](https://github.com/trento-project/wanda/pull/15) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Adds cache version to pipeline [\\#12](https://github.com/trento-project/wanda/pull/12) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Serialize an ExecutionCompleted json cloud event [\\#11](https://github.com/trento-project/wanda/pull/11) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Adds json schema for emitted ExecutionCompletedV1 [\\#10](https://github.com/trento-project/wanda/pull/10) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Receive Execution Requested event [\\#9](https://github.com/trento-project/wanda/pull/9) ([fabriziosestito](https://github.com/fabriziosestito))\n- Refactor Wanda.Execution in Wanda.Execution.Server, create execution API module [\\#8](https://github.com/trento-project/wanda/pull/8) ([fabriziosestito](https://github.com/fabriziosestito))\n- Receive facts gathered event [\\#6](https://github.com/trento-project/wanda/pull/6) ([fabriziosestito](https://github.com/fabriziosestito))\n- Setup amqp [\\#5](https://github.com/trento-project/wanda/pull/5) ([fabriziosestito](https://github.com/fabriziosestito))\n- Group expectations evaluation [\\#4](https://github.com/trento-project/wanda/pull/4) ([fabriziosestito](https://github.com/fabriziosestito))\n- Refactor execution pt1 [\\#3](https://github.com/trento-project/wanda/pull/3) ([fabriziosestito](https://github.com/fabriziosestito))\n- Expectations eval pt 1 [\\#2](https://github.com/trento-project/wanda/pull/2) ([fabriziosestito](https://github.com/fabriziosestito))\n- proof of concept of check execution orchestration, step 1 [\\#1](https://github.com/trento-project/wanda/pull/1) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n\n\n\\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*","ref":"changelog.html","title":"Changelog","type":"extras"},{"doc":"# How to contribute\n\nThanks for showing interest and sharing your time to contribute to this project!\n\nThis guide is meant to be used as a general guideline for creating issues or\npull requests. We encourage all first-time contributors to give this a read to avoid\ncommon mistakes and improve the quality of all contributions.","ref":"contributing.html","title":"How to contribute","type":"extras"},{"doc":"Before creating a new issue make sure you use the search functionality to confirm\nthat a similar issue doesn't already exist. Next, make sure you properly label\nthe issue as per our [labels](https://github.com/trento-project/wanda/labels)\n\nIf you are reporting a `bug`, please share a file generated using the\n`trento-support.sh` script with the following params:\n\n```\n# trento-support.sh --collect all --output file-tgz\n```\n\nand include the output in your issue. The script should remove sensitive data\nautomatically but please make sure you are not sharing any sensitive data of your own.","ref":"contributing.html#opening-issues","title":"Opening issues - How to contribute","type":"extras"},{"doc":"Always refer to the [docs repository](https://github.com/trento-project/docs) for coding standards and general guidelines.\n\n#","ref":"contributing.html#submitting-changes","title":"Submitting changes - How to contribute","type":"extras"},{"doc":"Reviews are hard. These few points will help us to reduce the time and effort required and allow us to merge your changes faster.\n\n1. Only touch relevant files.\n2. We have a PR template to aid you in completing the required details. Be\n sure to complete it and remove the non-relevant parts.\n3. Keep PRs as small as possible. When the PR gets too big, consider splitting it into multiple parts. A PR should ideally be between 100 and 500 additions.\n4. Check that the tests are passing.\n5. Check that your code is not generating new warnings.\n6. Check that any dependent changes have been merged and published in downstream modules\n7. Commit history should be short and group changes that otherwise wouldn't\n make sense on their own.\n8. Always write a clear log message for your commits. One-line messages are\n fine for small changes, but bigger changes should look like this:\n\n ```\n git commit -m \"A brief summary of the commit\n\n A paragraph describing what changed and its impact.\"\n ```\n\n9. Write a detailed description that gives context and explains why you are\n creating the PR.\n10. If the PR adds functionality, please add some tests and documentation\n to support it.\n11. Each PR needs 1 approval to be merged. Select a reviewer in particular if\n you are looking for specific feedback from someone.\n\n#","ref":"contributing.html#pull-requests-guideline","title":"Pull Requests guideline - How to contribute","type":"extras"},{"doc":"1. Opinionated comments are welcome but don't expect them always to be\n addressed. Be ready for discussion but also open to conceding.\n To avoid scope creep, consider proposing subsequent PRs\n rather than requesting changes for the current PR you are reviewing.\n2. Short, concise comments with examples are the most valuable.","ref":"contributing.html#reviewers-guideline","title":"Reviewers guideline - How to contribute","type":"extras"},{"doc":"# Rhai expressions cheatsheet\n\nIn this cheatsheet are grouped the most frequent manipulations that can be done through Rhai, for convenience.","ref":"rhai_expressions_cheat_sheet.html","title":"Rhai expressions cheatsheet","type":"extras"},{"doc":"{: .col-2}\n\n#","ref":"rhai_expressions_cheat_sheet.html#cheatsheet","title":"Cheatsheet - Rhai expressions cheatsheet","type":"extras"},{"doc":"##","ref":"rhai_expressions_cheat_sheet.html#arrays","title":"Arrays - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n[1, 2, 3].filter(|value| value % 2 == 0)\n=> [2]\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#filtering-an-array","title":"Filtering an array - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n[\"wow\", \"check\"].index_of(|value| value == \"check\")\n=> 1\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#finding-the-index-of-an-element-inside-an-array","title":"Finding the index of an element inside an array - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\nlet nodelist = [\n #{resource_id: 5, name: \"foo\"},\n #{resource_id: 12, name: \"bar\"}\n];\n\nnodelist.find(|value| value.resource_id == 5)\n=> #{\"name\": \"foo\", \"resource_id\": 5}\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#finding-an-element-inside-an-array","title":"Finding an element inside an array - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n[2, 4, 6].all(|value| value % 2 == 0)\n=> true\n```\n\n#","ref":"rhai_expressions_cheat_sheet.html#checking-if-an-expression-is-true-for-every-element-of-an-array","title":"Checking if an expression is true for every element of an array - Rhai expressions cheatsheet","type":"extras"},{"doc":"##","ref":"rhai_expressions_cheat_sheet.html#maps","title":"Maps - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n#{a: 1, b: 2}.keys()\n=> [\"a\", \"b\"]\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#get-only-keys-returns-an-array","title":"Get only keys (returns an array) - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n#{a: 1, b: 2}.values()\n=> [1, 2]\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#get-only-values-returns-an-array","title":"Get only values (returns an array) - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\nlet map = #{\n ring_one: 12,\n ring_two: 34,\n ring_three: 90,\n ring_four: 234,\n ring_five: 908\n};\n\nmap.keys().filter(|prop| prop.starts_with(\"ring\")).len() >= 5\n=> true\n```\n\n#","ref":"rhai_expressions_cheat_sheet.html#check-if-a-map-has-more-than-5-keys-which-name-starts-with-ring","title":"Check if a map has more than 5 keys which name starts with \"ring\" - Rhai expressions cheatsheet","type":"extras"},{"doc":"##","ref":"rhai_expressions_cheat_sheet.html#strings","title":"Strings - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n\"a;b;c\".split(\";\")\n=> [\"a\", \"b\", \"c\"]\n```","ref":"rhai_expressions_cheat_sheet.html#splitting-a-string","title":"Splitting a string - Rhai expressions cheatsheet","type":"extras"},{"doc":"# Checks Specification\n\nA language allowing to declare best practices to be adhered on target SAP Infrastructures.","ref":"specification.html","title":"Checks Specification","type":"extras"},{"doc":"The need this Specification aims to fulfill is to provide users a simple way to declare what we (the Trento Team) often refer to as \"Checks\".\n\nChecks are, in Trento's domain, the crystallization of SUSE's best practices when it comes to SAP workloads in a form that both a user ([Spec](#anatomy-of-a-check)) and a machine ([Execution](#checks-execution)) can read.\n\n[^1]: The Trento Team from now on.","ref":"specification.html#introduction","title":"Introduction - Checks Specification","type":"extras"},{"doc":"_Checks Execution_ is the process that determines whether the best practices defined in the [Checks Specifications](#anatomy-of-a-check) are being followed on a target infrastructure.\n\n> [Requesting an Execution](#requesting-an-execution) -> [Facts Gathering](#facts-gathering) -> [Expectation Evaluation](#expectation-evaluation)\n\n#","ref":"specification.html#checks-execution","title":"Checks Execution - Checks Specification","type":"extras"},{"doc":"An Execution can be requested to start by providing Wanda the following information:\n\n- an execution identifier\n- an execution Group identifier\n- the Checks Selection for the targets (a list of checks to be executed on the targets)\n\nWhen the Execution starts running, its current state is stored in the Database and the targets are notified - via the message broker - about Facts to be gathered.\n\nThen the _Execution_ waits for the [Facts Gathering](#facts-gathering) to complete.\n\n#","ref":"specification.html#requesting-an-execution","title":"Requesting an Execution - Checks Specification","type":"extras"},{"doc":"After an _Execution Request_ the targets are notified about the facts they need to [gather](./gatherers.md).\n\nWhenever a target has gathered all the needed facts for an _Execution_, it notifies Wanda - via the message broker - about the _Gathered Facts_.\n\n#","ref":"specification.html#facts-gathering","title":"Facts Gathering - Checks Specification","type":"extras"},{"doc":"_Expectation Evaluation_ is the process of [evaluating](#expression-language) the [Expectations](#expectations)\nusing the received _Gathered Facts_ to obtain the result of a check.\n\nThis will only happen once _Gathered Facts_ are received **from all the targets**.\n\nAfter the result has been determined, the currently `running` Execution transitions to `completed` and its new state is tracked on the Database.\n\nAt this point the Execution is considered **Completed** and interested parties are notified about the Execution Completion.\n\n#","ref":"specification.html#expectation-evaluation","title":"Expectation Evaluation - Checks Specification","type":"extras"},{"doc":"Once an execution is completed, a checks result should give feedback on what aspects of a target infrastructure adhere to the best practices and which don't.\n\nPossible results:\n\n- `passing`, everything ok\n- `warning`, best practice not followed, should fix\n- `critical`, best practice not followed, must fix\n\nSee also [Check Severity](#severity).","ref":"specification.html#checks-results","title":"Checks Results - Checks Specification","type":"extras"},{"doc":"A Check declaration comes in the form of a `yaml` file and all the Checks together build up the **Checks Catalog**\n\nHere's an example:\n\n```yaml\nid: \"156F64\"\nname: Corosync `token` timeout\ngroup: Corosync\ndescription: Corosync `token` timeout is set to the correct value\nremediation: |","ref":"specification.html#anatomy-of-a-check","title":"Anatomy of a Check - Checks Specification","type":"extras"},{"doc":"The value of the Corosync `token` timeout is not set as recommended.","ref":"specification.html#abstract","title":"Abstract - Checks Specification","type":"extras"},{"doc":"Adjust the corosync `token` timeout as recommended...\n\nfacts:\n - name: corosync_token_timeout\n gatherer: corosync.conf\n argument: totem.token\n\nvalues:\n - name: expected_token_timeout\n default: 5000\n conditions:\n - value: 30000\n when: env.provider == \"azure\" || env.provider == \"aws\"\n - value: 20000\n when: env.provider == \"gcp\"\n\nexpectations:\n - name: token_timeout\n expect: facts.corosync_token_timeout == values.expected_token_timeout\n```\n\n#","ref":"specification.html#remediation","title":"Remediation - Checks Specification","type":"extras"},{"doc":"**Note** that a Check's filename **MUST** be in the form ` .yaml` (ie: `156F64.yaml`)\n\n#","ref":"specification.html#filename-convention","title":"Filename Convention - Checks Specification","type":"extras"},{"doc":"Following are listed the top level properties of a Check definition yaml.\n\n| Key | Required/Not Required | Details |\n| -------------- | --------------------- | ------------------------- |\n| `id` | required | [see more](#id) |\n| `name` | required | [see more](#name) |\n| `group` | required | [see more](#group) |\n| `description` | required | [see more](#description) |\n| `remediation` | required | [see more](#remediation) |\n| `severity` | not required | [see more](#severity) |\n| `facts` | required | [see more](#facts) |\n| `values` | not required | [see more](#values) |\n| `expectations` | required | [see more](#expectations) |\n\n---\n\n##","ref":"specification.html#structure","title":"Structure - Checks Specification","type":"extras"},{"doc":"Uniquely identifies a Check in the Catalog\n\nie:\n\n```yaml\nid: \"156F64\"\nid: \"845CC9\"\nid: \"B089BE\"\n```\n\n##","ref":"specification.html#id","title":"id - Checks Specification","type":"extras"},{"doc":"A, preferably one-line, string representing the name for the Check being declared.\n\nie:\n\n```yaml\nname: Corosync `token` timeout\nname: Corosync `consensus` timeout\nname: SBD Startmode\n```\n\n##","ref":"specification.html#name","title":"name - Checks Specification","type":"extras"},{"doc":"A, preferably one-line, string representing the group where the Check being declared belongs.\n\nExample:\n\n```yaml\ngroup: Corosync\ngroup: Pacemaker\ngroup: SBD\n```\n\n##","ref":"specification.html#group","title":"group - Checks Specification","type":"extras"},{"doc":"A text providing a description for the Check being declared.\n\ncan be a one-liner\n\n```yaml\ndescription: Some plain description\n```\n\ncan be a multiline text\n\n```yaml\ndescription: |\n Some plain multiline\n description that carries a lot\n of information\n```\n\nformat is **markdown**\n\n```yaml\ndescription: |\n A `description` is a **markdown**\n```\n\n##","ref":"specification.html#description","title":"description - Checks Specification","type":"extras"},{"doc":"A text providing an comprehensive description about the remediation to apply for the Check being declared.\n\nIt has the same properties of the `description`\n\n- can be a one-liner (it usually is not)\n- can be a multiline (it usually is)\n- format is **markdown**\n\nExample:\n\n```yaml\nremediation: |","ref":"specification.html#remediation","title":"remediation - Checks Specification","type":"extras"},{"doc":"The value of the Corosync `token` timeout is not set as recommended.","ref":"specification.html#abstract","title":"Abstract - Checks Specification","type":"extras"},{"doc":"Adjust the corosync `token` timeout as recommended on the best \n ...\n 2. Reload the corosync configuration:\n ...\n```\n\n##","ref":"specification.html#remediation","title":"Remediation - Checks Specification","type":"extras"},{"doc":"A string determining the severity of the Check being declared, in case the check is not passing, so that the appropriate result is reported.\n\nAllowed values: `warning`, `critical`\n\n**Default:** if no severity is provided, the system would default to `critical`\n\nExample:\n\nReports a `warning` When the Check expectations do not pass\n\n```yaml\nseverity: warning\n```\n\nReports a `critical` When the Check expectations do not pass\n\n```yaml\nseverity: critical\n```\n\n##","ref":"specification.html#severity","title":"severity - Checks Specification","type":"extras"},{"doc":"A boolean determining whether the check is premium or not. It doesn't have any real impact in the check execution itself, it is only an informative field, mostly used by the web frontend.\n\n**Default:** if no premium flag is provided, the system would default to `false`\n\nExample:\n\nSets the check as premium\n\n```yaml\npremium: true\n```\n\n##","ref":"specification.html#premium","title":"premium - Checks Specification","type":"extras"},{"doc":"See main sections [Facts](#facts), [Values](#values), [Expectations](#expectations)","ref":"specification.html#facts-values-expectations","title":"Facts, Values, Expectations - Checks Specification","type":"extras"},{"doc":"Facts are the core data on which the engine evaluates the state of the target infrastructure.\nExamples include (but are not limited to) installed packages, cluster state, and configuration files content.\n\nThe process of determining the value of a declared fact during Check execution is referred to as _Facts Gathering_ and it is the responsibility of the [_Gatherers_](./gatherers.md).\nGatherers could be seen as functions that have a name and accept argument(s).\n\nThat said, a fact declaration contains:\n\n- the fact name\n- the gatherer used to retrieve the fact\n- the argument(s) to be provided to the gatherer\n\n**Note:**\n\n- many facts can be declared\n- all the declared facts would be registered in the [`facts`](#facts-1) namespaced evaluation scope.\n\n```yaml\nfacts:\n - name: \n gatherer: \n argument: \n\n - name: \n gatherer: \n argument: \n```\n\nThe following example declares a **fact** named `corosync_token_timeout`, retrievable via the built-in `corosync.conf` **gatherer** to which will be provided the **argument** `totem.token`\n\n```yaml\nfacts:\n - name: corosync_token_timeout\n gatherer: corosync.conf\n argument: totem.token\n\n # other facts maybe\n```\n\nFinally, gathered facts, are used in Check's [Expectations](#expectations) to determine whether expected conditions are met for the best practice to be adhered.","ref":"specification.html#facts","title":"Facts - Checks Specification","type":"extras"},{"doc":"Values are named variables that may evaluate differently based on the execution context and are used with Facts for _Contextual_ [Expectations](#expectations) Evaluation.\n\n> When contextual expectations is not needed, there's the following options available:\n>\n> - use [**hardcoded**](#hardcoded-values) values\n> - define `values` as [**constants**](#constant-values)\n>\n> Scenario:\n>\n> No matter what the context is, the fact `awesome_fact` MUST always be `wanda`\n\n#","ref":"specification.html#values","title":"Values - Checks Specification","type":"extras"},{"doc":"Direct usage of a simple hardcoded value\n\n```yaml\nexpectations:\n - name: awesome_expectation\n expect: facts.awesome_fact == \"wanda\"\n```\n\n#","ref":"specification.html#hardcoded-values","title":"Hardcoded Values - Checks Specification","type":"extras"},{"doc":"Define a Value with only the `default` specified (**omitting** `conditions`) for **constants** regardless of the context.\n\n```yaml\nvalues:\n - name: awesome_constant_value\n default: \"wanda\"\n\nexpectations:\n - name: awesome_expectation\n expect: facts.awesome_fact == values.awesome_constant_value\n```\n\n#","ref":"specification.html#constant-values","title":"Constant Values - Checks Specification","type":"extras"},{"doc":"This is needed because the same check might expect facts to be treated differently based on the context.\n\n> Let's clarify with an example:\n>\n> A Check might define a fact named `awesome_fact` which is expected to be different given the _color_ of the execution.\n>\n> - it has to be `cat` when the `color` in the execution context is `red`\n> - it has to be `dog` when the `color` in the execution context is `blue`\n> - it has to be `rabbit` in all other cases, regardless of the execution context\n>\n> so we define a named variable `awesome_expectation` that resolves to `cat|dog|rabbit` when proper conditions are met\n>\n> allowing us to have an expectation like this\n>\n> `expect: facts.awesome_fact == values.awesome_expectation`\n\nA Value declaration contains:\n\n- the value name\n- the default value\n- a list of conditions that determine the value given the context (optional, see [constant values](#constant-values))\n\n```yaml\nvalues:\n - name: \n default: \n conditions:\n - value: \n when: \n - value: \n when: \n```\n\nIt could read as:\n\nthe value named ` ` resolves to\n\n- ` ` when ` ` is true\n- ` ` when ` ` is true\n- ` ` in all other cases\n\nExample:\n\n> Check `156F64 Corosync token timeout is set to expected value` defines a fact `corosync_token_timeout` which is expected to be different given the platform (aws/azure/gcp), so we define a named variable `expected_token_timeout` resolving to the appropriate value.\n>\n> `expected_token_timeout` resolves to:\n>\n> - `30000` when `azure`/`aws` are detected\n> - `20000` on `gcp`\n> - `5000` in all other cases (ie: bare metal, VMs...)\n\n```yaml\nvalues:\n - name: expected_token_timeout\n default: 5000\n conditions:\n - value: 30000\n when: env.provider == \"azure\" || env.provider == \"aws\"\n - value: 20000\n when: env.provider == \"gcp\"\n\nexpectations:\n - name: corosync_token_timeout_is_correct\n expect: facts.corosync_token_timeout == values.expected_token_timeout\n```\n\nNote that `conditions` is a cascading chain of contextual inspection to determine which is the resolved value.\n\n- there may be many conditions\n- first condition that passes determines the value, following are not evaluated\n- `when` entry [Expression](#expression-language) has [access](#evaluation-scope) to gathered [facts](#facts-1) and [env](#env) evaluation scopes\n\nAll the _resolved_ declared values would be registered in the [`values`](#values-1) namespaced evaluation scope.","ref":"specification.html#contextual-values","title":"Contextual Values - Checks Specification","type":"extras"},{"doc":"Expectations are assertions on the state of a target infrastructure for a given scenario. By using fact and values they are able to determine if a check passes or not.\n\nAn Expectation declaration contains:\n\n- the expectation name\n- the expectation expression itself with [access](#evaluation-scope) to gathered [facts](#facts-1) and [resolved values](#values-1)\n- an optional [failure message](#failure-message)\n\n```yaml\nexpectations:\n - name: \n expect: \n\n - name: \n expect: \n failure_message: \n\n - name: \n expect_same: \n```\n\nExtra considerations:\n\n- there can be many expectations for a single Check\n- an expectation can be one of two types [`expect`](#expect) or [`expect_same`](#expect_same)\n- a Check passes when all the expectations are satisfied\n\nExample\n\n```yaml\nexpectations:\n - name: token_timeout\n expect: facts.corosync_token_timeout == values.expected_token_timeout\n\n - name: awesome_expectation\n expect: facts.awesome_fact == values.awesome_expected_value\n```\n\nIn the previous example a Checks passes (is successful) if all expectations are met, meaning that\n\n```\nfacts.corosync_token_timeout == values.expected_token_timeout\nAND\nfacts.awesome_fact == values.awesome_expected_value\n```\n\n#","ref":"specification.html#expectations","title":"Expectations - Checks Specification","type":"extras"},{"doc":"This type of expectation is satisfied when, after facts gathering, the expression is `true` for all the targets involved in the current execution.\n\n> Execution Scenario:\n>\n> - 2 targets [`A`, `B`]\n> - selected Checks [`corosync_check`]\n> - some environment (context)\n>\n> ```yaml\n> facts:\n> - name: corosync_token_timeout\n> gatherer: corosync.conf\n> argument: totem.token\n>\n> values: ...\n>\n> expectations:\n> - name: corosync_token_timeout_is_correct\n> expect: facts.corosync_token_timeout == values.expected_token_timeout\n> ```\n\nConsidering the previous scenario what happens is that:\n\n- the fact `corosync_token_timeout` is gathered on all targets (`A` and `B` in this case)\n- the expectation expression gets executed against the `corosync_token_timeout` fact gathered on every targets.\n - `targetA.corosync_token_timeout == values.expected_token_timeout`\n - `targetB.corosync_token_timeout == values.expected_token_timeout`\n- every evaluation has to be `true`\n\n#","ref":"specification.html#expect","title":"expect - Checks Specification","type":"extras"},{"doc":"This type of expectation is satisfied when, after facts gathering, the expression's return value is the same for all the targets involved in the current execution, regardless of the value itself.\n\n> Execution Scenario:\n>\n> - 2 targets [`A`, `B`, `C`]\n> - selected Checks [`some_check`]\n> - some environment (context)\n>\n> ```yaml\n> expectations:\n> - name: awesome_expectation\n> expect_same: facts.awesome_fact\n> ```\n\nConsidering the previous scenario what happens is that:\n\n- the fact `awesome_fact` is gathered on all targets (`A`, `B` and `C` in this case)\n- the expectation expression gets executed for every target involved.\n - `targetA.facts.awesome_fact`\n - `targetB.facts.awesome_fact`\n - `targetC.facts.awesome_fact`\n- the expressions results has to be the same for every target\n - `targetA.facts.awesome_fact == targetB.facts.awesome_fact == targetC.facts.awesome_fact`\n\n> Example:\n>\n> RPM version must be the same on all the targets, regardless of what version it is\n>\n> ```yaml\n> facts:\n> - name: installed_rpm_version\n> gatherer: package_version\n> argument: rpm\n>\n> expectations:\n> - name: installed_rpm_version_must_be_the_same_on_all_targets\n> expect_same: facts.installed_rpm_version\n> ```\n\n#","ref":"specification.html#expect_same","title":"expect_same - Checks Specification","type":"extras"},{"doc":"An optional failure message can be declared for every expectation.\n\nIn case of an `expect` one, the failure message can interpolate `facts` and `values` present in the check definition to provide more meaningful insights:\n\n```yaml\nexpectations:\n - name: awesome_expectation\n expect: values.awesome_constant_value == facts.awesome_fact\n failure_message: The expectation did not match ${values.awesome_constant_value}\n```\n\nThe outcome of the interpolation is available in `ExpectationEvaluation` inside the API response.\n\nIn case of an `expect_same` one, the failure message has to be a plain string:\n\n```yaml\nexpectations:\n - name: awesome_expectation\n expect_same: facts.awesome_fact\n failure_message: Boom!\n```\n\nThis plain string is available in `ExpectationResult` inside the API response.","ref":"specification.html#failure_message","title":"failure_message - Checks Specification","type":"extras"},{"doc":"Different parts of the Check declaration are places where an evaluation is needed.\n\n> Determine to what a [value](#values) resolves during execution\n>\n> `when: ` part of a Value's condition\n\n```yaml\nvalues:\n - name: expected_token_timeout\n default: 5000\n conditions:\n - value: 30000\n when: env.provider == \"azure\" || env.provider == \"aws\"\n - value: 20000\n when: env.provider == \"gcp\"\n```\n\n> Defining the [Expectation](#expectations) of a Check\n>\n> `expect|expect_same: `\n\n```yaml\nexpectations:\n - name: token_timeout\n expect: facts.corosync_token_timeout == values.expected_token_timeout\n```\n\nSee [reference for the Expression Language](./expression_language.md).\n\n#","ref":"specification.html#expression-language","title":"Expression Language - Checks Specification","type":"extras"},{"doc":"Every expression has access to an evaluation scope, allowing to access relevant piece of information to run the expression.\n\nScopes are namespaced and access to items in the scope is name based.\n\n#### **env**\n\n`env` is a map of information about the context of the running execution, it is set by the system on each execution/check compilation.\n\nExamples of entries in the scope. What is actually available during the execution depends on the scenario. Find the updated values in the reference column link.\n\n| name | Type | Reference\n| ---- | -----| ----------\n| `env.provider` | one of `azure`, `aws`, `gcp`,`kvm`,`nutanix`, `vmware`, `unknown` | [Providers](https://github.com/trento-project/web/blob/main/lib/trento/domain/enums/provider.ex)\n| `env.cluster_type` | one of `hana_scale_up`, `hana_scale_out`, `ascs_ers`, `unknown` | [Cluster types](https://github.com/trento-project/web/blob/main/lib/trento/domain/enums/cluster_type.ex)\n| `env.target_type` | one of `cluster`, `host` | No enum available\n\n#### **facts**\n\n`facts` is the map of the gathered facts, thus the scope varies based on which facts have been declared in the [relative section](#facts), and are accessible in other sections by fact name.\n\n```yaml\nfacts:\n - name: an_interesting_fact\n gatherer: \n argument: \n\n - name: another_interesting_fact\n gatherer: \n argument: \n```\n\nAvailable entries in scope, the value is what has been gathered on the targets\n| name \n| -----------------------------\n| `facts.an_interesting_fact` \n| `facts.another_interesting_fact`\n\n#### **values**\n\n`values` is the map of resolved variable names defined in the [relative section](#values)\n\n```yaml\nvalues:\n - name: expected_token_timeout\n default: 5000\n conditions:\n - value: 30000\n when: env.provider == \"azure\" || env.provider == \"aws\"\n - value: 20000\n when: env.provider == \"gcp\"\n\n - name: another_variable_value\n default: \"blue\"\n conditions:\n - value: \"red\"\n when: env.should_be_red == true\n```\n\nAvailable entries in scope\n| name | Resolved to \n| ------------------------------- | -------------------------------------------------------\n| `values.expected_token_timeout` | `5000`, `30000`, `20000` based on the conditions\n| `values.another_variable_value` | `blue`, `red` based on the conditions","ref":"specification.html#evaluation-scope","title":"Evaluation Scope - Checks Specification","type":"extras"},{"doc":"To have a standardized format for writing checks, follow the next best practices and conventions as much as possible:\n\n- The `id` field must be wrapped in double quotes to avoid any type of ambiguity, as this field must be of string format.\n- The remaining `name`, `description`, `group`, and `remediation` fields must not be wrapped in quotes, as they are text-based values always.\n- Take advantage of markdown tags in the `name`, `description`, and `remediation` fields to make the text easy and compelling to read.\n- The `name` field of `facts`, `values`, and `expectations` must follow `camel_case` format. \n For example:\n ```\n facts:\n - name: some_fact\n ...\n values:\n - name: expected_some_fact\n ...\n expectations:\n - name: some_expectation\n ...\n ```\n- Use 2 spaces to indent multiline expectation expressions.\n- Naming hardcoded values in the `values` section with the `default` field is encouraged instead of putting hardcoded values in the expectation expression itself. This gives some meaning to the expected value and improves potential interaction with the Wanda API. \n So this:\n\n ```\n expectations:\n - name: some_expectation\n expect: facts.foo == 30\n ```\n\n would be:\n\n ```\n values:\n - name: expected_foo\n default: 30\n\n expectations:\n - name: some_expectation\n expect: facts.foo == values.expected_foo\n ```\n\n- If the gathered fact is compared to a value, using `value` and `expected_value` names for facts and values respectively is recommended, as it improves the meaning of the comparison. \n For example:\n ```\n facts:\n - name: some_fact\n ...\n values:\n - name: expected_some_fact\n ...\n ```\n- Avoid adding prefixes such as `facts` or `values` to the entries of these sections, as they already use this as a namespace.\n For example, the next example should be avoided, as the `facts` prefix would be redundant in the expectation expression:\n ```\n facts:\n - name: facts_some_fact\n ```\n- If the implemented expectation expression contains any kind of `&&` to combine multiple operations, consider adding them as individual expectations, as the final result is the combination of all of them. \n So this:\n ```\n expectations:\n - name: some_expectation\n expect: facts.foo == values.expected_foo && facts.bar == values.expected_bar\n ```\n would be:\n ```\n expectations:\n - name: foo_expectation\n expect: facts.foo == values.expected_foo\n - name: bar_expectation\n expect: facts.bar == values.expected_bar\n ```\n- Pipe the expression language functions vertically in order to provide a better visual output of the code. \n So this:\n ```\n expectations:\n - name: some_expectation\n expect: facts.foo.find(|item| item.id == \"super\").properties.find(|prop| prop.name == \"good\").value\n ```\n would be:\n ```\n expectations:\n - name: some_expectation\n expect: |\n facts.foo\n .find(|item| item.id == \"super\").properties\n .find(|prop| prop.name == \"good\").value\n ```\n > Note: Keep in mind that some functions such as `sort` and `drain` run in-place modifications, so they cannot be piped.","ref":"specification.html#best-practices-and-conventions","title":"Best practices and conventions - Checks Specification","type":"extras"},{"doc":"# Expression Language\n\nA small, fast, easy-to-use scripting language and evaluation engine.","ref":"expression_language.html","title":"Expression Language","type":"extras"},{"doc":"An embedded scripting language and evaluation engine for Trento Checks Expressions that gives a safe and easy way to script specific steps during Checks Execution.","ref":"expression_language.html#introduction","title":"Introduction - Expression Language","type":"extras"},{"doc":"| Type | Example |\n| ------------------------------ | ------------------------ |\n| **Nothing/void/nil/null/Unit** | `()` |\n| **Integer** | `42`, `123` |\n| **Float** | `123.4567` |\n| **Boolean** | `true` or `false` |\n| **String** | `\"hello\"` |\n| **Array** | `[ 1, 2, 3, \"foobar\" ]` |\n| **Map** | `#{ \"a\": 1, \"b\": true }` |","ref":"expression_language.html#types","title":"Types - Expression Language","type":"extras"},{"doc":"| Operator | Description (`x` _operator_ `y`) | `x`, `y` same type or are numeric | `x`, `y` different types |\n| :------: | ------------------------------------ | :-------------------------------: | :----------------------: |\n| `==` | `x` is equals to `y` | error if not defined | `false` if not defined |\n| `!=` | `x` is not equals to `y` | error if not defined | `true` if not defined |\n| `>` | `x` is greater than `y` | error if not defined | `false` if not defined |\n| `>=` | `x` is greater than or equals to `y` | error if not defined | `false` if not defined |\n| `<` | `x` is less than `y` | error if not defined | `false` if not defined |\n| `<=` | `x` is less than or equals to `y` | error if not defined | `false` if not defined |\n\n#","ref":"expression_language.html#logic-operators-and-boolean","title":"Logic Operators and Boolean - Expression Language","type":"extras"},{"doc":"Comparing two values of _different_ data types defaults to `false`.\n\nThe exception is `!=` (not equals) which defaults to `true`. This is in line with intuition.\n\n```ts\n42 > \"42\"; // false: i64 cannot be compared with string\n42 <= \"42\"; // false: i64 cannot be compared with string\nts == 42; // false: different types cannot be compared\nts != 42; // true: different types cannot be compared\n```\n\n#","ref":"expression_language.html#comparing-different-types-defaults-to-false","title":"Comparing different types defaults to `false` - Expression Language","type":"extras"},{"doc":"| Operator | Description | Arity | Short-circuits? |\n| :---------------: | :---------: | :----: | :-------------: |\n| `!` _(prefix)_ | _NOT_ | unary | no |\n| `&&` | _AND_ | binary | yes |\n| `&` | _AND_ | binary | no |\n| \\|\\| | _OR_ | binary | yes |\n| \\| | _OR_ | binary | no |\n\nDouble boolean operators `&&` and `||` _short-circuit_ – meaning that the second operand will not be evaluated\nif the first one already proves the condition wrong.\n\nSingle boolean operators `&` and `|` always evaluate both operands.\n\n```ts\na() || b(); // b() is not evaluated if a() is true\na() && b(); // b() is not evaluated if a() is false\na() | b(); // both a() and b() are evaluated\na() & b(); // both a() and b() are evaluated\n```","ref":"expression_language.html#boolean-operators","title":"Boolean Operators - Expression Language","type":"extras"},{"doc":"`if` statements follow C syntax.\n\n```ts\nif foo(x) {\n print(\"It's true!\");\n} else if bar == baz {\n print(\"It's true again!\");\n} else if baz.is_foo() {\n print(\"Yet again true.\");\n} else if foo(bar - baz) {\n print(\"True again... this is getting boring.\");\n} else {\n print(\"It's finally false!\");\n}\n```\n\n> Unlike C, the condition expression does _not_ need to be enclosed in parentheses `(`...`)`, but all\n> branches of the `if` statement must be enclosed within braces `{`...`}`, even when there is only\n> one statement inside the branch.\n> Like Rust, there is no ambiguity regarding which `if` clause a branch belongs to.\n>\n> ```ts\n> // not C!\n> if (decision) print(42);\n> // ^ syntax error, expecting '{'\n> ```\n\n#","ref":"expression_language.html#if-statement","title":"If Statement - Expression Language","type":"extras"},{"doc":"`if` statements can also be used as _expressions_, replacing the `? :` conditional\noperators in other C-like languages.\n\n```ts\n// The following is equivalent to C: int x = 1 + (decision ? 42 : 123) / 2;\nlet x = 1 + if decision { 42 } else { 123 } / 2;\nx == 22;\nlet x = if decision { 42 }; // no else branch defaults to '()'\nx == ();\n```","ref":"expression_language.html#if-expression","title":"If Expression - Expression Language","type":"extras"},{"doc":"All elements stored in an array are dynamic, and the array can freely grow or shrink with elements\nadded or removed.\n\nArray literals are built within square brackets `[` ... `]` and separated by commas `,`:\n\n> `[` _value_`,` _value_`,` ... `,` _value_ `]`\n>\n> `[` _value_`,` _value_`,` ... `,` _value_ `,` `]` `// trailing comma is OK`\n\n```ts\nlet some_list = [1, 2, 3];\n\nlet another_list = [\"foo\", \"bar\", 42];\n```\n\n#","ref":"expression_language.html#arrays","title":"Arrays - Expression Language","type":"extras"},{"doc":"Like C, arrays are accessed with zero-based, non-negative integer indices:\n\n> _array_ `[` _index position from 0 to length−1_ `]`\n\n```ts\nlet some_list = [\"foo\", \"bar\", 42];\n\nlet second_element = some_list[1];\n\n// second_element is \"bar\"\n```\n\n#","ref":"expression_language.html#access-element-from-beginning","title":"Access Element From beginning - Expression Language","type":"extras"},{"doc":"A _negative_ position accesses an element in the array counting from the _end_, with −1 being the\n_last_ element.\n\n> _array_ `[` _index position from −1 to −length_ `]`\n\n```ts\nlet some_list = [\"foo\", \"bar\", 42];\n\nlet second_element = some_list[-2];\nlet last_element = some_list[-1];\n\n// second_element is \"bar\"\n// last_element is 42\n```\n\n| Function | Parameter(s) | Description |\n| -------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `get` | position, counting from end if array item _(optional)_ offset position |\n| `all` | predicate (usually a closure) | returns `true` if all items return `true` when called with the predicate function taking the following parameters: array item _(optional)_ offset position |\n\nExamples\n\n```ts\nlet some_list = [1, 2, 3, 4, \"foo\", \"bar\"];\n\nlet foo = some_list.get(4); // \"foo\"\n\nlet items_count = some_list.len(); // 6\n\nlet only_foo_and_bar = some_list.filter(|item| item == \"foo\" || item == \"bar\"); // [\"foo\", \"bar\"]\n// let only_foo_and_bar = some_list.filter(|item, idex_in_array| item == \"foo\" || item == \"bar\");\n\nlet another_list = [3, 5, 7, 9, 10, 20, 30];\n\nlet all_greater_than_2 = another_list.all(|item| item > 2); // true\nlet all_greater_than_10 = another_list.all(|item| item > 10); // false\n// let all_greater_than_10 = another_list.all(|item, idex_in_array| item > 10);\n```","ref":"expression_language.html#access-element-from-end","title":"Access Element From end - Expression Language","type":"extras"},{"doc":"Maps are hash dictionaries. Properties are all dynamic values and can be freely added and retrieved.\n\nMap literals are built within braces `#{` ... `}` with _name_`:`_value_ pairs separated by\ncommas `,`:\n\n> `#{` _property_ `:` _value_`,` ... `,` _property_ `:` _value_ `}`\n>\n> `#{` _property_ `:` _value_`,` ... `,` _property_ `:` _value_ `,` `}` `// trailing comma is OK`\n\n```ts\nlet some_map = #{ // map literal with 2 properties\n foo: 42,\n bar: \"hello\",\n};\n```\n\n#","ref":"expression_language.html#maps","title":"Maps - Expression Language","type":"extras"},{"doc":"The _dot notation_ allows to access properties by name.\n\n> _object_ `.` _property_\n\n```ts\nlet some_map = #{ // map literal with 2 properties\n foo: 42,\n bar: \"hello\",\n};\n\nsome_map.foo // 42\nsome_map.bar // \"hello\"\n\n```\n\n#","ref":"expression_language.html#dot-notation","title":"Dot notation - Expression Language","type":"extras"},{"doc":"Trying to read a non-existing property returns an error.\n\n```ts\nlet some_map = #{ // map literal with 2 properties\n foo: 42,\n bar: \"hello\",\n};\n\nsome_map.another_property // returns \"Property not found: another_property (line X, position Y)\"\n```\n\n#","ref":"expression_language.html#non-existing-property","title":"Non-existing property - Expression Language","type":"extras"},{"doc":"```ts\nlet some_map = #{ // map literal with 2 properties\n foo: 42,\n bar: \"hello\",\n rabbits: [\n #{\n name: \"wanda\",\n power: 9001\n },\n #{\n name: \"tonio\",\n power: 9002\n },\n #{\n name: \"weak_rabbit\",\n power: 8999\n }\n ]\n};\n\n// Tell me how many strong rabbits are there\nlet strong_rabbits = some_map.rabbits.filter(|rabbit| rabbit.power > 9000).len() // 2\n\nlet rabbits = some_map.rabbits\n\nlet all_rabbits_are_strong = rabbits.all(|rabbit| rabbit.power > 9000) // false, unfortunately\n\n```","ref":"expression_language.html#a-more-complex-example","title":"A more complex example - Expression Language","type":"extras"},{"doc":"For extra information about the underlying scripting language see [Rhai](https://rhai.rs/book/language/).","ref":"expression_language.html#rhai","title":"Rhai - Expression Language","type":"extras"},{"doc":"# Gatherers","ref":"gatherers.html","title":"Gatherers","type":"extras"},{"doc":"Gatherers can be thought of as functions:\n\n- they have a name\n- they accept argument(s)\n- they return a value, the gathered [Fact](./specification.md#facts)\n\nFacts Gathering process in a nutshell\n\n```\nfact = gatherer(argument)\n```","ref":"gatherers.html#introduction","title":"Introduction - Gatherers","type":"extras"},{"doc":"Here's a collection of built-in gatherers, with information about how to use them.\n\n| Name | Implementation |\n| :-------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| [`cibadmin`](#cibadmin) | [trento-project/agent/../gatherers/cibadmin.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/cibadmin.go) |\n| [`corosync.conf`](#corosyncconf) | [trento-project/agent/../gatherers/corosyncconf.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/corosyncconf.go) |\n| [`corosync-cmapctl`](#corosync-cmapctl) | [trento-project/agent/../gatherers/corosynccmapctl.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/corosynccmapctl.go) |\n| [`dir_scan`](#dir_scan) | [trento-project/agent/../gatherers/dir_scan.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/dir_scan.go) |\n| [`fstab`](#fstab) | [trento-project/agent/../gatherers/fstab.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/fstab.go) |\n| [`groups`](#groups) | [trento-project/agent/../gatherers/groups.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/groups.go) |\n| [`hosts`](#hosts-etchosts) | [trento-project/agent/../gatherers/hostsfile.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/hostsfile.go) |\n| [`package_version`](#package_version) | [trento-project/agent/../gatherers/packageversion.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/packageversion.go) |\n| [`passwd`](#passwd) | [trento-project/agent/../gatherers/passwd.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/passwd.go) |\n| [`sapcontrol`](#sapcontrol) | [trento-project/agent/../gatherers/sapcontrol.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sapcontrol.go) |\n| [`saphostctrl`](#saphostctrl) | [trento-project/agent/../gatherers/saphostctrl.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/saphostctrl.go) |\n| [`sap_profiles`](#sap_profiles) | [trento-project/agent/../gatherers/sapprofiles.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sapprofiles.go) |\n| [`saptune`](#saptune) | [trento-project/agent/../gatherers/saptune.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/saptune.go) |\n| [`sbd_config`](#sbd_config) | [trento-project/agent/../gatherers/sbd.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sbd.go) |\n| [`sbd_dump`](#sbd_dump) | [trento-project/agent/../gatherers/sbddump.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sbddump.go) |\n| [`sysctl`](#sysctl) | [trento-project/agent/../gatherers/sysctl.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sysctl.go) |\n| [`systemd`](#systemd) | [trento-project/agent/../gatherers/systemd.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/systemd.go) |\n| [`verify_password`](#verify_password) | [trento-project/agent/../gatherers/verifypassword.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/verifypassword.go) |\n\n#","ref":"gatherers.html#available-gatherers","title":"Available Gatherers - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows accessing Pacemaker's CIB information, the output of the `cibadmin` command more precisely.\nAs the `cibadmin` command output is in XML format, the gatherer converts it to map/dictionary type format, so the fields are available with the normal dot access way.\nSome specific fields, such as `primitive`, `clone`, `master`, etc (find the complete list [here](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/cibadmin.go#L48)) are converted to lists, in order to avoid differences when the field appears one or multiple times.\n\nExample arguments:\n\n| Name | Return value |\n| :------------------------------------------------------------- | :----------------------------------------------------------------- |\n| `cib.configuration` | complete cib configuration entry as a map |\n| `cib.configuration.resources.primitive.0` | first available primitive resource |\n| `cib.configuration.crm_config.cluster_property_set.0.nvpair.1` | second nvpair value from the first element of cluster_property_set |\n\nExample specification:\n\n```yaml\nfacts:\n - name: cib_configuration\n gatherer: cibadmin\n argument: cib.configuration\n\n - name: first_primitive\n gatherer: cibadmin\n argument: cib.configuration.resources.primitive.0\n\n - name: first_cluster_property_set_second_nvpair\n gatherer: cibadmin\n argument: cib.configuration.crm_config.cluster_property_set.0.nvpair.1\n```\n\nExample output (in Rhai):\n\n```ts\n// first_primitive\n#{\n class: \"stonith\",\n id: \"stonith-sbd\",\n instance_attributes: #{\n id: \"stonith-sbd-instance_attributes\",\n nvpair: [#{\n id: \"stonith-sbd-instance_attributes-pcmk_delay_max\",\n name: \"pcmk_delay_max\",\n value: \"30s\"\n }]\n },\n type: \"external/sbd\"\n};\n\n// first_cluster_property_set_second_nvpair\n#{\n id: \"cib-bootstrap-options-dc-version\",\n name: \"dc-version\",\n value: \"2.0.4+20200616.2deceaa3a-3.12.1-2.0.4+20200616.2deceaa3a\"\n};\n```\n\n#","ref":"gatherers.html#cibadmin","title":"cibadmin - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows accessing the information contained in `/etc/corosync/corosync.conf`\n\nExample arguments:\n\n| Name | Return value |\n| :---------------------------------- | -------------------------------------- |\n| `totem.token` | extracted value from the config |\n| `totem.join` | extracted value from the config |\n| `nodelist.node. .nodeid` | extracted value from the config |\n| `nodelist.node` | list of objects representing the nodes |\n\nExample specification:\n\n```yaml\nfacts:\n - name: corosync_token_timeout\n gatherer: corosync.conf\n argument: totem.token\n\n - name: corosync_join\n gatherer: corosync.conf\n argument: totem.join\n\n - name: corosync_node_id_0\n gatherer: corosync.conf\n argument: nodelist.node.0.nodeid\n\n - name: corosync_node_id_1\n gatherer: corosync.conf\n argument: nodelist.node.1.nodeid\n\n - name: corosync_nodes\n gatherer: corosync.conf\n argument: nodelist.node\n```\n\nExample output (in Rhai):\n\n```ts\n// corosync_token_timeout\n30000;\n\n// corosync_join\n60;\n\n// corosync_node_id_0\n1;\n\n// corosync_node_id_1\n2;\n\n// corosync_nodes\n[#{nodeid: 1, ring0_addr: \"192.168.157.10\"}, #{nodeid: 2, ring0_addr: \"192.168.157.11\"}];\n```\n\nFor extra information refer to [trento-project/agent/../gatherers/corosyncconf_test.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/corosyncconf_test.go)\n\n#","ref":"gatherers.html#corosync-conf","title":"corosync.conf - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nThis gatherer allows accessing the output of the `corosync-cmapctl` tool. It supports all of the keys returned by it to be queried.\n\nExample arguments:\n\n| Name | Return value |\n| :---------------------------------- | :------------------------------- |\n| `totem.token` | extracted value from the command |\n| `runtime.config.totem.token` | extracted value from the command |\n| `totem.transport` | extracted value from the command |\n| `runtime.config.totem.max_messages` | extracted value from the command |\n| `nodelist.node.0.ring0_addr` | extracted value from the command |\n| `nodelist.node` | extracted value from the command |\n| `nodelist.node.1` | extracted value from the command |\n\nExample specification:\n\n```yaml\nfacts:\n - name: totem_token\n gatherer: corosync-cmapctl\n argument: totem.token\n\n - name: runtime_totem_token\n gatherer: corosync-cmapctl\n argument: runtime.config.totem.token\n\n - name: totem_transport\n gatherer: corosync-cmapctl\n argument: totem.transport\n\n - name: totem_max_messages\n gatherer: corosync-cmapctl\n argument: runtime.config.totem.max_messages\n\n - name: node_0_ring0addr\n gatherer: corosync-cmapctl\n argument: nodelist.node.0.ring0_addr\n\n - name: node_list\n gatherer: corosync-cmapctl\n argument: nodelist.node\n \n - name: second_node\n gatherer: corosync-cmapctl\n argument: nodelist.node.1\n```\n\nExample output (in Rhai):\n\n```ts\n// totem_token\n30000;\n\n// runtime_totem_token\n30000;\n\n// totem_transport\n\"udpu\";\n\n// totem_max_messages\n20;\n\n// node_0_ring0addr\n\"10.80.1.11\";\n\n// node_list\n#{\n \"0\": #{\n nodeid: 1,\n ring0_addr: \"10.80.1.11\"\n },\n \"1\": #{\n nodeid: 2,\n ring0_addr: \"10.80.1.12\"\n }\n};\n\n// second_node\n#{ nodeid: 2, ring0_addr: \"10.80.1.12\" };\n```\n\n#","ref":"gatherers.html#corosync-cmapctl","title":"corosync-cmapctl - Gatherers","type":"extras"},{"doc":"**Argument required**: Yes\n\nThis gatherer allows to scan directories with a glob pattern provided as argument.\nThe gatherer returns a list of files matched by the pattern with group/user information associated to each file.\n\nExample argument:\n\n- `/usr/sap/[A-Z][A-Z0-9][A-Z0-9]/ERS[0-9][0-9]`\n- `/etc/polkit-1/rules.d/[0-9][0-9]-SAP[A-Z][A-Z0-9][A-Z0-9]-[0-9][0-9].rules`\n\nExample specification:\n\n```yaml\nfacts:\n - name: dir_scan\n gatherer: dir_scan\n argument: \"/usr/sap/[A-Z][A-Z0-9][A-Z0-9]/ERS[0-9][0-9]\"\n```\n\nExample output (in Rhai):\n\n```ts\n [\n #{\n \"name\": \"/usr/sap/PRD/ERS01\",\n \"owner\": \"trento\",\n \"group\": \"trento\"\n },\n #{\n \"name\": \"/usr/sap/QAS/ERS02\",\n \"owner\": \"trento\",\n \"group\": \"trento\"\n },\n ]\n```\n\n#","ref":"gatherers.html#dir_scan","title":"dir_scan - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows access to the /etc/fstab file, returning all entries available at the file.\n\nExample specification:\n\n```yaml\nfacts:\n - name: fstab\n gatherer: fstab\n```\n\nExample output (in Rhai):\n\n```ts\n[\n #{\n \"device\": \"/dev/system/root\",\n \"mount_point\": \"/\",\n \"file_system_type\": \"btrfs\",\n \"options\": [],\n \"backup\": 0,\n \"check_order\": 1,\n },\n #{\n \"device\": \"/dev/system/root\",\n \"mount_point\": \"/home\",\n \"file_system_type\": \"ext4\",\n \"options\": [\"defaults\"],\n \"backup\": 0,\n \"check_order\": 1,\n },\n ...\n];\n```\n\n#","ref":"gatherers.html#fstab","title":"fstab - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows access to the /etc/group file, returning all entries available at the file.\n\nExample specification:\n\n```yaml\nfacts:\n - name: groups\n gatherer: groups\n```\n\nExample output (in Rhai):\n\n```ts\n[\n #{\n \"name\": \"root\",\n \"gid\": 0,\n \"users\": [],\n },\n #{\n \"name\": \"adm\",\n \"gid\": 1,\n \"users\": [\"trento\"],\n }\n ...\n];\n```\n\n#","ref":"gatherers.html#groups","title":"groups - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows accessing the hostnames that are resolvable through `/etc/hosts`. It\ndoes **not** use domain resolution in any way but instead directly parses the file.\n\nIt allows one argument to be specified or none at all:\n\n- When a hostname is provided as an argument, the gatherer will return an array of IPv4 and/or IPv6 addresses.\n- When no argument is provided, the gatherer will return a map with hostname as keys and arrays with IPv4 and/or IPv6 addresses.\n\nExample arguments:\n\n| Name | Return value |\n| :--------------------- | :---------------------------------- |\n| `localhost` | list of IPs resolving |\n| `node1` | list of IPs resolving |\n| `no argument provided` | map with hostnames and IP addresses |\n\nExample specification:\n\n```yaml\nfacts:\n - name: hosts_node1\n gatherer: hosts\n argument: node1\n\n - name: hosts_node2\n gatherer: hosts\n argument: node2\n\n - name: hosts_all\n gatherer: hosts\n```\n\nExample output (in Rhai):\n\n```ts\n// hosts_node1\n[\"127.0.0.1\", \"::1\"];\n\n// hosts_node2\n[\"192.168.157.11\"];\n\n// hosts_all\n#{\n \"localhost\": [\"127.0.0.1\", \"::1\"],\n \"node1\": [\"192.168.157.10\"],\n \"node2\": [\"192.168.157.11\"],\n ...\n};\n```\n\n#","ref":"gatherers.html#hosts-etc-hosts","title":"hosts (/etc/hosts) - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nThis gatherer supports two usecases:\n\n- get information about the installed versions of the specified package.\n- compare a given version string against the latest installed version of a given package.\n\nIn the first usecase a list of objects is returned, where each object carries relevant information about an installed version of a package.\n\n> Note:\n>\n> - a list of one element is often expected since usually the installed version would be only one\n> - detected installed versions list is ordered by descending installation time: **latest installed versions come first**\n> - operating on the latest installed version requires accessing the first element in the list via `package_fact_name[0]` or `package_fact_name.first()`\n\nIn the second usecase, the return value is as follows (see additional details [here](https://fedoraproject.org/wiki/Archive:Tools/RPM/VersionComparison#The_rpmvercmp_algorithm)):\n\n- A value of `0` if the provided version string matches the installed package version for the requested package.\n- A value of `-1` if the provided version string is older that what's currently installed.\n- A value of `1` if the provided version string is newer than what's currently installed.\n\n> The latest detected installed version is used for comparison\n\nNaming the facts / expectations accordingly is specially important here to avoid confusion.\n\n- We suggest using a `compare_` prefix for package version comparisons and `package_` to retrieve\n a package version\n\nAdditionally, when using the version comparison, it increases readability to explicitly mention\nthe values to compare against:\n\n```yaml\nfacts:\n - name: compare_package_corosync\n gatherer: package_version\n argument: corosync,2.4.5\n\n - name: package_corosync\n gatherer: package_version\n argument: corosync\n\n - name: package_sbd\n gatherer: package_version\n argument: sbd\n\nvalues:\n - name: greater_than_installed\n default: 1\n - name: lesser_than_installed\n default: -1\n - name: same_as_installed\n default: 0\n - name: expected_corosync_version\n default: \"2.4.5\"\n\nexpectations:\n - name: compare_package_corosync\n expect: facts.compare_package_corosync == values.greater_than_installed\n\n - name: package_corosync_is_the_expected_one\n expect: facts.package_corosync.first().version == values.expected_corosync_version\n\n - name: sbd_version_same_on_all_hosts\n expect_same: facts.package_sbd.first().version\n```\n\nExample arguments:\n\n| Name | Return value |\n| :------------------- | :---------------------------------------------------------------------------- |\n| `package_name` | a list containing information about the installed versions of the rpm package |\n| `package_name,2.4.5` | an integer with a value of `-1`, `0` or `1` (see above) |\n\nExample specification:\n\n```yaml\nfacts:\n - name: package_corosync\n gatherer: package_version\n argument: corosync\n\n - name: package_pacemaker\n gatherer: package_version\n argument: pacemaker\n\n - name: multiple_sbd_versions_installed\n gatherer: package_version\n argument: sbd\n\n - name: compare_package_corosync\n gatherer: package_version\n argument: corosync,2.4.5\n\n ...\n```\n\nExample output (in Rhai):\n\n```ts\n// package_corosync\n[\n #{\n \"version\": \"2.4.5\"\n }\n]\n\n// package_pacemaker\n[\n #{\n \"version\": \"2.0.4+20200616.2deceaa3a\"\n }\n]\n\n// multiple_sbd_versions_installed\n[\n #{\n \"version\": \"1.5.1\" // latest installed version, not necessarily the newest one\n },\n #{\n \"version\": \"1.5.2\"\n }\n]\n\n// compare_package_corosync\n0\n```\n\n#","ref":"gatherers.html#package_version","title":"package_version - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows access to the /etc/passwd file, returning all entries available at the file.\n\nExample specification:\n\n```yaml\nfacts:\n - name: passwd\n gatherer: passwd\n```\n\nExample output (in Rhai):\n\n```ts\n[\n #{\n \"description\": \"bin\",\n \"gid\": 1,\n \"home\": \"/bin\",\n \"shell\": \"/sbin/nologin\",\n \"uid\": 1,\n \"user\": \"bin\"\n },\n #{\n \"description\": \"Chrony Daemon\",\n \"gid\": 475,\n \"home\": \"/var/lib/chrony\",\n \"shell\": \"/bin/false\",\n \"uid\": 474,\n \"user\": \"chrony\"\n },\n #{\n \"description\": \"Daemon\",\n \"gid\": 2,\n \"home\": \"/sbin\",\n \"shell\": \"/sbin/nologin\",\n \"uid\": 2,\n \"user\": \"daemon\"\n },\n ...\n];\n```\n\n#","ref":"gatherers.html#passwd","title":"passwd - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nThis gatherer allows access to certain webmethods that `sapcontrol` implements. An argument is required to specify which webmethod should be called. The communication with `sapcontrol` is created opening a unix socket connection using the file `/tmp/.sapstream5xx13`. The [Sapcontrol Web Service Interface](https://www.sap.com/documents/2016/09/0a40e60d-8b7c-0010-82c7-eda71af511fa.html) documents the SOAP API interface, including all the possible values each of the fields could have, specifically helpful for enumerators like `dispstatus` in `GetProcessList` and `state/category` in `HACheckConfig` webmethod.\n\nThe return value is grouped by discovered SIDs, which include the list of command outputs for each instance in this system.\n\nSupported webmethods:\n\n- `GetProcessList`\n- `GetSystemInstanceList`\n- `GetVersionInfo`\n- `HACheckConfig`\n- `HAGetFailoverConfig`\n\n\n\nExample specification:\n\n```yaml\nfacts:\n - name: processes\n gatherer: sapcontrol\n argument: GetProcessList\n\n - name: instances\n gatherer: sapcontrol\n argument: GetSystemInstanceList\n```\n\nExample output (in Rhai):\n\n```ts\n// GetProcessList\n#{\n \"NWP\": [\n #{\n \"instance_nr\": \"10\",\n \"name\": \"ERS10\",\n \"output\": [\n #{\n \"description\": \"EnqueueReplicator\",\n \"dispstatus\": \"SAPControl-GREEN\",\n \"elapsedtime\": \"266:08:15\",\n \"name\": \"enrepserver\",\n \"pid\": 7221,\n \"starttime\": \"2023 09 29 09:41:41\",\n \"textstatus\": \"Running\"\n }\n ]\n }\n ]\n} \n\n// GetSystemInstanceList\n#{\n \"NWP\": [\n #{\n \"instance_nr\": \"10\",\n \"name\": \"ERS10\",\n \"output\": [\n #{\n \"dispstatus\": \"SAPControl-GREEN\",\n \"features\": \"MESSAGESERVER|ENQUE\",\n \"hostname\": \"sapnwpas\",\n \"http_port\": 50013,\n \"https_port\": 50014,\n \"instance_nr\": 0,\n \"start_priority\": \"1\"\n },\n #{\n \"dispstatus\": \"SAPControl-GREEN\",\n \"features\": \"ENQREP\",\n \"hostname\": \"sapnwper\",\n \"http_port\": 51013,\n \"https_port\": 51014,\n \"instance_nr\": 10,\n \"start_priority\": \"0.5\"\n },\n ...\n ]\n }\n ]\n} \n\n// GetVersionInfo\n#{\n \"NWP\": [\n #{\n \"instance_nr\": \"10\",\n \"name\": \"ERS10\",\n \"output\": [\n #{\n \"architecture\": \"linuxx86_64\",\n \"build\": \"optU (Oct 16 2021, 00:03:15)\",\n \"changelist\": \"2094654\",\n \"filename\": \"/usr/sap/NWP/ERS10/exe/sapstartsrv\",\n \"patch\": \"900\",\n \"rks_compatibility_level\": \"1\",\n \"sap_kernel\": \"753\",\n \"time\": \"2021 10 15 22:14:31\"\n },\n #{\n \"architecture\": \"linuxx86_64\",\n \"build\": \"optU (Oct 16 2021, 00:03:15)\",\n \"changelist\": \"2094654\",\n \"filename\": \"/usr/sap/NWP/ERS10/exe/gwrd\",\n \"patch\": \"900\",\n \"rks_compatibility_level\": \"1\",\n \"sap_kernel\": \"753\",\n \"time\": \"2021 10 15 22:04:14\"\n },\n ...\n ]\n }\n ]\n}\n\n// HACheckConfig\n#{\n \"NWP\": [\n #{\n \"instance_nr\": \"10\",\n \"name\": \"ERS10\",\n \"output\": [\n #{\n \"category\": \"SAPControl-SAP-CONFIGURATION\",\n \"comment\": \"2 ABAP instances detected\",\n \"description\": \"Redundant ABAP instance configuration\",\n \"state\": \"SAPControl-HA-SUCCESS\"\n },\n #{\n \"category\": \"SAPControl-SAP-CONFIGURATION\",\n \"comment\": \"0 Java instances detected\",\n \"description\": \"Redundant Java instance configuration\",\n \"state\": \"SAPControl-HA-SUCCESS\"\n },\n ...\n ]\n }\n ]\n}\n\n//HAGetFailoverConfig\n#{\n \"NWP\": [\n #{\n \"instance_nr\": \"10\",\n \"name\": \"ERS10\",\n \"output\": #{\n \"ha_active\": false,\n \"ha_active_nodes\": \"\",\n \"ha_documentation\": \"\",\n \"ha_nodes\": [],\n \"ha_product_version\": \"\",\n \"ha_sap_interface_version\": \"\"\n }\n }\n ]\n}\n\n```\n\n#","ref":"gatherers.html#sapcontrol","title":"sapcontrol - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nThis gatherer allows access to certain webmethods that `saphostctrl` implements. An argument is required to specify\nwhich webmethod should be called. This webmethod is passed to the `saphostctrl` command-line tool through the `-function` argument.\n\nSupported webmethods:\n\n- `Ping`\n- `ListInstances`\n\nA `Ping` call with a successful return should look like this:\n\nExample specification:\n\n```yaml\nfacts:\n - name: ping\n gatherer: saphostctrl\n argument: Ping\n\n - name: list_instances\n gatherer: saphostctrl\n argument: ListInstances\n```\n\nExample output (in Rhai):\n\n```ts\n// ping\n#{elapsed: 579770.0, status: \"SUCCESS\"}\n\n// list_instances\n[\n #{\n \"changelist\": 1908545,\n \"hostname\": \"vmhana01\",\n \"instance\": \"00\",\n \"patch\": 410,\n \"sapkernel\": 753,\n \"system\": \"PRD\"\n }\n];\n```\n\n#","ref":"gatherers.html#saphostctrl","title":"saphostctrl - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows access to the latest SAP profile files content stored in `/sapmnt/ /profile`.\nThe \"latest\" profile means that backed up files like `DEFAULT.1.PFL` or `some_profile.1` are excluded.\nIt returns the profile files and content grouped by SID in a key\\value way.\n\nExample specification:\n\n```yaml\nfacts:\n - name: sap_profiles\n gatherer: sap_profiles\n```\n\nExample output (in Rhai):\n\n```ts\n#{\n \"NWP\": #{\n \"profiles\": [\n #{\n \"content\": #{\n \"SAPDBHOST\": \"10.80.1.13\",\n \"SAPGLOBALHOST\": \"sapnwpas\",\n \"SAPSYSTEMNAME\": \"NWP\",\n ...\n },\n \"name\": \"DEFAULT.PFL\",\n \"path\": \"/sapmnt/NWP/profile/DEFAULT.PFL\"\n },\n #{\n \"content\": #{\n \"DIR_CT_RUN\": \"$(DIR_EXE_ROOT)$(DIR_SEP)$(OS_UNICODE)$(DIR_SEP)linuxx86_64\",\n \"DIR_EXECUTABLE\": \"$(DIR_INSTANCE)/exe\",\n \"DIR_PROFILE\": \"$(DIR_INSTALL)$(DIR_SEP)profile\",\n ...\n },\n \"name\": \"NWP_ASCS00_sapnwpas\",\n \"path\": \"/sapmnt/NWP/profile/NWP_ASCS00_sapnwpas\"\n },\n ...\n ]\n },\n \"NWD\": #{\n \"profiles\": [\n #{\n \"content\": #{\n \"SAPDBHOST\": \"10.85.1.13\",\n \"SAPGLOBALHOST\": \"sapnwdas\",\n \"SAPSYSTEMNAME\": \"NWD\",\n ...\n },\n \"name\": \"DEFAULT.PFL\",\n \"path\": \"/sapmnt/NWD/profile/DEFAULT.PFL\"\n },\n ...\n ]\n }\n}\n```\n\n#","ref":"gatherers.html#sap_profiles","title":"sap_profiles - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nThis gatherer allows access to certain commands that `saptune` implements. An argument is required to specify\nwhich argument should be used when calling `saptune`.\n\n> Note: the gatherer will return the same JSON objects returned by saptune. The only transformation it applies is the snake casing of the keys.\n\nSupported arguments:\n\n- `status` (maps to `saptune --format json status --non-compliance-check`)\n- `solution-verify` (maps to `saptune --format json solution verify`)\n- `solution-list` (maps to `saptune --format json solution list`)\n- `note-verify` (maps to `saptune --format json note verify`)\n- `note-list` (maps to `saptune --format json note list`)\n\nA `status` call with a successful return should look like this:\n\nExample specification:\n\n```yaml\nfacts:\n - name: status\n gatherer: saptune\n argument: status\n```\n\nExample output (in Rhai):\n\n```ts\n// status\n#{\n \"$schema\": \"file:///usr/share/saptune/schemas/1.0/saptune_status.schema.json\",\n \"argv\": \"saptune --format json status\",\n \"command\": \"status\",\n \"exit_code\": 1,\n \"messages\": [\n #{\n \"message\": \"actions.go:85: ATTENTION: You are running a test version\",\n \"priority\": \"NOTICE\"\n }\n ],\n \"pid\": 6593,\n \"publish_time\": \"2023-09-15 15:15:14.599\",\n \"result\": #{\n \"configured_version\": \"3\",\n \"notes_applied\": [\n \"1410736\"\n ],\n \"notes_applied_by_solution\": [],\n \"notes_enabled\": [\n \"1410736\"\n ],\n \"notes_enabled_additionally\": [\n \"1410736\"\n ],\n \"notes_enabled_by_solution\": [],\n \"package_version\": \"3.1.0\",\n \"remember_message\": \"This is a reminder\",\n \"services\": #{\n \"sapconf\": [],\n \"saptune\": [\n \"disabled\",\n \"inactive\"\n ],\n \"tuned\": []\n },\n \"solution_applied\": [],\n \"solution_enabled\": [],\n \"staging\": #{\n \"notes_staged\": [],\n \"solutions_staged\": [],\n \"staging_enabled\": false\n },\n \"systemd_system_state\": \"degraded\",\n \"tuning_state\": \"compliant\",\n \"virtualization\": \"kvm\"\n }\n}\n```\n\n#","ref":"gatherers.html#saptune","title":"saptune - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nThis gatherer allows accessing the information contained in `/etc/sysconfig/sbd`\n\nExample arguments:\n\n| Name | Return value |\n| :-------------- | :------------------------------ |\n| `SBD_PACEMAKER` | extracted value from the config |\n| `SBD_STARTMODE` | extracted value from the config |\n| `SBD_DEVICE` | extracted value from the config |\n\nExample specification:\n\n```yaml\nfacts:\n - name: sbd_pacemaker\n gatherer: sbd_config\n argument: SBD_PACEMAKER\n\n - name: sbd_startmode\n gatherer: sbd_config\n argument: SBD_STARTMODE\n\n - name: sbd_device\n gatherer: sbd_config\n argument: SBD_DEVICE\n```\n\nExample output (in Rhai):\n\n```ts\n// sbd_pacemaker\n\"yes\";\n\n// sbd_startmode\n\"always\";\n\n// sbd_device\n\"/dev/vdc;/dev/vdb\";\n```\n\n#","ref":"gatherers.html#sbd_config","title":"sbd_config - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows accessing the sbd dump command output data.\n\nIt executes the `sbd -d dump` command in all devices configured in the `SBD_DEVICE` field on `/etc/sysconfig/sbd` and aggregates results in only one fact.\n\nNote that:\n\n- no arguments are required\n- if any of the dumps fail, a fact error is returned\n\nDumped keys (`Timeout (watchdog)`, `Timeout (msgwait)`, `Number of slots`, etc) are sanitized to simplify their access and usage in the expression language.\n\nExample specification:\n\n```yaml\nfacts:\n - name: sbd_devices_dump\n gatherer: sbd_dump\n```\n\nExample output (in Rhai):\n\n```ts\n// sbd_devices_dump\n#{\n \"/dev/vdc\": #{\n header_version: 2.1,\n number_of_slots: 255,\n sector_size: 512,\n timeout_allocate: 2,\n timeout_loop: 1,\n timeout_msgwait: 10,\n timeout_watchdog: 5,\n uuid: \"69048391-c647-4b34-a03a-f704f5cc2258\"\n }\n};\n```\n\nFor extra information refer to [trento-project/agent/../gatherers/sbddump_test.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sbddump_test.go)\n\n#","ref":"gatherers.html#sbd_dump","title":"sbd_dump - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nGather sysctl output. It takes a sysctl key as argument and it returns the value of the requested key or a map if a partial key is provided.\n\nExample arguments:\n\n| Name | Return value |\n| :-------------- | :---------------------------------------------------- |\n| `vm.swappiness` | corresponding value returned by sysctl |\n| `debug` | a map containing all the keys starting with `debug.`` |\n\n```yaml\nfacts:\n - name: vm_swappiness\n gatherer: sysctl\n argument: vm.swappiness\n\n - name: debug\n gatherer: sysctl\n argument: debug\n```\n\nExample output (in Rhai):\n\n```ts\n// vm_swapiness\n60;\n\n// debug\n#{\n \"exception-trace\": 1,\n \"kprobes-optimization\": 1\n};\n```\n\n#","ref":"gatherers.html#sysctl","title":"sysctl - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nGather systemd units state. It returns an `active/inactive` string.\nIf the service is disabled or it does not exist, `inactive` is returned.\n\nExample arguments:\n\n| Name | Return value |\n| :------------- | :------------------------ |\n| `trento-agent` | state of the systemd unit |\n\n```yaml\nfacts:\n - name: sbd_state\n gatherer: systemd\n argument: sbd\n\n - name: corosync_state\n gatherer: systemd\n argument: corosync\n```\n\nExample output (in Rhai):\n\n```ts\n// sbd_state\n\"active\";\n\n// corosync_state\n\"inactive\";\n```\n\n#","ref":"gatherers.html#systemd","title":"systemd - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nThis gatherer determines whether a given user has its password still set to an unsafe password.\nIt returns `true` if the password matches a password in the list of unsafe passwords, `false` otherwise.\n\nSpecification examples:\n\n```yaml\nfacts:\n - name: hacluster_has_default_password\n gatherer: verify_password\n argument: hacluster\n```\n\nFor the argument, only whitelisted users are allowed. Currently whitelisted usernames:\n\n- `hacluster`\n\nList of unsafe passwords:\n\n- `linux`\n\nExample output (in Rhai):\n\n```ts\n// hacluster_has_default_password\ntrue;\n```","ref":"gatherers.html#verify_password","title":"verify_password - Gatherers","type":"extras"},{"doc":"# Hack on Wanda","ref":"hack_on_wanda.html","title":"Hack on Wanda","type":"extras"},{"doc":"In order to run Wanda, the following software must be installed:\n\n1. [Elixir](https://elixir-lang.org/)\n2. [Erlang OTP](https://www.erlang.org/)\n3. [Rust](https://www.rust-lang.org/tools/install)\n4. [Docker](https://docs.docker.com/get-docker/)\n5. [Docker Compose](https://docs.docker.com/compose/install/)\n\n#","ref":"hack_on_wanda.html#requirements","title":"Requirements - Hack on Wanda","type":"extras"},{"doc":"[asdf](https://asdf-vm.com/guide/introduction.html) allows using specific versions of programming language tools that are known to be compatible with the project, rather than relying on the version that's installed globally on the host system.\n\nIn order to use asdf, follow the official [asdf getting started guide](https://asdf-vm.com/guide/getting-started.html).\n\nInstall all required asdf plugins from [.tool-versions](/.tool-versions) inside the web repository.\n\n```\ncut -d' ' -f1 .tool-versions|xargs -i asdf plugin add {}\n```\n\nSet up the asdf environment\n\n```\nasdf install\n```","ref":"hack_on_wanda.html#ensure-compatibility-with-asdf","title":"Ensure Compatibility with asdf - Hack on Wanda","type":"extras"},{"doc":"A `docker-compose` environment is provided for easy local development. To start the environment, run the following command:\n\n```\ndocker-compose up -d\n```\n\nThis command starts a **Postgres** database and a **RabbitMq** instance, which is used for storage and communication.","ref":"hack_on_wanda.html#development-environment","title":"Development environment - Hack on Wanda","type":"extras"},{"doc":"Before starting Wanda, some initial setup tasks are required. This can be achieved by running the following command:\n\n```\nmix setup\n```\n\nThis command performs necessary tasks such as installing dependencies, creating the database schema and running migrations.\n\n#","ref":"hack_on_wanda.html#setup-wanda","title":"Setup Wanda - Hack on Wanda","type":"extras"},{"doc":"Gain a deeper understanding of how Wanda is configured, reading the [mix.exs](https://github.com/trento-project/wanda/blob/main/mix.exs) file located in the root directory of the project. This file contains information on dependencies, configuration settings, and tasks that can be run using the Mix build tool, providing a complete picture of the project's setup.","ref":"hack_on_wanda.html#hint-about-project-setup","title":"Hint about Project setup - Hack on Wanda","type":"extras"},{"doc":"To start Wanda, you need to run the following command:\n\n```\niex -S mix phx.server\n```","ref":"hack_on_wanda.html#start-wanda-in-the-repl","title":"Start Wanda in the REPL - Hack on Wanda","type":"extras"},{"doc":"Congratulations, Wanda is now running locally on your machine! You can access its API documentation by visiting the following URL:\n[localhost:4001/swaggerui](http://localhost:4001/swaggerui).\n\nThe Swagger UI provides a user-friendly interface for exploring and testing the various API endpoints of Wanda.\n\nHappy Hacking!","ref":"hack_on_wanda.html#access-wanda-swaggerui","title":"Access Wanda Swaggerui - Hack on Wanda","type":"extras"},{"doc":"# Wanda Demo","ref":"demo.html","title":"Wanda Demo","type":"extras"},{"doc":"Wanda's demo mode provides a simulated environment where targets' gathered facts are faked via a configuration yaml file. This empowers showcasing Trento's capabilities, and eases the development of the platform. The user is able to run check executions from the web, and wanda's fake server returns faked gathered facts.","ref":"demo.html#introduction","title":"Introduction - Wanda Demo","type":"extras"},{"doc":"First set up the [local environment](./hack_on_wanda.md) and run the following command to start Wanda in demo mode, instead of the usual `iex -S mix phx.server`\n\n```bash\n$ DATABASE_URL=ecto://postgres:postgres@localhost:5434/wanda_dev \\\n AMQP_URL=amqp://wanda:wanda@localhost:5674 \\\n SECRET_KEY_BASE=Tbp26GilFTZOXafb7FNVqt4dFQdeb7FAJ++am7ItYx2sMzYaPSB9SwUczdJu6AhQ \\\n CORS_ORIGIN=http://localhost:4000 \\\n ACCESS_TOKEN_ENC_SECRET=s2ZdE+3+ke1USHEJ5O45KT364KiXPYaB9cJPdH3p60t8yT0nkLexLBNw8TFSzC7k \\\n PORT=4001 \\\n MIX_ENV=demo \\\n iex -S mix phx.server\n```\n\n#","ref":"demo.html#how-to-setup-wanda-in-demo-mode","title":"How to setup Wanda in demo mode? - Wanda Demo","type":"extras"},{"doc":"- DATABASE_URL: The URL to connect to the Postgres database running in the Docker container.\n- AMQP_URL: The URL for RabbitMQ, used for message exchange.\n- SECRET_KEY_BASE: The secret key for Wanda.\n- CORS_ORIGIN: The origin URL from where API requests are allowed (pointing to web).\n- ACCESS_TOKEN_ENC_SECRET: Secret key for encrypting access tokens.\n- PORT: The port on which Wanda will run (4001 in this case).\n- MIX_ENV: The environment in which Wanda will run (set to \"demo\" for the demo environment).","ref":"demo.html#explanation-of-environment-variables","title":"Explanation of environment variables: - Wanda Demo","type":"extras"},{"doc":"In the Wanda demo environment, configure fake facts by editing the [fake_facts configuration](https://github.com/trento-project/wanda/blob/main/priv/demo/fake_facts.yaml). Define or modify custom facts for different targets and checks.\n\n#","ref":"demo.html#modify-demo-facts-configuration","title":"Modify demo facts configuration - Wanda Demo","type":"extras"},{"doc":"The Configuration is saved in [fake_facts.yaml](https://github.com/trento-project/wanda/blob/main/priv/demo/fake_facts.yaml) file, which follows a specific structure with two main sections: `targets` and `facts`.\n\nExample:\n\n```yaml\ntargets:\n target1: 0a055c90-4cb6-54ce-ac9c-ae3fedaf40d4\n target2: 13e8c25c-3180-5a9a-95c8-51ec38e50cfc\nfacts:\n check_1:\n fact_name1:\n target1: 2\n target2: 3\n```\n\n#","ref":"demo.html#yaml-structure","title":"YAML Structure - Wanda Demo","type":"extras"},{"doc":"The targets section allows defining handles for targets' UUIDs, providing a reference that can be used through the configuration.\n\nFormat:\n\n```yaml\ntargets:\n : \n```\n\n` `: A user-defined handle or reference for a target.\n\n` `: The UUID or identifier of the target.\n\nAdd as many new target entries as required:\n\n```yaml\ntargets:\n target1: 0a055c90-4cb6-54ce-ac9c-ae3fedaf40d4\n target2: 13e8c25c-3180-5a9a-95c8-51ec38e50cfc\n : \n```\n\n#","ref":"demo.html#targets","title":"Targets - Wanda Demo","type":"extras"},{"doc":"The facts section allows specifying what fact value a target should return for a specific check.\n\nThe format for the facts section is as follows:\n\n```yaml\nfacts:\n :\n :\n : \n : \n```\n\n- There can be as many as needed.\n- Each there can be as many configured as needed.\n- Each can be instrumented to have a specific on a .\n\nExample:\n\n```yaml\ntargets:\n target1: 0a055c90-4cb6-54ce-ac9c-ae3fedaf40d4\n target2: 13e8c25c-3180-5a9a-95c8-51ec38e50cfc\n target3: 3f16cb32-57fb-46cc-9bf1-cd8d72d7eb9a\n\nfacts:\n.......existing facts..........\n new_check_id:\n new_fact_name:\n target1: \n target2: \n target3: \n```","ref":"demo.html#facts","title":"Facts: - Wanda Demo","type":"extras"},{"doc":"#","ref":"demo.html#faq","title":"FAQ - Wanda Demo","type":"extras"},{"doc":"Wanda will still evaluate and return a default fallback fact value \"some fact value\" for a check's execution. This means when a new check is added to wanda, changing the the configuration is optional.\n\n#","ref":"demo.html#what-happens-with-unmapped-targets-facts-or-checks","title":"What happens with unmapped targets, facts or checks? - Wanda Demo","type":"extras"},{"doc":"Every Fact Gatherer has specific return values. To get an overview of all gatherers, refer to [Wanda's gatherers guide](../gatherers.md).\nDetermining the correct return value of a fact requires inspecting the specific check itself.\nVisit the [Checks Catalog](https://github.com/trento-project/wanda/blob/main/priv/catalog) to find out which gatherer is used for the specific check and which values are expected.","ref":"demo.html#how-to-know-what-s-the-correct-return-value-of-a-fact","title":"How to know what's the correct return value of a fact? - Wanda Demo","type":"extras"}]} \ No newline at end of file diff --git a/gatherers.html b/gatherers.html index e0e70779..8aaf362a 100644 --- a/gatherers.html +++ b/gatherers.html @@ -114,13 +114,13 @@

Introduction

-

Gatherers can be thought of as functions:

  • they have a name
  • they accept argument(s)
  • they return a value, the gathered Fact

Facts Gathering process in a nutshell

fact = gatherer(argument)

+

Gatherers can be thought of as functions:

  • they have a name
  • they accept argument(s)
  • they return a value, the gathered Fact

Facts Gathering process in a nutshell

fact = gatherer(argument)

Available Gatherers

-

Here's a collection of built-in gatherers, with information about how to use them.

NameImplementation
cibadmintrento-project/agent/../gatherers/cibadmin.go
corosync.conftrento-project/agent/../gatherers/corosyncconf.go
corosync-cmapctltrento-project/agent/../gatherers/corosynccmapctl.go
dir_scantrento-project/agent/../gatherers/dir_scan.go
fstabtrento-project/agent/../gatherers/fstab.go
groupstrento-project/agent/../gatherers/groups.go
hoststrento-project/agent/../gatherers/hostsfile.go
package_versiontrento-project/agent/../gatherers/packageversion.go
passwdtrento-project/agent/../gatherers/passwd.go
saphostctrltrento-project/agent/../gatherers/saphostctrl.go
sap_profilestrento-project/agent/../gatherers/sapprofiles.go
saptunetrento-project/agent/../gatherers/saptune.go
sbd_configtrento-project/agent/../gatherers/sbd.go
sbd_dumptrento-project/agent/../gatherers/sbddump.go
sysctltrento-project/agent/../gatherers/sysctl.go
systemdtrento-project/agent/../gatherers/systemd.go
verify_passwordtrento-project/agent/../gatherers/verifypassword.go

+

Here's a collection of built-in gatherers, with information about how to use them.

NameImplementation
cibadmintrento-project/agent/../gatherers/cibadmin.go
corosync.conftrento-project/agent/../gatherers/corosyncconf.go
corosync-cmapctltrento-project/agent/../gatherers/corosynccmapctl.go
dir_scantrento-project/agent/../gatherers/dir_scan.go
fstabtrento-project/agent/../gatherers/fstab.go
groupstrento-project/agent/../gatherers/groups.go
hoststrento-project/agent/../gatherers/hostsfile.go
package_versiontrento-project/agent/../gatherers/packageversion.go
passwdtrento-project/agent/../gatherers/passwd.go
sapcontroltrento-project/agent/../gatherers/sapcontrol.go
saphostctrltrento-project/agent/../gatherers/saphostctrl.go
sap_profilestrento-project/agent/../gatherers/sapprofiles.go
saptunetrento-project/agent/../gatherers/saptune.go
sbd_configtrento-project/agent/../gatherers/sbd.go
sbd_dumptrento-project/agent/../gatherers/sbddump.go
sysctltrento-project/agent/../gatherers/sysctl.go
systemdtrento-project/agent/../gatherers/systemd.go
verify_passwordtrento-project/agent/../gatherers/verifypassword.go

cibadmin @@ -469,7 +469,147 @@

"user": "daemon" }, ... -];

+];

+ + + sapcontrol + +

+

Argument required: yes.

This gatherer allows access to certain webmethods that sapcontrol implements. An argument is required to specify which webmethod should be called. The communication with sapcontrol is created opening a unix socket connection using the file /tmp/.sapstream5xx13. The Sapcontrol Web Service Interface documents the SOAP API interface, including all the possible values each of the fields could have, specifically helpful for enumerators like dispstatus in GetProcessList and state/category in HACheckConfig webmethod.

The return value is grouped by discovered SIDs, which include the list of command outputs for each instance in this system.

Supported webmethods:

  • GetProcessList
  • GetSystemInstanceList
  • GetVersionInfo
  • HACheckConfig
  • HAGetFailoverConfig

Example specification:

facts:
+  - name: processes
+    gatherer: sapcontrol
+    argument: GetProcessList
+
+  - name: instances
+    gatherer: sapcontrol
+    argument: GetSystemInstanceList

Example output (in Rhai):

// GetProcessList
+#{
+  "NWP": [
+    #{
+      "instance_nr": "10",
+      "name": "ERS10",
+      "output": [
+        #{
+          "description": "EnqueueReplicator",
+          "dispstatus": "SAPControl-GREEN",
+          "elapsedtime": "266:08:15",
+          "name": "enrepserver",
+          "pid": 7221,
+          "starttime": "2023 09 29 09:41:41",
+          "textstatus": "Running"
+        }
+      ]
+    }
+  ]
+} 
+
+// GetSystemInstanceList
+#{
+  "NWP": [
+    #{
+      "instance_nr": "10",
+      "name": "ERS10",
+      "output": [
+        #{
+          "dispstatus": "SAPControl-GREEN",
+          "features": "MESSAGESERVER|ENQUE",
+          "hostname": "sapnwpas",
+          "http_port": 50013,
+          "https_port": 50014,
+          "instance_nr": 0,
+          "start_priority": "1"
+        },
+        #{
+          "dispstatus": "SAPControl-GREEN",
+          "features": "ENQREP",
+          "hostname": "sapnwper",
+          "http_port": 51013,
+          "https_port": 51014,
+          "instance_nr": 10,
+          "start_priority": "0.5"
+        },
+        ...
+      ]
+    }
+  ]
+} 
+
+// GetVersionInfo
+#{
+  "NWP": [
+    #{
+      "instance_nr": "10",
+      "name": "ERS10",
+      "output": [
+        #{
+          "architecture": "linuxx86_64",
+          "build": "optU (Oct 16 2021, 00:03:15)",
+          "changelist": "2094654",
+          "filename": "/usr/sap/NWP/ERS10/exe/sapstartsrv",
+          "patch": "900",
+          "rks_compatibility_level": "1",
+          "sap_kernel": "753",
+          "time": "2021 10 15 22:14:31"
+        },
+        #{
+          "architecture": "linuxx86_64",
+          "build": "optU (Oct 16 2021, 00:03:15)",
+          "changelist": "2094654",
+          "filename": "/usr/sap/NWP/ERS10/exe/gwrd",
+          "patch": "900",
+          "rks_compatibility_level": "1",
+          "sap_kernel": "753",
+          "time": "2021 10 15 22:04:14"
+        },
+        ...
+      ]
+    }
+  ]
+}
+
+// HACheckConfig
+#{
+  "NWP": [
+    #{
+      "instance_nr": "10",
+      "name": "ERS10",
+      "output": [
+        #{
+          "category": "SAPControl-SAP-CONFIGURATION",
+          "comment": "2 ABAP instances detected",
+          "description": "Redundant ABAP instance configuration",
+          "state": "SAPControl-HA-SUCCESS"
+        },
+        #{
+          "category": "SAPControl-SAP-CONFIGURATION",
+          "comment": "0 Java instances detected",
+          "description": "Redundant Java instance configuration",
+          "state": "SAPControl-HA-SUCCESS"
+        },
+        ...
+      ]
+    }
+  ]
+}
+
+//HAGetFailoverConfig
+#{
+  "NWP": [
+    #{
+      "instance_nr": "10",
+      "name": "ERS10",
+      "output": #{
+        "ha_active": false,
+        "ha_active_nodes": "",
+        "ha_documentation": "",
+        "ha_nodes": [],
+        "ha_product_version": "",
+        "ha_sap_interface_version": ""
+      }
+    }
+  ]
+}
+

saphostctrl diff --git a/hack_on_wanda.html b/hack_on_wanda.html index 9437e61c..503f74af 100644 --- a/hack_on_wanda.html +++ b/hack_on_wanda.html @@ -120,7 +120,7 @@

Ensure Compatibility with asdf

-

asdf allows using specific versions of programming language tools that are known to be compatible with the project, rather than relying on the version that's installed globally on the host system.

In order to use asdf, follow the official asdf getting started guide.

Install all required asdf plugins from .tool-versions inside the web repository.

cut -d' ' -f1 .tool-versions|xargs -i asdf plugin add  {}

Set up the asdf environment

asdf install

+

asdf allows using specific versions of programming language tools that are known to be compatible with the project, rather than relying on the version that's installed globally on the host system.

In order to use asdf, follow the official asdf getting started guide.

Install all required asdf plugins from .tool-versions inside the web repository.

cut -d' ' -f1 .tool-versions|xargs -i asdf plugin add  {}

Set up the asdf environment

asdf install

Development environment diff --git a/readme.html b/readme.html index 4c4939c3..f1a99080 100644 --- a/readme.html +++ b/readme.html @@ -250,14 +250,14 @@

Often times knowing the returned value of the gathered facts is not a trivial thing, more during the implementation of new checks.

To better debug the fact gathering process and the returned values, the facts subcommand of trento-agent is a really useful tool. This command helps to see in the target itself what the gathered fact looks like. This is specially interesting when the returned value is a complex object or the target under test is modified and the check developer wants to see how this affects the gathered fact.

The command can be used as:

./trento-agent facts gather --gatherer corosync.conf --argument totem.token
 # To see the currently available gatherers and their names
-# ./trento-agent facts list

Which would return the next where the Value is the available value in the written check:

{
+# ./trento-agent facts list

Which would return the next where the Value is the available value in the written check:

{
   "Name": "totem.token",
   "CheckID": "",
-  "Value": {
+  "Value": {
     "Value": 30000
-  },
+  },
   "Error": null
-}

+}

Adding new Checks diff --git a/search.html b/search.html index 7b4bfb93..41a279f7 100644 --- a/search.html +++ b/search.html @@ -104,7 +104,7 @@

- +