From a86acb5a5682f520d293e4cf58eb0806c88831fa Mon Sep 17 00:00:00 2001 From: arbulu89 Date: Tue, 24 Oct 2023 12:19:59 +0000 Subject: [PATCH] deploy: 0996f50e92732ce82390ed1e7c6ca957e1caa0d3 --- .build | 2 +- Wanda.DataCase.html | 6 +- Wanda.epub | Bin 520213 -> 521425 bytes ...ta-9BD0835A.js => search_data-9AEE737B.js} | 2 +- gatherers.html | 1193 ++++++----------- hack_on_wanda.html | 2 +- readme.html | 8 +- search.html | 2 +- specification.html | 6 +- 9 files changed, 424 insertions(+), 797 deletions(-) rename dist/{search_data-9BD0835A.js => search_data-9AEE737B.js} (81%) diff --git a/.build b/.build index 9269f675..27775c08 100644 --- a/.build +++ b/.build @@ -101,7 +101,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-9BD0835A.js +dist/search_data-9AEE737B.js dist/sidebar_items-05B55562.js expression_language.html gatherers.html diff --git a/Wanda.DataCase.html b/Wanda.DataCase.html index d32f5e71..3eef9502 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 968a6bd8e31952957cce66b55623b9279b98a059..4b416a0354531446e201f691c0a940b31c14df47 100644 GIT binary patch delta 23237 zcmYhiQ;aT58>~IHZF|<(wr$(CXVx>eZQHhOd)C;t^}pZ#vyh6?1 z!i94}I7JyyFf^e5Ef?biI8G23;|B3OU?>-3O^rj*Zh@w2U^i;OR^%2VlHZ&L++R&? z%Y&1~v>S?#0AcDU(A0<$GGjBT74oitzrGUkm?-t|2<9FtDB;=Ti_;6bvzCUrK2e!7 zOHd)gx0o3d>-F|OTqcSfw|=9nsf9N=GwXhsTHGc($p=c^no3}Bi)W$Np!o`@+21d@ zKsEJHy#tCxrF^3R*9GB3jHuZ9*7Cx$NE-*N0m3fO?!iTV)gjz^NeJuJj zBm9_DzN~W2Kj0x5CBIh8be`zS2T9==!HEouW=MF}b&OCb3f{OR9n!(t)pYl~<#TZ! z@(wWFGVXl_?ttn1d|U3%d`_Lo$rRJarE*Y$eF<%-pznaZ;yOv;eztpS zWAYYZpXch~qn1X$w*P4Hp2}K|v}|(rjj>%=g^AGd>CHo+P2U11 zmEOLbvU4%np!QisD`OT}7F<-xByi@1xEoSmK}ZdlI9=8>^cSs#w2O)xftVjs0#4MH zqC-LMx>JB8f-ct^#+Ux?oD`G02vs*C&S%xFEvKwx^&_6CSlbW^(9RM(M*P#F?yHJE z@P*{J;&-gnFpyuVC^O_?%Q(kTP~6e?e?5FtYRFNgq=~~0fMbtg($vrXDZQwBT*#5rx}uWwSW zVr&73@gAAb^64ZlmdcvIYxp&n5{0ZOIFVk#agfEplh_8FOwy`=w9|amjTO;AYjBNn zr9GN>^})yp`2>f*o)XTgVlcpwjs+8iMTySvJ#I}tbD$eeCZ>Xo@?CVYNs%;(z>dNT zrcne5R|}Dq5+wyp<~3C}#S1q|Rq6Ey^y}+TPP-t@Fp~NzB{v}89e(=2bn}k!y(Fgc zQsf2Qu=;taRl_g*bnv?_!6^igr#LNK;6+ot0I(=!eWBiAv-5_~gGgRg z2)nly6D+&WA*TO`a2VX416msdTRrk<4a{Lby4P4l zJh&uo9)`0zKT79iryjmx@QPE>>SmwjKD@I29VE-2F)ll|EzZXwJ8P9gs(z$Z<%u9i8q@q zSfg<{6v}B=j#HGNll^+GqmV;{`c(BjO}Qy3znx4_0f=2#+e=gDhoh%dCsJBy2I%tjyLl(kd} zogfQ!WXB%apCOAi;w3QKu>4~F_Vf06?#l)YJmRhD=QxlYJ!ycG zSZkYke}{^#QU=a)2Ka9ok>ADnKGvt-xX{19cWrND3*?^K5%+nO1+OgJCw-$z zf$veN^tq}7^nV^_u3Sn=_M)C@9s_JG-gY2)+qdpb(*a1s(MtA&=@qb$d8043!Ym8; z@nrUe)M9#3Ee%Ih7(7d^)-0%gotJ>y>#SXm&z|zA<6gyN6f!);> z!qa^sNZWEU9aYYeR2;v}(pogup{<}pk;;|CrS!*DU%d0W#FabxAZ(X)Ty47 z!o$DggocAh%_@%Rda4N!OoO+fL|k*wAHZKZ#4za@HA;D4bc9j{(ds?`UnRiJ7Wd$4 z%Xyq4_ux3Q5<&i9N7<@t1JFhT5!*ZlNn1JAPChb9tg3R}@+32RZp&3hYA-B$yjxUA zL`a#5u*_I@Jv1Nf&%4jO$4&^S@VP5&=a}m-QX>SKmh+kh+z-~IJPyr7yxJaUd)-QL zxD?WPabL zxFE+4Ebn6-m0w~iA9BD+w{nViCM35z{h|3!6_^gRCU5B1s_-&j&IOygVq0puDiGu! zoF$lx#A?3x9!QFc5KS88Ch{j7cz7!;Hk){(*TLczx0YIe!l(qdd3b;XVfgrtNh3;i z7(QY>WID{H)U5d4+psr+%aAI`7j3y%6z*E`<%||hgL{g+(-HFkz&TiNb#bV{h0n-` zOCVophM&>vCw8!}F1E$TmjK^q*6)u3R0w78$GCu=&SBOpG`4|N+Bhc=12VIG-a{wi znAnHnA57(PiQGI!4>W)y?dX)kG1rO3nl3`eXjM_iyd7O?zrs4#2Tej;;1ipdqnY7l zaS}yY{hxCf2aZnzB*gDh9wsTyky`JLk}Au%Y>%2%#S2QRggn|*4O6<#&NH3B=fuOA z`bUTGBEK8TB~Evo?2UFlm0k7h&KA>6UG!F|uX|y8P-ARJ9$i4#$%~x5ILE}Zt0xOA za_Fx7zIg0Opt8^fMAj{`>+AJ;FT11z!$d=jc9xX}yT`0G;g^12A6t9x=M78ykJndA z#p8K5Ul!tF)BBylOY?xoEY_}2SQ_!`KVX5s7eGA;4+8&r@9%Gq`mVzkJJR1*1E+a^ zBT$m6iAXvdRA7L8W{WteMR*RnAC2Y3AEy$j6oIQZqur(c}3zgX<(i|UdBHANOKAXhY%(is45j`kU|pogTn(0T$h#nmHt z825rBAPW$ju&T$atg%-%_aOSUNndFl%Oo6G`I2YfoB&7ZqnJt>)>AD{A|=rt(DQhV zN`%it%RU(EJR2Y|&oE|ZKBBJxob_4fc8)5dz zYbc@`(BZ;e?i;FVH{zfqhzxy@s@`d4RQDjf^%nCpS7wa!>fJA;^y|6P4-fUNQQyuQ zP}(O>Z#?_?jEVpHj*6QiAD*g$wFiET#FK_immK9-a%Z~d{XBP<5_)NFJ7p>I!;*vz zzdgX~mS`ljO~(*-zJd~W2nW$_o(j>e*wA#T_;-FDt1>G&X;Jct;Hr{GsRq^j0?BGd zdS&6>r_9hDEw*K`keH@K7%)t;Rk->kbEajYV3=QZ4ZKo)-IqK?3j9NuQ++J}8*F(5 zV>I(Em+VnPrU{%oH@~DMz3-H++K$X!x(@)+LC3-E!Z28P9x_Fp>xL5!mDG*OO!Qs_ z;$d42V~VGUz^9=<#?O4AH5>E!EoDc@OkM?-f7pzQ6(8hnt#K>BMYMab5+5~#pTP;U z4KS5>rU9l& z?dgr&4WYA1@$!mD78Z@`YZ8$vqU&ZgsTqo1x7V+hZq|N4z6LV|lUSW8;m%Gy<5dVa z{~1uOHI2+Xty~*(`>^Q0inK?0l#t=XiIl@`-DFp00a4D$$GUib0X=TLlk4i~J;CqZ zmiyPL8vDyl~02HK+^Q z7Nk&UXu0%EX(Gb7ifAQ`aXmAj>{^T`+@#?@Nk;Dq;_TCes8-9#Z2i8JZpAnNaTif6 zTlQ@x363!}Rp*n^xV}zoJ?+^u3@(G>&VHSbeCKvvHmrzZVb%B~&QbF z^~P+`>v-FMEtt2dfZ4}zPpyy|$MJ`=SnR5WA0i0N;ne`p*FQ5Uv9A+&rH?lZ-I>#6 zkEEUgdfh#}di|dhGc%^G>H4$#ALgQkUVM78brw%Au(IZad)uxrA5eurO?B(zd7JB*5ovYl{2$#va;Qqvm+`6g-~B8?(IR80Kbw63%BSxS(aN(adhhDe1U@#pt5NJW`(QQ-4?j{vdFl<4o^H z8~`^58ide*7vFOc#*G#=NnxDWQmYh>R22({h;!PZP>3OMcEgXk#)8;O6AT(6g)K zR1oyna3?yqyJ{KPfk0$c4R@*qwTionWCL0THq?}*FPRb8N5tt%qyQh^-$&4i0m>zh5_H3xvrrQWzA+l$6=&w&T;Ll~d?wG4;)iO#Z4gkrB*T z&1)v{$KLV!w@1{|6BkSj4>AHvdwD&q>x;I|%onYioE2)5p(T}rAK_T1h(2Q0d;p0g z=hZ~4a=g&!r`siVV54G58?DrGs=87M1a@C8o$0LE-WH>$M0S49po+@P zNaE?<-(2;Ky=uN>pYq-5x(~0+|A)uU>CUJId?z#@rZu`rGtWn{ps{BlIV2=WWka$} z8gp@_qW<_wFde`A=-uDr5dSWr79YqRXgz?AD%XdKf0BGo`qWM{Tt78i3}E59@mVg> z8+0O+GA_iZP4~1)+BzgWOZH68no6NF&vF)B8*QnR+mCcE7P3by?1_nhwT~#xfQAWL z;5)7xG+;vyvv?0__Kj8!zpBg5CMIWRHzHjjcb9FsMEl*fjRvb4le^fq!q~8?D(`NF z-%4sA+4a1x^OV6IQ*vhZ1c)9?EDQi$6gzV}(vW_M8FHpIK?);62*BLqwa2^HchM$h zuU_;4)mzd)L!FMc=g>DLoi*h?;+gOOe3Fw;Hy#XW?jNO+K4!hdzFyG;Y^tA1B*3*}o7Aty{^T!_ zuF%PY5zWkcMDfRvjMXsSdfX{}?;#^yVp2MG8iVs+lX9#y?dUR~^ z?*N$Mk@~IAXx7+=F<=LN^jrd8ZjaEYQm8eyU0JXmoTTW*2K02QJQ!X@~ zxTWt|5qZO|G}~bU9H@T4ha=VkO%=f67bnV>2Kw4Yzs{L+;>485F7!xhs@V zH5tG8>nUEOcn$D<&29EQ@1Q<^#UoKggt7nLBN@3(Nr0cH*Lpe(Kz|zYE#Pp118*_F zY>-ZpM{1*-0c6r^u~s8n_z0VII(ShE_#;L7R|*QUn=#NZENd96u)3~cPx?SJRhU+KWJtB-de$HdFQo2I zgVuSN;dfa7fiKnP+|EetTM(nCm_#IVg7O{DI=-jm0)pnk)fo=lLJg4ElF)NRq^*;Q zjq^4no;pY(cNO@2+(SPq2@d9bBg|AtZnb1mSpsLE(pC?{`aJDClTt>u3m3dIiPd$lx2+9nHLeOJ(Z`Mo5596z2TK2CEnP(T8vKMC+p)J{ zdOaEk471c2Grl5}FHB-ej$_eh^{`56mfl`OfW};;zx;+h_o1YX{D`51`xkTz;52)^ z&^e#3OXX;8H3cm`ADB1LP@WLlJDBLb{<~12y1T@(@xul?|F%J#nsYl0&)}LpX36oZ z2_16#e7yl)jZ5$4_g*Hx=uYn!SGL)9iKzfP)6d+!T)1J!{j{xsN#+_75YxqsgyjJ$ zO|*;aX7Wf7&F81~+8$4B8VcX#=TH9x2*G9J0WpO;Ze>-rCQ*KL?L`_v=-yD86= zDUNRb?H`Jt-~ZQIH8l*ViIDMGfPgO7fPm0}(uh|fF#*%*Iu6U6X#TsW8lFMTigrn^ zFi_g1r1Q>I!>Q<%!R`h$lujrrW3!vHxvl0%?Y*DjA9^iJIG*Vm^4 zb-(YQ_|$gfrA5&EZc?Eg>;Y#)aG&BnGqK#!Mc^Y$SDVa+6CQKod$2&8@1NS9o z+Vv;U7V;%oT$IE*RrBQO(FIQKjN!k17LtpRdSKv5vMN=sg39D{Nrvy+2Q|_YS7hGa zC^V2QZ5A;^8S9@-TOVkOUfEEu;RxcN&i#IAfwSqR8<6(vO+|1 zhPD9l-tp$5;MK7ke27fgjhkYkcwLrqvTB*kTy_S}u(`%L`HQ$fofa|&Yd80Hrk|ob zlMX;g(3~eo^w7!ddaj3oTFDM2pJS#7sIbQ(NalHDazj*6*`OwQGW6bXfmAglER35{ zdF#6=5diNAM%Jk;rJ_^fDhNG_arHj&MOj;tA}x(yrY`>@C1nx)R+v6q-@ch|HA%#! ziYW*Fm788P<2PelL|#5yZn@6nXwTq zQEbs+9VUc~PtvYR#unl9PK*gLMjga2T(#wvQXA!#Mei|_lk*(`AGW56$;YTvr`g-0 zqzSUR>E?;X)p<0OzR`h1#S|b#q}Rsz=)LA9!fs*x(`^+tGDx~*F+Tt#+Agt_^KCQulTscG1hyuY1?HReeR?Yiq~i{ z44+FOWs=jQg?|?Jp^zLgT$Z+{`NLhpQW~KaER_i*PNpbn>CIEd9b~Se249Lo->!EM zoC^NfLX)=cz1J2wzLvNTV`VLg*bFGeF{;yqcPft`Bx=o1jHEEZn)oK@Z{fJ*Dd0iz z8Z0E?*6#=vTzE-KbS}iv;YdA_)>tOMN43`|hT8}X^da((4 z)1LbEB<$QE4sg-Jyq5=b=_7%+E6_yY<5^uYSl`k*QVqj}6cOf67)-7D^=Mveg&r^Y z*-Oq~4#Jsccs_YBrnC4q=b9g(?O>nkTk)$nO42Im|$g|;IDj1P;@CS8; zF!}MX{mWP;!Ds6oOIRFxZx_GZ4!`A2Q>r1pJ(j*n{|Jm0WDEvBSo8c>kHX7_rI*3 z-ylhpk?P=O23(`bp`X{i1ea2n+)1n>y5J}y6e4PyFKz;aBm$t35#AMF2vV#1ni*O6 zIkHy3V=FKuWo4Gi95RsOV6g%tM&%~i?>&GR(pu3d(9T$6nWKF#;+eBY{P39Y{bw*` zb%@$rcNgo8aZ9=mm6OO?PZHGWdH8kT^rB<2jfXSi12LJCN|FC;AYc6e5i$kWQ_Qa9 z$Q>~}KFWe9S03=PZ~JepZUbh_fe;Cwa9)s?c0cTqI;COjzI_|C@bF+_Ut0i4(cou4 z+WPGW;*jGS-j}w9#~E_CCZ-zRmZS9y!YM5-w@g_GHb)BwG5++K6{bBu__=!B3S-CR-3EsN&PWZpP?4QX_7Ki~n`}>BIe9c3fCu)g3Rzk`(v1Yfus^g=8sNJ}i!*7#FU>KQsz( zNibeAs_=$n!Vlc+;qP-0Na6BPV=jcQM#2VUMp3=~`O4j9o8T}oO^Xi|y*oFZfC_c1xGh;%Pdhi*QJ{fol8 zZ~`E;8~`UbXL(``G13&T(nZ+<11b?rP zUmS-QWUx!qKb10UFZRi}>zkZar|>x*B4aMRb@pYO0hqhQ6zjWM1jYZj+IvfU>fu`jd zvT~KyJrbreD9!}le9Zt1ATrMIXgW#*DS%R)SwPnPpImw4%|B|BL@!9@j>NhVDz6W& zcXKH}SO`05yEkP~3~AR#-Gl+*ocWq)xZdnsj}IJG=2#`0 zc9&<8+#_4Mhf=ZRnEgm1J77LCY4ta-#PlQ70nr=1se;X*@E7HlOqL=(d z(z(OtcELZ7(c40PJTS*r>%fKPWvyfKK;G_o3o>YPqlDcL3n8CGN-)jHVd8Xs6P!zN zZ0xjDDp);#VSCAVD|gVzB}e}+Kyjc07VwUsGwJ?Yngo~VI+SP%`E-t=!RUqP;@z=w z&K@K6owd1J{7Wt=Xc*s6*(&4}?1TnTZ-F+`yc>-5X4#9`o}$PnZ6h_5XDcU>x%)!q z4ki-5W=^Fco8kIn7;$2;b&w$kTRK~8(*w{vY^AYo(?SFkP%%-Z-Y4`l;Iu!svqZy@ zGhrQ*j6xHm(Y%ajM8&W3{g2Fv=+WS{$%WD%`%90gku0XaaKEcKLro5+HTttZ8wiF; z2|wIf-}k3u3T{7*eOU>%G(CQP-8G7FW-4Fbj_bC31!~J$qSjVwI-{qcsrQUuh`_rm zta*N)Zvglf4Oq8ZjB8FU0EVFEW30(Y^ev#+HbP+6$ygWPJDKt33Xqz9GT+W(cc~iHW?;9NI@f^$yHPW)f-j{tZlK=+e!{5T~T*Sqd)%G%LzXN=BS&ogd4 z&Wkgtt|OFS9^F+S$L>17m|7n=Ey}o_TD!r~7FOw|6>#(E9s%o`^xUFm-F*Fcx_RmF ztDsfK!?>1mz(kV)vvP32OdPxXl7~3&i0=IK zQc;JnT9_%yxCp_sMQ6m;AZPR&5++t)Bx`aqa^U=+7-2udahS(b)-$*z`gm7q^$b$} zQ!KPrJ(fYUI;8dNDWmb#{YTl-YkzS(+8^10_xl3_*)M_?0Fuv;6(iwM-E4hpV1`#m z9UoePL`x3DW01e`{*luA-M)wRw@>H;`cH7CWSOt9c{Z~?aIII*R7{6W=9YfM+73%e zhXXd;`{B5cQFCrKx?*vR{LiZNIgUR=0bp>(85K1v8x(Je9JeU_&$1N28$ywyHu46! ztNxNvLxuJRV7+9&Z$3LDcSF}bBx^x1%G=+7Afxp|(>*4CzwYKv|L7X#UGELCW+eDT z>Unz_RGwHhUj5BvSCTPPx8ao{#ujYf>u{sed%+rQtZ(C4)3iA4+FkeHopVvdw<581 z(T}b-sqn~N-P`}A`Y7&@L;S^%yL1A%=b4SDyP?4kcy2+@yp@Q3J;^!j`K#0GYAtzL zvP__xJhI5GaVw^%HxB>M>Wx2IuVUt!CcPcSKjqPzCtVOTDswP2K}+1iE&rT4{B!z= z9~qYY^b7nypKaE<{9kPQd(#)_7|?}bq0^craoITvzI~yWX=vI45&D|%e#@d9;|_Z<#S52;YH;e`j+*eC6rPCj+HJkF+)9cL zL-Yk+BDW+}{g^v8#6wysW)`_v?n@(miE?Xj?_rBAs73KxNqDjD80mAH;sG{v z{+48ayu6{npVWigaJ!HuGF12fd%hOYCI7)C#vt32GOJMFV<8bM9RV@{vRo8Qw4_M? z<59VT-#Vymi8FQsc0N_HkQe$LvL?fc|5o;2<#JL{;PW#l z(3$`GHnVjZP^>Z~GAJwh1;|ubtM&9I&7m(po>q32BBFGWV%E9lLcwe59srd3fe@Gm zcQg~NcwTZMMSIt`$DKjkA!M5CVENNX8CEH`4ALIsM5!))G6uW+CTb+0Qlzfc__2}^ zE$ER*^czKFpM}s)JF@&_fTWJeZV>Cc9lr&Gb6mtEFQVOF5l81&~ly^*8hcO)1-Vk@lnZ;I3UbL} zI^4GbNFznBMF7rpfwYu77aO9_)Ae*cCVi%3URt(=^07TR%-k5m7~o_e9CaJ{?}AK2 zjd`-=64}a#OQ^*`Bn+BHq5#6Ws61H0m!i1dW-%gO8X4w+X@$4e-6~i_Bu&W-CuMr+q5h1?Y}G29toq`Ww3S7%y{tPOPcq!%0?x;x z=TTkm3lZ5zGCxCX4v;AJL>H&^{RRuR6_~3mFIT1O*o{2xMW5iNSd_Ld9~0N$?q~loZrPquK4QvlVs5wUXgGAs)A7x ze(A!LQxk8#XG*k=n=to^C9>&l*_ zSc~JGAX6PsgX>M5BjX;w{iPvy7s@f&>NQ03k+YCtTBx9fELpivE_T z9&nG2@&ojtg~FlBmH@5J9&nnys_fBb&R;eE`}DJV`J6ckG71Q#zC*di^kBlQ!}(_> z=YsQW4d*1HTk(7<@bRl6L4dk z;^|l{3HUQ9q1}GlC520>d}sfs5K0-2$nStA-1U0{Ua=B^!N0xF`{R=hzThYm$QH}f z&vPx+)8)BMouf%+LNQDy=8k+vp<7`!_Qg9FG~|pRb_>hrL7L}3e~!|&Rnjm)R_7Z4;F^23Y?_ZbwG|I2>%*u<~ zShh9T1AM2Si1j_gxtyrdn#);v_d5euisClUy3?|vC`i*fpd8#TR4Fj5CkxC($` zA!2z9TXKGT9{i=rhd*(Aq6;!2;$o+Yhf0Q$tcj1iE`+?tC zP%!2S{$WB;eWZRTXHQ!NBr1=-v$&GIV|bzZWB^GQ?9G`vaI6a18i%T9Jr1g zA)EV451M#PRZ%Jjo9Om_E?z_yrU6}Dy+7;2h$vP3qEDoUvm-AD#>)T}oNNxK8&Z%8 z2(;3)c}x4&j7a*hp#gs2T(K?C)u*sJtzSCa-jUy;Cg2~oiv0ZpBoYt6|C!ji`Y(al zltlWOt2G!6`cE(lQcI#c1Lcwd91~kr~UqIvca_tQdyMQ zvbj~JM!M~uyW(ZBALcq-8Y3hr$kUK~aLMxRDlZ1;soK+~hzH>X5o}YzH=)+D9@Br# zCfD+Qgp)NyFA2;YFz7w(IB&5$q6(Np@1{>B)Bo6V-=E6IW-kG-kIo^67R;5A&lwlJ zj=4b9iwRVSGYd#l()cd&@S$r(YR8H6jPJDL&33gTrbd19CTZOfLeLTz0J<0kG`s}RR5A1X2vXY^8= z)@X9^7zo^8o$mwou3UuSoj(;h+Th(>w*H$y$F?ckp^kI!(eJxl>;FwH* zF1ciZua)xC_wM&}_4~GU=w73jIWijtVVENq_LI-;c4xD?Nl0C?zCjv0=kD4zKefuh zS}XH~0cP*&u1b-&Z`Gn4O$FOwlxH2XZ(W4Er0;%26-7T)g5)q>Pxm6~%* zc>Rli*q8WuF6=E}xtPO#^8JXjR`rvBc!O>{6fD=*)qAWAuR;u~#~bAK*5dy3@pL?K z|6c$5a^wb}zA@sr=#M&<_z-xVlf0-TAxMt`DRDara3+UkI}p@gMCuOrNxtkBJ=koQ zNUYUlCrJ%e#x!`gDS9j-&5pityY6#5!+W63Sqg*KlRsF4*~U*hRU*#>9z_ZGH?9h*r(jC0Api3j1&>yMrhjyC z&zsxOnry>OcZhQoY@B?%C#UJ)0?lvRZmDrwk1YLFBRmQHsIRJ2p5dWK7v$9xId)R) zadwNLVB;zK&z~kFuHi|^V+QhKpI-C2AXY@$7di=ZMS@(mm%0ik@Ghl90wI+^$~D z(m{s8FDe@tmV7Uj_Rqi4#L`>xXVoH7w&F!7kc<^-SQz=@phQCy_8@RM*{RWg3ft1a z^KH2-6EE|w)SW5zM{u^0>?e3;5GWeEQvL&g_bnGKTvDMY9s@IAmXtL)Xi?jzES}6z z*iV{P4kHIzCtuw|3-SeuDU2>7MA^zd{lquPmjo@Sk4)5twy?~Qrko}EPhFUX^qC^& zmqR#uO{Ca51v%u>X~CJN6BzV54AC+v9?UcGJ)=5mn4ZWLq1j6ThNrhIh0kU zhFR4vF8h0#h(yvG)JybzZk}E zrXcfgv2t^$VXE`~j1;Ur-am}?`ey*})2rg)F4^79FhB#Va6hc>SO`RSjOzB-@3m^> zvHEc|dhEw9^7o<|zQOB=M(}5|zuTzY-a_NySTH*;%n3!msKH_Q;bS(m&vf(E?)bpV zYf9hP?&3x>5CxcheMYW3`$yl-kB7;ic_A(9uA?R|Y9>cOIp6k@#YQWeaVs4#V4H4A zQruxo#;+(DgWPmPpi&zF#LhSDHDpV^&SQgY3bTnao3V@xFL?o77_B^LraCr*TYjmL z`dE;zS(-A-&9$)J4zg4R93Xnwq=-98M)IahH6G4!W;V*r6-5mDZqJAq&p0pBjDqYx z4~>8gOM|?rSxAy1e^_N-Ku!thmj4S1<&;g%5=v6-D-wx=+CA8=$;dWK-XB=nKlo&T zZ4@4XB5ttg4320Ir(>EwEt(ai5A{ziCKe5S0v!`}D+&3PMmJwUQ|dYFa?Z;1pl6+} z>)1Pwu5JSItTqGsOAg?A3MS8oh+Z{)r)9}A)A{~doq~(X@G#_lzBLCxR7E#n#f1E2 zYyCO1RJ|&ikbzX$meN%rNa|{TzqUQzNh;IH?9H!yJ9tSdJ!Eg}Id(tPjM?JRVUWv{ z)w;|pwjKI~_iacXu@UdxYXi;?6U=jf=QF_ea6JB9ZBGipdloqPGE6r)c~EB;iBlSO zSsczhZkaYI(%C-6Ux)*&+^F0A^aW1?K>x??(^|j(ITXfkPM>kIo?3*e<2q|kYVnz6 zzQ=|fG0fAAx<>-rI%w|5i>JjX(#!Ji_l_@1Ye2CT%C(vr&|KE*chCDYi!jvp-7du9 zul{!~i&yASJSuTGqX5s@-I-emk+Eano~Wm^3C)`Q6x>*#Wo6ynYwP{3zBah5_1JpRx~*0~PfIHNetS5O ze7K`!#eF#)RrDs16H#j2T9?LPGTTN?at50d9yV;6Yl=nDxl`P*-Wg6Dw((~UWsFOR zw%dJ&5b$rG3>1Te6gX!As7m%ST`Z-`Om2-c0^3ueU3-Fpve+;?)rlyqv3+0-Ioy?b-@49fjpG~E_L;`$9mjr9y!GNvf|zP;Vm_Or$DnQe=$@0;<&uMh7Y z0qDYurR>=s*&8SIIO1nt<0w){d%bJ#q^U69em$ZRruy1>13{ny81VB^WcqBZ6kRNL z+pUMm=ltYpMwThijNI|aH2j{X8vky|G@vwp#z#!6G~y9T9lk1hbbUp&23XIvXM_k?hJv zhaa$JodTVKgR8>*5%TfhzIBRmFH4zVF=%+626%$!Vn-1}I%sjmFtpCVfzKoV62ygu z%K?HcVY@7mLeLk4VOSbi^+_jy@n^6USbYUmNwUqDz!inzm653-;?WEXp3GUk0dRNW z&%GLIj@cI2hbX~Z98jPz5A8k#OE>miT2p?NJ=zzoHMx`R)mvLbfXYPYN}7UrGBgI14tu<&?s6KPF(wmO7o+%j2ktqj z!4~?hJDrWnyiR53;yIu(zPSiG;73C6WtqS#$~5ju?%dPkKp&Doo)`WqOIpIYCDj(`=%*RX3!(W&+)1h^X8lYt&0ywC zU41y|a6v>0_D+jt#^3An&!k0R{t)JHU#Uy~y(^k6j!p2U}|mwN;GomAVN?WuvhTEDeT z7<-;^smQYXBrt6Regu)qVj&kz0njeU=Q+oEf8VV`!~V&!E%_55g+%K8pIOtDeyAT4 zOEYM>p$n=R48(mI99!uEbuh(jnisbir55+g8>cB^^b*TuBW5`@02`eY`1dLp)lHV+ z4!bnahP9zzXNpxDPsPQ#Qc0pGLP^&cIz@J*xeq{ZHpo?6SubaiwXtwbTQV`Y_kCHe z72`a9nhT*SmL9Jh?0WssG4bC{bFuCTXDPt2BPAlrOd0GdS7(CtNp5M~jfonA(1~NC z;}pD(GNe1Lr=YwDAS`5^X)oB`sWudI+}l8v5CC~@$oeF>A%`~^pC39{GRgj?NFRz= z+dC-L6&u0S1gY91u^d8|Uy{+9g@>{jkOpKYpC>f>g-YIM>U5`NfdPp_e>y@Q@=KJQIPO??t z(2$9{JbuOpFl``0Vv)J6W};u@E^4XPmc z5*Rh8DyP!hq9@bn99h?lF}ZO@%dA#OjOYq1VD>-$+?2~tCI!1Ixwr9eixeQqX0bPS zG2c_e2759BZ5NfRo!^&-rF3*Ku4L8FgisnkkyssE>*7x9n*5KR?N&RPbG1E!#y62iZwCK`H@Fz2L z9=*8;0Go=k*c$!+HwW9A|My3WPDyqe(g{c|?rlzt-Ro z;d|FZLb{Q3N^X(dr<@Q)#)Frjuj}*XjOMSO+*IYB=t^rP-MfXrfmewa zuLAlZ8C^LO!`N!{Ar*=F0LrKa3E-H*$W1FI_lt$(?tNdS=E@7K&~ilimz6XINr0;? z`qFfy1zCD_oQ#+2BDj$rlSoy|7{&}R&rHa$$4nv}F)h(Z^^T zWAqG_#G#=nCwn_HbERf9_Bu?X%E@tS`WhITnjZ*PlFr~UOQmu#Rb^sQV!E|N3?*?D zn|588i6ZhAt~DfosKW388NeS7cHK%RUQ2p7M1~9rR`&>F8kz`0hB0#!Wu0pI(K`Zz z(Z?@W2_*mG8FDzPY}Wp4BxkNz;DVcag_ma+a4S?aVSO$&MT{Cr*jIk4v0!VVAYH~$ z^5UvmE^m@-J4cLPE`u#!h`q6f-OJMzsl!K0g5$C~OhogR#HqIweZVStKCscdD(nol zrT0X%Z9BAI%Wxl8et6s3vZ~~crtvvCM{sK*Z7(reu1=LIGs%2=O$#enbUZqpHPzHK z-(Iahr-eQF5iB`*P5Ahpj93f$@)laC;GKG)(`x53hG$pWeTv`Qb+Y{jEe=yIjQ; zu6;@jr_j<6e-v$}wqSWe!h+}P&1r0+Jb>Bypj~1aR~zGS9kB8Zm&i|qLc&Q}#k>)C z7Fk|%trZmPvq1q%zb@q0Y%;;+h6&4&V8wa6wJCqt^Ll)K|85D!&_h}~=2>{WMqP*3 z1XNbqeJvdO@jZl&HW8R57@$qf&og+v{DS43w)KZ$gR!IFNdIcp;I8~BG>ea_ui*b{ z<4fS7dcXf?Eb}B}D;m4VnynN{Nwgqa$W9}XED_mCBWsqT&`oHuN0JC3TSb;+-?uE; zMXM$Cd+y~^|LOam*XzFSx#zskInO!gdCtAVok!(_Cds0}bk6w67+Koo)YD`9TyMfu z%|2Uk-l_B>1XeY3>39S?B`zSE06ES0SOCt!x`;BHT(mug*OtSLbfC(9=6* z;@`4CC)e|^aZV>meJoFR@(j(r_D&apC>2^Y(tNKRmC7CaMxwmYNkbC#u(|@Hn;E;# zFQ1ifQ=|$A7iw&3eoI>|io5N))g~&V(lRs1p?oOul^1h{^1cnl zQo7Rqa_L*lP0AeZ&84GvO;N zyYf(!>oe1!TSw<@-9ozLQiGk%+!uQciINP1;?~td#Lc!;F8HNBxdCmmk?)sYLu%fB zbGhZ=;^94CBLjS-^_^8$*uSZsdL>5X8FsX4#Ztj@k@t@9gWhn*XoIK~htv?M?fb8n zSZS9%n_oza7)WDsF?rGO(5OHzkSA=KHRpy+qMLk(?z2Fln3P~80mb|)+(%7;UnFf` zZSHBapjXEv8Q*z{giP0YoFpqAT>kc*bvR_U(JQoEqSz|1*hs5z$B=Enu0!YdxeXPJ zus)5~m^XGHdC^yfgr#p|d&DPLBx2y^caSOnT0+{rDONvGl2Wov=tb8lS6}I{{Z*fi zGp^Evg`78xyjB%wpGaTN!puF)f9#5R)qU?y1xbrG&Xp;@Z9W6sc~ZmP`vih}KbI+I z5I@`!|21-u-&uZ|@I)Ybu%p?T4wu&bPNL@QsQ5cA8sq&k@82Yo@&E5z)p@o4cow)X zM_xm;)+Y4KmBdVgo+Z=7Hlk zi5E)}iPsGt?Tb&;aAQ;ajxVKs)s?3HdzDi(aK70ft7lg0Ljp&6r0+1(t)+1bR15QYH(n;$DXnrmb)RDq%-HV4ti7e`#G7%tV`@=qvEva# z)qCo_%}rTnR2V|fS$LIAUm6RT((|{wRk!taYWSG3_@wqnOSbbim*m24N%ij>cf36w z)8MaP)Mc*S$m1_vskpLO>nYW2GL&E$HFWvQg5#8q|Fb1u@}*0WTXSWM0t#tPp1Zpe zt#QJ=?L;HdWhwtD-R%lCSxo~L1J&1-+9Iv`HTM--^J0|~m+sq+|H^q`q;ztRo&~$A z;dL%+Ih??Kd`4i(43}zT!4}sIb()?WwL%5iG#d`zxLkLNl)NKc?8u4sN{LoJkDyWF zb$`+O`7|HpqBk~>r%i_pVsrP19bG2(42I-&G<^Gv!f;{t0RbML?jP7fl`YdDl!&BFhJoyE`b$P(?l_!w_LO&h;Ls?=hX^87e({*!^7J>vu&ZMi2K!nIHAzb5_t<64g3tmoNve zDc#Pg$O;Tzv<$GlM?P1s8*ylMd)l3;de@ZY7P*@xhm-;r;9nf87uyt%oSa^j*tj?4 zicSlHL@yj|*u@uDzCTrK63?ZfTA@y{&>iemU(VWb?qtrL#KrQS;}AvJ3k; zgo5v6x}JTx=Y|9W3s0Qa5xd@-=ZM(`XTAfqiJNIlvKdG0!nCu=LH+X4+8xZbH+_32 zoLBXotVfbh*j~J4o>kb|f#?Di>aunL&#srpiKJu1hpVb5q@DazFP`0+W>0r~{wovP zYy_SERk{mNEwwK6haNmF{I;7UI54+GMdMw2{nV_L=V>93~j~mv+K?Yy$E@CwXnEz`lIF8&I>s%3*N@5 zOcg%gEw0kt`}8Ag__swu$SWnutG2wmvrRrp%zGTl`^_k5q7gT<)JfO>>rL;B{I$G} z_Ywi>Y~0FXjv)eJ5tjbHae2(8Hdrh0s4(G!tstOzFr;}94-YDMP{V_!uz8U7a~hNt zz6mCX)1t&eI6)TGDin$$Bw$2U3_%(rzT6?)!-(ia!hMX8OIpXYq!FYr4pkN*3?pvj ztP`C11b>WkuZW2y1ixE|w1Y3*{ z?<4eJ1mOc=m>M1G)F`2u9wlDR6UL}eBIOI=7KTw+B&cD;m7jzdJSy7!i*OU;q*DP) zOdSw_H8U!5Um@hM3V20T#G5}c^=8Q3z#0Xt;@Bp9&Kc5Eu7^m3|h-2VY2XF`@R9wIY%%J8) zK!p)HKA;W*b6o+F7)K)j{J?yv27xn}DDxV)g%JlLz*~&i5Cs}BqAMD7P*b^E7d}P6 zC`R0l2j(;==j(lN8;=qZ4*^UaB>2<71cup|36?N|_6eB5h%dPyotn-a?zxj{|D7We zNq!D?GhG7T(rJ&sq;-ihpr5>{=EBI`UT&Tk9@uvypjJV_BEFVL)^WE;iV2S0#FnbG zP2j$dMyFy1!@SdNvRfVJ`i?E}D0mr)zvAt6>jTR!OZ`{>NGqmf5tU#dlC68mqJv_tHk$x8n zt7e)eJ$O};;)YH>Wwwu16=%(P9`Ig6vzjAghxmv*QU7)SHn9dGIP6ZK(Kn2>krHZt zkbfxSfI-8x>t}EIRcTfYB%g`P3*-zKl(>~-^){Zy5yy;G`R3Ckw!C9Z3L|<)xuM-5m%O<%UV-3KoItpnu)oyQ%+b?&e zVSeURJ`Ghuqs-nfzm_{Cl9(&wjCq*1Gl(rw32M`Z>`6N5q1LQISIGa|Ri{^VNQ}kJ zdZ42t$j`iy&PTIhR)gqgNuSEW+SGA%zq;sNd8&lBVV*r)#*Z?+Z>d)vPW|j7m&G{G z`8-OLMJ!+aH1`s{WyG|0j}}L-4+=um2Qm2`dx*Nz|Az2w3}Vh%9HW59rHDh@hV*C+p;KJ#wx&eJm2oI($9OsOg7a>dfsNofAYc)0kO98{S{lD%T$l zO}|r}v9jsCq}HEOYjsR7w(L>-Lf*o{!l=#8xJ6?H@_DwZchU#)n#qnvM8263s^xyt zS4F8`d6BX-PQ{2@D2K8RtDb8%;VZ4Gih6}w|4_kBT51`e@F|MHNr+I~PX z=s4KvQNSdcF;~JA+oYVyFx|KR%8f#^U7j3LIs_#i#uU=;yAxFovb!{s+5P)i=J?0w z{TB9XCQY|oI_<7hk$8#R-o1dE-?vyE?#gsGC-H{zYI&G-I>-Cc#rGj8Jr>o!mbnwk z90gx8rRtQ?r0V#@c-)Ur@ZVmflj{6oR(Y;#kMh96k3I$ECAGz=g2rqM(nHs z_c5Zi4kTfOXCv5zwr(V(1q`8Q`&Li|?=gsE8<0cKr`y2(KfCuK8ErrrazE01kJT1BWBRcS-*Hq~Obt?sg!Gfhd3D`5y#_ zOTlkP_&b0QKWfR*vq7Yq8HX!Aio?O5#r*lC;4g+mcl!(M(AC6KZKg(d9$ee>t-#6D zYttqij$;oFC-?`BTJ^ev z>dr(oI{`0x?SNj>JV!!1fiPwX`>wPB2VaiC;aDgv6_+CKI|2GQh0LQ`B5#mQT|f}i zs#ca9uS}!Gp~n^qE&owO?>|(y+2-73xPe_BOyk<#ifhmmyhk_^(*?Gnwu`!;?W8Eg zuN!Pern zLBx6hFTx)O)qi!brGuddI#WwR#Cw3E09v1TeIa%WIKWffQ2Qd_Pu(Hz@h#G+tY8wSg=Ov=o2V^kRqUq5}VThuJA#JBXrBosh z`@k*?rSGnHi3_3v;9P@0RQ~fx!82B`4W6+dh+x)>fbXp0_h{OOuzv3eY z24EIDJO4lYpo%5`>Z8J%9njo_>FAqaJ+2 zUz`eu6ZsPanlWiSKq7w39Jq%!x#Xhhze{&YT??!Oj>>l zdn*QuDB+C5@lcp7+6a)X1i<@0$vo{sp6Gxhkf8lng_{dGIK1Z0X&7cik{1~m2JFbg zVZeiqp#o)wZbO-CGp_2!_4BK+o6e8maO@P`Cqxn1k@bd|Da=}N2G->{oG6s7m#B(d z904Mz?Rz88_VXi1=?D-hy(5mo+hWeQ5;&Y)WYpfnRuw6%j3)tvWDa-`g^sl>9Q+7FO+Jfpw<26Nfd1b;6@?=F9oG@dc7Wku#0M1d z#AO|^bsTV@wUHf%+|Tao+;c8q3*tMz<}@4?{q$ZJRgJGTjXso%Bd>G4d|*NNCe~{; z0Ywe|>mr*8z=e9a3b|A(A&BlI;6jQg04KJfnNDuwxs68kA`g2w>2X zkE89n5IO?OAxr@^yN*KTFq9`}nrk>j8Pef!0u-oEQ7DRMmz398cPGbxXGiZS;Z-2i z!$UpFfxL(TNF@RU5v3>?Wa7+Pkg`)S$k02OND}d#0vrO^^N?S0&24BV51OI8C6E#@ z>@H+x8cr7!n{ocSqqu}DE4Cv?s49kf~PXi+QoTM=gy``qCbNL>C%@orcwKmz2 z8KncQ-GL31vh(au!}N$q|1>NGw6=^|Yt96SY#I<-iwJUcXCSxa$$HtOo`8+W{>=X( zhVm>_UhwR%d?!`tbW1jt z*=~vHW9v}S!lz$TW_H?KUrDSL*-wI|_;M;wGZq(xzZi2_9c6DR4Qpv3V65E+AHnC! z;b#JTl>#-jp>~ZcR2GR%flezjnO_o8+Is3LZo@5HF?&ke;D#pFB-Q&w7j5EC9haV9 zEZ>oE9~$B$Ck^G*3DbfHrWU?_Wa4ze)7|QbBZ`h|ow328v}oZ$MbUI4C+bs)GOeU} z5igyL!j^ME?@)n+m_b68%F3L%{>nK_=0~!>yjl{Zl;y#y=47#1hJ}%98yR%~)dkyHN98(Y0 zDn2yho?@fq49;rn2=!WeJAbQ}c`0&N;opbkq23t4WxpmS0e*_H&@j@6K69^IX<~WSQRbs>Ysh8 zw!=~y=u@ckTH9L0*aS#b2rWPSMq%##FlDpe5dS|C!htRS$2&9E3VOad%R-Snth*Bx)1o&Y~C+es% z)EU}EVe4eBKo)2qTMhaxKA5T&Nrp4Mh>`x1}E5l}!Txo_B;WT~qs zA_ZbbQ|moMnxSf{3(z9Rvf3KB)5Lnj>kfxvxAl)mM!w+`Xb9hB(Yq7Sj$Pg(SOtZL zJV2AV%F@Fh+27nX>r-ix0)tt%rPv~5$LW+!vxC&6>TLL$HMD`dFuERS1;ErsWW|Rv z(~+U_pf6ELJ(t%OU-tc&ovhJRG5yG{{VVn^_%x42L-D6CRSNYv0;P7!9l{+Ivs^p} zmeyepo7Lbo(ctMfD27g#&65t=KF|<1F?9C|Mw4i$TM)_p*oCw&VE&`JKO&aJK?4uA zZcI-xlu>x&xjCWfE@;kR_3|$mMNJ$*%gX04f@8uR1gZ`@e=hAuqq29aK!$)h!*DeA zaf&B@#Hh^5$v?2v)E`pkh|#_!Jb@xmDPd}bw}QnAHXv;zA9&LdnQz&r>D#&Ue%9gv zBQ$O|+)!}tT6#wfK#{vt>|m~oL`(5(mecrF*;BcwOQd4l8aW2}BGxM6U0u_Oa_;<> zneuoX`TUP#X@3^aq=~nOtm9O`!ACNr%r1RxhSu#qSKQ z8}_QAC&lMWt76q|1IN|w15pu_c+=QogbO+cw7;DQy!o*9vb~;$!w--D zC}Nb**3#(1i#yDVpJBj6FfTmWB`HkCMF5e;In&H7r8f(^aq}f5HVn()O&ZWoF;_)8 za1#B+mLqQpmwZNxVx(|@H*%no7CSP#xLe+)^)>ko;GZ?QTz=7X34F9;laYi+{$&;| zI66!@6@BLJg*?b8X8~59G_H2#VBa1C#Et4@&bvKsU+8dl4Vk_Ev%?okBtJfBW3RSU zJ+0s4A;gtQik)K_@B29^H>m3Z zdTMQjW(Gx2)|6#hE1aU4I9{6-4Bo1YUDCr*#_cg+D~+}e6y@oYM(FQLAj&3hSpl{j z?WXGLez^d< zE9k9t3P9)rx@20^9T?H9Kug&#=&?BH%Ai)X4vFC#nAilTlBCxX&9uhb8uQua2ZM^h z8a+mNMt&kpUEbqNg;SYZrQML8f6RnvvgLYnL}e7=2^1iP3(7L#H4r3y z{8_IcJ>bjFb_~c?4Cu3aQa$zb_ zFv>0k@}(Wc^V(?M4UaC209@RGs==`}^TXkKO1ZfX)tYSIAJ)S*oT95U_4>x(&X%DP z2yWx~3{B;9v&->o0TvmiA=ShzrovS#E9t=soe(4tE_H2fwLA2?c1%r(12^EKB>sq! zoN6p^;T0&*r>?E!!U-`-v*MaTP=>K@B*LV-)n2CWIHMZXQtcK^kq-Y^OmXo$jW{m% z9DZ~11svJtF>n0d6YJC8y=MF1{&dat%G6twmY-}%>hpF3f7eZM>{%8hJ_7C)mEioE zvg*&xyb$rTBSBQ)<~_8dI1tcdH4I>!WfcM)yNq!d5>1CW*fv5149v`HMfqWsd>`*- zfYhVO{lODvE~DiITK@|6I_27qk{O`$Se|4uknlb1vTX@h6%vVh*Kh11x1C>>*u|(x zCv*(Y1;hw1U4=478W;DbMlLg7TmLN8QY{`=H7NY4$8{k!VB^)lM zlo1Wxk5_9?Ebb^!Pw4DF_J!K^=WDG;UdWbnu`6D&*hrnuZQ6hZR<0e9>KuDNpy~j8 z!2YivzvJxj;Ip0Jd%A%AO)mS0=iI*en1Fj9DhZ!(ed#;uf1~&7t6Ou|ag!4*;K|5& zF3<#$93;bqq<{(T0A#g{Kv+iRV*Aru{bh76l};79csBWZyP~CgOf!>awfp{im~UtM z=@wL6^Y$p$y#H@~sBHkt@*S!&?CC@&8@oKd*0BkKSdUA`q-aIS?wdd!geOe=oJ+o~}zCUN^KiZJr z)b%P2h*YrLn96+m`Ifu<-Sw>mZXKG(t{bA+OU5qrwI>QN19XY2RgCjFmi-b_6)dSP z^5U;Np?EjUX2U;@peEpP=`2xWv@4ZP*Kr(+7Ra>9+Coau7(!cO%b;{oI0m4dOYNac zT|(zNi6X%)<$>u0g>O|!2>6(4HtdPp;p2I|!KzG56=ln71@M(6aWH5pbOoq6)jSF_ zD!7)q*m~s9B|tMf$)l zkTInYJ(kZ0U@r--g2COOm>>EGKSOdf58=tW>^Mu@X4wq zxLosig6iNgQiHI6l$37;;V9r4JCIb}b8VULFt{r0CznpFI45)lzw+s}Pexy^OS&RH zJd7aquWY?Y?H95~!5X{E{}%XgSL7{S@#4py)~|SEE5^~ev)=wGboVHhl^1YUl4m+R zQCjiaxC3@XqB$Jf`Zx>JlsLmVh&Ku}iL0dh$I4{B3d>m4m+5Fq6Hf)!+&znQX{MIQ z7P4BZiVmI>`!8q-ZA&G@)MdjyBQ;tjYG2alnnv>ag|#**s;n=1QzkLNKS^?bJmy1- z{%{GKa{@4r3>e@w15el=+|pFN2&u6hLgTF4`vA?bjgh+HRksh8^&$4}Aqiv{t3^d6 zc^rL;E&oiAN@RXUM9XAhDaI_rov zjgaXXV>6%Cu5wXs+jVGZXM9Aw(qYm@{~35 zJrj`H(jU0!!{C9F-6*8a=0loCH)tO9ZKDyQl%7|nOZI9H#p(BaEJ7>rbvQ-q{77(;4Ny;^OTT-CvzNLIg#;!O>-XbyUKJrZEacYb=e z*vH9Y^U{M6qpr~%+d#)UBwv4;nfc_`WKKh(e*U$el8@dN{L?oc4pF=&Uv~&kQQI0p3OM{U#NbdpxNOc!a%7AOFXOWQl_Fd9@((vwtK|yPPUl-NZJUsJ zT7{`pCQs|v#GzmF`TzHI(G(>m1P%AUQ{tyDS!ME^JPn}dxXJy$OM-hDtm%6qHkYe4 zTU?++awd$`e8IFa>zkz9CvJQ zt1DU#xOhE_Bi8X?uRl9lU!TpqvP(+tE0I(=Hgs7i!c<-w(00?3xwbf~hWgEYT4Kur zFhs-7A$(G)(~-u`zIgp0&QTF>SRo@MZn<-OjDC zaY6bYn8R{n%3$dvf-NS?nm*M^Eq*gc5y77t0C}b^NmV!9xq*(;g-+r1ym$BGdH?nC zV{8&7+TO(Mq%Z5I-r?u;U0>rECof$Z5%|J7TNU%bq#G2^n-VYdg>yCSu9q)10b}&c!gEmBV1CcWtOR;0C z$S@SH;p13f`x^Z-ICK7TyximU1sfxfMOG6{{2;*o;(@F??YDX=7=Yc-U|)U@iUBO`~uG^gOjn-(C0e z^*%$tpK!5p5Rg<_JwQw3TvFIOu2|Hs0llQHSY;aw_t^WBrVkZ`8}S(MP68{69k`H; zjansg1z3tDsq_BnE{MI)XUos;??>@MU9zJxpZWFZue+ov&MI?*xYFr>D6Be;zGM%n z%5>>`G}p7Eij+~}!P+0-@s+?^HOke_ZB(&L4~3*XU4ZJtFMI9Z$elxx5QS>J3C)pe zqRIkEg|IFXsC#y*l{_JhE0u?1BZtmnf^n=!prsJg@B%gOhC) zBN6nD<3vkw&Qn#ldP@vl-1D}A{N6OtQBSwY%0rfo169l0h@b%+c{USi!F05R;r8&C z2e+AI^=3Y+$d@m4f7!Cn;|9{-VBxed+8C;DbPopWZtQ1RH=wj`Gw8t08o%ESy%r?n za|A&zUPIdc%pba6?x$(RiGz)A_);q2W~EHo$3;cgZ1Yo3h&zjZ!pUhsUBRpkQbTL_ zC`u40(l4r@3hDtu&!SCgwKwlYK&g`y=zoj3q4bIHCuD3zOoCPrnxY#wdyGH%8bnbl zhfuI{Uz|_`}1ynv>QT4+bSk!MBpK?4@#&6k}VtN=_^6`nNdDE2wEE2MOzGaleM#_Aurq2)8Q3cJocPf3a7 zH}c0!fAM^VqUVpLCQHkT`oCnKQ|a2ARCjqTW;_&YF;3P30nfiqTG?erp&T}+%FM0C zByC}-3cHMxChP2p$jEQH35~emj+azfZQiTy$oARIhLi^ykdg9s*l8i!-&v{CFs>2y zS%xHcC#e8=-}RKwK3DuULSpRCoW%l)S+o7;q1JO+B9nKvi&loZe{+7Sm8w~J7`cup z_6ADQLZ$@wdRF36+NJSap4Y@J&Ho$-eAi{4)F-r2o+xKmQz(g-Q+nDF7o3k46Sps) z1J;&(sXmW$e$G#Ex&0(j!-DplibMgSX@r%f!;%B%@cSo_E4Gf@H{>5iRs|p`6^V00qSIakdhrUSu@6oEQCDsY5v1A4VgR4vyP$vO4Ik5tFKNz^NwecB~{+L~6EwS=G z;1|e6kPA0ksQ`xEa*d(w*2!ZoISa>3c#l`7&>TbYI;U7hrr^+RmZ^vPX^cd{6T(|&+a_) zms$sC8f@bAOjC@D|BBSG52mA)mz8X)T+C6QQcX%zC$RV)JaWAMD{$zt>`1fW%-2S) zER&Ox(x_sJHZ!)^*^NKyBVab61RDg0K%H5pc@|hAt4rN~w+Z5+r)oMlecHW~F+(#isuqy=KqLyQ@yhpvAv z@?Nc5p+{5{y(HfyGe->;~IVz73*j6_?pIZLDQHIj0Oq^$msCOW%=mq`;=lDpClA zl%_?Kjy>Gzfsz1mm^zeCyms9!sVc@jgWhK{E9*HLF>+ZQUxZ1$R=uxHNgZZ!%i9xg zwe`3^g})hvnmIt6SikwlgV?6KFq@6Fw$<_yndV;83C*k$K+@~=$WI8nSPl@_d7OF0 zOb;s3N!r~w!EM5v26K>MH3XTN^rPB_)>aAClWB7Fy1Xfv>ep9cKzVB*hCl1`U@R`R zEGRoRTL!BmN!A{g4HT*Inr3NBWRyf1i$jEkmbJN7v0HI!EF07B2X8_vTIsMDRl5Y$ z!Uj}F`q6!>ODGF}5VoyCe*~hJ(IOD&kbWZ4S6Z=!C-Pr_>-*mKV0Ka@mNU{96_?t= zVc7%BbTn0s?xr$zZW5RK==&Zr(N65LSykbR3OJ|weDq#E>Hr4_g428EdQU5wI#k(p z(b3u8cx#HA-1R+`P@kwzJTREecvMc7)9BTeu}`&}D0XK@MSf&M7|^w~WG>_`K$#lQ z)-T6$_EkCdo?D5#970S}xI($;T0Of`>`!hPp&& zr17aTFxrINwQ<|=+jO8_J}oF@GwK{A=319*mDyLY9*r253y^(I#6CrbmJ!3 z(f199*&Sx)$v#WSvFmHyn`%&Uc zp#tev+;Q)NS_XW?L)Rmc2=<>Z1&R(J@gpti-n|4%**w^Z+dxuo`usfl=dcieCx!A%bwTF$R zY#Za>)aP(zeLGbzYctuZX))3Vaf4Vuv=Od5KTT+^S`+OEOtyBvr{T>zIn+LWt7 z^qzS)ep^&E%a^7SGpaRo;S$wRTh@Ci=(FJcg8ZLMwxwhLKbh?F%1ESLxb0`68IM7e zf}R8n(4}MVy4jBYIb#%5Xt^=|8Ld6IPWe{G>Svl|rI5kRT2|EPTEY=OCZHyp%nfrMdPB1r zAUU|ZclFFabeJPr_cvEvvy@48GH)!W+sOIlL7G$VKxxp4#y3B9?gYQ?13|Gd2HYKbpwrq&0&B7UMwp{(s*br z?87c+8m0#x!O#^f^42rl*1F~Xj4t;zu*0*3d^>(kR3o+5@TLVy_yr#`OZ2fS@_9D?Ll2{r@!?`qp-f@Z&@eCJC8bN5@73 z$HZFL;25!#omZkSQl;?_r@2oA=s&tm0QGcxJslQ*%gn#yw_V8@;@SGX_X z<yOLZI2666*G0Bfj|ipvh(k=i@Grgd`U>cN7XHlr@c!H;q!LuKOX;zXn&so+G2wpa zB81hv?OI$EfZ!3xZSb79M{$9PH|0)gU~9}PhG7gg<(~A)TiPG3=U~7~g{S?QNDbC- z%r-2Tgx+wFsEdmf&4->2XutQtSz)#JYd<4XC~HpHA?L(dDDyxdO_#X)iK65ZWXgLd zNgzd08AlrGzzD~m4w(o;M^1?Kg_|AqX+l?!QU6Tjk*V=yXbn0sV2)$n@Q!_G2|Nn& zZEXRWj^5hNh-?nk7ep7a) zm~*@DLg`!{llNCZ=H^3dGp;hmy`tEGiuvNHm_}~(o{G5wEMejNJYU5Et{OH2hH<5q zm0Id1{l3~Q2ai;l5B$jpak^c%7}O&hy6v|`n1~w=H*6A{(i$PFQa0$1*BWKEHp-3M z!Ir6y78Bu-q?T$hV<$&m6(>j;n?O4&wS)LrCk4kllCuZ+Nd>E5=rSa_!8$VW(z@QFeV~ z4B6iZZ@T22$AiWdg?7kq>LLBC?eQFfp+}&ZB9zaMdE>g2#<#|jc}IA2|3h*#AJj$z zk(8}*YxPc`4j*Ri@F-dW%b5)y`eMN+3L!Zrir8{J@!ww}PA=g~#A*Jviv_E8T_EZho6}TY= z(=*ugj&u6?a~I>1qCK4#?yC4(VW6d>FFco?|an<&!g1vGd@wtd~h`d&||&AJNr$$K!N%4UAMm9Rc&j7J-gTx zWfcIhDbDfvR>yslYioQJ0guxEn*7}>fXL4PNBgFIHEHvJkA zz;XA7uFRhazC{&+Il%oM;;aNi!7Xm9LAHh+`0o(SD#f6UWn*xK zl($!V!CJ0nP;)71uHaZ;gd-->P6vgtnnIMO?@R7X+=z}cjE#>=m8xR)^uAKPr|Z4U zrra%5yhB|bu^X5*P&sRYDxaq@CoCDY|)cx!zf(@mSF@x5x%L|*u9W`BcOSmix-_49w9qHB^O)p zw`;oa+M%Ev+V1`wQh?$|-H4+8ce7+_q7kSLk&>%SM;h!AOTk(tl}W}$PJ?DE{5G;G zOO5oUtXVW3sLMIl>C%BEE;9rLR2W zGVEym>-t4)xyaP0yW{P@!Nt;-&b)^o>j*pM&cE-PDGMr%xC4==HV*lZCW%8rh3uD9 ztBUQ%Rg>6I{7qf8t^68T;al|`)vOn&NQJTNzu%K+Q+j4@hya`Be<24LQ=Ya^E)8#> z4lDCaG-tE0sJ8!RA+1)#`9&jd4*nUe>k69v#x-gtMKu4KVEt%gNfjHdDXHF`U4tzSg7GnY+tG8s%_{652F|x1J}vZ(Z6Hbslgybg zdG0sb-vX%b<6x!S?Zb$FU}M-DWgzkq3aAA;91{{c+PEruP zz0B(2a8syGFE>RalGNzP%PXtMEKC|N5VgS@1yBD<$xEvw)&pGGvVHqyezv^1x+|wB z-xo7Tr*PMkC{>Xd&lx%)a4KG2qDRCn_*r$Y?RuZ@v7wN8K_tz<%Q6X*m9Cd4kE^b3 zsET};IJg{T8N32cB(>{Ex^@-80DGDYlxOTjpK!+$)KAy$!9{a)GEne_0m$;HTvi!^ zpHc@cZbe;^6j<{@Z?X36n$?>Y@d40I}KI^ZWS*aq#=TDS?kz*C&p159xr+>ThLe{ z!CAYSgR$TjG&d+bZKBi-BY zbcOt`fr?=g#`C>Bu*@T%o`2Hk-Xdd{^v|K3BoF*<*SEmmt>*qQ6}0svK|FR$XecT0 z(rosDVrF}I9#)E`3oy(Gu-LkN;81=%R8BTw)-jd{^2k=SKi@PmtIRH;$_)JsYy4Lt zT!n0nBE+F`%GjQsVyJ5$Jv>FkwExjFpzC2s0H;4_CB*+|JHo9wW8gGN=^iv2f3(`*yS!d>59`2O%)~rhd|TGkopoj$tDEUw+##-YwU||Z zCyNEWJz&?nIe5lr6{2@(sF5vB_hzk=J5@y!S>7s+*tHQ)W+6W?D3vJ)w^x;0DOkvn z0~9y|Hc&dO+Y=e&RX??#2s!bosV2zx^x@RIx@!gHI}t>>H#W-oKxLl#lsZ!05C{AaUG`I07|;Zh@7qLWbvZGUw2EZK+S ztcTZ&0&rBj!64TgTEr7 z+He^&7l++^`*|m%<66AiN`m8>7{fNR?a?BU3S?BB**g4aHoPP8s-s$EJUxx`5fDp* zMC48E`m*rcWFeOK`@#3VbBZQW0dV9eI6e2lj+p2d*(Cso%hw1uIY0+ ze@i=uEuhB&LhlNv=vItWxMMWMf7pz2g5!V4ZztJ+)Sr*2YCQhSysT6dMoF%%EIY1( z*~k7|p;y1hME1+mgD{gjt6Pygka1s!W7gpy^}`*K8c&ZgGm~G?_RhUU0H7HDvMpiX zntAz~@Gp1^5y#g3ZKi~2CoL?IY`hvD?-L;K`ry?ln+J9@_ z`+a!n5ufNA*LiZ|I(NV4m>Wgu=~Df~Er<2qA{+hoz8S0Wem&CJb~m~1+P3=|XSnx| zhtzK*s_gyCitSquiGt*T5g>I?UtDb@82fj~CXhKL_(pMM&W3{)tkWMFMtA{MUT|j} zd->AP9(0A^`SkgoqBc^wWu>HXRs4bL3t>kRUzg9;^Ua6jpnEj-iI{80cfw~iMu6|J z+Hk~glOP8>@MA?K${S4u9vPBbCpX?YX?r_2_nD@->}%zuaPjH|tBq(pgp9LjSKg@|Qm-h=xvj=R$cTne$r z#uy<@qy!}oig@T!^#%&U0%;t}m)L)rmSja@0EL7xb<_d9>9du6Ha3snmg=YyN z^Cc_c;wl^Dp-%uC>bM`c^*84VwYi_a6#Oas9)Gj~S}7V4cL3bm9Km8LZ$ZSzW1fJJ zNg-WK?W+f?_WnR@?8l$2lk8XC=3NsU>E64#W$sEgP|mE48_&A`b`WR~RJ9s(=v)5u z^V*SU7m@6H?r!bL)U}hF9N3piykYn+{NulW?i1@EHNY(dMwS8*oA$}snsdF=PFVwV zZ5~gRJ(0T`@_=D=N4kM7b2);9%NEN~S>etV zyLm06@5z-;uNH8&=}}!xHTSbkmrw3_E>fqq*WBPr1MpQ&RW>gS!5I9Q%lEkd+<_IuI=wTD>cjW0bridfxl znhmnSWYcnflY>g%MABLgW3REww`ztkL7H!h%+#qV_RiQw9sLdUgqFV>J|cfcNTEg< znW}uV(|h=TQ)x^8Q`I;z{->&$@Nzj*lT-CBYr1Bt*_HlVPV`T6@yyMO2$h!psQ_Rw zg3D@tf4Oe^g&Un@E~U7MTJE8X2wF2>d_2;j#Z5X!M|88T zN6i!3%rfHvwMj|C^@i>;GXkUErZGgy)MvEEWmWt4;ocRfWhRDHrPI*Iql}wlEX)Sv z*e(n(70~)}57mZ=X~_Q+{2DHy<#Eu&fWs$O9!QZH=2nu`nNQJXfG!lhp#=&tS|LdC z)*3Cz{E9gHZ(|hW^=Wx{3Nd_FkbGlYT=yVf3ryX8@H%{7UKV$aSQec{7>%H+PB!al?$@U*GXMCSM?i`g5rU z#yiwSz*pCL%XPp<(V>4O$zZ5t-gKQCM>1Nc@nYi3%!jpGSMr^$Fe~?Ci?icwSFZgo zocj<}u3T%<^``nIo0M*RHXTFltJ{bbckpJ`dv?{EfHGvTW5ZZzw+~b>z5!!=8YG|d z1Xm80mRfv3>7V$<`+u0>-CMr$AHfKkf`y+t=1XbiTtx*uGJkrD!uzmbS+Cn2cb}zw z^t2kXp4+@ncsS&!zAYuv22)_9R>qVlD~GBtSLq}`;Xp-+h8=3xlKvDUNwMsB*hTt2 zv-=t@@F0v#QHOK5q6)A{x)v_}=QHr3sbEXGWo@xy^2^z-jjnwZNg+pQRU=gy7 z!rkx|(u-UO%2sC#=eY*aq-bQGPk zOF?A^BshWC)@^={7LD*itI<}J5=5E8oaK7*w8HgX;x0!7-0X&Ub6>zX0BY;6oxZlbwrKo)+-dMc&T&a9KK#%K6v<{fscq87y2A zOVZmhyq?fC`7-<6A-GA!>E1aIzsEaj_wDNnmP<>kSm48btv9^4F1&xVe|UY_ySFii z+S?rfTnGtCfI84XB+nc7-)_)Fy|@ulc=66&P47vQ@1xV?zv<<-U$F1#>ByCP?OlvN#O0S-qD+)q-|Jveopu$c7Q7ht0!mL}ALhsL$(Bl`y!j9wLwG#T8Je!)m z&L5Qv-B5E6!y816s;aaM=(B7U{$&f{l77+{HA1xb0GKu^LV*U9Xe~3ew#JJdFFx0@ zK8%e{N{cY*w;<%mO&cQPLp`=VjA)9LgAL6vME6q8iXWzj*MrsI`v*pNDH>u+*c;OK za31JkmuB#}kbwqeHf-cVx>(i&XcN{!JYg^xDq&T~4`Ki99|W2b{c=NNkBrJgxj1-C zl{MnhfT2aRGD`C(X>HnyL;!k$!hJt^@OLL>+L4_d)xPgrYDHeUh2~6wo_io7vn=Ex zJMHu&YEeP4@Sj>3V9URA?S+pyK5U*GI+qQLSI=twqR_$Hn8=(WE7YwNt6u*qAeH9q zp2fvmb-i)qYE}BKxz4M$*wlAgY}dj<9&)~S0t5iXUJ`rsFj!OX`C9|@@Mp>V zdhgKP+YJwMmEL9%n!#c1^n z)ntW8H>A(%UTQl6Jb#mRtd>Y(nCoB+?l9{gjJ1w)t3RjUj@s8_U>`gCl$ZGh<&8W%U|^a8>^e= zne{pR6&Yw{gE*kg)+G0Tf<+5!1+~wIY|WUIe_ZxAwqAM=c(NG6aC$nO@M2Cn|K89j z*+(&!l~yJW{kqH4BWWxH3q|s5^YF4t1w10bBFq^Hn%J!L@1#-NoWg{|<~xaH^fMHX zWlDn0u!+$^PmjViRi%z!@xt%h?_`VRsCh<~as&vcoqApN>|IM-F6pw{JU}wG?Y(6( zykUL%>;@n-I@>N}nRw-vn((ZV3-f>f**V;EUs{zlT?9@4IRqQ;d;2*%ungQpqkf`h~ArQawIh(T_kRj|@|`yZt5IOjI8Nj;3{f zp+s=bn~@XDj(I9WRCPVUd}FP)mPayFO->;jEp9(gV*RI?R}vqgM@P}M;VW=7@wJ7P zPML9bcTW2k8{EB%?0MM0r`Zj6VCRcQy-hj)d=k`C!X2{u6)NnjM4=l)285y%Ld{jL1M(DA-RGs_9K9Ao9I7qig=e ztNJngpM_sK7+7gkaE%YC>e8o$pCU#Xu~3^uT|jQGq8#V2C0-FhjSsp;LKfs}Ump|& zdPB8|$o`+4dYA34XPY)Krp&;#Qs^}+5Ez-vE50rY0!0m@cO?x%> z6O?hFsXAjtj0J1{RapHvV8emA2(3_}OQ^oKtDGs_fz<$2zNJPDpCtzRm_}mcUIUAi z$WB^75%+pWASiYx0)4+BQv$chQeq(WUoKW63KfN(Ph(V>oR$4A%8LWOj%Ji!Xo=*b zY;7Wve&L&|p*E8`2_XodG8yRO)?9>;(d_jN&PhL=(EU*htMY>cFpdmC4D1SnYv^Vv zaLqMlMz*?)5ci!eaF(d4q73)&^4k#P=i$C=E;<-=)QdO>8N{(CnOiyBeB3{zjedNJ zS7aP}x4U~27)q}iw~eha!-T_z3(q%)51Q0tsXs728)O=Uy7unrCJ$N<3P3?Sh9K_o z=SlvJ7I<0C(xz?-peD`l(wpbpHRg--J|ye^#^}qd9|$=Lq+2_{e_W};Fsqa&S)pus zKZ5z{R{goApnqoMQIJG_$DYFX-XU2t;;CV9}`HwF9UwW zU8qZ4!pUu(S8=i`ghXif<%ezNg&;k}uEYrDKVT0ZltB6ipjrwIK4D#Pwcpv03-vh0 z0S#otR$H%e7kgxgsM{n2%R20mMgFyJuL?Kq-b54&MU79(;t8DH*qY`oX52g-vOTfo zbT4(lh0k(6*)V5ZdX3xcRIvT#6KL^-&ajjXQ&h1$=L0M9!=h+7D5Dn4rCjm8B~*mF zhso6GgNH5zc!yF3sXvir$`WQ{6fiGg#yU!6qpiud|CsGy=`H)qiqO;-C!WEOpv@X_ zF-U@KB8-dCxhgAJOmLOOrer=fSmQ-c=hl$rQZ|7%(#`Atf$2QRdIH@y=mv2N0<7PD1`Vh^p z`&_#MahE(E&`&Tq<*otjwHE1`1C%o)<3WQU801{X+CkY+H3v?GunA~K z53C&P;!90)p#&3>KYTwg9`m%^qY4PLxKQ$>p|25`^Xo)MXMS@F{&kX^p2V^2Wdj81 z1d{=q9}!zxt;Yx@&-R>d3xe4OM#G;ES&c7#J=Zr9Z!wL(ex-}W8{h0o;$z|BGOQKF z;=NG>ZoG*Vmo$-T)F}+-F3|_C3QloI>J$|De898A=DI#X2>x@XRbow(C*6c z(z{4WwanLIt>uT2sdc%lGcXVYks)0Z(aQlExW?HvU=C!lj9Ho%8Nr+n8fTInDK0%4 zM>yOswM@Ko9p9CUoiQrWL&Roj$-U@8AC$ekkuK(HB@(a}U3Bg^3KOGWECf+VKfP7C zwKg>fJq>U*^gl4Ho1)|@v)(cU(>Znv{(a?*nnk*V(9Q*TbjF2arO)42IBD>F-5dk| z4DKG6^V|Ll>g7X(3BwsSuqahq(?Sq&h`JULW+u9yrlyUyrF;tfloz-&*Sy&%j6ykY zHIn)XvDr@`bX*VcdEu5pGJVfhiy)GyO*;v=N$Ag}rFRei`lx)u35wy)U z#+P))c>ivgPqW)|!MEukr(qM0N&TT&iZ2h$C5iPC8D=x{-9! z;%}-JG8}Fa=8}Juco>BIBk#qKZ{Mw!P1=QmyxC4oYb+JYl`9|EQa-JlQHubiQ)=DK zqQn=@%8r&?&Z6!dtE-{UqVD&&#~thvzBl)WAt|-_SiMsOq^c;5)LdhCtSuq{*T>IMDd^#sS;|1Xbd=Q-6B9`TL_v25HFnxTO5KU^$BgZdvH zRnZ~*57AnhVgFCHc(OA1iYIxxixgO7!3w{AVkp`w@@o!3scN-~0T<2sQNR+FJ<+0s z*)#;-+T`&?Orx{#gXBEa!jVgE#{1x@QRySm<1qkNYK6#21e3E(s?Jfb&q#UM&vyl z@>eCeJZSU5Fx5Dk7=WOH{lZu30z%|JTWzfn;v0W+q{;pC&X*0<4^}4mNogz3$&9L~E}q{iLvpls?^;Lt-(i=O0^R*`y8yci);;ku|demKm{trryJD0>R(a3 z%}V8~-*+d|lmYkrz3%vTsnkYwv-io2T(25j@c~y{PlmtswSl6g?q4^WgRlU>VWvzk zuVkV#Be32Zgc^+Uo=d6|{AgKMW62b`szXnG@KngsO(W3CHdgi&^apGAJu0YMa!a%7 z*{KI~U7eY?YmBESPbts(pZ~Octnjv~{v>aQL+VE7kgkyf4SbIJg~P=g2g6!C&j~Q) z<}Lh=wVnImt$)D(j+kHNv99dLg0DmWK76J?{7%$slgLAo%k_56lR3cJ3Exa3DBdqrDk|qyrc$Gl$w;_XS9=*prOo=c}=S51_ z^z^jM^z407Jfn{sG8G&*4e^cGc12N;%6%gvYrg2n*;?KmM>FlLvmV+Cgo^pwT~xd! zD;@A*Z^yccts!<}bJDD4>^-c$OQ$z$CP;hrXCG)drINnu?sJDc<+RXlyaBZJ+htw% zy!pItQ`JGpsA2s_T0lZrLiB47K_KnROiH=f17vcM%JV2=vqD)n8@pNuWP@| znVH@bx%-!yh-zhx%bK~)CS)`Ho~d~7ey8NVd~}dJ1ym|*B+)708`SL=)J;KeDtdFF z_ng9@Ztl@!BrEg@z!kU&kQsunBdiKLBJem8&|~m5B*?yj-z0%~0)C4GBgt%?;52+S z$&_W`S4prnj}01&a37M{`vA8jL3TNQm;_5J@uMWTT#eh3p!*e`PJ*y{d^-uc8u3^X z&|C0BB};58lZ|gqp&@U(Y3g#{}L(C4j>u9!Ba+%;Nea*gydh6hicx3PMTd zAOLox`BOe{fH*!2ARZ77vyOmPk_q|~D3Hn}u0WRr-_HOZ z(jkurppt-}4ysAzCLgehWPm^TO3YPo6*!TS!`DC<31&jTGZIupfLA1lj0O!PI35SO zNnjZd_K{QNB!Vb1WaDJOs$A<`&`0W2Wr8UZJiZ48NswItQn<+PlOty34I$9J1pFaz zHC)zN*+%=ds_kF=%n*B+SOR37hGt&|47i`zA7(0Ye&f}eHTRTGWy;zmyPaQrC7?oj zw-~Pb>d6R$;asHZzVS3eDaC8^$VJaYPuhYR$DMIHHfD|E*?Dm`W?*J!aiga`HS zUtMdU>+;q2$+z}1PO^t*xn8^dy@M8|X&N!=f61#;-nKVh8EeI3jib#glJyKSZiie&Wsv2u|$T)m{eXqtw_gcB6 zu<`3P-DdNY{U0kEe*3I%z_&-eAJng>RONW zYwj-9+JQ}v4>e?KtoXb9qLf;gY+ttzqeg%@mC{%L zg;yfHf)=Fs=!se=Zb;~hzqB{xeNhTiYB<7w>ADlg26VOUYI!`i)-X+$UTot_>RnjZ zaC6fpV>xwd+_S6h??rdtxqCj$xZEIV)I&96-Y_jcL~en6p0T6Y)Lgqjqfj?|P(%2z z{tLc@I-ZKj)r~Q!pQ0WBIl7{YgY&(8QyL9_H7cA`a&b|8^H84hqFgcMvBi3m=Hu@5 z;**M%c@6tKHIDQLtMyE$-tVgrVLA%EX^L#o*=r$cYLwGg+Il9lDbCW?xUcGMGq?O@ zD|H_~M}b`J;_5qC!sNG(+04 z=qI|N+q6!qneF7!&G}-Y*F@bK_3HZImyFC!TID$$EdKb#xl^Ai6U6!s%Sj7i+Hf2ho&sJ-T7f>k}X;ZUl~ zHv0~^qjXE(lgrLeI#fmKv*QE(uGsu@w|a+>c&v+u;}uKn#TK{)h)40Sq!(`&-{bOa z?LrP)kHby88v-QQ@b_xO+)!%tAXQ!x50pM z(xr39KM9X>*~{PW8OXIVyt>%QQ#i)2?4-G)+@!}h!5NX}aS01`=h5CBR!JxNKTWo~ zZrtpB*2}BYv19guF^_uLWQ`#`*T$)|Fko(N}+{;w*JgGbAV1R$IqS%PalTcVnmBy+b2g zOIxFh@4KE?Zf6`>Ht&9;zKC5wj14Vcusg^VX!wD^&$}1e!nUQiQ@C1+>AP-h62~sg z{ZY7XNM|hn-N@}9X>tV~CkHF&n^(LWQvT8i+sEBR8QyZNoP1F*#Rw|vs+?+G`B=Ts&1Lr4RR7lA4u<-JGeeU}>dyw>HAbmC=*X?Dj-|g_ zs`FLr9i75)XHlWlBM?p=#syD70eR56JOdX%L)l z;XPPPEj0~)Zz`%}zLi21;v$}*#d>_vzjr}lm@s00z7i?Rt-^JzM1C_se^XXg3SwBv z77Ua8sf|7pDGz+YL;a-YbIt&_e*j|CN8#}J2e6KaFrF9-B*2FsfIKl~5MwEHZ&?eF zSVr9HeBAZy_(gO96W>A%Tf#AcX?FOsd>Y)}0{BTy@=p*ChF#Idumv2N)FK$r0*D_= zFueu&Kl%t(w}9ou_%kuC_!xe(`}f=e_6p@pqh~qgieMP)F=H&RiIn0i(7Y8$OA!Ii zVw7+F=sNmD6rdu1xt3rpA@o)I4WZs5=%;s0ip`iN4L zOMoFCfhZJ9Vb4gGth7{hhJj*FK(Whn_^wPQ^vNcAPS}6B3m0^PrBUrbfyhLu9dSNc zBnQvr;Sx}yos~r}A(@}Y(k{kDe+fPlg0Lc%iEIZDA^d1{AhNfVMK+h?^M7kF%QF_9 zq9}de`530c5u$lH%j|gvkR!9%*uG^(0;!Ioeq7F>T3SJg&?<}miiy}q)9r9wH*0h3 z>qho%-NbkatYzTy;H_@foEd~9XBfWd25O|gnxdepT`0?J(6IF!7v3XhOOiX=hQ3?O({U`S5r?SCtN(=aVYW$D3Zpj zYo{8eP%d0(GfHt7U#9}-27vT$t8DlA>N9z?Y>F-zCeC3p!wqwgVV}c3ldfi3E^^F1@T$cp;WrBMxJGfeK+&ON)~x<0Uyu-emytR{8fxjrCEjN^%Mf&p~xN409`WAy-oAT^9xq$C3@Av84@hz#0B zkh0L5!O{#N$nEAVa@$TI@ZWQBgiuJgVkxBA0D<31G!oUg_Bsk%iyy<3Il{KtO_*tu z$(hU#d~^gIm-km-m>7qa{ytdO&)U7S{itxC906Q#6=kC`z}kzZ1Bk6S%w~NDSn1p# z*pXvw_AOhNNw9yove^rR0EesGfB@7OWH*o)Z@=~v)PG~B|CV#aq2>0k6k^fHLRY)9RODHWO?l zY=@97^`<|x9|Gb~eh7$=rtY-llL5$dC+~loRXLDQT|=0L4k6RoVCec8tbkJyfFFJw zVs#snkko_|lGRY-Guvt5#geKhbpf~Er(l%StWBAMzLJ{hnRo{V}^k!xf|n060e?7k1+x<`Qa z-whK_2#3l@p)hQD3g*I(qwF;yM9ELsBB?R-a|e0T7(=XV6`MUi#!5MmV5_Rx?4vPO uo3#?`u~%%?rXD%}dAci%qau60fkxwC1>x3(7~9svz;U33OTI-7i2V-}pX^2e diff --git a/dist/search_data-9BD0835A.js b/dist/search_data-9AEE737B.js similarity index 81% rename from dist/search_data-9BD0835A.js rename to dist/search_data-9AEE737B.js index 03877113..f1fd7484 100644 --- a/dist/search_data-9BD0835A.js +++ b/dist/search_data-9AEE737B.js @@ -1 +1 @@ -searchData={"content_type":"text/markdown","items":[{"doc":"This module defines the setup for tests requiring\naccess to the application's data layer.\n\nYou may define functions here to be used as helpers in\nyour tests.\n\nFinally, if the test case interacts with the database,\nwe enable the SQL sandbox, so changes done to the database\nare reverted at the end of every test. If you are using\nPostgreSQL, you can even run database tests asynchronously\nby setting `use Wanda.DataCase, async: true`, although\nthis option is not recommended for other databases.","ref":"Wanda.DataCase.html","title":"Wanda.DataCase","type":"module"},{"doc":"A helper that transforms changeset errors into a map of messages.\n\n assert {:error, changeset} = Accounts.create_user(%{password: \"short\"})\n assert \"password is too short\" in errors_on(changeset).password\n assert %{password: [\"password is too short\"]} = errors_on(changeset)","ref":"Wanda.DataCase.html#errors_on/1","title":"Wanda.DataCase.errors_on/1","type":"function"},{"doc":"Sets up the sandbox based on the test tags.","ref":"Wanda.DataCase.html#setup_sandbox/1","title":"Wanda.DataCase.setup_sandbox/1","type":"function"},{"doc":"This module wraps the Rhai engine and provides a simple interface for\nevaluating expressions.\nIt also sets some default options for the engine.","ref":"Wanda.EvaluationEngine.html","title":"Wanda.EvaluationEngine","type":"module"},{"doc":"","ref":"Wanda.EvaluationEngine.html#eval/3","title":"Wanda.EvaluationEngine.eval/3","type":"function"},{"doc":"","ref":"Wanda.EvaluationEngine.html#new/0","title":"Wanda.EvaluationEngine.new/0","type":"function"},{"doc":"Handles integration events.","ref":"Wanda.Policy.html","title":"Wanda.Policy","type":"module"},{"doc":"","ref":"Wanda.Policy.html#handle_event/1","title":"Wanda.Policy.handle_event/1","type":"function"},{"doc":"Used for executing DB release tasks when run in production without Mix\ninstalled.","ref":"Wanda.Release.html","title":"Wanda.Release","type":"module"},{"doc":"","ref":"Wanda.Release.html#init/0","title":"Wanda.Release.init/0","type":"function"},{"doc":"","ref":"Wanda.Release.html#migrate/0","title":"Wanda.Release.migrate/0","type":"function"},{"doc":"","ref":"Wanda.Release.html#rollback/2","title":"Wanda.Release.rollback/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html","title":"Wanda.Repo","type":"module"},{"doc":"","ref":"Wanda.Repo.html#aggregate/3","title":"Wanda.Repo.aggregate/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#aggregate/4","title":"Wanda.Repo.aggregate/4","type":"function"},{"doc":"","ref":"Wanda.Repo.html#all/2","title":"Wanda.Repo.all/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#checked_out?/0","title":"Wanda.Repo.checked_out?/0","type":"function"},{"doc":"","ref":"Wanda.Repo.html#checkout/2","title":"Wanda.Repo.checkout/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#child_spec/1","title":"Wanda.Repo.child_spec/1","type":"function"},{"doc":"","ref":"Wanda.Repo.html#config/0","title":"Wanda.Repo.config/0","type":"function"},{"doc":"","ref":"Wanda.Repo.html#default_options/1","title":"Wanda.Repo.default_options/1","type":"function"},{"doc":"","ref":"Wanda.Repo.html#delete/2","title":"Wanda.Repo.delete/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#delete!/2","title":"Wanda.Repo.delete!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#delete_all/2","title":"Wanda.Repo.delete_all/2","type":"function"},{"doc":"A convenience function for SQL-based repositories that forces all connections in the\npool to disconnect within the given interval.\n\nSee `Ecto.Adapters.SQL.disconnect_all/3` for more information.","ref":"Wanda.Repo.html#disconnect_all/2","title":"Wanda.Repo.disconnect_all/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#exists?/2","title":"Wanda.Repo.exists?/2","type":"function"},{"doc":"A convenience function for SQL-based repositories that executes an EXPLAIN statement or similar\ndepending on the adapter to obtain statistics for the given query.\n\nSee `Ecto.Adapters.SQL.explain/4` for more information.","ref":"Wanda.Repo.html#explain/3","title":"Wanda.Repo.explain/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#get/3","title":"Wanda.Repo.get/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#get!/3","title":"Wanda.Repo.get!/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#get_by/3","title":"Wanda.Repo.get_by/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#get_by!/3","title":"Wanda.Repo.get_by!/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#get_dynamic_repo/0","title":"Wanda.Repo.get_dynamic_repo/0","type":"function"},{"doc":"","ref":"Wanda.Repo.html#in_transaction?/0","title":"Wanda.Repo.in_transaction?/0","type":"function"},{"doc":"","ref":"Wanda.Repo.html#insert/2","title":"Wanda.Repo.insert/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#insert!/2","title":"Wanda.Repo.insert!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#insert_all/3","title":"Wanda.Repo.insert_all/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#insert_or_update/2","title":"Wanda.Repo.insert_or_update/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#insert_or_update!/2","title":"Wanda.Repo.insert_or_update!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#load/2","title":"Wanda.Repo.load/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#one/2","title":"Wanda.Repo.one/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#one!/2","title":"Wanda.Repo.one!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#preload/3","title":"Wanda.Repo.preload/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#prepare_query/3","title":"Wanda.Repo.prepare_query/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#put_dynamic_repo/1","title":"Wanda.Repo.put_dynamic_repo/1","type":"function"},{"doc":"A convenience function for SQL-based repositories that executes the given query.\n\nSee `Ecto.Adapters.SQL.query/4` for more information.","ref":"Wanda.Repo.html#query/3","title":"Wanda.Repo.query/3","type":"function"},{"doc":"A convenience function for SQL-based repositories that executes the given query.\n\nSee `Ecto.Adapters.SQL.query!/4` for more information.","ref":"Wanda.Repo.html#query!/3","title":"Wanda.Repo.query!/3","type":"function"},{"doc":"A convenience function for SQL-based repositories that executes the given multi-result query.\n\nSee `Ecto.Adapters.SQL.query_many/4` for more information.","ref":"Wanda.Repo.html#query_many/3","title":"Wanda.Repo.query_many/3","type":"function"},{"doc":"A convenience function for SQL-based repositories that executes the given multi-result query.\n\nSee `Ecto.Adapters.SQL.query_many!/4` for more information.","ref":"Wanda.Repo.html#query_many!/3","title":"Wanda.Repo.query_many!/3","type":"function"},{"doc":"","ref":"Wanda.Repo.html#reload/2","title":"Wanda.Repo.reload/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#reload!/2","title":"Wanda.Repo.reload!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#rollback/1","title":"Wanda.Repo.rollback/1","type":"function"},{"doc":"","ref":"Wanda.Repo.html#start_link/1","title":"Wanda.Repo.start_link/1","type":"function"},{"doc":"","ref":"Wanda.Repo.html#stop/1","title":"Wanda.Repo.stop/1","type":"function"},{"doc":"","ref":"Wanda.Repo.html#stream/2","title":"Wanda.Repo.stream/2","type":"function"},{"doc":"A convenience function for SQL-based repositories that translates the given query to SQL.\n\nSee `Ecto.Adapters.SQL.to_sql/3` for more information.","ref":"Wanda.Repo.html#to_sql/2","title":"Wanda.Repo.to_sql/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#transaction/2","title":"Wanda.Repo.transaction/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#update/2","title":"Wanda.Repo.update/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#update!/2","title":"Wanda.Repo.update!/2","type":"function"},{"doc":"","ref":"Wanda.Repo.html#update_all/3","title":"Wanda.Repo.update_all/3","type":"function"},{"doc":"This module exposes functionalities to interact with the historycal log of executions.","ref":"Wanda.Executions.html","title":"Wanda.Executions","type":"module"},{"doc":"Marks a previously started execution as completed","ref":"Wanda.Executions.html#complete_execution!/2","title":"Wanda.Executions.complete_execution!/2","type":"function"},{"doc":"Counts executions in the database.","ref":"Wanda.Executions.html#count_executions/1","title":"Wanda.Executions.count_executions/1","type":"function"},{"doc":"Create a new execution.\n\nIf the execution already exists, it will be returned.","ref":"Wanda.Executions.html#create_execution!/3","title":"Wanda.Executions.create_execution!/3","type":"function"},{"doc":"Get an execution by execution_id.","ref":"Wanda.Executions.html#get_execution!/1","title":"Wanda.Executions.get_execution!/1","type":"function"},{"doc":"Get the last execution of a group by group_id.","ref":"Wanda.Executions.html#get_last_execution_by_group_id!/1","title":"Wanda.Executions.get_last_execution_by_group_id!/1","type":"function"},{"doc":"Get a paginated list of executions.\n\nCan be filtered by group_id.","ref":"Wanda.Executions.html#list_executions/1","title":"Wanda.Executions.list_executions/1","type":"function"},{"doc":"Represents the result of a check on a specific agent.","ref":"Wanda.Executions.AgentCheckError.html","title":"Wanda.Executions.AgentCheckError","type":"module"},{"doc":"","ref":"Wanda.Executions.AgentCheckError.html#t:t/0","title":"Wanda.Executions.AgentCheckError.t/0","type":"type"},{"doc":"Represents the result of a check on a specific agent.","ref":"Wanda.Executions.AgentCheckResult.html","title":"Wanda.Executions.AgentCheckResult","type":"module"},{"doc":"","ref":"Wanda.Executions.AgentCheckResult.html#t:t/0","title":"Wanda.Executions.AgentCheckResult.t/0","type":"type"},{"doc":"Represents the result of a check.","ref":"Wanda.Executions.CheckResult.html","title":"Wanda.Executions.CheckResult","type":"module"},{"doc":"","ref":"Wanda.Executions.CheckResult.html#t:t/0","title":"Wanda.Executions.CheckResult.t/0","type":"type"},{"doc":"Evaluation functional core.","ref":"Wanda.Executions.Evaluation.html","title":"Wanda.Executions.Evaluation","type":"module"},{"doc":"","ref":"Wanda.Executions.Evaluation.html#execute/7","title":"Wanda.Executions.Evaluation.execute/7","type":"function"},{"doc":"","ref":"Wanda.Executions.Evaluation.html#has_some_fact_gathering_error?/1","title":"Wanda.Executions.Evaluation.has_some_fact_gathering_error?/1","type":"function"},{"doc":"Schema of a persisted execution.","ref":"Wanda.Executions.Execution.html","title":"Wanda.Executions.Execution","type":"module"},{"doc":"","ref":"Wanda.Executions.Execution.html#changeset/2","title":"Wanda.Executions.Execution.changeset/2","type":"function"},{"doc":"","ref":"Wanda.Executions.Execution.html#t:t/0","title":"Wanda.Executions.Execution.t/0","type":"type"},{"doc":"","ref":"Wanda.Executions.Execution.Target.html","title":"Wanda.Executions.Execution.Target","type":"module"},{"doc":"Represents the evaluation of an expectation.","ref":"Wanda.Executions.ExpectationEvaluation.html","title":"Wanda.Executions.ExpectationEvaluation","type":"module"},{"doc":"","ref":"Wanda.Executions.ExpectationEvaluation.html#t:t/0","title":"Wanda.Executions.ExpectationEvaluation.t/0","type":"type"},{"doc":"Represents an error occurred during the evaluation of an expectation.","ref":"Wanda.Executions.ExpectationEvaluationError.html","title":"Wanda.Executions.ExpectationEvaluationError","type":"module"},{"doc":"","ref":"Wanda.Executions.ExpectationEvaluationError.html#t:t/0","title":"Wanda.Executions.ExpectationEvaluationError.t/0","type":"type"},{"doc":"Represents the result of an expectation.","ref":"Wanda.Executions.ExpectationResult.html","title":"Wanda.Executions.ExpectationResult","type":"module"},{"doc":"","ref":"Wanda.Executions.ExpectationResult.html#t:t/0","title":"Wanda.Executions.ExpectationResult.t/0","type":"type"},{"doc":"A fact is a piece of information that was gathered from a target.","ref":"Wanda.Executions.Fact.html","title":"Wanda.Executions.Fact","type":"module"},{"doc":"","ref":"Wanda.Executions.Fact.html#t:t/0","title":"Wanda.Executions.Fact.t/0","type":"type"},{"doc":"Fact with an error.","ref":"Wanda.Executions.FactError.html","title":"Wanda.Executions.FactError","type":"module"},{"doc":"","ref":"Wanda.Executions.FactError.html#t:t/0","title":"Wanda.Executions.FactError.t/0","type":"type"},{"doc":"Module responsible to generate the fake gathered facts from targets","ref":"Wanda.Executions.FakeGatheredFacts.html","title":"Wanda.Executions.FakeGatheredFacts","type":"module"},{"doc":"","ref":"Wanda.Executions.FakeGatheredFacts.html#get_demo_gathered_facts/2","title":"Wanda.Executions.FakeGatheredFacts.get_demo_gathered_facts/2","type":"function"},{"doc":"Execution server implementation that does not actually execute anything and just\nreturns (fake) random results.","ref":"Wanda.Executions.FakeServer.html","title":"Wanda.Executions.FakeServer","type":"module"},{"doc":"Facts gathering functional core.","ref":"Wanda.Executions.Gathering.html","title":"Wanda.Executions.Gathering","type":"module"},{"doc":"Check if all the agents have sent the facts","ref":"Wanda.Executions.Gathering.html#all_agents_sent_facts?/2","title":"Wanda.Executions.Gathering.all_agents_sent_facts?/2","type":"function"},{"doc":"Adds gathered facts of an agent.","ref":"Wanda.Executions.Gathering.html#put_gathered_facts/3","title":"Wanda.Executions.Gathering.put_gathered_facts/3","type":"function"},{"doc":"Adds timeout data to gathered facts.","ref":"Wanda.Executions.Gathering.html#put_gathering_timeouts/2","title":"Wanda.Executions.Gathering.put_gathering_timeouts/2","type":"function"},{"doc":"Check if an agent is a target of an execution","ref":"Wanda.Executions.Gathering.html#target?/2","title":"Wanda.Executions.Gathering.target?/2","type":"function"},{"doc":"Represents the result of an execution.","ref":"Wanda.Executions.Result.html","title":"Wanda.Executions.Result","type":"module"},{"doc":"","ref":"Wanda.Executions.Result.html#t:t/0","title":"Wanda.Executions.Result.t/0","type":"type"},{"doc":"Represents the execution of the CheckSelection(s) on the target nodes/agents of a cluster\nOrchestrates facts gathering on the targets - issuing execution and receiving back facts - and following check evaluations.","ref":"Wanda.Executions.Server.html","title":"Wanda.Executions.Server","type":"module"},{"doc":"Returns a specification to start this module under a supervisor.\n\nSee `Supervisor`.","ref":"Wanda.Executions.Server.html#child_spec/1","title":"Wanda.Executions.Server.child_spec/1","type":"function"},{"doc":"Starts a check execution.\n\nThe checks are filtered leveraging the `env` and evaluating the `when` condition using a best-effort approach.\nIf non-existing check IDs are provided inside a target, they will get filtered away.","ref":"Wanda.Executions.Server.html#start_execution/6","title":"Wanda.Executions.Server.start_execution/6","type":"function"},{"doc":"","ref":"Wanda.Executions.Server.html#start_link/1","title":"Wanda.Executions.Server.start_link/1","type":"function"},{"doc":"Execution server API behaviour.","ref":"Wanda.Executions.ServerBehaviour.html","title":"Wanda.Executions.ServerBehaviour","type":"behaviour"},{"doc":"","ref":"Wanda.Executions.ServerBehaviour.html#c:receive_facts/4","title":"Wanda.Executions.ServerBehaviour.receive_facts/4","type":"callback"},{"doc":"","ref":"Wanda.Executions.ServerBehaviour.html#c:start_execution/5","title":"Wanda.Executions.ServerBehaviour.start_execution/5","type":"callback"},{"doc":"","ref":"Wanda.Executions.ServerBehaviour.html#c:start_execution/6","title":"Wanda.Executions.ServerBehaviour.start_execution/6","type":"callback"},{"doc":"State of an execution.","ref":"Wanda.Executions.State.html","title":"Wanda.Executions.State","type":"module"},{"doc":"","ref":"Wanda.Executions.State.html#t:t/0","title":"Wanda.Executions.State.t/0","type":"type"},{"doc":"Execution targets.","ref":"Wanda.Executions.Target.html","title":"Wanda.Executions.Target","type":"module"},{"doc":"","ref":"Wanda.Executions.Target.html#get_checks_from_targets/1","title":"Wanda.Executions.Target.get_checks_from_targets/1","type":"function"},{"doc":"","ref":"Wanda.Executions.Target.html#map_targets/1","title":"Wanda.Executions.Target.map_targets/1","type":"function"},{"doc":"","ref":"Wanda.Executions.Target.html#t:t/0","title":"Wanda.Executions.Target.t/0","type":"type"},{"doc":"Represents a Value used in expectation evaluation.\nThis value has been already determined given the conditions in check definition.","ref":"Wanda.Executions.Value.html","title":"Wanda.Executions.Value","type":"module"},{"doc":"","ref":"Wanda.Executions.Value.html#t:t/0","title":"Wanda.Executions.Value.t/0","type":"type"},{"doc":"Function to interact with the checks catalog.","ref":"Wanda.Catalog.html","title":"Wanda.Catalog","type":"module"},{"doc":"Get the checks catalog with all checks","ref":"Wanda.Catalog.html#get_catalog/1","title":"Wanda.Catalog.get_catalog/1","type":"function"},{"doc":"Get a check from the catalog.","ref":"Wanda.Catalog.html#get_check/1","title":"Wanda.Catalog.get_check/1","type":"function"},{"doc":"Get specific checks from the catalog.","ref":"Wanda.Catalog.html#get_checks/2","title":"Wanda.Catalog.get_checks/2","type":"function"},{"doc":"Represents a check.","ref":"Wanda.Catalog.Check.html","title":"Wanda.Catalog.Check","type":"module"},{"doc":"","ref":"Wanda.Catalog.Check.html#t:t/0","title":"Wanda.Catalog.Check.t/0","type":"type"},{"doc":"Represents a condition.","ref":"Wanda.Catalog.Condition.html","title":"Wanda.Catalog.Condition","type":"module"},{"doc":"","ref":"Wanda.Catalog.Condition.html#t:t/0","title":"Wanda.Catalog.Condition.t/0","type":"type"},{"doc":"Represents an expectation.","ref":"Wanda.Catalog.Expectation.html","title":"Wanda.Catalog.Expectation","type":"module"},{"doc":"","ref":"Wanda.Catalog.Expectation.html#t:t/0","title":"Wanda.Catalog.Expectation.t/0","type":"type"},{"doc":"Represents a fact.","ref":"Wanda.Catalog.Fact.html","title":"Wanda.Catalog.Fact","type":"module"},{"doc":"","ref":"Wanda.Catalog.Fact.html#t:t/0","title":"Wanda.Catalog.Fact.t/0","type":"type"},{"doc":"Represents a value.","ref":"Wanda.Catalog.Value.html","title":"Wanda.Catalog.Value","type":"module"},{"doc":"","ref":"Wanda.Catalog.Value.html#t:t/0","title":"Wanda.Catalog.Value.t/0","type":"type"},{"doc":"Publishes messages to the message bus","ref":"Wanda.Messaging.html","title":"Wanda.Messaging","type":"module"},{"doc":"","ref":"Wanda.Messaging.html#publish/2","title":"Wanda.Messaging.publish/2","type":"function"},{"doc":"AMQP adapter","ref":"Wanda.Messaging.Adapters.AMQP.html","title":"Wanda.Messaging.Adapters.AMQP","type":"module"},{"doc":"AMQP consumer.","ref":"Wanda.Messaging.Adapters.AMQP.Consumer.html","title":"Wanda.Messaging.Adapters.AMQP.Consumer","type":"module"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Consumer.html#child_spec/1","title":"Wanda.Messaging.Adapters.AMQP.Consumer.child_spec/1","type":"function"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Consumer.html#start_link/1","title":"Wanda.Messaging.Adapters.AMQP.Consumer.start_link/1","type":"function"},{"doc":"AMQP processor.","ref":"Wanda.Messaging.Adapters.AMQP.Processor.html","title":"Wanda.Messaging.Adapters.AMQP.Processor","type":"module"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Processor.html#process/1","title":"Wanda.Messaging.Adapters.AMQP.Processor.process/1","type":"function"},{"doc":"AMQP publisher.","ref":"Wanda.Messaging.Adapters.AMQP.Publisher.html","title":"Wanda.Messaging.Adapters.AMQP.Publisher","type":"module"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Publisher.html#child_spec/1","title":"Wanda.Messaging.Adapters.AMQP.Publisher.child_spec/1","type":"function"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Publisher.html#init/0","title":"Wanda.Messaging.Adapters.AMQP.Publisher.init/0","type":"function"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Publisher.html#publish_message/2","title":"Wanda.Messaging.Adapters.AMQP.Publisher.publish_message/2","type":"function"},{"doc":"","ref":"Wanda.Messaging.Adapters.AMQP.Publisher.html#start_link/1","title":"Wanda.Messaging.Adapters.AMQP.Publisher.start_link/1","type":"function"},{"doc":"Maps domain structures to integration events.","ref":"Wanda.Messaging.Mapper.html","title":"Wanda.Messaging.Mapper","type":"module"},{"doc":"","ref":"Wanda.Messaging.Mapper.html#from_execution_requested/1","title":"Wanda.Messaging.Mapper.from_execution_requested/1","type":"function"},{"doc":"","ref":"Wanda.Messaging.Mapper.html#from_facts_gathererd/1","title":"Wanda.Messaging.Mapper.from_facts_gathererd/1","type":"function"},{"doc":"","ref":"Wanda.Messaging.Mapper.html#to_execution_completed/2","title":"Wanda.Messaging.Mapper.to_execution_completed/2","type":"function"},{"doc":"","ref":"Wanda.Messaging.Mapper.html#to_execution_started/3","title":"Wanda.Messaging.Mapper.to_execution_started/3","type":"function"},{"doc":"","ref":"Wanda.Messaging.Mapper.html#to_facts_gathering_requested/4","title":"Wanda.Messaging.Mapper.to_facts_gathering_requested/4","type":"function"},{"doc":"The entrypoint for defining your web interface, such\nas controllers, views, channels and so on.\n\nThis can be used in your application as:\n\n use WandaWeb, :controller\n use WandaWeb, :view\n\nThe definitions below will be executed for every view,\ncontroller, etc, so keep them short and clean, focused\non imports, uses and aliases.\n\nDo NOT define functions inside the quoted expressions\nbelow. Instead, define any helper function in modules\nand import those modules here.","ref":"WandaWeb.html","title":"WandaWeb","type":"module"},{"doc":"When used, dispatch to the appropriate controller/view/etc.","ref":"WandaWeb.html#__using__/1","title":"WandaWeb.__using__/1","type":"macro"},{"doc":"","ref":"WandaWeb.html#channel/0","title":"WandaWeb.channel/0","type":"function"},{"doc":"","ref":"WandaWeb.html#controller/0","title":"WandaWeb.controller/0","type":"function"},{"doc":"","ref":"WandaWeb.html#router/0","title":"WandaWeb.router/0","type":"function"},{"doc":"","ref":"WandaWeb.html#view/0","title":"WandaWeb.view/0","type":"function"},{"doc":"Jwt Token is the module responsible for creating a proper jwt access token.\n Uses Joken as jwt base library","ref":"WandaWeb.Auth.AccessToken.html","title":"WandaWeb.Auth.AccessToken","type":"module"},{"doc":"Combines `generate_claims/1` and `encode_and_sign/2`","ref":"WandaWeb.Auth.AccessToken.html#generate_and_sign/2","title":"WandaWeb.Auth.AccessToken.generate_and_sign/2","type":"function"},{"doc":"Same as `generate_and_sign/2` but raises if error","ref":"WandaWeb.Auth.AccessToken.html#generate_and_sign!/2","title":"WandaWeb.Auth.AccessToken.generate_and_sign!/2","type":"function"},{"doc":"Combines `verify/2` and `validate/2`","ref":"WandaWeb.Auth.AccessToken.html#verify_and_validate/3","title":"WandaWeb.Auth.AccessToken.verify_and_validate/3","type":"function"},{"doc":"Same as `verify_and_validate/2` but raises if error","ref":"WandaWeb.Auth.AccessToken.html#verify_and_validate!/3","title":"WandaWeb.Auth.AccessToken.verify_and_validate!/3","type":"function"},{"doc":"Plug responsible for reading the JWT from the authorization header and\n validating it.\n\n If the token is valid, the user_id is added to the private section of the\n connection.\n If the token is invalid, the connection is halted with a 401 response.","ref":"WandaWeb.Auth.JWTAuthPlug.html","title":"WandaWeb.Auth.JWTAuthPlug","type":"module"},{"doc":"Read, validate and decode the JWT from authorization header at each call","ref":"WandaWeb.Auth.JWTAuthPlug.html#call/2","title":"WandaWeb.Auth.JWTAuthPlug.call/2","type":"function"},{"doc":"","ref":"WandaWeb.Auth.JWTAuthPlug.html#init/1","title":"WandaWeb.Auth.JWTAuthPlug.init/1","type":"function"},{"doc":"This module defines the test case to be used by\ntests that require setting up a connection.\n\nSuch tests rely on `Phoenix.ConnTest` and also\nimport other functionality to make it easier\nto build common data structures and query the data layer.\n\nFinally, if the test case interacts with the database,\nwe enable the SQL sandbox, so changes done to the database\nare reverted at the end of every test. If you are using\nPostgreSQL, you can even run database tests asynchronously\nby setting `use WandaWeb.ConnCase, async: true`, although\nthis option is not recommended for other databases.","ref":"WandaWeb.ConnCase.html","title":"WandaWeb.ConnCase","type":"module"},{"doc":"","ref":"WandaWeb.Endpoint.html","title":"WandaWeb.Endpoint","type":"module"},{"doc":"","ref":"WandaWeb.Endpoint.html#broadcast/3","title":"WandaWeb.Endpoint.broadcast/3","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#broadcast!/3","title":"WandaWeb.Endpoint.broadcast!/3","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#broadcast_from/4","title":"WandaWeb.Endpoint.broadcast_from/4","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#broadcast_from!/4","title":"WandaWeb.Endpoint.broadcast_from!/4","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#call/2","title":"WandaWeb.Endpoint.call/2","type":"function"},{"doc":"Returns the child specification to start the endpoint\nunder a supervision tree.","ref":"WandaWeb.Endpoint.html#child_spec/1","title":"WandaWeb.Endpoint.child_spec/1","type":"function"},{"doc":"Returns the endpoint configuration for `key`\n\nReturns `default` if the key does not exist.","ref":"WandaWeb.Endpoint.html#config/2","title":"WandaWeb.Endpoint.config/2","type":"function"},{"doc":"Reloads the configuration given the application environment changes.","ref":"WandaWeb.Endpoint.html#config_change/2","title":"WandaWeb.Endpoint.config_change/2","type":"function"},{"doc":"Returns the host for the given endpoint.","ref":"WandaWeb.Endpoint.html#host/0","title":"WandaWeb.Endpoint.host/0","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#init/1","title":"WandaWeb.Endpoint.init/1","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#local_broadcast/3","title":"WandaWeb.Endpoint.local_broadcast/3","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#local_broadcast_from/4","title":"WandaWeb.Endpoint.local_broadcast_from/4","type":"function"},{"doc":"Generates the path information when routing to this endpoint.","ref":"WandaWeb.Endpoint.html#path/1","title":"WandaWeb.Endpoint.path/1","type":"function"},{"doc":"Generates the script name.","ref":"WandaWeb.Endpoint.html#script_name/0","title":"WandaWeb.Endpoint.script_name/0","type":"function"},{"doc":"Starts the endpoint supervision tree.","ref":"WandaWeb.Endpoint.html#start_link/1","title":"WandaWeb.Endpoint.start_link/1","type":"function"},{"doc":"* `:log_access_url` - if the access url should be logged\n once the endpoint starts\n\nAll other options are merged into the endpoint configuration.","ref":"WandaWeb.Endpoint.html#start_link/1-options","title":"Options - WandaWeb.Endpoint.start_link/1","type":"function"},{"doc":"Generates a base64-encoded cryptographic hash (sha512) to a static file\nin `priv/static`. Meant to be used for Subresource Integrity with CDNs.","ref":"WandaWeb.Endpoint.html#static_integrity/1","title":"WandaWeb.Endpoint.static_integrity/1","type":"function"},{"doc":"Returns a two item tuple with the first item being the `static_path`\nand the second item being the `static_integrity`.","ref":"WandaWeb.Endpoint.html#static_lookup/1","title":"WandaWeb.Endpoint.static_lookup/1","type":"function"},{"doc":"Generates a route to a static file in `priv/static`.","ref":"WandaWeb.Endpoint.html#static_path/1","title":"WandaWeb.Endpoint.static_path/1","type":"function"},{"doc":"Generates the static URL without any path information.\n\nIt uses the configuration under `:static_url` to generate\nsuch. It falls back to `:url` if `:static_url` is not set.","ref":"WandaWeb.Endpoint.html#static_url/0","title":"WandaWeb.Endpoint.static_url/0","type":"function"},{"doc":"Generates the endpoint base URL but as a `URI` struct.\n\nIt uses the configuration under `:url` to generate such.\nUseful for manipulating the URL data and passing it to\nURL helpers.","ref":"WandaWeb.Endpoint.html#struct_url/0","title":"WandaWeb.Endpoint.struct_url/0","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#subscribe/2","title":"WandaWeb.Endpoint.subscribe/2","type":"function"},{"doc":"","ref":"WandaWeb.Endpoint.html#unsubscribe/1","title":"WandaWeb.Endpoint.unsubscribe/1","type":"function"},{"doc":"Generates the endpoint base URL without any path information.\n\nIt uses the configuration under `:url` to generate such.","ref":"WandaWeb.Endpoint.html#url/0","title":"WandaWeb.Endpoint.url/0","type":"function"},{"doc":"Conveniences for translating and building error messages.","ref":"WandaWeb.ErrorHelpers.html","title":"WandaWeb.ErrorHelpers","type":"module"},{"doc":"Translates an error message.","ref":"WandaWeb.ErrorHelpers.html#translate_error/1","title":"WandaWeb.ErrorHelpers.translate_error/1","type":"function"},{"doc":"","ref":"WandaWeb.ErrorView.html","title":"WandaWeb.ErrorView","type":"module"},{"doc":"The resource name, as an atom, for this view","ref":"WandaWeb.ErrorView.html#__resource__/0","title":"WandaWeb.ErrorView.__resource__/0","type":"function"},{"doc":"Renders the given template locally.","ref":"WandaWeb.ErrorView.html#render/2","title":"WandaWeb.ErrorView.render/2","type":"function"},{"doc":"Callback invoked when no template is found.\nBy default it raises but can be customized\nto render a particular template.","ref":"WandaWeb.ErrorView.html#template_not_found/2","title":"WandaWeb.ErrorView.template_not_found/2","type":"function"},{"doc":"","ref":"WandaWeb.FallbackController.html","title":"WandaWeb.FallbackController","type":"module"},{"doc":"","ref":"WandaWeb.HealthController.html","title":"WandaWeb.HealthController","type":"module"},{"doc":"","ref":"WandaWeb.HealthController.html#health/2","title":"WandaWeb.HealthController.health/2","type":"function"},{"doc":"","ref":"WandaWeb.HealthController.html#open_api_operation/1","title":"WandaWeb.HealthController.open_api_operation/1","type":"function"},{"doc":"","ref":"WandaWeb.HealthController.html#ready/2","title":"WandaWeb.HealthController.ready/2","type":"function"},{"doc":"","ref":"WandaWeb.HealthController.html#shared_security/0","title":"WandaWeb.HealthController.shared_security/0","type":"function"},{"doc":"","ref":"WandaWeb.HealthController.html#shared_tags/0","title":"WandaWeb.HealthController.shared_tags/0","type":"function"},{"doc":"","ref":"WandaWeb.HealthView.html","title":"WandaWeb.HealthView","type":"module"},{"doc":"The resource name, as an atom, for this view","ref":"WandaWeb.HealthView.html#__resource__/0","title":"WandaWeb.HealthView.__resource__/0","type":"function"},{"doc":"Renders the given template locally.","ref":"WandaWeb.HealthView.html#render/2","title":"WandaWeb.HealthView.render/2","type":"function"},{"doc":"Callback invoked when no template is found.\nBy default it raises but can be customized\nto render a particular template.","ref":"WandaWeb.HealthView.html#template_not_found/2","title":"WandaWeb.HealthView.template_not_found/2","type":"function"},{"doc":"This Plug is responsible for redirecting api requests without a specific version\n to the latest version, when the requested path exists\n\n For example:\n Requesting /api/test, will redirect to /api/ Note: `api-key` value is not used if the unique goal is to run checks, so setting it as `--api-key 0` does the work.\n\nKeep in mind that the `agent_id` of the targets must match with values provided in the `targets` field of the execution request.\n\nThe ID can be obtained running:\n\n```\n./trento-agent id\n```\n\nIf the execution is run in a development/testing environment, [faking the agent id](https://github.com/trento-project/agent#fake-agent-id) might come handy.\n\n### **Consulting the catalog**\n\nAvailable Checks are part of the **Catalog**, and they can be retrieved by accessing the dedicated API\n\n```bash\ncurl -X 'GET' \\\n 'http://localhost:4000/api/v1/checks/catalog' \\\n -H 'accept: application/json'\n```\n\n### **Starting a Checks Execution**\n\nA Checks Execution can be started by calling the Start Execution endpoint, as follows\n\n```bash\ncurl --request POST 'http://localhost:4000/api/v1/checks/executions/start' \\\n--header 'accept: application/json' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n \"env\": {\n \"provider\": \"azure\"\n },\n \"execution_id\": \"205e326d-0c25-4f4b-9976-43f9ba1c86d3\",\n \"group_id\": \"3dff9d03-4adf-453e-9513-8533e221bb12\",\n \"targets\": [\n {\n \"agent_id\": \"a644919a-d953-43d4-bd57-7e0bb96ee894\",\n \"checks\": [\n \"156F64\"\n ]\n },\n {\n \"agent_id\": \"02d99b2f-0efd-443c-ac9c-32710323f620\",\n \"checks\": [\n \"OTH3R1\"\n ]\n }\n ]\n}'\n```\n\n> **execution_id** must be new and unique for every new execution. If an already used **execution_id** is provided, starting the execution fails.\n\nIn order to get detailed information for an execution, see [Getting Execution details](#getting-execution-details).\n\n> Note that execution is _eventually started_, meaning that a successful response to the previous API call does not guarantee that the execution is running, but that it has been accepted by the system to start.\n\n#","ref":"readme.html#testing-executions","title":"Testing Executions - Wanda","type":"extras"},{"doc":"An execution target is a target host where the checks are executed. This requires to have the `trento-agent` executable running in the host. In order to specify an execution order, its `agent_id` and a list of checks to be executed are provided. Once the execution is started, a facts gathering request is sent to these targets, facts are gathered and sent back to Wanda, where the checks result is evaluated using the gathered facts.\n\nThe `agent_id` can be obtained just issuing `trento-agent id` command in the target host.\n\nEach target _must_ specify a list of checks, that can be empty. These are the selected checks for each agent, that are executed.\n\nGiven two different targets, the same checks can be selected:\n\n```bash\ncurl --request POST 'http://localhost:4000/api/v1/checks/executions/start' \\\n--header 'accept: application/json' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n \"env\": {\n \"provider\": \"azure\"\n },\n \"execution_id\": \"205e326d-0c25-4f4b-9976-43f9ba1c86d3\",\n \"group_id\": \"3dff9d03-4adf-453e-9513-8533e221bb12\",\n \"targets\": [\n {\n \"agent_id\": \"a644919a-d953-43d4-bd57-7e0bb96ee894\",\n \"checks\": [\n \"156F64\",\n \"45B653\"\n ]\n },\n {\n \"agent_id\": \"02d99b2f-0efd-443c-ac9c-32710323f620\",\n \"checks\": [\n \"156F64\",\n \"45B653\"\n ]\n }\n ]\n}'\n```\n\nOr completely different ones:\n\n```bash\ncurl --request POST 'http://localhost:4000/api/v1/checks/executions/start' \\\n--header 'accept: application/json' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n \"env\": {\n \"provider\": \"azure\"\n },\n \"execution_id\": \"205e326d-0c25-4f4b-9976-43f9ba1c86d3\",\n \"group_id\": \"3dff9d03-4adf-453e-9513-8533e221bb12\",\n \"targets\": [\n {\n \"agent_id\": \"a644919a-d953-43d4-bd57-7e0bb96ee894\",\n \"checks\": [\n \"156F64\",\n \"45B653\"\n ]\n },\n {\n \"agent_id\": \"02d99b2f-0efd-443c-ac9c-32710323f620\",\n \"checks\": [\n \"OTH3R1\",\n \"OTH3R2\"\n ]\n }\n ]\n}'\n```\n\n### **Getting Execution details**\n\nTo get detailed information about the execution, the following API can be used.\n\n```bash\ncurl --request GET 'http://localhost:4000/api/v1/checks/executions/205e326d-0c25-4f4b-9976-43f9ba1c86d3' \\\n--header 'accept: application/json' \\\n--header 'Content-Type: application/json'\n```\n\n> **Note** that calling the execution detail API right after [starting an execution](#starting-a-checks-execution) might result in a `404 not found`, because the execution, as mentioned, is _eventually started_.\n>\n> In this case retry getting the detail of the execution.\n\nRefer to the [API doc](http://localhost:4000/swaggerui) for more information about requests and responses.\n\n### **Debugging gathered facts**\n\nOften times knowing the returned value of the gathered facts is not a trivial thing, more during the implementation of new checks.\n\nTo better debug the fact gathering process and the returned values, the `facts` subcommand of `trento-agent` is a really useful tool. This command helps to see in the target itself what the gathered fact looks like. This is specially interesting when the returned value is a complex object or the target under test is modified and the check developer wants to see how this affects the gathered fact.\n\nThe command can be used as:\n\n```\n./trento-agent facts gather --gatherer corosync.conf --argument totem.token\n# To see the currently available gatherers and their names\n# ./trento-agent facts list\n```\n\nWhich would return the next where the `Value` is the available value in the written check:\n\n```\n{\n \"Name\": \"totem.token\",\n \"CheckID\": \"\",\n \"Value\": {\n \"Value\": 30000\n },\n \"Error\": null\n}\n```","ref":"readme.html#execution-targets","title":"Execution Targets - Wanda","type":"extras"},{"doc":"Built-in Checks can be found in the Catalog directory at `./priv/catalog/`\n\nTo implement new checks and test them:\n\n- write a new [Check Specification](./guides/specification.md) file\n- locate the newly created Check in the Catalog directory `./priv/catalog/`\n- test the execution as [previously described](#testing-executions)\n\n# Running a local Wanda instance","ref":"readme.html#adding-new-checks","title":"Adding new Checks - Wanda","type":"extras"},{"doc":"To set up a local development environment for Wanda, follow the instructions provided in [how to hack on wanda](./guides/development/hack_on_wanda.md).\n\nThis guide walks through the process of installing and configuring the necessary dependencies, as well as setting up a local development environment.","ref":"readme.html#running-a-development-environment","title":"Running a Development Environment - Wanda","type":"extras"},{"doc":"The demo mode of Wanda allows to showcase checks evaluation without the full setup with actual agents on the host. To run a demo instance, follow the instructions provided in [how to run wanda demo guide](./guides/development/demo.md).\n\n# Support\n\nPlease only report bugs via [GitHub issues](https://github.com/trento-project/wanda/issues) and\nfor any other inquiry or topic use [GitHub discussion](https://github.com/trento-project/wanda/discussions).\n\n# Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md)\n\n# License\n\nCopyright 2021-2023 SUSE LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use\nany of the source code in this project except in compliance with the License. You may obtain a copy of the\nLicense at\n\nhttps://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed\nunder the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\nCONDITIONS OF ANY KIND, either express or implied. See the License for the\nspecific language governing permissions and limitations under the License.","ref":"readme.html#running-a-demo-environment","title":"Running a Demo Environment - Wanda","type":"extras"},{"doc":"# Changelog\n\n## [1.1.0](https://github.com/trento-project/wanda/tree/1.1.0) (2023-08-02)\n\n[Full Changelog](https://github.com/trento-project/wanda/compare/1.0.0...1.1.0)\n\n**Implemented enhancements:**\n\n- Refactor demo server [\\#271](https://github.com/trento-project/wanda/pull/271) ([EMaksy](https://github.com/EMaksy))\n- initial checks for VMware vSphere \\(jsc\\#TRNT-1682\\) [\\#259](https://github.com/trento-project/wanda/pull/259) ([yeoldegrove](https://github.com/yeoldegrove))\n- update reference section to clarify the package version decision [\\#255](https://github.com/trento-project/wanda/pull/255) ([angelabriel](https://github.com/angelabriel))\n- Add when conditions for resource types, propagate the resource type in the ExecutionCompleted event [\\#253](https://github.com/trento-project/wanda/pull/253) ([dottorblaster](https://github.com/dottorblaster))\n- Add user friendly failure message \\(jsc\\#TRNT-1825\\) [\\#237](https://github.com/trento-project/wanda/pull/237) ([angelabriel](https://github.com/angelabriel))\n\n**Fixed bugs:**\n\n- Fix formatting in demo guide [\\#275](https://github.com/trento-project/wanda/pull/275) ([EMaksy](https://github.com/EMaksy))\n- fixes found by checks-checker [\\#260](https://github.com/trento-project/wanda/pull/260) ([yeoldegrove](https://github.com/yeoldegrove))\n- Add default failure message for expect\\_same expectations [\\#243](https://github.com/trento-project/wanda/pull/243) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n**Merged pull requests:**\n\n- Bump rhai\\_rustler to v1.0.2 [\\#276](https://github.com/trento-project/wanda/pull/276) ([fabriziosestito](https://github.com/fabriziosestito))\n- Bump rhai\\_rustler from 1.0.0 to 1.0.1 [\\#270](https://github.com/trento-project/wanda/pull/270) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump ex\\_doc from 0.30.2 to 0.30.3 [\\#269](https://github.com/trento-project/wanda/pull/269) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump jason from 1.4.0 to 1.4.1 [\\#266](https://github.com/trento-project/wanda/pull/266) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump ex\\_doc from 0.29.4 to 0.30.2 [\\#265](https://github.com/trento-project/wanda/pull/265) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump rhai\\_rustler to v1.0.0 [\\#264](https://github.com/trento-project/wanda/pull/264) ([fabriziosestito](https://github.com/fabriziosestito))\n- Update contracts usage [\\#258](https://github.com/trento-project/wanda/pull/258) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Document target\\_type inside env [\\#256](https://github.com/trento-project/wanda/pull/256) ([dottorblaster](https://github.com/dottorblaster))\n- Bump phoenix\\_ecto from 4.4.0 to 4.4.2 [\\#252](https://github.com/trento-project/wanda/pull/252) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump docker/login-action from 2.1.0 to 2.2.0 [\\#251](https://github.com/trento-project/wanda/pull/251) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Document cluster type support [\\#248](https://github.com/trento-project/wanda/pull/248) ([arbulu89](https://github.com/arbulu89))\n- Bump open\\_api\\_spex from 3.16.1 to 3.17.3 [\\#246](https://github.com/trento-project/wanda/pull/246) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Update copyright year to 2023 [\\#240](https://github.com/trento-project/wanda/pull/240) ([EMaksy](https://github.com/EMaksy))\n- Bump docker/metadata-action from 4.3.0 to 4.4.0 [\\#234](https://github.com/trento-project/wanda/pull/234) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump dialyxir from 1.2.0 to 1.3.0 [\\#232](https://github.com/trento-project/wanda/pull/232) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump excoveralls from 0.16.0 to 0.16.1 [\\#231](https://github.com/trento-project/wanda/pull/231) ([dependabot[bot]](https://github.com/apps/dependabot))\n\n## [1.0.0](https://github.com/trento-project/wanda/tree/1.0.0) (2023-04-26)\n\n[Full Changelog](https://github.com/trento-project/wanda/compare/0.1.0...1.0.0)\n\n**Implemented enhancements:**\n\n- Make cors optional on production [\\#206](https://github.com/trento-project/wanda/pull/206) ([arbulu89](https://github.com/arbulu89))\n- Build wanda with premium checks, if available [\\#179](https://github.com/trento-project/wanda/pull/179) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n**Fixed bugs:**\n\n- Expectation results result to false when some agent evaluation is missing [\\#224](https://github.com/trento-project/wanda/pull/224) ([arbulu89](https://github.com/arbulu89))\n\n**Merged pull requests:**\n\n- enhance remediation section to clarify the value setting [\\#235](https://github.com/trento-project/wanda/pull/235) ([angelabriel](https://github.com/angelabriel))\n- Add failure message documentation [\\#230](https://github.com/trento-project/wanda/pull/230) ([dottorblaster](https://github.com/dottorblaster))\n- Bump ex\\_doc from 0.29.2 to 0.29.4 [\\#229](https://github.com/trento-project/wanda/pull/229) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Rename `health_test.exs` -\\> `health_controller_test.exs` [\\#228](https://github.com/trento-project/wanda/pull/228) ([jamie-suse](https://github.com/jamie-suse))\n- Rename `HealthcheckViewTest` -\\> `HealthViewTest` [\\#227](https://github.com/trento-project/wanda/pull/227) ([jamie-suse](https://github.com/jamie-suse))\n- add api versioning to the readme examples [\\#226](https://github.com/trento-project/wanda/pull/226) ([angelabriel](https://github.com/angelabriel))\n- Add healthcheck and readiness endpoints [\\#225](https://github.com/trento-project/wanda/pull/225) ([jamie-suse](https://github.com/jamie-suse))\n- Add dev.local.exs usage [\\#223](https://github.com/trento-project/wanda/pull/223) ([arbulu89](https://github.com/arbulu89))\n- Bump credo from 1.6.7 to 1.7.0 [\\#222](https://github.com/trento-project/wanda/pull/222) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Fix execution of SBD related checks \\(jsc\\#CFSA-1961\\) [\\#220](https://github.com/trento-project/wanda/pull/220) ([angelabriel](https://github.com/angelabriel))\n- Bump plug\\_cowboy from 2.6.0 to 2.6.1 [\\#218](https://github.com/trento-project/wanda/pull/218) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Refactor API errors [\\#217](https://github.com/trento-project/wanda/pull/217) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add failure message [\\#216](https://github.com/trento-project/wanda/pull/216) ([dottorblaster](https://github.com/dottorblaster))\n- Bump excoveralls from 0.15.3 to 0.16.0 [\\#213](https://github.com/trento-project/wanda/pull/213) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Fixed broken web URLs [\\#212](https://github.com/trento-project/wanda/pull/212) ([ksanjeet](https://github.com/ksanjeet))\n- Compile and test with --warnings-as-errors flag [\\#210](https://github.com/trento-project/wanda/pull/210) ([fabriziosestito](https://github.com/fabriziosestito))\n- Update the hack on wanda guide [\\#209](https://github.com/trento-project/wanda/pull/209) ([EMaksy](https://github.com/EMaksy))\n- Bump ex\\_doc from 0.29.1 to 0.29.2 [\\#208](https://github.com/trento-project/wanda/pull/208) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Remove jwt enablement flag usage from jwt plug tests [\\#207](https://github.com/trento-project/wanda/pull/207) ([arbulu89](https://github.com/arbulu89))\n- Enrich the faker by using catalog data [\\#205](https://github.com/trento-project/wanda/pull/205) ([rtorrero](https://github.com/rtorrero))\n- Facts schema value lists maps [\\#204](https://github.com/trento-project/wanda/pull/204) ([arbulu89](https://github.com/arbulu89))\n- Bump actions/checkout from 2 to 3 [\\#203](https://github.com/trento-project/wanda/pull/203) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump excoveralls from 0.15.0 to 0.15.3 [\\#200](https://github.com/trento-project/wanda/pull/200) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump open\\_api\\_spex from 3.13.0 to 3.16.1 [\\#198](https://github.com/trento-project/wanda/pull/198) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump ecto\\_sql from 3.8.3 to 3.9.2 [\\#197](https://github.com/trento-project/wanda/pull/197) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump joken from 2.5.0 to 2.6.0 [\\#196](https://github.com/trento-project/wanda/pull/196) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump ex\\_doc from 0.29.0 to 0.29.1 [\\#195](https://github.com/trento-project/wanda/pull/195) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump credo from 1.6.6 to 1.6.7 [\\#194](https://github.com/trento-project/wanda/pull/194) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump phoenix from 1.6.12 to 1.6.16 [\\#193](https://github.com/trento-project/wanda/pull/193) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump docker/build-push-action from 3 to 4 [\\#192](https://github.com/trento-project/wanda/pull/192) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Add dependabot [\\#191](https://github.com/trento-project/wanda/pull/191) ([fabriziosestito](https://github.com/fabriziosestito))\n- Filter out non-existing checks on the faker [\\#189](https://github.com/trento-project/wanda/pull/189) ([rtorrero](https://github.com/rtorrero))\n- Remotely trigger demo deploy on new wanda image [\\#188](https://github.com/trento-project/wanda/pull/188) ([rtorrero](https://github.com/rtorrero))\n- Add new demo env that uses faked execution server [\\#187](https://github.com/trento-project/wanda/pull/187) ([rtorrero](https://github.com/rtorrero))\n- Fix warning in api redirector test [\\#186](https://github.com/trento-project/wanda/pull/186) ([fabriziosestito](https://github.com/fabriziosestito))\n- Fix execution flaky test [\\#185](https://github.com/trento-project/wanda/pull/185) ([arbulu89](https://github.com/arbulu89))\n- Api version v1 [\\#183](https://github.com/trento-project/wanda/pull/183) ([CDimonaco](https://github.com/CDimonaco))\n- Update package\\_version gatherer doc [\\#182](https://github.com/trento-project/wanda/pull/182) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Run CI `test` step on different versions of Elixir & OTP [\\#181](https://github.com/trento-project/wanda/pull/181) ([jamie-suse](https://github.com/jamie-suse))\n- Add information on how to install wanda directly for development [\\#178](https://github.com/trento-project/wanda/pull/178) ([EMaksy](https://github.com/EMaksy))\n- Bump BCI base image to 15.4 for dev Dockerfile [\\#177](https://github.com/trento-project/wanda/pull/177) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Fix JWT plug runtime config [\\#176](https://github.com/trento-project/wanda/pull/176) ([fabriziosestito](https://github.com/fabriziosestito))\n- Use new `trento-wanda` image name for check development environment [\\#175](https://github.com/trento-project/wanda/pull/175) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- rewrite trento community checks regarding 'package version' [\\#124](https://github.com/trento-project/wanda/pull/124) ([angelabriel](https://github.com/angelabriel))\n\n## [0.1.0](https://github.com/trento-project/wanda/tree/0.1.0) (2023-01-23)\n\n[Full Changelog](https://github.com/trento-project/wanda/compare/a8b788751fe90542ed0d2541a816b3a148dedfd0...0.1.0)\n\n**Implemented enhancements:**\n\n- Build in obs [\\#173](https://github.com/trento-project/wanda/pull/173) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add JWT auth [\\#168](https://github.com/trento-project/wanda/pull/168) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add premium flag option to catalog loading code [\\#163](https://github.com/trento-project/wanda/pull/163) ([arbulu89](https://github.com/arbulu89))\n- Add check DA114A: Corosync has at least 2 rings configured [\\#141](https://github.com/trento-project/wanda/pull/141) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add SBD dump gatherer documentation [\\#137](https://github.com/trento-project/wanda/pull/137) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add last execution by group [\\#108](https://github.com/trento-project/wanda/pull/108) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add targets execution view [\\#106](https://github.com/trento-project/wanda/pull/106) ([arbulu89](https://github.com/arbulu89))\n- Fix protobuf message mapping [\\#94](https://github.com/trento-project/wanda/pull/94) ([arbulu89](https://github.com/arbulu89))\n- Ordered Execution list [\\#93](https://github.com/trento-project/wanda/pull/93) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add cargo to dockerfile and build rustler [\\#74](https://github.com/trento-project/wanda/pull/74) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Start execution api [\\#73](https://github.com/trento-project/wanda/pull/73) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add Checks Specification Documentation [\\#72](https://github.com/trento-project/wanda/pull/72) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Refactor executions api [\\#66](https://github.com/trento-project/wanda/pull/66) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Store execution state [\\#60](https://github.com/trento-project/wanda/pull/60) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add support for values computation based on environment [\\#46](https://github.com/trento-project/wanda/pull/46) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Use env values [\\#42](https://github.com/trento-project/wanda/pull/42) ([arbulu89](https://github.com/arbulu89))\n- Serve the execution results through an endpoint [\\#40](https://github.com/trento-project/wanda/pull/40) ([dottorblaster](https://github.com/dottorblaster))\n- Some needed improvements to make the code runnable on prod environment [\\#38](https://github.com/trento-project/wanda/pull/38) ([arbulu89](https://github.com/arbulu89))\n- Store execution result on Check execution completion [\\#36](https://github.com/trento-project/wanda/pull/36) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add a storable Wanda.Result.ExecutionResult entity [\\#35](https://github.com/trento-project/wanda/pull/35) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n**Fixed bugs:**\n\n- Fix default value when getting system env for JWT\\_AUTHENTICATION\\_ENABLED [\\#172](https://github.com/trento-project/wanda/pull/172) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Set critical state on agent timeout and warning severity [\\#166](https://github.com/trento-project/wanda/pull/166) ([arbulu89](https://github.com/arbulu89))\n- Fix get last execution by group id [\\#110](https://github.com/trento-project/wanda/pull/110) ([fabriziosestito](https://github.com/fabriziosestito))\n- Improve Execution open api doc [\\#109](https://github.com/trento-project/wanda/pull/109) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Init before start [\\#101](https://github.com/trento-project/wanda/pull/101) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Fix flaky evaluation test [\\#96](https://github.com/trento-project/wanda/pull/96) ([arbulu89](https://github.com/arbulu89))\n- Load checks properly for the execution [\\#61](https://github.com/trento-project/wanda/pull/61) ([arbulu89](https://github.com/arbulu89))\n- Fixed items definition for expectation\\_results in ExecutionComplete event [\\#14](https://github.com/trento-project/wanda/pull/14) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n**Closed issues:**\n\n- Bad links in README.md [\\#126](https://github.com/trento-project/wanda/issues/126)\n\n**Merged pull requests:**\n\n- Fix cors plug integration [\\#174](https://github.com/trento-project/wanda/pull/174) ([CDimonaco](https://github.com/CDimonaco))\n- Execution started event [\\#171](https://github.com/trento-project/wanda/pull/171) ([CDimonaco](https://github.com/CDimonaco))\n- Chore: move tests in subfolder [\\#170](https://github.com/trento-project/wanda/pull/170) ([fabriziosestito](https://github.com/fabriziosestito))\n- Remove ssh-address flag reference from docs [\\#169](https://github.com/trento-project/wanda/pull/169) ([arbulu89](https://github.com/arbulu89))\n- rewrite trento community check regarding 'running corosync rings' [\\#167](https://github.com/trento-project/wanda/pull/167) ([angelabriel](https://github.com/angelabriel))\n- Add list & map examples for `corosync-cmapctl` docs [\\#165](https://github.com/trento-project/wanda/pull/165) ([jamie-suse](https://github.com/jamie-suse))\n- Force rhai\\_rustler build [\\#164](https://github.com/trento-project/wanda/pull/164) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add doc for the new package\\_version comparisons [\\#162](https://github.com/trento-project/wanda/pull/162) ([rtorrero](https://github.com/rtorrero))\n- add when condition to decide where to run a check [\\#161](https://github.com/trento-project/wanda/pull/161) ([angelabriel](https://github.com/angelabriel))\n- Improve gatherers documentation and add rhai example outputs [\\#160](https://github.com/trento-project/wanda/pull/160) ([fabriziosestito](https://github.com/fabriziosestito))\n- Clean up doc saying that expectation evaluation has access to the env [\\#159](https://github.com/trento-project/wanda/pull/159) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Document the trento-agent facts command [\\#158](https://github.com/trento-project/wanda/pull/158) ([arbulu89](https://github.com/arbulu89))\n- Fix integer mapping [\\#157](https://github.com/trento-project/wanda/pull/157) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add starting the targets section on the docs [\\#156](https://github.com/trento-project/wanda/pull/156) ([arbulu89](https://github.com/arbulu89))\n- Document best practices [\\#155](https://github.com/trento-project/wanda/pull/155) ([arbulu89](https://github.com/arbulu89))\n- Implement when condition [\\#154](https://github.com/trento-project/wanda/pull/154) ([dottorblaster](https://github.com/dottorblaster))\n- rewrite trento community check regarding 'hacluster' password change [\\#153](https://github.com/trento-project/wanda/pull/153) ([angelabriel](https://github.com/angelabriel))\n- Fix external links in ExDocs [\\#152](https://github.com/trento-project/wanda/pull/152) ([fabriziosestito](https://github.com/fabriziosestito))\n- Chore: remove unusued fixture [\\#151](https://github.com/trento-project/wanda/pull/151) ([fabriziosestito](https://github.com/fabriziosestito))\n- Bump to rhai\\_rustler to v0.1.3 [\\#149](https://github.com/trento-project/wanda/pull/149) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add documentation for verify\\_password gatherer [\\#147](https://github.com/trento-project/wanda/pull/147) ([rtorrero](https://github.com/rtorrero))\n- rewrite trento community checks regarding 'cibadmin' configuration [\\#146](https://github.com/trento-project/wanda/pull/146) ([angelabriel](https://github.com/angelabriel))\n- Improve table format and add req argument info [\\#145](https://github.com/trento-project/wanda/pull/145) ([rtorrero](https://github.com/rtorrero))\n- Add saphostctrl gatherer to gatherers.md [\\#144](https://github.com/trento-project/wanda/pull/144) ([rtorrero](https://github.com/rtorrero))\n- Add a cheat sheet for Rhai [\\#143](https://github.com/trento-project/wanda/pull/143) ([dottorblaster](https://github.com/dottorblaster))\n- rewrite trento community checks regarding 'sbd dump' configuration [\\#142](https://github.com/trento-project/wanda/pull/142) ([angelabriel](https://github.com/angelabriel))\n- Document cibadmin gatherer [\\#136](https://github.com/trento-project/wanda/pull/136) ([arbulu89](https://github.com/arbulu89))\n- Add a ref to target to README [\\#133](https://github.com/trento-project/wanda/pull/133) ([dottorblaster](https://github.com/dottorblaster))\n- rewrite trento community checks regarding 'sbd' configuration [\\#123](https://github.com/trento-project/wanda/pull/123) ([angelabriel](https://github.com/angelabriel))\n- rewriting checks for Wanda gatherer corosync-cmapctl [\\#119](https://github.com/trento-project/wanda/pull/119) ([pirat013](https://github.com/pirat013))\n- Add severity to the JSON schema [\\#116](https://github.com/trento-project/wanda/pull/116) ([dottorblaster](https://github.com/dottorblaster))\n- Gatherer.corosyncconf [\\#115](https://github.com/trento-project/wanda/pull/115) ([pirat013](https://github.com/pirat013))\n- Refactor factories [\\#112](https://github.com/trento-project/wanda/pull/112) ([fabriziosestito](https://github.com/fabriziosestito))\n- Use Kernel.-- instead of Enum.filter [\\#111](https://github.com/trento-project/wanda/pull/111) ([fabriziosestito](https://github.com/fabriziosestito))\n- add license [\\#107](https://github.com/trento-project/wanda/pull/107) ([stefanotorresi](https://github.com/stefanotorresi))\n- Use specific compose ports for wanda dev/test docker-compose [\\#105](https://github.com/trento-project/wanda/pull/105) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add critical, warning and passing counts to the execution view [\\#104](https://github.com/trento-project/wanda/pull/104) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add ability to handle non-existent & malformed Checks supplied to catalog [\\#103](https://github.com/trento-project/wanda/pull/103) ([jamie-suse](https://github.com/jamie-suse))\n- Add corosynccmapctl to gatherers.md [\\#102](https://github.com/trento-project/wanda/pull/102) ([rtorrero](https://github.com/rtorrero))\n- Bump contracts [\\#99](https://github.com/trento-project/wanda/pull/99) ([fabriziosestito](https://github.com/fabriziosestito))\n- Generate and push swagger-ui to gh-pages [\\#98](https://github.com/trento-project/wanda/pull/98) ([fabriziosestito](https://github.com/fabriziosestito))\n- Re-add accidentaly removed headers [\\#97](https://github.com/trento-project/wanda/pull/97) ([rtorrero](https://github.com/rtorrero))\n- Add test for policy handling Fact error [\\#95](https://github.com/trento-project/wanda/pull/95) ([jamie-suse](https://github.com/jamie-suse))\n- Remove installation section from README.md [\\#92](https://github.com/trento-project/wanda/pull/92) ([fabriziosestito](https://github.com/fabriziosestito))\n- Update CONTRIBUTING.md [\\#91](https://github.com/trento-project/wanda/pull/91) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add documentation for the package\\_version gatherer [\\#90](https://github.com/trento-project/wanda/pull/90) ([rtorrero](https://github.com/rtorrero))\n- Document systemd gatherer [\\#89](https://github.com/trento-project/wanda/pull/89) ([arbulu89](https://github.com/arbulu89))\n- Add Documentation for SBD Gatherer [\\#88](https://github.com/trento-project/wanda/pull/88) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add badges to readme [\\#87](https://github.com/trento-project/wanda/pull/87) ([fabriziosestito](https://github.com/fabriziosestito))\n- Use correct remediation text for check 156F64 [\\#85](https://github.com/trento-project/wanda/pull/85) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Support no args gatherers [\\#84](https://github.com/trento-project/wanda/pull/84) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add coveralls [\\#83](https://github.com/trento-project/wanda/pull/83) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add /etc/hosts file gatherer documentation [\\#82](https://github.com/trento-project/wanda/pull/82) ([rtorrero](https://github.com/rtorrero))\n- Add ExDoc config in mix.exs and supporting file to generate the doc [\\#81](https://github.com/trento-project/wanda/pull/81) ([fabriziosestito](https://github.com/fabriziosestito))\n- Minor tweaks to the specs doc [\\#80](https://github.com/trento-project/wanda/pull/80) ([rtorrero](https://github.com/rtorrero))\n- Fix Checks Specification doc link [\\#79](https://github.com/trento-project/wanda/pull/79) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Use strict module ordering [\\#77](https://github.com/trento-project/wanda/pull/77) ([fabriziosestito](https://github.com/fabriziosestito))\n- Integrate TLint into CI [\\#76](https://github.com/trento-project/wanda/pull/76) ([dottorblaster](https://github.com/dottorblaster))\n- Do not raise if an execution already exists [\\#75](https://github.com/trento-project/wanda/pull/75) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add ex doc gh pages [\\#71](https://github.com/trento-project/wanda/pull/71) ([fabriziosestito](https://github.com/fabriziosestito))\n- Bump erlang version to 24.3.4 [\\#70](https://github.com/trento-project/wanda/pull/70) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Change Abacus to Rhai [\\#69](https://github.com/trento-project/wanda/pull/69) ([fabriziosestito](https://github.com/fabriziosestito))\n- Handle CORS in dev environment [\\#68](https://github.com/trento-project/wanda/pull/68) ([arbulu89](https://github.com/arbulu89))\n- Refactor context [\\#65](https://github.com/trento-project/wanda/pull/65) ([fabriziosestito](https://github.com/fabriziosestito))\n- Abstract RabbitMQ processing logic [\\#64](https://github.com/trento-project/wanda/pull/64) ([jamie-suse](https://github.com/jamie-suse))\n- Detect already running execution for group\\_id [\\#63](https://github.com/trento-project/wanda/pull/63) ([arbulu89](https://github.com/arbulu89))\n- Remove restart directive from container definitions [\\#62](https://github.com/trento-project/wanda/pull/62) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Chore: remove unused miss dep [\\#59](https://github.com/trento-project/wanda/pull/59) ([fabriziosestito](https://github.com/fabriziosestito))\n- Use google protobuf value [\\#58](https://github.com/trento-project/wanda/pull/58) ([fabriziosestito](https://github.com/fabriziosestito))\n- Chore: rename/refactor schemas [\\#56](https://github.com/trento-project/wanda/pull/56) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add get check result [\\#55](https://github.com/trento-project/wanda/pull/55) ([fabriziosestito](https://github.com/fabriziosestito))\n- Rename controllers context [\\#54](https://github.com/trento-project/wanda/pull/54) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add Result OpenAPI Schema and cleanup [\\#53](https://github.com/trento-project/wanda/pull/53) ([fabriziosestito](https://github.com/fabriziosestito))\n- More prod fixes [\\#52](https://github.com/trento-project/wanda/pull/52) ([arbulu89](https://github.com/arbulu89))\n- Add initialization tasks for a release [\\#51](https://github.com/trento-project/wanda/pull/51) ([arbulu89](https://github.com/arbulu89))\n- Enable phoenix server usage in prod [\\#50](https://github.com/trento-project/wanda/pull/50) ([arbulu89](https://github.com/arbulu89))\n- Catalog controller [\\#49](https://github.com/trento-project/wanda/pull/49) ([arbulu89](https://github.com/arbulu89))\n- Cleanup execution controller [\\#48](https://github.com/trento-project/wanda/pull/48) ([fabriziosestito](https://github.com/fabriziosestito))\n- Refactor evaluation tests [\\#47](https://github.com/trento-project/wanda/pull/47) ([arbulu89](https://github.com/arbulu89))\n- Switch to Views for JSON rendering [\\#45](https://github.com/trento-project/wanda/pull/45) ([dottorblaster](https://github.com/dottorblaster))\n- Add CI step to check for unused dependencies [\\#44](https://github.com/trento-project/wanda/pull/44) ([jamie-suse](https://github.com/jamie-suse))\n- Load check values from yaml [\\#43](https://github.com/trento-project/wanda/pull/43) ([arbulu89](https://github.com/arbulu89))\n- Check severity [\\#41](https://github.com/trento-project/wanda/pull/41) ([arbulu89](https://github.com/arbulu89))\n- Enable single pipe check on credo [\\#39](https://github.com/trento-project/wanda/pull/39) ([arbulu89](https://github.com/arbulu89))\n- Add dockerfile [\\#37](https://github.com/trento-project/wanda/pull/37) ([fabriziosestito](https://github.com/fabriziosestito))\n- Map ExecutionCompleted event [\\#34](https://github.com/trento-project/wanda/pull/34) ([arbulu89](https://github.com/arbulu89))\n- Phoenix lift off [\\#33](https://github.com/trento-project/wanda/pull/33) ([arbulu89](https://github.com/arbulu89))\n- Message content\\_type from Contracts [\\#32](https://github.com/trento-project/wanda/pull/32) ([CDimonaco](https://github.com/CDimonaco))\n- Add amqp consumer integration tests [\\#31](https://github.com/trento-project/wanda/pull/31) ([fabriziosestito](https://github.com/fabriziosestito))\n- Handle fact gathering errors [\\#30](https://github.com/trento-project/wanda/pull/30) ([arbulu89](https://github.com/arbulu89))\n- Update contracts dep to trento-projects/contracts [\\#29](https://github.com/trento-project/wanda/pull/29) ([fabriziosestito](https://github.com/fabriziosestito))\n- Set execution GenServer restart policy as transient [\\#28](https://github.com/trento-project/wanda/pull/28) ([arbulu89](https://github.com/arbulu89))\n- Do not requeue amqp message on error [\\#26](https://github.com/trento-project/wanda/pull/26) ([arbulu89](https://github.com/arbulu89))\n- Fix amqp message consumption [\\#25](https://github.com/trento-project/wanda/pull/25) ([arbulu89](https://github.com/arbulu89))\n- Publish facts gathering requested [\\#24](https://github.com/trento-project/wanda/pull/24) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add checks to execution server state [\\#23](https://github.com/trento-project/wanda/pull/23) ([fabriziosestito](https://github.com/fabriziosestito))\n- Map FactsGatheringRequested event [\\#22](https://github.com/trento-project/wanda/pull/22) ([fabriziosestito](https://github.com/fabriziosestito))\n- Timeout business logic implementation [\\#21](https://github.com/trento-project/wanda/pull/21) ([dottorblaster](https://github.com/dottorblaster))\n- Remove JSON schema, add new protobuf contracts [\\#20](https://github.com/trento-project/wanda/pull/20) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add timeout logic to Wanda.Execution.Server [\\#19](https://github.com/trento-project/wanda/pull/19) ([dottorblaster](https://github.com/dottorblaster))\n- Revert \"Adds cache version to pipeline\" [\\#18](https://github.com/trento-project/wanda/pull/18) ([fabriziosestito](https://github.com/fabriziosestito))\n- fix execution requested event schema [\\#15](https://github.com/trento-project/wanda/pull/15) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Adds cache version to pipeline [\\#12](https://github.com/trento-project/wanda/pull/12) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Serialize an ExecutionCompleted json cloud event [\\#11](https://github.com/trento-project/wanda/pull/11) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Adds json schema for emitted ExecutionCompletedV1 [\\#10](https://github.com/trento-project/wanda/pull/10) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Receive Execution Requested event [\\#9](https://github.com/trento-project/wanda/pull/9) ([fabriziosestito](https://github.com/fabriziosestito))\n- Refactor Wanda.Execution in Wanda.Execution.Server, create execution API module [\\#8](https://github.com/trento-project/wanda/pull/8) ([fabriziosestito](https://github.com/fabriziosestito))\n- Receive facts gathered event [\\#6](https://github.com/trento-project/wanda/pull/6) ([fabriziosestito](https://github.com/fabriziosestito))\n- Setup amqp [\\#5](https://github.com/trento-project/wanda/pull/5) ([fabriziosestito](https://github.com/fabriziosestito))\n- Group expectations evaluation [\\#4](https://github.com/trento-project/wanda/pull/4) ([fabriziosestito](https://github.com/fabriziosestito))\n- Refactor execution pt1 [\\#3](https://github.com/trento-project/wanda/pull/3) ([fabriziosestito](https://github.com/fabriziosestito))\n- Expectations eval pt 1 [\\#2](https://github.com/trento-project/wanda/pull/2) ([fabriziosestito](https://github.com/fabriziosestito))\n- proof of concept of check execution orchestration, step 1 [\\#1](https://github.com/trento-project/wanda/pull/1) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n\n\n\\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*","ref":"changelog.html","title":"Changelog","type":"extras"},{"doc":"# How to contribute\n\nThanks for showing interest and sharing your time to contribute to this project!\n\nThis guide is meant to be used as a general guideline for creating issues or\npull requests. We encourage all first-time contributors to give this a read to avoid\ncommon mistakes and improve the quality of all contributions.","ref":"contributing.html","title":"How to contribute","type":"extras"},{"doc":"Before creating a new issue make sure you use the search functionality to confirm\nthat a similar issue doesn't already exist. Next, make sure you properly label\nthe issue as per our [labels](https://github.com/trento-project/wanda/labels)\n\nIf you are reporting a `bug`, please share a file generated using the\n`trento-support.sh` script with the following params:\n\n```\n# trento-support.sh --collect all --output file-tgz\n```\n\nand include the output in your issue. The script should remove sensitive data\nautomatically but please make sure you are not sharing any sensitive data of your own.","ref":"contributing.html#opening-issues","title":"Opening issues - How to contribute","type":"extras"},{"doc":"Always refer to the [docs repository](https://github.com/trento-project/docs) for coding standards and general guidelines.\n\n#","ref":"contributing.html#submitting-changes","title":"Submitting changes - How to contribute","type":"extras"},{"doc":"Reviews are hard. These few points will help us to reduce the time and effort required and allow us to merge your changes faster.\n\n1. Only touch relevant files.\n2. We have a PR template to aid you in completing the required details. Be\n sure to complete it and remove the non-relevant parts.\n3. Keep PRs as small as possible. When the PR gets too big, consider splitting it into multiple parts. A PR should ideally be between 100 and 500 additions.\n4. Check that the tests are passing.\n5. Check that your code is not generating new warnings.\n6. Check that any dependent changes have been merged and published in downstream modules\n7. Commit history should be short and group changes that otherwise wouldn't\n make sense on their own.\n8. Always write a clear log message for your commits. One-line messages are\n fine for small changes, but bigger changes should look like this:\n\n ```\n git commit -m \"A brief summary of the commit\n\n A paragraph describing what changed and its impact.\"\n ```\n\n9. Write a detailed description that gives context and explains why you are\n creating the PR.\n10. If the PR adds functionality, please add some tests and documentation\n to support it.\n11. Each PR needs 1 approval to be merged. Select a reviewer in particular if\n you are looking for specific feedback from someone.\n\n#","ref":"contributing.html#pull-requests-guideline","title":"Pull Requests guideline - How to contribute","type":"extras"},{"doc":"1. Opinionated comments are welcome but don't expect them always to be\n addressed. Be ready for discussion but also open to conceding.\n To avoid scope creep, consider proposing subsequent PRs\n rather than requesting changes for the current PR you are reviewing.\n2. Short, concise comments with examples are the most valuable.","ref":"contributing.html#reviewers-guideline","title":"Reviewers guideline - How to contribute","type":"extras"},{"doc":"# Rhai expressions cheatsheet\n\nIn this cheatsheet are grouped the most frequent manipulations that can be done through Rhai, for convenience.","ref":"rhai_expressions_cheat_sheet.html","title":"Rhai expressions cheatsheet","type":"extras"},{"doc":"{: .col-2}\n\n#","ref":"rhai_expressions_cheat_sheet.html#cheatsheet","title":"Cheatsheet - Rhai expressions cheatsheet","type":"extras"},{"doc":"##","ref":"rhai_expressions_cheat_sheet.html#arrays","title":"Arrays - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n[1, 2, 3].filter(|value| value % 2 == 0)\n=> [2]\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#filtering-an-array","title":"Filtering an array - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n[\"wow\", \"check\"].index_of(|value| value == \"check\")\n=> 1\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#finding-the-index-of-an-element-inside-an-array","title":"Finding the index of an element inside an array - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\nlet nodelist = [\n #{resource_id: 5, name: \"foo\"},\n #{resource_id: 12, name: \"bar\"}\n];\n\nnodelist.find(|value| value.resource_id == 5)\n=> #{\"name\": \"foo\", \"resource_id\": 5}\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#finding-an-element-inside-an-array","title":"Finding an element inside an array - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n[2, 4, 6].all(|value| value % 2 == 0)\n=> true\n```\n\n#","ref":"rhai_expressions_cheat_sheet.html#checking-if-an-expression-is-true-for-every-element-of-an-array","title":"Checking if an expression is true for every element of an array - Rhai expressions cheatsheet","type":"extras"},{"doc":"##","ref":"rhai_expressions_cheat_sheet.html#maps","title":"Maps - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n#{a: 1, b: 2}.keys()\n=> [\"a\", \"b\"]\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#get-only-keys-returns-an-array","title":"Get only keys (returns an array) - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n#{a: 1, b: 2}.values()\n=> [1, 2]\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#get-only-values-returns-an-array","title":"Get only values (returns an array) - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\nlet map = #{\n ring_one: 12,\n ring_two: 34,\n ring_three: 90,\n ring_four: 234,\n ring_five: 908\n};\n\nmap.keys().filter(|prop| prop.starts_with(\"ring\")).len() >= 5\n=> true\n```\n\n#","ref":"rhai_expressions_cheat_sheet.html#check-if-a-map-has-more-than-5-keys-which-name-starts-with-ring","title":"Check if a map has more than 5 keys which name starts with \"ring\" - Rhai expressions cheatsheet","type":"extras"},{"doc":"##","ref":"rhai_expressions_cheat_sheet.html#strings","title":"Strings - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n\"a;b;c\".split(\";\")\n=> [\"a\", \"b\", \"c\"]\n```","ref":"rhai_expressions_cheat_sheet.html#splitting-a-string","title":"Splitting a string - Rhai expressions cheatsheet","type":"extras"},{"doc":"# Checks Specification\n\nA language allowing to declare best practices to be adhered on target SAP Infrastructures.","ref":"specification.html","title":"Checks Specification","type":"extras"},{"doc":"The need this Specification aims to fulfill is to provide users a simple way to declare what we (the Trento Team) often refer to as \"Checks\".\n\nChecks are, in Trento's domain, the crystallization of SUSE's best practices when it comes to SAP workloads in a form that both a user ([Spec](#anatomy-of-a-check)) and a machine ([Execution](#checks-execution)) can read.\n\n[^1]: The Trento Team from now on.","ref":"specification.html#introduction","title":"Introduction - Checks Specification","type":"extras"},{"doc":"_Checks Execution_ is the process that determines whether the best practices defined in the [Checks Specifications](#anatomy-of-a-check) are being followed on a target infrastructure.\n\n> [Requesting an Execution](#requesting-an-execution) -> [Facts Gathering](#facts-gathering) -> [Expectation Evaluation](#expectation-evaluation)\n\n#","ref":"specification.html#checks-execution","title":"Checks Execution - Checks Specification","type":"extras"},{"doc":"An Execution can be requested to start by providing Wanda the following information:\n\n- an execution identifier\n- an execution Group identifier\n- the Checks Selection for the targets (a list of checks to be executed on the targets)\n\nWhen the Execution starts running, its current state is stored in the Database and the targets are notified - via the message broker - about Facts to be gathered.\n\nThen the _Execution_ waits for the [Facts Gathering](#facts-gathering) to complete.\n\n#","ref":"specification.html#requesting-an-execution","title":"Requesting an Execution - Checks Specification","type":"extras"},{"doc":"After an _Execution Request_ the targets are notified about the facts they need to [gather](./gatherers.md).\n\nWhenever a target has gathered all the needed facts for an _Execution_, it notifies Wanda - via the message broker - about the _Gathered Facts_.\n\n#","ref":"specification.html#facts-gathering","title":"Facts Gathering - Checks Specification","type":"extras"},{"doc":"_Expectation Evaluation_ is the process of [evaluating](#expression-language) the [Expectations](#expectations)\nusing the received _Gathered Facts_ to obtain the result of a check.\n\nThis will only happen once _Gathered Facts_ are received **from all the targets**.\n\nAfter the result has been determined, the currently `running` Execution transitions to `completed` and its new state is tracked on the Database.\n\nAt this point the Execution is considered **Completed** and interested parties are notified about the Execution Completion.\n\n#","ref":"specification.html#expectation-evaluation","title":"Expectation Evaluation - Checks Specification","type":"extras"},{"doc":"Once an execution is completed, a checks result should give feedback on what aspects of a target infrastructure adhere to the best practices and which don't.\n\nPossible results:\n\n- `passing`, everything ok\n- `warning`, best practice not followed, should fix\n- `critical`, best practice not followed, must fix\n\nSee also [Check Severity](#severity).","ref":"specification.html#checks-results","title":"Checks Results - Checks Specification","type":"extras"},{"doc":"A Check declaration comes in the form of a `yaml` file and all the Checks together build up the **Checks Catalog**\n\nHere's an example:\n\n```yaml\nid: \"156F64\"\nname: Corosync `token` timeout\ngroup: Corosync\ndescription: Corosync `token` timeout is set to the correct value\nremediation: |","ref":"specification.html#anatomy-of-a-check","title":"Anatomy of a Check - Checks Specification","type":"extras"},{"doc":"The value of the Corosync `token` timeout is not set as recommended.","ref":"specification.html#abstract","title":"Abstract - Checks Specification","type":"extras"},{"doc":"Adjust the corosync `token` timeout as recommended...\n\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\n argument: cib.configuration\n\n - name: first_primitive\n gatherer: cibadmin\n argument: cib.configuration.resources.primitive.0\n\n - name: first_cluster_property_set_second_nvpair\n gatherer: cibadmin\n argument: cib.configuration.crm_config.cluster_property_set.0.nvpair.1\n```\n\nExample output (in Rhai):\n\n```ts\n// first_primitive\n#{\n class: \"stonith\",\n id: \"stonith-sbd\",\n instance_attributes: #{\n id: \"stonith-sbd-instance_attributes\",\n nvpair: [#{\n id: \"stonith-sbd-instance_attributes-pcmk_delay_max\",\n name: \"pcmk_delay_max\",\n value: \"30s\"\n }]\n },\n type: \"external/sbd\"\n};\n\n// first_cluster_property_set_second_nvpair\n#{\n id: \"cib-bootstrap-options-dc-version\",\n name: \"dc-version\",\n value: \"2.0.4+20200616.2deceaa3a-3.12.1-2.0.4+20200616.2deceaa3a\"\n};\n```\n\n \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\n argument: totem.token\n\n - name: corosync_join\n gatherer: corosync.conf\n argument: totem.join\n\n - name: corosync_node_id_0\n gatherer: corosync.conf\n argument: nodelist.node.0.nodeid\n\n - name: corosync_node_id_1\n gatherer: corosync.conf\n argument: nodelist.node.1.nodeid\n\n - name: corosync_nodes\n gatherer: corosync.conf\n argument: nodelist.node\n```\n\nExample output (in Rhai):\n\n```ts\n// corosync_token_timeout\n30000;\n\n// corosync_join\n60;\n\n// corosync_node_id_0\n1;\n\n// corosync_node_id_1\n2;\n\n// corosync_nodes\n[#{nodeid: 1, ring0_addr: \"192.168.157.10\"}, #{nodeid: 2, ring0_addr: \"192.168.157.11\"}];\n```\n\nFor extra information refer to [trento-project/agent/../gatherers/corosyncconf_test.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/corosyncconf_test.go)\n\n \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\n argument: totem.token\n\n - name: runtime_totem_token\n gatherer: corosync-cmapctl\n argument: runtime.config.totem.token\n\n - name: totem_transport\n gatherer: corosync-cmapctl\n argument: totem.transport\n\n - name: totem_max_messages\n gatherer: corosync-cmapctl\n argument: runtime.config.totem.max_messages\n\n - name: node_0_ring0addr\n gatherer: corosync-cmapctl\n argument: nodelist.node.0.ring0_addr\n\n - name: node_list\n gatherer: corosync-cmapctl\n argument: nodelist.node\n\n - name: second_node\n gatherer: corosync-cmapctl\n argument: nodelist.node.1\n```\n\nExample output (in Rhai):\n\n```ts\n// totem_token\n30000;\n\n// runtime_totem_token\n30000;\n\n// totem_transport\n\"udpu\";\n\n// totem_max_messages\n20;\n\n// node_0_ring0addr\n\"10.80.1.11\";\n\n// node_list\n#{\n \"0\": #{\n nodeid: 1,\n ring0_addr: \"10.80.1.11\"\n },\n \"1\": #{\n nodeid: 2,\n ring0_addr: \"10.80.1.12\"\n }\n};\n\n// second_node\n#{ nodeid: 2, ring0_addr: \"10.80.1.12\" };\n```\n\n \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\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 Note:\n>\n> - a list of one element is often expected since usually the installed version would be only one\n> - detected installed versions list is ordered by descending installation time: **latest installed versions come first**\n> - operating on the latest installed version requires accessing the first element in the list via `package_fact_name[0]` or `package_fact_name.first()`\n\nIn the second usecase, the return value is as follows (see additional details [here](https://fedoraproject.org/wiki/Archive:Tools/RPM/VersionComparison#The_rpmvercmp_algorithm)):\n\n- A value of `0` if the provided version string matches the installed package version for the requested package.\n- A value of `-1` if the provided version string is older that what's currently installed.\n- A value of `1` if the provided version string is newer than what's currently installed.\n\n> The latest detected installed version is used for comparison\n\nNaming the facts / expectations accordingly is specially important here to avoid confusion.\n\n- We suggest using a `compare_` prefix for package version comparisons and `package_` to retrieve\n a package version\n\nAdditionally, when using the version comparison, it increases readability to explicitly mention\nthe values to compare against:\n\n```yaml\nfacts:\n - name: compare_package_corosync\n gatherer: package_version\n argument: corosync,2.4.5\n\n - name: package_corosync\n gatherer: package_version\n argument: corosync\n\n - name: package_sbd\n gatherer: package_version\n argument: sbd\n\nvalues:\n - name: greater_than_installed\n default: 1\n - name: lesser_than_installed\n default: -1\n - name: same_as_installed\n default: 0\n - name: expected_corosync_version\n default: \"2.4.5\"\n\nexpectations:\n - name: compare_package_corosync\n expect: facts.compare_package_corosync == values.greater_than_installed\n\n - name: package_corosync_is_the_expected_one\n expect: facts.package_corosync.first().version == values.expected_corosync_version\n\n - name: sbd_version_same_on_all_hosts\n expect_same: facts.package_sbd.first().version\n```\n\nExample arguments:\n\n| Name | Return value |\n| :------------------- | :---------------------------------------------------------------------------- |\n| `package_name` | a list containing information about the installed versions of the rpm package |\n| `package_name,2.4.5` | an integer with a value of `-1`, `0` or `1` (see above) |\n\nExample specification:\n\n```yaml\nfacts:\n - name: package_corosync\n gatherer: package_version\n argument: corosync\n\n - name: package_pacemaker\n gatherer: package_version\n argument: pacemaker\n\n - name: multiple_sbd_versions_installed\n gatherer: package_version\n argument: sbd\n\n - name: compare_package_corosync\n gatherer: package_version\n argument: corosync,2.4.5\n\n ...\n```\n\nExample output (in Rhai):\n\n```ts\n// package_corosync\n[\n #{\n \"version\": \"2.4.5\"\n }\n]\n\n// package_pacemaker\n[\n #{\n \"version\": \"2.0.4+20200616.2deceaa3a\"\n }\n]\n\n// multiple_sbd_versions_installed\n[\n #{\n \"version\": \"1.5.1\" // latest installed version, not necessarily the newest one\n },\n #{\n \"version\": \"1.5.2\"\n }\n]\n\n// compare_package_corosync\n0\n```\n\n \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\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\n argument: GetProcessList\n\n - name: instances\n gatherer: sapcontrol\n argument: GetSystemInstanceList\n```\n\nExample output (in Rhai):\n\n```ts\n// GetProcessList\n#{\n \"NWP\": [\n #{\n \"instance_nr\": \"10\",\n \"name\": \"ERS10\",\n \"output\": [\n #{\n \"description\": \"EnqueueReplicator\",\n \"dispstatus\": \"SAPControl-GREEN\",\n \"elapsedtime\": \"266:08:15\",\n \"name\": \"enrepserver\",\n \"pid\": 7221,\n \"starttime\": \"2023 09 29 09:41:41\",\n \"textstatus\": \"Running\"\n }\n ]\n }\n ]\n}\n\n// GetSystemInstanceList\n#{\n \"NWP\": [\n #{\n \"instance_nr\": \"10\",\n \"name\": \"ERS10\",\n \"output\": [\n #{\n \"dispstatus\": \"SAPControl-GREEN\",\n \"features\": \"MESSAGESERVER|ENQUE\",\n \"hostname\": \"sapnwpas\",\n \"http_port\": 50013,\n \"https_port\": 50014,\n \"instance_nr\": 0,\n \"start_priority\": \"1\"\n },\n #{\n \"dispstatus\": \"SAPControl-GREEN\",\n \"features\": \"ENQREP\",\n \"hostname\": \"sapnwper\",\n \"http_port\": 51013,\n \"https_port\": 51014,\n \"instance_nr\": 10,\n \"start_priority\": \"0.5\"\n },\n ...\n ]\n }\n ]\n}\n\n// GetVersionInfo\n#{\n \"NWP\": [\n #{\n \"instance_nr\": \"10\",\n \"name\": \"ERS10\",\n \"output\": [\n #{\n \"architecture\": \"linuxx86_64\",\n \"build\": \"optU (Oct 16 2021, 00:03:15)\",\n \"changelist\": \"2094654\",\n \"filename\": \"/usr/sap/NWP/ERS10/exe/sapstartsrv\",\n \"patch\": \"900\",\n \"rks_compatibility_level\": \"1\",\n \"sap_kernel\": \"753\",\n \"time\": \"2021 10 15 22:14:31\"\n },\n #{\n \"architecture\": \"linuxx86_64\",\n \"build\": \"optU (Oct 16 2021, 00:03:15)\",\n \"changelist\": \"2094654\",\n \"filename\": \"/usr/sap/NWP/ERS10/exe/gwrd\",\n \"patch\": \"900\",\n \"rks_compatibility_level\": \"1\",\n \"sap_kernel\": \"753\",\n \"time\": \"2021 10 15 22:04:14\"\n },\n ...\n ]\n }\n ]\n}\n\n// HACheckConfig\n#{\n \"NWP\": [\n #{\n \"instance_nr\": \"10\",\n \"name\": \"ERS10\",\n \"output\": [\n #{\n \"category\": \"SAPControl-SAP-CONFIGURATION\",\n \"comment\": \"2 ABAP instances detected\",\n \"description\": \"Redundant ABAP instance configuration\",\n \"state\": \"SAPControl-HA-SUCCESS\"\n },\n #{\n \"category\": \"SAPControl-SAP-CONFIGURATION\",\n \"comment\": \"0 Java instances detected\",\n \"description\": \"Redundant Java instance configuration\",\n \"state\": \"SAPControl-HA-SUCCESS\"\n },\n ...\n ]\n }\n ]\n}\n\n//HAGetFailoverConfig\n#{\n \"NWP\": [\n #{\n \"instance_nr\": \"10\",\n \"name\": \"ERS10\",\n \"output\": #{\n \"ha_active\": false,\n \"ha_active_nodes\": \"\",\n \"ha_documentation\": \"\",\n \"ha_nodes\": [],\n \"ha_product_version\": \"\",\n \"ha_sap_interface_version\": \"\"\n }\n }\n ]\n}\n\n```\n\n \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\n argument: Ping\n\n - name: list_instances\n gatherer: saphostctrl\n argument: ListInstances\n```\n\nExample output (in Rhai):\n\n```ts\n// ping\n#{elapsed: 579770.0, status: \"SUCCESS\"}\n\n// list_instances\n[\n #{\n \"changelist\": 1908545,\n \"hostname\": \"vmhana01\",\n \"instance\": \"00\",\n \"patch\": 410,\n \"sapkernel\": 753,\n \"system\": \"PRD\"\n }\n];\n```\n\n \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 will then attempt to resolve those hostnames to confirm that they are resolvable and afterwards it will attempt a ping\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\n```\n\nExample output (in Rhai):\n\n```ts\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 \"NWP\": [\n #{\n \"addresses\": [\n \"2.1.1.82\"\n ],\n \"hostname\": \"sapnwpas\",\n \"instance_name\": \"ASCS00\",\n \"reachability\": true\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 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 it will attempt a ping\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\n```\n\nExample output (in Rhai):\n\n```ts\n\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","title":"sapinstance_hostname_resolver - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows access to the latest SAP profile files content stored in `/sapmnt/ /profile`.\nThe \"latest\" profile means that backed up files like `DEFAULT.1.PFL` or `some_profile.1` are excluded.\nIt returns the profile files and content grouped by SID in a key\\value way.\n\nExample specification:\n\n```yaml\nfacts:\n - name: sap_profiles\n gatherer: sap_profiles\n```\n\nExample output (in Rhai):\n\n```ts\n#{\n \"NWP\": #{\n \"profiles\": [\n #{\n \"content\": #{\n \"SAPDBHOST\": \"10.80.1.13\",\n \"SAPGLOBALHOST\": \"sapnwpas\",\n \"SAPSYSTEMNAME\": \"NWP\",\n ...\n },\n \"name\": \"DEFAULT.PFL\",\n \"path\": \"/sapmnt/NWP/profile/DEFAULT.PFL\"\n },\n #{\n \"content\": #{\n \"DIR_CT_RUN\": \"$(DIR_EXE_ROOT)$(DIR_SEP)$(OS_UNICODE)$(DIR_SEP)linuxx86_64\",\n \"DIR_EXECUTABLE\": \"$(DIR_INSTANCE)/exe\",\n \"DIR_PROFILE\": \"$(DIR_INSTALL)$(DIR_SEP)profile\",\n ...\n },\n \"name\": \"NWP_ASCS00_sapnwpas\",\n \"path\": \"/sapmnt/NWP/profile/NWP_ASCS00_sapnwpas\"\n },\n ...\n ]\n },\n \"NWD\": #{\n \"profiles\": [\n #{\n \"content\": #{\n \"SAPDBHOST\": \"10.85.1.13\",\n \"SAPGLOBALHOST\": \"sapnwdas\",\n \"SAPSYSTEMNAME\": \"NWD\",\n ...\n },\n \"name\": \"DEFAULT.PFL\",\n \"path\": \"/sapmnt/NWD/profile/DEFAULT.PFL\"\n },\n ...\n ]\n }\n}\n```\n\n \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\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\n argument: SBD_PACEMAKER\n\n - name: sbd_startmode\n gatherer: sbd_config\n argument: SBD_STARTMODE\n\n - name: sbd_device\n gatherer: sbd_config\n argument: SBD_DEVICE\n```\n\nExample output (in Rhai):\n\n```ts\n// sbd_pacemaker\n\"yes\";\n\n// sbd_startmode\n\"always\";\n\n// sbd_device\n\"/dev/vdc;/dev/vdb\";\n```\n\n \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\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\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\n argument: sbd\n\n - name: corosync_state\n gatherer: systemd\n argument: corosync\n```\n\nExample output (in Rhai):\n\n```ts\n// sbd_state\n\"active\";\n\n// corosync_state\n\"inactive\";\n```\n\n \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\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 version, when the requested path exists\n\n For example:\n Requesting /api/test, will redirect to /api/ Note: `api-key` value is not used if the unique goal is to run checks, so setting it as `--api-key 0` does the work.\n\nKeep in mind that the `agent_id` of the targets must match with values provided in the `targets` field of the execution request.\n\nThe ID can be obtained running:\n\n```\n./trento-agent id\n```\n\nIf the execution is run in a development/testing environment, [faking the agent id](https://github.com/trento-project/agent#fake-agent-id) might come handy.\n\n### **Consulting the catalog**\n\nAvailable Checks are part of the **Catalog**, and they can be retrieved by accessing the dedicated API\n\n```bash\ncurl -X 'GET' \\\n 'http://localhost:4000/api/v1/checks/catalog' \\\n -H 'accept: application/json'\n```\n\n### **Starting a Checks Execution**\n\nA Checks Execution can be started by calling the Start Execution endpoint, as follows\n\n```bash\ncurl --request POST 'http://localhost:4000/api/v1/checks/executions/start' \\\n--header 'accept: application/json' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n \"env\": {\n \"provider\": \"azure\"\n },\n \"execution_id\": \"205e326d-0c25-4f4b-9976-43f9ba1c86d3\",\n \"group_id\": \"3dff9d03-4adf-453e-9513-8533e221bb12\",\n \"targets\": [\n {\n \"agent_id\": \"a644919a-d953-43d4-bd57-7e0bb96ee894\",\n \"checks\": [\n \"156F64\"\n ]\n },\n {\n \"agent_id\": \"02d99b2f-0efd-443c-ac9c-32710323f620\",\n \"checks\": [\n \"OTH3R1\"\n ]\n }\n ]\n}'\n```\n\n> **execution_id** must be new and unique for every new execution. If an already used **execution_id** is provided, starting the execution fails.\n\nIn order to get detailed information for an execution, see [Getting Execution details](#getting-execution-details).\n\n> Note that execution is _eventually started_, meaning that a successful response to the previous API call does not guarantee that the execution is running, but that it has been accepted by the system to start.\n\n#","ref":"readme.html#testing-executions","title":"Testing Executions - Wanda","type":"extras"},{"doc":"An execution target is a target host where the checks are executed. This requires to have the `trento-agent` executable running in the host. In order to specify an execution order, its `agent_id` and a list of checks to be executed are provided. Once the execution is started, a facts gathering request is sent to these targets, facts are gathered and sent back to Wanda, where the checks result is evaluated using the gathered facts.\n\nThe `agent_id` can be obtained just issuing `trento-agent id` command in the target host.\n\nEach target _must_ specify a list of checks, that can be empty. These are the selected checks for each agent, that are executed.\n\nGiven two different targets, the same checks can be selected:\n\n```bash\ncurl --request POST 'http://localhost:4000/api/v1/checks/executions/start' \\\n--header 'accept: application/json' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n \"env\": {\n \"provider\": \"azure\"\n },\n \"execution_id\": \"205e326d-0c25-4f4b-9976-43f9ba1c86d3\",\n \"group_id\": \"3dff9d03-4adf-453e-9513-8533e221bb12\",\n \"targets\": [\n {\n \"agent_id\": \"a644919a-d953-43d4-bd57-7e0bb96ee894\",\n \"checks\": [\n \"156F64\",\n \"45B653\"\n ]\n },\n {\n \"agent_id\": \"02d99b2f-0efd-443c-ac9c-32710323f620\",\n \"checks\": [\n \"156F64\",\n \"45B653\"\n ]\n }\n ]\n}'\n```\n\nOr completely different ones:\n\n```bash\ncurl --request POST 'http://localhost:4000/api/v1/checks/executions/start' \\\n--header 'accept: application/json' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n \"env\": {\n \"provider\": \"azure\"\n },\n \"execution_id\": \"205e326d-0c25-4f4b-9976-43f9ba1c86d3\",\n \"group_id\": \"3dff9d03-4adf-453e-9513-8533e221bb12\",\n \"targets\": [\n {\n \"agent_id\": \"a644919a-d953-43d4-bd57-7e0bb96ee894\",\n \"checks\": [\n \"156F64\",\n \"45B653\"\n ]\n },\n {\n \"agent_id\": \"02d99b2f-0efd-443c-ac9c-32710323f620\",\n \"checks\": [\n \"OTH3R1\",\n \"OTH3R2\"\n ]\n }\n ]\n}'\n```\n\n### **Getting Execution details**\n\nTo get detailed information about the execution, the following API can be used.\n\n```bash\ncurl --request GET 'http://localhost:4000/api/v1/checks/executions/205e326d-0c25-4f4b-9976-43f9ba1c86d3' \\\n--header 'accept: application/json' \\\n--header 'Content-Type: application/json'\n```\n\n> **Note** that calling the execution detail API right after [starting an execution](#starting-a-checks-execution) might result in a `404 not found`, because the execution, as mentioned, is _eventually started_.\n>\n> In this case retry getting the detail of the execution.\n\nRefer to the [API doc](http://localhost:4000/swaggerui) for more information about requests and responses.\n\n### **Debugging gathered facts**\n\nOften times knowing the returned value of the gathered facts is not a trivial thing, more during the implementation of new checks.\n\nTo better debug the fact gathering process and the returned values, the `facts` subcommand of `trento-agent` is a really useful tool. This command helps to see in the target itself what the gathered fact looks like. This is specially interesting when the returned value is a complex object or the target under test is modified and the check developer wants to see how this affects the gathered fact.\n\nThe command can be used as:\n\n```\n./trento-agent facts gather --gatherer corosync.conf --argument totem.token\n# To see the currently available gatherers and their names\n# ./trento-agent facts list\n```\n\nWhich would return the next where the `Value` is the available value in the written check:\n\n```\n{\n \"Name\": \"totem.token\",\n \"CheckID\": \"\",\n \"Value\": {\n \"Value\": 30000\n },\n \"Error\": null\n}\n```","ref":"readme.html#execution-targets","title":"Execution Targets - Wanda","type":"extras"},{"doc":"Built-in Checks can be found in the Catalog directory at `./priv/catalog/`\n\nTo implement new checks and test them:\n\n- write a new [Check Specification](./guides/specification.md) file\n- locate the newly created Check in the Catalog directory `./priv/catalog/`\n- test the execution as [previously described](#testing-executions)\n\n# Running a local Wanda instance","ref":"readme.html#adding-new-checks","title":"Adding new Checks - Wanda","type":"extras"},{"doc":"To set up a local development environment for Wanda, follow the instructions provided in [how to hack on wanda](./guides/development/hack_on_wanda.md).\n\nThis guide walks through the process of installing and configuring the necessary dependencies, as well as setting up a local development environment.","ref":"readme.html#running-a-development-environment","title":"Running a Development Environment - Wanda","type":"extras"},{"doc":"The demo mode of Wanda allows to showcase checks evaluation without the full setup with actual agents on the host. To run a demo instance, follow the instructions provided in [how to run wanda demo guide](./guides/development/demo.md).\n\n# Support\n\nPlease only report bugs via [GitHub issues](https://github.com/trento-project/wanda/issues) and\nfor any other inquiry or topic use [GitHub discussion](https://github.com/trento-project/wanda/discussions).\n\n# Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md)\n\n# License\n\nCopyright 2021-2023 SUSE LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use\nany of the source code in this project except in compliance with the License. You may obtain a copy of the\nLicense at\n\nhttps://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed\nunder the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\nCONDITIONS OF ANY KIND, either express or implied. See the License for the\nspecific language governing permissions and limitations under the License.","ref":"readme.html#running-a-demo-environment","title":"Running a Demo Environment - Wanda","type":"extras"},{"doc":"# Changelog\n\n## [1.1.0](https://github.com/trento-project/wanda/tree/1.1.0) (2023-08-02)\n\n[Full Changelog](https://github.com/trento-project/wanda/compare/1.0.0...1.1.0)\n\n**Implemented enhancements:**\n\n- Refactor demo server [\\#271](https://github.com/trento-project/wanda/pull/271) ([EMaksy](https://github.com/EMaksy))\n- initial checks for VMware vSphere \\(jsc\\#TRNT-1682\\) [\\#259](https://github.com/trento-project/wanda/pull/259) ([yeoldegrove](https://github.com/yeoldegrove))\n- update reference section to clarify the package version decision [\\#255](https://github.com/trento-project/wanda/pull/255) ([angelabriel](https://github.com/angelabriel))\n- Add when conditions for resource types, propagate the resource type in the ExecutionCompleted event [\\#253](https://github.com/trento-project/wanda/pull/253) ([dottorblaster](https://github.com/dottorblaster))\n- Add user friendly failure message \\(jsc\\#TRNT-1825\\) [\\#237](https://github.com/trento-project/wanda/pull/237) ([angelabriel](https://github.com/angelabriel))\n\n**Fixed bugs:**\n\n- Fix formatting in demo guide [\\#275](https://github.com/trento-project/wanda/pull/275) ([EMaksy](https://github.com/EMaksy))\n- fixes found by checks-checker [\\#260](https://github.com/trento-project/wanda/pull/260) ([yeoldegrove](https://github.com/yeoldegrove))\n- Add default failure message for expect\\_same expectations [\\#243](https://github.com/trento-project/wanda/pull/243) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n**Merged pull requests:**\n\n- Bump rhai\\_rustler to v1.0.2 [\\#276](https://github.com/trento-project/wanda/pull/276) ([fabriziosestito](https://github.com/fabriziosestito))\n- Bump rhai\\_rustler from 1.0.0 to 1.0.1 [\\#270](https://github.com/trento-project/wanda/pull/270) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump ex\\_doc from 0.30.2 to 0.30.3 [\\#269](https://github.com/trento-project/wanda/pull/269) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump jason from 1.4.0 to 1.4.1 [\\#266](https://github.com/trento-project/wanda/pull/266) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump ex\\_doc from 0.29.4 to 0.30.2 [\\#265](https://github.com/trento-project/wanda/pull/265) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump rhai\\_rustler to v1.0.0 [\\#264](https://github.com/trento-project/wanda/pull/264) ([fabriziosestito](https://github.com/fabriziosestito))\n- Update contracts usage [\\#258](https://github.com/trento-project/wanda/pull/258) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Document target\\_type inside env [\\#256](https://github.com/trento-project/wanda/pull/256) ([dottorblaster](https://github.com/dottorblaster))\n- Bump phoenix\\_ecto from 4.4.0 to 4.4.2 [\\#252](https://github.com/trento-project/wanda/pull/252) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump docker/login-action from 2.1.0 to 2.2.0 [\\#251](https://github.com/trento-project/wanda/pull/251) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Document cluster type support [\\#248](https://github.com/trento-project/wanda/pull/248) ([arbulu89](https://github.com/arbulu89))\n- Bump open\\_api\\_spex from 3.16.1 to 3.17.3 [\\#246](https://github.com/trento-project/wanda/pull/246) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Update copyright year to 2023 [\\#240](https://github.com/trento-project/wanda/pull/240) ([EMaksy](https://github.com/EMaksy))\n- Bump docker/metadata-action from 4.3.0 to 4.4.0 [\\#234](https://github.com/trento-project/wanda/pull/234) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump dialyxir from 1.2.0 to 1.3.0 [\\#232](https://github.com/trento-project/wanda/pull/232) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump excoveralls from 0.16.0 to 0.16.1 [\\#231](https://github.com/trento-project/wanda/pull/231) ([dependabot[bot]](https://github.com/apps/dependabot))\n\n## [1.0.0](https://github.com/trento-project/wanda/tree/1.0.0) (2023-04-26)\n\n[Full Changelog](https://github.com/trento-project/wanda/compare/0.1.0...1.0.0)\n\n**Implemented enhancements:**\n\n- Make cors optional on production [\\#206](https://github.com/trento-project/wanda/pull/206) ([arbulu89](https://github.com/arbulu89))\n- Build wanda with premium checks, if available [\\#179](https://github.com/trento-project/wanda/pull/179) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n**Fixed bugs:**\n\n- Expectation results result to false when some agent evaluation is missing [\\#224](https://github.com/trento-project/wanda/pull/224) ([arbulu89](https://github.com/arbulu89))\n\n**Merged pull requests:**\n\n- enhance remediation section to clarify the value setting [\\#235](https://github.com/trento-project/wanda/pull/235) ([angelabriel](https://github.com/angelabriel))\n- Add failure message documentation [\\#230](https://github.com/trento-project/wanda/pull/230) ([dottorblaster](https://github.com/dottorblaster))\n- Bump ex\\_doc from 0.29.2 to 0.29.4 [\\#229](https://github.com/trento-project/wanda/pull/229) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Rename `health_test.exs` -\\> `health_controller_test.exs` [\\#228](https://github.com/trento-project/wanda/pull/228) ([jamie-suse](https://github.com/jamie-suse))\n- Rename `HealthcheckViewTest` -\\> `HealthViewTest` [\\#227](https://github.com/trento-project/wanda/pull/227) ([jamie-suse](https://github.com/jamie-suse))\n- add api versioning to the readme examples [\\#226](https://github.com/trento-project/wanda/pull/226) ([angelabriel](https://github.com/angelabriel))\n- Add healthcheck and readiness endpoints [\\#225](https://github.com/trento-project/wanda/pull/225) ([jamie-suse](https://github.com/jamie-suse))\n- Add dev.local.exs usage [\\#223](https://github.com/trento-project/wanda/pull/223) ([arbulu89](https://github.com/arbulu89))\n- Bump credo from 1.6.7 to 1.7.0 [\\#222](https://github.com/trento-project/wanda/pull/222) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Fix execution of SBD related checks \\(jsc\\#CFSA-1961\\) [\\#220](https://github.com/trento-project/wanda/pull/220) ([angelabriel](https://github.com/angelabriel))\n- Bump plug\\_cowboy from 2.6.0 to 2.6.1 [\\#218](https://github.com/trento-project/wanda/pull/218) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Refactor API errors [\\#217](https://github.com/trento-project/wanda/pull/217) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add failure message [\\#216](https://github.com/trento-project/wanda/pull/216) ([dottorblaster](https://github.com/dottorblaster))\n- Bump excoveralls from 0.15.3 to 0.16.0 [\\#213](https://github.com/trento-project/wanda/pull/213) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Fixed broken web URLs [\\#212](https://github.com/trento-project/wanda/pull/212) ([ksanjeet](https://github.com/ksanjeet))\n- Compile and test with --warnings-as-errors flag [\\#210](https://github.com/trento-project/wanda/pull/210) ([fabriziosestito](https://github.com/fabriziosestito))\n- Update the hack on wanda guide [\\#209](https://github.com/trento-project/wanda/pull/209) ([EMaksy](https://github.com/EMaksy))\n- Bump ex\\_doc from 0.29.1 to 0.29.2 [\\#208](https://github.com/trento-project/wanda/pull/208) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Remove jwt enablement flag usage from jwt plug tests [\\#207](https://github.com/trento-project/wanda/pull/207) ([arbulu89](https://github.com/arbulu89))\n- Enrich the faker by using catalog data [\\#205](https://github.com/trento-project/wanda/pull/205) ([rtorrero](https://github.com/rtorrero))\n- Facts schema value lists maps [\\#204](https://github.com/trento-project/wanda/pull/204) ([arbulu89](https://github.com/arbulu89))\n- Bump actions/checkout from 2 to 3 [\\#203](https://github.com/trento-project/wanda/pull/203) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump excoveralls from 0.15.0 to 0.15.3 [\\#200](https://github.com/trento-project/wanda/pull/200) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump open\\_api\\_spex from 3.13.0 to 3.16.1 [\\#198](https://github.com/trento-project/wanda/pull/198) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump ecto\\_sql from 3.8.3 to 3.9.2 [\\#197](https://github.com/trento-project/wanda/pull/197) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump joken from 2.5.0 to 2.6.0 [\\#196](https://github.com/trento-project/wanda/pull/196) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump ex\\_doc from 0.29.0 to 0.29.1 [\\#195](https://github.com/trento-project/wanda/pull/195) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump credo from 1.6.6 to 1.6.7 [\\#194](https://github.com/trento-project/wanda/pull/194) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump phoenix from 1.6.12 to 1.6.16 [\\#193](https://github.com/trento-project/wanda/pull/193) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Bump docker/build-push-action from 3 to 4 [\\#192](https://github.com/trento-project/wanda/pull/192) ([dependabot[bot]](https://github.com/apps/dependabot))\n- Add dependabot [\\#191](https://github.com/trento-project/wanda/pull/191) ([fabriziosestito](https://github.com/fabriziosestito))\n- Filter out non-existing checks on the faker [\\#189](https://github.com/trento-project/wanda/pull/189) ([rtorrero](https://github.com/rtorrero))\n- Remotely trigger demo deploy on new wanda image [\\#188](https://github.com/trento-project/wanda/pull/188) ([rtorrero](https://github.com/rtorrero))\n- Add new demo env that uses faked execution server [\\#187](https://github.com/trento-project/wanda/pull/187) ([rtorrero](https://github.com/rtorrero))\n- Fix warning in api redirector test [\\#186](https://github.com/trento-project/wanda/pull/186) ([fabriziosestito](https://github.com/fabriziosestito))\n- Fix execution flaky test [\\#185](https://github.com/trento-project/wanda/pull/185) ([arbulu89](https://github.com/arbulu89))\n- Api version v1 [\\#183](https://github.com/trento-project/wanda/pull/183) ([CDimonaco](https://github.com/CDimonaco))\n- Update package\\_version gatherer doc [\\#182](https://github.com/trento-project/wanda/pull/182) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Run CI `test` step on different versions of Elixir & OTP [\\#181](https://github.com/trento-project/wanda/pull/181) ([jamie-suse](https://github.com/jamie-suse))\n- Add information on how to install wanda directly for development [\\#178](https://github.com/trento-project/wanda/pull/178) ([EMaksy](https://github.com/EMaksy))\n- Bump BCI base image to 15.4 for dev Dockerfile [\\#177](https://github.com/trento-project/wanda/pull/177) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Fix JWT plug runtime config [\\#176](https://github.com/trento-project/wanda/pull/176) ([fabriziosestito](https://github.com/fabriziosestito))\n- Use new `trento-wanda` image name for check development environment [\\#175](https://github.com/trento-project/wanda/pull/175) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- rewrite trento community checks regarding 'package version' [\\#124](https://github.com/trento-project/wanda/pull/124) ([angelabriel](https://github.com/angelabriel))\n\n## [0.1.0](https://github.com/trento-project/wanda/tree/0.1.0) (2023-01-23)\n\n[Full Changelog](https://github.com/trento-project/wanda/compare/a8b788751fe90542ed0d2541a816b3a148dedfd0...0.1.0)\n\n**Implemented enhancements:**\n\n- Build in obs [\\#173](https://github.com/trento-project/wanda/pull/173) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add JWT auth [\\#168](https://github.com/trento-project/wanda/pull/168) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add premium flag option to catalog loading code [\\#163](https://github.com/trento-project/wanda/pull/163) ([arbulu89](https://github.com/arbulu89))\n- Add check DA114A: Corosync has at least 2 rings configured [\\#141](https://github.com/trento-project/wanda/pull/141) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add SBD dump gatherer documentation [\\#137](https://github.com/trento-project/wanda/pull/137) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add last execution by group [\\#108](https://github.com/trento-project/wanda/pull/108) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add targets execution view [\\#106](https://github.com/trento-project/wanda/pull/106) ([arbulu89](https://github.com/arbulu89))\n- Fix protobuf message mapping [\\#94](https://github.com/trento-project/wanda/pull/94) ([arbulu89](https://github.com/arbulu89))\n- Ordered Execution list [\\#93](https://github.com/trento-project/wanda/pull/93) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add cargo to dockerfile and build rustler [\\#74](https://github.com/trento-project/wanda/pull/74) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Start execution api [\\#73](https://github.com/trento-project/wanda/pull/73) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add Checks Specification Documentation [\\#72](https://github.com/trento-project/wanda/pull/72) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Refactor executions api [\\#66](https://github.com/trento-project/wanda/pull/66) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Store execution state [\\#60](https://github.com/trento-project/wanda/pull/60) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add support for values computation based on environment [\\#46](https://github.com/trento-project/wanda/pull/46) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Use env values [\\#42](https://github.com/trento-project/wanda/pull/42) ([arbulu89](https://github.com/arbulu89))\n- Serve the execution results through an endpoint [\\#40](https://github.com/trento-project/wanda/pull/40) ([dottorblaster](https://github.com/dottorblaster))\n- Some needed improvements to make the code runnable on prod environment [\\#38](https://github.com/trento-project/wanda/pull/38) ([arbulu89](https://github.com/arbulu89))\n- Store execution result on Check execution completion [\\#36](https://github.com/trento-project/wanda/pull/36) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add a storable Wanda.Result.ExecutionResult entity [\\#35](https://github.com/trento-project/wanda/pull/35) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n**Fixed bugs:**\n\n- Fix default value when getting system env for JWT\\_AUTHENTICATION\\_ENABLED [\\#172](https://github.com/trento-project/wanda/pull/172) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Set critical state on agent timeout and warning severity [\\#166](https://github.com/trento-project/wanda/pull/166) ([arbulu89](https://github.com/arbulu89))\n- Fix get last execution by group id [\\#110](https://github.com/trento-project/wanda/pull/110) ([fabriziosestito](https://github.com/fabriziosestito))\n- Improve Execution open api doc [\\#109](https://github.com/trento-project/wanda/pull/109) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Init before start [\\#101](https://github.com/trento-project/wanda/pull/101) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Fix flaky evaluation test [\\#96](https://github.com/trento-project/wanda/pull/96) ([arbulu89](https://github.com/arbulu89))\n- Load checks properly for the execution [\\#61](https://github.com/trento-project/wanda/pull/61) ([arbulu89](https://github.com/arbulu89))\n- Fixed items definition for expectation\\_results in ExecutionComplete event [\\#14](https://github.com/trento-project/wanda/pull/14) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n**Closed issues:**\n\n- Bad links in README.md [\\#126](https://github.com/trento-project/wanda/issues/126)\n\n**Merged pull requests:**\n\n- Fix cors plug integration [\\#174](https://github.com/trento-project/wanda/pull/174) ([CDimonaco](https://github.com/CDimonaco))\n- Execution started event [\\#171](https://github.com/trento-project/wanda/pull/171) ([CDimonaco](https://github.com/CDimonaco))\n- Chore: move tests in subfolder [\\#170](https://github.com/trento-project/wanda/pull/170) ([fabriziosestito](https://github.com/fabriziosestito))\n- Remove ssh-address flag reference from docs [\\#169](https://github.com/trento-project/wanda/pull/169) ([arbulu89](https://github.com/arbulu89))\n- rewrite trento community check regarding 'running corosync rings' [\\#167](https://github.com/trento-project/wanda/pull/167) ([angelabriel](https://github.com/angelabriel))\n- Add list & map examples for `corosync-cmapctl` docs [\\#165](https://github.com/trento-project/wanda/pull/165) ([jamie-suse](https://github.com/jamie-suse))\n- Force rhai\\_rustler build [\\#164](https://github.com/trento-project/wanda/pull/164) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add doc for the new package\\_version comparisons [\\#162](https://github.com/trento-project/wanda/pull/162) ([rtorrero](https://github.com/rtorrero))\n- add when condition to decide where to run a check [\\#161](https://github.com/trento-project/wanda/pull/161) ([angelabriel](https://github.com/angelabriel))\n- Improve gatherers documentation and add rhai example outputs [\\#160](https://github.com/trento-project/wanda/pull/160) ([fabriziosestito](https://github.com/fabriziosestito))\n- Clean up doc saying that expectation evaluation has access to the env [\\#159](https://github.com/trento-project/wanda/pull/159) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Document the trento-agent facts command [\\#158](https://github.com/trento-project/wanda/pull/158) ([arbulu89](https://github.com/arbulu89))\n- Fix integer mapping [\\#157](https://github.com/trento-project/wanda/pull/157) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add starting the targets section on the docs [\\#156](https://github.com/trento-project/wanda/pull/156) ([arbulu89](https://github.com/arbulu89))\n- Document best practices [\\#155](https://github.com/trento-project/wanda/pull/155) ([arbulu89](https://github.com/arbulu89))\n- Implement when condition [\\#154](https://github.com/trento-project/wanda/pull/154) ([dottorblaster](https://github.com/dottorblaster))\n- rewrite trento community check regarding 'hacluster' password change [\\#153](https://github.com/trento-project/wanda/pull/153) ([angelabriel](https://github.com/angelabriel))\n- Fix external links in ExDocs [\\#152](https://github.com/trento-project/wanda/pull/152) ([fabriziosestito](https://github.com/fabriziosestito))\n- Chore: remove unusued fixture [\\#151](https://github.com/trento-project/wanda/pull/151) ([fabriziosestito](https://github.com/fabriziosestito))\n- Bump to rhai\\_rustler to v0.1.3 [\\#149](https://github.com/trento-project/wanda/pull/149) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add documentation for verify\\_password gatherer [\\#147](https://github.com/trento-project/wanda/pull/147) ([rtorrero](https://github.com/rtorrero))\n- rewrite trento community checks regarding 'cibadmin' configuration [\\#146](https://github.com/trento-project/wanda/pull/146) ([angelabriel](https://github.com/angelabriel))\n- Improve table format and add req argument info [\\#145](https://github.com/trento-project/wanda/pull/145) ([rtorrero](https://github.com/rtorrero))\n- Add saphostctrl gatherer to gatherers.md [\\#144](https://github.com/trento-project/wanda/pull/144) ([rtorrero](https://github.com/rtorrero))\n- Add a cheat sheet for Rhai [\\#143](https://github.com/trento-project/wanda/pull/143) ([dottorblaster](https://github.com/dottorblaster))\n- rewrite trento community checks regarding 'sbd dump' configuration [\\#142](https://github.com/trento-project/wanda/pull/142) ([angelabriel](https://github.com/angelabriel))\n- Document cibadmin gatherer [\\#136](https://github.com/trento-project/wanda/pull/136) ([arbulu89](https://github.com/arbulu89))\n- Add a ref to target to README [\\#133](https://github.com/trento-project/wanda/pull/133) ([dottorblaster](https://github.com/dottorblaster))\n- rewrite trento community checks regarding 'sbd' configuration [\\#123](https://github.com/trento-project/wanda/pull/123) ([angelabriel](https://github.com/angelabriel))\n- rewriting checks for Wanda gatherer corosync-cmapctl [\\#119](https://github.com/trento-project/wanda/pull/119) ([pirat013](https://github.com/pirat013))\n- Add severity to the JSON schema [\\#116](https://github.com/trento-project/wanda/pull/116) ([dottorblaster](https://github.com/dottorblaster))\n- Gatherer.corosyncconf [\\#115](https://github.com/trento-project/wanda/pull/115) ([pirat013](https://github.com/pirat013))\n- Refactor factories [\\#112](https://github.com/trento-project/wanda/pull/112) ([fabriziosestito](https://github.com/fabriziosestito))\n- Use Kernel.-- instead of Enum.filter [\\#111](https://github.com/trento-project/wanda/pull/111) ([fabriziosestito](https://github.com/fabriziosestito))\n- add license [\\#107](https://github.com/trento-project/wanda/pull/107) ([stefanotorresi](https://github.com/stefanotorresi))\n- Use specific compose ports for wanda dev/test docker-compose [\\#105](https://github.com/trento-project/wanda/pull/105) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add critical, warning and passing counts to the execution view [\\#104](https://github.com/trento-project/wanda/pull/104) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add ability to handle non-existent & malformed Checks supplied to catalog [\\#103](https://github.com/trento-project/wanda/pull/103) ([jamie-suse](https://github.com/jamie-suse))\n- Add corosynccmapctl to gatherers.md [\\#102](https://github.com/trento-project/wanda/pull/102) ([rtorrero](https://github.com/rtorrero))\n- Bump contracts [\\#99](https://github.com/trento-project/wanda/pull/99) ([fabriziosestito](https://github.com/fabriziosestito))\n- Generate and push swagger-ui to gh-pages [\\#98](https://github.com/trento-project/wanda/pull/98) ([fabriziosestito](https://github.com/fabriziosestito))\n- Re-add accidentaly removed headers [\\#97](https://github.com/trento-project/wanda/pull/97) ([rtorrero](https://github.com/rtorrero))\n- Add test for policy handling Fact error [\\#95](https://github.com/trento-project/wanda/pull/95) ([jamie-suse](https://github.com/jamie-suse))\n- Remove installation section from README.md [\\#92](https://github.com/trento-project/wanda/pull/92) ([fabriziosestito](https://github.com/fabriziosestito))\n- Update CONTRIBUTING.md [\\#91](https://github.com/trento-project/wanda/pull/91) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add documentation for the package\\_version gatherer [\\#90](https://github.com/trento-project/wanda/pull/90) ([rtorrero](https://github.com/rtorrero))\n- Document systemd gatherer [\\#89](https://github.com/trento-project/wanda/pull/89) ([arbulu89](https://github.com/arbulu89))\n- Add Documentation for SBD Gatherer [\\#88](https://github.com/trento-project/wanda/pull/88) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add badges to readme [\\#87](https://github.com/trento-project/wanda/pull/87) ([fabriziosestito](https://github.com/fabriziosestito))\n- Use correct remediation text for check 156F64 [\\#85](https://github.com/trento-project/wanda/pull/85) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Support no args gatherers [\\#84](https://github.com/trento-project/wanda/pull/84) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Add coveralls [\\#83](https://github.com/trento-project/wanda/pull/83) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add /etc/hosts file gatherer documentation [\\#82](https://github.com/trento-project/wanda/pull/82) ([rtorrero](https://github.com/rtorrero))\n- Add ExDoc config in mix.exs and supporting file to generate the doc [\\#81](https://github.com/trento-project/wanda/pull/81) ([fabriziosestito](https://github.com/fabriziosestito))\n- Minor tweaks to the specs doc [\\#80](https://github.com/trento-project/wanda/pull/80) ([rtorrero](https://github.com/rtorrero))\n- Fix Checks Specification doc link [\\#79](https://github.com/trento-project/wanda/pull/79) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Use strict module ordering [\\#77](https://github.com/trento-project/wanda/pull/77) ([fabriziosestito](https://github.com/fabriziosestito))\n- Integrate TLint into CI [\\#76](https://github.com/trento-project/wanda/pull/76) ([dottorblaster](https://github.com/dottorblaster))\n- Do not raise if an execution already exists [\\#75](https://github.com/trento-project/wanda/pull/75) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add ex doc gh pages [\\#71](https://github.com/trento-project/wanda/pull/71) ([fabriziosestito](https://github.com/fabriziosestito))\n- Bump erlang version to 24.3.4 [\\#70](https://github.com/trento-project/wanda/pull/70) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Change Abacus to Rhai [\\#69](https://github.com/trento-project/wanda/pull/69) ([fabriziosestito](https://github.com/fabriziosestito))\n- Handle CORS in dev environment [\\#68](https://github.com/trento-project/wanda/pull/68) ([arbulu89](https://github.com/arbulu89))\n- Refactor context [\\#65](https://github.com/trento-project/wanda/pull/65) ([fabriziosestito](https://github.com/fabriziosestito))\n- Abstract RabbitMQ processing logic [\\#64](https://github.com/trento-project/wanda/pull/64) ([jamie-suse](https://github.com/jamie-suse))\n- Detect already running execution for group\\_id [\\#63](https://github.com/trento-project/wanda/pull/63) ([arbulu89](https://github.com/arbulu89))\n- Remove restart directive from container definitions [\\#62](https://github.com/trento-project/wanda/pull/62) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Chore: remove unused miss dep [\\#59](https://github.com/trento-project/wanda/pull/59) ([fabriziosestito](https://github.com/fabriziosestito))\n- Use google protobuf value [\\#58](https://github.com/trento-project/wanda/pull/58) ([fabriziosestito](https://github.com/fabriziosestito))\n- Chore: rename/refactor schemas [\\#56](https://github.com/trento-project/wanda/pull/56) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add get check result [\\#55](https://github.com/trento-project/wanda/pull/55) ([fabriziosestito](https://github.com/fabriziosestito))\n- Rename controllers context [\\#54](https://github.com/trento-project/wanda/pull/54) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add Result OpenAPI Schema and cleanup [\\#53](https://github.com/trento-project/wanda/pull/53) ([fabriziosestito](https://github.com/fabriziosestito))\n- More prod fixes [\\#52](https://github.com/trento-project/wanda/pull/52) ([arbulu89](https://github.com/arbulu89))\n- Add initialization tasks for a release [\\#51](https://github.com/trento-project/wanda/pull/51) ([arbulu89](https://github.com/arbulu89))\n- Enable phoenix server usage in prod [\\#50](https://github.com/trento-project/wanda/pull/50) ([arbulu89](https://github.com/arbulu89))\n- Catalog controller [\\#49](https://github.com/trento-project/wanda/pull/49) ([arbulu89](https://github.com/arbulu89))\n- Cleanup execution controller [\\#48](https://github.com/trento-project/wanda/pull/48) ([fabriziosestito](https://github.com/fabriziosestito))\n- Refactor evaluation tests [\\#47](https://github.com/trento-project/wanda/pull/47) ([arbulu89](https://github.com/arbulu89))\n- Switch to Views for JSON rendering [\\#45](https://github.com/trento-project/wanda/pull/45) ([dottorblaster](https://github.com/dottorblaster))\n- Add CI step to check for unused dependencies [\\#44](https://github.com/trento-project/wanda/pull/44) ([jamie-suse](https://github.com/jamie-suse))\n- Load check values from yaml [\\#43](https://github.com/trento-project/wanda/pull/43) ([arbulu89](https://github.com/arbulu89))\n- Check severity [\\#41](https://github.com/trento-project/wanda/pull/41) ([arbulu89](https://github.com/arbulu89))\n- Enable single pipe check on credo [\\#39](https://github.com/trento-project/wanda/pull/39) ([arbulu89](https://github.com/arbulu89))\n- Add dockerfile [\\#37](https://github.com/trento-project/wanda/pull/37) ([fabriziosestito](https://github.com/fabriziosestito))\n- Map ExecutionCompleted event [\\#34](https://github.com/trento-project/wanda/pull/34) ([arbulu89](https://github.com/arbulu89))\n- Phoenix lift off [\\#33](https://github.com/trento-project/wanda/pull/33) ([arbulu89](https://github.com/arbulu89))\n- Message content\\_type from Contracts [\\#32](https://github.com/trento-project/wanda/pull/32) ([CDimonaco](https://github.com/CDimonaco))\n- Add amqp consumer integration tests [\\#31](https://github.com/trento-project/wanda/pull/31) ([fabriziosestito](https://github.com/fabriziosestito))\n- Handle fact gathering errors [\\#30](https://github.com/trento-project/wanda/pull/30) ([arbulu89](https://github.com/arbulu89))\n- Update contracts dep to trento-projects/contracts [\\#29](https://github.com/trento-project/wanda/pull/29) ([fabriziosestito](https://github.com/fabriziosestito))\n- Set execution GenServer restart policy as transient [\\#28](https://github.com/trento-project/wanda/pull/28) ([arbulu89](https://github.com/arbulu89))\n- Do not requeue amqp message on error [\\#26](https://github.com/trento-project/wanda/pull/26) ([arbulu89](https://github.com/arbulu89))\n- Fix amqp message consumption [\\#25](https://github.com/trento-project/wanda/pull/25) ([arbulu89](https://github.com/arbulu89))\n- Publish facts gathering requested [\\#24](https://github.com/trento-project/wanda/pull/24) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add checks to execution server state [\\#23](https://github.com/trento-project/wanda/pull/23) ([fabriziosestito](https://github.com/fabriziosestito))\n- Map FactsGatheringRequested event [\\#22](https://github.com/trento-project/wanda/pull/22) ([fabriziosestito](https://github.com/fabriziosestito))\n- Timeout business logic implementation [\\#21](https://github.com/trento-project/wanda/pull/21) ([dottorblaster](https://github.com/dottorblaster))\n- Remove JSON schema, add new protobuf contracts [\\#20](https://github.com/trento-project/wanda/pull/20) ([fabriziosestito](https://github.com/fabriziosestito))\n- Add timeout logic to Wanda.Execution.Server [\\#19](https://github.com/trento-project/wanda/pull/19) ([dottorblaster](https://github.com/dottorblaster))\n- Revert \"Adds cache version to pipeline\" [\\#18](https://github.com/trento-project/wanda/pull/18) ([fabriziosestito](https://github.com/fabriziosestito))\n- fix execution requested event schema [\\#15](https://github.com/trento-project/wanda/pull/15) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Adds cache version to pipeline [\\#12](https://github.com/trento-project/wanda/pull/12) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Serialize an ExecutionCompleted json cloud event [\\#11](https://github.com/trento-project/wanda/pull/11) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Adds json schema for emitted ExecutionCompletedV1 [\\#10](https://github.com/trento-project/wanda/pull/10) ([nelsonkopliku](https://github.com/nelsonkopliku))\n- Receive Execution Requested event [\\#9](https://github.com/trento-project/wanda/pull/9) ([fabriziosestito](https://github.com/fabriziosestito))\n- Refactor Wanda.Execution in Wanda.Execution.Server, create execution API module [\\#8](https://github.com/trento-project/wanda/pull/8) ([fabriziosestito](https://github.com/fabriziosestito))\n- Receive facts gathered event [\\#6](https://github.com/trento-project/wanda/pull/6) ([fabriziosestito](https://github.com/fabriziosestito))\n- Setup amqp [\\#5](https://github.com/trento-project/wanda/pull/5) ([fabriziosestito](https://github.com/fabriziosestito))\n- Group expectations evaluation [\\#4](https://github.com/trento-project/wanda/pull/4) ([fabriziosestito](https://github.com/fabriziosestito))\n- Refactor execution pt1 [\\#3](https://github.com/trento-project/wanda/pull/3) ([fabriziosestito](https://github.com/fabriziosestito))\n- Expectations eval pt 1 [\\#2](https://github.com/trento-project/wanda/pull/2) ([fabriziosestito](https://github.com/fabriziosestito))\n- proof of concept of check execution orchestration, step 1 [\\#1](https://github.com/trento-project/wanda/pull/1) ([nelsonkopliku](https://github.com/nelsonkopliku))\n\n\n\n\\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*","ref":"changelog.html","title":"Changelog","type":"extras"},{"doc":"# How to contribute\n\nThanks for showing interest and sharing your time to contribute to this project!\n\nThis guide is meant to be used as a general guideline for creating issues or\npull requests. We encourage all first-time contributors to give this a read to avoid\ncommon mistakes and improve the quality of all contributions.","ref":"contributing.html","title":"How to contribute","type":"extras"},{"doc":"Before creating a new issue make sure you use the search functionality to confirm\nthat a similar issue doesn't already exist. Next, make sure you properly label\nthe issue as per our [labels](https://github.com/trento-project/wanda/labels)\n\nIf you are reporting a `bug`, please share a file generated using the\n`trento-support.sh` script with the following params:\n\n```\n# trento-support.sh --collect all --output file-tgz\n```\n\nand include the output in your issue. The script should remove sensitive data\nautomatically but please make sure you are not sharing any sensitive data of your own.","ref":"contributing.html#opening-issues","title":"Opening issues - How to contribute","type":"extras"},{"doc":"Always refer to the [docs repository](https://github.com/trento-project/docs) for coding standards and general guidelines.\n\n#","ref":"contributing.html#submitting-changes","title":"Submitting changes - How to contribute","type":"extras"},{"doc":"Reviews are hard. These few points will help us to reduce the time and effort required and allow us to merge your changes faster.\n\n1. Only touch relevant files.\n2. We have a PR template to aid you in completing the required details. Be\n sure to complete it and remove the non-relevant parts.\n3. Keep PRs as small as possible. When the PR gets too big, consider splitting it into multiple parts. A PR should ideally be between 100 and 500 additions.\n4. Check that the tests are passing.\n5. Check that your code is not generating new warnings.\n6. Check that any dependent changes have been merged and published in downstream modules\n7. Commit history should be short and group changes that otherwise wouldn't\n make sense on their own.\n8. Always write a clear log message for your commits. One-line messages are\n fine for small changes, but bigger changes should look like this:\n\n ```\n git commit -m \"A brief summary of the commit\n\n A paragraph describing what changed and its impact.\"\n ```\n\n9. Write a detailed description that gives context and explains why you are\n creating the PR.\n10. If the PR adds functionality, please add some tests and documentation\n to support it.\n11. Each PR needs 1 approval to be merged. Select a reviewer in particular if\n you are looking for specific feedback from someone.\n\n#","ref":"contributing.html#pull-requests-guideline","title":"Pull Requests guideline - How to contribute","type":"extras"},{"doc":"1. Opinionated comments are welcome but don't expect them always to be\n addressed. Be ready for discussion but also open to conceding.\n To avoid scope creep, consider proposing subsequent PRs\n rather than requesting changes for the current PR you are reviewing.\n2. Short, concise comments with examples are the most valuable.","ref":"contributing.html#reviewers-guideline","title":"Reviewers guideline - How to contribute","type":"extras"},{"doc":"# Rhai expressions cheatsheet\n\nIn this cheatsheet are grouped the most frequent manipulations that can be done through Rhai, for convenience.","ref":"rhai_expressions_cheat_sheet.html","title":"Rhai expressions cheatsheet","type":"extras"},{"doc":"{: .col-2}\n\n#","ref":"rhai_expressions_cheat_sheet.html#cheatsheet","title":"Cheatsheet - Rhai expressions cheatsheet","type":"extras"},{"doc":"##","ref":"rhai_expressions_cheat_sheet.html#arrays","title":"Arrays - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n[1, 2, 3].filter(|value| value % 2 == 0)\n=> [2]\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#filtering-an-array","title":"Filtering an array - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n[\"wow\", \"check\"].index_of(|value| value == \"check\")\n=> 1\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#finding-the-index-of-an-element-inside-an-array","title":"Finding the index of an element inside an array - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\nlet nodelist = [\n #{resource_id: 5, name: \"foo\"},\n #{resource_id: 12, name: \"bar\"}\n];\n\nnodelist.find(|value| value.resource_id == 5)\n=> #{\"name\": \"foo\", \"resource_id\": 5}\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#finding-an-element-inside-an-array","title":"Finding an element inside an array - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n[2, 4, 6].all(|value| value % 2 == 0)\n=> true\n```\n\n#","ref":"rhai_expressions_cheat_sheet.html#checking-if-an-expression-is-true-for-every-element-of-an-array","title":"Checking if an expression is true for every element of an array - Rhai expressions cheatsheet","type":"extras"},{"doc":"##","ref":"rhai_expressions_cheat_sheet.html#maps","title":"Maps - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n#{a: 1, b: 2}.keys()\n=> [\"a\", \"b\"]\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#get-only-keys-returns-an-array","title":"Get only keys (returns an array) - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n#{a: 1, b: 2}.values()\n=> [1, 2]\n```\n\n##","ref":"rhai_expressions_cheat_sheet.html#get-only-values-returns-an-array","title":"Get only values (returns an array) - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\nlet map = #{\n ring_one: 12,\n ring_two: 34,\n ring_three: 90,\n ring_four: 234,\n ring_five: 908\n};\n\nmap.keys().filter(|prop| prop.starts_with(\"ring\")).len() >= 5\n=> true\n```\n\n#","ref":"rhai_expressions_cheat_sheet.html#check-if-a-map-has-more-than-5-keys-which-name-starts-with-ring","title":"Check if a map has more than 5 keys which name starts with \"ring\" - Rhai expressions cheatsheet","type":"extras"},{"doc":"##","ref":"rhai_expressions_cheat_sheet.html#strings","title":"Strings - Rhai expressions cheatsheet","type":"extras"},{"doc":"```ts\n\"a;b;c\".split(\";\")\n=> [\"a\", \"b\", \"c\"]\n```","ref":"rhai_expressions_cheat_sheet.html#splitting-a-string","title":"Splitting a string - Rhai expressions cheatsheet","type":"extras"},{"doc":"# Checks Specification\n\nA language allowing to declare best practices to be adhered on target SAP Infrastructures.","ref":"specification.html","title":"Checks Specification","type":"extras"},{"doc":"The need this Specification aims to fulfill is to provide users a simple way to declare what we (the Trento Team) often refer to as \"Checks\".\n\nChecks are, in Trento's domain, the crystallization of SUSE's best practices when it comes to SAP workloads in a form that both a user ([Spec](#anatomy-of-a-check)) and a machine ([Execution](#checks-execution)) can read.\n\n[^1]: The Trento Team from now on.","ref":"specification.html#introduction","title":"Introduction - Checks Specification","type":"extras"},{"doc":"_Checks Execution_ is the process that determines whether the best practices defined in the [Checks Specifications](#anatomy-of-a-check) are being followed on a target infrastructure.\n\n> [Requesting an Execution](#requesting-an-execution) -> [Facts Gathering](#facts-gathering) -> [Expectation Evaluation](#expectation-evaluation)\n\n#","ref":"specification.html#checks-execution","title":"Checks Execution - Checks Specification","type":"extras"},{"doc":"An Execution can be requested to start by providing Wanda the following information:\n\n- an execution identifier\n- an execution Group identifier\n- the Checks Selection for the targets (a list of checks to be executed on the targets)\n\nWhen the Execution starts running, its current state is stored in the Database and the targets are notified - via the message broker - about Facts to be gathered.\n\nThen the _Execution_ waits for the [Facts Gathering](#facts-gathering) to complete.\n\n#","ref":"specification.html#requesting-an-execution","title":"Requesting an Execution - Checks Specification","type":"extras"},{"doc":"After an _Execution Request_ the targets are notified about the facts they need to [gather](./gatherers.md).\n\nWhenever a target has gathered all the needed facts for an _Execution_, it notifies Wanda - via the message broker - about the _Gathered Facts_.\n\n#","ref":"specification.html#facts-gathering","title":"Facts Gathering - Checks Specification","type":"extras"},{"doc":"_Expectation Evaluation_ is the process of [evaluating](#expression-language) the [Expectations](#expectations)\nusing the received _Gathered Facts_ to obtain the result of a check.\n\nThis will only happen once _Gathered Facts_ are received **from all the targets**.\n\nAfter the result has been determined, the currently `running` Execution transitions to `completed` and its new state is tracked on the Database.\n\nAt this point the Execution is considered **Completed** and interested parties are notified about the Execution Completion.\n\n#","ref":"specification.html#expectation-evaluation","title":"Expectation Evaluation - Checks Specification","type":"extras"},{"doc":"Once an execution is completed, a checks result should give feedback on what aspects of a target infrastructure adhere to the best practices and which don't.\n\nPossible results:\n\n- `passing`, everything ok\n- `warning`, best practice not followed, should fix\n- `critical`, best practice not followed, must fix\n\nSee also [Check Severity](#severity).","ref":"specification.html#checks-results","title":"Checks Results - Checks Specification","type":"extras"},{"doc":"A Check declaration comes in the form of a `yaml` file and all the Checks together build up the **Checks Catalog**\n\nHere's an example:\n\n```yaml\nid: \"156F64\"\nname: Corosync `token` timeout\ngroup: Corosync\ndescription: Corosync `token` timeout is set to the correct value\nremediation: |","ref":"specification.html#anatomy-of-a-check","title":"Anatomy of a Check - Checks Specification","type":"extras"},{"doc":"The value of the Corosync `token` timeout is not set as recommended.","ref":"specification.html#abstract","title":"Abstract - Checks Specification","type":"extras"},{"doc":"Adjust the corosync `token` timeout as recommended...\n\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\n argument: cib.configuration\n\n - name: first_primitive\n gatherer: cibadmin\n argument: cib.configuration.resources.primitive.0\n\n - name: first_cluster_property_set_second_nvpair\n gatherer: cibadmin\n argument: cib.configuration.crm_config.cluster_property_set.0.nvpair.1\n```\n\nExample output (in Rhai):\n\n```ts\n// first_primitive\n#{\n class: \"stonith\",\n id: \"stonith-sbd\",\n instance_attributes: #{\n id: \"stonith-sbd-instance_attributes\",\n nvpair: [#{\n id: \"stonith-sbd-instance_attributes-pcmk_delay_max\",\n name: \"pcmk_delay_max\",\n value: \"30s\"\n }]\n },\n type: \"external/sbd\"\n};\n\n// first_cluster_property_set_second_nvpair\n#{\n id: \"cib-bootstrap-options-dc-version\",\n name: \"dc-version\",\n value: \"2.0.4+20200616.2deceaa3a-3.12.1-2.0.4+20200616.2deceaa3a\"\n};\n```\n\n \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\n argument: totem.token\n\n - name: corosync_join\n gatherer: corosync.conf\n argument: totem.join\n\n - name: corosync_node_id_0\n gatherer: corosync.conf\n argument: nodelist.node.0.nodeid\n\n - name: corosync_node_id_1\n gatherer: corosync.conf\n argument: nodelist.node.1.nodeid\n\n - name: corosync_nodes\n gatherer: corosync.conf\n argument: nodelist.node\n```\n\nExample output (in Rhai):\n\n```ts\n// corosync_token_timeout\n30000;\n\n// corosync_join\n60;\n\n// corosync_node_id_0\n1;\n\n// corosync_node_id_1\n2;\n\n// corosync_nodes\n[#{nodeid: 1, ring0_addr: \"192.168.157.10\"}, #{nodeid: 2, ring0_addr: \"192.168.157.11\"}];\n```\n\nFor extra information refer to [trento-project/agent/../gatherers/corosyncconf_test.go](https://github.com/trento-project/agent/blob/main/internal/factsengine/gatherers/corosyncconf_test.go)\n\n \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\n argument: totem.token\n\n - name: runtime_totem_token\n gatherer: corosync-cmapctl\n argument: runtime.config.totem.token\n\n - name: totem_transport\n gatherer: corosync-cmapctl\n argument: totem.transport\n\n - name: totem_max_messages\n gatherer: corosync-cmapctl\n argument: runtime.config.totem.max_messages\n\n - name: node_0_ring0addr\n gatherer: corosync-cmapctl\n argument: nodelist.node.0.ring0_addr\n\n - name: node_list\n gatherer: corosync-cmapctl\n argument: nodelist.node\n\n - name: second_node\n gatherer: corosync-cmapctl\n argument: nodelist.node.1\n```\n\nExample output (in Rhai):\n\n```ts\n// totem_token\n30000;\n\n// runtime_totem_token\n30000;\n\n// totem_transport\n\"udpu\";\n\n// totem_max_messages\n20;\n\n// node_0_ring0addr\n\"10.80.1.11\";\n\n// node_list\n#{\n \"0\": #{\n nodeid: 1,\n ring0_addr: \"10.80.1.11\"\n },\n \"1\": #{\n nodeid: 2,\n ring0_addr: \"10.80.1.12\"\n }\n};\n\n// second_node\n#{ nodeid: 2, ring0_addr: \"10.80.1.12\" };\n```\n\n \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\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\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\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\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\n argument: node1\n\n - name: hosts_node2\n gatherer: hosts\n argument: node2\n\n - name: hosts_all\n gatherer: hosts\n```\n\nExample output (in Rhai):\n\n```ts\n// hosts_node1\n[\"127.0.0.1\", \"::1\"];\n\n// hosts_node2\n[\"192.168.157.11\"];\n\n// hosts_all\n#{\n \"localhost\": [\"127.0.0.1\", \"::1\"],\n \"node1\": [\"192.168.157.10\"],\n \"node2\": [\"192.168.157.11\"],\n ...\n};\n```\n\n \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\n argument: corosync,2.4.5\n\n - name: package_corosync\n gatherer: package_version\n argument: corosync\n\n - name: package_sbd\n gatherer: package_version\n argument: sbd\n\nvalues:\n - name: greater_than_installed\n default: 1\n - name: lesser_than_installed\n default: -1\n - name: same_as_installed\n default: 0\n - name: expected_corosync_version\n default: \"2.4.5\"\n\nexpectations:\n - name: compare_package_corosync\n expect: facts.compare_package_corosync == values.greater_than_installed\n\n - name: package_corosync_is_the_expected_one\n expect: facts.package_corosync.first().version == values.expected_corosync_version\n\n - name: sbd_version_same_on_all_hosts\n expect_same: facts.package_sbd.first().version\n```\n\nExample arguments:\n\n| Name | Return value |\n| :------------------- | :---------------------------------------------------------------------------- |\n| `package_name` | a list containing information about the installed versions of the rpm package |\n| `package_name,2.4.5` | an integer with a value of `-1`, `0` or `1` (see above) |\n\nExample specification:\n\n```yaml\nfacts:\n - name: package_corosync\n gatherer: package_version\n argument: corosync\n\n - name: package_pacemaker\n gatherer: package_version\n argument: pacemaker\n\n - name: multiple_sbd_versions_installed\n gatherer: package_version\n argument: sbd\n\n - name: compare_package_corosync\n gatherer: package_version\n argument: corosync,2.4.5\n\n ...\n```\n\nExample output (in Rhai):\n\n```ts\n// package_corosync\n[\n #{\n \"version\": \"2.4.5\"\n }\n]\n\n// package_pacemaker\n[\n #{\n \"version\": \"2.0.4+20200616.2deceaa3a\"\n }\n]\n\n// multiple_sbd_versions_installed\n[\n #{\n \"version\": \"1.5.1\" // latest installed version, not necessarily the newest one\n },\n #{\n \"version\": \"1.5.2\"\n }\n]\n\n// compare_package_corosync\n0\n```\n\n \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\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\n argument: GetProcessList\n\n - name: instances\n gatherer: sapcontrol\n argument: GetSystemInstanceList\n```\n\nExample output (in Rhai):\n\n```ts\n// GetProcessList\n#{\n \"NWP\": [\n #{\n \"instance_nr\": \"10\",\n \"name\": \"ERS10\",\n \"output\": [\n #{\n \"description\": \"EnqueueReplicator\",\n \"dispstatus\": \"SAPControl-GREEN\",\n \"elapsedtime\": \"266:08:15\",\n \"name\": \"enrepserver\",\n \"pid\": 7221,\n \"starttime\": \"2023 09 29 09:41:41\",\n \"textstatus\": \"Running\"\n }\n ]\n }\n ]\n}\n\n// GetSystemInstanceList\n#{\n \"NWP\": [\n #{\n \"instance_nr\": \"10\",\n \"name\": \"ERS10\",\n \"output\": [\n #{\n \"dispstatus\": \"SAPControl-GREEN\",\n \"features\": \"MESSAGESERVER|ENQUE\",\n \"hostname\": \"sapnwpas\",\n \"http_port\": 50013,\n \"https_port\": 50014,\n \"instance_nr\": 0,\n \"start_priority\": \"1\"\n },\n #{\n \"dispstatus\": \"SAPControl-GREEN\",\n \"features\": \"ENQREP\",\n \"hostname\": \"sapnwper\",\n \"http_port\": 51013,\n \"https_port\": 51014,\n \"instance_nr\": 10,\n \"start_priority\": \"0.5\"\n },\n ...\n ]\n }\n ]\n}\n\n// GetVersionInfo\n#{\n \"NWP\": [\n #{\n \"instance_nr\": \"10\",\n \"name\": \"ERS10\",\n \"output\": [\n #{\n \"architecture\": \"linuxx86_64\",\n \"build\": \"optU (Oct 16 2021, 00:03:15)\",\n \"changelist\": \"2094654\",\n \"filename\": \"/usr/sap/NWP/ERS10/exe/sapstartsrv\",\n \"patch\": \"900\",\n \"rks_compatibility_level\": \"1\",\n \"sap_kernel\": \"753\",\n \"time\": \"2021 10 15 22:14:31\"\n },\n #{\n \"architecture\": \"linuxx86_64\",\n \"build\": \"optU (Oct 16 2021, 00:03:15)\",\n \"changelist\": \"2094654\",\n \"filename\": \"/usr/sap/NWP/ERS10/exe/gwrd\",\n \"patch\": \"900\",\n \"rks_compatibility_level\": \"1\",\n \"sap_kernel\": \"753\",\n \"time\": \"2021 10 15 22:04:14\"\n },\n ...\n ]\n }\n ]\n}\n\n// HACheckConfig\n#{\n \"NWP\": [\n #{\n \"instance_nr\": \"10\",\n \"name\": \"ERS10\",\n \"output\": [\n #{\n \"category\": \"SAPControl-SAP-CONFIGURATION\",\n \"comment\": \"2 ABAP instances detected\",\n \"description\": \"Redundant ABAP instance configuration\",\n \"state\": \"SAPControl-HA-SUCCESS\"\n },\n #{\n \"category\": \"SAPControl-SAP-CONFIGURATION\",\n \"comment\": \"0 Java instances detected\",\n \"description\": \"Redundant Java instance configuration\",\n \"state\": \"SAPControl-HA-SUCCESS\"\n },\n ...\n ]\n }\n ]\n}\n\n//HAGetFailoverConfig\n#{\n \"NWP\": [\n #{\n \"instance_nr\": \"10\",\n \"name\": \"ERS10\",\n \"output\": #{\n \"ha_active\": false,\n \"ha_active_nodes\": \"\",\n \"ha_documentation\": \"\",\n \"ha_nodes\": [],\n \"ha_product_version\": \"\",\n \"ha_sap_interface_version\": \"\"\n }\n }\n ]\n}\n\n```\n\n \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\n argument: Ping\n\n - name: list_instances\n gatherer: saphostctrl\n argument: ListInstances\n```\n\nExample output (in Rhai):\n\n```ts\n// ping\n#{elapsed: 579770.0, status: \"SUCCESS\"}\n\n// list_instances\n[\n #{\n \"changelist\": 1908545,\n \"hostname\": \"vmhana01\",\n \"instance\": \"00\",\n \"patch\": 410,\n \"sapkernel\": 753,\n \"system\": \"PRD\"\n }\n];\n```\n\n \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 will then attempt to resolve those hostnames to confirm that they are resolvable and afterwards it will attempt a ping\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\n```\n\nExample output (in Rhai):\n\n```ts\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 \"NWP\": [\n #{\n \"addresses\": [\n \"2.1.1.82\"\n ],\n \"hostname\": \"sapnwpas\",\n \"instance_name\": \"ASCS00\",\n \"reachability\": true\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 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 it will attempt a ping\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\n```\n\nExample output (in Rhai):\n\n```ts\n\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","title":"sapinstance_hostname_resolver - Gatherers","type":"extras"},{"doc":"**Argument required**: no.\n\nThis gatherer allows access to the latest SAP profile files content stored in `/sapmnt/ /profile`.\nThe \"latest\" profile means that backed up files like `DEFAULT.1.PFL` or `some_profile.1` are excluded.\nIt returns the profile files and content grouped by SID in a key\\value way.\n\nExample specification:\n\n```yaml\nfacts:\n - name: sap_profiles\n gatherer: sap_profiles\n```\n\nExample output (in Rhai):\n\n```ts\n#{\n \"NWP\": #{\n \"profiles\": [\n #{\n \"content\": #{\n \"SAPDBHOST\": \"10.80.1.13\",\n \"SAPGLOBALHOST\": \"sapnwpas\",\n \"SAPSYSTEMNAME\": \"NWP\",\n ...\n },\n \"name\": \"DEFAULT.PFL\",\n \"path\": \"/sapmnt/NWP/profile/DEFAULT.PFL\"\n },\n #{\n \"content\": #{\n \"DIR_CT_RUN\": \"$(DIR_EXE_ROOT)$(DIR_SEP)$(OS_UNICODE)$(DIR_SEP)linuxx86_64\",\n \"DIR_EXECUTABLE\": \"$(DIR_INSTANCE)/exe\",\n \"DIR_PROFILE\": \"$(DIR_INSTALL)$(DIR_SEP)profile\",\n ...\n },\n \"name\": \"NWP_ASCS00_sapnwpas\",\n \"path\": \"/sapmnt/NWP/profile/NWP_ASCS00_sapnwpas\"\n },\n ...\n ]\n },\n \"NWD\": #{\n \"profiles\": [\n #{\n \"content\": #{\n \"SAPDBHOST\": \"10.85.1.13\",\n \"SAPGLOBALHOST\": \"sapnwdas\",\n \"SAPSYSTEMNAME\": \"NWD\",\n ...\n },\n \"name\": \"DEFAULT.PFL\",\n \"path\": \"/sapmnt/NWD/profile/DEFAULT.PFL\"\n },\n ...\n ]\n }\n}\n```\n\n \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\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\n argument: SBD_PACEMAKER\n\n - name: sbd_startmode\n gatherer: sbd_config\n argument: SBD_STARTMODE\n\n - name: sbd_device\n gatherer: sbd_config\n argument: SBD_DEVICE\n```\n\nExample output (in Rhai):\n\n```ts\n// sbd_pacemaker\n\"yes\";\n\n// sbd_startmode\n\"always\";\n\n// sbd_device\n\"/dev/vdc;/dev/vdb\";\n```\n\n \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\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\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\n argument: sbd\n\n - name: corosync_state\n gatherer: systemd\n argument: corosync\n```\n\nExample output (in Rhai):\n\n```ts\n// sbd_state\n\"active\";\n\n// corosync_state\n\"inactive\";\n```\n\n \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\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 f35c83f1..fc54beda 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)

