From f1200d967a172c6f16a720c28ed7b7cee672e75a Mon Sep 17 00:00:00 2001
From: "th.l" <thl-cmk@outlook.com>
Date: Fri, 17 Jan 2025 17:57:04 +0100
Subject: [PATCH] added suffix option

---
 README.md                                     |   2 +-
 mkp/vsphere_topo-0.0.9-20250116.mkp           | Bin 0 -> 8421 bytes
 .../vsphere_topo/agent_based/vsphere_topo.py  |  50 +++-----
 .../vsphere_topo/constants.py                 |  75 ++++++-----
 .../vsphere_topo/lib/utils.py                 |  56 +++-----
 .../vsphere_topo/rulesets/vsphere_topo.py     | 121 ++++++------------
 source/packages/vsphere_topo                  |   2 +-
 7 files changed, 124 insertions(+), 182 deletions(-)
 create mode 100644 mkp/vsphere_topo-0.0.9-20250116.mkp

diff --git a/README.md b/README.md
index 6f32402..14c416a 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[PACKAGE]: ../../raw/master/mkp/vsphere_topo-0.0.8-20240806.mkp "vsphere_topo-0.0.8-20240806.mkp"
+[PACKAGE]: ../../raw/master/mkp/vsphere_topo-0.0.9-20250116.mkp "vsphere_topo-0.0.9-20250116.mkp"
 # vSphere Topology Visualization
 
 This plugin uses the data from the _VMware ESX via vSphere_ special agent to create a topology of the vSphere environment.\
