From 4535f076cc65474f5f85e130e09d4aa4ef4d1b85 Mon Sep 17 00:00:00 2001 From: Stavros Kois <47820033+stavros-k@users.noreply.github.com> Date: Tue, 19 Mar 2024 14:50:20 +0200 Subject: [PATCH] charts/minio - migration (#2256) --- library/ix-dev/charts/minio/Chart.lock | 8 +- library/ix-dev/charts/minio/Chart.yaml | 10 +- library/ix-dev/charts/minio/README.md | 48 +- library/ix-dev/charts/minio/app-readme.md | 5 +- .../charts/minio/charts/common-1.2.9.tgz | Bin 0 -> 63213 bytes .../charts/minio/charts/common-2304.0.1.tgz | Bin 4994 -> 0 bytes .../ix-dev/charts/minio/ci/basic-values.yaml | 20 + .../ix-dev/charts/minio/ci/https-values.yaml | 66 +- .../ix-dev/charts/minio/ci/test-values.yaml | 45 - .../ix-dev/charts/minio/migrations/migrate | 184 ++-- .../minio/migrations/migrate_from_1.0.0 | 28 - library/ix-dev/charts/minio/questions.yaml | 928 +++++++++++------- .../ix-dev/charts/minio/templates/NOTES.txt | 3 +- .../ix-dev/charts/minio/templates/_cert.tpl | 33 - .../charts/minio/templates/_configuration.tpl | 91 ++ .../charts/minio/templates/_helpers.tpl | 77 -- .../charts/minio/templates/_logsearch.tpl | 40 + .../charts/minio/templates/_logsearchapi.tpl | 34 - .../charts/minio/templates/_migration.tpl | 48 + .../ix-dev/charts/minio/templates/_minio.tpl | 93 ++ .../charts/minio/templates/_persistence.tpl | 77 ++ .../ix-dev/charts/minio/templates/_portal.tpl | 16 + .../charts/minio/templates/_postgres.tpl | 81 +- .../charts/minio/templates/_service.tpl | 33 + .../templates/backup-postgres-config.yaml | 15 - .../minio/templates/backup-postgres-hook.yaml | 40 - .../ix-dev/charts/minio/templates/common.yaml | 18 + .../charts/minio/templates/configmap.yaml | 6 - .../charts/minio/templates/deployment.yaml | 134 --- .../templates/logsearchapi-deployment.yaml | 51 - .../minio/templates/logsearchapi-secret.yaml | 23 - .../minio/templates/logsearchapi-service.yaml | 8 - .../minio/templates/postgres-deployment.yaml | 58 -- .../minio/templates/postgres-secret.yaml | 20 - .../minio/templates/postgres-service.yaml | 8 - .../minio/templates/pre-install-job.yaml | 32 - .../charts/minio/templates/secrets.yaml | 13 - .../charts/minio/templates/service.yaml | 14 - .../minio/templates/serviceaccount.yaml | 1 - .../ix-dev/charts/minio/to_keep_versions.md | 4 + .../ix-dev/charts/minio/to_keep_versions.yaml | 1 + library/ix-dev/charts/minio/values.yaml | 70 +- 42 files changed, 1227 insertions(+), 1257 deletions(-) create mode 100644 library/ix-dev/charts/minio/charts/common-1.2.9.tgz delete mode 100644 library/ix-dev/charts/minio/charts/common-2304.0.1.tgz create mode 100644 library/ix-dev/charts/minio/ci/basic-values.yaml delete mode 100644 library/ix-dev/charts/minio/ci/test-values.yaml delete mode 100755 library/ix-dev/charts/minio/migrations/migrate_from_1.0.0 delete mode 100644 library/ix-dev/charts/minio/templates/_cert.tpl create mode 100644 library/ix-dev/charts/minio/templates/_configuration.tpl delete mode 100644 library/ix-dev/charts/minio/templates/_helpers.tpl create mode 100644 library/ix-dev/charts/minio/templates/_logsearch.tpl delete mode 100644 library/ix-dev/charts/minio/templates/_logsearchapi.tpl create mode 100644 library/ix-dev/charts/minio/templates/_migration.tpl create mode 100644 library/ix-dev/charts/minio/templates/_minio.tpl create mode 100644 library/ix-dev/charts/minio/templates/_persistence.tpl create mode 100644 library/ix-dev/charts/minio/templates/_portal.tpl create mode 100644 library/ix-dev/charts/minio/templates/_service.tpl delete mode 100644 library/ix-dev/charts/minio/templates/backup-postgres-config.yaml delete mode 100644 library/ix-dev/charts/minio/templates/backup-postgres-hook.yaml create mode 100644 library/ix-dev/charts/minio/templates/common.yaml delete mode 100644 library/ix-dev/charts/minio/templates/configmap.yaml delete mode 100644 library/ix-dev/charts/minio/templates/deployment.yaml delete mode 100644 library/ix-dev/charts/minio/templates/logsearchapi-deployment.yaml delete mode 100644 library/ix-dev/charts/minio/templates/logsearchapi-secret.yaml delete mode 100644 library/ix-dev/charts/minio/templates/logsearchapi-service.yaml delete mode 100644 library/ix-dev/charts/minio/templates/postgres-deployment.yaml delete mode 100644 library/ix-dev/charts/minio/templates/postgres-secret.yaml delete mode 100644 library/ix-dev/charts/minio/templates/postgres-service.yaml delete mode 100644 library/ix-dev/charts/minio/templates/pre-install-job.yaml delete mode 100644 library/ix-dev/charts/minio/templates/secrets.yaml delete mode 100644 library/ix-dev/charts/minio/templates/service.yaml delete mode 100644 library/ix-dev/charts/minio/templates/serviceaccount.yaml create mode 100644 library/ix-dev/charts/minio/to_keep_versions.md create mode 100644 library/ix-dev/charts/minio/to_keep_versions.yaml diff --git a/library/ix-dev/charts/minio/Chart.lock b/library/ix-dev/charts/minio/Chart.lock index eca937d01e..f5ecd05fbb 100644 --- a/library/ix-dev/charts/minio/Chart.lock +++ b/library/ix-dev/charts/minio/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: common - repository: file://../../../common/2304.0.1 - version: 2304.0.1 -digest: sha256:1ed155c6760e1166e2cb75b52bc5e81c6bdf0252c16ff5ede001157077c41670 -generated: "2023-07-14T11:04:04.184288265+03:00" + repository: file://../../../common + version: 1.2.9 +digest: sha256:af1a9a1f87e3e48453c9f25f909f5ebcd7fa6e25162b7b425448ba752bcdbc5c +generated: "2024-03-05T19:01:30.381261596+02:00" diff --git a/library/ix-dev/charts/minio/Chart.yaml b/library/ix-dev/charts/minio/Chart.yaml index 954d25a46d..d323589b77 100644 --- a/library/ix-dev/charts/minio/Chart.yaml +++ b/library/ix-dev/charts/minio/Chart.yaml @@ -3,18 +3,18 @@ description: High Performance, Kubernetes Native Object Storage annotations: title: MinIO type: application -version: 1.7.24 +version: 2.0.0 apiVersion: v2 -appVersion: '2023-03-13' -kubeVersion: '>=1.16.0-0' +appVersion: "2023-03-13" +kubeVersion: ">=1.16.0-0" maintainers: - name: truenas url: https://www.truenas.com/ email: dev@ixsystems.com dependencies: - name: common - repository: file://../../../common/2304.0.1 - version: 2304.0.1 + repository: file://../../../common + version: 1.2.9 home: https://min.io icon: https://media.sys.truenas.net/apps/minio/icons/icon.png sources: diff --git a/library/ix-dev/charts/minio/README.md b/library/ix-dev/charts/minio/README.md index d21b8c0107..6f8d5e1025 100755 --- a/library/ix-dev/charts/minio/README.md +++ b/library/ix-dev/charts/minio/README.md @@ -1,52 +1,8 @@ -MinIO -===== +# MinIO [MinIO](https://min.io) is a High Performance Object Storage released under Apache License v2.0. It is API compatible with Amazon S3 cloud storage service. Use MinIO to build high performance infrastructure for machine learning, analytics and application data workloads. -MinIO supports [distributed mode](https://docs.minio.io/docs/distributed-minio-quickstart-guide). In distributed mode, you can pool multiple drives (even on different machines) into a single object storage server. - -For more detailed documentation please visit [here](https://docs.minio.io/) - -Introduction ------------- - -This chart bootstraps MinIO deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. - - -Configuration -------------- - -The following table lists the configurable parameters of the MinIO chart and their default values. - -| Parameter | Description | Default | -|:-------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------| -| `image.repository` | Image repository | `minio/minio` | -| `image.tag` | MinIO image tag. Possible values listed [here](https://hub.docker.com/r/minio/minio/tags/). | `RELEASE.2020-11-06T23-17-07Z` | -| `image.pullPolicy` | Image pull policy | `IfNotPresent` | -| `extraArgs` | Additional command line arguments to pass to the MinIO server | `[]` | -| `accessKey` | Default access key (5 to 20 characters) | random 20 chars | -| `secretKey` | Default secret key (8 to 40 characters) | random 40 chars | -| `persistence.enabled` | Use persistent volume to store data | `true` | -| `persistence.size` | Size of persistent volume claim | `500Gi` | -| `persistence.existingClaim` | Use an existing PVC to persist data | `nil` | -| `persistence.storageClass` | Storage class name of PVC | `nil` | -| `persistence.accessMode` | ReadWriteOnce or ReadOnly | `ReadWriteOnce` | -| `persistence.subPath` | Mount a sub directory of the persistent volume if set | `""` | -| `environment` | Set MinIO server relevant environment variables in `values.yaml` file. MinIO containers will be passed these variables when they start. | `MINIO_STORAGE_CLASS_STANDARD: EC:4"` | - -Some parameters above map to the env variables defined in the [MinIO DockerHub image](https://hub.docker.com/r/minio/minio/). - -Pass environment variables to MinIO containers ----------------------------------------------- - -To pass environment variables to MinIO containers when deploying via Helm chart, use the below command line format - -```bash -$ helm install --set environment.MINIO_BROWSER=on,environment.MINIO_DOMAIN=domain-name minio/minio -``` - -You can add as many environment variables as required, using the above format. Just add `environment.=` under `set` flag. - **NOTE** + - On fresh installation, minIO data directory's ownership will be updated to minio:minio. - For existing installations that are exhibiting the upgrade to >=1.5.0, the minIO data directory's ownership will be migrated to minio:minio. diff --git a/library/ix-dev/charts/minio/app-readme.md b/library/ix-dev/charts/minio/app-readme.md index 648ed287e4..6f8d5e1025 100644 --- a/library/ix-dev/charts/minio/app-readme.md +++ b/library/ix-dev/charts/minio/app-readme.md @@ -1,5 +1,8 @@ +# MinIO + [MinIO](https://min.io) is a High Performance Object Storage released under Apache License v2.0. It is API compatible with Amazon S3 cloud storage service. Use MinIO to build high performance infrastructure for machine learning, analytics and application data workloads. **NOTE** -- On installation, minIO data directory's ownership will be updated to minio:minio. + +- On fresh installation, minIO data directory's ownership will be updated to minio:minio. - For existing installations that are exhibiting the upgrade to >=1.5.0, the minIO data directory's ownership will be migrated to minio:minio. diff --git a/library/ix-dev/charts/minio/charts/common-1.2.9.tgz b/library/ix-dev/charts/minio/charts/common-1.2.9.tgz new file mode 100644 index 0000000000000000000000000000000000000000..ae3f7de88192695c57b87f5f95d90f229d32ffb3 GIT binary patch literal 63213 zcmV)$K#sp3iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0POwwciT9!D2~t1{wwe}&K;|tCCmGaUnlqLcG79z=_Ee3)BSxn zH!lY!A&Fy(U=xrWPvZambFdNs!9|OerNwi)Ba>JP1)w$*szN*-<8U9~ zxG#5b-^c^g6jMlJoRX6b0BB4TbOO%!ssO*nH#yAj0bd;(FpGafIf-$40;YQ#Fw2TR zcQ+zL!aU9>|N9gqvTDexf&tD!{Qn1U27@?^VFJz|g$W*RjA5Ko7^f&FCmUUW#xPD! zK!m3MzxX4$ClrlIFT~>w08%(cCxGS?ltQurz$8yjz=+a}ob2q}-QD%%CsurCLzEV4 zdxPF*=tKduF;y_{_V#-J*!a@;|I&}#|5KPu5P2j5(6IlH50CcT{eOITu-^Zxc>W5y zU9c75knCK(IDP)=MQGloOjQ$2aJj?@qRpHvk|gpT;4&$T7tsPEG&~jn|^+Su!CM z<>wcy1-6+9MXCCT#u>eT9_Q@aG`vKNxSW6iOb8OMuHt{A6R`U-X2S_XM93=~Ar1}z zU2utD^m`st^d=2i4MK4ahv+PUgq(mN&``%?geO$iOX4X?5s`lZ5T`MXVe%X$@cs&g zIE}~&*zL=&8OmcEmETj*rv7j!-w$A%OmcKR$`KjiBr3j;2_J#+WtV@+5sc!m1E4+r zh3zpq$>sv*umYOBN@$MyHTbDmpYa$D5rZ#B8748s`MsQP3WsXuCrNUFlQ_IT0q29) zm|o$e2uMOFUlWsWDA z@eaZ0O`6=Z+CRq$67q=A4onh!cag`_I6*`7f`l-ELi|zmh7k+-IWpf86oz=5UF3KW zCrIrIA*WnUQnu11o#dZFn8BMkiD``Vj)qZm0^Yrse?>Xgn~RaL(_epO2*;6lIdI1& zU!09#Iz(zt-f%>{ipdz#a3lboWLbj7D5WsrHHhw%+>?+d;_r$H%n`wpJQP4D@i<=#L2^R?%Ij;9>t2EBX4j^XKQMAI?rMt`z--Nm2z( zhNCx`7IaYxZxVDR7|XA5dP|B48eu|TBYKDP+u~)8I1y9GI!*52JzM2bO4K{anSPFQ zLdBOeoDSll01g+O3s{AannsusJ#}0TI{^V-!3>VmB!&bjv{Rg*Trpt&CKtyx5<9H+d!mpKg4g-v<)ZEl`oiU>y~|HTF}LNH?c z=rbR{U%~Gv3Go;Kiotb0L9b7*z}4C5uP^xL>k&+E!9AV`bs!}aCP|zQ!KY84Clt`r zLcr*8RRladfYU7NZLrqE388p=0)kJU0LA|ojuWui`;AMk;NgJ{TbE#e3^1l9aL;i# z;Y*pd&)->ZI8<~L69BUegfIm+2n_HfjR2&Tss_VMPj>LrWXK6(E+_PSAVwRrCcw>P z2;x-tunn>VL4p7y0RW~TCS-!lt_l?hQZ~IYOnWI(oaQ>*{V)3jLfZ}-f^MMEGz{tn=12HrJ{x?X6?G-wGm#l}3A%$h+W0GA?3i!U91T#;))Zh%ek1<);v+?Q3X}7cqI>{D zBuVcimn`|+`^WBsQD3r@j?Pd{<3Sukx}*kw!^uPeXYN@p^j=Joa(f|6P-&J#yWUTwvGHOC z`ir{8OMkyFFWwfVUtYXbZS(E3!I%O}c+D@Z@!OBI|4=l}61LuUV3vItOwy1u;hhgs zN9fUPe#20`{b%>!X#d!;{~RCh9gg~U$-^s?OPasaiWD+3|#2+GTQ2oYpSN?gNu=S=mj#Qcj+N9{=%K2~EaQH3}OG;^b+8 zVGz7xg`fWfxz)fhnjK|ic9>ZMqkAM8b{U8lH z&X)?)Rbhb=r3~|odQ3Bo-gMdIgrh;%=!s&zFq;5AiN&LAG~V*!qge%|)1PxZHaqM} z@^^^_HXP~{kTq@W8KX6Bo426ns|)5szOaIBcS2D9G{=~NZg+$UeVX79ChQmJb~8xG z9nPbto3BnU&rhHK^x^W&o9ho3r&m|Mzqx!K*kg6A{&gz@6q?dU6x!Iu<1tJlcc@)J zMx|HXu=FaJq%=;{s_MdM9H$&Ze9#XMAY<&~KmMbp1fh^l$o~Nm1|&f!1AFXuiUMaz z#ebU7I_DMN=~$U;cjnMLwqL5{FN4o&8SL%(^MKJG5WJMXI^Z)%(>nZ%3%O36e@cUriX;?rH6B&-!~v|;iU9%l)nsOLh9(#RTd@wfRG|E*?)ecJg! zSvXnmx9FaMlw!(s0K(=yPJxYtZE3-WDFJtg^Kd+&B#w}@Wo%vK_y*o2_u%ZjBT6TT z0#l*LC+P+di>G-G75onm>JUue#*zxyW^vo#t&1)FU--s3_U3Q}Bb1DLWVAEF_%=8( z6`%6=?j4GUBO085U^no5ju4xeZpIH0f)l`B@{>y@x4QC)a}4nsO;KJUxRgd+N5;M_ z(WT7i8iQutWh~>PC1vqaAx={i(yl!8e|pH7oioe`J1+o0;Ru7^cNkMfJDFOl zR8opLRYfqm?}01E3|WaihD4l3Bq%i{87A4VyG+rS#)M$%i{k>aJ+mk-Hp)Go<->GkPPr&li?G|LL?HWVtO$vE@YtHkL4l)%=HJtJ)pU(?t#zOxLC`r%>6 z1L%j%tq4*C{`Zsr+kGU#M6S)%f17$+#=44ffVvG>4- zb}3#B;xr~B6g{qp2Li?*0}!wd0uYQblfqo1K}iraWeO=3mTZsRJ6JL~-qmmDC72Z1 zHmNWxa)9b>i|x&W?&wPPL0(|VM#9!MEP;g?>{t>vt&LgHO_%l2+M?Cgpu?8oMw7f^ zF;Or3tY(}JQ@7bUXXJ+kAJ-iG@Q6FAD1NKl!I*lcppbmF;IOS&m?F_%nh{%UXDQ6r zVKoNB{qn4KrqQ-yufEZmMDo$kf11w!40bU08DN9|_tEjufqnkB*FQQwT%Z4~;<0&f z>Yn$}5u{)ce?-JOV_AUTR>~KLM}L>{1^;Er7lOUAHx_&4uokXl1}~LwIvdZlX6|W?$>456yu>^DaBs{Y36pl0lx z&WIx|ySvdCN1_}4%P4J?W5{Er*uTc>m-6*X`Pu|Q9O5J~F?yB=2wmtqRG#uGw+ zfkc8YTIg6tDQ+d(%JMj+0}xyo)1zfu&;{>U&G*`XhEpyny?a952Vm=8I8H&Z4Fc6c z$7ALy0Nc8a)99SAnVP~Rjsh{69fWlkFdQ$> zpU>3$%k$?8_xX0lKHs+JQ&^+j-Bu@BveJD2@^%~vQ#<~*5)pU%Wf}2scaO`6UNf3u zK6gh-QOsyM*cqpEN1gGWG=l9A$ z4GXt{Z9s10j0tC^NXAx1oEk>ZL0qWY(!w#xxdXzRJEm2S;*2{TnClX!;GF>L{Yl`| z=DrRmU~`K}m!KPh;K>9$83uA3opSjxj_mT#C~O}+pg$xXRVVTf58PZ2&If?MkBM+> z*e>}}D8sse-lESZ6V)T=qCfbiU>xD$0lWwQ@gH{4VX5d#S+rt?3Oq9CaL(qZ2d?Dg z^m;vWeg^T!513VW8t}Djpv$(|dfJXt-TKemi>bP8Mgs!x8gRFPz%Tc{j0Zrx<-R1W z$6-80sg2n(Zea;wy6rN`)WFQ;26NPiH!(UUI*=0PO1P`)qzQpmCpHQ>5=|T`a%{Xw z2(lNk5+6LPSh?wlf4R#K@7G3l&5U~C^Z~Z>131mH+*&C1l%Ty}iwD z8ufp9HSc^n(On(nXF0a(H3n(B-9wwYeNukZm@pO@wY zY~s)B1*{4zVByz&JiZ^WgP-<}zy*wdCQsmE6}CA-@s_sqOW`zYz46rN`e(Z{mdHqV&!$?=oohCLZ zB)5!BmNX_ue&*+?tZeDMWw%_+b5*u%%N1p*qAXKbeka9Szkh4-y@jw*?+jaEhih_% z)pnL8dBdvqeD1IoObv#%8BAr>9Sb+Iz)1D4NA2GqYdpB95_^>F68w zjP)&l+cnlC^kt&%C;pK`v@N#-$pWg*R_u*zM85(krFkq(q#EueY}JdR54~fv;d4k~ zVZxSSOnc%z`~H)(tCdTLFJg(w^5%BqFU)a;W)P$eRey#$93z6V&ax}5aT`00aaduc z6Tp`&hw`I@({lS_dVy%b<91Y->>9>nZQD98Gv1v9s-=3Rq_MI2h($eTm5W1$ zPt>bSz77P+O#Zef6%!-a7nU(Q6(p|YUyzzo5ViP5+k^i|c35AkZoy^!)m;xFZC2)u z)aY8vL5n;!nGG?v3RI;SnWJ=!Qm%59jD#x<2L9rtJtxeg40S$I(0Zbbqaf{~S11E0Hg4ZG^wnXZ{PG>1&*L5A^xh1(Xxf zx~ZA8J!6+O^#OY`rIfg8qsf$uR%$Sp9F93ol&cO$RfDUE_*7vE)G@Pn`~BSttL3s! zP>a~=Ga4#2jK&wsOWb(x@fDX}*N3Xbcpmpqb>}8dciNrSNm7=?pbJ5;dHLe``IQlo zs+)n$Px9rP%j*xX-@f|k#pOx&X#e;hGD6U2Fw9W~x_^L+H?LpLU{C%|hWW^cu3vJH zbtXj7S%dvh@Q@`L4|!ug%V7aZ9iwi`imMHV#pk6mkLLh&JkC6bKc@a z->P-6w76~4ps^cAdN=;^=IT0F()P6MhAqJJT^6_QS9olXX5&I`;!6TX_x~$sqc=9` zf6|!of@%8ms)3FA-;opld2hGBySLW=R`GC3ulzM2AftE;hA8D(M$#d;hvP(C0$1J| z86<=s^#ita8Nq}hoxnsh2?E&vbAW{xZg8|e}<& z!GS7R^7P`yeN|SK5*Z^LUncu{`;}Z2S8OYG!HbWXNc)iDw9BtFgLigo?}Lul70Lvr z0+1dI6Pek=aX-`Je_B_!$1e<6otvIl?c35tnqyI_8B%F28fQoqte+uOYB@7xx7IjA z)-HZp1ys*0RgIXdS3iL(zK5GIL&i7VY}(DHVLfih_+~k1(G4|YL{g`x9w>V9+h_2{ z1XCxftDs)~YW$P8mLzW8YVw=6o+f_Yn)<7^t|pJ(y85fHuDPR&DvEmY%P-CzEGVnD zH*Zy+pQXQN&a|8!`MamZ@^~_R83$FB{j0&hzE!TF#^tRF)-P^VYB?+1Zfz#gY*+0` z9_h}bc>A<%wOM>vhldTdp~V-yy^Ao{_4JuRY-~~qx8BvCRYpALtl7Z0R~szpe_;X%+4)dpd0Oo3 z?=Q{z-`>HloB!wNaCdjD|E=N?>XMpl!1GAXt4Q&s)6*+QYf(AI^o)KCz$OUr&A(7c zg?G|s@rSVe$$}@~dV~Ov=@-iD4ANr9v&r{1ih3tHH9V`58pge10UKGYSt0S;Tg=LD z&B_`tycM`R4KK-^hRQ`6Oot_mnVO))2G z7Ce&w};V%(p3raMN|tYBUIV7g74IZ7jxdsd<9AV^e~;zx&3(L5e^#Hi(>(QK?| z(AEP`5y@)PTrxGdGKUu4zMjhR%2KS zH#RPeR#IP;fLV3@o3?6eMAjkC<@Ps_hNGQ==Zn#=IsTgCe{~$6NI$IE_QzF*!a9H} zH%m!c;OAJHxT%9ybEgzf%S|D@%PKa9;}lZ$EMW^Rv8N12E9!|z7X;N^(;Q!m>v|cE z0`*F`mY6d_MmU#l5uVLrPw>i!je1O?V*+CCo87&t+mgN^w53RDq1I5QmNVOae%ny7 zrFV+l#NQVS4&8*hi!$rj3cxh z$=k)2K3mphSEa|UMu%OE{`ytxt}EADU7gk4)_(^NbphPIoSM3F74=(EPaj7${eo(# zS0!z=R^=;G3thDaT8a_%DDr=m{QeM>*qBdOXptqk)`!;m5cpH*Lw~lXO8-j{Wm9-c zDGWzrl+x!+c8>W)>sj@}#`_=pN6!8Ky}hIL{r{CbT-SRoCL0v94T|YrhGtl^n!fBU zk=l{h-yCVI+U7P%V;4RaM1rw^m4E9x#paYvo2tRPjo}B9lb(OiVoL(bjVn{*FiZVd|~8K+k&O z7wFYET&RqyyD#HTJ2`^Q>(cDxMVulkV+*PFRG{7gOp+TI-bzSW|KX)5-8G{>Y%#gw zoPgj4+@L%~6cMI16qGjV-rU=p+oZzZ ztZWK17{>Ho#-kP?KxCK@xuJPgS0=kOsgVkBViG9f%_iF8Ed6!;{)J(P2ziAg)R=IK zVKJMAJ)_DTWhP0o<3n1V04!ky+!wW{2lSWVnL2jlA*jehPUWErEl`r7-xae zU&m<2f{MplGlB7T?$oKzn`!+eV$xVqXiR+Z7&TU8rOK6J27S6ZUyeO^&xD&{LV}wP z$g;pq2jp?Um1zD7RL!>f-x(t-b1H!i`rpC+;h`J=K*8f)Vc=bO%*~?J^eMk5! z)dJ6&)WEa$dLS=apcm~wQ!_JSt9ao?pljR3`F{eVX|ZPEqLS}B7D|Ceyf zFm`;7q!!u(TcX4D41MRksE?X^z#r_<@&z4CZ!-M6KC zeN`$C;JeeW`0xQZ*%Wg0#{`igpF*|j=p{G>cM^q6ZY8yeo})&1l!RuX-%&tUhP1su z-*L{&PnG+xQ0{a6 z*Lu6JxBGg#TiYEcNT$q#SuAt2R_?nE02bz}4ckl09_>hwO!@zPdYS+62 zc8UG2^+Nts>3<@R<8m~>rt_bEDgXOXe{X&Mvyw+-j1n0|m!JWPW%FfqK)G~lwZNiG z8$GZnEt1x-V*EI{^xdBjLVa(g%PABt`7*l9%zDkhK6wg)HyQk6f~;<24jT8&JP1)v z<3Suk>f}%}+k6TF+iQm=R^mhBh`!td&pvxGNs=pL@U41@aCnPy;l}+hqV6)-UDkR5 z*sWI-ZFABhKsVDG6%EfW_pXJ~wNU!FLaBXb%JB9JB;^gjvv4{zptN5*9W#5!4Aey2 z&re7%%xP&ya0D5}3rX(g=m4c*QTrC%`)g-;JcSh9qI-Ykd1w=_*mDVwxBuEsZO<#| z%SC7&r^DwKCg;tB0%p&J^40k#t)Itzs^x#K@2w*L%aJGl+ul0=_i7#~|MSUSjsn1& zT3s9{*&&y=x9wEro`6tlq@tD961g1H(*2#tG*kk4iSZO-N~3d;1n^o3tSSrEc^XqN zg?S8b5=2Z2zd3^B7fk2{&Z##!_y`lKE+_lGXE+kju&?@NsOtD7qTm8YKo+@yY$jyB zcNG-|Y{`31@P?o?0qF1~d6kVt$7IQn03n%E5 zGL9E8c1^CUP+%fbNDGr(WV@FG^&tFdod*hzdPdpSqtamN0Z2f9AEDHOGA7(3NagRx z(KZ<1oRbG`U_8Ir1_Y~(N5CCUDWLg%;mXKnnQ1c_&M8q1u`cW}#{=NCZ>2l)-_GC?Lo5^am0?sgVv=-MOa zC3}b`UysVy4fr5Oko*(f%SJ_}d7RUrBP**Hh{a?=Z z672xh{sJpK5VY2E!@;0iw%q}tU27Jzf=1C}xo^6{uk7%fl7ZJU<)1*NEP!P?Cjv0Z z5sdBuOcHztCw3{Tl%zm`56&6idt1Fu^x4N$v$v zgA&_QThMw;l7*y{rKQu&Hq>O z2>#CI7`#ZQJQmgSNtW>Q*11Ih8PS4qY#65~@0n|97FhrU;=Wq|HpLGR+@kvcY~G^# zj&Q4-@611J-Zn5dBpucL??Mlz_0iY5z5aVeu;-8_FJ4?KtkeSDt0G7 zvPIh%(B2n+?h)Pt%C6Tz={)hhem5nYSw%^&W{> zhjK2SN@sE`M>3N1mu(KSo|svFP-*yI7zNl*H}$^kzjP#R zc4XJ^K=M?^jx*mCao;|JIHjI$oe2Q;$vVF|rzt@%!FL_7l~6fk)eCRCBVX#0^0hnG zlAKf!8bMZSMm;mYj9_)Z*02S{tmqsd3z9f1%j)4&k@SbaCR@P0FKeJf!h?{ zi6y9|z(J13z@7$Wsb;(=rT~4+k~oZMa?e}5(w=o7gel0;0Oj00l5f2z&QVB{`)#I* z@XYkQzZ*1y(-=>3wzQ$%0jxc?Ch&whFlc#k3lcIJBLad6K}uu{I*xOq$vf3F2YQeJ z=((O1HiCq>>Of$+k=-F6;4n8ZD={H)IuzQalv1^psaroy2xjf4NN8vwXX68$gYhJx zah9mcF%p*_wn5DBuZ>4IMaoH0FY~F+%4(xRd;CS(;V<&(NxGquXCJHKS*G^)8kxLu z-*Qmg3Y@xAXHgP+jj@^Ms|%-IovQURP-v;t6Xp|^w1ompMW1mBn7qU{L6##n7I7id z@NqU_)B@I@-P@!5RLg%cxuQ7B&_bdge;VY!{z2c(|9#v)I9khpt9Y8uH1sN{6m#sO z35qj*y*Ma|B@TfUC$hcx;~A5}q)p6qk}kS0Ic~F#9IHg5ySAwHr}z0XpX&W@#iL({ z1~i@j?)4Ac{eQH#yWan+c$)UVla;`r0U{TIO#ya(kbCqzrJPOwf|4Vk*F^`)U zr*xbB@8|&F91Ic+>Cr(?8CN97<_COiW~iVZ|3*1x0?Z_dxR8FsPiLnnrzny&DdsjZ zID~NuAQ2J`zY0cZ9%mpyFk-?aYl`UpUQfn1C?`d0teqD?Ij(@4doc#qkjkQ)+`)UI z&Of+l6`+7?lQ5(x?=czvj){~~qz9^XKu4JHY*6+E37D!u=zG}wg3FtML~}=7!;VuL z@c$nj1R#*e3p(nK05_m*jUc(m(IEZ^f_?zD70z18Lzp;)cTF|B5C_}2vYJDXwr z*2?$-2Z7D}zp#YPD*`m?f4loG|3BJY`~R-w5e(i~<-a+G@5Lp6VgYF(V9_H!v-vjX zcU9ob>U!&mMjS_F2iP{;FnZ>@=x*tRbw_zZ(^D=dW0(asr8}KECtW|RKiW+^lWuSj zyc@&p{WfCAa2-7TOip+QbS=`Qf2K{(8I> z9=Kgup!m(QNg9HqeR;|3YBJy^u5M5!C1n@~lO$ObPSu8eRg<@RQWvtPJl38=?6nzA zv}T2_x9w^C`%`ZTzX48GD10BfPe|a@7lo?TmUO|1kTL}#<~nMPc9&thi0^6WZ7$7i zsh4PoKEC3P62bp_2fP37cmMHzOa18n=jZN!sy{lP`rAjl59-g&Ky*>ZJ301D=MfHT z54@TXWxi&7oMD4&4=@EV$wn}pj8Ptk0;3@$$h01xQ*JR=_T|5I|JLJP%4|5C1yeA_ zgt7_HwMfr_wvx+Afi6dk-*YsJ{mbB-iYvna65;NCb6;3k#BJCar;h)&X3brP#!i>N z<-KL_8RRHSV2D8QzXK3_2xeP(Uz)IfBTp^=$8;6^f46^7=KuTsHUD45(`GAUZ6|EZ z)*xz(5ad_Ld$UvuCxqhhjFko$Q=_L6)oU1<0<@r++y`G-Q5M{~heP_P@R3_5IJ4JWBr) z^SvzVpK5Or+h1*%o}!1A5qhi&{wy6vkv1kp?--Y0P>hNrM9ZYe`+Ehm3WFl6)?iYs zHyK8H5-RM3J^)0w+BV2$IL0Z=?@a^Yw8B8hdt93Zzvxp%|HakroewY{F02AH(f|Fv z8~^=ycW-_FYbB3mC}Wci_~Gkf#9u~1Vahs#{pa}bc%A=!C67h_mG z{a?jn(f=3ebU9=nrPJ?%6ERkfd54ImuSG##DqDb`p-d(l8F8E zXr$b45rM4)rC@7w3O<8dbWb`Ru-lOijr#hV{t7;WL7WrX5ukL+lT{OQRGTSLI(;Tx zFhGt5j5>_q6agOkVZdEDN-mB6!f^_MZ4k(w%{LZ&1n2ZL$wshKN-*UKkhY0FW-t|T z5>C9ynY3q15V)27j`H<$QpT8ZJ7g*v(`!WidE%~SeDg2XCAU4uO64_gn6rCnIS5|s z`7-R{Yh^Y#~0G#2spifp{ffk!P|b=}nM!?`}=i%=vw zsEGZ>D?YXEh!oCJrQ&MUSSK+vFPb=&WQWNgI*d;Qo)8)Cn9C|UJ|Ap6>bg(G z+~{#HX_DkN-*TMcYO*u<-B648kX|rKq^OYOq(|qB_E?*n7c8V;`l>DU;>6`Ud?u$o z^wNex`)2}$q8^ss4hcCgb z(n9}dBH?4&e-921O7VY=*73hr^OW>|Hrq=x0wet+1RHg-XbuEu})g0-O8@Wrs`@vo& z)XBYHO}xQ$H2Xm0U}PHJ4(;v1sU8-cG&2kT;9u zi(IG865!EY>?*ZtaD{r)Mn$m|oBA4+1FBVMj1fCQSgjI8nwB8&>uyY{W(&dD_Fff6 z_UBiA3U4%XDk_vA3D;A@rOOAOnIV+}SrDUnAQZJ{0`H1f@xs=mD@a)8Ru+^ZU?i3) z2!sj?QDh}*993EAsWAonb+IpD54J<*G9AS`;=*9u+G1c*jOA)VRa0T80Q~ThFKT7z za`PX)_UcF9p>IkH`Ty6LES3Pa$^WB#{&#$|yY~NE$y1X5e_fjIhg>?}i~KLf@;HZq zDD@o$@~P;SkJ?yqSLmC`Ucz^@l=3{ZOdQI+C=S{{Oytp=ow4T&oKA{akPJuR!4|oT zlSW>^j6hg@f>$o-JH;zXm5lNhdnwq7o+^u(Ebmv^Tc1!+$ z$NTH}4=Z^r`u{VV?B#iZsI~K5aDZYkOJxB&KY-IIjw6u93CM7qQk1)q{H#EDCSlYt zIRwy`#nLG4rVS~Ddzi*i49{Rje3=b$B%Z ze1vi))E$8&2|y6yaW>(R@g_7*VtOBdV3@;f6o(`L!8DE#_E`->$OE*SsPTvx+7W}7 z=McDE5x?Y`jsrS2^tucg2I7xUc!r3F4 zTDfyKIaU}%Ng?3z57+;=K_ax4ZO;%9b zUOq`r$y|@xj{vXC+T5P$r*nBap{(OhMK%`Y!B2&WM)n7sQ)?BYf_)xu(!- zWfbU>ry$@Z%jwq45Y;BAHviKtJ#{a0)|pu?3*=fV$Cgq#^C)D8nSC*vP;+yGKm{kI~+2+jwuF}=tUK`E^Xu(X-63NbQG zb#~R@lxGfOx*VFKJaF`3+wSIrTX(S#){6$8H5=iK88FOo1spy&>ui}C$6qq({rb^Q zll+&&0~Fqe33|NzU;F*zV^{v$-Cy7TUddz0e|oZ)BlPL!z6*iR7|pVUy%EN@Cfmqz zbVZp49b}l$D++UJF^f%+>$<3bKB6!H!HCjK{zI$^C6Tb0X_Jvin*{@BTl^zsG@a$M zL*)#vQ#Wh?d9~7hPF|7I_Zxpah*jY2rg4Ph& z7&Ji<)4Vt`IY6@^Q}*nFn6jIIG2_~GFr7{i`u45ftTTDg!9TvVfn9x{ynw-M+LjdLvdttqx5ZCm!P>JT zsEP~Lrruosbz4Gd!{W6;SKwHy*Th|`1zgc)-3qo=u^wXeT6WfRbuZ?cAQdaQ2DcR< zIXnxba&5O<-`1eLtGsHZdzblg$K+hY^ASb`B+2ZXtd0pe z6>NWzogcvUBdS3*v23Cz!joY^}`!OAG0J5W14W^Wj1hd7bl5Ti;w17$1Nn36)>U~>c(QT z$7q}9+e9DXI7`qrTY2|*B0S0=xIVk!puc^7AxI9NMn;_oTQB@oIvL-fyeA_mj+5&uisn)I2fRia`=q7-3E~8ViKPsd7(8n zo;Hy?i;Yl{5h3;Kc>#ALlv*o>sWX$D@hm(TNL}Dd>tbKxY1ID(Q~qs{G*Aut|K9%o zk#qjDdvvt+|5?dn=Kn=G0Y5@hHL+A^VTG{jTqt0wT!zA) z;cjcFdqUc^BweL7l}rPsU#hEExnnZKbJK26Qj9!0g6U(foQ;Y)fvgd9z}9AIx;q|e z{%05`tieLxOL7FGdjNIsMe|;X-k8d=I9EO+dZVHS70t@<#Hv3gpfOIAU>Nyh)pbiD za||GS$ZZ`cPA#xY^v5L5c}C#`K|(piC4_8?sknDng)vFyw2N3$1*jfh6$@3TX6LGl z0&ObmaUI?&1;#H;UBCXPng8RPMUw#6^Z(uc?olcK*TK=jn*XojvF!gBe6p9t@>yHo zhw)zyW!Y{YyxrG4BYt5TN#ZF=5g`Ex7>kPKZ=OtklG$z`yn$=S7sRrvC{xQY&%!{S zymx$Vl9nBguY!82?Q?<<73-2v+TqJh1axgdgF8kzdCnAIzI118Tp}bXlkUM*d|#`@ z8e@cQ|5ng%%ikrjt3YJ+{c7EciHnpQbXBmN?!cRsL_!&Hb_*sn}QrXNq>j-F= zUE%QdOO8RXh(!h=TKH1%uh^?>0r)+%pshf49gh*7c%3S0!PFZyuqb^6tPO0?QMX(H z5-1>-C`i_f`x})fixDkLtaPPHUZ(iVlsu`Lp^9W0RZLPA`} z%VUZJUsXrO)LJZ>v+CF4ZuTpb4^h!V@!8j3#nls@t*4NaV_~{`juLo(g+iQ0Ok8H% zb&{j&QI5z6ClM39Ct-*PF<;5sR$0tiw2FNvn4foR-HJ#)x+?VU=`hk>C|#RvnuWg zoGR{TR>fY}P6hiTD{d`&r?mAAtS@LSognn_x2BW-TPmA{k8w^N*+sm zyHu0C9LY_uo$o?wGe)y)L!fS&6=H1hIYQYP&PrG83m|I5F1w7DGm6)Kk*fG!*O-r$ z&lJOJ>Nx{0Fk3(&1sbTf} ziL-0_*TY#11OsWcP^=T^@fIi`mQ2Xz9@5uN)5O4*j6croB;$K!Egnm4&$ zh5sT*z1Mv05Gqeoi2tsKwLR@PdFGdjUDn17z?Ymu8=R%hnq({4?9saiicC88Ue}$e zNHV1i;5PQLT} z;1@hO-`Opkx^{j5uU@>Wtnm8vES*(YTus}o@!)R3-5o-3cXxLPPH=||9w4{}cXti$ z?g4_kyF1L;b%sUO1Mb~$5V$S^;v0#mdzkLKQg(+FW2T}O|o%N5$rn4H_j z9Rg>M!&w|#+*kS(t6w5R*Z{LbvqPW5{i%v9P`< zoQBgZ8l&#yI^7({G`Gob5^Cf(;WV~q{pj#3eT%$AUmja zC)8+PvQr*u=vgdJ^_7!QId?S4t3TyyI)R*zGMhtbt~+wd#7O41?nOE=@Lv19c)NN{ zNIo^8xx16M7j4dP+*a%wvf_bDB=SSOHOQWBiUC72?C5JUw@kL{H6u?@D$+#}jNhvG znvD|axdDgXOQg028~Y9eB)bK61rQ^AX_A43=9%>eLI1NA;TBb|XXPs7)NmXosFvpk zE)_+7_*+pVSnh~8P4Gr@eZTG|<1=b`cVpf?qksAt@I5`uTM3fj3~2vU^wiz{$?g@f zB^h_on)%7ddoHrCtQ)y@&QyH4qm#>3TttGpq#fmk8*h@fMVJNyVYTKyiaFGsU-{L3 zDr)IfjK2zTq6V>>n(i^x!q|;Ho4?OkiAvEFwzCy-EcuNd<^#YbGxx>w7Kp~;l3-0U zn%1mU!_tI(rf>BjPA?RNS+!2wOHWZ$djeSs5tD`O%PcjGVMaUMZWDwt0hY7Ks z&iPCEUzYnnNUz6@#I}5rKDy!G)`9P~DCVjTxMbdV-{{5<5;&XKwUwIeZ2G<`cTdhT zKc{K0^6As`)obK>cnlA5SFlvAz52~w#@Ycw-Y``5v z)DVHA-1~xg9Iq~#mt|GQ1pW66Yg$L1-pS@Cwhj)O3Z4&0Eq$JqHq!BX^8wEE>J`{q zb~(dk1$R?6H7aVMVhpK7DS@pCiNyo!H-21pP6Q=xICPpYRcdn9^1X8Abs6;Qi{%g3 z$z~BYy&ai_TqKmoqeMFS%2(Vd&J220(LWSRV!z*6+j&G zyE~>3>E{f5&6W9bREZg&-n#Rp@KT>xQ8T6=`|`kO*^=^nu_@K7H@pskhP@4j(Q@V2 zPorgVYnoT82yyK2hZNC#CdlPnZF_+q=4SB^!GSYV=+n}dU)$UBW_?_jmvldcI1K-T z#(rNwtJB_r;#}U{-+oZ5XHSW`RBXMo-27z8Nuao9e9#$}r=lQD_vw=BYBd+)Mo@W4 zjNNN7=bL&)rEeA}L|E~`IP%6hbBgd;RzUGO$HVgjHoNR!?{9kd#EH!Us?yH((@>+} zx{=HSzhqNqeBxF-V+6sXM`4gVg|m(#79Tm@*2Zd-BXHkh$Y6W8YPRAC5tOrkK4|yGNRsgN_?N)2_g4Ml z4eZ+(lYRrdAkARo5MKq8@!rx{WuuUvHkhW_vGolJ_U$ZDTQ z`@*^v72}`RI`oXyy(Yl%2}+;82)-|ei;yG@AUlp*xTvpJzw!81oRIZwR!)r=H;&_6 zXes`xJKzZxr=HR_E2P{19Mq%-*JEA4*AUDhp2UAwAtJ`B7Z!VYP%zD2hlP;QlQg*gP0#pOu(zsm`YGFw{$nu&Z<`%xUcBaIWPB?`Yr z#f^h5nU<@gamt+KN>=JG>M|T{%;~0HuW5C8ZDv}G$6+PDsyWELLypTf=r(6VNnD)b z>LjN9pK{5qyecJVwr`>;FSsfatdCDn>;9f|mM@sVs{4gVk4Sw;x9}cNq~Z6p-%+vX z$#y;A={3B?$O@P|*iB`uB*!qCtzWgh$gMbkpRL!I$ zF-N1>7g3s7limNlUhm-cMZPDrs<)!=S5JNf_rEpdT_;?4xlFG&Af=RCxE zJpOy=))Yv2k5yzqSMMO2GZwd4kXtpz&~{gUd$NrVe1K2=hLRLIu;l##w(RCvgx4aA z9m%9NtbhJCb{Jd#+e%=DoN&qaLiU@2)S~;VRgqUXjcU_Xf@6c6MbZ8MBA-rOfq$2cGOfX+z&6TYWu?p2RKhF-Uq;RtEu^Q1Wl8qSc6oM)L#0Zrsb!i4J3 z?=3{Nnk@RHBCv-H`=!i~%p2j2h&zv#pMw)#+3-J)kGj>*E6{u~bPWo#GJ0WEXK6Hp zM7aZXgU&Vpp{339nqz>04QqHDBvTW!U80g7fYw%mksfjc%-}O-(9;wa5xZ7AX1WiQZv%WgV6V$d52I< ze-APVaiQ2|FiQIFGtN};!kueAJ!gf&K%}zl+UUF+VG`(rOHHM9CxXNakybq47c@q) zkup^Gc~xaiVxGq{81{$Y(CGc`(R9a6&c7o)nSkgQpw12u-hMf@s&>kLQ ziC(%FFKaG=s=fGZakH+#Y$wWzQ3{3J#yCI7RK{tKC2oh@t$JQ6q7y21n#`z*F44+Q zgXV(Bw7jRJB?%pibB`|=6DJ#&*HW&2YAqdjSB&GHCwH>bjasi+1WF|vr%x-x1)o!F zqn9+{PxkMam=_~Tu&gMwSc93K6jx!c=3dZXb1f{z>;@hUYXEf&|840c}wnD@R ze%?bWcR>7t!_#qrU20elO?vmqD>rr*unE~covc8l$~4aW%td~WY>?DGfHg+8B&Q1d z-Jr5LN6S_2T}5!W|EUgUn$zj4SXt;l9RqbQ+Q`ltu|mb)`Z?^3K=~Mlk}6frBRLIAi7F;3We|nVIyPHfLH5+T`BLqVAz<*kz&6GovXS@^wHJk%Nb)AOW;tMM6Yl79C53P#ERQZ~% z8_lB`Mn;(|r(peqwXL3IupB+91dGp1;PO8-m^>!#503a}eGBmp!fhBx3WD14-?RMN z5}Ca?KelO=!`p04Yh}VZH$vEi*rkRho{%i#;`lSArFy3^p)Pr{?7EF;h;ew_>`r;; z5k+v42B4jCP1L`Q)$)1foY9JyJkV_R0wu*;E)K7{95K>a2o>!((>b;1iy3ucH~K>-UZ?hcrBgbsk&$dx!y z!|G=A=7nHWWXFljFE#BbEqm~)?+ZE*)81vN6U!UUYA}L4#gz%t$}<&1)L*K|l)q2{ z+~IQdL?j+pW=6EcqSVtiGn#X3LhINu>8Tk+ABSX^3!#Fa2`e=@Xh8THKO9yDJBh!z zTVgK_+Xd3XpV}^%vA&a1A}*VF3iVL&GIP&lLgo@2fdHq+Tx{UjDeJ@Fh*hCOCKyFi zGl_wSqHyM#D(zl^wZJIO#nqfPQioiEK|^C!T46k`nCuHk-{Y0Dabb-vk1D@v3|57~ z4}a#~T!XhUECt6TT&P=!*0$|m7;kozE_DE)eJ0O~ts3UN?oLW8;F5%txatv*Bk6J& zz^<`8{nd4_a$nA{YWKe)j(%q0wef->oCy7&Y4{=oj;-FhgzH3#=J_?&#`z!ROFpSL zRmX$~4V9k!t)kwMbQGQVm)48p9{xz8g@=xeN(iAg;r2X6@~KlU&-7zRwbNd#CAtq8 zUixSc_{C1)`4^L&>&rM}CC;S`lM(X3iDcuo{r~jw_eK7@2suD6O<_2FTmYv z(QD2pJK%$4;mArmB&s!{n{aYV&U2zS$ZH&7ak7ZeBk@$_B*1?p;0g}Lk%l9~of1j@ z2^Ursn4Eke`8S?U=_f@{ktx=Q6Bp8|EzxTIG@9AJQE!60*bzc;4eC)7>gI3G@odYo zOE`TnolbdQxfa^UenCXS>#l|O`7jh+S0jY#kc1JtkH1jCnFS9*hx68M8w96F6^(@6 zZ>0wg$bt3l<97`3%7*bRZTD=#zIsJQn%GErHF}6wqJ=l(k0_4vdO3uB@m)Wm-mRW_ zGPm)@9M>E;(I;YOI@v>sN~J$a1^ZvFqb_ z-CaDLKC}M*FDH^MoAjR=5|;$L8PcDV^;_Bk5u^};)SLhAUZp&yiimk15M<*=bk0C# z3%-YYzb7xSAJh?6a<{%?IiqV-fi=hNa4OZM)9P2|FlPY zC4UO;>RX*l@$}Ex0<6|h-`4=&YQPu-n0$n@6H07>@!*HwEnPMRhGW&rNjNhbS3CDU zHLNdOXTU_gmcZZV%PwDV!=kW|-hZH-jWf7iLEZR3r`u8x*5wrGa*Hbdkd0TNV2+Bg zcQKKjhf7)XA5|Z~bqPod1LyxSLHEy>W7#jao79f)-qSy#%k5r!U2?+SSz#I^xk0~P zg^Qj*?Zduy@1QTSNq{;Dl>8qHC;_JdAoRf>Y59k`>}^NOw{!$<=Kg?uKIYMwlK~$8 zL@!=%#6mc;A6yPJl_AfM$h2NCd3W0Dv973n-PtR|t# zMj>sD8$f+4{B4{X(fZ}^eIpwVTyx{dTnNK;1*~@peg*piUc`X^msoA^q3Enrc|#4e zGn(+HSyQd*2&uT8&(tw6g4UU8zYi2!)*PxLu7FCed@A<*UJMb*2o_RYv!p;=d|+q*i}%8l`LHaN{etmw(wO^tl_D*5Zt3hn zelgUtr|I1BB4~Af5PTQA|EN5`Np$WPfEDQ-Bks+-_y7Cy zCP$FdkAT^(Q{dxp_U$PCfPE`(LEQVhk@UtPnN_E{s z!mJ@O+P-R8LnQN;Kfo%Q6ZBJozd{8Q#fBzOtx-b-Gz3-H?VQpixOWtA5_OIa^n%t! zvO=a{llJ9dne{83z5M@A+2F|V2`lK1_b_+m7`39y^i|>H*4(`@;(9HbYAQblVJ!RA z&E-hFfaW*dr$MnXX#XB^k_B+zS)uw^WzPC3-XFipEk|Q8WklV=vpaqV50-hw3=5pi zYh@@Pb`-bCb1AoJsLQMu(veoo6mbTdX=J0J)1v$lRsY4s?bq?vj#Z$vTbo*doS3%r zw&5kaJ!8FPmOzEa6CwVa-T-g>?vrZz-&ahwq>bQd`?4NcG3vSfP=x56Mvctwd+ix3 zrK+oTFQv7ZqvoXe7Au-@X5*<>14*Bk!Ykn?5+u2EQHE_Oov5BFW%h=vCkMJ{zMXQ40hf~3R>_qx*F zXXNbRCBwd*u%*iaM?(aOGUcPLv)RCgw$SYi=F5h`Kba2i^-8j-%;84j&6jnKuDYpybd{RE@6Wl&V5B~%y<9!*n2*oaRcVVxz7!cVYtypUFuZ9 zHLM!$2g?nGU~BucxRk~5Nr)G{vFsd1`9`YRW_c=9L~n-1MM0Brk)ou~#+`l6Tz0%W zuDxK#KG;EBdSer}9ehASSN1oGO$|i?KGCU9#^CODVVp>r0|*o?OKUGa;EsIptgGI} zczj`gbJvIWT6hyqf9)!H{n&N-gFk@L+p8<5|6)8k55QqfO#qi`FIR%;HXaT_ekA<& z%^+;_BG*4Y+{*xG;Pwa7!6Q!-lK*zdL+jCIvhBAw3Fg>kulahB?2JlSB%##mzC|C% z#3H1zkz4AZ$3k9V!`qx*{1H%2;TWWo>%1y`bC?p$#3SXz@QitMJRqMXa~OpgepBWL z;xW!`J}Tmv%~%4{An2_|!@hLHTXV;u!cfY99=y8SLv-=Ul|a+!;pDJ zt808nWs}V(H9}3rQ~9~Lk5Rf@zl8ipoFW@kqB&PZYmO-7u4tZIkNLG>yCVOH#=;hmtQ#kC?h`cXJ$?G1SE z4|WHC#KTj-+Sxaf$=xo$HY-_<2*>I*#iwB^*A`lkgDG`=11j(D?vsq8L6@17HVbOe zH!7-6r+YjLcR6L6C9=o}dh@7DZs5g_P}MLMlWB)?vtO{XgL`bKkCU5#z95?h4effXh|7dnLn zyG0cl=@!i=lH|6!Y9&hhq}JW&i}Z9B?N-i2?M$dva`Di{#1BF=%1Rm>QQ5rv{ZbYL zQkyr2_W^cUSw)S_{=}API?42g zY9bJ<#_74gx1Im8FqD%xxiAN!;b!|dW1+1-l#}-a@c*L8H(p2GQ{#>J*LW-rn{4}d z&|b*(H3px9bCY)itJU)T|8ma8A28Y&3b2(obyS)>Y54R#%XCXFSSwcIweJd(=Do}1 z*uKOf(zv3o+#^Y6fhxGvpn6@uY< zU2y>t+{s01N5#<9E~d-zjgy{}KT?Vb5~1m9E*&eU-|_ynEqcP}WF^!o1Ri%{sr;5m zIl$U``JNH2SrU6sIX8-617cz`<2|h)s;Fa4W@4hAd9&D4W%gT3;E@O<{mxHnpNFwf zlH{;3-zRg$tIN}nVy2hQo5^2_Ny5TmQPGAMw_WMK2$CRgT2LL2rjzWOMAK;2fRq9O`ntVqHGD71 zP{jC7l78cf=u=B-YX&4bR#4kFAzk$%HtJMeL+Vp=zr}%=;lZ{L_hvDMx5{8wSB5Nu zr4#g|1rY8$`?uUn?eH)Scy}R1At!=rA6%E@^+KI9MWNkfb4<$LlUT+N*3fGEN?m72 zjVS}&wKJDn^?sk-{U6<@+G}WLTP4f|BzOM7D$k*tirUmOwSMA(jq(YaG2K>tCp0aN zlHo*Q8{d*BLj2gC?2;u(t|vtU=$OV3SqLGyB$nfoAvFV*~yc+;0uIM60SJrtnZ)caM>{t@iKV2(>3R&8pa4`8u-Z^FtN*F zT`A7$Le2iV$Rt;bb9xi*Pc(%Hjc!UV zyBxhjPh5m*h$mj24G{%YGipokcM#!O9e~Pba{5tZ9o&u~=N_L1AtNK8P$WQIC~5|; zPrOlhbjOT!SA&t)LDpevD+-TbwjL?)#ig>}-ev5TCud0uG8pLW@UmO7ShGPi4Kgz7 z_`*h~Y$ru0y#p`tO%j^ok0{mmNLn)-+utg(_-*`$NBNc2i#Y-Ink{#~D`dVIcJ+j9 zmYeCyoS7ESoF)an786n4xdBUgZ15a z`3v@Rg7A19b}#ee=FFUv@2b=r!X(Y368HX1gpARt;=oL>Ye0?vx99#N^V^I$08udY zin?^(z`Ww`HS-Gsw;g@0Hwkk}euoPx?h_N7u+V-JKAxGmm9I;J<^N2`*-u(W(2J<@ zujG>MN4jE9(Mrn$IxR96vNGOAQv4bAb$k+#tM{}r80Uk_ce!|0qzqCd0Rfv$@KJLI zHd|)hoEcp~w>xoPlv?f7Oal4I{1ATSQs`qFJ407>%bei(McO{SU>tpH# zY6m3_^81Sh;0WJV-0rhKNkq7madycG#yjhwE>#)}dVwI4=k`!H5+Pt5|H?-lSET)C z=-)%C5roY!I7M7)zHy>jFq;g|!3of3tUaug z`g)F`wf{L>{i@(>glFT5xWBY|K(KN7Wyd|8FY#6tFR>q?Vmo9LJx&v+`ZsID(G8XV zJ1PdKzGMZQNIBI3+o^K|C6WjnI)4Nn-TWH6r+~JE;d;Ozl3tsg46pG`2k9uI>6NEI zr+N1$2C^E0OtdBbZ-a1{hBe5Rq3x&Oaux6M3yd@xg4;JaC$#!W{0zP`JM%hS5{nHEf#8loMF+!|0@8Npz>4^@S@P)uzhQDuPLCvZc@(&euv*$jwIaO+ZD&BhSn(fQ4mk z1f;AGsP>vVKJgfnqPzjQmm9$9>E(ING)U`a>CISycgwXa=~uu7#f!&az+aIRW`q%v zHQ&H-9H>myr8OS-Yq9o2L~Z%~nVulNWKD@P zcE3FIkHve%>_1#tb@*A2VatWJlHEZq@Nu#+A_~i;5ZF2w_ddn9(eBN;sL5;a(3YY& z;hu!{O3x=roq8Mnh{SVH*_@dPY3G!?M+~i2MIp0fGzRI2FOWUF`ZK6;Mk4Z7oM5c< zo7HHJO3U_Q$sALD8i+7AsKmXlfNq#AT3V4_d`n2{KkmD^U;5)uVJ0QhPM~Ym9*<(n zeMRb>?c8iX`AlyMEU|KHwl`&`;QAa7sk~P%Oc=D^HmKbDWV#k_Pk$H&1y%ifm|1TI1#rpdEQ*-C5AYZR@Ko~AzyOMeG1?!E{AFFrO0n2q7l+)Ju&vY37yuC?d*&eau(jc)1L zT^4(GMk$a>oT(O+Bud1M@>^-pk-d6 zdmUwpYwev{^a~p^^gcKaY13u5pH(Q|NepAU(ii7HgldTtkCz~K%}Z0S=nXY(jaUC6 zA=yzA1pe)yQ1Bbq7ztr#!hQ|WgMmac2Y_5UeWm@`K-c9$OW#~GF<0~Vt7 zXF2Lv_<$C1*W?pZXqpw_i?}IVmV6U8F&q#4_gYWJ#8bkMQE};G2de{Rmea59XjGEP zT)*R(zt9dGwO_m;``NL+X}qSZ>JPdX{An?#S{K_0_iE|rMHFY*-6%t59j~oiURZ}4 zNUI2FJ?`pqb!(ZG%*;T1a9FcJ$41y?TYafwlCTVZZA}p@J0~2jw?7-esrR#Lo&kj! zh5sIDVdf>2FQ_Uj$c~C`?T`%R3Lap2XVM8p{&q}ej)giq-phsjJ(v7XL{~0Xp7|YY zDA%2Anw%ZHdF3AFHcu=?iqV!E7wr^p8qU^)MR8y&o8>nfJlxnCyijO981dy+m4926 z5OzEVUAd!~GKVHw0S)jZT(m=oBMH}&yr^W1(|q=R4aCYVyJd@#>rOp4q<6OuHCGwH z7Qm;gR6qh1_07EoKc^*+c?g;K}+fjPYZJv^R20sNnQPhWv#?A1a6q^Qc@|FS@771im-QG$Zi zAK{O2OzQ_)RZ}HJb^Eo;nvF2E)2BrLOr+WF-|^4CJ_`?~Il00g3sgUEgatPq>##&4Xk_GV(qN{m@R5jr<%kyJul5~u6$MoN>h zQcz!2>4v;{DRxyPqcTt!4^5?_)jQ4#w-HbN{6%2ljV5>#4b5_!(<|@?Rx+!aVNKZZLXYvwW^}?f!C%bvp zl*ZQnrP`->Qc1-YnKrxI!x7EUrB3Ro>o71uZPYBG5_9V$>B0O%W=a^T{J(9#3>{lv zSn|dtc#RXfUIG)DaL_eqm4Yc{V1(JZyz4j|U!6(PHdh zYj!)`!H3D%;$S@SXzrvKJJ-6y05$i1bAFi87^W2(g;~RId?y}?y}DLkqzuJ<*fy{w z;dk9BKlcfx(7|&O%gqn($WYMf{vfGq+vAI}xU}!)T$iv3S(X%oyW>20Xy+BMnqR~` zrjZtijtftOdn0w-K0u`vGJ~|FyvqaXR2Stad1qn1i(PEeP{=E2`~H($C$$!7)PA$V zb7!TzOer*+7bM)?3(d?~zYHE}PwqBwj*o6N(H%;=l^Bppmt>gVo=BsS|HR(lRvG{w z!Ia2#)2fMnhKxAULPUMb|9-xUC2{iHt!Br{44&&^1kY{rfp_I1dw~TN)|7MYwO<0< zLph$`W-CDoete(t(!lCcAm&J@P}h>T6?Evm2Dt46xd5>_I2o_M4B)@&NHW0Zw!-cN zEH1gZw5+>VgwF}n?ffEFKmLMl4|d)+eu2NU>vZY6*0sM23kSXIED!xm#nTq<0-s91 zTpGg*ypU!9;6^)%A0^$mik>-$3ouSw7eo6N5OpiCUyL4DU$oyzUu#}LlB?m!zSfV! zlgt*2`R_<8-TCjNHo%v2AlcHLzQzy3gdqQxjaoc`j37VbHHl5r%IY#e+vk}#Mhvs~ z(z1|eSl$>POCJ1uW}V$_QCV< z%V*cwZ*be&!4TK8n1tZvcPmdMgjy{;kvp|<4FqG%L`ANOvn%}+R}ptP1$$F527P|^ z$_5L;W%Fx!F7qzuV~+Yz%AD(N<5~7(kMbAB;hqt)H3GAvmQQ}rtt`e3^Wz}7DZ})) z7EdpgKOcjH!6r~$h<{`3fvs2irftf8zqHrg!DzQI-BC`em~(SZ4?5v*(E=(Lgwb;6 zZ$aM*+dG~%Kk-Y$fNkg zAVpQueX{Ps!oNBRB7Vj|G8(*@yc@qr_{Vqf`Q)jZG&xZ3F@tHd8fPzCq}2V$hYW*4iLJPQGvzx$ zoy8yYMyD_cr*s{`#48*~*mYI}&V|omP`DcL$7a z%(*qNcaAOd_k7sZ}(_43>*$9AlIgQKs(!O3pk};3gsngg)sw_x7 z&a#2Oxn}&e;=8vfU+(r5Q_p;xs1{vw+cmRd4b5`N_HoHG#CN{xbY-wwN8I<_DS>+y zB+n(v2`TRm*u*=EE*>uPMtMvYt@Or0+1clQo;V3}h5jIs%$AFA`|3{Spz;K?*Xfy9 zDk=meO+=rU@ene!A+7-*o?v8@4ga%GRLh&@iFLDHqfBg9p)eOWIDY(`yVGwh>K~t5 zP{3A$aNAOZ6K`rc*g#^ue>46Q%Q_2w-O9!PkoZ5Gd~@o-F`)OSPaTDb&0XLy4eZB; zq=T;0wOS(LcYezoJY7O&*qXSn9!qt+N`Oy-I`UaojW3tPYDV*-KsQQQS2i?jVzmr) zR-1$0LinFhkzLN;CS@DOZH-DI^61F!&B}E-!|>Ir>UB9%N#`+O6y@P1hwLdm`_$^6 zPOdwcbhv%^;T^c%*w6zTOO{OlkCFA*E=#uv?9<)>Ajka-Ume;Y&&{0dZ-;?kPPafT zDf|RFN+!G>+$*7Q@sTH`VPPyLdZdG&{k{=1_zO9#nIXE3<+CA|GGA+#)&ji|`$NB> zR?2NJ(qCo25Czi||H3hxEDVADjA(;F;f$`sZ?8Efsz~PKr*oF6+1nA?ym`XA;KrmG zBijDsl`1$zOcPow(G>kIHCi~Q{gK6{hv4goy%7;~{K;C-`XrX3oefM?G^|H~eJnF( z!*SGitbMomJNi5wb63>%&ioZ<4?RVV0eVDuxOO-*MI}aRQ?v+yD;3v1YaR(wqEo9~ znniF7gP$3{CS!5huv-0BNc-r6Yl5*D?aZWqDN)8k)fNmaC0ZdhZFW(1WE4J1 zbxOe!9bhUl?sZ#WGEu$xR=s)F8ixa2p0zO_9j#^~pv$LlR;8_AgvOLxdmkp_KxC9J zOA<}D9x+?DFaFi_^hFRo?C5 zCk4)XAE_N=>mPISGSk_Xn{PkSrugSec?JB*q8GY(et>=Fi1>?0`xnfaG^d70y&Np| z>zjo(6~hRM`yILIhkO*)W@*CYKhxn4%VI|zaQ2%OMXjem%_SU7OBB=Erq_ZVT~@(O zmgq_KsMU^{sd@OpR@XwgTbKIdO^5@QV49zwC3^^-9Ur%rVgL^}zuK<<_N04|%K%>K zZ6f-jT5d2E5-!ZIzTdWT!r^1@&XnZc3f5w8KJ3)1pLhZe4PgMsl(U-UI*)%+JP;e< zDg~{Cs+dy-DD-36qcFClI2h?^hBRw#%n_Oy(dbFn!SegLt^mUhm?G z6K``*~8L8s$x|eq;xtE=SJ#B_j+);gQjKhET_i09*%fFW8LfZ^s zrSMrdl)Cf?fqjgg?d^3Gy$nEJ4z?l7HF4=U@JKCGe{ z@kB?wLP1DFKOWqayGY$?#l{a)Wk^8(6}b{@<{->Z(X-s+vl&3n`_crVSyfY>wi-kf z??U^+z+C0htogN;f;3~nI+@+5&VAN0W$AY;ZM0bC+9{mp9EZNthC!2SZEqvjPJ}^T zMwp`gf!cg2l5jxDQ+LtUx{o|nAJ@B582>pR#%puPTclb&&@cKi2*)JspMp>y9zD+9 zK~|nwfH$?|1t4}^7tQh%Fx~PBT}m>MIaKy&Z&?d}uH4)YEjH=l1^p{Y=|}W~$iH>kQ-d;IYl3|FpvWNAdM4w4nK6=!GWAZ|8-=*QnMX zsssb(9B*1z@)6Rg&U&2cbYuk7+G^BL%qmM$~G9Md)}wTvV;0l z==JGprBL?bZ9)hApa@HczJ9W{UQy+mV~$khyYI(Nh6nM@l?F$Z|0Kz8V~?C*T4;G- zWH(b@qq8+CC(eqsG~?Bk{Po%x78jf4=@)JQGi;HM=f%{;hEXr@>ctGye9S69KDLNh zRJJno{2hEioIkwEYpvIYN{hOL_qC-@vvj$MN2*gQ5j9Gt+9VpoJH4TA+w(J%Q5iKn zj~k!z@_c(eMM)McR!YL&TmGrZ-)~$l5<(5eRt`-i;rs`>k|Pb3Woiydzwn=n0(S1G zMTwitjc%ch-lG#RLy0}9A`c)+m!sS?)|p&hd`|ecxU!Snd3YpP3?V|M%~P2)e>Ky5 zvQ)|TBy7wY9eZd)CkTizF8@S_>~)MGKAqIRDEH%NqI=da89B-l3mawW{9nRCTST$G zTP2yxmu4VZ_Sa%20q9pbEmaIqc$tVO5TfgMialR3QtLw z^9Msg27{goJWbE5@?clPemj&e9TD2b_^H>pb?3aBXM9GY+4oXHITy=C9Z;qK4XzM`h6Z7{Opj_s`qln~2*G0z}wM4i&1N+E6RP)yFb{krv+Q`DJn`6Yg^bRf|W z&#$*&Y>yu(@;mz%5oU@nWjI*b(IByS=tJ*C3o`$cGLeF&)L;L4=>d0TmcZm{{A$@u zK!%HAwc*m$EM;!Ek|g(@^OiGyXr;=N+YhEy&fFHB{nIK{djJLs^Tgl}fV-$WhlD#p>OyjYF`XW*MzUvUBsG{x zJwwn;uzbg5KYi(zyD|~!{6&|$;XkRQVh40O)&TweyG`$pa&n_DU&B1(`2!)J>Mjtp zXj7Od{|rm$zbczw9~Dxm1{?iq`@Yv!`pR(QG_%eXTl3%$WJ?FFNgTE0Zn$-(Fy1Kc zeTtc9mb9}8y5!MU8&cp!0JaX7nqP&ZK|SUK^A68aWy}BF{ygoU9S=>i0AK3C6=30t z#cW)=mSmMBXSdV7PPvJy#m&5hWb0aTp*efeg8t$Az2SR8Sbu=Q&9LEor_4wI6)O#o zigMuwJ4gdw-0|Xtm!ZDuVYO>{F6Fh;mP>k|bvwf$JWEKrbLe@5ohegO4;Ot>Sz%7BUXC(c>0=@X$m`TCc zn^Y+XhBG2}lh|*c-po@!{xr&{Svmn?WNVo@%i*5%cMzzg79g#>1hh0N-vKpbR<+&s zaR1G8j#!6w*4*wh^}L1LRzvgqMyX}m)8!K(xjv1R&7XxAYpG2|qIRIWhPF91mPP$3 zbQcn!(qrJ6^)zT%`R3Py9ObX&mbQ2dU$gBbsGNHNg!x9wgo4DsAG46j{X!zh7?Tyz zKUKRVMUeGzGZ|uH1=nrAgAv4MU@U*0g%}qCR5xh8V^`Vk!5y6(F>KnGxAMSKWRhGL zkfY396g&832S#IVua=Ts+UG~-J-kj!f8ysKtg*_>GLvcOZGe-WTqjJ}z`)E$N^%W^ek)8#HzGUgZZ~W%cI+kZaimMnE`p>-_2@^QTiAtmHk@B5g2ID&0 zeIz+7zA2movS|&A0llQUSZh!9?smcM8SFX1|F3K1cjgOq=b4X+#ZV?l@Cxyl!ouBF zg*~ripQ=r*-|5MC4HQuW+Rl7>p~0oQz^kv;+jM8=$2vN+jT{6T&{>ea0k;1Hi(V#|3`EWQ5(}<(Q0#QPT#J@kPK;oQd4= zszo((kz9Z<*enxiVPN+fNt=#!R#>1!`)w7$Jn_JV;9hQEuN2$L?bWN-$$ewQEqYMTuzF2|muionYB5QD z!q4D<0A^!la2esW4fARpaHm}iY0}HlQ=RTi{~lToKTE1bdj!!ni|*lo|4c!Y%1)li zr=*xKvm59M^9qu;mfHv;IgZ@SEbAWH_Sg1x01g&dDTE(g=OkMHPDNAZ%%`nlD_Cu1 zh@q87TY(3V$6-)%4mt3?SM5ioo3_C!Vj%QP*@#n4tU^9Z+e~(`ILLni&_11=-S}<5 zu(>|~uRlG&H3hpLO?rSFV(rscVT1gJ@!M9^XS1=pfhe1-3r}3jP0;w$`L&> z#$Sh>s6pzH<>X)~9qWbu07BVaSCV}0Sc|2saI1Dq2d&&jphn}p?&15rCx}Z0~aEV`3P~&H}{{k!o5Fd zET%HR1KDp8?#!+-xh2=|rKQ57iL&rpB{u0Z8M5UDQ}Ym`N4P9cT7Qsut*g-_PW9fu z%$3tGyb2R;R+<39Yy2!1!0GL#T;vSU1^%J>+MUK8>kk~l*mMFF)u4=55Xc6ZES)NQ zS+5%?u>q9ls*#P2rZBmQzaW#;{-(`nRk)4|Z;ZPf5oydi6mX$nVyMNJf2$8Z=NBE^ zAiRH>y-81hH-2-*H5u|Uw%UdH@(O@wtE+(3^>xEnP*tJzOSe4x61)`Q{%T()a&NjA znjGY(I?CZ1%As?xT7Q4jfVb|A1$kmtb!Dh*>cxk*hYq%vrinST$|tR^cP!9`(j zKs|+^+JpyJ>OyCsaCa@olysar)!{&W-Z~^kff^Bru!a}Nq`BQM*uQ%beJM$%_Frwn~0WP8p z^Rz7IQXI;q_(p6j2Ud3GretVA-nU5vs`Y=Cr#ZxFFe?fDj^PL|PpK4YNi28M6I|II z=1r{{%*X@lmy($4TNzsRv6|nb`iF+ago7qvSAkEkEu;VBg_v16tcp<3r23 z5lE46nJ4-{4I{VKIOy*c(j1+D`Q0R1>Ub@%vdKCCtgQXE#Ie4Ij(uhJFv7tIgKO z;o}sHT%w982>C^jzEb#4C~{6>N&0yuv=+aB45Mka%Zir&I^<~99ke{kdRO6}g zWrh1v*KNtp}IbYW>VN=0)HB5mzI3h0;5?yu|l)&1Z4_WKYRp!NKQ1)L|y(X7@o^$8C5+7L$ z`0H{mt}C;c<2_qlVNR$8UM8EixV+hkAV^!wU~W9kUv*EB&jm=hNcozs5{eXd4X36f zYO!^V@c@f4s2ltF@@nJ(*!);CKuvMl&1N5K5LoAClW0+DGv>|n`Q?@4Sy{2BXdG0^ zZ%TzAs=FG^ZtkhNQ=`E!(cb1&rh*6W5TP=m`BN1XHjQ*5UIV`s3Rd(}!$xML>W9Kb zt!pGkMM_l!-Z2nMs(EiUL)AZt#VYeu<(-fk@HkKblP6E~@>%cGv$KKcKwU!@V5o?Z zib`dgR77<*667beOO!7UQ`vF!Ww5naj7;oduqG_nZ;>wE>GKH^?pSv5W8L;#obh)L z)vw(vXX)C(hS#k24XkvjUQ!tHtWJDEk(a##VdJ7EM;`_zS`Z@Cr;`^8IYD)PttGwl z3h6*A&F|3u4@VhHK<&3i<>i!UiT?*3LE^r(Yl@w|A;rm%q?aThUK%A<3J1xG%W799 zaVYJm0YY{81E1=}-a1k_l%TK@&q?S0e-|aUL4^JOCohS@e?>Q!G4W>S0Cng8y@LJE z&fePoe>FvH?@1K?M|3lH&>uB#dfK#ErM(Y7ntLPSPXcv1m%rc|J&8gzh>|f*w-6%) zjnXt`C;dJNdw2Af#>A(%7bU|!|JCQ!Ial$b(3>O)3B4?_44gT(&<{~^L;WojCFmWA z1MHC=QWx!f4}fYM1m8u7{~yr}`-yVV>i!iS(^P6GCgU5D@Ggm3Xh1{CM#M+|if)*= z*-kMHP0+ibg_wX-*I*LVfzE3-1HTX8`ALk1!xsem0S!qOepblMV5B47h-~2^eDNSk zvM*tj{uSNuO`4`?Od)%K8WSJl+QJ7oyhjPaEVA$jX}~ez^?r>)Ii~6tD0j^IN;h%! zj}AirLry>~>Qg1(cTe60n|iSci}^Ngog~%cFPSNX9gl(z%EB;>NDz~xN7-c>#WC@_ zmR(AA+)|BbF$xUlKTgRXuAlp$7Uy@Xlm-t^8RL@ByOe}@Sl;D&M?**8g0@({?v?vS~xyXpfXUafWiX)#1 z#dk>V_<@-vFC#~t7qVSZ@IPeovb>WR`o>>gtRjDW($l1k3VhAA$OkE9t9rkI1{Nf&| z?z<=mXgK^i_W2;0>Xt-*rx5@s7$tcau+ne3WBmE&5Kl1;@J+zsH~Z#tk_<_AQ+jL} z?@!EdWUWz9M!4qV;vncidS+!a9cD41MpLvzFExbVK|Lx^tsIG&&5LXJ|J=Ht|5nfc z5B82N{m<_4!QTFw|F5C|mtUyv=j-TwI17#j11A?xNSaW>&7ka3pj;<2WFiorq5u7zwykE5UuPTmfFLv>$8~O#&a?5R^E(<>68?XmzUy}oCvu7BoP-tnqDU%0p_17 zQx`aaUePf@=?JG8I%9kfx6{y!A~@8)XK;B91HoaCWK2W8E7J7;CtXak2!au#@I4Jv zG9*b)1j1)JJI`J9;`uN%Dgnq!V;?^~&`E1$+_- zQUr8BKur}55QcRE-5p_;4>tKsya~{2gV1zD5_Bf!4M9-?fi8)^*%OX(lz&G8pQFx5 zx>bf8!u%JYz#Elqu`NVJh|quzDd$Sk7+{h{W1LbC^I7N<-nQREe;bi713~%x=hI%k z=Aan#&%5^mf`${E;4meGp$*a-_IR5RJ2hdO!oBW>pivY?2?t&1%p?@uk*(cD;df~T zYA#~%&iqP}D2H-Gyl6}c-IY)f9gm4maY}-FNiUjar0St7qX8VmBfK4uDG5M4qD)wg z$S$Fqduiy!#1M-xmw?LE)hlyw1_Y;*gqT~z>&Pc3YUt%}Wqv{!8bx>LBJ%Y;1%c^U zg1uWHNfv(e`b`v`hd%jC{A;u!Wx!27nXc92R!4(nDKoV_tD#h{ePIdqIxH&FEzRSP$)3XDN@j08Z$;aN9EI?Yr-ii1oc@}Py!mfg@35`_4nU9 zr5mKxNZDScX-4;UtlR-+6hjB|;q^@1H1rSNjONjn8u>qt{CT7Q)XM*d`#ZM$ ze{{6Fmj72$g#AzCFHZiCBfqt&_ab6D2-#r5gllj@LSG6{7m?qJT|x&IVeJDMKJ|d; znSXGF;Z)@JiXY8%nBp5Nm%ccVO9SLpbW6eph*W((D@w^E{mHCNYiy|^ zr44V9j`5IOOoHH2no-S{(#8U(<+Z6wZ1el?ol(TnHzeg#vjLs7+Ov{KNWF5nU(xWk zE(;NFxA@V_lY_vyQoHA^nHhThT}YBe z;azbOb#;S=6nv!eu9#1ncE|W?MO|t#p+#uFxhJy(qh@4b8n4fRi!RmYzuf*kGX;L% z-X)~Y{$uyBkpKH=e|`R2Nipny7vuY38&bY+>Hjg?1(2;};~!h9HTk*n1##T(=xVe= z?ZOp}u12$Jw>LMnlbE%1@U6CoG&G&X*OpC(`+H4Q${$k0c?E2pyScSxS6W1OH>(}_ zicMwEtG)Wvl-2z(3czZ-Pi)t|yyYTZZa=^3bSW+q*P>UfqbFMEJ@w)9DpyzqLJB(! zVR1bcGU}5p#3FPD5gLV)KYu0j;iXYzBn)eGyW4g>uNn0NF3tIWZeZ3{1gPWxI|sJ^ z&%yrTI{y1gif#Y7U=hGIX_hGkm=>6s$ye@|-L^>xt>nQD>BC z@@@H;TB)>@v1Y+8u#$6UZD?StS++LIjJRYHP)la5x0)f-l1n!+e1r>tAow}9iCp|Z zCl)xR$`4&0sN&V;OcXO(er^PWpizjE`vTpR(`ljA3No$P_8*}%=l`>v{r_77{=c`s zWAXpJ%eckE1dQVUsj#hjmlDn$gGrflcgHo zRy@4xkZoZ=0^LG+0|n{8Lavm_WnCk`6grf5rC{D~AL;culULSH_T^p7f(|i~qPr0Z zi~Y}SB30)<+DKX1$V>1n+RxSDseQ3fJnQ7LwZyUd(wzURhwX)cI{v?ZY{!2;*x6gh ze_BZaHvcy{wCH=xsJCcQAWrBQC-*wDdkSm3jZIb&hOPiT4{1ulT3u;2_2_;OsSv*B zyw8rTz+b-v3l`set$_a+p=e4Hq>#~J%iw?^9+NHfG^@ecwv368J=3@k$9Ry#qfA3CPB}h2gPiR9pitDm7=)k__)eyi|l!z|QXame7IR+Y?*Yj%Wi18WIgh zS4?|@C?o@%(IxX9G6}PmFe*!t|3}y-N&gcLg841KMXBNcJNrAkmi_nP!NK90|F5FJ zVt$Qjh)9?w_i;qS6k;+7@3)&I+bGK!HO!bE4uY<6Ky^z7qB0F>+C{y_^>G{r_t^*Q zWxTLbzWzDI7qbJ@>i-T3`JZ?8*Xw^J1=jzo2>V=+2@n$|g{W%duU{dOBvHcZtqz17uOhILt`ev%DFnPc&LGC=YaDN|&3eePk3B6i zs%~hw<7|N>DIHJ`r=(pQ`F9Ok5$*x48c=awYhj;{@sOa4Nf5|pSgUpl9uW;X1O5O= zI*qhz&UArk(AvB2PtRJlklbLe0o<3LQ<8)@K<8mfk^%PGjX#l}XJ0pH^5T8FoNpb(!7}21qhgFeF@l@=wK$+c*m4J70wBDuvtIuzDMGiO4>h`s@g1K4v#S1`lCP%kFW*L-Uup^hQ`fH5($($E!vWFz zV_*8}AG($5U{Fo?w-|X*oLLX*En2E$>&hN9>Msb1&-mwhi<<@YwfItHhSzejZ~uvP ztK6=HH3X*y>kTGBApAX_ZVC#SnsbrkV-O`{lwawwf&#ozTaI)dvgy1lg`0+Q$l7SM zO%&1u{+OiL$0=?B9Cby)`Y!5f6REpdm?akpiTU{!!VlOp!k2SlkVNDEU{P2(lo}C+ zL}Jt;gn~_ur=NJs%*tBU^~Hz2W=WFu<&uaXUU2i1MwOG@4P7Mr@48lRp%pzZU;CB{ z)2&(e*(ge6GzC~9#Z}MuImp}&6cBqrZr#&txxn|?vAj(j3}dHSm5oFN|5xgfxlaLg z{D1do&*uL-N9+6ll@u}Y)le^v`{%l~cDz6TuAK8{*lK(~e^_Mr*+g!~?lXw(n7#UJ z&FXE)**H8vMz1u;4mR&(TBVcY(XuRU={(x}I4MsJ;K&v+e(O4iDG& ze=8}lixe+87A6QdEkRMAfb>LuHL@I#Di2Q1tUQ7ow(J^tAVm1OzkE zgGz#6n`XZ%#iL~iN1aMhLUQUf(rE}4no!U!SajM82zBB?C<4o!rYZJDV-lt>__C$# zGyAXQgNIbg`M-7JKZh2ej{hIq_CI?&d+YeGt106CuV5R3WNfi{*?+-oq!sfod|j#& zpyOd)&tQrsh@y7D_;Mv00;9zhYY85Kn!w(79-gwGuv`kB6`A(Gc{c@XZms$+jH--B z0C_xI_Y(784HUZH?t-9fQCA8{@DYl6o2*Tnk3jG8b*~D_`F}i}GwoAWs`>x!?*7rf zZU1w;yVn1&qzF#%{%m0fey~Pt#pU6PQqCT0N%u9ru0JmDbnRt3j;=#(#nZJ9iyXab zJ2X=)^Bq=8udF&dz#_+_O6R2a{wi~mbMf{e2}y#3*?7E8MhBy8yi+ZoBVXj078UrJ zBitK2rr{70kaNxwqIl{7S7Rqx9sWpc=L}(37!dvz*r^j7K`9aWJfjc=k%u{(n6Q*2n^_z5^Y*U;wq0yW<|Xn;OoSI4w{W`w&Q65G(hGpY(P>ZmQv2XM#Q@n8QZf)goh?1Mgn*LWD($B zQ8({z7Zgr%1iPY%%}wdUsDVsQEhML}+6QEp~o4(YK# z>}g<30NYo$|4jMG6Lk6ddvtbrZg!=Ps!S~49vk1BU7pXi!CGxTW%SoVm=}1~h__6= zOJ29=ocwfz*+_cf6lN?;TG6u6EaX%(AB}Kg%@O1ZY2!y@Ohc<)5tHK5(ccyUx>_#y zOxr@jB&5Gg70%nPe;-R*vIS!lkz;GBwX_kG$$k3L*X%E)dbr%yxl457oQ`C(yV|P*F zcdb}O;%QxLt~FdpH&?ZP>RSg%>;3Yf;FA?TbcXa0$tv8Z{4h=Z=&@KR0A;dUL`(h>tg?IR0&e3a+O$>R5E7v zH7vLuK09O&)o#l$)~e&RYcrz<$E((5@uiCYLu{@E2mp2b|M19;|9W(|_Wxc@k^7$r z)wduOKo-@lr2rtmYM}^FbF`T%K-F%i4Uk`%f`@qIkUT^St56Hbw$_?~2P_KBE3b$Z z(MI$V^KSvyWEFyunEdLN=^K)e7 z@ojVXY)|_h@1rQp!^>}>2@{VP35b_!>0#!T9aMMY$iIw< zhggJY3Kk3Dcd5uL7lkOK0fNL=YUeA=VW+`@1nMwWC?u@Ya_fqZo`dN`8VRF`+Qhyy zh(RUB+Io6O8|^C5$=AM{!&tM*jvSIzw!!IN{DUPSqjF}pLdZ*^a9*VBJk?7UH4E~e zF!)|&{*T?A{eu7h(ec4r{#!+vBTol>dNm@bD_22RZTC8Nv2qBu6)BB`A5T%eFll^{ z8-mk;7AhFJq#KPt70+_74MWDN{E!o--~Qf z#cRDe-y1B36d5VT4Whll8A1Ta4s9A`0lJc3tM|?;=qcKjs5rL;LY3^|1 z=TUIAlT~&va0XJzHj;Ev6BLIMTbNd3e9tEeMhRh)Amwt2oQ*x}Lr(Opt0(B6;Xgz4 zr>Xe=k|+}3n`o;1B76F{I0FDbbcQPT|GoX4gWgVWx8LKdn-0S$Aq#7xX8+$g+_&|= z`$ud0@70ti=mMuHNkZ5>#K4PyJU0^>_iGpUH)USrlm3HT@K&+cKWwSJdpur9=6_M@>_2w*cI@@Pf3!aTucY9Z zz9$KzQFwx;dmVmqKaq$2j!&4E&^U#cr`btf=mKOgueXB%^(YR|8BTE!4LhAD=u}qW zQs50igr*}1Lx8@+aU4(&Hh}LC=cVX73H3YiO|SEW1IVk1#|-j_W8_6aAY-6KgG{Jn zg3-(7pbB*-3>uPrAd6z<}1B-3_-*IpP-2d?>0$kKvPN> z$9gacJ#keqh!QPLs!ygQh+>lT(A9|Cf0vL<2o0hji0;rO8RIaeo~p>fY>d)0W+(kV zBjYJadQmd$Z+50?X{i0t?!DDhsq@mu^@ecp88NE~)Opg7M2bLKOFgsS!Xq>5d*?|- z@5OvoXe4A15GnO5MD1R|S&x6&!Eu~#AiIx&<*kcWZ2tf5<>`ypFMDHufo;_3e|8J@ zAA84pYyXdxl$`OMRk3yc3@UUw&z}A5^xd2DH$R@BtDnv<(b-R@@2=4KC3^Gr3cY@L z`sNB zA9<{wMltnRUvi*Nf~obN@H(44be?|4P&`Ru&M&E8%EKg@#C+qGI{P3RQV-pb^o|g* zo8A7I{r^YNSn?RwL!Hhg4LvSp1QBQnB=3~lCK$%yaeg=fy^@lN?l6M`6R1rR;!iw+ z#+ZgF2{8xiMJzR%SL~h(E>evGj5xVR*c(wY<%kR;9B@no4|(zK@4Zgv$rE%Qrb*;a zKoXDy6^v2}Ell-VF-$ZfK}-^c?ncxbDM4u>6=zaxK_R(QXu;kt2B4iSjFu_O=~m)pXK9NE|eEWxNC~%&AOEU18$WLtoG@lPDz!)T~f3#-0FU zr4>g{Ox`UjI1Z6BC@1E|yg9PHWm zf5!)V>-E2q0_*=uzakT1BN@V6M!N|n1a4bEs=|=+MQjq{9!^Ry{J<$p()`XHO-D4; zjYp)A)GOUkfHubLVV-bE-eqtqm=+^J6?hVzzN8kH8 z1rs)7|Fbtd-E>CbC?gJMmxoARYg+G}V0iysF!h+jnl+0E=UY}sdvIdm;^>8ifc}fc z#5>86+K3XgL4L^xsCytEB*Ex z3H_XSnyq4n+MCEH7g3USbu?fG$QtJ7*)L(93b!p8(s24v0F@*lG)eNh2Q;dNJy^GF zaIN`eE$<#&9%V+764|cSv8gm(QVVkveL-nL$J)s5iRKi~uAAI7%w6N{-wtbURGRbu zPcUq=NC9>FpPhpv+yD3IU>*N+B?b8ZJ7IAntYruim%ETk#rGk@D-JFqp$kb6wnTu& zY+bE;jk9X(eX85Gz)OLK#v#Q6!>048{tW&;G5vSICQ{adO50FPoEi9EibJG08ItrO zdzb&#ner%26- zc{N4X|74C}+IW|4?nV+3zFj0y5Xc=a!J&T|#3TG>GDe5GBIX;^pgium0 z(q0ZQSMdn#QWwWD>rZ#P1wCu04ThPMVp|lm50{SPWr|ZWm;~+V$mEx+pycdWN*~B7 z3~zAijr!Bw8-F=gT;Z?Kilgz;t+=VVJj74p!jZxjv!>BmEk{{)9Ku(azn zzh$xhT5B;XN~8T>OoL_J{~i?W|Bv^M*Z03GDX>?){2VKPf8BLoTI82)QTpcMxUk(& z{_<8L(Y$V`G9;+?a)*YSOSL`lN^hqmNvKcY8fX%F=xATw2#GsZ)ZOlGqSp7iVabJV z*y1Kvh_re1nF1fkLOrQY4kkfxkA9ipfDS0<2yqNl?{)r0ME9V6$~(zNfMu?hEE*H^ z*KGF|V>O^8@Wn-4K*v;Cx`T1z#?3v9zoge+|&h-%yU!N5sJ_~ zxs&ZgI&NY>USeB4E%F=pS*C^-tw90G=76kH`o3b0Wc)y0hZ?i6@g&S~%*ZBy7&b^I zeBNi{ZIhW?M6(zZ(}emoYz#Z+jt^$Rl&u|YQu1v|`6OT_CZ?R_q87+ab(2$yp9V@A zN%aXJ{>}x)gv0^%2{(L91wteP}$T$mmN&ZUib0e|LB20(Y^+v?ImGuJ3RLspyW4F{l5vqb8 zl4yLH=Z;$zE+XTW*y-huzmj`}-L_`2sbeT5IL&lD!&w-)Wsu&H!HJBr;s%u?U;^aj zmfV+pzrzxb?e?}B)75Lsg}rU$APcpI3bKw_@!v5;UIYV;73KX5H1}85>DMt zE4A}aA*S2RR*k{e=0xlAHA-{&kB;$hHYcDu`>&(@W83~?e{U`St)wWMfCOBQVT@%~ znMsld+t21flf4&!oB@p0?zahvBSzCGx$mNGiicg)jVD2H5e3xC^NenI$&>W-^%CmL%ElpXcbaCM8E&u742SR=oqdaIhHH8k!!yG<0zTY3Apb5 zf5*=My|=TsySD#aNio;Iu#=y2{j1NxOm5&WoVfJQv|7e;X9YpaWd@Td6OJ1t?|NJU~^*>EgI-3z#&Hlf)yR%cU|6j-d zTTLi?`4*S%_?peEsw?(-r&n_3U0&{(ZN+Jr+mlnf>d88o5Qt&M`YcUwN{07+ z1+Gay#gk7gCZ6^?kspQ3-MlnN>YB9k)?eL@r0C3T& zi5)x8PlOK0P2^pMm(DfaGt_u%iQ$_n)%-ss>0OlE(s0=S~(*FgWXe^BuM*;(g* zTul*{5N|HgS);uwpAbDiWX3n$+%TBG%k>%A4`DoQyfZ9z<(C4g{8Ic7PTg6AkGzr< z5Mpii+qP7%|Aeq;l6ZvmKY3)v=nwV!pQD|^`rq4I=YLsAF-4d(nUMYf%V0Bn$mxKB zJt}1gPcaSPT91Z^em=|Jmfw?1U<4 z+e^kGYtCq&H$Eh3+i&&gOa+YN$xT4Lyt??jr;l9GFhW*}6FS8yxg`Z%{)1GyHQxWh zxO}!45ViMz#|8VZgSGs(ngV+hLI}N+Lyfe7R+~}zUX)kX#J`Ow$-TQE1GWPGidSdZ z%V9h*L`cwZWWc%52k_a6k`AkYO4BAUo(MTpC2fo+P(i&PlW~;X8&$?+oK-0Zq$Q{p zW8jt6ET|B2eSSiInGlxB7>4#Fao|G4bUyQ7hXkDX5&I123vF*g*dq{j}GjTHL9hR0r+)n*mv$y zGTAJ?$psZn8W~f@XgK7LIeh4dWdNr*zWQ88f&5~(qhgZv&?XW>v9m3av-LEN`NA~b z^eXwj5<~Pa)N?b>-D^<;{Yhp{%txV%HjMATpnpX)MBOc<3u;E|dOt)Y$Wsj)pqG$fM?{(TtDP*q_QYP7Mx|!|Poo46N&gd$<4f`P;^Y4u?A!65_n`WE|6f6o zo=_q$R2;vLg2|Y?jwYdu_E>NEA?HYL_Hk;0IS^btOYv6x%3+xA%ZyX%Oja@n zKA4DLE5i|k=%i{`%5_rZ6PB%bf|dwFS=8&2xoS^H-Il*(4!fphJ}XOSkN7f5MD=l; z-oKy;dYb(y$tEhRhbQPaBkr{DB~+u7h3ghmrl+326v$+;Rn^qvM-`9oMI-OhpbkfPNU!jhjH>3kxAL8 z3^dUm=;&sXBzu$r&d6QpgIp|$RA2ri$^AnTjp_dqV7fU@&H%IJL0KAj>HbJk2uwVc z7&p69S7_rPaINlzum*{d+dZRllj${f%CLx#u>naAvAxegl#C@Cd($%LBObIRl0$T8 zPPDHrQ$42AQ2yt;EZ-yEi@l6SVT*G>jr_lVd}P~y?;Y%}{XbSxV0)3HO0t7LA8wJq z8?-(wCLSG7k4so%T#*<`u4l!QSw3C5CJ)0w5Zw{~6K_MrJrI0v9Hw2=Wt59sZ098ApYPdw`%SHwwB+foI z@cI0squg^;SIkQ;K4Q?&Y0a=z4}lYSaX3~+dUfh3P`zHgpxSj4ybRm2!Rj^o+Pw^m z*AO}XZz%uK&yo_$$p3J7VBi1m93HRZzptd2wn@3%2lq_$bG86(Fe5&SLL_wy)y7KA zv<8+wt9FBVswpniLDgp}^B>2s(FT&=_dPWxZ8{aylra(x*v!kQ{T|_>c0m?<>D+rmc3aXsx zH#YM1fDT{d*aVP0&U@q~B(-r>k({80hXaB%`$h{QNvx_bKc^%Kae&Ullq3VlnS4z@ zZ$EvPMfC2;DbgZBqIFu4TR$jhr~xQNmL;5&KLAo za&K!>+LkW}A;^cw|9q!z2l>;VNH9iM%0W_Al}N*{7le5U1+-^qxAO&^Y|mRz2IR!~ zXI{*Q&MK|i?R?2iRAEe2w&u3fzxJt@UJL4?|N6iGM?C(o|NP%*<83HH@}VdU?l(n^ z>)(FAmY<$x=|quC^dPc_$8m7arwtB*EU&ne{#FO{w9u>Wz^T@DvtBqlFs5OabGc0i zXvp!G9r(}xjnv;r>yfIAuK(xG&d#;?^_qrsJQ+i#X9Ufj3T0!XmbDHHa1h*J?^f*z zy*P<(h+LO-9k^!T0&?B71EVyJWe3!9hUUPH9^H*d2)mCsghHBXk$qlWmIh=>g1QdK zxYQRa%F6;ffUZ-|?tlvaokf)?>xQaWI|8y|gE45?f$Joa&1hZyt(R5=oK5R0Xinp#I=JN9k6zxnkjTi2)ZFbbmv$Dsy%tDP`V15 zjDX&O-Us;k@zHmnM?;!Y9K0X_zP}`16#A_7HtOtv3vg{OX6Qgn5*qocg?t3&?tlrn z*#OMa0XfD-4;In^3-HpW&;Zk5l8~!WLf9w@{DpO(0JupPX6OK$cphPF@f|1tZq|X$ z_V#wCw7#7I!0%NN7$5vgh`hv#{xV-yF0?BO`qG@Q**+cphI|SkAiw` zckTr3O1oD2HIdlsAjHqD=_GEA!l4s`y%G$Lc1r1ReSIxQ@ujpn(8f&&xF>nk9smPT z$3ehWKhro6!8o&=Bhi>-8Qr>8z@C|bXoB_$;_`5(!~1G191cB`VowkkIysq5vG4?? zp7vN&&E%sFLY5G7l9|P3(6z~IPv`1^ESpVb^QnABl}+rz)c%?Xi79DJ^OoowmSD42 zip|kZ1%2`fpX)_r?nCVa7=_(H6RoCh+wLPYJ?^(Qp{>&uEzPv#Pwe zhL%I})OuW8+dvT%KDsUt_C_U%A<&-Z$$V#*GIFVTn%(yloJBdyA1c| zKzWwsR}FMtl=J9>&W~n8xf~x>#L{clD1G^z+r3J0=%WA*&8{ zcC4UPfBuoSh;D^+`9xIS=A6EhQ<*<4vey$4mPdM*OFouAG&scxI)$m&K}ZWoD>ZjN z(1fMpO&)L-DGL{+ds05~p&z9zb83(|2)lb-iHF>SPSA&s9i%UD`NUp9C#Va0&Wc%@ z_o;GXoS^+3r^-#tJ$>fYv%%B zbGwpuCFu1Ecbv;Z&xoqSTB6sx`1$-r8G5rY8i40G5+;){q~Q=@hLR{sHyfh&^Xt>g zzq-+zN!lodH`Cy9iRhHQiNbeLl-lUcB3U#pEztX!6=&g$gS!m$eoUfC{4mjzv4!~H z{y+o5?paF44`y(|tM?+IQyP#VdC8fXiVyk_(2EsjwkhDlK#vj6i^lOq5)G(vc`)O) zyj1jhX=c7Qs zs9ZYX8uWStCoj{{`)W*0L+=dyD2nRCueowLdTbKM0Rdl;z(L2aJokF+o_T4xbHnn{ zYo>T{=v=JcoOBR+g0?mHLZoWIF+!~XBRm*`kIu9+`Xo@kI9WhXEr+SlaPYIh2|7Ib zGyDS4`vi4&c0jWMdW%eWK7lBL`C~4$=AY(*qV~)wooR5&{*piYRTrRF$#sOYICVd=ov%6g=DL^wldh3Kx-IPJg}&l~X>B{0`#(3eW?a zLXHK0g5CnTUsDFj{-iCQwenbox}5d!+t34@kMWSOO4Y`f62Gc;dW$LrMI+y*TJ3|e z^hLsQYhjn$rI)Sia~n*t5j{(IwfjMJBkyuBjz&^E%zH9>BUd>XM&ORvsL7gYS9!A30nMYr;~5HAH)zbN(C$EJ9d)376z78bhog;p&}6QNVyA6Gp@iHA$l} zPN^r;{EPIWtk?M=N>t#mE%f0X38N`a$;XXRn#Sy;56;28L_WTWAWda|9Ql)gu>Kf_ zcu11|hy>$pp|R~h$*I3hLxCfW!c95;nirknZ+g<{Y@-jH{6U2Mj~nW*+%b8RSID^5 z$BpbytBSPF{kS3juwH96x*s>RAH{|SbU4N_G$j7aTksN+@&@?->S>nbUpVZuj~n(A z3qz^o&k&WrRjuR(dmlIWzu9-vRO91@`pbBu1qF~bv?oSQ6%!x}2_Wkio~y6IC?)LU z2K)!l#9+SRzfYt~uuvf~guNtU40s}+<$ht54W=T(E?ocD|NTGLXiTs&`pB*T5M|&| zpkfpGvi^Vm@ACRt-7Ude^C^yK$WnrR6b%qYBb@kN64zyh<<~tS zxP(5h3D=!BBE>NFh>vdWHI&p$1%HU^BDiZLd%&^7fe?NAlX#e5UpPkemJ&2U_y5-? z`6An>i~qTEY{mcFJ=ob<=l@$td6LH^X>svYddcN!>Q7@~shXN)ha zt_?A&>Fg-IlS3s2c`1pTQE8ZMd^qn+s(RFfbu0%e2gbSN>M;Vl05=-hiHeNalSV9 zT9g0R5=E5PkwYm>0 zlON>;ffOHeI#eKG$ZV}{`x^;t5~DgKKuvN<0^+4nQhT?RNhV*=HGFxUQ9?8<6kI@q zGy(-!6H3G)@Z&s`xFo6Fb zLPUa1F2i4Em9CX(?I4=5vdHoKW^l{YPl*@zpwydE!LlTWYZpc5> z^8x)#{FmYMDHJ*WukDbMmc{XW}1?Z^9h&V z4w|ETqNN-tHXur|8BvTq@I?I7Uc(wLe3YgN5ZpODd4kSEnrb|~IUimM7k0PQoHZ|n zF_&{|suQn*W6#U0jdo0a?W9%>UKtawV_G`rtYzOOk~86zX7i~rM|aW-;F$Pq@Sj^s zU%rK;u6&d8mFMVk630=JiaQ9g%_h;@h_ksEj|JyqELh!k)QWE*OCsi z0+OHiR=Ka5vuK{Z^$F_rdTZ50^Wr}LOJQO`ZPc9q_jV6=3g`cWb^f=Nlqcvk8M4J4 z{VRoXOD!Na|0~T_dYM8;(_#oG<;F?N5J6grDtwJ9x`8cY-?Zd0&u9jN{qWIXus9iR zu+1Ji9|)Th;gYwd4k9X$ALa~$x6p=?A}16_bzUqLBtZ3Q6fvTl6-nrG^ad$EZjK1L z=A^mqp`RHUOaeGxO&Ce?j&O899Qg6)^Q9g`dw|Keb420YIpP26Fw_X280prwvlnZ2 z{D6y_|K}QpMYK_u|L5pn-{Sv=2m5ROzmg*IKj6^+8X~|~5CAmp{uOw;RJ;Pg=Vpi! zPCM4URBk6R`i29AdxjizRZi$5ZYBUU(VLD5P( zMa?45p@=2nbc1cedCHj=pq{3DU-@uL?%g>hEL6)h#?n+SxEF>DU|Q0;|w)UO&nyl(VYLe<;|vjBW9 zRB!Elp%zt>s+Fh~fX{_0`5fcWe+wy|AOu>?1-XgpH5W0UPk+;{$N?nUz`mb(DNTX^ zNDKx9d?(<-t8Gm392}z z?@7W6a!?V~N~&6@mO*WbYUeo@IB61vV-lv>*f2d^%ryz8*O@;R^Ki&taIwRmK=}An zSk82wqZ^Xm5fTcEXF1(8M<&KkGJR<+(pTmsaNp_3N{c8zMWX=?eTHy&-|IX_*ZP9G z7WcjuKj5gQBXn)AwrlVqOCz<4WIRj;=`p7=JHHRUYn|u98`MiDI8Ppk6YT^a`gyE7 za3UR0;&U)F;B+ zpE8ltbD7EnJ_)`ZMFI(@rn=zeoA;mIoW6d!djfyHKYjJ{OJ{{Wha&)N70M65{$Ss1 z2-z~F{TiVs2)sAdiW8GbWODsZZS9sj!FL59A~vR3t569%4Dvd+uM0y1T*~lT!VU zw9s2b8#Vf$1OBd{|36;qe^yaI|AY8oKRhMS>I@RCcAIK{R%e{(R{QW_tEZtA=&00o z+okV;7G_iUXgJDKN%J#lJ7daf=&f;_CElZ62cdWcs!aQoKj@-D|cpwmRKhXQvzO@NnJoe6ek8N@b^$ znuAf<0c6=Hfl~Qj`qwO?jXL|^!^5Ke&%wc3{$E8A@;@K!uP6UEjXc;w%rA)WEn^Qh zk<=Bp=ETc;qNMFwVcRxuExTORT9Kkk^PqjD_o79?L~lmim=>C;Fik3Hrg-%V(!;fE z=sHUgs=9r7cKYfinC0>(T`lT~t~GwIw8q`0>SWQ{Lr^I%m)S!MuYLLRqP)&6+T{c$sms|{?w1X%asnn1hxzvhU$fHvylf9&kq{y&F@M>}i&zl!n% z{lLfiL0Ew`jzH`vSx{m}S+vVgnSQW!eB)+i;r>L>fsAumBVa~PE|*_iMJjCEWAIjG zc4i|IauTPgRuQtst=&7j|-35RRV^Y!us8HPlUZsbA zzI^%a)A@@n^z-?PO?wpdJjpF&d3*l2(>Z5Ts-z2g-9k^c5W(IEkuXi}xzvm`U%U#d z3NHSt-Yr4?Z7cRF|M>6kvtBC|A?VhO;M~O3BM_Ib{&C`3uN#tR;?w~Fd_!wKK;Azz z34M}igxTzDt8@o#SJeD%@|CpWb}x@Uy?c53;?vtVum1k&-P^ak{oQM6R14|fuHESx zu2GbrYdsN!rtamC`5N0Y)>zZ7Wh;D+o^gp>?}N%rp`i^469m#b*Bs#=Ii5ehd;9YR zVEiM;_$m^*?SZP!u~17gj(oK7k_tt-wtVGlEhDBdPo4!UxfQ&4cmDq6JH8{Fet-Vz z{ObJWCtJR+bx+46p&stPA$Ont z9woQtk+YB~H!t966i-r9xtynQ**77HY%krN2YfhPm!%i?`CpF;Hh&v6=l{cl{eu4g z_;79ivy$=zy;5WS)zAOPkf?RHU|uqXK=y3@Q1dgDI`g0g2mS?xsGq3-{@DUArGI9n zp&ga2(DCl4w$(=7)a*xP#|Y$GRGg5@G>Vtk1Jyt!(dOzw#L~+YC+VZ@!G}>4-G0>a zo(kl00bMkr%R8FZJ+N++ID8S&Y=e9z-WD3AX)OL_n`q-_CcNCS4E4#SUH)!^ZNgV< zvtbXEbG|^scF!cN3Kd%(r?lle@llB+J@Vmu8#p9>h^Tj|6fmizU)}z=_kg z2jcXTq+2>#I+b(G=9)#Lh^4d6BC`kCUs?}1^euGzXQobWLOJyI1v6H0}VP2xu_vhhoKnLgthM5QiEFLksrUE z<7d_<^9(83gnh6SnKb$SQ*bPC#KAy%&O#3v|- zJRI;p?a#pDqR;=czso0H5o;}p#vkTL>^}cx!Jik>M)mn`_uz2<*gpU5@2<~(D=AOV z1&sBBIsDnheHawQJQC*b9S6fErRom3h}PFTU=~kwt!|iW4xfuE%Rj`5U8*TjQHc;E ziY|5`tAbllt1J~a;YGxJ(y?6@^ zlh|vatSY0DuA{P$aYU4qB(T(0^HWKwhgwl-NlGvmm2^Frg$ycDit+L3r(WFGN25YP zwk#?+6>SD`@DFRD@hPQJS7PTf{Jx5}u*_~{RF2IJrb3Gn?T@uJXYjulr+CD%LCSa5)Y;0AlQ^3=w9fXWpe zlW3A!n7NP=_K;Ri9=j3^5tDzmEtOP?NkSw4(g3|MDp}TuZ3t!JB`p@s6=&3#gFX$Y zlnNXTGA)owvl7Wd%S9!t%DiN%q|yM>V3LrlQ9{@#3jD=VX;vZ?u=>4t4N#~vADt?x z#3r6c7<*t;Dq!WHQlXAUrH$+;%mqSqmKjf2ig0j;!EGMxZkkkD;$?|UiS_N=l!y+Q zcLj>(_6q$@)l!6aFC9EZF!NgD{nGv=Qwz|CtupmZ%iX=UL1V!1nt_` zB9k*XYnZ#Dvx>bXI4jvJqEIPQeY78<)N6bR_05n=?i=liHPfA7aY{O4m2!FP;cs&BJe0q6YvS0>AOziDU_aV=|7C`xXe+;3we~G$nQgchHg?U_i$-WfgO< z(zVi!q=czCRT>wB@UmhOx)4+Y>=@z-1gp@~M%aa5`2d$7DCyk_!AktJ5q2V2I>5^7 z6ni77$xKH$MO0)^)}pU~BVE?+we&Z0c%tRe;)Wze35f&j5nsgC&OO-_j(BDFHpFNPB%P`hJZtQ`k$GJ@mH` z^+s@05fJS2qbOL9-f*T#y_DlCBjerkLx=~c(+M6fVrvxct^1a zd&BXT_aZX*Tz3*eP2zXa%{_mb(r_qlQh-DZZCrctM8+x?19-g&(av@_^La3qRDxG7gF)J`Cyp}hkW?I z9i2ngCtK~nCrBZk_K`}A`U%?oky__sF_YaucE%-O4tHMD$8nrlmzKqS{h-je=AZqXOxfu?(!|x8iirqL;;v zaL^*V$C`&0&0=-rXgIY1a74_iEW)0(lok*;sNmr8GoKgD_5Bv|i`V*>QU`7U&IbtRI|Rhb)G#C>cHcGjeG!6> zZy(nv3d?bO_Uz5ut7p#u$1zEU#P2+}aD?FfNi-G&Xt~dQz`oz-Xnefxq3V z6gpmN@OXR3z8!VC)iYD~t;<>tL#ON*dx8#+{#<+or#ia*5v1N;67`tZ?u%4fC980_@bE4WfH1H(dI zDRrk+kp1#`vV{^dCgU5C%t|d!8hXLRC+Pa@^y1UCR8{smKST*4VjgdacW+)^eL8*d z`ut6n;^~H<>-=f&4|CJu*8is@8PgDE;sPwd>hk~W9qiinU;77Z`>&OhC+I34>xZHG zZ)yQHU#!1HT6N8+69*i$rBrlf`(Ob1%m${d*8m>IF9wXf9ENPN(18rwkpo82F7k-)2Zt247#d?G4-4{97;$ip8g^6*@LA-+eG9H~MS zgUfR_RuhQCEU6Vjd zh+SP@8Ies0Tv8OtgrA)dsO#&Bzz|aUKq9Xz0(E^|5r`HL`+DJ6oj_4v#U!jrU<{*M z6ki}8x$%kbS7nATj2o3o4=?h(n5q8RMc)?|@6w391%V{8=n^Zpx=gBEnT3Z3=&_NS zysJ~yPctalv(%S%dN56Qgja!Y0}?642d2P<6zy0Wl`lZRx?Y&gOY0Ou;)x`^T+N~q zcd7I{4mgDYn8SMn7E3?Ip^tcF7}4^^(ISkWDtaumKX|cPi zW2_MmSYL=k-;y0x?29Trtg!{IS{2~iRdTLYd&30$a|xduO!OVKC{MuR>38;rzN1z{ zeuw>`@9<@aUuHl4x0I1PE>VsEnXg77wFN|SxKUkLi+f>qfARFY-ulc;yGhS7PcMZ9 z;u}j(Gf%P`sV8O6Gmr6AIe9Go1tsK<(sG$`(T)9AAiyxs{{e}+3;Jx7YWe?R=KOy! zKJMlJ8!6j>tKM>F{@QNX+IoHk1NrQczOhsFDn{wNbw2ftzSk7IUmzqkB$_#qK6vct z^ZCo=#|tMevtd`g7oXmo2Xtv5?6$No>u89+Xy0AZm@HOnU)CYTxkJGg-4dNvRMH0n z56lROrLVAPUtL(GeOX7N{+Dw&oHoVR$mwqI8-Y+=1KG0)_=E2U+u%3kyM%FY1YDe+ z{3`O$U(R802cC%V`^5o`q3<(J>3_1V=#()%4r6e@_wVnWEg<3KIpl%tThhV@;w~2` z5WEJzmbxPK8;mVw^(sfw8CeD%fH80!M^^OX@)krWBvCAwgR_|+5wi!u&GI&3a9K@5 z5OPipaC;&c08Hr;sVWn#zJ)u}XsM3$I=^K?*3!72{9U#I4BWl|MbO1D%{cag$rJzt4xwiK+w$oq9_&WXeeKg04k zsR?zL%D%twGZc~b@#EilFNQoL*g1^nL#b(8z;GyqnnU2Bd+eei2=Cn?z>lMU&FF~# zri+_VcrShj{383kQvue3EQ9#GC~|sJu+lTjG-a}ul7RAwT0NnVodKZl8%97vqzoej zC>L$D{6vgqYk(Dz5Z>CX+{$aNm|0zdWl*?I%*w%{%bS+-YExh-3O6vXs=!iK_N{6z z*OINcz$>scg_}UDVu8=72^-bCZm`$_|DctRo?7uS1)>j15vRoKBHT6qZUK$~39{gJ z2o`DTKeq{{6mlL^s0%~laX8GmMI<=glqO&~S0V9gv#Xl~i_zo(IE$qx8pF+;ZAeYF z)k;gSa^}J>3#`OMTFc~$Rgz_8y0JTw{?8R;8J1NR!cwTRXB6k^7>YOrKUK^VjiaR-FC*kM zGEFL`FELFjB2qn~iQRf{A1lHp%#xzn(iiUUPh<%mpr}dgauCotWKb6jp5gGb^&Wg- zJnRFeXvnLQ&ZSF=@}0J_9x>rL5AY1T_9n_zmBu$*&k)NH{#O`bWu8<9Snt8*oKVCM zGGcx#79;@EJM=`S`q;C(Yf!ek%aAfmhS{@2fP)!{7GhUmy_VKUbOW&a9T@S?n ztE)ofbUmQThlXDb@7?P`c<(0dDH#-NQT^6+XsOioAo;ECCUUClLGqj5EmXU119_2Q zrl+(*LC(G{1I)=5kWUpEb;%4MvI>4lvqBT_R=mtFtEJg=Ten-5an*4F&GHN3Z6MCM z!(=)ni#+qU4qhB3YX- zwX0Jnf3m9P4j^7qwxV!b`mDHdWst2HC4ER$*$3?uNJa- zl;}}Zi+BKQ%4I5)sE;8Gye|p44GwfF+jz>eL{ta{(DT$TGF$pSCl^u~V`3-MCw{k_ zP`MR-B3@BwvL-PDlD&;rIN%u-Z&2c>fw|~n0b{mvzS(>C?%kW6dWhl}Em8vN3V)b% zpoferjBqDmG>B?tlpG1$YD3R!bncQBVbwXxs**lW^=Yh4sFBHfRYD7sV%H!v9na|R z7(HapL}Ui0<~fZ`r7KgjowDJ)9%xIv9jBPTx3XOe7>@3VU(S6c%Rjr8tV_ln4zs8v zvl^J}s`0%{t*!T9D!%5aj_w&oD2|`NVkr_-0V=t#sd{(nfXlh?^amcE%}~U*CM?Ys@C?9w zty0F!<-CY{8^rJq0cZpVaJg6H5cv2G={SFM8HPUMTb|DYD$<;^S$nt&#bvjPuxHW7!p&Ezhi$U-1IR>MW$C z@Sw&MhpMd?J z`!sf$QndaX%C42$s9gUKv-#hS$A^9Vw~dr-&0zE=fdAMNz)M)m8BL72tzOIZganOP z;}1CEy1=I|(P@NW{F=3Ln=3`@f66Ff#WpI||HF5OIsX6PUBCWsq--1RQ1y2Ju@GGv zX<(}2eHN6e+?&tj-J2qz?iN+-qFWJWv|)KJM_#j3Y-VQYOFs76Zau5wDu^suR7xz^ zd3E+knQQf{%#cuuiy0jAxp2t_=-doARi0ci#DO9f7%FC~O4Jg=&~z-l^~nwNE&iqV z?pM)JHglBnJ(>&qPR|2#wuB{6vCEQ3m7N`s04xI;!37LHVbAl?19#{WR-e$P`Xw9- z`%(}2C{}v!&lgpWrqFc}rJsn0Xu=b|70TiQTvEX&Yoc;uG?UL#Y21_&i}Syq4gsD4 z9RGy^ii2Apso*jy&k{_68V-{fg-``RTyefgNlY^OTHRYXU(!K2YfqR9){->?9j74y zq}k`ty8IzbZZQ>7cZNC_(%{Zx~ULPWKMtwS+bkFfo<^{1Bq;Kw?vx15SVhK!Zi@pT=B zVK4RRycDhfDaVo(+o)Lo-@QA^$^Q?Id-=~s%C-^qrbYO-UJz7o&#KzEs`jk%^2#Ja z#-R41A)9E(pt_e4*I_!EhbN&!OAeJ);t9iWP&H$|l+ z#Fz=t=btXXg^ifCmkNO9?32w={Y(IHVg{dKx0yI);u1pE6ErnfQi z!6+A}+Mk%cNDrtY>J&gCcmoNOJ&b*5rx$0d^}a@_575=M^sef52Gs*dI%AnQZ3w1D z014iv5RNh|_66*CTO!HnLcD9NP6$)12WhtBv-=1Jlc_wL220E*;4od|wp zsgnPU53=%~qw(Q!FaOy@*#^x8KfTbWSP0S!e2N4!7&Kofwj*6J_HP1HO{UN@uF=@#UxZja>0~Mv{TjgbAST_py-ew z#Dp6qt-VwTc7#3DsShcYVQ#ttCkc&NMA?f6Co4Dov&l@i-h&Z1n*no{7!L0$IA!WY zKG}ND4}ot+Z}=~9c#W4)K)H}_2p;Cxor48}0R<8I=MssLXR8I5X>&Zt*$P@bYC_0sq6(;?f=1RcJXeA0=k14f;A`KGr0# zHkEzAM(_i-Nobfu90Gt&;N*hV@3Hy-cr<@|pR4txKfjg)O8 z1!`~qU0Qnk@3PX{e^-^>{=1^|_TRnzcW?i_*78d1zb`)h*xP^Gs7nE4BWCTT9H1pd zQBMB!TmXHu5wrGE4p0aweISvSq563MI=2zC_R@P0RFvL>prZ611Qq2qc@P-#2k`nm z2vQCNYB%JU)gSzh+6MR?^+%P{fz{*Sz}d@q9C$eTeL*~wdo+>N8r}&ZiWa@Kz@N65 z^55tNcIWhAlnVLp{^7xXM*h41uGjx>rfh?+Kc1X6lKd9x{;l%fjtu|=1q~#z^=tq# z7dsWGa&p|eoFH6S?0b`}u)3-LWF zXypPR+M*2dse{PmUiXb6lye#C)?gWH`df~{JJ(vPk{ z#;)hEU8~T1LKF~e)e3Y)a8}CSkZL=@zJGzDd+eeU*Jb=&;-=DQN+iDw3nGyO3_#!K zJUMo`oLRI&A`p;RB@R&T0uDElA4U)S=_#Qi&!FS)f@Ze?3}9iFP11(xM2ZVQ5)I~;f^f*T@iGf14WN`;UvA)gQ9>Igd- zok%wXvr5-Ruv#!XC0JG3j%e-__S+lOsi2bQ^t0lpPB9q@B^l~2n@LhseG-NUMik&+vb8k=Q>D3Q zk4%-U94>e=T6c~Xh(C5NDw=@l4?it^|1+QAg9!NuQt7-_jD1xaOivG4lw#d87Z-TtMcDavE6SyIcCLTWL1kpceMn z1B_jf$xN*j=(mKzphooy0A2+Q@#vQQwY3ERVF#vB_v-Ae04c^ma4&J z;^yT>i1P$H)kI~o#dRu)Epj@mBr21tt$S&!g|bSbuxHMx%2QBgPN`GS*#~uuHwO;~ z06!WHQ%%&?dvK!2RlGkRUYTzS>@)t3iX(_fdcq!OU7dhw>{G{$;wgZEC;qxaPgAFY zGta_M%%z)rHhZCh&sL9=@Y&h68Ec^jA;U~1HY1Xm2LJw^`lO!GZ$O`MV8$7 zS(pZ8K5eMbUQ+ETOMIU^@U90q3{ku?y@Hsm$lZ9pR7 z)mUCvq4%Sl`5D(n-9`o4G(;{N&{qVv#?kD#-FE1KM0Y-c9T*U$hfXUFb zP)`6J5eHK6fP8-lLKG!L?AYc(i;><03|m{<;71bA#bk;QWqcM602Hqv56rNS)EccD z05C4Z^Ure%`tz3D`S0UnjG_SgXF-gj8FV{11y-E@j*pKIvi`q^N4@{=Mv6NBsbL3t z+*^19tCBtx8bzNE(@(ECXpGrbV;|n~V`V{Ee~6hBW$M_F`*!P$R9d@c6!Z9yJPxX2 zld$atso8`TC6sNkwS4$eV^y#uWh|8~-O3zo8+R)??3(r`o+tD-iL0kj&thunGJnJO z^&U?fb&FVB-?|*F-+1)Fgf?sU8rTk&bZbs%Ts9?hCt0&wh9MFI9KzBVt~seei*8xOKvm7wDiz&wVja=J z(yg_O7Vj2scHp`5a0n=yf^M@^HdWmcb)KD{l3<2!mk~@hmh`tJ*BW=GX}7+TWt=m3Tf@F3sgFc+8|s$h z@u;tA9N&lO}7O-BN9}8#2R?Bg0kLtvD=uq}=C2;!!Y|rZ@2# zHX4=}%1tzeiH$}`ysTk{g~D1!7*;Z}HW>EaXM}@wM7z03R3hNTkE0*H3URIw^Wwlm zk5e$fkE4{BcdtsQn`?El1;8lHDNL09n#~?1dJ!@;t=Kl_`UG5Er!HsK;p72}hg~9$ zwabS_X$evHBAMLz|L5~>UHgDl#(y1W^}h#)@Amrh|0aq$|Nngct?hx|IPI?`6l}{g zyH)qw;lVuF5Pv@Z)(|hnyI6F=U7W2=$|?_)8Or2|rIIprGWm_m&(mHF#ekGh=3FU% zVvDa?8_X`}NUxrZK*}2`2cQ;t&Q)4IpW?DDs#rTCbD0vuSJ9WE>^5AMb|V8^YDh~c zQ$u}-w1|PyECg#k&&de>M)qGRIT@G(x}&wz3Z1;)3|p=m zF)r!Jndeyy4cmJl>Ovm7@fWF{yG1d8VTb|`2_A@Bih=3jq10@T_ula!3RAiaLm%1)LXrt=^0Ck z|LZX3zga5zzg+y+gM)Fe|Jg{{1{d|?|F<*ttHtouVe(p8_SIwT#Qs_ppuDjepH+Y> zo5`B+B@{SUMm+B83JNNWzOvr-vT>`weGvtnSPhoA&nLJSQm~SVU=tg`LJC&02W(;x zSV(~>lds5fkPqqkC4~Q6a(&k6lE!4ATC)lI3n}21ef4Kz#*xtWE$|xi`2qf@Vtn|c z^=tyg`c`2Tm^@S_LgEiiwvu@JW!@D+WF*iQ)w8AZW%}K)VX)MpT}f(mH&?|Un&IOz zN8sZi@wX9 zaQG8kVE^fy_}HzSc&$2;vM@-sHn`v+$S-2(-VMPyH~RRnguc8Wr>(xSQ==o;8koh> zk@}gRN;*=rHB0+-I^tX@yvjm<)la)r(vc@HI6J>T9D=j+`{O1CA0-{3h*C^~lNmqf zRL!kbr)Pw5!M(Ra8ZHNj-XLDw$SU`By46Ll{f=MEGJAZmUh`V)?E}rY43&?z1?oA7>$4 z-uRf#Ka=Lk93JWMm zlz8>CKQd~B{BYQZ#MV$o0ijE-7{(#4M0rNNxGu55Tr~kV5iqEjN^WSIU zA=bGK`Trm9?dSdf_s9MDZxdx3sL}3^f0+YVfBfr@fBo^VKmPT{zZY=)Yw(S9ak^XI z5v|TQ(%}iLMn^6qHnMKTD!l49qWcqz=0GUdVY$f+!LP)He&MH5(h+`AaIW+j;o1o# zPh;;$_8V!oYO%WcNg*8!5j}>4B2Ptc2#8nUK=lF+wv0G_)~S8270OJ_DuNEqu`lZ= zYW)}{iUa!3I<2Z3>MNOmgT2>%itS6=VmtrqWu>Dw%FqAfgTte&{`c_k;GjSMZ=!4i z8E|!#<9{=|KwBwI|Na7Uzvs#dVup5RjCIRP$OWG(Cim7H>c&==wo;P)+@7+db@rrA zN-?`zOL1-rGQmNOxY}8dCTHwL9GO^lK3L>-G&Cv`7+gpZC1>zi@u0I zqF)^96K}IHB)PUqWETYoWfO>2iL+8rl&?(^h=(N5Q6W__%htL}+03bOXRR@F>g;~S zS=3WACnVgr)W^Y{Ig^Iq=1B$06e6M}MOmN2l_1K{R3RNJeYa^2BWtP4UkP%w$^Q%7 z{c_^Oe1F!?Uu6K}tmvv;Uad5ezlLeqYlX{#R`T3YMF8yC0@J`?VS?THU{$j(8rj!}Gr*gEEAoUyfhlG7g(!=30B4CoHPG#i&f2GoGdn2conkK(`-RX&kIVYq>GW>REa=~Jnn zQcjic!R4G##1}U)YNpzg9aW+4gWX-(m)%`w>%DofWzP)(4rU};h&Xm^!9-H&IRq4; zT=;yRo{`M-JZ4Z_=_B6t!1Q)wy}nXszUzTu2)Xkgsu{EBe`G$eP3eF3jt=&+@xPDu z_WJk_8!1}<1LUy3!0b=v^7_*9K-qO1DkEhna;s;A%CuIlvdEL?Tv1q{Q)qm|&4rmr zB|fjAAt)m+C&6DmbyblZ9u|yTDS2wUE+(&ha1-(_P;93MQjl$>HhEcbe)l=H%CV~; zFDpD>Q?{)V8cWH`#+q*{kWELDPfpMIB(^%3tdzFaCXYmwmXnq**AineBwjw|TG86p zG=greu0MYqT_eG9cky$}`ra^#ZtDFFa{aQ!dd$D^@J`0=@yA3!F7k0NW5N>D`kc(oxfeKZ(18yMY z(yn+8rs}G5l?r9Y4!_<-h+LtON4Mx{%8KaPM7nY~-!D&Q-zmc0E_#3&&>I2Ky192d%iNW*i3rfzhg0*%X3~H?l&-yK# z6A%2_VDZXSRR@DQ>%!(SU>!ecliV>^RV@rkgd+(}4JGA<5F#Yr7m?D@-c%fjroMll zf&t$*cLWB1p`Z?JU0^ULH2#cYcDJ~qmICDhEX*d&t{XK74C>I<1qOm<BNAgFDN_ zYlT4p0G9T0I4BJ2(AEV85u!1S;!+>`mL^#RD5P8D0G#*_@F_9LQy8S4bkt)*@EP5s zXb8RpKSAs-qw*wrHNOQeV=n`J39V)1C#Nqg#HkGe8e=a;|JLogS!G_jSL3=|Ns5px1!UV0^trl zO`XK>g9QE)c;GgY2|WJ`OgTW)6+tNa*q$8(PFOn_8iRmlGi&DP&7U087znzi&fqio z_=wzPjM%B@!kr^;=_3_&Ik~d40tU(N#?rKoB?xH@a&%3d+Evw(EH8r?FVLwEDg9iq z`*ti@&bG++hBt3^j2fh5xdv@rU_g<(j70cPo>z`&VN zo_jotL3iK6^yv7n6>O5iz(z~MvI+*La~RwrDaPr@EqVGS_)19p3DX6P-FYz(84Oai zXjMzPvLa@o6$bfi^c_o88=RgkvJm4{#m(^@iI}Dzv8)vlr&xV18mWE{&3{vOE z&7T~n0e2fw;eR+yo5#Rp8lM3J!5Xd(LM;rESS)2UJ(IPrCT`FuQjA$u9Sm@Qy#dJm>r!=W9gxWNmIu?v0wiTgkmC@`k-jAB@a7;b#vJ(y;>x~cGO z6V7=622WA~!kY~|9r;YVuHE|N2Ko+uJe|WRRv%|@k39^(W-A|Vy$5&(Ao%(G8~3S` zK6%_*&;J@ICg?E%JU3 zNfiIiEj6ZzgJNn_rGp%6*C!8%#>y%2oQHrKkO)jgG$=eXqQWy&10sF2k+%ba<>H1R zY9KB9Qb=rwgWKP4*_Qr$#2B3VB=U$y_;$V?a?5=v)pD^3@5$d}TNQqjsTHhg*cA0L z?KE&o;vh5vSBbUk^}y4=Rp=CHKYKlJBNF_B+^FmPn)vm>w0YG+Lehq{}t&Enc=snPaSiLGQR zbA_>GOaQmGlQ;5KcIo@d#9#s_S)h^nQ{FALOPYZ3-kwp7G^R+pGXgkd4>{_8N&btZ zVdHu6&f-ZZHyxk2(9hhYF^S+U%G}E}G_KbW_h>C??FPDc%aEq->HU3@vO`GjrW2t6 zU}%#~3Pxb;@c%N`_MAQAno>cg-wf#3q4%yzM>q1w0^-1tU+z}Ala3cqsmgTdayG+{ z`T?ob$yCl~L*S8^rr_Z7asuA$zp*@yynw3FHAI8vTu_qNiImG5wFqJ51ZY{MaW5yt zn}CC3J(IG#znsSM^2lY^w-l7A6G=jv6c0?m(eYoi7fqSLBqJ+G1}S&8P9tj8E6+hz z$PM;`&p5$%@J-z|663x7LvVa_ba2%BV!y^>_5V(G?@rpN%Ky55FwVyRIvDr)UpG>= zmCsXK_wPRvZ|~A%ud3vHy4yN%xAfMwI%F58bL$|9h$<*UmH zqS8^rikq@wT|6eX+*3`0(TijC~$M>X6qBH(fx@; zH`trn@y$0iIPrb*Fa%#w=tCC`fp~wXoa7nAKJxxXZs;$Vv7Ar8;sw_6q07>ITC!sT zFde6r%qGbtO*KN9E?pN}KZP)u@3Q_V<@VHD%w_5*^Rj{{_AkK2%(Z8}AA zaZ`;*b_wIK*>d?Qn`N?MF6T&|ekQ?L;GsvPXLDvQrZ8C~2w@$svrO?;{`6MHeKOtr#UuH6l5Vefb%j%=j@jz;rHx zOSB+)I^N$a-1kbFYD6-0V|#9Z8Z{W0EPz2PL~y?1FkUw;4|W-;DW9`?fa$`+|_d9cBV#Zd&_- zp2(!kwP*s4Bt_t^MR?F4YGQ72w|Laiq^FM0ve+T*azlR6C{%0d)8?@E^)aUsO4zD>w*M@g%!?v~H$=XS2 z>vLWy;cRoUY%76mGYOWK!#0<|wvxTJl&>`xwzd+pHpFgh!>*QGwUtD*8H1$-sm(>G zt%RptjBG7w>8qBLDlyt?lq>RZa$WIY3W#26*q6Tar7tbZe+K{n|NoSwZPWlF2mtBY BLHhsz literal 0 HcmV?d00001 diff --git a/library/ix-dev/charts/minio/charts/common-2304.0.1.tgz b/library/ix-dev/charts/minio/charts/common-2304.0.1.tgz deleted file mode 100644 index 7c62d116a04b6460223493f886aee30802a74fa2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4994 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 M|FKB=!T^c@07MDw_y7O^ diff --git a/library/ix-dev/charts/minio/ci/basic-values.yaml b/library/ix-dev/charts/minio/ci/basic-values.yaml new file mode 100644 index 0000000000..ab33ace467 --- /dev/null +++ b/library/ix-dev/charts/minio/ci/basic-values.yaml @@ -0,0 +1,20 @@ +minioConfig: + rootUser: super-admin + rootPassword: super-admin-password + +minioNetwork: + apiPort: 31000 + consolePort: 31001 + +minioStorage: + export: + type: pvc + logSearchApi: true + logSearchDiskCapacityGB: 5 + pgData: + type: pvc + pgBackup: + type: emptyDir + emptyDirConfig: + medium: "" + size: "" diff --git a/library/ix-dev/charts/minio/ci/https-values.yaml b/library/ix-dev/charts/minio/ci/https-values.yaml index 4b67b27752..f7a6e2df6c 100644 --- a/library/ix-dev/charts/minio/ci/https-values.yaml +++ b/library/ix-dev/charts/minio/ci/https-values.yaml @@ -1,50 +1,25 @@ -appVolumeMounts: +minioStorage: export: - emptyDir: true - mountPath: /export -distributedIps: [] -distributedMode: false -dnsConfig: - options: [] -emptyDirVolumes: true -environmentVariables: [] -extraAppVolumeMounts: [] -extraArgs: [] -image: - pullPolicy: IfNotPresent - repository: minio/minio - tag: RELEASE.2023-03-13T19-46-17Z -ixChartContext: {} -logSearchImage: - pullPolicy: IfNotPresent - repository: minio/operator - tag: v4.5.4 -logsearchapi: - diskCapacityGB: 5 - enabled: true -minioDomain: null -postgresAppVolumeMounts: - postgres-backup: - emptyDir: true - mountPath: /postgres_backups - postgres-data: - emptyDir: true - mountPath: /var/lib/postgresql/data -postgresql: - backupVolume: - datasetName: ix-postgres_backups - mountPath: /postgres_backups - dataVolume: - datasetName: ix-postgres_data - mountPath: /var/lib/postgresql/data -runAsGroup: 473 -runAsUser: 473 -service: - consolePort: 32325 - nodePort: 32324 -updateStrategy: RollingUpdate + type: pvc + logSearchApi: true + logSearchDiskCapacityGB: 5 + pgData: + type: pvc + pgBackup: + type: emptyDir + emptyDirConfig: + medium: "" + size: "" + +minioConfig: + rootUser: super-admin + rootPassword: super-admin-password + +minioNetwork: + apiPort: 31000 + consolePort: 31001 + certificateID: 1 -certificate: "1" ixCertificates: "1": certificate: | @@ -74,7 +49,6 @@ ixCertificates: x5TKv3wcPnktx0zMPfLb5BTSE9rc9djcBG0eIAsPT4FgiatCUChe7VhuMnqskxEz MymJLoq8+mzucRwFkOkR2EIt1x+Irl2mJVMeBow63rVZfUQBD8h++LqB -----END CERTIFICATE----- - -----BEGIN CERTIFICATE----- MIIEhDCCA2ygAwIBAgIDYFMXMA0GCSqGSIb3DQEBCwUAMGwxDDAKBgNVBAMMA2Fz ZDELMAkGA1UEBhMCVVMxDTALBgNVBAgMBGFzZGYxCzAJBgNVBAcMAmFmMQ0wCwYD diff --git a/library/ix-dev/charts/minio/ci/test-values.yaml b/library/ix-dev/charts/minio/ci/test-values.yaml deleted file mode 100644 index a16c1b8cf0..0000000000 --- a/library/ix-dev/charts/minio/ci/test-values.yaml +++ /dev/null @@ -1,45 +0,0 @@ -appVolumeMounts: - export: - emptyDir: true - mountPath: /export -distributedIps: [] -distributedMode: false -dnsConfig: - options: [] -emptyDirVolumes: true -environmentVariables: [] -extraAppVolumeMounts: [] -extraArgs: [] -image: - pullPolicy: IfNotPresent - repository: minio/minio - tag: RELEASE.2023-03-13T19-46-17Z -ixChartContext: {} -logSearchImage: - pullPolicy: IfNotPresent - repository: minio/operator - tag: v4.5.4 -logsearchapi: - diskCapacityGB: 5 - enabled: true -minioDomain: null -postgresAppVolumeMounts: - postgres-backup: - emptyDir: true - mountPath: /postgres_backups - postgres-data: - emptyDir: true - mountPath: /var/lib/postgresql/data -postgresql: - backupVolume: - datasetName: ix-postgres_backups - mountPath: /postgres_backups - dataVolume: - datasetName: ix-postgres_data - mountPath: /var/lib/postgresql/data -runAsGroup: 473 -runAsUser: 473 -service: - consolePort: 32325 - nodePort: 32324 -updateStrategy: RollingUpdate diff --git a/library/ix-dev/charts/minio/migrations/migrate b/library/ix-dev/charts/minio/migrations/migrate index 155c8ff372..5ec59c3e87 100755 --- a/library/ix-dev/charts/minio/migrations/migrate +++ b/library/ix-dev/charts/minio/migrations/migrate @@ -2,119 +2,101 @@ import json import os import sys -import subprocess -from pathlib import Path - -from middlewared.client import Client -from middlewared.service import ValidationErrors, CallError -def path_in_locked_datasets(path: str) -> bool: - with Client() as c: - return c.call('pool.dataset.path_in_locked_datasets', path) +def migrate_volume(volume): + return { + 'type': 'hostPath', + 'hostPathConfig': { + 'hostPath': volume['hostPath'] + }, + } if volume.get('hostPathEnabled', False) else { + 'type': 'ixVolume', + 'ixVolumeConfig': { + 'datasetName': volume['datasetName'], + }, + } -def get_configured_user_group(path: str) -> dict: - with Client() as c: - return c.call('filesystem.stat', path) +def migrate_common_lib(values): + delete_keys = [ + 'dnsConfig', 'updateStrategy', 'enableResourceLimits', 'cpuLimit', + 'memLimit', 'certificate', 'service', 'environmentVariables', 'minioDomain', + 'accessKey', 'secretKey', 'distributedMode', 'distributedIps', 'logsearchapi', + 'appVolumeMounts', 'extraAppVolumeMounts', 'postgresAppVolumeMounts' + ] + values.update({ + # Migrate Config + 'minioConfig': { + 'rootUser': values['accessKey'], + 'rootPassword': values['secretKey'], + 'domain': values.get('minioDomain', ''), + 'extraArgs': values.get('extraArgs', []), + 'additionalEnvs': [e for e in values.get('environmentVariables', []) if e['name'] not in ['PLEX_UID', 'PLEX_GID'] ], + }, + # Migrate Network + 'minioNetwork': { + 'apiPort': values['service']['nodePort'], + 'consolePort': values['service']['consolePort'], + 'certificateID': values['certificate'], + }, + # Migrate Resources + 'resources': { + 'limits': { + 'cpu': values.get('cpuLimit', '4000m'), + 'memory': values.get('memLimit', '8Gi'), + } + }, + # Migrate DNS + 'podOptions': { + 'dnsConfig': { + 'options': [ + {'name': opt['name'], 'value': opt['value']} + for opt in values.get('dnsConfig', {}).get('options', []) + ] + } + }, + # Migrate Storage + 'minioStorage': { + 'distributedMode': values['distributedMode'] + 'distributedIps': values['distributedIps'] if values['distributedMode'] else [], + 'logSearchApi': values['logsearchapi']['enabled'], + 'logSearchDiskCapacityGB': values['logsearchapi']['diskCapacityGB'] if values['logsearchapi']['enabled'] else 5, + 'export': migrate_volume(values['appVolumeMounts']['export']).update({ + mountPath: values['appVolumeMounts']['export'][mountPath] + }), + 'pgData': migrate_volume(values['postgresAppVolumeMounts']['postgres-data']), + 'pgBackup': migrate_volume(values['postgresAppVolumeMounts']['postgres-backup']), + 'additionalStorages': [ + { + 'type': 'hostPath', + 'hostPathConfig': {'hostPath': e['hostPath']}, + 'mountPath': e['mountPath'], + 'readOnly': e['readOnly'], + } + for e in values.get('extraAppVolumeMounts', []) + ], + }, + }) -def get_host_path_attachments(path: str) -> set: - with Client() as c: - return { - attachment['type'] - for attachment in c.call('pool.dataset.attachments_with_path', path) - if attachment['type'].lower() not in ['kubernetes', 'chart releases'] - } - - -def get_kubernetes_config() -> dict: - with Client() as c: - return c.call('kubernetes.config') - - -def validate_host_path(path: str, schema_name: str, verrors: ValidationErrors) -> None: - """ - These validations are taken from `FilesystemService._common_perm_path_validate`. - Including an additional validation that makes sure all the children under - a path are on same device. - """ - schema_name += ".migration.chown" - p = Path(path) - if not p.is_absolute(): - verrors.add(schema_name, f"Must be an absolute path: {path}") - - if p.is_file(): - verrors.add(schema_name, f"Recursive operations on a file are invalid: {path}") - - if not p.absolute().as_posix().startswith("/mnt/"): - verrors.add( - schema_name, - f"Changes to permissions on paths that are not beneath the directory /mnt are not permitted: {path}" - ) - elif len(p.resolve().parents) == 2: - verrors.add(schema_name, f"The specified path is a ZFS pool mountpoint: {path}") - - # Make sure that dataset is not locked - if path_in_locked_datasets(path): - verrors.add(schema_name, f"Dataset is locked at path: {path}.") - - # Validate attachments - if attachments := get_host_path_attachments(path): - verrors.add(schema_name, f"The path '{path}' is already attached to service(s): {', '.join(attachments)}.") - - # Make sure all the minio's data directory children are on same device. - device_id = os.stat(path).st_dev - for root, dirs, files in os.walk(path): - for child in dirs + files: - abs_path = os.path.join(root, child) - if os.stat(abs_path).st_dev != device_id: - verrors.add( - schema_name, - (f"All the children of MinIO data directory should be on " - f"same device as root: path={abs_path} device={os.stat(abs_path).st_dev}") - ) - break - - -def migrate(values: dict) -> dict: - # minio user / group ID - uid = gid = 473 - verrors = ValidationErrors() - k8s_config = get_kubernetes_config() - if values["appVolumeMounts"]["export"]["hostPathEnabled"]: - host_path = values["appVolumeMounts"]["export"]["hostPath"] - else: - app_dataset = values["appVolumeMounts"]["export"]["datasetName"] - host_path = os.path.join( - "/mnt", k8s_config['dataset'], "releases", values["release_name"], "volumes/ix_volumes", app_dataset - ) - - current_config = get_configured_user_group(host_path) - if current_config["uid"] == uid and current_config["gid"] == gid: - return values - - validate_host_path(host_path, values['release_name'], verrors) - verrors.check() - # chown the host path - acltool = subprocess.run([ - "/usr/bin/nfs4xdr_winacl", - "-a", "chown", - "-O", str(uid), "-G", str(gid), - "-r", - "-c", host_path, - "-p", host_path], check=False, capture_output=True - ) - if acltool.returncode != 0: - raise CallError(f"acltool [chown] on path {host_path} failed with error: [{acltool.stderr.decode().strip()}]") + for k in delete_keys: + values.pop(k, None) return values +def migrate(values): + # If this missing, we have already migrated + if not 'nodePort' in values.keys(): + return values -if __name__ == "__main__": + return migrate_common_lib(values) + + +if __name__ == '__main__': if len(sys.argv) != 2: exit(1) if os.path.exists(sys.argv[1]): - with open(sys.argv[1], "r") as f: + with open(sys.argv[1], 'r') as f: print(json.dumps(migrate(json.loads(f.read())))) diff --git a/library/ix-dev/charts/minio/migrations/migrate_from_1.0.0 b/library/ix-dev/charts/minio/migrations/migrate_from_1.0.0 deleted file mode 100755 index d9772faa1d..0000000000 --- a/library/ix-dev/charts/minio/migrations/migrate_from_1.0.0 +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/python3 -import json -import os -import sys - - -def migrate(values): - if values.get('appVolumeMounts'): - return values - - values.update({ - 'appVolumeMounts': { - 'export': { - 'hostPathEnabled': values['minioHostPathEnabled'], - **({'hostPath': values['minioHostPath']} if values.get('minioHostPath') else {}) - }, - }, - }) - return values - - -if __name__ == '__main__': - if len(sys.argv) != 2: - exit(1) - - if os.path.exists(sys.argv[1]): - with open(sys.argv[1], 'r') as f: - print(json.dumps(migrate(json.loads(f.read())))) diff --git a/library/ix-dev/charts/minio/questions.yaml b/library/ix-dev/charts/minio/questions.yaml index 1ac1e9bb82..587d04987f 100644 --- a/library/ix-dev/charts/minio/questions.yaml +++ b/library/ix-dev/charts/minio/questions.yaml @@ -1,380 +1,634 @@ groups: - - name: "Container Images" - description: "Image to be used for container" - - name: "Workload Configuration" - description: "Configure workload deployment" - - name: "Minio Configuration" - description: "Configure Minio credentials" - - name: "Storage" - description: "Configure Storage for Minio" - - name: "Advanced DNS Settings" - description: "Configure DNS settings" - - name: "Resource Limits" - description: "Set CPU/memory limits for Kubernetes Pod" + - name: Minio Configuration + description: Configure Minio + - name: Advanced Pod Configuration + description: Configure Advanced Pod Options for Minio + - name: Network Configuration + description: Configure Network for Minio + - name: Storage Configuration + description: Configure Storage for Minio + - name: Resources Configuration + description: Configure Resources for Minio portals: web_portal: protocols: - - "$kubernetes-resource_configmap_minio-config_protocol" + - "$kubernetes-resource_configmap_portal_protocol" host: - - "$node_ip" + - "$kubernetes-resource_configmap_portal_host" ports: - - "$variable-service.consolePort" + - "$kubernetes-resource_configmap_portal_port" + path: "$kubernetes-resource_configmap_portal_path" questions: - - - variable: dnsConfig - label: "DNS Configuration" - group: "Advanced DNS Settings" - schema: - type: dict - attrs: - - variable: options - label: "DNS Options" - schema: - type: list - items: - - variable: optionsEntry - label: "Option Entry Configuration" - schema: - type: dict - attrs: - - variable: name - label: "Option Name" - schema: - type: string - required: true - - variable: value - label: "Option Value" - schema: - type: string - required: true - - - variable: updateStrategy - label: "Minio update strategy" - group: "Workload Configuration" - schema: - type: string - default: "Recreate" - enum: - - value: "RollingUpdate" - description: "Create new pods and then kill old ones" - - value: "Recreate" - description: "Kill existing pods before creating new ones" - - - variable: distributedMode - label: "Enable Distributed Mode" - description: "Run Minio instance to connect to a distributed minio cluster" - group: "Minio Configuration" - schema: - type: boolean - default: false - show_subquestions_if: true - subquestions: - - variable: distributedIps - label: "Distributed Minio Instance URI(s)" - schema: - type: list - required: true - default: [] - items: - - variable: ip - label: "Distributed Minio Instance URI" - schema: - type: string - empty: false - - - - variable: extraArgs - label: "Minio Extra Arguments" - group: "Minio Configuration" - schema: - type: list - default: [] - items: - - variable: arg - label: "Argument" - schema: - type: string - - - variable: accessKey - label: "Root User" - group: "Minio Configuration" - description: "Enter the S3 Root User" - schema: - type: string - private: true - required: true - min_length: 5 - max_length: 20 - - - variable: secretKey - label: "Root Password" - group: "Minio Configuration" - description: "Enter the S3 Root Password" - schema: - type: string - private: true - required: true - min_length: 8 - max_length: 40 - - - variable: environmentVariables - label: "Minio image environment" - group: "Minio Configuration" - schema: - type: list - default: [] - items: - - variable: environmentVariable - label: "Environment Variable" - schema: - type: dict - attrs: - - variable: name - label: "Name" - schema: - type: string - - variable: value - label: "Value" - schema: - type: string - - - variable: service - description: "Minio Service Configuration" - label: "Minio Service Configuration" - group: "Minio Configuration" - schema: - type: dict - required: true - attrs: - - variable: nodePort - label: "Node Port to use for Minio API" - schema: - type: int - min: 9000 - max: 65535 - default: 9000 - required: true - - variable: consolePort - label: "Node Port to use for Minio UI Access" - schema: - type: int - min: 9000 - max: 65535 - default: 9002 - required: true - - - variable: certificate - description: "Minio Certificate" - label: "Minio Certificate" - group: "Minio Configuration" - schema: - type: int - $ref: - - "definitions/certificate" - - - variable: minioDomain - label: "Minio Domain Name" - description: | - Depending on your setup/environment, you may need to leave this blank. - Check MinIO documentation for more information. - group: "Minio Configuration" - schema: - type: string - default: null - "null": true - show_if: [["certificate", "!=", null]] - - - variable: logsearchapi - label: Log Search API Configuration - description: Log Search API Configuration + - variable: minioConfig + label: "" group: Minio Configuration schema: type: dict attrs: - - variable: enabled - label: Enable Log Search API - description: Enables Log Search API and configures MinIO to use it. It also deploys a postgres DB for it. + - variable: rootUser + label: Root User + description: The root user for Minio. + schema: + type: string + private: true + required: true + min_length: 5 + max_length: 20 + - variable: rootPassword + label: Root Password + description: The root password for Minio. + schema: + type: string + private: true + required: true + min_length: 8 + max_length: 40 + - variable: domain + label: Domain (Optional) + description: | + Depending on your setup/environment, you may need to leave this blank. + Check MinIO documentation for more information. + schema: + type: string + - variable: extraArgs + label: Extra Arguments + description: Extra arguments for Minio. + schema: + type: list + default: [] + items: + - variable: arg + label: Argument + schema: + type: string + required: true + + - variable: additionalEnvs + label: Additional Environment Variables + description: Configure additional environment variables for Netdata. + schema: + type: list + default: [] + items: + - variable: env + label: Environment Variable + schema: + type: dict + attrs: + - variable: name + label: Name + schema: + type: string + required: true + - variable: value + label: Value + schema: + type: string + required: true + + - variable: podOptions + label: "" + group: Advanced Pod Configuration + schema: + type: dict + attrs: + - variable: dnsConfig + label: Advanced DNS Configuration + schema: + type: dict + attrs: + - variable: options + label: DNS Options + schema: + type: list + items: + - variable: optionsEntry + label: DNS Option Entry + schema: + type: dict + attrs: + - variable: name + label: Option Name + schema: + type: string + required: true + - variable: value + label: Option Value + schema: + type: string + required: true + + - variable: minioNetwork + label: "" + group: Network Configuration + schema: + type: dict + attrs: + - variable: apiPort + label: API Port + description: The port for the Minio API. + schema: + type: int + default: 9000 + min: 9000 + max: 65535 + required: true + - variable: consolePort + label: Console Port + description: The port for the Minio WebUI. + schema: + type: int + default: 9002 + min: 9000 + max: 65535 + required: true + - variable: certificateID + label: Certificate + description: The certificate to use for Minio. + schema: + type: int + "null": true + $ref: + - "definitions/certificate" + + - variable: minioStorage + label: "" + group: Storage Configuration + schema: + type: dict + attrs: + - variable: distributedMode + label: Enable Distributed Mode schema: type: boolean default: false - - variable: diskCapacityGB - label: Disk Capacity in GB - description: Capacity in GB that logs are allowed to occupy. + - variable: distributedIps + label: Distributed Minio Instance URI(s) schema: - type: int - show_if: [["enabled", "=", true]] - default: 5 - - - variable: appVolumeMounts - label: "Minio Storage" - group: "Storage" - schema: - type: dict - show_if: [["distributedMode", "=", false]] - attrs: - - variable: export - label: "Data Volume" - schema: - type: dict - attrs: - - variable: datasetName - label: "Minio Data Volume Name" + type: list + show_if: [["distributedMode", "==", true]] + required: true + default: [] + items: + - variable: ip + label: Distributed Minio Instance URI schema: type: string - hidden: true + required: true + - variable: export + label: Minio Export Storage + description: The path to store Minio Export. + schema: + type: dict + show_if: [["distributedMode", "==", true]] + attrs: + - variable: type + label: Type + description: | + ixVolume: Is dataset created automatically by the system.
+ Host Path: Is a path that already exists on the system. + schema: + type: string + required: true + default: ixVolume + enum: + - value: hostPath + description: Host Path (Path that already exists on the system) + - value: ixVolume + description: ixVolume (Dataset created automatically by the system) + - variable: mountPath + label: Mount Path + description: The path inside the container to mount the storage. + schema: + type: path + default: /export + required: true + immutable: true + - variable: ixVolumeConfig + label: ixVolume Configuration + description: The configuration for the ixVolume dataset. + schema: + type: dict + show_if: [["type", "=", "ixVolume"]] $ref: - "normalize/ixVolume" - show_if: [["hostPathEnabled", "=", false]] - default: "ix-minio" - editable: false - - variable: mountPath - label: "Minio Data Mount Path" - description: "Path where the volume will be mounted inside the pod" - schema: - type: path - default: "/export" - immutable: true - - variable: hostPathEnabled - label: "Enable Host Path for Minio Data Volume" - schema: - type: boolean - default: false - show_subquestions_if: true - subquestions: - - variable: hostPath - label: "Host Path for Minio Data Volume" + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. schema: - type: hostpath + type: boolean + default: false + - variable: datasetName + label: Dataset Name + description: The name of the dataset to use for storage. + schema: + type: string required: true immutable: true + hidden: true + default: "export" + - variable: aclEntries + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + - variable: hostPathConfig + label: Host Path Configuration + schema: + type: dict + show_if: [["type", "=", "hostPath"]] + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + default: false + - variable: acl + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + $ref: + - "normalize/acl" + - variable: hostPath + label: Host Path + description: The host path to use for storage. + schema: + type: hostpath + show_if: [["aclEnable", "=", false]] + required: true - - variable: extraAppVolumeMounts - label: "Extra Host Path Volumes" - group: "Storage" - schema: - type: list - items: - - variable: extraAppVolume - label: "Host Path Volume" - description: "Add an extra host path volume for Minio application" + - variable: logSearchApi + label: Enable Log Search API + schema: + type: boolean + default: false + - variable: logSearchDiskCapacityGB + label: Log Search Disk Capacity + schema: + type: int + show_if: [["logSearchApi", "==", true]] + default: 5 + - variable: pgData + label: Minio Postgres Data Storage + description: The path to store Minio Postgres Data. schema: type: dict + show_if: [["logSearchApi", "==", true]] attrs: - - variable: mountPath - label: "Mount Path in Pod" - description: "Path where the volume will be mounted inside the pod" + - variable: type + label: Type + description: | + ixVolume: Is dataset created automatically by the system.
+ Host Path: Is a path that already exists on the system. schema: - type: path + type: string required: true - - variable: hostPath - label: "Host Path" - description: "Host path" + default: ixVolume + enum: + - value: hostPath + description: Host Path (Path that already exists on the system) + - value: ixVolume + description: ixVolume (Dataset created automatically by the system) + - variable: ixVolumeConfig + label: ixVolume Configuration + description: The configuration for the ixVolume dataset. schema: - type: hostpath + type: dict + # Nothing to show for the user + hidden: true + show_if: [["type", "=", "ixVolume"]] + $ref: + - "normalize/ixVolume" + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + # Postgres does a CHMOD at startup + # Which fails with ACL + hidden: true + default: false + - variable: datasetName + label: Dataset Name + description: The name of the dataset to use for storage. + schema: + type: string + required: true + immutable: true + hidden: true + default: "pgData" + - variable: aclEntries + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + - variable: hostPathConfig + label: Host Path Configuration + schema: + type: dict + show_if: [["type", "=", "hostPath"]] + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + # Postgres does a CHMOD at startup + # Which fails with ACL + hidden: true + default: false + - variable: acl + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + $ref: + - "normalize/acl" + - variable: hostPath + label: Host Path + description: The host path to use for storage. + schema: + type: hostpath + show_if: [["aclEnable", "=", false]] + required: true + - variable: pgBackup + label: Minio Postgres Backup Storage + description: The path to store Minio Postgres Backup. + schema: + type: dict + show_if: [["logSearchApi", "==", true]] + attrs: + - variable: type + label: Type + description: | + ixVolume: Is dataset created automatically by the system.
+ Host Path: Is a path that already exists on the system. + schema: + type: string required: true + immutable: true + default: ixVolume + enum: + - value: hostPath + description: Host Path (Path that already exists on the system) + - value: ixVolume + description: ixVolume (Dataset created automatically by the system) + - variable: ixVolumeConfig + label: ixVolume Configuration + description: The configuration for the ixVolume dataset. + schema: + type: dict + # Nothing to show for the user + hidden: true + show_if: [["type", "=", "ixVolume"]] + $ref: + - "normalize/ixVolume" + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + # Postgres does a CHMOD at startup + # Which fails with ACL + hidden: true + default: false + - variable: datasetName + label: Dataset Name + description: The name of the dataset to use for storage. + schema: + type: string + required: true + immutable: true + hidden: true + default: "pgBackup" + - variable: aclEntries + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + - variable: hostPathConfig + label: Host Path Configuration + schema: + type: dict + show_if: [["type", "=", "hostPath"]] + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + # Postgres does a CHMOD at startup + # Which fails with ACL + hidden: true + default: false + - variable: acl + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + $ref: + - "normalize/acl" + - variable: hostPath + label: Host Path + description: The host path to use for storage. + schema: + type: hostpath + show_if: [["aclEnable", "=", false]] + required: true - - variable: postgresAppVolumeMounts - label: Postgres Storage - group: Storage + - variable: additionalStorages + label: Additional Storage + description: Additional storage for Minio. + schema: + type: list + default: [] + items: + - variable: storageEntry + label: Storage Entry + schema: + type: dict + attrs: + - variable: type + label: Type + description: | + ixVolume: Is dataset created automatically by the system.
+ Host Path: Is a path that already exists on the system.
+ SMB Share: Is a SMB share that is mounted to a persistent volume claim. + schema: + type: string + required: true + default: "ixVolume" + enum: + - value: "hostPath" + description: Host Path (Path that already exists on the system) + - value: "ixVolume" + description: ixVolume (Dataset created automatically by the system) + - value: "smb-pv-pvc" + description: SMB Share (Mounts a persistent volume claim to a SMB share) + - variable: readOnly + label: Read Only + description: Mount the volume as read only. + schema: + type: boolean + default: false + - variable: mountPath + label: Mount Path + description: The path inside the container to mount the storage. + schema: + type: path + required: true + - variable: hostPathConfig + label: Host Path Configuration + schema: + type: dict + show_if: [["type", "=", "hostPath"]] + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + default: false + - variable: acl + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + $ref: + - "normalize/acl" + - variable: hostPath + label: Host Path + description: The host path to use for storage. + schema: + type: hostpath + show_if: [["aclEnable", "=", false]] + required: true + - variable: ixVolumeConfig + label: ixVolume Configuration + description: The configuration for the ixVolume dataset. + schema: + type: dict + show_if: [["type", "=", "ixVolume"]] + $ref: + - "normalize/ixVolume" + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + default: false + - variable: datasetName + label: Dataset Name + description: The name of the dataset to use for storage. + schema: + type: string + required: true + immutable: true + default: "storage_entry" + - variable: aclEntries + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + - variable: smbConfig + label: SMB Share Configuration + description: The configuration for the SMB Share. + schema: + type: dict + show_if: [["type", "=", "smb-pv-pvc"]] + attrs: + - variable: server + label: Server + description: The server for the SMB share. + schema: + type: string + required: true + - variable: share + label: Share + description: The share name for the SMB share. + schema: + type: string + required: true + - variable: domain + label: Domain (Optional) + description: The domain for the SMB share. + schema: + type: string + - variable: username + label: Username + description: The username for the SMB share. + schema: + type: string + required: true + - variable: password + label: Password + description: The password for the SMB share. + schema: + type: string + required: true + private: true + - variable: size + label: Size (in Gi) + description: The size of the volume quota. + schema: + type: int + required: true + min: 1 + default: 1 + + - variable: resources + group: Resources Configuration + label: "" schema: type: dict attrs: - - variable: postgres-data - label: Postgres Data Volume + - variable: limits + label: Limits schema: type: dict attrs: - - variable: datasetName - label: Postgres Data Volume Name + - variable: cpu + label: CPU + description: CPU limit for WG-Easy. schema: type: string - hidden: true - $ref: - - normalize/ixVolume - default: ix-postgres_data - show_if: [["hostPathEnabled", "=", false]] - editable: false - - variable: mountPath - label: Postgresql Data Mount Path - description: Path where the volume will be mounted inside the pod - schema: - type: path - hidden: true - editable: false - default: /var/lib/postgresql/data - - variable: hostPathEnabled - label: Enable Host Path for Postgres Data Volume - schema: - type: boolean - default: false - show_subquestions_if: true - subquestions: - - variable: hostPath - label: Host Path for Postgres Data Volume - schema: - type: hostpath - required: true - immutable: true - - - variable: postgres-backup - label: Postgres Backup Volume - schema: - type: dict - attrs: - - variable: datasetName - label: Postgres Backup Volume Name + max_length: 6 + valid_chars: '^(0\.[1-9]|[1-9][0-9]*)(\.[0-9]|m?)$' + valid_chars_error: | + Valid CPU limit formats are
+ - Plain Integer - eg. 1
+ - Float - eg. 0.5
+ - Milicpu - eg. 500m + default: "4000m" + required: true + - variable: memory + label: Memory + description: Memory limit for WG-Easy. schema: type: string - hidden: true - $ref: - - normalize/ixVolume - default: ix-postgres_backups - show_if: [["hostPathEnabled", "=", false]] - editable: false - - variable: mountPath - label: Postgresql Backup Mount Path - description: Path where the volume will be mounted inside the pod - schema: - type: path - hidden: true - editable: false - default: /postgres_backups - - variable: hostPathEnabled - label: Enable Host Path for Postgres Backup Volume - schema: - type: boolean - default: false - show_subquestions_if: true - subquestions: - - variable: hostPath - label: Host Path for Postgres Backup Volume - schema: - type: hostpath - required: true - - - variable: enableResourceLimits - label: "Enable Pod resource limits" - group: "Resource Limits" - schema: - type: boolean - default: false - - variable: cpuLimit - label: "CPU Limit" - description: "CPU resource limit allow plain integer values with suffix m(milli) e.g 1000m, 100." - group: "Resource Limits" - schema: - type: string - show_if: [["enableResourceLimits", "=", true]] - valid_chars: "^\\d+(?:\\.\\d+(?!.*m$)|m?$)" - default: "4000m" - - variable: memLimit - label: "Memory Limit" - group: "Resource Limits" - description: "Memory limits is specified by number of bytes. Followed by quantity suffix like E,P,T,G,M,k and Ei,Pi,Ti,Mi,Gi,Ki can also be used. e.g 129e6, 129M, 128974848000m, 123Mi" - schema: - type: string - show_if: [["enableResourceLimits", "=", true]] - valid_chars: "^([+-]?[0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" - default: "8Gi" + max_length: 12 + valid_chars: "^[1-9][0-9]*([EPTGMK]i?|e[0-9]+)?$" + valid_chars_error: | + Valid Memory limit formats are
+ - Suffixed with E/P/T/G/M/K - eg. 1G
+ - Suffixed with Ei/Pi/Ti/Gi/Mi/Ki - eg. 1Gi
+ - Plain Integer in bytes - eg. 1024
+ - Exponent - eg. 134e6 + default: "8Gi" + required: true diff --git a/library/ix-dev/charts/minio/templates/NOTES.txt b/library/ix-dev/charts/minio/templates/NOTES.txt index 88e8e93ef8..ba4e01146c 100644 --- a/library/ix-dev/charts/minio/templates/NOTES.txt +++ b/library/ix-dev/charts/minio/templates/NOTES.txt @@ -1,2 +1 @@ -Minio can be accessed from the following URL: -http://$node_ip:{{ .Values.service.nodePort }}/ +{{ include "ix.v1.common.lib.chart.notes" $ }} diff --git a/library/ix-dev/charts/minio/templates/_cert.tpl b/library/ix-dev/charts/minio/templates/_cert.tpl deleted file mode 100644 index f34777f65a..0000000000 --- a/library/ix-dev/charts/minio/templates/_cert.tpl +++ /dev/null @@ -1,33 +0,0 @@ -{{/* -Formats volumeMount for Minio tls keys and trusted certs -*/}} -{{- define "minio.tlsKeysVolumeMount" -}} -{{- if eq (include "minio.certAvailable" .) "true" -}} -- name: cert-secret-volume - mountPath: "/etc/minio/certs" -- name: trusted-cert-secret-volume - mountPath: "/etc/minio/certs/CAs" -{{- end }} -{{- end -}} - -{{/* -Formats volume for Minio tls keys and trusted certs -*/}} -{{- define "minio.tlsKeysVolume" -}} -{{- if eq (include "minio.certAvailable" .) "true" -}} -- name: cert-secret-volume - secret: - secretName: {{ include "minio.secretName" . }} - items: - - key: certPublicKey - path: public.crt - - key: certPrivateKey - path: private.key -- name: trusted-cert-secret-volume - secret: - secretName: {{ include "minio.secretName" . }} - items: - - key: certPublicKey - path: public.crt -{{- end }} -{{- end -}} diff --git a/library/ix-dev/charts/minio/templates/_configuration.tpl b/library/ix-dev/charts/minio/templates/_configuration.tpl new file mode 100644 index 0000000000..9e4d9f85df --- /dev/null +++ b/library/ix-dev/charts/minio/templates/_configuration.tpl @@ -0,0 +1,91 @@ +{{- define "minio.configuration" -}} + + {{- $fullname := (include "ix.v1.common.lib.chart.names.fullname" $) -}} + + {{- $auditToken := randAlphaNum 32 -}} + {{- $queryToken := randAlphaNum 32 -}} + {{/* Fetch secrets from pre-migration secret */}} + {{- with (lookup "v1" "Secret" .Release.Namespace "logsearchapi-details") -}} + {{- $auditToken = ((index .data "auditToken") | b64dec) -}} + {{- $queryToken = ((index .data "queryToken") | b64dec) -}} + {{- end -}} + + {{- with (lookup "v1" "Secret" .Release.Namespace (printf "%s-logsearch-creds" $fullname)) -}} + {{- $auditToken = ((index .data "LOGSEARCH_AUDIT_AUTH_TOKEN") | b64dec) -}} + {{- $queryToken = ((index .data "MINIO_LOG_QUERY_AUTH_TOKEN") | b64dec) -}} + {{- end -}} + {{- $queryURL := printf "http://%v-log:8080" $fullname -}} + {{- $webhookURL := printf "http://%v-log:8080/api/ingest?token=%v" $fullname $auditToken -}} + + {{/* DB details */}} + {{- $dbHost := (printf "%s-postgres" $fullname) -}} + {{- $dbUser := "logsearchapi" -}} + {{- $dbName := "logsearchapi" -}} + {{- $dbPass := randAlphaNum 32 -}} + + {{/* Fetch secrets from pre-migration secret */}} + {{- $tmpBackupHost := "" -}} + {{- with (lookup "v1" "Secret" .Release.Namespace "postgres-details") -}} + {{- $dbPass = ((index .data "db_password") | b64dec) -}} + {{- $tmpBackupHost = ((index .data "postgresHost") | b64dec) -}} + {{- end -}} + + {{- with (lookup "v1" "Secret" .Release.Namespace (printf "%s-postgres-creds" $fullname)) -}} + {{- $dbPass = ((index .data "POSTGRES_PASSWORD") | b64dec) -}} + {{- end -}} + + {{/* Temporary set dynamic db details on values, + so we can print them on the notes */}} + {{- $_ := set .Values "minioDbPass" $dbPass -}} + {{- $_ := set .Values "minioDbHost" $dbHost -}} + + {{- $dbURL := (printf "postgres://%s:%s@%s:5432/%s?sslmode=disable" $dbUser $dbPass $dbHost $dbName) }} +secret: + minio-creds: + enabled: true + data: + MINIO_ROOT_USER: {{ .Values.minioConfig.rootUser | quote }} + MINIO_ROOT_PASSWORD: {{ .Values.minioConfig.rootPassword | quote }} + + {{ if and .Values.minioNetwork.certificateID .Values.minioConfig.domain }} + MINIO_BROWSER_REDIRECT_URL: {{ printf "https://%s:%v" .Values.minioConfig.domain .Values.minioNetwork.consolePort }} + MINIO_SERVER_URL: {{ printf "https://%s:%v" .Values.minioConfig.domain .Values.minioNetwork.apiPort }} + {{ end }} + + {{ if .Values.minioStorage.logSearchApi }} + MINIO_LOG_QUERY_AUTH_TOKEN: {{ $queryToken }} + MINIO_LOG_QUERY_URL: {{ $queryURL }} + MINIO_AUDIT_WEBHOOK_ENDPOINT_ix-logsearch: {{ $webhookURL }} + MINIO_AUDIT_WEBHOOK_ENABLE_ix-logsearch: "on" + {{ end }} + + logsearch-creds: + enabled: true + data: + MINIO_LOG_QUERY_AUTH_TOKEN: {{ $queryToken | quote }} + LOGSEARCH_AUDIT_AUTH_TOKEN: {{ $auditToken | quote }} + LOGSEARCH_PG_CONN_STR: {{ $dbURL | quote }} + LOGSEARCH_DISK_CAPACITY_GB: {{ .Values.minioStorage.logSearchDiskCapacityGB | quote }} + postgres-creds: + enabled: true + data: + POSTGRES_USER: {{ $dbUser }} + POSTGRES_DB: {{ $dbName }} + POSTGRES_PASSWORD: {{ $dbPass }} + POSTGRES_HOST: {{ $dbHost }} + POSTGRES_URL: {{ $dbURL }} + {{- if eq (include "minio.is-migration" $) "true" }} + postgres-backup-creds: + enabled: true + annotations: + helm.sh/hook: "pre-upgrade" + helm.sh/hook-delete-policy: "hook-succeeded" + helm.sh/hook-weight: "1" + data: + POSTGRES_USER: {{ $dbUser }} + POSTGRES_DB: {{ $dbName }} + POSTGRES_PASSWORD: {{ $dbPass }} + POSTGRES_HOST: {{ $tmpBackupHost }} + POSTGRES_URL: {{ printf "postgres://%s:%s@%s-pg:5432/%s?sslmode=disable" $dbUser $dbPass $dbHost $dbName }} + {{- end }} +{{- end -}} diff --git a/library/ix-dev/charts/minio/templates/_helpers.tpl b/library/ix-dev/charts/minio/templates/_helpers.tpl deleted file mode 100644 index 4dcb8c5dd9..0000000000 --- a/library/ix-dev/charts/minio/templates/_helpers.tpl +++ /dev/null @@ -1,77 +0,0 @@ -{{/* -Determine secret name. -*/}} -{{- define "minio.secretName" -}} -{{- include "common.names.fullname" . -}} -{{- end -}} - - -{{/* -Retrieve true/false if minio certificate is configured -*/}} -{{- define "minio.certAvailable" -}} -{{- if .Values.certificate -}} -{{- $values := (. | mustDeepCopy) -}} -{{- $_ := set $values "commonCertOptions" (dict "certKeyName" $values.Values.certificate) -}} -{{- template "common.resources.cert_present" $values -}} -{{- else -}} -{{- false -}} -{{- end -}} -{{- end -}} - - -{{/* -Retrieve public key of minio certificate -*/}} -{{- define "minio.cert.publicKey" -}} -{{- $values := (. | mustDeepCopy) -}} -{{- $_ := set $values "commonCertOptions" (dict "certKeyName" $values.Values.certificate "publicKey" true) -}} -{{ include "common.resources.cert" $values }} -{{- end -}} - - -{{/* -Retrieve private key of minio certificate -*/}} -{{- define "minio.cert.privateKey" -}} -{{- $values := (. | mustDeepCopy) -}} -{{- $_ := set $values "commonCertOptions" (dict "certKeyName" $values.Values.certificate) -}} -{{ include "common.resources.cert" $values }} -{{- end -}} - - -{{/* -Retrieve scheme/protocol for minio -*/}} -{{- define "minio.scheme" -}} -{{- if eq (include "minio.certAvailable" .) "true" -}} -{{- print "https" -}} -{{- else -}} -{{- print "http" -}} -{{- end -}} -{{- end -}} - - -{{/* -Retrieve command for minio application -*/}} -{{- define "minio.commandArgs" -}} -{{- $arg := (printf "/usr/bin/docker-entrypoint.sh minio -S /etc/minio/certs server --console-address=':%d'" (.Values.service.consolePort | int)) -}} -{{- if .Values.distributedMode -}} -{{- cat $arg (join " " (concat (.Values.distributedIps | default list) (.Values.extraArgs | default list))) -}} -{{- else -}} -{{- cat $arg ((concat (list (printf "--address ':%d'" (.Values.service.nodePort | int))) (list (printf "%s" .Values.appVolumeMounts.export.mountPath)) (.Values.extraArgs | default list)) | join " ") -}} -{{- end -}} -{{- end -}} - - -{{/* -Enable host networking -*/}} -{{- define "minio.hostNetworking" -}} -{{- if .Values.distributedMode -}} -{{- print "true" -}} -{{- else -}} -{{- print "false" -}} -{{- end -}} -{{- end -}} diff --git a/library/ix-dev/charts/minio/templates/_logsearch.tpl b/library/ix-dev/charts/minio/templates/_logsearch.tpl new file mode 100644 index 0000000000..67ff197641 --- /dev/null +++ b/library/ix-dev/charts/minio/templates/_logsearch.tpl @@ -0,0 +1,40 @@ +{{- define "logsearchapi.workload" -}} +workload: + logsearchapi: + enabled: true + type: Deployment + podSpec: + hostNetwork: false + containers: + logsearchapi: + enabled: true + primary: true + imageSelector: logSearchImage + securityContext: + runAsUser: 473 + runAsGroup: 473 + command: + - /logsearchapi + envFrom: + - secretRef: + name: logsearch-creds + probes: + liveness: + enabled: true + type: http + path: /status + port: 8080 + readiness: + enabled: true + type: http + path: /status + port: 8080 + startup: + enabled: true + type: http + path: /status + port: 8080 + initContainers: + {{- include "ix.v1.common.app.postgresWait" (dict "name" "postgres-wait" + "secretName" "postgres-creds") | nindent 8 }} +{{- end -}} diff --git a/library/ix-dev/charts/minio/templates/_logsearchapi.tpl b/library/ix-dev/charts/minio/templates/_logsearchapi.tpl deleted file mode 100644 index 7ca162d970..0000000000 --- a/library/ix-dev/charts/minio/templates/_logsearchapi.tpl +++ /dev/null @@ -1,34 +0,0 @@ -{{- define "logsearchapi.imageName" -}} -{{- printf "%s:%s" .Values.logSearchImage.repository .Values.logSearchImage.tag -}} -{{- end -}} - -{{- define "logsearchapi.nameSuffix" -}} -{{- print "logsearchapi" -}} -{{- end -}} - -{{- define "logsearchapi.command" -}} -{{- print "/logsearchapi" -}} -{{- end -}} - -{{- define "logsearchapi.secretName" -}} -{{- print "logsearchapi-details" -}} -{{- end -}} - -{{- define "logsearchapi.envVariableConfiguration" -}} -{{- $envList := list -}} -{{- $secretName := (include "logsearchapi.secretName" .) -}} -{{- $postgresSecretName := (include "postgres.secretName" .) -}} -{{- $envList = mustAppend $envList (dict "name" "MINIO_LOG_QUERY_AUTH_TOKEN" "valueFromSecret" true "secretName" $secretName "secretKey" "queryToken") -}} -{{- $envList = mustAppend $envList (dict "name" "LOGSEARCH_AUDIT_AUTH_TOKEN" "valueFromSecret" true "secretName" $secretName "secretKey" "auditToken") -}} -{{- $envList = mustAppend $envList (dict "name" "LOGSEARCH_PG_CONN_STR" "valueFromSecret" true "secretName" $postgresSecretName "secretKey" "postgresURL") -}} -{{- $envList = mustAppend $envList (dict "name" "LOGSEARCH_DISK_CAPACITY_GB" "value" .Values.logsearchapi.diskCapacityGB) -}} -{{- include "common.containers.environmentVariables" (dict "environmentVariables" $envList) -}} -{{- end -}} - -{{/* Used in the minio init container (checks that logsearchapi is available) */}} -{{- define "logsearchapiInit.envVariableConfiguration" -}} -{{- $envList := list -}} -{{- $secretName := (include "logsearchapi.secretName" .) -}} -{{- $envList = mustAppend $envList (dict "name" "apiURL" "valueFromSecret" true "secretName" $secretName "secretKey" "logQueryURL") -}} -{{- include "common.containers.environmentVariables" (dict "environmentVariables" $envList) -}} -{{- end -}} diff --git a/library/ix-dev/charts/minio/templates/_migration.tpl b/library/ix-dev/charts/minio/templates/_migration.tpl new file mode 100644 index 0000000000..dfd7eb5a15 --- /dev/null +++ b/library/ix-dev/charts/minio/templates/_migration.tpl @@ -0,0 +1,48 @@ +{{- define "minio.get-versions" -}} + {{- $oldChartVersion := "" -}} + {{- $newChartVersion := "" -}} + + {{/* Safely access the context, so it wont block CI */}} + {{- if hasKey .Values.global "ixChartContext" -}} + {{- if .Values.global.ixChartContext.upgradeMetadata -}} + + {{- $oldChartVersion = .Values.global.ixChartContext.upgradeMetadata.oldChartVersion -}} + {{- $newChartVersion = .Values.global.ixChartContext.upgradeMetadata.newChartVersion -}} + {{- if and (not $oldChartVersion) (not $newChartVersion) -}} + {{- fail "Upgrade Metadata is missing. Cannot proceed" -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- toYaml (dict "old" $oldChartVersion "new" $newChartVersion) -}} +{{- end -}} + +{{- define "minio.migration" -}} + {{- $versions := (fromYaml (include "minio.get-versions" $)) -}} + {{- if and $versions.old $versions.new -}} + {{- $oldV := semver $versions.old -}} + {{- $newV := semver $versions.new -}} + + {{/* If new is v2.x.x */}} + {{- if eq ($newV.Major | int) 2 -}} + {{/* And old is v1.x.x, but lower than .7.24 */}} + {{- if and (eq $oldV.Major 1) (or (ne $oldV.Minor 7) (lt ($oldV.Patch | int) 24)) -}} + {{/* Block the upgrade */}} + {{- fail "Migration to 2.x.x is only allowed from 1.7.24 or higher" -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- define "minio.is-migration" -}} + {{- $isMigration := "" -}} + {{- $versions := (fromYaml (include "minio.get-versions" $)) -}} + {{- if $versions.old -}} + {{- $oldV := semver $versions.old -}} + {{- if and (eq $oldV.Major 1) (or (ne $oldV.Minor 7) (lt ($oldV.Patch | int) 24)) -}} + {{- $isMigration = "true" -}} + {{- end -}} + {{- end -}} + + {{- $isMigration -}} +{{- end -}} diff --git a/library/ix-dev/charts/minio/templates/_minio.tpl b/library/ix-dev/charts/minio/templates/_minio.tpl new file mode 100644 index 0000000000..3ed1143ace --- /dev/null +++ b/library/ix-dev/charts/minio/templates/_minio.tpl @@ -0,0 +1,93 @@ +{{- define "minio.workload" -}} +{{- $fullname := (include "ix.v1.common.lib.chart.names.fullname" $) -}} +{{- $logapi := printf "http://%v-log:8080" $fullname -}} +workload: + minio: + enabled: true + primary: true + type: Deployment + podSpec: + hostNetwork: {{ .Values.minioStorage.distributedMode }} + containers: + minio: + enabled: true + primary: true + imageSelector: image + securityContext: + runAsUser: 473 + runAsGroup: 473 + # readOnlyRootFilesystem: false + env: + MINIO_VOLUMES: /export + args: + - server + - --console-address + - {{ printf ":%v" .Values.minioNetwork.consolePort | quote }} + {{- if .Values.minioStorage.distributedMode }} + {{- range .Values.minioStorage.distributedIps }} + - {{ quote . }} + {{- end }} + {{- else }} + - "--address" + - {{ printf ":%v" .Values.minioNetwork.apiPort | quote }} + {{- end }} + {{- if .Values.minioNetwork.certificateID }} + - "--certs-dir" + - "/etc/minio/certs" + {{- end }} + {{- range .Values.minioConfig.extraArgs }} + - {{ quote . }} + {{ end }} + envFrom: + - secretRef: + name: minio-creds + {{ with .Values.minioConfig.additionalEnvs }} + envList: + {{ range $env := . }} + - name: {{ $env.name }} + value: {{ $env.value }} + {{ end }} + {{ end }} + probes: + {{- $proto := "http" -}} + {{- if .Values.minioNetwork.certificateID -}} + {{- $proto = "https" -}} + {{- end }} + liveness: + enabled: true + type: {{ $proto }} + path: /minio/health/live + port: {{ .Values.minioNetwork.consolePort }} + readiness: + enabled: true + type: {{ $proto }} + path: /minio/health/live + port: {{ .Values.minioNetwork.consolePort }} + startup: + enabled: true + type: {{ $proto }} + path: /minio/health/live + port: {{ .Values.minioNetwork.consolePort }} + initContainers: + {{- include "ix.v1.common.app.permissions" (dict "containerName" "01-permissions" + "UID" 473 + "GID" 473 + "mode" "check" + "type" "init") | nindent 8 }} + wait-api: + enabled: true + type: init + imageSelector: bashImage + command: + - bash + args: + - -c + - | + echo "Waiting for [{{ $logapi }}]"; + until wget --spider --quiet --timeout=3 --tries=1 {{ $logapi }}/status; + do + echo "Waiting for [{{ $logapi }}]"; + sleep 2; + done + echo "API is up: {{ $logapi }}"; +{{- end -}} diff --git a/library/ix-dev/charts/minio/templates/_persistence.tpl b/library/ix-dev/charts/minio/templates/_persistence.tpl new file mode 100644 index 0000000000..b08b941a2c --- /dev/null +++ b/library/ix-dev/charts/minio/templates/_persistence.tpl @@ -0,0 +1,77 @@ +{{- define "minio.persistence" -}} +persistence: + export: + enabled: true + {{- include "ix.v1.common.app.storageOptions" (dict "storage" .Values.minioStorage.export) | nindent 4 }} + targetSelector: + minio: + minio: + mountPath: {{ .Values.minioStorage.export.mountPath }} + {{- if and (eq .Values.minioStorage.export.type "ixVolume") + (not (.Values.minioStorage.export.ixVolumeConfig | default dict).aclEnable) }} + 01-permissions: + mountPath: /mnt/directories/export + {{- end }} + tmp: + enabled: true + type: emptyDir + targetSelector: + minio: + minio: + mountPath: /tmp + {{- range $idx, $storage := .Values.minioStorage.additionalStorages }} + {{ printf "minio-%v:" (int $idx) }} + enabled: true + {{- include "ix.v1.common.app.storageOptions" (dict "storage" $storage) | nindent 4 }} + targetSelector: + minio: + minio: + mountPath: {{ $storage.mountPath }} + {{- if and (eq $storage.type "ixVolume") (not ($storage.ixVolumeConfig | default dict).aclEnable) }} + 01-permissions: + mountPath: /mnt/directories{{ $storage.mountPath }} + {{- end }} + {{- end }} + + {{- include "ix.v1.common.app.postgresPersistence" + (dict "pgData" .Values.minioStorage.pgData + "pgBackup" .Values.minioStorage.pgBackup + ) | nindent 2 }} + + {{- if .Values.minioNetwork.certificateID }} + cert: + enabled: true + type: secret + objectName: minio-cert + defaultMode: "0600" + items: + - key: tls.key + path: private.key + - key: tls.crt + path: public.crt + targetSelector: + minio: + minio: + mountPath: /etc/minio/certs + readOnly: true + certca: + enabled: true + type: secret + objectName: minio-cert + defaultMode: "0600" + items: + - key: tls.crt + path: public.crt + targetSelector: + minio: + minio: + mountPath: /etc/minio/certs/CAs + readOnly: true + +scaleCertificate: + minio-cert: + enabled: true + id: {{ .Values.minioNetwork.certificateID }} + {{- end }} + +{{- end -}} diff --git a/library/ix-dev/charts/minio/templates/_portal.tpl b/library/ix-dev/charts/minio/templates/_portal.tpl new file mode 100644 index 0000000000..66cfecf247 --- /dev/null +++ b/library/ix-dev/charts/minio/templates/_portal.tpl @@ -0,0 +1,16 @@ +{{- define "minio.portal" -}} + {{- $proto := "http" -}} + {{- if .Values.minioNetwork.certificateID -}} + {{- $proto = "https" -}} + {{- end }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: portal +data: + path: / + port: {{ .Values.minioNetwork.consolePort | quote }} + protocol: {{ $proto }} + host: "$node_ip" +{{- end -}} diff --git a/library/ix-dev/charts/minio/templates/_postgres.tpl b/library/ix-dev/charts/minio/templates/_postgres.tpl index 63b577ee1c..c1f3f393df 100644 --- a/library/ix-dev/charts/minio/templates/_postgres.tpl +++ b/library/ix-dev/charts/minio/templates/_postgres.tpl @@ -1,71 +1,12 @@ -{{- define "postgres.imageName" -}} -{{- print "postgres:14.5" -}} -{{- end -}} - -{{- define "postgres.nameSuffix" -}} -{{- print "postgres" -}} -{{- end -}} - -{{- define "postgres.secretName" -}} -{{- print "postgres-details" -}} -{{- end -}} - -{{- define "postgres.dbName" -}} -{{- print "logsearchapi" -}} -{{- end -}} - -{{- define "postgres.dbUser" -}} -{{- print "logsearchapi" -}} -{{- end -}} - -{{/* -Retrieve postgres backup name -This will return a unique name based on revision and chart numbers specified. -*/}} -{{- define "postgres.backupName" -}} -{{- $upgradeDict := .Values.ixChartContext.upgradeMetadata -}} -{{- printf "postgres-backup-from-%s-to-%s-revision-%d" $upgradeDict.oldChartVersion $upgradeDict.newChartVersion (int64 $upgradeDict.preUpgradeRevision) -}} -{{- end -}} - -{{- define "postgres.envVariableConfiguration" -}} -{{- $envList := list -}} -{{- $secretName := (include "postgres.secretName" .) -}} -{{- $envList = mustAppend $envList (dict "name" "POSTGRES_USER" "valueFromSecret" true "secretName" $secretName "secretKey" "db_user") -}} -{{- $envList = mustAppend $envList (dict "name" "POSTGRES_DB" "valueFromSecret" true "secretName" $secretName "secretKey" "db_name") -}} -{{- $envList = mustAppend $envList (dict "name" "POSTGRES_PASSWORD" "valueFromSecret" true "secretName" $secretName "secretKey" "db_password") -}} -{{- include "common.containers.environmentVariables" (dict "environmentVariables" $envList) -}} -{{- end -}} - -{{- define "postgresBackup.envVariableConfiguration" -}} -{{- $envList := list -}} -{{- $secretName := (include "postgres.secretName" .) -}} -{{- $envList = mustAppend $envList (dict "name" "POSTGRES_USER" "valueFromSecret" true "secretName" $secretName "secretKey" "db_user") -}} -{{- $envList = mustAppend $envList (dict "name" "POSTGRES_DB" "valueFromSecret" true "secretName" $secretName "secretKey" "db_name") -}} -{{/* PGPASSWORD is used by pg_dump */}} -{{- $envList = mustAppend $envList (dict "name" "PGPASSWORD" "valueFromSecret" true "secretName" $secretName "secretKey" "db_password") -}} -{{- $envList = mustAppend $envList (dict "name" "pgHost" "valueFromSecret" true "secretName" $secretName "secretKey" "postgresHost") -}} -{{- include "common.containers.environmentVariables" (dict "environmentVariables" $envList) -}} -{{- end -}} - -{{/* Used in the logsearchapi init container (checks that postgres is available) */}} -{{- define "postgresInit.envVariableConfiguration" -}} -{{- $envList := list -}} -{{- $secretName := (include "postgres.secretName" .) -}} -{{- $envList = mustAppend $envList (dict "name" "pgHost" "valueFromSecret" true "secretName" $secretName "secretKey" "postgresHost") -}} -{{- $envList = mustAppend $envList (dict "name" "pguser" "valueFromSecret" true "secretName" $secretName "secretKey" "db_user") -}} -{{- include "common.containers.environmentVariables" (dict "environmentVariables" $envList) -}} -{{- end -}} - -{{/* -Retrieve postgres volume configuration -*/}} -{{- define "postgres.volumeConfiguration" -}} -{{ include "common.storage.configureAppVolumes" (dict "appVolumeMounts" .Values.postgresAppVolumeMounts "emptyDirVolumes" .Values.emptyDirVolumes "ixVolumes" .Values.ixVolumes) | nindent 0 }} -{{- end -}} - -{{/* -Retrieve postgres volume mounts configuration -*/}} -{{- define "postgres.volumeMountsConfiguration" -}} -{{ include "common.storage.configureAppVolumeMountsInContainer" (dict "appVolumeMounts" .Values.postgresAppVolumeMounts ) | nindent 0 }} +{{- define "postgres.workload" -}} + {{- $backupSecretName := "postgres-creds" -}} + {{- if eq (include "minio.is-migration" $) "true" }} + {{- $backupSecretName = "postgres-backup-creds" -}} + {{- end }} +workload: +{{- include "ix.v1.common.app.postgres" (dict "secretName" "postgres-creds" + "backupSecretName" $backupSecretName + "resources" .Values.resources + "imageSelector" "logPostgresImage" + "ixChartContext" .Values.ixChartContext) | nindent 2 }} {{- end -}} diff --git a/library/ix-dev/charts/minio/templates/_service.tpl b/library/ix-dev/charts/minio/templates/_service.tpl new file mode 100644 index 0000000000..5ca378174d --- /dev/null +++ b/library/ix-dev/charts/minio/templates/_service.tpl @@ -0,0 +1,33 @@ +{{- define "minio.service" -}} +service: + minio: + enabled: true + primary: true + type: NodePort + targetSelector: minio + ports: + console: + enabled: true + primary: true + port: {{ .Values.minioNetwork.consolePort }} + nodePort: {{ .Values.minioNetwork.consolePort }} + targetSelector: minio + api: + enabled: true + port: {{ .Values.minioNetwork.apiPort }} + nodePort: {{ .Values.minioNetwork.apiPort }} + targetSelector: minio + {{ if .Values.minioStorage.logSearchApi }} + log: + enabled: true + type: ClusterIP + targetSelector: logsearchapi + ports: + log: + enabled: true + port: 8080 + targetPort: 8080 + targetSelector: logsearchapi + {{- include "ix.v1.common.app.postgresService" $ | nindent 2 }} + {{ end }} +{{- end -}} diff --git a/library/ix-dev/charts/minio/templates/backup-postgres-config.yaml b/library/ix-dev/charts/minio/templates/backup-postgres-config.yaml deleted file mode 100644 index e5892b8222..0000000000 --- a/library/ix-dev/charts/minio/templates/backup-postgres-config.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: postgres-backup-hook-config-map - annotations: - rollme: {{ randAlphaNum 5 | quote }} -data: - entrypoint.sh: |- - #!/bin/sh - cmd="/docker-entrypoint.sh postgres" - eval "${cmd}" & disown; - until pg_isready -U "$POSTGRES_USER" -h "$pgHost"; do - sleep 5; - done; - pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -h "$pgHost" -f /postgres_backups/$BACKUP_NAME.sql; diff --git a/library/ix-dev/charts/minio/templates/backup-postgres-hook.yaml b/library/ix-dev/charts/minio/templates/backup-postgres-hook.yaml deleted file mode 100644 index 5a576900b3..0000000000 --- a/library/ix-dev/charts/minio/templates/backup-postgres-hook.yaml +++ /dev/null @@ -1,40 +0,0 @@ -{{- if .Values.logsearchapi.enabled -}} -{{- if .Values.ixChartContext.isUpgrade -}} -{{ $values := (. | mustDeepCopy) }} -{{ $_ := set $values "common" (dict "nameSuffix" (include "postgres.nameSuffix" .)) }} -apiVersion: batch/v1 -kind: Job -metadata: - name: pre-upgrade-hook - annotations: - "helm.sh/hook": pre-upgrade - "helm.sh/hook-weight": "1" - "helm.sh/hook-delete-policy": hook-succeeded - rollme: {{ randAlphaNum 5 | quote }} -spec: - template: - metadata: - name: pre-upgrade-hook - spec: - restartPolicy: Never - containers: - - name: {{ .Chart.Name }}-postgres-backup - image: {{ include "postgres.imageName" . }} - imagePullPolicy: {{ .Values.image.pullPolicy }} - env: {{ include "postgresBackup.envVariableConfiguration" $values | nindent 10 }} - - name: BACKUP_NAME - value: {{ include "postgres.backupName" . }} - volumeMounts: {{ include "postgres.volumeMountsConfiguration" $values | nindent 10 }} - - name: backup-script-configmap - mountPath: /bin/backup_entrypoint.sh - readOnly: true - subPath: entrypoint.sh - command: - - /bin/backup_entrypoint.sh - volumes: {{ include "postgres.volumeConfiguration" $values | nindent 8 }} - - name: backup-script-configmap - configMap: - defaultMode: 0700 - name: postgres-backup-hook-config-map -{{- end -}} -{{- end -}} diff --git a/library/ix-dev/charts/minio/templates/common.yaml b/library/ix-dev/charts/minio/templates/common.yaml new file mode 100644 index 0000000000..cf48d7d300 --- /dev/null +++ b/library/ix-dev/charts/minio/templates/common.yaml @@ -0,0 +1,18 @@ +{{- include "ix.v1.common.loader.init" . -}} + +{{- include "minio.migration" $ -}} + +{{/* Merge the templates with Values */}} +{{- $_ := mustMergeOverwrite .Values (include "minio.service" $ | fromYaml) -}} +{{- $_ := mustMergeOverwrite .Values (include "minio.workload" $ | fromYaml) -}} +{{- $_ := mustMergeOverwrite .Values (include "minio.persistence" $ | fromYaml) -}} +{{- $_ := mustMergeOverwrite .Values (include "minio.configuration" $ | fromYaml) -}} +{{- if .Values.minioStorage.logSearchApi -}} + {{- $_ := mustMergeOverwrite .Values (include "postgres.workload" $ | fromYaml) -}} + {{- $_ := mustMergeOverwrite .Values (include "logsearchapi.workload" $ | fromYaml) -}} +{{- end -}} + +{{/* Create the configmap for portal manually*/}} +{{- include "minio.portal" $ -}} + +{{- include "ix.v1.common.loader.apply" . -}} diff --git a/library/ix-dev/charts/minio/templates/configmap.yaml b/library/ix-dev/charts/minio/templates/configmap.yaml deleted file mode 100644 index 98a62a3890..0000000000 --- a/library/ix-dev/charts/minio/templates/configmap.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: minio-config -data: - protocol: {{ include "minio.scheme" . }} diff --git a/library/ix-dev/charts/minio/templates/deployment.yaml b/library/ix-dev/charts/minio/templates/deployment.yaml deleted file mode 100644 index 2eaee3d75c..0000000000 --- a/library/ix-dev/charts/minio/templates/deployment.yaml +++ /dev/null @@ -1,134 +0,0 @@ -{{ include "common.storage.hostPathValidate" .Values }} -{{ $logsearchValues := (. | mustDeepCopy) }} -{{ $_ := set $logsearchValues "common" (dict "nameSuffix" (include "logsearchapi.nameSuffix" .)) }} -apiVersion: {{ template "common.capabilities.deployment.apiVersion" . }} -kind: Deployment -metadata: - name: {{ template "common.names.fullname" . }}-minio - labels: - app: {{ template "common.names.name" . }} - release: {{ .Release.Name }} - app.kubernetes.io/name: {{ template "common.names.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - annotations: - rollme: {{ randAlphaNum 5 | quote }} -spec: - replicas: {{ (default 1 .Values.replicas) }} - strategy: - type: {{ (default "Recreate" .Values.updateStrategy ) }} - selector: - matchLabels: - app: {{ template "common.names.name" . }} - release: {{ .Release.Name }} - app.kubernetes.io/name: {{ template "common.names.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - template: - metadata: - name: {{ template "common.names.fullname" . }} - labels: - {{- include "common.labels.selectorLabels" . | nindent 8 }} - annotations: {{ include "common.annotations" . | nindent 8 }} - spec: - securityContext: - runAsUser: {{ .Values.runAsUser }} - runAsGroup: {{ .Values.runAsGroup }} - serviceAccountName: {{ include "common.names.serviceAccountName" . | quote }} - hostNetwork: {{ include "minio.hostNetworking" . }} - {{ if .Values.logsearchapi.enabled }} - initContainers: - - name: {{ .Chart.Name }}-waitapi - image: alpine/curl - imagePullPolicy: {{ .Values.image.pullPolicy }} - env: {{ include "logsearchapiInit.envVariableConfiguration" $logsearchValues | nindent 10 }} - command: - - sh - - -c - - "until curl --silent $apiURL/status; do sleep 2; done" - {{ end }} - containers: - - name: {{ .Chart.Name }} - {{ include "common.resources.limitation" . | nindent 10 }} - {{ include "common.containers.imageConfig" .Values.image | nindent 10 }} - {{ if hasKey .Values "appVolumeMounts" }} - volumeMounts: {{ include "common.storage.configureAppVolumeMountsInContainer" .Values | nindent 12 }} - {{ else }} - volumeMounts: - {{ end }} - {{- include "minio.tlsKeysVolumeMount" . | nindent 12 }} - {{ range $index, $hostPathConfiguration := .Values.extraAppVolumeMounts }} - - name: extrappvolume-{{ $index }} - mountPath: {{ $hostPathConfiguration.mountPath }} - {{ end }} - command: - - "/bin/sh" - - "-ce" - - {{ include "minio.commandArgs" . }} - ports: - - name: api - containerPort: {{ .Values.service.nodePort | int }} - - name: console - containerPort: {{ .Values.service.consolePort | int }} - readinessProbe: - httpGet: - path: /minio/health/live - port: {{ .Values.service.consolePort | int }} - scheme: {{ include "minio.scheme" . | upper }} - initialDelaySeconds: 10 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 5 - successThreshold: 2 - livenessProbe: - httpGet: - path: /minio/health/live - port: {{ .Values.service.consolePort | int }} - scheme: {{ include "minio.scheme" . | upper }} - initialDelaySeconds: 10 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 5 - successThreshold: 1 - startupProbe: - httpGet: - path: /minio/health/live - port: {{ .Values.service.consolePort | int }} - scheme: {{ include "minio.scheme" . | upper }} - initialDelaySeconds: 10 - periodSeconds: 5 - timeoutSeconds: 2 - failureThreshold: 60 - successThreshold: 1 - env: - {{ $secretName := (include "minio.secretName" .) }} - {{ $envList := (default list .Values.environmentVariables) }} - {{ if and (eq (include "minio.certAvailable" .) "true") .Values.minioDomain }} - {{ $envList = mustAppend $envList (dict "name" "MINIO_BROWSER_REDIRECT_URL" "value" (printf "%s://%s:%d" (include "minio.scheme" .) .Values.minioDomain (.Values.service.consolePort | int))) }} - {{ $envList = mustAppend $envList (dict "name" "MINIO_SERVER_URL" "value" (printf "%s://%s:%d" (include "minio.scheme" .) .Values.minioDomain (.Values.service.nodePort | int))) }} - {{ end }} - {{ $envList = mustAppend $envList (dict "name" "MINIO_ROOT_USER" "valueFromSecret" true "secretName" $secretName "secretKey" "accesskey") }} - {{ $envList = mustAppend $envList (dict "name" "MINIO_ROOT_PASSWORD" "valueFromSecret" true "secretName" $secretName "secretKey" "secretkey") }} - {{ if .Values.logsearchapi.enabled }} - {{/* - We can put any ID we want here. Just make sure it's unique - It can be rolled on each startup without problems, or se can set a static one. - */}} - {{ $webhookID := (printf "ix-%v" (randAlphaNum 5)) }} - {{ $logsearchSecretName := (include "logsearchapi.secretName" .) }} - {{ $envList = mustAppend $envList (dict "name" "MINIO_LOG_QUERY_AUTH_TOKEN" "valueFromSecret" true "secretName" $logsearchSecretName "secretKey" "queryToken") }} - {{ $envList = mustAppend $envList (dict "name" "MINIO_LOG_QUERY_URL" "valueFromSecret" true "secretName" $logsearchSecretName "secretKey" "logQueryURL") }} - {{ $envList = mustAppend $envList (dict "name" (printf "MINIO_AUDIT_WEBHOOK_ENDPOINT_%v" $webhookID) "valueFromSecret" true "secretName" $logsearchSecretName "secretKey" "webhookURL") }} - {{ $envList = mustAppend $envList (dict "name" (printf "MINIO_AUDIT_WEBHOOK_ENABLE_%v" $webhookID) "value" "on") }} - {{ end }} - {{ include "common.containers.environmentVariables" (dict "environmentVariables" $envList) | nindent 12 }} -{{ include "common.networking.dnsConfiguration" .Values | nindent 6 }} - {{ if hasKey .Values "appVolumeMounts" }} - volumes: {{ include "common.storage.configureAppVolumes" .Values | nindent 8 }} - {{ else }} - volumes: - {{ end }} - {{- include "minio.tlsKeysVolume" . | nindent 8 }} - {{ range $index, $hostPathConfiguration := .Values.extraAppVolumeMounts }} - - name: extrappvolume-{{ $index }} - hostPath: - path: {{ $hostPathConfiguration.hostPath }} - {{ end }} diff --git a/library/ix-dev/charts/minio/templates/logsearchapi-deployment.yaml b/library/ix-dev/charts/minio/templates/logsearchapi-deployment.yaml deleted file mode 100644 index abe0e2774d..0000000000 --- a/library/ix-dev/charts/minio/templates/logsearchapi-deployment.yaml +++ /dev/null @@ -1,51 +0,0 @@ -{{ if .Values.logsearchapi.enabled }} -{{ $values := (. | mustDeepCopy) }} -{{ $_ := set $values "common" (dict "nameSuffix" (printf "%s-log" (include "logsearchapi.nameSuffix" .))) }} -{{ $pg_values := (. | mustDeepCopy) }} -{{ $_ := set $pg_values "common" (dict "nameSuffix" (include "postgres.nameSuffix" .)) }} -{{ include "common.deployment.common_config" $values | nindent 0 }} -spec: {{ include "common.deployment.common_spec" $values | nindent 2 }} - template: {{ include "common.deployment.pod.metadata" $values | nindent 4 }} - spec: - initContainers: - - name: {{ .Chart.Name }}-{{ include "logsearchapi.nameSuffix" . }}-waitdb - image: {{ include "postgres.imageName" . }} - imagePullPolicy: {{ .Values.image.pullPolicy }} - env: {{ include "postgresInit.envVariableConfiguration" $pg_values | nindent 10 }} - command: - - sh - - -c - - 'until pg_isready -U "$pgUser" -h "$pgHost"; do sleep 2; done' - containers: - - name: {{ .Chart.Name }}-{{ include "logsearchapi.nameSuffix" . }} - image: {{ include "logsearchapi.imageName" . }} - imagePullPolicy: {{ .Values.logSearchImage.pullPolicy }} - env: {{ include "logsearchapi.envVariableConfiguration" $values | nindent 10 }} - command: - - {{ include "logsearchapi.command" . }} - ports: - - name: logsearchapi - containerPort: 8080 - protocol: TCP - readinessProbe: - httpGet: - path: /status - port: 8080 - failureThreshold: 5 - periodSeconds: 15 - initialDelaySeconds: 15 - livenessProbe: - httpGet: - path: /status - port: 8080 - failureThreshold: 5 - periodSeconds: 15 - initialDelaySeconds: 15 - startupProbe: - httpGet: - path: /status - port: 8080 - failureThreshold: 5 - periodSeconds: 15 - initialDelaySeconds: 15 -{{ end }} diff --git a/library/ix-dev/charts/minio/templates/logsearchapi-secret.yaml b/library/ix-dev/charts/minio/templates/logsearchapi-secret.yaml deleted file mode 100644 index 0478e5bc04..0000000000 --- a/library/ix-dev/charts/minio/templates/logsearchapi-secret.yaml +++ /dev/null @@ -1,23 +0,0 @@ -{{ $logSearchValues := (. | mustDeepCopy) }} -{{ $_ := set $logSearchValues "common" (dict "nameSuffix" (include "logsearchapi.nameSuffix" .)) }} - -{{ $auditToken := randAlphaNum 32 | b64enc }} -{{ $queryToken := randAlphaNum 32 | b64enc }} - -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "logsearchapi.secretName" . }} -data: - {{ with (lookup "v1" "Secret" .Release.Namespace (include "logsearchapi.secretName" .)) }} - {{ $auditToken = (index .data "auditToken") }} - {{ end }} - auditToken: {{ $auditToken }} - - {{ with (lookup "v1" "Secret" .Release.Namespace (include "logsearchapi.secretName" .)) }} - {{ $queryToken = (index .data "queryToken") }} - {{ end }} - queryToken: {{ $queryToken }} - - logQueryURL: {{ (printf "http://%v-log:8080" (include "common.names.fullname" $logSearchValues)) | b64enc }} - webhookURL: {{ (printf "http://%v-log:8080/api/ingest?token=%v" (include "common.names.fullname" $logSearchValues) ($auditToken | b64dec)) | b64enc }} diff --git a/library/ix-dev/charts/minio/templates/logsearchapi-service.yaml b/library/ix-dev/charts/minio/templates/logsearchapi-service.yaml deleted file mode 100644 index 0ddfa91c4e..0000000000 --- a/library/ix-dev/charts/minio/templates/logsearchapi-service.yaml +++ /dev/null @@ -1,8 +0,0 @@ -{{ if .Values.logsearchapi.enabled }} -{{ $ports := list }} -{{ $ports = mustAppend $ports (dict "name" "logsearchapi-tcp" "port" 8080 "targetPort" 8080) }} -{{ $values := (. | mustDeepCopy) }} -{{ $_ := set $values "common" (dict "nameSuffix" (printf "%s-log" (include "logsearchapi.nameSuffix" .))) }} -{{ $_1 := set $values "commonService" (dict "type" "ClusterIP" "ports" $ports ) }} -{{ include "common.classes.service" $values }} -{{ end }} diff --git a/library/ix-dev/charts/minio/templates/postgres-deployment.yaml b/library/ix-dev/charts/minio/templates/postgres-deployment.yaml deleted file mode 100644 index 204ff44fdb..0000000000 --- a/library/ix-dev/charts/minio/templates/postgres-deployment.yaml +++ /dev/null @@ -1,58 +0,0 @@ -{{ if .Values.logsearchapi.enabled }} -{{ $values := (. | mustDeepCopy) }} -{{ $_ := set $values "common" (dict "nameSuffix" (printf "%s-pg" (include "postgres.nameSuffix" .))) }} -{{ include "common.deployment.common_config" $values | nindent 0 }} -spec: - replicas: {{ (default 1 .Values.replicas) }} - strategy: - type: Recreate - selector: - matchLabels: - app.kubernetes.io/name: {{ template "common.names.name" $values }} - app.kubernetes.io/instance: {{ .Release.Name }}-postgres-pg - app: {{ template "common.names.name" . }} - release: {{ .Release.Name }} - template: {{ include "common.deployment.pod.metadata" $values | nindent 4 }} - spec: - containers: - - name: {{ .Chart.Name }}-{{ include "postgres.nameSuffix" .}} - image: {{ template "postgres.imageName" . }} - imagePullPolicy: {{ .Values.image.pullPolicy }} - env: {{ include "postgres.envVariableConfiguration" $values | nindent 10 }} - volumeMounts: {{ include "postgres.volumeMountsConfiguration" $values | nindent 10 }} - ports: - - name: postgres-tcp - containerPort: 5432 - protocol: TCP - readinessProbe: - exec: - command: - - sh - - -c - - "until pg_isready -U${POSTGRES_USER} -h localhost; do sleep 2; done" - initialDelaySeconds: 15 - failureThreshold: 5 - periodSeconds: 15 - timeoutSeconds: 2 - livenessProbe: - exec: - command: - - sh - - -c - - "until pg_isready -U${POSTGRES_USER} -h localhost; do sleep 2; done" - initialDelaySeconds: 15 - failureThreshold: 5 - periodSeconds: 15 - timeoutSeconds: 2 - startupProbe: - exec: - command: - - sh - - -c - - "until pg_isready -U${POSTGRES_USER} -h localhost; do sleep 2; done" - initialDelaySeconds: 15 - failureThreshold: 20 - periodSeconds: 15 - timeoutSeconds: 2 - volumes: {{ include "postgres.volumeConfiguration" $values | nindent 8 }} -{{ end }} diff --git a/library/ix-dev/charts/minio/templates/postgres-secret.yaml b/library/ix-dev/charts/minio/templates/postgres-secret.yaml deleted file mode 100644 index 2d7a4fac37..0000000000 --- a/library/ix-dev/charts/minio/templates/postgres-secret.yaml +++ /dev/null @@ -1,20 +0,0 @@ -{{ $pgValues := (. | mustDeepCopy) }} -{{ $_ := set $pgValues "common" (dict "nameSuffix" (include "postgres.nameSuffix" .)) }} - -{{ $dbPass := randAlphaNum 32 | b64enc }} - -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "postgres.secretName" . }} -data: - {{ with (lookup "v1" "Secret" .Release.Namespace (include "postgres.secretName" .)) }} - {{ $dbPass = (index .data "db_password") }} - {{ end }} - db_password: {{ $dbPass }} - - db_user: {{ include "postgres.dbUser" . | b64enc }} - db_name: {{ include "postgres.dbName" . | b64enc }} - - postgresURL: {{ printf "postgres://%v:%v@%v-pg:5432/%v?sslmode=disable" (include "postgres.dbUser" .) ($dbPass | b64dec) (include "common.names.fullname" $pgValues) (include "postgres.dbName" .) | b64enc }} - postgresHost: {{ printf "%v-pg" (include "common.names.fullname" $pgValues) | b64enc }} diff --git a/library/ix-dev/charts/minio/templates/postgres-service.yaml b/library/ix-dev/charts/minio/templates/postgres-service.yaml deleted file mode 100644 index d5de40df64..0000000000 --- a/library/ix-dev/charts/minio/templates/postgres-service.yaml +++ /dev/null @@ -1,8 +0,0 @@ -{{ if .Values.logsearchapi.enabled }} -{{ $ports := list }} -{{ $ports = mustAppend $ports (dict "name" "postgres-tcp" "port" 5432 "targetPort" 5432) }} -{{ $values := (. | mustDeepCopy) }} -{{ $_ := set $values "common" (dict "nameSuffix" (printf "%s-pg" (include "postgres.nameSuffix" .))) }} -{{ $_1 := set $values "commonService" (dict "type" "ClusterIP" "ports" $ports ) }} -{{ include "common.classes.service" $values }} -{{ end }} diff --git a/library/ix-dev/charts/minio/templates/pre-install-job.yaml b/library/ix-dev/charts/minio/templates/pre-install-job.yaml deleted file mode 100644 index e6b94e35db..0000000000 --- a/library/ix-dev/charts/minio/templates/pre-install-job.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{- if .Values.appVolumeMounts -}} -{{- if hasKey .Values.appVolumeMounts "export" }} -apiVersion: batch/v1 -kind: Job -metadata: - name: "{{ template "common.names.fullname" . }}-preinstall-job" - labels: - app.kubernetes.io/managed-by: {{ .Release.Service | quote }} - app.kubernetes.io/instance: {{ .Release.Name | quote }} - app.kubernetes.io/version: {{ .Chart.AppVersion }} - helm.sh/chart: {{ template "common.names.chart" . }} - annotations: - "helm.sh/hook": pre-install - "helm.sh/hook-delete-policy": hook-succeeded -spec: - template: - metadata: - name: "{{ template "common.names.fullname" . }}-preinstall-hook" - labels: - app.kubernetes.io/managed-by: {{ .Release.Service | quote }} - app.kubernetes.io/instance: {{ .Release.Name | quote }} - helm.sh/chart: {{ template "common.names.chart" . }} - spec: - restartPolicy: Never - containers: - - name: pre-install-job - image: "alpine:latest" - command: ["chown", "-R", "{{ .Values.runAsUser }}:{{ .Values.runAsGroup }}", "{{ .Values.appVolumeMounts.export.mountPath }}"] - volumeMounts: {{ include "common.storage.configureAppVolumeMountsInContainer" .Values | nindent 12 }} - volumes: {{ include "common.storage.configureAppVolumes" .Values | nindent 8 }} -{{- end -}} -{{- end -}} diff --git a/library/ix-dev/charts/minio/templates/secrets.yaml b/library/ix-dev/charts/minio/templates/secrets.yaml deleted file mode 100644 index 4085fd585b..0000000000 --- a/library/ix-dev/charts/minio/templates/secrets.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: {{ template "minio.secretName" . }} - labels: {{ include "common.labels" . | nindent 4 }} -type: Opaque -data: - accesskey: {{ if .Values.accessKey }}{{ .Values.accessKey | toString | b64enc | quote }}{{ else }}{{ randAlphaNum 20 | b64enc | quote }}{{ end }} - secretkey: {{ if .Values.secretKey }}{{ .Values.secretKey | toString | b64enc | quote }}{{ else }}{{ randAlphaNum 40 | b64enc | quote }}{{ end }} - {{ if eq (include "minio.certAvailable" .) "true" }} - certPublicKey: {{ (include "minio.cert.publicKey" .) | toString | b64enc | quote }} - certPrivateKey: {{ (include "minio.cert.privateKey" .) | toString | b64enc | quote }} - {{ end }} diff --git a/library/ix-dev/charts/minio/templates/service.yaml b/library/ix-dev/charts/minio/templates/service.yaml deleted file mode 100644 index 8bb8fdb9d3..0000000000 --- a/library/ix-dev/charts/minio/templates/service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -{{ $selectors := list }} -{{ $selectors = mustAppend $selectors (dict "key" "app" "value" (include "common.names.name" .) ) }} -{{ $selectors = mustAppend $selectors (dict "key" "release" "value" .Release.Name ) }} -{{ $_1 := set .Values "extraSelectorLabels" $selectors }} - -{{ if eq (include "minio.hostNetworking" .) "false" }} -{{ $svc := .Values.service }} -{{ $ports := list }} -{{ $ports = mustAppend $ports (dict "name" "api" "port" $svc.nodePort "nodePort" $svc.nodePort "targetPort" (.Values.service.nodePort | int)) }} -{{ $ports = mustAppend $ports (dict "name" "console" "port" $svc.consolePort "nodePort" $svc.consolePort "targetPort" (.Values.service.consolePort | int)) }} -{{ $params := . }} -{{ $_ := set $params "commonService" (dict "type" "NodePort" "ports" $ports ) }} -{{ include "common.classes.service" $params }} -{{ end }} diff --git a/library/ix-dev/charts/minio/templates/serviceaccount.yaml b/library/ix-dev/charts/minio/templates/serviceaccount.yaml deleted file mode 100644 index 12bd3f4a39..0000000000 --- a/library/ix-dev/charts/minio/templates/serviceaccount.yaml +++ /dev/null @@ -1 +0,0 @@ -{{ include "common.serviceaccount" . }} diff --git a/library/ix-dev/charts/minio/to_keep_versions.md b/library/ix-dev/charts/minio/to_keep_versions.md new file mode 100644 index 0000000000..dcb388200a --- /dev/null +++ b/library/ix-dev/charts/minio/to_keep_versions.md @@ -0,0 +1,4 @@ +# 1.7.24 + +This version is kept because it contains a fix that is needed for migration to v2.x.x +It should be safe to remove few months after v2.x.x is released. diff --git a/library/ix-dev/charts/minio/to_keep_versions.yaml b/library/ix-dev/charts/minio/to_keep_versions.yaml new file mode 100644 index 0000000000..fac9431849 --- /dev/null +++ b/library/ix-dev/charts/minio/to_keep_versions.yaml @@ -0,0 +1 @@ +- 1.7.24 diff --git a/library/ix-dev/charts/minio/values.yaml b/library/ix-dev/charts/minio/values.yaml index b0729d9939..8b5d55eb22 100644 --- a/library/ix-dev/charts/minio/values.yaml +++ b/library/ix-dev/charts/minio/values.yaml @@ -6,8 +6,68 @@ logSearchImage: pullPolicy: IfNotPresent repository: minio/operator tag: v4.5.4 -logsearchapi: - diskCapacityGB: 5 - enabled: false -runAsGroup: 473 -runAsUser: 473 +logPostgresImage: + pullPolicy: IfNotPresent + repository: postgres + tag: "14.5" + +resources: + limits: + cpu: 4000m + memory: 8Gi + +podOptions: + dnsConfig: + options: [] + +minioConfig: + rootUser: "" + rootPassword: "" + domain: "" + extraArgs: [] + additionalEnvs: [] + +minioNetwork: + apiPort: 9000 + consolePort: 9002 + certificateID: + +minioStorage: + distributedMode: false + distributedIps: [] + export: + type: ixVolume + mountPath: /export + ixVolumeConfig: + datasetName: export + logSearchApi: false + logSearchDiskCapacityGB: 5 + pgData: + type: ixVolume + ixVolumeConfig: + datasetName: pgData + pgBackup: + type: ixVolume + ixVolumeConfig: + datasetName: pgBackup + additionalStorages: [] + +notes: + custom: | + {{ if .Values.minioStorage.logSearchApi }} + ## Database + You can connect to the database using the pgAdmin App from the catalog + +
+ Database Details + + - Database: `logsearchapi` + - Username: `logsearchapi` + - Password: `{{ .Values.minioDbPass }}` + - Host: `{{ .Values.minioDbHost }}.{{ .Release.Namespace }}.svc.cluster.local` + - Port: `5432` + +
+ {{ end }} + {{- $_ := unset .Values "haDbPass" }} + {{- $_ := unset .Values "haDbHost" }}