@@ -307,150 +307,87 @@

"owner": "trento", "group": "trento" }, - ]adm` user. The fields for -each system are returned in a map using the SAP sid as key. - -If the `disp+work` command execution fails, the fields are returned with an empty string value. - -The available fields are `compilation_mode`, `kernel_release` and `patch_number`. - -Example specification: - -```yaml -facts: + ]

+ + + + disp+work@v1 +

+

Argument required: No

This gatherer allows access to the disp+work command output and returns some fields available there. +The command is executed for all installed SAP systems, accessing it with the <sid>adm user. The fields for +each system are returned in a map using the SAP sid as key.

If the disp+work command execution fails, the fields are returned with an empty string value.

The available fields are compilation_mode, kernel_release and patch_number.

Example specification:

facts:
   - name: dispwork
-    gatherer: disp+work
-```
-
-Example output (in Rhai):
-
-```ts
-#{
-  "NWP": #{
-    "compilation_mode": "UNICODE",
-    "kernel_release": "753",
-    "patch_number": "900"
+    gatherer: disp+work

Example output (in Rhai):

#{
+  "NWP": #{
+    "compilation_mode": "UNICODE",
+    "kernel_release": "753",
+    "patch_number": "900"
   },
   // failed execution
-  "NWQ": #{
-    "compilation_mode": "",
-    "kernel_release": "",
-    "patch_number": ""
+  "NWQ": #{
+    "compilation_mode": "",
+    "kernel_release": "",
+    "patch_number": ""
   },
