From 64e694e77f9636c41b2b4aed5b3da4c92c84c28d Mon Sep 17 00:00:00 2001 From: CDimonaco Date: Thu, 26 Oct 2023 12:48:39 +0000 Subject: [PATCH] deploy: dc2862e6f5ae1d1b306f0ef72bb14410b1bc0a72 --- .build | 2 +- Wanda.DataCase.html | 6 ++-- Wanda.epub | Bin 523629 -> 523903 bytes ...ta-89FED348.js => search_data-8AE95F7C.js} | 2 +- gatherers.html | 27 ++++++++++++++++-- hack_on_wanda.html | 2 +- readme.html | 8 +++--- search.html | 2 +- specification.html | 6 ++-- 9 files changed, 38 insertions(+), 17 deletions(-) rename dist/{search_data-89FED348.js => search_data-8AE95F7C.js} (76%) diff --git a/.build b/.build index 6d0a30d3..7a47b914 100644 --- a/.build +++ b/.build @@ -104,7 +104,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-89FED348.js +dist/search_data-8AE95F7C.js dist/sidebar_items-ABFFF37D.js expression_language.html gatherers.html diff --git a/Wanda.DataCase.html b/Wanda.DataCase.html index e2392958..b5f40321 100644 --- a/Wanda.DataCase.html +++ b/Wanda.DataCase.html @@ -202,9 +202,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 ba364a2c8c0213e607ab7a2afe800278c50c3c13..9dae528d46a84ceb26e5daec532f43a6a3b8dffa 100644 GIT binary patch delta 23139 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 z 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 delta 23019 zcmY(qQ;;TFur%7XZQC}cZQHi({@S)ZZQHhO+xE2a?{iMvhr3?#c|~MYMrLLGei7b$ z5W*|UfP$d`{m)}E)=Gru1pN;hB=Ufv{zHv>S$o2!8{hzHz=mODHiumr#{wZ%%z*!& z4ozti8ksEpMTnOp4`+4Deh#jTR%&QbdDDyAg&w}LV6R(xYYqicG?*R(Qwo!z&iAqy zp`Gqm>?O^pP7e+f4?WY17%!D5$Ol_7WG2ZX+*ZT@0XfH)Egz8PL6SEJk=U#ktR*p6 zDQ!BQ!Og-bKp|~yj}aK)9N`{B#>W8O!LX0KGv2OG1L$ecQ3&zMviW*Kbi|07YMSm_ zA=zpmIst`HteGgqH;o~9U(qL2D8X}a3u!`)WZBp*@=VCjzuU!IWk0v+^SklW1OnV_ zX##R&LRr0*EW51Etgjdyi37wk8Fe?A@lS!igf6TmKuk}S4@~DEh)%HrUlM-Q>3|5U ze%6+p86V{{^pA_q1t|>^^Ey_4HO+$5Kg(WM?oT^Q;SW}&)sGw2z2HrE$(bu)(6NA_ z7S;s>as$)ki`R?emq%}RRy>Pqnc%!WcyCiAvvhj;Fe~I0S7|Mu(cShSUBClnmg8L! zy8Z7H0ISIV#*@w%D7(FYRSN&)U)8O?0+7$6cXWBF3P*#;ufGBAP`vA>nn#<4+l4Q_ zfM1$}R4|MXf7q_W0)40VLBht(KTluou1xva)S|XYC(C7j+Oe(C;f~s8bq$1?O#?kG z8WlbYJhj+&sX5*^;t;uSNhyJ{Q4mlvXTOzJlQ&IUAbvbFqKedI666NhUpJtnfK9RO zf@Q`k-Q{9?OLPnn>7kP-??UM%&cz(>Tzs_h7HHLELC)C ztG77#(|3v#wpYaek9<)7L%ybIdUvq@rJYJdO;nRK3px^DgUg>go8pKJ0Xb|>{y;qL zG)P(K5+a)r$@TSSy_Z9>j&Y(PRy*5DgTrIin(#}%uaCXG_x+Z&{m1L8rQ+$Ln?D=z zsOkM4@X|csF^jb)6rN7}x(+Ppe+kr+^a%Km^}oM8>U$1b97z7J22S$amQF$N6q1N;XO7kmnz=^IB@4m6w~P1Z_ogo^^)F`IEJ+=b@8-C?e`xD! zDJ3jw_KxXOI42f=;f?qw^Q$Lp(5{6ifaSrL5jZV2JP_}yZZPy}Q{Qu1=PB4T06EfE zUde%u(#I_{GHe!Fj>xPuvL$$^iT-iK5Z&-v%re}8&Vyc)8=$1>m(=`Qhi^+x16|k|lUJhaOH>iIaB zY3r466e!W6hOA^TWD}?gcY|FeVa>w7jhgqsTISe+K)S`SI|z_|B;jo>xVJO?)DtFK zC&d*~Q_o9OZ0NAXFkJ_WmldL~Ea3<%fkulCKp!Z}Jqbe+!P0agDmrJ`0hnHqI?JtQ zmo98NC)EeP@hP`QM_(Sw0{#9j<-iOG?7rl7i`ip94LwDd<=$MCdCRvvI11-=tM2LY zanx?i4~GSA?p4yV{7w?G^v7oktG=5LyFyXy4sHD$`6>z=VeAB(`RW9fk^|$VQojYI z%&IHYlqHGh{OfWah1!(UfMw#vtk}xJqgVNXYbrdO5-|}~>Cm4LwN{au_w@OuQG$U# z8e9C8R@Z$gQ=q^oI~dw0jMW>w9x7SXRObzY092>6zKM$aaQg9@}Zlf zwIiIa-%K0Btc<}4#3*Zpg~fU7{qimUjNpo;jKia3yuwSr#Wx;y0euy*!4xHKfyvzn zg++<=F?Ke3=c6JzUzLeYS|UxO#5#ufw1_(7amV<=R|fJF=z&pJ4b3xTT!W@AG*=!; z{bVIMRClC{U*1)NUF~7F?6C$c@$DTU8^Pp`agM%`QKB-@1Fh1+#VoztCKcT=yB;P@ z3O<^ju=g%DAaaZ2fLx}0gF_{GuVY7#TwQwgwWl@Cs`ta2_KR>w%sXW%HiB@)v(_D6 zwH4q}g;E6oMWrBNCp12Ho7is#5QsGOxVx?&$)-XlW*f#02RBJ%hH0dt4zis)-QLs(egKhBgcA zl}rAeSk2a|NIUIsFq+oE3siE`E%dKeABn@!3x5@5VE<38|8HPMN~nQD|Bp`hEqMts zB%jGr0POx}l>OuxIIRTS$e4~ygwbV^=G!!K{E3FJ3p4r@m$8VB7PTfj!LmsG@ zW4krRlnc;o9rrnL84JhjY4`uV{CVxdE!R~!lOXl)FRV!Ik)}D@oTAH~I}3i__>*nL z(cRuYj=@KHAeG*txKstE22$l9vH#m0C1cwKct|7AYDKNPcs@SnTdI+BM!`~}n%tI& z!*KzbeqDl3qAkfq76<4 zR28SJn&H_-wdhJF|2&Ru5$+o7_2PPN=r_>E*y3xd*hX#lb@Kase#|fi3sU12(aBE6 z$8j-h{mop^OqZduHnK7@2C7g+Lp5WvtP3NWS|RG$om9z4Ruj=bRuNp*ejC*8I(*^Z=_RF(w7UztA4&@ zJs@mFuf#karhE^FcS*s;&>)s|)w|;EKvY-Q*2M}b zZ9*7@Qr4op#F?5>T0JGzJ8Ry3rx6~lB(EQJGu8Czrg)D94E4sbq^*;WAW1Xh`&&bqL=SG>Udh9ph&Dycq!ntK9Ix)r~O0+Zp8vAu3gK!;b zpK_xEUK%cTFc+8;R5#F>(@n%{))GvEQR*(P<(0iO^T6=A`HdLIzHF&qZ?f-an*m7@ z39Ud3cbpWxT0rrRDRwN*v_xnrHnMoEXMb(zyf})ZIF$~pgih3ANT1wr1sNj`CUXlr zi-Pm|zdW|$uHEEP=QSUI4%vI#UXI=u*v}JfW)>WxD%)EO$?QvD>zYlI%Jtv52>OuB z+m!d9`x9bsRf8MINU(MS>$2@g;Iwt>MG8e2%EgKWy=-ULzPE?x@TaGxrzayG*~h*< z(epihs-wdEaK;3V-w1?qy7m}fp~5VwB6Np)gQB=zqOpdNn`chIV=;<_=2cp*EGOQs z3!{(p$2&*ERm;hZC_uPae^7n0grulgP%*Ii+{5Q@rkofNy#o!abqx7GFHov$6l*=j z=)DMUpjRF?o4#9Im^gliEec!HT4EB9clLcn@l_W^y}CnwC~>{d7Th<=R2KuKRugAo z4tgkUH)C|`ti1(*J0JUa4}JIj2{%SJ{LG!o^#B zjO9gyG1*|Z`WyKPVNZyobjnr8+~soU=}iASEz~ZuygCGd#ui6D&yerGiHE}pieUzP zqMAGRNg>g-Ku^D5Elfuoh#xImjDv1_aUacw<7x z7E3D1SnyDAZQ5y;QTwi-cZWF`?qU=j)n<%PQ6IQap@WZh4WMSR(Aayd%cn(2kFbcrYy`9<5< z41J3(_s|P~ORw(Pd)Pt>XX&$qBpkDdb&D5dzdV$YyU{#;UJ*aF*9VK<;YQ}f*J|P^ z>;dxt*sF&j1HQIgNgfKvEprZf5fKh;UMlDl@MK+gyCW#%z`K*TP9dhUv?!$`jZ{SF zzeJ>AC}DPn_s@Ak$o(hr%nd1?8c^ZH93S!whT9W>&S%KHqxO^g^82$K9DFYd*fGjh zJBbUZqjaM#J*S%R(`4z?#pjfB-yVl6Z{ZK@t&BZkQl3E?zxEEF&+?KQ_pSA*w9X>s z(Z)VXuijF!hy2p#4ZVaoT0+EY`|#JH)=laM!85dI^VU+-u8cyeb`x>e^^Oer1y^SU zQ+{H=mv6uK1-yi*-!;78;0kRatZKg=KF{kzrxNw0wx7-GGvhWY(mfnoHzSQNa33mM zN3Tc*QDk3tcNh4fCBDnRJhtUsjuelk;4UBF`~Kz8vg%3c=xOwg=J4?|IoYUHUi+sb zamFXehXrXU)WE@qW~w;~DnW`;Tp6-RvAj)vDUAvSj?80Wb@T0IXa@FXas!*(z=N1B z$(9}ZV+;3h`R*m|LaWSvmsXO`0OOGwu2`cFVO$bi)akdvQ%QT0s;M700Ke> zN{>H+#7wqVMF8N^B^|nor7bgSSGNJ_@t^@m-H_*#NgInK;z+$e-gzKUZ#d(0S;v6f zilio-jo#^snmtZsD*$%Co?dm7H>G7IP<<1`$csDRq;0OEx$@@D7QVcSU6JGG=H`yT zC&8#(iOcC2Kq){QKdeNz1uYJPR^%Fu!Y$lx>2mXOasVTh90O=*6y!x4%U1F<=G0O$ zmGDjJLMBi5@d3j(r6=n37e3Z9rI{RLWCrEaRGG0wPOdDG-~Mw6#pqpdFcg`k>K6gU z(%KXQk6RQu_`7Yg_-SeF?ulO(xbK>qsmQREaUAB z%mi$vK>)^fguU<2hmkT)4S<+@8>_AIjEzi;{3i`3K%f8j?PsX#oHik2Sl^Ndhd8CZ zh($`Zm8>EkB59F;=on=d?791&v#e+9X2=OTX&+&_iR^7f^5LR&DtpBV49nUk`}8+K zp$Y@+U(C(ChlyaCk}PI?l7@VKvb$C`k1M193}GcVyiA^%EQrbu6CahwsmUclX=$U1 z==s2Njn z49F?PQ2s<9@YHqS7|pkCvy2c#Afjwhr)CXvd?v$%9ia%}6|LEDO{$D>%b@Wd%gTC- zf{j>F#Sx-ctx@f7Q&5Fi+V=9m;%q$~Na1TnpkM%q66iLwJ&SC){b8}T(zIMzCRX2% ze%N?Betp>3u;M}}ooijcUVOmHmdI6(0j%#IAhp8JgWCvG8G=p>1`)18@u~szMXGK5 zZ(g!T+qE>vp&lzS;2t`h$x171N(y!@=fEnkVzejZLdD8lN7)*pn50k#BEVpvZ zE#_@2D+g2u!P{hV<{J%r)lX1#5Wm!s-<4T(iRIug0#{W@uhFZB5zv*fhA~u?0Sl&Z zq+aWw?JuW(l&%sabDFB6W3+2XRGUA#%JQlvSEEU~7g3u z?yC3CI3WF;#m&u4&1In9Ate?lh zFRY{82THz=>ZX_&_xDTwA5*u%VY~N zyTqfbuxTWB+RwWLDK6S^`*M;^F(!8^!01Dwr^a1-ELp&90!pm`Tai}?F?Zs`YYaXD zbw~t|oYEhl0|z-?i+U(T0LLsHP5qfb6HkmR^JzIyL5R(lo^%OLKiQ%!6k+I@ADi~u zhLGd|0dxrCDv=D@^TDzr{CijNj(%*6T33kKSG_Djhwi@H?xdCcU-M2tz)2Ywn@Wb_ z51eL#)DZYC#F}e9M>{<+u0Kv8o*dCuv8v1Q)@j${FkNS8c$cj_pn8-rvg_(&Uzo;| zm@&ez!w*}wZf9pAZ4bF?)AQXk6f1Ttm$ZAS^`{X(Y&BELOSma&3cGuU5DzuC-`o2G zH+?4TqaP6+)PM&3-X;kOLTtOYW8eA(J!7oa^+>dwtd=UBIfZX&-mszTj9Kds*#ix# z6Q;6if9j=>iqdmE;El&M{6>O{x@KCrl&SscrdqoIsssUAlku%!og60;P&MuoN) zwhom~)L)>HP^^8?n{OoMN(YqCT<5|K1X8pH){3Y$?@b^_mS5w;9+Fb!Hw*<5d=io$ zYgzj1A>SFauDm8?`xY44`2lWtX+j_`_Va^X=iu!IwD1TNfD>Us{^co9!s5f7*TkUVi8X zw2#qMbGfq|5TS459>!zvO#nr{sMHTL{Yh=WD z+nQ*LX|yd!mxi_AXkYV85R-I`(Rbn1fWIVtoFGXqVo;;+EGVp{vcmhG-|x=z3;I84 z*tXXHS;$)hq4qy*#)+ofdaK-V4fg8+AUjO1fKMhvDlqM0Iu5joq!d)6all?;$`=NA z>k$qUPJZMJFTq`&5Bb!E+}^wos^P4;aR}GUv>SkBluCoG>*8!Q#T!kG)%?*Kr?fF5 zrf_gPU-c1HPA|`48T|!~<8c$?r-8&S7*|}PA@PxIhEJY>Fz4}o)2L?IwfvWIhMG#La zlShZRsqm97F;3mg_=o;U=?zOep$w?;`AK-(x>-;Z{`CP1-ouEEk2NOg{hle~E9{Jv zy)4SiO&NsGL)k9A626x;ilI)cYCZ29z`xlXXlPoRwEV)D=gg#>u1O?r|3RH?tju%} z5Ow`%nqyF#2$J7&Z^iXj3i%ifmBRd63bBCvO^??Zx)U7eqs9cneKiTq!iXaIs@Ua+rELZ82G zYp_}s<~{_NA~;4AoPl&OhqIv)kXRwpxn5SXmBl;>4FrsH$ZftIhR_+z<)Lbn$xX7z zrdYrW2k}J?8|4ZOVMb>s8Zb;VgS@)qo*IQdUC(U?*R^gekZueq6Ic*Y4vxr9{lQ@Z zl&FTaPs7cQ=2QyLqX*JvA4KQ-@bfSGXSjBY$^RtZ_UljNzaTa6ec(PJz-CagA@m$M zX+%9;upLN%m! z0H6_qPsT*GbjU#rNIBx6zW*-u^$2@vExSH-?^ta#K){K`q(da!8H4PbX#GvYOj>Vi z19$HUztVR&NaY8q0XDMY6IEqOUF^RPo%)l;QSSO@5lFirY_1BTI%{L5!F&@b=$c_Q3QXH5gbbjt%CPLApJDTA=GGdxf+Z1lKVwgopmWQN^NIBV%u|o6@)t4 zGXs!wQS?Wr?=#Ic~d_63>YOx$?EH&XBM>88J=VPV-Tqs8fF4Xbl0%w1htS7QGc zY1zwQ0Woj^0ApZguo>HIs-!|55}}K5_Z665$TK6Wi=ET&36Q_R6c&A$ES_m6G15#N-{XvP??g5X4R znSe(|Mfx3?k1XqF_pKe(YVSNYwO7P0c5zi>%F6@1ye0Y0;-vV085uU|N(9zEr3jUMbef)@jT5OMC^ld6Q;d|_B)0Zky}C*#SosPBP~ zcu9)m+ckEHj#$#1tQZ!@Sd1H2;R}ueTrz}@gi5wPh42G6hvNGJBwRYq2MQi(h#H%8 z1YOD^stzhxDI`sEL==fxoETHrUXu$-B`1{T-47oNnl8;tI>Wg$Z>1&^ja!9{ylD)O z;m*;W&;+jM&CAD)2*R4_R6x)fpbVIDjjFStPDEjh^vz;tqg(xAUa#D6q@dD4a6*gp z@mYdEp-C+Rc#6zvW?`$?acW;XyUvVL*R4-Bti!(!VvwoN+ZRncjjV@}R{ z#az_!D(g=CEWhGX`*DQ;Bzg$oJW2p&cAdF0jK4D-Jd;IqZGD%@v2u9apgO#k|AGo$ z?a#sWk(O^%KkpBDhll0iZ`QCfnN341*~A9|-LF?NY6@E>=F;}H)~l~rg4Hk`e$QShN39pu4*IXqZRo;edaqRR|SXr?NK zxTM}vLqtV3c|bVpEg7g1&!Yg9SVqmVZ+K>!)FfDwU_1}Ap%XU7Cg0J@+|xrgmN3fF)O&W`y-EuM_`(Phz5*oZN2Qt z#d^}f?MI(Xd890xRH=j4MKT6L@5yJsqK^gy(?3kOJPrIm|IYU5W&i`el}-~lT9=5F z3jRKrimedciy^@NBk5ydd2{w%y|7W7@D#5(m|ctZOag5i&&JSLU91>MYz@0brK)-W zGmV-L1wMi*Cc@}R2-49$pPd!7rV|3?{?SWLr8HNGt60;Jg_~Y z`-8AM;+43kBz^zpg5Jp#ppnp}NSJy?*%sj0SQzLvFgk%kb(5Laz#yy34uF28!1tIy zmIIH)g&~O$@kH05L{m?ua}^CJE+rSwPn7WwsOaylo&P1g+yW8;hw=(kuRvcy+tC9Y z%GKdwas#toD*UjymYIH|Y+(=twD^e3-50VBFp=;zb1Mzm4cAE{h?C5%gAF;^GuY)H zAK~U=9Du$`Vl%yG#mvIO(`UW>*-8ql`0wEJ8ELl%a30G^a^bnI0Yea2xZQ*<}iw_Z-@W zgqtuMsmH!?+=}6>s>hCC4&o4OWK2O4n`h&6a3EGAd?9@A*$~h^T`Ve<$jC zM#nrVPQcf2!y{jvN5|EzJ&xgq5R1DpAZ;TJAduD2>yI~w1rSWNxQ@~hRe>FHVV-#* zxAnlLFW}xyE$o!rB?;C`?Y=?7x#jhPX#3pm-A1RnrAf??Sy3Z4_x%OgKmqiAFxBR@ z@I`G!zZAE@UXq7Rx3$4dB)4>B3xzQp-S+OP0@8%EUH_en{v$zXg~^DiLdod0Du^h< zO4?|z=fw9bGRAcc<+MbosIBut@_X&4-^ho9wVG#_c@#yzI;i$uEQ$8lU!{KTar813 z?~mXl2=R-K?43pjo==}0RpC?DZh5U|iPJ#y9BPb6MG44doS)eENbLoG-$(QB6Z$Zs z1B7Hr*7<6h=dkDl*LwBL#CEu3=@>+=?Q)iMcwocbP8{blX(KMcP%Vm&^{gm&LhQ?& z|8*SNCL5+W1EO@D7^NbHbzA3gDYsxXGU%)7T9JPMdpVZvbPe||?>X|p0w8^}3B0`%RUXr@*Z^d8tjwRTj;kjN&-~G? zu|~QNptQ%#2BPpC>VovkLKl88#J4a4nBC6>XK))oq<0=LVs^bn-VFHK-6#({uOS$2 zZ1O)~U}s)Q89kq7VfFjy4Mf?C|5;ndGf!4p;n#bRl-Hg?clU} zdH1x;=9Q1gGY63Ah{t&1UektuApKMx1pl|q(EUH+%7yX2;%eA7vYD29y6A>)5-e-Z z(QnHs8FeF~gw^b7>m(9MBelVd@qOolKt1s&*1&4lhUjLSi`(aNqO_?8w@H_>oiXKJ zjgjA_TpWMn6n)T_NJVG`IPkxtup4dJ-_aCBE>5?rafZ^U@YH6}_H4Xy z8Xb}l2#22J6fXJIgcAo=iq$D1@{j(tI7)2LE_r%L%{zlGPP2N;f`vy`{-6|T1zExc zm&}e8938CZZezBbpFY+qZDyZlK%asS*$%+wS=5b_P>wk>%#^eMNK3;%#466CZ!fskmRxooRO_cC2j{b zbXiNvO!QI<5@k0%*j>I^2$T9aQ5`3M^pVtM{a_07u^i?PobrU052b}bf)b35xL`Qf zfFs3*fGfNf1ngP^>h0|?Nw`yKe7~}2VNG`+zqbFhn`=c;NIL4Hg_Mqv4x$!XDFq^1 zL3!rk{i}KL37}VFAmso@3uU9K0}%kZ8o74LUQ&Q@3!x(VjS@2ymLz?Y8rVm)7XuMd zAJt8ch7%FQBq$%OXAv{YSHg)>zj(@H5Z+)S2s4ChsOHxJ5UW8Ih|qyq6e)@+mL^Iv ze;ejXvJz}cO`^VS|FXbDILC|$B$b_^_4%tXtp+iyKRY1@VtLcVP9j~m@A-~5fTwdK zoo?4>CMnay``7^;u|I$_vk809u_unrMr2oW|*QfoJqstQr<9+2(A=x;x>4x zVMPseU>5pE7TjmXbI^;bJ{cyiWpEh9_;1H-g6v0OJyrFe+r$Ak)cNDFl=E^elE8RG z9>j@m8-KWbYQ${n+Q3oE=1z_usrCJFfsv`>=C9rWjI5b^`stp@x@ad8#B`4r;HV?- zcXy%J5_&3^V3aLlp{b3XbWaJ;!AlCCVjJx0A)`RMA=1Rv`f8872}eS$lr-hUoUa65 zpqh&c{0**}tlhkWY&=I!Mwx>PHsI@Uv6Yzq(6uBl-E8vGofKhZhHYqP%pYkJvv*CZ zqQO1^O#X{#uFuKeY$+H5OD$3aZBbGkBo#ncUPr$Wl`Me*f6utYXl%{Ff}s%sQ*(Hh zo2Mip@b7l2L{~8Nx&C4sE-08PXMvYFmGaVj&S0rxbA6KBxC^)S$ae(m#v+i6JG;tx zmiMu!$qFMR_xdZ#8mmter>RZQ&4b_~x)YQKP;{27EOzWhp7vx&bW*c)Dv|L8H2 zNfJK!(v-{SdZA}V{bfc!lf?!%i@DN7Aa?REB?90}REM&GWp(+vD|}0w=&ALm63}%F zm>lI);F};*9Z-|)Pg5Wl7z2HR5@h?16!Rq?h(FU~7~v~H%G!9ft1Mg>vhxkN?&SdT zd<+nUEXk^fQV(rC$7Y^W?_ADQ##fvE3hwEQ~>~o5R2OoZF9{ zhm{uw?Fi-OSR;>PUpI`)!Qg=$%`Qa-G+e&>yJsJY-OIrT=HHtuhAi?dN6{*uGx=+k z{ARjg2@)T~=Nr(t&S)lQ8Tz4mZc5Pyw$Yx+(Ej`u9sTp}DMbnFNHF5*9+esMn;yxA zSkqb}fE=i;5-57s_;rDJ(>BmN>ASuHkMXndvud#(Tva5bt=Z%K-jez)-V-DQ9n;tZ#QeknpYpK(G-8!+6?~ag}ie~Y1OM-*JRjPEbA=p+5GP(pTvv* zEY^f8Hv7;Ie*`WWci1wMY(VM(M*IH`z;zGZRt?N{i2e&B@a+u-F+HtHoX6Vf?XOUz z`2~x=5}|pe^bhWLygoN37!K|6eVUOMNSb&bIMGKCbLrzcBBUn=UYaz?>!~R$Q%sB# zoTJx?+!AOiPUUppSvMc_%W)A7sQTRWBL>`Jh+B;N93_{H*yI^!dp#gdV+ktowsN2Ug+*Mcj1hC9+S3ESrm?~Ayyz9>WL3q6+J~~oAuUrqN%ex2Hw{+ zH57P#=P%}o7zREXw%E}CCjBd83WoHtf;~azO;#g9xyR=6W&cWnRlFf#kD-{1$^KX9 zu)@3yr32D-ScywNy{$^cw)HyVdMS)&MMM%TAr;@Nlkr@c3_`{%b%-{&n^_qp&eBZRLz2i7#eld*LF{yU4$imGVH=VWD-lLr*R$R9TTYu z1UdoPZgGN^*&sil(r)n)9#tUwWbtN%NNgobr^G7zcRj$63@&KQ&Yp&_Qjb3 za&i}>{+8G2G$alXCho@y>{zT48T|Ef!xwq;tXa&=NFP?it93E+&=OdqnTx_i8w^Q# ze!Dq%!Cayq+z^4g;sk-B2xZE=wE#K-K8nMFFH5JnMF+9t&=?g~*1q32h${$l6SlV< zix02WCgE)0AV)y;{I~6RuSQEx~?$GM?8!O)@ z<>B&M|9APXq00NJql;sAhg9Eb!Vv$wceeEWOSzI%`Q%(_KzLQxRbk1mJHX|sAd--5 z)j#4K{dg4s|N7;-4&cPgVRyPE0jYpME5)3*v~SIeWssML$OikrM(44X&;Qh*e)s+c zIffU48|zFK+2t%}WOK#S%PI3-Fu4W}NH&XUQm7?0nz(-7@+v3QSX>obHQ37?Xp-Fd zb?@P$I=4`wV@NMhdwnp6jB!NyJ7{O?jBknovb*j#c3Tes&GkwmQ-B3rv0F4prGn|k z^Y9oYjyQre)xSp$oGr%}r7s=oHZAkaO2MJ3rrwhQ_%7qvsg*CsD)h*%KVxPj2f+m# zHnd`vvYe(QRgrdPZt;0ov$#7~h?8xPir@v4FmqJ(o0rPiDPAV?J$(DJ(6^j%pFO(( zuT)M6FiY?WrM??@h@GR|{58Pd)$a~3z+TC z=j7AW=*Zp4M2e~UkRjP`=#L^px%P2k+FVX7;ho35YoEtEk_Ku+Z`F;Po?YFQ^=Dph zYZmXyu02P#0Z;Q?WI{@l3df<~j@1ZY@S&U}4#6+2OF_%i!#*YE#_C|dd%hEMFCP;_42t8<&`K;W$^JLywjmGor+nFB>g;CnC5Am zd=Z&VF#uFc-tRDMdPLTYn`8{|#*gMHrW~airJCirXa`q|h>*|Pxz_MITiZ16;2B1^ z=7t?7IO%4<#Yd?Z@J%Y~CqR0*=M$tn5U=m$8G$cmA>&SZEz_vfVl&>J?Ev-kqo35i z4eiFUZ%jmM#quS%opKEY<{=^hZ=n?5LSdk1MXe$l!{qr6+su4%CK~{F)j>F4*>C^{ z5ikqDF1)?sVOsgFEea8Ax~i|%;Q8ED_iq878h>a=xyMl^H09(A(#rt9!cS<3Pox|_ zcl(wCPb^!i1SaBR{tOJFkO|6qjkUrz5^@?Us+C#4>O>)4;87yY51nBw@|GGJyJ+ zl>D(QOvfMvJ)B=CCz`JR$PzIQOW4#NaOE&>$L-iJ+b;or}=r2bxB9`OQ*}m!Uesd3NFJtaT0X zWH?oqn?#9rmm>nSw4Xr~zP%ykYm@B84{H=yAsNu^s;)_(M8iRdPBVLzB2jg8|5VZLtrx)&7k}nfoKBlWK{3h@%dP?(#)aA zHpoa!3$LuSm)1lI$+Y6v(qq%Jxv@*FI<<)G&jIdji>?jWpz}Wo=$q$AZ(iTJ81UV| zu;?;A4~O-c?$K1=HTz{!8x~x%f2o9hMR7uP2@jII70IM$JX!g?Q`=rMdD5HmYk@%o z2O6Ea0#HS=fh!_fDD}&FQFzaak}@E%8B%E{)Z_A*w|1%WY=SC&0Nt=R92myc3?wou znIFZ#pc?}S$4GduEI5%a&a!)g@Db^6jFnG z4{gtLL+b{Lz@=GN8S4V`kL#uzAO|@l9!FFbA36h08QHYT6J@(Hk=f6fDy^}hsS2Tw zTvU>T`f!d6k%|?c9wuE5(=6%SpDnej8w{jI$I7d-FM#;L5q!qOQp{qPZRquO%Z$cq zVUJl>s!lJL%$LIcYGh~DK2mID@15!M2vVYrcLoOw_3n>)pnYHsJ4sr)R%_7TjxOGM z>Yg^n=HI+1x4d-|L zaW(0GdV$u|4-HNgOzD=I_rPq$EDR5 z4VyM2F^7`uHX1~fQ5IzMAH6A@*J{bHmOeX>i~YF)wYwXyS35?T&SoyTmd^J{-3YZEadK{G zY%Ol!-9c?xyj#?O#O@R|6M>YV}Cjva(#IG zz(n)MmM$jz(cz)L$v1&%TI)hk1%!5NtyD~A3?n%tbJ_4VUt9gWeqM7yLl?x`(e9|B z$NT>6dtLfsajvCI-qSdl-2)<=XVbo2TmN6BKZc`>)89$K>@< z5ct^l94U1Ag4(Q%SqCd42 z3dZqHGdtPyM+-n>9weq-BK*CY#Fm{ayJ;nL#M>FsRJAJIGokx_RKi6FNo)=bu^Vpi zNU~8Sn;h=8$_UTo8j6`v__eZiRJe$Sdvg#OB|?v2h$f3P4IQT#b#-L_`f8hSRbMS# zYK`ksAG^f6eniImdUt;G0yuW~X76G2U?T-+ARj>~-Kn5bO_7mQ$)onF0P=1LYuOzH6=9Uy2=}0{HGm=RiJ1YxBMI zBKufQ;UkvDsEpjw?6Y#35t6z!YjVi=c3WXK=A5*^@S}o1{55d!+u|Eg z%xlSqb?sK?CV=Mf@W&9cLV3KRIz%)np<9xy(~&NTuS%8xGG+&aa2y=^U#W%l+&MuN ziIFvsn;QmpKFw10^cojj);D-q@wJegE%A!BH-)F0(@bM$c+_P%uoj2e`iZ_`!~hC5 zB}z}Yv&W4|XPXELb(Y`OEZ0@7-62#Iz`Kl{W(`lkKb<6GxQHVO-I?HlDEZpE(k_Y@}XT;M0>cu8MJ27egbu z0>H;~qCtbh)&9>&`Kc@i&BToe?W9={=m%t)PNHWQj7vCwea19DB|VN?mlT5UsJF7u zDLiLN&fXRSb){N)MV9yoUM+@=rnX^1n7Tgi;JRohM~Dbb0sJ6_|2iHtO>n#F0))fl z@crnD#Ch{oK(TdO|JhV|I7nkc*~|}?I3R^p=OaE}udHYh1~O8p4c&^@gw~Kfz-D-B7oiyqgEo;ndI!jR9P|NEoRSKb@Ef0H7Gy zE>R02P?CGhT&BtM+-TNkQPB=q(^?a-V}p|}XvfwF=I!1cWZBHvqJA^4u9x50{kYXt!nacV1i$JS0FYGfvW+5FWNxAzm;ca7jKWCipPb6u@=izsW=zis zFpKE)R=x^Roc?Eq8jP<{0x0e2oLgLTDv>FSK$oN4DRY*{*aGVWlE1p2yq!*^67kjta7Dh3IR1laf=S!U9;v229K&(?jBnF$KSfmisN7229S&+j5@(D zeMEkCDx`2H?}N%f<7QcRQ?Q|P1dARcJoQ)F5m_A3rk3$?Z>o^ZEe{lQq3;N1Ll-vq z-nYyI8uuR2iR!k5$`xV{Wm2eKt8^##FEL}Q(qtFpD`x@SO3*6sw%of!(~&5KzpD=| zf=8UUZwsiD9%(1-zvo}R0bFAuWqzzFc_FNVI>Iv<(s6jenFT<@1hljTYJ~ugfn<;^ zPnF&jCBGaz3`muo5a9dU;?E)?=(PI<=tRfg42i9|y}ovhm2?FWmZ@R-2Aa;x^|F}= z1BVf*w%KX1zm&v?&9$bheoSl!Rf6adE+(`X&o0|F!V95Gxn1zK0Yows>~N$8jRafW z`V*kkaf~gDh*hl=XI+;0BU(&n{OP%;HvL3bobjo|J_83ygF8=)fafgvb>1A-J=y9s z)=B+W!-T2%lT|Q+I7p1>6n%OF|2T5; zsFsK^%c7x`u@#gC0iM*+IA*Nf-uw30)CUDW6G1x`~G)# zv!n5Um#Aw7LR|gzz=*ddOO)c=L^p1B_!=69fea{26A~+E z)W_jIsJA19a~huuSy9r18~?!CEDB7oqM;c&>MpuHTe?t=lrb9vr^gh5%yerh zsJ;KHC|i!#QCg6~glY%Jfv3OfW0ZKc6?gm+0Mb#1Qsj$_}O+n3Z7L$IiRphjTi_^Ao zjOkjK$Q^PUYg*XAK-Xmm)3F4^rIC}^$#lcgG0fTWkqfMzIVdgju;y*@fDgi$?9Y{f z0Ho5W_RuPZ5vpnZpqwwh+Y|FVSDuj zpR7drD=$m)uJAuF1$l!$`#C}>MisQ(>i1xgx&)MoQ)NlxCjcpubVgwk-BaoGyvT6X z!ZZL8T=9YD^rW`tElZXQ5?p$E#%3_jE#J<8NAU-{1rmmDVga(rf)RzaY|qjN06vKA z{39oWhZc(cXqm;XqM``Hw8W`HdF4CsI>?K0Buvq@p3QLQVrZOZK8>_Y30^0O!~yFF z0gA@mXygBtaV6kTc5QeD^PW(4#=eFovJ@@y6)GW=l1LGf6v`H@^Mw+TY`vDTm8C=_ z%OGo_k|k6^cCzpL{=f6S)A#-U-*wI9?tY%MNIp;kynlt*{(<$+C<-NU>Ej)Q= zr|%h=nn#+2s2J?n_G0-?>h#vqPlLWpYk_i!tle!EvbjptsyIgE^rq^lSrAba%a_Ar zM=mbDd6Vk7)~!h0Y@cjtKYq=|wQ{gm(%R_EmUw_XVDE zKHcO|?l@=(&1fc3w3dA4mESlMGuq2pJ6ASSZr%#g=l(fzy~xbibSbdj=2Yn258bb~ zSdx$3$|KoyObfh{_aMwxKDvL#m*H$a>t=hFan}vfa`IZbm(sY8pBwV%)*<31m5E-t zj~v5=v@h9TWLr_QIGvMO$yxuJdMa4SWv(K)B=ddt+DJ-{IZHu%u7FiXjd0%7Ji~Ab z7d8F9P`~)Rsb+<1>^)@$hJ+|7rW=WecvM))##D_5d>dW-LrvpS@Qq>@oJ$r8vn5*A ze5Ar#$g(#K!-S%vyv(mgT~H=iQ9?Gji(PYogE)Byc}FZ5F4xVo!I^P z!wchq*N0u4o73X*D)d(~ldnmFSM{@3M2vdaqs3T$;ok=<1g=8szm}8v?76ilbEGob)V+rokZ<(y1_el3<^>dPhf(2+t>vg6SfHJ*>{Q>3Q_F(FyDCC{4; z1HN2ym)@M?exNzJ@@I;lqF;9t+qU*QhFbM1>^ufP$M5%0$jfU@DR*@CF6A0n_u+jK zNzw0Y$USN$SM|2A_KgPh+KqWHIXkO#Z)ktUA)J1}WmH>l!k)unr%)VM(d-FMD73C$ zUT2~CFBfuZaX?+WfM*!)gqwk8)mer5HN4yypR$)=yipyK!qsiTw1M}03@}I=yqP8ebC2ak; zNjV>S5sQ27mDn$Ifc+IWvndf?-FaMhSdE#(Uw!72)u?2Rjel^x`v(8%ca93zwVsJT zlojzK^y+zA6C7D7gWFAH%5~O~3>vzguRb0QU=k0}=rwLDynnKh`EdSejub0f6R>e1 zNuT)!O!^Cd`HOZ{z{>|5XG@>3K3=1nyI#et|CYcn=HWtQ5#&YS@S1J_WiCLZD=lznu7GyzE3{I2F7gKF0ukRkjmz&j9 z@v@RGb7p1A=sF#5t?Di!3+xzJG#L94bC=8#HPdU~5>{OK(cw+Kd5Kw@zr*+3M=j2C zidwhD^8#?~mdwHano&<`)LM5vHcPYk`xMKzi9)98edO;>3H(0Ix(>=G;WC}?Nsf|a zzk?gf2o9|269cXRTN{^%JXuFqo+Q>P%9aKFwA-gd-m7=SCyrC}eq|`%o>;{T>2I{% z*exr|6h0UF&V7AUFWKqA5lC&d+x#Q~xwE5SC!3r+r$~gSiCxRxOJ?cD_Or~A(;5xK z9LDLHhf*5F-p@ws%3b#BDJgPvr>?%(mCvc`CN!( z^s{Mk@D1;kH81gWzD3)a#i44B&$0cRawqL2GZPDWMUNK~1_E_5471sjLGP9KQLW|1 z+KM7SPCNO|oZhu3z~sWFkYDdxW2r^EhJIU~-#V#yb@jSw@?449tmEBHv1?B7!dmoh z)}`x$3}xy!PG{Df>ZtayT9Xsk_SB0UoIl0fu)5GPT+A_5Q7c!dD zIanHpE$Dy>Q!(0t_U`NT?d!!OF9zhrh`gAneZ7Qpluk(p8@${C@~xQirs_rdA@oQ7Ri7%Q{$=7 zIVN;-F&=4q5eTPdLsD?f0APoIWkak~?E)wOk2d_h5W0)Wn7xONW9U@{bOA%eFOWTk zylbH|Oq{eY@iWPp;H;T&I06?ArvP&nK!Q}3Z;&_U_V_1ch@sA3P$Y(KcS5!p>g|P2 zFrdxu?T4B$jyM9jU?^Y$`pSx0EmxonMig=5K`>@bA%FuI8es;ZSn}Si;4#MWae%W} z#5HbUg>JpnW+}jiaYHh|4D&lI2hKpKaEC{}9MyT;5|ai${l^-9%DQ2>JAJ2+)S!IUNX6n?ry)79j8h1Y;;Y5`4sv zM+~UO(BTB|9YbPCpc_Mk7r-1##U>quV_jQ%^=H6?GC?2acby96G353R3}MK+7$h^I z6HMNOpce#lmH|~pJ&FvhTLvV^KU{vxv>uq^I@FVQyKgU1dU15Q`r(kr70VEP;&pZZ zD#f?*F0W)PlHITK-G5jvX(|k9)s%TRG&EebANBlQZ)Uh~s|!D;Gp8as`!RL5_uHsf z16KBXGNUS%mShvQgcF}>gy9Wr|WmI_OrAm#qKm@jqr5s5P!i}FXh)ExI2}cr%q(fYh`Df^KJ-_q)f0M zY?RisHyuH_~iFmV(Cq?j}+3Jr^@zEKHF64j1yILT~d{H7~uAG^K)zUXW0Rt zq*jTdRi-T-a#d^;r#{ZjQOr&R)?kx8iINki_s*wfoxk;{^6B=Xnh42JK3%Jd-CLgS z5RXVr-MmA>4@%9!%+4OP= zF9L5ii!vPbi{PBf$x&eHnF)v|Q$PHA6^8FmKXyX_?>N#F>f<6+;+N)`Qg}B!HA*&; z=Zx{z*M}RLaj%V7{kVd)qE#w_i#y66@R-?^#GY{0&Po$!2|N}s<`Uy~DK;=m_w^PL zF`iB>8y!F7ThmO>wlDDV!^6uio>XHNA%#tEj+{KCXab> zI;2)j2XDXA#={&^r&MoRCd}vWMqc#Gv`^LI@XtOa_@2-7ty|l9>J|5qh0=_SvpvZ# zayQMV#q9s#_G%Q=@}4uWYJV$IWiNgIyJ^;~@2UYYn&Lkk+fL%;>RX>dH{4WDz9BW& z7`~)VSy!jo#SHGK*RF5uQ8?Xwt;RuOD&HqEK0;%MpKM!_NJ_Gm^(p%pbIyC@?6)Ci zdy2>3Xl@_0lQ+2Ay|Kc{7Lpn|XsrA0T-Y?BHlu!5R4JvSwZipO$I$$>u;nYg7k&F= zt5lZ)-xKT}aVJGVKa~$`b7o*I4(s|$OH4suh%F^A;y%GvU8RcUtV68tbduJs$$?h7apYfqKbN;lkFUMJYqK3 zJ%Dq+tY;45jMAx^0itQL;apwWk*B`0|D81a@&6Lp@$Hl53bx*K*C&sS+@n%NdmAF}p)_}0PX-1%CC z3XZJLhBeX_%j&uZ%d-W)5;qd0@!am-EtNQZ^Y?-`C%R+qu@%lQmEH=U&*IoF^66)j zLVSF_*gg}jwZ!ddu5h9@2S!t?J@*K%!Jmfb$KJ9jS+b9Y9!sO`Gbb89APYJ57{Ld|2j zUg-Sn;N>roZR1ULw$;Uh0r5+5gT?FLa(r~wxNC_#mOpUgaMX@Z;6Apq+gF2ZY{!p1nU1>#0T?rf&D0L+67Mhb5RfDkPVA2d@;ecK&o?yVfds5G3^t;k zIgY12+1PM6;!dP*>pUMsz+yc>8TF!;4IODhMgXwja6;?68k6CxJ%EJuvXQB)v{@C=PU(&pU;IsWe7|rumKhn(NYuIQ22*R2D^g^}M*!x)+Tb&KD z!$(KJMsyOQhvU2bfRDi}hh{&3=7k=Q@i-iX0f&=a*J5uz%}W^mIsgRF7KaBAZE69H z6@XU?AtCtdpP|$rL`-{2F_YIIAff>j8vD2$V}DdYY;eaQeUQdzriIU#Y5x~U7# zn~n`3Cfgd!^s*M(h+IF2XW(I^6&<}#3r?VUe5l7fkh3@O-{2LR$)yo91r7racwh){ zqCL%7kocmHRKOQmJ=@pyw5;VHe_7P^R*~y~6ynN?6l?vUSax8pBg6DEY#c!v{MduB zn|?!^&;dugZ$UGO^kJs35g>u7YmCw> za0X!+HJ2gy$_hk+BgVi+bkbMlKKghHk$i)syM9lYS%cuOqd*?bXN{)m#{}1oBHLUw z0T~a}hxDaNYF3E3#S|z)Lbf1{R*6&nCGEB$%`n)|sI1)puyb10^_m zg1)1s%5as~BB^F0Y69z$$kT({Cx9%P1oI>kcG3`*nFKN@ag;`^8Ns5{NQHbR>60wI zRqGHh0f*~Dx+A$x?8!;YwR#fpqn$S!4m7)gjQKre%-65=q0=;18CY%#aH4JPpF-M7 zJA<)nXOVZY0)KX!c$$gX3NxLtMohG6fkxq{5mU~2nn?pCtPp}R;Ua*Yospd3X}bDL z8hzj@N=w0k%k=Oi8ZGHY_rB;3Ho||+&~5rNh|SQGZu6S?v*2lT$Spek^ETl9cajP- z4{DSlMVtD+4Ulq|9w0vp_|XEBkCH?lA|+90{@=|q{yyFJ_8;Ft1#Z$1qDw%YUNY-O z+`*sjTQiHKMSF4&(?E0(otB)VuVKwOgboX))5tqYBK&BM-qRSGZ7GayYoPs$rZhnV zK@oIXcAoz5(3nSPGYXxKi$RnE=jlomnvE1sw_Qm9;{R2u1;mC={MW_{>n{K$xDL^T4M}D1- zNj^P5e+fvSI#-vF$$78{4qO6C=yE{cMk6cdJaPmOTo*i23b!tSEoiF$eac(EShGF? zSh)_FaeJ5P^ZMvAlB!-6oqkjeSpS{e6q=3UD{2#in~*t=%C|Br;Vh6Ilpx#I`e(gY z1AsHWA&XLegH-4;rShTmS$7 diff --git a/dist/search_data-89FED348.js b/dist/search_data-8AE95F7C.js similarity index 76% rename from dist/search_data-89FED348.js rename to dist/search_data-8AE95F7C.js index b00d6903..569ef8f0 100644 --- a/dist/search_data-89FED348.js +++ b/dist/search_data-8AE95F7C.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 available version, when the requested path exists\n\n For example:\n Requesting /api/test, will try to redirect to to /api/ /test,\n only if the /api/ /test exists, otherwise, it will continue with the next available version.\n If the route doesn't match with any of the available versions, it returns a not found error.\n\n router and available_api_versions options should be provided.\n\n `available_api_versions` option should be a list with the available version from newest to oldest.\n\n For example: [\"v3\", \"v2\", \"v1\"]","ref":"WandaWeb.Plugs.ApiRedirector.html","title":"WandaWeb.Plugs.ApiRedirector","type":"module"},{"doc":"","ref":"WandaWeb.Router.html","title":"WandaWeb.Router","type":"module"},{"doc":"","ref":"WandaWeb.Router.html#api/2","title":"WandaWeb.Router.api/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.html#api_v1/2","title":"WandaWeb.Router.api_v1/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.html#api_v2/2","title":"WandaWeb.Router.api_v2/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.html#available_api_versions/0","title":"WandaWeb.Router.available_api_versions/0","type":"function"},{"doc":"","ref":"WandaWeb.Router.html#browser/2","title":"WandaWeb.Router.browser/2","type":"function"},{"doc":"Callback invoked by Plug on every request.","ref":"WandaWeb.Router.html#call/2","title":"WandaWeb.Router.call/2","type":"function"},{"doc":"Callback required by Plug that initializes the router\nfor serving web requests.","ref":"WandaWeb.Router.html#init/1","title":"WandaWeb.Router.init/1","type":"function"},{"doc":"","ref":"WandaWeb.Router.html#protected_api/2","title":"WandaWeb.Router.protected_api/2","type":"function"},{"doc":"Module with named helpers generated from WandaWeb.Router.","ref":"WandaWeb.Router.Helpers.html","title":"WandaWeb.Router.Helpers","type":"module"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#api_redirector_path/3","title":"WandaWeb.Router.Helpers.api_redirector_path/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#api_redirector_path/4","title":"WandaWeb.Router.Helpers.api_redirector_path/4","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#api_redirector_url/3","title":"WandaWeb.Router.Helpers.api_redirector_url/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#api_redirector_url/4","title":"WandaWeb.Router.Helpers.api_redirector_url/4","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#catalog_path/2","title":"WandaWeb.Router.Helpers.catalog_path/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#catalog_path/3","title":"WandaWeb.Router.Helpers.catalog_path/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#catalog_url/2","title":"WandaWeb.Router.Helpers.catalog_url/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#catalog_url/3","title":"WandaWeb.Router.Helpers.catalog_url/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#execution_path/2","title":"WandaWeb.Router.Helpers.execution_path/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#execution_path/3","title":"WandaWeb.Router.Helpers.execution_path/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#execution_path/4","title":"WandaWeb.Router.Helpers.execution_path/4","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#execution_url/2","title":"WandaWeb.Router.Helpers.execution_url/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#execution_url/3","title":"WandaWeb.Router.Helpers.execution_url/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#execution_url/4","title":"WandaWeb.Router.Helpers.execution_url/4","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#health_path/2","title":"WandaWeb.Router.Helpers.health_path/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#health_path/3","title":"WandaWeb.Router.Helpers.health_path/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#health_url/2","title":"WandaWeb.Router.Helpers.health_url/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#health_url/3","title":"WandaWeb.Router.Helpers.health_url/3","type":"function"},{"doc":"Generates the path information including any necessary prefix.","ref":"WandaWeb.Router.Helpers.html#path/2","title":"WandaWeb.Router.Helpers.path/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#render_spec_path/2","title":"WandaWeb.Router.Helpers.render_spec_path/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#render_spec_path/3","title":"WandaWeb.Router.Helpers.render_spec_path/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#render_spec_url/2","title":"WandaWeb.Router.Helpers.render_spec_url/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#render_spec_url/3","title":"WandaWeb.Router.Helpers.render_spec_url/3","type":"function"},{"doc":"Generates an integrity hash to a static asset given its file path.","ref":"WandaWeb.Router.Helpers.html#static_integrity/2","title":"WandaWeb.Router.Helpers.static_integrity/2","type":"function"},{"doc":"Generates path to a static asset given its file path.","ref":"WandaWeb.Router.Helpers.html#static_path/2","title":"WandaWeb.Router.Helpers.static_path/2","type":"function"},{"doc":"Generates url to a static asset given its file path.","ref":"WandaWeb.Router.Helpers.html#static_url/2","title":"WandaWeb.Router.Helpers.static_url/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#swagger_ui_path/2","title":"WandaWeb.Router.Helpers.swagger_ui_path/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#swagger_ui_path/3","title":"WandaWeb.Router.Helpers.swagger_ui_path/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#swagger_ui_url/2","title":"WandaWeb.Router.Helpers.swagger_ui_url/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#swagger_ui_url/3","title":"WandaWeb.Router.Helpers.swagger_ui_url/3","type":"function"},{"doc":"Generates the connection/endpoint base URL without any path information.","ref":"WandaWeb.Router.Helpers.html#url/1","title":"WandaWeb.Router.Helpers.url/1","type":"function"},{"doc":"Minimal information about an Execution accepted by the system,\nit carries the same identifiers provided by the consumer that requested the execution to start.\n\nThese identifiers may be used to query the APIs about the state of an execution.","ref":"WandaWeb.Schemas.AcceptedExecutionResponse.html","title":"WandaWeb.Schemas.AcceptedExecutionResponse","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.AcceptedExecutionResponse.html#schema/0","title":"WandaWeb.Schemas.AcceptedExecutionResponse.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.AcceptedExecutionResponse.html#t:t/0","title":"WandaWeb.Schemas.AcceptedExecutionResponse.t/0","type":"type"},{"doc":"OpenApi specification entry point\n\n`api_version` must be provided to specify the version of this openapi specification\n\nExample:\n use WandaWeb.OpenApi.ApiSpec,\n api_version: \"v1\"","ref":"WandaWeb.Schemas.ApiSpec.html","title":"WandaWeb.Schemas.ApiSpec","type":"module"},{"doc":"Bad Request","ref":"WandaWeb.Schemas.BadRequest.html","title":"WandaWeb.Schemas.BadRequest","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.BadRequest.html#response/0","title":"WandaWeb.Schemas.BadRequest.response/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.BadRequest.html#schema/0","title":"WandaWeb.Schemas.BadRequest.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.BadRequest.html#t:t/0","title":"WandaWeb.Schemas.BadRequest.t/0","type":"type"},{"doc":"Checks catalog response API spec","ref":"WandaWeb.Schemas.CatalogResponse.html","title":"WandaWeb.Schemas.CatalogResponse","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.CatalogResponse.html#schema/0","title":"WandaWeb.Schemas.CatalogResponse.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.CatalogResponse.html#t:t/0","title":"WandaWeb.Schemas.CatalogResponse.t/0","type":"type"},{"doc":"Individual check of the catalog response API spec","ref":"WandaWeb.Schemas.CatalogResponse.Check.html","title":"WandaWeb.Schemas.CatalogResponse.Check","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.CatalogResponse.Check.html#schema/0","title":"WandaWeb.Schemas.CatalogResponse.Check.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.CatalogResponse.Check.html#t:t/0","title":"WandaWeb.Schemas.CatalogResponse.Check.t/0","type":"type"},{"doc":"Execution item response API spec","ref":"WandaWeb.Schemas.ExecutionResponse.html","title":"WandaWeb.Schemas.ExecutionResponse","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.ExecutionResponse.html#schema/0","title":"WandaWeb.Schemas.ExecutionResponse.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.ExecutionResponse.html#t:t/0","title":"WandaWeb.Schemas.ExecutionResponse.t/0","type":"type"},{"doc":"Healthcheck","ref":"WandaWeb.Schemas.Health.html","title":"WandaWeb.Schemas.Health","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.Health.html#response/0","title":"WandaWeb.Schemas.Health.response/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.Health.html#schema/0","title":"WandaWeb.Schemas.Health.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.Health.html#t:t/0","title":"WandaWeb.Schemas.Health.t/0","type":"type"},{"doc":"Execution list response API spec","ref":"WandaWeb.Schemas.ListExecutionsResponse.html","title":"WandaWeb.Schemas.ListExecutionsResponse","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.ListExecutionsResponse.html#schema/0","title":"WandaWeb.Schemas.ListExecutionsResponse.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.ListExecutionsResponse.html#t:t/0","title":"WandaWeb.Schemas.ListExecutionsResponse.t/0","type":"type"},{"doc":"404 - Not Found","ref":"WandaWeb.Schemas.NotFound.html","title":"WandaWeb.Schemas.NotFound","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.NotFound.html#response/0","title":"WandaWeb.Schemas.NotFound.response/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.NotFound.html#schema/0","title":"WandaWeb.Schemas.NotFound.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.NotFound.html#t:t/0","title":"WandaWeb.Schemas.NotFound.t/0","type":"type"},{"doc":"Ready","ref":"WandaWeb.Schemas.Ready.html","title":"WandaWeb.Schemas.Ready","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.Ready.html#response/0","title":"WandaWeb.Schemas.Ready.response/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.Ready.html#schema/0","title":"WandaWeb.Schemas.Ready.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.Ready.html#t:t/0","title":"WandaWeb.Schemas.Ready.t/0","type":"type"},{"doc":"The request to be sent to start an execution","ref":"WandaWeb.Schemas.StartExecutionRequest.html","title":"WandaWeb.Schemas.StartExecutionRequest","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.StartExecutionRequest.html#schema/0","title":"WandaWeb.Schemas.StartExecutionRequest.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.StartExecutionRequest.html#t:t/0","title":"WandaWeb.Schemas.StartExecutionRequest.t/0","type":"type"},{"doc":"OpenApi specification for entrypoint V1","ref":"WandaWeb.Schemas.V1.ApiSpec.html","title":"WandaWeb.Schemas.V1.ApiSpec","type":"module"},{"doc":"The request to be sent to start an execution","ref":"WandaWeb.Schemas.V1.StartExecutionRequest.html","title":"WandaWeb.Schemas.V1.StartExecutionRequest","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.V1.StartExecutionRequest.html#schema/0","title":"WandaWeb.Schemas.V1.StartExecutionRequest.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.V1.StartExecutionRequest.html#t:t/0","title":"WandaWeb.Schemas.V1.StartExecutionRequest.t/0","type":"type"},{"doc":"OpenApi specification for entrypoint V2","ref":"WandaWeb.Schemas.V2.ApiSpec.html","title":"WandaWeb.Schemas.V2.ApiSpec","type":"module"},{"doc":"The request to be sent to start an execution","ref":"WandaWeb.Schemas.V2.StartExecutionRequest.html","title":"WandaWeb.Schemas.V2.StartExecutionRequest","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.V2.StartExecutionRequest.html#schema/0","title":"WandaWeb.Schemas.V2.StartExecutionRequest.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.V2.StartExecutionRequest.html#t:t/0","title":"WandaWeb.Schemas.V2.StartExecutionRequest.t/0","type":"type"},{"doc":"","ref":"WandaWeb.V1.CatalogController.html","title":"WandaWeb.V1.CatalogController","type":"module"},{"doc":"","ref":"WandaWeb.V1.CatalogController.html#catalog/2","title":"WandaWeb.V1.CatalogController.catalog/2","type":"function"},{"doc":"","ref":"WandaWeb.V1.CatalogController.html#open_api_operation/1","title":"WandaWeb.V1.CatalogController.open_api_operation/1","type":"function"},{"doc":"","ref":"WandaWeb.V1.CatalogController.html#shared_security/0","title":"WandaWeb.V1.CatalogController.shared_security/0","type":"function"},{"doc":"","ref":"WandaWeb.V1.CatalogController.html#shared_tags/0","title":"WandaWeb.V1.CatalogController.shared_tags/0","type":"function"},{"doc":"","ref":"WandaWeb.V1.CatalogView.html","title":"WandaWeb.V1.CatalogView","type":"module"},{"doc":"The resource name, as an atom, for this view","ref":"WandaWeb.V1.CatalogView.html#__resource__/0","title":"WandaWeb.V1.CatalogView.__resource__/0","type":"function"},{"doc":"Renders the given template locally.","ref":"WandaWeb.V1.CatalogView.html#render/2","title":"WandaWeb.V1.CatalogView.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.V1.CatalogView.html#template_not_found/2","title":"WandaWeb.V1.CatalogView.template_not_found/2","type":"function"},{"doc":"","ref":"WandaWeb.V1.ExecutionController.html","title":"WandaWeb.V1.ExecutionController","type":"module"},{"doc":"","ref":"WandaWeb.V1.ExecutionController.html#index/2","title":"WandaWeb.V1.ExecutionController.index/2","type":"function"},{"doc":"","ref":"WandaWeb.V1.ExecutionController.html#last/2","title":"WandaWeb.V1.ExecutionController.last/2","type":"function"},{"doc":"","ref":"WandaWeb.V1.ExecutionController.html#open_api_operation/1","title":"WandaWeb.V1.ExecutionController.open_api_operation/1","type":"function"},{"doc":"","ref":"WandaWeb.V1.ExecutionController.html#shared_security/0","title":"WandaWeb.V1.ExecutionController.shared_security/0","type":"function"},{"doc":"","ref":"WandaWeb.V1.ExecutionController.html#shared_tags/0","title":"WandaWeb.V1.ExecutionController.shared_tags/0","type":"function"},{"doc":"","ref":"WandaWeb.V1.ExecutionController.html#show/2","title":"WandaWeb.V1.ExecutionController.show/2","type":"function"},{"doc":"","ref":"WandaWeb.V1.ExecutionController.html#start/2","title":"WandaWeb.V1.ExecutionController.start/2","type":"function"},{"doc":"","ref":"WandaWeb.V1.ExecutionView.html","title":"WandaWeb.V1.ExecutionView","type":"module"},{"doc":"The resource name, as an atom, for this view","ref":"WandaWeb.V1.ExecutionView.html#__resource__/0","title":"WandaWeb.V1.ExecutionView.__resource__/0","type":"function"},{"doc":"Renders the given template locally.","ref":"WandaWeb.V1.ExecutionView.html#render/2","title":"WandaWeb.V1.ExecutionView.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.V1.ExecutionView.html#template_not_found/2","title":"WandaWeb.V1.ExecutionView.template_not_found/2","type":"function"},{"doc":"","ref":"WandaWeb.V2.CatalogController.html","title":"WandaWeb.V2.CatalogController","type":"module"},{"doc":"","ref":"WandaWeb.V2.CatalogController.html#catalog/2","title":"WandaWeb.V2.CatalogController.catalog/2","type":"function"},{"doc":"","ref":"WandaWeb.V2.CatalogController.html#open_api_operation/1","title":"WandaWeb.V2.CatalogController.open_api_operation/1","type":"function"},{"doc":"","ref":"WandaWeb.V2.CatalogController.html#shared_security/0","title":"WandaWeb.V2.CatalogController.shared_security/0","type":"function"},{"doc":"","ref":"WandaWeb.V2.CatalogController.html#shared_tags/0","title":"WandaWeb.V2.CatalogController.shared_tags/0","type":"function"},{"doc":"","ref":"WandaWeb.V2.CatalogView.html","title":"WandaWeb.V2.CatalogView","type":"module"},{"doc":"The resource name, as an atom, for this view","ref":"WandaWeb.V2.CatalogView.html#__resource__/0","title":"WandaWeb.V2.CatalogView.__resource__/0","type":"function"},{"doc":"Renders the given template locally.","ref":"WandaWeb.V2.CatalogView.html#render/2","title":"WandaWeb.V2.CatalogView.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.V2.CatalogView.html#template_not_found/2","title":"WandaWeb.V2.CatalogView.template_not_found/2","type":"function"},{"doc":"","ref":"WandaWeb.V2.ExecutionController.html","title":"WandaWeb.V2.ExecutionController","type":"module"},{"doc":"","ref":"WandaWeb.V2.ExecutionController.html#open_api_operation/1","title":"WandaWeb.V2.ExecutionController.open_api_operation/1","type":"function"},{"doc":"","ref":"WandaWeb.V2.ExecutionController.html#shared_security/0","title":"WandaWeb.V2.ExecutionController.shared_security/0","type":"function"},{"doc":"","ref":"WandaWeb.V2.ExecutionController.html#shared_tags/0","title":"WandaWeb.V2.ExecutionController.shared_tags/0","type":"function"},{"doc":"","ref":"WandaWeb.V2.ExecutionController.html#start/2","title":"WandaWeb.V2.ExecutionController.start/2","type":"function"},{"doc":"# Wanda\n\n[![CI](https://github.com/trento-project/wanda/actions/workflows/ci.yaml/badge.svg)](https://github.com/trento-project/wanda/actions/workflows/ci.yaml)\n[![Coverage Status](https://coveralls.io/repos/github/trento-project/wanda/badge.svg?branch=main)](https://coveralls.io/github/trento-project/wanda?branch=main)\n[![Documentation](https://img.shields.io/badge/documentation-grey.svg)](https://trento-project.io/wanda/)\n\nA service responsible to orchestrate Checks executions on a target infrastructure.\n\n# Documentation\n\nThe documentation is available at [trento-project.io/wanda](https://trento-project.io/wanda/).\n\nSwagger UI is available at [trento-project.io/wanda/swaggerui](https://trento-project.io/wanda/swaggerui).\n\n# Developing Checks\n\nWanda architecture aims to simplify [testing Checks Executions](#testing-executions) and [adding new ones](#adding-new-checks).","ref":"readme.html","title":"Wanda","type":"extras"},{"doc":"For development purposes, a [docker-compose file](https://github.com/trento-project/wanda/blob/main/docker-compose.yaml) is provided.\nThe [docker-compose.checks.yaml](https://github.com/trento-project/wanda/blob/main/docker-compose.checks.yaml) provides additional configuration to start an environment for Checks development.\n\n#","ref":"readme.html#infrastructure","title":"Infrastructure - Wanda","type":"extras"},{"doc":"Start the environment with:\n\n```bash\n$ docker-compose -f docker-compose.checks.yaml up -d\n```\n\nWanda is exposed on port `4000` and the API documentation is available at http://localhost:4000/swaggerui\n\n**Note** that the [message broker](https://www.rabbitmq.com/) **must** be reachable by Wanda and all the targets.","ref":"readme.html#starting-a-local-environment","title":"Starting a local environment - Wanda","type":"extras"},{"doc":"With a running setup, it is possible to easily test Checks and their Execution by:\n\n- starting the targets\n- consulting the catalog\n- starting a Checks Execution\n- checking the state of an execution\n- debugging the gathered facts\n\n### **Starting the targets**\n\nThe [trento-agent](https://github.com/trento-project/agent) must be up and running on the targets to run a correct execution, otherwise a timeout error is raised.\n\nHere an example on how to start it:\n\n```\n./trento-agent start --api-key --facts-service-url amqp://wanda:wanda@localhost:5674\n```\n\n> 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\nseverity: warning\n\nmetadata:\n target_type: cluster\n cluster_type: hana_scale_up\n provider: [azure, nutanix, kvm, vmware]\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| `metadata` | not required | [see more](#metadata) |\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":"A key-value map that enriches the Check being declared by providing extra information about when to consider it as applicable given a specific [env](#env)\n\n- keys must be non empty strings (`foo`, `bar`, `foo_bar`, `qux1`)\n- values can be any of the following types `string`, `number`, `boolean`, `string[]` (list of strings)\n\nExample:\n\n```yaml\nmetadata:\n foo: bar\n bar: 42\n baz: true\n qux: [foo, bar, baz]\n```\n\nMetadata is used when:\n- querying checks from the catalog\n- loading relevant checks for an execution (when requesting an execution to start either via the rest API or via a message through the message broker)\n\n##","ref":"specification.html#metadata","title":"metadata - Checks Specification","type":"extras"},{"doc":"For each of the metadata key-value the system checks whether a matching key is present in the current context (catalog or execution env) and if so, whether the value matches the one declared in the check.\n\nFor a check to be considered applicable all the metadata key-value pairs should match something in the env.\n\nAny extra key in the env not having a corresponding one in the check metadata is ignored.\n\nNotes:\n- a string in the env (ie `env.qux` being `baz`) can match either a plain string as in `qux: baz` and a string contained in a list as in `qux: [foo, bar, baz]`\n- an empty env always matches any metadata\n- an empty metadata always matches any env\n\n**Matching example**\n```ts\nlet env = #{\n foo: \"bar\",\n qux: \"baz\"\n}\n```\n\n```yaml\nmetadata:\n foo: bar\n bar: 42\n baz: true\n qux: baz\n```\n\n**Not matching example**\n\n```ts\nlet env = #{\n foo: \"bar\",\n qux: \"baz\",\n baz: false\n}\n```\n\n```yaml\nmetadata:\n foo: bar\n bar: 42\n baz: true\n qux: [foo, bar, baz]\n```\n\n##","ref":"specification.html#how-does-the-matching-work","title":"How does the matching work? - 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":"The gatherers implementation supports a versioning mechanism in order to enable non-backwards compatibility changes in any of them. When an update to\nthe trento-agent includes a non-backwards compatible change in a gatherer (e.g., changes to the Rhai output format), its version is\nbumped by incrementing the @vN suffix that follows the gatherer's name, where 'N' represents the new version of that gatherer.\nExample:\n\n- `systemd@v1` -> Represents the first version of the systemd gatherer\n- `systemd@v2` -> Represents the second version of the systemd gatherer\n\nNote that when writing a check, if no tag is specified (e.g. `systemd`), the latest version is used. It is **strongly** recommended to always pin your\nchecks to a specific version of a gatherer.\n\nNot all changes in a released gatherer get a new version tag. A new version tag is released only for breaking changes, while non-breaking changes such\nas additional fields in the Rhai output reuse the latest existing tag. To use a check that relies on a newer field introduced after an update, upgrade\nthe agent to the latest version to ensure that the required gatherers are also up-to-date.","ref":"gatherers.html#gatherers-versioning","title":"Gatherers versioning - 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@v1`](#cibadminv1) | [trento-project/agent/../gatherers/cibadmin.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/cibadmin.go) |\n| [`corosync.conf@v1`](#corosyncconfv1) | [trento-project/agent/../gatherers/corosyncconf.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/corosyncconf.go) |\n| [`corosync-cmapctl@v1`](#corosync-cmapctlv1) | [trento-project/agent/../gatherers/corosynccmapctl.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/corosynccmapctl.go) |\n| [`dir_scan@v1`](#dir_scanv1) | [trento-project/agent/../gatherers/dir_scan.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/dir_scan.go) |\n| [`disp+work@v1`](#dispworkv1) | [trento-project/agent/../gatherers/dispwork.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/dispwork.go) |\n| [`fstab@v1`](#fstabv1) | [trento-project/agent/../gatherers/fstab.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/fstab.go) |\n| [`groups@v1`](#groupsv1) | [trento-project/agent/../gatherers/groups.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/groups.go) |\n| [`hosts@v1`](#hostsv1) | [trento-project/agent/../gatherers/hostsfile.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/hostsfile.go) |\n| [`package_version@v1`](#package_versionv1) | [trento-project/agent/../gatherers/packageversion.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/packageversion.go) |\n| [`passwd@v1`](#passwdv1) | [trento-project/agent/../gatherers/passwd.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/passwd.go) |\n| [`sapcontrol@v1`](#sapcontrolv1) | [trento-project/agent/../gatherers/sapcontrol.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sapcontrol.go) |\n| [`saphostctrl@v1`](#saphostctrlv1) | [trento-project/agent/../gatherers/saphostctrl.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/saphostctrl.go) |\n| [`sap_profiles@v1`](#sap_profilesv1) | [trento-project/agent/../gatherers/sapprofiles.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sapprofiles.go) |\n| [`sapinstance_hostname_resolver@v1`](#sapinstance_hostname_resolverv1) | [trento-project/agent/../gatherers/sapinstancehostnameresolver.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sapinstancehostnameresolver.go) |\n| [`saptune@v1`](#saptunev1) | [trento-project/agent/../gatherers/saptune.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/saptune.go) |\n| [`sbd_config@v1`](#sbd_configv1) | [trento-project/agent/../gatherers/sbd.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sbd.go) |\n| [`sbd_dump@v1`](#sbd_dumpv1) | [trento-project/agent/../gatherers/sbddump.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sbddump.go) |\n| [`sysctl@v1`](#sysctlv1) | [trento-project/agent/../gatherers/sysctl.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sysctl.go) |\n| [`systemd@v1`](#systemdv1) | [trento-project/agent/../gatherers/systemd.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/systemd.go) |\n| [`systemd@v2`](#systemdv2) | [trento-project/agent/../gatherers/systemd_v2.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/systemd_v2.go) |\n| [`verify_password@v1`](#verify_passwordv1) | [trento-project/agent/../gatherers/verifypassword.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/verifypassword.go) |\n\n \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@v1\n argument: cib.configuration\n\n - name: first_primitive\n gatherer: cibadmin@v1\n argument: cib.configuration.resources.primitive.0\n\n - name: first_cluster_property_set_second_nvpair\n gatherer: cibadmin@v1\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 \n\n#","ref":"gatherers.html#cibadmin-v1","title":"cibadmin@v1 - 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@v1\n argument: totem.token\n\n - name: corosync_join\n gatherer: corosync.conf@v1\n argument: totem.join\n\n - name: corosync_node_id_0\n gatherer: corosync.conf@v1\n argument: nodelist.node.0.nodeid\n\n - name: corosync_node_id_1\n gatherer: corosync.conf@v1\n argument: nodelist.node.1.nodeid\n\n - name: corosync_nodes\n gatherer: corosync.conf@v1\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 \n\n#","ref":"gatherers.html#corosync-conf-v1","title":"corosync.conf@v1 - 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@v1\n argument: totem.token\n\n - name: runtime_totem_token\n gatherer: corosync-cmapctl@v1\n argument: runtime.config.totem.token\n\n - name: totem_transport\n gatherer: corosync-cmapctl@v1\n argument: totem.transport\n\n - name: totem_max_messages\n gatherer: corosync-cmapctl@v1\n argument: runtime.config.totem.max_messages\n\n - name: node_0_ring0addr\n gatherer: corosync-cmapctl@v1\n argument: nodelist.node.0.ring0_addr\n\n - name: node_list\n gatherer: corosync-cmapctl@v1\n argument: nodelist.node\n\n - name: second_node\n gatherer: corosync-cmapctl@v1\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 \n\n#","ref":"gatherers.html#corosync-cmapctl-v1","title":"corosync-cmapctl@v1 - 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@v1\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 \n\n#","ref":"gatherers.html#dir_scan-v1","title":"dir_scan@v1 - Gatherers","type":"extras"},{"doc":"**Argument required**: No\n\nThis gatherer allows access to the `disp+work` command output and returns some fields available there.\nThe command is executed for all installed SAP systems, accessing it with the ` adm` user. The fields for\neach system are returned in a map using the SAP sid as key.\n\nIf the `disp+work` command execution fails, the fields are returned with an empty string value.\n\nThe available fields are `compilation_mode`, `kernel_release` and `patch_number`.\n\nExample specification:\n\n```yaml\nfacts:\n - name: dispwork\n gatherer: disp+work@v1\n```\n\nExample output (in Rhai):\n\n```ts\n#{\n \"NWP\": #{\n \"compilation_mode\": \"UNICODE\",\n \"kernel_release\": \"753\",\n \"patch_number\": \"900\"\n },\n // failed execution\n \"NWQ\": #{\n \"compilation_mode\": \"\",\n \"kernel_release\": \"\",\n \"patch_number\": \"\"\n },\n \"NWD\": #{\n \"compilation_mode\": \"UNICODE\",\n \"kernel_release\": \"753\",\n \"patch_number\": \"910\"\n }\n}\n```\n\n \n\n#","ref":"gatherers.html#disp-work-v1","title":"disp+work@v1 - 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@v1\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 \n\n#","ref":"gatherers.html#fstab-v1","title":"fstab@v1 - 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@v1\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 \n\n#","ref":"gatherers.html#groups-v1","title":"groups@v1 - 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@v1\n argument: node1\n\n - name: hosts_node2\n gatherer: hosts@v1\n argument: node2\n\n - name: hosts_all\n gatherer: hosts@v1\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 \n\n#","ref":"gatherers.html#hosts-v1","title":"hosts@v1 - 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@v1\n argument: corosync,2.4.5\n\n - name: package_corosync\n gatherer: package_version@v1\n argument: corosync\n\n - name: package_sbd\n gatherer: package_version@v1\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@v1\n argument: corosync\n\n - name: package_pacemaker\n gatherer: package_version@v1\n argument: pacemaker\n\n - name: multiple_sbd_versions_installed\n gatherer: package_version@v1\n argument: sbd\n\n - name: compare_package_corosync\n gatherer: package_version@v1\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 \n\n#","ref":"gatherers.html#package_version-v1","title":"package_version@v1 - 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@v1\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 \n\n#","ref":"gatherers.html#passwd-v1","title":"passwd@v1 - 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\nExample specification:\n\n```yaml\nfacts:\n - name: processes\n gatherer: sapcontrol@v1\n argument: GetProcessList\n\n - name: instances\n gatherer: sapcontrol@v1\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 \n\n#","ref":"gatherers.html#sapcontrol-v1","title":"sapcontrol@v1 - 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@v1\n argument: Ping\n\n - name: list_instances\n gatherer: saphostctrl@v1\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 \n\n#","ref":"gatherers.html#saphostctrl-v1","title":"saphostctrl@v1 - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer uses the filesystem to search for SAP systems using the discovered profile file names to get the virtual hostnames associated to each\ninstance of the sap system. It then attempts to resolve those hostnames to confirm that they are resolvable and afterwards a ping is attempted\nto those hostnames. Keep in mind that ping could be disallowed through firewall rules so it should only be used for networks in which we know this is\nnot true.\n\nExample specification:\n\n```yaml\nfacts:\n - name: resolvability_check\n gatherer: sapinstance_hostname_resolver@v1\n```\n\nExample output (in Rhai):\n\n```ts\n// 2 resolvable & 1 non-resolvable hosts\n#{\n \"NWP\": [\n #{\n \"addresses\": [\n \"2.1.1.82\"\n ],\n \"hostname\": \"sapnwpas\",\n \"instance_name\": \"ASCS00\",\n \"reachability\": true\n }\n ],\n \"QAS\": [\n #{\n \"addresses\": [\n \"1.1.1.82\"\n ],\n \"hostname\": \"sapqasas\",\n \"instance_name\": \"ASCS00\",\n \"reachability\": true\n },\n #{\n \"addresses\": (),\n \"hostname\": \"sapwaser\",\n \"instance_name\": \"ERS00\",\n \"reachability\": false\n }\n ]\n}\n```\n\n \n\n#","ref":"gatherers.html#sapinstance_hostname_resolver-v1","title":"sapinstance_hostname_resolver@v1 - 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@v1\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 \n\n#","ref":"gatherers.html#sap_profiles-v1","title":"sap_profiles@v1 - 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@v1\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 \n\n#","ref":"gatherers.html#saptune-v1","title":"saptune@v1 - 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@v1\n argument: SBD_PACEMAKER\n\n - name: sbd_startmode\n gatherer: sbd_config@v1\n argument: SBD_STARTMODE\n\n - name: sbd_device\n gatherer: sbd_config@v1\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 \n\n#","ref":"gatherers.html#sbd_config-v1","title":"sbd_config@v1 - 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@v1\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 \n\n#","ref":"gatherers.html#sbd_dump-v1","title":"sbd_dump@v1 - 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@v1\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 \n\n#","ref":"gatherers.html#sysctl-v1","title":"sysctl@v1 - 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@v1\n argument: sbd\n\n - name: corosync_state\n gatherer: systemd@v1\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 \n\n#","ref":"gatherers.html#systemd-v1","title":"systemd@v1 - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nGather systemd units information. It returns an object with multiple fields about the systemd unit.\n\nThe provided unit name must include the extension, such as `.service` or `.mount`.\n\nOnly a subset of properties are returned. Additional information about these is available in\nthe [systemd](https://www.man7.org/linux/man-pages/man5/org.freedesktop.systemd1.5.html#UNIT_OBJECTS) man pages,\nwith some detailed description in the `Properties` sub-chapter.\n\nExample arguments:\n\n| Name | Return value |\n| :--------------------- | :----------------------- |\n| `trento-agent.service` | systemd unit information |\n\n```yaml\nfacts:\n - name: corosync\n gatherer: systemd@v2\n argument: corosync.service\n\n - name: not_found\n gatherer: systemd@v2\n argument: unknown.service\n```\n\nExample output (in Rhai):\n\n```ts\n// corosync\n#{\n \"active_state\": \"inactive\",\n \"description\": \"Corosync Cluster Engine\",\n \"id\": \"corosync.service\",\n \"load_state\": \"loaded\",\n \"need_daemon_reload\": false,\n \"unit_file_preset\": \"disabled\",\n \"unit_file_state\": \"disabled\"\n}\n\n// not_found\n#{\n \"active_state\": \"inactive\",\n \"description\": \"unknown.service\",\n \"id\": \"unknown.service\",\n \"load_state\": \"not-found\",\n \"need_daemon_reload\": false,\n \"unit_file_preset\": \"\",\n \"unit_file_state\": \"\"\n}\n\n```\n\n \n\n#","ref":"gatherers.html#systemd-v2","title":"systemd@v2 - 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@v1\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-v1","title":"verify_password@v1 - 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 available version, when the requested path exists\n\n For example:\n Requesting /api/test, will try to redirect to to /api/ /test,\n only if the /api/ /test exists, otherwise, it will continue with the next available version.\n If the route doesn't match with any of the available versions, it returns a not found error.\n\n router and available_api_versions options should be provided.\n\n `available_api_versions` option should be a list with the available version from newest to oldest.\n\n For example: [\"v3\", \"v2\", \"v1\"]","ref":"WandaWeb.Plugs.ApiRedirector.html","title":"WandaWeb.Plugs.ApiRedirector","type":"module"},{"doc":"","ref":"WandaWeb.Router.html","title":"WandaWeb.Router","type":"module"},{"doc":"","ref":"WandaWeb.Router.html#api/2","title":"WandaWeb.Router.api/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.html#api_v1/2","title":"WandaWeb.Router.api_v1/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.html#api_v2/2","title":"WandaWeb.Router.api_v2/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.html#available_api_versions/0","title":"WandaWeb.Router.available_api_versions/0","type":"function"},{"doc":"","ref":"WandaWeb.Router.html#browser/2","title":"WandaWeb.Router.browser/2","type":"function"},{"doc":"Callback invoked by Plug on every request.","ref":"WandaWeb.Router.html#call/2","title":"WandaWeb.Router.call/2","type":"function"},{"doc":"Callback required by Plug that initializes the router\nfor serving web requests.","ref":"WandaWeb.Router.html#init/1","title":"WandaWeb.Router.init/1","type":"function"},{"doc":"","ref":"WandaWeb.Router.html#protected_api/2","title":"WandaWeb.Router.protected_api/2","type":"function"},{"doc":"Module with named helpers generated from WandaWeb.Router.","ref":"WandaWeb.Router.Helpers.html","title":"WandaWeb.Router.Helpers","type":"module"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#api_redirector_path/3","title":"WandaWeb.Router.Helpers.api_redirector_path/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#api_redirector_path/4","title":"WandaWeb.Router.Helpers.api_redirector_path/4","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#api_redirector_url/3","title":"WandaWeb.Router.Helpers.api_redirector_url/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#api_redirector_url/4","title":"WandaWeb.Router.Helpers.api_redirector_url/4","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#catalog_path/2","title":"WandaWeb.Router.Helpers.catalog_path/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#catalog_path/3","title":"WandaWeb.Router.Helpers.catalog_path/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#catalog_url/2","title":"WandaWeb.Router.Helpers.catalog_url/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#catalog_url/3","title":"WandaWeb.Router.Helpers.catalog_url/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#execution_path/2","title":"WandaWeb.Router.Helpers.execution_path/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#execution_path/3","title":"WandaWeb.Router.Helpers.execution_path/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#execution_path/4","title":"WandaWeb.Router.Helpers.execution_path/4","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#execution_url/2","title":"WandaWeb.Router.Helpers.execution_url/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#execution_url/3","title":"WandaWeb.Router.Helpers.execution_url/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#execution_url/4","title":"WandaWeb.Router.Helpers.execution_url/4","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#health_path/2","title":"WandaWeb.Router.Helpers.health_path/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#health_path/3","title":"WandaWeb.Router.Helpers.health_path/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#health_url/2","title":"WandaWeb.Router.Helpers.health_url/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#health_url/3","title":"WandaWeb.Router.Helpers.health_url/3","type":"function"},{"doc":"Generates the path information including any necessary prefix.","ref":"WandaWeb.Router.Helpers.html#path/2","title":"WandaWeb.Router.Helpers.path/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#render_spec_path/2","title":"WandaWeb.Router.Helpers.render_spec_path/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#render_spec_path/3","title":"WandaWeb.Router.Helpers.render_spec_path/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#render_spec_url/2","title":"WandaWeb.Router.Helpers.render_spec_url/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#render_spec_url/3","title":"WandaWeb.Router.Helpers.render_spec_url/3","type":"function"},{"doc":"Generates an integrity hash to a static asset given its file path.","ref":"WandaWeb.Router.Helpers.html#static_integrity/2","title":"WandaWeb.Router.Helpers.static_integrity/2","type":"function"},{"doc":"Generates path to a static asset given its file path.","ref":"WandaWeb.Router.Helpers.html#static_path/2","title":"WandaWeb.Router.Helpers.static_path/2","type":"function"},{"doc":"Generates url to a static asset given its file path.","ref":"WandaWeb.Router.Helpers.html#static_url/2","title":"WandaWeb.Router.Helpers.static_url/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#swagger_ui_path/2","title":"WandaWeb.Router.Helpers.swagger_ui_path/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#swagger_ui_path/3","title":"WandaWeb.Router.Helpers.swagger_ui_path/3","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#swagger_ui_url/2","title":"WandaWeb.Router.Helpers.swagger_ui_url/2","type":"function"},{"doc":"","ref":"WandaWeb.Router.Helpers.html#swagger_ui_url/3","title":"WandaWeb.Router.Helpers.swagger_ui_url/3","type":"function"},{"doc":"Generates the connection/endpoint base URL without any path information.","ref":"WandaWeb.Router.Helpers.html#url/1","title":"WandaWeb.Router.Helpers.url/1","type":"function"},{"doc":"Minimal information about an Execution accepted by the system,\nit carries the same identifiers provided by the consumer that requested the execution to start.\n\nThese identifiers may be used to query the APIs about the state of an execution.","ref":"WandaWeb.Schemas.AcceptedExecutionResponse.html","title":"WandaWeb.Schemas.AcceptedExecutionResponse","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.AcceptedExecutionResponse.html#schema/0","title":"WandaWeb.Schemas.AcceptedExecutionResponse.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.AcceptedExecutionResponse.html#t:t/0","title":"WandaWeb.Schemas.AcceptedExecutionResponse.t/0","type":"type"},{"doc":"OpenApi specification entry point\n\n`api_version` must be provided to specify the version of this openapi specification\n\nExample:\n use WandaWeb.OpenApi.ApiSpec,\n api_version: \"v1\"","ref":"WandaWeb.Schemas.ApiSpec.html","title":"WandaWeb.Schemas.ApiSpec","type":"module"},{"doc":"Bad Request","ref":"WandaWeb.Schemas.BadRequest.html","title":"WandaWeb.Schemas.BadRequest","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.BadRequest.html#response/0","title":"WandaWeb.Schemas.BadRequest.response/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.BadRequest.html#schema/0","title":"WandaWeb.Schemas.BadRequest.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.BadRequest.html#t:t/0","title":"WandaWeb.Schemas.BadRequest.t/0","type":"type"},{"doc":"Checks catalog response API spec","ref":"WandaWeb.Schemas.CatalogResponse.html","title":"WandaWeb.Schemas.CatalogResponse","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.CatalogResponse.html#schema/0","title":"WandaWeb.Schemas.CatalogResponse.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.CatalogResponse.html#t:t/0","title":"WandaWeb.Schemas.CatalogResponse.t/0","type":"type"},{"doc":"Individual check of the catalog response API spec","ref":"WandaWeb.Schemas.CatalogResponse.Check.html","title":"WandaWeb.Schemas.CatalogResponse.Check","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.CatalogResponse.Check.html#schema/0","title":"WandaWeb.Schemas.CatalogResponse.Check.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.CatalogResponse.Check.html#t:t/0","title":"WandaWeb.Schemas.CatalogResponse.Check.t/0","type":"type"},{"doc":"Execution item response API spec","ref":"WandaWeb.Schemas.ExecutionResponse.html","title":"WandaWeb.Schemas.ExecutionResponse","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.ExecutionResponse.html#schema/0","title":"WandaWeb.Schemas.ExecutionResponse.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.ExecutionResponse.html#t:t/0","title":"WandaWeb.Schemas.ExecutionResponse.t/0","type":"type"},{"doc":"Healthcheck","ref":"WandaWeb.Schemas.Health.html","title":"WandaWeb.Schemas.Health","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.Health.html#response/0","title":"WandaWeb.Schemas.Health.response/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.Health.html#schema/0","title":"WandaWeb.Schemas.Health.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.Health.html#t:t/0","title":"WandaWeb.Schemas.Health.t/0","type":"type"},{"doc":"Execution list response API spec","ref":"WandaWeb.Schemas.ListExecutionsResponse.html","title":"WandaWeb.Schemas.ListExecutionsResponse","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.ListExecutionsResponse.html#schema/0","title":"WandaWeb.Schemas.ListExecutionsResponse.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.ListExecutionsResponse.html#t:t/0","title":"WandaWeb.Schemas.ListExecutionsResponse.t/0","type":"type"},{"doc":"404 - Not Found","ref":"WandaWeb.Schemas.NotFound.html","title":"WandaWeb.Schemas.NotFound","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.NotFound.html#response/0","title":"WandaWeb.Schemas.NotFound.response/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.NotFound.html#schema/0","title":"WandaWeb.Schemas.NotFound.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.NotFound.html#t:t/0","title":"WandaWeb.Schemas.NotFound.t/0","type":"type"},{"doc":"Ready","ref":"WandaWeb.Schemas.Ready.html","title":"WandaWeb.Schemas.Ready","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.Ready.html#response/0","title":"WandaWeb.Schemas.Ready.response/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.Ready.html#schema/0","title":"WandaWeb.Schemas.Ready.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.Ready.html#t:t/0","title":"WandaWeb.Schemas.Ready.t/0","type":"type"},{"doc":"The request to be sent to start an execution","ref":"WandaWeb.Schemas.StartExecutionRequest.html","title":"WandaWeb.Schemas.StartExecutionRequest","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.StartExecutionRequest.html#schema/0","title":"WandaWeb.Schemas.StartExecutionRequest.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.StartExecutionRequest.html#t:t/0","title":"WandaWeb.Schemas.StartExecutionRequest.t/0","type":"type"},{"doc":"OpenApi specification for entrypoint V1","ref":"WandaWeb.Schemas.V1.ApiSpec.html","title":"WandaWeb.Schemas.V1.ApiSpec","type":"module"},{"doc":"The request to be sent to start an execution","ref":"WandaWeb.Schemas.V1.StartExecutionRequest.html","title":"WandaWeb.Schemas.V1.StartExecutionRequest","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.V1.StartExecutionRequest.html#schema/0","title":"WandaWeb.Schemas.V1.StartExecutionRequest.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.V1.StartExecutionRequest.html#t:t/0","title":"WandaWeb.Schemas.V1.StartExecutionRequest.t/0","type":"type"},{"doc":"OpenApi specification for entrypoint V2","ref":"WandaWeb.Schemas.V2.ApiSpec.html","title":"WandaWeb.Schemas.V2.ApiSpec","type":"module"},{"doc":"The request to be sent to start an execution","ref":"WandaWeb.Schemas.V2.StartExecutionRequest.html","title":"WandaWeb.Schemas.V2.StartExecutionRequest","type":"module"},{"doc":"","ref":"WandaWeb.Schemas.V2.StartExecutionRequest.html#schema/0","title":"WandaWeb.Schemas.V2.StartExecutionRequest.schema/0","type":"function"},{"doc":"","ref":"WandaWeb.Schemas.V2.StartExecutionRequest.html#t:t/0","title":"WandaWeb.Schemas.V2.StartExecutionRequest.t/0","type":"type"},{"doc":"","ref":"WandaWeb.V1.CatalogController.html","title":"WandaWeb.V1.CatalogController","type":"module"},{"doc":"","ref":"WandaWeb.V1.CatalogController.html#catalog/2","title":"WandaWeb.V1.CatalogController.catalog/2","type":"function"},{"doc":"","ref":"WandaWeb.V1.CatalogController.html#open_api_operation/1","title":"WandaWeb.V1.CatalogController.open_api_operation/1","type":"function"},{"doc":"","ref":"WandaWeb.V1.CatalogController.html#shared_security/0","title":"WandaWeb.V1.CatalogController.shared_security/0","type":"function"},{"doc":"","ref":"WandaWeb.V1.CatalogController.html#shared_tags/0","title":"WandaWeb.V1.CatalogController.shared_tags/0","type":"function"},{"doc":"","ref":"WandaWeb.V1.CatalogView.html","title":"WandaWeb.V1.CatalogView","type":"module"},{"doc":"The resource name, as an atom, for this view","ref":"WandaWeb.V1.CatalogView.html#__resource__/0","title":"WandaWeb.V1.CatalogView.__resource__/0","type":"function"},{"doc":"Renders the given template locally.","ref":"WandaWeb.V1.CatalogView.html#render/2","title":"WandaWeb.V1.CatalogView.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.V1.CatalogView.html#template_not_found/2","title":"WandaWeb.V1.CatalogView.template_not_found/2","type":"function"},{"doc":"","ref":"WandaWeb.V1.ExecutionController.html","title":"WandaWeb.V1.ExecutionController","type":"module"},{"doc":"","ref":"WandaWeb.V1.ExecutionController.html#index/2","title":"WandaWeb.V1.ExecutionController.index/2","type":"function"},{"doc":"","ref":"WandaWeb.V1.ExecutionController.html#last/2","title":"WandaWeb.V1.ExecutionController.last/2","type":"function"},{"doc":"","ref":"WandaWeb.V1.ExecutionController.html#open_api_operation/1","title":"WandaWeb.V1.ExecutionController.open_api_operation/1","type":"function"},{"doc":"","ref":"WandaWeb.V1.ExecutionController.html#shared_security/0","title":"WandaWeb.V1.ExecutionController.shared_security/0","type":"function"},{"doc":"","ref":"WandaWeb.V1.ExecutionController.html#shared_tags/0","title":"WandaWeb.V1.ExecutionController.shared_tags/0","type":"function"},{"doc":"","ref":"WandaWeb.V1.ExecutionController.html#show/2","title":"WandaWeb.V1.ExecutionController.show/2","type":"function"},{"doc":"","ref":"WandaWeb.V1.ExecutionController.html#start/2","title":"WandaWeb.V1.ExecutionController.start/2","type":"function"},{"doc":"","ref":"WandaWeb.V1.ExecutionView.html","title":"WandaWeb.V1.ExecutionView","type":"module"},{"doc":"The resource name, as an atom, for this view","ref":"WandaWeb.V1.ExecutionView.html#__resource__/0","title":"WandaWeb.V1.ExecutionView.__resource__/0","type":"function"},{"doc":"Renders the given template locally.","ref":"WandaWeb.V1.ExecutionView.html#render/2","title":"WandaWeb.V1.ExecutionView.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.V1.ExecutionView.html#template_not_found/2","title":"WandaWeb.V1.ExecutionView.template_not_found/2","type":"function"},{"doc":"","ref":"WandaWeb.V2.CatalogController.html","title":"WandaWeb.V2.CatalogController","type":"module"},{"doc":"","ref":"WandaWeb.V2.CatalogController.html#catalog/2","title":"WandaWeb.V2.CatalogController.catalog/2","type":"function"},{"doc":"","ref":"WandaWeb.V2.CatalogController.html#open_api_operation/1","title":"WandaWeb.V2.CatalogController.open_api_operation/1","type":"function"},{"doc":"","ref":"WandaWeb.V2.CatalogController.html#shared_security/0","title":"WandaWeb.V2.CatalogController.shared_security/0","type":"function"},{"doc":"","ref":"WandaWeb.V2.CatalogController.html#shared_tags/0","title":"WandaWeb.V2.CatalogController.shared_tags/0","type":"function"},{"doc":"","ref":"WandaWeb.V2.CatalogView.html","title":"WandaWeb.V2.CatalogView","type":"module"},{"doc":"The resource name, as an atom, for this view","ref":"WandaWeb.V2.CatalogView.html#__resource__/0","title":"WandaWeb.V2.CatalogView.__resource__/0","type":"function"},{"doc":"Renders the given template locally.","ref":"WandaWeb.V2.CatalogView.html#render/2","title":"WandaWeb.V2.CatalogView.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.V2.CatalogView.html#template_not_found/2","title":"WandaWeb.V2.CatalogView.template_not_found/2","type":"function"},{"doc":"","ref":"WandaWeb.V2.ExecutionController.html","title":"WandaWeb.V2.ExecutionController","type":"module"},{"doc":"","ref":"WandaWeb.V2.ExecutionController.html#open_api_operation/1","title":"WandaWeb.V2.ExecutionController.open_api_operation/1","type":"function"},{"doc":"","ref":"WandaWeb.V2.ExecutionController.html#shared_security/0","title":"WandaWeb.V2.ExecutionController.shared_security/0","type":"function"},{"doc":"","ref":"WandaWeb.V2.ExecutionController.html#shared_tags/0","title":"WandaWeb.V2.ExecutionController.shared_tags/0","type":"function"},{"doc":"","ref":"WandaWeb.V2.ExecutionController.html#start/2","title":"WandaWeb.V2.ExecutionController.start/2","type":"function"},{"doc":"# Wanda\n\n[![CI](https://github.com/trento-project/wanda/actions/workflows/ci.yaml/badge.svg)](https://github.com/trento-project/wanda/actions/workflows/ci.yaml)\n[![Coverage Status](https://coveralls.io/repos/github/trento-project/wanda/badge.svg?branch=main)](https://coveralls.io/github/trento-project/wanda?branch=main)\n[![Documentation](https://img.shields.io/badge/documentation-grey.svg)](https://trento-project.io/wanda/)\n\nA service responsible to orchestrate Checks executions on a target infrastructure.\n\n# Documentation\n\nThe documentation is available at [trento-project.io/wanda](https://trento-project.io/wanda/).\n\nSwagger UI is available at [trento-project.io/wanda/swaggerui](https://trento-project.io/wanda/swaggerui).\n\n# Developing Checks\n\nWanda architecture aims to simplify [testing Checks Executions](#testing-executions) and [adding new ones](#adding-new-checks).","ref":"readme.html","title":"Wanda","type":"extras"},{"doc":"For development purposes, a [docker-compose file](https://github.com/trento-project/wanda/blob/main/docker-compose.yaml) is provided.\nThe [docker-compose.checks.yaml](https://github.com/trento-project/wanda/blob/main/docker-compose.checks.yaml) provides additional configuration to start an environment for Checks development.\n\n#","ref":"readme.html#infrastructure","title":"Infrastructure - Wanda","type":"extras"},{"doc":"Start the environment with:\n\n```bash\n$ docker-compose -f docker-compose.checks.yaml up -d\n```\n\nWanda is exposed on port `4000` and the API documentation is available at http://localhost:4000/swaggerui\n\n**Note** that the [message broker](https://www.rabbitmq.com/) **must** be reachable by Wanda and all the targets.","ref":"readme.html#starting-a-local-environment","title":"Starting a local environment - Wanda","type":"extras"},{"doc":"With a running setup, it is possible to easily test Checks and their Execution by:\n\n- starting the targets\n- consulting the catalog\n- starting a Checks Execution\n- checking the state of an execution\n- debugging the gathered facts\n\n### **Starting the targets**\n\nThe [trento-agent](https://github.com/trento-project/agent) must be up and running on the targets to run a correct execution, otherwise a timeout error is raised.\n\nHere an example on how to start it:\n\n```\n./trento-agent start --api-key --facts-service-url amqp://wanda:wanda@localhost:5674\n```\n\n> 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\nseverity: warning\n\nmetadata:\n target_type: cluster\n cluster_type: hana_scale_up\n provider: [azure, nutanix, kvm, vmware]\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| `metadata` | not required | [see more](#metadata) |\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":"A key-value map that enriches the Check being declared by providing extra information about when to consider it as applicable given a specific [env](#env)\n\n- keys must be non empty strings (`foo`, `bar`, `foo_bar`, `qux1`)\n- values can be any of the following types `string`, `number`, `boolean`, `string[]` (list of strings)\n\nExample:\n\n```yaml\nmetadata:\n foo: bar\n bar: 42\n baz: true\n qux: [foo, bar, baz]\n```\n\nMetadata is used when:\n- querying checks from the catalog\n- loading relevant checks for an execution (when requesting an execution to start either via the rest API or via a message through the message broker)\n\n##","ref":"specification.html#metadata","title":"metadata - Checks Specification","type":"extras"},{"doc":"For each of the metadata key-value the system checks whether a matching key is present in the current context (catalog or execution env) and if so, whether the value matches the one declared in the check.\n\nFor a check to be considered applicable all the metadata key-value pairs should match something in the env.\n\nAny extra key in the env not having a corresponding one in the check metadata is ignored.\n\nNotes:\n- a string in the env (ie `env.qux` being `baz`) can match either a plain string as in `qux: baz` and a string contained in a list as in `qux: [foo, bar, baz]`\n- an empty env always matches any metadata\n- an empty metadata always matches any env\n\n**Matching example**\n```ts\nlet env = #{\n foo: \"bar\",\n qux: \"baz\"\n}\n```\n\n```yaml\nmetadata:\n foo: bar\n bar: 42\n baz: true\n qux: baz\n```\n\n**Not matching example**\n\n```ts\nlet env = #{\n foo: \"bar\",\n qux: \"baz\",\n baz: false\n}\n```\n\n```yaml\nmetadata:\n foo: bar\n bar: 42\n baz: true\n qux: [foo, bar, baz]\n```\n\n##","ref":"specification.html#how-does-the-matching-work","title":"How does the matching work? - 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":"The gatherers implementation supports a versioning mechanism in order to enable non-backwards compatibility changes in any of them. When an update to\nthe trento-agent includes a non-backwards compatible change in a gatherer (e.g., changes to the Rhai output format), its version is\nbumped by incrementing the @vN suffix that follows the gatherer's name, where 'N' represents the new version of that gatherer.\nExample:\n\n- `systemd@v1` -> Represents the first version of the systemd gatherer\n- `systemd@v2` -> Represents the second version of the systemd gatherer\n\nNote that when writing a check, if no tag is specified (e.g. `systemd`), the latest version is used. It is **strongly** recommended to always pin your\nchecks to a specific version of a gatherer.\n\nNot all changes in a released gatherer get a new version tag. A new version tag is released only for breaking changes, while non-breaking changes such\nas additional fields in the Rhai output reuse the latest existing tag. To use a check that relies on a newer field introduced after an update, upgrade\nthe agent to the latest version to ensure that the required gatherers are also up-to-date.","ref":"gatherers.html#gatherers-versioning","title":"Gatherers versioning - 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@v1`](#cibadminv1) | [trento-project/agent/../gatherers/cibadmin.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/cibadmin.go) |\n| [`corosync.conf@v1`](#corosyncconfv1) | [trento-project/agent/../gatherers/corosyncconf.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/corosyncconf.go) |\n| [`corosync-cmapctl@v1`](#corosync-cmapctlv1) | [trento-project/agent/../gatherers/corosynccmapctl.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/corosynccmapctl.go) |\n| [`dir_scan@v1`](#dir_scanv1) | [trento-project/agent/../gatherers/dir_scan.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/dir_scan.go) |\n| [`disp+work@v1`](#dispworkv1) | [trento-project/agent/../gatherers/dispwork.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/dispwork.go) |\n| [`fstab@v1`](#fstabv1) | [trento-project/agent/../gatherers/fstab.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/fstab.go) |\n| [`groups@v1`](#groupsv1) | [trento-project/agent/../gatherers/groups.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/groups.go) |\n| [`hosts@v1`](#hostsv1) | [trento-project/agent/../gatherers/hostsfile.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/hostsfile.go) |\n| [`package_version@v1`](#package_versionv1) | [trento-project/agent/../gatherers/packageversion.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/packageversion.go) |\n| [`passwd@v1`](#passwdv1) | [trento-project/agent/../gatherers/passwd.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/passwd.go) |\n| [`sapcontrol@v1`](#sapcontrolv1) | [trento-project/agent/../gatherers/sapcontrol.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sapcontrol.go) |\n| [`saphostctrl@v1`](#saphostctrlv1) | [trento-project/agent/../gatherers/saphostctrl.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/saphostctrl.go) |\n| [`sap_profiles@v1`](#sap_profilesv1) | [trento-project/agent/../gatherers/sapprofiles.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sapprofiles.go) |\n| [`sapinstance_hostname_resolver@v1`](#sapinstance_hostname_resolverv1) | [trento-project/agent/../gatherers/sapinstancehostnameresolver.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sapinstancehostnameresolver.go) |\n| [`sapservices@v1`](#sapservicesv1) | [trento-project/agent/../gatherers/sapservices.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sapservices.go) |\n| [`saptune@v1`](#saptunev1) | [trento-project/agent/../gatherers/saptune.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/saptune.go) |\n| [`sbd_config@v1`](#sbd_configv1) | [trento-project/agent/../gatherers/sbd.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sbd.go) |\n| [`sbd_dump@v1`](#sbd_dumpv1) | [trento-project/agent/../gatherers/sbddump.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sbddump.go) |\n| [`sysctl@v1`](#sysctlv1) | [trento-project/agent/../gatherers/sysctl.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/sysctl.go) |\n| [`systemd@v1`](#systemdv1) | [trento-project/agent/../gatherers/systemd.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/systemd.go) |\n| [`systemd@v2`](#systemdv2) | [trento-project/agent/../gatherers/systemd_v2.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/systemd_v2.go) |\n| [`verify_password@v1`](#verify_passwordv1) | [trento-project/agent/../gatherers/verifypassword.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/verifypassword.go) |\n\n \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@v1\n argument: cib.configuration\n\n - name: first_primitive\n gatherer: cibadmin@v1\n argument: cib.configuration.resources.primitive.0\n\n - name: first_cluster_property_set_second_nvpair\n gatherer: cibadmin@v1\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 \n\n#","ref":"gatherers.html#cibadmin-v1","title":"cibadmin@v1 - 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@v1\n argument: totem.token\n\n - name: corosync_join\n gatherer: corosync.conf@v1\n argument: totem.join\n\n - name: corosync_node_id_0\n gatherer: corosync.conf@v1\n argument: nodelist.node.0.nodeid\n\n - name: corosync_node_id_1\n gatherer: corosync.conf@v1\n argument: nodelist.node.1.nodeid\n\n - name: corosync_nodes\n gatherer: corosync.conf@v1\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 \n\n#","ref":"gatherers.html#corosync-conf-v1","title":"corosync.conf@v1 - 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@v1\n argument: totem.token\n\n - name: runtime_totem_token\n gatherer: corosync-cmapctl@v1\n argument: runtime.config.totem.token\n\n - name: totem_transport\n gatherer: corosync-cmapctl@v1\n argument: totem.transport\n\n - name: totem_max_messages\n gatherer: corosync-cmapctl@v1\n argument: runtime.config.totem.max_messages\n\n - name: node_0_ring0addr\n gatherer: corosync-cmapctl@v1\n argument: nodelist.node.0.ring0_addr\n\n - name: node_list\n gatherer: corosync-cmapctl@v1\n argument: nodelist.node\n\n - name: second_node\n gatherer: corosync-cmapctl@v1\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 \n\n#","ref":"gatherers.html#corosync-cmapctl-v1","title":"corosync-cmapctl@v1 - 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@v1\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 \n\n#","ref":"gatherers.html#dir_scan-v1","title":"dir_scan@v1 - Gatherers","type":"extras"},{"doc":"**Argument required**: No\n\nThis gatherer allows access to the `disp+work` command output and returns some fields available there.\nThe command is executed for all installed SAP systems, accessing it with the ` adm` user. The fields for\neach system are returned in a map using the SAP sid as key.\n\nIf the `disp+work` command execution fails, the fields are returned with an empty string value.\n\nThe available fields are `compilation_mode`, `kernel_release` and `patch_number`.\n\nExample specification:\n\n```yaml\nfacts:\n - name: dispwork\n gatherer: disp+work@v1\n```\n\nExample output (in Rhai):\n\n```ts\n#{\n \"NWP\": #{\n \"compilation_mode\": \"UNICODE\",\n \"kernel_release\": \"753\",\n \"patch_number\": \"900\"\n },\n // failed execution\n \"NWQ\": #{\n \"compilation_mode\": \"\",\n \"kernel_release\": \"\",\n \"patch_number\": \"\"\n },\n \"NWD\": #{\n \"compilation_mode\": \"UNICODE\",\n \"kernel_release\": \"753\",\n \"patch_number\": \"910\"\n }\n}\n```\n\n \n\n#","ref":"gatherers.html#disp-work-v1","title":"disp+work@v1 - 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@v1\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 \n\n#","ref":"gatherers.html#fstab-v1","title":"fstab@v1 - 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@v1\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 \n\n#","ref":"gatherers.html#groups-v1","title":"groups@v1 - 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@v1\n argument: node1\n\n - name: hosts_node2\n gatherer: hosts@v1\n argument: node2\n\n - name: hosts_all\n gatherer: hosts@v1\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 \n\n#","ref":"gatherers.html#hosts-v1","title":"hosts@v1 - 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@v1\n argument: corosync,2.4.5\n\n - name: package_corosync\n gatherer: package_version@v1\n argument: corosync\n\n - name: package_sbd\n gatherer: package_version@v1\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@v1\n argument: corosync\n\n - name: package_pacemaker\n gatherer: package_version@v1\n argument: pacemaker\n\n - name: multiple_sbd_versions_installed\n gatherer: package_version@v1\n argument: sbd\n\n - name: compare_package_corosync\n gatherer: package_version@v1\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 \n\n#","ref":"gatherers.html#package_version-v1","title":"package_version@v1 - 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@v1\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 \n\n#","ref":"gatherers.html#passwd-v1","title":"passwd@v1 - 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\nExample specification:\n\n```yaml\nfacts:\n - name: processes\n gatherer: sapcontrol@v1\n argument: GetProcessList\n\n - name: instances\n gatherer: sapcontrol@v1\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 \n\n#","ref":"gatherers.html#sapcontrol-v1","title":"sapcontrol@v1 - 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@v1\n argument: Ping\n\n - name: list_instances\n gatherer: saphostctrl@v1\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 \n\n#","ref":"gatherers.html#saphostctrl-v1","title":"saphostctrl@v1 - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer uses the filesystem to search for SAP systems using the discovered profile file names to get the virtual hostnames associated to each\ninstance of the sap system. It then attempts to resolve those hostnames to confirm that they are resolvable and afterwards a ping is attempted\nto those hostnames. Keep in mind that ping could be disallowed through firewall rules so it should only be used for networks in which we know this is\nnot true.\n\nExample specification:\n\n```yaml\nfacts:\n - name: resolvability_check\n gatherer: sapinstance_hostname_resolver@v1\n```\n\nExample output (in Rhai):\n\n```ts\n// 2 resolvable & 1 non-resolvable hosts\n#{\n \"NWP\": [\n #{\n \"addresses\": [\n \"2.1.1.82\"\n ],\n \"hostname\": \"sapnwpas\",\n \"instance_name\": \"ASCS00\",\n \"reachability\": true\n }\n ],\n \"QAS\": [\n #{\n \"addresses\": [\n \"1.1.1.82\"\n ],\n \"hostname\": \"sapqasas\",\n \"instance_name\": \"ASCS00\",\n \"reachability\": true\n },\n #{\n \"addresses\": (),\n \"hostname\": \"sapwaser\",\n \"instance_name\": \"ERS00\",\n \"reachability\": false\n }\n ]\n}\n```\n\n \n\n#","ref":"gatherers.html#sapinstance_hostname_resolver-v1","title":"sapinstance_hostname_resolver@v1 - 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@v1\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 \n\n#","ref":"gatherers.html#sap_profiles-v1","title":"sap_profiles@v1 - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows access to the SAP services file content stored in `/usr/sap/sapservices`.\nEach entry in the file is returned as a map, containing the SID, the raw line content of the entry and\nthe kind of system used for startup, `systemctl` or `sapstartsrv`.\n\nExample specification:\n\n```yaml\nfacts:\n - name: sapservices\n gatherer: sapservices@v1\n```\n\nExample output (in Rhai):\n\n```ts\n[\n #{\n \"sid\": \"HS1\",\n \"kind\": \"sapstartsrv\",\n \"content\": \"LD_LIBRARY_PATH=/usr/sap/HS1/HDB11/exe:$LD_LIBRARY_PATH;export LD_LIBRARY_PATH;/usr/sap/HS1/HDB11/exe/sapstartsrv pf=/usr/sap/HS1/SYS/profile/HS1_HDB11_s41db -D -u hs1adm\"\n },\n #{\n \"sid\": \"S41\",\n \"kind\": \"systemctl\",\n \"content\": \"systemctl --no-ask-password start SAPS41_40\"\n },\n]\n```\n\n \n\n#","ref":"gatherers.html#sapservices-v1","title":"sapservices@v1 - 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@v1\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 \n\n#","ref":"gatherers.html#saptune-v1","title":"saptune@v1 - 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@v1\n argument: SBD_PACEMAKER\n\n - name: sbd_startmode\n gatherer: sbd_config@v1\n argument: SBD_STARTMODE\n\n - name: sbd_device\n gatherer: sbd_config@v1\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 \n\n#","ref":"gatherers.html#sbd_config-v1","title":"sbd_config@v1 - 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@v1\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 \n\n#","ref":"gatherers.html#sbd_dump-v1","title":"sbd_dump@v1 - 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@v1\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 \n\n#","ref":"gatherers.html#sysctl-v1","title":"sysctl@v1 - 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@v1\n argument: sbd\n\n - name: corosync_state\n gatherer: systemd@v1\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 \n\n#","ref":"gatherers.html#systemd-v1","title":"systemd@v1 - Gatherers","type":"extras"},{"doc":"**Argument required**: yes.\n\nGather systemd units information. It returns an object with multiple fields about the systemd unit.\n\nThe provided unit name must include the extension, such as `.service` or `.mount`.\n\nOnly a subset of properties are returned. Additional information about these is available in\nthe [systemd](https://www.man7.org/linux/man-pages/man5/org.freedesktop.systemd1.5.html#UNIT_OBJECTS) man pages,\nwith some detailed description in the `Properties` sub-chapter.\n\nExample arguments:\n\n| Name | Return value |\n| :--------------------- | :----------------------- |\n| `trento-agent.service` | systemd unit information |\n\n```yaml\nfacts:\n - name: corosync\n gatherer: systemd@v2\n argument: corosync.service\n\n - name: not_found\n gatherer: systemd@v2\n argument: unknown.service\n```\n\nExample output (in Rhai):\n\n```ts\n// corosync\n#{\n \"active_state\": \"inactive\",\n \"description\": \"Corosync Cluster Engine\",\n \"id\": \"corosync.service\",\n \"load_state\": \"loaded\",\n \"need_daemon_reload\": false,\n \"unit_file_preset\": \"disabled\",\n \"unit_file_state\": \"disabled\"\n}\n\n// not_found\n#{\n \"active_state\": \"inactive\",\n \"description\": \"unknown.service\",\n \"id\": \"unknown.service\",\n \"load_state\": \"not-found\",\n \"need_daemon_reload\": false,\n \"unit_file_preset\": \"\",\n \"unit_file_state\": \"\"\n}\n\n```\n\n \n\n#","ref":"gatherers.html#systemd-v2","title":"systemd@v2 - 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@v1\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-v1","title":"verify_password@v1 - 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 67073520..51a940b9 100644 --- a/gatherers.html +++ b/gatherers.html @@ -130,7 +130,7 @@

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)

@@ -148,7 +148,7 @@

Available Gatherers

-

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

NameImplementation
cibadmin@v1trento-project/agent/../gatherers/cibadmin.go
corosync.conf@v1trento-project/agent/../gatherers/corosyncconf.go
corosync-cmapctl@v1trento-project/agent/../gatherers/corosynccmapctl.go
dir_scan@v1trento-project/agent/../gatherers/dir_scan.go
disp+work@v1trento-project/agent/../gatherers/dispwork.go
fstab@v1trento-project/agent/../gatherers/fstab.go
groups@v1trento-project/agent/../gatherers/groups.go
hosts@v1trento-project/agent/../gatherers/hostsfile.go
package_version@v1trento-project/agent/../gatherers/packageversion.go
passwd@v1trento-project/agent/../gatherers/passwd.go
sapcontrol@v1trento-project/agent/../gatherers/sapcontrol.go
saphostctrl@v1trento-project/agent/../gatherers/saphostctrl.go
sap_profiles@v1trento-project/agent/../gatherers/sapprofiles.go
sapinstance_hostname_resolver@v1trento-project/agent/../gatherers/sapinstancehostnameresolver.go
saptune@v1trento-project/agent/../gatherers/saptune.go
sbd_config@v1trento-project/agent/../gatherers/sbd.go
sbd_dump@v1trento-project/agent/../gatherers/sbddump.go
sysctl@v1trento-project/agent/../gatherers/sysctl.go
systemd@v1trento-project/agent/../gatherers/systemd.go
systemd@v2trento-project/agent/../gatherers/systemd_v2.go
verify_password@v1trento-project/agent/../gatherers/verifypassword.go

+

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

NameImplementation
cibadmin@v1trento-project/agent/../gatherers/cibadmin.go
corosync.conf@v1trento-project/agent/../gatherers/corosyncconf.go
corosync-cmapctl@v1trento-project/agent/../gatherers/corosynccmapctl.go
dir_scan@v1trento-project/agent/../gatherers/dir_scan.go
disp+work@v1trento-project/agent/../gatherers/dispwork.go
fstab@v1trento-project/agent/../gatherers/fstab.go
groups@v1trento-project/agent/../gatherers/groups.go
hosts@v1trento-project/agent/../gatherers/hostsfile.go
package_version@v1trento-project/agent/../gatherers/packageversion.go
passwd@v1trento-project/agent/../gatherers/passwd.go
sapcontrol@v1trento-project/agent/../gatherers/sapcontrol.go
saphostctrl@v1trento-project/agent/../gatherers/saphostctrl.go
sap_profiles@v1trento-project/agent/../gatherers/sapprofiles.go
sapinstance_hostname_resolver@v1trento-project/agent/../gatherers/sapinstancehostnameresolver.go
sapservices@v1trento-project/agent/../gatherers/sapservices.go
saptune@v1trento-project/agent/../gatherers/saptune.go
sbd_config@v1trento-project/agent/../gatherers/sbd.go
sbd_dump@v1trento-project/agent/../gatherers/sbddump.go
sysctl@v1trento-project/agent/../gatherers/sysctl.go
systemd@v1trento-project/agent/../gatherers/systemd.go
systemd@v2trento-project/agent/../gatherers/systemd_v2.go
verify_password@v1trento-project/agent/../gatherers/verifypassword.go

@@ -781,7 +781,28 @@

... ] } -}