diff --git a/mkp/vsphere_topo-0.0.9-20250116.mkp b/mkp/vsphere_topo-0.0.9-20250116.mkp
new file mode 100644
index 0000000000000000000000000000000000000000..c585d371a7c5406a6320668caf6cbe21f85bad77
GIT binary patch
literal 8421
zcmbW+b3+`C!vOHKwCb{Le&aGO+qPYoZQEY%vW;cCrNyP?*3~kve$Q)o{`|a#4@Ckp
z%&&xaTewe%2-IV{yX8ec<jY^rXf2kd^!F^gqSu9v!Z8o;OIsoPrudmsshN{JYVF_+
zx1fu?5APdsI9j>sg~=V|@w_qW9zB?Z@hgj#ul~b4fj3D_7)HI@+ehq1<AePwU2kQ*
z{ariT=a-ic-uo|CS691V8}9xH8QB+XU}?Sl8NBmfh4A#C(DXN*>++q%)euc5?G?>|
zV!XLfSH=LN+od@4V0nJWi-zb*A&_ufpWmM-*lfXABOy0SwjQ^R-r1KVk{$!>1xc~K
zU^{zDA#XA^v?<3)6(?unC~kKj&zC1lWf!|B#gx;lv9_T30q+PY?%&UCUIaLOYhy77
z?%?hUW(K%jKlSvjfp2XLd?qjr2|Fmf{Gji}aMJq6qb!%>4-qHhTalj2OA~+~<zAuC
z=$^F7j!%hR9;zpq-&)`5pgHhc4uJr=lI<;JLWax7L#Fr83l!_ow;_P@qyi0vd_V^6
zUH4$mw9Hr^%Bj3v^wPsgN6z!3uZR1g3dpuA-^cqX%D!*9H|3szu&U^KBJ@H%<~AF`
z4}^2Ps#-S*O^NxTXR-1$k#GO!r9~iQ=#L_M&oe?QgLkTM8$Xdt0!QL%+NpVO@}&S8
z^g$PhR{@mbi&LzY`C9H~_S1;80s97rkoGlNIe~?jZE9O+-;y^<&}K4l=gJER<K5f)
z$I#>Ci_Xyp%LDbg_+n9ywfBTEiVa8=6y|#*g60w6E#$&re&$HlX6sG6$kRDF;8+2h
z$R*vSyvRn(zP286cpUb@7m_@>zrOOh<NVC__p^TovS9ETLI52UFJF}j0W+5K8jvt<
z{!60V*sm%1JUGs&`ONZ!&cs7C|Dk2|e-Dlh<|aZ7%0Bk`V9pqW(ZnBvD`5Nun~mZH
z3(Q<WFw2Kkb3`X+<6CpBMu>o$2}~1#J&XO;vJ~>0kpzbXdLUE57DiUbg&TkEP#;Qd
zmle-GqJ4gyv}AF!_uuC%jeVK$d+_bxHq9X2%O1oT0%|z^eClRCy<8^`5!~JBhlsrT
z*j|4z{kV31ID3Bb_BRZGS^pw)7WDIGy`A82^{$Y(+xj}BYJFDBsnV@o;4xg8uY2VL
zP+}6^FrnB0t?J}OA;WA6VpFb!=suU<VDA?AmIzyRHT4I5iU<5f1R<cl3zNO=Mh>oA
z`6GB1+tm%|G*rNxjgF(R_PiQYc*EsNsvRT43;Oi#Y&!aQ9~_XV$v!uy$B>{~I4eo)
z+3JMbr!aiy%a2hnE8Myh@NB9mtVD6x{sX0BwByU|W=r}kJ6kk3;V<yyP5CB74`5?J
zKQU`6nV6?Y7cy`MN$&M=vIk;x-GA9ox+F@qO5O=ywu4_1Ld_I5yW`*27K|adPrBae
z8JdtMwhdB*j`iMSKT)E=ZTXxb_80rF+gstdFWOFGfHf<>Dm8wkP0FirHc1fAUJltA
z6mD%?Som3g2d(q*^b7L#w=*s%G+yfU5Nfr(XBa6g=!Z`G4~F=!I`EJrMIWkkIP$eD
zZXxu7KyzonF=*nyc~K@bbn#g<*p4tD1<mrOz-7DXHYDV_>+@#%ef7gC>Em6tUtYnj
zPwmKUi87_qyu8JLhkdaXm3uvu508c0)|;#6079I8m0R_8T8^_ee4YZPHz*L#wYwf2
zf+&(Bnn0V&o+oGTd}Ik^!C380mC=Y`V7iQWbcXs*?_fku8DzWtkRUddGW=!|GgxM>
z3G(!qgJ;|Q7_1iO1934LEG^YnR6u`^xIB_oiJTH4Wkl!2BpB@R_ur-G=d;Lp$8SrN
zmETX;l6(&*&7)hY$odn0|3IHm!!rg~jRg0EmyfwJ)qH_l6uqd+hnTxNZ~|AU->>sP
z48$N!?c1YE7cV;Kzkyn-HChP4e7N+u;{0RK{DY<L2yfS6_wcms9F5OK(AsN+d(%($
z<XzIwe*IygdUZ`GmP}-+{q2&z@Snd?Me8_KE4BXriS_B%kcX$Q%A_54oJ*g~cGDIQ
zT%lQ=%$0<olFCKm9S?Fg#sm+q(>zBght1poPURlkP5<P;QDoW@J5o4@p*dO6_<Fvs
zXMk6-z40nQn)>8eEQ%E5{hObz?j3Nb+Bk$&A>Dm~Le`AP6g4v|7=T_dT%qM#@{EO%
zF-dnS<kW#xWilI{Wkw!b24Dq)Ebk%c?BtX>m=hYsIxIlnSjS_uZ*RXpr0|kr6nSWo
z`X3sb9?>mzzTV3TSnG6TEM|@7L#!OMv=q*tBiErvqXQ(o+Ks5;_U@QYA{z=P`d*fn
zCu?Vo{S1}MoN8~=sJl^r99RrMh?L#LffNbSBcph@AVB_xT)fIvZG0gjEEOTjajmsj
zuXo}?$t(fk%Agoyb65$ZEFp~%bC}`JTzION-<(+LEJ?7NafZ2=Jvc3ZV0T@`0!na4
zwqb9X@)G|2NAEN4{)CkatMeyVCGmGE)%&lbdcHOnroZ~Gwh?~jnJ*2}rG&uZxd&A8
zauAK65`cT}E2slq2LvB;E^vudTd;3Z!-}d5K;tJ&m!c_Oj#YOp?4TH@!&V$loXvIq
z(itxCs0^nG<3wmCV_>ZlrX*{}Og1V{_Uo$uC^|QnztCJAUcwJ=x56VM)Ucdq>5F1F
zhpuq7TCHBrH)WUakwYz1a*8c6YSuD#F3dinEX{rCJivHDZuVqxO7{g9QCN5y=6^ln
zOk9-K2p2qt1v(}LD-qh6ERwuyMPGv^P=?Sq%^UY+ZX?Yi$~VpCY1maf1Y$fyWb(5F
zRRosIM23ziU840lcNx%Vbgp{3AwI6Yja@v@BZQCSa&I$+X)B#O*eY%NXB0Qw!#SR<
zRHD$aDCFuGO^Zm?rFZ-p)3<|-#ZM_|YaEu`??5|NYaZD$Jgzy1DP4U;GIJQvcMeTb
z=B4k-jfr+yjG+F|j<I}ESU^h+<A2k+)QmEDoL8am1@q)m^lE1(A0AT;lpQum$vj_g
z9xO7LDeZg4wE-(qBX*^1igf0_r!rC`YI(6=X%}L8nDGOiLT8!Hx!bm9yrqsiiYiws
zkT#P|h9I<t-_sk;mZ%Au((`DD<Te_@e#7`l>XzLDPZ8$AzQ15|{Do_lbX!w!92TU~
zUHzH)kJRhi{IQPi6aQbYFIji<*%b)?xdhFwreD$OWjdcNQZ*tby%O&akHvIg#O4S+
zr3=sWqa!+h{Y$^_b@mpHy@i#=8(Om%)c4JDpWo;@M;Ld=_&8?bu&jm=prF$X?#61~
z@XU~JjIuo=5_etMq^%e-SWeg&nQo{?Um1G)O@K+?_F|KXm@kKBe1ucOh9?P4KjWM4
zZwt!pBWV$mr||*9j0Ble1_fSZa1X0&l#6Zab&4p%OPtT=a8q8+z46Wc;ysJu9X_K2
zI4?%jkaUeQF;V_9Q<gwVQn>=Ak^DC$YzF=u{wC)NCD0;_l`FwFX+}iE_hGHA0Ji=`
z07z7Mm>K0T5e6TO(b#Y)2`;0Z5wZPdZ(&doK^T8Q+SkwyvL=<a3h3rV2n92u(wId8
zTme5)8bMgI;NSYMq>g51%7t;Ui44egR(nrh8znB(vBjsW*D&wYyIAjOBg~T65|mcI
zh*r@4J=JDIbq3ZR%;Fn&0r|MpaDwL)oaj~2GcclVVtv%=(!GB`0(d*a|Jy&?kt1UV
zGwjZxuh2%EJfS|1m(>vK8ze7$Tbz#wvpEaqhedQ$j|ugUyi-BH`Amx~;|WqETr>nv
z2&IhB7DS4&mdpDM(RZooqqYYfO>nX{Em8@ZS%>-F`$^YqiI$++I_uw45K%uzePg}H
zyP*qKLK)eTydwFfrPhq<g?`6rU)xQ8NC-s;Lsn&mt4FZeRPVD6x?WG&l_<bQaEF6x
z^8bi>$+;_xXiF8A#EKHDE?AZ&0^52d&i$tmmPf$-oqi628<HrMRxHVgEXZkjra<@%
zKtl;|0H5sp>UXKhj!;wiQv%su4SDc9*yYS4EEv1j7n`z`Bje<;(m#=oLc*e*P?^cp
z(j6=2*vhKvhwEX``uV|#Q(VXFy$D<mSl4iE=J91Z?j~Q00zqyWu}RA?Q*+TAtEyD9
zm%lBU0%)x{0CP1Jz;6Fb<&mk11wdzWmU#(I_Nm?~c-A?jP?==&iZv~&9tZ@=@#Cj#
zv_+Y;p@<`~QoQBmZ%C!d5u-Vjj{$X&&zmBpSjz*>m`f{9%1VdSHgS`!r_>X<;=n7d
zp_w0gJWKefi&|988X_A5r@zAKN-^GP)?m7l9HL2e)C*m~T6|q|H~qr*g11QMlV8Zq
zDZgGSPw-oHmO}p{ID&?8z1w1_=YDM=+3~}9%3BG`3jUC)$%lsv(6neJ!!S7ggCw(Z
z>=By%5l=dpnV~SMG(lI4=)hewwA276nWIFPmzf|KT~1qVBPO#-N6JrYG!rIk8b$Oa
zDYfpHeHnE`qqF=&tu*C`C^dpTA7Ma9TRD8HcL1w6AwQJ}R8KhD#rP}-3%90}NjU#X
zo>%hc_Yh|^j(OV$mMp4Ix7&dt5^Hh;zu!JAbg}c_nzN91prvdYG*m~AIJCc%9X~<6
z?I!V=g7d%Y-tkY*PVWOBs*kF-pu3Q@8?nK*=VFlaJD{3G%m#~2f;5$+oSXcIJHnu$
z0kJQo<k>dIS4UV0Uo1lS`09K<6SFtU{bazxt|0{=dDoQ8`2Ku_YI7M;5d$5?DS?kl
z$G)ELKhXkG{Tx|cjUl8PD*Ram0b2CwFy@Hc0_^_b9SyaDZ-Lc!w#`QwJ6Tb$w0!yx
zHdzaFf*KH-#&EQEI(hf|Vgsl1KUkdMX_^Nj&9Z)cp|Rqv1r9vHW)VXUCF%(J()E|a
z(=oHm8f|)Xe@}|G&|}_o-*n~|mEJkL5Ef_a+7f8!Xf@+oyvTY$B?Q|F-uJW0^OpMY
za_2T(QHH<$jl1;Dgd(tL5EW8k2p9A&$Cs~g)_IZwP1i!;P`hcmknJI+aO|dm!lKoT
z2-d7ZCu5f56^n5i0vF{uKW?rrZ)bkIqfB}D>qk!7TaN=cU;7#FZ?>N{+C35>0)p)e
zyL~O9*|UD@u)Lt;|NPclM$T7%u$VpjDlnXnFKvSdbu(kQ)}F)U2n=+P<CyV#ymoqy
zBe}ONiK2Plt6`*hQO@30pcE;rGL6)^-JCO}_OTn*M4l?+#b`05R?=$NN{Db>Fw<k1
z*x%!r45+^*Fo%U_N%D(EXadBB;%HPy%i@8aOVU(!KuxT0L^gF~VsafAN^$f1ps2F}
zaK<P#ixjGFZRPb&Vn!DuZXZf4e-|x&W3ZrD?b+alA6)d7G+pZbL|4*h<8=RX^vzy?
zp<!<;bp5Yqz_#O?i}R=UWXQGFW(YN)&6CvuZeT8HQiVb{j?n95-iQshhS+Qlt=^i(
zg&NLVV1LX9GL^(bz?TKXkqpa@PE)x=FASL1sA#^)=?-JQCWCPh`hpH(0QS9c{OAC4
zpp%CCp*6%<Q~A>`M%0Ii`z3s<@L=1ku6*$nrnMq|O(wys4YT&*PnO)1KJ6N~=J$j*
z1(vapOn9862M}t_BfHh0YyC-Sdt0GL7jf@9UmYjpKB@eb3^?4XB#j<s5E<U$Di6Ir
ztoaW^JOv<*_J>5-m3IEK0(3OY&4Z9C$_tfNhHJUkp-@_=Ng~;@N|pOZ!RI_J%E~|{
zqrOqV>t9c0O>43Nacujy;Kk*0SGn)Fo!O5;Tad;;?Sxu%Gas&64x})Eoz(>!7W*xV
z?3X`pyaoDYbhUP^tOHS~CuO_?BNhr$s<x7n7TA7x$T<nNj5(_8yDsFbKuD7|<%u`s
zL+Nz5<ZCct94v|3%8AkfAi*Hi4ri~~4s$!vpQIJ}Q~xk8Gw0o5GIM)3mpASm(uPx}
zk(X_jw@f;Odbz%hu&$a~z6!x#rNf>S$Vk-KfBo8j@;j1$JZ-q+IR2d8op;)yhJvw*
zknp23)T6ZkT@%yq#8_2jfq&@Bj(|Q@$1M^82u)a(g4F*80US&|7W3y?aVaI%jr@|q
znC10~jJ4B{mFMdrIcFV>BT45>dFtcuLuVR9;nL3>+M>k{>IMU&)SPsc+Vwp=c_x+)
zRQhgt`lDM<LhVSjI)iMa7fE`KGk9$!qL7S=;6)@q#^B(eE7Ar@thXA8N6z0AsN`t5
zPq{oiYIzUzy7NajCb8`;kuiQcbi}@hv`3qwZX?%fjL%&Q3)xLAChCktP)8z*OGC$y
zjB_zp14I59?Hy=RB}`T&HeC4`KPvxyQlbzKSKBK2Qm7{-gWm0HA$sk^r)y^a8x#96
zo~h($pIr%62l!jT>|9>zn1B3Bkm(&<;`o^y&}sZXcwC&Za^ZFjYUR!?ko_puUe{!U
z+y%k@xBU-2ifpHOQ?#9Tf%|YS`mC-nYP=w8oh#SWyPe7(H+qepOID@&x6wgZfSrz?
z-s=u?I>$x1S%d5l;r?yit4OR#%sZin@m}wyI#dFx*Mc6O*CR8ArWLwVpl@MO?GV|Q
zzI-Ys%uMKo^<d}y$i#Px1h&>|Zepu^@Zz+RA(1kZkcyeBCRs$NDx!4zw<Q>OD5xxF
z6a!HrIIH|@rpM$`xs3_2@7C0UCHCnFbgSn?27sK3+ddbe^Cu<Lr0G`38J{>EMb@(j
z<1!PYOD7X$#hL(rYCO3vU@IUu8BiA_!sHeMOzeI1S+y42jGQm&$T9QFBg?=n7(5*y
zrQyOlLeN12|IrNOd6<OcNP?)Ew15GkJhNSc?JPZz*5aDXl$gjd!IswcJ*jFbYcZ3?
zp<YSx1f;u|)~~+Q3>=jCcJ45h?PXvwnO?uI0vX8U;PRhYEfqj5LvXeitn6I0`mICd
zPf*pZ#;xL3LuLI(0=|{h(k?eQfHhNVQSbh&t9??sO+T)0itpWzCBp8%;-pCV+5=sp
z26uZ0B#pmSn1-P&U|4;MJX^7uKm-HaxrwlkoBQ45sU_L1LR;H96aQEBTMmY_8P<PI
zXNQzXtYpafd;;*;L8`ZDhx~<U1?VvJzKlAI7+(Ge>+9M+3h25uZt<amu&oM>H2t}B
z8s=14Dy6l}nTteRm>OCC{I&Afb-ZIKxy>);%YHL!3}boZE}|dgx&`tU)|xeG5@bll
zy?9<ImvLZJ#Xa(|yN<l&*82eCp9Bkax1?3My}Pz8+3jmFOYI#Pb~oTT?|=cfJv)$U
z;L0kEEgtAe&`@aGvP#5zN9FAoi*41;=H~bILddzdOYin3nNQ`HwuT2!jYl0?YZosK
zL{s4O)nD7x8!r)}fUAvQ5oe!H{{TplrO(!3A!O&#b8^?sr=W&=H|XKm>i6p_X-{UN
zE#(BY^Xz-#P4z$$;&>cEd2zA$@D&#-sDEq6A?1m*3!>!hy%n&%q6;y$z4c$-@e|qI
z@~T|}&`cW)<ZBa6R~-8-5jGgm;6JvvrOKk!uF7R;9e?EkIfM|(;SAPKY{JyF^OM84
z@sZdFb2!wl5mg1!)oUHyzvG&3PAA$qHQ$GmHH=);a&|_^5H!F)c8~Azu|QmH3RWKs
z%<Qcvb(<|vJMi*Z^yNpAh|>%X*B;v^TBqf-4PCs_6G!sOpnfG@B(n*+{El`v(U^Wl
z@rhOHGWt^TC!>^WeopeRc{4_1{?<i8eX9<_fT%b+A^F&}IIs4B$B1ckdcwOP)Yl89
z#&8R5ys%%jSw>K}bg3(?28wCLj>*t_x=!DLUF?tp4;?qOw`H$&oNT|JXEz!69(~hv
z3#l274z>6e)!*N9QS$u#9s#Zfd7iJ^U=~qRi{pc1q|)Mr#k?8YELW$x)*+IgRgJ`m
zszKW&%C_Atj}(w%VczBj@}NV&N%8m3Ith_^S6jueo@5Fp4AvP7%T`77E+fd9QpJ<>
zxKxTJWRkde&@fhNTq5;v@(3fiW`u6|$j@~exJ)S0==lUAqs<oze#x$sp|K7(qn5*(
zRT87!+)q8n$lW+*#D@MJ8xx07XYh&TW;5{vdbRPH0`wKr#*jxX&p=9EZFHzrP|iyG
zILb;r-9UW+?%1JTE6qH!jl(h8yseEW$va24ja$8rT&@Z8a8(LNROx?4SL8M;s?2Ia
zZmr;*MPfM##Z(JZ4&&+vmT9R1mI~%0B2CNa-T5LLZ_!zP1m=J4i+WjN-A%%YVNb4<
zyV@@sTukX<*i0JIIKgy7I$0jkEY>ZszYRyX!#sMbie|1(<AhY(4~N{uGNfKEzK0TF
z>v{G#2xnze|Kz~4a%;$KNH1<BJgV`jf5W40W>qg{Q7UG%aG1Y6zBl-FHC4+5D$LeQ
zh<vA+VWe#lF}+c=jpvDHvWgmtz4QuRj6GDwhG%gjlk6!R!C=5lY8V-&^@3DIZIBzk
z-1ov>YaZP9qNW_pHW66p;$@lFuVK{lxFiU&TB0z&G<Sqqv<U)eUF^rAPYl=6yE^vG
zzDR_RBRwcTa1Z!>p7n;gd*;6*|G?uUkL`U&aNOCq-6%dIOKUjC%lB5wsTwcgv$Gi=
z(Y7<1{-uuZq3RTcDb3Ih)bnCN+0#4WvBkKn`RJNb#3mTMh6y^C0xuW+L#>kUK-doF
zjYm{R5x4Mrle_piG-V;(-iax-yvp0r_$KJm;gVt;QetX7{3Dz_W#SUM71+gWAXkM~
z)1Viec=t2e>;xkbL&&F`E>gt|m>(qzK|6E7X&Lhn+J`#x*b(GC&`-dHmEetBC$g?t
zsl95ciJxZqx2B4cWg=aTMFhHt>pG*OiZnn)b?}S^`YbVNI3H6e#CaGe#nm~;Ngq=q
zm=DLL$}K$qn&}^rvyI%v#HPBo?7`3JgBryg?%Ur}Y5@*`+wXf<yZA33qdGpeUA^m@
z!C`7bf8Y1KK4g_YT&kEqX%5YqUT6|zPnza?LEh=2!7%bD;vu#-{Vq2u=yJc*5K$E0
zIUMY(j_eiRFn!G$OF#T6=y~U_k(MJ*&9?pQg6h&1cI=2X{IaPYM>nFPCh}d=CkS#4
z*OwPg{@WM&8A^g)i7WjBc?)pphXTx!VRlrwO{#{a%A~q5uVmId+k+9Zj}02TTPQan
z-VVg$5PwBO&YBx63M`?3qcm=^=b`%4b>s%&lwEcG%l)zl&f1VEcYD!WZRenf_?0g(
zp4LuHIwLMxi%4b%UMW9x^b|O^c=DH7aBH-`!Qt6cpip@2+zT1Lw!>Qp+1S=U{rtZO
zXdC!Uzj38{VRyH8|Ml`Q{!!Br;%i41%r63+w(x$uS)!AtENcS%+%?6@O+o6`zPq`v
zsS)V`o<gv27lhV}yV`M#ew8Fs_Cz+65o6Ef`QEoh70<Age<$6z8JnQ`5g9TN;EH48
zCpe=kJCM*CaST-h=N&QLDV4}mNBEXEHS<(Fxp3qtFovEgw6&LLz%&2tr>%-pke9d^
z_ydbY&I%kcf);iUd%1g%a?Jb0x4;wRT2@X(4O;(LdeG}sva`Q7^9#U4OqT7q#UtOo
z`IVj?iA$S}Z<1B7)wKW%p?My+oUK@8t;|LS=M<x8zgj7pMzYY>VM3zsDURUTT>i-k
zKFF>YI^NsCCl$pRZ#2@+dXJoxgx>7ml4b{g!tT&MqsQ_vWmjOpy<7@6!YURg>NluT
zORn8tgcj%lMJ3gpa2ejs^ltZ=y9)#3Y$*d9D(Q6F0SJ@~*v&t1OD7eZ)4{a3dUpVO
zVI)WI0!diz*|oyh`!uqhD6nZ<)9w>eSqW!6#ZwKTaWLYT0=y!E!hGr<`ypZ>u`(dQ
zI~X;C=V~aGHZg4Pyu5zHxwCd_Miu<*?`+MWAK20PpF;8Zfy7v9ipfDSq;zCvWO4Id
zl1pFCzYs+9@GItiJ&RL;!jc$QY+X~nx#mOEDszc^+?zfA$WVPuTb?3ItFBS_Z9o}S
zC(v9-tsvtkwc>%0)VKEGwx*Yf@g`tll5Ac-J_)ul$4bveZIdF?`DM9vq(25h&B<NH
zsY70(!V=R;D`DSirl^GZG=xXbf`#w2T>iTlFEO1q!z5ykBqht3$(J52ZSDAxAdCB>
zxUctwF#Xi?OpYzfI?N0rc#Bg9U-kxcDO3k#eV&<QRnL>$%NiCrgCi$7$+g<+by1aR
z8F;w@Hs=;3YlrkKt)?tm%ihuJ$EVKU;f=DiW4O<+IlxC$O2fA(-B^+Oyhnr<x14Fh
zVliLRbGL3XabeA6O)@e*x6R-zOLOyR4ZM!RlB05a3Vz#>9I5?4|JGL);!ruYQ1C{s
zG%VV%VDYVZ6n}hGB#zS|=26!cy;6?r$}Hb~P`NWT8U3BS-YwVqIat6)PQG=}5@Wip
zC}dP=WFg_*L|6j;WB?<fx#ZuTK+K}q;2wX3++?I^l<q|~IjZ9fmOGm-rZir@961x;
zkmMK{R8jWo0uelEr`8DJZxL3~N9I6}VIo2C_04?N)@%b!Er2mqsc2x!Ig1294oJ`1
zsEe%f5+m7MJS>3nzH&pif@4jE!Oed~s0{55Jk?el&%~OqdekY!FUtoL^et9S*)|1a
znw7OFN-L2?&iL88owQP39$D++g9OBmogpq_V-{I^zGHPN8&Dg|kb2?Bt6mj|M-OP)
zejXz=li`{>rsScWld(YkJriq)EdQ5%6aTDB93o=t!igxlC~Z+1dro7cjKkWQ?%D08
z^UqUJ`rB<ycR9KtESFcCD=0mQ|Lg<hdZ#Dj%ZO2Kx70p8OocgO-3GBnIG^3&r9}i1
z_o435fKmo3gHT8WtY`zjhZ|j$l<3r~FvYjV@;`J>f?`2GI`0%?)sG7euVyjjG^G>q
zY`T4=uLd;$k@Dk_A#j~=6;pA$gQ!_kHW!!P*33*~V3w>Amc2{kel$8^Tq3Dgv6#X~
z$6n|)^ifPSuXwAteyRAgx~nKMzTm@g{?A|7?T!!w#n|>2CZ!w72EX_{av%F@{^>A=
z)<_SOm#wzKRicQjZw2P`qcUsyb<Q9=UtxtuzgdP-r$#ikE5V?uIE@$Y8(e84HJKj+
zQgZCAi`T3}K(eR8aU$dcvsvoz(=n2Wv>3y`#l*w}L^lQnMFT=M9T+P?!}CqZfrsgr
xwPv3xzH_6%_)uU_KSsWZ>0ig7hNg#(fwlElga04?^7%u>5)eZOVWwbU{s(#bX`}!E