-  "NWD": #{
-    "compilation_mode": "UNICODE",
-    "kernel_release": "753",
-    "patch_number": "910"
+  "NWD": #{
+    "compilation_mode": "UNICODE",
+    "kernel_release": "753",
+    "patch_number": "910"
   }
-} 
-```
-
-
-
-### fstab@v1
-
-**Argument required**: no.
-
-This gatherer allows access to the /etc/fstab file, returning all entries available at the file.
-
-Example specification:
-
-```yaml
-facts:
+} 

+ + + + fstab@v1 +

+

Argument required: no.

This gatherer allows access to the /etc/fstab file, returning all entries available at the file.

Example specification:

facts:
   - name: fstab
-    gatherer: fstab
-```
-
-Example output (in Rhai):
-
-```ts
-[
+    gatherer: fstab

Example output (in Rhai):

[
     #{
-        "device": "/dev/system/root",
-        "mount_point": "/",
-        "file_system_type": "btrfs",
-        "options": [],
-        "backup": 0,
-        "check_order": 1,
+        "device": "/dev/system/root",
+        "mount_point": "/",
+        "file_system_type": "btrfs",
+        "options": [],
+        "backup": 0,
+        "check_order": 1,
     },
     #{
-        "device": "/dev/system/root",
-        "mount_point": "/home",
-        "file_system_type": "ext4",
-        "options": ["defaults"],
-        "backup": 0,
-        "check_order": 1,
+        "device": "/dev/system/root",
+        "mount_point": "/home",
+        "file_system_type": "ext4",
+        "options": ["defaults"],
+        "backup": 0,
+        "check_order": 1,
     },
   ...