+}

+ + + + sapservices@v1 +

+

Argument required: no.

This gatherer allows access to the SAP services file content stored in /usr/sap/sapservices. +Each entry in the file is returned as a map, containing the SID, the raw line content of the entry and +the kind of system used for startup, systemctl or sapstartsrv.

Example specification:

facts:
+  - name: sapservices
+    gatherer: sapservices@v1

Example output (in Rhai):

[
+  #{
+    "sid": "HS1",
+    "kind": "sapstartsrv",
+    "content": "LD_LIBRARY_PATH=/usr/sap/HS1/HDB11/exe:$LD_LIBRARY_PATH;export LD_LIBRARY_PATH;/usr/sap/HS1/HDB11/exe/sapstartsrv pf=/usr/sap/HS1/SYS/profile/HS1_HDB11_s41db -D -u hs1adm"
+  },
+  #{
+    "sid": "S41",
+    "kind": "systemctl",
+    "content": "systemctl --no-ask-password start SAPS41_40"
+  },
+]

diff --git a/hack_on_wanda.html b/hack_on_wanda.html index 6ee5a5bc..b194700f 100644 --- a/hack_on_wanda.html +++ b/hack_on_wanda.html @@ -136,7 +136,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

diff --git a/readme.html b/readme.html index 453ccd1c..90d64959 100644 --- a/readme.html +++ b/readme.html @@ -266,14 +266,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
-}

+}

diff --git a/search.html b/search.html index 5cefd9df..02a40347 100644 --- a/search.html +++ b/search.html @@ -120,7 +120,7 @@

- +