literal 0
HcmV?d00001

diff --git a/source/cmk_addons_plugins/vsphere_topo/agent_based/vsphere_topo.py b/source/cmk_addons_plugins/vsphere_topo/agent_based/vsphere_topo.py
index 0d2f9a4..b17f298 100644
--- a/source/cmk_addons_plugins/vsphere_topo/agent_based/vsphere_topo.py
+++ b/source/cmk_addons_plugins/vsphere_topo/agent_based/vsphere_topo.py
@@ -23,11 +23,13 @@
 #             added option to ignore VMs by name (regex)
 # 2024-07-31: added option to map vSphere names to CMK/topology names for data center, cluster, hosts and VMs
 # 2024-08-06: fixed crash on mapping vm_name
+# 2024-01-16: added suffix option
+#             refactored constants to enum
+
 from collections.abc import Mapping, Sequence
 from re import compile as re_compile
 from time import time_ns
 
-
 from cmk.agent_based.v2 import (
     CheckPlugin,
     CheckResult,
@@ -40,21 +42,9 @@ from cmk.agent_based.v2 import (
 )
 from cmk.base.check_api import host_name
 from cmk_addons.plugins.vsphere_topo.constants import (
-    EMBLEM_CLUSTER,
-    EMBLEM_DATA_CENTER,
-    EMBLEM_DATA_STORE,
+    Emblem,
     ICON_VCENTER,
-    PARAM_CLUSTER,
-    PARAM_DATA_CENTER,
-    PARAM_DATA_STORE,
-    PARAM_DATA_STORE_AS_SERVICE,
-    PARAM_HOST_SYSTEMS,
-    PARAM_IGNORE_POWERED_OFF_VMS,
-    PARAM_IGNORE_VM_NAME_REGEX,
-    PARAM_MAKE_DEFAULT,
-    PARAM_MAP_NAMES,
-    PARAM_VCENTER,
-    PARAM_VM_NAMES,
+    Param,
     RULE_SET_NAME_VSPHERE_TOPO,
     TOPOLOGY_NAME,
 )
@@ -94,9 +84,9 @@ def check_vsphere_topo(
     ignored_powered_off_vms: int = 0
     ignored_by_name_vms: int = 0
 
-    name_map = get_name_map(params.get(PARAM_MAP_NAMES, []))
+    name_map = get_name_map(params.get(Param.MAP_NAMES, []))
 
-    if ignore_by_name_str := ')|('.join(params.get(PARAM_IGNORE_VM_NAME_REGEX, [])):
+    if ignore_by_name_str := ')|('.join(params.get(Param.IGNORE_VM_NAME_REGEX, [])):
         re_ignore_vms = re_compile(f'({ignore_by_name_str})')
     else:
         re_ignore_vms = None
@@ -114,7 +104,7 @@ def check_vsphere_topo(
         objects.add_host(
             host=raw_vsphere_host,
             obj_id_prefix='vc',
-            icon=get_emblem(ICON_VCENTER, params.get(PARAM_VCENTER)),
+            icon=get_emblem(ICON_VCENTER, params.get(Param.VCENTER)),
         )
         vsphere_host = f'vc{raw_vsphere_host}'
 
@@ -124,21 +114,21 @@ def check_vsphere_topo(
             if objects.topo_objects.get(data_center) is None:
                 objects.add_host(
                     host=data_center,
-                    emblem=get_emblem(EMBLEM_DATA_CENTER, params.get(PARAM_DATA_CENTER)),
+                    emblem=get_emblem(Emblem.DATA_CENTER, params.get(Param.DATA_CENTER)),
                     link2core=False,
                 )
                 connections.add_connection(data_center, vsphere_host)
             cluster = name_map.get(raw_cluster, raw_cluster)
             objects.add_host(
                 host=cluster,
-                emblem=get_emblem(EMBLEM_CLUSTER, params.get(PARAM_CLUSTER)),
+                emblem=get_emblem(Emblem.CLUSTER, params.get(Param.CLUSTER)),
                 link2core=False
             )
             connections.add_connection(cluster, data_center)
 
             host_systems: Sequence[str] = section_esx_vsphere_clusters[raw_cluster].get('hostsystems', '').split(',')
             for host_system in host_systems:
-                esx_name: str = adjust_name(host_system, params.get(PARAM_HOST_SYSTEMS, {}))
+                esx_name: str = adjust_name(host_system, params.get(Param.HOST_SYSTEMS, {}))
                 esx_name = name_map.get(esx_name, esx_name)
                 objects.add_host(host=esx_name)
                 connections.add_connection(cluster, esx_name)
@@ -183,11 +173,11 @@ def check_vsphere_topo(
             }
         ]
         for vm in section_esx_vsphere_virtual_machines:
-            if params.get(PARAM_IGNORE_POWERED_OFF_VMS) is not True or vm.get('powerstate') != 'poweredOff':
-                vm_name: str = adjust_name(vm['vm_name'], params.get(PARAM_VM_NAMES, {}))
+            if params.get(Param.IGNORE_POWERED_OFF_VMS) is not True or vm.get('powerstate') != 'poweredOff':
+                vm_name: str = adjust_name(str(vm['vm_name']), params.get(Param.VM_NAMES, {}))
                 if re_ignore_vms is None or re_ignore_vms.match(vm_name) is None:
                     vm_name = name_map.get(vm_name, vm_name)
-                    host_system: str = adjust_name(vm['hostsystem'], params.get(PARAM_HOST_SYSTEMS, {}))
+                    host_system: str = adjust_name(str(vm['hostsystem']), params.get(Param.HOST_SYSTEMS, {}))
                     host_system = name_map.get(host_system, host_system)
                     objects.add_host(host=vm_name)
                     connections.add_connection(vm_name, host_system)
@@ -205,17 +195,17 @@ def check_vsphere_topo(
         objects.add_host(
             host=data_stores_host,
             link2core=False,
-            emblem=get_emblem(EMBLEM_DATA_STORE, params.get(PARAM_DATA_STORE)),
+            emblem=get_emblem(Emblem.DATA_STORE, params.get(Param.DATA_STORE)),
         )
         for ds_name in section_esx_vsphere_datastores:
             objects.add_host(
                 host=ds_name,
                 link2core=False,
-                emblem=get_emblem(EMBLEM_DATA_STORE, params.get(PARAM_DATA_STORE)),
+                emblem=get_emblem(Emblem.DATA_STORE, params.get(Param.DATA_STORE)),
             )
             connections.add_connection(ds_name, data_stores_host)
 
-        if params.get(PARAM_DATA_STORE_AS_SERVICE) is True:
+        if params.get(Param.DATA_STORE_AS_SERVICE) is True:
             query: str = (
                 'GET services\n'
                 'Columns: service_description\n'
@@ -243,7 +233,7 @@ def check_vsphere_topo(
     )
     if (vm_to_data_stores := ls_connection.query(query=query)) is not None:
         for vm, data_stores in vm_to_data_stores:
-            vm_name: str = adjust_name(vm, params.get(PARAM_VM_NAMES, {}))
+            vm_name: str = adjust_name(vm, params.get(Param.VM_NAMES, {}))
             vm_name = name_map.get(vm_name, vm_name)
             if vm_name in objects.topo_objects:
                 data_stores = data_stores.split(',')
@@ -272,11 +262,11 @@ def check_vsphere_topo(
     # workaround for backend is only picking up topologies from default folder
     add_dummy_topologies(sub_directory=raw_vsphere_host)
     # end workaround
-    make_topo_default(sub_directory=raw_vsphere_host, make_default=params.get(PARAM_MAKE_DEFAULT, False))
+    make_topo_default(sub_directory=raw_vsphere_host, make_default=params.get(Param.MAKE_DEFAULT, False))
 
     yield Result(state=State.OK, summary=f'Objects: {len(objects.topo_objects)}')
     yield Result(state=State.OK, summary=f'Connections: {len(connections.topo_connections)}')
-    if params.get(PARAM_IGNORE_POWERED_OFF_VMS) is True:
+    if params.get(Param.IGNORE_POWERED_OFF_VMS) is True:
         yield Result(state=State.OK, summary=f'Ignored powered off VMs: {ignored_powered_off_vms}')
     if re_ignore_vms is not None:
         yield Result(state=State.OK, summary=f'Ignored VMs by name: {ignored_by_name_vms}')
diff --git a/source/cmk_addons_plugins/vsphere_topo/constants.py b/source/cmk_addons_plugins/vsphere_topo/constants.py
index e7b40d6..9daa281 100644
--- a/source/cmk_addons_plugins/vsphere_topo/constants.py
+++ b/source/cmk_addons_plugins/vsphere_topo/constants.py
@@ -8,41 +8,54 @@
 # Date  : 2024-07-16
 # File  : vsphere_topo/lib/ruelset_names.py
 
+from enum import Enum, unique
+from os import environ
 from typing import Final
 
-EMBLEM_CLUSTER: Final[str] = 'icon_plugins_hw'
-EMBLEM_DATA_CENTER: Final[str] = 'icon_cloud'
-EMBLEM_DATA_STORE: Final[str] = 'icon_services_green'
 
 ICON_VCENTER: Final[str] = 'icon_topic_hosts'
+RULE_SET_NAME_VSPHERE_TOPO: Final[str] = 'vsphere_topo'
+TOPOLOGY_NAME: Final[str] ='vSphere'
+OMD_ROOT = environ['OMD_ROOT']
+BASE_TOPO_PATH: Final[str] = f'{OMD_ROOT}/var/check_mk/topology/data'
 
-# PARAM_ADD_DUMMY_TOPOLOGIES: Final[str] = 'add_dummy_topologies'
-# PARAM_DONT_ADD_VC_AS_VM: Final[str] = 'dont_add_vc_as_vm'
-PARAM_CHANGE_CASE: Final[str] = 'change_case'
-PARAM_CLUSTER: Final[str] = 'cluster'
-PARAM_CUSTOM_EMBLEM: Final[str] = 'custom_emblem'
-PARAM_DATA_CENTER: Final[str] = 'data_center'
-PARAM_DATA_STORE: Final[str] = 'data_store'
-PARAM_DATA_STORE_AS_SERVICE: Final[str] = 'data_sore_as_service'
-PARAM_DEFAULT_EMBLEM: Final[str] = 'default_emblem'
-PARAM_HOST_SYSTEMS: Final[str] = 'host_systems'
-PARAM_IGNORE_POWERED_OFF_VMS: Final[str] = 'ignore_powered_off_vms'
-PARAM_IGNORE_VM_NAME_REGEX: Final[str] = 'ignore_vms_by_name'
-PARAM_KEEP_DOMAIN: Final[str] = 'keep_domain'
-PARAM_LOWER: Final[str] = 'lower'
-PARAM_MAKE_DEFAULT: Final[str] = 'make_default'
-PARAM_MAP_NAMES: Final[str] = 'map_names'
-PARAM_MAP_NAME_CMK: Final[str] = 'name_cmk'
-PARAM_MAP_NAME_VSPHERE: Final[str] = 'name_vsphere'
-PARAM_NO_CHANGE: Final[str] = 'no_change'
-PARAM_NO_EMBLEM: Final[str] = 'no_emblem'
-PARAM_PREFIX: Final[str] = 'prefix'
-PARAM_UPPER: Final[str] = 'upper'
-PARAM_VCENTER: Final[str] = 'vcenter_icon'
-PARAM_VM_NAMES: Final[str] = 'vm_names'
+class EnumValue(Enum):
+    def __get__(self, instance, owner):
+        return self.value
 
-PICTURE_TYPE_EMBLEM: Final[str] = 'emblem'
-PICTURE_TYPE_ICON: Final[str] = 'icon'
+@unique
+class Emblem(EnumValue):
+    CLUSTER: Final[str] = 'icon_plugins_hw'
+    DATA_CENTER: Final[str] = 'icon_cloud'
+    DATA_STORE: Final[str] = 'icon_services_green'
 
-RULE_SET_NAME_VSPHERE_TOPO: Final[str] = 'vsphere_topo'
-TOPOLOGY_NAME: Final[str] ='vSphere'
+@unique
+class Param(EnumValue):
+    CHANGE_CASE: Final[str] = 'change_case'
+    CLUSTER: Final[str] = 'cluster'
+    CUSTOM_EMBLEM: Final[str] = 'custom_emblem'
+    DATA_CENTER: Final[str] = 'data_center'
+    DATA_STORE: Final[str] = 'data_store'
+    DATA_STORE_AS_SERVICE: Final[str] = 'data_sore_as_service'
+    DEFAULT_EMBLEM: Final[str] = 'default_emblem'
+    HOST_SYSTEMS: Final[str] = 'host_systems'
+    IGNORE_POWERED_OFF_VMS: Final[str] = 'ignore_powered_off_vms'
+    IGNORE_VM_NAME_REGEX: Final[str] = 'ignore_vms_by_name'
+    KEEP_DOMAIN: Final[str] = 'keep_domain'
+    LOWER: Final[str] = 'lower'
+    MAKE_DEFAULT: Final[str] = 'make_default'
+    MAP_NAMES: Final[str] = 'map_names'
+    MAP_NAME_CMK: Final[str] = 'name_cmk'
+    MAP_NAME_VSPHERE: Final[str] = 'name_vsphere'
+    NO_CHANGE: Final[str] = 'no_change'
+    NO_EMBLEM: Final[str] = 'no_emblem'
+    PREFIX: Final[str] = 'prefix'
+    SUFFIX: Final[str] = 'suffix'
+    UPPER: Final[str] = 'upper'
+    VCENTER: Final[str] = 'vcenter_icon'
+    VM_NAMES: Final[str] = 'vm_names'
+
+@unique
+class Picture(EnumValue):
+    TYPE_EMBLEM: Final[str] = 'emblem'
+    TYPE_ICON: Final[str] = 'icon'
diff --git a/source/cmk_addons_plugins/vsphere_topo/lib/utils.py b/source/cmk_addons_plugins/vsphere_topo/lib/utils.py
index 9f4b36a..7f11bed 100644
--- a/source/cmk_addons_plugins/vsphere_topo/lib/utils.py
+++ b/source/cmk_addons_plugins/vsphere_topo/lib/utils.py
@@ -10,28 +10,17 @@
 
 from collections.abc import Mapping, MutableMapping, MutableSequence, Sequence
 from json import dumps as json_dunps, loads as json_loads
-from os import environ
 from pathlib import Path
 from re import compile as re_compile
-from typing import Final, Tuple
+from typing import Tuple
 
 from livestatus import MultiSiteConnection, SiteConfigurations, SiteId
 from cmk_addons.plugins.vsphere_topo.constants import (
-    PARAM_CHANGE_CASE,
-    PARAM_CUSTOM_EMBLEM,
-    PARAM_DEFAULT_EMBLEM,
-    PARAM_KEEP_DOMAIN,
-    PARAM_LOWER,
-    PARAM_MAP_NAME_CMK,
-    PARAM_MAP_NAME_VSPHERE,
-    PARAM_NO_CHANGE,
-    PARAM_NO_EMBLEM,
-    PARAM_PREFIX,
-    PARAM_UPPER,
+    BASE_TOPO_PATH,
+    OMD_ROOT,
+    Param,
     TOPOLOGY_NAME,
 )
-OMD_ROOT = environ['OMD_ROOT']
-BASE_TOPO_PATH: Final[str] = f'{OMD_ROOT}/var/check_mk/topology/data'
 
 
 def get_name_map(mappings: Sequence):
@@ -39,49 +28,42 @@ def get_name_map(mappings: Sequence):
     name_map = {}
 
     for mapping in mappings:
-        if re_hostname.match(mapping[PARAM_MAP_NAME_CMK]) is not None:
-            name_map[mapping[PARAM_MAP_NAME_VSPHERE]] = mapping[PARAM_MAP_NAME_CMK]
+        if re_hostname.match(mapping[Param.MAP_NAME_CMK]) is not None:
+            name_map[mapping[Param.MAP_NAME_VSPHERE]] = mapping[Param.MAP_NAME_CMK]
 
     return name_map
 
 
 def adjust_name(name: str, params: Mapping[str, object]) -> str:
-    class Case:
-        upper: str = PARAM_UPPER
-        lower: str = PARAM_LOWER
-        no_change: str = PARAM_NO_CHANGE
-
-    if params.get(PARAM_KEEP_DOMAIN) is None:
+    name = name.strip()
+    if params.get(Param.KEEP_DOMAIN) is None:
         name = name.split('.')[0]
 
-    match params.get(PARAM_CHANGE_CASE, PARAM_NO_CHANGE):
-        case Case.upper:
+    match params.get(Param.CHANGE_CASE, Param.NO_CHANGE):
+        case Param.UPPER:
             name = name.upper()
-        case Case.lower:
+        case Param.LOWER:
             name = name.lower()
-        case Case.no_change | _:  # all else
+        case Param.NO_CHANGE | _:  # all else
             pass
 
-    if (prefix := params.get(PARAM_PREFIX)) is not None:
-        name = f'{prefix.strip()}{name.strip()}'
+    if (prefix := params.get(Param.PREFIX)) is not None:
+        name = f'{str(prefix).strip()}{name}'
 
+    if (suffix := params.get(Param.SUFFIX)) is not None:
+        name = f'{name}{str(suffix).strip()}'
     return name.strip()
 
 
 def get_emblem(emblem: str, params: Tuple[str, bool | str] | None = None) -> str | None:
-    class Emblem:
-        no_emblem: str = PARAM_NO_EMBLEM
-        default_emblem: str = PARAM_DEFAULT_EMBLEM
-        custom_emblem: str = PARAM_CUSTOM_EMBLEM
-
     match params:
         case None:
             return emblem
-        case (Emblem.no_emblem, True):
+        case (Param.NO_EMBLEM, True):
             return None
-        case (Emblem.default_emblem, True):
+        case (Param.DEFAULT_EMBLEM, True):
             return emblem
-        case _:  # custom_emblem
+        case Param.CUSTOM_EMBLEM | _:
             return params[1].strip()
 
 
diff --git a/source/cmk_addons_plugins/vsphere_topo/rulesets/vsphere_topo.py b/source/cmk_addons_plugins/vsphere_topo/rulesets/vsphere_topo.py
index 95ff9b2..4929399 100644
--- a/source/cmk_addons_plugins/vsphere_topo/rulesets/vsphere_topo.py
+++ b/source/cmk_addons_plugins/vsphere_topo/rulesets/vsphere_topo.py
@@ -28,82 +28,61 @@ from cmk.rulesets.v1.form_specs import (
 from cmk.rulesets.v1.form_specs.validators import LengthInRange, MatchRegex
 from cmk.rulesets.v1.rule_specs import CheckParameters, HostCondition, Topic
 from cmk_addons.plugins.vsphere_topo.constants import (
-    # PARAM_ADD_DUMMY_TOPOLOGIES,
-    # PARAM_DONT_ADD_VC_AS_VM,
-    EMBLEM_CLUSTER,
-    EMBLEM_DATA_CENTER,
-    EMBLEM_DATA_STORE,
+    Emblem,
+    Param,
+    Picture,
     ICON_VCENTER,
-    PARAM_CHANGE_CASE,
-    PARAM_CLUSTER,
-    PARAM_CUSTOM_EMBLEM,
-    PARAM_DATA_CENTER,
-    PARAM_DATA_STORE,
-    PARAM_DATA_STORE_AS_SERVICE,
-    PARAM_DEFAULT_EMBLEM,
-    PARAM_HOST_SYSTEMS,
-    PARAM_IGNORE_POWERED_OFF_VMS,
-    PARAM_IGNORE_VM_NAME_REGEX,
-    PARAM_KEEP_DOMAIN,
-    PARAM_LOWER,
-    PARAM_MAKE_DEFAULT,
-    PARAM_MAP_NAMES,
-    PARAM_MAP_NAME_CMK,
-    PARAM_MAP_NAME_VSPHERE,
-    PARAM_NO_CHANGE,
-    PARAM_NO_EMBLEM,
-    PARAM_PREFIX,
-    PARAM_UPPER,
-    PARAM_VCENTER,
-    PARAM_VM_NAMES,
-    PICTURE_TYPE_EMBLEM,
-    PICTURE_TYPE_ICON,
     RULE_SET_NAME_VSPHERE_TOPO,
 )
 
 adjust_names_elements: Mapping[str, DictElement] = {
-    PARAM_KEEP_DOMAIN: DictElement(
+    Param.KEEP_DOMAIN: DictElement(
         parameter_form=FixedValue(
             title=Title('Keep domain name'),
             label=Label('The domain name will not be cut'),
             value=True,
         )),
-    PARAM_CHANGE_CASE: DictElement(
+    Param.CHANGE_CASE: DictElement(
         parameter_form=SingleChoice(
             title=Title('Change case'),
             elements=[
-                SingleChoiceElement(name=PARAM_UPPER, title=Title('All upper case')),
-                SingleChoiceElement(name=PARAM_LOWER, title=Title('All lower case')),
-                SingleChoiceElement(name=PARAM_NO_CHANGE, title=Title('Don\'t change case'))
+                SingleChoiceElement(name=Param.UPPER, title=Title('All upper case')),
+                SingleChoiceElement(name=Param.LOWER, title=Title('All lower case')),
+                SingleChoiceElement(name=Param.NO_CHANGE, title=Title('Don\'t change case'))
             ],
-            prefill=DefaultValue(PARAM_NO_CHANGE)
+            prefill=DefaultValue(Param.NO_CHANGE)
         )),
-    PARAM_PREFIX: DictElement(
+    Param.PREFIX: DictElement(
         parameter_form=String(
             title=Title('Name prefix'),
             custom_validate=(LengthInRange(min_value=1),)
         )),
+    Param.SUFFIX: DictElement(
+        parameter_form=String(
+            title=Title('Name suffix'),
+            custom_validate=(LengthInRange(min_value=1),)
+        )),
 }
 
 
 def get_emblem_element(default_emblem: str, picture_type: str) -> Sequence[CascadingSingleChoiceElement]:
     return [
         CascadingSingleChoiceElement(
-            name=PARAM_NO_EMBLEM,
+            name=Param.NO_EMBLEM,
             title=Title(f'No custom {picture_type}'),
             parameter_form=FixedValue(
                 value=True,
                 label=Label(f'No custom {picture_type} will be used')
             )),
         CascadingSingleChoiceElement(
-            name=PARAM_DEFAULT_EMBLEM,
+            name=Param.DEFAULT_EMBLEM,
             title=Title(f'Use default {picture_type}'),
             parameter_form=FixedValue(
                 value=True,
                 label=Label(f'"{default_emblem}" will be used as {picture_type}')
             )),
         CascadingSingleChoiceElement(
-            name=PARAM_CUSTOM_EMBLEM,
+            name=Param.CUSTOM_EMBLEM,
             title=Title(f'Use custom {picture_type}'),
             parameter_form=String(
                 custom_validate=(LengthInRange(min_value=1),),
@@ -115,57 +94,57 @@ def get_emblem_element(default_emblem: str, picture_type: str) -> Sequence[Casca
 def _parameter_form() -> Dictionary:
     return Dictionary(
         elements={
-            PARAM_HOST_SYSTEMS: DictElement(
+            Param.HOST_SYSTEMS: DictElement(
                 parameter_form=Dictionary(
                     title=Title('Adjust ESXi host names'),
                     elements=adjust_names_elements
                 )),
-            PARAM_VM_NAMES: DictElement(
+            Param.VM_NAMES: DictElement(
                 parameter_form=Dictionary(
                     title=Title('Adjust VM names'),
                     elements=adjust_names_elements
                 )),
-            PARAM_VCENTER: DictElement(
+            Param.VCENTER: DictElement(
                 parameter_form=CascadingSingleChoice(
                     title=Title('vCenter Icon'),
-                    elements=get_emblem_element(ICON_VCENTER, PICTURE_TYPE_ICON),
-                    prefill=DefaultValue(PARAM_DEFAULT_EMBLEM),
+                    elements=get_emblem_element(ICON_VCENTER, Picture.TYPE_ICON),
+                    prefill=DefaultValue(Param.DEFAULT_EMBLEM),
                     help_text=Help(
                         'Here you can change the icon for the vCenter object. If you use the built-in icons prefix '
                         'the name with "icon_"'
                     ),
                 )),
-            PARAM_CLUSTER: DictElement(
+            Param.CLUSTER: DictElement(
                 parameter_form=CascadingSingleChoice(
                     title=Title('Cluster emblem'),
-                    elements=get_emblem_element(EMBLEM_CLUSTER, PICTURE_TYPE_EMBLEM),
-                    prefill=DefaultValue(PARAM_DEFAULT_EMBLEM),
+                    elements=get_emblem_element(Emblem.CLUSTER, Picture.TYPE_EMBLEM),
+                    prefill=DefaultValue(Param.DEFAULT_EMBLEM),
                     help_text=Help(
                         'Here you can change the picture for the cluster. If you use the built-in icons prefix '
                         'the name with "icon_"'
                     ),
                 )),
-            PARAM_DATA_CENTER: DictElement(
+            Param.DATA_CENTER: DictElement(
                 parameter_form=CascadingSingleChoice(
                     title=Title('Datacenter emblem'),
-                    elements=get_emblem_element(EMBLEM_DATA_CENTER, PICTURE_TYPE_EMBLEM),
-                    prefill=DefaultValue(PARAM_DEFAULT_EMBLEM),
+                    elements=get_emblem_element(Emblem.DATA_CENTER, Picture.TYPE_EMBLEM),
+                    prefill=DefaultValue(Param.DEFAULT_EMBLEM),
                     help_text=Help(
                         'Here you can change the picture for the datacenter. If you use the built-in icons prefix '
                         'the name with "icon_"'
                     ),
                 )),
-            PARAM_DATA_STORE: DictElement(
+            Param.DATA_STORE: DictElement(
                 parameter_form=CascadingSingleChoice(
                     title=Title('Datastore emblem'),
-                    elements=get_emblem_element(EMBLEM_DATA_STORE, PICTURE_TYPE_EMBLEM),
-                    prefill=DefaultValue(PARAM_DEFAULT_EMBLEM),
+                    elements=get_emblem_element(Emblem.DATA_STORE, Picture.TYPE_EMBLEM),
+                    prefill=DefaultValue(Param.DEFAULT_EMBLEM),
                     help_text=Help(
                         'Here you can change the picture for the datastore. If you use the built-in icons prefix '
                         'the name with "icon_"'
                     ),
                 )),
-            PARAM_DATA_STORE_AS_SERVICE: DictElement(
+            Param.DATA_STORE_AS_SERVICE: DictElement(
                 parameter_form=FixedValue(
                     title=Title('Add data store service'),
                     label=Label('enabled'),
@@ -175,7 +154,7 @@ def _parameter_form() -> Dictionary:
                     ),
                     value=True
                 )),
-            PARAM_MAKE_DEFAULT: DictElement(
+            Param.MAKE_DEFAULT: DictElement(
                 parameter_form=FixedValue(
                     title=Title('Make default'),
                     label=Label('This will be the default topology'),
@@ -185,7 +164,7 @@ def _parameter_form() -> Dictionary:
                     ),
                     value=True
                 )),
-            PARAM_IGNORE_POWERED_OFF_VMS: DictElement(
+            Param.IGNORE_POWERED_OFF_VMS: DictElement(
                 parameter_form=FixedValue(
                     title=Title('Ignore powered off VMs'),
                     label=Label('enabled'),
@@ -194,7 +173,7 @@ def _parameter_form() -> Dictionary:
                     ),
                     value=True,
                 )),
-            PARAM_IGNORE_VM_NAME_REGEX: DictElement(
+            Param.IGNORE_VM_NAME_REGEX: DictElement(
                 parameter_form=List(
                     title=Title('Ignore VMs by name (regex)'),
                     element_template=String(),
@@ -203,18 +182,18 @@ def _parameter_form() -> Dictionary:
                         'change to the VM names. If there more than one regex string the will be "OR" connected.'
                     ),
                 )),
-            PARAM_MAP_NAMES: DictElement(
+            Param.MAP_NAMES: DictElement(
                 parameter_form=List(
                     title=Title('Map vSphere names to CMK names'),
                     element_template=Dictionary(
                         elements={
-                            PARAM_MAP_NAME_VSPHERE: DictElement(
+                            Param.MAP_NAME_VSPHERE: DictElement(
                                 parameter_form=String(
                                     title=Title('vSphere name'),
                                 ),
                                 required=True,
                             ),
-                            PARAM_MAP_NAME_CMK: DictElement(
+                            Param.MAP_NAME_CMK: DictElement(
                                 parameter_form=String(
                                     title=Title('Checkmk name'),
                                     custom_validate=(
@@ -232,28 +211,6 @@ def _parameter_form() -> Dictionary:
                     ),
                     help_text=Help(''),
                 )),
-            # PARAM_DONT_ADD_VC_AS_VM: DictElement(
-            #     render_only=True,
-            #     parameter_form=FixedValue(
-            #         title=Title('Don\'t add vCenter as VM'),
-            #         label=Label('The vCenter will not be added as VM'),
-            #         help_text=Help(
-            #             'Use this option if the vCenter is also a VM within the managed datacenter.'
-            #             'This will create a clearer topology, but you lose the info where the vCenter is running.'
-            #         ),
-            #         value=True
-            #     )),
-            # PARAM_ADD_DUMMY_TOPOLOGIES: DictElement(
-            #     render_only=True,
-            #     parameter_form=FixedValue(
-            #         title=Title('Add dummy topologies'),
-            #         label=Label('Adds empty CDP, LLDP, L3v4 and STATIC topology'),
-            #         help_text=Help(
-            #             'Use this option if you are also using the NVDCT. This is a workaround, as the backend '
-            #             'only picks up layers that are present in the default topology folder.'
-            #         ),
-            #         value=True
-            #     )),
         }
     )
 
diff --git a/source/packages/vsphere_topo b/source/packages/vsphere_topo
index 2800961..2275e41 100644
--- a/source/packages/vsphere_topo
+++ b/source/packages/vsphere_topo
@@ -13,7 +13,7 @@
                                   'vsphere_topo/rulesets/vsphere_topo.py']},
  'name': 'vsphere_topo',
  'title': 'vSphere Topology',
- 'version': '0.0.8-20240806',
+ 'version': '0.0.9-20250116',
  'version.min_required': '2.3.0b1',
  'version.packaged': 'cmk-mkp-tool 0.2.0',
  'version.usable_until': '2.4.0b1'}
-- 
GitLab