-];
-```
-
-
-
-### groups@v1
-
-**Argument required**: no.
-
-This gatherer allows access to the /etc/group file, returning all entries available at the file.
-
-Example specification:
-
-```yaml
-facts:
+];

+ + + + groups@v1 +

+

Argument required: no.

This gatherer allows access to the /etc/group file, returning all entries available at the file.

Example specification:

facts:
   - name: groups
-    gatherer: groups
-```
-
-Example output (in Rhai):
-
-```ts
-[
+    gatherer: groups

Example output (in Rhai):

[
     #{
-        "name": "root",
-        "gid": 0,
-        "users": [],
+        "name": "root",
+        "gid": 0,
+        "users": [],
     },
     #{
-        "name": "adm",
-        "gid": 1,
-        "users": ["trento"],
+        "name": "adm",
+        "gid": 1,
+        "users": ["trento"],
     }
   ...
-];
-```
-
-
-
-### hosts@v1
-
-**Argument required**: no.
-
-This gatherer allows accessing the hostnames that are resolvable through `/etc/hosts`. It
-does **not** use domain resolution in any way but instead directly parses the file.
-
-It allows one argument to be specified or none at all:
-
-- When a hostname is provided as an argument, the gatherer will return an array of IPv4 and/or IPv6 addresses.
-- When no argument is provided, the gatherer will return a map with hostname as keys and arrays with IPv4 and/or IPv6 addresses.
-
-Example arguments:
-
-| Name                   | Return value                        |
-| :--------------------- | :---------------------------------- |
-| `localhost`            | list of IPs resolving               |
-| `node1`                | list of IPs resolving               |
-| `no argument provided` | map with hostnames and IP addresses |
-
-Example specification:
-
-```yaml
-facts:
+];

