From 97b2955e38be295e780e67d38ab9b7ccca51c1af Mon Sep 17 00:00:00 2001 From: Anton Popovichenko Date: Fri, 16 Jun 2023 10:48:11 +0200 Subject: [PATCH 01/11] Add warning message to README about not reusing Step 1 S3 bucket in Configure Terraform. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index aa3b939..e89715c 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,8 @@ Before you can provision your Mendix environments on Amazon EKS, you must instal cluster_secret = "" environments_internal_names = ["app1", "app2", "app3"] ``` + +**Important: Do not reuse the same S3 bucket created in Step 1 for the `s3_bucket_name` field. Terraform will create a new bucket with given name.** The number of applications deployed is handled by the `environments_internal_names` variable. Internal names are used during the environment creation, as shown here: From 237006b68f98444643cc49858cd3935ad5a2b0e5 Mon Sep 17 00:00:00 2001 From: Anton Popovichenko Date: Thu, 27 Jul 2023 11:16:57 +0200 Subject: [PATCH 02/11] Replace Secret Store with IRSA. (#2) * Replace Secret Store with IRSA. --- README.md | 6 +- .../templates/apps-secretproviderclass.yaml | 35 ------ .../templates/apps-serviceaccount.yaml | 12 -- .../templates/mendix-installer-configmap.yaml | 20 +++- .../templates/mendix-installer-job.yaml | 18 ++- .../templates/mendix-installer-secret.yaml | 65 ++++++++++- charts/mendix-installer/values.yaml | 15 +++ doc/deployment_guide/images/secrets-store.png | Bin 71818 -> 0 bytes .../csi-secrets-store-provider-aws.yaml | 2 - helm-values/mendix-installer-values.yaml.tpl | 17 +++ main.tf | 100 +++++++++++----- modules/databases/main.tf | 110 +++--------------- modules/databases/outputs.tf | 5 + modules/databases/variables.tf | 37 +----- modules/vpc/main.tf | 2 +- templates/iam_environment_policy.tftpl | 51 ++++++++ templates/iam_provisioner_policy.tftpl | 64 ++++++++++ variables.tf | 2 +- 18 files changed, 346 insertions(+), 215 deletions(-) delete mode 100644 charts/mendix-installer/templates/apps-secretproviderclass.yaml delete mode 100644 charts/mendix-installer/templates/apps-serviceaccount.yaml delete mode 100644 doc/deployment_guide/images/secrets-store.png delete mode 100644 helm-values/csi-secrets-store-provider-aws.yaml create mode 100644 templates/iam_environment_policy.tftpl create mode 100644 templates/iam_provisioner_policy.tftpl diff --git a/README.md b/README.md index e89715c..ec38ddf 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,6 @@ Before you can provision your Mendix environments on Amazon EKS, you must instal cluster_secret = "" environments_internal_names = ["app1", "app2", "app3"] ``` - **Important: Do not reuse the same S3 bucket created in Step 1 for the `s3_bucket_name` field. Terraform will create a new bucket with given name.** The number of applications deployed is handled by the `environments_internal_names` variable. Internal names are used during the environment creation, as shown here: @@ -265,6 +264,9 @@ After you deploy this Partner Solution, confirm that your resources and services | Name | Type | |------|------| | [aws_ebs_encryption_by_default.ebs_encryption](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ebs_encryption_by_default) | resource | +| [aws_iam_policy.environment-policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.provisioner-policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_role.storage-provisioner-role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_route53_zone.cluster_dns](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_zone) | resource | | [helm_release.mendix_installer](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | | [kubernetes_namespace.mendix](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource | @@ -284,7 +286,7 @@ After you deploy this Partner Solution, confirm that your resources and services | [allowed\_ips](#input\_allowed\_ips) | List of IP adresses allowed to access EKS cluster endpoint | `list(string)` |
[
"0.0.0.0/0"
]
| no | | [eks\_node\_instance\_type](#input\_eks\_node\_instance\_type) | EKS instance type | `string` | `"t3.medium"` | no | | [environments\_internal\_names](#input\_environments\_internal\_names) | List of internal environments names | `list(string)` |
[
"app1"
]
| no | -| [mendix\_operator\_version](#input\_mendix\_operator\_version) | Mendix Private Cloud Operator version | `string` | `"2.10.0"` | no | +| [mendix\_operator\_version](#input\_mendix\_operator\_version) | Mendix Private Cloud Operator version | `string` | `"2.12.0"` | no | ## Outputs diff --git a/charts/mendix-installer/templates/apps-secretproviderclass.yaml b/charts/mendix-installer/templates/apps-secretproviderclass.yaml deleted file mode 100644 index 06181c2..0000000 --- a/charts/mendix-installer/templates/apps-secretproviderclass.yaml +++ /dev/null @@ -1,35 +0,0 @@ -{{- range $.Values.environmentsInternalNames }} ---- -apiVersion: secrets-store.csi.x-k8s.io/v1 -kind: SecretProviderClass -metadata: - name: {{ . }} - namespace: mendix - annotations: - privatecloud.mendix.com/environment-class: "true" -spec: - provider: aws - parameters: - objects: | - - objectName: "{{ $.Values.clusterName }}-{{ . }}-secrets" - objectType: secretsmanager - jmesPath: - - path: '"database-type"' - objectAlias: "database-type" - - path: '"database-jdbc-url"' - objectAlias: "database-jdbc-url" - - path: '"database-username"' - objectAlias: "database-username" - - path: '"database-password"' - objectAlias: "database-password" - - path: '"database-host"' - objectAlias: "database-host" - - path: '"database-name"' - objectAlias: "database-name" - - path: '"storage-service-name"' - objectAlias: "storage-service-name" - - path: '"storage-endpoint"' - objectAlias: "storage-endpoint" - - path: '"storage-bucket-name"' - objectAlias: "storage-bucket-name" -{{- end }} \ No newline at end of file diff --git a/charts/mendix-installer/templates/apps-serviceaccount.yaml b/charts/mendix-installer/templates/apps-serviceaccount.yaml deleted file mode 100644 index 660d0f4..0000000 --- a/charts/mendix-installer/templates/apps-serviceaccount.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- range $.Values.environmentsInternalNames }} ---- -apiVersion: v1 -automountServiceAccountToken: true -kind: ServiceAccount -metadata: - annotations: - eks.amazonaws.com/role-arn: arn:aws:iam::{{ $.Values.accountID }}:role/{{ $.Values.clusterName }}-app-role-{{ . }} - privatecloud.mendix.com/environment-account: "true" - name: {{ . }} - namespace: mendix -{{- end }} \ No newline at end of file diff --git a/charts/mendix-installer/templates/mendix-installer-configmap.yaml b/charts/mendix-installer/templates/mendix-installer-configmap.yaml index 813a7d9..6d4ec74 100644 --- a/charts/mendix-installer/templates/mendix-installer-configmap.yaml +++ b/charts/mendix-installer/templates/mendix-installer-configmap.yaml @@ -6,10 +6,28 @@ metadata: data: mxpc-cli-installer-script: | #/bin/sh + wget https://cdn.mendix.com/mendix-for-private-cloud/mxpc-cli/mxpc-cli-{{ .Values.mendixOperatorVersion }}-linux-amd64.tar.gz tar xvf mxpc-cli-{{ .Values.mendixOperatorVersion }}-linux-amd64.tar.gz - ./mxpc-cli base-install --namespace mendix -i {{ .Values.clusterID }} -s {{ .Values.clusterSecret }} --clusterMode connected --clusterType generic + ./mxpc-cli base-install --namespace mendix -i {{ .Values.clusterID }} -s {{ .Values.clusterSecret }} --clusterMode connected --clusterType generic --clusterTag="aws-reference-deployment" + + wget --output-document=custom.crt https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem + kubectl -n mendix create secret generic mendix-custom-tls --from-file=custom.crt=custom.crt + ./mxpc-cli apply-config -i {{ .Values.clusterID }} -s {{ .Values.clusterSecret }} --file mendix-installer-config-file/mendix-installer-config-file + +{{- range $.Values.database_plans }} + ./mxpc-cli apply-config -i {{ $.Values.clusterID }} -s {{ $.Values.clusterSecret }} --file mendix-installer-config-db-{{ .name }}/mendix-installer-config-file + + export PGUSER={{ .user }} + export PGHOST={{ .host }} + export PGPASSWORD=$(cat mendix-rds-master-pass-{{ .name }}/rds-password) + + psql -c 'GRANT rds_iam TO {{ .user }};' + + kubectl -n mendix delete secret mendix-rds-master-pass-{{ .name }} +{{- end }} + kubectl -n mendix patch OperatorConfiguration mendix-operator-configuration --type merge --patch '{"spec":{"endpoint":{"ingress":{"annotations":{"cert-manager.io/cluster-issuer":"letsencrypt-prod"}}}}}' kubectl -n mendix patch OperatorConfiguration mendix-operator-configuration --type merge --patch '{"spec":{"endpoint":{"ingress":{"tlsSecretName":"tls-{{ .Values.appName }}"}}}}' kubectl -n mendix patch OperatorConfiguration mendix-operator-configuration --type merge --patch '{"spec":{"runtimeAutomountServiceAccountToken":true,"runtimeDeploymentPodAnnotations":{"linkerd.io/inject":"enabled","prometheus.io/path":"/metrics","prometheus.io/port":"8900","prometheus.io/scrape":"true"}}}' \ No newline at end of file diff --git a/charts/mendix-installer/templates/mendix-installer-job.yaml b/charts/mendix-installer/templates/mendix-installer-job.yaml index 665564e..d90feff 100644 --- a/charts/mendix-installer/templates/mendix-installer-job.yaml +++ b/charts/mendix-installer/templates/mendix-installer-job.yaml @@ -10,7 +10,7 @@ spec: containers: - name: mxpc-cli-installer image: alpine - command: ["/bin/sh", "-c", "wget https://dl.k8s.io/release/v1.25.0/bin/linux/amd64/kubectl; mv kubectl /usr/bin/kubectl; chmod +x /usr/bin/kubectl; /mxpc-cli-installer-script;"] + command: ["/bin/sh", "-c", "apk --update add postgresql-client; wget https://dl.k8s.io/release/v1.25.0/bin/linux/amd64/kubectl; mv kubectl /usr/bin/kubectl; chmod +x /usr/bin/kubectl; /mxpc-cli-installer-script;"] volumeMounts: - name: mxpc-cli-installer-script mountPath: /mxpc-cli-installer-script @@ -18,6 +18,14 @@ spec: - name: mendix-installer-config-file mountPath: mendix-installer-config-file readOnly: true +{{- range $.Values.database_plans }} + - name: "mendix-installer-config-db-{{ .name }}" + mountPath: "mendix-installer-config-db-{{ .name }}" + readOnly: true + - name: "mendix-rds-master-pass-{{ .name }}" + mountPath: "mendix-rds-master-pass-{{ .name }}" + readOnly: true +{{- end }} volumes: - name: mxpc-cli-installer-script configMap: @@ -26,4 +34,12 @@ spec: - name: mendix-installer-config-file secret: secretName: mendix-installer-config-file +{{- range $.Values.database_plans }} + - name: "mendix-installer-config-db-{{ .name }}" + secret: + secretName: "mendix-installer-config-db-{{ .name }}" + - name: "mendix-rds-master-pass-{{ .name }}" + secret: + secretName: "mendix-rds-master-pass-{{ .name }}" +{{- end }} restartPolicy: Never diff --git a/charts/mendix-installer/templates/mendix-installer-secret.yaml b/charts/mendix-installer/templates/mendix-installer-secret.yaml index 16adb02..77b8973 100644 --- a/charts/mendix-installer/templates/mendix-installer-secret.yaml +++ b/charts/mendix-installer/templates/mendix-installer-secret.yaml @@ -10,11 +10,11 @@ stringData: cluster_mode: connected mask: database_plan: false - storage_plan: false + storage_plan: true ingress: true registry: true proxy: false - custom_tls: false + custom_tls: true ingress: type: kubernetes-ingress enable_tls: true @@ -34,3 +34,64 @@ stringData: is_static_credential: false aws_iam_role: "{{ .Values.registry.iamRole }}" kubernetes_service_account: "mendix-builder" + storage_plan: + name: s3 + type: amazon-s3 + s3: + irsa_authentication: true + create_bucket: false + create_user: false + create_inline_policy: false + existing_bucket: "{{ .Values.storage_plan.existing_bucket }}" + existing_policy: "{{ .Values.storage_plan.existing_policy }}" + bucket_autogen_prefix: true + region: "{{ .Values.awsRegion }}" + admin_iam_role: "{{ .Values.storage_plan.admin_iam_role }}" + kubernetes_service_account: "{{ .Values.storage_plan.kubernetes_service_account }}" + oidc_url: "{{ .Values.storage_plan.oidc_url }}" + custom_tls: + ca_certificates_secret_name: mendix-custom-tls + +{{- range $.Values.database_plans }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: "mendix-installer-config-db-{{ .name }}" + namespace: mendix +type: Opaque +stringData: + mendix-installer-config-file: | + namespace: mendix + cluster_mode: connected + mask: + database_plan: true + storage_plan: false + ingress: false + registry: false + proxy: false + custom_tls: false + database_plan: + name: "{{ .name }}" + type: postgres + postgres: + databaseprops: + host: "{{ .host }}" + port: {{ .port }} + user: "{{ .user }}" + password: "" + strict_tls: true + db_name: "{{ .db_name }}" + authentication_mode: aws-iam + aws_iam_role: "{{ .aws_iam_role }}" + kubernetes_service_account: "{{ .kubernetes_service_account }}" +--- +apiVersion: v1 +kind: Secret +metadata: + name: "mendix-rds-master-pass-{{ .name }}" + namespace: mendix +type: Opaque +stringData: + rds-password: "{{ .master_password }}" +{{- end }} \ No newline at end of file diff --git a/charts/mendix-installer/values.yaml b/charts/mendix-installer/values.yaml index 38ffc5b..cffcb9b 100644 --- a/charts/mendix-installer/values.yaml +++ b/charts/mendix-installer/values.yaml @@ -11,6 +11,21 @@ registry: ingress: className: "" domainName: "" +database_plans: + - name: "" + host: "" + aws_iam_role: "" + kubernetes_service_account: "" + port: "" + user: "" + db_name: "" + master_password: "" +storage_plan: + existing_bucket: "" + existing_policy: "" + admin_iam_role: "" + oidc_url: "" + kubernetes_service_account: "" environmentsInternalNames: [] clusterName: "" accountID: "" \ No newline at end of file diff --git a/doc/deployment_guide/images/secrets-store.png b/doc/deployment_guide/images/secrets-store.png deleted file mode 100644 index a86eeb6aed62e83fc703143c26832ada4b99619e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71818 zcmeFYcT`hd(>Dw#7ErJO0@6f!l`bVg0g>K&2kC@RLWdwAAR?et3BC8;dl5yt)Bph@ zy#}O&k`Q>~b>GkPT<_)m_qX2lttV@pI=nli?e0mk9_+YVBoY)D>i87}edtHug@|1O%@l5|XZK-#4IogH-l? zb>rg?qYaghsstQNwLkJg3g14FW@ow@Ofqd?+(jWL3#)!p@|dKY_+y=A*L%w=6eb_# zWKF0@MYJyn$-3q*&o2WnB-YbThSIRRZQ$V+_gw<%d{^0QA$_tp5Q}=TiQW);y8BAK zQ3N;432tu?36hB__1wC7li=OpaA4BO$sI>o=M=Rw%*pzt&Wg`DH!p$ujqaPR+|J_N z@}Hi5qll;>lt#Tg@*Sv_)AGM*0eh%$XYqnV6}DK#q59cI$aj`iGCs7Dguwe=II}9z zo7|X<&1Z8@ddU0kTPQK9G0Hw{x?aAyNiF&IQ)B1Ds=G{*s~MkurDf!HoGE|AthmJH zO4cOVclnW2%i5<>T&{1QB4g88lcOx&-O{X{7JZQXsWr2G;#MFB>HXkfTZ7J&`i!;L z5#Szf_Zt1Gn!#mnj1oMbn0U}FyEBCc9XCXlVGT{xo92!be34gm?<@Bjw|kGfD@)N` z%>aQ69&|>^BYNS1XTjey4TcqOA7<28D4;DB3WWmOfAm`MmN!85HVu#{z0Sn)Ayu-I zgxxg3B%s;%)Wc*7o}sATlOtG7#K+mlYN^~RS$if;KPW6lJ0syft4T`Kqwh_1Ok-Z3 zyZ1?xt$*HZl_qc-eSWp_8d)ca*kf^Bk-)PFYU0vcqa;;~9M4jQWs5(k*^)L<9&St} zPKgjGPwotU@}?CxiTpTL^vvX%rp$+vS7}aZ<1F!nKXl){h4L4SBZ&#}2;NMomdmCJ z=A>}4ttd%feX!z~NmBcUp8wj~E9h}2bt5x1Hpu)AnPum_PU1dBx_4ayAIYbJU#Q=z ze}l>-nFzjCN&e_+_;Xq@!r|b^pPY?1cZ0*t32uc@ncr%?e*ezZMMeSHP;DmAcLITs zQl@JwBtFjx)!83h`6{FE@lLGt*$>~shn%6snc{_aF%;rtX`#F_Qa=Lh?$CrTNM~3) zP!6`QWOceR5>Cy3|2X{1;#Ze@sW;cViGSHN5|xLOcb5G!IOX)GqJLx7xy=41_Blru zM176@+WSzFmtV8*X;@BhYTqq>q!Z)t(j&83y+PwjVN#)*9XITKe$LS7u$>v?DlBqX zw&Df&gTj*R zmQ{-S%%xYRsAxk}y4Ea2Exas^Ds3yJrkQrc$ilV0CNCPhbcvDi((1h{>7naP`!?Tw zdl|4~{cG0Su~ig6$=6fyC29F&S#1%#DF5sJ)n~zkT@iPbf8N!-qj;m`Cf!@ww-()3 zHPY>5AxvTSwca^KQ1sX=5nBTH%RYSgQ2rrj@C9|yAWbq!vW!5|>uc74PY+(@KcVD^ ze!>J|MX{tY&9k+!#Px-}_HyHXmeQI$_X;2nRlZ?@-81=2RCNZ~1OHZxL_t-&PXLuCnK-wVZu!C<;>6cs{E8RMWM| zvTjM?DB)OPJ+bF+Y2^Bo6|0}g zVt!2is~XM2)HNj@79Ov%2W0|fT825Z+8{kpkZ1C-J!%~yCmxsnvLZ91AZF8U<8MrCDNzA`?y@8!rB`6;)Rx3~!#rMBkqIhOntqX&G`f5;ST@@ge{c#U`2a*IHCtDvrsH zEwMIOjq3s7-r+Rirq`nGc2D;-uDo+Saxq4Eckjo=wQ1FlTNHGp4y9?Ook#$U%xm9t zn4bhQQJGLhE2Ry*;hGm-K-LsN>F?80Rm+jBlpr&qN48XY552%uqf4uie0&;4vGpq}n*Ex?W6b-XPYX|R z`(|QYslLPBL=su779R$dc7L}2Y&z`s&he*$as)mZWvLR{H;7dltIr*M-LP`7l0=l4 zsrXC$t7x9cs*Hon*1|+zZDDO9#NXE+#~$?8J9IQo1=fxWC&xY?!oiR+uDcSOg5XnwsWSu9@tTqay-Oz zt%v8on0eu9v3G6#b{#M~@WJ_X+o+Az>Nl`lYc|){#ILJg%|u*9P0sqZ3f^b1in2NH z@>cQ9)DgGHHLfn`Hk4r%SC!nA!t05h9eHw+C=%Kb?GWs$8{%M=u7@s`?g|AV1u6lP zV8q#>&7wD7c3kLOG+H>Le`vu5UN1A*ZGkxoJ4QMJFS$>fDuxTn>lP~8TL}>#$A3Y* zR(8wH9(D-rY9O>)*SAd<7lHz^u*0I_LL$5HX|u7bq6)B=xow

~}0k>;yI*-dKKhs1cGQ+*{cD-Y{#5qRa}^2fBiKijwNZMSFRQc|F1o zEj6^UK~%Lfv?UGP-g_7SoLJeM8(+4SwKYvw5to=~sy$q6+Hm(8=95GQbX|7mMJ`Z{ zcsy-UHFIl%ELD%MF6%win=PL;1GU+Bp{6}rwtJgVEk3-vdR~*vl z+Rk-VGG8)NzkA0ki+8*>zA_jD`cw0ID?$wc*-~StgP55JjlI#75h^JLD3kBg{pw$8 zXFx|&>JD*C64ngSZG{Jja2B6 zfnVh(a9Z-Y0|2%W5$>1uF$kO}~c+x3sY zSQ^?e9pwzSvK!|zHki}BgNyZB`K`0Tfy0+XT|qZmwPCvacr#YlT3^9NMTLM9e}993 zFx;NtD*lcTf6?GC0)i{CVFcIlzxVK$Y$nlvm0nHEyz*c7gcrXnKG%{_P{99cS-DwT zJGvVDtt#IlGH{ zOFjOphB*HI_hY`tjDJ;uI7&U%S5aq_0lQfJKMpO=>xua_V%*v*#j>9c3g`1l3*1O#~SHF(^8oFNw8JkIXS|7zsF+L5(( zw{o+0f!Kqc8GpBHVF~ttNIic1yQBa9{A--n-uC~~le7E3r-h#&-|rH>r@Z`p|J^p8 zRPy&zadmrdYbOI)dk~&I_&xx_Px&SPs{cpH|Md7bO8x(#eEL*W=bv(69V`j(fphE?}h&+l;rz8^}n&=Uwr=SDW1^)5=p-Q78-ygj&wYkfIyl+LH4<} zH{s6w_0$Pj+TQ)}g_1Xn@7@a$R+)E&y`!Ko^P@VdI|-w^D`)1ncl#>|rM8pMU5z`k z#KgpegcR{)V-kDkw&29MYOjVlx}EubTELu5P2ZC<)mWAEwB!dyd$FJHND~lV{pZ)T zY|v7Qm{c6|8v>#mjQ{xhNqmF5ius>Ue^**jeAB5}KK=RTpDjwi>AZ*i4~@N%F28z% zd-Z)(@;}G$dtCUA$p5#a|7G1@y7B*+GAKgai!%8K(*@zIIKa>a&g;|UbiVI%gEF3K z`fYfH7XmQ3He_aAqE}Y`o`UPO;qI2OVPdq5{UFa>Lc*0>P@M) z8?|(7S6V(FY*t^%tJbe~YQp_m9;x>~BPlU$E2iMmEmbe|dv4m-bhw5%>bTs;{yHZn z#T6%V84b^To0_dcsF>_l5t{j1%RlmUdA<+vp$Wy96X>G-%a8*an>o;?oVoU zkL!zSn76`Re}?^Hc^t9l9#^pDgE>n-#*qVO7W`1@2yT)c|5;mjg_-SrHkGQrxPs)S zfF{kn_n`;=`y2Q9X5a0-L_o2-O$M!(9!NH?g~P%!HBNtvR-JvMJh(pim&A6RO zII`*lP5|&UvD|?Clw4x&j7Erq|7C7>CFTaU#{8Khd!<_o0oGU_u6mioj{?-k$Z) zGl^dwdhyxTy#ua5`59se-j!Q5x&WgwKOl#9RTAb^yu+=?yhLlt<~Gp09~Y4iW=8v4R4QrGe8~FVSG+Eknm&hbAy$mv&sgh@~(cvthFN|#?Vqs!wCtt4d zL*Y!#5N+1(j$_`oz!@5Kze9FE~6~KQj`;#ojyjew7P%JUFt{Y|&H55WpDl{Rgb;oXe&h_d@(m_t#Njj(kxShMd?O zRx zYEkelIl10`O$NU%w7L*&V>tvI2qln}@>eYCZHnmu1L4Jiq)j+^iU zzP3Uu|9zjC{20J4I42PE)o`z-fWw7Kc%V<9oyg$UYtc*coZeaZm-fT;tCO!r-8=-n zt4Os=O*hjKrn6Q`|A#4F-`2$!kp)#I5GIK1-H8w0!uN z4HFdn>0blSRLB1+VHr*V{Gya%Ux0z(fk`N00y1jAWzl;KuCyxlUoG+>B);m%A zVbfxqrgoZkZQRQe+(gsM=0ewIY*Rnm&un_b9!KIdeA;#$2sgr*C34({CHrd4uI1D@w=e7+qpgc2Id$2=WhPPdGsCBT z`BG=fYj^FnC@}fB=9&B2jD~!z zuu6&HlgSdD!=Wa!X)qr!YK=ki^=D*;$DwAulL0unwCN>eCdJR27H*s$B*Di~nY)NV zz=vv8P%)A{0Mv=x7zneqeK+6GQT$~NB9~y}bB2{@qgo?Qb~FBdjH_ricKVR7&7wmE zGrz7^s_%+uH>LB6mU_Bs!!nZ)>Y#b#hAkbd1k0bji6mO4!kuty4RI%U6oxkSq>-k( zV>ivlFI|`6&6$RB66Zfe_7AZ9F-XRi4_ognr~YRc61aje6Zdv5j7oePZNY&S%i zaUz_IhpriVrL7WE_u`^)NpnqSFs|W-`_U5pfu+mmq4eNnqN|)##EcN=#52n%35H^k zZ$of1=dVf+8ipI@Q0p4^>ugOru|f@~q^6%a?Je~FE6-?G`prb=hhQSrq{9--rhZi; z;TeeK@*Qx;nL{8zozW6uDD1CpEUdv0uq9{IY8OGSXa>2MnJQe2hCYMOLkh~=GRSw~ z2!N+bIlb>WF%W=R?~~s>s8dPzJ*L2();!;RRIwK`=4sb*1t((v3`%PT9Ut)=KGRG2 zu)7VdxukDCJH{H{E;TXvm|1dpKGJbfzk32$gQ-QG?43AFjyX49RG(J4_%&SLVLO?@ zZ^?EiQb)CB3xIM3>w+3J*PwB!?2^PO3t=m>D!06jbp3YA(92KC$i7jU5OLlGFY6j# zG-sf*D&?!a&33Io2%#Yzl{kE}g%MV(hFdOoh0JH;%$4Zfo3HsSB$Omp>^TRli$a33 zBS(M(Nv;s7xZB$_YS@-`HFS=JYHyQ6W7|EVgHukd;MRcVxSF~Ur2S%U$ApW5z zwtbI9(QqE+fS^c9cU+xoGT|uMCKqOzIQhC5PQT(fQf5#h?eI*Cr%lb|c8fw>0VY!; zBy9^DpggQNlO|Eu!6vc3)vScjuX*XQy%a6Sg7eOE4|d4rILkbmVe73>a~Ieb+`s;> zWs8XOV*ne0kxO16M5iSo8Wi}MJh)IdjQ5?)m`V+=&9z2=bYfGay@_(+*=G#HjUff0 zDCeKpWa*snToZUdi?gswTg}aDKA&uKKSQC1FMwE&$S&}a1-K>td{_u zcHS%VLkY3YS925)$M0G;)qfT#CcNKWD=8gHmKd4f3#r#r=&I|;zXTO~Xyq$&08Pi| z0``{kS-}_&L#m#fb_T0vgZHdM4HLpa96M&+_%F_I5gF)E{>70#>>nTiW?$o-1k z>K`g2q`NP)3GYuD7cTNvrn`1na>ewQM??qv7!C+KPGNk;&g6~V*M?6@DwW2=l6CV` zQJ??<$cl+A{ZKHX4o!^P}vRQEkC2^IUU8M!kzScTVK)TG@9CR{lW75GXP&Cgwd-Rqt;Af`C z_{B%=qG$QeVLI1lS&6wQAX+40vwcN6{ie*s#bfS(6p~8HtE+mMSg?Jtv z8Q9j0Xfl`P@QM@svJh|?H{HW=uA)oXwh)mJib=Ss5Oj^F!R95jE&)~;hFG3>X zP6$Achhfri+{b^q0f|-UuF6B{No#c3rOAYm(b_Z1N0H6sqCEyjIxwqTcVf8*c8b_gheQ|A}q3cnVQ7Zfy;T~x7J;9AU) zhcjU%A-}LlYmsk=xq~bj~^J>p)8FG2P1}g{C6Ca>2>YY!pdvXDyWRUgk6!4{) z{)di5vVe>thDT}F(H+n>)YA5&dXHcU@~!Z+oEWF=k!=!L^u`QgonoHK(^(x^(Gnak zzFRxLWu$DM%!L>qX&TI6_SofGhbcHPh#k&xftCmLkEc;>}Zon{o{anbzPe_b9fIO8H#UWeoiJu#qL-%9z8 zDuo)how~nABvHIg$SdblY;lhYb|IODc)^88%)?vbOakqa#Tz);i>;(DkLF9Z*#jDq zc#LMToSnIhrmygCd5!pb@dus6<}l4M^z0X2eOl-f?M@w}ZHyG!?fmoiz9*&R75@sz zJdh0{(y&qxrN+3yRlY?_Ow`PKf^3ktE{Ad1M|mc@(3vRKc_C!r2uOF%KNU zTYB9uB}83yGS%%3$j)x{t1vcbW=^#;$4}czOx;fSdw zTd640#b@r->e-Jrld^aO+=MX2fm_)XE7K8VHoIAH-WzTDWB9t#k)ti#sA7Nn5YfW{ z=zLg0=Td?wh{Q(AP^8lF+t~#b-lhCmt4hM}zyQA}kuE+ye7$+36$*lV{vKa6Cj>>-?6$B^6`tVV>%$a%g60nM@foY|-$W80(VyBx22{r#Em zU3+k6!);t=VZC^}#kVB2ULhcf{Y_>H>`)?YH$^?v3G50G&!=l5)#N=|AL$!@IvHQf zJ*NWee+03PoB%9Wl%P5qZ)^5BOCVh*%C_Tyuf%jf9+d?svh+ z*wT_Vds8-wxBVFXsS59Vf%fd#7^wEPH%G5GH+9BtAAUnAlTg-49cW{J5EFr2*Q>To zqVC~dWu@RGS|G>B&3+@GvuvD$E=OZ7jb26D`Df$^Uq^l<`J*BZ|K1wa_iE4|gxKk2 z^7+k}yYB36Badg4yZlKwE*lb%vn@kx)jW5W*+Dt+v?daf z@j|in;>L2q9%y&2*ia(|K)p?_0_S1NaQV=7xX=rDC*?l1!{5{r)`yuZnhoz8ZpxxG z{Vof4B=IkrIW+N_`&mJ~i$PjJ1F28H!js!`Y6K$akxXW$cmE3Ava=HrKd#K}{1^)j z(EQ0Pv<=&U3XjR9IFrbb)X5*UyMDQLjEe!D89rKcZ`+FCP;6!zH>W>MBQ_?6C49rxsC z^(Jr?G;*1hmb!`N)hOi6HXpM?E~%l3o$6@+lw#Y@sB-gs`u&QiE_8e+@Bf={S@=iW_yItobb%~0x^p==@YTAWf25L-{~*Wla-pR-Sgy9ZqMke zXVn8rK~GsG&2M5`gBM7+&qN9jgx-mP87$Fkj4=|CLnd{9m zm9LO&vkl$QJ8KI5I&8m4l(&0fwB>DL7yIw_pe{p7;fRLvnl1CnvB_^U@wtXfiX=3f z*jJnUdhSZXu}3ENZ*$u-+(ZUCSQcfrIq*}w6|!83SZh9Aj%!oNsI zQpN6RvERa@QD|tgA7}2^MVXa~w@!=ZP;I=LsV0=pokaJ<9f`2&Rr%HRv2w5UyVWzN zE!TE$g;L5SSU6YFanXS~h_lQ{s50IgclVLU`36>gohKoI*OqM1JJv)?Pf4wgIY+qY z(06yjO$M}gO#*eN!{!J2ql16w-d-g%#o^xCGR40vUIMW*9MvBJCJ>=NX)`N{{mxn}1c zcgtXO#q<^NJDX+}Ejo@byPo3UUyCo`3f_;v8#2YO`=+BD3`Eslbv=gD=GasnmEU}G+qJ97_7tX7tXeUvv?a6Jlw=w+9GkyrS>C5k+~I`YOWY={PF?nq`7jExDqq_og4kcFku@b-VcJQ zvp!p`YXa&?Yt`{Lx0rz#e11kN6aLt!MmttxmZ(p*!57yIg!>-&t0umO7QCS# zdfThnkZ;TCm1sqzG0!(W;~}!icibBsC7>~1uat}|}f#+vQfe)G;ZaFKC zMUB+(9eqd$-R^zTQvID5xzxUv40Cm6XHM&g&+d&~*!HK>yipl?vI)H{T47dD$xwE( zI6O_mCK9-{e=g%0S7K7a_{l*m)o;`TP#HUUObnc)BvGgnh`)D5!Z+6XRTtmBACrIj zj!vCExb2H@nma==IPcE+==ef;Yk5gg2Mlk=I3$^Rt5(mrKcZ?+2^bpuP()#;s|l1F zt<}o?vRBD7Ix_z3eD%j7bRT0nfsVYeJ>Rv=usxzHvawPuPNRu+;FHs`TY41WX337& zfTV~&I!SE;iXTo<#@B4WPJTtj2!-?pKT|_VU1EH0?x2l)4c1;@^sR3 zNHO7s>EdB)x`Ye>!>dUGH>V-Pw!lK=wVYM5efU58b&%DWNIC7|(VUl*TGjfa;7$8r zj0;_3SZ?u3^9{W+I;nZ~+?ks7uY9xl%DC|u)t#$a!fDZ-RVVB)gfts?4PY>`R&LMMm}C-&CEX#)z<0&;9sRv!u{ zotiBiCG$FbkyHLGB3e;nGZbYMeo+p&k{cc7;aWku$xIHMzTDbP+P-*gEMeUwR+bX{ z8dE_k0veaqyZ?Az!IZ@N19nvue%1Otx!YEfI`P=GmH_n%&Lqkq*lR-_kE_KXx2c+RyqQ#`<9;*LyzOpQs}ETzK_>m=*O=Ov4hEgnt7x=kqDVtz*4aCUx`L0)XR z+I?Xb@w2x%0f*AUZIf1A6i%GqITApc*MGzS&a(GvHjMP#UmzYF$4p-#u{1h0`KHBk zGViB`TzR3ErakmgTg!VkeMz&LuQ zr$B!9UH%>KchOwzUwpfhV}qZM8z1VYRan^qPoyDKGVB`JpTVX|f($fk?f35b>goZa_VaJ#$}l8W-O{l>P&0@|x^ zwlBv7#68(L0a?VbD94>Pv&1xQ?sB9nZj~AZ=}5IQ1IO~|*GZbc9~4w|V8Wv}!g~y; z16nub6SOrw*Qa{Uw4QmfO02W4WTA`nsFV9X1|R=uYgqS*3$AkzE#mkT3o~KgbX_X`RuNr5@pG)AwD`CppKeB~ zNg+VG=vj_<+U?1X0a@r*baKJwh|hZJ8Ya!>hp3c##%*8UbmvFf19BI>ZVAB-qqTGM zvhpYLD)8NpSI&N=_g#;+T?%<9SjV(BO`lt0kIM<@^~eQASOz<$G0NNGI9>n?HzgO<(_+V0<6KsMQi$KnoJ?IC)e}VI%dg_ zYM)N}j*Zt$oWH<+B0Anu2hLvY9f|*vp-w3df2~7VTvs?-P`qDY{@ru;A#f3h5?n3) zDQ^vbhJFmss)IRgg-J|2obT``wO7igCfT4x6MHCQJ1if;|)wYId!%U(w6t^U?LGtP7FTMh+ z0KdK6E7A-BV@To`iKnV-xbROvad~@STMm|aHzLu`u%#Z0J=A`E4=H4#2GZf*oT%YN zKYz)iwf;j;4XXwjJN=bUf4NUBI^LPtg*;^pa$pE$%MO#n{e&HE_EO=*Any>+gol9_~Zi?tE6jf3F}{|5ZKQLIyZ>KJtb#LRKF+o>A`_k*i-SOz z7*v|=C*)G{wN%)p4os=&Fb8@J(!eIOs7d({C=c9f06k#e9Cyp|(#kPg`ZJLwjo0_C z>!+V)P20%P!P=zT{R5ZVX%i!%m^}4LRw15IWhS$XpbWu7x9oA*z^~)}Jaa0Mx2%h- zOGMrVvnVE+&GlV66q#*7f{M(@Dg28y1gHGvN;Z>FYmuzUTm-`1lZijZ`-@v>)X#im z9+*t!lMSF);aN>k^n|B9t`@cBq$ON>bb8nmKY#JrE;j}9S>twwia^fTu)Oe5t-mm# zmiq%b+EKR&%x2h&W!9EipXOv8)2&XEF8+jM3~00>%h$o|D@heAG-A6w54jCTZ+Jd2 zY6p-jJXa)s3~^s&=-qW5_9%T>pkPz@s9R{O&`i{;SXf|eQd9F#X(kPY(N*%ooYn+E zFUOjFEB!O&R zzdl4e=0m4;IMhDD7EhFV+1Od6`CaP^CLP+=y9}ijP8-%MzFVT&Y$e<&6!2Nzy+>0h zhM(7@0vUxF1&=#Z3r}ZnXZ?gt=>RVZFWat|nECovI8qTqPh5iBJ9wzk{%US?^5KWg z$Dy%#il@;d!ckhk40@#mN*h+5dMRUN0;0I3m_YbL+IBvEDe4~;rr*M_sF_My*=GV% zX2i`FwaEJKegXFo3)4avLjI>}#CAu_xrt>Arc;fFEwCxGMThM0HP;ALi-^8&y$8t3 zdy4_nY5&@W!az3x#rApOX&cSD0U}!*uHv4P>lwj%OlK%$r8u;ffr|C#zioXYPW8e0 zTI+4{yL;h(BwVS#yWgt@~V6y`;G zqLiHqiMG!l7NARiI)D4})d7;GIm3`M4le%WJY2_Tt5@@qD&O~UTy%)tOyS^!kaSFn zo_l+Dy0)WJ**2K-C@3KXHM-nB`TFs`|HqV8l77hQv)m&9N{O#4hlyvZ4>WII zms+iS`2wVn#(ZQ@3ru`{1}=9cX)dX^-}oTz`s_k-g=m?=7&MhSEaNLa=dfO27%KOy zXb|GR(e==Pg*Z*O88$<5kq@h1d0Mbnt=+M$WpX*ETHwL47p!>ZGZZ)3yaL%B+)7R1 z1_pRlc&aRj=6#4;{UY`+v=~XO^lVD^DkXCjFrvr*!L3)GU$V{K9hI1CC^a{#)wlV~ zs}jF=+iGB}^3hiv(3Y;?zls*IrgNWV5S@G#l)V$ID4=^7*+XV7Y-(Nq?3j2pEjpe- z^!CjB_dKhV1FK{_lXQDQLf_+4JYMB-Ydi8LlnPI(2mu*t+&k45HSa5LNf`Px+1UN}F?_ zD=m0`I$Y!9FC+gCVCiY?px6{~8P)L$la{I92er%4vmu*d80c#x zRfBk)qrvja+dG}OZg^dlvq^cw!D_$H=wu0e8eZ;WoF-nk)Qv}9HF%WI8281plo>Zw@9)#7Lre53 zj+Z%gia&1(wiz_J<*8f*z!G@1W+xSk?Gu>COU*hK02fY~8MZ?(;d<}=dqCq>*_$Qm zfO-H__FD!q=|$aU;H4G1zQk&>SSJGdfWfrgKa`_Fz`9=_54BPr!sV-C2k^LI8;M=@ z5yi$2V{wCg3*z;ADR+3? z5PA7w)x|nBVHIh4=!kr6?&v+2+>AV@nL+D22cyj@8T$=fF~arkA#?&D$Imb62aJ6j z&ay;c4vM&a_^l4|?^)VK{xg%^kA39+xvU2fF{%#|Gfb^}NWJtw$uV(T9Rj4}tI*CO zDgdaETQjSEz6AqL-EaGJ+kACs&(9>1Sy7%N%*Pf;D0J>8bWb1cpo4Qks$J7Zj$E5Q z0iLJYW9Gdaozp7Xd-{|39KGgn@1p2L0pshwIq0p)!{pOba66r~7jAFVn_rnhXu7C9 z?KI=q^O&0LYr%M@wI0&p3m#jy?jbpJLg6uhINi}p&rQ+jyAnaQw0Z|1cA7cm zx$Kd2mTB;iYG{3&+_dI8z0bFHjIZqJbkaVLsIh%`g9JMu`VWP?!+uV5rWy76{H=m( zMC7mpS8t}Kzolqp_vEiW-lCb$u|&^JT7VBSw4bL~D5D$tn&>u^^iX%F|D}R$%Xp-s7J!$ERmI(+f%)% zXw$mP;SEUB(C2-%Q?ZNUH>0OWR>U?RaM4lWEAab6vDKYOQ2`h*Fl*jL$qV}{jlMlh zZ%MLM{trd!=BQ+{{1lF65WQ$Pof}FKjv!xO@BGR1Wof4EXeUI(|CjtRu5x7Ot1W%4 zk#l1=JoDMvTPx7?&)dRbhI=gqx3LGzmzR_44Cq6?bFWV&1`qr=Q(j8CUDAm_)EWG? zCkvG8pz-Pc`QZVVR%?bDG!@bs`1PU`?l>~tyVv2+TZ>e`uMm_LLN?v2ZMBYqr;AKx zlh~hrXXrK`)0=!XCjR#F3NQfS&=lP(BfdOw`S!WQ`iD5wd!>;YHOx`%C^H7}i;2O& zZa5!}6|piX((e&edAM=5*0P_e*;0S~6ogqiT<|<&S;ufpKEs0Mca=VK9qVpq!qlz+ zdVzM=mF%j^>rqkdWm7x3R(Fv!dZ=P5l__w5| zzJt@JE|AQc?VV=(xUhVhS5&EfFOQg8c9v8DopnlaFFi3Fw875>ZHI@2OqOWTh+K~w zmwxU0&aDxq>yEr4t5mTV$e7!96G0M2NE4{bMjr?{oxXtJXgKmL?`CjVWbPGI0g8n% zs&KtT%&XaaU*VQtt%A!zkA>xpn;dkyQ`fG59drwz8HPgOr7IQ|*{_8&yKP$^|I^l! zUcCQ3Dc@y_O`%RdUbo5S^=dz8V^F-~6&c7cQ|fYz7SKW%5(c|q@Q^i*U5yH|V^k0f5q=mlAsq0+F?@Urt>->D+tS`X8#t zb%-wPE+gqGFBd%VP+=R`>%Q2$V}r{sk>jMB`OtXEi1QQh-Smcpz=*7JV7c#n@v-mz)WWKsGWE_^4T zc=o}`M8oSMhlKw9(e`g2x3?7((n7XxdNHl8aoD-94>!<)TM)KcfZW~Ywi*h)_C*CS z9`9De94#?^anc!gTveiTG*EFr;0}8Mw76S5@1Qt8m?^`tXMNFZ6aE^E)_8FAavZN`Ow;8sIwami^M3t$ zdgDm*oWF;EwQGm-#yZCb;~iKOOTOKB=~Lik?B;S+hm+mKRApCmG5|3LUf7!N4U0Kl z;Cq>7w$}hIiJ~lGs}6Gx@I zhep%+s0>KK{-1oE7QcGHQdw&>V1wV&s@mT?_#oCcZhicFlfs|G*D{!}O=qBKo#uCa zdQANe+Zwm+U{jENy@J=#J5)QGbtV#WpF6(2FQBt_aq z`f*&uFKKqPkumh!4s*9~Hn~Iiq@@#u+)olMZ$4q(YGRHK`F7gK0lzVrsEqu4Ru3k8 z@cI{j64~48>((kWkqkT52)}1cSLob-om)d>^n1#TgFDU!hYcUn1!$@Me)wVuQVM%$%yls|bIQhkQAP=gEZLh|iuX&13W@zBv zcoCadW#Xsy)O)~@y%WA;Z?5#bdMy4hA)*8R1_Q>M9Mq2PKiiKz_sDU!RHmLX{xl#X z0YR0IX>yVwZ-cbdB&S$aG4l(TKLu%}Y*N!^HV>4w>A<}T=Yt4o`hXI3%BfMP2{;8g^TY4Sv;G^=m2zYAxqzba+io%`RU04iYuBPBNVsr4gR{l`F9dFGmp`Kd(pv_0owS|32UHlMX;YujUKh>uEY*5{pl`zx>ZA#`Nq}5hHVZ z$B@^4|183X#L86OY_S;`MbxzY2fqYx^NxN$+pFq7BujX;UIZVE_+PreFTZ~U9RDBV z%Zie@{Y7wSJw7Fkwrs3FfeW-&I#UnDVWI$5vR(I1K}&nbgQQX@7;VeU^#CkIX#!WK zV-D_ON@BMLcnQ;xhVz3<>hNiCSho!qqjrC}1p!5YleIyKzNImN;=(-!`{&kKf7cxK zpTC#%qwWE)VGP_CTrC_Zrt{KS#)bhP_-6!46;_C*)u*8 zslEXkEx@ZZQoqe;#LR44AF3ZIO^8SCg&DL-PGzs8nU(e&hEX6KnZ zY8Ol2a5y6M#S>ANtOApqT-d?|RqSgNc=Axani=@*-r|#F2S?m-LtZl+Z1j$0Co_WS zz4&d-+HYr}J6gOIFhE?@O50+Ae^*@e!I}W6HG;*-A}g1PYzFS*L^E` zsUAwQ3c~MMQ>gTCRQBOW{epALY8BR*r*ysxi=f{XHfTOfmoF{D8k1Q;X>2Epb*spF zA6fk6+4*?t!ocqwXCX(QP&+*9&lVf{Jo`fF%J$fBxby$R-dlxL*|lq+QqqDTiqr(@ z2I*E%Qo6faLb{PgX(`Dm9h2@(1?gr2la%hx$%Os-|7)$!e|_IR+9&&9UDrJDy5t@2 z7~>uBjQhTydt8d1B_y({_E5ByL;UZ7)Ya5L;`_mLyC_oL3hGBfGZzcqc=y^>Ee2i} zRB5+xZn()$zPb^EW*9oi*B-zjE@93Fy{h~Bi=essC4?1l9;mOgyQrtu_nQ-9fA`;B z0G%RjNcOJ=5F0RMKLl{3w)8$|gXr(2CsfUe^32|B#Ur^b>DON&Bqxe7H}>5{ti0>z zhVGpA;_MglZ!G-8Vn`iu-R3%fCxqO;o3N-AxxeLN9(XzFGn?nSJ3Z?S^05Ju0_w!> z((TW8>@0zU`waJ8R&QoC8=s*m5ag{^YqgjaEo`Jt>3`VvT=ZJJMO$<@8)1xt(3iDm)nB+GZ>KSTMMKmttS&Aoc9x-%_#^?k2o2!D`y9bTy0hJ z`ra&EOgfj(q_y76a5^nH^I>})Hb{to%@um{FYdb^*_l!=h@K5xee%n2c^86UV6M)W zCy~^g#Va>xom+G@=NjC%JelHjA3v6YJvukt&30CnsXu@~OOAWrrHtnxJPTTd+?WK? ztaK_(%*X9;dMi_9FT5_P{f9r1uc9}s^Tb%jEeLRm#*t!}e_aqT1#&^A;fOXr|4crI zwx!HfAu@CC{n>F#qB`3YA-47#i(oO0M?!0qLRTHr7qjj5*v^rgUCF98J$yxNU)@^}s&zTd7gPq~A{;zJ5zKJ?jQ4(PLk%hB zI{@AhlCIbbPL-=lFGb&W-nn%K^hA*~96RqNm0ixgfS&EPXDHN%+KVJ4BMVV6KB)M< zuqHLZ@+|!ZidO%HcKsg6+P+R3wJmS@8SNa9iO-;0>6Ex%(|zG~zP{P~twZK+Lw|y~ z^aBEF)!MXxsK6u9b5o|*{WZOt2?rl_R+3(;)eGFTNs(oN5gdFXPZLLXcsC(uJ@QVT6K7uf1-gtCo>#4WJ)y~ zg{oAw0O8kKZ_JHfWb3gT$lZBv+LP?SVUWG?!~)*EUuwP|>;4CLbP2g#>WLH7H~a8|MVO_md(-Y}s<|GkT9^8KD&wrUieLvtQ|N}1lz z{eFqqYr(lj@jZ;vS!X6O_3zWMGxe5{U#DuWtJm6?!`#6lKCjFjo;9c{Nx!DdOYdji zb67a^9YlXrbFX+02Q{xuABcu~*9a{NlKD2^1)n2aK8|n==BzfD^%3}a>g3-+i&{$! zmzWZn;nvkoDn>G%%#8j+%>~%wlBd&_MPzAn_aNV2Xu8|c%%$ytc5^Xp&hRu94U4<( zU@`V)N*6Gm*y*m*fk43=*nX*TV0O^8lbALm;t7sQ#o8pH&`ees+19{`@3TnRciMKQ zUlowj1lc(1SBU+E{USGA6mUGZc)psu4>PD2=Zg7fc<6bzFEQZX??sef8|9y1!15k^ z87^R*7f{{ofH-XJ1b$ja2o|@vQebU%?nP&)Lp0#lQNlY^-SdaaaM>RUd z0OkxW8lj-RqkNt1^(RP3ZmQS{bYp)3_opl0!Zy4Jv;Bbi)}n^;x|WMc zvv|uPU-1K946WXgnd$_krmD7o@vDmH{zp8xb_mJ+kK(a$$+ofp=SX^Jr? zyucc~Mx&Z#6T90fKHPQ~C04Uo7~B5R0(Rhy>p7msst=@OYL)92>hjsaczQ#edA4N@ z9m%aWYK)YePLsqSqcc#G*e6)L?DJ61oN_D*-^F`5ApqjrJ5#+|6&ru4Dvvd8uUj38 zhn&c!&$LKZdQn$fQiZ*|U2R2Jt2VIfp*eB5H=%e2;dEF;1_?KAe8yfi=h-MQd|wO^ zN&X7t=1~|f)`;c9@N)bwkeYU;OySmU3aqJo$FoJeN?Mj^%-Kcv9aMLAz>Z*}u;A29 zqFR91Mj6&ld7GSLJf$?wnd78<&9HxH!FPpU~wU%#}9 ziH$!e_pav4IbWWUf*Y)G8IYsMe(LpL+I%Bsx~8bG87arcPcK><*eck2C%TSjJLy<( zbp=~+E856KPBiqnj?yjHaa+&3KL%7=A1M5)uJ3gtj zFEu_3R&);=#3}BZNN391C|1BE`Kib{hX5;t0fIx1cAFOqm!9Y0>m54~+!bCMaqlm_ zoNiHEb*jQT4f&|(0lq4BQXVRuP!MICkYd#{6aqJQe5n)4EjgJ3{3^O>@*iZ|h%prA z=8}F$tWGtc&8I7~)`W=Y=x9QN?bxAuJ2N?Wr?pJn`UnRWbUYQmjU z^P{2!HIK=-11>kDldk&Tt?~+Q$4`f?+cHs{7PM7K)IuN^{5SBJ(rE-i>zKPnI z%GUnwKyv9`t2DXxMg~!AmZ*lk4WKeULm8Fr3P-iLsm-bUREccrOgJ~tBhmRc<~O6Q zW4MtwOfpGbyos*9;R86hp%JY}DW*f(rL-);`rXuYPN z`Z7LL*{?k0H(4K_y1HKD3$OV+g>f@Hg{4X;TDtoheQ)(yo@Z^@n6Fef5D@g$FpcfY z)Z%cN#~#y_*#5%(P-V@dz&AOToA0nwZPW40u+c9|^z#02+f8+Rc{4vjvqrD$gsH*E zp?G^i6nwRs1uKRAu8t*n!!3O1_d< z-EEjNzK(O*3wt8c(|t`{;B4}huf@WBcWxJ%TgUrg6@GOsxxT zk6HaQnlFziNeL959!-vR=Axk4?x84rS_S#QJ$lg6T3t?Ce7ztu*&Zx5<~;pG6Smi* zdw9V!eBsJ7IytX8v?)GbHINMRxF0Ol|Cy}$Cu;LkEWihwWxYlg@W~`WwkgX_r7g;T zC^U5$UmQblj{ZeeCF;Qx!C3j`PQsO=<^=Vmi^>oZPnfDdC6(1n(bar8-z5e{eEb{j zF}QY_n}i9++ttJx`Qr7XfvcsLuDp;D$;LMA$;qv0(y~Z*jQP_ccVBrD-%J+Td4Jk8 zvz&Z>n_mPr#P5sM$I%+%vPyaYl(E$o1m1&2K8h!F5MCuT-url1O+~6#YAW{q9BZUD?L{c= zJoKOQmC__K|L?hw(g`P$ljESaP5YL>|YA)=Fsd5k`r7+(vt0>RLB+4~I zBJA#4S4~k{epOUIvsYx86KvAi#3dv9+PVeVf5)GBkA8<=wBQNygtmNge`O9r-#2-? z^8sJOtGHpJV$Z^a86OU>;T^tZIsajG=XYp{Q!JXBL$NM{w&002!e~<8B#@i&^Z$(6 z7g0ZN+Fi(}=_)!;L;=;U))HZqkq4c<`4$qFD*s7f2UB9_RH8G)xa>Z@@gQHqGgzU5 zumI{U!XxdA#CRVx|59SEKz;9%Mbov4Xp{1Rm{s`xW*}}8mAZ-;hga8Ezjdf8VBzWD zCevO8nf;Vmm7nkKCI02cN4a1@*5#?)?t!`y<8^aYy0djN;}IGe(YOPO|I9B zd>Y!NF*bhI&1Pk3A|lrZzw-*{z07$O{US99g%eBLJ6!^j0duOG_e5mx%;A%V3DeF; zvBt*=eTf07Q;Z_l@A3R6ATP%VrwJUq5O1FQpQwalIWclfUrq$vebU@fGC&X%^=VFKhKI)Q?rQ~q(8I|Z*~O=Q<+-lfwY`?^_-S*xEa@X!*~s9o>sjlx{3%3QYS zP+N06fp0su-R)>U{Ka}d+@`-?RlFwzPN#^TW|D5gkPCI3s18up;`tM zNFZg--5b^xYCdg7zVw#|ucR#%PuyE!$>)L{@mNPyQC$5-k4qEcGmup-n+r((LpW%3 zinS&eMa$zl9^X%(S~yE!5F^-9>YY6y3p!KgqNhDSd~8o4K9p@G+NPLa#y2-H(!K-6 zAQBZity%3}mMq_iot{So+Yp9`%5%q2*!scbHPdV!ZF3&U7I$XTtB1HO3KU%TR=PKy zB8kZ&er{O^LR@^ps1Z?BHx%Ql`3YwjZui74^{pdqN2#C!Kk>5!A)W~prh`EO)tZ!d zzbsc;r`^{8x26e(DAo96luKBze|o%nmAOrilBj5Wq?i|0lKm6!h7KK%7nwJD<2ika zRsGDf9{Zrae%@JwoP73?mQgMPxp%em_HK$1Sn~Z%n-%PZ+Hp5O#ssC(^bP=hkw(*6fUaFSk%&b|SQ39;p1KtHt2Oiv=70_y#vd$vPrAsAKE%UX) zccS-dz5TKo^AjgtZO3JxX%HHk!ParUfBC+3>qur9ue{K`!EP?)5E0bvxV9m|(tbeh zIbD*!2Z&V;4c($~IpEIFDD^}NEdc4`AR3orBB<;0L6ymkI#0uq!NW8i3^oE^izx-r5o%3`a8EXlW0bD|vs)&QEXSF!BWuI7+!N_6V_thRo!dPTqea-v4;1m9m_ zxKE+>!MPHqh`dT|mh_)+U4YOiQd<=mT7yThCBjE4d+{o4igkZeGgHJ5;5LP91BL3(alTC`!T^R5Ob*t5q1C?c#^s z``Wm^%xMD{=9N=K+F(Xb-5dCh6j`3?zNL+cI8I;o2UGKP4%lv+lnaggi?$?`ksX$- zIxCf&v(l23Wgl8Sm$?^>0@8BstTmH?>sqy?TwN!zl~>%Rr>oi0KwKYrZn>%s&M z>(zEw#m&y_q^ZbY+8)o8-8)_fH@JA!b~R}-@p7O2ocuKlq)NsdJaCYnsNOc_I$)m$ zv?>e*@gD?r#|Du!K#n-SPf8`gy*aT3*9r#V`i{SkHjktKyU?(r7CX0;aem{Yre!bo zQ#S7NYC^l{I)S9bXkmY1k?Fcpb?Q5sN|zFpfj5AtL4{~JJ+b)7#2-DV*6^U-CLE%z}XLC^4l{Gpj`5KJSt3n$lCfkqPH7>+V6{h%Mz~y?e|f}UJ4nt zx9)vIxmXBa155~J8w~wUS7Cs4=#%sTTfvR*3cRL0Viy3+S~?U!%Fb1O%_a8d@cP#_ z@LnLmr>OF5RdKZh+6t}UK?U=gSG4R{ByBHCx z-fM|2&<@MNtAAT&F|0b$YSOK@2<-4R8E!L+!vd#fLOVxw$DUts3uC~RhCT~z&qc>K z2Gbl^-K>8>_W{h-^v7qS)9N$7^78F_^<=OE;M@ekbsRz@u^ZY0S15%oxGb1!)Y>Gz zn*gxZL|%`deAE7;nsp|5wt@9PL<}E-&U^*?R|3%6K>povGI_(&qF-yy&~Q~XgML$j zp=7c>-i$-MU%k{pJ8;j*cG%dzXyZ}@z_bQGlG2VMnX>zBfVqecKABKVxhcr-xIy!4 z0NkhM4p`IRD`x&SQ^m&BmLs*DhPd_B3PMz(GWV|~ZXE%QiO)ps6}tUzwaLXW90Usk zpVb4*zwvo}`ELDXpz}xtAjbYqkMQjWT`Zf9%!S8^>Ewh8&H4+HS+B>RIVZxLBH6?L zVZ)1f)%Gxnpxy|&A-^BqJva05wZuMfAnrktTR8Nd7u|!6C@uoGSfz0oSBb#8Y%idO z{xE%gAsB(?sbps~dpn5*U?&p^wjV!KwVOFo_Gr8%N2`!@OeW4w4pZ3)JzB$3Y!macIA(!4nVJW^36CeK&zi@p7;Sag(+beH1`;cAvoquI|Aly&9X5)YuM+yzbXzuw)m3$09gxotrm@({9(w+t1tN(}m4*w84IRneQeT!?O$0 zX!GF*ZBvTw>*n|8AVz+-t1P?s()aFmqXn(M;$wgW2C?+`5F3=Y@pb3Fb&nEk&`E20*NTJs-auWfD&MmM=DYjM=0lPplbn^FD7TkWvMNdn0X(!*94fE2 zh&3ZvIQ!^P69K_uZPd*M*Y5Q%Q&Eh({T=xB1F->bwxe9(z|(pO0C?CS7~-m5C;neB z@4q`Nro#e{C6SHDcKCc`aMlmIHwOGi7l;Bag96COP#7<8PN{;5-~j zp;rL#M}?nqJrnDS42DEM$nPYKq&J@4@}J|@94)=|<3Apmsa!=A0;-brwEd#K3}gly zg8bYEa@<8Ji%4adx?dGK$!U2+BIt(7={!=)0Dk%xsOUO5b*QK@_2!$33P?@1Nb3rd z>u#_8(4g(1^6{@9@8oeMbSgNm>q1AWy%X(#HR&`S$BpNE!VT{2css?1nNHFv4-zpd z4L_!G!h7c$z;AHe&31NhuI>|$^X=?8G?#mfXF(NfcwLXM!Ae!=J_{ZXbHX`2{rtD^ zf17ZoM1G}4d%|+?Ot)TcLh|k$tX=saelb`y;1>P4|Jj@BCfF43)H{`-l-GuScFna` z8)*rQU&k)KA#M|jXLEDuG_==M>)t&VlRq1Y^f%chOwA4%`K?pIbwMy7M9p=G*9}Se z<^(3-`B9{EM~|0adQd)9?pmv9n!7rcTyR!TnL}1Az%i3OMA$Mt9eWNWijw*3<~ikE zIU1lp!SEhF7dZF4?{w?>u)naIEIOKR=T$#KpHc-Du#NU#`rgRUL8KDj!&!jukt#y} zbj^0!rCTuh!+KU*l9~loo=WtN;^*MMwHr;*sQO{jQO){YL(g$s2MmR+ApAEymQpkofx!VBN#bh zTlA%pM0f0iF~52Qhp)zfQfW>L4ce?4mt1Y_5QP9XI9AF^}KFxPAW z=rHXDkPaO$NASvZW=S11cLON|3l8fS=XKS;!yj-{bR&D)FFKfS{YKsDBUtl>vg+-` zbSR*fRV+xA!J_%?IoI|)T`>1i0I|Gd1-7ttdgi>_PvwFuzo;h(B&*0eL+;jQc=HoK zHsh~0V}ma1^ACG6-?$HAl5_D4jW>}s_?Likw|p!!-1ExE2m=+17pj*;y(Q`UrW}Ee zuvpAhMiDCt~*%ce;LvpEg&-CGA8V-8$BjW{5QlP;0)u*NX(BUhBhkF zsW&QIeCKg4+i%J3UM_iC$X==y)TcRw`mriXvW$Es|=-k#>0HsqBJeC!g9vU1g@S z-+cP&z`bPh_%zlXh@xlK0Xy@hojzAXUy-iq5^Yk^;WLu{5|2u)#VEJMKJ*dpu@Aiz zDb_lzm}?OUc#u6K*7o4h-aEH$TH0Ny%% zWF9XoU|;hx@^4^305X-*;CXy}{UfiFhUYtB*86j{2YuFwrDlEe>fgrc3ahtXmNDv^ zLyKIwAH*;0SU2jlAsc@>6+RVL^j=x#(~n)pXx_aTt~2XX(cMf^okh#%)$GT^E`uIks6^L9{F$`H`o5@!M*y){MT6}P18t%v~H-G%;~>g8gO6j{?t)L-H=SI zV|;;9+MSw_D(Yi)@C&MbLlq_Q1O+6_w~uL2x9xMAo12Al)6kx3T`esww06U0Qx;|y z0v25T!tjLH51J1b4b4vm3S@N26VezQf=)3*lo^wdE_SW&%MN*{yZ4@Vt79Ki zqtkgR&ep`+OtH&ELi&-JHx1}`E$cJKsuyVu+z#!f%$xCYL{cZ>(Zj~>u6=h`jgUpC zehf9;fv91os4pEl9%$;a0J;DkoxWf0l-QoL{r1FNyVj=BH0b|6k z$w@&#uwG)$0)FV_)4tIkCtvKZBy+OXPcgnDt}fbeIIE;i@`$w2X|O9xd!F{MIT-x; zqi!(mUZYWf@Oag1G7`zkBW1={A#B4fn#B!kgK_7zpJc6iewjnoe?%lB1?MfNCIeIX z<=W=riN;PsCy_7f?)|N8;3WJEFhzf|xLcPqHeZ>+yqVBEY*i`Mb&fZgn|hY3ak{(oQtvpffAvJgaQpJ#^L<(Db%$M-3XmpD^8v_n z{Wjm`tLb%4$}&Xa&&FlJ9_zfxE*o&`nd_56prYj4l_}!Q#F-13 zJQa+Eg0p`_K9-Oz+K03m8vN>wfDGJvuct-=;j%)yAa#*yUaXg^O@B?w>Dq3-p>z+< z_WS*g@3}?JW^pHF0sE>{IsnJXttP!2T52OQ?K^F};)zX#`liAi1y=3ZE#1|1>06f8ncCwyy1D=X)`0#5B zksULZEtyEK=wmi9O+L3;;L?|^VtBp^B+#FnI#92T=lQRX#I2h3pEaJmp8Blv#*ISJ*gYub=y@tn zvg1m1UG23%r`_lkq<42&yrJ3lo^iombLW*u7*`$QA#P$x3YRSTdMy&Hv}L77A)U=| z^8U?dBF4hxEb#L5b(q6h%XN^m-T9pSc)cZhwe+ZAx@8dh+2p3Z(&oqVL+l@paqrbj zKw^F@hfjVo8**R0F@e|)>1m49z;z5YVQMMS`?|9Ek=y2rVshr?1ndXQF-`RoZF#U% zYVW7Iq#P@IWPbUpCqq{PpY027kMm7JWm@Jh`Xw#fbwl!uRmr1@Fr#gh^Xl z7_EvyK*NEppW2W2HgHsEoWJ6DrUy_sbimeEPkw`4hYjK7TA@GEuynq48qqfVK}@gK zB1d%TDXTs$)L}kBxY1cUUhDd7Y`@GkKW zrDAdy_~hkX1-an`ul=Q+&lgU$7M_(ZVK&4}DfL<&wn;Q)B=)x#l$Ta4-oF!yc*^#z zTmpFN{Br)jt&n=cVh{>-Ix&;U-SehJp6BWwcbD3nbO`cdc39DjI~X3`k2N^_NJ?#i zg$e=v)fX&oly#~bR?>ekn;0hwe>j5p5rme(cZ&@8k2c7poC?{K4E49Uu07Kre0Cr zu_!Oe;g9tfnTC3YF+*Df@X|Bx%gDIoo(ahO6^J~}?10dZaPSgk<5KJm`3r}4WJS%eBdpAg~ic9GaYaAa=*H zIT>-h>1rz@N|b-GJKDZBIE#(!?&{5~QSss7WSY6x?1w)@ke3>G zR2Y6WURhnu*+oNH6WEz-OMF_f{5+P@&qpZ23M_$vTRg&? zAzbv=kISv&coj`dd;E1uzpSMrGRVd~e$4*ZhI>L-O07sCO4f%A@3Un1&eb=BcEY#7 zXYVF$_Y8@OFJPm}zgABtr+eFb2TbAtg zT9RM3d3uPZnt)C!CW9#~VHtf42}&T&Mo24bWEYs}=JqHig+qU1*f4t}MiO`TCmOBf z-Hd-YCHOOSP+^cQqud6Lmp^U9v!t~?ggC46T{&kwZ7l)FQ2(;M*=GUWeIeU#o_@Ln zR${0EQD?Y)P6>lk7A}nUx?<*M}zA%-Q1gc%ucgM9S zJ6uNLZ6H`ZRf97{X5@N*!erX(S0VISt!VBeJtB?;P4tl&{1S_-8q&+xsG;q5oO5kV zA~D{M|C;T;fH5VsKE1C=HKAL#KMmDMVtLLZvFna}VA_zR0KwnMzqkE%NPf_8pW>#F z$*Z|ouBIWXLS?d>&@ulDrr>1osU%ADUM(W6!SX=J@jI)pyNkl}54|03ZuVhkUVP`X z{v?ktPul%5?T3eZ=|vUK@Ob2s$}yFGkkED%NN2wL_5Bm;>xE0?_qi5&A{PFIrsQuE zdn*-6#K-PcezAQAeQiv>P`+%O7pUGntd%PUiMec3V<(qPE@fOT27hcbI>u_1*Ba5( zj80j6eE-*}-U(nEPbIQm>Z1*b6L9p9L>6BWIUm=PJ)&>W#S`zl) z9vAayY3MOUT*+8c!Bm(WE#7X70k|e)!->`XkQebMsNDlZCk??c`cfxQbjp%pa z3Gc)Ip!5{hu{YveLyka%YMes|IX;s10T>KtVcSH##}$VDa80>awaEAf_Y1m-XIjd$CL;Vmj*)ZIC_ z7j*9#(;89_ z9p2&ET&UakPT80JPDjcc5XW0M{%p; z%9yQ3Zj1&su_a2#TOkq2HJ1ij@Pobds*BmNM)L991syQLrHV%8EE@=Qw-0N+4NG}2 zcg7PgMI2Fn$9s2$l)X?de;y+Y%o<8z?V+hd79V#1g75CcUFRhJh}Jf!cDwURr^UhQ z&+TxK`5Y4-zcbn8zF0|ny;5%)zr_q*)PINCA5mXmBh_Qdc_7_@+Z}_4seQU^W~bN> zdyXh^f-WE8AY-(Az)$*UNEub%NlkQTio>q$m;GhwOZsf}&NI#yJwdEaE?A19M*^`j z=D<GUAA1H|au6eWo1wCfR#^Kugib@Sd zX2$qO0eJ{z?&!t!4Dl z7AFhR(DPx>xCcfE4QZ_~8!lZwpl^CX@2}TrX{zd>^qlL(At5ctEVf)HC$}p<1g|&0 z~z|7j|?JIBMMD)jj9# zom5AT&h>bFSEO)f`4eiy29Z4Y^mRte(Ou`|_0#iKbmKk`fAJ^0oB7r7%yYj$M5EUr zK8Xzv#tBANb?Uj$(mbRDsyA0tRIB--4zt|U!j8S*FIb22#bb;Tli(`XPil+E9^d$@ z&64yeFAlXa3_ICp@iqGs*vbsQ?@2wVZhK$^qN^u38Er5rQq6bN!O48a!Ct;q_p+=7 zXAVo3PDQKhBTEFif;egi`@Unnl;7vKa+pUT3f*M?QuYZ2!j3*{XG>!X0aCUT|{7$(|~(e{$cTQ_qP0 zp;RKdZH^0B99z5{f9Ka{wBDywULKA7*)6%XfZEDMCuzhQ?6 z2%!(kS!U`9yiXr=>wDtw!QEM6g1+(i=HfEkP^~QEoT+?N1<`I;9?h$aZ=SCGgq$UC zms02B3w{ttwA?}2_o|*hyHIGf0Pd+~HcKP)k zbErfP{JOT=ks+(=!H}!<0+?CoXEJ^AQ|x2$C}-?!wIcV3hx2FakXetNmf)4S9!g~V zf#p04VfTthp5IE4(UUp@g*FkgXb5PcH?NKKm+vFgL=&(3Y|CEa6pIFTb?ssY5`6ax z513WI6SA~GWOXKRUJAjlV;Aou>DhKZ5%7GzxaD@8^KZ&Iyl`!L3Hm)+1c7ndu$_o* z@3=`l-2Qo8cHreY6?U8-qNh|4MAEhz)O;vl6U5y6u1Ft=_eTsxTauD@Neu;;Dt}o< zSb{c%LGR!m82lFsi9d$XAg_fb)4P{>Y&JdrRI66VhcQsTS5?eZ5!s%522`M7L}Qe`VhCd1z|!^b zp+tT3upEQfV0lFyS>n-isg1n3K<8<%MG95pfQyYSG7bs%RUbZhjlCtP$4Wo!nZ+7` z#BkOH)0zvS$4)SJSf}Tm?#PPE_W0Hh{>!-PhoNh2=<1@N_#8R*vwKtFnON+f9;4b& zm}1yQQ+;{2V2qCphleT^h!|(laoG-MliLaY>g>b0aP>>hbJTOp7%E~XnUvM1YMvOl z%Qie7cj`rI8trCFt?r5uau+#LnIitLvFJ_+t)hBSgN5E>e;_oDjUFc2_2by@7jS5g zLbNbnzK7c(x6PsJk*b8w%(aPnM0CaDd5%s)$XpVcQ7M!tmkm&cTchD%`vQWyz?bf4 z3u6N7R^Vx8pEpirxB{HszBM`tef)f*;RA24y!9AJ z?_h9in*3u6aR14IbyD-qHC;>!#Lh(EFK8J<5xHE?sA~o*awFu~yIucaxdxM;s{v!n z_|qSx*R#K_f}cSBbZK@%;DRR|CF+>p;-oO}Dvfzo<%5(rmBa{QUPvh_J=DAg(%B0~ z6L$sAmyYWb=AFFx zv2yqYOemEv5am1Wsyx!;2keieU)h85R|}(;lc<)Sd=HLDX4^HJl}_I+ZtQw$g7n34 zwY{%Cz%9-E`s5)_H3yux>w$0>KJUYkntdSzDpLaH4%sUYY~kiuYHXQrAM7aoF^5yW z;WX+hJ!1DhnhPA=dZ$z=7Pi9qfc@DX9=i!Yx<%plc@CP$dOk7<4{27d7L}NvVYW!n z?;?qiJ|gGyCU=czsK)V%*q-sRvEIcbQ++mc{!kEgkImTAK(a5}uy(6dyS#u!H zxTW-TSJkp@BJI)a8}Pbpd*bqBZ-qvvaxa?uEesFvQGuD z<{fY3t|!JGdQR)M|Lp~!+$%~C$z5qk{zehmA3ASzvGMPr=A#vp;pj&En-!Jn@^Hx4Q~nsC^o&B(rTX zK|&zT6Q;6-N}GxYdO}}AL(bYZcQ}JQcz|1dGvGLv#(K<$MZ2su7fsR6C6&kuC8P7= z{s(t{Wk$XHG=}z8=QBD_WQj#BfIAn4AsD9Ldd-Q_Y)~gU8-FEuqf@t?jfTEP(Zw;; zbA}xx+vSD0kr%Ofo+N=|qct+p-Iu@xzJPOkDh_)2q&niiqZVK#@HS1LjQspiBHIN1 zxb+O{UX1t{oyuUTW;fqC9cKqR)HKIidbuCdF~=79CJ0?G_(2z?_@w5ipT}Jm4)_nf z+^p&SBZ=vk{5I=BElMUSJa2%dJ$tFB*$}jRZDx*I)-4$g%@mhb!@|Ram;-=gliPc0 z!u-K;14%7(MZ8D@q6BTYmEofmQ+|z~MZp#P#KCNn5vXO;s6ErGX67Mwdz+Pm#3z(? zs_e()O&1dpl>EQiIpKDt@DCxS$Dy6{9&t72gP0y2AfUkln)gh8R3yLiq z9ckHhseE0Uj+?J`lcLPe8W;ufp1r{)*80^jdnr?{=1)2JqLU8?9>lL+D(flYaNj#7 zFkdzM?4?T7*U7xz2l~MENuvk0`%y-~XNT2Wmz9%7-aQPO3AXJFF5U^b^A~qs(5>&S zIdA%L%eP~Gp~)k=LV2IeN#Cnk z-i`R>{bSMN>96#UN}tB+VsD8ba?Zs$?gB$}A6zzgpm=n-*Kvs`yrBP>H@r+ND7ZvE zg>L+$i(i;3ik``B)yjL|;5=98z(4vT=uj$bGuGeno6ya_g8s381^wi{uU|NwihMdH z&Y_uBqi)jacG4FBeJG74=1~so&>gA&cHljIXEZlu8hS_?euIB)jM2=Ol^-3Q!j^ld z1q(5^xN{}vihTH~lNEnwZ;Qfa?uX)Et7NzpYIdRFfW9-c7Yb`Hd)7~1BZ@_`eS)q& zx$}`Y%b1)KD*cBJ6p_JhS|PbBKMtV*A{iS6NP-?@lz1q@f#Rk=8-u(`Wa@*8(FGU` zibt`$*`IhguV{KjIz4$pEnLy1i|OlfR%Ln-^%B37jFynk{KcH57HlulP7D5NHG*bo z`Wd@zMrQ`f3`KV@^-{dLbj`GJ#`KE2V&+!v#cO@JnVwmJ$a!-`HS(DP=1_dOc2T+t zPu7Mi^8N;=1$514sG{kRHra|F3~u-mOPVG%Q;vQuN(ga+^=}RQrY5BWv)tnI94eG$ z?9?~>%n`xE3@BLxTJ?)THAb@vA+98_3hU zp6+BqaNf}1EJWQwD&B4@P0c=r?Gky0>U15yP`!j#tL`q2y&%nIPHkE2;$=E{^~RE0 z!f!Y?YDc}sox`cB@zi@LqZbFdstPW6ZLp*vnNIgVc|Jj8OvNC1MKqbn+ngFXH&=I* z`N%d+-7EkJl;Rpt-l9x|XH*ri@f%o*E0d<>Ov}sf?}KOPe?JMKtGY#Z(ow;P(CsDPBVb z)&JVii$)ShV$)-$Z^XTpoY%j03e7HT44a1Ta+W}Io8i4Te{s1TM97b2wVd)g%OQh@ z-FJ1g+Pr=KFke^#o@Y5W|1K>OAO6P&k+EtJU#;3~vylxSZVuboaE>UwcdPUxlN4dD zHk$Rc&}a-hQ_{Z*{Wnug$&dV)=?PmyPuuW023kjm|X{|b%&pw4NQF;N*$*uXMm!n@dsr8 zXH7F-eeC)|PiB7c|I)z*C_w$nk(eMf|1&%P;~$DZ_x2G+zl2NwMG5>_emPLTJm`Z& z^?&|6AL;RroGj@vcYK+Kgt#-W>+7%ulK1z9k2|o4VGb88>WSEu| zB3>-NDS-LLDw#NOv=_#Bi|^w#%V9J^?)%B4d=4^;!UDNto34xRQ5yLEsY3%e2pu84 z<5zuLdAT@H+_IN%DXF%4lc#h zj%U|zdjSwCShJEz<5JNX36FE=`pZP%v!~uVV8-gi|ax= z?Y9K`(8MHIP33JqkjZ!%;<7s_d1yI&OX~&lbTUsaPxH%4M(|ivk@35zHMv=_I^-!l zf6yEg6Epa=RmpR1?@4f}IY14ySsi`KRZP}MP6KedbYWkOoyjsbfY^=$Ff6&TF0@>y zke6S0HuLF52tEXYpo;(ZEALJ`14+8pXN z`mN@h^(DM+v%koDKT{*GQ8r7-sV;58I90Zz&iq@$aOQ>~lE&{EO(x(aKGLpA8N*$o zsY^f;?qKUY6a%q2tODp5ne1T9T(wWxg29|RHC8XJcizvoO(+uEEVMP3t!~~ethb#= zOBAl&p-2I^8zH>4kZ`G~3=UZ2Gh3xLXt+k%t zdO8Cg*5D|SmN96#pGiWs3F8N{`oUe0%y|8bAeZ+>Q=SK1;zEmy_7;;4qsYUZHu{ff zswaUP^copac*kIm!#2@s#`Y()KJCZMjQYJVNm|4H=nIJf%>I`L7myChPpf2r?AZdk zMInr}1;2(r74EcMYA5T9%8DcMy^#w#;hXMy$6IxSe5VVfvW&-){s#WX48~T|Hq(QS zG-w;U6Xu>b7YD7L^(jQ`uHhHQ9uEuZO5_TZ{0dnmKFBe{+OFZr>TF@9!kyDLzevG1 z_a*aDkpY&74UI{=9QH+-5_+WpA<>JJIel692EXM#L?O;(V4^4xA=dv{tyCCQeZpk~ z-77mR4ImJP+GO&c#9n0hPA)MY6ABCO`@UnCSyM3EOnEs*9)d1G{3?SRBp-nR*B5a4 zvF_9Ja~AhjL0PF(wrXVch!W9~1e*B4{pJXh?Zf-$ZI&yB6FE{MVL3nIC>eZXyet>WN|veIv0#HF)0E0&?ao)L}Zw*{-lUu~?`23){Uuh+=IqPR*uuXY)XdW5Uo9 z*g%t)Ln31VF=b~{8}nt|Ym)HebpK8aBqKs>?Sp9jTPV!FRpJh8_HM%IRyZLzuFm=* z=pt0OLyq9rVU+Y7GF?7;?YagD4o4uh*KOT&h;+K=H?g8<{xbUGY5(DmVGu)*mrD%( zY|YP2-%9DUBd<@fNSO+~`yQ#AcYi!!+<(KopnadcAOJ(I;eT~v3P$K|aeHjf?E9&I z9O%&V<-PKIUt3*#J%;PwTjLXjs{C2r9!^k;P~sFu2MA-A`abX{PQZ?t`1xQSZ@ocu7B6!tfsb0Tjyw|)r+bt0 z&YU`;|4tg+*1^3bq8@bwsu*_L^eA#@&~(G>@5!L+kUty%lEgZ2O+CgIk?1i7$4WK9 z;Up?=mPCIlZj_KjM^|HyLMs~eU zuk=3roHt>=Z4mm#{EofEk?NEql;fB(mD@NIy8hg68y$&INoZEPSQ%F54Hktd+#`!w z!I(lRmsLc)EU+n;)p~Mg4WLG zN-MhX@#v3vut{OHtG?K{xo$+`4w;f5QfZ*uHJB!1jiTYii?HQ-Fw-Q?G=mlRV?4IR z>8B1Ar*;F~40#YFC8=!=T4+=zl_v#+MD^$7m#XA!9WcVn!1)UM5V#)@PaC0K1(I)QdhQ%Bz^cH#<@G@*G5z`YQt^e2Ao?dS5g&5wIJ=orWo0{a{oWyou(gH3 zSMV()^d!7UT%ThMxDze4C6VA84B=M2^n0&$J!avss0vT{Ue5f(|=+3F6o2qY=zfHz0CumC1PWoiNc94bkVQD z=K{@kvDY0DlDGx)JXJOQqMBIk;+(5O*vGSB;_N@zd#6_1A zfXpaIJ7)5jyMmE(_d4Uq<@c2`r~}8A-?Qi!9t!L#?z|@@D3i{w@pR_l z>lXNH`1r4Dv~a<%ffQeU1S`%Oh#_JjjaHLOq3@1?V=#8VlXRp@QlpC9*QTcQ?HFYE zUa3*arRBzpr!@Mwep*%%kIpD@eB6JcIH9Vj z-|6=G>s?eGhoJv)W*ozCUkA|-i0jiA-+*+^xVvby!57jc2{Xr)ZH<|7G zyUu#ppa5Fqwy>P5kTVj|3P76BYO4)qc!y{xzzRLu+N5o^KLzxHR~Vr=T`70y zM}fZD)(nCy+t|!GrHViA9O-A(nhakof-AeqjCw;2@h+C$Oa+%9JRyXc%5bn=6I*+G zbSQ+LrJz3Kx8|YYlH(S+N1%ZQgo%oX@%3KW>%J%S%M^I$gBkpAhXb)AP-@ zKE^oj@lpSzef7Yt;~{kuboNSfv|oBZR|fK2e%kThcxpitV*AH_nOWy?j?qWoqn19b z?NQ)s2HERmnvSD0G*QcHfOkoWtV!+rpf0h7ks2^Cw^n5gCcn}=7mpJCMebOn`uHvG z>#NKP@+=<@+~KjD%4Kt{2Pyr3J+Jt zyHCeJc@1M}v0FA~Vq5x|#`(otN5jtCLZ+Vi?feDL9i5_<9MQ56;D@jx$iyCmR)fh= z`{9ZE9~<=_6;Kg8*S8onTYVzVpgbB{jn-x8dsq`-t26SIWH6_jDg>E` z44VMmFew7qI$Pb2q#`Kaz+Qjf8qz2Ax*$kUE`;pHzK-1|AcN=ky3jEj()=dj-j*-C zH(n@1$6lfy+jZ22n~k2KQ)^p`%jZ~r>fgc$d%7L_$X=E!!bR|$GhduNz0n|r(3#k& z_v|SiD`{6JlRsPlD-=Mqhye}{6NxZ}Liv@%ls(ShXSpCbc?^jrX8*a`N|_K5GKiEp z(f?HR{sFw*R%!61tP3Z%Kct6RDL`gS=d0fQ72w+=jmA zGM4MrFOnG8J}se|-|fcWvIH~|Q4K_3K`X4PX;`<4V-X@G4{)bUvIfG~BsWzZ*=#${ z@f!0k6*_iZ%2PSw@}w{Zzjt;gesfWqaRnF@K9uLB2OM(bu4Ni5R)?g6nVkQYF`%Zv zFZfV9?vBXJ`@(TorO^i3bi?b<`u3~y)9h22)=0!N6nbx#I#hOT6Y{?6Pv;Fk12EsL zjy;MHRlR&anXDVtl}EQ(5`7OIDa>N^Ntw*+_Jj`;-Wyj_pO2W#0-_(>>E|Ig(%0!@ z8|(ghju*X%G>;K;QZTH2H5xEh;LqQ4pIoom&|_Q$zLta{n&S0{UVk+{#3GN zu7JTus%@Tn46gsYdN@k=*5q~s6i4ACu376-%lP0j5zOtt2lSG9XAS_TPuY}x>fa+F z;yCnA0>2YK1~MXDkq5Ieo?HF^K0a(LbD`qH&+XyK8&}JrzbR^|P1CZ{Q9UK$Z8|mf zxxeLiK_snJdvtlkq;jV8R3g=+LPXX;VDIzaoO~Y%&%Hi-MzO1 zz|1v3ILSV~@Wx~3pq#_&jPqM~7PAPqa>f&Bsi5EL!x~fNytNMtwv9Pe@?WJ}JBg=q zJnRzV^W7Y9A$Tw&c!T!hT@XcNi0|K)Kk+!mm2{Y74+|LKkTzv=ibvX+-9nVYnaygT zs7BcX6DMF>F-uHg^H*ZB+E8V)#hZ1Xb6X`n z#o3mtNX!tJmG|!QQ>ugtXg#FzGNcG-4FSM56N$ljz_gRs_*+d_1jzVkJKpS5;3aa5 zE%+vt=t%A5$(8mhwU{t#wp)Vl_-sqO?^bV>3Y;A>N_PR;-*4_{^Bk%ca?JG=)P$eJ z=dnfxpD=^r$cIChUw}a+Uu2#Iq?-=wKbT9;%*5k#@UL95jCnXOD;+pZC`trs$%#pkAoumvffA(2H+qA%9J%E&xm_HZ+cTn^5bC3e^$-rQ)nPP@7bQkhOBE=JwWl-+K(uP-Gt*no7i7?xdWXsZo6~!d!B(G$d^92%+4^|Z1GaODvrg= z5uXVAu3R8n;Yev(#Z(~S8=!IC7g~MlhtLcdL=->K;G6E@l_EPa&%A*O$m!*kg;KLH z4wvg%!Z#4x--~g6kFWd^LqMBz_v#+;rv+iOVhpQRBc5R}^B4`h@oz0}F)b$>ItR1D zqH(8&`R8AsQr3UnAbYFg@df#{mF9!09;LGHxVs{`Y8Q2lW>6P9?jD(b^7;6IR@Jil zgW8&^C=2k0I_|l&04U#LPaUWPITOZNTAmg7TYfs?Fr|{uKqJ4ouf!H_ode)vOs0z{ zLJ+iLoav(530_puCo?1(KY4`j#tIJA?TI>OpDMDIY_l11e`)vtl(JaN+Vn@rhR6&r zu-@=@=6S1>$06ad3jt~-Y17f<{h9HJ&lzopl1hDtwI-{DV$mbS7izO4ouSlj_Y!SS z)w&iyRxB;lC6&V>-pX+lJwDwzf>@R58hf*+}wRS|pU*-l?0WRM`~% z8I{hzXj4xmXg^6w;#6Pf*~tTlY02_e{uZnw(+El@t(#5ZnxmvCNRigkC+^4bIsypn z<9hFxoSs}8^SiZ$9Fi?L&GQ#}EN&1dA@oCPOU3x{vHUM{uZQY{AVmUrJiSQ+9sIEr zud@c%UP|XHC6QOSRC+2lJ%#}kTYKD^@N7DOUY7+?wBeJQz-E(PB@$h@Ofa2A7*m%b zkD0x}Yn<*H-!IM;uG1A|_+mKSM-2&G?Rd;P9U_k?8a8Q_T&c%!zu0d+wf7_ro7}OF zf+2BdA(>IcTu90IT3K1itCSO8$`#v2#21HUX|3okF*~zYn&ed~y85$ElD1b1gFzE#Qr!^OJe5!u@BI5ktjV65(_|-2qXJewE+my6DN+Q(mP|R z{N?A_>0DlV+|CD7Pfbs55pUx-9gOzS($&gmi{g)j-3JnwGal+Y+{fHZh5{{W9>1em z+^D|nPvZ%xI31YU8-Lsus4E&TSH^30_?;x1&Mgsz&zC*(k0Rsz?qCLFqR_u83208( zLrvu^(F<(c=ugzO>+qOoOkv(5y4IPh_B^2Ea@-FbIEfSX5b?I8V>LXb2eg*5$qGd| zN`J=8% zz2E(b15IaZP2YuzX0%);mrElJr0_-L$=oK5xUc|aKL(8yo3gB@vfnjgQZYU~$A*on z&vpf9y!6O`x!)DdGWh28J+}@DRVJsRFh!{DsHtr!FJo0&;}M*A3iPSg7>!02jL!?~ z#!JpgyV42Li7Y`C##{SAH73`%y1j`Fq>V#e6m+UThmi%IK8yiof)IF*ZF(_gPV z)G5CZk_wz3=5?QbL>5WVev_%(9dedTB5;{xB!&Q0)owg!co#eHcJL?Dee0g*P`GP( z8vKoaHpI{zqC1*JVqsOf73rKI@Hi=FhgeC2ecE6m`Ph*8aQa&TcJsaEyT3rJe~l$b z5uP^&cg?yD^z|`yH%nq>%)@k{T7Ng_5N(5GUc*bG`Wf|pp-H4|qoPYxpYRirpm>6X zr994o9ywJHSc+s-D-Nj5CsP&Lu$A0-IKcXqF40Wrpz5eZu-dOAgOL;v#ClAeU>Dx0j&`EnJ_WEf4a$zbW320E2=-u56sMF!;q z>#$fy!bez9jNJ%xpQ1*aCg5{|ZsaKp>pABD*njMsfu3Gv3-+QfuA#Y_*Q!28Qp%6- zO!_ybwj7&rR5C`CHd$tvbhVM1XmJgc%DK}2D;N8RoXUdkp5M|`eU8m+vE-l6t*?CGW+iTpaEmU*OkAc2;Wl-Ah9WR5tz1MdR!fi zq)Koh_zNuhSD}!&4ZcZLBbC#%;Sfb!k=4-7ro+NWhFiBnRw{)BR6)484@#_sBeCq0 zPfyCB?La@JCYdY~o>lT>V!Sy`)snmGPVOgICixxcw-@>&#G%USU z#Nx;=5S>ISElWIp)g)T=ke>!?sAz7gv8c6}C^FC+wp;JI4IA+}YIW!lm;%Kytvlvh zmi`7CSO$#cdJD?jNowcg&;CV$_~KbJK3 zX~qV*vFvgEvFXEouLy)Ugy*I|v)>G>R(uqPw`ete>?FH+oVS?xsNo0`KKR$A^{?x$ zAVJK;+n-DxV|Yv8#!E7AA8_1QDdflOF9B)|A@5mIljZ!*Snlgq8sSw!PcJKn0WIv@ z?npu&F#Vt)*v!@Uy)HBI8rDm3s1g7QN> zO@1-{d3J@a04lrK@yj1u|LN%|1Py6&2yq%B{``hXIRTj*?e1B%$KM|9U&jWjBK${< z@FI!e1JZxa=)Y0~#C~w{Ko38RfS@(u-&2Htj)ABOpyU64{S{PJH5@^w_6*DY=l@tc z1j;LILNAJy^6dwga@th3l2SF`|NOWypC!-?sM93~Y+aN7{Kgj~0C3?}qlWU&BMJmK z0G9!^udV&_fUNKX_ZRx&*#A7>z<&?Ki;5v>85DmUujiLf_xY2`!v6g0c*6lKBbs|* zpZ?F!*AxxhzpOTq`wzcP@rg>ATs1TQqY5JV9R%EOj;65s^K5z^O$tyMxyT$m|K>~a z&-r-xWKRL2*TnequXD!)W;3Bn)2!y7U#>k7aR1P_KlN{`@SnSlLD-JXuBK>w4F(xVUOic zwup_sJ?t-Q8bZ-3S)^c>Lu?lEtKqGE!M(gF^a9SgU z#rTgn1{q2k{f0b%&QWz|3%mU@#t;d!kYl?)>nm9Rx#=@x)&B4}ZfXeM^}~(8OJ+B& zXCpq9h_j5ThMw2$A#Sqhx9Yd8r?%lOc_M}smI9PI#`_4D;Nvz7BYpY;zOJO|oBZzC}Gg73Jr8fyg~7RGB*vYK20&l;dIVI7E`*ajx* z{{=sxnl>I3wl}s;Ws@_0d7ve^>VLh_JFH#f+O2l|O&V5vQQ2%L9$<|Ie{Z)pn5O?N z+WF^^8k!EXKue!5ogy5L1)@R?bHFhF31sCIn&afBeU%_`v!So2J152#Qw^mHt#103 zJ}Rm#w1&C=RZrVy)Sv}=ug52pd+%wgjr-zm2XeQb>^y!?>pE^9>h^zqu(8m1#3)uO zE@RwYUne_nx2Cv0-HI!CEM@9Ixz+w)vq+;4QdGyCF3q3W1WaR~-b%VYx5jn&0v=kY z8$*mo>a;-ET}sYu{A2W-*xCmA<+{drMvu#PwI)w-)#{f-B=jgm@|fFxr>Np+LW@Wm zpx@4%0f6ni@Ep=RJa761-Sx==Q1ZiPP&$56ICgM#p{w_(ndOqG16?h$dDj~ z*~{-?8SwDna^Gkg`j}~KKB5;xfQKc6l=zai=w?j48-ISXWM1^BMk3i&iCEuOv&E-DU%-PkH3>36f97BG3{X!O*>Fs~CRQ^@kf(@drMskR?+9 zuM>ZRhq=#{ou%ytLWW+*YhX|qBm;v>xhGf1hXq{!N4XtmW>U)3+t2o4^Z_1f)!Dr^3kb7YjfqaU$G=yzO#( z>0nP7p0<{Y4M$`~!#8lu)Hq!h63n=$xLyBS3Nv0j@NZav8bXzR*Rfwcbdw zC-}-UYie}Rk_M%~*DP}4akZSyca?>qKyZJy?Sd#VcgN08{SDH!U)d|67ld*h$on*< z$s;k*{6*Hf46ukBvDd790~c=)U6d@!7V1nx%7=JhPX`hle1AeIST~MVJ9cU`;IpA? z`GXCPopRsP;9iXtx`GSFv#s>GydH9FYPTU-gDcCA!IiNF~O}!%SllibbxlPA|U`^Dd~aI;-uS>C!RaX1CpkI>T86Tq1Uz0MbJ~ zM{BnD`&!(#q7~hMzzwSzyN2?b+JeSPrAk1g;@cBBL&u7%o81+=A zeA(LW5uOC@RdhL1YF%QY)dvJ9tg^&Ac1uh@Nx16Qda9g^pqocV7k)bux5EXex-gsB z#L^iUf8w&kLL&IKq4(kVykiE(*0qgLB9%DtEMHo{`)O3_yNGAhubDoNKh0sk7z}$W zYW!1pSoRuhMLJ@e#sF>WBed6o>7tf#%z9`b{@q)2v!&7Zm=tE3+mlBO0a`W^t{`$WYqs7$u0E`^QAHDf+W^5a27u?mZd!OiVm7g*2nx?yW&e zZps&F>(4XN`3Oh-ZslpPv~i>!N(^0J-;U)Yt`??5YNe=)QERKk* zo#cbYgkl`cnD64F)6S2tn77J&YL{ls!QAY1g_G&NNpQm0XgM>@622+yJxqa+S=VDu z;h#EnMT(}s^f3UT9y}5b-Lxx|GuHN1Ja{S9W%!fHl)k-W!jjpzw`wGuZd>y68%}^3 z_-E?*KNqNGFBH3V0wUfLCs^*D*0(r6^7|~&!LfHs8uS|Vo&M(TqW+{dn8i_;x!7h? zcp)o%h4D}*ouU&|*E5IYV4i=keGHGvB9> z?Q)?T;00iz#d-8aU;(yV$HjNt-wO3$E1AhJ8#wU$o>X2J+K3hw?^KxeUge)qRoBfq z7wxxj2O`u&)+yW)Rm*_s^3QP9z4ID;t{NDxFUyl$Ie0(*e0rvS*5*r!Y4bX7k$XPM zn9iq1NT--@zN~+CYNzc(p-PvGf#iY`onHZd1%;VCc4Q`tC|_=pdy*OzviK5#z)vz| z{0JJmf~uxkF;J+~ZY|{}0cn3JLGCtE#!{r;`0N(x0I940OZ`K8>kkz@!A~-h2gRqK zg$ZfyBv=l=N`GS^v1xWPjR#aQD6KZTUEV3`n=!JDr|woDD4I z9BwaRTK1XI-RAbJG-AjYy#bmPxCK;Zkjn$CQ|ZplFCp_VV|x(=Hsq$KCZ|%vC}%&N z5#Lpg-pVAr&qjadwhKz6R}>9efSo2IiHgi(Q})uxm&%Z4)Ni)L7`H6FF+d%Xbv(73 zb4h&iApDS+(6+1orjAOhQ7@p*e3Cb@>^{4((dM?HJay+F;O2M1NbI+{?=Jr{qy9C= zRxDs%(7|LAe~zIt{uyF?k8+gc7Z73<`;06NG`oVKTX&M|LIG-FYuN|Pg`lQ@)!0N1 zni+8gvBTM5GLy^rPPL^8%NOq8bO|7gNa~SM-y2&#-5xA&j69_U#{kimL&Jy<2Ki0z zCnr>a2AkzvvHadhs8s2@$g(LeOtmstV)Cg9O}SD1z-Syrcz^6bmUzVC2HfZ6`bSX> zjsP_?c0W>z?n@=Pf^`E+DH(3V>*=~bSD5nDU~x1a%DXi&hpY}&$fPeW_rFpcr6Ky(75rV6CH6kho4+yY<_m)DL^ z%sO3eY^CjZ1iGNDc)nnb;qZIfhW&*WdKw(&Tnp;E*C*tf<3EIgow7RsB4Ls=^|Dhbdk#RIp`^ry#r1}`f9qSELW zsqx;d*`E$8AZhWl2kK@t3!_ebf0%Q?F1RcYe1RZN@cfccfmo+5Rku{Oe7HqCHWH2mD|{>bO78z*Y&9Tq|q7qD7E1f1gDcV> z59gApW-u05^Lb`@y)I;z)9jYmyMhD$=>_2EO>lkFKDt-A40m074^W0bG{F}j`@Z_# z?N?qULXdS{?G6X4(V(XPs;KJ_uWSmZ7)1Qb8g}7}6d5_t0p*tz;{05+L|eXnUsm^u zv_BJw7#C|VzkR{xQ$%<>LL4e4%_+Vjw(*B+w^tj@;eKcLCOGGD*~F_LO^dwo3}hx*Z6MH@7BT2zb5Z zxPL`+E2op%_+*0HpC3-! zmw{9zz~S+x?iP>~WsZO^%rG?SqrOAFa0znZFY@}?9kRr-0qHPZ_UnG`%KFVN`Pnko zbG7!~ltP89{?2ZR^GicXHw+#9E+sd~c_V#7(%pq?nY`UcXao@Y0crARd+7Yu34#9+ znL0z>cFFx^M(HhlrK3>Bqg{>Ms>cI3%;(jm?C!`1owl<|pq)cOoy+hHH4KkK{xcL1 z$BAFQMwx-c7>nPb8|Z#yy?R~?DqKRRlDEd;a{ep|_*@sQp^sY)E1G)S+KcvF*Kl}b za@oPo0HVnq)>9$tMW{dQspO!U{wssEKls$X@}U8pteJ-DVUD*YN(bL9XamU6cu!_i zB*a5Pd#+@Jq&9J$FM&L zTRLfYp41!uc5sy`*gpGc%C3sd>aH1RR}>6_)k%19{af;yg(C0UO(5StDCV|IWNJv> ze4HNN=b0zF+ks3-Lp0!=Jn)02*7UXlJdn28oWQ84!hgGA97f1zk99%Bn=>#HmmP4s zb5K}%?@0rpu@3oI_Z4VUrKtx^T@K3JxjVR|_*Uw~Gp`r+hbfzryOdxmRm#hyd~nM2 zUOYqW|4NckPVn_Bn@beE(h_?WXh4i#dwS?pE<)UMY5unQj^FyrQ^zHu8V1{N?yO4$?`LI+b9sQPGFa+hVba;3%$=(f9jU=fHz2BWw&ZoC}na zIILgYmjv>QN8qYH^`gmXyM2nzdMfdOrlOzf6_Ad|7#S#5v4BKWJk7-Rz-v`HX|&BA z0~-`>`_oBHpl>uYo!d#?$-Pm-(1m`f@qS?PA9lB`p2wVJgy_U^iQejb3+nX7bh$!B z0=3%=Nx8I`d0yKMo@g*Z|H19nlccq@%SemO;!}zJHQbgG;N)YM#J7F#oba+oL-&gHyM?=rIhFPU$0)h(KrgZoqmF0oqi&be(H-)^;+17+JlfOwZ`H56Q~EsrA^C2lG{o&9Rs4 zTCoViKCp5UJy8Z1B_R^{0n(ex6E=Zv_`C@A?KyHpYu~qGIopA+5#Yk z2HPnOg3H?)`IC}@ivD8OZL1?TIE6vA3PgK(PGkRv$J$RpNLSUh?fg|Q7g$>!uWFZ$ z`iR<@+>RF2XU@DqSyFktm-aT(DmHE=K7FPcj8?uj+*U865cmB~H9GHKgM80+stBt1L_4FFFPAyoHTEAZcXbY~D zI=(zv9g}jeb6npeECPr@?=0h)DTnP6Bi-aZ!g9#*LaBOTu-sMmJ?UvZi~Uoug;TzHruANMGO`F^eF-cEfoT_ z=MI|yi1$>0FD`2*8oD2!1=AJzXsnXJ*q;3=9zfjts^@*N4-1N>Rld z_S`-ML9dul1MgRsEY4+nJ-sW3b*ofHia_1=OWkCsdW0htv)>xV5{m@fAHLtC5W=`4 zcij`-8Fcbd1zog?s@q-%Y*(pTeSoglf7+!TCRRAaAJ0?dlLEZ{^EXQSzqR`gpCChV zj#cIS3Rg~8Bs>ZZ0QXh-4F19_t`haqjqT^_D+|5X+XLXC2j1`O*pp7w?Fvs#y`|H( zlMqdJ{vJ2HsJEFIh9uWf@HE>iQ3B9z2kQKho@OY{Gn-D(YlvCJLL-ugPGM0W?ZY|_ zydr$jQBlV>=gk|)P%u;zZuy|9ey{PTK!mzvW0VcKrc#F!EJP61_e8hJ?0!oS*pO#Z zJ$(8u_Bd=NmXF>JCMK~!UvG5u%BrpQN|z0!=pN*LImqa`p~p%6%~Z5)@!MGA<2G-X zV+LOcSF1c)1!0`|@Ji;CJwK;sK^F=aU@?Ko%evZHtdkNqw?2XI>+>Z03IgH_MISou zv$5XWF|v8zc;&TbPwLN~CIE!*zUFylK?p5x?(+9+ePWX+8KYoz_Qz1x&?*PXNJrKW;rRq>PgG-;Tgc=edcW{O`Mv z5Q&J0gun)$Lki>%w0B=)xMKpT%(9B|C@sIi9bMUTwzaZo!pPA%8w)YER1IxlYq5e1)jC%3| z)@DN4C4%!jR@u9|=eQvu>KMhdi~I&fh_V6v5?*fX%{3S|9=_DO`LYTtU^=j2Hhpm| zSr5+?tQK$_;`F;`5UVru<%HQV7Vj^06{g>uM<)h+&Q}_`8CLPbpRotLCV(UU z#Cj9|Ug%D6JCK#qy(-YYMVpz$^=`w0p=|@G+3T-&AmJ42%eJcs!xCmX*sgERELqPK z0Q;qG+M9Ekj^+;;_0P`@=K1e^Cs1tMuX^s0Q5NB*IzgR^L;)p`F$e#h+rChTo1j{& zzUlE5*3HN>H3K_xck;Dtv{xjU9cx|q1gz?npf<^sPRunsSqhc&$7>YO5OEHhB8k+` zXy*OO6HkGWhbwCF>7($+MmIuxCCphOUzrgu>==6D@NoE-*r>c>Vi0`6qoK9pbWNab z4Qbm0djIx!7?;ElT2K0WIz=>?SbVI9^V0m_rPJ+vTGqv(G_6EJ_Ny>g$Ct{ulcP>$jyAt)B}NX^Z*FN*8>agdzHaFHWl}*JTx)cLF`F504`Mjaj6+|22+4X+vzM2UOsaWwJZdWuJ>#i#o7S=n57GAY z99xEfk4t$P9s<)9yO-hRqB^0K6WZxgJi)wdRQFZA1j__GEvD+^EEVtQyixKaJnUV_5#?}|qUw?rL@;zj&STS2uI${Ox`s2q zOtWz|My&Xn4EzO39EfJ&8*@7`(M%@2@hS&I#0i_0;7~%hz9mL?Fctb-jLnq}Tn4vOdx5(pC z6!5b}h9H;WUkdu9^IX@01*G zy-elRQM(K$_?OZ<=STZ@KutG+x~fzZun8_`Vd`1`bt!O?WLdKnQ>0vC&POYO?;2Ct zI%Z?Y7uFxvcRwW{Vb}8P0s2eYM3E#&pJO{JkDEFu2|>uMftltnQ3@CRIkBwa z9PZSF*Ne$g%08#kuwbjTwIZ>>uMA+>ODQ!rbTCIA+r*=6P7Bcs+z6Mdk;&@aOIf12 zIBQ7z;UbOvF4fqlZ4WH{1Bo9f4o8OlWtz3%`NSnYhiW#H;rvG-6B^>uCZGB9>dOV5 zwO8hE900Sk9WgCOn{P7`A)8Ad5j&2BHIVmYPRJj^$zX?T9qwN!(X){IMdToir! zy4r3bx8LJ8zw=jEdo^(vT-I#tn(Loctk;OgmTe!#&+*htdFo~1-Iw@2_;0Ft&c{9s zm1e}zc@~_RIQ(jmqq`jgXLYv<5*ao(@JX4*uCeghBuc0el%$zwxcd9t+?ITwfkgRG zm@0ld$Y%%{iJh#_J=2@Gx52Ooa4PTKJIF1gg*8q%cMO8(3H%6#tfc75v4($x#hfVhQyD-Z>Lmyf+u-o?|X{Q zZ3=FZtpq5Q`9jxAeRfzY9-x_$Db%q&Lnl;O83QLM@~c@^c=6o*5Xw4-+ITIhO5h)=3T*%iNmF=<=`BuR@9>$H;s_+vy1bRA8z^Sem{UzH2I z;7i9!0(KgQdy9G-DHr|y7wjwmr-;5XNGvL-0v-{NN#%jLjj>ldrX?d z@CNHq5Xft@zVZH3CjX0?Fx-J}D&y6-2R9b^s_{eT6l2KBSRA;@@8Ab8Gw8&=RA3C? z$SFj&@#C8)=EcfKBG|T`Z{f%(`DWfk2-HX5bt0qVDuCX@Y^GuIuda*riQxoAm)ZLi zY$jwC-uzM#5?YziD8|3(KS11?1gGzb$KcdX#_4?A$ zm+N?y*TU^81rYwnfx`C_E(qj~m&y{_<9#$txuiicm{HJUX+u(uA#u7zzT7@jtw+oviyEFK>pK>SX6= z>V`AqxSt48M4Kt12m|dSavYLpVDGxxI-XA0E47bX80qL#vTUePk&I5J$$HZ<;&t@9 zHgV!f%RZN&$1j6gM>B~@3AE}Tdg7MCJTFYxiSz3Qa<;G5e#>7DaB8OSg37j4(CMAd zkr7`qSSqZO-wc%=Qs!eV4Ch+pL*0;V6qGcD^>Qsr>1)P$?K?WhhHVW*5Ng%$YTvmg zG~$zFR1MW5_f3Vwj7%0!fKN%ae9!U4-^!#miA-aq)~igv@l2NNk0ozT$8c#@_Vk22 zvVe zI}pJVYf2Q86`$lHN>9jN#}}V!g~sgq2RO3%}Yb zR6xiM7SE+ss@Na3vw9>cip?q#1wLz|Yu1V0^XsSBw5|3TTEeadh+fiiO6!~ilVdJ( z_im@*gRKdZy5f57*iPXBT*FXUmd~MB>!_w&kOl)uMhsT-7g+enMsdM4QM0bN<5hGw z9cQnMy6Dbho;ia?+bL2{>9rQ4j-PX4WKi_Tfu9QcKIhpJwSKklX`>~ZU3)`i?x-{P z)i!SOV@q|&@w8pcCgH5+>@}b51}IEh&lSXSgFcrypj21X=qgKB7X6s=Tal)X@cT}a zJ~MDKLtRI{xF(^-5-xYvHCWk-EdjZHOxCkElcvEQ|5-<0l{2elIaQ)*-3VRp3Qbh0 z&N!4%Vg3eE%9HLaj{1aJ&S96S`y5~OOR!Tn3ts&9T|RRzVh((oT1<0U^n_L=)F5-J z)DHW|D%r(k^MzWE-v>)CnN`IfNUhpuet8deuIrb$r*0P=SoCkiZbMyRxZ#c zOH^SZYX@}DmZ{J;Pr_t99o*uZjQj)mZFAZPdhGEYkc=lhMB`WGh4%FqY5oB;IfcFK zk>G<>x4Ng*V?UxaLnP^&CGonR&A_3TD_J8q_zjp&ite)dZk*1}J-IhV{Dx)5DQAE_ zKikb=XWe9vs%LRRCoBGpSNjKNeyr7Nij*7l=7tU_h<2Ej#D^jUm&HV^Uunj@o`~PK zGfeBtg3pG2NHrZ9`d($I03mg-BVE#`^n`{;sr+~{VBO@8JJK;|VR}6Oq^%f1xR^HI zQl|Ofww&7@8GGANR_BECJ+hzzJKYguvi32jHZX~raTK#KPbotYFXliKakrm^nHGx3 zVY~3Yp5|;_36G^Lq5dH#FXw*O+J(QE=-p*{QbDC=YP(ilNA@fgMR)|Z=zUn;1tosp ze;r$lFsB6?1Di&xUq`QzI^K2&zDZv2As@S9U&YqUDKf^@`@Gy@&>uJc!IcEO!@{N& zPpROLaZ9?X!KjS5ZTyN=^LhWKuuz18+W^{dDv4EKQ6R6_;*wAL`!S+%*GE0@|J8&!VnuA zZz@b#yoqZ)HTwyCKi6!MFH^vcO8-%%!hU$iqcel5g`sS(TdMlUtAp`nc^Ae)Tul^+ z8Yd-vu1gc>*5%%8>V8EpKkA$R#=sX|bwxfU>(?|6EQ|A_@UkTlDHT(ld~|V~lyimA zSIkG=E5k?mKak!rb>7?BaGc`&f?koIT=r-V?>AWaRyIx6;*3NNiiBM3U6W6pAm!dk z&HT)lOPEh+@GFs00xZu>}bA zAXN|$1te4ry-SxCdJsYp6%mjY0!Rrc5PA^IQ7z{Eb{+am znQBZ+oJ0#%$o9=(!ujm9w@E$YLbHPq{x3O-iw;GzEf~IP5s1Y5BIZ#G{6_4pk#47z zf+wjNi<3N>WuqNoCtp4nk3>J2hsAG6?$u(m6XvTtW)LX%t(sKT30uf?s+a4L>dtA}sDV*iBjMGqcA79^xIjj z;#FTKdcDAHd^?3jKc;`oWtl{0le6%0A>h&@Qhb1rdgaPc^Qkup$xf$D3O%PS)Axkw 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 v Date: Mon, 31 Jul 2023 17:10:42 +0200 Subject: [PATCH 03/11] Update naming of cluster id & secret to the namespace id & secret. Add cluster name prefix. (#3) --- .header.md | 4 +-- README.md | 12 ++++--- .../templates/mendix-installer-configmap.yaml | 6 ++-- charts/mendix-installer/values.yaml | 4 +-- examples/basic/.header.md | 8 ++--- examples/basic/main.tf | 4 +-- examples/basic/variables.tf | 8 ++--- helm-values/mendix-installer-values.yaml.tpl | 4 +-- main.tf | 35 ++++++++++++------- modules/vpc/main.tf | 18 +++------- modules/vpc/outputs.tf | 5 --- modules/vpc/variables.tf | 5 +++ outputs.tf | 2 +- terraform.tfvars | 5 +-- test/examples_basic_test.go | 8 ++--- variables.tf | 19 +++++++--- 16 files changed, 81 insertions(+), 66 deletions(-) diff --git a/.header.md b/.header.md index 7b6479e..ad981ed 100644 --- a/.header.md +++ b/.header.md @@ -83,8 +83,8 @@ Before you can provision your Mendix environments on Amazon EKS, you must instal domain_name = "project-name-example.com" certificate_expiration_email = "example@example.com" s3_bucket_name = "project-name" - cluster_id = "" - cluster_secret = "" + namespace_id = "" + namespace_secret = "" environments_internal_names = ["app1", "app2", "app3"] ``` diff --git a/README.md b/README.md index ec38ddf..6d3f2bc 100644 --- a/README.md +++ b/README.md @@ -84,11 +84,10 @@ Before you can provision your Mendix environments on Amazon EKS, you must instal domain_name = "project-name-example.com" certificate_expiration_email = "example@example.com" s3_bucket_name = "project-name" - cluster_id = "" - cluster_secret = "" + namespace_id = "" + namespace_secret = "" environments_internal_names = ["app1", "app2", "app3"] ``` -**Important: Do not reuse the same S3 bucket created in Step 1 for the `s3_bucket_name` field. Terraform will create a new bucket with given name.** The number of applications deployed is handled by the `environments_internal_names` variable. Internal names are used during the environment creation, as shown here: @@ -246,6 +245,7 @@ After you deploy this Partner Solution, confirm that your resources and services | [aws](#provider\_aws) | >= 4.35 | | [helm](#provider\_helm) | >= 2.7.1 | | [kubernetes](#provider\_kubernetes) | >= 2.16.1 | +| [random](#provider\_random) | >= 3.4.3 | ## Modules @@ -270,6 +270,7 @@ After you deploy this Partner Solution, confirm that your resources and services | [aws_route53_zone.cluster_dns](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_zone) | resource | | [helm_release.mendix_installer](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | | [kubernetes_namespace.mendix](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource | +| [random_string.random-eks-suffix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_eks_cluster_auth.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/eks_cluster_auth) | data source | @@ -279,11 +280,12 @@ After you deploy this Partner Solution, confirm that your resources and services |------|-------------|------|---------|:--------:| | [aws\_region](#input\_aws\_region) | AWS Region name | `string` | n/a | yes | | [certificate\_expiration\_email](#input\_certificate\_expiration\_email) | Let's Encrypt certificate expiration email | `string` | n/a | yes | -| [cluster\_id](#input\_cluster\_id) | Mendix Private Cloud Cluster ID | `string` | n/a | yes | -| [cluster\_secret](#input\_cluster\_secret) | Mendix Private Cloud Cluster Secret | `string` | n/a | yes | | [domain\_name](#input\_domain\_name) | Domain name | `string` | n/a | yes | +| [namespace\_id](#input\_namespace\_id) | Mendix Private Cloud Namespace ID | `string` | n/a | yes | +| [namespace\_secret](#input\_namespace\_secret) | Mendix Private Cloud Namespace Secret | `string` | n/a | yes | | [s3\_bucket\_name](#input\_s3\_bucket\_name) | S3 bucket name | `string` | n/a | yes | | [allowed\_ips](#input\_allowed\_ips) | List of IP adresses allowed to access EKS cluster endpoint | `list(string)` |

[
"0.0.0.0/0"
]
| no | +| [eks\_cluster\_name\_prefix](#input\_eks\_cluster\_name\_prefix) | EKS name prefix for the new cluster | `string` | `"mendix-eks"` | no | | [eks\_node\_instance\_type](#input\_eks\_node\_instance\_type) | EKS instance type | `string` | `"t3.medium"` | no | | [environments\_internal\_names](#input\_environments\_internal\_names) | List of internal environments names | `list(string)` |
[
"app1"
]
| no | | [mendix\_operator\_version](#input\_mendix\_operator\_version) | Mendix Private Cloud Operator version | `string` | `"2.12.0"` | no | diff --git a/charts/mendix-installer/templates/mendix-installer-configmap.yaml b/charts/mendix-installer/templates/mendix-installer-configmap.yaml index 6d4ec74..b6c334f 100644 --- a/charts/mendix-installer/templates/mendix-installer-configmap.yaml +++ b/charts/mendix-installer/templates/mendix-installer-configmap.yaml @@ -9,15 +9,15 @@ data: wget https://cdn.mendix.com/mendix-for-private-cloud/mxpc-cli/mxpc-cli-{{ .Values.mendixOperatorVersion }}-linux-amd64.tar.gz tar xvf mxpc-cli-{{ .Values.mendixOperatorVersion }}-linux-amd64.tar.gz - ./mxpc-cli base-install --namespace mendix -i {{ .Values.clusterID }} -s {{ .Values.clusterSecret }} --clusterMode connected --clusterType generic --clusterTag="aws-reference-deployment" + ./mxpc-cli base-install --namespace mendix -i {{ .Values.namespaceID }} -s {{ .Values.namespaceSecret }} --clusterMode connected --clusterType generic --clusterTag="aws-reference-deployment" wget --output-document=custom.crt https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem kubectl -n mendix create secret generic mendix-custom-tls --from-file=custom.crt=custom.crt - ./mxpc-cli apply-config -i {{ .Values.clusterID }} -s {{ .Values.clusterSecret }} --file mendix-installer-config-file/mendix-installer-config-file + ./mxpc-cli apply-config -i {{ .Values.namespaceID }} -s {{ .Values.namespaceSecret }} --file mendix-installer-config-file/mendix-installer-config-file {{- range $.Values.database_plans }} - ./mxpc-cli apply-config -i {{ $.Values.clusterID }} -s {{ $.Values.clusterSecret }} --file mendix-installer-config-db-{{ .name }}/mendix-installer-config-file + ./mxpc-cli apply-config -i {{ $.Values.namespaceID }} -s {{ $.Values.namespaceSecret }} --file mendix-installer-config-db-{{ .name }}/mendix-installer-config-file export PGUSER={{ .user }} export PGHOST={{ .host }} diff --git a/charts/mendix-installer/values.yaml b/charts/mendix-installer/values.yaml index cffcb9b..1704c1d 100644 --- a/charts/mendix-installer/values.yaml +++ b/charts/mendix-installer/values.yaml @@ -1,6 +1,6 @@ appName: "{{.Name}}" -clusterID: "" -clusterSecret: "" +namespaceID: "" +namespaceSecret: "" mendixOperatorVersion: "" awsRegion: "" certificateExpirationEmail: "" diff --git a/examples/basic/.header.md b/examples/basic/.header.md index 6cedaaa..420b05e 100644 --- a/examples/basic/.header.md +++ b/examples/basic/.header.md @@ -1,17 +1,17 @@ ## Provisionning -Retrieve the cluster_id and cluster_secret on https://privatecloud.mendixcloud.com +Retrieve the namespace_id and namespace_secret on https://privatecloud.mendixcloud.com ``` aws_region="" domain_name="" certificate_expiration_email="" s3_bucket_name="" -cluster_id="" -cluster_secret="" +namespace_id="" +namespace_secret="" environments_internal_names = ["", "", ""] terraform init -terraform apply -auto-approve -var cluster_id=${cluster_id} -var cluster_secret=${cluster_secret} -var mendix_operator_version=${mendix_operator_version} -var aws_region=${aws_region} -var domain_name=${domain_name} -var certificate_expiration_email=${certificate_expiration_email} -var s3_bucket_name=${s3_bucket_name} +terraform apply -auto-approve -var namespace_id=${namespace_id} -var namespace_secret=${namespace_secret} -var mendix_operator_version=${mendix_operator_version} -var aws_region=${aws_region} -var domain_name=${domain_name} -var certificate_expiration_email=${certificate_expiration_email} -var s3_bucket_name=${s3_bucket_name} ``` ## Clean up diff --git a/examples/basic/main.tf b/examples/basic/main.tf index fdb21c0..7fed2ba 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -5,8 +5,8 @@ module "mendix_private_cloud_example" { domain_name = var.domain_name certificate_expiration_email = var.certificate_expiration_email s3_bucket_name = var.s3_bucket_name - cluster_id = var.cluster_id - cluster_secret = var.cluster_secret + namespace_id = var.namespace_id + namespace_secret = var.namespace_secret mendix_operator_version = var.mendix_operator_version } diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index d8de4f3..5c2a115 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -13,14 +13,14 @@ variable "s3_bucket_name" { description = "S3 bucket name" } -variable "cluster_id" { +variable "namespace_id" { type = string - description = "Mendix Private Cloud Cluster ID" + description = "Mendix Private Cloud Namespace ID" } -variable "cluster_secret" { +variable "namespace_secret" { type = string - description = "Mendix Private Cloud Cluster Secret" + description = "Mendix Private Cloud Namespace Secret" } variable "mendix_operator_version" { diff --git a/helm-values/mendix-installer-values.yaml.tpl b/helm-values/mendix-installer-values.yaml.tpl index 64bcfbd..3335f81 100644 --- a/helm-values/mendix-installer-values.yaml.tpl +++ b/helm-values/mendix-installer-values.yaml.tpl @@ -1,5 +1,5 @@ -clusterID: "${cluster_id}" -clusterSecret: "${cluster_secret}" +namespaceID: "${namespace_id}" +namespaceSecret: "${namespace_secret}" mendixOperatorVersion: "${mendix_operator_version}" awsRegion: "${aws_region}" certificateExpirationEmail: "${certificate_expiration_email}" diff --git a/main.tf b/main.tf index 60327e0..e9c9760 100644 --- a/main.tf +++ b/main.tf @@ -1,10 +1,21 @@ +locals { + cluster_name = "${var.eks_cluster_name_prefix}-${random_string.random-eks-suffix.result}" +} + +resource "random_string" "random-eks-suffix" { + length = 3 + min_lower = 3 + special = false +} + data "aws_eks_cluster_auth" "this" { name = module.eks_blueprints.eks_cluster_id } module "vpc" { - source = "./modules/vpc" - region = var.aws_region + source = "./modules/vpc" + region = var.aws_region + cluster_name = local.cluster_name } resource "aws_route53_zone" "cluster_dns" { @@ -21,13 +32,13 @@ module "databases" { for_each = toset(var.environments_internal_names) source = "./modules/databases" - identifier = "${module.vpc.cluster_name}-database-${each.key}" + identifier = "${local.cluster_name}-database-${each.key}" subnets = module.vpc.vpc_private_subnets cluster_primary_security_group_id = module.eks_blueprints.cluster_primary_security_group_id } resource "aws_iam_policy" "environment-policy" { - name = "${module.vpc.cluster_name}-env-policy" + name = "${local.cluster_name}-env-policy" description = "Environment Template Policy" policy = templatefile("./templates/iam_environment_policy.tftpl", { @@ -39,7 +50,7 @@ resource "aws_iam_policy" "environment-policy" { } resource "aws_iam_policy" "provisioner-policy" { - name = "${module.vpc.cluster_name}-provisioner-policy" + name = "${local.cluster_name}-provisioner-policy" description = "Storage Provisioner admin Policy" policy = templatefile("./templates/iam_provisioner_policy.tftpl", { @@ -53,7 +64,7 @@ resource "aws_iam_policy" "provisioner-policy" { } resource "aws_iam_role" "storage-provisioner-role" { - name = "${module.vpc.cluster_name}-storage-provisioner-irsa" + name = "${local.cluster_name}-storage-provisioner-irsa" description = "Storage Provisioner admin Policy" assume_role_policy = jsonencode({ @@ -82,7 +93,7 @@ data "aws_caller_identity" "current" {} module "container_registry" { source = "./modules/container-registry" - registry_repository_name = "${module.vpc.cluster_name}-ecr" + registry_repository_name = "${local.cluster_name}-ecr" region = var.aws_region account_id = data.aws_caller_identity.current.account_id oidc_provider = module.eks_blueprints.oidc_provider @@ -117,7 +128,7 @@ module "eks_blueprints" { } # EKS CLUSTER - cluster_name = module.vpc.cluster_name + cluster_name = local.cluster_name cluster_version = "1.24" vpc_id = module.vpc.vpc_id private_subnet_ids = module.vpc.vpc_private_subnets @@ -194,7 +205,7 @@ module "monitoring" { source = "./modules/monitoring" aws_region = var.aws_region account_id = data.aws_caller_identity.current.account_id - cluster_name = module.vpc.cluster_name + cluster_name = local.cluster_name oidc_provider = module.eks_blueprints.oidc_provider domain_name = var.domain_name @@ -214,10 +225,10 @@ resource "helm_release" "mendix_installer" { values = [ templatefile("${path.module}/helm-values/mendix-installer-values.yaml.tpl", { - cluster_name = module.vpc.cluster_name, + cluster_name = local.cluster_name, account_id = data.aws_caller_identity.current.account_id, - cluster_id = var.cluster_id, - cluster_secret = sensitive(var.cluster_secret), + namespace_id = var.namespace_id, + namespace_secret = sensitive(var.namespace_secret), mendix_operator_version = var.mendix_operator_version, aws_region = module.vpc.region, certificate_expiration_email = var.certificate_expiration_email diff --git a/modules/vpc/main.tf b/modules/vpc/main.tf index a097e33..c43bdca 100644 --- a/modules/vpc/main.tf +++ b/modules/vpc/main.tf @@ -1,20 +1,10 @@ data "aws_availability_zones" "available" {} -locals { - cluster_name = "mendix-eks-${random_string.random.result}" -} - -resource "random_string" "random" { - length = 3 - min_lower = 3 - special = false -} - module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "4.0.1" - name = "${local.cluster_name}-vpc" + name = "${var.cluster_name}-vpc" cidr = "10.0.0.0/16" azs = data.aws_availability_zones.available.names private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] @@ -24,16 +14,16 @@ module "vpc" { enable_dns_hostnames = true tags = { - "kubernetes.io/cluster/${local.cluster_name}" = "shared" + "kubernetes.io/cluster/${var.cluster_name}" = "shared" } public_subnet_tags = { - "kubernetes.io/cluster/${local.cluster_name}" = "shared" + "kubernetes.io/cluster/${var.cluster_name}" = "shared" "kubernetes.io/role/elb" = "1" } private_subnet_tags = { - "kubernetes.io/cluster/${local.cluster_name}" = "shared" + "kubernetes.io/cluster/${var.cluster_name}" = "shared" "kubernetes.io/role/internal-elb" = "1" } } diff --git a/modules/vpc/outputs.tf b/modules/vpc/outputs.tf index 9edc176..a870c7c 100644 --- a/modules/vpc/outputs.tf +++ b/modules/vpc/outputs.tf @@ -4,11 +4,6 @@ output "region" { value = var.region } -output "cluster_name" { - description = "Kubernetes cluster name" - value = local.cluster_name -} - output "vpc_id" { description = "VPC ID" value = module.vpc.vpc_id diff --git a/modules/vpc/variables.tf b/modules/vpc/variables.tf index 4e80598..4b91e9b 100644 --- a/modules/vpc/variables.tf +++ b/modules/vpc/variables.tf @@ -1,4 +1,9 @@ variable "region" { type = string description = "AWS Region name" +} + +variable "cluster_name" { + type = string + description = "EKS cluster name" } \ No newline at end of file diff --git a/outputs.tf b/outputs.tf index bc53bdb..d4822a8 100644 --- a/outputs.tf +++ b/outputs.tf @@ -8,7 +8,7 @@ output "region" { # Kubernetes cluster output "cluster_name" { description = "Kubernetes cluster name" - value = module.vpc.cluster_name + value = local.cluster_name } output "vpc_private_subnets" { diff --git a/terraform.tfvars b/terraform.tfvars index 13c4596..83be3e8 100644 --- a/terraform.tfvars +++ b/terraform.tfvars @@ -1,7 +1,8 @@ aws_region = "" domain_name = "" +eks_cluster_name_prefix = "mx-private-cloud" certificate_expiration_email = "" s3_bucket_name = "" -cluster_id = "" -cluster_secret = "" +namespace_id = "" +namespace_secret = "" environments_internal_names = ["", "", ""] \ No newline at end of file diff --git a/test/examples_basic_test.go b/test/examples_basic_test.go index 3c12c27..4686a44 100644 --- a/test/examples_basic_test.go +++ b/test/examples_basic_test.go @@ -26,8 +26,8 @@ func TestExamplesBasicTest(t *testing.T) { "domain_name": uniqueId + "domain.com", "certificate_expiration_email": uniqueId + "@test.com", "s3_bucket_name": uniqueId + "-s3-bucket", - "cluster_id": uniqueId + "-7824-4e08-97fd-9b5d1792a027", - "cluster_secret": uniqueId + "UdfdTK7P0FD5", + "namespace_id": uniqueId + "-7824-4e08-97fd-9b5d1792a027", + "namespace_secret": uniqueId + "UdfdTK7P0FD5", "mendix_operator_version": "2.10.0", }, BackendConfig: map[string]interface{}{ @@ -56,8 +56,8 @@ func TestExamplesBasicTest(t *testing.T) { "domain_name": uniqueId + "domain.com", "certificate_expiration_email": uniqueId + "@test.com", "s3_bucket_name": uniqueId + "-s3-bucket", - "cluster_id": uniqueId + "-7824-4e08-97fd-9b5d1792a027", - "cluster_secret": uniqueId + "UdfdTK7P0FD5", + "namespace_id": uniqueId + "-7824-4e08-97fd-9b5d1792a027", + "namespace_secret": uniqueId + "UdfdTK7P0FD5", "mendix_operator_version": "2.10.0", }, BackendConfig: map[string]interface{}{ diff --git a/variables.tf b/variables.tf index 9046e67..c37559e 100644 --- a/variables.tf +++ b/variables.tf @@ -13,9 +13,14 @@ variable "s3_bucket_name" { description = "S3 bucket name" } -variable "cluster_id" { +variable "namespace_id" { type = string - description = "Mendix Private Cloud Cluster ID" + description = "Mendix Private Cloud Namespace ID" +} + +variable "namespace_secret" { + type = string + description = "Mendix Private Cloud Namespace Secret" } variable "eks_node_instance_type" { @@ -24,9 +29,15 @@ variable "eks_node_instance_type" { default = "t3.medium" } -variable "cluster_secret" { +variable "eks_cluster_name_prefix" { type = string - description = "Mendix Private Cloud Cluster Secret" + description = "EKS name prefix for the new cluster" + default = "mendix-eks" + + validation { + condition = length(var.eks_cluster_name_prefix) < 65 && can(regex("^[0-9A-Za-z][A-Za-z0-9\\-_]*", var.eks_cluster_name_prefix)) + error_message = "EKS name prefix max length is 65 and it should have the next patter: ^[0-9A-Za-z][A-Za-z0-9\\-_]*" + } } variable "mendix_operator_version" { From 4e76a8b25db635b65891503ea1b27d27212514bf Mon Sep 17 00:00:00 2001 From: Anton Popovichenko Date: Thu, 3 Aug 2023 09:25:36 +0200 Subject: [PATCH 04/11] Trying to fix terraform init command. --- main.tf | 4 ++-- providers.tf | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/main.tf b/main.tf index e9c9760..8842fa5 100644 --- a/main.tf +++ b/main.tf @@ -106,7 +106,7 @@ resource "aws_ebs_encryption_by_default" "ebs_encryption" { } module "eks_blueprints" { - source = "github.com/aws-ia/terraform-aws-eks-blueprints?ref=v4.28.0" + source = "github.com/aws-ia/terraform-aws-eks-blueprints?ref=v4.32.1" node_security_group_additional_rules = { cluster_to_nginx_webhook = { @@ -150,7 +150,7 @@ module "eks_blueprints" { } module "eks_blueprints_kubernetes_addons" { - source = "github.com/aws-ia/terraform-aws-eks-blueprints//modules/kubernetes-addons?ref=v4.28.0" + source = "github.com/aws-ia/terraform-aws-eks-blueprints//modules/kubernetes-addons?ref=v4.32.1" eks_cluster_id = module.eks_blueprints.eks_cluster_id eks_cluster_endpoint = module.eks_blueprints.eks_cluster_endpoint diff --git a/providers.tf b/providers.tf index ca18ee8..b67905b 100644 --- a/providers.tf +++ b/providers.tf @@ -13,7 +13,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.35" + version = ">= 5.10" } kubernetes = { source = "hashicorp/kubernetes" From 2a485ea36d012083dbf1276dd9766ee3f52e8531 Mon Sep 17 00:00:00 2001 From: Anton Popovichenko Date: Thu, 3 Aug 2023 15:33:02 +0200 Subject: [PATCH 05/11] Specify Postgres version. --- main.tf | 1 + modules/databases/main.tf | 1 + modules/databases/variables.tf | 5 +++++ variables.tf | 6 ++++++ 4 files changed, 13 insertions(+) diff --git a/main.tf b/main.tf index 8842fa5..4b17b05 100644 --- a/main.tf +++ b/main.tf @@ -34,6 +34,7 @@ module "databases" { source = "./modules/databases" identifier = "${local.cluster_name}-database-${each.key}" subnets = module.vpc.vpc_private_subnets + postgres_version = var.postgres_version cluster_primary_security_group_id = module.eks_blueprints.cluster_primary_security_group_id } diff --git a/modules/databases/main.tf b/modules/databases/main.tf index 4787aa1..965e856 100644 --- a/modules/databases/main.tf +++ b/modules/databases/main.tf @@ -22,6 +22,7 @@ resource "aws_db_instance" "default" { identifier = var.identifier db_name = "postgres" engine = local.database_engine + engine_version = var.postgres_version instance_class = var.rds_instance_class port = local.database_port username = local.database_username diff --git a/modules/databases/variables.tf b/modules/databases/variables.tf index 87bc59f..fbac3ef 100644 --- a/modules/databases/variables.tf +++ b/modules/databases/variables.tf @@ -18,3 +18,8 @@ variable "rds_instance_class" { default = "db.t3.small" type = string } + +variable "postgres_version" { + type = string + description = "The version of Postgres that terraform would create." +} \ No newline at end of file diff --git a/variables.tf b/variables.tf index c37559e..0184cba 100644 --- a/variables.tf +++ b/variables.tf @@ -66,4 +66,10 @@ variable "environments_internal_names" { condition = alltrue([for app in var.environments_internal_names : can(regex("^[a-z0-9]{1,8}$", app))]) error_message = "Use only lowercase letters and numbers, with a maximum of 8 characters and a minimum of 1 character." } +} + +variable "postgres_version" { + type = string + description = "The version of Postgres that terraform would create." + default = "14.8" } \ No newline at end of file From 495a11e989a022a4ae82ccb01d7a816f48f385c8 Mon Sep 17 00:00:00 2001 From: Anton Popovichenko Date: Fri, 4 Aug 2023 13:46:05 +0200 Subject: [PATCH 06/11] Remove Secret Store section from readme. --- .header.md | 9 ++++----- README.md | 18 +++++++++--------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/.header.md b/.header.md index ad981ed..21dba43 100644 --- a/.header.md +++ b/.header.md @@ -117,11 +117,7 @@ The internal name must match the name that you specify in the `environments_inte 4. Depending on your provider, update **External Domain Name Registrar** or **Route53 registered domain** with the *aws_route53_zone_name_servers* values. For more information, refer to [Configuring Amazon Route 53 as your DNS service](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-configuring.html). -5. In the developer portal, choose **Cluster Manager**, then choose the **Customization** tab. Enable **External Secrets Store**. - -![Customization tab](https://raw.githubusercontent.com/aws-ia/terraform-aws-mendix-private-cloud/main/doc/deployment_guide/images/secrets-store.png) - -6. If you're deploying more than three apps, change the default instance type of the `eks_node_instance_type` variable. By default, the instance type for the Kubernetes nodes is optimized to support up to three apps. Deploying more than three apps with the default instance type may affect the performance of your applications. For more information, refer to [Choosing an Amazon EC2 instance type](https://docs.aws.amazon.com/eks/latest/userguide/choosing-instance-type.html) in the Amazon EKS User Guide. +5. If you're deploying more than three apps, change the default instance type of the `eks_node_instance_type` variable. By default, the instance type for the Kubernetes nodes is optimized to support up to three apps. Deploying more than three apps with the default instance type may affect the performance of your applications. For more information, refer to [Choosing an Amazon EC2 instance type](https://docs.aws.amazon.com/eks/latest/userguide/choosing-instance-type.html) in the Amazon EKS User Guide. ## Security @@ -206,6 +202,9 @@ In the Mendix Private Cloud portal, in the Cluster Manager, the status of your c ## Cleanup +Before cleaning up, make sure that you have deleted Mendix App environments. +Otherwise, you will need to manually remove some finalizers in the namespace and detach some roles from policies in AWS IAM. + To clean up your environment, run the following commands: ``` diff --git a/README.md b/README.md index 6d3f2bc..e4e5be9 100644 --- a/README.md +++ b/README.md @@ -118,11 +118,7 @@ The internal name must match the name that you specify in the `environments_inte 4. Depending on your provider, update **External Domain Name Registrar** or **Route53 registered domain** with the *aws\_route53\_zone\_name\_servers* values. For more information, refer to [Configuring Amazon Route 53 as your DNS service](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-configuring.html). -5. In the developer portal, choose **Cluster Manager**, then choose the **Customization** tab. Enable **External Secrets Store**. - -![Customization tab](https://raw.githubusercontent.com/aws-ia/terraform-aws-mendix-private-cloud/main/doc/deployment_guide/images/secrets-store.png) - -6. If you're deploying more than three apps, change the default instance type of the `eks_node_instance_type` variable. By default, the instance type for the Kubernetes nodes is optimized to support up to three apps. Deploying more than three apps with the default instance type may affect the performance of your applications. For more information, refer to [Choosing an Amazon EC2 instance type](https://docs.aws.amazon.com/eks/latest/userguide/choosing-instance-type.html) in the Amazon EKS User Guide. +5. If you're deploying more than three apps, change the default instance type of the `eks_node_instance_type` variable. By default, the instance type for the Kubernetes nodes is optimized to support up to three apps. Deploying more than three apps with the default instance type may affect the performance of your applications. For more information, refer to [Choosing an Amazon EC2 instance type](https://docs.aws.amazon.com/eks/latest/userguide/choosing-instance-type.html) in the Amazon EKS User Guide. ## Security @@ -207,6 +203,9 @@ In the Mendix Private Cloud portal, in the Cluster Manager, the status of your c ## Cleanup +Before cleaning up, make sure that you have deleted Mendix App environments. +Otherwise, you will need to manually remove some finalizers in the namespace and detach some roles from policies in AWS IAM. + To clean up your environment, run the following commands: ``` @@ -231,7 +230,7 @@ After you deploy this Partner Solution, confirm that your resources and services | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 0.14 | -| [aws](#requirement\_aws) | >= 4.35 | +| [aws](#requirement\_aws) | >= 5.10 | | [helm](#requirement\_helm) | >= 2.7.1 | | [kubectl](#requirement\_kubectl) | >= 1.14 | | [kubernetes](#requirement\_kubernetes) | >= 2.16.1 | @@ -242,7 +241,7 @@ After you deploy this Partner Solution, confirm that your resources and services | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.35 | +| [aws](#provider\_aws) | >= 5.10 | | [helm](#provider\_helm) | >= 2.7.1 | | [kubernetes](#provider\_kubernetes) | >= 2.16.1 | | [random](#provider\_random) | >= 3.4.3 | @@ -253,8 +252,8 @@ After you deploy this Partner Solution, confirm that your resources and services |------|--------|---------| | [container\_registry](#module\_container\_registry) | ./modules/container-registry | n/a | | [databases](#module\_databases) | ./modules/databases | n/a | -| [eks\_blueprints](#module\_eks\_blueprints) | github.com/aws-ia/terraform-aws-eks-blueprints | v4.28.0 | -| [eks\_blueprints\_kubernetes\_addons](#module\_eks\_blueprints\_kubernetes\_addons) | github.com/aws-ia/terraform-aws-eks-blueprints//modules/kubernetes-addons | v4.28.0 | +| [eks\_blueprints](#module\_eks\_blueprints) | github.com/aws-ia/terraform-aws-eks-blueprints | v4.32.1 | +| [eks\_blueprints\_kubernetes\_addons](#module\_eks\_blueprints\_kubernetes\_addons) | github.com/aws-ia/terraform-aws-eks-blueprints//modules/kubernetes-addons | v4.32.1 | | [file\_storage](#module\_file\_storage) | ./modules/file-storage | n/a | | [monitoring](#module\_monitoring) | ./modules/monitoring | n/a | | [vpc](#module\_vpc) | ./modules/vpc | n/a | @@ -289,6 +288,7 @@ After you deploy this Partner Solution, confirm that your resources and services | [eks\_node\_instance\_type](#input\_eks\_node\_instance\_type) | EKS instance type | `string` | `"t3.medium"` | no | | [environments\_internal\_names](#input\_environments\_internal\_names) | List of internal environments names | `list(string)` |
[
"app1"
]
| no | | [mendix\_operator\_version](#input\_mendix\_operator\_version) | Mendix Private Cloud Operator version | `string` | `"2.12.0"` | no | +| [postgres\_version](#input\_postgres\_version) | The version of Postgres that terraform would create. | `string` | `"14.8"` | no | ## Outputs From cd08d0a399e15e7350b4c467c718d12edef1817e Mon Sep 17 00:00:00 2001 From: Anton Popovichenko Date: Fri, 4 Aug 2023 14:39:17 +0200 Subject: [PATCH 07/11] Use snake case naming convention. --- main.tf | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/main.tf b/main.tf index 4b17b05..20a21ed 100644 --- a/main.tf +++ b/main.tf @@ -1,8 +1,8 @@ locals { - cluster_name = "${var.eks_cluster_name_prefix}-${random_string.random-eks-suffix.result}" + cluster_name = "${var.eks_cluster_name_prefix}-${random_string.random_eks_suffix.result}" } -resource "random_string" "random-eks-suffix" { +resource "random_string" "random_eks_suffix" { length = 3 min_lower = 3 special = false @@ -38,7 +38,7 @@ module "databases" { cluster_primary_security_group_id = module.eks_blueprints.cluster_primary_security_group_id } -resource "aws_iam_policy" "environment-policy" { +resource "aws_iam_policy" "environment_policy" { name = "${local.cluster_name}-env-policy" description = "Environment Template Policy" @@ -50,7 +50,7 @@ resource "aws_iam_policy" "environment-policy" { }) } -resource "aws_iam_policy" "provisioner-policy" { +resource "aws_iam_policy" "provisioner_policy" { name = "${local.cluster_name}-provisioner-policy" description = "Storage Provisioner admin Policy" @@ -60,11 +60,11 @@ resource "aws_iam_policy" "provisioner-policy" { db_instance_resource_ids = [for value in values(module.databases) : tostring(value.database_resource_id[0])] db_instance_usernames = [for value in values(module.databases) : tostring(value.database_username[0])] filestorage_shared_bucket_name = var.s3_bucket_name - environment_policy_arn = aws_iam_policy.environment-policy.arn + environment_policy_arn = aws_iam_policy.environment_policy.arn }) } -resource "aws_iam_role" "storage-provisioner-role" { +resource "aws_iam_role" "storage_provisioner_role" { name = "${local.cluster_name}-storage-provisioner-irsa" description = "Storage Provisioner admin Policy" @@ -87,7 +87,7 @@ resource "aws_iam_role" "storage-provisioner-role" { ] }) - managed_policy_arns = [aws_iam_policy.provisioner-policy.arn] + managed_policy_arns = [aws_iam_policy.provisioner_policy.arn] } data "aws_caller_identity" "current" {} @@ -234,8 +234,8 @@ resource "helm_release" "mendix_installer" { aws_region = module.vpc.region, certificate_expiration_email = var.certificate_expiration_email s3_bucket_name = var.s3_bucket_name - environment_iam_template_policy = aws_iam_policy.environment-policy.arn - storage_provisioner_iam_admin_role = aws_iam_role.storage-provisioner-role.arn + environment_iam_template_policy = aws_iam_policy.environment_policy.arn + storage_provisioner_iam_admin_role = aws_iam_role.storage_provisioner_role.arn oidc_url = "https://${module.eks_blueprints.oidc_provider}" database_server_addresses = [for value in values(module.databases) : tostring(value.database_server_address[0])] database_ports = [for value in values(module.databases) : tostring(value.database_port[0])] From 79ca8df4fff1ba0975797e6b469a5f8634cdc338 Mon Sep 17 00:00:00 2001 From: Anton Popovichenko Date: Fri, 4 Aug 2023 15:53:08 +0200 Subject: [PATCH 08/11] Try to fix linter by changing files extension names. --- main.tf | 4 ++-- ...vironment_policy.tftpl => iam_environment_policy.json.tpl} | 0 ...ovisioner_policy.tftpl => iam_provisioner_policy.json.tpl} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename templates/{iam_environment_policy.tftpl => iam_environment_policy.json.tpl} (100%) rename templates/{iam_provisioner_policy.tftpl => iam_provisioner_policy.json.tpl} (100%) diff --git a/main.tf b/main.tf index 20a21ed..ae1bd16 100644 --- a/main.tf +++ b/main.tf @@ -42,7 +42,7 @@ resource "aws_iam_policy" "environment_policy" { name = "${local.cluster_name}-env-policy" description = "Environment Template Policy" - policy = templatefile("./templates/iam_environment_policy.tftpl", { + policy = templatefile("./templates/iam_environment_policy.json.tpl", { aws_region = var.aws_region aws_account_id = data.aws_caller_identity.current.account_id db_instance_resource_ids = [for value in values(module.databases) : tostring(value.database_resource_id[0])] @@ -54,7 +54,7 @@ resource "aws_iam_policy" "provisioner_policy" { name = "${local.cluster_name}-provisioner-policy" description = "Storage Provisioner admin Policy" - policy = templatefile("./templates/iam_provisioner_policy.tftpl", { + policy = templatefile("./templates/iam_provisioner_policy.json.tpl", { aws_region = var.aws_region aws_account_id = data.aws_caller_identity.current.account_id db_instance_resource_ids = [for value in values(module.databases) : tostring(value.database_resource_id[0])] diff --git a/templates/iam_environment_policy.tftpl b/templates/iam_environment_policy.json.tpl similarity index 100% rename from templates/iam_environment_policy.tftpl rename to templates/iam_environment_policy.json.tpl diff --git a/templates/iam_provisioner_policy.tftpl b/templates/iam_provisioner_policy.json.tpl similarity index 100% rename from templates/iam_provisioner_policy.tftpl rename to templates/iam_provisioner_policy.json.tpl From ada776fe68f9fd1e070d02da5789c57240c377c6 Mon Sep 17 00:00:00 2001 From: Anton Popovichenko Date: Fri, 4 Aug 2023 16:21:40 +0200 Subject: [PATCH 09/11] Rename templates directory to avoid cfn-lint triggering. --- {templates => iam-templates}/iam_environment_policy.json.tpl | 0 {templates => iam-templates}/iam_provisioner_policy.json.tpl | 0 main.tf | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename {templates => iam-templates}/iam_environment_policy.json.tpl (100%) rename {templates => iam-templates}/iam_provisioner_policy.json.tpl (100%) diff --git a/templates/iam_environment_policy.json.tpl b/iam-templates/iam_environment_policy.json.tpl similarity index 100% rename from templates/iam_environment_policy.json.tpl rename to iam-templates/iam_environment_policy.json.tpl diff --git a/templates/iam_provisioner_policy.json.tpl b/iam-templates/iam_provisioner_policy.json.tpl similarity index 100% rename from templates/iam_provisioner_policy.json.tpl rename to iam-templates/iam_provisioner_policy.json.tpl diff --git a/main.tf b/main.tf index ae1bd16..1e44f84 100644 --- a/main.tf +++ b/main.tf @@ -42,7 +42,7 @@ resource "aws_iam_policy" "environment_policy" { name = "${local.cluster_name}-env-policy" description = "Environment Template Policy" - policy = templatefile("./templates/iam_environment_policy.json.tpl", { + policy = templatefile("./iam-templates/iam_environment_policy.json.tpl", { aws_region = var.aws_region aws_account_id = data.aws_caller_identity.current.account_id db_instance_resource_ids = [for value in values(module.databases) : tostring(value.database_resource_id[0])] @@ -54,7 +54,7 @@ resource "aws_iam_policy" "provisioner_policy" { name = "${local.cluster_name}-provisioner-policy" description = "Storage Provisioner admin Policy" - policy = templatefile("./templates/iam_provisioner_policy.json.tpl", { + policy = templatefile("./iam-templates/iam_provisioner_policy.json.tpl", { aws_region = var.aws_region aws_account_id = data.aws_caller_identity.current.account_id db_instance_resource_ids = [for value in values(module.databases) : tostring(value.database_resource_id[0])] From a0bab6fca05827f7e86aa6ce4258e4726d84f5dc Mon Sep 17 00:00:00 2001 From: Anton Popovichenko Date: Fri, 4 Aug 2023 16:29:38 +0200 Subject: [PATCH 10/11] Update README after linter fixes. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e4e5be9..f609f4f 100644 --- a/README.md +++ b/README.md @@ -263,13 +263,13 @@ After you deploy this Partner Solution, confirm that your resources and services | Name | Type | |------|------| | [aws_ebs_encryption_by_default.ebs_encryption](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ebs_encryption_by_default) | resource | -| [aws_iam_policy.environment-policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | -| [aws_iam_policy.provisioner-policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | -| [aws_iam_role.storage-provisioner-role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_policy.environment_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.provisioner_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_role.storage_provisioner_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_route53_zone.cluster_dns](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_zone) | resource | | [helm_release.mendix_installer](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | | [kubernetes_namespace.mendix](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource | -| [random_string.random-eks-suffix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource | +| [random_string.random_eks_suffix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_eks_cluster_auth.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/eks_cluster_auth) | data source | From 00dc97dd206d009467745b194dc4aef3a20a2775 Mon Sep 17 00:00:00 2001 From: Anton Popovichenko Date: Fri, 4 Aug 2023 16:41:09 +0200 Subject: [PATCH 11/11] Fix formatting --- modules/vpc/main.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/vpc/main.tf b/modules/vpc/main.tf index c43bdca..b13552a 100644 --- a/modules/vpc/main.tf +++ b/modules/vpc/main.tf @@ -19,11 +19,11 @@ module "vpc" { public_subnet_tags = { "kubernetes.io/cluster/${var.cluster_name}" = "shared" - "kubernetes.io/role/elb" = "1" + "kubernetes.io/role/elb" = "1" } private_subnet_tags = { "kubernetes.io/cluster/${var.cluster_name}" = "shared" - "kubernetes.io/role/internal-elb" = "1" + "kubernetes.io/role/internal-elb" = "1" } }