+ + + + hosts@v1 +

+

Argument required: no.

This gatherer allows accessing the hostnames that are resolvable through /etc/hosts. It +does not use domain resolution in any way but instead directly parses the file.

It allows one argument to be specified or none at all:

  • When a hostname is provided as an argument, the gatherer will return an array of IPv4 and/or IPv6 addresses.
  • When no argument is provided, the gatherer will return a map with hostname as keys and arrays with IPv4 and/or IPv6 addresses.

Example arguments:

NameReturn value
localhostlist of IPs resolving
node1list of IPs resolving
no argument providedmap with hostnames and IP addresses

Example specification:

facts:
   - name: hosts_node1
     gatherer: hosts
     argument: node1
@@ -460,64 +397,27 @@ 

argument: node2 - name: hosts_all - gatherer: hosts -``` - -Example output (in Rhai): - -```ts -// hosts_node1 -["127.0.0.1", "::1"]; + gatherer: hosts

Example output (in Rhai):

// hosts_node1
+["127.0.0.1", "::1"];
 
 // hosts_node2
-["192.168.157.11"];
+["192.168.157.11"];
 
 // hosts_all
 #{
-  "localhost": ["127.0.0.1", "::1"],
-  "node1": ["192.168.157.10"],
-  "node2": ["192.168.157.11"],
+  "localhost": ["127.0.0.1", "::1"],
+  "node1": ["192.168.157.10"],
+  "node2": ["192.168.157.11"],
   ...
-};
-```
-
-
-
-### package_version@v1
-
-**Argument required**: yes.
-
-This gatherer supports two usecases:
-
-- get information about the installed versions of the specified package.
-- compare a given version string against the latest installed version of a given package.
-
-In the first usecase a list of objects is returned, where each object carries relevant information about an installed version of a package.
-
-> Note:
->
-> - a list of one element is often expected since usually the installed version would be only one
-> - detected installed versions list is ordered by descending installation time: **latest installed versions come first**
-> - operating on the latest installed version requires accessing the first element in the list via `package_fact_name[0]` or `package_fact_name.first()`
-
-In the second usecase, the return value is as follows (see additional details [here](https://fedoraproject.org/wiki/Archive:Tools/RPM/VersionComparison#The_rpmvercmp_algorithm)):
-
-- A value of `0` if the provided version string matches the installed package version for the requested package.
-- A value of `-1` if the provided version string is older that what's currently installed.
-- A value of `1` if the provided version string is newer than what's currently installed.
-
-> The latest detected installed version is used for comparison
-
-Naming the facts / expectations accordingly is specially important here to avoid confusion.
-
-- We suggest using a `compare_` prefix for package version comparisons and `package_` to retrieve
-  a package version
-
-Additionally, when using the version comparison, it increases readability to explicitly mention
-the values to compare against:
-
-```yaml
-facts:
+};

+ + + + package_version@v1 +

+

Argument required: yes.

This gatherer supports two usecases:

  • get information about the installed versions of the specified package.
  • compare a given version string against the latest installed version of a given package.

In the first usecase a list of objects is returned, where each object carries relevant information about an installed version of a package.

Note:

  • a list of one element is often expected since usually the installed version would be only one
  • detected installed versions list is ordered by descending installation time: latest installed versions come first
  • operating on the latest installed version requires accessing the first element in the list via package_fact_name[0] or package_fact_name.first()

In the second usecase, the return value is as follows (see additional details here):

  • A value of 0 if the provided version string matches the installed package version for the requested package.
  • A value of -1 if the provided version string is older that what's currently installed.
  • A value of 1 if the provided version string is newer than what's currently installed.

The latest detected installed version is used for comparison

Naming the facts / expectations accordingly is specially important here to avoid confusion.

  • We suggest using a compare_ prefix for package version comparisons and package_ to retrieve +a package version

Additionally, when using the version comparison, it increases readability to explicitly mention +the values to compare against:

facts:
   - name: compare_package_corosync
     gatherer: package_version
     argument: corosync,2.4.5
@@ -538,7 +438,7 @@ 

- name: same_as_installed default: 0 - name: expected_corosync_version - default: "2.4.5" + default: "2.4.5" expectations: - name: compare_package_corosync @@ -548,20 +448,7 @@

expect: facts.package_corosync.first().version == values.expected_corosync_version - name: sbd_version_same_on_all_hosts - expect_same: facts.package_sbd.first().version -``` - -Example arguments: - -| Name | Return value | -| :------------------- | :---------------------------------------------------------------------------- | -| `package_name` | a list containing information about the installed versions of the rpm package | -| `package_name,2.4.5` | an integer with a value of `-1`, `0` or `1` (see above) | - -Example specification: - -```yaml -facts: + expect_same: facts.package_sbd.first().version

Example arguments:

NameReturn value
package_namea list containing information about the installed versions of the rpm package
package_name,2.4.5an integer with a value of -1, 0 or 1 (see above)

Example specification:

facts:
   - name: package_corosync
     gatherer: package_version
     argument: corosync
@@ -578,137 +465,93 @@ 

gatherer: package_version argument: corosync,2.4.5 - ... -``` - -Example output (in Rhai): - -```ts -// package_corosync + ...

Example output (in Rhai):

// package_corosync
 [
   #{
-    "version": "2.4.5"
+    "version": "2.4.5"
   }
 ]
 
 // package_pacemaker
 [
   #{
-    "version": "2.0.4+20200616.2deceaa3a"
+    "version": "2.0.4+20200616.2deceaa3a"
   }
 ]
 
 // multiple_sbd_versions_installed
 [
   #{
-    "version": "1.5.1" // latest installed version, not necessarily the newest one
+    "version": "1.5.1" // latest installed version, not necessarily the newest one
   },
   #{
-    "version": "1.5.2"
+    "version": "1.5.2"
   }
 ]
 
 // compare_package_corosync
-0
-```
-
-
-
-### passwd@v1
-
-**Argument required**: no.
-
-This gatherer allows access to the /etc/passwd file, returning all entries available at the file.
-
-Example specification:
-
-```yaml
-facts:
+0

+ + + + passwd@v1 +

+

Argument required: no.

This gatherer allows access to the /etc/passwd file, returning all entries available at the file.

Example specification:

facts:
   - name: passwd
-    gatherer: passwd
-```
-
-Example output (in Rhai):
-
-```ts
-[
+    gatherer: passwd

Example output (in Rhai):

[
     #{
-        "description": "bin",
-        "gid": 1,
-        "home": "/bin",
-        "shell": "/sbin/nologin",
-        "uid": 1,
-        "user": "bin"
+        "description": "bin",
+        "gid": 1,
+        "home": "/bin",
+        "shell": "/sbin/nologin",
+        "uid": 1,
+        "user": "bin"
     },
     #{
-        "description": "Chrony Daemon",
-        "gid": 475,
-        "home": "/var/lib/chrony",
-        "shell": "/bin/false",
-        "uid": 474,
-        "user": "chrony"
+        "description": "Chrony Daemon",
+        "gid": 475,
+        "home": "/var/lib/chrony",
+        "shell": "/bin/false",
+        "uid": 474,
+        "user": "chrony"
     },
     #{
-        "description": "Daemon",
-        "gid": 2,
-        "home": "/sbin",
-        "shell": "/sbin/nologin",
-        "uid": 2,
-        "user": "daemon"
+        "description": "Daemon",
+        "gid": 2,
+        "home": "/sbin",
+        "shell": "/sbin/nologin",
+        "uid": 2,
+        "user": "daemon"
     },
   ...
-];
-```
-
-
-
-### sapcontrol@v1
-
-**Argument required**: yes.
-
-This gatherer allows access to certain webmethods that `sapcontrol` implements. An argument is required to specify which webmethod should be called. The communication with `sapcontrol` is created opening a unix socket connection using the file `/tmp/.sapstream5xx13`. The [Sapcontrol Web Service Interface](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.
-
-The return value is grouped by discovered SIDs, which include the list of command outputs for each instance in this system.
-
-Supported webmethods:
-
-- `GetProcessList`
-- `GetSystemInstanceList`
-- `GetVersionInfo`
-- `HACheckConfig`
-- `HAGetFailoverConfig`
-
-Example specification:
-
-```yaml
-facts:
+];

+ + + + sapcontrol@v1 +

+

Argument required: yes.

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

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

Supported webmethods:

  • GetProcessList
  • GetSystemInstanceList
  • GetVersionInfo
  • HACheckConfig
  • HAGetFailoverConfig

Example specification:

facts:
   - name: processes
     gatherer: sapcontrol
     argument: GetProcessList
 
   - name: instances
     gatherer: sapcontrol
-    argument: GetSystemInstanceList
-```
-
-Example output (in Rhai):
-
-```ts
-// GetProcessList
+    argument: GetSystemInstanceList

Example output (in Rhai):

// GetProcessList
 #{
-  "NWP": [
+  "NWP": [
     #{
-      "instance_nr": "10",
-      "name": "ERS10",
-      "output": [
+      "instance_nr": "10",
+      "name": "ERS10",
+      "output": [
         #{
-          "description": "EnqueueReplicator",
-          "dispstatus": "SAPControl-GREEN",
-          "elapsedtime": "266:08:15",
-          "name": "enrepserver",
-          "pid": 7221,
-          "starttime": "2023 09 29 09:41:41",
-          "textstatus": "Running"
+          "description": "EnqueueReplicator",
+          "dispstatus": "SAPControl-GREEN",
+          "elapsedtime": "266:08:15",
+          "name": "enrepserver",
+          "pid": 7221,
+          "starttime": "2023 09 29 09:41:41",
+          "textstatus": "Running"
         }
       ]
     }
@@ -717,28 +560,28 @@ 

// GetSystemInstanceList #{ - "NWP": [ + "NWP": [ #{ - "instance_nr": "10", - "name": "ERS10", - "output": [ + "instance_nr": "10", + "name": "ERS10", + "output": [ #{ - "dispstatus": "SAPControl-GREEN", - "features": "MESSAGESERVER|ENQUE", - "hostname": "sapnwpas", - "http_port": 50013, - "https_port": 50014, - "instance_nr": 0, - "start_priority": "1" + "dispstatus": "SAPControl-GREEN", + "features": "MESSAGESERVER|ENQUE", + "hostname": "sapnwpas", + "http_port": 50013, + "https_port": 50014, + "instance_nr": 0, + "start_priority": "1" }, #{ - "dispstatus": "SAPControl-GREEN", - "features": "ENQREP", - "hostname": "sapnwper", - "http_port": 51013, - "https_port": 51014, - "instance_nr": 10, - "start_priority": "0.5" + "dispstatus": "SAPControl-GREEN", + "features": "ENQREP", + "hostname": "sapnwper", + "http_port": 51013, + "https_port": 51014, + "instance_nr": 10, + "start_priority": "0.5" }, ... ] @@ -748,30 +591,30 @@

// GetVersionInfo #{ - "NWP": [ + "NWP": [ #{ - "instance_nr": "10", - "name": "ERS10", - "output": [ + "instance_nr": "10", + "name": "ERS10", + "output": [ #{ - "architecture": "linuxx86_64", - "build": "optU (Oct 16 2021, 00:03:15)", - "changelist": "2094654", - "filename": "/usr/sap/NWP/ERS10/exe/sapstartsrv", - "patch": "900", - "rks_compatibility_level": "1", - "sap_kernel": "753", - "time": "2021 10 15 22:14:31" + "architecture": "linuxx86_64", + "build": "optU (Oct 16 2021, 00:03:15)", + "changelist": "2094654", + "filename": "/usr/sap/NWP/ERS10/exe/sapstartsrv", + "patch": "900", + "rks_compatibility_level": "1", + "sap_kernel": "753", + "time": "2021 10 15 22:14:31" }, #{ - "architecture": "linuxx86_64", - "build": "optU (Oct 16 2021, 00:03:15)", - "changelist": "2094654", - "filename": "/usr/sap/NWP/ERS10/exe/gwrd", - "patch": "900", - "rks_compatibility_level": "1", - "sap_kernel": "753", - "time": "2021 10 15 22:04:14" + "architecture": "linuxx86_64", + "build": "optU (Oct 16 2021, 00:03:15)", + "changelist": "2094654", + "filename": "/usr/sap/NWP/ERS10/exe/gwrd", + "patch": "900", + "rks_compatibility_level": "1", + "sap_kernel": "753", + "time": "2021 10 15 22:04:14" }, ... ] @@ -781,22 +624,22 @@

// HACheckConfig #{ - "NWP": [ + "NWP": [ #{ - "instance_nr": "10", - "name": "ERS10", - "output": [ + "instance_nr": "10", + "name": "ERS10", + "output": [ #{ - "category": "SAPControl-SAP-CONFIGURATION", - "comment": "2 ABAP instances detected", - "description": "Redundant ABAP instance configuration", - "state": "SAPControl-HA-SUCCESS" + "category": "SAPControl-SAP-CONFIGURATION", + "comment": "2 ABAP instances detected", + "description": "Redundant ABAP instance configuration", + "state": "SAPControl-HA-SUCCESS" }, #{ - "category": "SAPControl-SAP-CONFIGURATION", - "comment": "0 Java instances detected", - "description": "Redundant Java instance configuration", - "state": "SAPControl-HA-SUCCESS" + "category": "SAPControl-SAP-CONFIGURATION", + "comment": "0 Java instances detected", + "description": "Redundant Java instance configuration", + "state": "SAPControl-HA-SUCCESS" }, ... ] @@ -806,345 +649,242 @@

//HAGetFailoverConfig #{ - "NWP": [ + "NWP": [ #{ - "instance_nr": "10", - "name": "ERS10", - "output": #{ - "ha_active": false, - "ha_active_nodes": "", - "ha_documentation": "", - "ha_nodes": [], - "ha_product_version": "", - "ha_sap_interface_version": "" + "instance_nr": "10", + "name": "ERS10", + "output": #{ + "ha_active": false, + "ha_active_nodes": "", + "ha_documentation": "", + "ha_nodes": [], + "ha_product_version": "", + "ha_sap_interface_version": "" } } ] } - -``` - - - -### saphostctrl@v1 - -**Argument required**: yes. - -This gatherer allows access to certain webmethods that `saphostctrl` implements. An argument is required to specify -which webmethod should be called. This webmethod is passed to the `saphostctrl` command-line tool through the `-function` argument. - -Supported webmethods: - -- `Ping` -- `ListInstances` - -A `Ping` call with a successful return should look like this: - -Example specification: - -```yaml -facts: +

+ + + + saphostctrl@v1 +

+

Argument required: yes.

This gatherer allows access to certain webmethods that saphostctrl implements. An argument is required to specify +which webmethod should be called. This webmethod is passed to the saphostctrl command-line tool through the -function argument.

Supported webmethods:

  • Ping
  • ListInstances

A Ping call with a successful return should look like this:

Example specification:

facts:
   - name: ping
     gatherer: saphostctrl
     argument: Ping
 
   - name: list_instances
     gatherer: saphostctrl
-    argument: ListInstances
-```
-
-Example output (in Rhai):
-
-```ts
-// ping
-#{elapsed: 579770.0, status: "SUCCESS"}
+    argument: ListInstances

Example output (in Rhai):

// ping
+#{elapsed: 579770.0, status: "SUCCESS"}
 
 // list_instances
 [
     #{
-        "changelist": 1908545,
-        "hostname": "vmhana01",
-        "instance": "00",
-        "patch": 410,
-        "sapkernel": 753,
-        "system": "PRD"
+        "changelist": 1908545,
+        "hostname": "vmhana01",
+        "instance": "00",
+        "patch": 410,
+        "sapkernel": 753,
+        "system": "PRD"
     }
-];
-```
-
-
-
-### sapinstance_hostname_resolver@v1
-
-**Argument required**: no.
-
-This gatherer uses the filesystem to search for sap systems using the discovered profile file names to get the virtual hostnames associated to each
+];

+ + + + sapinstance_hostname_resolver@v1 +

+

Argument required: no.

This gatherer uses the filesystem to search for sap systems using the discovered profile file names to get the virtual hostnames associated to each instance of the sap system. It will then attempt to resolve those hostnames to confirm that they are resolvable and afterwards it will attempt a ping to 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 -not true. - -Example specification: - -```yaml -facts: +not true.

Example specification:

facts:
   - name: resolvability_check
-    gatherer: sapinstance_hostname_resolver
-```
-
-Example output (in Rhai):
-
-```ts
-#{
-  "QAS": [
+    gatherer: sapinstance_hostname_resolver

Example output (in Rhai):

#{
+  "QAS": [
     #{
-      "addresses": [
-        "1.1.1.82"
+      "addresses": [
+        "1.1.1.82"
       ],
-      "hostname": "sapqasas",
-      "instance_name": "ASCS00",
-      "reachability": true
+      "hostname": "sapqasas",
+      "instance_name": "ASCS00",
+      "reachability": true
     },
     #{
-      "addresses": (),
-      "hostname": "sapwaser",
-      "instance_name": "ERS00",
-      "reachability": false
+      "addresses": (),
+      "hostname": "sapwaser",
+      "instance_name": "ERS00",
+      "reachability": false
     }
   ],
-  "NWP": [
+  "NWP": [
     #{
-      "addresses": [
-        "2.1.1.82"
+      "addresses": [
+        "2.1.1.82"
       ],
-      "hostname": "sapnwpas",
-      "instance_name": "ASCS00",
-      "reachability": true
+      "hostname": "sapnwpas",
+      "instance_name": "ASCS00",
+      "reachability": true
     }
   ]
-}
-```
-
-### sapinstance_hostname_resolver
-
-**Argument required**: no.
-
-This gatherer uses the filesystem to search for SAP systems using the discovered profile file names to get the virtual hostnames associated to each
+}

+ + + + sapinstance_hostname_resolver +

+

Argument required: no.

This gatherer uses the filesystem to search for SAP systems using the discovered profile file names to get the virtual hostnames associated to each instance of the sap system. It then attempts to resolve those hostnames to confirm that they are resolvable and afterwards it will attempt a ping to 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 -not true. - -Example specification: - -```yaml -facts: +not true.

Example specification:

facts:
   - name: resolvability_check
-    gatherer: sapinstance_hostname_resolver
-```
-
-Example output (in Rhai):
-
-```ts
-
-// 2 resolvable & 1 non-resolvable hosts
+    gatherer: sapinstance_hostname_resolver

Example output (in Rhai):


+// 2 resolvable & 1 non-resolvable hosts
 #{
-  "NWP": [
+  "NWP": [
     #{
-      "addresses": [
-        "2.1.1.82"
+      "addresses": [
+        "2.1.1.82"
       ],
-      "hostname": "sapnwpas",
-      "instance_name": "ASCS00",
-      "reachability": true
+      "hostname": "sapnwpas",
+      "instance_name": "ASCS00",
+      "reachability": true
     }
   ],
-  "QAS": [
+  "QAS": [
     #{
-      "addresses": [
-        "1.1.1.82"
+      "addresses": [
+        "1.1.1.82"
       ],
-      "hostname": "sapqasas",
-      "instance_name": "ASCS00",
-      "reachability": true
+      "hostname": "sapqasas",
+      "instance_name": "ASCS00",
+      "reachability": true
     },
     #{
-      "addresses": (),
-      "hostname": "sapwaser",
-      "instance_name": "ERS00",
-      "reachability": false
+      "addresses": (),
+      "hostname": "sapwaser",
+      "instance_name": "ERS00",
+      "reachability": false
     }
   ]
-}
-```
-
-
-
-### sap_profiles@v1
-
-**Argument required**: no.
-
-This gatherer allows access to the latest SAP profile files content stored in `/sapmnt//profile`.
-The "latest" profile means that backed up files like `DEFAULT.1.PFL` or `some_profile.1` are excluded.
-It returns the profile files and content grouped by SID in a key\value way.
-
-Example specification:
-
-```yaml
-facts:
+}

+ + + + sap_profiles@v1 +

+

Argument required: no.

This gatherer allows access to the latest SAP profile files content stored in /sapmnt/<SID>/profile. +The "latest" profile means that backed up files like DEFAULT.1.PFL or some_profile.1 are excluded. +It returns the profile files and content grouped by SID in a key\value way.

Example specification:

facts:
   - name: sap_profiles
-    gatherer: sap_profiles
-```
-
-Example output (in Rhai):
-
-```ts
-#{
-  "NWP": #{
-    "profiles": [
+    gatherer: sap_profiles

Example output (in Rhai):

#{
+  "NWP": #{
+    "profiles": [
       #{
-        "content": #{
-          "SAPDBHOST": "10.80.1.13",
-          "SAPGLOBALHOST": "sapnwpas",
-          "SAPSYSTEMNAME": "NWP",
+        "content": #{
+          "SAPDBHOST": "10.80.1.13",
+          "SAPGLOBALHOST": "sapnwpas",
+          "SAPSYSTEMNAME": "NWP",
           ...
         },
-        "name": "DEFAULT.PFL",
-        "path": "/sapmnt/NWP/profile/DEFAULT.PFL"
+        "name": "DEFAULT.PFL",
+        "path": "/sapmnt/NWP/profile/DEFAULT.PFL"
       },
       #{
-        "content": #{
-          "DIR_CT_RUN": "$(DIR_EXE_ROOT)$(DIR_SEP)$(OS_UNICODE)$(DIR_SEP)linuxx86_64",
-          "DIR_EXECUTABLE": "$(DIR_INSTANCE)/exe",
-          "DIR_PROFILE": "$(DIR_INSTALL)$(DIR_SEP)profile",
+        "content": #{
+          "DIR_CT_RUN": "$(DIR_EXE_ROOT)$(DIR_SEP)$(OS_UNICODE)$(DIR_SEP)linuxx86_64",
+          "DIR_EXECUTABLE": "$(DIR_INSTANCE)/exe",
+          "DIR_PROFILE": "$(DIR_INSTALL)$(DIR_SEP)profile",
           ...
         },
-        "name": "NWP_ASCS00_sapnwpas",
-        "path": "/sapmnt/NWP/profile/NWP_ASCS00_sapnwpas"
+        "name": "NWP_ASCS00_sapnwpas",
+        "path": "/sapmnt/NWP/profile/NWP_ASCS00_sapnwpas"
       },
       ...
     ]
   },
-  "NWD": #{
-    "profiles": [
+  "NWD": #{
+    "profiles": [
       #{
-        "content": #{
-          "SAPDBHOST": "10.85.1.13",
-          "SAPGLOBALHOST": "sapnwdas",
-          "SAPSYSTEMNAME": "NWD",
+        "content": #{
+          "SAPDBHOST": "10.85.1.13",
+          "SAPGLOBALHOST": "sapnwdas",
+          "SAPSYSTEMNAME": "NWD",
           ...
         },
-        "name": "DEFAULT.PFL",
-        "path": "/sapmnt/NWD/profile/DEFAULT.PFL"
+        "name": "DEFAULT.PFL",
+        "path": "/sapmnt/NWD/profile/DEFAULT.PFL"
       },
       ...
     ]
   }
-}
-```
-
-
-
-### saptune@v1
-
-**Argument required**: yes.
-
-This gatherer allows access to certain commands that `saptune` implements. An argument is required to specify
-which argument should be used when calling `saptune`.
-
-> Note: the gatherer will return the same JSON objects returned by saptune. The only transformation it applies is the snake casing of the keys.
-
-Supported arguments:
-
-- `status` (maps to `saptune --format json status --non-compliance-check`)
-- `solution-verify` (maps to `saptune --format json solution verify`)
-- `solution-list` (maps to `saptune --format json solution list`)
-- `note-verify` (maps to `saptune --format json note verify`)
-- `note-list` (maps to `saptune --format json note list`)
-
-A `status` call with a successful return should look like this:
-
-Example specification:
-
-```yaml
-facts:
+}

+ + + + saptune@v1 +

+

Argument required: yes.

This gatherer allows access to certain commands that saptune implements. An argument is required to specify +which argument should be used when calling saptune.

Note: the gatherer will return the same JSON objects returned by saptune. The only transformation it applies is the snake casing of the keys.

Supported arguments:

  • status (maps to saptune --format json status --non-compliance-check)
  • solution-verify (maps to saptune --format json solution verify)
  • solution-list (maps to saptune --format json solution list)
  • note-verify (maps to saptune --format json note verify)
  • note-list (maps to saptune --format json note list)

A status call with a successful return should look like this:

Example specification:

facts:
   - name: status
     gatherer: saptune
-    argument: status
-```
-
-Example output (in Rhai):
-
-```ts
-// status
+    argument: status

Example output (in Rhai):

// status
 #{
-  "$schema": "file:///usr/share/saptune/schemas/1.0/saptune_status.schema.json",
-  "argv": "saptune --format json status",
-  "command": "status",
-  "exit_code": 1,
-  "messages": [
+  "$schema": "file:///usr/share/saptune/schemas/1.0/saptune_status.schema.json",
+  "argv": "saptune --format json status",
+  "command": "status",
+  "exit_code": 1,
+  "messages": [
     #{
-      "message": "actions.go:85: ATTENTION: You are running a test version",
-      "priority": "NOTICE"
+      "message": "actions.go:85: ATTENTION: You are running a test version",
+      "priority": "NOTICE"
     }
   ],
-  "pid": 6593,
-  "publish_time": "2023-09-15 15:15:14.599",
-  "result": #{
-    "configured_version": "3",
-    "notes_applied": [
-      "1410736"
+  "pid": 6593,
+  "publish_time": "2023-09-15 15:15:14.599",
+  "result": #{
+    "configured_version": "3",
+    "notes_applied": [
+      "1410736"
     ],
-    "notes_applied_by_solution": [],
-    "notes_enabled": [
-      "1410736"
+    "notes_applied_by_solution": [],
+    "notes_enabled": [
+      "1410736"
     ],
-    "notes_enabled_additionally": [
-      "1410736"
+    "notes_enabled_additionally": [
+      "1410736"
     ],
-    "notes_enabled_by_solution": [],
-    "package_version": "3.1.0",
-    "remember_message": "This is a reminder",
-    "services": #{
-      "sapconf": [],
-      "saptune": [
-        "disabled",
-        "inactive"
+    "notes_enabled_by_solution": [],
+    "package_version": "3.1.0",
+    "remember_message": "This is a reminder",
+    "services": #{
+      "sapconf": [],
+      "saptune": [
+        "disabled",
+        "inactive"
       ],
-      "tuned": []
+      "tuned": []
     },
-    "solution_applied": [],
-    "solution_enabled": [],
-    "staging": #{
-      "notes_staged": [],
-      "solutions_staged": [],
-      "staging_enabled": false
+    "solution_applied": [],
+    "solution_enabled": [],
+    "staging": #{
+      "notes_staged": [],
+      "solutions_staged": [],
+      "staging_enabled": false
     },
-    "systemd_system_state": "degraded",
-    "tuning_state": "compliant",
-    "virtualization": "kvm"
+    "systemd_system_state": "degraded",
+    "tuning_state": "compliant",
+    "virtualization": "kvm"
   }
-}
-```
-
-
-
-### sbd_config@v1
-
-**Argument required**: yes.
-
-This gatherer allows accessing the information contained in `/etc/sysconfig/sbd`
-
-Example arguments:
-
-| Name            | Return value                    |
-| :-------------- | :------------------------------ |
-| `SBD_PACEMAKER` | extracted value from the config |
-| `SBD_STARTMODE` | extracted value from the config |
-| `SBD_DEVICE`    | extracted value from the config |
-
-Example specification:
-
-```yaml
-facts:
+}

+ + + + sbd_config@v1 +

+

Argument required: yes.

This gatherer allows accessing the information contained in /etc/sysconfig/sbd

Example arguments:

NameReturn value
SBD_PACEMAKERextracted value from the config
SBD_STARTMODEextracted value from the config
SBD_DEVICEextracted value from the config

Example specification:

facts:
   - name: sbd_pacemaker
     gatherer: sbd_config
     argument: SBD_PACEMAKER
@@ -1155,53 +895,24 @@ 

- name: sbd_device gatherer: sbd_config - argument: SBD_DEVICE -``` - -Example output (in Rhai): - -```ts -// sbd_pacemaker -"yes"; + argument: SBD_DEVICE

Example output (in Rhai):

// sbd_pacemaker
+"yes";
 
 // sbd_startmode
-"always";
+"always";
 
 // sbd_device
-"/dev/vdc;/dev/vdb";
-```
-
-
-
-### sbd_dump@v1
-
-**Argument required**: no.
-
-This gatherer allows accessing the sbd dump command output data.
-
-It 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.
-
-Note that:
-
-- no arguments are required
-- if any of the dumps fail, a fact error is returned
-
-Dumped keys (`Timeout (watchdog)`, `Timeout (msgwait)`, `Number of slots`, etc) are sanitized to simplify their access and usage in the expression language.
-
-Example specification:
-
-```yaml
-facts:
+"/dev/vdc;/dev/vdb";

+ + + + sbd_dump@v1 +

+

Argument required: no.

This gatherer allows accessing the sbd dump command output data.

It executes the sbd -d <device> dump command in all devices configured in the SBD_DEVICE field on /etc/sysconfig/sbd and aggregates results in only one fact.

Note that:

  • no arguments are required
  • if any of the dumps fail, a fact error is returned

Dumped keys (Timeout (watchdog), Timeout (msgwait), Number of slots, etc) are sanitized to simplify their access and usage in the expression language.

Example specification:

facts:
   - name: sbd_devices_dump
-    gatherer: sbd_dump
-```
-
-Example output (in Rhai):
-
-```ts
-// sbd_devices_dump
+    gatherer: sbd_dump

Example output (in Rhai):

// sbd_devices_dump
 #{
-    "/dev/vdc": #{
+    "/dev/vdc": #{
         header_version: 2.1,
         number_of_slots: 255,
         sector_size: 512,
@@ -1209,178 +920,94 @@ 

timeout_loop: 1, timeout_msgwait: 10, timeout_watchdog: 5, - uuid: "69048391-c647-4b34-a03a-f704f5cc2258" + uuid: "69048391-c647-4b34-a03a-f704f5cc2258" } -}; -``` - -For 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) - - - -### sysctl@v1 - -**Argument required**: yes. - -Gather 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. - -Example arguments: - -| Name | Return value | -| :-------------- | :---------------------------------------------------- | -| `vm.swappiness` | corresponding value returned by sysctl | -| `debug` | a map containing all the keys starting with `debug.`` | - -```yaml -facts: +};

For extra information refer to trento-project/agent/../gatherers/sbddump_test.go

+ + + + sysctl@v1 +

+

Argument required: yes.

Gather 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.

Example arguments:

NameReturn value
vm.swappinesscorresponding value returned by sysctl
debuga map containing all the keys starting with `debug.``
facts:
   - name: vm_swappiness
     gatherer: sysctl
     argument: vm.swappiness
 
   - name: debug
     gatherer: sysctl
-    argument: debug
-```
-
-Example output (in Rhai):
-
-```ts
-// vm_swapiness
+    argument: debug

Example output (in Rhai):

// vm_swapiness
 60;
 
 // debug
 #{
-  "exception-trace": 1,
-  "kprobes-optimization": 1
-};
-```
-
-
-
-### systemd@v1
-
-**Argument required**: yes.
-
-Gather systemd units state. It returns an `active/inactive` string.
-If the service is disabled or it does not exist, `inactive` is returned.
-
-Example arguments:
-
-| Name           | Return value              |
-| :------------- | :------------------------ |
-| `trento-agent` | state of the systemd unit |
-
-```yaml
-facts:
+  "exception-trace": 1,
+  "kprobes-optimization": 1
+};

+ + + + systemd@v1 +

+

Argument required: yes.

Gather systemd units state. It returns an active/inactive string. +If the service is disabled or it does not exist, inactive is returned.

Example arguments:

NameReturn value
trento-agentstate of the systemd unit
facts:
   - name: sbd_state
     gatherer: systemd
     argument: sbd
 
   - name: corosync_state
     gatherer: systemd
-    argument: corosync
-```
-
-Example output (in Rhai):
-
-```ts
-// sbd_state
-"active";
+    argument: corosync

Example output (in Rhai):

// sbd_state
+"active";
 
 // corosync_state
-"inactive";
-```
-
-
-
-### systemd@v2
-
-**Argument required**: yes.
-
-Gather systemd units information. It returns an object with multiple fields about the systemd unit.
-
-The provided unit name must include the extension, such as `.service` or `.mount`.
-
-Only a subset of properties are returned. Additional information about these is available in
-the [systemd](https://www.man7.org/linux/man-pages/man5/org.freedesktop.systemd1.5.html#UNIT_OBJECTS) man pages,
-with some detailed description in the `Properties` sub-chapter.
-
-Example arguments:
-
-| Name                   | Return value             |
-| :--------------------- | :----------------------- |
-| `trento-agent.service` | systemd unit information |
-
-```yaml
-facts:
+"inactive";

+ + + + systemd@v2 +

+

Argument required: yes.

Gather systemd units information. It returns an object with multiple fields about the systemd unit.

The provided unit name must include the extension, such as .service or .mount.

Only a subset of properties are returned. Additional information about these is available in +the systemd man pages, +with some detailed description in the Properties sub-chapter.

Example arguments:

NameReturn value
trento-agent.servicesystemd unit information
facts:
   - name: corosync
     gatherer: systemd@v2
     argument: corosync.service
 
   - name: not_found
     gatherer: systemd@v2
-    argument: unknown.service
-```
-
-Example output (in Rhai):
-
-```ts
-// corosync
+    argument: unknown.service

Example output (in Rhai):

// corosync
 #{
-  "active_state": "inactive",
-  "description": "Corosync Cluster Engine",
-  "id": "corosync.service",
-  "load_state": "loaded",
-  "need_daemon_reload": false,
-  "unit_file_preset": "disabled",
-  "unit_file_state": "disabled"
+  "active_state": "inactive",
+  "description": "Corosync Cluster Engine",
+  "id": "corosync.service",
+  "load_state": "loaded",
+  "need_daemon_reload": false,
+  "unit_file_preset": "disabled",
+  "unit_file_state": "disabled"
 }
 
 // not_found
 #{
-  "active_state": "inactive",
-  "description": "unknown.service",
-  "id": "unknown.service",
-  "load_state": "not-found",
-  "need_daemon_reload": false,
-  "unit_file_preset": "",
-  "unit_file_state": ""
+  "active_state": "inactive",
+  "description": "unknown.service",
+  "id": "unknown.service",
+  "load_state": "not-found",
+  "need_daemon_reload": false,
+  "unit_file_preset": "",
+  "unit_file_state": ""
 }
-
-```
-
-
-
-### verify_password@v1
-
-**Argument required**: yes.
-
-This gatherer determines whether a given user has its password still set to an unsafe password.
-It returns `true` if the password matches a password in the list of unsafe passwords, `false` otherwise.
-
-Specification examples:
-
-```yaml
-facts:
+

+ + + + verify_password@v1 +

+

Argument required: yes.

This gatherer determines whether a given user has its password still set to an unsafe password. +It returns true if the password matches a password in the list of unsafe passwords, false otherwise.

Specification examples:

facts:
   - name: hacluster_has_default_password
     gatherer: verify_password
-    argument: hacluster
-```
-
-For the argument, only whitelisted users are allowed. Currently whitelisted usernames:
-
-- `hacluster`
-
-List of unsafe passwords:
-
-- `linux`
-
-Example output (in Rhai):
-
-```ts
-// hacluster_has_default_password
-true;
-```
+    argument: hacluster

For the argument, only whitelisted users are allowed. Currently whitelisted usernames:

  • hacluster

List of unsafe passwords:

  • linux

Example output (in Rhai):

// hacluster_has_default_password
+true;
diff --git a/hack_on_wanda.html b/hack_on_wanda.html index f784593e..fa97e388 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 54cef169..cb57e076 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 4b348dff..9e50c40c 100644 --- a/search.html +++ b/search.html @@ -120,7 +120,7 @@

- +