From d71b9723395a2e71daf6a0c08da9a49e8c39c1ef Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 12 Jun 2023 16:19:01 +0000 Subject: [PATCH] Charts CI ``` Updated: bitnami/mysql: - 9.10.4 bitnami/postgresql: - 12.5.7 datadog/datadog: - 3.32.1 gluu/gluu: - 5.0.18 jenkins/jenkins: - 4.3.27 prophetstor/federatorai: - 5.1.2 speedscale/speedscale-operator: - 1.3.12 ``` --- assets/bitnami/mysql-9.10.4.tgz | Bin 0 -> 44059 bytes assets/bitnami/postgresql-12.5.7.tgz | Bin 0 -> 56426 bytes assets/datadog/datadog-3.32.1.tgz | Bin 0 -> 135095 bytes assets/gluu/gluu-5.0.18.tgz | Bin 0 -> 109182 bytes assets/jenkins/jenkins-4.3.27.tgz | Bin 0 -> 72750 bytes assets/prophetstor/federatorai-5.1.2.tgz | Bin 0 -> 68290 bytes .../speedscale/speedscale-operator-1.3.12.tgz | Bin 0 -> 14673 bytes charts/bitnami/mysql/Chart.yaml | 2 +- charts/bitnami/mysql/values.yaml | 2 - charts/bitnami/postgresql/Chart.yaml | 2 +- charts/bitnami/postgresql/README.md | 2 +- .../bitnami/postgresql/templates/_helpers.tpl | 2 +- .../templates/primary/statefulset.yaml | 6 + charts/datadog/datadog/CHANGELOG.md | 4 + charts/datadog/datadog/Chart.yaml | 2 +- charts/datadog/datadog/README.md | 4 +- charts/datadog/datadog/values.yaml | 2 +- charts/gluu/gluu/Chart.yaml | 48 +- charts/gluu/gluu/README.md | 66 +- charts/gluu/gluu/charts/admin-ui/Chart.yaml | 2 +- charts/gluu/gluu/charts/admin-ui/README.md | 4 +- charts/gluu/gluu/charts/admin-ui/values.yaml | 2 +- .../auth-server-key-rotation/Chart.yaml | 2 +- .../charts/auth-server-key-rotation/README.md | 4 +- .../auth-server-key-rotation/values.yaml | 2 +- .../gluu/gluu/charts/auth-server/Chart.yaml | 2 +- charts/gluu/gluu/charts/auth-server/README.md | 4 +- .../gluu/gluu/charts/auth-server/values.yaml | 2 +- charts/gluu/gluu/charts/casa/Chart.yaml | 2 +- charts/gluu/gluu/charts/casa/README.md | 2 +- .../gluu/charts/cn-istio-ingress/Chart.yaml | 2 +- .../gluu/charts/cn-istio-ingress/README.md | 2 +- charts/gluu/gluu/charts/config-api/Chart.yaml | 2 +- charts/gluu/gluu/charts/config-api/README.md | 4 +- .../gluu/gluu/charts/config-api/values.yaml | 2 +- charts/gluu/gluu/charts/config/Chart.yaml | 2 +- charts/gluu/gluu/charts/config/README.md | 4 +- charts/gluu/gluu/charts/config/values.yaml | 2 +- charts/gluu/gluu/charts/fido2/Chart.yaml | 2 +- charts/gluu/gluu/charts/fido2/README.md | 4 +- charts/gluu/gluu/charts/fido2/values.yaml | 2 +- .../gluu/gluu/charts/nginx-ingress/Chart.yaml | 2 +- .../gluu/gluu/charts/nginx-ingress/README.md | 2 +- charts/gluu/gluu/charts/opendj/Chart.yaml | 2 +- charts/gluu/gluu/charts/opendj/README.md | 2 +- charts/gluu/gluu/charts/oxpassport/Chart.yaml | 2 +- charts/gluu/gluu/charts/oxpassport/README.md | 2 +- .../gluu/gluu/charts/oxshibboleth/Chart.yaml | 2 +- .../gluu/gluu/charts/oxshibboleth/README.md | 2 +- .../gluu/gluu/charts/persistence/Chart.yaml | 2 +- charts/gluu/gluu/charts/persistence/README.md | 4 +- .../gluu/gluu/charts/persistence/values.yaml | 2 +- charts/gluu/gluu/charts/scim/Chart.yaml | 2 +- charts/gluu/gluu/charts/scim/README.md | 4 +- charts/gluu/gluu/charts/scim/values.yaml | 2 +- charts/gluu/gluu/openbanking-values.yaml | 8 +- charts/gluu/gluu/values.yaml | 18 +- charts/jenkins/jenkins/CHANGELOG.md | 17 + charts/jenkins/jenkins/Chart.yaml | 6 +- charts/jenkins/jenkins/README.md | 4 +- charts/jenkins/jenkins/VALUES_SUMMARY.md | 26 +- charts/jenkins/jenkins/values.yaml | 10 +- charts/prophetstor/federatorai/.helmignore | 24 + charts/prophetstor/federatorai/Chart.yaml | 4 +- charts/prophetstor/federatorai/README.md | 17 +- .../federatorai/crds/crd-alamedaservice.yaml | 536 +++ charts/prophetstor/federatorai/questions.yaml | 6 +- .../clusterrolebindings.yaml | 16 - .../alameda-ai-dispatcher/clusterroles.yaml | 21 - .../alameda-ai-dispatcher/configmaps.yaml | 11 +- .../alameda-ai-dispatcher/deployments.yaml | 173 +- .../alameda-ai-dispatcher/pvc-log.yaml | 16 +- .../serviceaccounts.yaml | 11 +- .../alameda-ai-dispatcher/services.yaml | 19 +- .../alameda-ai/clusterrolebindings.yaml | 16 - .../templates/alameda-ai/clusterroles.yaml | 21 - .../templates/alameda-ai/configmaps.yaml | 11 +- .../templates/alameda-ai/deployments.yaml | 196 +- .../templates/alameda-ai/pvc-data.yaml | 16 +- .../templates/alameda-ai/pvc-log.yaml | 16 +- .../templates/alameda-ai/serviceaccounts.yaml | 11 +- .../templates/alameda-ai/services.yaml | 19 +- .../alameda-datahub/clusterrolebindings.yaml | 16 - .../alameda-datahub/clusterroles.yaml | 44 - .../alameda-datahub/deployments.yaml | 169 +- .../templates/alameda-datahub/pvc-log.yaml | 16 +- .../alameda-datahub/rolebindings.yaml | 17 +- .../templates/alameda-datahub/roles.yaml | 52 +- .../alameda-datahub/serviceaccounts.yaml | 11 +- .../templates/alameda-datahub/services.yaml | 19 +- .../alameda-executor/clusterrolebindings.yaml | 19 +- .../alameda-executor/clusterroles.yaml | 139 +- .../alameda-executor/configmaps.yaml | 13 +- .../alameda-executor/deployments.yaml | 159 +- .../templates/alameda-executor/pvc-log.yaml | 18 +- .../alameda-executor/serviceaccounts.yaml | 13 +- .../alameda-influxdb/clusterrolebindings.yaml | 16 - .../alameda-influxdb/clusterroles.yaml | 21 - .../templates/alameda-influxdb/pvc-data.yaml | 16 +- .../templates/alameda-influxdb/pvc-log.yaml | 16 +- .../alameda-influxdb/serviceaccounts.yaml | 11 +- .../templates/alameda-influxdb/services.yaml | 17 +- .../alameda-influxdb/statefulsets.yaml | 175 +- .../alameda-notifier/clusterrolebindings.yaml | 16 - .../alameda-notifier/clusterroles.yaml | 37 - .../alameda-notifier/deployments.yaml | 149 +- .../templates/alameda-notifier/pvc-log.yaml | 16 +- .../alameda-notifier/serviceaccounts.yaml | 11 +- .../alameda-rabbitmq/clusterrolebindings.yaml | 16 - .../alameda-rabbitmq/clusterroles.yaml | 28 - .../alameda-rabbitmq/configmaps.yaml | 11 +- .../alameda-rabbitmq/deployments.yaml | 169 +- .../alameda-rabbitmq/serviceaccounts.yaml | 11 +- .../templates/alameda-rabbitmq/services.yaml | 27 +- .../fedemeter-api/clusterrolebindings.yaml | 16 - .../templates/fedemeter-api/clusterroles.yaml | 21 - .../templates/fedemeter-api/configmaps.yaml | 11 +- .../templates/fedemeter-api/deployments.yaml | 173 +- .../templates/fedemeter-api/pvc-log.yaml | 16 +- .../fedemeter-api/serviceaccounts-api.yaml | 11 +- .../fedemeter-api/serviceaccounts-sa.yaml | 11 +- .../templates/fedemeter-api/services.yaml | 19 +- .../clusterrolebindings.yaml | 16 - .../fedemeter-influxdb/clusterroles.yaml | 21 - .../fedemeter-influxdb/pvc-data.yaml | 16 +- .../templates/fedemeter-influxdb/pvc-log.yaml | 16 +- .../fedemeter-influxdb/serviceaccounts.yaml | 11 +- .../fedemeter-influxdb/services.yaml | 27 +- .../fedemeter-influxdb/statefulsets.yaml | 123 +- .../configmaps.yaml | 60 + .../deployments.yaml | 100 + .../federatorai-agent-preloader/pvc-log.yaml | 29 + .../serviceaccounts.yaml | 18 + .../clusterrolebindings.yaml | 16 - .../federatorai-agent/clusterroles.yaml | 21 - .../federatorai-agent/configmaps.yaml | 292 +- .../federatorai-agent/deployments.yaml | 191 +- .../templates/federatorai-agent/pvc-log.yaml | 16 +- .../federatorai-agent/serviceaccounts.yaml | 11 +- .../clusterrolebindings.yaml | 16 - .../clusterroles.yaml | 21 - .../deployments.yaml | 101 +- .../federatorai-alert-detector/pvc-log.yaml | 16 +- .../serviceaccounts.yaml | 11 +- .../clusterrolebindings.yaml | 16 - .../clusterroles.yaml | 21 - .../deployments.yaml | 149 +- .../federatorai-alert-manager/pvc-log.yaml | 16 +- .../serviceaccounts.yaml | 11 +- .../clusterrolebindings.yaml | 16 - .../clusterroles.yaml | 27 - .../configmaps.yaml | 11 +- .../deployments.yaml | 169 +- .../pvc-log.yaml | 16 +- .../serviceaccounts.yaml | 11 +- .../services.yaml | 17 +- .../clusterrolebindings.yaml | 16 - .../clusterroles.yaml | 21 - .../deployments.yaml | 155 +- .../ingress.yaml | 11 +- .../pvc-log.yaml | 16 +- .../serviceaccounts.yaml | 11 +- .../services-loadbalancer.yaml | 11 +- .../services-nodeport.yaml | 25 +- .../services.yaml | 27 +- .../tls-secrets.yaml | 21 +- .../clusterrolebindings.yaml | 16 - .../clusterroles.yaml | 28 - .../configmaps-historical.yaml | 1725 +++---- .../federatorai-data-adapter/configmaps.yaml | 4112 +++++++++-------- .../federatorai-data-adapter/deployments.yaml | 347 +- .../federatorai-data-adapter/pvc-log.yaml | 16 +- .../serviceaccounts.yaml | 11 +- .../federatorai-data-adapter/services.yaml | 19 +- .../federatorai-operator/alamedaservice.yaml | 11 +- .../clusterrolebindings.yaml | 19 +- .../federatorai-operator/clusterroles.yaml | 18 +- .../federatorai-operator/deployments.yaml | 86 +- .../mutatingwebhookconfigurations.yaml | 55 +- .../federatorai-operator/rolebindings.yaml | 19 +- .../templates/federatorai-operator/roles.yaml | 103 +- .../federatorai-operator/secrets.yaml | 15 +- .../federatorai-operator/serviceaccounts.yaml | 13 +- .../federatorai-operator/services.yaml | 17 +- .../validatingwebhookconfigurations.yaml | 55 +- .../clusterrolebindings.yaml | 16 - .../federatorai-postgresql/clusterroles.yaml | 27 - .../federatorai-postgresql/pvc-data.yaml | 16 +- .../federatorai-postgresql/pvc-log.yaml | 16 +- .../federatorai-postgresql/rolebindings.yaml | 24 + .../federatorai-postgresql/roles.yaml | 35 + .../serviceaccounts.yaml | 11 +- .../federatorai-postgresql/services.yaml | 19 +- .../federatorai-postgresql/statefulsets.yaml | 153 +- .../clusterrolebindings.yaml | 16 - .../clusterroles.yaml | 21 - .../configmaps.yaml | 11 +- .../deployments.yaml | 159 +- .../pvc-log.yaml | 16 +- .../serviceaccounts.yaml | 11 +- .../clusterrolebindings.yaml | 16 - .../clusterroles.yaml | 21 - .../configmaps.yaml | 11 +- .../deployments.yaml | 165 +- .../pvc-data.yaml | 16 +- .../pvc-log.yaml | 16 +- .../serviceaccounts.yaml | 11 +- .../federatorai-rest/clusterrolebindings.yaml | 16 - .../federatorai-rest/clusterroles.yaml | 48 - .../configmaps-auto-provision-template.yaml | 2461 ++++++++++ .../federatorai-rest/deployments.yaml | 189 +- .../templates/federatorai-rest/pvc-log.yaml | 16 +- .../federatorai-rest/rolebindings.yaml | 17 +- .../templates/federatorai-rest/roles.yaml | 45 +- .../federatorai-rest/serviceaccounts.yaml | 11 +- .../services-loadbalancer.yaml | 11 +- .../federatorai-rest/services-nodeport.yaml | 25 +- .../templates/federatorai-rest/services.yaml | 35 +- charts/prophetstor/federatorai/values.yaml | 205 +- .../speedscale/speedscale-operator/Chart.yaml | 4 +- .../speedscale/speedscale-operator/README.md | 4 +- .../speedscale-operator/app-readme.md | 4 +- .../speedscale-operator/values.yaml | 2 +- index.yaml | 337 ++ 224 files changed, 10175 insertions(+), 5915 deletions(-) create mode 100644 assets/bitnami/mysql-9.10.4.tgz create mode 100644 assets/bitnami/postgresql-12.5.7.tgz create mode 100644 assets/datadog/datadog-3.32.1.tgz create mode 100644 assets/gluu/gluu-5.0.18.tgz create mode 100644 assets/jenkins/jenkins-4.3.27.tgz create mode 100644 assets/prophetstor/federatorai-5.1.2.tgz create mode 100644 assets/speedscale/speedscale-operator-1.3.12.tgz create mode 100644 charts/prophetstor/federatorai/.helmignore delete mode 100644 charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/clusterroles.yaml delete mode 100644 charts/prophetstor/federatorai/templates/alameda-ai/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/alameda-ai/clusterroles.yaml delete mode 100644 charts/prophetstor/federatorai/templates/alameda-datahub/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/alameda-datahub/clusterroles.yaml delete mode 100644 charts/prophetstor/federatorai/templates/alameda-influxdb/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/alameda-influxdb/clusterroles.yaml delete mode 100644 charts/prophetstor/federatorai/templates/alameda-notifier/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/alameda-notifier/clusterroles.yaml delete mode 100644 charts/prophetstor/federatorai/templates/alameda-rabbitmq/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/alameda-rabbitmq/clusterroles.yaml delete mode 100644 charts/prophetstor/federatorai/templates/fedemeter-api/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/fedemeter-api/clusterroles.yaml delete mode 100644 charts/prophetstor/federatorai/templates/fedemeter-influxdb/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/fedemeter-influxdb/clusterroles.yaml create mode 100644 charts/prophetstor/federatorai/templates/federatorai-agent-preloader/configmaps.yaml create mode 100644 charts/prophetstor/federatorai/templates/federatorai-agent-preloader/deployments.yaml create mode 100644 charts/prophetstor/federatorai/templates/federatorai-agent-preloader/pvc-log.yaml create mode 100644 charts/prophetstor/federatorai/templates/federatorai-agent-preloader/serviceaccounts.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-agent/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-agent/clusterroles.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-alert-detector/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-alert-detector/clusterroles.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-alert-manager/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-alert-manager/clusterroles.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/clusterroles.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/clusterroles.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-data-adapter/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-data-adapter/clusterroles.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-postgresql/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-postgresql/clusterroles.yaml create mode 100644 charts/prophetstor/federatorai/templates/federatorai-postgresql/rolebindings.yaml create mode 100644 charts/prophetstor/federatorai/templates/federatorai-postgresql/roles.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/clusterroles.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-recommender-worker/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-recommender-worker/clusterroles.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-rest/clusterrolebindings.yaml delete mode 100644 charts/prophetstor/federatorai/templates/federatorai-rest/clusterroles.yaml create mode 100644 charts/prophetstor/federatorai/templates/federatorai-rest/configmaps-auto-provision-template.yaml diff --git a/assets/bitnami/mysql-9.10.4.tgz b/assets/bitnami/mysql-9.10.4.tgz new file mode 100644 index 0000000000000000000000000000000000000000..a7c2a96fb38c469a871b18deb01dd29a94fb4251 GIT binary patch literal 44059 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 z z8|96?^Pq7j7<1BEfki9vzE}ZAqaKP2yad&)dvj(GjoO;IahAP`y=jVwqN%cp{*LSL zXJ|44gS*fqChJ^Lc%G|4#SeFrYj>NB*>rR09BAMbWynFX0XjsMfIm>ehxs`0@ck?P zcbUic5|Y_$Ew!^28zvi-hYxTG{Mf!`Vj57jE9JV+4V3(NR2YTcOx^zg+2<%cbrM6& zOjwOOdYAJB+Vtr#zvK_TIFa6)ZeS3JX>;gN$i+kY{i)F2Xf4zkIx|TV_9z=z*H_NU zknXt!mh;Rn!gAoe%6(g<7Fk}$dLMbgIpw?8$}D!g&bg!X^f!E>2Mf$E;lBUZ$LF_? zqy0h0Hmwb#c@=A}s$XJRyMz4#GwEj6u}oo38@?0B&PCMlpN^F*$BT6Dt6(^SfiBb$=3IP^Jn~myi9x@tb2m#x}w< zBEm3GVsn4VQlUW&OKGh$1 zWYh|)CSquAMXKF&n_ML8Btt>F?Gju?PH@?S2s5?699fXj(_7qhK6$+w|0qk)m*p;C zY^R-u)`}EA4ROakb+1*-p?ryUHQ)ATC z>Bx0RMQn4mo2pluXm48JWYF^8C7mQs$pk@? zQWF+@SL?^G^9PJlAo_VM`91e z@#rDChY_Q&ZS=@(x^{gC_ds7$jU=&0aE7Z4pW^Q{@bD(bSZ%-l&VvgW8~f>+OvhBP z{k$ylV&ZEi`%B;5?_WWSVxheJLC!Ci>Fv(GUw7EkE-QfU&Is$JZku1%ai%he-Mk0# znlW&W8e@RO1xaD3OGl?Ty1odX+2Jc#wMZ1XDw6ws6j9c|NAi~vJ>Zpt(e(^rOhYE0 zo&WjER_ZHhaaagHimLb83hS5}g^pb1lqo5@HN+Q36pbOwcE(UjXOSHaoDh~i@?-1@ zz^r@g!MWCTHJNB%YSG)0g2sQ_=fXYHfDh`-T~y5D)Y8FNm7KK(yS_cnefcWYA+>bh6lX zla>>QbLo->?8b=fqA+KaHxAY|SVXl-SrhryVn3Ym?dT8q#w8wTM;yf>f3xDt-ST7x zlVtw+@qga_>9F0@z`2_Fq`p18j7`o+G9h1Ewta8gCfRtuwA(l59=no$H;M=$siF*m zj(1v=-QM|z0|S8cOQg_rO44pTaWO^&F#}@`PVX}i@SrE#Bv%X?DI)YnV=1R29fC}1 zWG&yQhSK=A`U0?eSIUm42k~Y82>tz!>r$B~)roruP|%W3M0!>G5O_tUp*pzBCb@C| zA0cO9MBvbi^frlrMq%%J1X$G>4r-G0HDh#WmAtQiRvEcRd*pP<@9+wKzOYv1-r0EM ztVa!VMl}39G(GDnZpl0s9e&xIAD;kmA5-&1q>I%G&T?#NoN-oh>x3p2Yg!izMxf5w za=KoFm!T5~Ocsi2#K8QISK&~JPF$ZF6wV>mp<6PLmSNo+6L=<24=tEA8n*?2bKwyj z8kPhbdbK7S!HA)DC@>n`3MUvg9iBp3rgjRvMPwhDG{hm48?h+JYylGxCs-yeN&G=w zLZV9bp}~+75GVpVI!fK+7Mc`P(s7=zVjvQj^aRuHuzN6oq2}lLe2@WLV8t0x!G5xwPp6Ui1^)m}>wptEO9D z+yCDS5`={;=W4bP#D6b3LHxI;BFLf|`jw3(NUWf;X9yUKTe$#`Rb{kWvkZ`yG@M(x z29Q>Cv|G6ekQFz$Hbqt)r+uTY-VoY2xeZJxD#NM?Vkj)vXElRHeUcE|_H#7lziC@b zO@+Nd9q&vANMFCGo|0an6k6AbHw#qXp2`L&>%E419GmLa{&wX#ykK3L`T(t)J)44A zA=&G*ze>>6j28944O>poEfbZtEznJsqUg&52A*f2*0nYlL+H!Bd7^+}q8K*qAi^6w z9ZTa3H2nq(p%}9TN-(fG|2i=Sgy_~CIKlpv5eNf=b*TIWtTtKOk~9qaJ+Pz0`Q_@W zfSYDU!PtPscmXQ-3dK?*c-z{zu1N_tQ=kABtP<5`bgv>Oe9Px33{(`m0^=XeMjb-1 zZ4$o))t16gp6Oj!D27dElyJxIqop`#1`Q6HaMb$qObNqrg0E7YG!TQcsZRo+{`xfG z1jC}b*1YhTCY!c2n&SPASutLU(d|<-Z=ULj!2>Bi z)#bnU`gS+H<7a68s$9vAyjNkwVA*7Uia@UoAOzYM2R2QR0=Qu9q(F;Y_pKTfku#Np z24qfbPqdU^j-S25w`wba&Gv6$y>Y{%d)OAbt$23>GZdGp$Q$Vyk4U3Y8k+Jj=C*K! zW6^y44u}}uN>7efyW62A{3vlvlsrMt%^?$ZA6@oWqsCokuJR_p$6JfDS5E0=xEwN= z{ccegx;56wn#0{=Uo$HMUIU^`4Qb+BK{nrd#mGyah%Ywj0I<)kkg{MQ8D-orbQEy`2rm9YGp zcO)%Qx*oZu;${YlXC*-=>;7{P_QVyVe_EP3-ylF(by)S-WkSfH7BJ!~kMp`~7i;Lc zO&6HVP|{fKW6A?F`060v#Lq( z03T{0UnnZ?JTvYh((@pJWz_lxe40Ud!dN12lb#>_br}f_J(@87fS`ANH+ztH#5|w5 zWRQ(x4H>J-$06s+mXbh8)cKKEGB^M;6>&I$1E<2nx%xc_@c?m=5w&Td!ardaAdU{f z<`6UXh0EvQ8DDzlgii|vfhL%tDvI7QJ$dH!*N+8OB#y{rq+g0Fm2QV?M~P>J8KSA# z{t5qt8M0E{ynMja&5qNn2N}0TIWMOj5;nzvT0#ce7H__PVt4Eeb$^mQ@j{ zZBdR60kT#LF%VaKVH{^PT{5pM11j?6*)XR(s|t`o1E3;OW_DD2b5jiHwGr)y3?N$~ z04$UOsj#CDnr~bEEel}626*`nR$~}l$rS?CEI=L7Y!1dkwD8=Hn$QM;(buPXWewqBW)xdy2!3#sCX@lVKxr((0?o;z2g z5&UCWF*mfEd9JsrZoUF(K%;bUy|sJ!&c(^+hkyUG(YQH}6W55P&9Z^IW}xTJECg$( z1W71S%DHE}cZT&LOH(>;l~>T%4#GApRCZd)RKsWH(J)%m*;5bm>2{$Ir_fx#;ecgI z8bZg`CB2E2FPltS@es$Rkypk$VOu9Pr{-uCJ1d7yO9e3NWVm&PB_Gl8&P z|5uDO1nX8aWHwHfgNkr5ZE`MVHV&1CibzG--h@(!TkWSTLZJh5{me-M6hO$Y)`4vK%` zC+iZbO#%FzjmdS|KL zDI_5Hhft&-%5!I^Eqs?d&aUPP=F%djuF`9x6&Cv5W=wr;u`-MSH~h3le!IzP40=p? zhU1zm z%(lAe3R6%EILNJ}c`l5)Ci*t2g-Jv1E5Jpk6gVDGw2+GAwSy2K)x_pC905`JG7)P? zrZVz6Z4ulh8rJYjxG*L39(}m^pmEz6m}~dTJ1k zjZfk3>&Z#7uvqd!$44`+_G=1h#6fvLr^nC-8~lgRmH#QBYygDA8p zB#3I=y{O?^?#@Qz0>Go_fSva=Z*V6O=frh+3Cs$`&Cs*Su;0li9R9+!divcwVztEj zrMCc8^WAW}Ou9%oqj=>311gNjK|*%O3+Yb)4J%P%KH*TfttPl;{{_qL{LVpoL3NwJ@fUa`8P`84{ z@*I*EPX<+S2{UjcR*OE=MQzjO85}J`92klbLnnC8Wc~(+0?i?g$2EJ!IV1I_>u^yi~pgs{5+jwd?%L%)Dh-YHht`39qxIq=5LQ{Y)RcxuRPY64i8iLLWl=h zP$&!8et8d5etZVXMsvDyYC>hu_rTIq&`X)msKaJA>|%j}K!=P2O09&`T?@Bvy5yRs zbm*4gh#ubClsjZ53{q;(HG$<+7CZ+&Ra2FR*OlwFMJ@m5(@Qgzjt&|_fw|CGYmZ*i zjb!Cp&yiE{$w?L89?8a_{to8CLZtItqjnA*trFW=sfY}#+BIHvtAU%2Fn^iMdak~K_dyg=Tu>hCM2%mq z-Rj7i`;GNtQ1~R2^|ykrjw+~CUCjbD5ebx(Ak?Ve4rYTCnMswo)^13R{E*~g4pZ*l zWDk_dF`E?j$%18HgM{ZPF$tM;qpLr8oR_tSF6P+k?{m8s-BP~ByZwNk6`f!hacI%2s?}`gnV#WTCV^xxnB1)_ZYJBJ*$nFBW%DLJE(+y zxr=TV#aubrDVuRQEV}Q!5)nqZGu}LA&;8)xxxn{Hi$aIpeeU+_j{3QoxU}T99 znbDpOl?W23gF8M1;L#feo)Szl@?8^E@yx(Nn}!k z`ID(bvReAGycW>oAUWe**|RcB*u>&HDd=qA5vv02u{1R{XBi)O7$(an4zqv8XJG-h zelTBFUsV18D?s1>^pARSOvi3UPDwiZoB?n0W|!&FXgytb-}YW4VqN?@4b-Bur^sTxG(>LnS#Px?B+&Bdr(-|RTpgVix<`P$a6@C z6CxrH1JpTErH%_pUS4jvp{+ptEK@&eeQz{L{TwfXS8G;a6<~tLn4yY`w$lZ3Ui>YV zz%$|7^|ry1jM-6RaZ}X(yWIFTeO5;qwL$)dW@-*X{{{0?Fx7$Ja!Tc z_|^eE%2{V|I-zk5H<2m42Aoew7{14aT*xOU{JtBtPvr^v|KPWs?>C-3}!= zHP%FZ!km>iU~m2MHSR$pkC(wb@M_e<7VAw#5Zm&E?7YMt|8T(YSKt_Sk(lb@qJKI| z^6^8;{ygV&I2LdtN_G-T)~Oe{CPdBn{mjm>GV!^@9pML2^1ln8yb6!>p9`N%q{b=v z-4x-Vl;=zO#G|e=+!>6Ls6C(5{w*;0z`=dWJ*NcNAUYl_?T_Ejvx9?nmCY$f=w@q5 zlB9xVwkSGHU9!MIK2woGa50o^O3Y=T1V_9}tOAKR5pX~6LY;{d=3$>E7Nn8gS4lP( z<1#i)3KLUE>dltK7D9h@R;lIkP`MQ#$!G>Q;;Ua7|9Q*(xpPpXV$`O55&hka=PAk< zr^9Gup$IT$ceFqC>h9Oe-wN_e>^|L$(OTyPuCCJObZ|iFepwh9`bAh=is6$^E#xhj zGOyt0S!749v>k>z?rwSC4Ik=3@Mcb7PI|0z^f5ONP3~MxiZ$9fs*4rvES2`K6-f~_ zkj1)8ro>doQzdj}f#r`7rSC{*_i5;gLe%ud$#gr?Hd6Go;QIAzrjC#fS)wrc1Au^i z`ABe~(VC|mko76bw!=Iq2!^TF2!$AS+#<&wDaMcX^%Mw$6cWCvtIL;h?y)~ zD`|xmG)kkqQr2U7G_SpRYAVUu*AG;m98O&iKrkU|TLsyMP7pbQ2M-ib7!z{B?wcP# zoevO-0UzfIX;5~-StAYMRBZYtw4*f879X(ggrxQNoK>(|n2UII@Z<|{zT}{5XDa4< zqb?Ki2o4Ry!&#@sExwhSB3L$5jiBv(!a=`$#O479{d?6XP-GZXNI(LZVGtM=A~Fv* z-0h-)@=@-oUX&C6`}Kvl?ZrjZ9bgBiK9N08ikpis@yE83Cy18E0(#pHLki zh?byGr9W19nVH#wV@fPY^WJ(XLA-{_XmjN%o>1pDyq}3$@VYMfsl3+qkQ|e<*^ZXSyBuU` zmBnr$<}t#n8Jh%X<=T*mK88yjf>Z_MD=8tjer7n75%_aw#g!$nH)4dZ-3K1H6E(|dWBK&yYvs)9kHuJO@|STIQeD z7+gTPj;Y`oE2efQ7cev#?Ys2pIi00OoXVBnh&cMJsIfoOCjAzCJ>m_3B=FZ0z#U$C zHTl_qsJ#a*BEBvqg#f{0V5ilG8 zK6q!vlyIDXja|G*EKcyrLwmYY3HtSQ0nuf| z%!G>+2PO`FTIavYui%)oX4uTm%e1m3aIaL|{8zb5HCbg|l1hioDG}1qc)Eyib7^j^ zzk;4q$h*rj?X8QehkJDVMhHkg=O4gsIjV&B99Ma~7~cWoFO)dN<zyEQK0~66cRf z7|0`0o8rx|$zZ4&7O)7iU_au%NsK327vn##w|Day$L${(hCeEkQ(6ErYG@R2s2a=_ z@M5qLaQ53o2g7nyCW`Ve@Pti;Ha(wz^NCrXs!>^`h+9`cg_J#&lJ!1dZ_Fk}gbk01 zA!j@bmnMD#plJgc>X6)l)5|o3PBpSDb=K6_1TtT8k#f&TRZ?P>6iq*N2~lza?krr%!)Q z5107oTpZk*{DuE{9FCkdAXb=G(pA@uKR!h>szN{=5Ag-CH ztxAFu5@W@+PNq^#3^uMnJ!j0o<>H8I#)p-35|%JAYG21pDfu+r8w^=owmJfF<;b%39&jeJk%~)TgrUjo&F=;&JC>z4 zU{@SeD&o%P98k$>eBXf?}#OJOFTXCEV31Qrei$-FKEzaI=wMY`H>pN@( z0~K%2*Cb1kOrfeWgec~jB(!$1#(k;=6IeO?>r3~;lsXa z-NI(f#x#udwS&*&tF`zadU;+sq}HgnVcseNF0o>Nu$%1 z4RAr+JwI_4hvAk23gV1O=8g$mYlPgVd0zqVkmovyp5U&2K40y@Tvlgid0+8SAg+EK zoHwICKmJ@>bWS}!jsO`u{_a!x0i?vE@hB6sh zk8hi^mv5`!Bq=27)raUSA1k^k9xKke0-hnGHAjaZaz~+xTKLAvd%t1JHZwXyl~<$JMv=*OUF6I$GxAQWCpYvc*P3~+8KI@DcFY&jL`kHWQi2cUdL-6VA}MhX z%YE=`KTG258pK;6^MmpJmE?n_5Do>yFt~iulp270zC~Brf-+nn_clgX^w#!J9WfI= zrO$EZ`<9yjoo)gKR+$9+)%mQ$!mf)O~ zoh7UN@m{o*zL6G0w+>PFCsS`{rQiIIyExTD@-G+L$rXFx_pG_8vF%)&6dPKP7W59R zd~M}JEodFf(Q2p-pu6=nldag~VzKpr1k>u!%*J{eMLjbkUt9H8{(DWNpF78_IQ}y@eDb(oj{iLAKfRCt+{Lp-{Ku->Y#;m86@;2JR)Le`dZafB^Cg~+ zGRtBdvLOx&DyIC>?!#`lpp|Pi1FdHLZOjAjxeez}`PZK5#SGBcv#r|nD4Q9fm2axc zHgOhn3dxw+4y`!=8c@Mg*pVHk!I&goyE%*X@!_n$!psRWoe}<=O=HXn>il)!9S+=n zr)u{!^MTjRIt1GVb<~i(*LF{@ zqKR?4z7E6I5B%p_4_vqEY-F*zr`laF@#jCBJkM`~Y$;WIi2W7x&F#%1HDH=d7}pgZ zS0dq}&o@WP=jSil642+t3iP`@>*1K@Y`+re8ot~d)lSY%^_>naX@_HKK4?$E{w7GM zPh+jle~sU6j*S11tj(eXhfwP1Bu$v`aY%Ses!n3Og5iF&Dmk-|xV^$k${ki{r6H%$ zxHmh5CQFE0`JjocOF!P+bi5^86>(l`GG_OavC3o!l<<_8D&KG-OPxx~57`}gM}PF3 z6DZsQ)%S^i-O&05t6X%eTtONoG|UcZXs){b0*zTwbS)TLg(Ip%k)U_d0fhjl!hZ7vK@k4>8 zG@{cqs+)~Rk6L;->IkN=U@gdlMVZd;`?L3b_s{?8K6?NEe)-p@R%H{P5T)RX#iHvOF2Nl zkB*;Jb{6wSLTA=_a^R47&}Fvc3hz`FLX4A%moU#j)$eyuM-`UJ{_zTup*m2z1wK(t z-G0B5uXPm&2it;humXgG48jU1T6j&(iELV`kl1KtyU{f>QYAsRnBXDT*K>1jAUj$Q z#Se7p>GEjEMOv-8$b9LcpQ$S5mbcbLpoBhh&SCvNkcwPglcQLVCg_Gm4-=G3IJ+?m zjvQA*iCn02uKtyecZT7xyKdBMY%L>czQbK66(phj%4h^hD^)7k`}a5sYQ8ttm!~f~ z^G?MZeGJ^*e|i8gYMLHDL!A$iDSmK)UY?)7K3Dg}fIRBrX{LB82P)+9TM}~Xq`22< z9`u>GZN{Gg*dV63mzaA28BY8`Ys1mkV{_`J2$^x>qFX=`q0P^ zF`bHyfc<02;b^m68dR5y%1R~T1Z}2{XKyb@-c{`9!fgd^HZQupo*A(Qirtp#j7FG-_gNj^^0UPLQ@7k~*ZzCbKRT+|e}{v6`|mEE73@DNexa)S>WdZNo`)Lq zL-P*&r-Sy9vNqt)bHNlP=GjeD*$0A1<0fGomfB-$+=TEcjnwK;>?grv+nuyyDfNjjI+sQDU|=?h zlT{?2HGJVVWvN*Imc!+c26RkBVuNEL{0w#eyR_EWI6tfDs0QoO;6+TTOH$`M(fdxw z|8+`j%X4QzT7at(N2-pXx?jD=HlaT)IxnCo7di!Y&t^!~)K$0GqW!!o;W1RBDe^fd zQ9$@v8iwjCVFEne1;QBT%}XMgnf;AYIXGy3ci3%`*)}3ufXXtVt>2{x0eF(8Wy!Gl zL?64d1;D0}o8=oHYF?I^jZm=0yLWw10p?Tbzh7b71X#eq5tagt$9w5k||nUb6rQm^;`Xyes{)rlE2e`mE+TA zRy5k`GYdp}V0gg2RMw?mz92h!Z8fKHR_ zikpPvNMsiW<>go5cJTam)-2p@E=54C3bY7Q+*R8f{&Y4pKSTnDdMw=D#_v*Sz z>pjeD*@e{apy)(Xhw7%xW81NpqIN1!M@?m?GKOqg>Cb*?XC6vYnGR``6npFD??xfR z$_hvX?)#`wsC5zQq4~zZYGnJl^aA_gwEDNazq&0mxkBPc10q%M?_w2S%3}$El zO!v}JcFi)Dt$t=P+I~&y*Pm8S{i@`CK`qt(EH)Sib}2+%gSqUUL;w-xDH z{d{p|-Rk7sI(0MR`h+L$6i0XrJ5qW>(<+t;+Vk?~3%HD*1djXw?&OzCokUSx4g<5K z31ffmoRd*rQytG-hOf*VlTKj_wQ75%S^{@CFMgr3$?Joix)4UfAa>6peVWaK zE9r%<7h>1{P?s*x{9=n`v@H}6xh;8DCDs2zh4>%#EYbgpLvE-3m&Sjdd|%oBA3VLU z|9L0R3i|)$rx>n$Dc!@Pu5E5qQ?`zA^Cr3!0(=YF#F(G5pAa;>K)oAatsN%$kO@Y zc4ccN&%H+Fwph2!!{sOYnp7`dUC6c&35$u}^_)46qn8n*21qV16bz5LT_r^ zRhVtDhrE;t^IQGCNnUJrr4=_?mlo!XX{zSQVRR@uZ>RGzRZG?8t*-ZFxToB>^`7zq zm~3IO23;UA3tMeKY%=l`hiWT2<-F&j2-Uv5wJ6p0x@nO*$!`0!xmUz;wNPp9Opzxb z>TuvR4HN3-jja2^^wm^D$UZhVr7T~Rp`V(S*~VLqWh*@R<@T#IZd}OV$eYeMx6{EN zikw7kmybF;OVeG6LY5aGuiMnd>fGzDM2fF%`oXir{#S=jwz~g2czRgP|9x_FAOE?N zX9fE|+y2$J@~dTY!MbUfr?6C-4b=;MzNs$kTx=tkRM1LN7b$t_pw4uj{d3UcL6 zy)69D%g!FXj@1cUwMQzUF_&gqTfipI5`MR?$w6Z}Bav|{QbD+`V47JQ*5O;YUsLN@ z77-7@GN5)8sJWPvsog}3|CG^b&HI?<}#eimHmdOTZDza4825AAvM2U^l96>*+mYm7%@c*~sV%_;k5=U*|U@ zxT+TQ@iTS7M?q|Bq^4MMyCOHmFN)co)gI-Dzu-7F#~-YOR0+#7M5BOwTJ+U}4Cv;Z z(xt*?x>zo2*#Tb05hn?!WJV-s!5P(%6CBKu52k$3N+$E;vT8@gO6@8fb~Y|^Q3g>* zpH>at7OQ5L&rc6(&Qu?Ex~LP9Xq-$sXwZi_WO5E6hoI=e7yi94c}$Cbg=3LhVA+Ri zCLdKe7>Ag+})bbgq&J?I>PLK=vMY*<=FsnBj z)3N5w0C5}zY?={Hb)%*ex#$PRLV}}WSMMeSPV6R3I+jSxr$eUp=2~=}M=xs3oYH)# zAPy*II6Eyc4f2ahm1$#QPa+-a*!i;a>By}dP-&(+OXQgS_x8^>N#(|-Q9NNBV1D5Gp92SnQrsoAt zF!)*_W7lbnIy1R^8%w=K&@Jm%&v(}gWS7>FQfnaFq|>=!_G|mnw<3EOpev(U_Qq ze5RBRkg;RH=vWZdFt2@JuM7$l#aOE%P!%h;IyY}?%E_oQJ@tTC-pi)S0yV=@E9b?- zZJxH!N|S$)@C=jvklhfD_T}1f62=pZ2Hmdu^Hn+}ocd_cMf+(SS6hA7wRJvrn&cPS z3!l=8Zf^R3jLD~SwRwLMhCkB;Vpg3GAKqECfJ5+~r7CP%W3~jIX8yRuqzDGGeeTG3I8OvTB9@FDjk-zv5Z8|DQ09$7HMLzXyY- zk1PBC_w~Q-=2^Y|mtDT)La_&eGk>+ZRr8N88{`Mivhs{Rso#yW8svqA7H7njhRQ=c z`USuU8$VX(Ug4!%t;AK{(b4r%DxcYRm=;HTw)mrko1~yOt6%9?`{Xy+2re|~mbRA6 z;%c{1hn_!lK6LC7G`0`1>|5ou)I-*Y&AnpZy=RI3&#T_tVg*>D|NBq--ZN$1+`(5ZO<5{S(Hd!Q$q#rVW81It3jAm~!HkHT+ zc#Z}6vGOTwG`Qs|g5@#nHKVb&yl`Msi+!Z_Dm>J!v5(=;eA}Y2mxffWBwvXktghEi zHG@lMZsA^TmOZ8ZT1mtz9p?ciiH+Xbwr0@l6l06^!CF|4lGnpu<%>?|oXjXu2Xjc2P_ConY=jGDnM^&XeELaLiC7n-BJfHL4+U!FhmiHT-~}2 z%QfdMlv4Sw$$U`cLrCCTl@kl&l@mZU`jC^8z2js?xFA2tA7M`b{?x6CTxK^dPx5*> z6khF~bGMMSV6j6fd(^9Ln=g#CYoSBCVTj&8U*%b1|KDI9(P(@-7hq}pw_l0>KK=gQ z{=buF1^fS<;su07AdaCr8aE>^UXp%^$(Bc`R zL6zG2p2Zk0dxYdr63r-Qkvcd9$1|F5AkwrUT$oFUAc+_1G`V^dSB~OZEgdU%aldB# zFL@U0e=BvZ_tD2f;3(jD)x}_m{(sURJT1k4508%S_y6wXSwa8ntUrRD8%D@eX7VfJ zFjrT;R<3w#lNXt@Sk_@vaL5#X&Js7xL7t+E&@Mfrc*0D#Qz;oavgY;)PIO*|$$`qC z&f*=y)zGSOO-5C+qg!yC9dUkmX5#GxG;GS zy35MJ%0hoS-M3Xos%@!MJJ`+}&Yht=f2}lTF@+V( z3dWV;@SuG54=PZXPm#hNYuCKg1W`q4i>C!ES-hegty(1mx`J+F`g0BQc9sE_2fnKB z>T{X%4VdLR0BW4XmHSdnzcuO7cK&f~`tgDaEa@j2Qq1SpAt4phhN>)dJV{K9jq%c% z--XI;si>IBK?~H?S5O;E!7fD9yc|S}W6Ej&d7nzQ%I9oNfV-55u&B${9c^mjwdCfg ztTy*XyVXy6`^hl5nlYTaqrJC*v|NV2GK^(52WXIUY{9bJ3e0xNmugt%=fxGoF=Q+{Sapk_Ok2Tdz8WQEU2<%dbf@vHD2$ z&r82w?!GSm{+z@i^?^m2(5bel_PV1kae0;+-Qq&SX4hErh%2Xf!`^WLf+98mq|GSn z9LBFOT%CtpOpLTIpDe)8ttPl{ItXDXT_y5H!w}_sdmDXqftam*I+iSS77(F9sG7O2 zrhN-0%)iMidzAN+sK){BCR4=4c~1zFel}Ag_+IG>~C^b zbMTkUsI4XIX3YNm>xSW0iT|)@%r+nY8T22Q>wg~}_6JYz<3D%ttQG%}jPT-z|Keo) zm(2%(G?(p85Xi>1ITED6zGW=P9%@Sgp(=S-3kd1&Hxdvk_SFy&S{%kHcF_>VSsGL- zA=MmI+O>et3!LB~7Uk~){qtP~lrD%l*ij87sdr0zI!Tks%bZuNelosj2t&coFPqtH zm3WB_#S&k13(+qXgRnu^$*`DKb^ifjG4+8hWVabL>t}f|4vIGwQ7*x<{g_;7Mcb*E zoFGYykX){omIdQ<%N9(p+Pi`zZdO))gAq6l$bIast+BDW*c%vM!;QF&E#O`!CZN0h zwqtJ^i52F3-Pl`0FSm`o>27yC_SQN=(_}$!GeWarKc^9gWnmgipwzNNzRr3r5&dn6FIC)q;HR^+rN`c28?&d=-FMJKxLh9M>|L*2lC;oG$7-1VhAdAO#CK8mx)Eo}V+uSZDWR10* zz)(GbSBef+OwF?UNMePGemhl77%;YfWkuN zY&8Sh4KFOlY?lHJ>zU61@o7M^`{#%ROsPoV@*&BfRkv`{NJDLwu#ysQTvQfgP&B7YPE5m{O0})5aV+*!oDz^v zExsyT&s@iQUoFR7MjjkYAbaczel|5Oz9lkQbj*3aR;uJKPm0JvkY}P$!jnP)L zN8a>JwjsJ)gMh7E70m^Fi)8V^&@UUli0@Uda9&o?ta5u zT#L`JULpR= zNkG@S2x3Y8-_xUhznuT~`2POKyLp^-0>I~z6Si~wS25Yn#C`#s=CCikzFovujj)|y zZ-toc!m{eKb`jaegu6l~*JLid7}}OPf-5I5r~f9wTf#*{h_29?^@%rA-*nXFN6j(p zL|T}9j`s89H@E|-gh!_?iK4sotLg{jw_4OpXs{{V-e_01$pb3~i|ez%s!4(Y6?X7( zB~oP}#N|Y?o3Lxi^6Kbr}{o_ z>6xiccQWLpRy=iiq;bR)_N^%m5gEO3Zqdium=)5z>^D!d`o^BK#iV~eA^x?uQQ7}L z{C?2C_y6zWS;zg??yzhFj{cBTeSKxSLwgYH=PVla`%<~=mrcIxmS6a()8y-C$qd>= za{GO4CO3>W*z9P7Y_v8eUz4S$?m4cdO&to=JC94#fMRR0H(1sOIW8yq9_xe|O9Y^f z#=0vSSr&>n$J4NI+A(+b8saIrS_$am8K8dDzP)y3sGvm*UslC*97x&A80mF~3mS zm*dokOQ(EA!BUZ&&Rx50ZVg-iyce3g6`GQ(QRyAIMf6NlxB%C}&k7_<3}f&>M&2qy zS(Ke}%yQkE*>j0&I$WttYJ->+qv~|*xRck(ou95bglYX!-R+)L_PHO-aCTx;ii2Lt z3Qfi&d7g4kqCBYB>68OEI0`b&p*2P+equ&yq8fa3$zDdYx0u^Wk_}+wJ`B3d-DO`j zQLKIZA^H%RY{c)xhp5KWQG+YU<;-acc-@9XuVMs1b^q`?@vy4avJ0AV5TJ*yE6pP5 zZasS-n`O_^=yep%5sTnU2@;A4 zMR0&e=oHflJZb=NBlTTsYpCCO!Cn1-|1A|IK^w|K^9uxF`S5{3&Kp zFYjoG{p&Oa-$yu)JaH2{kGvtib{=`jG&f?n!;<_ze*E-a{_o`3LqE_Y z!c%Ib;b%JJ(rS4wS;BEn(EERoa9aHNU;C3JiN$fRCsztjOnL$HMK577^+hjKO+RX; z+LLX%5dR)?mc~-0C`Lme8&e+*NpeF-lmVi?^Bm`A#;#@SgrQUr#8QrMoF&i*X`aTM z1t~<|{|~z4bM*f0FE^MIbdtA2&vAl7HqL<_s)0P8O?xCt2#+}xqw)xjXOz=3f);QD)#*bdp2DxIT*n3yCAijk59QD2=6EoizjS za7^Et;b#NqnnuAfdd{K|9sh!3XG#(*t$hi(g1g4WlP`ofO2bg)Zo&?{`D!{>rX1@0 zgM=YN?-&n*jsjwD51mFyHgS#vi;6OwV$NnXAOc~-BPJM$CM1jr7wBd}{R#4MBuzHh zu7HCXGZL~GMdU{F4@#vYpt!ffuU)gKp(&2=m~hW=itJYy09L5?Kcz#0<5=XqUF%=G zfXsS|#RC$DY(AC7tTe7w_wXkhA&{i!s(%_GKTJhJxKJE)#tDQA1Wkx=92d#)ctjE+ z(7+q~`HzmPIymwUz5XB7H`0$KvJd$4A|^h?A)-;7CP?@bGR5#_51mf&n4B|~WUI61E)7)}Osq9qxX(98a@8%#xKH+H`l4F#ytK(Q~ zy=18KtR+xS^)K1W?pd>cFB;S6lj9_KysTT*PlCsGHv@0*)El?~8B!d%gTBk39yv~& zhT$0tslOCfAoggEuPGC3Z;AnE8hB4Hel$@35kv5YtWK4C%yY;ph-^p=I` zl%NaM5rUo$(CNtVUdQbmAbXfsp!+)=t#bn^B%A^Tb69_rww9|1jm8CtJ8s8uuz3CoRe7X~^fIC#ftLSDlJ2>S1(gI&;nlNCnz)8DD%NLOZAzh^p1 zILs$9DD-63?S<@YSVv9zUST>EUH6bh*b)Ku5KsVs-UA2B8aCtEmxVl}oNZyLUxK9_ z#WVR#IzU)Jb~@L+Uz7PSIF?r5ak(%3du9NtK4aob&2vrWp!s1TkZ&SuWciXtO+YC4 z*${lRMZ{LNO$O>7vVq-0D2qkPMkY1qCo<1SDQO7^OTbd8soqJ~`9|l7B0(ZS!5Icw zgxWc_i9jQSHQ)zGuqi&urHUh*j^I61f2VD9(tc8j?`SYwm9ZOzS zX`-HWItL|MKI?RV;~$oqwv6PL2Y6rv{iE!n6y0y$p>Q&(BcEc%6J&Ms?7_bD3;iU7 zkIjys3wkcbKFQ7^=e&SihJF<+lHfh-{0{dwc@`Ib=}7g41$p`yxk1;dBf(%T5)5n- z3^qf8!4^m`D3id165hmPjst0_fC{-}XyEm|zT>=q9idljMy5l;(ctI+9rh3V2g-$> z9hx9Ey1@d03nJa45sj#rkRW&Q$26IwLkJZ~=GBqXJ(1uf6)qdO$%ME%9t;sAD$o@F z%D9Q|NLNo~C<=+NHej;E0Dpp`F%c@TrD7TKeI6;$G6oJp!lY7QJZ2mx%7_iXEXbpcg5J+T?|pMmChj0MSH{a3q~7%mZy#WF&j}`e#pT<#!XD zWU${5P7u{09iq35%XIiZj^m;;PG%5C*FOqH4=QYgQ$f&G(IUA*`&w%N9for>WXVK* zbO`tz8RAaC?0m zNu~q>3Bdyb3VNGd2ZNC#A}DlpBCyaHGw{9A8Nw{`(ISF`yN zXykyGMQ)OC2ox*#*BIN6fUvOKKY|StG{FK5rSZ;qKqN!sFrMHcNvIDJ1s3jvP1%@4 zM9%yTo+~?8t^gB~MOLlYnC7wPl34@7b+i{YrBWm9N>FIVNs_xxb*MpG&Z;dbw?re( zrU*;a6fd%fm^I17`n2R6K!0K)U54mkf<{tx;b@Mi5GfJuhg3GYmLtum!Y2{tlt~34 zb+(=<9dxn34j2(~c%!n6JmP3BCo%^k#{&F>lCasRDWQ>Ii$!o3iJ{jLPDX?qMfIMI zMihdM&@5nnDm@#Rv&F(QJN!61`Z%RyHNm~T?4NEbi0flPL|2Q6eieG#vF+DrvpQH)n6o;b6iD2Q3xDvcW`2Qm}W+HKOP}EHK{$}^s z2AkRsh9MjGR2$+-OkhlRcIYNd|MRH#H(1twrap)qVkco;zR7$5gS)kO4uK7Ic3 z)x}Hq(Ch!rao$8B5h7nFhjX*{Bb9ZCZ;;d>V@{NArxCj0G=Ys~!A8jq=EMo8NH`s) zNr5~DCMuBKK&s>jbxtnO=|umSj{tAC=OPG7w^K!mDj-Y2Owg#?gJVO95>3qlHmn<$rx$5J1KI2xyT zOwgFk2#;Xjo$x6YYMI1Q;DmHa6Riv@=y>1Ip7Z^4|J*;j@%;Y*00960?;q7y0Imc8 DGumn3 literal 0 HcmV?d00001 diff --git a/assets/bitnami/postgresql-12.5.7.tgz b/assets/bitnami/postgresql-12.5.7.tgz new file mode 100644 index 0000000000000000000000000000000000000000..306f360eb8da639505cc0419d1aaf336f5fbdbeb GIT binary patch literal 56426 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
IKV7=S|z=I+mkE=;=?vxv8-t( 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

v>@S!;Meyry?o{?OxiCc_+SM}@Xlje%%BFt&S| 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 WQ=h(0`u_j`0RR6@IVbl33K0MwNyWJU literal 0 HcmV?d00001 diff --git a/assets/gluu/gluu-5.0.18.tgz b/assets/gluu/gluu-5.0.18.tgz new file mode 100644 index 0000000000000000000000000000000000000000..2d8d7f82015aa31266692c9092e0a4bc1cf0d90f GIT binary patch literal 109182 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

jNW7sQSSRb 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�@e2Ki{h&n&=xKM1MEYy{b4n$M$%kf9f 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 literal 0 HcmV?d00001 diff --git a/assets/prophetstor/federatorai-5.1.2.tgz b/assets/prophetstor/federatorai-5.1.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..ddd2010f877d6883655ddba5155f347a9e173bd6 GIT binary patch literal 68290 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 literal 0 HcmV?d00001 diff --git a/assets/speedscale/speedscale-operator-1.3.12.tgz b/assets/speedscale/speedscale-operator-1.3.12.tgz new file mode 100644 index 0000000000000000000000000000000000000000..26f8caf11a59d4fa75834437ba23f3e485d7383d GIT binary patch literal 14673 zcmV-XIj+VZiwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PMYOd)qdXFnWJI`W3TE_ln&WDcfgIEPP;ux zPYRKcgqj3c0JN>9eSZ77FaSu9q9o^~N&7tJheRgvG8ha7GlRj5Dkx1=LNXeOf=Z%= z93ISw)bX6;**`wWv$eIgwYR&A|8H$=wg2CKw7vb0?cLqo?Y-Td-MzhkY;8Z@-rfEO zY<-ySS3jlFME+yzz58kp?r-uC&V?qL39d#xfP`q0iD{e=tuq=kF-)k`Y{F5nNPM1!pKsd!%6B`}VH4d!#6;KeyvY@jrKaDOHJNg~oRmT2iGzQ>9@pN(uXC#|mzko`Iw! zgBu~U6jVYvkxZx<;6P*=!UDho)m+$;z2y^q9Zu`^PVZAMq`&FY z#s9BKR#NrhHh?w!|IyA@A915+UBuO*W-1uY;EoEuiB z1?U+KmuHfRGL3r=;CN!#CU8nqAlL>j^(8AkHthL3Iv+v5-|IbqeNZ%!RO9-Ggm4&B zkaR*NF3ygQ4lfS&PmW&ipB=yc?&!x6{OgL&zgqly_WH&7$q4>MisFUL zzH$S(z`p%(0tBVPa6p5(Qc*K(Q)>i$QWS9$Cs@;r192cGb{k5vQfVsVp8Ii%e6XL- zBln`+VIuNEaLTm;mXoPLi#9x7#XbDnZ0?dynbLATf@vbnb{gyr0GdqAmT5OhfTGN@ zGm)`mK7#%1hRl`e@kC4^qt`Su2=4Ab?qyl{8c=Ly8>6j}m%S0>i49m2b(jpUckW`6MnqD|fs8U4E%~!@X zl_b%2XAdz96DjgGd8b6p#)8N+?o~hc6Vu)Zv@EFs<0;Eb_46{LrUz0K*}P+=JQebW z$dt<71S^>GBj_tlcuHi7xH%-6z===_&Lq92+=wQ@{H0l8W^dWZDJNruSrf=iBSqcF zgc4m!s(Rpxr6ZV-Owk@Tcp&(MO-o5^VIezPF_IV-Y{PwQms$l(A=2Ru9nXZgQkEsy zsTLf|&4kikim;29DZ_G%*n-8)inmP~*++^Dii~h%3|#1n9i>dtL|beV(`oMk!cM2L zseeE+mI%{usSHjZqYEB-& z(Jje~j2iY-OXl%}Nu@`C`*QP(qKV+C|1{0Sm}L8bNblCnK1|9i10%L^rsp8Wzn~0j zu%Zb=y6~u|$A@ygNYqdhb)|-hqZS$!B8|)xp@3&3Qa0u0rHZ&nsftQv5N3WyzRRBf z;XyJiFJnq0!xkB}M5yizQzCdm3$2FAu#qw|J<@BIm{x`cG93|~Ms?G}UeL`5UjAee zgAh9w^C#nF*fak%_}Qo4{yXJAP4glnhQLpsUmjh=`c}VJAM5o0?MHhp`EPIU@z%Zk z_c5N!8R1tb!xdZ=uZEjen)xLLcSUf=A{{f8l! zgbPZsuB!@W_2PhYAt@Lk#Yl@ro$NJsgjN@d>arNRMura5VXt>QfwGuNf-siK_9aD@ ziBcPp#OxeKLdpqG?N&vS8B`LEvn5!`rDvp7yRWNKHZbZsRzM_$vPg-h>B#KlhBX=F zMI8QBwffZp1U2q^z2`ik?HNJ&zvSFw+G7igDJrj7Lg9vG8K{}KfwBO>D|{_Vw!`?- zv$y+a&9j>SlQd^&9eOWgz-s=#y|w$e#s7D&#kpKu5>@>2ju27g(#s?tNv!yB%7F4 zYcLSDFM;ut-oj@pMir%>kT{XL55HG({YI;V&J-5egx_Jjx0}+WIktr+eT9zlX5gLW zujqWCJkU&0@Ks5sar_2PDDQ4SAsN?`1~UBGi~n79B5reSwOCyzOR5IAG*C<_KiKbV zrVo$y9&ZKZsilD_#@w0@)*i36Ou(Q?|i+20vJ36mE zP@dxND2f^e|B78XONZV4uf9Nu{d&81#f+}>tTbW)pZ;J8u%QI^a;k|n5CJ5T;>$~x zn;kSSM!?G~tL)WXW@!LN!}0glin^ea8Oi`44JGXjXz?S-vlX>|2X5$(YuL3dctrg1 zN6#zWqh3_w;GAAFdgE||hdU8mZ<}FdjB;&TOTQQ!XT}ao#EXEuwwFd}KRZv??JK zInl}N=(ccYA7K~wefB!Ydof>2pOM$kXz{pz)~rH`t=EufO{DP0GveL&w;ArY(ITfY8K;wxT!S>c)kd;K$>Eb;{c@K^f1uZ5bkFK{PcYayn zx5aUu5>`))Ep*Rr{(N?`fZ`9sY!>)SWA^`a4)Hz7SbEPR{;E9U+D^|sm-s)NORN@2 zJ`~HSxPn!Y8>_$Nhy^gCSsts|(5$f$6p}{H;JENLN@+$ljS5GaV>%I%MpnCaOr_^1 zW*w8b8&~j5!OeSP`rd+%HEaOAyRBb)n%|^;ovB{MM$s~`oT)f9-xcWmjO)vMHVSC? z`BPhKKK!%V{%4Q2a#H+>_P?#2t*zY!``^9)=f`=LvM9S#KO;qhORd^~@3#4V0zt(C ze{gdA`un5vi{s~~7DU$?I>^MDOl{4BlNT44N9V6k_n#d#$_2hSw&d}%{cnz5pS?Ia zd42Z$$~d_XdjKcTzj=Lf^!?FE0~Ov2$zmdK<~lq% zdwuZy^yzUEb!k?_mftPZczS$d2;%(3Ns}OImmXW?^62E~+0o_skFSqUFOSZ@-#;0_ zj@j3KIKKSW^t;fZ^U7(;QCRx;^y2L3;PUx-vrf|;saenYusOO~q~FkIEv)&edC>jy z>7F(Fzf9GzDgC~KB(Qq_f3*8}Z>zQc?`-Woy5Ijl#?!E96pY?#%2AbCuw)#RN{js5 z=|+bX-MQK}j0G*mdGcjcMpMdTBesuAmZcOOP%9_?>#g{UcYyrUV)~sL zopH3NETV{F0kea;w9TD+B_HsN?z_crCroMlUSy>tSsM^*te6RD&%Z{2DcZHG7@w9I zk*%6WnM{PyXsVqx?Ezdj3@9W`5!EC+ljzENAhI&Awc1~l;Ad#ih?OR~R53|3yQU4R z$$t3CDp6x0GD>(yD+NvBT%^qwp4BgGeWfMi)1^QdMHt~$FQe_zPjOC_BGYD@7g+R8 ztyU(E1sZ9NbJ_$lwZ}^Svoj5-WJYu1O(3G6eE;nD`$rdz*8q*nLJfidrmV*k)7q#xzZIDd~_D zEJD!HWm&~}`k*r7JZ!+aKxFnoez0N&3{Nm~PFz(xiW<@0Y3lsw;TG_5Wh zS{`Hm6H>=;IU^cw$Q+$H6T<83J2UDEbu=rfDl=WJZO2gjEt*86hK8|WdrOk0@j@$0 zrqeu$*H49Wk%xwi6UT|F z#ycjJalGL&W78Q>L+*_7WIoKqjlHKMN?nv1mq%RPreP^1_I8%3*U{>=ksT=%RHD~2 zH@lSCGMc1=H&Wh?b_^VAaAPFM_9}O5?87bcNttDlT;$~7L~>OKo>CbJo^=(dW~95o z3PLHQxSc;+kA*W|uG*8ZW_?^mvH%@;Wz9ObqiWE8yhjvlq(-Dj%pS4%Hegp6c{}<( zZ&mB2@2c^?KYiParss6Bj1z{$#)ZxM1YOS_f+nj=%8B1p1t_^jKhe#$$Rh7@! z6@?8NPh+caMj5-NDg5^jm;P!clFfL&mcJMzl2XrvWWU)ffJkfKUS6I-Lb6P4E+U9& zns|I{T{yZKut2w6a`) zvk$6;onKmmI&};yfTpuUSiRf;mz=$2-PLadjU)Van+t+)_>oAt!1Nq{SVyz|W{l%V z{_cm}LRqqI2Vae4e>bNKRShtXv0$e>mPcH5NdC)an(GDRXeAXu_k2PZ0 z-^lR&D6Z&SxsU~GMq=*@;+VZU`T>TtlEK+0FLg<>J1(DRSokhW$Ts^oTR|3R1KQtv z0o{EZf8q604+59b$5{=cTmgOq^yg*wrfT37rS>5j+|J>jt`l8iT@`Nk@pvjfyMTIh+|r~(La|d%Fxn2&%2XtoGktGR zre{=Q_@0bvYM8?W17CFLek%~??T_blvJP#bF6VV&YuBt=fsKn7mk@!PD@}7Km)H*s z*=!;mHR%}psC|F!mGyCD62QPxORVhmoqW$JEM&{n%hg-|va`KT#O$9Px6SWf%Ur=g zmu@19=UJV-;<45T=x(_dy;g^Q*Y2#Z;obUd%&G5q;O`DsHksweKpkDbJ>1LH{s`x* z<8`MkVCnYQ-9Z#C&)yvxvgh~h(=|j@8+0*NR9@56S-TP8(RQom(sMcNr*Sgp+k3yG zIqUwgh7(zb2w*&A3DH!+&5R;5MB{Vol#MA!N@=L3!zK)tMco)SErE*;MzQA5#ra7r zLVP!STmQf}QCrz;1S1>fL~sg36=nnR2Qqdroitpb9uZ;qlK1+FA&MevinXE0&?3t< z<*75=+u&TC&6dgl0fbvK6%g&z0h*-_hYr--kUBButfwzAq zg$=vPr?2|fSK?LwkWM8@Y5J;fy84fT=w$Yc$|?Ph&cDPCs@E4<5>2P`FLU#~vlCM` zV@hAn3;JbFit5EPQdA9ARHNYKPdU}(dONP(bvFC+FG}#ytA0K9fyfPw7JB}w4-M!> zulfj|fA0q~det|*zv?eDpJ_2JC!<&W@my0i*d9n)3=ALqvhMX&|7SDr!yyP$Z@?|D#PGP90%#n zK%Ae>m>PbyqR|<(Tq&CysW_<_#EkGMO=Ga}`v|UKE;L*j>K>Si%Ui{eO|>jv zE$~so@zox9)2hr0`g8ofro0=XjFtvtVpPD5OGx7(@{AXjax(A-*SHSTq*gK@pLyNqZUXL*^A zU~470m_2&hsYDr}k*GV;h%H*n7{oBwsU&$$G)sV`lw+`Xd6xxbMR9D<+aoGmKU9v3 z221KpinL6q>@w2WM@$;$Rc_kQ4Gq_#6*Pg~7I>KM91+d_yR^xi63+Nk)m{n6=Io|j z3yidCOX4ULOR4PC&Fw>AS`taPrZhFo)9S3&vQaa5QakId;T>QZj%C4SsLt^Z`OX~} z&i2;M3JR-AEh$nEt*PWA`2Sw+NB=L0e*0;|{n(2B`Fb$=>GR;vpEm#Nvv*}}U5ZKl zG)UELpSAyyrG^3St*BO%bO29Drsx1(aNPWsA*$Qc#6A)9O;g>%41UHwmVbABzbi_x zz+Di65}%la{48(=1?0m<@{OIajUoJMXVImEXEcImgwLU7wpJc)uLz}$G))pIRDE#2 zd@-Y+LnTaG);^{QK{Y~-nU+M(1Kr8T4=)v+l*`X@HWZ~0bCJ@;Jz~>xe3t{khLuhP zpJWU*o#mTFUI?iP*ReBiP3bK#ZEx^XbX(a-x!T^|d2~^ZZEWzTxgKu**T%0U$uPaf zDaq;6Tz4NvH-&@ky|wFb+^^65tIhw~conbwzWKQUEm*@py^QJw9RKwB z=6?m>Hs5hMuXci16t6prHSZKOzuC>D^OFj%9W*}~sJo1f@8*5st+d^0MeDS`_J^qi z>y{Z}MpV`0;*wl1POq2}yv{>1_S<^^OO*!7ubC7a1B#-=SK?L0Nttz8P6|m2B0uKe;2}N%!0yE!u$CwnGa*}=E5#2?sZ=U%r3iP3ZT3Om^ zIeR(8-6H5J+0uHPuRr+eJeO;@w%a>lZ|Qh$tFCt&HvN|}s}3SMee2(*V;3g=1Fm=1 z;s+)tZxa4isCB1!KLkZR31KjQlBSqG$+|F_FL+u))8(#Ni(`BX>~`|tg_oABU8V** zB|?%Z4d0aGR*;uUwuCo-^lCBFnlS9{+_*T{w*sBN4TygRc3gP*Q_prx(<(TPdHJdD zd$ym|_kV*}eD4tfWKH~!Cr|bsx8r~8?(N>+|NR)xLR7P&Q1zYP!#ZO4%3HqGVS76! zI|lC@fsM(IML$jqqKu5GchDq7u{>s&yPu4SM%vIrtj5U^qktgwg=#ufCH#?HE)3e5C(VYXXw+#{2p-cH*bLPBr8)2 z8yM>YK8r71AMw{j(KDiF&~Jqt>ThC@F*PGQkM~rW*MY{e26oos=Up(=ykuA<_6P#8 zxtRVn6cG#;I;Q+OEMV#9?D-)E=m;=``tnmLTBZiH>2&y2w4(MjKVl_&Z@N1&TpNyy zv;BjQ4NUVCo$~8uf01)|dPa(c9@hl|1bDD2aZBZZGOVsu2E`&$u;KM~yz^-IpqlmQ zdOJ#NBx2ve4@PKnSaS&y3cZmTVRW!Mx zMk`8aN*l)E2Vj|@Gh?EY7vXTkuWf4t(h^yUb@g1++B;!464z8pmNq3#QP@jMfq-Ru zsBX-3HUIF<8{o7%I8DC~zXM(E^TcLDEnmWnsTbtnH1xOuHYg~Ud|*{Gm)hucpQ8+Wc^LsZ`FmfoKceL z*>BBHLh2FNFA=in#%H|TPe*v`C-~s30f#gr^D3m_qwtWSppuES`-Y<;o4P`MLZl9H6&al*E@?l@zn z(fOY?VUL&3*W(W`T?;xCAX(>3w`}xDQ5u|VHT@rRnhQA}!Q<_nXDs;QgBZL`8{0cy z1Z^mql#=QBf#90nHZYI3gU=+pW*ME*Bf~+Q+ftKBShsmBlrDZV)ApQa^K&8eQQr!3Y_X9Ca9(mC3ZxKtf;eV8HN+f7W0;j=6j6e-bHPuhR7utF@!q2+ zyX}5oC@RBqL3=UsnJ9U4G3Dls-JXZK3Z??pVhG0QdrZQ(7N%9*>5_;BLwiRQsvl+;uc+_{ud_>*u8H`p=!s3kx`(^>=uIkZx{NK6# zu-%rzSmiLRW+ccgxS%&yrR(^RU(_`lDq}}qVP3+jOe2fnVvk{+cj`3E5m*;$We!~E zwoz+czk&Y0+Wv#_z27?#^t$-3PxjjRpP%g9$AA4ePuu>3nLcU*(0_~Z$Ba@vu-k|c zM`-HYCmLU*lpA-_#;YInI-?&4ADW(l0 z`UF4gz-~Pob4ug?nT;|V*$Wf+%kGBw^9Enu5$t9bv;eF>6&9Z;t_6(C&h|-=vl!EO z5k4Cr&c95n*v2iO8;~q^wIU(ZVwbr~9p_Z(#@%j9SJzeQsAXmD4BFCF-GK_bx~0hI znDNvIeC_vd)iruXwEC!|;Z-fInAEN|t8+uQN^P_(OD`hzFVPay_=8xp%qJqxu8|mU zhnbk(9n0M`f>LQFgK~}cKo%I*$AUExLZ;53x|ASL z8~;?uYzL`t!L|@+{x1*Xu=1|%SjItT#gZ*sPDLTbFUyv0CdxLueyhQ~m&E(EWgB-+ ziu5VOTai&`obZ@kG0L9zXbi>rRbx^mx>}+D?X%g12OJ;3MXDny6)CmAgP>+-m*R?Y zciPek%-s}}zp%U5Cn2Fvt(D$CAM06d|8Y|EdzygO*nhV6o@}@6KaU^Z+kZaFV_2=t z*VeR08!m9y)TIk7&RVYT%;4VVP^mf)di3!QgsiXZ^Md?Z(ki*&;<-de?zL8~(Zv&r zR-NL7%o=s7ymudpMXy``R$+cW2C#1ZKY6lX|9$f4$^H8O7|)6n#W?l%0@OPRQ2yMt z@?4CZTc3AT#4tCB$VPB^aJJz8|3Oh$-)71LNxvo;;R&^FLhIJQ&feeqW8M1S-rjrM z%Kx{$_hjpS{eP6lCV!P0Mqfg|4-xJ$kr)S5?!(|M{N_uZhgzck}PwuKAzHWVX6- zQ}Qm2Q$>>Is7jeZbTU!U_ioMZLT)@2VwzD>Fx7H#j-;K>q5uDSJKoufw}xZJhZ*DL z?eMcV2ChG_Qlhhd!wU!?5-=>49A+XR8CG)zo3PDtk-~r6-lgmnoogX7h-|bESUJC3Dfs>Owom%%#_S^Vjp6Mmmb4pP? z-`QwON_KLqbv zb4e?-P$>Vl8H3Tl zF+8t}V+sY8kTFiBZ3p>tpr$-`U&V-fgY_-JM7G z_kTai1M8msf+RBvCoG|SbzV>>M8HnGHGuynyd-iCJ6l`J0*l+gD5K%<=H@0Q*i9_t zbeP$$)UanNULKu4yMX=ELpXSTdU$+!{QUF+o<2W^7Z*nZI6pc&e}4Glz`Pz{sl(%o z%k$%}Uzj)8z&7Up^%pwgo`a_EM$`v2BUy%l-dzw|nPW`&Ft+qWNGKH@U`hm$mMGHu z^e(1sYSa!kb{W?iF`6!{0-#_U^h{#v>wi|+byAU(IVO^B!X@MaV2LQ^(n!!CZa9@7 zBv7uIo>xh{u|IF8>8RneeM}|c+9&dGcnAQXQElooY_LsRRoqZHaA}Kd5On){VD>{BZM;quXFnkZB;%og#!p;9YN zP|q{dB&qT(vP~FMPA4p3Bx|-Fz*$fEkD~0uhLHG6_BX>>CmeBd&C=4eB_X5_*8shx zGGUk-rl8X4;*QRIHcF-zN$mpF@;*kgZBtr-LE5CvE0yC4%*mDMA{Qx}_*(^jf^Bd? z^LboqOn-oZh-hl&QHhDZG34a}t(on4P_4Z%6NoJ^@asR!7i{E%8g!f8ei3xS=k}eX zs?2bGU`ijC0y3%63}b4GIs&jEW%DL;e@=jaMGrPNXb!M4i#CRth`eBCLAhj+c9>O& zyXJsH?v)7cQV*gSXxDB|Q$}p|jC$BV2zj-@6fi=Lff)Iap|pAlFz$y@EdYx;H>{kb z6o?P=@7907mj;HL`W$UG=3T`XJa^+lvxHXc&Bd9-G>?X@Xl;{Ux){#}TGzw|;Xb#R zspyh;`uvcvUlf$5>=wo}6E~YR77i(;cBW*OkCn0 z#6E$WnaFTafRTkUf9T?zFY;s0rzVZ%KY%v+9QF(~`xv1&_#P1>X-=y1a77Cukx~p^ za2Pq2G@Bbm;R+FlQMAT$RM|KEq%*FmoR9=Ji9xVOR!Cg{%3z0zNj>WahLyWLzH`Rg zYoJ=PL4OqjTe&_fI80-WIYAmuQx;ATj*4hoOUR|b4}wLZ4c8Z()N%M#InJ4O%)`qa zF1dS>mC7XvslantgH1#+NA0>C#2UVwYa->ut%HT<>da)q>)nMgTRPnB` z55WVNASWy{l{2Qa8iZR`B?{Sab1G!v7zxg7Aqno0u7sU_v-4SLrINKmqz?i%(x8F> z+nDu=siefLg|^2W`K1#he?X2`Z%y>pBcVA~PmhVxtn3GJ; zqlu(+08C1HEfT}X7j|=}|CtWGwnYa%Psk#ttJ!%`jx&~Ib3>>_M&^V1jZ6JJFxbv2 z!6MY#LNUMM#V9N<^w_bTBX6-2^eC91GlDsf{{FMGL2naUXt3!hv=@<>0%aAVO(^VG zgW1c;6&=`Q2G)+z-poM~;%J#&Fzx-l9Y=GI?dxtrV|l)N9Obd0wiryMqtM z>1l;jDdjLonIpamyO@J7qp4*DyD^;8&@vQb*SXCsV>w%!3nijpUbboQqZLvfPKgm4 zY0AocVCl$6G)&KG2c)LjY`5?woNQ35LWq!>v~o&a+Gdeu;--;WR*iaKl?KtYDZ_G!%VBm_TS@pal1awkGkPxQ+Tg$3dSiOX_LDO4}_%_SV^O~hI}jYg;4XL#n(4-HCti`*h{h-uMx6?+^sY+1 zT8oUJcccT8co=J3*BEM0m0AhIe}>GwL1f{&ZW^F~O=>=4w#;e011`2N6EGUsSzoVIT7gnc*=3u^2c(AH; zW#l7Spu8Fhr3sE(Tgb8I4cmORZICoIzopT4LW&Gp@t`{l-DM>VEcR71v4fC4U4NQV zo|d^6TN@PP8H?5b{B*W?8Y0*mF-X?En9y1UW1B8i%d$;>7BS1tEjm$DYZWNAqOslz z04>8;Fcqc|H;xcwAt7ZG%o`F&xg8RGZQAQNGP2DCXGLPt0nMOZHWO49=Sx(P&^lKw zC2Y@h9a!^f02WTG8oO{MbtfXXqO_r-hFPZ4R9c!qV?rLIvg1wytgc#1fhvX>&QwM)$3!_*g9GoF5AIJP!O^fS?1|PxJgBWsPEGaMWsxRqCRp6kaY`}V zACYr}hH;nfaO|d{Qaad_E!t=OYVz~uc7u*Bz+&o242Mji>O`d}^#hRxFY{^v`cgLrP1E9>F0N)mvBeEI^ zL%xy*X3}~Ep`Da?J~f9Miz-xzGRX*`1I-d@#!~5&yG$n2k`9Z z{NUUD)64y@k57&-e?$^`dVG0$bYa~G_FWri`{$R(2QNp__y1w0qDnJBt8LEy>BWX~Q?Qy-Pst9H0uCu-eGRc*0U6*xI86Bfwaj zE+d(5)N|-$MhuFm1S0L3x!J|5y;_x-ZY#Qo&9dS#rO($MWGZhuDp(e<@=V-AWrm#z zOR!TR(i@hAw!S`-DD(gDf@r2*U}JhEO8*`(yPaD$s*hbKrP^4t(_h!5K_Rht8( zLnENK4RNlG%9u{lYlerU6X(966mv-M&JC`4y8`|h!#?J4HCXVR*Yvz!Z`8q}_+e&5 z_vUhK9~Q1WZu3%TG84jDLDACLIBZ9oD-f7ad^Gp**!U zW+F>FOy@-A$cemgU170a&ZU&~X_>Pe6Q!s$%f}f}2a9&&@w}OKUQCSGB?FvR!u(A@ zje*!$!D0#c==9L+t6gqz_UctTobjxrVdm@Sp2 zV0dsJTw3}C=NAJeC5lz&@eXtT+_f^#)J6^>lNr1AoU%Sl+}YaMhB`C`eswgF1}ajM zS_Yy2Cv2Dkm5b#jh6wQLhgtV_w{q5UFSRr7v`*xN6#-QeO`zn9F&f86!$RljmS|7i z>pV=Ir*pIuZ()_Y2;|E|4d-Ik3yqQue0lJgY7|%|aKERt?d5Dl+XbZ!5Ijwz6f*7CcE#&{& zeY|y_|NWyp4+2IH&;1SSp4m8G)?a?w@S$4_Cv9HQ-mIz_&PL$nchv>B>dJOqzatrQ zBDi7yYKVy%(kMu8S&`&s5BFER8S8YGATI~z&h&@>m7k}}Sb#gPCRbFUzdBy{QJ(Ks z?vd8AUtKXz(2otzLkSd8+|KREVWExMaswWI3=84uck@^ z<=0FKj#37ZqU33h1mm&nnJTlfG~oiK70o6V(Ln`^9A=G}B)cJV11`+{MWg;>(Ka{h?0O(lT4H;cHu5)`#C}Azo8n=X(8a4PeiZx z^UptziJJ9r#L~PcX&T1jsp1mVkhsjNOjI-&nd-x!5qD$z=bwM>^XMGYPf1Q)@q?2W7neup(dquP zqpud`$qi!dRJn5NXA4)2zXA=vh_N@5^m;#7n@!RBZdl5UCRg>*jh|lAMRlDUl*s+n zk6JdZf*QoVo;yhQebN-tQhH0H>(QB2=c0UQrp`%(^}#Te(r{H<&(#^>#P^QOrx6^V zUR>^Ie1E~vMgbfn_&Nx_c694P1K?bsV+HbABZgY9l1xmMGn=A% zP{oO=2rvj<6;Kh@`$deqXs(fp5qsXBpb?ARdKBT<2T*c9I~9X;0mueE$`<0x4*3@` z?&01d=N@0E-%knSqt=RPLRsNQJA;HR;u(*mxwtl4 zsY6n*FI1sg7LC_+sz|E_XIR0Kv%N^)Seg|uYZqr#a^3PgI6qV_Qb&Cs$$=!%YT<^4 zUsF0EWoDtRO$RyQB_22?87184c0~tax`|3;+DePj+UV+ODyEX4m9}e|!mXxj-mo%# z2UcwRKlfb32{*VRoOpu*1$Vmcn1Z{lrv(%&xiT9LE?Htkm0qylxa2f3yl`iIE@_7k z#8u6bwOJ&yI=TXCnx3=a-J|ZM|F5dXR|~Dza*-Y44~7C!Sh;>QfIAR^#db&ty(NU; zO2)kd!O?DyMjn`;SG!c@Kq}EhLU@mH!%~RGgSWAy_V%A^&(I}a2E@5=qP>bk$Pvcv z_))yQvq(hN>KVD5^^u`jh$fXND9MeJ0ZT=tJL5%pDOgoa(J&{B4{dir2<1ekYS>}~ zbCOqFx&`cZyw&S{ef0GC`4PN0`{sQA@M!Jkw=@9cG?9sxjFLHly3|*1J#WmYL9x2I|(kgSr)O@5GNj8mzXvw*vO56nVu~@Jgly zdaDBe)(R<($EnU;Q46@Xh2viDMML5%B)!J?9!@H8KGJmo%h}N9O(l}(WMS1QGL#Qlq497@%53jNDa9ky4j^c*fSl3dkonL4pD?{G?V zFez1?A>JKNUo(EqG#&n?qua+ak-zcX=zqTbX8Zs7HTm}Re~zF1uid%$?Ogu$#s22M z-J5#$9p^X_TP{3+}nTe?Z5Z--+TM-z5Vyz{(Eo# zy|@3~+kfxvzxVdvd;9Ob{rBGfdvE`}xBuSTfA8(T_x9iaeV;D-@2@3QmNCD7?$>|Z zA^!iP$8G!X-uCXJd;9Olc&fP`^&+??5^qF~oY|!ZUH~3JfATg@AFEckT}IIFwq4n% zwVVe*(b`tN*d`mY<*NjJHrIyI(%wSCTvH?L!NNVYXMZt8DL{Z{0ul&;4`% T_~-u*00960NuM}d03ZPXWJ~1{ literal 0 HcmV?d00001 diff --git a/charts/bitnami/mysql/Chart.yaml b/charts/bitnami/mysql/Chart.yaml index 28cafeddc..67294b564 100644 --- a/charts/bitnami/mysql/Chart.yaml +++ b/charts/bitnami/mysql/Chart.yaml @@ -29,4 +29,4 @@ maintainers: name: mysql sources: - https://github.com/bitnami/charts/tree/main/bitnami/mysql -version: 9.10.2 +version: 9.10.4 diff --git a/charts/bitnami/mysql/values.yaml b/charts/bitnami/mysql/values.yaml index 91f4953be..69097e93e 100644 --- a/charts/bitnami/mysql/values.yaml +++ b/charts/bitnami/mysql/values.yaml @@ -201,7 +201,6 @@ primary: character-set-server=UTF8 collation-server=utf8_general_ci slow_query_log=0 - slow_query_log_file=/opt/bitnami/mysql/logs/mysqld.log long_query_time=10.0 [client] @@ -580,7 +579,6 @@ secondary: character-set-server=UTF8 collation-server=utf8_general_ci slow_query_log=0 - slow_query_log_file=/opt/bitnami/mysql/logs/mysqld.log long_query_time=10.0 [client] diff --git a/charts/bitnami/postgresql/Chart.yaml b/charts/bitnami/postgresql/Chart.yaml index 9fbbc0867..a1f10715f 100644 --- a/charts/bitnami/postgresql/Chart.yaml +++ b/charts/bitnami/postgresql/Chart.yaml @@ -31,4 +31,4 @@ maintainers: name: postgresql sources: - https://github.com/bitnami/charts/tree/main/bitnami/postgresql -version: 12.5.6 +version: 12.5.7 diff --git a/charts/bitnami/postgresql/README.md b/charts/bitnami/postgresql/README.md index fc7478081..86ed99e56 100644 --- a/charts/bitnami/postgresql/README.md +++ b/charts/bitnami/postgresql/README.md @@ -668,7 +668,7 @@ Refer to the [chart documentation for more information about how to upgrade from ## License -Copyright © 2023 Bitnami +Copyright © 2023 VMware, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/charts/bitnami/postgresql/templates/_helpers.tpl b/charts/bitnami/postgresql/templates/_helpers.tpl index 818938064..4aeb82a9d 100644 --- a/charts/bitnami/postgresql/templates/_helpers.tpl +++ b/charts/bitnami/postgresql/templates/_helpers.tpl @@ -154,7 +154,7 @@ Get the user-password key. Return true if a secret object should be created */}} {{- define "postgresql.createSecret" -}} -{{- if not (or .Values.global.postgresql.auth.existingSecret .Values.auth.existingSecret) -}} +{{- if and (not (or .Values.global.postgresql.auth.existingSecret .Values.auth.existingSecret)) (.Values.auth.enablePostgresUser) -}} {{- true -}} {{- end -}} {{- end -}} diff --git a/charts/bitnami/postgresql/templates/primary/statefulset.yaml b/charts/bitnami/postgresql/templates/primary/statefulset.yaml index d56d052e3..d9e922a06 100644 --- a/charts/bitnami/postgresql/templates/primary/statefulset.yaml +++ b/charts/bitnami/postgresql/templates/primary/statefulset.yaml @@ -207,6 +207,10 @@ spec: value: {{ .Values.containerPorts.postgresql | quote }} - name: POSTGRESQL_VOLUME_DIR value: {{ .Values.primary.persistence.mountPath | quote }} + {{- if not .Values.auth.enablePostgresUser }} + - name: ALLOW_EMPTY_PASSWORD + value: "true" + {{- end }} {{- if .Values.primary.persistence.mountPath }} - name: PGDATA value: {{ .Values.postgresqlDataDir | quote }} @@ -228,6 +232,7 @@ spec: {{- end }} {{- end }} {{- end }} + {{- if .Values.auth.enablePostgresUser }} {{- if .Values.auth.usePasswordFiles }} - name: POSTGRES_PASSWORD_FILE value: {{ printf "/opt/bitnami/postgresql/secrets/%s" (include "postgresql.userPasswordKey" .) }} @@ -238,6 +243,7 @@ spec: name: {{ include "postgresql.secretName" . }} key: {{ include "postgresql.userPasswordKey" . }} {{- end }} + {{- end }} {{- if (include "postgresql.database" .) }} - name: POSTGRES_DB value: {{ (include "postgresql.database" .) | quote }} diff --git a/charts/datadog/datadog/CHANGELOG.md b/charts/datadog/datadog/CHANGELOG.md index ed446c7fe..c047cb074 100644 --- a/charts/datadog/datadog/CHANGELOG.md +++ b/charts/datadog/datadog/CHANGELOG.md @@ -1,5 +1,9 @@ # Datadog changelog +## 3.32.1 + +* Fix CVE in the FIPS compliant side car container + ## 3.32.0 * Add a new preferred parameter to enable Remote Configuration on both the agent and the cluster agent. diff --git a/charts/datadog/datadog/Chart.yaml b/charts/datadog/datadog/Chart.yaml index 2185a208b..2ae43d51e 100644 --- a/charts/datadog/datadog/Chart.yaml +++ b/charts/datadog/datadog/Chart.yaml @@ -19,4 +19,4 @@ name: datadog sources: - https://app.datadoghq.com/account/settings#agent/kubernetes - https://github.com/DataDog/datadog-agent -version: 3.32.0 +version: 3.32.1 diff --git a/charts/datadog/datadog/README.md b/charts/datadog/datadog/README.md index e0206bd6e..60b0662d3 100644 --- a/charts/datadog/datadog/README.md +++ b/charts/datadog/datadog/README.md @@ -1,6 +1,6 @@ # Datadog -![Version: 3.32.0](https://img.shields.io/badge/Version-3.32.0-informational?style=flat-square) ![AppVersion: 7](https://img.shields.io/badge/AppVersion-7-informational?style=flat-square) +![Version: 3.32.1](https://img.shields.io/badge/Version-3.32.1-informational?style=flat-square) ![AppVersion: 7](https://img.shields.io/badge/AppVersion-7-informational?style=flat-square) [Datadog](https://www.datadoghq.com/) is a hosted infrastructure monitoring platform. This chart adds the Datadog Agent to all nodes in your cluster via a DaemonSet. It also optionally depends on the [kube-state-metrics chart](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-state-metrics). For more information about monitoring Kubernetes with Datadog, please refer to the [Datadog documentation website](https://docs.datadoghq.com/agent/basic_agent_usage/kubernetes/). @@ -739,7 +739,7 @@ helm install \ | fips.image.name | string | `"fips-proxy"` | | | fips.image.pullPolicy | string | `"IfNotPresent"` | Datadog the FIPS sidecar image pull policy | | fips.image.repository | string | `nil` | | -| fips.image.tag | string | `"0.5.2"` | Define the FIPS sidecar container version to use. | +| fips.image.tag | string | `"0.5.3"` | Define the FIPS sidecar container version to use. | | fips.local_address | string | `"127.0.0.1"` | | | fips.port | int | `9803` | | | fips.portRange | int | `15` | | diff --git a/charts/datadog/datadog/values.yaml b/charts/datadog/datadog/values.yaml index a0582f330..84f5d2bae 100644 --- a/charts/datadog/datadog/values.yaml +++ b/charts/datadog/datadog/values.yaml @@ -1175,7 +1175,7 @@ fips: name: fips-proxy # fips.image.tag -- Define the FIPS sidecar container version to use. - tag: 0.5.2 + tag: 0.5.3 # fips.image.pullPolicy -- Datadog the FIPS sidecar image pull policy pullPolicy: IfNotPresent diff --git a/charts/gluu/gluu/Chart.yaml b/charts/gluu/gluu/Chart.yaml index 1d88580ad..650be6a06 100644 --- a/charts/gluu/gluu/Chart.yaml +++ b/charts/gluu/gluu/Chart.yaml @@ -1,28 +1,28 @@ annotations: artifacthub.io/changes: | - - Chart 5.0.17 official release + - Chart 5.0.18 official release artifacthub.io/containsSecurityUpdates: "true" artifacthub.io/images: | - name: auth-server - image: ghcr.io/janssenproject/jans/auth-server:1.0.13_dev + image: ghcr.io/janssenproject/jans/auth-server:1.0.14_dev - name: auth-server-key-rotation - image: ghcr.io/janssenproject/jans/certmanager:1.0.13_dev + image: ghcr.io/janssenproject/jans/certmanager:1.0.14_dev - name: configuration-manager - image: ghcr.io/janssenproject/jans/configurator:1.0.13_dev + image: ghcr.io/janssenproject/jans/configurator:1.0.14_dev - name: config-api - image: ghcr.io/janssenproject/jans/config-api:1.0.13_dev + image: ghcr.io/janssenproject/jans/config-api:1.0.14_dev - name: fido2 - image: ghcr.io/janssenproject/jans/fido2:1.0.13_dev + image: ghcr.io/janssenproject/jans/fido2:1.0.14_dev - name: opendj image: gluufederation/opendj:5.0.0_dev - name: persistence - image: ghcr.io/janssenproject/jans/persistence-loader:1.0.13_dev + image: ghcr.io/janssenproject/jans/persistence-loader:1.0.14_dev - name: scim - image: ghcr.io/janssenproject/jans/scim:1.0.13_dev + image: ghcr.io/janssenproject/jans/scim:1.0.14_dev - name: casa image: ghcr.io/gluufederation/flex/casa:5.0.0_dev - name: admin-ui - image: ghcr.io/gluufederation/flex/admin-ui:1.0.13_dev + image: ghcr.io/gluufederation/flex/admin-ui:1.0.14_dev artifacthub.io/license: Apache-2.0 artifacthub.io/prerelease: "true" catalog.cattle.io/certified: partner @@ -35,59 +35,59 @@ dependencies: - condition: global.config.enabled name: config repository: file://./charts/config - version: 5.0.17 + version: 5.0.18 - condition: global.config-api.enabled name: config-api repository: file://./charts/config-api - version: 5.0.17 + version: 5.0.18 - condition: global.opendj.enabled name: opendj repository: file://./charts/opendj - version: 5.0.17 + version: 5.0.18 - condition: global.auth-server.enabled name: auth-server repository: file://./charts/auth-server - version: 5.0.17 + version: 5.0.18 - condition: global.admin-ui.enabled name: admin-ui repository: file://./charts/admin-ui - version: 5.0.17 + version: 5.0.18 - condition: global.fido2.enabled name: fido2 repository: file://./charts/fido2 - version: 5.0.17 + version: 5.0.18 - condition: global.scim.enabled name: scim repository: file://./charts/scim - version: 5.0.17 + version: 5.0.18 - condition: global.nginx-ingress.enabled name: nginx-ingress repository: file://./charts/nginx-ingress - version: 5.0.17 + version: 5.0.18 - condition: global.oxshibboleth.enabled name: oxshibboleth repository: file://./charts/oxshibboleth - version: 5.0.17 + version: 5.0.18 - condition: global.oxpassport.enabled name: oxpassport repository: file://./charts/oxpassport - version: 5.0.17 + version: 5.0.18 - condition: global.casa.enabled name: casa repository: file://./charts/casa - version: 5.0.17 + version: 5.0.18 - condition: global.auth-server-key-rotation.enabled name: auth-server-key-rotation repository: file://./charts/auth-server-key-rotation - version: 5.0.17 + version: 5.0.18 - condition: global.persistence.enabled name: persistence repository: file://./charts/persistence - version: 5.0.17 + version: 5.0.18 - condition: global.istio.ingress name: cn-istio-ingress repository: file://./charts/cn-istio-ingress - version: 5.0.17 + version: 5.0.18 description: Gluu Access and Identity Management home: https://www.gluu.org icon: https://gluu.org/docs/gluu-server/favicon.ico @@ -99,4 +99,4 @@ name: gluu sources: - https://gluu.org/docs/gluu-server - https://github.com/GluuFederation/flex/flex-cn-setup -version: 5.0.17 +version: 5.0.18 diff --git a/charts/gluu/gluu/README.md b/charts/gluu/gluu/README.md index 10b9eeea4..19eb8acaa 100644 --- a/charts/gluu/gluu/README.md +++ b/charts/gluu/gluu/README.md @@ -1,6 +1,6 @@ # gluu -![Version: 5.0.17](https://img.shields.io/badge/Version-5.0.17-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) +![Version: 5.0.18](https://img.shields.io/badge/Version-5.0.18-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) Gluu Access and Identity Management @@ -23,26 +23,26 @@ Kubernetes: `>=v1.21.0-0` | Repository | Name | Version | |------------|------|---------| -| | admin-ui | 5.0.17 | -| | auth-server | 5.0.17 | -| | auth-server-key-rotation | 5.0.17 | -| | casa | 5.0.17 | -| | cn-istio-ingress | 5.0.17 | -| | config | 5.0.17 | -| | config-api | 5.0.17 | -| | fido2 | 5.0.17 | -| | nginx-ingress | 5.0.17 | -| | opendj | 5.0.17 | -| | oxpassport | 5.0.17 | -| | oxshibboleth | 5.0.17 | -| | persistence | 5.0.17 | -| | scim | 5.0.17 | +| | admin-ui | 5.0.18 | +| | auth-server | 5.0.18 | +| | auth-server-key-rotation | 5.0.18 | +| | casa | 5.0.18 | +| | cn-istio-ingress | 5.0.18 | +| | config | 5.0.18 | +| | config-api | 5.0.18 | +| | fido2 | 5.0.18 | +| | nginx-ingress | 5.0.18 | +| | opendj | 5.0.18 | +| | oxpassport | 5.0.18 | +| | oxshibboleth | 5.0.18 | +| | persistence | 5.0.18 | +| | scim | 5.0.18 | ## Values | Key | Type | Default | Description | |-----|------|---------|-------------| -| admin-ui | object | `{"additionalAnnotations":{},"additionalLabels":{},"dnsConfig":{},"dnsPolicy":"","hpa":{"behavior":{},"enabled":true,"maxReplicas":10,"metrics":[],"minReplicas":1,"targetCPUUtilizationPercentage":50},"image":{"pullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/gluufederation/flex/admin-ui","tag":"1.0.13_dev"},"lifecycle":{},"livenessProbe":{"failureThreshold":20,"initialDelaySeconds":60,"periodSeconds":25,"tcpSocket":{"port":8080},"timeoutSeconds":5},"pdb":{"enabled":true,"maxUnavailable":"90%"},"readinessProbe":{"failureThreshold":20,"initialDelaySeconds":60,"periodSeconds":25,"tcpSocket":{"port":8080},"timeoutSeconds":5},"replicas":1,"resources":{"limits":{"cpu":"2000m","memory":"2000Mi"},"requests":{"cpu":"2000m","memory":"2000Mi"}},"topologySpreadConstraints":{},"usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | Admin GUI for configuration of the auth-server | +| admin-ui | object | `{"additionalAnnotations":{},"additionalLabels":{},"dnsConfig":{},"dnsPolicy":"","hpa":{"behavior":{},"enabled":true,"maxReplicas":10,"metrics":[],"minReplicas":1,"targetCPUUtilizationPercentage":50},"image":{"pullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/gluufederation/flex/admin-ui","tag":"1.0.14-1"},"lifecycle":{},"livenessProbe":{"failureThreshold":20,"initialDelaySeconds":60,"periodSeconds":25,"tcpSocket":{"port":8080},"timeoutSeconds":5},"pdb":{"enabled":true,"maxUnavailable":"90%"},"readinessProbe":{"failureThreshold":20,"initialDelaySeconds":60,"periodSeconds":25,"tcpSocket":{"port":8080},"timeoutSeconds":5},"replicas":1,"resources":{"limits":{"cpu":"2000m","memory":"2000Mi"},"requests":{"cpu":"2000m","memory":"2000Mi"}},"topologySpreadConstraints":{},"usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | Admin GUI for configuration of the auth-server | | admin-ui.additionalAnnotations | object | `{}` | Additional annotations that will be added across the gateway in the format of {cert-manager.io/issuer: "letsencrypt-prod"} | | admin-ui.additionalLabels | object | `{}` | Additional labels that will be added across the gateway in the format of {mylabel: "myapp"} | | admin-ui.dnsConfig | object | `{}` | Add custom dns config | @@ -53,7 +53,7 @@ Kubernetes: `>=v1.21.0-0` | admin-ui.image.pullPolicy | string | `"IfNotPresent"` | Image pullPolicy to use for deploying. | | admin-ui.image.pullSecrets | list | `[]` | Image Pull Secrets | | admin-ui.image.repository | string | `"ghcr.io/gluufederation/flex/admin-ui"` | Image to use for deploying. | -| admin-ui.image.tag | string | `"1.0.13_dev"` | Image tag to use for deploying. | +| admin-ui.image.tag | string | `"1.0.14-1"` | Image tag to use for deploying. | | admin-ui.livenessProbe | object | `{"failureThreshold":20,"initialDelaySeconds":60,"periodSeconds":25,"tcpSocket":{"port":8080},"timeoutSeconds":5}` | Configure the liveness healthcheck for the admin ui if needed. | | admin-ui.pdb | object | `{"enabled":true,"maxUnavailable":"90%"}` | Configure the PodDisruptionBudget | | admin-ui.readinessProbe | object | `{"failureThreshold":20,"initialDelaySeconds":60,"periodSeconds":25,"tcpSocket":{"port":8080},"timeoutSeconds":5}` | Configure the readiness healthcheck for the admin ui if needed. | @@ -69,8 +69,8 @@ Kubernetes: `>=v1.21.0-0` | admin-ui.usrEnvs.secret | object | `{}` | Add custom secret envs to the service variable1: value1 | | admin-ui.volumeMounts | list | `[]` | Configure any additional volumesMounts that need to be attached to the containers | | admin-ui.volumes | list | `[]` | Configure any additional volumes that need to be attached to the pod | -| auth-server | object | `{"additionalAnnotations":{},"additionalLabels":{},"dnsConfig":{},"dnsPolicy":"","hpa":{"behavior":{},"enabled":true,"maxReplicas":10,"metrics":[],"minReplicas":1,"targetCPUUtilizationPercentage":50},"image":{"pullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/janssenproject/jans/auth-server","tag":"1.0.13_dev"},"lifecycle":{},"livenessProbe":{"exec":{"command":["python3","/app/scripts/healthcheck.py"]},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5},"pdb":{"enabled":true,"maxUnavailable":"90%"},"readinessProbe":{"exec":{"command":["python3","/app/scripts/healthcheck.py"]},"initialDelaySeconds":25,"periodSeconds":25,"timeoutSeconds":5},"replicas":1,"resources":{"limits":{"cpu":"2500m","memory":"2500Mi"},"requests":{"cpu":"2500m","memory":"2500Mi"}},"topologySpreadConstraints":{},"usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | OAuth Authorization Server, the OpenID Connect Provider, the UMA Authorization Server--this is the main Internet facing component of Gluu. It's the service that returns tokens, JWT's and identity assertions. This service must be Internet facing. | -| auth-server-key-rotation | object | `{"additionalAnnotations":{},"additionalLabels":{},"dnsConfig":{},"dnsPolicy":"","image":{"pullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/janssenproject/jans/certmanager","tag":"1.0.13_dev"},"keysLife":48,"lifecycle":{},"resources":{"limits":{"cpu":"300m","memory":"300Mi"},"requests":{"cpu":"300m","memory":"300Mi"}},"usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | Responsible for regenerating auth-keys per x hours | +| auth-server | object | `{"additionalAnnotations":{},"additionalLabels":{},"dnsConfig":{},"dnsPolicy":"","hpa":{"behavior":{},"enabled":true,"maxReplicas":10,"metrics":[],"minReplicas":1,"targetCPUUtilizationPercentage":50},"image":{"pullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/janssenproject/jans/auth-server","tag":"1.0.14-1"},"lifecycle":{},"livenessProbe":{"exec":{"command":["python3","/app/scripts/healthcheck.py"]},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5},"pdb":{"enabled":true,"maxUnavailable":"90%"},"readinessProbe":{"exec":{"command":["python3","/app/scripts/healthcheck.py"]},"initialDelaySeconds":25,"periodSeconds":25,"timeoutSeconds":5},"replicas":1,"resources":{"limits":{"cpu":"2500m","memory":"2500Mi"},"requests":{"cpu":"2500m","memory":"2500Mi"}},"topologySpreadConstraints":{},"usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | OAuth Authorization Server, the OpenID Connect Provider, the UMA Authorization Server--this is the main Internet facing component of Gluu. It's the service that returns tokens, JWT's and identity assertions. This service must be Internet facing. | +| auth-server-key-rotation | object | `{"additionalAnnotations":{},"additionalLabels":{},"dnsConfig":{},"dnsPolicy":"","image":{"pullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/janssenproject/jans/certmanager","tag":"1.0.14-1"},"keysLife":48,"lifecycle":{},"resources":{"limits":{"cpu":"300m","memory":"300Mi"},"requests":{"cpu":"300m","memory":"300Mi"}},"usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | Responsible for regenerating auth-keys per x hours | | auth-server-key-rotation.additionalAnnotations | object | `{}` | Additional annotations that will be added across the gateway in the format of {cert-manager.io/issuer: "letsencrypt-prod"} | | auth-server-key-rotation.additionalLabels | object | `{}` | Additional labels that will be added across the gateway in the format of {mylabel: "myapp"} | | auth-server-key-rotation.dnsConfig | object | `{}` | Add custom dns config | @@ -78,7 +78,7 @@ Kubernetes: `>=v1.21.0-0` | auth-server-key-rotation.image.pullPolicy | string | `"IfNotPresent"` | Image pullPolicy to use for deploying. | | auth-server-key-rotation.image.pullSecrets | list | `[]` | Image Pull Secrets | | auth-server-key-rotation.image.repository | string | `"ghcr.io/janssenproject/jans/certmanager"` | Image to use for deploying. | -| auth-server-key-rotation.image.tag | string | `"1.0.13_dev"` | Image tag to use for deploying. | +| auth-server-key-rotation.image.tag | string | `"1.0.14-1"` | Image tag to use for deploying. | | auth-server-key-rotation.keysLife | int | `48` | Auth server key rotation keys life in hours | | auth-server-key-rotation.resources | object | `{"limits":{"cpu":"300m","memory":"300Mi"},"requests":{"cpu":"300m","memory":"300Mi"}}` | Resource specs. | | auth-server-key-rotation.resources.limits.cpu | string | `"300m"` | CPU limit. | @@ -100,7 +100,7 @@ Kubernetes: `>=v1.21.0-0` | auth-server.image.pullPolicy | string | `"IfNotPresent"` | Image pullPolicy to use for deploying. | | auth-server.image.pullSecrets | list | `[]` | Image Pull Secrets | | auth-server.image.repository | string | `"ghcr.io/janssenproject/jans/auth-server"` | Image to use for deploying. | -| auth-server.image.tag | string | `"1.0.13_dev"` | Image tag to use for deploying. | +| auth-server.image.tag | string | `"1.0.14-1"` | Image tag to use for deploying. | | auth-server.livenessProbe | object | `{"exec":{"command":["python3","/app/scripts/healthcheck.py"]},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5}` | Configure the liveness healthcheck for the auth server if needed. | | auth-server.livenessProbe.exec | object | `{"command":["python3","/app/scripts/healthcheck.py"]}` | Executes the python3 healthcheck. https://github.com/JanssenProject/docker-jans-auth-server/blob/master/scripts/healthcheck.py | | auth-server.pdb | object | `{"enabled":true,"maxUnavailable":"90%"}` | Configure the PodDisruptionBudget | @@ -117,7 +117,7 @@ Kubernetes: `>=v1.21.0-0` | auth-server.usrEnvs.secret | object | `{}` | Add custom secret envs to the service variable1: value1 | | auth-server.volumeMounts | list | `[]` | Configure any additional volumesMounts that need to be attached to the containers | | auth-server.volumes | list | `[]` | Configure any additional volumes that need to be attached to the pod | -| casa | object | `{"additionalAnnotations":{},"additionalLabels":{},"dnsConfig":{},"dnsPolicy":"","hpa":{"behavior":{},"enabled":true,"maxReplicas":10,"metrics":[],"minReplicas":1,"targetCPUUtilizationPercentage":50},"image":{"pullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/gluufederation/flex/casa","tag":"5.0.0_dev"},"lifecycle":{},"livenessProbe":{"httpGet":{"path":"/casa/health-check","port":"http-casa"},"initialDelaySeconds":25,"periodSeconds":25,"timeoutSeconds":5},"pdb":{"enabled":true,"maxUnavailable":"90%"},"readinessProbe":{"httpGet":{"path":"/casa/health-check","port":"http-casa"},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5},"replicas":1,"resources":{"limits":{"cpu":"500m","memory":"500Mi"},"requests":{"cpu":"500m","memory":"500Mi"}},"topologySpreadConstraints":{},"usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | Gluu Casa ("Casa") is a self-service web portal for end-users to manage authentication and authorization preferences for their account in a Gluu Server. | +| casa | object | `{"additionalAnnotations":{},"additionalLabels":{},"dnsConfig":{},"dnsPolicy":"","hpa":{"behavior":{},"enabled":true,"maxReplicas":10,"metrics":[],"minReplicas":1,"targetCPUUtilizationPercentage":50},"image":{"pullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/gluufederation/flex/casa","tag":"5.0.0-13"},"lifecycle":{},"livenessProbe":{"httpGet":{"path":"/casa/health-check","port":"http-casa"},"initialDelaySeconds":25,"periodSeconds":25,"timeoutSeconds":5},"pdb":{"enabled":true,"maxUnavailable":"90%"},"readinessProbe":{"httpGet":{"path":"/casa/health-check","port":"http-casa"},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5},"replicas":1,"resources":{"limits":{"cpu":"500m","memory":"500Mi"},"requests":{"cpu":"500m","memory":"500Mi"}},"topologySpreadConstraints":{},"usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | Gluu Casa ("Casa") is a self-service web portal for end-users to manage authentication and authorization preferences for their account in a Gluu Server. | | casa.additionalAnnotations | object | `{}` | Additional annotations that will be added across the gateway in the format of {cert-manager.io/issuer: "letsencrypt-prod"} | | casa.additionalLabels | object | `{}` | Additional labels that will be added across the gateway in the format of {mylabel: "myapp"} | | casa.dnsConfig | object | `{}` | Add custom dns config | @@ -128,7 +128,7 @@ Kubernetes: `>=v1.21.0-0` | casa.image.pullPolicy | string | `"IfNotPresent"` | Image pullPolicy to use for deploying. | | casa.image.pullSecrets | list | `[]` | Image Pull Secrets | | casa.image.repository | string | `"ghcr.io/gluufederation/flex/casa"` | Image to use for deploying. | -| casa.image.tag | string | `"5.0.0_dev"` | Image tag to use for deploying. | +| casa.image.tag | string | `"5.0.0-13"` | Image tag to use for deploying. | | casa.livenessProbe | object | `{"httpGet":{"path":"/casa/health-check","port":"http-casa"},"initialDelaySeconds":25,"periodSeconds":25,"timeoutSeconds":5}` | Configure the liveness healthcheck for casa if needed. | | casa.livenessProbe.httpGet.path | string | `"/casa/health-check"` | http liveness probe endpoint | | casa.pdb | object | `{"enabled":true,"maxUnavailable":"90%"}` | Configure the PodDisruptionBudget | @@ -146,8 +146,8 @@ Kubernetes: `>=v1.21.0-0` | casa.usrEnvs.secret | object | `{}` | Add custom secret envs to the service variable1: value1 | | casa.volumeMounts | list | `[]` | Configure any additional volumesMounts that need to be attached to the containers | | casa.volumes | list | `[]` | Configure any additional volumes that need to be attached to the pod | -| config | object | `{"additionalAnnotations":{},"additionalLabels":{},"adminPassword":"Test1234#","city":"Austin","configmap":{"cnAwsAccessKeyId":"","cnAwsDefaultRegion":"us-west-1","cnAwsProfile":"gluu","cnAwsSecretAccessKey":"","cnAwsSecretsEndpointUrl":"","cnAwsSecretsNamePrefix":"gluu","cnAwsSecretsReplicaRegions":[],"cnCacheType":"NATIVE_PERSISTENCE","cnConfigKubernetesConfigMap":"cn","cnCouchbaseBucketPrefix":"jans","cnCouchbaseCrt":"SWFtTm90YVNlcnZpY2VBY2NvdW50Q2hhbmdlTWV0b09uZQo=","cnCouchbaseIndexNumReplica":0,"cnCouchbasePassword":"P@ssw0rd","cnCouchbaseSuperUser":"admin","cnCouchbaseSuperUserPassword":"Test1234#","cnCouchbaseUrl":"cbgluu.default.svc.cluster.local","cnCouchbaseUser":"gluu","cnGoogleProjectId":"google-project-to-save-config-and-secrets-to","cnGoogleSecretManagerServiceAccount":"SWFtTm90YVNlcnZpY2VBY2NvdW50Q2hhbmdlTWV0b09uZQo=","cnGoogleSecretNamePrefix":"gluu","cnGoogleSecretVersionId":"latest","cnGoogleSpannerDatabaseId":"","cnGoogleSpannerInstanceId":"","cnJettyRequestHeaderSize":8192,"cnLdapUrl":"opendj:1636","cnMaxRamPercent":"75.0","cnPersistenceHybridMapping":"{}","cnRedisSentinelGroup":"","cnRedisSslTruststore":"","cnRedisType":"STANDALONE","cnRedisUrl":"redis.redis.svc.cluster.local:6379","cnRedisUseSsl":false,"cnScimProtectionMode":"OAUTH","cnSecretKubernetesSecret":"cn","cnSqlDbDialect":"mysql","cnSqlDbHost":"my-release-mysql.default.svc.cluster.local","cnSqlDbName":"gluu","cnSqlDbPort":3306,"cnSqlDbSchema":"","cnSqlDbTimezone":"UTC","cnSqlDbUser":"gluu","cnSqldbUserPassword":"Test1234#","lbAddr":""},"countryCode":"US","dnsConfig":{},"dnsPolicy":"","email":"support@gluu.org","image":{"pullSecrets":[],"repository":"ghcr.io/janssenproject/jans/configurator","tag":"1.0.13_dev"},"ldapPassword":"P@ssw0rds","lifecycle":{},"migration":{"enabled":false,"migrationDataFormat":"ldif","migrationDir":"/ce-migration"},"orgName":"Gluu","redisPassword":"P@assw0rd","resources":{"limits":{"cpu":"300m","memory":"300Mi"},"requests":{"cpu":"300m","memory":"300Mi"}},"state":"TX","usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | Configuration parameters for setup and initial configuration secret and config layers used by Gluu services. | -| config-api | object | `{"additionalAnnotations":{},"additionalLabels":{},"dnsConfig":{},"dnsPolicy":"","hpa":{"behavior":{},"enabled":true,"maxReplicas":10,"metrics":[],"minReplicas":1,"targetCPUUtilizationPercentage":50},"image":{"pullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/janssenproject/jans/config-api","tag":"1.0.13_dev"},"lifecycle":{},"livenessProbe":{"httpGet":{"path":"/jans-config-api/api/v1/health/live","port":8074},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5},"pdb":{"enabled":true,"maxUnavailable":"90%"},"readinessProbe":{"httpGet":{"path":"jans-config-api/api/v1/health/ready","port":8074},"initialDelaySeconds":25,"periodSeconds":25,"timeoutSeconds":5},"replicas":1,"resources":{"limits":{"cpu":"1000m","memory":"1000Mi"},"requests":{"cpu":"1000m","memory":"1000Mi"}},"topologySpreadConstraints":{},"usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | Config Api endpoints can be used to configure the auth-server, which is an open-source OpenID Connect Provider (OP) and UMA Authorization Server (AS). | +| config | object | `{"additionalAnnotations":{},"additionalLabels":{},"adminPassword":"Test1234#","city":"Austin","configmap":{"cnAwsAccessKeyId":"","cnAwsDefaultRegion":"us-west-1","cnAwsProfile":"gluu","cnAwsSecretAccessKey":"","cnAwsSecretsEndpointUrl":"","cnAwsSecretsNamePrefix":"gluu","cnAwsSecretsReplicaRegions":[],"cnCacheType":"NATIVE_PERSISTENCE","cnConfigKubernetesConfigMap":"cn","cnCouchbaseBucketPrefix":"jans","cnCouchbaseCrt":"SWFtTm90YVNlcnZpY2VBY2NvdW50Q2hhbmdlTWV0b09uZQo=","cnCouchbaseIndexNumReplica":0,"cnCouchbasePassword":"P@ssw0rd","cnCouchbaseSuperUser":"admin","cnCouchbaseSuperUserPassword":"Test1234#","cnCouchbaseUrl":"cbgluu.default.svc.cluster.local","cnCouchbaseUser":"gluu","cnGoogleProjectId":"google-project-to-save-config-and-secrets-to","cnGoogleSecretManagerServiceAccount":"SWFtTm90YVNlcnZpY2VBY2NvdW50Q2hhbmdlTWV0b09uZQo=","cnGoogleSecretNamePrefix":"gluu","cnGoogleSecretVersionId":"latest","cnGoogleSpannerDatabaseId":"","cnGoogleSpannerInstanceId":"","cnJettyRequestHeaderSize":8192,"cnLdapUrl":"opendj:1636","cnMaxRamPercent":"75.0","cnPersistenceHybridMapping":"{}","cnRedisSentinelGroup":"","cnRedisSslTruststore":"","cnRedisType":"STANDALONE","cnRedisUrl":"redis.redis.svc.cluster.local:6379","cnRedisUseSsl":false,"cnScimProtectionMode":"OAUTH","cnSecretKubernetesSecret":"cn","cnSqlDbDialect":"mysql","cnSqlDbHost":"my-release-mysql.default.svc.cluster.local","cnSqlDbName":"gluu","cnSqlDbPort":3306,"cnSqlDbSchema":"","cnSqlDbTimezone":"UTC","cnSqlDbUser":"gluu","cnSqldbUserPassword":"Test1234#","lbAddr":""},"countryCode":"US","dnsConfig":{},"dnsPolicy":"","email":"support@gluu.org","image":{"pullSecrets":[],"repository":"ghcr.io/janssenproject/jans/configurator","tag":"1.0.14-1"},"ldapPassword":"P@ssw0rds","lifecycle":{},"migration":{"enabled":false,"migrationDataFormat":"ldif","migrationDir":"/ce-migration"},"orgName":"Gluu","redisPassword":"P@assw0rd","resources":{"limits":{"cpu":"300m","memory":"300Mi"},"requests":{"cpu":"300m","memory":"300Mi"}},"state":"TX","usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | Configuration parameters for setup and initial configuration secret and config layers used by Gluu services. | +| config-api | object | `{"additionalAnnotations":{},"additionalLabels":{},"dnsConfig":{},"dnsPolicy":"","hpa":{"behavior":{},"enabled":true,"maxReplicas":10,"metrics":[],"minReplicas":1,"targetCPUUtilizationPercentage":50},"image":{"pullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/janssenproject/jans/config-api","tag":"1.0.14-1"},"lifecycle":{},"livenessProbe":{"httpGet":{"path":"/jans-config-api/api/v1/health/live","port":8074},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5},"pdb":{"enabled":true,"maxUnavailable":"90%"},"readinessProbe":{"httpGet":{"path":"jans-config-api/api/v1/health/ready","port":8074},"initialDelaySeconds":25,"periodSeconds":25,"timeoutSeconds":5},"replicas":1,"resources":{"limits":{"cpu":"1000m","memory":"1000Mi"},"requests":{"cpu":"1000m","memory":"1000Mi"}},"topologySpreadConstraints":{},"usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | Config Api endpoints can be used to configure the auth-server, which is an open-source OpenID Connect Provider (OP) and UMA Authorization Server (AS). | | config-api.additionalAnnotations | object | `{}` | Additional annotations that will be added across the gateway in the format of {cert-manager.io/issuer: "letsencrypt-prod"} | | config-api.additionalLabels | object | `{}` | Additional labels that will be added across the gateway in the format of {mylabel: "myapp"} | | config-api.dnsConfig | object | `{}` | Add custom dns config | @@ -158,7 +158,7 @@ Kubernetes: `>=v1.21.0-0` | config-api.image.pullPolicy | string | `"IfNotPresent"` | Image pullPolicy to use for deploying. | | config-api.image.pullSecrets | list | `[]` | Image Pull Secrets | | config-api.image.repository | string | `"ghcr.io/janssenproject/jans/config-api"` | Image to use for deploying. | -| config-api.image.tag | string | `"1.0.13_dev"` | Image tag to use for deploying. | +| config-api.image.tag | string | `"1.0.14-1"` | Image tag to use for deploying. | | config-api.livenessProbe | object | `{"httpGet":{"path":"/jans-config-api/api/v1/health/live","port":8074},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5}` | Configure the liveness healthcheck for the auth server if needed. | | config-api.livenessProbe.httpGet | object | `{"path":"/jans-config-api/api/v1/health/live","port":8074}` | http liveness probe endpoint | | config-api.pdb | object | `{"enabled":true,"maxUnavailable":"90%"}` | Configure the PodDisruptionBudget | @@ -221,7 +221,7 @@ Kubernetes: `>=v1.21.0-0` | config.email | string | `"support@gluu.org"` | Email address of the administrator usually. Used for certificate creation. | | config.image.pullSecrets | list | `[]` | Image Pull Secrets | | config.image.repository | string | `"ghcr.io/janssenproject/jans/configurator"` | Image to use for deploying. | -| config.image.tag | string | `"1.0.13_dev"` | Image tag to use for deploying. | +| config.image.tag | string | `"1.0.14-1"` | Image tag to use for deploying. | | config.ldapPassword | string | `"P@ssw0rds"` | LDAP admin password if OpenDJ is used for persistence. | | config.migration | object | `{"enabled":false,"migrationDataFormat":"ldif","migrationDir":"/ce-migration"}` | CE to CN Migration section | | config.migration.enabled | bool | `false` | Boolean flag to enable migration from CE | @@ -240,7 +240,7 @@ Kubernetes: `>=v1.21.0-0` | config.usrEnvs.secret | object | `{}` | Add custom secret envs to the service. variable1: value1 | | config.volumeMounts | list | `[]` | Configure any additional volumesMounts that need to be attached to the containers | | config.volumes | list | `[]` | Configure any additional volumes that need to be attached to the pod | -| fido2 | object | `{"additionalAnnotations":{},"additionalLabels":{},"dnsConfig":{},"dnsPolicy":"","hpa":{"behavior":{},"enabled":true,"maxReplicas":10,"metrics":[],"minReplicas":1,"targetCPUUtilizationPercentage":50},"image":{"pullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/janssenproject/jans/fido2","tag":"1.0.13_dev"},"lifecycle":{},"livenessProbe":{"httpGet":{"path":"/jans-fido2/sys/health-check","port":"http-fido2"},"initialDelaySeconds":25,"periodSeconds":25,"timeoutSeconds":5},"pdb":{"enabled":true,"maxUnavailable":"90%"},"readinessProbe":{"httpGet":{"path":"/jans-fido2/sys/health-check","port":"http-fido2"},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5},"replicas":1,"resources":{"limits":{"cpu":"500m","memory":"500Mi"},"requests":{"cpu":"500m","memory":"500Mi"}},"service":{"name":"http-fido2","port":8080},"topologySpreadConstraints":{},"usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | FIDO 2.0 (FIDO2) is an open authentication standard that enables leveraging common devices to authenticate to online services in both mobile and desktop environments. | +| fido2 | object | `{"additionalAnnotations":{},"additionalLabels":{},"dnsConfig":{},"dnsPolicy":"","hpa":{"behavior":{},"enabled":true,"maxReplicas":10,"metrics":[],"minReplicas":1,"targetCPUUtilizationPercentage":50},"image":{"pullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/janssenproject/jans/fido2","tag":"1.0.14-1"},"lifecycle":{},"livenessProbe":{"httpGet":{"path":"/jans-fido2/sys/health-check","port":"http-fido2"},"initialDelaySeconds":25,"periodSeconds":25,"timeoutSeconds":5},"pdb":{"enabled":true,"maxUnavailable":"90%"},"readinessProbe":{"httpGet":{"path":"/jans-fido2/sys/health-check","port":"http-fido2"},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5},"replicas":1,"resources":{"limits":{"cpu":"500m","memory":"500Mi"},"requests":{"cpu":"500m","memory":"500Mi"}},"service":{"name":"http-fido2","port":8080},"topologySpreadConstraints":{},"usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | FIDO 2.0 (FIDO2) is an open authentication standard that enables leveraging common devices to authenticate to online services in both mobile and desktop environments. | | fido2.additionalAnnotations | object | `{}` | Additional annotations that will be added across the gateway in the format of {cert-manager.io/issuer: "letsencrypt-prod"} | | fido2.additionalLabels | object | `{}` | Additional labels that will be added across the gateway in the format of {mylabel: "myapp"} | | fido2.dnsConfig | object | `{}` | Add custom dns config | @@ -251,7 +251,7 @@ Kubernetes: `>=v1.21.0-0` | fido2.image.pullPolicy | string | `"IfNotPresent"` | Image pullPolicy to use for deploying. | | fido2.image.pullSecrets | list | `[]` | Image Pull Secrets | | fido2.image.repository | string | `"ghcr.io/janssenproject/jans/fido2"` | Image to use for deploying. | -| fido2.image.tag | string | `"1.0.13_dev"` | Image tag to use for deploying. | +| fido2.image.tag | string | `"1.0.14-1"` | Image tag to use for deploying. | | fido2.livenessProbe | object | `{"httpGet":{"path":"/jans-fido2/sys/health-check","port":"http-fido2"},"initialDelaySeconds":25,"periodSeconds":25,"timeoutSeconds":5}` | Configure the liveness healthcheck for the fido2 if needed. | | fido2.livenessProbe.httpGet | object | `{"path":"/jans-fido2/sys/health-check","port":"http-fido2"}` | http liveness probe endpoint | | fido2.pdb | object | `{"enabled":true,"maxUnavailable":"90%"}` | Configure the PodDisruptionBudget | @@ -551,7 +551,7 @@ Kubernetes: `>=v1.21.0-0` | oxshibboleth.usrEnvs.secret | object | `{}` | Add custom secret envs to the service variable1: value1 | | oxshibboleth.volumeMounts | list | `[]` | Configure any additional volumesMounts that need to be attached to the containers | | oxshibboleth.volumes | list | `[]` | Configure any additional volumes that need to be attached to the pod | -| persistence | object | `{"additionalAnnotations":{},"additionalLabels":{},"dnsConfig":{},"dnsPolicy":"","image":{"pullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/janssenproject/jans/persistence-loader","tag":"1.0.13_dev"},"lifecycle":{},"resources":{"limits":{"cpu":"300m","memory":"300Mi"},"requests":{"cpu":"300m","memory":"300Mi"}},"usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | Job to generate data and initial config for Gluu Server persistence layer. | +| persistence | object | `{"additionalAnnotations":{},"additionalLabels":{},"dnsConfig":{},"dnsPolicy":"","image":{"pullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/janssenproject/jans/persistence-loader","tag":"1.0.14-1"},"lifecycle":{},"resources":{"limits":{"cpu":"300m","memory":"300Mi"},"requests":{"cpu":"300m","memory":"300Mi"}},"usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | Job to generate data and initial config for Gluu Server persistence layer. | | persistence.additionalAnnotations | object | `{}` | Additional annotations that will be added across the gateway in the format of {cert-manager.io/issuer: "letsencrypt-prod"} | | persistence.additionalLabels | object | `{}` | Additional labels that will be added across the gateway in the format of {mylabel: "myapp"} | | persistence.dnsConfig | object | `{}` | Add custom dns config | @@ -559,7 +559,7 @@ Kubernetes: `>=v1.21.0-0` | persistence.image.pullPolicy | string | `"IfNotPresent"` | Image pullPolicy to use for deploying. | | persistence.image.pullSecrets | list | `[]` | Image Pull Secrets | | persistence.image.repository | string | `"ghcr.io/janssenproject/jans/persistence-loader"` | Image to use for deploying. | -| persistence.image.tag | string | `"1.0.13_dev"` | Image tag to use for deploying. | +| persistence.image.tag | string | `"1.0.14-1"` | Image tag to use for deploying. | | persistence.resources | object | `{"limits":{"cpu":"300m","memory":"300Mi"},"requests":{"cpu":"300m","memory":"300Mi"}}` | Resource specs. | | persistence.resources.limits.cpu | string | `"300m"` | CPU limit | | persistence.resources.limits.memory | string | `"300Mi"` | Memory limit. | @@ -570,7 +570,7 @@ Kubernetes: `>=v1.21.0-0` | persistence.usrEnvs.secret | object | `{}` | Add custom secret envs to the service variable1: value1 | | persistence.volumeMounts | list | `[]` | Configure any additional volumesMounts that need to be attached to the containers | | persistence.volumes | list | `[]` | Configure any additional volumes that need to be attached to the pod | -| scim | object | `{"additionalAnnotations":{},"additionalLabels":{},"dnsConfig":{},"dnsPolicy":"","hpa":{"behavior":{},"enabled":true,"maxReplicas":10,"metrics":[],"minReplicas":1,"targetCPUUtilizationPercentage":50},"image":{"pullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/janssenproject/jans/scim","tag":"1.0.13_dev"},"lifecycle":{},"livenessProbe":{"httpGet":{"path":"/jans-scim/sys/health-check","port":8080},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5},"pdb":{"enabled":true,"maxUnavailable":"90%"},"readinessProbe":{"httpGet":{"path":"/jans-scim/sys/health-check","port":8080},"initialDelaySeconds":25,"periodSeconds":25,"timeoutSeconds":5},"replicas":1,"resources":{"limits":{"cpu":"1000m","memory":"1000Mi"},"requests":{"cpu":"1000m","memory":"1000Mi"}},"service":{"name":"http-scim","port":8080},"topologySpreadConstraints":{},"usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | System for Cross-domain Identity Management (SCIM) version 2.0 | +| scim | object | `{"additionalAnnotations":{},"additionalLabels":{},"dnsConfig":{},"dnsPolicy":"","hpa":{"behavior":{},"enabled":true,"maxReplicas":10,"metrics":[],"minReplicas":1,"targetCPUUtilizationPercentage":50},"image":{"pullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/janssenproject/jans/scim","tag":"1.0.14-1"},"lifecycle":{},"livenessProbe":{"httpGet":{"path":"/jans-scim/sys/health-check","port":8080},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5},"pdb":{"enabled":true,"maxUnavailable":"90%"},"readinessProbe":{"httpGet":{"path":"/jans-scim/sys/health-check","port":8080},"initialDelaySeconds":25,"periodSeconds":25,"timeoutSeconds":5},"replicas":1,"resources":{"limits":{"cpu":"1000m","memory":"1000Mi"},"requests":{"cpu":"1000m","memory":"1000Mi"}},"service":{"name":"http-scim","port":8080},"topologySpreadConstraints":{},"usrEnvs":{"normal":{},"secret":{}},"volumeMounts":[],"volumes":[]}` | System for Cross-domain Identity Management (SCIM) version 2.0 | | scim.additionalAnnotations | object | `{}` | Additional annotations that will be added across the gateway in the format of {cert-manager.io/issuer: "letsencrypt-prod"} | | scim.additionalLabels | object | `{}` | Additional labels that will be added across the gateway in the format of {mylabel: "myapp"} | | scim.dnsConfig | object | `{}` | Add custom dns config | @@ -581,7 +581,7 @@ Kubernetes: `>=v1.21.0-0` | scim.image.pullPolicy | string | `"IfNotPresent"` | Image pullPolicy to use for deploying. | | scim.image.pullSecrets | list | `[]` | Image Pull Secrets | | scim.image.repository | string | `"ghcr.io/janssenproject/jans/scim"` | Image to use for deploying. | -| scim.image.tag | string | `"1.0.13_dev"` | Image tag to use for deploying. | +| scim.image.tag | string | `"1.0.14-1"` | Image tag to use for deploying. | | scim.livenessProbe | object | `{"httpGet":{"path":"/jans-scim/sys/health-check","port":8080},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5}` | Configure the liveness healthcheck for SCIM if needed. | | scim.livenessProbe.httpGet.path | string | `"/jans-scim/sys/health-check"` | http liveness probe endpoint | | scim.pdb | object | `{"enabled":true,"maxUnavailable":"90%"}` | Configure the PodDisruptionBudget | diff --git a/charts/gluu/gluu/charts/admin-ui/Chart.yaml b/charts/gluu/gluu/charts/admin-ui/Chart.yaml index 72fc8936a..d340ad6b7 100644 --- a/charts/gluu/gluu/charts/admin-ui/Chart.yaml +++ b/charts/gluu/gluu/charts/admin-ui/Chart.yaml @@ -17,4 +17,4 @@ sources: - https://github.com/GluuFederation/docker-gluu-admin-ui - https://github.com/GluuFederation/flex/tree/main/flex-cn-setup/pygluu/kubernetes/templates/helm/gluu/charts/admin-ui type: application -version: 5.0.17 +version: 5.0.18 diff --git a/charts/gluu/gluu/charts/admin-ui/README.md b/charts/gluu/gluu/charts/admin-ui/README.md index fa72cfeb0..640293c36 100644 --- a/charts/gluu/gluu/charts/admin-ui/README.md +++ b/charts/gluu/gluu/charts/admin-ui/README.md @@ -1,6 +1,6 @@ # admin-ui -![Version: 5.0.17](https://img.shields.io/badge/Version-5.0.17-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) +![Version: 5.0.18](https://img.shields.io/badge/Version-5.0.18-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) Admin GUI. Requires license. @@ -35,7 +35,7 @@ Kubernetes: `>=v1.21.0-0` | image.pullPolicy | string | `"IfNotPresent"` | Image pullPolicy to use for deploying. | | image.pullSecrets | list | `[]` | Image Pull Secrets | | image.repository | string | `"gluufederation/admin-ui"` | Image to use for deploying. | -| image.tag | string | `"1.0.13_dev"` | Image tag to use for deploying. | +| image.tag | string | `"1.0.14-1"` | Image tag to use for deploying. | | lifecycle | object | `{}` | | | livenessProbe | object | `{"failureThreshold":20,"initialDelaySeconds":60,"periodSeconds":25,"tcpSocket":{"port":8080},"timeoutSeconds":5}` | Configure the liveness healthcheck for the admin ui if needed. | | readinessProbe | object | `{"failureThreshold":20,"initialDelaySeconds":60,"periodSeconds":25,"tcpSocket":{"port":8080},"timeoutSeconds":5}` | Configure the readiness healthcheck for the admin ui if needed. | diff --git a/charts/gluu/gluu/charts/admin-ui/values.yaml b/charts/gluu/gluu/charts/admin-ui/values.yaml index c0b0d2266..d9e245a6f 100644 --- a/charts/gluu/gluu/charts/admin-ui/values.yaml +++ b/charts/gluu/gluu/charts/admin-ui/values.yaml @@ -27,7 +27,7 @@ image: # -- Image to use for deploying. repository: gluufederation/admin-ui # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14-1 # -- Image Pull Secrets pullSecrets: [ ] # -- Service replica number. diff --git a/charts/gluu/gluu/charts/auth-server-key-rotation/Chart.yaml b/charts/gluu/gluu/charts/auth-server-key-rotation/Chart.yaml index 480216e16..a586f4d80 100644 --- a/charts/gluu/gluu/charts/auth-server-key-rotation/Chart.yaml +++ b/charts/gluu/gluu/charts/auth-server-key-rotation/Chart.yaml @@ -15,4 +15,4 @@ sources: - https://github.com/JanssenProject/docker-jans-certmanager - https://github.com/GluuFederation/flex/tree/main/flex-cn-setup/pygluu/kubernetes/templates/helm/gluu/charts/auth-server-key-rotation type: application -version: 5.0.17 +version: 5.0.18 diff --git a/charts/gluu/gluu/charts/auth-server-key-rotation/README.md b/charts/gluu/gluu/charts/auth-server-key-rotation/README.md index b5821dd6a..b201f594f 100644 --- a/charts/gluu/gluu/charts/auth-server-key-rotation/README.md +++ b/charts/gluu/gluu/charts/auth-server-key-rotation/README.md @@ -1,6 +1,6 @@ # auth-server-key-rotation -![Version: 5.0.17](https://img.shields.io/badge/Version-5.0.17-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) +![Version: 5.0.18](https://img.shields.io/badge/Version-5.0.18-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) Responsible for regenerating auth-keys per x hours @@ -33,7 +33,7 @@ Kubernetes: `>=v1.21.0-0` | image.pullPolicy | string | `"IfNotPresent"` | Image pullPolicy to use for deploying. | | image.pullSecrets | list | `[]` | Image Pull Secrets | | image.repository | string | `"janssenproject/certmanager"` | Image to use for deploying. | -| image.tag | string | `"1.0.13_dev"` | Image tag to use for deploying. | +| image.tag | string | `"1.0.14-1"` | Image tag to use for deploying. | | keysLife | int | `48` | Auth server key rotation keys life in hours | | lifecycle | object | `{}` | | | nodeSelector | object | `{}` | | diff --git a/charts/gluu/gluu/charts/auth-server-key-rotation/values.yaml b/charts/gluu/gluu/charts/auth-server-key-rotation/values.yaml index ed62f4279..21eea0f4f 100644 --- a/charts/gluu/gluu/charts/auth-server-key-rotation/values.yaml +++ b/charts/gluu/gluu/charts/auth-server-key-rotation/values.yaml @@ -18,7 +18,7 @@ image: # -- Image to use for deploying. repository: janssenproject/certmanager # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14-1 # -- Image Pull Secrets pullSecrets: [ ] # -- Auth server key rotation keys life in hours diff --git a/charts/gluu/gluu/charts/auth-server/Chart.yaml b/charts/gluu/gluu/charts/auth-server/Chart.yaml index 8b9175b20..abd39cc05 100644 --- a/charts/gluu/gluu/charts/auth-server/Chart.yaml +++ b/charts/gluu/gluu/charts/auth-server/Chart.yaml @@ -19,4 +19,4 @@ sources: - https://github.com/JanssenProject/docker-jans-auth-server - https://github.com/GluuFederation/flex/tree/main/flex-cn-setup/pygluu/kubernetes/templates/helm/gluu/charts/auth-server type: application -version: 5.0.17 +version: 5.0.18 diff --git a/charts/gluu/gluu/charts/auth-server/README.md b/charts/gluu/gluu/charts/auth-server/README.md index 0285e68bb..a596f7980 100644 --- a/charts/gluu/gluu/charts/auth-server/README.md +++ b/charts/gluu/gluu/charts/auth-server/README.md @@ -1,6 +1,6 @@ # auth-server -![Version: 5.0.17](https://img.shields.io/badge/Version-5.0.17-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) +![Version: 5.0.18](https://img.shields.io/badge/Version-5.0.18-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) OAuth Authorization Server, the OpenID Connect Provider, the UMA Authorization Server--this is the main Internet facing component of Gluu. It's the service that returns tokens, JWT's and identity assertions. This service must be Internet facing. @@ -36,7 +36,7 @@ Kubernetes: `>=v1.21.0-0` | image.pullPolicy | string | `"IfNotPresent"` | Image pullPolicy to use for deploying. | | image.pullSecrets | list | `[]` | Image Pull Secrets | | image.repository | string | `"janssenproject/auth-server"` | Image to use for deploying. | -| image.tag | string | `"1.0.13_dev"` | Image tag to use for deploying. | +| image.tag | string | `"1.0.14-1"` | Image tag to use for deploying. | | lifecycle | object | `{}` | | | livenessProbe | object | `{"exec":{"command":["python3","/app/scripts/healthcheck.py"]},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5}` | Configure the liveness healthcheck for the auth server if needed. | | livenessProbe.exec | object | `{"command":["python3","/app/scripts/healthcheck.py"]}` | Executes the python3 healthcheck. https://github.com/GluuFederation/docker-oxauth/blob/4.3/scripts/healthcheck.py | diff --git a/charts/gluu/gluu/charts/auth-server/values.yaml b/charts/gluu/gluu/charts/auth-server/values.yaml index 14b5b4be6..fefc029b1 100644 --- a/charts/gluu/gluu/charts/auth-server/values.yaml +++ b/charts/gluu/gluu/charts/auth-server/values.yaml @@ -28,7 +28,7 @@ image: # -- Image to use for deploying. repository: janssenproject/auth-server # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14-1 # -- Image Pull Secrets pullSecrets: [ ] # -- Service replica number. diff --git a/charts/gluu/gluu/charts/casa/Chart.yaml b/charts/gluu/gluu/charts/casa/Chart.yaml index c2646f374..f1f05e7bf 100644 --- a/charts/gluu/gluu/charts/casa/Chart.yaml +++ b/charts/gluu/gluu/charts/casa/Chart.yaml @@ -19,4 +19,4 @@ sources: - https://github.com/GluuFederation/docker-casa - https://github.com/GluuFederation/flex/tree/main/flex-cn-setup/pygluu/kubernetes/templates/helm/gluu/charts/casa type: application -version: 5.0.17 +version: 5.0.18 diff --git a/charts/gluu/gluu/charts/casa/README.md b/charts/gluu/gluu/charts/casa/README.md index b8d9a5be6..6c01447b7 100644 --- a/charts/gluu/gluu/charts/casa/README.md +++ b/charts/gluu/gluu/charts/casa/README.md @@ -1,6 +1,6 @@ # casa -![Version: 5.0.17](https://img.shields.io/badge/Version-5.0.17-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) +![Version: 5.0.18](https://img.shields.io/badge/Version-5.0.18-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) Gluu Casa ("Casa") is a self-service web portal for end-users to manage authentication and authorization preferences for their account in a Gluu Server. diff --git a/charts/gluu/gluu/charts/cn-istio-ingress/Chart.yaml b/charts/gluu/gluu/charts/cn-istio-ingress/Chart.yaml index 69820f751..205b351e4 100644 --- a/charts/gluu/gluu/charts/cn-istio-ingress/Chart.yaml +++ b/charts/gluu/gluu/charts/cn-istio-ingress/Chart.yaml @@ -16,4 +16,4 @@ sources: - https://gluu.org/docs/gluu-server/ - https://github.com/GluuFederation/flex/tree/main/flex-cn-setup/pygluu/kubernetes/templates/helm/gluu/charts/cn-istio-ingress type: application -version: 5.0.17 +version: 5.0.18 diff --git a/charts/gluu/gluu/charts/cn-istio-ingress/README.md b/charts/gluu/gluu/charts/cn-istio-ingress/README.md index 9df284124..ba1614989 100644 --- a/charts/gluu/gluu/charts/cn-istio-ingress/README.md +++ b/charts/gluu/gluu/charts/cn-istio-ingress/README.md @@ -1,6 +1,6 @@ # cn-istio-ingress -![Version: 5.0.17](https://img.shields.io/badge/Version-5.0.17-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) +![Version: 5.0.18](https://img.shields.io/badge/Version-5.0.18-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) Istio Gateway diff --git a/charts/gluu/gluu/charts/config-api/Chart.yaml b/charts/gluu/gluu/charts/config-api/Chart.yaml index 5e776bacc..e117fe0e0 100644 --- a/charts/gluu/gluu/charts/config-api/Chart.yaml +++ b/charts/gluu/gluu/charts/config-api/Chart.yaml @@ -19,4 +19,4 @@ sources: - https://github.com/JanssenProject/jans/docker-jans-config-api - https://github.com/GluuFederation/flex/tree/main/flex-cn-setup/pygluu/kubernetes/templates/helm/gluu/charts/config-api type: application -version: 5.0.17 +version: 5.0.18 diff --git a/charts/gluu/gluu/charts/config-api/README.md b/charts/gluu/gluu/charts/config-api/README.md index 4d517ce52..21677dcab 100644 --- a/charts/gluu/gluu/charts/config-api/README.md +++ b/charts/gluu/gluu/charts/config-api/README.md @@ -1,6 +1,6 @@ # config-api -![Version: 5.0.17](https://img.shields.io/badge/Version-5.0.17-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) +![Version: 5.0.18](https://img.shields.io/badge/Version-5.0.18-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) Jans Config Api endpoints can be used to configure jans-auth-server, which is an open-source OpenID Connect Provider (OP) and UMA Authorization Server (AS) @@ -38,7 +38,7 @@ Kubernetes: `>=v1.21.0-0` | image.pullPolicy | string | `"IfNotPresent"` | Image pullPolicy to use for deploying. | | image.pullSecrets | list | `[]` | Image Pull Secrets | | image.repository | string | `"janssenproject/config-api"` | Image to use for deploying. | -| image.tag | string | `"1.0.13_dev"` | Image tag to use for deploying. | +| image.tag | string | `"1.0.14-1"` | Image tag to use for deploying. | | lifecycle | object | `{}` | | | livenessProbe | object | `{"httpGet":{"path":"/jans-config-api/api/v1/health/live","port":8074},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5}` | Configure the liveness healthcheck for the auth server if needed. | | livenessProbe.httpGet | object | `{"path":"/jans-config-api/api/v1/health/live","port":8074}` | Executes the python3 healthcheck. https://github.com/GluuFederation/docker-oxauth/blob/4.3/scripts/healthcheck.py | diff --git a/charts/gluu/gluu/charts/config-api/values.yaml b/charts/gluu/gluu/charts/config-api/values.yaml index 78ebd8aff..f1d755d61 100644 --- a/charts/gluu/gluu/charts/config-api/values.yaml +++ b/charts/gluu/gluu/charts/config-api/values.yaml @@ -33,7 +33,7 @@ image: # -- Image to use for deploying. repository: janssenproject/config-api # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14-1 # -- Image Pull Secrets pullSecrets: [ ] # -- Service replica number. diff --git a/charts/gluu/gluu/charts/config/Chart.yaml b/charts/gluu/gluu/charts/config/Chart.yaml index b094e268e..ae57428f0 100644 --- a/charts/gluu/gluu/charts/config/Chart.yaml +++ b/charts/gluu/gluu/charts/config/Chart.yaml @@ -18,4 +18,4 @@ sources: - https://github.com/JanssenProject/jans/docker-jans-configurator - https://github.com/GluuFederation/flex/tree/main/flex-cn-setup/pygluu/kubernetes/templates/helm/gluu/charts/config type: application -version: 5.0.17 +version: 5.0.18 diff --git a/charts/gluu/gluu/charts/config/README.md b/charts/gluu/gluu/charts/config/README.md index 96d2f251a..58b075434 100644 --- a/charts/gluu/gluu/charts/config/README.md +++ b/charts/gluu/gluu/charts/config/README.md @@ -1,6 +1,6 @@ # config -![Version: 5.0.17](https://img.shields.io/badge/Version-5.0.17-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) +![Version: 5.0.18](https://img.shields.io/badge/Version-5.0.18-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) Configuration parameters for setup and initial configuration secret and config layers used by Gluu services. @@ -79,7 +79,7 @@ Kubernetes: `>=v1.21.0-0` | fullNameOverride | string | `""` | | | image.pullSecrets | list | `[]` | Image Pull Secrets | | image.repository | string | `"janssenproject/configurator"` | Image to use for deploying. | -| image.tag | string | `"1.0.13_dev"` | Image tag to use for deploying. | +| image.tag | string | `"1.0.14-1"` | Image tag to use for deploying. | | ldapPassword | string | `"P@ssw0rds"` | LDAP admin password if OpennDJ is used for persistence. | | lifecycle | object | `{}` | | | migration | object | `{"enabled":false,"migrationDataFormat":"ldif","migrationDir":"/ce-migration"}` | CE to CN Migration section | diff --git a/charts/gluu/gluu/charts/config/values.yaml b/charts/gluu/gluu/charts/config/values.yaml index 8a81f8c59..4501dceb3 100644 --- a/charts/gluu/gluu/charts/config/values.yaml +++ b/charts/gluu/gluu/charts/config/values.yaml @@ -122,7 +122,7 @@ image: # -- Image to use for deploying. repository: janssenproject/configurator # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14-1 # -- Image Pull Secrets pullSecrets: [ ] # -- LDAP admin password if OpennDJ is used for persistence. diff --git a/charts/gluu/gluu/charts/fido2/Chart.yaml b/charts/gluu/gluu/charts/fido2/Chart.yaml index 175dd2277..b33e6ea91 100644 --- a/charts/gluu/gluu/charts/fido2/Chart.yaml +++ b/charts/gluu/gluu/charts/fido2/Chart.yaml @@ -19,4 +19,4 @@ sources: - https://github.com/JanssenProject/jans/docker-jans-fido2 - https://github.com/GluuFederation/flex/tree/main/flex-cn-setup/pygluu/kubernetes/templates/helm/gluu/charts/fido2 type: application -version: 5.0.17 +version: 5.0.18 diff --git a/charts/gluu/gluu/charts/fido2/README.md b/charts/gluu/gluu/charts/fido2/README.md index 5d5bc39ed..c582d8451 100644 --- a/charts/gluu/gluu/charts/fido2/README.md +++ b/charts/gluu/gluu/charts/fido2/README.md @@ -1,6 +1,6 @@ # fido2 -![Version: 5.0.17](https://img.shields.io/badge/Version-5.0.17-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) +![Version: 5.0.18](https://img.shields.io/badge/Version-5.0.18-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) FIDO 2.0 (FIDO2) is an open authentication standard that enables leveraging common devices to authenticate to online services in both mobile and desktop environments. @@ -37,7 +37,7 @@ Kubernetes: `>=v1.21.0-0` | image.pullPolicy | string | `"IfNotPresent"` | Image pullPolicy to use for deploying. | | image.pullSecrets | list | `[]` | Image Pull Secrets | | image.repository | string | `"janssenproject/fido2"` | Image to use for deploying. | -| image.tag | string | `"1.0.13_dev"` | Image tag to use for deploying. | +| image.tag | string | `"1.0.14-1"` | Image tag to use for deploying. | | lifecycle | object | `{}` | | | livenessProbe | object | `{"httpGet":{"path":"/jans-fido2/sys/health-check","port":"http-fido2"},"initialDelaySeconds":25,"periodSeconds":25,"timeoutSeconds":5}` | Configure the liveness healthcheck for the fido2 if needed. | | livenessProbe.httpGet | object | `{"path":"/jans-fido2/sys/health-check","port":"http-fido2"}` | http liveness probe endpoint | diff --git a/charts/gluu/gluu/charts/fido2/values.yaml b/charts/gluu/gluu/charts/fido2/values.yaml index bc93d09f7..48f7ef6d4 100644 --- a/charts/gluu/gluu/charts/fido2/values.yaml +++ b/charts/gluu/gluu/charts/fido2/values.yaml @@ -29,7 +29,7 @@ image: # -- Image to use for deploying. repository: janssenproject/fido2 # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14-1 # -- Image Pull Secrets pullSecrets: [ ] # -- Service replica number. diff --git a/charts/gluu/gluu/charts/nginx-ingress/Chart.yaml b/charts/gluu/gluu/charts/nginx-ingress/Chart.yaml index dd38fa0ec..3be9d36da 100644 --- a/charts/gluu/gluu/charts/nginx-ingress/Chart.yaml +++ b/charts/gluu/gluu/charts/nginx-ingress/Chart.yaml @@ -17,4 +17,4 @@ sources: - https://kubernetes.io/docs/concepts/services-networking/ingress/ - https://github.com/GluuFederation/flex/tree/main/flex-cn-setup/pygluu/kubernetes/templates/helm/gluu/charts/nginx-ingress type: application -version: 5.0.17 +version: 5.0.18 diff --git a/charts/gluu/gluu/charts/nginx-ingress/README.md b/charts/gluu/gluu/charts/nginx-ingress/README.md index 008cb3ab7..f1ee85507 100644 --- a/charts/gluu/gluu/charts/nginx-ingress/README.md +++ b/charts/gluu/gluu/charts/nginx-ingress/README.md @@ -1,6 +1,6 @@ # nginx-ingress -![Version: 5.0.17](https://img.shields.io/badge/Version-5.0.17-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) +![Version: 5.0.18](https://img.shields.io/badge/Version-5.0.18-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) Nginx ingress definitions chart diff --git a/charts/gluu/gluu/charts/opendj/Chart.yaml b/charts/gluu/gluu/charts/opendj/Chart.yaml index 8c48ab68e..a21e14d2a 100644 --- a/charts/gluu/gluu/charts/opendj/Chart.yaml +++ b/charts/gluu/gluu/charts/opendj/Chart.yaml @@ -19,4 +19,4 @@ sources: - https://github.com/GluuFederation/docker-opendj - https://github.com/GluuFederation/flex/tree/main/flex-cn-setup/pygluu/kubernetes/templates/helm/gluu/charts/opendj type: application -version: 5.0.17 +version: 5.0.18 diff --git a/charts/gluu/gluu/charts/opendj/README.md b/charts/gluu/gluu/charts/opendj/README.md index 1224b094e..e1409e8ec 100644 --- a/charts/gluu/gluu/charts/opendj/README.md +++ b/charts/gluu/gluu/charts/opendj/README.md @@ -1,6 +1,6 @@ # opendj -![Version: 5.0.17](https://img.shields.io/badge/Version-5.0.17-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) +![Version: 5.0.18](https://img.shields.io/badge/Version-5.0.18-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) OpenDJ is a directory server which implements a wide range of Lightweight Directory Access Protocol and related standards, including full compliance with LDAPv3 but also support for Directory Service Markup Language (DSMLv2).Written in Java, OpenDJ offers multi-master replication, access control, and many extensions. diff --git a/charts/gluu/gluu/charts/oxpassport/Chart.yaml b/charts/gluu/gluu/charts/oxpassport/Chart.yaml index 4ffa82317..ddbcf74b5 100644 --- a/charts/gluu/gluu/charts/oxpassport/Chart.yaml +++ b/charts/gluu/gluu/charts/oxpassport/Chart.yaml @@ -18,4 +18,4 @@ sources: - https://github.com/GluuFederation/docker-oxpassport - https://github.com/GluuFederation/flex/tree/main/flex-cn-setup/pygluu/kubernetes/templates/helm/gluu/charts/oxpassport type: application -version: 5.0.17 +version: 5.0.18 diff --git a/charts/gluu/gluu/charts/oxpassport/README.md b/charts/gluu/gluu/charts/oxpassport/README.md index d36019f0b..8af973da0 100644 --- a/charts/gluu/gluu/charts/oxpassport/README.md +++ b/charts/gluu/gluu/charts/oxpassport/README.md @@ -1,6 +1,6 @@ # oxpassport -![Version: 5.0.17](https://img.shields.io/badge/Version-5.0.17-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) +![Version: 5.0.18](https://img.shields.io/badge/Version-5.0.18-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) Gluu interface to Passport.js to support social login and inbound identity. diff --git a/charts/gluu/gluu/charts/oxshibboleth/Chart.yaml b/charts/gluu/gluu/charts/oxshibboleth/Chart.yaml index 2a3a1ca10..8ef9abc11 100644 --- a/charts/gluu/gluu/charts/oxshibboleth/Chart.yaml +++ b/charts/gluu/gluu/charts/oxshibboleth/Chart.yaml @@ -17,4 +17,4 @@ sources: - https://github.com/GluuFederation/docker-oxshibboleth - https://github.com/GluuFederation/flex/tree/main/flex-cn-setup/pygluu/kubernetes/templates/helm/gluu/charts/oxshibboleth type: application -version: 5.0.17 +version: 5.0.18 diff --git a/charts/gluu/gluu/charts/oxshibboleth/README.md b/charts/gluu/gluu/charts/oxshibboleth/README.md index 18d3eb18e..8175b49bb 100644 --- a/charts/gluu/gluu/charts/oxshibboleth/README.md +++ b/charts/gluu/gluu/charts/oxshibboleth/README.md @@ -1,6 +1,6 @@ # oxshibboleth -![Version: 5.0.17](https://img.shields.io/badge/Version-5.0.17-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) +![Version: 5.0.18](https://img.shields.io/badge/Version-5.0.18-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) Shibboleth project for the Gluu Server's SAML IDP functionality. diff --git a/charts/gluu/gluu/charts/persistence/Chart.yaml b/charts/gluu/gluu/charts/persistence/Chart.yaml index bba6fc2ac..1482d1b8a 100644 --- a/charts/gluu/gluu/charts/persistence/Chart.yaml +++ b/charts/gluu/gluu/charts/persistence/Chart.yaml @@ -15,4 +15,4 @@ sources: - https://github.com/JanssenProject/jans/docker-jans-persistence-loader - https://github.com/GluuFederation/flex/tree/main/flex-cn-setup/pygluu/kubernetes/templates/helm/gluu/charts/persistence type: application -version: 5.0.17 +version: 5.0.18 diff --git a/charts/gluu/gluu/charts/persistence/README.md b/charts/gluu/gluu/charts/persistence/README.md index 792429cc7..75ca5a54e 100644 --- a/charts/gluu/gluu/charts/persistence/README.md +++ b/charts/gluu/gluu/charts/persistence/README.md @@ -1,6 +1,6 @@ # persistence -![Version: 5.0.17](https://img.shields.io/badge/Version-5.0.17-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) +![Version: 5.0.18](https://img.shields.io/badge/Version-5.0.18-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) Job to generate data and initial config for Gluu Server persistence layer. @@ -33,7 +33,7 @@ Kubernetes: `>=v1.21.0-0` | image.pullPolicy | string | `"IfNotPresent"` | Image pullPolicy to use for deploying. | | image.pullSecrets | list | `[]` | Image Pull Secrets | | image.repository | string | `"gluufederation/persistence"` | Image to use for deploying. | -| image.tag | string | `"1.0.13_dev"` | Image tag to use for deploying. | +| image.tag | string | `"1.0.14-1"` | Image tag to use for deploying. | | imagePullSecrets | list | `[]` | | | lifecycle | object | `{}` | | | nameOverride | string | `""` | | diff --git a/charts/gluu/gluu/charts/persistence/values.yaml b/charts/gluu/gluu/charts/persistence/values.yaml index 2813f4f02..546249a32 100644 --- a/charts/gluu/gluu/charts/persistence/values.yaml +++ b/charts/gluu/gluu/charts/persistence/values.yaml @@ -18,7 +18,7 @@ image: # -- Image to use for deploying. repository: gluufederation/persistence # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14-1 # -- Image Pull Secrets pullSecrets: [ ] # -- Resource specs. diff --git a/charts/gluu/gluu/charts/scim/Chart.yaml b/charts/gluu/gluu/charts/scim/Chart.yaml index ba9887059..a38cb2ecd 100644 --- a/charts/gluu/gluu/charts/scim/Chart.yaml +++ b/charts/gluu/gluu/charts/scim/Chart.yaml @@ -17,4 +17,4 @@ sources: - https://github.com/JanssenProject/jans/docker-jans-scim - https://github.com/GluuFederation/flex/tree/main/flex-cn-setup/pygluu/kubernetes/templates/helm/gluu/charts/scim type: application -version: 5.0.17 +version: 5.0.18 diff --git a/charts/gluu/gluu/charts/scim/README.md b/charts/gluu/gluu/charts/scim/README.md index 2b7374e25..27723b398 100644 --- a/charts/gluu/gluu/charts/scim/README.md +++ b/charts/gluu/gluu/charts/scim/README.md @@ -1,6 +1,6 @@ # scim -![Version: 5.0.17](https://img.shields.io/badge/Version-5.0.17-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) +![Version: 5.0.18](https://img.shields.io/badge/Version-5.0.18-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 5.0.0](https://img.shields.io/badge/AppVersion-5.0.0-informational?style=flat-square) System for Cross-domain Identity Management (SCIM) version 2.0 @@ -36,7 +36,7 @@ Kubernetes: `>=v1.21.0-0` | image.pullPolicy | string | `"IfNotPresent"` | Image pullPolicy to use for deploying. | | image.pullSecrets | list | `[]` | Image Pull Secrets | | image.repository | string | `"janssenproject/scim"` | Image to use for deploying. | -| image.tag | string | `"1.0.13_dev"` | Image tag to use for deploying. | +| image.tag | string | `"1.0.14-1"` | Image tag to use for deploying. | | lifecycle | object | `{}` | | | livenessProbe | object | `{"httpGet":{"path":"/jans-scim/sys/health-check","port":8080},"initialDelaySeconds":30,"periodSeconds":30,"timeoutSeconds":5}` | Configure the liveness healthcheck for SCIM if needed. | | livenessProbe.httpGet.path | string | `"/jans-scim/sys/health-check"` | http liveness probe endpoint | diff --git a/charts/gluu/gluu/charts/scim/values.yaml b/charts/gluu/gluu/charts/scim/values.yaml index 4803db872..e2734e1cf 100644 --- a/charts/gluu/gluu/charts/scim/values.yaml +++ b/charts/gluu/gluu/charts/scim/values.yaml @@ -28,7 +28,7 @@ image: # -- Image to use for deploying. repository: janssenproject/scim # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14-1 # -- Image Pull Secrets pullSecrets: [ ] # -- Service replica number. diff --git a/charts/gluu/gluu/openbanking-values.yaml b/charts/gluu/gluu/openbanking-values.yaml index 6081c0345..9adc81080 100644 --- a/charts/gluu/gluu/openbanking-values.yaml +++ b/charts/gluu/gluu/openbanking-values.yaml @@ -28,7 +28,7 @@ auth-server: # -- Image to use for deploying. repository: janssenproject/auth-server # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14_dev # -- Image Pull Secrets pullSecrets: [ ] # -- Service replica number. @@ -167,7 +167,7 @@ config: # -- Image to use for deploying. repository: janssenproject/configurator # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14_dev # -- Image Pull Secrets pullSecrets: [ ] # -- Organization name. Used for certificate creation. @@ -231,7 +231,7 @@ config-api: # -- Image to use for deploying. repository: janssenproject/config-api # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14_dev # -- Image Pull Secrets pullSecrets: [ ] # -- Service replica number. @@ -674,7 +674,7 @@ persistence: # -- Image to use for deploying. repository: janssenproject/persistence-loader # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14_dev # -- Image Pull Secrets pullSecrets: [ ] # -- Resource specs. diff --git a/charts/gluu/gluu/values.yaml b/charts/gluu/gluu/values.yaml index c10679c54..423198b42 100644 --- a/charts/gluu/gluu/values.yaml +++ b/charts/gluu/gluu/values.yaml @@ -106,7 +106,7 @@ admin-ui: # -- Image to use for deploying. repository: ghcr.io/gluufederation/flex/admin-ui # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14-1 # -- Image Pull Secrets pullSecrets: [ ] # -- Service replica number. @@ -203,7 +203,7 @@ auth-server: # -- Image to use for deploying. repository: ghcr.io/janssenproject/jans/auth-server # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14-1 # -- Image Pull Secrets pullSecrets: [ ] # -- Service replica number. @@ -276,7 +276,7 @@ auth-server-key-rotation: # -- Image to use for deploying. repository: ghcr.io/janssenproject/jans/certmanager # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14-1 # -- Image Pull Secrets pullSecrets: [ ] # -- Auth server key rotation keys life in hours @@ -357,7 +357,7 @@ casa: # -- Image to use for deploying. repository: ghcr.io/gluufederation/flex/casa # -- Image tag to use for deploying. - tag: 5.0.0_dev + tag: 5.0.0-13 # -- Image Pull Secrets pullSecrets: [ ] # -- Service replica number. @@ -535,7 +535,7 @@ config: # -- Image to use for deploying. repository: ghcr.io/janssenproject/jans/configurator # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14-1 # -- Image Pull Secrets pullSecrets: [ ] # -- LDAP admin password if OpenDJ is used for persistence. @@ -636,7 +636,7 @@ config-api: # -- Image to use for deploying. repository: ghcr.io/janssenproject/jans/config-api # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14-1 # -- Image Pull Secrets pullSecrets: [ ] # -- Service replica number. @@ -735,7 +735,7 @@ fido2: # -- Image to use for deploying. repository: ghcr.io/janssenproject/jans/fido2 # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14-1 # -- Image Pull Secrets pullSecrets: [ ] # -- Service replica number. @@ -1618,7 +1618,7 @@ persistence: # -- Image to use for deploying. repository: ghcr.io/janssenproject/jans/persistence-loader # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14-1 # -- Image Pull Secrets pullSecrets: [ ] # -- Resource specs. @@ -1698,7 +1698,7 @@ scim: # -- Image to use for deploying. repository: ghcr.io/janssenproject/jans/scim # -- Image tag to use for deploying. - tag: 1.0.13_dev + tag: 1.0.14-1 # -- Image Pull Secrets pullSecrets: [ ] # -- Service replica number. diff --git a/charts/jenkins/jenkins/CHANGELOG.md b/charts/jenkins/jenkins/CHANGELOG.md index 54d0c436b..138c873a2 100644 --- a/charts/jenkins/jenkins/CHANGELOG.md +++ b/charts/jenkins/jenkins/CHANGELOG.md @@ -12,6 +12,23 @@ Use the following links to reference issues, PRs, and commits prior to v2.6.0. The changelog until v1.5.7 was auto-generated based on git commits. Those entries include a reference to the git commit to be able to get more details. +## 4.3.27 + +Bump kiwigrid/k8s-sidecar from 1.23.1 to 1.24.4 and jenkins/inbound-agent from 3107.v665000b_51092-5 to 3107.v665000b_51092-15. + +## 4.3.26 + +Fix various typos in the chart documentation. + +## 4.3.25 + +| plugin | old version | new version | +|-----------------------|----------------------|-----------------------| +| kubernetes | 3900.va_dce992317b_4 | 3937.vd7b_82db_e347b_ | +| configuration-as-code | 1625.v27444588cc3d | 1647.ve39ca_b_829b_42 | +| git | 5.0.0 | 5.1.0 | +| ldap | 671.v2a_9192a_7419d | 682.v7b_544c9d1512 | + ## 4.3.24 Update Jenkins image and appVersion to jenkins lts release version 2.401.1 diff --git a/charts/jenkins/jenkins/Chart.yaml b/charts/jenkins/jenkins/Chart.yaml index cbd227226..9b31b041d 100644 --- a/charts/jenkins/jenkins/Chart.yaml +++ b/charts/jenkins/jenkins/Chart.yaml @@ -4,9 +4,9 @@ annotations: - name: jenkins image: jenkins/jenkins:2.401.1-jdk11 - name: k8s-sidecar - image: kiwigrid/k8s-sidecar:1.23.1 + image: kiwigrid/k8s-sidecar:1.24.4 - name: inbound-agent - image: jenkins/inbound-agent:3107.v665000b_51092-5 + image: jenkins/inbound-agent:3107.v665000b_51092-15 - name: backup image: maorfr/kube-tasks:0.2.0 artifacthub.io/license: Apache-2.0 @@ -49,4 +49,4 @@ sources: - https://github.com/jenkinsci/docker-inbound-agent - https://github.com/maorfr/kube-tasks - https://github.com/jenkinsci/configuration-as-code-plugin -version: 4.3.24 +version: 4.3.27 diff --git a/charts/jenkins/jenkins/README.md b/charts/jenkins/jenkins/README.md index 40108573d..ed504e48d 100644 --- a/charts/jenkins/jenkins/README.md +++ b/charts/jenkins/jenkins/README.md @@ -222,8 +222,8 @@ Further JCasC examples can be found [here](https://github.com/jenkinsci/configur #### Breaking out large Config as Code scripts -Jenkins Config as Code scripts can become quite large, and maintaining all of your scripts within one yaml file can be difficult. The Config as Code plugin itself suggests updating the `CASC_JENKINS_CONFIG` environment variable to be a comma seperated list of paths for the plugin to traverse, picking up the yaml files as needed. -However, under the Jenkins helm chart, this `CASC_JENKINS_CONFIG` value is maintained through the templates. A better solution is to split your `controller.JCasC.configScripts` into seperate values files, and provide each file during the helm install. +Jenkins Config as Code scripts can become quite large, and maintaining all of your scripts within one yaml file can be difficult. The Config as Code plugin itself suggests updating the `CASC_JENKINS_CONFIG` environment variable to be a comma separated list of paths for the plugin to traverse, picking up the yaml files as needed. +However, under the Jenkins helm chart, this `CASC_JENKINS_CONFIG` value is maintained through the templates. A better solution is to split your `controller.JCasC.configScripts` into separate values files, and provide each file during the helm install. For example, you can have a values file (e.g values_main.yaml) that defines the values described in the `VALUES_SUMMARY.md` for your Jenkins configuration: diff --git a/charts/jenkins/jenkins/VALUES_SUMMARY.md b/charts/jenkins/jenkins/VALUES_SUMMARY.md index 6a3562b5c..5ea05feae 100644 --- a/charts/jenkins/jenkins/VALUES_SUMMARY.md +++ b/charts/jenkins/jenkins/VALUES_SUMMARY.md @@ -21,19 +21,19 @@ The following tables list the configurable parameters of the Jenkins chart and t #### Jenkins Configuration as Code (JCasC) -| Parameter | Description | Default | -| --------------------------------- | ------------------------------------ | ----------------------------------------- | -| `controller.JCasC.defaultConfig` | Enables default Jenkins configuration via configuration as code plugin | `true` | -| `controller.JCasC.configScripts` | List of Jenkins Config as Code scripts | `{}` | -| `controller.JCasC.security` | Jenkins Config as Code for Security section | `legacy` | -| `controller.JCasC.securityRealm` | Jenkins Config as Code for Security Realm | `legacy` | -| `controller.JCasC.authorizationStrategy` | Jenkins Config as Code for Authorization Strategy | `loggedInUsersCanDoAnything` | -| `controller.sidecars.configAutoReload` | Jenkins Config as Code auto-reload settings | | -| `controller.sidecars.configAutoReload.enabled` | Jenkins Config as Code auto-reload settings (Attention: rbac needs to be enabled otherwise the sidecar can't read the config map) | `true` | -| `controller.sidecars.configAutoReload.image` | Image which triggers the reload | `kiwigrid/k8s-sidecar:1.23.1` | -| `controller.sidecars.configAutoReload.reqRetryConnect` | How many connection-related errors to retry on | `10` | -| `controller.sidecars.configAutoReload.envFrom` | Environment variable sources for the Jenkins Config as Code auto-reload container | Not set | -| `controller.sidecars.configAutoReload.env` | Environment variables for the Jenkins Config as Code auto-reload container | Not set | +| Parameter | Description | Default | +| --------------------------------- | ------------------------------------ |-------------------------------------------------------------------| +| `controller.JCasC.defaultConfig` | Enables default Jenkins configuration via configuration as code plugin | `true` | +| `controller.JCasC.configScripts` | List of Jenkins Config as Code scripts | `{}` | +| `controller.JCasC.security` | Jenkins Config as Code for Security section | `legacy` | +| `controller.JCasC.securityRealm` | Jenkins Config as Code for Security Realm | `legacy` | +| `controller.JCasC.authorizationStrategy` | Jenkins Config as Code for Authorization Strategy | `loggedInUsersCanDoAnything` | +| `controller.sidecars.configAutoReload` | Jenkins Config as Code auto-reload settings | | +| `controller.sidecars.configAutoReload.enabled` | Jenkins Config as Code auto-reload settings (Attention: rbac needs to be enabled otherwise the sidecar can't read the config map) | `true` | +| `controller.sidecars.configAutoReload.image` | Image which triggers the reload | `kiwigrid/k8s-sidecar:1.24.4` | +| `controller.sidecars.configAutoReload.reqRetryConnect` | How many connection-related errors to retry on | `10` | +| `controller.sidecars.configAutoReload.envFrom` | Environment variable sources for the Jenkins Config as Code auto-reload container | Not set | +| `controller.sidecars.configAutoReload.env` | Environment variables for the Jenkins Config as Code auto-reload container | Not set | | `controller.sidecars.configAutoReload.containerSecurityContext` | Enable container security context | `{readOnlyRootFilesystem: true, allowPrivilegeEscalation: false}` | #### Jenkins Configuration Files & Scripts diff --git a/charts/jenkins/jenkins/values.yaml b/charts/jenkins/jenkins/values.yaml index 11c0350ba..9df15588e 100644 --- a/charts/jenkins/jenkins/values.yaml +++ b/charts/jenkins/jenkins/values.yaml @@ -241,10 +241,10 @@ controller: # List of plugins to be install during Jenkins controller start installPlugins: - - kubernetes:3900.va_dce992317b_4 + - kubernetes:3937.vd7b_82db_e347b_ - workflow-aggregator:596.v8c21c963d92d - - git:5.0.0 - - configuration-as-code:1625.v27444588cc3d + - git:5.1.0 + - configuration-as-code:1647.ve39ca_b_829b_42 # Set to false to download the minimum required version of all dependencies. installLatestPlugins: true @@ -363,7 +363,7 @@ controller: # jcasc changes will cause a reboot and will only be applied at the subsequent start-up. Auto-reload uses the # http:///reload-configuration-as-code endpoint to reapply config when changes to the configScripts are detected. enabled: true - image: kiwigrid/k8s-sidecar:1.23.1 + image: kiwigrid/k8s-sidecar:1.24.4 imagePullPolicy: IfNotPresent resources: {} # limits: @@ -626,7 +626,7 @@ agent: maxRequestsPerHostStr: "32" namespace: image: "jenkins/inbound-agent" - tag: "3107.v665000b_51092-5" + tag: "3107.v665000b_51092-15" workingDir: "/home/jenkins/agent" nodeUsageMode: "NORMAL" customJenkinsLabels: [] diff --git a/charts/prophetstor/federatorai/.helmignore b/charts/prophetstor/federatorai/.helmignore new file mode 100644 index 000000000..6e16d0407 --- /dev/null +++ b/charts/prophetstor/federatorai/.helmignore @@ -0,0 +1,24 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +tmp/ +archives/ +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/prophetstor/federatorai/Chart.yaml b/charts/prophetstor/federatorai/Chart.yaml index 46458b64d..79615f534 100644 --- a/charts/prophetstor/federatorai/Chart.yaml +++ b/charts/prophetstor/federatorai/Chart.yaml @@ -4,7 +4,7 @@ annotations: catalog.cattle.io/kube-version: '>= 1.16.0-0' catalog.cattle.io/release-name: federatorai apiVersion: v2 -appVersion: 5.1.1-ga +appVersion: 5.1.2-ga description: Federator.ai helps enterprises optimize cloud resources, maximize application performance, and save significant cost without excessive over-provisioning or under-provisioning of resources, meeting the service-level requirements of their applications. @@ -24,4 +24,4 @@ maintainers: name: federatorai sources: - https://www.prophetstor.com -version: 5.1.1 +version: 5.1.2 diff --git a/charts/prophetstor/federatorai/README.md b/charts/prophetstor/federatorai/README.md index 41eb42432..5a42832e3 100644 --- a/charts/prophetstor/federatorai/README.md +++ b/charts/prophetstor/federatorai/README.md @@ -98,7 +98,8 @@ Their default values and other configurable parameters are specified inside valu | global.commonLabels | Common labels to be added to resources | | global.podAnnotations | Annotations to be added to pods | | global.podLabels | Labels to be added to pods | -| global.resourcesEnabled | Boolean to specify if you want to apply resources limits/requests settings | +| global.resourcesLimitsEnabled | Boolean to specify if you want to apply resources limits settings | +| global.resourcesRequestsEnabled | Boolean to specify if you want to apply resources requests settings | ### alamedaAi Parameters @@ -108,6 +109,13 @@ Their default values and other configurable parameters are specified inside valu | alamedaAi.persistence.dataStorageSize | Persistence storage size for data volume | +### alamedaExecutor Parameters + +| Parameter | Description | +| -------------------------------------------------------------- | ------------------------------------------------ | +| alamedaExecutor.enabled | Enable deployment of alameda-executor | + + ### alamedaInfluxdb Parameters | Parameter | Description | @@ -149,6 +157,13 @@ Their default values and other configurable parameters are specified inside valu | federatoraiDashboardFrontend.service.annotations | Additional annotations for REST service | +### federatoraiOperator Parameters + +| Parameter | Description | +| -------------------------------------------------------------- | ------------------------------------------------ | +| federatoraiOperator.enabled | Enable deployment of federatorai-operator | + + ### federatoraiPostgresql Parameters | Parameter | Description | diff --git a/charts/prophetstor/federatorai/crds/crd-alamedaservice.yaml b/charts/prophetstor/federatorai/crds/crd-alamedaservice.yaml index 41850441a..cdbe3d77c 100644 --- a/charts/prophetstor/federatorai/crds/crd-alamedaservice.yaml +++ b/charts/prophetstor/federatorai/crds/crd-alamedaservice.yaml @@ -50,6 +50,10 @@ spec: properties: alameda-dispatcher: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -174,6 +178,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -234,6 +242,10 @@ spec: type: object alamedaAi: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -358,6 +370,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -418,6 +434,10 @@ spec: type: object alamedaDatahub: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -542,6 +562,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -602,6 +626,10 @@ spec: type: object alamedaExecutor: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -726,6 +754,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -786,6 +818,10 @@ spec: type: object alamedaInfluxdb: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -910,6 +946,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -970,6 +1010,10 @@ spec: type: object alamedaNotifier: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -1094,6 +1138,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -1154,6 +1202,10 @@ spec: type: object alamedaRabbitMQ: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -1278,6 +1330,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -1336,6 +1392,10 @@ spec: type: object type: array type: object + annotations: + additionalProperties: + type: string + type: object enableExecution: type: boolean enablePreloader: @@ -1446,6 +1506,10 @@ spec: type: array fedemeter: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -1570,6 +1634,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -1630,6 +1698,10 @@ spec: type: object fedemeterInfluxdb: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -1754,6 +1826,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -1814,6 +1890,10 @@ spec: type: object federatoraiAgent: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -1938,6 +2018,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -1998,6 +2082,10 @@ spec: type: object federatoraiAgentPreloader: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -2122,6 +2210,394 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object + replicas: + format: int32 + minimum: 0 + type: integer + resources: + description: ResourceRequirements describes the compute resource + requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + storages: + items: + properties: + accessModes: + items: + type: string + type: array + class: + type: string + size: + type: string + type: + enum: + - pvc + - ephemeral + type: string + usage: + enum: + - log + - data + type: string + required: + - type + - usage + type: object + type: array + type: object + federatoraiAlertDetector: + properties: + annotations: + additionalProperties: + type: string + type: object + bootstrap: + properties: + image: + type: string + imagepullpolicy: + description: PullPolicy describes a policy for if/when to + pull a container image + type: string + type: object + env: + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be a + C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in + the container and any service environment variables. If + a variable cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced to a single + $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, + metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, requests.memory + and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + image: + type: string + imagepullpolicy: + description: PullPolicy describes a policy for if/when to pull + a container image + type: string + labels: + additionalProperties: + type: string + type: object + replicas: + format: int32 + minimum: 0 + type: integer + resources: + description: ResourceRequirements describes the compute resource + requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + storages: + items: + properties: + accessModes: + items: + type: string + type: array + class: + type: string + size: + type: string + type: + enum: + - pvc + - ephemeral + type: string + usage: + enum: + - log + - data + type: string + required: + - type + - usage + type: object + type: array + type: object + federatoraiAlertManager: + properties: + annotations: + additionalProperties: + type: string + type: object + bootstrap: + properties: + image: + type: string + imagepullpolicy: + description: PullPolicy describes a policy for if/when to + pull a container image + type: string + type: object + env: + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be a + C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in + the container and any service environment variables. If + a variable cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced to a single + $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, + metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, requests.memory + and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + image: + type: string + imagepullpolicy: + description: PullPolicy describes a policy for if/when to pull + a container image + type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -2182,6 +2658,10 @@ spec: type: object federatoraiBackend: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -2306,6 +2786,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -2366,6 +2850,10 @@ spec: type: object federatoraiDataAdapter: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -2490,6 +2978,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -2550,6 +3042,10 @@ spec: type: object federatoraiFrontend: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -2674,6 +3170,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -2734,6 +3234,10 @@ spec: type: object federatoraiPostgreSQL: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -2858,6 +3362,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -2918,6 +3426,10 @@ spec: type: object federatoraiRecommendDispatcher: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -3042,6 +3554,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -3102,6 +3618,10 @@ spec: type: object federatoraiRecommendWorker: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -3226,6 +3746,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -3286,6 +3810,10 @@ spec: type: object federatoraiRest: properties: + annotations: + additionalProperties: + type: string + type: object bootstrap: properties: image: @@ -3410,6 +3938,10 @@ spec: description: PullPolicy describes a policy for if/when to pull a container image type: string + labels: + additionalProperties: + type: string + type: object replicas: format: int32 minimum: 0 @@ -3470,6 +4002,10 @@ spec: type: object imageLocation: type: string + labels: + additionalProperties: + type: string + type: object resources: description: ResourceRequirements describes the compute resource requirements. properties: diff --git a/charts/prophetstor/federatorai/questions.yaml b/charts/prophetstor/federatorai/questions.yaml index 0d1d12fac..f880b10c3 100644 --- a/charts/prophetstor/federatorai/questions.yaml +++ b/charts/prophetstor/federatorai/questions.yaml @@ -1,5 +1,5 @@ questions: -#image configurations +# image configurations - variable: defaultImage default: true description: "Use default Federator.ai image or specify a custom one" @@ -15,12 +15,12 @@ questions: group: "Container Images" label: Federator.ai Image Registry - variable: global.imageTag - default: "v5.1.1-ga" + default: "v5.1.2-gz" description: "Federator.ai image tag" type: string group: "Container Images" label: Federator.ai Image Tag -#service configurations +# service configurations - variable: federatoraiDashboardFrontend.service.nodePort required: true default: "31012" diff --git a/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/clusterrolebindings.yaml deleted file mode 100644 index cad778dd6..000000000 --- a/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-alameda-ai-dispatcher -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-alameda-ai-dispatcher -subjects: -- kind: ServiceAccount - name: alameda-ai-dispatcher - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/clusterroles.yaml b/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/clusterroles.yaml deleted file mode 100644 index 1b5642294..000000000 --- a/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/clusterroles.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-alameda-ai-dispatcher -rules: -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use diff --git a/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/configmaps.yaml b/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/configmaps.yaml index dba3ff8ad..d69b4e207 100644 --- a/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/configmaps.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/configmaps.yaml @@ -1,3 +1,4 @@ +--- apiVersion: v1 data: ai-dispatcher.toml: |- @@ -39,8 +40,14 @@ data: outputLevel = "info" # debug, info, warn, error, fatal, none kind: ConfigMap metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-ai-dispatcher-config diff --git a/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/deployments.yaml b/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/deployments.yaml index 67ca1f1c5..26d90417a 100644 --- a/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/deployments.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-ai-dispatcher @@ -18,84 +25,106 @@ spec: type: Recreate template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-ai-dispatcher spec: - affinity: {{- include "render-value" ( dict "value" .Values.alamedaAiDispatcher.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.alamedaAiDispatcher.affinity }} +{{- include "render-value" ( dict "value" .Values.alamedaAiDispatcher.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - env: - - name: NAMESPACE_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.name - - name: ALAMEDA_AI_DISPATCHER_DATAHUB_ADDRESS - value: alameda-datahub.{{ .Release.Namespace }}.svc:50050 - - name: ALAMEDA_AI_DISPATCHER_QUEUE_URL - value: amqp://admin:adminpass@alameda-rabbitmq.{{ .Release.Namespace }}.svc:5672 - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/alameda-ai-dispatcher:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: - - /usr/local/bin/ai-dispatcher - - probe - - --type=liveness - failureThreshold: 5 - initialDelaySeconds: 60 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 300 - name: ai-dispatcher - ports: - - containerPort: 9091 - name: metrics - protocol: TCP - readinessProbe: - exec: - command: - - /usr/local/bin/ai-dispatcher - - probe - - --type=readiness - failureThreshold: 3 - initialDelaySeconds: 60 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 60 - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.alamedaAiDispatcher.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/log/alameda - name: alameda-dispatcher-log-storage - - mountPath: /etc/alameda/ai-dispatcher/ai-dispatcher.toml - name: alameda-ai-dispatcher-config - subPath: ai-dispatcher.toml - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - env: + - name: NAMESPACE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ALAMEDA_AI_DISPATCHER_DATAHUB_ADDRESS + value: alameda-datahub.{{ .Release.Namespace }}.svc:50050 + - name: ALAMEDA_AI_DISPATCHER_QUEUE_URL + value: amqp://admin:adminpass@alameda-rabbitmq.{{ .Release.Namespace }}.svc:5672 + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/alameda-ai-dispatcher:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - /usr/local/bin/ai-dispatcher + - probe + - --type=liveness + failureThreshold: 5 + initialDelaySeconds: 60 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 300 + name: ai-dispatcher + ports: + - containerPort: 9091 + name: metrics + protocol: TCP + readinessProbe: + exec: + command: + - /usr/local/bin/ai-dispatcher + - probe + - --type=readiness + failureThreshold: 3 + initialDelaySeconds: 60 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 60 + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.alamedaAiDispatcher.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.alamedaAiDispatcher.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /var/log/alameda + name: alameda-dispatcher-log-storage + - mountPath: /etc/alameda/ai-dispatcher/ai-dispatcher.toml + name: alameda-ai-dispatcher-config + subPath: ai-dispatcher.toml + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.alamedaAiDispatcher.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.alamedaAiDispatcher.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.alamedaAiDispatcher.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: alameda-ai-dispatcher serviceAccountName: alameda-ai-dispatcher - tolerations: {{- include "render-value" ( dict "value" .Values.alamedaAiDispatcher.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.alamedaAiDispatcher.tolerations }} +{{- include "render-value" ( dict "value" .Values.alamedaAiDispatcher.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - configMap: - defaultMode: 420 + - configMap: + defaultMode: 420 + name: alameda-ai-dispatcher-config name: alameda-ai-dispatcher-config - name: alameda-ai-dispatcher-config - - emptyDir: {} - name: alameda-dispatcher-data-storage - - name: alameda-dispatcher-log-storage - persistentVolumeClaim: - claimName: alameda-dispatcher-log.pvc + - emptyDir: {} + name: alameda-dispatcher-data-storage + - name: alameda-dispatcher-log-storage + persistentVolumeClaim: + claimName: alameda-dispatcher-log.pvc diff --git a/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/pvc-log.yaml b/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/pvc-log.yaml index 8cd5c3e0a..244278520 100644 --- a/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/pvc-log.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-dispatcher-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.alamedaAiDispatcher.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.alamedaAiDispatcher.persistence.accessModes }} +{{ .Values.alamedaAiDispatcher.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.alamedaAiDispatcher.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/serviceaccounts.yaml index cddb96376..74238616d 100644 --- a/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-ai-dispatcher diff --git a/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/services.yaml b/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/services.yaml index f36c0f476..9a129a776 100644 --- a/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/services.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-ai-dispatcher/services.yaml @@ -1,18 +1,25 @@ +--- apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-ai-dispatcher namespace: {{ .Release.Namespace }} spec: ports: - - name: ai-dispatcher-metrics - port: 9091 - protocol: TCP - targetPort: metrics + - name: ai-dispatcher-metrics + port: 9091 + protocol: TCP + targetPort: metrics selector: component: alameda-ai-dispatcher type: ClusterIP diff --git a/charts/prophetstor/federatorai/templates/alameda-ai/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/alameda-ai/clusterrolebindings.yaml deleted file mode 100644 index 91879ed7b..000000000 --- a/charts/prophetstor/federatorai/templates/alameda-ai/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-alameda-ai -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-alameda-ai -subjects: -- kind: ServiceAccount - name: alameda-ai - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/alameda-ai/clusterroles.yaml b/charts/prophetstor/federatorai/templates/alameda-ai/clusterroles.yaml deleted file mode 100644 index 43d2911c0..000000000 --- a/charts/prophetstor/federatorai/templates/alameda-ai/clusterroles.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-alameda-ai -rules: -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use diff --git a/charts/prophetstor/federatorai/templates/alameda-ai/configmaps.yaml b/charts/prophetstor/federatorai/templates/alameda-ai/configmaps.yaml index 66850ce00..759c7530c 100644 --- a/charts/prophetstor/federatorai/templates/alameda-ai/configmaps.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-ai/configmaps.yaml @@ -1,3 +1,4 @@ +--- apiVersion: v1 data: config.yaml: |- @@ -38,8 +39,14 @@ data: minimal_metric_size: 10 kind: ConfigMap metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-ai-config diff --git a/charts/prophetstor/federatorai/templates/alameda-ai/deployments.yaml b/charts/prophetstor/federatorai/templates/alameda-ai/deployments.yaml index f0dd9b7ae..e44da69c3 100644 --- a/charts/prophetstor/federatorai/templates/alameda-ai/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-ai/deployments.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-ai @@ -18,97 +25,118 @@ spec: type: Recreate template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-ai name: alameda-ai spec: - affinity: {{- include "render-value" ( dict "value" .Values.alamedaAi.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.alamedaAi.affinity }} +{{- include "render-value" ( dict "value" .Values.alamedaAi.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - env: - - name: NAMESPACE_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.name - - name: DATAHUB_ADDRESS - value: alameda-datahub.{{ .Release.Namespace }}.svc:50050 - - name: PREDICT_QUEUE_URL - value: amqp://admin:adminpass@alameda-rabbitmq.{{ .Release.Namespace }}.svc:5672 - - name: MAX_CPU_USAGE_PERCENTAGE - value: "0.5" - - name: NODE_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: spec.nodeName - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/alameda-ai:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: - - /probe.sh - - --type=liveness - failureThreshold: 3 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 30 - name: alameda-ai-engine - ports: - - containerPort: 9091 - name: ai-metrics - protocol: TCP - readinessProbe: - exec: - command: - - /probe.sh - - --type=readiness - failureThreshold: 3 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 30 - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.alamedaAi.resources "context" .) | nindent 10 }} - {{- else }} - requests: - cpu: "2" - memory: 1000Mi - {{- end }} - volumeMounts: - - mountPath: /var/lib/alameda - name: alameda-ai-data-storage - - mountPath: /var/log/alameda - name: alameda-ai-log-storage - - mountPath: /etc/alameda/alameda-ai/config.yaml - name: alameda-ai-config - subPath: config.yaml - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - env: + - name: NAMESPACE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: DATAHUB_ADDRESS + value: alameda-datahub.{{ .Release.Namespace }}.svc:50050 + - name: PREDICT_QUEUE_URL + value: amqp://admin:adminpass@alameda-rabbitmq.{{ .Release.Namespace }}.svc:5672 + - name: MAX_CPU_USAGE_PERCENTAGE + value: "0.5" + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/alameda-ai:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - /probe.sh + - --type=liveness + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 30 + name: alameda-ai-engine + ports: + - containerPort: 9091 + name: ai-metrics + protocol: TCP + readinessProbe: + exec: + command: + - /probe.sh + - --type=readiness + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 30 + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.alamedaAi.resources.limits "context" .) | nindent 14 }} +{{- end }} + requests: +{{- if .Values.global.resourcesRequestsEnabled }} +{{- include "render-value" ( dict "value" .Values.alamedaAi.resources.requests "context" .) | nindent 14 }} +{{- else }} + cpu: 2000m + memory: 1000Mi +{{- end }} + volumeMounts: + - mountPath: /var/lib/alameda + name: alameda-ai-data-storage + - mountPath: /var/log/alameda + name: alameda-ai-log-storage + - mountPath: /etc/alameda/alameda-ai/config.yaml + name: alameda-ai-config + subPath: config.yaml + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.alamedaAi.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.alamedaAi.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.alamedaAi.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: alameda-ai serviceAccountName: alameda-ai - tolerations: {{- include "render-value" ( dict "value" .Values.alamedaAi.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.alamedaAi.tolerations }} +{{- include "render-value" ( dict "value" .Values.alamedaAi.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - configMap: - defaultMode: 420 + - configMap: + defaultMode: 420 + name: alameda-ai-config name: alameda-ai-config - name: alameda-ai-config - - name: alameda-ai-data-storage - persistentVolumeClaim: - claimName: alameda-ai-data.pvc - - name: alameda-ai-log-storage - persistentVolumeClaim: - claimName: alameda-ai-log.pvc + - name: alameda-ai-data-storage + persistentVolumeClaim: + claimName: alameda-ai-data.pvc + - name: alameda-ai-log-storage + persistentVolumeClaim: + claimName: alameda-ai-log.pvc diff --git a/charts/prophetstor/federatorai/templates/alameda-ai/pvc-data.yaml b/charts/prophetstor/federatorai/templates/alameda-ai/pvc-data.yaml index 25a41799e..930d036bb 100644 --- a/charts/prophetstor/federatorai/templates/alameda-ai/pvc-data.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-ai/pvc-data.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-ai-data.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.alamedaAi.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.alamedaAi.persistence.accessModes }} +{{ .Values.alamedaAi.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.alamedaAi.persistence.dataStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/alameda-ai/pvc-log.yaml b/charts/prophetstor/federatorai/templates/alameda-ai/pvc-log.yaml index 507c2236a..85ee95184 100644 --- a/charts/prophetstor/federatorai/templates/alameda-ai/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-ai/pvc-log.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-ai-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.alamedaAi.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.alamedaAi.persistence.accessModes }} +{{ .Values.alamedaAi.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.alamedaAi.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/alameda-ai/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/alameda-ai/serviceaccounts.yaml index 1cfcc6865..5cfce0aec 100644 --- a/charts/prophetstor/federatorai/templates/alameda-ai/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-ai/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-ai diff --git a/charts/prophetstor/federatorai/templates/alameda-ai/services.yaml b/charts/prophetstor/federatorai/templates/alameda-ai/services.yaml index d2a6ec755..a4ff81a99 100644 --- a/charts/prophetstor/federatorai/templates/alameda-ai/services.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-ai/services.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-ai @@ -10,10 +17,10 @@ metadata: namespace: {{ .Release.Namespace }} spec: ports: - - name: ai-metrics - port: 9091 - protocol: TCP - targetPort: 9091 + - name: ai-metrics + port: 9091 + protocol: TCP + targetPort: 9091 selector: component: alameda-ai type: ClusterIP diff --git a/charts/prophetstor/federatorai/templates/alameda-datahub/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/alameda-datahub/clusterrolebindings.yaml deleted file mode 100644 index e7016fc78..000000000 --- a/charts/prophetstor/federatorai/templates/alameda-datahub/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-alameda-datahub -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-alameda-datahub -subjects: -- kind: ServiceAccount - name: alameda-datahub - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/alameda-datahub/clusterroles.yaml b/charts/prophetstor/federatorai/templates/alameda-datahub/clusterroles.yaml deleted file mode 100644 index 81730e8b9..000000000 --- a/charts/prophetstor/federatorai/templates/alameda-datahub/clusterroles.yaml +++ /dev/null @@ -1,44 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-alameda-datahub -rules: -- apiGroups: - - "" - resources: - - namespaces - - pods - verbs: - - get -- apiGroups: - - federatorai.containers.ai - resources: - - '*' - verbs: - - '*' -- apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - update - - create -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use diff --git a/charts/prophetstor/federatorai/templates/alameda-datahub/deployments.yaml b/charts/prophetstor/federatorai/templates/alameda-datahub/deployments.yaml index b30ebaecb..7cfd3c0b0 100644 --- a/charts/prophetstor/federatorai/templates/alameda-datahub/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-datahub/deployments.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-datahub @@ -21,82 +28,104 @@ spec: type: RollingUpdate template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-datahub name: alameda-datahub spec: - affinity: {{- include "render-value" ( dict "value" .Values.alamedaDatahub.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.alamedaDatahub.affinity }} +{{- include "render-value" ( dict "value" .Values.alamedaDatahub.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - env: - - name: NAMESPACE_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.name - - name: ALAMEDA_DATAHUB_INFLUXDB_ADDRESS - value: https://alameda-influxdb.{{ .Release.Namespace }}.svc:8086 - - name: ALAMEDA_DATAHUB_INFLUXDB_USERNAME - value: admin - - name: ALAMEDA_DATAHUB_INFLUXDB_PASSWORD - value: adminpass - - name: ALAMEDA_DATAHUB_RABBITMQ_URL - value: amqp://admin:adminpass@alameda-rabbitmq.{{ .Release.Namespace }}.svc:5672 - - name: ALAMEDA_DATAHUB_FEDEMETER_ADDRESS - value: http://fedemeter-api.{{ .Release.Namespace }}.svc:8888 - - name: ALAMEDA_DATAHUB_FEDEMETER_USERNAME - value: fedemeter - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/alameda-datahub-ubi:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: - - sh - - -c - - /init.sh liveness - failureThreshold: 3 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 5 - name: alameda-datahub - readinessProbe: - exec: - command: - - sh - - -c - - /init.sh readiness - failureThreshold: 3 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 5 - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.alamedaDatahub.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/log/alameda - name: alameda-datahub-log-storage - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - env: + - name: NAMESPACE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ALAMEDA_DATAHUB_INFLUXDB_ADDRESS + value: https://alameda-influxdb.{{ .Release.Namespace }}.svc:8086 + - name: ALAMEDA_DATAHUB_INFLUXDB_USERNAME + value: admin + - name: ALAMEDA_DATAHUB_INFLUXDB_PASSWORD + value: adminpass + - name: ALAMEDA_DATAHUB_RABBITMQ_URL + value: amqp://admin:adminpass@alameda-rabbitmq.{{ .Release.Namespace }}.svc:5672 + - name: ALAMEDA_DATAHUB_FEDEMETER_ADDRESS + value: http://fedemeter-api.{{ .Release.Namespace }}.svc:8888 + - name: ALAMEDA_DATAHUB_FEDEMETER_USERNAME + value: fedemeter + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/alameda-datahub-ubi:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - sh + - -c + - /init.sh liveness + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 5 + name: alameda-datahub + readinessProbe: + exec: + command: + - sh + - -c + - /init.sh readiness + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 5 + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.alamedaDatahub.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.alamedaDatahub.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /var/log/alameda + name: alameda-datahub-log-storage + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.alamedaDatahub.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.alamedaDatahub.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.alamedaDatahub.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: alameda-datahub serviceAccountName: alameda-datahub - tolerations: {{- include "render-value" ( dict "value" .Values.alamedaDatahub.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.alamedaDatahub.tolerations }} +{{- include "render-value" ( dict "value" .Values.alamedaDatahub.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - emptyDir: {} - name: alameda-datahub-data-storage - - name: alameda-datahub-log-storage - persistentVolumeClaim: - claimName: alameda-datahub-log.pvc + - emptyDir: {} + name: alameda-datahub-data-storage + - name: alameda-datahub-log-storage + persistentVolumeClaim: + claimName: alameda-datahub-log.pvc diff --git a/charts/prophetstor/federatorai/templates/alameda-datahub/pvc-log.yaml b/charts/prophetstor/federatorai/templates/alameda-datahub/pvc-log.yaml index 7b2f76fea..f0cc10535 100644 --- a/charts/prophetstor/federatorai/templates/alameda-datahub/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-datahub/pvc-log.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-datahub-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.alamedaDatahub.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.alamedaDatahub.persistence.accessModes }} +{{ .Values.alamedaDatahub.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.alamedaDatahub.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/alameda-datahub/rolebindings.yaml b/charts/prophetstor/federatorai/templates/alameda-datahub/rolebindings.yaml index 45a3ce6ba..f3353b3c7 100644 --- a/charts/prophetstor/federatorai/templates/alameda-datahub/rolebindings.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-datahub/rolebindings.yaml @@ -1,8 +1,15 @@ +--- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-datahub @@ -12,6 +19,6 @@ roleRef: kind: Role name: alameda-datahub subjects: -- kind: ServiceAccount - name: alameda-datahub - namespace: {{ .Release.Namespace }} + - kind: ServiceAccount + name: alameda-datahub + namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/alameda-datahub/roles.yaml b/charts/prophetstor/federatorai/templates/alameda-datahub/roles.yaml index 5d8e21d06..9f3fef121 100644 --- a/charts/prophetstor/federatorai/templates/alameda-datahub/roles.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-datahub/roles.yaml @@ -1,29 +1,39 @@ +--- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-datahub namespace: {{ .Release.Namespace }} rules: -- apiGroups: - - "" - resources: - - configmaps - verbs: - - update - - create -- apiGroups: - - "" - resources: - - pods - verbs: - - list -- apiGroups: - - "" - resources: - - pods/exec - verbs: - - create + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - update + - create + - apiGroups: + - "" + resources: + - pods + verbs: + - list + - apiGroups: + - "" + resources: + - pods/exec + verbs: + - create diff --git a/charts/prophetstor/federatorai/templates/alameda-datahub/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/alameda-datahub/serviceaccounts.yaml index ef8f67898..56a7f5ce4 100644 --- a/charts/prophetstor/federatorai/templates/alameda-datahub/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-datahub/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-datahub diff --git a/charts/prophetstor/federatorai/templates/alameda-datahub/services.yaml b/charts/prophetstor/federatorai/templates/alameda-datahub/services.yaml index 74a3e4343..76ecfb9a5 100644 --- a/charts/prophetstor/federatorai/templates/alameda-datahub/services.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-datahub/services.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-datahub @@ -10,10 +17,10 @@ metadata: namespace: {{ .Release.Namespace }} spec: ports: - - name: grpc - port: 50050 - protocol: TCP - targetPort: 50050 + - name: grpc + port: 50050 + protocol: TCP + targetPort: 50050 selector: component: alameda-datahub type: ClusterIP diff --git a/charts/prophetstor/federatorai/templates/alameda-executor/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/alameda-executor/clusterrolebindings.yaml index 1ff1b1c13..3b4c6979b 100644 --- a/charts/prophetstor/federatorai/templates/alameda-executor/clusterrolebindings.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-executor/clusterrolebindings.yaml @@ -1,8 +1,16 @@ +--- +{{- if .Values.alamedaExecutor.enabled }} apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: {{ .Release.Namespace }}-alameda-executor @@ -11,6 +19,7 @@ roleRef: kind: ClusterRole name: {{ .Release.Namespace }}-alameda-executor subjects: -- kind: ServiceAccount - name: alameda-executor - namespace: {{ .Release.Namespace }} + - kind: ServiceAccount + name: alameda-executor + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/alameda-executor/clusterroles.yaml b/charts/prophetstor/federatorai/templates/alameda-executor/clusterroles.yaml index 69ce91cec..2464a50e8 100644 --- a/charts/prophetstor/federatorai/templates/alameda-executor/clusterroles.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-executor/clusterroles.yaml @@ -1,72 +1,81 @@ +--- +{{- if .Values.alamedaExecutor.enabled }} apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: {{ .Release.Namespace }}-alameda-executor rules: -- apiGroups: - - "" - resources: - - resourcequotas - verbs: - - create - - list - - get - - patch - - delete -- apiGroups: - - apps - - extensions - resources: - - replicasets - - deployments - verbs: - - get - - list - - update - - patch -- apiGroups: - - apps - resources: - - statefulsets - verbs: - - get - - list - - update - - patch -- apiGroups: - - apps.openshift.io - resources: - - deploymentconfigs - verbs: - - get - - list - - update - - patch -- apiGroups: - - autoscaling - resources: - - horizontalpodautoscalers - verbs: - - list -- apiGroups: - - "" - resources: - - configmaps - verbs: - - get -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use + - apiGroups: + - "" + resources: + - resourcequotas + verbs: + - create + - list + - get + - patch + - delete + - apiGroups: + - apps + - extensions + resources: + - replicasets + - deployments + verbs: + - get + - list + - update + - patch + - apiGroups: + - apps + resources: + - statefulsets + verbs: + - get + - list + - update + - patch + - apiGroups: + - apps.openshift.io + resources: + - deploymentconfigs + verbs: + - get + - list + - update + - patch + - apiGroups: + - autoscaling + resources: + - horizontalpodautoscalers + verbs: + - list + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - apiGroups: + - policy + resources: + - podsecuritypolicies + verbs: + - use + - apiGroups: + - security.openshift.io + resources: + - securitycontextconstraints + verbs: + - use +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/alameda-executor/configmaps.yaml b/charts/prophetstor/federatorai/templates/alameda-executor/configmaps.yaml index 80669b839..58e6288fe 100644 --- a/charts/prophetstor/federatorai/templates/alameda-executor/configmaps.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-executor/configmaps.yaml @@ -1,3 +1,5 @@ +--- +{{- if .Values.alamedaExecutor.enabled }} apiVersion: v1 data: config.toml: |- @@ -21,9 +23,16 @@ data: output_log_level = "info" kind: ConfigMap metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-executor-config namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/alameda-executor/deployments.yaml b/charts/prophetstor/federatorai/templates/alameda-executor/deployments.yaml index 8b3ede08c..b07c7d5de 100644 --- a/charts/prophetstor/federatorai/templates/alameda-executor/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-executor/deployments.yaml @@ -1,8 +1,16 @@ +--- +{{- if .Values.alamedaExecutor.enabled }} apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-executor @@ -18,76 +26,99 @@ spec: type: Recreate template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-executor spec: - affinity: {{- include "render-value" ( dict "value" .Values.alamedaExecutor.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.alamedaExecutor.affinity }} +{{- include "render-value" ( dict "value" .Values.alamedaExecutor.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - env: - - name: NAMESPACE_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.name - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/alameda-executor-ubi:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: - - /usr/local/bin/federatorai-executor - - probe - - --type=liveness - failureThreshold: 3 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 5 - name: alameda-executor - readinessProbe: - exec: - command: - - /usr/local/bin/federatorai-executor - - probe - - --type=readiness - failureThreshold: 3 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 5 - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.alamedaExecutor.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/log/alameda - name: alameda-executor-log-storage - - mountPath: /etc/alameda/federatorai-execution/config.toml - name: alameda-executor-config - subPath: config.toml - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - env: + - name: NAMESPACE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/alameda-executor-ubi:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - /usr/local/bin/federatorai-executor + - probe + - --type=liveness + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 5 + name: alameda-executor + readinessProbe: + exec: + command: + - /usr/local/bin/federatorai-executor + - probe + - --type=readiness + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 5 + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.alamedaExecutor.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.alamedaExecutor.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /var/log/alameda + name: alameda-executor-log-storage + - mountPath: /etc/alameda/federatorai-execution/config.toml + name: alameda-executor-config + subPath: config.toml + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.alamedaExecutor.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.alamedaExecutor.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.alamedaExecutor.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: alameda-executor serviceAccountName: alameda-executor - tolerations: {{- include "render-value" ( dict "value" .Values.alamedaExecutor.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.alamedaExecutor.tolerations }} +{{- include "render-value" ( dict "value" .Values.alamedaExecutor.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - emptyDir: {} - name: alameda-executor-data-storage - - name: alameda-executor-log-storage - persistentVolumeClaim: - claimName: alameda-executor-log.pvc - - configMap: - defaultMode: 420 + - emptyDir: {} + name: alameda-executor-data-storage + - name: alameda-executor-log-storage + persistentVolumeClaim: + claimName: alameda-executor-log.pvc + - configMap: + defaultMode: 420 + name: alameda-executor-config name: alameda-executor-config - name: alameda-executor-config +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/alameda-executor/pvc-log.yaml b/charts/prophetstor/federatorai/templates/alameda-executor/pvc-log.yaml index 33665b3a7..2526ebb19 100644 --- a/charts/prophetstor/federatorai/templates/alameda-executor/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-executor/pvc-log.yaml @@ -1,17 +1,29 @@ +--- +{{- if .Values.alamedaExecutor.enabled }} apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-executor-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.alamedaExecutor.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.alamedaExecutor.persistence.accessModes }} +{{ .Values.alamedaExecutor.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.alamedaExecutor.persistence.logStorageSize }} {{- if .Values.global.storageClassName }} storageClassName: {{ .Values.global.storageClassName }} {{- end }} +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/alameda-executor/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/alameda-executor/serviceaccounts.yaml index 1582db4e8..a14941a80 100644 --- a/charts/prophetstor/federatorai/templates/alameda-executor/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-executor/serviceaccounts.yaml @@ -1,9 +1,18 @@ +--- +{{- if .Values.alamedaExecutor.enabled }} apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-executor namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/alameda-influxdb/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/alameda-influxdb/clusterrolebindings.yaml deleted file mode 100644 index a9c0c8066..000000000 --- a/charts/prophetstor/federatorai/templates/alameda-influxdb/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-alameda-influxdb -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-alameda-influxdb -subjects: -- kind: ServiceAccount - name: alameda-influxdb - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/alameda-influxdb/clusterroles.yaml b/charts/prophetstor/federatorai/templates/alameda-influxdb/clusterroles.yaml deleted file mode 100644 index 6a19fe3dd..000000000 --- a/charts/prophetstor/federatorai/templates/alameda-influxdb/clusterroles.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-alameda-influxdb -rules: -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use diff --git a/charts/prophetstor/federatorai/templates/alameda-influxdb/pvc-data.yaml b/charts/prophetstor/federatorai/templates/alameda-influxdb/pvc-data.yaml index 9257ebe7f..d65635367 100644 --- a/charts/prophetstor/federatorai/templates/alameda-influxdb/pvc-data.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-influxdb/pvc-data.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: my-alameda.influxdb-data.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.alamedaInfluxdb.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.alamedaInfluxdb.persistence.accessModes }} +{{ .Values.alamedaInfluxdb.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.alamedaInfluxdb.persistence.dataStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/alameda-influxdb/pvc-log.yaml b/charts/prophetstor/federatorai/templates/alameda-influxdb/pvc-log.yaml index 74db0d33d..fb3838722 100644 --- a/charts/prophetstor/federatorai/templates/alameda-influxdb/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-influxdb/pvc-log.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: my-alameda.influxdb-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.alamedaInfluxdb.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.alamedaInfluxdb.persistence.accessModes }} +{{ .Values.alamedaInfluxdb.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.alamedaInfluxdb.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/alameda-influxdb/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/alameda-influxdb/serviceaccounts.yaml index e77f10660..54af7b3a9 100644 --- a/charts/prophetstor/federatorai/templates/alameda-influxdb/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-influxdb/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-influxdb diff --git a/charts/prophetstor/federatorai/templates/alameda-influxdb/services.yaml b/charts/prophetstor/federatorai/templates/alameda-influxdb/services.yaml index c94139c7e..52e6a790e 100644 --- a/charts/prophetstor/federatorai/templates/alameda-influxdb/services.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-influxdb/services.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-influxdb @@ -10,9 +17,9 @@ metadata: namespace: {{ .Release.Namespace }} spec: ports: - - port: 8086 - protocol: TCP - targetPort: 8086 + - port: 8086 + protocol: TCP + targetPort: 8086 selector: component: alameda-influxdb type: ClusterIP diff --git a/charts/prophetstor/federatorai/templates/alameda-influxdb/statefulsets.yaml b/charts/prophetstor/federatorai/templates/alameda-influxdb/statefulsets.yaml index 929825b18..4b9eb2c40 100644 --- a/charts/prophetstor/federatorai/templates/alameda-influxdb/statefulsets.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-influxdb/statefulsets.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: StatefulSet metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-influxdb @@ -17,86 +24,108 @@ spec: serviceName: "" template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-influxdb spec: - affinity: {{- include "render-value" ( dict "value" .Values.alamedaInfluxdb.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.alamedaInfluxdb.affinity }} +{{- include "render-value" ( dict "value" .Values.alamedaInfluxdb.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - env: - - name: INFLUXDB_REPORTING_DISABLED - value: "true" - - name: INFLUXDB_HTTP_HTTPS_ENABLED - value: "true" - - name: INFLUXDB_HTTP_AUTH_ENABLED - value: "true" - - name: INFLUXDB_ADMIN_USER - value: admin - - name: INFLUXDB_ADMIN_PASSWORD - value: adminpass - - name: INFLUXDB_USER - value: user - - name: INFLUXDB_USER_PASSWORD - value: userpass - - name: INFLUXDB_LOGGING_LEVEL - value: warn - - name: INFLUXDB_DATA_MAX_VALUES_PER_TAG - value: "0" - - name: INFLUXDB_DATA_MAX_SERIES_PER_DATABASE - value: "0" - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/alameda-influxdb:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: - - sh - - -c - - /init.sh liveness - failureThreshold: 3 - initialDelaySeconds: 600 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 30 - name: influxdb - readinessProbe: - exec: - command: - - sh - - -c - - /init.sh readiness - failureThreshold: 3 - initialDelaySeconds: 30 - periodSeconds: 30 - successThreshold: 1 - timeoutSeconds: 30 - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.alamedaInfluxdb.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/log/influxdb - name: influxdb-log-storage - subPath: influxdb - - mountPath: /var/lib/influxdb - name: influxdb-data-storage - subPath: influxdb - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - env: + - name: INFLUXDB_REPORTING_DISABLED + value: "true" + - name: INFLUXDB_HTTP_HTTPS_ENABLED + value: "true" + - name: INFLUXDB_HTTP_AUTH_ENABLED + value: "true" + - name: INFLUXDB_ADMIN_USER + value: admin + - name: INFLUXDB_ADMIN_PASSWORD + value: adminpass + - name: INFLUXDB_USER + value: user + - name: INFLUXDB_USER_PASSWORD + value: userpass + - name: INFLUXDB_LOGGING_LEVEL + value: warn + - name: INFLUXDB_DATA_MAX_VALUES_PER_TAG + value: "0" + - name: INFLUXDB_DATA_MAX_SERIES_PER_DATABASE + value: "0" + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/alameda-influxdb:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - sh + - -c + - /init.sh liveness + failureThreshold: 3 + initialDelaySeconds: 600 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 30 + name: influxdb + readinessProbe: + exec: + command: + - sh + - -c + - /init.sh readiness + failureThreshold: 3 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 30 + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.alamedaInfluxdb.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.alamedaInfluxdb.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /var/log/influxdb + name: influxdb-log-storage + subPath: influxdb + - mountPath: /var/lib/influxdb + name: influxdb-data-storage + subPath: influxdb + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.alamedaInfluxdb.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.alamedaInfluxdb.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.alamedaInfluxdb.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: alameda-influxdb serviceAccountName: alameda-influxdb - tolerations: {{- include "render-value" ( dict "value" .Values.alamedaInfluxdb.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.alamedaInfluxdb.tolerations }} +{{- include "render-value" ( dict "value" .Values.alamedaInfluxdb.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - name: influxdb-data-storage - persistentVolumeClaim: - claimName: my-alameda.influxdb-data.pvc - - name: influxdb-log-storage - persistentVolumeClaim: - claimName: my-alameda.influxdb-log.pvc + - name: influxdb-data-storage + persistentVolumeClaim: + claimName: my-alameda.influxdb-data.pvc + - name: influxdb-log-storage + persistentVolumeClaim: + claimName: my-alameda.influxdb-log.pvc updateStrategy: type: RollingUpdate diff --git a/charts/prophetstor/federatorai/templates/alameda-notifier/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/alameda-notifier/clusterrolebindings.yaml deleted file mode 100644 index 7e986a9b1..000000000 --- a/charts/prophetstor/federatorai/templates/alameda-notifier/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-alameda-notifier-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-alameda-notifier-role -subjects: -- kind: ServiceAccount - name: alameda-notifier - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/alameda-notifier/clusterroles.yaml b/charts/prophetstor/federatorai/templates/alameda-notifier/clusterroles.yaml deleted file mode 100644 index 02b95573e..000000000 --- a/charts/prophetstor/federatorai/templates/alameda-notifier/clusterroles.yaml +++ /dev/null @@ -1,37 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-alameda-notifier-role -rules: -- apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch -- apiGroups: - - "" - resources: - - nodes - verbs: - - get - - list - - watch -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use diff --git a/charts/prophetstor/federatorai/templates/alameda-notifier/deployments.yaml b/charts/prophetstor/federatorai/templates/alameda-notifier/deployments.yaml index 14e45d838..ca5087cf2 100644 --- a/charts/prophetstor/federatorai/templates/alameda-notifier/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-notifier/deployments.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-notifier @@ -18,71 +25,93 @@ spec: type: Recreate template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-notifier spec: - affinity: {{- include "render-value" ( dict "value" .Values.alamedaNotifier.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.alamedaNotifier.affinity }} +{{- include "render-value" ( dict "value" .Values.alamedaNotifier.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - env: - - name: NAMESPACE_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.name - - name: ALAMEDA_NOTIFIER_DATAHUB_ADDRESS - value: alameda-datahub.{{ .Release.Namespace }}.svc:50050 - - name: ALAMEDA_NOTIFIER_RABBITMQ_URL - value: amqp://admin:adminpass@alameda-rabbitmq.{{ .Release.Namespace }}.svc:5672 - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/alameda-notifier-ubi:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: - - /usr/local/bin/notifier - - --liveness-probe - failureThreshold: 3 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 5 - name: alameda-notifier - readinessProbe: - exec: - command: - - /usr/local/bin/notifier - - --readiness-probe - failureThreshold: 3 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 5 - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.alamedaNotifier.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/log/alameda - name: alameda-notifier-log-storage - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - env: + - name: NAMESPACE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ALAMEDA_NOTIFIER_DATAHUB_ADDRESS + value: alameda-datahub.{{ .Release.Namespace }}.svc:50050 + - name: ALAMEDA_NOTIFIER_RABBITMQ_URL + value: amqp://admin:adminpass@alameda-rabbitmq.{{ .Release.Namespace }}.svc:5672 + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/alameda-notifier-ubi:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - /usr/local/bin/notifier + - --liveness-probe + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 5 + name: alameda-notifier + readinessProbe: + exec: + command: + - /usr/local/bin/notifier + - --readiness-probe + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 5 + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.alamedaNotifier.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.alamedaNotifier.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /var/log/alameda + name: alameda-notifier-log-storage + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.alamedaNotifier.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.alamedaNotifier.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.alamedaNotifier.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: alameda-notifier serviceAccountName: alameda-notifier - tolerations: {{- include "render-value" ( dict "value" .Values.alamedaNotifier.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.alamedaNotifier.tolerations }} +{{- include "render-value" ( dict "value" .Values.alamedaNotifier.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - emptyDir: {} - name: alameda-notifier-data-storage - - name: alameda-notifier-log-storage - persistentVolumeClaim: - claimName: alameda-notifier-log.pvc + - emptyDir: {} + name: alameda-notifier-data-storage + - name: alameda-notifier-log-storage + persistentVolumeClaim: + claimName: alameda-notifier-log.pvc diff --git a/charts/prophetstor/federatorai/templates/alameda-notifier/pvc-log.yaml b/charts/prophetstor/federatorai/templates/alameda-notifier/pvc-log.yaml index e7227b374..fd0ac04ed 100644 --- a/charts/prophetstor/federatorai/templates/alameda-notifier/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-notifier/pvc-log.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: alameda-notifier-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.alamedaNotifier.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.alamedaNotifier.persistence.accessModes }} +{{ .Values.alamedaNotifier.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.alamedaNotifier.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/alameda-notifier/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/alameda-notifier/serviceaccounts.yaml index 75dccf3b6..8f8b2dfcc 100644 --- a/charts/prophetstor/federatorai/templates/alameda-notifier/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-notifier/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-notifier diff --git a/charts/prophetstor/federatorai/templates/alameda-rabbitmq/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/alameda-rabbitmq/clusterrolebindings.yaml deleted file mode 100644 index a94b94848..000000000 --- a/charts/prophetstor/federatorai/templates/alameda-rabbitmq/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-alameda-rabbitmq -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-alameda-rabbitmq -subjects: -- kind: ServiceAccount - name: alameda-rabbitmq - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/alameda-rabbitmq/clusterroles.yaml b/charts/prophetstor/federatorai/templates/alameda-rabbitmq/clusterroles.yaml deleted file mode 100644 index ea4e5a867..000000000 --- a/charts/prophetstor/federatorai/templates/alameda-rabbitmq/clusterroles.yaml +++ /dev/null @@ -1,28 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - component: alameda-rabbitmq - name: {{ .Release.Namespace }}-alameda-rabbitmq -rules: -- apiGroups: - - "" - resources: - - endpoints - verbs: - - get -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use diff --git a/charts/prophetstor/federatorai/templates/alameda-rabbitmq/configmaps.yaml b/charts/prophetstor/federatorai/templates/alameda-rabbitmq/configmaps.yaml index 348aedc84..96b3eb842 100644 --- a/charts/prophetstor/federatorai/templates/alameda-rabbitmq/configmaps.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-rabbitmq/configmaps.yaml @@ -1,3 +1,4 @@ +--- apiVersion: v1 data: definitions.json: | @@ -128,8 +129,14 @@ data: } kind: ConfigMap metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: rabbitmq-config diff --git a/charts/prophetstor/federatorai/templates/alameda-rabbitmq/deployments.yaml b/charts/prophetstor/federatorai/templates/alameda-rabbitmq/deployments.yaml index 593cab63f..63a6e6ee9 100644 --- a/charts/prophetstor/federatorai/templates/alameda-rabbitmq/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-rabbitmq/deployments.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-rabbitmq @@ -18,82 +25,104 @@ spec: type: Recreate template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-rabbitmq spec: - affinity: {{- include "render-value" ( dict "value" .Values.alamedaRabbitmq.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.alamedaRabbitmq.affinity }} +{{- include "render-value" ( dict "value" .Values.alamedaRabbitmq.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - env: - - name: NAMESPACE_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.name - - name: RABBITMQ_DEFAULT_USER - value: admin - - name: RABBITMQ_DEFAULT_PASS - value: adminpass - - name: TRACE_ENABLED - value: "false" - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/alameda-rabbitmq:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: - - sh - - -c - - /prob.sh liveness - failureThreshold: 3 - initialDelaySeconds: 60 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 15 - name: rabbitmq - ports: - - containerPort: 15672 - name: http - protocol: TCP - - containerPort: 5672 - name: amqp - protocol: TCP - readinessProbe: - exec: - command: - - sh - - -c - - /prob.sh readiness - failureThreshold: 3 - initialDelaySeconds: 20 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 30 - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.alamedaRabbitmq.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /definitions.json - name: rabbitmq-config - subPath: definitions.json - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - env: + - name: NAMESPACE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: RABBITMQ_DEFAULT_USER + value: admin + - name: RABBITMQ_DEFAULT_PASS + value: adminpass + - name: TRACE_ENABLED + value: "false" + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/alameda-rabbitmq:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - sh + - -c + - /prob.sh liveness + failureThreshold: 3 + initialDelaySeconds: 60 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 15 + name: rabbitmq + ports: + - containerPort: 15672 + name: http + protocol: TCP + - containerPort: 5672 + name: amqp + protocol: TCP + readinessProbe: + exec: + command: + - sh + - -c + - /prob.sh readiness + failureThreshold: 3 + initialDelaySeconds: 20 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 30 + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.alamedaRabbitmq.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.alamedaRabbitmq.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /definitions.json + name: rabbitmq-config + subPath: definitions.json + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.alamedaRabbitmq.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.alamedaRabbitmq.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.alamedaRabbitmq.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: alameda-rabbitmq serviceAccountName: alameda-rabbitmq - tolerations: {{- include "render-value" ( dict "value" .Values.alamedaRabbitmq.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.alamedaRabbitmq.tolerations }} +{{- include "render-value" ( dict "value" .Values.alamedaRabbitmq.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - configMap: - defaultMode: 420 + - configMap: + defaultMode: 420 + name: rabbitmq-config name: rabbitmq-config - name: rabbitmq-config diff --git a/charts/prophetstor/federatorai/templates/alameda-rabbitmq/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/alameda-rabbitmq/serviceaccounts.yaml index 4ecee0f14..53b6d18e0 100644 --- a/charts/prophetstor/federatorai/templates/alameda-rabbitmq/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-rabbitmq/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-rabbitmq diff --git a/charts/prophetstor/federatorai/templates/alameda-rabbitmq/services.yaml b/charts/prophetstor/federatorai/templates/alameda-rabbitmq/services.yaml index 9ea08269b..7546bc0b3 100644 --- a/charts/prophetstor/federatorai/templates/alameda-rabbitmq/services.yaml +++ b/charts/prophetstor/federatorai/templates/alameda-rabbitmq/services.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alameda-rabbitmq @@ -10,14 +17,14 @@ metadata: namespace: {{ .Release.Namespace }} spec: ports: - - name: amqp - port: 5672 - protocol: TCP - targetPort: amqp - - name: http - port: 15672 - protocol: TCP - targetPort: http + - name: amqp + port: 5672 + protocol: TCP + targetPort: amqp + - name: http + port: 15672 + protocol: TCP + targetPort: http selector: component: alameda-rabbitmq type: ClusterIP diff --git a/charts/prophetstor/federatorai/templates/fedemeter-api/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/fedemeter-api/clusterrolebindings.yaml deleted file mode 100644 index 29b41ffcc..000000000 --- a/charts/prophetstor/federatorai/templates/fedemeter-api/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-fedemeter-api -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-fedemeter-api -subjects: -- kind: ServiceAccount - name: fedemeter-api - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/fedemeter-api/clusterroles.yaml b/charts/prophetstor/federatorai/templates/fedemeter-api/clusterroles.yaml deleted file mode 100644 index 4de7f0bd4..000000000 --- a/charts/prophetstor/federatorai/templates/fedemeter-api/clusterroles.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-fedemeter-api -rules: -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use diff --git a/charts/prophetstor/federatorai/templates/fedemeter-api/configmaps.yaml b/charts/prophetstor/federatorai/templates/fedemeter-api/configmaps.yaml index ed793f920..13f86da52 100644 --- a/charts/prophetstor/federatorai/templates/fedemeter-api/configmaps.yaml +++ b/charts/prophetstor/federatorai/templates/fedemeter-api/configmaps.yaml @@ -1,3 +1,4 @@ +--- apiVersion: v1 data: DATAHUB_HOST: alameda-datahub.{{ .Release.Namespace }}.svc @@ -8,8 +9,14 @@ data: FEDEMETER_WORKER_NODE_LOWER_LIMIT: "1" kind: ConfigMap metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: fedemeter-config diff --git a/charts/prophetstor/federatorai/templates/fedemeter-api/deployments.yaml b/charts/prophetstor/federatorai/templates/fedemeter-api/deployments.yaml index 2a1c943e1..13aaabc18 100644 --- a/charts/prophetstor/federatorai/templates/fedemeter-api/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/fedemeter-api/deployments.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: fedemeter-api @@ -18,83 +25,105 @@ spec: type: Recreate template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: fedemeter-api spec: - affinity: {{- include "render-value" ( dict "value" .Values.fedemeterApi.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.fedemeterApi.affinity }} +{{- include "render-value" ( dict "value" .Values.fedemeterApi.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - env: - - name: NAMESPACE_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.name - - name: PRICE_BOOK_UPDATE_POLICY - value: auto - - name: PRICE_BOOK_REPOSITORY_URL - value: https://github.com/prophetstor-ai/public/raw/master/fedemeter-pricebook - - name: FEDEMETER_API_INFLUXDB_CACHE - value: "8192" - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - envFrom: - - configMapRef: - name: fedemeter-config - image: {{ .Values.global.imageRegistry }}/fedemeter-api-ubi:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: - - sh - - -c - - /run.sh liveness - failureThreshold: 30 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 5 - name: fedemeter-api - ports: - - containerPort: 8888 - name: gui-fedemeter - protocol: TCP - readinessProbe: - exec: - command: - - sh - - -c - - /run.sh readiness - failureThreshold: 10 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 5 - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.fedemeterApi.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/log/alameda/fedemeter - name: fedemeter-log-storage - subPath: alameda/fedemeter - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - env: + - name: NAMESPACE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: PRICE_BOOK_UPDATE_POLICY + value: auto + - name: PRICE_BOOK_REPOSITORY_URL + value: https://github.com/prophetstor-ai/public/raw/master/fedemeter-pricebook + - name: FEDEMETER_API_INFLUXDB_CACHE + value: "8192" + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + envFrom: + - configMapRef: + name: fedemeter-config + image: {{ .Values.global.imageRegistry }}/fedemeter-api-ubi:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - sh + - -c + - /run.sh liveness + failureThreshold: 30 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 5 + name: fedemeter-api + ports: + - containerPort: 8888 + name: gui-fedemeter + protocol: TCP + readinessProbe: + exec: + command: + - sh + - -c + - /run.sh readiness + failureThreshold: 10 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 5 + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.fedemeterApi.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.fedemeterApi.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /var/log/alameda/fedemeter + name: fedemeter-log-storage + subPath: alameda/fedemeter + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.fedemeterApi.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.fedemeterApi.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.fedemeterApi.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: fedemeter-api serviceAccountName: fedemeter-api - tolerations: {{- include "render-value" ( dict "value" .Values.fedemeterApi.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.fedemeterApi.tolerations }} +{{- include "render-value" ( dict "value" .Values.fedemeterApi.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - emptyDir: {} - name: fedemeter-data-storage - - name: fedemeter-log-storage - persistentVolumeClaim: - claimName: fedemeter-log.pvc + - emptyDir: {} + name: fedemeter-data-storage + - name: fedemeter-log-storage + persistentVolumeClaim: + claimName: fedemeter-log.pvc diff --git a/charts/prophetstor/federatorai/templates/fedemeter-api/pvc-log.yaml b/charts/prophetstor/federatorai/templates/fedemeter-api/pvc-log.yaml index 0bbec1b84..4edf7e3e3 100644 --- a/charts/prophetstor/federatorai/templates/fedemeter-api/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/fedemeter-api/pvc-log.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: fedemeter-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.fedemeterApi.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.fedemeterApi.persistence.accessModes }} +{{ .Values.fedemeterApi.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.fedemeterApi.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/fedemeter-api/serviceaccounts-api.yaml b/charts/prophetstor/federatorai/templates/fedemeter-api/serviceaccounts-api.yaml index b13e4f8bb..84e6296ff 100644 --- a/charts/prophetstor/federatorai/templates/fedemeter-api/serviceaccounts-api.yaml +++ b/charts/prophetstor/federatorai/templates/fedemeter-api/serviceaccounts-api.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: fedemeter-api diff --git a/charts/prophetstor/federatorai/templates/fedemeter-api/serviceaccounts-sa.yaml b/charts/prophetstor/federatorai/templates/fedemeter-api/serviceaccounts-sa.yaml index 1aaf6faa1..95c0253ff 100644 --- a/charts/prophetstor/federatorai/templates/fedemeter-api/serviceaccounts-sa.yaml +++ b/charts/prophetstor/federatorai/templates/fedemeter-api/serviceaccounts-sa.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: fedemeter-sa diff --git a/charts/prophetstor/federatorai/templates/fedemeter-api/services.yaml b/charts/prophetstor/federatorai/templates/fedemeter-api/services.yaml index 5d07675b2..65184ecd8 100644 --- a/charts/prophetstor/federatorai/templates/fedemeter-api/services.yaml +++ b/charts/prophetstor/federatorai/templates/fedemeter-api/services.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: fedemeter-api @@ -10,10 +17,10 @@ metadata: namespace: {{ .Release.Namespace }} spec: ports: - - name: fedemeter-api - port: 8888 - protocol: TCP - targetPort: 8888 + - name: fedemeter-api + port: 8888 + protocol: TCP + targetPort: 8888 selector: component: fedemeter-api type: ClusterIP diff --git a/charts/prophetstor/federatorai/templates/fedemeter-influxdb/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/fedemeter-influxdb/clusterrolebindings.yaml deleted file mode 100644 index 2e10de55c..000000000 --- a/charts/prophetstor/federatorai/templates/fedemeter-influxdb/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-fedemeter-influxdb -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-fedemeter-influxdb -subjects: -- kind: ServiceAccount - name: fedemeter-influxdb - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/fedemeter-influxdb/clusterroles.yaml b/charts/prophetstor/federatorai/templates/fedemeter-influxdb/clusterroles.yaml deleted file mode 100644 index 7e3161322..000000000 --- a/charts/prophetstor/federatorai/templates/fedemeter-influxdb/clusterroles.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-fedemeter-influxdb -rules: -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use diff --git a/charts/prophetstor/federatorai/templates/fedemeter-influxdb/pvc-data.yaml b/charts/prophetstor/federatorai/templates/fedemeter-influxdb/pvc-data.yaml index bf3d26a9b..b9dc81543 100644 --- a/charts/prophetstor/federatorai/templates/fedemeter-influxdb/pvc-data.yaml +++ b/charts/prophetstor/federatorai/templates/fedemeter-influxdb/pvc-data.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: fedemeter.influxdb-data.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.fedemeterInfluxdb.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.fedemeterInfluxdb.persistence.accessModes }} +{{ .Values.fedemeterInfluxdb.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.fedemeterInfluxdb.persistence.dataStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/fedemeter-influxdb/pvc-log.yaml b/charts/prophetstor/federatorai/templates/fedemeter-influxdb/pvc-log.yaml index ee586254c..b39823e5f 100644 --- a/charts/prophetstor/federatorai/templates/fedemeter-influxdb/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/fedemeter-influxdb/pvc-log.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: fedemeter.influxdb-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.fedemeterInfluxdb.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.fedemeterInfluxdb.persistence.accessModes }} +{{ .Values.fedemeterInfluxdb.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.fedemeterInfluxdb.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/fedemeter-influxdb/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/fedemeter-influxdb/serviceaccounts.yaml index 70901c09c..32ea81e40 100644 --- a/charts/prophetstor/federatorai/templates/fedemeter-influxdb/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/fedemeter-influxdb/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: fedemeter-influxdb diff --git a/charts/prophetstor/federatorai/templates/fedemeter-influxdb/services.yaml b/charts/prophetstor/federatorai/templates/fedemeter-influxdb/services.yaml index 725e56854..228dceb63 100644 --- a/charts/prophetstor/federatorai/templates/fedemeter-influxdb/services.yaml +++ b/charts/prophetstor/federatorai/templates/fedemeter-influxdb/services.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: fedemeter-influxdb @@ -10,14 +17,14 @@ metadata: namespace: {{ .Release.Namespace }} spec: ports: - - name: http-fedemeter-influxdb - port: 8086 - protocol: TCP - targetPort: 8086 - - name: tcp-fedemeter-influxdb - port: 8088 - protocol: TCP - targetPort: 8088 + - name: http-fedemeter-influxdb + port: 8086 + protocol: TCP + targetPort: 8086 + - name: tcp-fedemeter-influxdb + port: 8088 + protocol: TCP + targetPort: 8088 selector: component: fedemeter-influxdb type: ClusterIP diff --git a/charts/prophetstor/federatorai/templates/fedemeter-influxdb/statefulsets.yaml b/charts/prophetstor/federatorai/templates/fedemeter-influxdb/statefulsets.yaml index e208c1871..2397ec981 100644 --- a/charts/prophetstor/federatorai/templates/fedemeter-influxdb/statefulsets.yaml +++ b/charts/prophetstor/federatorai/templates/fedemeter-influxdb/statefulsets.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: StatefulSet metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: fedemeter-influxdb @@ -17,60 +24,82 @@ spec: serviceName: fedemeter-influxdb template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: fedemeter-influxdb spec: - affinity: {{- include "render-value" ( dict "value" .Values.fedemeterInfluxdb.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.fedemeterInfluxdb.affinity }} +{{- include "render-value" ( dict "value" .Values.fedemeterInfluxdb.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - env: - - name: INFLUXDB_LOGGING_LEVEL - value: warn - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/fedemeter-influxdb:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: - - /bin/bash - - -c - - /run.sh liveness - failureThreshold: 3 - initialDelaySeconds: 300 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 300 - name: fedemeter-influxdb - ports: - - containerPort: 8086 - protocol: TCP - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.fedemeterInfluxdb.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/log/influxdb - name: fedemeter-influxdb-log-storage - subPath: influxdb - - mountPath: /influxdb - name: fedemeter-influxdb-data-storage - subPath: influxdb - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - env: + - name: INFLUXDB_LOGGING_LEVEL + value: warn + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/fedemeter-influxdb:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - /bin/bash + - -c + - /run.sh liveness + failureThreshold: 3 + initialDelaySeconds: 300 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 300 + name: fedemeter-influxdb + ports: + - containerPort: 8086 + protocol: TCP + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.fedemeterInfluxdb.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.fedemeterInfluxdb.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /var/log/influxdb + name: fedemeter-influxdb-log-storage + subPath: influxdb + - mountPath: /influxdb + name: fedemeter-influxdb-data-storage + subPath: influxdb + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.fedemeterInfluxdb.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.fedemeterInfluxdb.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.fedemeterInfluxdb.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: fedemeter-influxdb serviceAccountName: fedemeter-influxdb - tolerations: {{- include "render-value" ( dict "value" .Values.fedemeterInfluxdb.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.fedemeterInfluxdb.tolerations }} +{{- include "render-value" ( dict "value" .Values.fedemeterInfluxdb.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - name: fedemeter-influxdb-data-storage - persistentVolumeClaim: - claimName: fedemeter.influxdb-data.pvc - - name: fedemeter-influxdb-log-storage - persistentVolumeClaim: - claimName: fedemeter.influxdb-log.pvc + - name: fedemeter-influxdb-data-storage + persistentVolumeClaim: + claimName: fedemeter.influxdb-data.pvc + - name: fedemeter-influxdb-log-storage + persistentVolumeClaim: + claimName: fedemeter.influxdb-log.pvc updateStrategy: type: RollingUpdate diff --git a/charts/prophetstor/federatorai/templates/federatorai-agent-preloader/configmaps.yaml b/charts/prophetstor/federatorai/templates/federatorai-agent-preloader/configmaps.yaml new file mode 100644 index 000000000..494223ead --- /dev/null +++ b/charts/prophetstor/federatorai/templates/federatorai-agent-preloader/configmaps.yaml @@ -0,0 +1,60 @@ +--- +{{- if .Values.federatoraiAgentPreloader.enabled }} +apiVersion: v1 +data: + transmitter.toml: |- + [log] + set-logcallers = false + output-level = "info" # debug, info, warn, error, fatal, none + + [input_jobs] + [input_jobs.preloader] + name = "alameda_preloader" + lib-path = "/lib/inputlib/alamedapreloader.so" + lib-configuration = "/etc/alameda/federatorai-agent/input/alameda_preloader.toml" + + alameda_preloader.toml: | + [global] + enable = false + target_database = "" + target_address = "alameda-datahub:50050" + target_user = "" + target_password = "" + + [source] + address = "alameda-datahub:50050" + user = "" + password = "" + + [preloader] + cpu_metrics_file = "/etc/alameda/federatorai-agent/csv/container_cpu.csv" + cpu_metrics_file_granularity = 60 + mem_metrics_file = "/etc/alameda/federatorai-agent/csv/container_memory.csv" + mem_metrics_file_granularity = 60 + node_cpu_metrics_file = "/etc/alameda/federatorai-agent/csv/node_metric_cpu.csv" + node_cpu_metrics_file_granularity = 60 + node_mem_metrics_file = "/etc/alameda/federatorai-agent/csv/node_metric_memory.csv" + node_mem_metrics_file_granularity = 60 + granularity = 60 + preload_count = 4 + preload_unit = "month" + max_write_data_length = 1000 + disable_load_current_metrics = false + disable_load_history_metrics = false + disable_load_all_node_metrics = false + +kind: ConfigMap +metadata: + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} + app.kubernetes.io/part-of: federatorai + app: alameda + name: federatorai-agent-preloader-config + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-agent-preloader/deployments.yaml b/charts/prophetstor/federatorai/templates/federatorai-agent-preloader/deployments.yaml new file mode 100644 index 000000000..3d6282670 --- /dev/null +++ b/charts/prophetstor/federatorai/templates/federatorai-agent-preloader/deployments.yaml @@ -0,0 +1,100 @@ +--- +{{- if .Values.federatoraiAgentPreloader.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} + app.kubernetes.io/part-of: federatorai + app: alameda + component: federatorai-agent-preloader + name: federatorai-agent-preloader + namespace: {{ .Release.Namespace }} +spec: + replicas: 1 + selector: + matchLabels: + app: alameda + component: federatorai-agent-preloader + strategy: + type: Recreate + template: + metadata: + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} + app.kubernetes.io/part-of: federatorai + app: alameda + component: federatorai-agent-preloader + spec: + affinity: +{{- if .Values.federatoraiAgentPreloader.affinity }} +{{- include "render-value" ( dict "value" .Values.federatoraiAgentPreloader.affinity "context" .) | nindent 8 }} +{{- end }} + containers: + - env: + - name: NAMESPACE_NAME + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + name: federatorai-agent-preloader + image: {{ .Values.global.imageRegistry }}/federatorai-agent-preloader:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.federatoraiAgentPreloader.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.federatoraiAgentPreloader.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /var/log/alameda + name: federatorai-agent-preloader-log-storage + - mountPath: /etc/alameda/federatorai-agent/transmitter.toml + name: federatorai-agent-preloader-config + subPath: transmitter.toml + - mountPath: /etc/alameda/federatorai-agent/input/alameda_preloader.toml + name: federatorai-agent-preloader-config + subPath: alameda_preloader.toml + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} + securityContext: + fsGroup: 1001 +{{- if .Values.federatoraiAgentPreloader.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.federatoraiAgentPreloader.podSecurityContext "context" .) | nindent 8 }} +{{- end }} + serviceAccount: federatorai-agent-preloader + serviceAccountName: federatorai-agent-preloader + tolerations: +{{- if .Values.federatoraiAgentPreloader.tolerations }} +{{- include "render-value" ( dict "value" .Values.federatoraiAgentPreloader.tolerations "context" .) | nindent 6 }} +{{- end }} + volumes: + - emptyDir: {} + name: federatorai-agent-preloader-data-storage + - emptyDir: {} + name: federatorai-agent-preloader-log-storage + - configMap: + defaultMode: 420 + name: federatorai-agent-preloader-config + name: federatorai-agent-preloader-config +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-agent-preloader/pvc-log.yaml b/charts/prophetstor/federatorai/templates/federatorai-agent-preloader/pvc-log.yaml new file mode 100644 index 000000000..55bda745c --- /dev/null +++ b/charts/prophetstor/federatorai/templates/federatorai-agent-preloader/pvc-log.yaml @@ -0,0 +1,29 @@ +--- +{{- if .Values.federatoraiAgentPreloader.enabled }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} + app.kubernetes.io/part-of: federatorai + app: alameda + name: federatorai-agent-preloader-log.pvc + namespace: {{ .Release.Namespace }} +spec: + accessModes: +{{- if .Values.federatoraiAgentPreloader.persistence.accessModes }} +{{ .Values.federatoraiAgentPreloader.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} + resources: + requests: + storage: {{ .Values.federatoraiAgentPreloader.persistence.logStorageSize }} +{{- if .Values.global.storageClassName }} + storageClassName: {{ .Values.global.storageClassName }} +{{- end }} +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-agent-preloader/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/federatorai-agent-preloader/serviceaccounts.yaml new file mode 100644 index 000000000..afeba9184 --- /dev/null +++ b/charts/prophetstor/federatorai/templates/federatorai-agent-preloader/serviceaccounts.yaml @@ -0,0 +1,18 @@ +--- +{{- if .Values.federatoraiAgentPreloader.enabled }} +apiVersion: v1 +kind: ServiceAccount +metadata: + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} + app.kubernetes.io/part-of: federatorai + app: alameda + name: federatorai-agent-preloader + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-agent/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/federatorai-agent/clusterrolebindings.yaml deleted file mode 100644 index b36be0222..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-agent/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-federatorai-agent -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-federatorai-agent -subjects: -- kind: ServiceAccount - name: federatorai-agent - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-agent/clusterroles.yaml b/charts/prophetstor/federatorai/templates/federatorai-agent/clusterroles.yaml deleted file mode 100644 index 1e5cb7b37..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-agent/clusterroles.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-federatorai-agent -rules: -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use diff --git a/charts/prophetstor/federatorai/templates/federatorai-agent/configmaps.yaml b/charts/prophetstor/federatorai/templates/federatorai-agent/configmaps.yaml index 19c4821a3..0a644c2c0 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-agent/configmaps.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-agent/configmaps.yaml @@ -1,144 +1,6 @@ +--- apiVersion: v1 data: - cost_analysis_high_recommendation.toml: | - enable_multiple_worker = true - [datahub] - address = "alameda-datahub:50050" - - [datahub."retry-interval"] - default = 3 # second - - [fedemeter] - url = "http://fedemeter-api:8888/fedemeter-api/v1" - username = "" - password = "" - task = "recommendation" - timeout = 300 # seconds - - [cost_analysis] - calculate_current = false - calculate_current_unit = "month" - - [recommendation] - ri = true - granularity = "3600,21600,86400,604800" # daily: 3600, weekly: 21600, monthly: 86400, yearly: 604800 - - cost_analysis_normal_cluster_daily.toml: | - enable_multiple_worker = true - [datahub] - address = "alameda-datahub:50050" - - [datahub."retry-interval"] - default = 3 # second - - [fedemeter] - url = "http://fedemeter-api:8888/fedemeter-api/v1" - username = "" - password = "" - task = "calculate_instance,recommendation_cost_node,recommendation_cost_cluster,cost_node_analysis,cost_cluster_analysis,cost_allocations_node,cost_allocations_cluster,recommendations_scaling" - timeout = 300 # seconds - - [cost_analysis] - calculate_current = true - calculate_current_unit = "month" - - [recommendation] - ri = true - granularity = "3600" # daily: 3600, weekly: 21600, monthly: 86400 - fill_days = "1" # daily: 1, weekly: 7, monthly: 31 - - cost_analysis_normal_daily.toml: | - enable_multiple_worker = true - [datahub] - address = "alameda-datahub:50050" - - [datahub."retry-interval"] - default = 3 # second - - [fedemeter] - url = "http://fedemeter-api:8888/fedemeter-api/v1" - username = "" - password = "" - task = "calculate_instance,recommendation_cost_app,recommendation_cost_namespace,recommendation_cost_node,recommendation_cost_cluster,cost_namespace_analysis,cost_node_analysis,cost_cluster_analysis,cost_allocations_application,cost_allocations_namespace,cost_allocations_node,cost_allocations_cluster,recommendations_scaling" - timeout = 300 # seconds - - [cost_analysis] - calculate_current = true - calculate_current_unit = "month" - - [recommendation] - ri = true - granularity = "3600" # daily: 3600, weekly: 21600, monthly: 86400 - fill_days = "1" # daily: 1, weekly: 7, monthly: 31 - cost_analysis_normal_monthly.toml: | - enable_multiple_worker = true - [datahub] - address = "alameda-datahub:50050" - - [datahub."retry-interval"] - default = 3 # second - - [fedemeter] - url = "http://fedemeter-api:8888/fedemeter-api/v1" - username = "" - password = "" - task = "calculate_instance,recommendation_cost_app,recommendation_cost_namespace,recommendation_cost_node,recommendation_cost_cluster,cost_namespace_analysis,cost_node_analysis,cost_cluster_analysis,cost_allocations_application,cost_allocations_namespace,cost_allocations_node,cost_allocations_cluster,recommendations_scaling" - timeout = 300 # seconds - - [cost_analysis] - calculate_current = false - calculate_current_unit = "month" - - [recommendation] - ri = true - granularity = "86400" # daily: 3600, weekly: 21600, monthly: 86400 - fill_days = "31" # daily: 1, weekly: 7, monthly: 31 - cost_analysis_normal_weekly.toml: | - enable_multiple_worker = true - [datahub] - address = "alameda-datahub:50050" - - [datahub."retry-interval"] - default = 3 # second - - [fedemeter] - url = "http://fedemeter-api:8888/fedemeter-api/v1" - username = "" - password = "" - task = "calculate_instance,recommendation_cost_app,recommendation_cost_namespace,recommendation_cost_node,recommendation_cost_cluster,cost_namespace_analysis,cost_node_analysis,cost_cluster_analysis,cost_allocations_application,cost_allocations_namespace,cost_allocations_node,cost_allocations_cluster,recommendations_scaling" - timeout = 300 # seconds - - [cost_analysis] - calculate_current = false - calculate_current_unit = "month" - - [recommendation] - ri = true - granularity = "21600" # daily: 3600, weekly: 21600, monthly: 86400 - fill_days = "7" # daily: 1, weekly: 7, monthly: 31 - cost_analysis_normal_yearly.toml: | - enable_multiple_worker = true - [datahub] - address = "alameda-datahub:50050" - - [datahub."retry-interval"] - default = 3 # second - - [fedemeter] - url = "http://fedemeter-api:8888/fedemeter-api/v1" - username = "" - password = "" - task = "calculate_instance,recommendation_cost_app,recommendation_cost_namespace,recommendation_cost_node,recommendation_cost_cluster,cost_namespace_analysis,cost_node_analysis,cost_cluster_analysis,cost_allocations_application,cost_allocations_namespace,cost_allocations_node,cost_allocations_cluster,recommendations_scaling" - timeout = 300 # seconds - - [cost_analysis] - calculate_current = false - calculate_current_unit = "month" - - [recommendation] - ri = true - granularity = "604800" # daily: 3600, weekly: 21600, monthly: 86400, yearly: 604800 - fill_days = "52" # daily: 1, weekly: 7, monthly: 31, yearly: 52 transmitter.toml: |- [log] set-logcallers = false @@ -192,10 +54,158 @@ data: lib-configuration = "/etc/alameda/federatorai-agent/input/cost_analysis_normal_yearly.toml" health-check-retry = -1 + cost_analysis_normal_daily.toml: | + enable_multiple_worker = true + [datahub] + address = "alameda-datahub:50050" + + [datahub."retry-interval"] + default = 3 # second + + [fedemeter] + url = "http://fedemeter-api:8888/fedemeter-api/v1" + username = "" + password = "" + task = "recommendation_cost_app,recommendation_cost_namespace,cost_namespace_analysis,cost_allocations_application,cost_allocations_namespace" + timeout = 300 # seconds + + [cost_analysis] + calculate_current = true + calculate_current_unit = "month" + + [recommendation] + ri = true + granularity = "3600" # daily: 3600, weekly: 21600, monthly: 86400 + fill_days = "1" # daily: 1, weekly: 7, monthly: 31 + + cost_analysis_normal_cluster_daily.toml: | + enable_multiple_worker = true + [datahub] + address = "alameda-datahub:50050" + + [datahub."retry-interval"] + default = 3 # second + + [fedemeter] + url = "http://fedemeter-api:8888/fedemeter-api/v1" + username = "" + password = "" + task = "calculate_instance,recommendation_cost_node,recommendation_cost_cluster,cost_node_analysis,cost_cluster_analysis,cost_allocations_node,cost_allocations_cluster,recommendations_scaling" + timeout = 300 # seconds + + [cost_analysis] + calculate_current = true + calculate_current_unit = "month" + + [recommendation] + ri = true + granularity = "3600" # daily: 3600, weekly: 21600, monthly: 86400 + fill_days = "1" # daily: 1, weekly: 7, monthly: 31 + + cost_analysis_high_recommendation.toml: | + enable_multiple_worker = true + [datahub] + address = "alameda-datahub:50050" + + [datahub."retry-interval"] + default = 3 # second + + [fedemeter] + url = "http://fedemeter-api:8888/fedemeter-api/v1" + username = "" + password = "" + task = "recommendation" + timeout = 300 # seconds + + [cost_analysis] + calculate_current = false + calculate_current_unit = "month" + + [recommendation] + ri = true + granularity = "3600,21600,86400,604800" # daily: 3600, weekly: 21600, monthly: 86400, yearly: 604800 + + cost_analysis_normal_weekly.toml: | + enable_multiple_worker = true + [datahub] + address = "alameda-datahub:50050" + + [datahub."retry-interval"] + default = 3 # second + + [fedemeter] + url = "http://fedemeter-api:8888/fedemeter-api/v1" + username = "" + password = "" + task = "calculate_instance,recommendation_cost_app,recommendation_cost_namespace,recommendation_cost_node,recommendation_cost_cluster,cost_namespace_analysis,cost_node_analysis,cost_cluster_analysis,cost_allocations_application,cost_allocations_namespace,cost_allocations_node,cost_allocations_cluster,recommendations_scaling" + timeout = 300 # seconds + + [cost_analysis] + calculate_current = false + calculate_current_unit = "month" + + [recommendation] + ri = true + granularity = "21600" # daily: 3600, weekly: 21600, monthly: 86400 + fill_days = "7" # daily: 1, weekly: 7, monthly: 31 + + cost_analysis_normal_monthly.toml: | + enable_multiple_worker = true + [datahub] + address = "alameda-datahub:50050" + + [datahub."retry-interval"] + default = 3 # second + + [fedemeter] + url = "http://fedemeter-api:8888/fedemeter-api/v1" + username = "" + password = "" + task = "calculate_instance,recommendation_cost_app,recommendation_cost_namespace,recommendation_cost_node,recommendation_cost_cluster,cost_namespace_analysis,cost_node_analysis,cost_cluster_analysis,cost_allocations_application,cost_allocations_namespace,cost_allocations_node,cost_allocations_cluster,recommendations_scaling" + timeout = 300 # seconds + + [cost_analysis] + calculate_current = false + calculate_current_unit = "month" + + [recommendation] + ri = true + granularity = "86400" # daily: 3600, weekly: 21600, monthly: 86400 + fill_days = "31" # daily: 1, weekly: 7, monthly: 31 + cost_analysis_normal_yearly.toml: | + enable_multiple_worker = true + [datahub] + address = "alameda-datahub:50050" + + [datahub."retry-interval"] + default = 3 # second + + [fedemeter] + url = "http://fedemeter-api:8888/fedemeter-api/v1" + username = "" + password = "" + task = "calculate_instance,recommendation_cost_app,recommendation_cost_namespace,recommendation_cost_node,recommendation_cost_cluster,cost_namespace_analysis,cost_node_analysis,cost_cluster_analysis,cost_allocations_application,cost_allocations_namespace,cost_allocations_node,cost_allocations_cluster,recommendations_scaling" + timeout = 300 # seconds + + [cost_analysis] + calculate_current = false + calculate_current_unit = "month" + + [recommendation] + ri = true + granularity = "604800" # daily: 3600, weekly: 21600, monthly: 86400, yearly: 604800 + fill_days = "52" # daily: 1, weekly: 7, monthly: 31, yearly: 52 + kind: ConfigMap metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-agent-config diff --git a/charts/prophetstor/federatorai/templates/federatorai-agent/deployments.yaml b/charts/prophetstor/federatorai/templates/federatorai-agent/deployments.yaml index a2261e93b..bb872fd3e 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-agent/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-agent/deployments.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-agent @@ -18,94 +25,114 @@ spec: type: Recreate template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-agent spec: - affinity: {{- include "render-value" ( dict "value" .Values.federatoraiAgent.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.federatoraiAgent.affinity }} +{{- include "render-value" ( dict "value" .Values.federatoraiAgent.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - env: - - name: NAMESPACE_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.name - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/federatorai-agent-ubi:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: - - /opt/alameda/federatorai-agent/bin/transmitter - - probe - - --type=liveness - failureThreshold: 20 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 5 - name: federatorai-agent - readinessProbe: - exec: - command: - - /opt/alameda/federatorai-agent/bin/transmitter - - probe - - --type=readiness - failureThreshold: 20 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 5 - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.federatoraiAgent.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/log/alameda - name: federatorai-agent-log-storage - - mountPath: /etc/alameda/federatorai-agent/transmitter.toml - name: federatorai-agent-config - subPath: transmitter.toml - - mountPath: /etc/alameda/federatorai-agent/input/cost_analysis_normal_cluster_daily.toml - name: federatorai-agent-config - subPath: cost_analysis_normal_cluster_daily.toml - - mountPath: /etc/alameda/federatorai-agent/input/cost_analysis_normal_daily.toml - name: federatorai-agent-config - subPath: cost_analysis_normal_daily.toml - - mountPath: /etc/alameda/federatorai-agent/input/cost_analysis_high_recommendation.toml - name: federatorai-agent-config - subPath: cost_analysis_high_recommendation.toml - - mountPath: /etc/alameda/federatorai-agent/input/cost_analysis_normal_weekly.toml - name: federatorai-agent-config - subPath: cost_analysis_normal_weekly.toml - - mountPath: /etc/alameda/federatorai-agent/input/cost_analysis_normal_monthly.toml - name: federatorai-agent-config - subPath: cost_analysis_normal_monthly.toml - - mountPath: /etc/alameda/federatorai-agent/input/cost_analysis_normal_yearly.toml - name: federatorai-agent-config - subPath: cost_analysis_normal_yearly.toml - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - env: + - name: NAMESPACE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/federatorai-agent-ubi:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - /opt/alameda/federatorai-agent/bin/transmitter + - probe + - --type=liveness + failureThreshold: 20 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 5 + name: federatorai-agent + readinessProbe: + exec: + command: + - /opt/alameda/federatorai-agent/bin/transmitter + - probe + - --type=readiness + failureThreshold: 20 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 5 + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.federatoraiAgent.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.federatoraiAgent.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - name: federatorai-agent-config + mountPath: /etc/alameda/federatorai-agent/transmitter.toml + subPath: transmitter.toml + - name: federatorai-agent-config + mountPath: /etc/alameda/federatorai-agent/input/cost_analysis_normal_daily.toml + subPath: cost_analysis_normal_daily.toml + - name: federatorai-agent-config + mountPath: /etc/alameda/federatorai-agent/input/cost_analysis_normal_cluster_daily.toml + subPath: cost_analysis_normal_cluster_daily.toml + - name: federatorai-agent-config + mountPath: /etc/alameda/federatorai-agent/input/cost_analysis_high_recommendation.toml + subPath: cost_analysis_high_recommendation.toml + - name: federatorai-agent-config + mountPath: /etc/alameda/federatorai-agent/input/cost_analysis_normal_weekly.toml + subPath: cost_analysis_normal_weekly.toml + - name: federatorai-agent-config + mountPath: /etc/alameda/federatorai-agent/input/cost_analysis_normal_yearly.toml + subPath: cost_analysis_normal_yearly.toml + - name: federatorai-agent-config + mountPath: /etc/alameda/federatorai-agent/input/cost_analysis_normal_monthly.toml + subPath: cost_analysis_normal_monthly.toml + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.federatoraiAgent.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.federatoraiAgent.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.federatoraiAgent.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: federatorai-agent serviceAccountName: federatorai-agent - tolerations: {{- include "render-value" ( dict "value" .Values.federatoraiAgent.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.federatoraiAgent.tolerations }} +{{- include "render-value" ( dict "value" .Values.federatoraiAgent.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - configMap: - defaultMode: 420 + - configMap: + defaultMode: 420 + name: federatorai-agent-config name: federatorai-agent-config - name: federatorai-agent-config - - emptyDir: {} - name: federatorai-agent-data-storage - - name: federatorai-agent-log-storage - persistentVolumeClaim: - claimName: federatorai-agent-log.pvc + - emptyDir: {} + name: federatorai-agent-data-storage + - name: federatorai-agent-log-storage + persistentVolumeClaim: + claimName: federatorai-agent-log.pvc diff --git a/charts/prophetstor/federatorai/templates/federatorai-agent/pvc-log.yaml b/charts/prophetstor/federatorai/templates/federatorai-agent/pvc-log.yaml index 5e7a5e411..b3491ca46 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-agent/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-agent/pvc-log.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-agent-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.federatoraiAgent.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.federatoraiAgent.persistence.accessModes }} +{{ .Values.federatoraiAgent.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.federatoraiAgent.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-agent/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/federatorai-agent/serviceaccounts.yaml index cc921d5fa..9ba16dea2 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-agent/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-agent/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-agent diff --git a/charts/prophetstor/federatorai/templates/federatorai-alert-detector/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/federatorai-alert-detector/clusterrolebindings.yaml deleted file mode 100644 index faa076d42..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-alert-detector/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: federatorai-federatorai-alert-detector -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: federatorai-federatorai-alert-detector -subjects: -- kind: ServiceAccount - name: federatorai-alert-detector - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-alert-detector/clusterroles.yaml b/charts/prophetstor/federatorai/templates/federatorai-alert-detector/clusterroles.yaml deleted file mode 100644 index aa61c53fb..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-alert-detector/clusterroles.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: federatorai-federatorai-alert-detector -rules: -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use diff --git a/charts/prophetstor/federatorai/templates/federatorai-alert-detector/deployments.yaml b/charts/prophetstor/federatorai/templates/federatorai-alert-detector/deployments.yaml index e54bded56..8f158163e 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-alert-detector/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-alert-detector/deployments.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alert-detector @@ -18,47 +25,69 @@ spec: type: Recreate template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alert-detector spec: - affinity: {{- include "render-value" ( dict "value" .Values.federatoraiAlertDetector.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.federatoraiAlertDetector.affinity }} +{{- include "render-value" ( dict "value" .Values.federatoraiAlertDetector.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - command: - - /opt/federatorai/alert-manager/bin/detector - env: - - name: DETECT_DATAHUB_HOST - value: alameda-datahub.federatorai.svc - - name: DETECT_DATAHUB_PORT - value: "50050" - - name: DETECT_RABBITMQ_HOST - value: alameda-rabbitmq.federatorai.svc - - name: DETECT_RABBITMQ_PORT - value: "5672" - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/federatorai-alert-manager:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - name: alert-detector - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.federatoraiAlertDetector.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/log/alameda - name: federatorai-alert-detector-log-storage - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - command: + - /opt/federatorai/alert-manager/bin/detector + env: + - name: DETECT_DATAHUB_HOST + value: alameda-datahub.federatorai.svc + - name: DETECT_DATAHUB_PORT + value: "50050" + - name: DETECT_RABBITMQ_HOST + value: alameda-rabbitmq.federatorai.svc + - name: DETECT_RABBITMQ_PORT + value: "5672" + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/federatorai-alert-manager:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + name: alert-detector + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.federatoraiAlertDetector.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.federatoraiAlertDetector.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /var/log/alameda + name: federatorai-alert-detector-log-storage + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.federatoraiAlertDetector.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.federatoraiAlertDetector.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.federatoraiAlertDetector.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: federatorai-alert-detector serviceAccountName: federatorai-alert-detector - tolerations: {{- include "render-value" ( dict "value" .Values.federatoraiAlertDetector.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.federatoraiAlertDetector.tolerations }} +{{- include "render-value" ( dict "value" .Values.federatoraiAlertDetector.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - emptyDir: {} - name: federatorai-alert-detector-data-storage - - name: federatorai-alert-detector-log-storage - persistentVolumeClaim: - claimName: federatorai-alert-detector-log.pvc + - emptyDir: {} + name: federatorai-alert-detector-data-storage + - name: federatorai-alert-detector-log-storage + persistentVolumeClaim: + claimName: federatorai-alert-detector-log.pvc diff --git a/charts/prophetstor/federatorai/templates/federatorai-alert-detector/pvc-log.yaml b/charts/prophetstor/federatorai/templates/federatorai-alert-detector/pvc-log.yaml index 756cd4101..fbff67fad 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-alert-detector/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-alert-detector/pvc-log.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-alert-detector-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.federatoraiAlertDetector.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.federatoraiAlertDetector.persistence.accessModes }} +{{ .Values.federatoraiAlertDetector.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.federatoraiAlertDetector.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-alert-detector/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/federatorai-alert-detector/serviceaccounts.yaml index 252a1ff5e..8306eb87b 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-alert-detector/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-alert-detector/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-alert-detector diff --git a/charts/prophetstor/federatorai/templates/federatorai-alert-manager/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/federatorai-alert-manager/clusterrolebindings.yaml deleted file mode 100644 index e33164e07..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-alert-manager/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: federatorai-federatorai-alert-manager -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: federatorai-federatorai-alert-manager -subjects: -- kind: ServiceAccount - name: federatorai-alert-manager - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-alert-manager/clusterroles.yaml b/charts/prophetstor/federatorai/templates/federatorai-alert-manager/clusterroles.yaml deleted file mode 100644 index 1b6fde435..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-alert-manager/clusterroles.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: federatorai-federatorai-alert-manager -rules: -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use diff --git a/charts/prophetstor/federatorai/templates/federatorai-alert-manager/deployments.yaml b/charts/prophetstor/federatorai/templates/federatorai-alert-manager/deployments.yaml index e9bbc6815..e7d725de7 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-alert-manager/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-alert-manager/deployments.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alert-manager @@ -18,71 +25,93 @@ spec: type: Recreate template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: alert-manager spec: - affinity: {{- include "render-value" ( dict "value" .Values.federatoraiAlertManager.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.federatoraiAlertManager.affinity }} +{{- include "render-value" ( dict "value" .Values.federatoraiAlertManager.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - command: - - /opt/federatorai/alert-manager/bin/alertmgr - env: - - name: ALERT_DATAHUB_HOST - value: alameda-datahub.federatorai.svc - - name: ALERT_DATAHUB_PORT - value: "50050" - - name: ALERT_RABBITMQ_HOST - value: alameda-rabbitmq.federatorai.svc - - name: ALERT_RABBITMQ_PORT - value: "5672" - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/federatorai-alert-manager:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: - - /opt/federatorai/alert-manager/bin/mgrctl - - probe - - --type - - liveness - failureThreshold: 3 - initialDelaySeconds: 10 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 30 - name: alert-manager - readinessProbe: - exec: - command: - - /opt/federatorai/alert-manager/bin/mgrctl - - probe - - --type - - readiness - failureThreshold: 3 - initialDelaySeconds: 10 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 30 - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.federatoraiAlertManager.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/log/alameda - name: federatorai-alert-manager-log-storage - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - command: + - /opt/federatorai/alert-manager/bin/alertmgr + env: + - name: ALERT_DATAHUB_HOST + value: alameda-datahub.federatorai.svc + - name: ALERT_DATAHUB_PORT + value: "50050" + - name: ALERT_RABBITMQ_HOST + value: alameda-rabbitmq.federatorai.svc + - name: ALERT_RABBITMQ_PORT + value: "5672" + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/federatorai-alert-manager:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - /opt/federatorai/alert-manager/bin/mgrctl + - probe + - --type + - liveness + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 30 + name: alert-manager + readinessProbe: + exec: + command: + - /opt/federatorai/alert-manager/bin/mgrctl + - probe + - --type + - readiness + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 30 + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.federatoraiAlertManager.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.federatoraiAlertManager.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /var/log/alameda + name: federatorai-alert-manager-log-storage + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.federatoraiAlertManager.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.federatoraiAlertManager.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.federatoraiAlertManager.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: federatorai-alert-manager serviceAccountName: federatorai-alert-manager - tolerations: {{- include "render-value" ( dict "value" .Values.federatoraiAlertManager.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.federatoraiAlertManager.tolerations }} +{{- include "render-value" ( dict "value" .Values.federatoraiAlertManager.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - emptyDir: {} - name: federatorai-alert-manager-data-storage - - name: federatorai-alert-manager-log-storage - persistentVolumeClaim: - claimName: federatorai-alert-manager-log.pvc + - emptyDir: {} + name: federatorai-alert-manager-data-storage + - name: federatorai-alert-manager-log-storage + persistentVolumeClaim: + claimName: federatorai-alert-manager-log.pvc diff --git a/charts/prophetstor/federatorai/templates/federatorai-alert-manager/pvc-log.yaml b/charts/prophetstor/federatorai/templates/federatorai-alert-manager/pvc-log.yaml index 8c6255783..a00c8ef39 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-alert-manager/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-alert-manager/pvc-log.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-alert-manager-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.federatoraiAlertManager.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.federatoraiAlertManager.persistence.accessModes }} +{{ .Values.federatoraiAlertManager.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.federatoraiAlertManager.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-alert-manager/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/federatorai-alert-manager/serviceaccounts.yaml index b26e86676..1287c6693 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-alert-manager/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-alert-manager/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-alert-manager diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/clusterrolebindings.yaml deleted file mode 100644 index 64b0a88c1..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-federatorai-dashboard-backend -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-federatorai-dashboard-backend -subjects: -- kind: ServiceAccount - name: federatorai-dashboard-backend - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/clusterroles.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/clusterroles.yaml deleted file mode 100644 index b1f2c93c6..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/clusterroles.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-federatorai-dashboard-backend -rules: -- apiGroups: - - "" - resources: - - namespaces - verbs: - - get -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/configmaps.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/configmaps.yaml index d9ad91c11..9ee472c42 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/configmaps.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/configmaps.yaml @@ -1,3 +1,4 @@ +--- apiVersion: v1 data: config.json: |- @@ -44,8 +45,14 @@ data: } kind: ConfigMap metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-dashboard-backend-config diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/deployments.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/deployments.yaml index 184d4b4e5..385e1db71 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/deployments.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-dashboard-backend @@ -21,82 +28,104 @@ spec: type: RollingUpdate template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-dashboard-backend spec: - affinity: {{- include "render-value" ( dict "value" .Values.federatoraiDashboardBackend.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.federatoraiDashboardBackend.affinity }} +{{- include "render-value" ( dict "value" .Values.federatoraiDashboardBackend.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - env: - - name: NAMESPACE_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.name - - name: FEDERATORAI_DASHBOARD_BACKEND_SERVICE_NAME - value: federatorai-dashboard-backend - - name: FEDERATORAI_DASHBOARD_BACKEND_PORT - value: "8081" - - name: FEDERATORAI_DASHBOARD_ENABLE_PLANNING_REC - value: "false" - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/federatorai-dashboard-backend:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: - - /probe.sh - - --type=liveness - failureThreshold: 3 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 5 - name: federatorai-dashboard-backend - ports: - - containerPort: 8081 - protocol: TCP - readinessProbe: - exec: - command: - - /probe.sh - - --type=readiness - failureThreshold: 3 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 5 - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.federatoraiDashboardBackend.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/log/alameda - name: federatorai-backend-log-storage - - mountPath: /federatorai-portal/server/config - name: federatorai-dashboard-backend-config - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - env: + - name: NAMESPACE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: FEDERATORAI_DASHBOARD_BACKEND_SERVICE_NAME + value: federatorai-dashboard-backend + - name: FEDERATORAI_DASHBOARD_BACKEND_PORT + value: "8081" + - name: FEDERATORAI_DASHBOARD_ENABLE_PLANNING_REC + value: "false" + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/federatorai-dashboard-backend:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - /probe.sh + - --type=liveness + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 5 + name: federatorai-dashboard-backend + ports: + - containerPort: 8081 + protocol: TCP + readinessProbe: + exec: + command: + - /probe.sh + - --type=readiness + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 5 + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.federatoraiDashboardBackend.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.federatoraiDashboardBackend.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /var/log/alameda + name: federatorai-backend-log-storage + - mountPath: /federatorai-portal/server/config + name: federatorai-dashboard-backend-config + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.federatoraiDashboardBackend.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.federatoraiDashboardBackend.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.federatoraiDashboardBackend.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: federatorai-dashboard-backend serviceAccountName: federatorai-dashboard-backend - tolerations: {{- include "render-value" ( dict "value" .Values.federatoraiDashboardBackend.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.federatoraiDashboardBackend.tolerations }} +{{- include "render-value" ( dict "value" .Values.federatoraiDashboardBackend.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - configMap: - defaultMode: 420 + - configMap: + defaultMode: 420 + name: federatorai-dashboard-backend-config name: federatorai-dashboard-backend-config - name: federatorai-dashboard-backend-config - - emptyDir: {} - name: federatorai-backend-data-storage - - name: federatorai-backend-log-storage - persistentVolumeClaim: - claimName: federatorai-backend-log.pvc + - emptyDir: {} + name: federatorai-backend-data-storage + - name: federatorai-backend-log-storage + persistentVolumeClaim: + claimName: federatorai-backend-log.pvc diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/pvc-log.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/pvc-log.yaml index 07c2e4a2c..88baeec2f 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/pvc-log.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-backend-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.federatoraiDashboardBackend.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.federatoraiDashboardBackend.persistence.accessModes }} +{{ .Values.federatoraiDashboardBackend.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.federatoraiDashboardBackend.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/serviceaccounts.yaml index 424dd3d1d..1dc06d58c 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-dashboard-backend diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/services.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/services.yaml index c53adc204..2a969ea8c 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/services.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-dashboard-backend/services.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-dashboard-backend @@ -10,9 +17,9 @@ metadata: namespace: {{ .Release.Namespace }} spec: ports: - - port: 8081 - protocol: TCP - targetPort: 8081 + - port: 8081 + protocol: TCP + targetPort: 8081 selector: component: federatorai-dashboard-backend type: ClusterIP diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/clusterrolebindings.yaml deleted file mode 100644 index 728ca2006..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-federatorai-dashboard-frontend -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-federatorai-dashboard-frontend -subjects: -- kind: ServiceAccount - name: federatorai-dashboard-frontend - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/clusterroles.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/clusterroles.yaml deleted file mode 100644 index 32336a0c7..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/clusterroles.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-federatorai-dashboard-frontend -rules: -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/deployments.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/deployments.yaml index adeb23f78..f072ad8c0 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/deployments.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-dashboard-frontend @@ -21,74 +28,96 @@ spec: type: RollingUpdate template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-dashboard-frontend spec: - affinity: {{- include "render-value" ( dict "value" .Values.federatoraiDashboardFrontend.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.federatoraiDashboardFrontend.affinity }} +{{- include "render-value" ( dict "value" .Values.federatoraiDashboardFrontend.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - env: - - name: NAMESPACE_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.name - - name: FEDERATORAI_DASHBOARD_FRONTEND_PORT - value: "9000" - - name: FEDERATORAI_DASHBOARD_BACKEND_URL - value: http://federatorai-dashboard-backend.{{ .Release.Namespace }}.svc:8081 - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/federatorai-dashboard-frontend:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: - - /probe.sh - - --type=liveness - failureThreshold: 3 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 5 - name: federatorai-dashboard-frontend - ports: - - containerPort: 9000 - protocol: TCP - readinessProbe: - exec: - command: - - /probe.sh - - --type=readiness - failureThreshold: 3 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 5 - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.federatoraiDashboardFrontend.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/log/alameda - name: federatorai-frontend-log-storage - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - env: + - name: NAMESPACE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: FEDERATORAI_DASHBOARD_FRONTEND_PORT + value: "9000" + - name: FEDERATORAI_DASHBOARD_BACKEND_URL + value: http://federatorai-dashboard-backend.{{ .Release.Namespace }}.svc:8081 + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/federatorai-dashboard-frontend:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - /probe.sh + - --type=liveness + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 5 + name: federatorai-dashboard-frontend + ports: + - containerPort: 9000 + protocol: TCP + readinessProbe: + exec: + command: + - /probe.sh + - --type=readiness + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 5 + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.federatoraiDashboardFrontend.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.federatoraiDashboardFrontend.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /var/log/alameda + name: federatorai-frontend-log-storage + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.federatoraiDashboardFrontend.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.federatoraiDashboardFrontend.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.federatoraiDashboardFrontend.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: federatorai-dashboard-frontend serviceAccountName: federatorai-dashboard-frontend - tolerations: {{- include "render-value" ( dict "value" .Values.federatoraiDashboardFrontend.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.federatoraiDashboardFrontend.tolerations }} +{{- include "render-value" ( dict "value" .Values.federatoraiDashboardFrontend.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - emptyDir: {} - name: federatorai-frontend-data-storage - - name: federatorai-frontend-log-storage - persistentVolumeClaim: - claimName: federatorai-frontend-log.pvc + - emptyDir: {} + name: federatorai-frontend-data-storage + - name: federatorai-frontend-log-storage + persistentVolumeClaim: + claimName: federatorai-frontend-log.pvc diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/ingress.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/ingress.yaml index f520e6f3b..0ac7de27e 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/ingress.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/ingress.yaml @@ -1,12 +1,19 @@ +--- {{- if .Values.federatoraiDashboardFrontend.ingress.enabled }} apiVersion: {{ template "ingress.apiVersion" . }} kind: Ingress metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} {{- with .Values.federatoraiDashboardFrontend.ingress.annotations }} {{- toYaml . | nindent 4 }} {{- end }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-dashboard-frontend diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/pvc-log.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/pvc-log.yaml index 87f02f131..4e8d90ec5 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/pvc-log.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-frontend-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.federatoraiDashboardFrontend.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.federatoraiDashboardFrontend.persistence.accessModes }} +{{ .Values.federatoraiDashboardFrontend.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.federatoraiDashboardFrontend.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/serviceaccounts.yaml index bd215807a..64ad15195 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-dashboard-frontend diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/services-loadbalancer.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/services-loadbalancer.yaml index 6771b1536..31758a220 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/services-loadbalancer.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/services-loadbalancer.yaml @@ -1,12 +1,19 @@ +--- {{- if eq .Values.federatoraiDashboardFrontend.service.type "LoadBalancer" }} apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} {{- with .Values.federatoraiDashboardFrontend.service.annotations }} {{- toYaml . | nindent 4 }} {{- end }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-dashboard-frontend diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/services-nodeport.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/services-nodeport.yaml index 487fb26a5..831f0eaff 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/services-nodeport.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/services-nodeport.yaml @@ -1,12 +1,19 @@ +--- {{- if eq .Values.federatoraiDashboardFrontend.service.type "NodePort" }} apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} {{- with .Values.federatoraiDashboardFrontend.service.annotations }} {{- toYaml . | nindent 4 }} {{- end }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-dashboard-frontend @@ -14,13 +21,13 @@ metadata: namespace: {{ .Release.Namespace }} spec: ports: - - name: frontend-node-port - {{- if and .Values.federatoraiDashboardFrontend.service.nodePort }} - nodePort: {{ .Values.federatoraiDashboardFrontend.service.nodePort }} - {{- end }} - port: 9001 - protocol: TCP - targetPort: {{ .Values.federatoraiDashboardFrontend.service.targetPort }} + - name: frontend-node-port + {{- if and .Values.federatoraiDashboardFrontend.service.nodePort }} + nodePort: {{ .Values.federatoraiDashboardFrontend.service.nodePort }} + {{- end }} + port: 9001 + protocol: TCP + targetPort: {{ .Values.federatoraiDashboardFrontend.service.targetPort }} selector: component: federatorai-dashboard-frontend type: NodePort diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/services.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/services.yaml index 83119ef53..ee0a285f7 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/services.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/services.yaml @@ -1,11 +1,18 @@ +--- apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} {{- with .Values.federatoraiDashboardFrontend.service.annotations }} {{- toYaml . | nindent 4 }} {{- end }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-dashboard-frontend @@ -16,14 +23,14 @@ spec: clusterIP: {{ .Values.federatoraiDashboardFrontend.service.clusterIP }} {{- end }} ports: - - name: frontend-http - port: 9000 - protocol: TCP - targetPort: 9000 - - name: frontend-https - port: 9001 - protocol: TCP - targetPort: 9001 + - name: frontend-http + port: 9000 + protocol: TCP + targetPort: 9000 + - name: frontend-https + port: 9001 + protocol: TCP + targetPort: 9001 selector: component: federatorai-dashboard-frontend type: ClusterIP diff --git a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/tls-secrets.yaml b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/tls-secrets.yaml index 99aa7c261..782e73acf 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/tls-secrets.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-dashboard-frontend/tls-secrets.yaml @@ -1,11 +1,18 @@ +--- {{- if .Values.federatoraiDashboardFrontend.ingress.enabled }} {{- if .Values.federatoraiDashboardFrontend.ingress.secrets }} {{- range .Values.federatoraiDashboardFrontend.ingress.secrets }} apiVersion: v1 kind: Secret metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-dashboard-frontend @@ -24,8 +31,14 @@ data: apiVersion: v1 kind: Secret metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-dashboard-frontend diff --git a/charts/prophetstor/federatorai/templates/federatorai-data-adapter/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/federatorai-data-adapter/clusterrolebindings.yaml deleted file mode 100644 index 962a8cd35..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-data-adapter/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-federatorai-data-adapter -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-federatorai-data-adapter -subjects: -- kind: ServiceAccount - name: federatorai-data-adapter - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-data-adapter/clusterroles.yaml b/charts/prophetstor/federatorai/templates/federatorai-data-adapter/clusterroles.yaml deleted file mode 100644 index 60c723bcd..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-data-adapter/clusterroles.yaml +++ /dev/null @@ -1,28 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-federatorai-data-adapter -rules: -- apiGroups: - - "" - resources: - - namespaces - - configmaps - verbs: - - get -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use diff --git a/charts/prophetstor/federatorai/templates/federatorai-data-adapter/configmaps-historical.yaml b/charts/prophetstor/federatorai/templates/federatorai-data-adapter/configmaps-historical.yaml index 4c9242cd3..7067929ab 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-data-adapter/configmaps-historical.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-data-adapter/configmaps-historical.yaml @@ -1,865 +1,876 @@ +--- apiVersion: v1 kind: ConfigMap metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-data-adapter-historical-config namespace: {{ .Release.Namespace }} data: - telegraf_historical.conf: |+ - [global_tags] - - [agent] - interval = "1m" - delay_query_interval = "$DELAY_QUERY_INTERVAL" - delay_historical_query = "$DELAY_HISTORICAL_QUERY" - round_interval = true - metric_batch_size = 10000 - metric_buffer_limit = 100000 - collection_jitter = "5s" - flush_interval = "20s" - flush_jitter = "0s" - precision = "1us" - debug = $DEBUG - aggregator_queue = 200000 - max_rpc_receive_size = $MAX_RPC_RECEIVE_SIZE - logfile = "/var/log/telegraf_historical.log" - logfile_rotation_interval = "1d" - logfile_rotation_max_archives = 10 - logfile_rotation_max_size = "200MB" - logfile_compress_archives = true - logfile_total_max_size = "$FEDERATORAI_MAXIMUM_LOG_SIZE" - logfile_queue_size = $MAX_LOG_QUEUE_SIZE - logfile_queue_trace_interval = "$LOG_QUEUE_TRACE_INTERVAL" - logfile_enabled_async_logger = $ENABLED_ASYNC_LOGGER - ## Data adapter will flush log queue to console if queue is full - enable_logfile_flush_to_console = $ENABLE_FLUSH_LOG_TO_CONSOLE - logfile_flush_to_console_level = "$LOG_FLUSH_TO_CONSOLE_LEVEL" - ## Query will retry if some metrics hasn't returned yet. - max_retry = 1 - retry_interval = "10s" - max_request_line = $MAX_REQUEST_LINE - sysdig_max_char_per_chunk = $SYSDIG_MAX_CHAR_PER_CHUNK - # sysdig_max_query_per_chunk accepted value [1-20], default value is 10 if not setted - sysdig_max_query_per_chunk = $SYSDIG_MAX_QUERY_PER_CHUNK - quiet = false - hostname = "" - omit_hostname = false - alamedascaler_enable = true - enable_historical_data_collection = true - force_reload_configuration = false - fed_rest_url = "$FED_REST_URL" - fed_rest_port = "$FED_REST_PORT" - datahub_url = "$DATAHUB_URL" - datahub_port = "$DATAHUB_PORT" - rabbitmq_url = "$RABBITMQ_URL" - rabbitmq_port = "$RABBITMQ_PORT" - rabbitmq_subscriber = "historical_data_adapter" - expired_time = "8760h" - event_cache_expired_time = "$POST_EVENT_INTERVAL" - - ## set collect_metadata_only=false to collect resource metadata and metrics - ## set collect_metadata_only=true to only collect resource metadata - collect_metadata_only = false - - # Default disable integration metrics setting - # Cost Analysis related metrics - cost_analysis_metrics = ["federatorai.cost_analysis.instance.cost","federatorai.cost_analysis.namespace.cost","federatorai.prediction.namespace.cost","federatorai.recommendation.instance","federatorai.cost_analysis.resource_alloc_cost.cluster","federatorai.cost_analysis.resource_alloc_cost.node","federatorai.cost_analysis.resource_alloc_cost.namespace","federatorai.cost_analysis.resource_usage_cost.cluster","federatorai.cost_analysis.resource_usage_cost.node","federatorai.cost_analysis.resource_usage_cost.namespace","federatorai.cost_analysis.cost_per_day.cluster","federatorai.cost_analysis.cost_per_day.node","federatorai.cost_analysis.cost_per_day.namespace","federatorai.cost_analysis.cost_per_week.cluster","federatorai.cost_analysis.cost_per_week.node","federatorai.cost_analysis.cost_per_week.namespace","federatorai.cost_analysis.cost_per_month.cluster","federatorai.cost_analysis.cost_per_month.node","federatorai.cost_analysis.cost_per_month.namespace","federatorai.recommendation.cost_analysis.cost_per_day.cluster","federatorai.recommendation.cost_analysis.cost_per_day.node","federatorai.recommendation.cost_analysis.cost_per_day.namespace","federatorai.recommendation.cost_analysis.cost_per_week.cluster","federatorai.recommendation.cost_analysis.cost_per_week.node","federatorai.recommendation.cost_analysis.cost_per_week.namespace","federatorai.recommendation.cost_analysis.cost_per_month.cluster","federatorai.recommendation.cost_analysis.cost_per_month.node","federatorai.recommendation.cost_analysis.cost_per_month.namespace","federatorai.prediction.cost_analysis.cost_per_day.cluster","federatorai.prediction.cost_analysis.cost_per_day.node","federatorai.prediction.cost_analysis.cost_per_day.namespace","federatorai.prediction.cost_analysis.cost_per_week.cluster","federatorai.prediction.cost_analysis.cost_per_week.node","federatorai.prediction.cost_analysis.cost_per_week.namespace","federatorai.prediction.cost_analysis.cost_per_month.cluster","federatorai.prediction.cost_analysis.cost_per_month.node","federatorai.prediction.cost_analysis.cost_per_month.namespace"] - - ## Automation - enable_dump_mock_data = false - testing_mode = false - configuration_mock_data_path = "/var/log/mock_server/mock_data/configuration" - datadog_mock_data_path = "/var/log/mock_server/mock_data/datadog" - sysdig_mock_data_path = "/var/log/mock_server/mock_data/sysdig" - prometheus_mock_data_path = "/var/log/mock_server/mock_data/prometheus" - expected_result_path = "/var/log/mock_server/mock_data/expected_result" - test_mode_result_path = "mock_server/mock_data/test_mode_result" - - ## Dashboard - check_sysdig_dashboard_interval = "$CHECK_SYSDIG_DASHBOARD_INTERVAL" - enable_sysdig_dashboard = $ENABLE_SYSDIG_DASHBOARD - sysdig_dashboards = ["/etc/telegraf/dashboards/sysdig/kafka-overview.json", "/etc/telegraf/dashboards/sysdig/application-overview.json", "/etc/telegraf/dashboards/sysdig/cluster-overview.json"] - - ## Datadog tag mapping table - # if enable_autodiscover_datadog_cluster_name_tag_key=true, agent uses datadog_default_cluster_tag_key to autodiscover cluster name tag key - # if enable_autodiscover_datadog_cluster_name_tag_key=false, agent uses the cluster name tag key defined in agent.datadog_cluster_tag_mapping. - enable_autodiscover_datadog_cluster_name_tag_key = true - #DD_CLUSTER_NAME_TAG_KEYS is "cluster_name,kube_cluster_name,kube_cluster" by default. - datadog_default_cluster_tag_keys = "$DD_CLUSTER_NAME_TAG_KEYS" - [agent.datadog_cluster_tag_mapping] - # Datadog cluster name tag = [""] - kube_cluster = [] - cluster_name = [] - kube_cluster_name = [] - - ############################# - ### Aggregator Basicstats ### - ############################# - - # Datadog metrics - [[aggregators.basicstats]] - grace = "2m" - period = "1m" - drop_original = true - # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule - traverse_all_rules = false - # By default, data adapter send all the metrics through basicstats - namepass = ["datadog_cluster_collection_done"] - # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator - namedrop = [] - [[aggregators.basicstats.metric]] - groups = ["*"] - measurement_name = "datadog_cluster_collection_done" - aggregation_method = "" - fields = [""] - - ## Openshift Prometheus integration: aggregator ## - [[aggregators.basicstats]] - grace = "2m" - period = "1m" - drop_original = true - # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule - traverse_all_rules = false - # By default, data adapter send all the metrics through basicstats - namepass = ["openshift_prometheus_cluster_collection_done"] - # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator - namedrop = [] - [[aggregators.basicstats.metric]] - groups = ["*"] - measurement_name = "openshift_prometheus_cluster_collection_done" - aggregation_method = "" - fields = [""] - - ## Federation Prometheus/Prometheus integration: aggregator ## - [[aggregators.basicstats]] - grace = "2m" - period = "1m" - drop_original = true - # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule - traverse_all_rules = false - # By default, data adapter send all the metrics through basicstats - namepass = ["prometheus_cluster_collection_done"] - # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator - namedrop = [] - [[aggregators.basicstats.metric]] - groups = ["*"] - measurement_name = "prometheus_cluster_collection_done" - aggregation_method = "" - fields = [""] - - ## Sysdig integration: aggregator ## - [[aggregators.basicstats]] - grace = "2m" - period = "1m" - drop_original = true - # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule - traverse_all_rules = false - # By default, data adapter send all the metrics through basicstats - namepass = ["sysdig_cluster_collection_done"] - # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator - namedrop = [] - [[aggregators.basicstats.metric]] - groups = ["*"] - measurement_name = "sysdig_cluster_collection_done" - aggregation_method = "" - fields = [""] - - ### VMware integration: aggregator ## - #[[aggregators.basicstats]] - # grace = "5m" - # period = "1m" - # drop_original = true - # # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule - # traverse_all_rules = false - # # By default, data adapter send all the metrics through basicstats - # namepass = ["vmware_cluster_collection_done"] - # # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator - # namedrop = [] - - # [[aggregators.basicstats.metric]] - # groups = ["*"] - # measurement_name = "vmware_cluster_collection_done" - # aggregation_method = "" - # fields = [""] - - # AWS Cloudwatch metrics - [[aggregators.basicstats]] - period = "1m" - drop_original = true - # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule - traverse_all_rules = false - # By default, data adapter send all the metrics through basicstats - namepass = ["aws_cloudwatch_cluster_collection_done"] - # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator - namedrop = [] - - [[aggregators.basicstats.metric]] - groups = ["*"] - measurement_name = "aws_cloudwatch_cluster_collection_done" - aggregation_method = "" - fields = [""] - - ################## - ### Processors ### - ################## - - [[processors.filter_out]] - order = 1 - namepass = ["kafka_topic_partition_current_offset", "kafka_consumer_group_current_offset", "node_disk_io_util", "sysdig_kafka_topic_partition_current_offset", "sysdig_kafka_consumergroup_current_offset", "openshift_prometheus_kube_pod_owner", "prometheus_kube_pod_owner", "openshift_prometheus_kube_replicationcontroller_spec_replicas", "openshift_prometheus_kube_replicationcontroller_status_available_replicas", "datadog_node_pod_phase"] - [[processors.filter_out.metric]] - measurement_name = "sysdig_kafka_topic_partition_current_offset" - fields = ["kafka_topic_partition_current_offset"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "sysdig_kafka_consumergroup_current_offset" - fields = ["kafka_consumergroup_current_offset"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "kafka_topic_partition_current_offset" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "kafka_consumer_group_current_offset" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "node_disk_io_util" - fields = ["value"] - aggregation_method = "set_max_value" - max_value = 100.0 - [[processors.filter_out.metric]] - measurement_name = "prometheus_kube_pod_owner" - fields = ["owner_name"] - aggregation_method = "trim_last_index" - match_string = "-" - [processors.filter_out.metric.condition] - owner_kind = "ReplicaSet" - [[processors.filter_out.metric]] - measurement_name = "prometheus_kube_pod_owner" - fields = ["owner_name"] - aggregation_method = "trim_last_index" - match_string = "-" - [processors.filter_out.metric.condition] - owner_kind = "ReplicationController" - [[processors.filter_out.metric]] - measurement_name = "openshift_prometheus_kube_pod_owner" - fields = ["owner_name"] - aggregation_method = "trim_last_index" - match_string = "-" - [processors.filter_out.metric.condition] - owner_kind = "ReplicaSet" - [[processors.filter_out.metric]] - measurement_name = "openshift_prometheus_kube_pod_owner" - fields = ["owner_name"] - aggregation_method = "trim_last_index" - match_string = "-" - [processors.filter_out.metric.condition] - owner_kind = "ReplicationController" - [[processors.filter_out.metric]] - measurement_name = "openshift_prometheus_kube_replicationcontroller_spec_replicas" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "openshift_prometheus_kube_replicationcontroller_status_available_replicas" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "openshift_prometheus_kube_replicationcontroller_spec_replicas" - fields = ["replicationcontroller"] - aggregation_method = "trim_last_index" - match_string = "-" - [[processors.filter_out.metric]] - measurement_name = "openshift_prometheus_kube_replicationcontroller_status_available_replicas" - fields = ["replicationcontroller"] - aggregation_method = "trim_last_index" - match_string = "-" - - ## Datadog integration: processors - [[processors.metrics_decorator]] - order = 2 - namepass = ["datadog_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/datadog_pre_metric_decorator.json" - - [[processors.metrics_grouping]] - order = 3 - namepass = ["datadog_*", "alameda_*"] - namedrop = ["datadog_historical_collection_done"] - schema_file = "/etc/telegraf/schema/datadog_grouping_rules.json" - - [[processors.metrics_decorator]] - order = 4 - namepass = ["datadog_namespace_*"] - schema_file = "/etc/telegraf/schema/datadog_post_metric_decorator.json" - - [[processors.schema_mapping]] - order = 5 - datasource = "datadog" - aggregator_processor = true - namepass = ["datadog_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/datadog_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - ## Set default cloud information ifneeded - enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY - default_provider = "$DEFAULT_PROVIDER" - default_region = "$DEFAULT_REGION" - default_instance_type = "$DEFAULT_INSTANCE_TYPE" - default_instance_id = "$DEFAULT_INSTANCE_ID" - default_zone = "$DEFAULT_ZONE" - - ## Openshift Prometheus integration: processors ## - [[processors.metrics_decorator]] - order = 2 - namepass = ["openshift_prometheus_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/openshift_prometheus_pre_metric_decorator.json" - - [[processors.metrics_grouping]] - order = 3 - namepass = ["openshift_prometheus_*", "alameda_*"] - namedrop = ["openshift_prometheus_historical_collection_done"] - schema_file = "/etc/telegraf/schema/openshift_prometheus_grouping_rules.json" - - [[processors.metrics_decorator]] - order = 4 - namepass = ["openshift_prometheus_alameda_config_cluster_namespace", "openshift_prometheus_node_cpu_usage_seconds_total", "openshift_prometheus_node_memory_usage_bytes", "openshift_prometheus_kube_node_status_capacity_cpu_cores", "openshift_prometheus_namespace_*"] - schema_file = "/etc/telegraf/schema/openshift_prometheus_post_metric_decorator.json" - - [[processors.schema_mapping]] - order = 5 - datasource = "prometheus" - aggregator_processor = true - namepass = ["openshift_prometheus_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/openshift_prometheus_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - ## Set default cloud information ifneeded - enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY - default_provider = "$DEFAULT_PROVIDER" - default_region = "$DEFAULT_REGION" - default_instance_type = "$DEFAULT_INSTANCE_TYPE" - default_instance_id = "$DEFAULT_INSTANCE_ID" - default_zone = "$DEFAULT_ZONE" - - ## Federation Prometheus/Prometheus integration: processors ## - [[processors.metrics_decorator]] - order = 2 - namepass = ["prometheus_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/prometheus_pre_metric_decorator.json" - - [[processors.metrics_grouping]] - order = 3 - namepass = ["prometheus_*", "alameda_*"] - namedrop = ["prometheus_historical_collection_done"] - schema_file = "/etc/telegraf/schema/prometheus_grouping_rules.json" - - [[processors.metrics_decorator]] - order = 4 - namepass = ["prometheus_alameda_config_cluster_namespace", "prometheus_node_cpu_usage_seconds_total", "prometheus_node_memory_usage_bytes", "prometheus_kube_node_status_capacity_cpu_cores", "prometheus_namespace_*"] - schema_file = "/etc/telegraf/schema/prometheus_post_metric_decorator.json" - - [[processors.schema_mapping]] - order = 5 - datasource = "prometheus" - aggregator_processor = true - namepass = ["prometheus_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/prometheus_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - ## Set default cloud information ifneeded - enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY - default_provider = "$DEFAULT_PROVIDER" - default_region = "$DEFAULT_REGION" - default_instance_type = "$DEFAULT_INSTANCE_TYPE" - default_instance_id = "$DEFAULT_INSTANCE_ID" - default_zone = "$DEFAULT_ZONE" - - ## Sysdig integration: processors ## - [[processors.metrics_decorator]] - order = 2 - namepass = ["sysdig_*", "alameda_*", "federatorai.kafka.consumer_lag", "federatorai.kafka.consumer_offset_rate", "federatorai.kafka.broker_offset_rate", "federatorai.prediction.kafka", "federatorai.recommendation", "federatorai.prediction.controller", "federatorai.prediction.controller.max", "federatorai.prediction.controller.min", "federatorai.prediction.controller.avg", "federatorai.prediction.node", "federatorai.prediction.node.max", "federatorai.prediction.node.min", "federatorai.prediction.node.avg", "federatorai.resource_planning.node", "federatorai.resource_planning.controller", "federatorai.kubernetes.cpu.usage.total.node", "federatorai.kubernetes.cpu.usage.total.controller", "federatorai.kubernetes.memory.usage.node", "federatorai.kubernetes.memory.usage.controller", "federatorai.kubernetes.cpu.usage.total.node_rollup_3600sec", "federatorai.kubernetes.cpu.usage.total.controller_rollup_3600sec", "federatorai.kubernetes.memory.usage.node_rollup_3600sec", "federatorai.kubernetes.memory.usage.controller_rollup_3600sec", "federatorai.kubernetes.cpu.usage.total.node_rollup_21600sec", "federatorai.kubernetes.cpu.usage.total.controller_rollup_21600sec", "federatorai.kubernetes.memory.usage.node_rollup_21600sec", "federatorai.kubernetes.memory.usage.controller_rollup_21600sec", "federatorai.kubernetes.cpu.usage.total.node_rollup_86400sec", "federatorai.kubernetes.cpu.usage.total.controller_rollup_86400sec", "federatorai.kubernetes.memory.usage.node_rollup_86400sec", "federatorai.kubernetes.memory.usage.controller_rollup_86400sec"] - schema_file = "/etc/telegraf/schema/sysdig_pre_metric_decorator.json" - - [[processors.metrics_grouping]] - order = 3 - namepass = ["sysdig_*", "alameda_*"] - namedrop = ["sysdig_historical_collection_done"] - schema_file = "/etc/telegraf/schema/sysdig_grouping_rules.json" - - [[processors.metrics_decorator]] - order = 4 - namepass = ["sysdig_alameda_config_cluster_namespace", "sysdig_namespace_*", "sysdig_kube_container_resource_limits_cpu_cores", "sysdig_kube_container_resource_requests_cpu_cores", "sysdig_alameda_config_namespace_metric_instance_config_info"] - schema_file = "/etc/telegraf/schema/sysdig_post_metric_decorator.json" - - [[processors.schema_mapping]] - order = 5 - datasource = "sysdig" - aggregator_processor = true - namepass = ["sysdig_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/sysdig_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - ## Set default cloud information ifneeded - enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY - default_provider = "$DEFAULT_PROVIDER" - default_region = "$DEFAULT_REGION" - default_instance_type = "$DEFAULT_INSTANCE_TYPE" - default_instance_id = "$DEFAULT_INSTANCE_ID" - default_zone = "$DEFAULT_ZONE" - - ### VMware integration: processors - #[[processors.metrics_decorator]] - # order = 2 - # namepass = ["vmware_*", "alameda_*"] - # schema_file = "/etc/telegraf/schema/vmware_pre_metric_decorator.json" - - #[[processors.metrics_grouping]] - # order = 3 - # namepass = ["vmware_*", "alameda_*"] - # namedrop = ["vmware_historical_collection_done"] - # schema_file = "/etc/telegraf/schema/vmware_grouping_rules.json" - - #[[processors.metrics_decorator]] - # order = 4 - # namepass = [""] - # schema_file = "/etc/telegraf/schema/vmware_post_metric_decorator.json" - - #[[processors.schema_mapping]] - # order = 5 - # datasource = "vmware" - # aggregator_processor = true - # namepass = ["vmware_*", "alameda_*"] - # schema_file = "/etc/telegraf/schema/vmware_schema.json" - # cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - # ## Set default cloud information ifneeded - # enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY - # default_provider = "$DEFAULT_PROVIDER" - # default_region = "$DEFAULT_REGION" - # default_instance_type = "$DEFAULT_INSTANCE_TYPE" - # default_instance_id = "$DEFAULT_INSTANCE_ID" - # default_zone = "$DEFAULT_ZONE" - - ## AWS Cloudwatch integration: processors - [[processors.metrics_decorator]] - order = 2 - namepass = ["aws_cloudwatch_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/aws_pre_metric_decorator.json" - - [[processors.metrics_grouping]] - order = 3 - namepass = ["aws_cloudwatch_*", "alameda_*"] - namedrop = ["aws_cloudwatch_historical_collection_done"] - schema_file = "/etc/telegraf/schema/aws_grouping_rules.json" - - [[processors.metrics_decorator]] - order = 4 - namepass = ["aws_cloudwatch_alameda_config_cluster_vm", "aws_cloudwatch_node_group_*"] - schema_file = "/etc/telegraf/schema/aws_post_metric_decorator.json" - - [[processors.schema_mapping]] - order = 5 - datasource = "aws" - aggregator_processor = true - namepass = ["aws_cloudwatch_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/aws_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - ## Set default cloud information ifneeded - enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY - default_provider = "$DEFAULT_PROVIDER" - default_region = "$DEFAULT_REGION" - default_instance_type = "$DEFAULT_INSTANCE_TYPE" - default_instance_id = "$DEFAULT_INSTANCE_ID" - default_zone = "$DEFAULT_ZONE" - - ############################## - ### Aggregator Federatorai ### - ############################## - - [[aggregators.federatorai]] - period = "1m" - drop_original = true - concurrent_job = 3 - schema_file = "/etc/telegraf/schema/basic_aggregator_schema.json" - namepass = [""] - - ## Datadog metrics ## - [[aggregators.federatorai]] - grace = "3m" - period = "1m" - drop_original = true - concurrent_job = 3 - schema_file = "/etc/telegraf/schema/datadog_aggregator_schema.json" - config_file = "/etc/telegraf/schema/aggregator_config.json" - namepass = ["datadog_*"] - - ## Openshift Prometheus integration: aggregator ## - [[aggregators.federatorai]] - grace = "3m" - period = "1m" - drop_original = true - concurrent_job = 3 - schema_file = "/etc/telegraf/schema/openshift_prometheus_aggregator_schema.json" - config_file = "/etc/telegraf/schema/aggregator_config.json" - namepass = ["openshift_prometheus_*"] - - ## Federation Prometheus/Prometheus integration: aggregator ## - [[aggregators.federatorai]] - grace = "3m" - period = "1m" - drop_original = true - concurrent_job = 3 - schema_file = "/etc/telegraf/schema/prometheus_aggregator_schema.json" - config_file = "/etc/telegraf/schema/aggregator_config.json" - namepass = ["prometheus_*"] - - ## Sysdig integration: aggregator ## - [[aggregators.federatorai]] - grace = "3m" - period = "1m" - drop_original = true - concurrent_job = 3 - schema_file = "/etc/telegraf/schema/sysdig_aggregator_schema.json" - config_file = "/etc/telegraf/schema/aggregator_config.json" - namepass = ["sysdig_*"] - - ### VMware integration: aggregator ## - #[[aggregators.federatorai]] - # grace = "5m" - # period = "1m" - # drop_original = true - # concurrent_job = 3 - # schema_file = "/etc/telegraf/schema/vmware_aggregator_schema.json" - # config_file = "/etc/telegraf/schema/aggregator_config.json" - # namepass = ["vmware_*"] - - ## AWS Cloudwatch metrics ## - [[aggregators.federatorai]] - grace = "2m" - period = "1m" - drop_original = true - concurrent_job = 3 - schema_file = "/etc/telegraf/schema/aws_aggregator_schema.json" - config_file = "/etc/telegraf/schema/aggregator_config.json" - namepass = ["aws_cloudwatch_*"] - - ############################ - ### Input/Output Plugins ### - ############################ - - ## Alameda Configuration: inputs.data_collector ## - [[inputs.data_collector]] - query_start_time_offset = "-1m" - query_end_time_offset = "0h" #Support s(second),m(minute),h(hour) - collection_jitter = "0s" - ## data source type from which to query data - ## accept values: alameda_datahub - source = "alameda_datahub" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = true - overwrite_query_delay_interval = true - delay_query_interval = "0s" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/alameda_config_historical_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Openshift Prometheus integration: inputs.data_collector ## - [[inputs.data_collector]] - query_start_time_offset = "-1m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: prometheus - source = "prometheus" - ## which collector to handle the data collection - collector = "prometheus" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "http://prometheus-prometheus-oper-prometheus.default.svc:9090" - ## metrics schema path - metric_path = ["/etc/telegraf/schema/openshift_prometheus_historical_metrics.json"] - config_file = "/etc/telegraf/schema/collector_prometheus_config.json" - target_label = "" - cluster_name = "default" - discover_path = "" - controller_name = [] - node_uids = [] - group_names = [] - historical_data_restart_limit = $HISTORICAL_DATA_RESTART_LIMIT - handle_missing_data_times = $HANDLE_MISSING_DATA_TIMES - - ## Federation Prometheus integration: inputs.data_collector ## - [[inputs.data_collector]] - query_start_time_offset = "-1m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: prometheus - source = "prometheus" - ## which collector to handle the data collection - collector = "prometheus" - ## account name - account = "" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "http://prometheus-prometheus-oper-prometheus.default.svc:9090" - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federation_prometheus_historical_metrics.json"] - config_file = "/etc/telegraf/schema/collector_prometheus_config.json" - target_label = "clusterID: cluster1" - cluster_name = "default" - discover_path = "" - controller_name = [] - node_uids = [] - group_names = [] - historical_data_restart_limit = $HISTORICAL_DATA_RESTART_LIMIT - handle_missing_data_times = $HANDLE_MISSING_DATA_TIMES - - ## Rancher Prometheus integration: inputs.data_collector ## - [[inputs.data_collector]] - query_start_time_offset = "-1m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: prometheus - source = "prometheus" - ## which collector to handle the data collection - collector = "prometheus" - ## account name - account = "" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "http://prometheus-prometheus-oper-prometheus.default.svc:9090" - ## metrics schema path - metric_path = ["/etc/telegraf/schema/rancher_prometheus_historical_metrics.json"] - config_file = "/etc/telegraf/schema/collector_prometheus_config.json" - target_label = "" - cluster_name = "default" - discover_path = "" - controller_name = [] - node_uids = [] - group_names = [] - historical_data_restart_limit = $HISTORICAL_DATA_RESTART_LIMIT - handle_missing_data_times = $HANDLE_MISSING_DATA_TIMES - - ## Prometheus integration: inputs.data_collector ## - [[inputs.data_collector]] - query_start_time_offset = "-1m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: prometheus - source = "prometheus" - ## which collector to handle the data collection - collector = "prometheus" - ## account name - account = "" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "http://prometheus-prometheus-oper-prometheus.default.svc:9090" - ## metrics schema path - metric_path = ["/etc/telegraf/schema/prometheus_historical_metrics.json"] - config_file = "/etc/telegraf/schema/collector_prometheus_config.json" - target_label = "" - cluster_name = "default" - discover_path = "" - controller_name = [] - node_uids = [] - group_names = [] - historical_data_restart_limit = $HISTORICAL_DATA_RESTART_LIMIT - handle_missing_data_times = $HANDLE_MISSING_DATA_TIMES - - ## Datadog integration: inputs.data_collector - [[inputs.data_collector]] - query_start_time_offset = "-1m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: prometheus, datadog, sysdig - source = "datadog" - ## which collector to handle the data collection - collector = "datadog" - ## authenticated token path - token= "${DD-API-KEY}" - application_key = "${DD-APPLICATION-KEY}" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "https://api.datadoghq.com/api/v1/query" - ## Set batch query parameters - max_query_per_chunk = $DATADOG_MAX_QUERY_PER_CHUNK - max_characters_per_chunk = $DATADOG_MAX_CHAR_PER_CHUNK - ## metrics schema path - metric_path = ["/etc/telegraf/schema/datadog_historical_metrics.json"] - config_file = "/etc/telegraf/schema/collector_datadog_config.json" - cluster_name = "default" - historical_data_restart_limit = $HISTORICAL_DATA_RESTART_LIMIT - handle_missing_data_times = $HANDLE_MISSING_DATA_TIMES - - ## Sysdig integration: inputs.data_collector ## - [[inputs.data_collector]] - query_start_time_offset = "-1m" - query_end_time_offset = "0m" - ## data source type from which to query data - ## accept values: sysdig - source = "sysdig" - ## which collector to handle the data collection - collector = "sysdig" - ## account name - account = "" - ## authenticated token path - token= "${SYSDIG_API_TOKEN}" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "${SYSDIG_API_URL}/data/batch" - ## metrics schema path - metric_path = ["/etc/telegraf/schema/sysdig_historical_metrics.json"] - config_file = "/etc/telegraf/schema/collector_sysdig_config.json" - target_label = "" - cluster_name = "${CLUSTER_NAME}" - discover_path = "" - controller_name = [] - node_uids = [] - group_names = [] - historical_data_restart_limit = $HISTORICAL_DATA_RESTART_LIMIT - handle_missing_data_times = $HANDLE_MISSING_DATA_TIMES - - ### VMware integration: inputs.data_collector ## - #[[inputs.data_collector]] - # interval = "5m" - # query_start_time_offset = "-5m" - # query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - # ## data source type from which to query data - # ## accept values: vmware - # source = "vmware" - # ## which collector to handle the data collection - # collector = "vmware" - # ## account name - # account = "" - # ## authenticated token path - # token= "" - # ## TLS Insecure skip verify - # insecure_skip_verify = true - # ## one URL from which to read formatted metrics - # url = "${VMWARE_API_URL}" - # ## metrics schema path - # metric_path = ["/etc/telegraf/schema/vmware_metrics.json"] - # config_file = "/etc/telegraf/schema/collector_vmware_config.json" - # target_label = "" - # cluster_name = "${CLUSTER_NAME}" - # discover_path = "" - # controller_name = [] - # node_uids = [] - # group_names = [] - # historical_data_restart_limit = $HISTORICAL_DATA_RESTART_LIMIT - # handle_missing_data_times = $HANDLE_MISSING_DATA_TIMES - - ## AWS Cloudwatch integration: inputs.data_collector - [[inputs.data_collector]] - #interval = "5m" - query_start_time_offset = "-10m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: vmware - source = "aws" - ## which collector to handle the data collection - collector = "aws" - ## account name - account = "" - ## authenticated token path - token= "" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "" - ## metrics schema path - metric_path = ["/etc/telegraf/schema/aws_historical_metrics.json"] - config_file = "/etc/telegraf/schema/collector_aws_config.json" - cluster_name = "${CLUSTER_NAME}" - discover_path = "" - controller_name = [] - node_uids = [] - group_names = [] - historical_data_restart_limit = $HISTORICAL_DATA_RESTART_LIMIT - handle_missing_data_times = $HANDLE_MISSING_DATA_TIMES - - ## Openshift Prometheus integration: outputs.alameda_datahub ## - [[outputs.alameda_datahub]] - namepass = ["openshift_prometheus_*"] - metric_prefix = "openshift_prometheus_" - datasource = "prometheus" - concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB - schema_file = "/etc/telegraf/schema/datahub_historical_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - - ## Federation Prometheus/Prometheus integration: outputs.alameda_datahub ## - [[outputs.alameda_datahub]] - namepass = ["prometheus_*"] - metric_prefix = "prometheus_" - datasource = "prometheus" - concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB - schema_file = "/etc/telegraf/schema/datahub_historical_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - - ## Sysdig integration: outputs.alameda_datahub ## - [[outputs.alameda_datahub]] - namepass = ["sysdig_*"] - metric_prefix = "sysdig_" - datasource = "sysdig" - concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB - schema_file = "/etc/telegraf/schema/datahub_historical_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - - ## Datadog integration: outputs.alameda_datahub ## - [[outputs.alameda_datahub]] - namepass = ["datadog_*"] - metric_prefix = "datadog_" - datasource = "datadog" - concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB - schema_file = "/etc/telegraf/schema/datahub_historical_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - - ### VMware integration: outputs.alameda_datahub ## - #[[outputs.alameda_datahub]] - # namepass = ["vmware_*"] - # metric_prefix = "vmware_" - # datasource = "vmware" - # concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB - # schema_file = "/etc/telegraf/schema/datahub_historical_schema.json" - # cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - - ## AWS Cloudwatch integration: outputs.alameda_datahub - [[outputs.alameda_datahub]] - namepass = ["aws_cloudwatch_*"] - metric_prefix = "aws_cloudwatch_" - datasource = "aws" - concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB - schema_file = "/etc/telegraf/schema/datahub_historical_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - - ## Post Datahub event - [[outputs.alameda_datahub]] - namepass = ["datahub_event"] - metric_prefix = "datahub_" - post_event_interval = "$POST_EVENT_INTERVAL" - schema_file = "/etc/telegraf/schema/datahub_historical_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + telegraf_historical.conf: |+ + [global_tags] + + [agent] + interval = "1m" + delay_query_interval = "$DELAY_QUERY_INTERVAL" + delay_historical_query = "$DELAY_HISTORICAL_QUERY" + round_interval = true + metric_batch_size = 100000 + metric_buffer_limit = 100000 + collection_jitter = "5s" + flush_interval = "20s" + flush_jitter = "0s" + precision = "1us" + debug = $DEBUG + aggregator_queue = 200000 + max_rpc_receive_size = $MAX_RPC_RECEIVE_SIZE + logfile = "/var/log/telegraf_historical.log" + logfile_rotation_interval = "1d" + logfile_rotation_max_archives = 10 + logfile_rotation_max_size = "200MB" + logfile_compress_archives = true + logfile_total_max_size = "$FEDERATORAI_MAXIMUM_LOG_SIZE" + logfile_queue_size = $MAX_LOG_QUEUE_SIZE + logfile_queue_trace_interval = "$LOG_QUEUE_TRACE_INTERVAL" + logfile_enabled_async_logger = $ENABLED_ASYNC_LOGGER + ## Data adapter will flush log queue to console if queue is full + enable_logfile_flush_to_console = $ENABLE_FLUSH_LOG_TO_CONSOLE + logfile_flush_to_console_level = "$LOG_FLUSH_TO_CONSOLE_LEVEL" + ## Query will retry if some metrics hasn't returned yet. + max_retry = 1 + retry_interval = "10s" + max_request_line = $MAX_REQUEST_LINE + sysdig_max_char_per_chunk = $SYSDIG_MAX_CHAR_PER_CHUNK + # sysdig_max_query_per_chunk accepted value [1-20], default value is 10 if not setted + sysdig_max_query_per_chunk = $SYSDIG_MAX_QUERY_PER_CHUNK + quiet = false + hostname = "" + omit_hostname = false + alamedascaler_enable = true + enable_historical_data_collection = true + force_reload_configuration = false + fed_rest_url = "$FED_REST_URL" + fed_rest_port = "$FED_REST_PORT" + datahub_url = "$DATAHUB_URL" + datahub_port = "$DATAHUB_PORT" + rabbitmq_url = "$RABBITMQ_URL" + rabbitmq_port = "$RABBITMQ_PORT" + rabbitmq_subscriber = "historical_data_adapter" + expired_time = "8760h" + event_cache_expired_time = "$POST_EVENT_INTERVAL" + + ## set collect_metadata_only=false to collect resource metadata and metrics + ## set collect_metadata_only=true to only collect resource metadata + collect_metadata_only = false + + aws_metric_list = "$AWS_METRIC_LIST" + drop_duplicated_rest_api = true + force_send_rest_api_time = "1h" + + # Default disable integration metrics setting + # Cost Analysis related metrics + cost_analysis_metrics = ["federatorai.cost_analysis.instance.cost","federatorai.cost_analysis.namespace.cost","federatorai.prediction.namespace.cost","federatorai.recommendation.instance","federatorai.cost_analysis.resource_alloc_cost.cluster","federatorai.cost_analysis.resource_alloc_cost.node","federatorai.cost_analysis.resource_alloc_cost.namespace","federatorai.cost_analysis.resource_usage_cost.cluster","federatorai.cost_analysis.resource_usage_cost.node","federatorai.cost_analysis.resource_usage_cost.namespace","federatorai.cost_analysis.cost_per_day.cluster","federatorai.cost_analysis.cost_per_day.node","federatorai.cost_analysis.cost_per_day.namespace","federatorai.cost_analysis.cost_per_week.cluster","federatorai.cost_analysis.cost_per_week.node","federatorai.cost_analysis.cost_per_week.namespace","federatorai.cost_analysis.cost_per_month.cluster","federatorai.cost_analysis.cost_per_month.node","federatorai.cost_analysis.cost_per_month.namespace","federatorai.recommendation.cost_analysis.cost_per_day.cluster","federatorai.recommendation.cost_analysis.cost_per_day.node","federatorai.recommendation.cost_analysis.cost_per_day.namespace","federatorai.recommendation.cost_analysis.cost_per_week.cluster","federatorai.recommendation.cost_analysis.cost_per_week.node","federatorai.recommendation.cost_analysis.cost_per_week.namespace","federatorai.recommendation.cost_analysis.cost_per_month.cluster","federatorai.recommendation.cost_analysis.cost_per_month.node","federatorai.recommendation.cost_analysis.cost_per_month.namespace","federatorai.prediction.cost_analysis.cost_per_day.cluster","federatorai.prediction.cost_analysis.cost_per_day.node","federatorai.prediction.cost_analysis.cost_per_day.namespace","federatorai.prediction.cost_analysis.cost_per_week.cluster","federatorai.prediction.cost_analysis.cost_per_week.node","federatorai.prediction.cost_analysis.cost_per_week.namespace","federatorai.prediction.cost_analysis.cost_per_month.cluster","federatorai.prediction.cost_analysis.cost_per_month.node","federatorai.prediction.cost_analysis.cost_per_month.namespace"] + + ## Automation + enable_dump_mock_data = false + testing_mode = false + configuration_mock_data_path = "/var/log/mock_server/mock_data/configuration" + datadog_mock_data_path = "/var/log/mock_server/mock_data/datadog" + sysdig_mock_data_path = "/var/log/mock_server/mock_data/sysdig" + prometheus_mock_data_path = "/var/log/mock_server/mock_data/prometheus" + expected_result_path = "/var/log/mock_server/mock_data/expected_result" + test_mode_result_path = "mock_server/mock_data/test_mode_result" + + ## Dashboard + check_sysdig_dashboard_interval = "$CHECK_SYSDIG_DASHBOARD_INTERVAL" + enable_sysdig_dashboard = $ENABLE_SYSDIG_DASHBOARD + sysdig_dashboards = ["/etc/telegraf/dashboards/sysdig/kafka-overview.json", "/etc/telegraf/dashboards/sysdig/application-overview.json", "/etc/telegraf/dashboards/sysdig/cluster-overview.json"] + + ## Datadog tag mapping table + # if enable_autodiscover_datadog_cluster_name_tag_key=true, agent uses datadog_default_cluster_tag_key to autodiscover cluster name tag key + # if enable_autodiscover_datadog_cluster_name_tag_key=false, agent uses the cluster name tag key defined in agent.datadog_cluster_tag_mapping. + enable_autodiscover_datadog_cluster_name_tag_key = true + #DD_CLUSTER_NAME_TAG_KEYS is "cluster_name,kube_cluster_name,kube_cluster" by default. + datadog_default_cluster_tag_keys = "$DD_CLUSTER_NAME_TAG_KEYS" + [agent.datadog_cluster_tag_mapping] + # Datadog cluster name tag = [""] + kube_cluster = [] + cluster_name = [] + kube_cluster_name = [] + + ############################# + ### Aggregator Basicstats ### + ############################# + + # Datadog metrics + [[aggregators.basicstats]] + grace = "2m" + period = "1m" + drop_original = true + # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule + traverse_all_rules = false + # By default, data adapter send all the metrics through basicstats + namepass = ["datadog_cluster_collection_done"] + # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator + namedrop = [] + [[aggregators.basicstats.metric]] + groups = ["*"] + measurement_name = "datadog_cluster_collection_done" + aggregation_method = "" + fields = [""] + + ## Openshift Prometheus integration: aggregator ## + [[aggregators.basicstats]] + grace = "2m" + period = "1m" + drop_original = true + # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule + traverse_all_rules = false + # By default, data adapter send all the metrics through basicstats + namepass = ["openshift_prometheus_cluster_collection_done"] + # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator + namedrop = [] + [[aggregators.basicstats.metric]] + groups = ["*"] + measurement_name = "openshift_prometheus_cluster_collection_done" + aggregation_method = "" + fields = [""] + + ## Federation Prometheus/Prometheus integration: aggregator ## + [[aggregators.basicstats]] + grace = "2m" + period = "1m" + drop_original = true + # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule + traverse_all_rules = false + # By default, data adapter send all the metrics through basicstats + namepass = ["prometheus_cluster_collection_done"] + # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator + namedrop = [] + [[aggregators.basicstats.metric]] + groups = ["*"] + measurement_name = "prometheus_cluster_collection_done" + aggregation_method = "" + fields = [""] + + ## Sysdig integration: aggregator ## + [[aggregators.basicstats]] + grace = "2m" + period = "1m" + drop_original = true + # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule + traverse_all_rules = false + # By default, data adapter send all the metrics through basicstats + namepass = ["sysdig_cluster_collection_done"] + # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator + namedrop = [] + [[aggregators.basicstats.metric]] + groups = ["*"] + measurement_name = "sysdig_cluster_collection_done" + aggregation_method = "" + fields = [""] + + ### VMware integration: aggregator ## + #[[aggregators.basicstats]] + # grace = "5m" + # period = "1m" + # drop_original = true + # # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule + # traverse_all_rules = false + # # By default, data adapter send all the metrics through basicstats + # namepass = ["vmware_cluster_collection_done"] + # # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator + # namedrop = [] + + # [[aggregators.basicstats.metric]] + # groups = ["*"] + # measurement_name = "vmware_cluster_collection_done" + # aggregation_method = "" + # fields = [""] + + # AWS Cloudwatch metrics + [[aggregators.basicstats]] + period = "1m" + drop_original = true + # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule + traverse_all_rules = false + # By default, data adapter send all the metrics through basicstats + namepass = ["aws_cloudwatch_cluster_collection_done"] + # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator + namedrop = [] + + [[aggregators.basicstats.metric]] + groups = ["*"] + measurement_name = "aws_cloudwatch_cluster_collection_done" + aggregation_method = "" + fields = [""] + + ################## + ### Processors ### + ################## + + [[processors.filter_out]] + order = 1 + namepass = ["kafka_topic_partition_current_offset", "kafka_consumer_group_current_offset", "node_disk_io_util", "sysdig_kafka_topic_partition_current_offset", "sysdig_kafka_consumergroup_current_offset", "openshift_prometheus_kube_pod_owner", "prometheus_kube_pod_owner", "openshift_prometheus_kube_replicationcontroller_spec_replicas", "openshift_prometheus_kube_replicationcontroller_status_available_replicas", "datadog_node_pod_phase"] + [[processors.filter_out.metric]] + measurement_name = "sysdig_kafka_topic_partition_current_offset" + fields = ["kafka_topic_partition_current_offset"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "sysdig_kafka_consumergroup_current_offset" + fields = ["kafka_consumergroup_current_offset"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "kafka_topic_partition_current_offset" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "kafka_consumer_group_current_offset" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "node_disk_io_util" + fields = ["value"] + aggregation_method = "set_max_value" + max_value = 100.0 + [[processors.filter_out.metric]] + measurement_name = "prometheus_kube_pod_owner" + fields = ["owner_name"] + aggregation_method = "trim_last_index" + match_string = "-" + [processors.filter_out.metric.condition] + owner_kind = "ReplicaSet" + [[processors.filter_out.metric]] + measurement_name = "prometheus_kube_pod_owner" + fields = ["owner_name"] + aggregation_method = "trim_last_index" + match_string = "-" + [processors.filter_out.metric.condition] + owner_kind = "ReplicationController" + [[processors.filter_out.metric]] + measurement_name = "openshift_prometheus_kube_pod_owner" + fields = ["owner_name"] + aggregation_method = "trim_last_index" + match_string = "-" + [processors.filter_out.metric.condition] + owner_kind = "ReplicaSet" + [[processors.filter_out.metric]] + measurement_name = "openshift_prometheus_kube_pod_owner" + fields = ["owner_name"] + aggregation_method = "trim_last_index" + match_string = "-" + [processors.filter_out.metric.condition] + owner_kind = "ReplicationController" + [[processors.filter_out.metric]] + measurement_name = "openshift_prometheus_kube_replicationcontroller_spec_replicas" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "openshift_prometheus_kube_replicationcontroller_status_available_replicas" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "openshift_prometheus_kube_replicationcontroller_spec_replicas" + fields = ["replicationcontroller"] + aggregation_method = "trim_last_index" + match_string = "-" + [[processors.filter_out.metric]] + measurement_name = "openshift_prometheus_kube_replicationcontroller_status_available_replicas" + fields = ["replicationcontroller"] + aggregation_method = "trim_last_index" + match_string = "-" + + ## Datadog integration: processors + [[processors.metrics_decorator]] + order = 2 + namepass = ["datadog_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/datadog_pre_metric_decorator.json" + + [[processors.metrics_grouping]] + order = 3 + namepass = ["datadog_*", "alameda_*"] + namedrop = ["datadog_historical_collection_done"] + schema_file = "/etc/telegraf/schema/datadog_grouping_rules.json" + + [[processors.metrics_decorator]] + order = 4 + namepass = ["datadog_namespace_*"] + schema_file = "/etc/telegraf/schema/datadog_post_metric_decorator.json" + + [[processors.schema_mapping]] + order = 5 + datasource = "datadog" + aggregator_processor = true + namepass = ["datadog_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/datadog_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + ## Set default cloud information ifneeded + enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY + default_provider = "$DEFAULT_PROVIDER" + default_region = "$DEFAULT_REGION" + default_instance_type = "$DEFAULT_INSTANCE_TYPE" + default_instance_id = "$DEFAULT_INSTANCE_ID" + default_zone = "$DEFAULT_ZONE" + + ## Openshift Prometheus integration: processors ## + [[processors.metrics_decorator]] + order = 2 + namepass = ["openshift_prometheus_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/openshift_prometheus_pre_metric_decorator.json" + + [[processors.metrics_grouping]] + order = 3 + namepass = ["openshift_prometheus_*", "alameda_*"] + namedrop = ["openshift_prometheus_historical_collection_done"] + schema_file = "/etc/telegraf/schema/openshift_prometheus_grouping_rules.json" + + [[processors.metrics_decorator]] + order = 4 + namepass = ["openshift_prometheus_alameda_config_cluster_namespace", "openshift_prometheus_node_cpu_usage_seconds_total", "openshift_prometheus_node_memory_usage_bytes", "openshift_prometheus_kube_node_status_capacity_cpu_cores", "openshift_prometheus_namespace_*"] + schema_file = "/etc/telegraf/schema/openshift_prometheus_post_metric_decorator.json" + + [[processors.schema_mapping]] + order = 5 + datasource = "prometheus" + aggregator_processor = true + namepass = ["openshift_prometheus_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/openshift_prometheus_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + ## Set default cloud information ifneeded + enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY + default_provider = "$DEFAULT_PROVIDER" + default_region = "$DEFAULT_REGION" + default_instance_type = "$DEFAULT_INSTANCE_TYPE" + default_instance_id = "$DEFAULT_INSTANCE_ID" + default_zone = "$DEFAULT_ZONE" + + ## Federation Prometheus/Prometheus integration: processors ## + [[processors.metrics_decorator]] + order = 2 + namepass = ["prometheus_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/prometheus_pre_metric_decorator.json" + + [[processors.metrics_grouping]] + order = 3 + namepass = ["prometheus_*", "alameda_*"] + namedrop = ["prometheus_historical_collection_done"] + schema_file = "/etc/telegraf/schema/prometheus_grouping_rules.json" + + [[processors.metrics_decorator]] + order = 4 + namepass = ["prometheus_alameda_config_cluster_namespace", "prometheus_node_cpu_usage_seconds_total", "prometheus_node_memory_usage_bytes", "prometheus_kube_node_status_capacity_cpu_cores", "prometheus_namespace_*"] + schema_file = "/etc/telegraf/schema/prometheus_post_metric_decorator.json" + + [[processors.schema_mapping]] + order = 5 + datasource = "prometheus" + aggregator_processor = true + namepass = ["prometheus_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/prometheus_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + ## Set default cloud information ifneeded + enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY + default_provider = "$DEFAULT_PROVIDER" + default_region = "$DEFAULT_REGION" + default_instance_type = "$DEFAULT_INSTANCE_TYPE" + default_instance_id = "$DEFAULT_INSTANCE_ID" + default_zone = "$DEFAULT_ZONE" + + ## Sysdig integration: processors ## + [[processors.metrics_decorator]] + order = 2 + namepass = ["sysdig_*", "alameda_*", "federatorai.kafka.consumer_lag", "federatorai.kafka.consumer_offset_rate", "federatorai.kafka.broker_offset_rate", "federatorai.prediction.kafka", "federatorai.recommendation", "federatorai.prediction.controller", "federatorai.prediction.controller.max", "federatorai.prediction.controller.min", "federatorai.prediction.controller.avg", "federatorai.prediction.node", "federatorai.prediction.node.max", "federatorai.prediction.node.min", "federatorai.prediction.node.avg", "federatorai.resource_planning.node", "federatorai.resource_planning.controller", "federatorai.kubernetes.cpu.usage.total.node", "federatorai.kubernetes.cpu.usage.total.controller", "federatorai.kubernetes.memory.usage.node", "federatorai.kubernetes.memory.usage.controller", "federatorai.kubernetes.cpu.usage.total.node_rollup_3600sec", "federatorai.kubernetes.cpu.usage.total.controller_rollup_3600sec", "federatorai.kubernetes.memory.usage.node_rollup_3600sec", "federatorai.kubernetes.memory.usage.controller_rollup_3600sec", "federatorai.kubernetes.cpu.usage.total.node_rollup_21600sec", "federatorai.kubernetes.cpu.usage.total.controller_rollup_21600sec", "federatorai.kubernetes.memory.usage.node_rollup_21600sec", "federatorai.kubernetes.memory.usage.controller_rollup_21600sec", "federatorai.kubernetes.cpu.usage.total.node_rollup_86400sec", "federatorai.kubernetes.cpu.usage.total.controller_rollup_86400sec", "federatorai.kubernetes.memory.usage.node_rollup_86400sec", "federatorai.kubernetes.memory.usage.controller_rollup_86400sec"] + schema_file = "/etc/telegraf/schema/sysdig_pre_metric_decorator.json" + + [[processors.metrics_grouping]] + order = 3 + namepass = ["sysdig_*", "alameda_*"] + namedrop = ["sysdig_historical_collection_done"] + schema_file = "/etc/telegraf/schema/sysdig_grouping_rules.json" + + [[processors.metrics_decorator]] + order = 4 + namepass = ["sysdig_alameda_config_cluster_namespace", "sysdig_namespace_*", "sysdig_kube_container_resource_limits_cpu_cores", "sysdig_kube_container_resource_requests_cpu_cores", "sysdig_alameda_config_namespace_metric_instance_config_info"] + schema_file = "/etc/telegraf/schema/sysdig_post_metric_decorator.json" + + [[processors.schema_mapping]] + order = 5 + datasource = "sysdig" + aggregator_processor = true + namepass = ["sysdig_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/sysdig_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + ## Set default cloud information ifneeded + enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY + default_provider = "$DEFAULT_PROVIDER" + default_region = "$DEFAULT_REGION" + default_instance_type = "$DEFAULT_INSTANCE_TYPE" + default_instance_id = "$DEFAULT_INSTANCE_ID" + default_zone = "$DEFAULT_ZONE" + + ### VMware integration: processors + #[[processors.metrics_decorator]] + # order = 2 + # namepass = ["vmware_*", "alameda_*"] + # schema_file = "/etc/telegraf/schema/vmware_pre_metric_decorator.json" + + #[[processors.metrics_grouping]] + # order = 3 + # namepass = ["vmware_*", "alameda_*"] + # namedrop = ["vmware_historical_collection_done"] + # schema_file = "/etc/telegraf/schema/vmware_grouping_rules.json" + + #[[processors.metrics_decorator]] + # order = 4 + # namepass = [""] + # schema_file = "/etc/telegraf/schema/vmware_post_metric_decorator.json" + + #[[processors.schema_mapping]] + # order = 5 + # datasource = "vmware" + # aggregator_processor = true + # namepass = ["vmware_*", "alameda_*"] + # schema_file = "/etc/telegraf/schema/vmware_schema.json" + # cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + # ## Set default cloud information ifneeded + # enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY + # default_provider = "$DEFAULT_PROVIDER" + # default_region = "$DEFAULT_REGION" + # default_instance_type = "$DEFAULT_INSTANCE_TYPE" + # default_instance_id = "$DEFAULT_INSTANCE_ID" + # default_zone = "$DEFAULT_ZONE" + + ## AWS Cloudwatch integration: processors + [[processors.metrics_decorator]] + order = 2 + namepass = ["aws_cloudwatch_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/aws_pre_metric_decorator.json" + + [[processors.metrics_grouping]] + order = 3 + namepass = ["aws_cloudwatch_*", "alameda_*"] + namedrop = ["aws_cloudwatch_historical_collection_done"] + schema_file = "/etc/telegraf/schema/aws_grouping_rules.json" + + [[processors.metrics_decorator]] + order = 4 + namepass = ["aws_cloudwatch_alameda_config_cluster_vm", "aws_cloudwatch_node_group_*"] + schema_file = "/etc/telegraf/schema/aws_post_metric_decorator.json" + + [[processors.schema_mapping]] + order = 5 + datasource = "aws" + aggregator_processor = true + namepass = ["aws_cloudwatch_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/aws_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + ## Set default cloud information ifneeded + enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY + default_provider = "$DEFAULT_PROVIDER" + default_region = "$DEFAULT_REGION" + default_instance_type = "$DEFAULT_INSTANCE_TYPE" + default_instance_id = "$DEFAULT_INSTANCE_ID" + default_zone = "$DEFAULT_ZONE" + + ############################## + ### Aggregator Federatorai ### + ############################## + + [[aggregators.federatorai]] + period = "1m" + drop_original = true + concurrent_job = 3 + schema_file = "/etc/telegraf/schema/basic_aggregator_schema.json" + namepass = [""] + + ## Datadog metrics ## + [[aggregators.federatorai]] + grace = "3m" + period = "1m" + drop_original = true + concurrent_job = 3 + schema_file = "/etc/telegraf/schema/datadog_aggregator_schema.json" + config_file = "/etc/telegraf/schema/aggregator_config.json" + namepass = ["datadog_*"] + + ## Openshift Prometheus integration: aggregator ## + [[aggregators.federatorai]] + grace = "3m" + period = "1m" + drop_original = true + concurrent_job = 3 + schema_file = "/etc/telegraf/schema/openshift_prometheus_aggregator_schema.json" + config_file = "/etc/telegraf/schema/aggregator_config.json" + namepass = ["openshift_prometheus_*"] + + ## Federation Prometheus/Prometheus integration: aggregator ## + [[aggregators.federatorai]] + grace = "3m" + period = "1m" + drop_original = true + concurrent_job = 3 + schema_file = "/etc/telegraf/schema/prometheus_aggregator_schema.json" + config_file = "/etc/telegraf/schema/aggregator_config.json" + namepass = ["prometheus_*"] + + ## Sysdig integration: aggregator ## + [[aggregators.federatorai]] + grace = "3m" + period = "1m" + drop_original = true + concurrent_job = 3 + schema_file = "/etc/telegraf/schema/sysdig_aggregator_schema.json" + config_file = "/etc/telegraf/schema/aggregator_config.json" + namepass = ["sysdig_*"] + + ### VMware integration: aggregator ## + #[[aggregators.federatorai]] + # grace = "5m" + # period = "1m" + # drop_original = true + # concurrent_job = 3 + # schema_file = "/etc/telegraf/schema/vmware_aggregator_schema.json" + # config_file = "/etc/telegraf/schema/aggregator_config.json" + # namepass = ["vmware_*"] + + ## AWS Cloudwatch metrics ## + [[aggregators.federatorai]] + grace = "2m" + period = "1m" + drop_original = true + concurrent_job = 3 + schema_file = "/etc/telegraf/schema/aws_aggregator_schema.json" + config_file = "/etc/telegraf/schema/aggregator_config.json" + namepass = ["aws_cloudwatch_*"] + + ############################ + ### Input/Output Plugins ### + ############################ + + ## Alameda Configuration: inputs.data_collector ## + [[inputs.data_collector]] + query_start_time_offset = "-1m" + query_end_time_offset = "0h" #Support s(second),m(minute),h(hour) + collection_jitter = "0s" + ## data source type from which to query data + ## accept values: alameda_datahub + source = "alameda_datahub" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = true + overwrite_query_delay_interval = true + delay_query_interval = "0s" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/alameda_config_historical_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Openshift Prometheus integration: inputs.data_collector ## + [[inputs.data_collector]] + query_start_time_offset = "-1m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: prometheus + source = "prometheus" + ## which collector to handle the data collection + collector = "prometheus" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## one URL from which to read formatted metrics + url = "http://prometheus-prometheus-oper-prometheus.default.svc:9090" + ## metrics schema path + metric_path = ["/etc/telegraf/schema/openshift_prometheus_historical_metrics.json"] + config_file = "/etc/telegraf/schema/collector_prometheus_config.json" + target_label = "" + cluster_name = "default" + discover_path = "" + controller_name = [] + node_uids = [] + group_names = [] + historical_data_restart_limit = $HISTORICAL_DATA_RESTART_LIMIT + handle_missing_data_times = $HANDLE_MISSING_DATA_TIMES + + ## Federation Prometheus integration: inputs.data_collector ## + [[inputs.data_collector]] + query_start_time_offset = "-1m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: prometheus + source = "prometheus" + ## which collector to handle the data collection + collector = "prometheus" + ## account name + account = "" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## one URL from which to read formatted metrics + url = "http://prometheus-prometheus-oper-prometheus.default.svc:9090" + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federation_prometheus_historical_metrics.json"] + config_file = "/etc/telegraf/schema/collector_prometheus_config.json" + target_label = "clusterID: cluster1" + cluster_name = "default" + discover_path = "" + controller_name = [] + node_uids = [] + group_names = [] + historical_data_restart_limit = $HISTORICAL_DATA_RESTART_LIMIT + handle_missing_data_times = $HANDLE_MISSING_DATA_TIMES + + ## Rancher Prometheus integration: inputs.data_collector ## + [[inputs.data_collector]] + query_start_time_offset = "-1m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: prometheus + source = "prometheus" + ## which collector to handle the data collection + collector = "prometheus" + ## account name + account = "" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## one URL from which to read formatted metrics + url = "http://prometheus-prometheus-oper-prometheus.default.svc:9090" + ## metrics schema path + metric_path = ["/etc/telegraf/schema/rancher_prometheus_historical_metrics.json"] + config_file = "/etc/telegraf/schema/collector_prometheus_config.json" + target_label = "" + cluster_name = "default" + discover_path = "" + controller_name = [] + node_uids = [] + group_names = [] + historical_data_restart_limit = $HISTORICAL_DATA_RESTART_LIMIT + handle_missing_data_times = $HANDLE_MISSING_DATA_TIMES + + ## Prometheus integration: inputs.data_collector ## + [[inputs.data_collector]] + query_start_time_offset = "-1m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: prometheus + source = "prometheus" + ## which collector to handle the data collection + collector = "prometheus" + ## account name + account = "" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## one URL from which to read formatted metrics + url = "http://prometheus-prometheus-oper-prometheus.default.svc:9090" + ## metrics schema path + metric_path = ["/etc/telegraf/schema/prometheus_historical_metrics.json"] + config_file = "/etc/telegraf/schema/collector_prometheus_config.json" + target_label = "" + cluster_name = "default" + discover_path = "" + controller_name = [] + node_uids = [] + group_names = [] + historical_data_restart_limit = $HISTORICAL_DATA_RESTART_LIMIT + handle_missing_data_times = $HANDLE_MISSING_DATA_TIMES + + ## Datadog integration: inputs.data_collector + [[inputs.data_collector]] + query_start_time_offset = "-1m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: prometheus, datadog, sysdig + source = "datadog" + ## which collector to handle the data collection + collector = "datadog" + ## authenticated token path + token= "${DD-API-KEY}" + application_key = "${DD-APPLICATION-KEY}" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## one URL from which to read formatted metrics + url = "https://api.datadoghq.com/api/v1/query" + ## Set batch query parameters + max_query_per_chunk = $DATADOG_MAX_QUERY_PER_CHUNK + max_characters_per_chunk = $DATADOG_MAX_CHAR_PER_CHUNK + ## metrics schema path + metric_path = ["/etc/telegraf/schema/datadog_historical_metrics.json"] + config_file = "/etc/telegraf/schema/collector_datadog_config.json" + cluster_name = "default" + historical_data_restart_limit = $HISTORICAL_DATA_RESTART_LIMIT + handle_missing_data_times = $HANDLE_MISSING_DATA_TIMES + + ## Sysdig integration: inputs.data_collector ## + [[inputs.data_collector]] + query_start_time_offset = "-1m" + query_end_time_offset = "0m" + ## data source type from which to query data + ## accept values: sysdig + source = "sysdig" + ## which collector to handle the data collection + collector = "sysdig" + ## account name + account = "" + ## authenticated token path + token= "${SYSDIG_API_TOKEN}" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## one URL from which to read formatted metrics + url = "${SYSDIG_API_URL}/data/batch" + ## metrics schema path + metric_path = ["/etc/telegraf/schema/sysdig_historical_metrics.json"] + config_file = "/etc/telegraf/schema/collector_sysdig_config.json" + target_label = "" + cluster_name = "${CLUSTER_NAME}" + discover_path = "" + controller_name = [] + node_uids = [] + group_names = [] + historical_data_restart_limit = $HISTORICAL_DATA_RESTART_LIMIT + handle_missing_data_times = $HANDLE_MISSING_DATA_TIMES + + ### VMware integration: inputs.data_collector ## + #[[inputs.data_collector]] + # interval = "5m" + # query_start_time_offset = "-5m" + # query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + # ## data source type from which to query data + # ## accept values: vmware + # source = "vmware" + # ## which collector to handle the data collection + # collector = "vmware" + # ## account name + # account = "" + # ## authenticated token path + # token= "" + # ## TLS Insecure skip verify + # insecure_skip_verify = true + # ## one URL from which to read formatted metrics + # url = "${VMWARE_API_URL}" + # ## metrics schema path + # metric_path = ["/etc/telegraf/schema/vmware_metrics.json"] + # config_file = "/etc/telegraf/schema/collector_vmware_config.json" + # target_label = "" + # cluster_name = "${CLUSTER_NAME}" + # discover_path = "" + # controller_name = [] + # node_uids = [] + # group_names = [] + # historical_data_restart_limit = $HISTORICAL_DATA_RESTART_LIMIT + # handle_missing_data_times = $HANDLE_MISSING_DATA_TIMES + + ## AWS Cloudwatch integration: inputs.data_collector + [[inputs.data_collector]] + #interval = "5m" + query_start_time_offset = "-30m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: vmware + source = "aws" + ## which collector to handle the data collection + collector = "aws" + ## account name + account = "" + ## authenticated token path + token= "" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## one URL from which to read formatted metrics + url = "" + ## metrics schema path + metric_path = ["/etc/telegraf/schema/aws_historical_metrics.json"] + config_file = "/etc/telegraf/schema/collector_aws_config.json" + cluster_name = "${CLUSTER_NAME}" + discover_path = "" + controller_name = [] + node_uids = [] + group_names = [] + historical_data_restart_limit = $HISTORICAL_DATA_RESTART_LIMIT + handle_missing_data_times = $HANDLE_MISSING_DATA_TIMES + + ## Openshift Prometheus integration: outputs.alameda_datahub ## + [[outputs.alameda_datahub]] + namepass = ["openshift_prometheus_*"] + metric_prefix = "openshift_prometheus_" + datasource = "prometheus" + concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB + schema_file = "/etc/telegraf/schema/datahub_historical_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + + ## Federation Prometheus/Prometheus integration: outputs.alameda_datahub ## + [[outputs.alameda_datahub]] + namepass = ["prometheus_*"] + metric_prefix = "prometheus_" + datasource = "prometheus" + concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB + schema_file = "/etc/telegraf/schema/datahub_historical_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + + ## Sysdig integration: outputs.alameda_datahub ## + [[outputs.alameda_datahub]] + namepass = ["sysdig_*"] + metric_prefix = "sysdig_" + datasource = "sysdig" + concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB + schema_file = "/etc/telegraf/schema/datahub_historical_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + + ## Datadog integration: outputs.alameda_datahub ## + [[outputs.alameda_datahub]] + namepass = ["datadog_*"] + metric_prefix = "datadog_" + datasource = "datadog" + concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB + schema_file = "/etc/telegraf/schema/datahub_historical_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + + ### VMware integration: outputs.alameda_datahub ## + #[[outputs.alameda_datahub]] + # namepass = ["vmware_*"] + # metric_prefix = "vmware_" + # datasource = "vmware" + # concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB + # schema_file = "/etc/telegraf/schema/datahub_historical_schema.json" + # cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + + ## AWS Cloudwatch integration: outputs.alameda_datahub + [[outputs.alameda_datahub]] + namepass = ["aws_cloudwatch_*"] + metric_prefix = "aws_cloudwatch_" + datasource = "aws" + concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB + schema_file = "/etc/telegraf/schema/datahub_historical_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + + ## Post Datahub event + [[outputs.alameda_datahub]] + namepass = ["datahub_event"] + metric_prefix = "datahub_" + post_event_interval = "$POST_EVENT_INTERVAL" + schema_file = "/etc/telegraf/schema/datahub_historical_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" diff --git a/charts/prophetstor/federatorai/templates/federatorai-data-adapter/configmaps.yaml b/charts/prophetstor/federatorai/templates/federatorai-data-adapter/configmaps.yaml index dc99b67f6..d75206a0f 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-data-adapter/configmaps.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-data-adapter/configmaps.yaml @@ -1,2058 +1,2070 @@ +--- apiVersion: v1 kind: ConfigMap metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-data-adapter-config namespace: {{ .Release.Namespace }} data: - telegraf.conf: |+ - [global_tags] - - [agent] - interval = "1m" - ## DA will try to reload user configuration periodically - # configuration_reload_interval = "1h", DA will reload user configuration every hour - # configuration_reload_interval = "0s", DA will disabled this feature. And DA only reload user configuration when receiving configuration change notification - configuration_reload_interval = "$CONFIGURATION_RELOAD_INTERVAL" - delay_query_interval = "$DELAY_QUERY_INTERVAL" - round_interval = true - metric_batch_size = 10000 - metric_buffer_limit = 100000 - collection_jitter = "5s" - flush_interval = "20s" - flush_jitter = "0s" - precision = "1us" - debug = $DEBUG - aggregator_queue = 200000 - max_rpc_receive_size = $MAX_RPC_RECEIVE_SIZE - logfile = "/var/log/telegraf.log" - logfile_rotation_interval = "1d" - logfile_rotation_max_archives = 10 - logfile_rotation_max_size = "200MB" - logfile_compress_archives = true - logfile_total_max_size = "$FEDERATORAI_MAXIMUM_LOG_SIZE" - logfile_queue_size = $MAX_LOG_QUEUE_SIZE - logfile_queue_trace_interval = "$LOG_QUEUE_TRACE_INTERVAL" - logfile_enabled_async_logger = $ENABLED_ASYNC_LOGGER - ## Data adapter will flush log queue to console if queue is full - enable_logfile_flush_to_console = $ENABLE_FLUSH_LOG_TO_CONSOLE - logfile_flush_to_console_level = "$LOG_FLUSH_TO_CONSOLE_LEVEL" - ## Query will retry if some metrics hasn't returned yet. - max_retry = 1 - retry_interval = "10s" - max_request_line = $MAX_REQUEST_LINE - sysdig_max_char_per_chunk = $SYSDIG_MAX_CHAR_PER_CHUNK - # sysdig_max_query_per_chunk accepted value [1-20], default value is 10 if not setted - sysdig_max_query_per_chunk = $SYSDIG_MAX_QUERY_PER_CHUNK - quiet = false - hostname = "" - omit_hostname = false - alamedascaler_enable = true - enable_historical_data_collection = false - force_reload_configuration = false - fed_rest_url = "$FED_REST_URL" - fed_rest_port = "$FED_REST_PORT" - datahub_url = "$DATAHUB_URL" - datahub_port = "$DATAHUB_PORT" - rabbitmq_url = "$RABBITMQ_URL" - rabbitmq_port = "$RABBITMQ_PORT" - rabbitmq_subscriber = "data_adapter" - expired_time = "$DATA_EXPIRED_TIME" - event_cache_expired_time = "$POST_EVENT_INTERVAL" - - ## set collect_metadata_only=false to collect resource metadata and metrics - ## set collect_metadata_only=true to only collect resource metadata - collect_metadata_only = $COLLECT_METADATA_ONLY - - # Default disable integration metrics setting - # Cost Analysis related metrics - cost_analysis_metrics = ["federatorai.cost_analysis.instance.cost","federatorai.cost_analysis.namespace.cost","federatorai.prediction.namespace.cost","federatorai.recommendation.instance","federatorai.cost_analysis.resource_alloc_cost.cluster","federatorai.cost_analysis.resource_alloc_cost.node","federatorai.cost_analysis.resource_alloc_cost.namespace","federatorai.cost_analysis.resource_usage_cost.cluster","federatorai.cost_analysis.resource_usage_cost.node","federatorai.cost_analysis.resource_usage_cost.namespace","federatorai.cost_analysis.cost_per_day.cluster","federatorai.cost_analysis.cost_per_day.node","federatorai.cost_analysis.cost_per_day.namespace","federatorai.cost_analysis.cost_per_week.cluster","federatorai.cost_analysis.cost_per_week.node","federatorai.cost_analysis.cost_per_week.namespace","federatorai.cost_analysis.cost_per_month.cluster","federatorai.cost_analysis.cost_per_month.node","federatorai.cost_analysis.cost_per_month.namespace","federatorai.recommendation.cost_analysis.cost_per_day.cluster","federatorai.recommendation.cost_analysis.cost_per_day.node","federatorai.recommendation.cost_analysis.cost_per_day.namespace","federatorai.recommendation.cost_analysis.cost_per_week.cluster","federatorai.recommendation.cost_analysis.cost_per_week.node","federatorai.recommendation.cost_analysis.cost_per_week.namespace","federatorai.recommendation.cost_analysis.cost_per_month.cluster","federatorai.recommendation.cost_analysis.cost_per_month.node","federatorai.recommendation.cost_analysis.cost_per_month.namespace","federatorai.cost_analysis.cost_efficiency_per_day.cluster","federatorai.cost_analysis.cost_efficiency_per_day.node","federatorai.cost_analysis.cost_efficiency_per_day.namespace","federatorai.cost_analysis.cost_efficiency_per_week.cluster","federatorai.cost_analysis.cost_efficiency_per_week.node","federatorai.cost_analysis.cost_efficiency_per_week.namespace","federatorai.cost_analysis.cost_efficiency_per_month.cluster","federatorai.cost_analysis.cost_efficiency_per_month.node","federatorai.cost_analysis.cost_efficiency_per_month.namespace","federatorai.recommendation.cost_analysis.cost_efficiency_per_day.cluster","federatorai.recommendation.cost_analysis.cost_efficiency_per_day.namespace","federatorai.recommendation.cost_analysis.cost_efficiency_per_week.cluster","federatorai.recommendation.cost_analysis.cost_efficiency_per_week.namespace","federatorai.recommendation.cost_analysis.cost_efficiency_per_month.cluster","federatorai.recommendation.cost_analysis.cost_efficiency_per_month.namespace"] - - ## Dashboard - check_sysdig_dashboard_interval = "$CHECK_SYSDIG_DASHBOARD_INTERVAL" - enable_sysdig_dashboard = $ENABLE_SYSDIG_DASHBOARD - sysdig_dashboards = ["/etc/telegraf/dashboards/sysdig/kafka-overview.json", "/etc/telegraf/dashboards/sysdig/application-overview.json", "/etc/telegraf/dashboards/sysdig/cluster-overview.json"] - - ## Automation - enable_dump_mock_data = false - testing_mode = false - configuration_mock_data_path = "/var/log/mock_server/mock_data/configuration" - datadog_mock_data_path = "/var/log/mock_server/mock_data/datadog" - sysdig_mock_data_path = "/var/log/mock_server/mock_data/sysdig" - prometheus_mock_data_path = "/var/log/mock_server/mock_data/prometheus" - expected_result_path = "/var/log/mock_server/mock_data/expected_result" - test_mode_result_path = "mock_server/mock_data/test_mode_result" - - ## Datadog tag mapping table - # if enable_autodiscover_datadog_cluster_name_tag_key=true, agent uses datadog_default_cluster_tag_key to autodiscover cluster name tag key - # if enable_autodiscover_datadog_cluster_name_tag_key=false, agent uses the cluster name tag key defined in agent.datadog_cluster_tag_mapping. - enable_autodiscover_datadog_cluster_name_tag_key = true - #DD_CLUSTER_NAME_TAG_KEYS is "cluster_name,kube_cluster_name,kube_cluster" by default. - datadog_default_cluster_tag_keys = "$DD_CLUSTER_NAME_TAG_KEYS" - [agent.datadog_cluster_tag_mapping] - # Datadog cluster name tag = [""] - kube_cluster = [] - cluster_name = [] - kube_cluster_name = [] - - ############################# - ### Aggregator Basicstats ### - ############################# - - # Datadog metrics - [[aggregators.basicstats]] - grace = "2m" - period = "1m" - drop_original = true - # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule - traverse_all_rules = false - # By default, data adapter send all the metrics through basicstats - namepass = ["datadog_cluster_collection_done"] - # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator - namedrop = [] - [[aggregators.basicstats.metric]] - groups = ["*"] - measurement_name = "datadog_cluster_collection_done" - aggregation_method = "" - fields = [""] - - ## Openshift Prometheus integration: aggregator ## - [[aggregators.basicstats]] - grace = "2m" - period = "1m" - drop_original = true - # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule - traverse_all_rules = false - # By default, data adapter send all the metrics through basicstats - namepass = ["openshift_prometheus_cluster_collection_done"] - # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator - namedrop = [] - [[aggregators.basicstats.metric]] - groups = ["*"] - measurement_name = "openshift_prometheus_cluster_collection_done" - aggregation_method = "" - fields = [""] - - ## Federation Prometheus/Prometheus integration: aggregator ## - [[aggregators.basicstats]] - grace = "2m" - period = "1m" - drop_original = true - # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule - traverse_all_rules = false - # By default, data adapter send all the metrics through basicstats - namepass = ["prometheus_cluster_collection_done"] - # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator - namedrop = [] - [[aggregators.basicstats.metric]] - groups = ["*"] - measurement_name = "prometheus_cluster_collection_done" - aggregation_method = "" - fields = [""] - - ## Sysdig integration: aggregator ## - [[aggregators.basicstats]] - grace = "2m" - period = "1m" - drop_original = true - # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule - traverse_all_rules = false - # By default, data adapter send all the metrics through basicstats - namepass = ["sysdig_cluster_collection_done"] - # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator - namedrop = [] - [[aggregators.basicstats.metric]] - groups = ["*"] - measurement_name = "sysdig_cluster_collection_done" - aggregation_method = "" - fields = [""] - - ## VMware integration: aggregator ## - [[aggregators.basicstats]] - grace = "5m" - period = "1m" - drop_original = true - # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule - traverse_all_rules = false - # By default, data adapter send all the metrics through basicstats - namepass = ["vmware_cluster_collection_done"] - # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator - namedrop = [] - - [[aggregators.basicstats.metric]] - groups = ["*"] - measurement_name = "vmware_cluster_collection_done" - aggregation_method = "" - fields = [""] - - # AWS Cloudwatch metrics - [[aggregators.basicstats]] - period = "1m" - drop_original = true - # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule - traverse_all_rules = false - # By default, data adapter send all the metrics through basicstats - namepass = ["aws_cloudwatch_cluster_collection_done"] - # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator - namedrop = [] - - [[aggregators.basicstats.metric]] - groups = ["*"] - measurement_name = "aws_cloudwatch_cluster_collection_done" - aggregation_method = "" - fields = [""] - - # Dashboard Datadog metrics - [[aggregators.basicstats]] - period = "1m" - drop_original = true - # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule - traverse_all_rules = false - # By default, data adapter send all the metrics through basicstats - namepass = ["federatorai_datadog_cluster_collection_done"] - # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator - namedrop = [] - - [[aggregators.basicstats.metric]] - groups = ["*"] - measurement_name = "federatorai_datadog_cluster_collection_done" - aggregation_method = "" - fields = [""] - - # Dashboard Sysdig metrics - [[aggregators.basicstats]] - period = "1m" - drop_original = true - # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule - traverse_all_rules = false - # By default, data adapter send all the metrics through basicstats - namepass = ["federatorai_sysdig_cluster_collection_done"] - # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator - namedrop = [] - - [[aggregators.basicstats.metric]] - groups = ["*"] - measurement_name = "federatorai_sysdig_cluster_collection_done" - aggregation_method = "" - fields = [""] - - ################## - ### Processors ### - ################## - - [[processors.filter_out]] - order = 1 - namepass = ["kafka_topic_partition_current_offset", "kafka_consumer_group_current_offset", "node_disk_io_util", "sysdig_kafka_topic_partition_current_offset", "sysdig_kafka_consumergroup_current_offset", "openshift_prometheus_kube_pod_owner", "prometheus_kube_pod_owner", "openshift_prometheus_kube_replicationcontroller_spec_replicas", "openshift_prometheus_kube_replicationcontroller_status_available_replicas", "datadog_node_pod_phase", "datadog_kubernetes_pod_cpu_limit", "datadog_kubernetes_pod_memory_limit", "datadog_kubernetes_pod_cpu_requests", "datadog_kubernetes_pod_memory_requests", "datadog_kubernetes_container_cpu_limit", "datadog_kubernetes_container_memory_limit", "datadog_kubernetes_container_cpu_requests", "datadog_kubernetes_container_memory_requests", "datadog_pod_cpu_request_usage", "datadog_pod_cpu_limit_usage", "datadog_pod_memory_request", "datadog_pod_memory_limit", "sysdig_kube_pod_resource_limits_cpu_cores", "sysdig_kube_pod_resource_limits_memory_bytes", "sysdig_kube_pod_resource_requests_cpu_cores", "sysdig_kube_pod_resource_requests_memory_bytes", "sysdig_pod_cpu_limit_usage", "sysdig_pod_memory_limit", "sysdig_pod_cpu_request_usage", "sysdig_pod_memory_request","sysdig_kube_pod_status_phase"] - [[processors.filter_out.metric]] - measurement_name = "sysdig_kafka_topic_partition_current_offset" - fields = ["kafka_topic_partition_current_offset"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "sysdig_kafka_consumergroup_current_offset" - fields = ["kafka_consumergroup_current_offset"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "kafka_topic_partition_current_offset" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "kafka_consumer_group_current_offset" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "node_disk_io_util" - fields = ["value"] - aggregation_method = "set_max_value" - max_value = 100.0 - [[processors.filter_out.metric]] - measurement_name = "prometheus_kube_pod_owner" - fields = ["owner_name"] - aggregation_method = "trim_last_index" - match_string = "-" - [processors.filter_out.metric.condition] - owner_kind = "ReplicaSet" - [[processors.filter_out.metric]] - measurement_name = "prometheus_kube_pod_owner" - fields = ["owner_name"] - aggregation_method = "trim_last_index" - match_string = "-" - [processors.filter_out.metric.condition] - owner_kind = "ReplicationController" - [[processors.filter_out.metric]] - measurement_name = "openshift_prometheus_kube_pod_owner" - fields = ["owner_name"] - aggregation_method = "trim_last_index" - match_string = "-" - [processors.filter_out.metric.condition] - owner_kind = "ReplicaSet" - [[processors.filter_out.metric]] - measurement_name = "openshift_prometheus_kube_pod_owner" - fields = ["owner_name"] - aggregation_method = "trim_last_index" - match_string = "-" - [processors.filter_out.metric.condition] - owner_kind = "ReplicationController" - [[processors.filter_out.metric]] - measurement_name = "openshift_prometheus_kube_replicationcontroller_spec_replicas" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "openshift_prometheus_kube_replicationcontroller_status_available_replicas" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "openshift_prometheus_kube_replicationcontroller_spec_replicas" - fields = ["replicationcontroller"] - aggregation_method = "trim_last_index" - match_string = "-" - [[processors.filter_out.metric]] - measurement_name = "openshift_prometheus_kube_replicationcontroller_status_available_replicas" - fields = ["replicationcontroller"] - aggregation_method = "trim_last_index" - match_string = "-" - [[processors.filter_out.metric]] - measurement_name = "datadog_node_pod_phase" - fields = ["value"] - aggregation_method = "drop_zero_value" - # Drop Datadog cpu/memory limits/requests - # For metadata(pod, container and kafka_consumer_group) - [[processors.filter_out.metric]] - measurement_name = "datadog_kubernetes_pod_cpu_limit" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "datadog_kubernetes_pod_memory_limit" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "datadog_kubernetes_pod_cpu_requests" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "datadog_kubernetes_pod_memory_requests" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "datadog_kubernetes_container_cpu_limit" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "datadog_kubernetes_container_memory_limit" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "datadog_kubernetes_container_cpu_requests" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "datadog_kubernetes_container_memory_requests" - fields = ["value"] - aggregation_method = "drop_zero_value" - # Drop Datadog cpu/memory limits/requests - # For metrics data(pod_cpu_limit, pod_cpu_request, pod_memory_limit and pod_memory_request) - [[processors.filter_out.metric]] - measurement_name = "datadog_pod_cpu_request_usage" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "datadog_pod_cpu_limit_usage" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "datadog_pod_memory_request" - fields = ["value"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "datadog_pod_memory_limit" - fields = ["value"] - aggregation_method = "drop_zero_value" - # Drop Sysdig cpu/memory limits/requests - # For metadata(pod, container and kafka_consumer_group) - [[processors.filter_out.metric]] - measurement_name = "sysdig_kube_pod_resource_limits_cpu_cores" - fields = ["kubernetes.pod.resourceLimits.cpuCores"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "sysdig_kube_pod_resource_limits_memory_bytes" - fields = ["kubernetes.pod.resourceLimits.memBytes"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "sysdig_kube_pod_resource_requests_cpu_cores" - fields = ["kubernetes.pod.resourceRequests.cpuCores"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "sysdig_kube_pod_resource_requests_memory_bytes" - fields = ["kubernetes.pod.resourceRequests.memBytes"] - aggregation_method = "drop_zero_value" - # Drop Sysdig cpu/memory limits/requests - # For metrics data(pod_cpu_limit, pod_cpu_request, pod_memory_limit and pod_memory_request) - [[processors.filter_out.metric]] - measurement_name = "sysdig_pod_cpu_limit_usage" - fields = ["kubernetes.pod.resourceLimits.cpuCores"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "sysdig_pod_memory_limit" - fields = ["kubernetes.pod.resourceLimits.memBytes"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "sysdig_pod_cpu_request_usage" - fields = ["kubernetes.pod.resourceRequests.cpuCores"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "sysdig_pod_memory_request" - fields = ["kubernetes.pod.resourceRequests.memBytes"] - aggregation_method = "drop_zero_value" - [[processors.filter_out.metric]] - measurement_name = "sysdig_kube_pod_status_phase" - fields = ["kube_pod_status_phase"] - aggregation_method = "drop_zero_value" - - ## Datadog integration: processors - [[processors.metrics_decorator]] - order = 2 - namepass = ["datadog_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/datadog_pre_metric_decorator.json" - - [[processors.metrics_grouping]] - order = 3 - namepass = ["datadog_*", "alameda_*", "aws_cloudwatch_vm", "aws_cloudwatch_cluster_collection_done"] - schema_file = "/etc/telegraf/schema/datadog_grouping_rules.json" - - [[processors.metrics_decorator]] - order = 4 - namepass = ["datadog_namespace_*"] - schema_file = "/etc/telegraf/schema/datadog_post_metric_decorator.json" - - [[processors.schema_mapping]] - order = 5 - datasource = "datadog" - aggregator_processor = true - namepass = ["datadog_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/datadog_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - ## Set default cloud information ifneeded - enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY - default_provider = "$DEFAULT_PROVIDER" - default_region = "$DEFAULT_REGION" - default_instance_type = "$DEFAULT_INSTANCE_TYPE" - default_instance_id = "$DEFAULT_INSTANCE_ID" - default_zone = "$DEFAULT_ZONE" - - ## Openshift Prometheus integration: processors ## - [[processors.metrics_decorator]] - order = 2 - namepass = ["openshift_prometheus_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/openshift_prometheus_pre_metric_decorator.json" - - [[processors.metrics_grouping]] - order = 3 - namepass = ["openshift_prometheus_*", "alameda_*", "aws_cloudwatch_vm", "aws_cloudwatch_cluster_collection_done"] - schema_file = "/etc/telegraf/schema/openshift_prometheus_grouping_rules.json" - - [[processors.metrics_decorator]] - order = 4 - namepass = ["openshift_prometheus_alameda_config_cluster_namespace", "openshift_prometheus_node_cpu_usage_seconds_total", "openshift_prometheus_node_memory_usage_bytes", "openshift_prometheus_kube_node_status_capacity_cpu_cores", "openshift_prometheus_namespace_*"] - schema_file = "/etc/telegraf/schema/openshift_prometheus_post_metric_decorator.json" - - [[processors.schema_mapping]] - order = 5 - datasource = "prometheus" - aggregator_processor = true - namepass = ["openshift_prometheus_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/openshift_prometheus_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - ## Set default cloud information ifneeded - enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY - default_provider = "$DEFAULT_PROVIDER" - default_region = "$DEFAULT_REGION" - default_instance_type = "$DEFAULT_INSTANCE_TYPE" - default_instance_id = "$DEFAULT_INSTANCE_ID" - default_zone = "$DEFAULT_ZONE" - - ## Federation Prometheus/Prometheus integration: processors ## - [[processors.metrics_decorator]] - order = 2 - namepass = ["prometheus_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/prometheus_pre_metric_decorator.json" - - [[processors.metrics_grouping]] - order = 3 - namepass = ["prometheus_*", "alameda_*", "aws_cloudwatch_vm", "aws_cloudwatch_cluster_collection_done"] - schema_file = "/etc/telegraf/schema/prometheus_grouping_rules.json" - - [[processors.metrics_decorator]] - order = 4 - namepass = ["prometheus_alameda_config_cluster_namespace", "prometheus_node_cpu_usage_seconds_total", "prometheus_node_memory_usage_bytes", "prometheus_kube_node_status_capacity_cpu_cores", "prometheus_nginx_http_average_response_time_ms", "prometheus_namespace_*"] - schema_file = "/etc/telegraf/schema/prometheus_post_metric_decorator.json" - - [[processors.schema_mapping]] - order = 5 - datasource = "prometheus" - aggregator_processor = true - namepass = ["prometheus_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/prometheus_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - ## Set default cloud information ifneeded - enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY - default_provider = "$DEFAULT_PROVIDER" - default_region = "$DEFAULT_REGION" - default_instance_type = "$DEFAULT_INSTANCE_TYPE" - default_instance_id = "$DEFAULT_INSTANCE_ID" - default_zone = "$DEFAULT_ZONE" - - ## Sysdig integration: processors ## - [[processors.metrics_decorator]] - order = 2 - namepass = ["sysdig_*", "alameda_*", "federatorai.kafka.consumer_lag", "federatorai.kafka.consumer_offset_rate", "federatorai.kafka.broker_offset_rate", "federatorai.prediction.kafka", "federatorai.recommendation", "federatorai.prediction.controller", "federatorai.prediction.controller.max", "federatorai.prediction.controller.min", "federatorai.prediction.controller.avg", "federatorai.prediction.node", "federatorai.prediction.node.max", "federatorai.prediction.node.min", "federatorai.prediction.node.avg", "federatorai.resource_planning.node", "federatorai.resource_planning.controller", "federatorai.kubernetes.cpu.usage.total.node", "federatorai.kubernetes.cpu.usage.total.controller", "federatorai.kubernetes.memory.usage.node", "federatorai.kubernetes.memory.usage.controller", "federatorai.kubernetes.cpu.usage.total.node_rollup_3600sec", "federatorai.kubernetes.cpu.usage.total.controller_rollup_3600sec", "federatorai.kubernetes.memory.usage.node_rollup_3600sec", "federatorai.kubernetes.memory.usage.controller_rollup_3600sec", "federatorai.kubernetes.cpu.usage.total.node_rollup_21600sec", "federatorai.kubernetes.cpu.usage.total.controller_rollup_21600sec", "federatorai.kubernetes.memory.usage.node_rollup_21600sec", "federatorai.kubernetes.memory.usage.controller_rollup_21600sec", "federatorai.kubernetes.cpu.usage.total.node_rollup_86400sec", "federatorai.kubernetes.cpu.usage.total.controller_rollup_86400sec", "federatorai.kubernetes.memory.usage.node_rollup_86400sec", "federatorai.kubernetes.memory.usage.controller_rollup_86400sec"] - schema_file = "/etc/telegraf/schema/sysdig_pre_metric_decorator.json" - - [[processors.metrics_grouping]] - order = 3 - namepass = ["sysdig_*", "alameda_*", "aws_cloudwatch_vm", "aws_cloudwatch_cluster_collection_done"] - schema_file = "/etc/telegraf/schema/sysdig_grouping_rules.json" - - [[processors.metrics_decorator]] - order = 4 - namepass = ["sysdig_alameda_config_cluster_namespace", "sysdig_namespace_*", "sysdig_kube_container_resource_limits_cpu_cores", "sysdig_kube_container_resource_requests_cpu_cores", "sysdig_alameda_config_namespace_metric_instance_config_info"] - schema_file = "/etc/telegraf/schema/sysdig_post_metric_decorator.json" - - [[processors.schema_mapping]] - order = 5 - datasource = "sysdig" - aggregator_processor = true - namepass = ["sysdig_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/sysdig_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - ## Set default cloud information ifneeded - enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY - default_provider = "$DEFAULT_PROVIDER" - default_region = "$DEFAULT_REGION" - default_instance_type = "$DEFAULT_INSTANCE_TYPE" - default_instance_id = "$DEFAULT_INSTANCE_ID" - default_zone = "$DEFAULT_ZONE" - - ## VMware integration: processors - [[processors.metrics_decorator]] - order = 2 - namepass = ["vmware_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/vmware_pre_metric_decorator.json" - - [[processors.metrics_grouping]] - order = 3 - namepass = ["vmware_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/vmware_grouping_rules.json" - - [[processors.metrics_decorator]] - order = 4 - namepass = [""] - schema_file = "/etc/telegraf/schema/vmware_post_metric_decorator.json" - - [[processors.schema_mapping]] - order = 5 - datasource = "vmware" - aggregator_processor = true - namepass = ["vmware_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/vmware_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - ## Set default cloud information ifneeded - enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY - default_provider = "$DEFAULT_PROVIDER" - default_region = "$DEFAULT_REGION" - default_instance_type = "$DEFAULT_INSTANCE_TYPE" - default_instance_id = "$DEFAULT_INSTANCE_ID" - default_zone = "$DEFAULT_ZONE" - - ## AWS Cloudwatch integration: processors - [[processors.metrics_decorator]] - order = 2 - namepass = ["aws_cloudwatch_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/aws_pre_metric_decorator.json" - - [[processors.metrics_grouping]] - order = 3 - namepass = ["aws_cloudwatch_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/aws_grouping_rules.json" - - [[processors.metrics_decorator]] - order = 4 - namepass = ["aws_cloudwatch_alameda_config_cluster_vm", "aws_cloudwatch_node_group_*"] - schema_file = "/etc/telegraf/schema/aws_post_metric_decorator.json" - - [[processors.schema_mapping]] - order = 5 - datasource = "aws" - aggregator_processor = true - namepass = ["aws_cloudwatch_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/aws_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - ## Set default cloud information ifneeded - enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY - default_provider = "$DEFAULT_PROVIDER" - default_region = "$DEFAULT_REGION" - default_instance_type = "$DEFAULT_INSTANCE_TYPE" - default_instance_id = "$DEFAULT_INSTANCE_ID" - default_zone = "$DEFAULT_ZONE" - - ## Datadog Dashboard integration: processors - [[processors.metrics_decorator]] - order = 2 - namepass = ["federatorai_datadog_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/federatorai_datadog_pre_metric_decorator.json" - - [[processors.metrics_grouping]] - order = 3 - namepass = ["federatorai_datadog_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/federatorai_datadog_grouping_rules.json" - - [[processors.metrics_decorator]] - order = 4 - namepass = ["federatorai_datadog_*"] - schema_file = "/etc/telegraf/schema/federatorai_datadog_post_metric_decorator.json" - - [[processors.schema_mapping]] - order = 5 - datasource = "datadog" - aggregator_processor = true - namepass = ["federatorai_datadog_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/federatorai_datadog_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - ## Set default cloud information ifneeded - enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY - default_provider = "$DEFAULT_PROVIDER" - default_region = "$DEFAULT_REGION" - default_instance_type = "$DEFAULT_INSTANCE_TYPE" - default_instance_id = "$DEFAULT_INSTANCE_ID" - default_zone = "$DEFAULT_ZONE" - - ## Sysdig Dashboard integration: processors - [[processors.metrics_decorator]] - order = 2 - namepass = ["federatorai_sysdig_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/federatorai_sysdig_pre_metric_decorator.json" - - [[processors.metrics_grouping]] - order = 3 - namepass = ["federatorai_sysdig_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/federatorai_sysdig_grouping_rules.json" - - [[processors.metrics_decorator]] - order = 4 - namepass = ["federatorai_sysdig_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/federatorai_sysdig_post_metric_decorator.json" - - [[processors.schema_mapping]] - order = 5 - datasource = "sysdig" - aggregator_processor = true - namepass = ["federatorai_sysdig_*", "alameda_*"] - schema_file = "/etc/telegraf/schema/federatorai_sysdig_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - ## Set default cloud information ifneeded - enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY - default_provider = "$DEFAULT_PROVIDER" - default_region = "$DEFAULT_REGION" - default_instance_type = "$DEFAULT_INSTANCE_TYPE" - default_instance_id = "$DEFAULT_INSTANCE_ID" - default_zone = "$DEFAULT_ZONE" - - ############################## - ### Aggregator Federatorai ### - ############################## - - [[aggregators.federatorai]] - period = "1m" - drop_original = true - concurrent_job = 3 - schema_file = "/etc/telegraf/schema/basic_aggregator_schema.json" - namepass = [""] - - ## Datadog metrics ## - [[aggregators.federatorai]] - grace = "2m" - period = "1m" - drop_original = true - concurrent_job = 3 - schema_file = "/etc/telegraf/schema/datadog_aggregator_schema.json" - namepass = ["datadog_*"] - - ## Openshift Prometheus integration: aggregator ## - [[aggregators.federatorai]] - grace = "2m" - period = "1m" - drop_original = true - concurrent_job = 3 - schema_file = "/etc/telegraf/schema/openshift_prometheus_aggregator_schema.json" - namepass = ["openshift_prometheus_*"] - - ## Federation Prometheus/Prometheus integration: aggregator ## - [[aggregators.federatorai]] - grace = "2m" - period = "1m" - drop_original = true - concurrent_job = 3 - schema_file = "/etc/telegraf/schema/prometheus_aggregator_schema.json" - namepass = ["prometheus_*"] - - ## Sysdig integration: aggregator ## - [[aggregators.federatorai]] - grace = "2m" - period = "1m" - drop_original = true - concurrent_job = 3 - schema_file = "/etc/telegraf/schema/sysdig_aggregator_schema.json" - namepass = ["sysdig_*"] - - ## VMware integration: aggregator ## - [[aggregators.federatorai]] - grace = "5m" - period = "1m" - drop_original = true - concurrent_job = 3 - schema_file = "/etc/telegraf/schema/vmware_aggregator_schema.json" - namepass = ["vmware_*"] - - ## AWS Cloudwatch metrics ## - [[aggregators.federatorai]] - grace = "1m" - period = "1m" - drop_original = true - concurrent_job = 3 - schema_file = "/etc/telegraf/schema/aws_aggregator_schema.json" - namepass = ["aws_cloudwatch_*"] - - ## Federatorai Metrics - Datadog metrics ## - [[aggregators.federatorai]] - grace = "1m" - period = "1m" - drop_original = true - concurrent_job = 3 - schema_file = "/etc/telegraf/schema/federatorai_datadog_aggregator_schema.json" - namepass = ["federatorai_datadog_*"] - - ## Federatorai Metrics - Sysdig metrics ## - [[aggregators.federatorai]] - grace = "1m" - period = "1m" - drop_original = true - concurrent_job = 3 - schema_file = "/etc/telegraf/schema/federatorai_sysdig_aggregator_schema.json" - namepass = ["federatorai_sysdig_*"] - - ############################ - ### Input/Output Plugins ### - ############################ - - [[outputs.datadog]] - User-Agent = "Federator.ai/4.2" - kafka_dashboards = ["/etc/telegraf/dashboards/datadog/kafka/overview.json"] - general_dashboards = ["/etc/telegraf/dashboards/datadog/kubernetes/application-overview.json", "/etc/telegraf/dashboards/datadog/kubernetes/cluster-overview.json", "/etc/telegraf/dashboards/datadog/cost/cost-analysis-overview.json", "/etc/telegraf/dashboards/datadog/cost/cost-management-cluster-overview.json", "/etc/telegraf/dashboards/datadog/cost/cost-management-node-overview.json", "/etc/telegraf/dashboards/datadog/cost/cost-management-namespace-overview.json"] - enable_kafka_dashboard = $ENABLE_DD_DASHBOARD - enable_general_dashboard = $ENABLE_DD_DASHBOARD - namepass = ["federatorai_datadog_*"] - namedrop= ["federatorai_datadog_cluster_collection_done"] - metric_prefix = "federatorai_datadog_" - - [[outputs.datadog.clusters]] - cluster_name = "cluster" - user_agent = "Federatorai/5.0" - api_key = "$DATADOG_API_KEY" - application_key = "$DATADOG_APPLICATION_KEY" - url = "https://api.datadoghq.com/api/v1/series" - rest_url = "https://api.datadoghq.com/api/v1" - - # This pattern support federatorai.integration.status, federatorai.recommendation and federatorai.prediction.* - [[outputs.datadog.integration_metrics]] - name="federatorai.*" - aggregation_type="raw" - - ## Alameda Configuration: inputs.data_collector ## - [[inputs.data_collector]] - query_start_time_offset = "-1m" - query_end_time_offset = "0h" #Support s(second),m(minute),h(hour) - collection_jitter = "0s" - ## data source type from which to query data - ## accept values: alameda_datahub - source = "alameda_datahub" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = true - overwrite_query_delay_interval = true - delay_query_interval = "1s" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/alameda_config_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Openshift Prometheus integration: inputs.data_collector ## - [[inputs.data_collector]] - query_start_time_offset = "-1m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: prometheus - source = "prometheus" - ## which collector to handle the data collection - collector = "prometheus" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "http://prometheus-prometheus-oper-prometheus.default.svc:9090" - ## metrics schema path - metric_path = ["/etc/telegraf/schema/openshift_prometheus_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - controller_name = [] - node_uids = [] - group_names = [] - - ## Federation Prometheus integration: inputs.data_collector ## - [[inputs.data_collector]] - query_start_time_offset = "-1m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: prometheus - source = "prometheus" - ## which collector to handle the data collection - collector = "prometheus" - ## account name - account = "" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "http://prometheus-prometheus-oper-prometheus.default.svc:9090" - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federation_prometheus_metrics.json"] - target_label = "clusterID: cluster1" - cluster_name = "default" - discover_path = "" - controller_name = [] - node_uids = [] - group_names = [] - - ## Rancher Prometheus integration: inputs.data_collector ## - [[inputs.data_collector]] - query_start_time_offset = "-1m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: prometheus - source = "prometheus" - ## which collector to handle the data collection - collector = "prometheus" - ## account name - account = "" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "http://prometheus-prometheus-oper-prometheus.default.svc:9090" - ## metrics schema path - metric_path = ["/etc/telegraf/schema/rancher_prometheus_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - controller_name = [] - node_uids = [] - group_names = [] - - ## Prometheus integration: inputs.data_collector ## - [[inputs.data_collector]] - query_start_time_offset = "-1m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: prometheus - source = "prometheus" - ## which collector to handle the data collection - collector = "prometheus" - ## account name - account = "" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "http://prometheus-prometheus-oper-prometheus.default.svc:9090" - ## metrics schema path - metric_path = ["/etc/telegraf/schema/prometheus_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - controller_name = [] - node_uids = [] - group_names = [] - - ## Datadog integration: inputs.data_collector - [[inputs.data_collector]] - query_start_time_offset = "-1m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: prometheus, datadog, sysdig - source = "datadog" - ## which collector to handle the data collection - collector = "datadog" - ## authenticated token path - token= "${DD-API-KEY}" - application_key = "${DD-APPLICATION-KEY}" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "https://api.datadoghq.com/api/v1/query" - ## metrics schema path - metric_path = ["/etc/telegraf/schema/datadog_metrics.json"] - cluster_name = "default" - - ## Sysdig integration: inputs.data_collector ## - [[inputs.data_collector]] - query_start_time_offset = "-1m" - query_end_time_offset = "0m" - ## data source type from which to query data - ## accept values: sysdig - source = "sysdig" - ## which collector to handle the data collection - collector = "sysdig" - ## account name - account = "" - ## authenticated token path - token= "${SYSDIG_API_TOKEN}" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "${SYSDIG_API_URL}/data/batch" - ## Set batch query parameters - max_query_per_chunk = $DATADOG_MAX_QUERY_PER_CHUNK - max_characters_per_chunk = $DATADOG_MAX_CHAR_PER_CHUNK - ## metrics schema path - metric_path = ["/etc/telegraf/schema/sysdig_metrics.json"] - target_label = "" - cluster_name = "${CLUSTER_NAME}" - discover_path = "" - controller_name = [] - node_uids = [] - group_names = [] - - ## VMware integration: inputs.data_collector ## - # This plugin is for list vm in one minute - [[inputs.data_collector]] - query_start_time_offset = "-1m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: vmware - source = "vmware" - ## which collector to handle the data collection - collector = "vmware" - ## account name - account = "" - ## authenticated token path - token= "" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "${VMWARE_API_URL}" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/vmware_list_metrics.json"] - target_label = "" - cluster_name = "${CLUSTER_NAME}" - discover_path = "" - controller_name = [] - node_uids = [] - group_names = [] - - ## VMware integration: inputs.data_collector ## - [[inputs.data_collector]] - interval = "5m" - query_start_time_offset = "-5m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: vmware - source = "vmware" - ## which collector to handle the data collection - collector = "vmware" - ## account name - account = "" - ## authenticated token path - token= "" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "${VMWARE_API_URL}" - ## metrics schema path - metric_path = ["/etc/telegraf/schema/vmware_metrics.json"] - target_label = "" - cluster_name = "${CLUSTER_NAME}" - discover_path = "" - controller_name = [] - node_uids = [] - group_names = [] - - ## AWS Cloudwatch integration: inputs.data_collector - # This plugin is for list vm in one minute - [[inputs.data_collector]] - query_start_time_offset = "-1m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: vmware - source = "aws" - ## which collector to handle the data collection - collector = "aws" - ## account name - account = "" - ## authenticated token path - token= "" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/aws_list_metrics.json"] - cluster_name = "${CLUSTER_NAME}" - discover_path = "" - controller_name = [] - node_uids = [] - group_names = [] - - ## AWS Cloudwatch integration: inputs.data_collector - [[inputs.data_collector]] - interval = "5m" - query_start_time_offset = "-10m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: vmware - source = "aws" - ## which collector to handle the data collection - collector = "aws" - ## account name - account = "" - ## authenticated token path - token= "" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## one URL from which to read formatted metrics - url = "" - ## metrics schema path - metric_path = ["/etc/telegraf/schema/aws_metrics.json"] - cluster_name = "${CLUSTER_NAME}" - discover_path = "" - controller_name = [] - node_uids = [] - group_names = [] - - ### Federatorai Metrics ### - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "3m" - use_query_timestamp = true - query_start_time_offset = "-3m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "10s" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_3_mins_aggregation_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Sysdig : inputs.data_collector ## - [[inputs.data_collector]] - interval = "3m" - use_query_timestamp = true - query_start_time_offset = "-3m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: alameda_datahub - source = "sysdig" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "10s" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_previous_3_mins_aggregation_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_1H" - use_query_timestamp = false - query_start_time_offset = "-23h59m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = [ - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_1_day_cost_metrics_3600s.json" - ] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_1H" - use_query_timestamp = true - query_start_time_offset = "-59m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = [ - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_1_hour_aggregation_metrics.json", - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_1_hour_cost_metrics_3600s.json" - ] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Sysdig : inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_1H" - use_query_timestamp = true - query_start_time_offset = "-59m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "sysdig" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_previous_1_hour_aggregation_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_1H" - use_query_timestamp = false - query_start_time_offset = "-167h59m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = [ - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_7_days_cost_metrics_21600s.json" - ] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_6H" - use_query_timestamp = true - query_start_time_offset = "-5h59m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = [ - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_6_hours_aggregation_metrics.json", - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_6_hours_cost_metrics_21600s.json" - ] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Sysdig : inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_6H" - use_query_timestamp = true - query_start_time_offset = "-5h59m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "sysdig" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_previous_6_hours_aggregation_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_1H" - use_query_timestamp = false - query_start_time_offset = "-719h59m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = [ - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_30_days_cost_metrics_86400s.json" - ] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_24H" - use_query_timestamp = true - query_start_time_offset = "-23h59m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = [ - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_24_hours_aggregation_metrics.json", - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_24_hours_cost_metrics_86400s.json" - ] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Sysdig : inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_24H" - use_query_timestamp = true - query_start_time_offset = "-23h59m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "sysdig" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_previous_24_hours_aggregation_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_1H" - use_query_timestamp = false - query_start_time_offset = "1m" - query_end_time_offset = "24h" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = [ - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_1_day_aggregation_metrics.json", - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_1_day_cost_metrics_3600s.json", - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_1_day_planning_metrics_3600s.json" - ] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Sysdig : inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_1H" - use_query_timestamp = false - query_start_time_offset = "1m" - query_end_time_offset = "24h" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "sysdig" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_next_1_day_aggregation_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_6H" - use_query_timestamp = false - query_start_time_offset = "1m" - query_end_time_offset = "168h" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = [ - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_7_days_aggregation_metrics.json" - ] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_1H" - use_query_timestamp = false - query_start_time_offset = "1m" - query_end_time_offset = "168h" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = [ - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_7_days_cost_metrics_21600s.json", - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_7_days_planning_metrics_21600s.json" - ] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Sysdig : inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_6H" - use_query_timestamp = false - query_start_time_offset = "1m" - query_end_time_offset = "168h" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "sysdig" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_next_7_days_aggregation_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_24H" - use_query_timestamp = false - query_start_time_offset = "1m" - query_end_time_offset = "720h" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = [ - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_30_days_aggregation_metrics.json" - ] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_1H" - use_query_timestamp = false - query_start_time_offset = "1m" - query_end_time_offset = "720h" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = [ - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_30_days_cost_metrics_86400s.json", - "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_30_days_planning_metrics_86400s.json" - ] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Sysdig : inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_24H" - use_query_timestamp = false - query_start_time_offset = "1m" - query_end_time_offset = "720h" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "sysdig" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_next_30_days_aggregation_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "1m" - use_query_timestamp = true - query_start_time_offset = "-1m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "10s" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_1_min_prediction_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Sysdig : inputs.data_collector ## - [[inputs.data_collector]] - interval = "1m" - use_query_timestamp = true - query_start_time_offset = "-1m" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: alameda_datahub - source = "sysdig" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "10s" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_previous_1_min_prediction_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "1m" - use_query_timestamp = true - query_start_time_offset = "-2m" - query_end_time_offset = "-1m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "10s" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_2_mins_observation_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Sysdig : inputs.data_collector ## - [[inputs.data_collector]] - interval = "1m" - use_query_timestamp = true - query_start_time_offset = "-2m" - query_end_time_offset = "-1m" #Support s(second),m(minute),h(hour) - ## data source type from which to query data - ## accept values: alameda_datahub - source = "sysdig" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "10s" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_previous_2_mins_observation_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_1H" - use_query_timestamp = false - query_start_time_offset = "720h1m" - query_end_time_offset = "744h" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_30_days_recommendation_instance.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_1H" - use_query_timestamp = false - query_start_time_offset = "-48h" - query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_2_days_aggregation_cost_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ## Federatorai Metrics - Datadog: inputs.data_collector ## - [[inputs.data_collector]] - interval = "$COLLECTION_INTERVAL_1H" - use_query_timestamp = false - query_start_time_offset = "1m" - query_end_time_offset = "720h" #Support s(second),m(minute),h(hour) - retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" - max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES - ## data source type from which to query data - ## accept values: alameda_datahub - source = "datadog" - ## which collector to handle the data collection - collector = "alameda_datahub" - ## authenticated token path - token= "/var/run/secrets/kubernetes.io/serviceaccount/token" - ## TLS Insecure skip verify - insecure_skip_verify = true - ## Alameda Read Configuration used - configuration_only = false - overwrite_query_delay_interval = true - delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" - ## one URL from which to read formatted metrics - url = "" - ## Load metric instance configs from Datahub or not - skip_metric_instance_configs = true - ## metrics schema path - metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_30_days_aggregation_cost_metrics.json"] - target_label = "" - cluster_name = "default" - discover_path = "" - node_uids = [] - group_names = [] - - ### Sync database metadata - #[[outputs.alameda_datahub]] - # namedrop = ["*"] - # enable_sync_metadata = true - # sync_metadata_schema_file = "/etc/telegraf/schema/sync_metadata_schema.json" - - ## Openshift Prometheus integration: outputs.alameda_datahub ## - [[outputs.alameda_datahub]] - namepass = ["openshift_prometheus_*"] - metric_prefix = "openshift_prometheus_" - datasource = "prometheus" - concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB - schema_file = "/etc/telegraf/schema/datahub_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - - ## Federation Prometheus/Prometheus integration: outputs.alameda_datahub ## - [[outputs.alameda_datahub]] - namepass = ["prometheus_*"] - metric_prefix = "prometheus_" - datasource = "prometheus" - concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB - schema_file = "/etc/telegraf/schema/datahub_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - - ## Sysdig integration: outputs.alameda_datahub ## - [[outputs.alameda_datahub]] - namepass = ["sysdig_*"] - metric_prefix = "sysdig_" - datasource = "sysdig" - concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB - schema_file = "/etc/telegraf/schema/datahub_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - - ## Datadog integration: outputs.alameda_datahub ## - [[outputs.alameda_datahub]] - namepass = ["datadog_*"] - metric_prefix = "datadog_" - datasource = "datadog" - concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB - schema_file = "/etc/telegraf/schema/datahub_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - - ## VMware integration: outputs.alameda_datahub ## - [[outputs.alameda_datahub]] - namepass = ["vmware_*"] - metric_prefix = "vmware_" - datasource = "vmware" - concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB - schema_file = "/etc/telegraf/schema/datahub_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - - ## AWS Cloudwatch integration: outputs.alameda_datahub - [[outputs.alameda_datahub]] - namepass = ["aws_cloudwatch_*"] - metric_prefix = "aws_cloudwatch_" - datasource = "aws" - concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB - schema_file = "/etc/telegraf/schema/datahub_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - - ## Post Datahub event - [[outputs.alameda_datahub]] - namepass = ["datahub_event"] - metric_prefix = "datahub_" - post_event_interval = "$POST_EVENT_INTERVAL" - schema_file = "/etc/telegraf/schema/datahub_schema.json" - cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" - - [[outputs.prometheus_client]] - namepass = ["federatorai_sysdig_*"] - collectors_exclude = ["gocollector", "process"] - export_all_metrics = true - ## Address to listen on - listen = ":8080" - ## Path to publish the metrics on. - path = "/metrics" - metric_prefix = "federatorai_sysdig_" - expiration_interval = "5m" - - ## Test only: export DA's Prometheus metrics for automation tests - [[outputs.prometheus_client]] - namepass = ["prometheus_*"] - collectors_exclude = ["gocollector", "process"] - enable_default_value = ["prometheus_cluster", "prometheus_node", "prometheus_application", "prometheus_namespace", "prometheus_controller", "prometheus_pod", "prometheus_container", "prometheus_kafka_topic", "prometheus_kafka_consumer_group", "prometheus_nginx_web_service"] - default_value = -1 - export_all_metrics = true - ## Address to listen on - listen = ":8081" - ## Path to publish the metrics on. - path = "/test-metrics" - metric_prefix = "" - expiration_interval = "5m" - - ## Test only: export DA's Datadog metrics for automation tests - [[outputs.prometheus_client]] - namepass = ["datadog_*", "federatorai_datadog_*"] - collectors_exclude = ["gocollector", "process"] - enable_default_value = ["datadog_cluster", "datadog_node", "datadog_application", "datadog_namespace", "datadog_controller", "datadog_pod", "datadog_container", "datadog_kafka_topic", "datadog_kafka_consumer_group", "datadog_nginx_web_service"] - default_value = -1 - export_all_metrics = true - ## Address to listen on - listen = ":8082" - ## Path to publish the metrics on. - path = "/test-metrics" - metric_prefix = "federatorai_datadog_" - expiration_interval = "5m" - - ## Test only: export DA's Sysdig metrics for automation tests - [[outputs.prometheus_client]] - namepass = ["sysdig_*", "federatorai_sysdig_*"] - collectors_exclude = ["gocollector", "process"] - enable_default_value = ["sysdig_cluster", "sysdig_node", "sysdig_application", "sysdig_namespace", "sysdig_controller", "sysdig_pod", "sysdig_container", "sysdig_kafka_topic", "sysdig_kafka_consumer_group", "sysdig_nginx_web_service"] - default_value = -1 - export_all_metrics = true - ## Address to listen on - listen = ":8083" - ## Path to publish the metrics on. - path = "/test-metrics" - metric_prefix = "federatorai_sysdig_" - expiration_interval = "5m" + telegraf.conf: |+ + [global_tags] + + [agent] + interval = "1m" + ## DA will try to reload user configuration periodically + # configuration_reload_interval = "1h", DA will reload user configuration every hour + # configuration_reload_interval = "0s", DA will disabled this feature. And DA only reload user configuration when receiving configuration change notification + configuration_reload_interval = "$CONFIGURATION_RELOAD_INTERVAL" + delay_query_interval = "$DELAY_QUERY_INTERVAL" + round_interval = true + metric_batch_size = 100000 + metric_buffer_limit = 100000 + collection_jitter = "5s" + flush_interval = "20s" + flush_jitter = "0s" + precision = "1us" + debug = $DEBUG + aggregator_queue = 200000 + max_rpc_receive_size = $MAX_RPC_RECEIVE_SIZE + logfile = "/var/log/telegraf.log" + logfile_rotation_interval = "1d" + logfile_rotation_max_archives = 10 + logfile_rotation_max_size = "200MB" + logfile_compress_archives = true + logfile_total_max_size = "$FEDERATORAI_MAXIMUM_LOG_SIZE" + logfile_queue_size = $MAX_LOG_QUEUE_SIZE + logfile_queue_trace_interval = "$LOG_QUEUE_TRACE_INTERVAL" + logfile_enabled_async_logger = $ENABLED_ASYNC_LOGGER + ## Data adapter will flush log queue to console if queue is full + enable_logfile_flush_to_console = $ENABLE_FLUSH_LOG_TO_CONSOLE + logfile_flush_to_console_level = "$LOG_FLUSH_TO_CONSOLE_LEVEL" + ## Query will retry if some metrics hasn't returned yet. + max_retry = 1 + retry_interval = "10s" + max_request_line = $MAX_REQUEST_LINE + sysdig_max_char_per_chunk = $SYSDIG_MAX_CHAR_PER_CHUNK + # sysdig_max_query_per_chunk accepted value [1-20], default value is 10 if not setted + sysdig_max_query_per_chunk = $SYSDIG_MAX_QUERY_PER_CHUNK + quiet = false + hostname = "" + omit_hostname = false + alamedascaler_enable = true + enable_historical_data_collection = false + force_reload_configuration = false + fed_rest_url = "$FED_REST_URL" + fed_rest_port = "$FED_REST_PORT" + datahub_url = "$DATAHUB_URL" + datahub_port = "$DATAHUB_PORT" + rabbitmq_url = "$RABBITMQ_URL" + rabbitmq_port = "$RABBITMQ_PORT" + rabbitmq_subscriber = "data_adapter" + expired_time = "$DATA_EXPIRED_TIME" + event_cache_expired_time = "$POST_EVENT_INTERVAL" + + ## set collect_metadata_only=false to collect resource metadata and metrics + ## set collect_metadata_only=true to only collect resource metadata + collect_metadata_only = $COLLECT_METADATA_ONLY + + aws_metric_list = "$AWS_METRIC_LIST" + drop_duplicated_rest_api = true + force_send_rest_api_time = "1h" + + # Default disable integration metrics setting + # Cost Analysis related metrics + cost_analysis_metrics = ["federatorai.cost_analysis.instance.cost","federatorai.cost_analysis.namespace.cost","federatorai.prediction.namespace.cost","federatorai.recommendation.instance","federatorai.cost_analysis.resource_alloc_cost.cluster","federatorai.cost_analysis.resource_alloc_cost.node","federatorai.cost_analysis.resource_alloc_cost.namespace","federatorai.cost_analysis.resource_usage_cost.cluster","federatorai.cost_analysis.resource_usage_cost.node","federatorai.cost_analysis.resource_usage_cost.namespace","federatorai.cost_analysis.cost_per_day.cluster","federatorai.cost_analysis.cost_per_day.node","federatorai.cost_analysis.cost_per_day.namespace","federatorai.cost_analysis.cost_per_week.cluster","federatorai.cost_analysis.cost_per_week.node","federatorai.cost_analysis.cost_per_week.namespace","federatorai.cost_analysis.cost_per_month.cluster","federatorai.cost_analysis.cost_per_month.node","federatorai.cost_analysis.cost_per_month.namespace","federatorai.recommendation.cost_analysis.cost_per_day.cluster","federatorai.recommendation.cost_analysis.cost_per_day.node","federatorai.recommendation.cost_analysis.cost_per_day.namespace","federatorai.recommendation.cost_analysis.cost_per_week.cluster","federatorai.recommendation.cost_analysis.cost_per_week.node","federatorai.recommendation.cost_analysis.cost_per_week.namespace","federatorai.recommendation.cost_analysis.cost_per_month.cluster","federatorai.recommendation.cost_analysis.cost_per_month.node","federatorai.recommendation.cost_analysis.cost_per_month.namespace","federatorai.cost_analysis.cost_efficiency_per_day.cluster","federatorai.cost_analysis.cost_efficiency_per_day.node","federatorai.cost_analysis.cost_efficiency_per_day.namespace","federatorai.cost_analysis.cost_efficiency_per_week.cluster","federatorai.cost_analysis.cost_efficiency_per_week.node","federatorai.cost_analysis.cost_efficiency_per_week.namespace","federatorai.cost_analysis.cost_efficiency_per_month.cluster","federatorai.cost_analysis.cost_efficiency_per_month.node","federatorai.cost_analysis.cost_efficiency_per_month.namespace","federatorai.recommendation.cost_analysis.cost_efficiency_per_day.cluster","federatorai.recommendation.cost_analysis.cost_efficiency_per_day.namespace","federatorai.recommendation.cost_analysis.cost_efficiency_per_week.cluster","federatorai.recommendation.cost_analysis.cost_efficiency_per_week.namespace","federatorai.recommendation.cost_analysis.cost_efficiency_per_month.cluster","federatorai.recommendation.cost_analysis.cost_efficiency_per_month.namespace"] + + ## Dashboard + check_sysdig_dashboard_interval = "$CHECK_SYSDIG_DASHBOARD_INTERVAL" + enable_sysdig_dashboard = $ENABLE_SYSDIG_DASHBOARD + sysdig_dashboards = ["/etc/telegraf/dashboards/sysdig/kafka-overview.json", "/etc/telegraf/dashboards/sysdig/application-overview.json", "/etc/telegraf/dashboards/sysdig/cluster-overview.json"] + + ## Automation + enable_dump_mock_data = false + testing_mode = false + configuration_mock_data_path = "/var/log/mock_server/mock_data/configuration" + datadog_mock_data_path = "/var/log/mock_server/mock_data/datadog" + sysdig_mock_data_path = "/var/log/mock_server/mock_data/sysdig" + prometheus_mock_data_path = "/var/log/mock_server/mock_data/prometheus" + expected_result_path = "/var/log/mock_server/mock_data/expected_result" + test_mode_result_path = "mock_server/mock_data/test_mode_result" + + ## Datadog tag mapping table + # if enable_autodiscover_datadog_cluster_name_tag_key=true, agent uses datadog_default_cluster_tag_key to autodiscover cluster name tag key + # if enable_autodiscover_datadog_cluster_name_tag_key=false, agent uses the cluster name tag key defined in agent.datadog_cluster_tag_mapping. + enable_autodiscover_datadog_cluster_name_tag_key = true + #DD_CLUSTER_NAME_TAG_KEYS is "cluster_name,kube_cluster_name,kube_cluster" by default. + datadog_default_cluster_tag_keys = "$DD_CLUSTER_NAME_TAG_KEYS" + [agent.datadog_cluster_tag_mapping] + # Datadog cluster name tag = [""] + kube_cluster = [] + cluster_name = [] + kube_cluster_name = [] + + ############################# + ### Aggregator Basicstats ### + ############################# + + # Datadog metrics + [[aggregators.basicstats]] + grace = "2m" + period = "1m" + drop_original = true + # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule + traverse_all_rules = false + # By default, data adapter send all the metrics through basicstats + namepass = ["datadog_cluster_collection_done"] + # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator + namedrop = [] + [[aggregators.basicstats.metric]] + groups = ["*"] + measurement_name = "datadog_cluster_collection_done" + aggregation_method = "" + fields = [""] + + ## Openshift Prometheus integration: aggregator ## + [[aggregators.basicstats]] + grace = "2m" + period = "1m" + drop_original = true + # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule + traverse_all_rules = false + # By default, data adapter send all the metrics through basicstats + namepass = ["openshift_prometheus_cluster_collection_done"] + # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator + namedrop = [] + [[aggregators.basicstats.metric]] + groups = ["*"] + measurement_name = "openshift_prometheus_cluster_collection_done" + aggregation_method = "" + fields = [""] + + ## Federation Prometheus/Prometheus integration: aggregator ## + [[aggregators.basicstats]] + grace = "2m" + period = "1m" + drop_original = true + # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule + traverse_all_rules = false + # By default, data adapter send all the metrics through basicstats + namepass = ["prometheus_cluster_collection_done"] + # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator + namedrop = [] + [[aggregators.basicstats.metric]] + groups = ["*"] + measurement_name = "prometheus_cluster_collection_done" + aggregation_method = "" + fields = [""] + + ## Sysdig integration: aggregator ## + [[aggregators.basicstats]] + grace = "2m" + period = "1m" + drop_original = true + # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule + traverse_all_rules = false + # By default, data adapter send all the metrics through basicstats + namepass = ["sysdig_cluster_collection_done"] + # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator + namedrop = [] + [[aggregators.basicstats.metric]] + groups = ["*"] + measurement_name = "sysdig_cluster_collection_done" + aggregation_method = "" + fields = [""] + + ## VMware integration: aggregator ## + [[aggregators.basicstats]] + grace = "5m" + period = "1m" + drop_original = true + # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule + traverse_all_rules = false + # By default, data adapter send all the metrics through basicstats + namepass = ["vmware_cluster_collection_done"] + # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator + namedrop = [] + + [[aggregators.basicstats.metric]] + groups = ["*"] + measurement_name = "vmware_cluster_collection_done" + aggregation_method = "" + fields = [""] + + # AWS Cloudwatch metrics + [[aggregators.basicstats]] + period = "1m" + drop_original = true + # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule + traverse_all_rules = false + # By default, data adapter send all the metrics through basicstats + namepass = ["aws_cloudwatch_cluster_collection_done"] + # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator + namedrop = [] + + [[aggregators.basicstats.metric]] + groups = ["*"] + measurement_name = "aws_cloudwatch_cluster_collection_done" + aggregation_method = "" + fields = [""] + + # Dashboard Datadog metrics + [[aggregators.basicstats]] + period = "1m" + drop_original = true + # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule + traverse_all_rules = false + # By default, data adapter send all the metrics through basicstats + namepass = ["federatorai_datadog_cluster_collection_done"] + # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator + namedrop = [] + + [[aggregators.basicstats.metric]] + groups = ["*"] + measurement_name = "federatorai_datadog_cluster_collection_done" + aggregation_method = "" + fields = [""] + + # Dashboard Sysdig metrics + [[aggregators.basicstats]] + period = "1m" + drop_original = true + # Set traverse_all_rules to true if we want to generate more than one metrics from different aggreagtor rule + traverse_all_rules = false + # By default, data adapter send all the metrics through basicstats + namepass = ["federatorai_sysdig_cluster_collection_done"] + # Add the metric name to namedrop if data adapter aggregate the metrics in other aggregator + namedrop = [] + + [[aggregators.basicstats.metric]] + groups = ["*"] + measurement_name = "federatorai_sysdig_cluster_collection_done" + aggregation_method = "" + fields = [""] + + ################## + ### Processors ### + ################## + + [[processors.filter_out]] + order = 1 + namepass = ["kafka_topic_partition_current_offset", "kafka_consumer_group_current_offset", "node_disk_io_util", "sysdig_kafka_topic_partition_current_offset", "sysdig_kafka_consumergroup_current_offset", "openshift_prometheus_kube_pod_owner", "prometheus_kube_pod_owner", "openshift_prometheus_kube_replicationcontroller_spec_replicas", "openshift_prometheus_kube_replicationcontroller_status_available_replicas", "datadog_node_pod_phase", "datadog_kubernetes_pod_cpu_limit", "datadog_kubernetes_pod_memory_limit", "datadog_kubernetes_pod_cpu_requests", "datadog_kubernetes_pod_memory_requests", "datadog_kubernetes_container_cpu_limit", "datadog_kubernetes_container_memory_limit", "datadog_kubernetes_container_cpu_requests", "datadog_kubernetes_container_memory_requests", "datadog_pod_cpu_request_usage", "datadog_pod_cpu_limit_usage", "datadog_pod_memory_request", "datadog_pod_memory_limit", "sysdig_kube_pod_resource_limits_cpu_cores", "sysdig_kube_pod_resource_limits_memory_bytes", "sysdig_kube_pod_resource_requests_cpu_cores", "sysdig_kube_pod_resource_requests_memory_bytes", "sysdig_pod_cpu_limit_usage", "sysdig_pod_memory_limit", "sysdig_pod_cpu_request_usage", "sysdig_pod_memory_request","sysdig_kube_pod_status_phase"] + [[processors.filter_out.metric]] + measurement_name = "sysdig_kafka_topic_partition_current_offset" + fields = ["kafka_topic_partition_current_offset"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "sysdig_kafka_consumergroup_current_offset" + fields = ["kafka_consumergroup_current_offset"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "kafka_topic_partition_current_offset" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "kafka_consumer_group_current_offset" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "node_disk_io_util" + fields = ["value"] + aggregation_method = "set_max_value" + max_value = 100.0 + [[processors.filter_out.metric]] + measurement_name = "prometheus_kube_pod_owner" + fields = ["owner_name"] + aggregation_method = "trim_last_index" + match_string = "-" + [processors.filter_out.metric.condition] + owner_kind = "ReplicaSet" + [[processors.filter_out.metric]] + measurement_name = "prometheus_kube_pod_owner" + fields = ["owner_name"] + aggregation_method = "trim_last_index" + match_string = "-" + [processors.filter_out.metric.condition] + owner_kind = "ReplicationController" + [[processors.filter_out.metric]] + measurement_name = "openshift_prometheus_kube_pod_owner" + fields = ["owner_name"] + aggregation_method = "trim_last_index" + match_string = "-" + [processors.filter_out.metric.condition] + owner_kind = "ReplicaSet" + [[processors.filter_out.metric]] + measurement_name = "openshift_prometheus_kube_pod_owner" + fields = ["owner_name"] + aggregation_method = "trim_last_index" + match_string = "-" + [processors.filter_out.metric.condition] + owner_kind = "ReplicationController" + [[processors.filter_out.metric]] + measurement_name = "openshift_prometheus_kube_replicationcontroller_spec_replicas" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "openshift_prometheus_kube_replicationcontroller_status_available_replicas" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "openshift_prometheus_kube_replicationcontroller_spec_replicas" + fields = ["replicationcontroller"] + aggregation_method = "trim_last_index" + match_string = "-" + [[processors.filter_out.metric]] + measurement_name = "openshift_prometheus_kube_replicationcontroller_status_available_replicas" + fields = ["replicationcontroller"] + aggregation_method = "trim_last_index" + match_string = "-" + [[processors.filter_out.metric]] + measurement_name = "datadog_node_pod_phase" + fields = ["value"] + aggregation_method = "drop_zero_value" + # Drop Datadog cpu/memory limits/requests + # For metadata(pod, container and kafka_consumer_group) + [[processors.filter_out.metric]] + measurement_name = "datadog_kubernetes_pod_cpu_limit" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "datadog_kubernetes_pod_memory_limit" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "datadog_kubernetes_pod_cpu_requests" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "datadog_kubernetes_pod_memory_requests" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "datadog_kubernetes_container_cpu_limit" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "datadog_kubernetes_container_memory_limit" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "datadog_kubernetes_container_cpu_requests" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "datadog_kubernetes_container_memory_requests" + fields = ["value"] + aggregation_method = "drop_zero_value" + # Drop Datadog cpu/memory limits/requests + # For metrics data(pod_cpu_limit, pod_cpu_request, pod_memory_limit and pod_memory_request) + [[processors.filter_out.metric]] + measurement_name = "datadog_pod_cpu_request_usage" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "datadog_pod_cpu_limit_usage" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "datadog_pod_memory_request" + fields = ["value"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "datadog_pod_memory_limit" + fields = ["value"] + aggregation_method = "drop_zero_value" + # Drop Sysdig cpu/memory limits/requests + # For metadata(pod, container and kafka_consumer_group) + [[processors.filter_out.metric]] + measurement_name = "sysdig_kube_pod_resource_limits_cpu_cores" + fields = ["kubernetes.pod.resourceLimits.cpuCores"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "sysdig_kube_pod_resource_limits_memory_bytes" + fields = ["kubernetes.pod.resourceLimits.memBytes"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "sysdig_kube_pod_resource_requests_cpu_cores" + fields = ["kubernetes.pod.resourceRequests.cpuCores"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "sysdig_kube_pod_resource_requests_memory_bytes" + fields = ["kubernetes.pod.resourceRequests.memBytes"] + aggregation_method = "drop_zero_value" + # Drop Sysdig cpu/memory limits/requests + # For metrics data(pod_cpu_limit, pod_cpu_request, pod_memory_limit and pod_memory_request) + [[processors.filter_out.metric]] + measurement_name = "sysdig_pod_cpu_limit_usage" + fields = ["kubernetes.pod.resourceLimits.cpuCores"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "sysdig_pod_memory_limit" + fields = ["kubernetes.pod.resourceLimits.memBytes"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "sysdig_pod_cpu_request_usage" + fields = ["kubernetes.pod.resourceRequests.cpuCores"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "sysdig_pod_memory_request" + fields = ["kubernetes.pod.resourceRequests.memBytes"] + aggregation_method = "drop_zero_value" + [[processors.filter_out.metric]] + measurement_name = "sysdig_kube_pod_status_phase" + fields = ["kube_pod_status_phase"] + aggregation_method = "drop_zero_value" + + ## Datadog integration: processors + [[processors.metrics_decorator]] + order = 2 + namepass = ["datadog_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/datadog_pre_metric_decorator.json" + + [[processors.metrics_grouping]] + order = 3 + namepass = ["datadog_*", "alameda_*", "aws_cloudwatch_vm", "aws_cloudwatch_cluster_collection_done"] + schema_file = "/etc/telegraf/schema/datadog_grouping_rules.json" + + [[processors.metrics_decorator]] + order = 4 + namepass = ["datadog_namespace_*"] + schema_file = "/etc/telegraf/schema/datadog_post_metric_decorator.json" + + [[processors.schema_mapping]] + order = 5 + datasource = "datadog" + aggregator_processor = true + namepass = ["datadog_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/datadog_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + ## Set default cloud information ifneeded + enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY + default_provider = "$DEFAULT_PROVIDER" + default_region = "$DEFAULT_REGION" + default_instance_type = "$DEFAULT_INSTANCE_TYPE" + default_instance_id = "$DEFAULT_INSTANCE_ID" + default_zone = "$DEFAULT_ZONE" + + ## Openshift Prometheus integration: processors ## + [[processors.metrics_decorator]] + order = 2 + namepass = ["openshift_prometheus_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/openshift_prometheus_pre_metric_decorator.json" + + [[processors.metrics_grouping]] + order = 3 + namepass = ["openshift_prometheus_*", "alameda_*", "aws_cloudwatch_vm", "aws_cloudwatch_cluster_collection_done"] + schema_file = "/etc/telegraf/schema/openshift_prometheus_grouping_rules.json" + + [[processors.metrics_decorator]] + order = 4 + namepass = ["openshift_prometheus_alameda_config_cluster_namespace", "openshift_prometheus_node_cpu_usage_seconds_total", "openshift_prometheus_node_memory_usage_bytes", "openshift_prometheus_kube_node_status_capacity_cpu_cores", "openshift_prometheus_namespace_*"] + schema_file = "/etc/telegraf/schema/openshift_prometheus_post_metric_decorator.json" + + [[processors.schema_mapping]] + order = 5 + datasource = "prometheus" + aggregator_processor = true + namepass = ["openshift_prometheus_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/openshift_prometheus_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + ## Set default cloud information ifneeded + enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY + default_provider = "$DEFAULT_PROVIDER" + default_region = "$DEFAULT_REGION" + default_instance_type = "$DEFAULT_INSTANCE_TYPE" + default_instance_id = "$DEFAULT_INSTANCE_ID" + default_zone = "$DEFAULT_ZONE" + + ## Federation Prometheus/Prometheus integration: processors ## + [[processors.metrics_decorator]] + order = 2 + namepass = ["prometheus_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/prometheus_pre_metric_decorator.json" + + [[processors.metrics_grouping]] + order = 3 + namepass = ["prometheus_*", "alameda_*", "aws_cloudwatch_vm", "aws_cloudwatch_cluster_collection_done"] + schema_file = "/etc/telegraf/schema/prometheus_grouping_rules.json" + + [[processors.metrics_decorator]] + order = 4 + namepass = ["prometheus_alameda_config_cluster_namespace", "prometheus_node_cpu_usage_seconds_total", "prometheus_node_memory_usage_bytes", "prometheus_kube_node_status_capacity_cpu_cores", "prometheus_nginx_http_average_response_time_ms", "prometheus_namespace_*"] + schema_file = "/etc/telegraf/schema/prometheus_post_metric_decorator.json" + + [[processors.schema_mapping]] + order = 5 + datasource = "prometheus" + aggregator_processor = true + namepass = ["prometheus_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/prometheus_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + ## Set default cloud information ifneeded + enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY + default_provider = "$DEFAULT_PROVIDER" + default_region = "$DEFAULT_REGION" + default_instance_type = "$DEFAULT_INSTANCE_TYPE" + default_instance_id = "$DEFAULT_INSTANCE_ID" + default_zone = "$DEFAULT_ZONE" + + ## Sysdig integration: processors ## + [[processors.metrics_decorator]] + order = 2 + namepass = ["sysdig_*", "alameda_*", "federatorai.kafka.consumer_lag", "federatorai.kafka.consumer_offset_rate", "federatorai.kafka.broker_offset_rate", "federatorai.prediction.kafka", "federatorai.recommendation", "federatorai.prediction.controller", "federatorai.prediction.controller.max", "federatorai.prediction.controller.min", "federatorai.prediction.controller.avg", "federatorai.prediction.node", "federatorai.prediction.node.max", "federatorai.prediction.node.min", "federatorai.prediction.node.avg", "federatorai.resource_planning.node", "federatorai.resource_planning.controller", "federatorai.kubernetes.cpu.usage.total.node", "federatorai.kubernetes.cpu.usage.total.controller", "federatorai.kubernetes.memory.usage.node", "federatorai.kubernetes.memory.usage.controller", "federatorai.kubernetes.cpu.usage.total.node_rollup_3600sec", "federatorai.kubernetes.cpu.usage.total.controller_rollup_3600sec", "federatorai.kubernetes.memory.usage.node_rollup_3600sec", "federatorai.kubernetes.memory.usage.controller_rollup_3600sec", "federatorai.kubernetes.cpu.usage.total.node_rollup_21600sec", "federatorai.kubernetes.cpu.usage.total.controller_rollup_21600sec", "federatorai.kubernetes.memory.usage.node_rollup_21600sec", "federatorai.kubernetes.memory.usage.controller_rollup_21600sec", "federatorai.kubernetes.cpu.usage.total.node_rollup_86400sec", "federatorai.kubernetes.cpu.usage.total.controller_rollup_86400sec", "federatorai.kubernetes.memory.usage.node_rollup_86400sec", "federatorai.kubernetes.memory.usage.controller_rollup_86400sec"] + schema_file = "/etc/telegraf/schema/sysdig_pre_metric_decorator.json" + + [[processors.metrics_grouping]] + order = 3 + namepass = ["sysdig_*", "alameda_*", "aws_cloudwatch_vm", "aws_cloudwatch_cluster_collection_done"] + schema_file = "/etc/telegraf/schema/sysdig_grouping_rules.json" + + [[processors.metrics_decorator]] + order = 4 + namepass = ["sysdig_alameda_config_cluster_namespace", "sysdig_namespace_*", "sysdig_kube_container_resource_limits_cpu_cores", "sysdig_kube_container_resource_requests_cpu_cores", "sysdig_alameda_config_namespace_metric_instance_config_info"] + schema_file = "/etc/telegraf/schema/sysdig_post_metric_decorator.json" + + [[processors.schema_mapping]] + order = 5 + datasource = "sysdig" + aggregator_processor = true + namepass = ["sysdig_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/sysdig_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + ## Set default cloud information ifneeded + enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY + default_provider = "$DEFAULT_PROVIDER" + default_region = "$DEFAULT_REGION" + default_instance_type = "$DEFAULT_INSTANCE_TYPE" + default_instance_id = "$DEFAULT_INSTANCE_ID" + default_zone = "$DEFAULT_ZONE" + + ## VMware integration: processors + [[processors.metrics_decorator]] + order = 2 + namepass = ["vmware_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/vmware_pre_metric_decorator.json" + + [[processors.metrics_grouping]] + order = 3 + namepass = ["vmware_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/vmware_grouping_rules.json" + + [[processors.metrics_decorator]] + order = 4 + namepass = [""] + schema_file = "/etc/telegraf/schema/vmware_post_metric_decorator.json" + + [[processors.schema_mapping]] + order = 5 + datasource = "vmware" + aggregator_processor = true + namepass = ["vmware_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/vmware_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + ## Set default cloud information ifneeded + enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY + default_provider = "$DEFAULT_PROVIDER" + default_region = "$DEFAULT_REGION" + default_instance_type = "$DEFAULT_INSTANCE_TYPE" + default_instance_id = "$DEFAULT_INSTANCE_ID" + default_zone = "$DEFAULT_ZONE" + + ## AWS Cloudwatch integration: processors + [[processors.metrics_decorator]] + order = 2 + namepass = ["aws_cloudwatch_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/aws_pre_metric_decorator.json" + + [[processors.metrics_grouping]] + order = 3 + namepass = ["aws_cloudwatch_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/aws_grouping_rules.json" + + [[processors.metrics_decorator]] + order = 4 + namepass = ["aws_cloudwatch_alameda_config_cluster_vm", "aws_cloudwatch_node_group_*"] + schema_file = "/etc/telegraf/schema/aws_post_metric_decorator.json" + + [[processors.schema_mapping]] + order = 5 + datasource = "aws" + aggregator_processor = true + namepass = ["aws_cloudwatch_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/aws_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + ## Set default cloud information ifneeded + enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY + default_provider = "$DEFAULT_PROVIDER" + default_region = "$DEFAULT_REGION" + default_instance_type = "$DEFAULT_INSTANCE_TYPE" + default_instance_id = "$DEFAULT_INSTANCE_ID" + default_zone = "$DEFAULT_ZONE" + + ## Datadog Dashboard integration: processors + [[processors.metrics_decorator]] + order = 2 + namepass = ["federatorai_datadog_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/federatorai_datadog_pre_metric_decorator.json" + + [[processors.metrics_grouping]] + order = 3 + namepass = ["federatorai_datadog_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/federatorai_datadog_grouping_rules.json" + + [[processors.metrics_decorator]] + order = 4 + namepass = ["federatorai_datadog_*"] + schema_file = "/etc/telegraf/schema/federatorai_datadog_post_metric_decorator.json" + + [[processors.schema_mapping]] + order = 5 + datasource = "datadog" + aggregator_processor = true + namepass = ["federatorai_datadog_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/federatorai_datadog_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + ## Set default cloud information ifneeded + enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY + default_provider = "$DEFAULT_PROVIDER" + default_region = "$DEFAULT_REGION" + default_instance_type = "$DEFAULT_INSTANCE_TYPE" + default_instance_id = "$DEFAULT_INSTANCE_ID" + default_zone = "$DEFAULT_ZONE" + + ## Sysdig Dashboard integration: processors + [[processors.metrics_decorator]] + order = 2 + namepass = ["federatorai_sysdig_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/federatorai_sysdig_pre_metric_decorator.json" + + [[processors.metrics_grouping]] + order = 3 + namepass = ["federatorai_sysdig_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/federatorai_sysdig_grouping_rules.json" + + [[processors.metrics_decorator]] + order = 4 + namepass = ["federatorai_sysdig_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/federatorai_sysdig_post_metric_decorator.json" + + [[processors.schema_mapping]] + order = 5 + datasource = "sysdig" + aggregator_processor = true + namepass = ["federatorai_sysdig_*", "alameda_*"] + schema_file = "/etc/telegraf/schema/federatorai_sysdig_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + ## Set default cloud information ifneeded + enable_set_default_cloud_info_if_empty = $ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY + default_provider = "$DEFAULT_PROVIDER" + default_region = "$DEFAULT_REGION" + default_instance_type = "$DEFAULT_INSTANCE_TYPE" + default_instance_id = "$DEFAULT_INSTANCE_ID" + default_zone = "$DEFAULT_ZONE" + + ############################## + ### Aggregator Federatorai ### + ############################## + + [[aggregators.federatorai]] + period = "1m" + drop_original = true + concurrent_job = 3 + schema_file = "/etc/telegraf/schema/basic_aggregator_schema.json" + namepass = [""] + + ## Datadog metrics ## + [[aggregators.federatorai]] + grace = "2m" + period = "1m" + drop_original = true + concurrent_job = 3 + schema_file = "/etc/telegraf/schema/datadog_aggregator_schema.json" + namepass = ["datadog_*"] + + ## Openshift Prometheus integration: aggregator ## + [[aggregators.federatorai]] + grace = "2m" + period = "1m" + drop_original = true + concurrent_job = 3 + schema_file = "/etc/telegraf/schema/openshift_prometheus_aggregator_schema.json" + namepass = ["openshift_prometheus_*"] + + ## Federation Prometheus/Prometheus integration: aggregator ## + [[aggregators.federatorai]] + grace = "2m" + period = "1m" + drop_original = true + concurrent_job = 3 + schema_file = "/etc/telegraf/schema/prometheus_aggregator_schema.json" + namepass = ["prometheus_*"] + + ## Sysdig integration: aggregator ## + [[aggregators.federatorai]] + grace = "2m" + period = "1m" + drop_original = true + concurrent_job = 3 + schema_file = "/etc/telegraf/schema/sysdig_aggregator_schema.json" + namepass = ["sysdig_*"] + + ## VMware integration: aggregator ## + [[aggregators.federatorai]] + grace = "5m" + period = "1m" + drop_original = true + concurrent_job = 3 + schema_file = "/etc/telegraf/schema/vmware_aggregator_schema.json" + namepass = ["vmware_*"] + + ## AWS Cloudwatch metrics ## + [[aggregators.federatorai]] + grace = "1m" + period = "1m" + drop_original = true + concurrent_job = 3 + schema_file = "/etc/telegraf/schema/aws_aggregator_schema.json" + namepass = ["aws_cloudwatch_*"] + + ## Federatorai Metrics - Datadog metrics ## + [[aggregators.federatorai]] + grace = "1m" + period = "1m" + drop_original = true + concurrent_job = 3 + schema_file = "/etc/telegraf/schema/federatorai_datadog_aggregator_schema.json" + namepass = ["federatorai_datadog_*"] + + ## Federatorai Metrics - Sysdig metrics ## + [[aggregators.federatorai]] + grace = "1m" + period = "1m" + drop_original = true + concurrent_job = 3 + schema_file = "/etc/telegraf/schema/federatorai_sysdig_aggregator_schema.json" + namepass = ["federatorai_sysdig_*"] + + ############################ + ### Input/Output Plugins ### + ############################ + + [[outputs.datadog]] + User-Agent = "Federator.ai/4.2" + kafka_dashboards = ["/etc/telegraf/dashboards/datadog/kafka/overview.json"] + general_dashboards = ["/etc/telegraf/dashboards/datadog/kubernetes/application-overview.json", "/etc/telegraf/dashboards/datadog/kubernetes/cluster-overview.json", "/etc/telegraf/dashboards/datadog/cost/cost-analysis-overview.json", "/etc/telegraf/dashboards/datadog/cost/cost-management-cluster-overview.json", "/etc/telegraf/dashboards/datadog/cost/cost-management-node-overview.json", "/etc/telegraf/dashboards/datadog/cost/cost-management-namespace-overview.json"] + enable_kafka_dashboard = $ENABLE_DD_DASHBOARD + enable_general_dashboard = $ENABLE_DD_DASHBOARD + namepass = ["federatorai_datadog_*"] + namedrop= ["federatorai_datadog_cluster_collection_done"] + metric_prefix = "federatorai_datadog_" + + [[outputs.datadog.clusters]] + cluster_name = "cluster" + user_agent = "Federatorai/5.0" + api_key = "$DATADOG_API_KEY" + application_key = "$DATADOG_APPLICATION_KEY" + url = "https://api.datadoghq.com/api/v1/series" + rest_url = "https://api.datadoghq.com/api/v1" + + # This pattern support federatorai.integration.status, federatorai.recommendation and federatorai.prediction.* + [[outputs.datadog.integration_metrics]] + name="federatorai.*" + aggregation_type="raw" + + ## Alameda Configuration: inputs.data_collector ## + [[inputs.data_collector]] + query_start_time_offset = "-1m" + query_end_time_offset = "0h" #Support s(second),m(minute),h(hour) + collection_jitter = "0s" + ## data source type from which to query data + ## accept values: alameda_datahub + source = "alameda_datahub" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = true + overwrite_query_delay_interval = true + delay_query_interval = "1s" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/alameda_config_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Openshift Prometheus integration: inputs.data_collector ## + [[inputs.data_collector]] + query_start_time_offset = "-1m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: prometheus + source = "prometheus" + ## which collector to handle the data collection + collector = "prometheus" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## one URL from which to read formatted metrics + url = "http://prometheus-prometheus-oper-prometheus.default.svc:9090" + ## metrics schema path + metric_path = ["/etc/telegraf/schema/openshift_prometheus_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + controller_name = [] + node_uids = [] + group_names = [] + + ## Federation Prometheus integration: inputs.data_collector ## + [[inputs.data_collector]] + query_start_time_offset = "-1m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: prometheus + source = "prometheus" + ## which collector to handle the data collection + collector = "prometheus" + ## account name + account = "" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## one URL from which to read formatted metrics + url = "http://prometheus-prometheus-oper-prometheus.default.svc:9090" + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federation_prometheus_metrics.json"] + target_label = "clusterID: cluster1" + cluster_name = "default" + discover_path = "" + controller_name = [] + node_uids = [] + group_names = [] + + ## Rancher Prometheus integration: inputs.data_collector ## + [[inputs.data_collector]] + query_start_time_offset = "-1m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: prometheus + source = "prometheus" + ## which collector to handle the data collection + collector = "prometheus" + ## account name + account = "" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## one URL from which to read formatted metrics + url = "http://prometheus-prometheus-oper-prometheus.default.svc:9090" + ## metrics schema path + metric_path = ["/etc/telegraf/schema/rancher_prometheus_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + controller_name = [] + node_uids = [] + group_names = [] + + ## Prometheus integration: inputs.data_collector ## + [[inputs.data_collector]] + query_start_time_offset = "-1m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: prometheus + source = "prometheus" + ## which collector to handle the data collection + collector = "prometheus" + ## account name + account = "" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## one URL from which to read formatted metrics + url = "http://prometheus-prometheus-oper-prometheus.default.svc:9090" + ## metrics schema path + metric_path = ["/etc/telegraf/schema/prometheus_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + controller_name = [] + node_uids = [] + group_names = [] + + ## Datadog integration: inputs.data_collector + [[inputs.data_collector]] + query_start_time_offset = "-1m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: prometheus, datadog, sysdig + source = "datadog" + ## which collector to handle the data collection + collector = "datadog" + ## authenticated token path + token= "${DD-API-KEY}" + application_key = "${DD-APPLICATION-KEY}" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## one URL from which to read formatted metrics + url = "https://api.datadoghq.com/api/v1/query" + ## metrics schema path + metric_path = ["/etc/telegraf/schema/datadog_metrics.json"] + cluster_name = "default" + + ## Sysdig integration: inputs.data_collector ## + [[inputs.data_collector]] + query_start_time_offset = "-1m" + query_end_time_offset = "0m" + ## data source type from which to query data + ## accept values: sysdig + source = "sysdig" + ## which collector to handle the data collection + collector = "sysdig" + ## account name + account = "" + ## authenticated token path + token= "${SYSDIG_API_TOKEN}" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## one URL from which to read formatted metrics + url = "${SYSDIG_API_URL}/data/batch" + ## Set batch query parameters + max_query_per_chunk = $DATADOG_MAX_QUERY_PER_CHUNK + max_characters_per_chunk = $DATADOG_MAX_CHAR_PER_CHUNK + ## metrics schema path + metric_path = ["/etc/telegraf/schema/sysdig_metrics.json"] + target_label = "" + cluster_name = "${CLUSTER_NAME}" + discover_path = "" + controller_name = [] + node_uids = [] + group_names = [] + + ## VMware integration: inputs.data_collector ## + # This plugin is for list vm in one minute + [[inputs.data_collector]] + query_start_time_offset = "-1m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: vmware + source = "vmware" + ## which collector to handle the data collection + collector = "vmware" + ## account name + account = "" + ## authenticated token path + token= "" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## one URL from which to read formatted metrics + url = "${VMWARE_API_URL}" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/vmware_list_metrics.json"] + target_label = "" + cluster_name = "${CLUSTER_NAME}" + discover_path = "" + controller_name = [] + node_uids = [] + group_names = [] + + ## VMware integration: inputs.data_collector ## + [[inputs.data_collector]] + interval = "5m" + query_start_time_offset = "-5m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: vmware + source = "vmware" + ## which collector to handle the data collection + collector = "vmware" + ## account name + account = "" + ## authenticated token path + token= "" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## one URL from which to read formatted metrics + url = "${VMWARE_API_URL}" + ## metrics schema path + metric_path = ["/etc/telegraf/schema/vmware_metrics.json"] + target_label = "" + cluster_name = "${CLUSTER_NAME}" + discover_path = "" + controller_name = [] + node_uids = [] + group_names = [] + + ## AWS Cloudwatch integration: inputs.data_collector + # This plugin is for list vm in one minute + # [[inputs.data_collector]] + # interval = "3m" + # query_start_time_offset = "-1m" + # query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + # ## data source type from which to query data + # ## accept values: vmware + # source = "aws" + # ## which collector to handle the data collection + # collector = "aws" + # ## account name + # account = "" + # ## authenticated token path + # token= "" + # ## TLS Insecure skip verify + # insecure_skip_verify = true + # ## one URL from which to read formatted metrics + # url = "" + # ## Load metric instance configs from Datahub or not + # skip_metric_instance_configs = true + # ## metrics schema path + # metric_path = ["/etc/telegraf/schema/aws_list_metrics.json"] + # cluster_name = "${CLUSTER_NAME}" + # discover_path = "" + # controller_name = [] + # node_uids = [] + # group_names = [] + + ## AWS Cloudwatch integration: inputs.data_collector + [[inputs.data_collector]] + interval = "5m" + query_start_time_offset = "-30m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: vmware + source = "aws" + ## which collector to handle the data collection + collector = "aws" + ## account name + account = "" + ## authenticated token path + token= "" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## one URL from which to read formatted metrics + url = "" + ## metrics schema path + metric_path = ["/etc/telegraf/schema/aws_metrics.json"] + cluster_name = "${CLUSTER_NAME}" + discover_path = "" + controller_name = [] + node_uids = [] + group_names = [] + + ### Federatorai Metrics ### + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "3m" + use_query_timestamp = true + query_start_time_offset = "-3m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "10s" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_3_mins_aggregation_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Sysdig : inputs.data_collector ## + [[inputs.data_collector]] + interval = "3m" + use_query_timestamp = true + query_start_time_offset = "-3m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: alameda_datahub + source = "sysdig" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "10s" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_previous_3_mins_aggregation_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_1H" + use_query_timestamp = false + query_start_time_offset = "-23h59m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = [ + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_1_day_cost_metrics_3600s.json" + ] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_1H" + use_query_timestamp = true + query_start_time_offset = "-59m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = [ + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_1_hour_aggregation_metrics.json", + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_1_hour_cost_metrics_3600s.json" + ] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Sysdig : inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_1H" + use_query_timestamp = true + query_start_time_offset = "-59m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "sysdig" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_previous_1_hour_aggregation_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_1H" + use_query_timestamp = false + query_start_time_offset = "-167h59m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = [ + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_7_days_cost_metrics_21600s.json" + ] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_6H" + use_query_timestamp = true + query_start_time_offset = "-5h59m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = [ + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_6_hours_aggregation_metrics.json", + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_6_hours_cost_metrics_21600s.json" + ] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Sysdig : inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_6H" + use_query_timestamp = true + query_start_time_offset = "-5h59m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "sysdig" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_previous_6_hours_aggregation_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_1H" + use_query_timestamp = false + query_start_time_offset = "-719h59m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = [ + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_30_days_cost_metrics_86400s.json" + ] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_24H" + use_query_timestamp = true + query_start_time_offset = "-23h59m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = [ + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_24_hours_aggregation_metrics.json", + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_24_hours_cost_metrics_86400s.json" + ] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Sysdig : inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_24H" + use_query_timestamp = true + query_start_time_offset = "-23h59m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "sysdig" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_previous_24_hours_aggregation_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_1H" + use_query_timestamp = false + query_start_time_offset = "1m" + query_end_time_offset = "24h" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = [ + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_1_day_aggregation_metrics.json", + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_1_day_cost_metrics_3600s.json", + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_1_day_planning_metrics_3600s.json" + ] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Sysdig : inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_1H" + use_query_timestamp = false + query_start_time_offset = "1m" + query_end_time_offset = "24h" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "sysdig" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_next_1_day_aggregation_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_6H" + use_query_timestamp = false + query_start_time_offset = "1m" + query_end_time_offset = "168h" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = [ + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_7_days_aggregation_metrics.json" + ] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_1H" + use_query_timestamp = false + query_start_time_offset = "1m" + query_end_time_offset = "168h" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = [ + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_7_days_cost_metrics_21600s.json", + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_7_days_planning_metrics_21600s.json" + ] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Sysdig : inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_6H" + use_query_timestamp = false + query_start_time_offset = "1m" + query_end_time_offset = "168h" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "sysdig" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_next_7_days_aggregation_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_24H" + use_query_timestamp = false + query_start_time_offset = "1m" + query_end_time_offset = "720h" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = [ + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_30_days_aggregation_metrics.json" + ] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_1H" + use_query_timestamp = false + query_start_time_offset = "1m" + query_end_time_offset = "720h" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = [ + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_30_days_cost_metrics_86400s.json", + "/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_30_days_planning_metrics_86400s.json" + ] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Sysdig : inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_24H" + use_query_timestamp = false + query_start_time_offset = "1m" + query_end_time_offset = "720h" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "sysdig" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_next_30_days_aggregation_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "1m" + use_query_timestamp = true + query_start_time_offset = "-1m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "10s" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_1_min_prediction_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Sysdig : inputs.data_collector ## + [[inputs.data_collector]] + interval = "1m" + use_query_timestamp = true + query_start_time_offset = "-1m" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: alameda_datahub + source = "sysdig" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "10s" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_previous_1_min_prediction_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "1m" + use_query_timestamp = true + query_start_time_offset = "-2m" + query_end_time_offset = "-1m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "10s" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_2_mins_observation_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Sysdig : inputs.data_collector ## + [[inputs.data_collector]] + interval = "1m" + use_query_timestamp = true + query_start_time_offset = "-2m" + query_end_time_offset = "-1m" #Support s(second),m(minute),h(hour) + ## data source type from which to query data + ## accept values: alameda_datahub + source = "sysdig" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "10s" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_sysdig_previous_2_mins_observation_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_1H" + use_query_timestamp = false + query_start_time_offset = "720h1m" + query_end_time_offset = "744h" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_30_days_recommendation_instance.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_1H" + use_query_timestamp = false + query_start_time_offset = "-48h" + query_end_time_offset = "0m" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_previous_2_days_aggregation_cost_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ## Federatorai Metrics - Datadog: inputs.data_collector ## + [[inputs.data_collector]] + interval = "$COLLECTION_INTERVAL_1H" + use_query_timestamp = false + query_start_time_offset = "1m" + query_end_time_offset = "720h" #Support s(second),m(minute),h(hour) + retry_interval = "$FEDERATORAI_METRICS_RETRY_INTERVAL" + max_retry_times = $FEDERATORAI_METRICS_MAX_RETRY_TIMES + ## data source type from which to query data + ## accept values: alameda_datahub + source = "datadog" + ## which collector to handle the data collection + collector = "alameda_datahub" + ## authenticated token path + token= "/var/run/secrets/kubernetes.io/serviceaccount/token" + ## TLS Insecure skip verify + insecure_skip_verify = true + ## Alameda Read Configuration used + configuration_only = false + overwrite_query_delay_interval = true + delay_query_interval = "$FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL" + ## one URL from which to read formatted metrics + url = "" + ## Load metric instance configs from Datahub or not + skip_metric_instance_configs = true + ## metrics schema path + metric_path = ["/etc/telegraf/schema/federatorai_metrics/federatorai_datadog_next_30_days_aggregation_cost_metrics.json"] + target_label = "" + cluster_name = "default" + discover_path = "" + node_uids = [] + group_names = [] + + ### Sync database metadata + #[[outputs.alameda_datahub]] + # namedrop = ["*"] + # enable_sync_metadata = true + # sync_metadata_schema_file = "/etc/telegraf/schema/sync_metadata_schema.json" + + ## Openshift Prometheus integration: outputs.alameda_datahub ## + [[outputs.alameda_datahub]] + namepass = ["openshift_prometheus_*"] + metric_prefix = "openshift_prometheus_" + datasource = "prometheus" + concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB + schema_file = "/etc/telegraf/schema/datahub_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + + ## Federation Prometheus/Prometheus integration: outputs.alameda_datahub ## + [[outputs.alameda_datahub]] + namepass = ["prometheus_*"] + metric_prefix = "prometheus_" + datasource = "prometheus" + concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB + schema_file = "/etc/telegraf/schema/datahub_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + + ## Sysdig integration: outputs.alameda_datahub ## + [[outputs.alameda_datahub]] + namepass = ["sysdig_*"] + metric_prefix = "sysdig_" + datasource = "sysdig" + concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB + schema_file = "/etc/telegraf/schema/datahub_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + + ## Datadog integration: outputs.alameda_datahub ## + [[outputs.alameda_datahub]] + namepass = ["datadog_*"] + metric_prefix = "datadog_" + datasource = "datadog" + concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB + schema_file = "/etc/telegraf/schema/datahub_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + + ## VMware integration: outputs.alameda_datahub ## + [[outputs.alameda_datahub]] + namepass = ["vmware_*"] + metric_prefix = "vmware_" + datasource = "vmware" + concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB + schema_file = "/etc/telegraf/schema/datahub_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + + ## AWS Cloudwatch integration: outputs.alameda_datahub + [[outputs.alameda_datahub]] + namepass = ["aws_cloudwatch_*"] + metric_prefix = "aws_cloudwatch_" + datasource = "aws" + concurrent_job = $WRITE_DATAHUB_CONCURRENT_JOB + schema_file = "/etc/telegraf/schema/datahub_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + + ## Post Datahub event + [[outputs.alameda_datahub]] + namepass = ["datahub_event"] + metric_prefix = "datahub_" + post_event_interval = "$POST_EVENT_INTERVAL" + schema_file = "/etc/telegraf/schema/datahub_schema.json" + cluster_collection_done_schema_file = "/etc/telegraf/schema/cluster_collection_done_schema.json" + + [[outputs.prometheus_client]] + namepass = ["federatorai_sysdig_*"] + collectors_exclude = ["gocollector", "process"] + export_all_metrics = true + ## Address to listen on + listen = ":8080" + ## Path to publish the metrics on. + path = "/metrics" + metric_prefix = "federatorai_sysdig_" + expiration_interval = "5m" + + ## Test only: export DA's Prometheus metrics for automation tests + [[outputs.prometheus_client]] + namepass = ["prometheus_*"] + collectors_exclude = ["gocollector", "process"] + enable_default_value = ["prometheus_cluster", "prometheus_node", "prometheus_application", "prometheus_namespace", "prometheus_controller", "prometheus_pod", "prometheus_container", "prometheus_kafka_topic", "prometheus_kafka_consumer_group", "prometheus_nginx_web_service"] + default_value = -1 + export_all_metrics = true + ## Address to listen on + listen = ":8081" + ## Path to publish the metrics on. + path = "/test-metrics" + metric_prefix = "" + expiration_interval = "5m" + + ## Test only: export DA's Datadog metrics for automation tests + [[outputs.prometheus_client]] + namepass = ["datadog_*", "federatorai_datadog_*"] + collectors_exclude = ["gocollector", "process"] + enable_default_value = ["datadog_cluster", "datadog_node", "datadog_application", "datadog_namespace", "datadog_controller", "datadog_pod", "datadog_container", "datadog_kafka_topic", "datadog_kafka_consumer_group", "datadog_nginx_web_service"] + default_value = -1 + export_all_metrics = true + ## Address to listen on + listen = ":8082" + ## Path to publish the metrics on. + path = "/test-metrics" + metric_prefix = "federatorai_datadog_" + expiration_interval = "5m" + + ## Test only: export DA's Sysdig metrics for automation tests + [[outputs.prometheus_client]] + namepass = ["sysdig_*", "federatorai_sysdig_*"] + collectors_exclude = ["gocollector", "process"] + enable_default_value = ["sysdig_cluster", "sysdig_node", "sysdig_application", "sysdig_namespace", "sysdig_controller", "sysdig_pod", "sysdig_container", "sysdig_kafka_topic", "sysdig_kafka_consumer_group", "sysdig_nginx_web_service"] + default_value = -1 + export_all_metrics = true + ## Address to listen on + listen = ":8083" + ## Path to publish the metrics on. + path = "/test-metrics" + metric_prefix = "federatorai_sysdig_" + expiration_interval = "5m" diff --git a/charts/prophetstor/federatorai/templates/federatorai-data-adapter/deployments.yaml b/charts/prophetstor/federatorai/templates/federatorai-data-adapter/deployments.yaml index fc13ba8b8..611112096 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-data-adapter/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-data-adapter/deployments.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-data-adapter @@ -18,175 +25,199 @@ spec: type: Recreate template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} prometheus.io/path: /metrics prometheus.io/port: "8080" prometheus.io/scrape: "true" - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-data-adapter spec: - affinity: {{- include "render-value" ( dict "value" .Values.federatoraiDataAdapter.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.federatoraiDataAdapter.affinity }} +{{- include "render-value" ( dict "value" .Values.federatoraiDataAdapter.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - args: - - -c - - /entrypoint.sh - command: - - /bin/bash - env: - - name: NAMESPACE_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.name - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - - name: CONFIGURATION_RELOAD_INTERVAL - value: "1h" - - name: DELAY_QUERY_INTERVAL - value: 10s - - name: DELAY_HISTORICAL_QUERY - value: 3m - - name: FED_REST_URL - value: federatorai-rest.{{ .Release.Namespace }} - - name: FED_REST_PORT - value: "5059" - - name: DATAHUB_URL - value: alameda-datahub.{{ .Release.Namespace }} - - name: DATAHUB_PORT - value: "50050" - - name: WRITE_DATAHUB_CONCURRENT_JOB - value: "3" - - name: RABBITMQ_URL - value: alameda-rabbitmq.{{ .Release.Namespace }} - - name: RABBITMQ_PORT - value: "5672" - - name: DATA_EXPIRED_TIME - value: 5m - - name: POST_EVENT_INTERVAL - value: 1h - - name: LOG_QUEUE_TRACE_INTERVAL - value: 5m - - name: MAX_LOG_QUEUE_SIZE - value: "50000" - - name: ENABLED_ASYNC_LOGGER - value: "true" - - name: ENABLE_FLUSH_LOG_TO_CONSOLE - value: "false" - - name: LOG_FLUSH_TO_CONSOLE_LEVEL - value: ERROR - - name: SYSDIG_API_URL - value: https://app.sysdigcloud.com - - name: DD_CLUSTER_NAME_TAG_KEYS - value: kube_cluster_name,cluster_name,kube_cluster - - name: ENABLE_DD_DASHBOARD - value: "false" - - name: CHECK_SYSDIG_DASHBOARD_INTERVAL - value: 2m - - name: ENABLE_SYSDIG_DASHBOARD - value: "true" - - name: ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY - value: "false" - - name: DEFAULT_PROVIDER - value: aws - - name: DEFAULT_REGION - value: us-west-1 - - name: DEFAULT_INSTANCE_TYPE - value: m5.4xlarge - - name: DEFAULT_INSTANCE_ID - value: i-00cd730e045190cad - - name: DEFAULT_ZONE - value: us-west-1a - - name: COLLECT_METADATA_ONLY - value: "false" - - name: DEBUG - value: "false" - - name: MAX_REQUEST_LINE - value: "5000" - - name: DATADOG_MAX_CHAR_PER_CHUNK - value: "7000" - - name: DATADOG_MAX_QUERY_PER_CHUNK - value: "35" - - name: SYSDIG_MAX_CHAR_PER_CHUNK - value: "10000" - - name: SYSDIG_MAX_QUERY_PER_CHUNK - value: "20" - - name: DATADOG_API_KEY - - name: DATADOG_APPLICATION_KEY - - name: SYSDIG_API_TOKEN - - name: COLLECTION_INTERVAL_1H - value: 1h - - name: COLLECTION_INTERVAL_6H - value: 6h - - name: COLLECTION_INTERVAL_24H - value: 24h - - name: FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL - value: 10s - - name: FEDERATORAI_METRICS_RETRY_INTERVAL - value: 5m - - name: FEDERATORAI_METRICS_MAX_RETRY_TIMES - value: "6" - - name: MAX_RPC_RECEIVE_SIZE - value: "134217728" - - name: HISTORICAL_DATA_RESTART_LIMIT - value: "5" - - name: HANDLE_MISSING_DATA_TIMES - value: "1" - image: {{ .Values.global.imageRegistry }}/federatorai-data-adapter:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: - - /bin/bash + - args: - -c - - /livenessProbe.sh - failureThreshold: 10 - initialDelaySeconds: 30 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 5 - name: federatorai-data-adapter - ports: - - containerPort: 8080 - name: export-metrics - protocol: TCP - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.federatoraiDataAdapter.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /etc/telegraf/telegraf.conf - name: federatorai-data-adapter-config - subPath: telegraf.conf - - mountPath: /etc/telegraf/telegraf_historical.conf - name: federatorai-data-adapter-historical-config - subPath: telegraf_historical.conf - - mountPath: /var/log - name: federatorai-data-adapter-log-storage - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - /entrypoint.sh + command: + - /bin/bash + env: + - name: NAMESPACE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + - name: CONFIGURATION_RELOAD_INTERVAL + value: "1h" + - name: DELAY_QUERY_INTERVAL + value: 10s + - name: DELAY_HISTORICAL_QUERY + value: 3m + - name: FED_REST_URL + value: federatorai-rest.{{ .Release.Namespace }} + - name: FED_REST_PORT + value: "5059" + - name: DATAHUB_URL + value: alameda-datahub.{{ .Release.Namespace }} + - name: DATAHUB_PORT + value: "50050" + - name: WRITE_DATAHUB_CONCURRENT_JOB + value: "3" + - name: RABBITMQ_URL + value: alameda-rabbitmq.{{ .Release.Namespace }} + - name: RABBITMQ_PORT + value: "5672" + - name: DATA_EXPIRED_TIME + value: 5m + - name: POST_EVENT_INTERVAL + value: 1h + - name: LOG_QUEUE_TRACE_INTERVAL + value: 5m + - name: MAX_LOG_QUEUE_SIZE + value: "50000" + - name: ENABLED_ASYNC_LOGGER + value: "true" + - name: ENABLE_FLUSH_LOG_TO_CONSOLE + value: "false" + - name: LOG_FLUSH_TO_CONSOLE_LEVEL + value: ERROR + - name: SYSDIG_API_URL + value: https://app.sysdigcloud.com + - name: DD_CLUSTER_NAME_TAG_KEYS + value: kube_cluster_name,cluster_name,kube_cluster + - name: ENABLE_DD_DASHBOARD + value: "false" + - name: CHECK_SYSDIG_DASHBOARD_INTERVAL + value: 2m + - name: ENABLE_SYSDIG_DASHBOARD + value: "true" + - name: ENABLE_SET_DEFAULT_CLOUD_INFO_IF_EMPTY + value: "false" + - name: DEFAULT_PROVIDER + value: aws + - name: DEFAULT_REGION + value: us-west-1 + - name: DEFAULT_INSTANCE_TYPE + value: m5.4xlarge + - name: DEFAULT_INSTANCE_ID + value: i-00cd730e045190cad + - name: DEFAULT_ZONE + value: us-west-1a + - name: COLLECT_METADATA_ONLY + value: "false" + - name: DEBUG + value: "false" + - name: MAX_REQUEST_LINE + value: "3000" + - name: DATADOG_MAX_CHAR_PER_CHUNK + value: "7000" + - name: DATADOG_MAX_QUERY_PER_CHUNK + value: "35" + - name: SYSDIG_MAX_CHAR_PER_CHUNK + value: "10000" + - name: SYSDIG_MAX_QUERY_PER_CHUNK + value: "20" + - name: DATADOG_API_KEY + - name: DATADOG_APPLICATION_KEY + - name: SYSDIG_API_TOKEN + - name: COLLECTION_INTERVAL_1H + value: 1h + - name: COLLECTION_INTERVAL_6H + value: 6h + - name: COLLECTION_INTERVAL_24H + value: 24h + - name: FEDERATORAI_METRIC_DELAY_QUERY_INTERVAL + value: 10s + - name: FEDERATORAI_METRICS_RETRY_INTERVAL + value: 5m + - name: FEDERATORAI_METRICS_MAX_RETRY_TIMES + value: "6" + - name: MAX_RPC_RECEIVE_SIZE + value: "134217728" + - name: HISTORICAL_DATA_RESTART_LIMIT + value: "5" + - name: HANDLE_MISSING_DATA_TIMES + value: "1" + - name: AWS_METRIC_LIST + value: "CPUUtilization,mem_used_percent,Memory % Committed Bytes In Use,NetworkIn,NetworkOut,DiskReadBytes,EBSReadBytes,DiskWriteBytes,EBSWriteBytes,GroupMinSize,GroupMaxSize,GroupDesiredCapacity,GroupInServiceInstances,GroupPendingInstances,GroupStandbyInstances,GroupTerminatingInstances,GroupTotalInstances" + image: {{ .Values.global.imageRegistry }}/federatorai-data-adapter:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - /bin/bash + - -c + - /livenessProbe.sh + failureThreshold: 10 + initialDelaySeconds: 30 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + name: federatorai-data-adapter + ports: + - containerPort: 8080 + name: export-metrics + protocol: TCP + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.federatoraiDataAdapter.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.federatoraiDataAdapter.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /etc/telegraf/telegraf.conf + name: federatorai-data-adapter-config + subPath: telegraf.conf + - mountPath: /etc/telegraf/telegraf_historical.conf + name: federatorai-data-adapter-historical-config + subPath: telegraf_historical.conf + - mountPath: /var/log + name: federatorai-data-adapter-log-storage + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.federatoraiDataAdapter.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.federatoraiDataAdapter.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.federatoraiDataAdapter.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: federatorai-data-adapter serviceAccountName: federatorai-data-adapter - tolerations: {{- include "render-value" ( dict "value" .Values.federatoraiDataAdapter.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.federatoraiDataAdapter.tolerations }} +{{- include "render-value" ( dict "value" .Values.federatoraiDataAdapter.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - configMap: - defaultMode: 420 + - configMap: + defaultMode: 420 + name: federatorai-data-adapter-config name: federatorai-data-adapter-config - name: federatorai-data-adapter-config - - configMap: - defaultMode: 420 + - configMap: + defaultMode: 420 + name: federatorai-data-adapter-historical-config name: federatorai-data-adapter-historical-config - name: federatorai-data-adapter-historical-config - - emptyDir: {} - name: federatorai-data-adapter-data-storage - - name: federatorai-data-adapter-log-storage - persistentVolumeClaim: - claimName: federatorai-data-adapter-log.pvc + - emptyDir: {} + name: federatorai-data-adapter-data-storage + - name: federatorai-data-adapter-log-storage + persistentVolumeClaim: + claimName: federatorai-data-adapter-log.pvc diff --git a/charts/prophetstor/federatorai/templates/federatorai-data-adapter/pvc-log.yaml b/charts/prophetstor/federatorai/templates/federatorai-data-adapter/pvc-log.yaml index 3570cfb03..f656fb830 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-data-adapter/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-data-adapter/pvc-log.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-data-adapter-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.federatoraiDataAdapter.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.federatoraiDataAdapter.persistence.accessModes }} +{{ .Values.federatoraiDataAdapter.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.federatoraiDataAdapter.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-data-adapter/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/federatorai-data-adapter/serviceaccounts.yaml index e3873f1d8..953c427a9 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-data-adapter/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-data-adapter/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-data-adapter diff --git a/charts/prophetstor/federatorai/templates/federatorai-data-adapter/services.yaml b/charts/prophetstor/federatorai/templates/federatorai-data-adapter/services.yaml index cf04f63a3..87c486cd0 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-data-adapter/services.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-data-adapter/services.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-data-adapter @@ -10,10 +17,10 @@ metadata: namespace: {{ .Release.Namespace }} spec: ports: - - name: export-metrics - port: 8080 - protocol: TCP - targetPort: 8080 + - name: export-metrics + port: 8080 + protocol: TCP + targetPort: 8080 selector: component: federatorai-data-adapter type: ClusterIP diff --git a/charts/prophetstor/federatorai/templates/federatorai-operator/alamedaservice.yaml b/charts/prophetstor/federatorai/templates/federatorai-operator/alamedaservice.yaml index 31b9faaf5..ca57fca8c 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-operator/alamedaservice.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-operator/alamedaservice.yaml @@ -1,10 +1,17 @@ +--- apiVersion: federatorai.containers.ai/v1alpha1 kind: AlamedaService metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} "helm.sh/hook": post-install "helm.sh/hook-weight": "3000" - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: my-alamedaservice diff --git a/charts/prophetstor/federatorai/templates/federatorai-operator/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/federatorai-operator/clusterrolebindings.yaml index d911c10cd..eccb79e2e 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-operator/clusterrolebindings.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-operator/clusterrolebindings.yaml @@ -1,16 +1,25 @@ +--- +{{- if .Values.federatoraiOperator.enabled }} apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-operator subjects: -- kind: ServiceAccount - name: federatorai-operator - namespace: {{ .Release.Namespace }} + - kind: ServiceAccount + name: federatorai-operator + namespace: {{ .Release.Namespace }} roleRef: kind: ClusterRole name: federatorai-operator apiGroup: rbac.authorization.k8s.io +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-operator/clusterroles.yaml b/charts/prophetstor/federatorai/templates/federatorai-operator/clusterroles.yaml index 70e2de2b3..2946ed945 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-operator/clusterroles.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-operator/clusterroles.yaml @@ -1,8 +1,16 @@ +--- +{{- if .Values.federatoraiOperator.enabled }} apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-operator @@ -202,7 +210,11 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: alameda-gc - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} "helm.sh/hook-weight": "5000" "helm.sh/hook": post-install,post-delete rules: [] +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-operator/deployments.yaml b/charts/prophetstor/federatorai/templates/federatorai-operator/deployments.yaml index 475eefe4b..c4ca6826a 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-operator/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-operator/deployments.yaml @@ -1,9 +1,17 @@ +--- +{{- if .Values.federatoraiOperator.enabled }} apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} "helm.sh/hook-weight": "1000" - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai name: federatorai-operator app: Federator.ai @@ -18,17 +26,31 @@ spec: name: federatorai-operator template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai name: federatorai-operator app: Federator.ai spec: - affinity: {{- include "render-value" ( dict "value" .Values.federatoraiOperator.affinity "context" .) | nindent 8 }} - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + affinity: +{{- if .Values.federatoraiOperator.affinity }} +{{- include "render-value" ( dict "value" .Values.federatoraiOperator.affinity "context" .) | nindent 8 }} +{{- end }} + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.federatoraiOperator.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.federatoraiOperator.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.federatoraiOperator.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccountName: federatorai-operator initContainers: - name: upgrader @@ -39,7 +61,7 @@ spec: {{- end }} imagePullPolicy: {{ .Values.global.imagePullPolicy }} args: - - "upgrade" + - "upgrade" env: - name: DO_NOT_DEPLOY_ASSETS value: "true" @@ -58,15 +80,20 @@ spec: - name: FEDERATORAI_OPERATOR_INFLUXDB_PASSWORD value: adminpass resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.federatoraiOperator.resources "context" .) | nindent 12 }} - {{- end }} +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.federatoraiOperator.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.federatoraiOperator.resources.requests "context" .) | nindent 14 }} +{{- end }} volumeMounts: - - mountPath: /var/log/alameda - name: log - - mountPath: /tmp/k8s-webhook-server/serving-certs - name: cert - readOnly: true + - mountPath: /var/log/alameda + name: log + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true containers: - name: federatorai-operator # Replace this with the built image name @@ -102,16 +129,24 @@ spec: successThreshold: 1 timeoutSeconds: 5 resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.federatoraiOperator.resources "context" .) | nindent 12 }} - {{- end }} +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.federatoraiOperator.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.federatoraiOperator.resources.requests "context" .) | nindent 14 }} +{{- end }} volumeMounts: - - mountPath: /var/log/alameda - name: log - - mountPath: /tmp/k8s-webhook-server/serving-certs - name: cert - readOnly: true - tolerations: {{- include "render-value" ( dict "value" .Values.federatoraiOperator.tolerations "context" .) | nindent 6 }} + - mountPath: /var/log/alameda + name: log + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true + tolerations: +{{- if .Values.federatoraiOperator.tolerations }} +{{- include "render-value" ( dict "value" .Values.federatoraiOperator.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - name: log emptyDir: {} @@ -119,3 +154,4 @@ spec: secret: defaultMode: 420 secretName: federatorai-operator-service-cert +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-operator/mutatingwebhookconfigurations.yaml b/charts/prophetstor/federatorai/templates/federatorai-operator/mutatingwebhookconfigurations.yaml index 7112c2f75..f0c611e19 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-operator/mutatingwebhookconfigurations.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-operator/mutatingwebhookconfigurations.yaml @@ -1,30 +1,39 @@ +--- +{{- if .Values.federatoraiOperator.enabled }} apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-operator-servicesmutation webhooks: -- admissionReviewVersions: - - v1beta1 - - v1 - clientConfig: - service: - name: federatorai-operator-service - namespace: {{ .Release.Namespace }} - path: /mutate-federatorai-containers-ai-v1alpha1-alamedaservice - failurePolicy: Ignore - name: alamedaservicemutate.federatorai.containers.ai - rules: - - apiGroups: - - federatorai.containers.ai - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - alamedaservices - sideEffects: None \ No newline at end of file + - admissionReviewVersions: + - v1beta1 + - v1 + clientConfig: + service: + name: federatorai-operator-service + namespace: {{ .Release.Namespace }} + path: /mutate-federatorai-containers-ai-v1alpha1-alamedaservice + failurePolicy: Ignore + name: alamedaservicemutate.federatorai.containers.ai + rules: + - apiGroups: + - federatorai.containers.ai + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - alamedaservices + sideEffects: None +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-operator/rolebindings.yaml b/charts/prophetstor/federatorai/templates/federatorai-operator/rolebindings.yaml index f6bfeba2b..4ad0c5842 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-operator/rolebindings.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-operator/rolebindings.yaml @@ -1,17 +1,26 @@ +--- +{{- if .Values.federatoraiOperator.enabled }} kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-operator namespace: {{ .Release.Namespace }} subjects: -- kind: ServiceAccount - name: federatorai-operator - namespace: {{ .Release.Namespace }} + - kind: ServiceAccount + name: federatorai-operator + namespace: {{ .Release.Namespace }} roleRef: kind: Role name: federatorai-operator apiGroup: rbac.authorization.k8s.io +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-operator/roles.yaml b/charts/prophetstor/federatorai/templates/federatorai-operator/roles.yaml index 66e8e8d20..c4ec91273 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-operator/roles.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-operator/roles.yaml @@ -1,55 +1,64 @@ +--- +{{- if .Values.federatoraiOperator.enabled }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-operator namespace: {{ .Release.Namespace }} rules: -- apiGroups: - - "" - resources: - - configmaps - - endpoints - - persistentvolumeclaims - - pods - - secrets - - services - verbs: - - '*' -- apiGroups: - - "" - resources: - - nodes - - persistentvolumeclaims - - replicationcontrollers - - services - verbs: - - get - - list - - watch -- apiGroups: - - "" - resources: - - pods/exec - verbs: - - create -- apiGroups: - - apps - resources: - - daemonsets - - statefulsets - verbs: - - '*' -- apiGroups: - - apps - - extensions - resources: - - deployments - - replicasets - verbs: - - get - - list - - watch + - apiGroups: + - "" + resources: + - configmaps + - endpoints + - persistentvolumeclaims + - pods + - secrets + - services + verbs: + - '*' + - apiGroups: + - "" + resources: + - nodes + - persistentvolumeclaims + - replicationcontrollers + - services + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - pods/exec + verbs: + - create + - apiGroups: + - apps + resources: + - daemonsets + - statefulsets + verbs: + - '*' + - apiGroups: + - apps + - extensions + resources: + - deployments + - replicasets + verbs: + - get + - list + - watch +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-operator/secrets.yaml b/charts/prophetstor/federatorai/templates/federatorai-operator/secrets.yaml index 89db8b143..4c1b893cf 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-operator/secrets.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-operator/secrets.yaml @@ -1,11 +1,20 @@ +--- +{{- if .Values.federatoraiOperator.enabled }} apiVersion: v1 kind: Secret metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-operator-service-cert namespace: {{ .Release.Namespace }} data: -type: Opaque \ No newline at end of file +type: Opaque +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-operator/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/federatorai-operator/serviceaccounts.yaml index 31daf046e..ce259c902 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-operator/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-operator/serviceaccounts.yaml @@ -1,9 +1,18 @@ +--- +{{- if .Values.federatoraiOperator.enabled }} apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-operator namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-operator/services.yaml b/charts/prophetstor/federatorai/templates/federatorai-operator/services.yaml index 23bac2dbd..4e358ec78 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-operator/services.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-operator/services.yaml @@ -1,8 +1,16 @@ +--- +{{- if .Values.federatoraiOperator.enabled }} apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-operator @@ -10,8 +18,9 @@ metadata: namespace: {{ .Release.Namespace }} spec: ports: - - port: 443 - targetPort: 50443 + - port: 443 + targetPort: 50443 selector: name: federatorai-operator app: Federator.ai +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-operator/validatingwebhookconfigurations.yaml b/charts/prophetstor/federatorai/templates/federatorai-operator/validatingwebhookconfigurations.yaml index db0f5adc3..c0bd4dff3 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-operator/validatingwebhookconfigurations.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-operator/validatingwebhookconfigurations.yaml @@ -1,30 +1,39 @@ +--- +{{- if .Values.federatoraiOperator.enabled }} apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-operator-servicesvalidation webhooks: -- admissionReviewVersions: - - v1beta1 - - v1 - clientConfig: - service: - name: federatorai-operator-service - namespace: {{ .Release.Namespace }} - path: /validate-federatorai-containers-ai-v1alpha1-alamedaservice - failurePolicy: Ignore - name: alamedaservicevalidate.federatorai.containers.ai - rules: - - apiGroups: - - federatorai.containers.ai - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - alamedaservices - sideEffects: None \ No newline at end of file + - admissionReviewVersions: + - v1beta1 + - v1 + clientConfig: + service: + name: federatorai-operator-service + namespace: {{ .Release.Namespace }} + path: /validate-federatorai-containers-ai-v1alpha1-alamedaservice + failurePolicy: Ignore + name: alamedaservicevalidate.federatorai.containers.ai + rules: + - apiGroups: + - federatorai.containers.ai + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - alamedaservices + sideEffects: None +{{- end }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-postgresql/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/federatorai-postgresql/clusterrolebindings.yaml deleted file mode 100644 index ff19d77d1..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-postgresql/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-federatorai-postgresql -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-federatorai-postgresql -subjects: -- kind: ServiceAccount - name: federatorai-postgresql - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-postgresql/clusterroles.yaml b/charts/prophetstor/federatorai/templates/federatorai-postgresql/clusterroles.yaml deleted file mode 100644 index 006e2ca98..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-postgresql/clusterroles.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-federatorai-postgresql -rules: -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use -- apiGroups: - - federatorai.containers.ai - resources: - - '*' - verbs: - - '*' diff --git a/charts/prophetstor/federatorai/templates/federatorai-postgresql/pvc-data.yaml b/charts/prophetstor/federatorai/templates/federatorai-postgresql/pvc-data.yaml index a269fc0b4..48efc6665 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-postgresql/pvc-data.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-postgresql/pvc-data.yaml @@ -1,15 +1,25 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-postgresql name: federatorai-postgresql-data.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.federatoraiPostgresql.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.federatoraiPostgresql.persistence.accessModes }} +{{ .Values.federatoraiPostgresql.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.federatoraiPostgresql.persistence.dataStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-postgresql/pvc-log.yaml b/charts/prophetstor/federatorai/templates/federatorai-postgresql/pvc-log.yaml index d1f5e92bb..768ff24a8 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-postgresql/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-postgresql/pvc-log.yaml @@ -1,15 +1,25 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-postgresql name: federatorai-postgresql-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.federatoraiPostgresql.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.federatoraiPostgresql.persistence.accessModes }} +{{ .Values.federatoraiPostgresql.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.federatoraiPostgresql.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-postgresql/rolebindings.yaml b/charts/prophetstor/federatorai/templates/federatorai-postgresql/rolebindings.yaml new file mode 100644 index 000000000..009f854be --- /dev/null +++ b/charts/prophetstor/federatorai/templates/federatorai-postgresql/rolebindings.yaml @@ -0,0 +1,24 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} + app.kubernetes.io/part-of: federatorai + app: alameda + name: federatorai-postgresql + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: federatorai-postgresql +subjects: + - kind: ServiceAccount + name: federatorai-postgresql + namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-postgresql/roles.yaml b/charts/prophetstor/federatorai/templates/federatorai-postgresql/roles.yaml new file mode 100644 index 000000000..8fc44f39c --- /dev/null +++ b/charts/prophetstor/federatorai/templates/federatorai-postgresql/roles.yaml @@ -0,0 +1,35 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} + app.kubernetes.io/part-of: federatorai + app: alameda + name: federatorai-postgresql + namespace: {{ .Release.Namespace }} +rules: + - apiGroups: + - "" + resources: + - pods + verbs: + - list + - apiGroups: + - "" + resources: + - pods/exec + verbs: + - create + - apiGroups: + - federatorai.containers.ai + resources: + - '*' + verbs: + - '*' diff --git a/charts/prophetstor/federatorai/templates/federatorai-postgresql/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/federatorai-postgresql/serviceaccounts.yaml index f0d069701..a9afcfe11 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-postgresql/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-postgresql/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-postgresql diff --git a/charts/prophetstor/federatorai/templates/federatorai-postgresql/services.yaml b/charts/prophetstor/federatorai/templates/federatorai-postgresql/services.yaml index c7869478b..2727b549b 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-postgresql/services.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-postgresql/services.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-postgresql @@ -10,10 +17,10 @@ metadata: namespace: {{ .Release.Namespace }} spec: ports: - - name: postgresql - port: 5432 - protocol: TCP - targetPort: 5432 + - name: postgresql + port: 5432 + protocol: TCP + targetPort: 5432 selector: component: federatorai-postgresql type: ClusterIP diff --git a/charts/prophetstor/federatorai/templates/federatorai-postgresql/statefulsets.yaml b/charts/prophetstor/federatorai/templates/federatorai-postgresql/statefulsets.yaml index 0915312d9..63bc4d750 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-postgresql/statefulsets.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-postgresql/statefulsets.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: StatefulSet metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-postgresql @@ -17,75 +24,97 @@ spec: serviceName: federatorai-postgresql template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-postgresql spec: - affinity: {{- include "render-value" ( dict "value" .Values.federatoraiPostgresql.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.federatoraiPostgresql.affinity }} +{{- include "render-value" ( dict "value" .Values.federatoraiPostgresql.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - env: - - name: POSTGRES_DB - value: federatorai - - name: POSTGRES_PASSWORD - value: adminpass - - name: POSTGRES_USER - value: postgres - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/federatorai-postgresql:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: - - sh - - -c - - /init.sh liveness - failureThreshold: 3 - initialDelaySeconds: 600 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 30 - name: federatorai-postgresql - ports: - - containerPort: 5432 - name: postgres - protocol: TCP - readinessProbe: - exec: - command: - - sh - - -c - - /init.sh readiness - failureThreshold: 3 - initialDelaySeconds: 30 - periodSeconds: 30 - successThreshold: 1 - timeoutSeconds: 30 - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.federatoraiPostgresql.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/log/postgresql - name: federatorai-postgresql-log-storage - subPath: postgresql - - mountPath: /var/lib/postgresql/data - name: federatorai-postgresql-data-storage - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - env: + - name: POSTGRES_DB + value: federatorai + - name: POSTGRES_PASSWORD + value: adminpass + - name: POSTGRES_USER + value: postgres + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/federatorai-postgresql:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - sh + - -c + - /init.sh liveness + failureThreshold: 3 + initialDelaySeconds: 600 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 30 + name: federatorai-postgresql + ports: + - containerPort: 5432 + name: postgres + protocol: TCP + readinessProbe: + exec: + command: + - sh + - -c + - /init.sh readiness + failureThreshold: 3 + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 30 + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.federatoraiPostgresql.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.federatoraiPostgresql.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /var/log/postgresql + name: federatorai-postgresql-log-storage + subPath: postgresql + - mountPath: /var/lib/postgresql/data + name: federatorai-postgresql-data-storage + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.federatoraiPostgresql.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.federatoraiPostgresql.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.federatoraiPostgresql.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: federatorai-postgresql serviceAccountName: federatorai-postgresql - tolerations: {{- include "render-value" ( dict "value" .Values.federatoraiPostgresql.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.federatoraiPostgresql.tolerations }} +{{- include "render-value" ( dict "value" .Values.federatoraiPostgresql.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - name: federatorai-postgresql-data-storage - persistentVolumeClaim: - claimName: federatorai-postgresql-data.pvc - - name: federatorai-postgresql-log-storage - persistentVolumeClaim: - claimName: federatorai-postgresql-log.pvc + - name: federatorai-postgresql-data-storage + persistentVolumeClaim: + claimName: federatorai-postgresql-data.pvc + - name: federatorai-postgresql-log-storage + persistentVolumeClaim: + claimName: federatorai-postgresql-log.pvc updateStrategy: type: RollingUpdate diff --git a/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/clusterrolebindings.yaml deleted file mode 100644 index 4af90c50d..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-federatorai-recommender-dispatcher -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-federatorai-recommender-dispatcher -subjects: -- kind: ServiceAccount - name: federatorai-recommender-dispatcher - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/clusterroles.yaml b/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/clusterroles.yaml deleted file mode 100644 index 2d24b2c7e..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/clusterroles.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-federatorai-recommender-dispatcher -rules: -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use diff --git a/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/configmaps.yaml b/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/configmaps.yaml index 49d00c890..4f3a72b77 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/configmaps.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/configmaps.yaml @@ -1,3 +1,4 @@ +--- apiVersion: v1 data: dispatcher.toml: |- @@ -55,8 +56,14 @@ data: cache_ttl = 3600 # 0 means no ttl kind: ConfigMap metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-recommender-dispatcher-config diff --git a/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/deployments.yaml b/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/deployments.yaml index 40c25aa1a..4c9d23a2e 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/deployments.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-recommender-dispatcher @@ -18,79 +25,101 @@ spec: type: Recreate template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-recommender-dispatcher spec: - affinity: {{- include "render-value" ( dict "value" .Values.federatoraiRecommenderDispatcher.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.federatoraiRecommenderDispatcher.affinity }} +{{- include "render-value" ( dict "value" .Values.federatoraiRecommenderDispatcher.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - command: - - /usr/local/bin/federatorai-recommender - - dispatcher - env: - - name: NAMESPACE_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.name - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/alameda-recommender-ubi:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: + - command: - /usr/local/bin/federatorai-recommender - dispatcher - - --mode=livenessprob - failureThreshold: 3 - initialDelaySeconds: 10 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 30 - name: federatorai-recommender-dispatcher - readinessProbe: - exec: - command: - - /usr/local/bin/federatorai-recommender - - dispatcher - - --mode=readinessprob - failureThreshold: 3 - initialDelaySeconds: 10 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 30 - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.federatoraiRecommenderDispatcher.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/log/alameda - name: federatorai-recommender-dispatcher-log-storage - - mountPath: /etc/alameda/federatorai-recommendation/dispatcher.toml - name: federatorai-recommender-dispatcher-config - subPath: dispatcher.toml - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + env: + - name: NAMESPACE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/alameda-recommender-ubi:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - /usr/local/bin/federatorai-recommender + - dispatcher + - --mode=livenessprob + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 30 + name: federatorai-recommender-dispatcher + readinessProbe: + exec: + command: + - /usr/local/bin/federatorai-recommender + - dispatcher + - --mode=readinessprob + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 30 + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.federatoraiRecommenderDispatcher.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.federatoraiRecommenderDispatcher.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /var/log/alameda + name: federatorai-recommender-dispatcher-log-storage + - mountPath: /etc/alameda/federatorai-recommendation/dispatcher.toml + name: federatorai-recommender-dispatcher-config + subPath: dispatcher.toml + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.federatoraiRecommenderDispatcher.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.federatoraiRecommenderDispatcher.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.federatoraiRecommenderDispatcher.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: federatorai-recommender-dispatcher serviceAccountName: federatorai-recommender-dispatcher - tolerations: {{- include "render-value" ( dict "value" .Values.federatoraiRecommenderDispatcher.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.federatoraiRecommenderDispatcher.tolerations }} +{{- include "render-value" ( dict "value" .Values.federatoraiRecommenderDispatcher.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - emptyDir: {} - name: federatorai-recommender-dispatcher-data-storage - - name: federatorai-recommender-dispatcher-log-storage - persistentVolumeClaim: - claimName: federatorai-recommender-dispatcher-log.pvc - - configMap: - defaultMode: 420 + - emptyDir: {} + name: federatorai-recommender-dispatcher-data-storage + - name: federatorai-recommender-dispatcher-log-storage + persistentVolumeClaim: + claimName: federatorai-recommender-dispatcher-log.pvc + - configMap: + defaultMode: 420 + name: federatorai-recommender-dispatcher-config name: federatorai-recommender-dispatcher-config - name: federatorai-recommender-dispatcher-config diff --git a/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/pvc-log.yaml b/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/pvc-log.yaml index ee63af369..adaf5e3a9 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/pvc-log.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-recommender-dispatcher-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.federatoraiRecommenderDispatcher.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.federatoraiRecommenderDispatcher.persistence.accessModes }} +{{ .Values.federatoraiRecommenderDispatcher.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.federatoraiRecommenderDispatcher.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/serviceaccounts.yaml index 26de87c65..f966bf231 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-recommender-dispatcher/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-recommender-dispatcher diff --git a/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/clusterrolebindings.yaml deleted file mode 100644 index f26231c2b..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-federatorai-recommender-worker -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-federatorai-recommender-worker -subjects: -- kind: ServiceAccount - name: federatorai-recommender-worker - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/clusterroles.yaml b/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/clusterroles.yaml deleted file mode 100644 index d051c98b6..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/clusterroles.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-federatorai-recommender-worker -rules: -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use diff --git a/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/configmaps.yaml b/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/configmaps.yaml index 6d5b9d43c..0f5d78875 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/configmaps.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/configmaps.yaml @@ -1,3 +1,4 @@ +--- apiVersion: v1 data: worker.toml: |- @@ -75,8 +76,14 @@ data: apply_after = 60 kind: ConfigMap metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-recommender-worker-config diff --git a/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/deployments.yaml b/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/deployments.yaml index 368030a48..c4514ff23 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/deployments.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-recommender-worker @@ -18,82 +25,104 @@ spec: type: Recreate template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-recommender-worker spec: - affinity: {{- include "render-value" ( dict "value" .Values.federatoraiRecommenderWorker.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.federatoraiRecommenderWorker.affinity }} +{{- include "render-value" ( dict "value" .Values.federatoraiRecommenderWorker.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - command: - - /usr/local/bin/federatorai-recommender - - worker - env: - - name: NAMESPACE_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.name - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/alameda-recommender-ubi:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: + - command: - /usr/local/bin/federatorai-recommender - worker - - --mode=livenessprob - failureThreshold: 3 - initialDelaySeconds: 10 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 30 - name: federatorai-recommender-worker - readinessProbe: - exec: - command: - - /usr/local/bin/federatorai-recommender - - worker - - --mode=readinessprob - failureThreshold: 3 - initialDelaySeconds: 10 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 30 - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.federatoraiRecommenderWorker.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/lib/alameda - name: federatorai-recommender-worker-data-storage - - mountPath: /var/log/alameda - name: federatorai-recommender-worker-log-storage - - mountPath: /etc/alameda/federatorai-recommendation/worker.toml - name: federatorai-recommender-worker-config - subPath: worker.toml - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + env: + - name: NAMESPACE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/alameda-recommender-ubi:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - /usr/local/bin/federatorai-recommender + - worker + - --mode=livenessprob + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 30 + name: federatorai-recommender-worker + readinessProbe: + exec: + command: + - /usr/local/bin/federatorai-recommender + - worker + - --mode=readinessprob + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 30 + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.federatoraiRecommenderWorker.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.federatoraiRecommenderWorker.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /var/lib/alameda + name: federatorai-recommender-worker-data-storage + - mountPath: /var/log/alameda + name: federatorai-recommender-worker-log-storage + - mountPath: /etc/alameda/federatorai-recommendation/worker.toml + name: federatorai-recommender-worker-config + subPath: worker.toml + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - {{- include "render-value" ( dict "value" .Values.federatoraiRecommenderWorker.podSecurityContext "context" .) | nindent 8 }} +{{- if .Values.federatoraiRecommenderWorker.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.federatoraiRecommenderWorker.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: federatorai-recommender-worker serviceAccountName: federatorai-recommender-worker - tolerations: {{- include "render-value" ( dict "value" .Values.federatoraiRecommenderWorker.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.federatoraiRecommenderWorker.tolerations }} +{{- include "render-value" ( dict "value" .Values.federatoraiRecommenderWorker.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - name: federatorai-recommender-worker-data-storage - persistentVolumeClaim: - claimName: federatorai-recommender-worker-data.pvc - - name: federatorai-recommender-worker-log-storage - persistentVolumeClaim: - claimName: federatorai-recommender-worker-log.pvc - - configMap: - defaultMode: 420 + - name: federatorai-recommender-worker-data-storage + persistentVolumeClaim: + claimName: federatorai-recommender-worker-data.pvc + - name: federatorai-recommender-worker-log-storage + persistentVolumeClaim: + claimName: federatorai-recommender-worker-log.pvc + - configMap: + defaultMode: 420 + name: federatorai-recommender-worker-config name: federatorai-recommender-worker-config - name: federatorai-recommender-worker-config diff --git a/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/pvc-data.yaml b/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/pvc-data.yaml index 9c909f3ff..ab5d80c51 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/pvc-data.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/pvc-data.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-recommender-worker-data.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.federatoraiRecommenderWorker.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.federatoraiRecommenderWorker.persistence.accessModes }} +{{ .Values.federatoraiRecommenderWorker.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.federatoraiRecommenderWorker.persistence.dataStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/pvc-log.yaml b/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/pvc-log.yaml index 8c78ecc68..0e20126a4 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/pvc-log.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-recommender-worker-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.federatoraiRecommenderWorker.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.federatoraiRecommenderWorker.persistence.accessModes }} +{{ .Values.federatoraiRecommenderWorker.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.federatoraiRecommenderWorker.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/serviceaccounts.yaml index a70307e47..f08fd99db 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-recommender-worker/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-recommender-worker diff --git a/charts/prophetstor/federatorai/templates/federatorai-rest/clusterrolebindings.yaml b/charts/prophetstor/federatorai/templates/federatorai-rest/clusterrolebindings.yaml deleted file mode 100644 index 7d88b1da4..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-rest/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-federatorai-rest -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-federatorai-rest -subjects: -- kind: ServiceAccount - name: federatorai-rest - namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-rest/clusterroles.yaml b/charts/prophetstor/federatorai/templates/federatorai-rest/clusterroles.yaml deleted file mode 100644 index 80adf9b25..000000000 --- a/charts/prophetstor/federatorai/templates/federatorai-rest/clusterroles.yaml +++ /dev/null @@ -1,48 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} - app.kubernetes.io/part-of: federatorai - app: alameda - name: {{ .Release.Namespace }}-federatorai-rest -rules: -- apiGroups: - - "" - resources: - - nodes - verbs: - - list -- apiGroups: - - "" - resources: - - namespaces - - services - verbs: - - get -- apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch -- apiGroups: - - policy - resources: - - podsecuritypolicies - verbs: - - use -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use -- apiGroups: - - route.openshift.io - resources: - - routes - verbs: - - get diff --git a/charts/prophetstor/federatorai/templates/federatorai-rest/configmaps-auto-provision-template.yaml b/charts/prophetstor/federatorai/templates/federatorai-rest/configmaps-auto-provision-template.yaml new file mode 100644 index 000000000..9dd846b63 --- /dev/null +++ b/charts/prophetstor/federatorai/templates/federatorai-rest/configmaps-auto-provision-template.yaml @@ -0,0 +1,2461 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} + app.kubernetes.io/part-of: federatorai + app: alameda + name: auto-provision-script-template + namespace: {{ .Release.Namespace }} +data: + planning-util.sh.template: |- + #!/usr/bin/env bash + + # Creation Time: {{`{{.CreateTime}}`}} Version: {{ .Chart.AppVersion }} Build: {{ .Chart.Name }}-{{ .Chart.Version }} + #=========================== target config info start ========================= + target_config_info='{{`{{.TargetConfigInfo}}`}}' + {{`{{.TfComment}}`}}#=========================== target config info end =========================== + + if [ "$BASH_VERSION" = "" ]; then + err_code="6" + /bin/echo -e "{\n \"reason\": \"Please use bash to run the script.\",\n \"error_code\": $err_code\n}" + exit $err_code + fi + set -o pipefail + + awk_egrep () { + local pattern_string=$1 + + gawk '{ + while ($0) { + start=match($0, pattern); + token=substr($0, start, RLENGTH); + print token; + $0=substr($0, start+RLENGTH); + } + }' pattern="$pattern_string" + } + + tokenize_json () { + input="$1" + local GREP + local ESCAPE + local CHAR + + if echo "test string" | egrep -ao --color=never "test" >/dev/null 2>&1 + then + GREP='egrep -ao --color=never' + else + GREP='egrep -ao' + fi + + if echo "test string" | egrep -o "test" >/dev/null 2>&1 + then + ESCAPE='(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})' + CHAR='[^[:cntrl:]"\\]' + else + GREP=awk_egrep + ESCAPE='(\\\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})' + CHAR='[^[:cntrl:]"\\\\]' + fi + + local STRING="\"$CHAR*($ESCAPE$CHAR*)*\"" + local NUMBER='-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?' + local KEYWORD='null|false|true' + local SPACE='[[:space:]]+' + + # Force zsh to expand $A into multiple words + local is_wordsplit_disabled=$(unsetopt 2>/dev/null | grep -c '^shwordsplit$') + if [ $is_wordsplit_disabled != 0 ]; then setopt shwordsplit; fi + echo "$input"|$GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | egrep -v "^$SPACE$" + if [ $is_wordsplit_disabled != 0 ]; then unsetopt shwordsplit; fi + } + + parse_json_array () { + local index=0 + local ary='' + read -r token + case "$token" in + ']') ;; + *) + while : + do + parse_json_value "$1" "$index" + index=$((index+1)) + ary="$ary""$value" + read -r token + case "$token" in + ']') break ;; + ',') ary="$ary," ;; + *) exit 71;; + esac + read -r token + done + ;; + esac + [ "$BRIEF" -eq 0 ] && value=$(printf '[%s]' "$ary") || value= + : + } + + parse_json_object () { + local key + local obj='' + read -r token + case "$token" in + '}') ;; + *) + while : + do + case "$token" in + '"'*'"') key=$token ;; + *) exit 70;; + esac + read -r token + case "$token" in + ':') ;; + *) exit 73;; + esac + read -r token + parse_json_value "$1" "$key" + obj="$obj$key:$value" + read -r token + case "$token" in + '}') break ;; + ',') obj="$obj," ;; + *) exit 74;; + esac + read -r token + done + ;; + esac + [ "$BRIEF" -eq 0 ] && value=$(printf '{%s}' "$obj") || value= + : + } + + parse_json_value () { + local jpath="${1:+$1,}$2" isleaf=0 isempty=0 print=0 + case "$token" in + '{') parse_json_object "$jpath" ;; + '[') parse_json_array "$jpath" ;; + # At this point, the only valid single-character tokens are digits. + ''|[!0-9]) exit 75;; + *) value=$token + # if asked, replace solidus ("\/") in json strings with normalized value: "/" + [ "$NORMALIZE_SOLIDUS" -eq 1 ] && value=$(echo "$value" | sed 's#\\/#/#g') + isleaf=1 + [ "$value" = '""' ] && isempty=1 + ;; + esac + [ "$value" = '' ] && return + [ "$NO_HEAD" -eq 1 ] && [ -z "$jpath" ] && return + + [ "$LEAFONLY" -eq 0 ] && [ "$PRUNE" -eq 0 ] && print=1 + [ "$LEAFONLY" -eq 1 ] && [ "$isleaf" -eq 1 ] && [ $PRUNE -eq 0 ] && print=1 + [ "$LEAFONLY" -eq 0 ] && [ "$PRUNE" -eq 1 ] && [ "$isempty" -eq 0 ] && print=1 + [ "$LEAFONLY" -eq 1 ] && [ "$isleaf" -eq 1 ] && \ + [ $PRUNE -eq 1 ] && [ $isempty -eq 0 ] && print=1 + [ "$print" -eq 1 ] && printf "[%s]\t%s\n" "$jpath" "$value" + : + } + + parse_json_begin () { + read -r token + parse_json_value + read -r token + case "$token" in + '') ;; + *) exit 72;; + esac + } + + check_target_config() + { + if [ -z "$target_config_info" ]; then + err_code="2" + show_error "target_config_info variable is not defined." $err_code + exit $err_code + else + echo "-------------- config info ----------------" >> $debug_log + # Hide password + echo "$target_config_info" |sed 's/"login_password.*/"login_password": *****/g' >> $debug_log + echo "-----------------------------------------------------" >> $debug_log + fi + } + + show_usage() + { + cat << __EOF__ + + Usage: + Requirement: + Modify "target_config_info" variable at the beginning of this script to specify target's info + Run the script: + bash $(basename $BASH_SOURCE) + Standalone options: + --test-connection-only + --dry-run-only + --verbose + --log-name [/] [e.g., --log-name mycluster.log] + --terraform-path [e.g., --terraform-path /var/test/output] + __EOF__ + } + + show_info() + { + if [ "$verbose_mode" = "y" ]; then + tee -a $debug_log 1>&2 << __EOF__ + $* + __EOF__ + else + echo "$*" >> $debug_log + fi + return 0 + } + + show_error() + { + echo -e "{\n \"reason\": \"$1\",\n \"error_code\": $2,\n \"log_file\": \"$debug_log\"\n}" | tee -a $debug_log + } + + show_detail_to_stderr() + { + echo "$*" >> $debug_log + if [ "$detail_to_stderr" = "y" ]; then + echo "$*" 1>&2 + fi + } + + check_user_token() + { + if [ "$access_token" = "null" ] || [ "$access_token" = "" ]; then + err_code="2" + show_error "Failed to get login token from REST API." $err_code + show_detail_to_stderr "Please check login account and login password." + exit $err_code + fi + } + + parse_value_from_target_var() + { + target_string="$1" + if [ -z "$target_string" ]; then + err_code="2" + show_error "parse_value_from_target_var() target_string parameter can't be empty." $err_code + exit $err_code + fi + echo "$target_config_info"|tr -d '\n'|grep -o "\"$target_string\":[^\"]*\"[^\"]*\""|sed -E 's/".*".*"(.*)"/\1/' + } + + check_rest_api_url() + { + show_info "Getting REST API URL..." + api_url=$(parse_value_from_target_var "rest_api_url") + + if [ "$api_url" = "" ]; then + err_code="2" + show_error "Failed to get REST API URL from target_config_info." $err_code + exit $err_code + fi + show_info "REST API URL = $api_url" + show_info "Done." + } + + rest_api_login() + { + show_info "Logging into REST API..." + if [ "$FEDERATORAI_ACCESS_TOKEN" = "" ]; then + login_account=$(parse_value_from_target_var "login_account") + if [ "$login_account" = "" ]; then + err_code="2" + show_error "Failed to get login account from target_config_info." $err_code + exit $err_code + fi + login_password=$(parse_value_from_target_var "login_password") + if [ "$login_password" = "" ]; then + err_code="2" + show_error "Failed to get login password from target_config_info." $err_code + exit $err_code + fi + auth_string="${login_account}:${login_password}" + auth_cipher=$(echo -n "$auth_string"|base64) + if [ "$auth_cipher" = "" ]; then + err_code="2" + show_error "Failed to encode login string using base64 command." $err_code + exit $err_code + fi + rest_output=$(curl -sS -k -X POST "$api_url/apis/v1/users/login" -H "accept: application/json" -H "authorization: Basic ${auth_cipher}") + if [ "$?" != "0" ]; then + err_code="3" + show_error "Failed to connect to REST API service ($api_url/apis/v1/users/login)" $err_code + show_detail_to_stderr "Please check REST API IP/login account/login password" + exit $err_code + fi + access_token="$(echo $rest_output|tr -d '\n'|grep -o "\"accessToken\":[^\"]*\"[^\"]*\""|sed -E 's/".*".*"(.*)"/\1/')" + else + access_token="$FEDERATORAI_ACCESS_TOKEN" + # Examine http response code + token_test_http_response="$(curl -o /dev/null -sS -k -X GET "$api_url/apis/v1/resources/clusters" -w "%{http_code}" -H "accept: application/json" -H "Authorization: Bearer $access_token")" + if [ "$token_test_http_response" != "200" ]; then + err_code="3" + show_error "The access_token can't access the REST API service." $err_code + exit $err_code + fi + fi + + check_user_token + + show_info "Done." + } + + do_application_way(){ + show_info "Getting the information of controller under application ..." + exec_cmd="curl -sS -k -X GET \"$api_url/apis/v1/configs/scaler\" -H \"accept: application/json\" -H \"Authorization: Bearer $access_token\"" + rest_output=$(eval $exec_cmd) + + if [ "$?" != "0" ]; then + err_code="3" + show_error "Failed to get clusters info using REST API (Command: $exec_cmd)" $err_code + exit $err_code + fi + + scaler_all="$rest_output" + + # check if return is '"plannings":[]}' + scaler_count=${#scaler_all} + if [ "$scaler_all" = "" ] || [ "$scaler_count" -le "18" ]; then + err_code="1" + show_error "Scaler info is empty." $err_code + show_detail_to_stderr "REST API output: ${rest_output}" + exit $err_code + fi + + data=$(tokenize_json "$scaler_all"| parse_json_begin) + err_code="$?" + if [ "$err_code" != "0" ]; then + show_error "Failed to parse json output (scaler result)." $err_code + exit $err_code + fi + #echo "$data" + scaler_record_no=$(echo "$data"|cut -d ',' -f2|sort -n -r|head -1) + scaler_found="n" + controller_name_array=() + controller_namespace_array=() + controller_kind_array=() + controller_profile_array=() + profile_array=() + + for scaler_index in `seq 0 $scaler_record_no` + do + obj_name=$(get_valued_from_parsed_json "$data" "\[\"data\",$scaler_index,\"object_meta\",\"name\"\]") + target_cluster_name=$(get_valued_from_parsed_json "$data" "\[\"data\",$scaler_index,\"target_cluster_name\"\]") + if [ "$obj_name" = "$resource_name" ] && [ "$target_cluster_name" = "$cluster_name" ]; then + scaler_found="y" + controller_record_no=$(echo "$data"|grep "\[\"data\",$scaler_index,\"controllers\","|cut -d ',' -f4|sort -n -r|head -1) + + doable_controller_found="n" + for controller_index in `seq 0 $controller_record_no` + do + application_type=$(get_valued_from_parsed_json "$data" "\[\"data\",$scaler_index,\"controllers\",$controller_index,\"application_type\"\]") + #echo "application_type=$controller_index $application_type" + scaling_type=$(get_valued_from_parsed_json "$data" "\[\"data\",$scaler_index,\"controllers\",$controller_index,\"scaling_type\"\]") + #echo "scaling_type=$controller_index $scaling_type" + if [ "$application_type" = "generic" ] && [ "$scaling_type" = "1" ]; then + doable_controller_found="y" + controller_name=$(get_valued_from_parsed_json "$data" "\[\"data\",$scaler_index,\"controllers\",$controller_index,\"generic\",\"target\",\"name\"\]") + #echo "controller_name=$controller_index $controller_name" + controller_namespace=$(get_valued_from_parsed_json "$data" "\[\"data\",$scaler_index,\"controllers\",$controller_index,\"generic\",\"target\",\"namespace\"\]") + controller_kind=$(get_valued_from_parsed_json "$data" "\[\"data\",$scaler_index,\"controllers\",$controller_index,\"generic\",\"target\",\"controller_kind\"\]") + + [ "$controller_kind" = "1" ] && controller_kind="deployment" + [ "$controller_kind" = "2" ] && controller_kind="statefulset" + [ "$controller_kind" = "3" ] && controller_kind="deploymentconfig" + #echo "$controller_name $controller_namespace $controller_kind" + controller_name_array+=( "$controller_name" ) + controller_namespace_array+=( "$controller_namespace" ) + controller_kind_array+=( "$controller_kind" ) + fi + done + break + fi + done + if [ "$scaler_found" != "y" ]; then + err_code="1" + show_error "Failed to locate application info in scaler settings." $err_code + exit $err_code + fi + if [ "$doable_controller_found" != "y" ]; then + err_code="1" + show_error "No suitable controller (Generic, Non HPA) found under application." $err_code + exit $err_code + fi + + # Get controller allocation (profile) info + exec_cmd="curl -sS -k -X GET \"$api_url/apis/v1/autoprovision/allocations/controllers\" -H \"accept: application/json\" -H \"Authorization: Bearer $access_token\"" + rest_output=$(eval $exec_cmd) + + if [ "$?" != "0" ]; then + err_code="3" + show_error "Failed to get autoprovision allocation info using REST API (Command: $exec_cmd)" $err_code + exit $err_code + fi + + allocation_all="$rest_output" + data=$(tokenize_json "$allocation_all"| parse_json_begin) + err_code="$?" + if [ "$err_code" != "0" ]; then + show_error "Failed to parse json output (allocation result)." $err_code + exit $err_code + fi + + allocation_record_no=$(echo "$data"|cut -d ',' -f2|sort -n -r|head -1) + con_array_len=${#controller_name_array[@]} + + if [ "$allocation_record_no" = "" ]; then + for con_index in `seq 0 $(( con_array_len - 1 ))` + do + controller_profile_array+=( "noprofilematch" ) + done + else + for con_index in `seq 0 $(( con_array_len - 1 ))` + do + profile_found="n" + con_name=${controller_name_array[con_index]} + con_namespace=${controller_namespace_array[con_index]} + con_kind=${controller_kind_array[con_index]} + for allocation_index in `seq 0 $allocation_record_no` + do + #echo "allocation_index = $allocation_index" + tmp_c_name=$(get_valued_from_parsed_json "$data" "\[\"data\",$allocation_index,\"name\"\]") + tmp_c_namespace=$(get_valued_from_parsed_json "$data" "\[\"data\",$allocation_index,\"namespace\"\]") + tmp_cluster_name=$(get_valued_from_parsed_json "$data" "\[\"data\",$allocation_index,\"cluster_name\"\]") + tmp_profile_name=$(get_valued_from_parsed_json "$data" "\[\"data\",$allocation_index,\"profile_name\"\]") + tmp_profile_type=$(get_valued_from_parsed_json "$data" "\[\"data\",$allocation_index,\"profile_type\"\]") + tmp_c_kind=$(get_valued_from_parsed_json "$data" "\[\"data\",$allocation_index,\"kind\"\]") + tmp_c_kind="$(echo "$tmp_c_kind" | tr '[:upper:]' '[:lower:]')" + if [ "$tmp_cluster_name" = "$cluster_name" ] && [ "$tmp_c_name" = "$con_name" ] && [ "$tmp_c_namespace" = "$con_namespace" ] && [ "$tmp_profile_type" = "k8s" ] && [ "$tmp_c_kind" = "$con_kind" ]; then + profile_found="y" + controller_profile_array+=( "$tmp_profile_name" ) + fi + done + if [ "$profile_found" != "y" ]; then + controller_profile_array+=( "noprofilematch" ) + fi + done + fi + + get_profile_detail + + for con_index in `seq 0 $(( con_array_len - 1 ))` + do + export resource_type=controller + export resource_name=${controller_name_array[con_index]} + export target_namespace=${controller_namespace_array[con_index]} + export owner_reference_kind=${controller_kind_array[con_index]} + + show_info "Cluster name = $cluster_name" + show_info "Resource type = $resource_type" + show_info "Resource name = $resource_name" + show_info "Kind = $owner_reference_kind" + show_info "Namespace = $target_namespace" + + c_profile_name=${controller_profile_array[con_index]} + if [ "$c_profile_name" != "noprofilematch" ]; then + for profile in "${profile_array[@]}" + do + p_name=$(echo "$profile"|cut -d ',' -f1) + if [ "$c_profile_name" = "$p_name" ]; then + export readable_granularity=$(echo "$profile"|cut -d ',' -f2) + export cpu_headroom=$(echo "$profile"|cut -d ',' -f3) + export min_cpu=$(echo "$profile"|cut -d ',' -f4) + export max_cpu=$(echo "$profile"|cut -d ',' -f5) + export memory_headroom=$(echo "$profile"|cut -d ',' -f6) + export min_memory=$(echo "$profile"|cut -d ',' -f7) + export max_memory=$(echo "$profile"|cut -d ',' -f8) + export trigger_condition=$(echo "$profile"|cut -d ',' -f9) + break + fi + done + else + # reset + export readable_granularity=$app_granularity + unset cpu_headroom + unset cpu_headroom_mode + unset min_cpu + unset max_cpu + unset memory_headroom + unset memory_headroom_mode + unset min_memory + unset max_memory + unset trigger_condition + fi + parse_condition + normal_way + done + } + + get_profile_detail(){ + # Get profile detail + exec_cmd="curl -sS -k -X GET \"$api_url/apis/v1/autoprovision/profiles?profile_type=k8s&task_type=auto_provision\" -H \"accept: application/json\" -H \"Authorization: Bearer $access_token\"" + rest_output=$(eval $exec_cmd) + + if [ "$?" != "0" ]; then + err_code="3" + show_error "Failed to get profile info using REST API (Command: $exec_cmd)" $err_code + exit $err_code + fi + + profile_all="$rest_output" + data=$(tokenize_json "$profile_all"| parse_json_begin) + err_code="$?" + if [ "$err_code" != "0" ]; then + show_error "Failed to parse json output (profile result)." $err_code + exit $err_code + fi + + profile_record_no=$(echo "$data"|cut -d ',' -f2|sort -n -r|head -1) + + if [ "$profile_record_no" != "" ]; then + for profile_index in `seq 0 $profile_record_no` + do + tmp_p_name=$(get_valued_from_parsed_json "$data" "\[\"data\",$profile_index,\"name\"\]") + tmp_p_recommendation_window=$(get_valued_from_parsed_json "$data" "\[\"data\",$profile_index,\"recommendation_window\"\]") + + tmp_p_cpu_headroom=$(get_valued_from_parsed_json "$data" "\[\"data\",$profile_index,\"cpu_headroom\"\]") + if [[ $tmp_p_cpu_headroom =~ ^[0-9]+m$ ]]; then + # Remove last 'm' + if [ "$machine_type" = "Linux" ]; then + tmp_p_cpu_headroom=`echo ${tmp_p_cpu_headroom::-1}` + else + # Mac + tmp_p_cpu_headroom=`echo "${tmp_p_cpu_headroom%?}"` + fi + fi + + tmp_p_cpu_minimum=$(get_valued_from_parsed_json "$data" "\[\"data\",$profile_index,\"cpu_minimum\"\]") + if [[ $tmp_p_cpu_minimum =~ ^[0-9]+$ ]]; then + # Convert to mCore + tmp_p_cpu_minimum=$(( tmp_p_cpu_minimum * 1000 )) + elif [[ $tmp_p_cpu_minimum =~ ^[0-9]+m$ ]]; then + # Remove last 'm' + if [ "$machine_type" = "Linux" ]; then + tmp_p_cpu_minimum=`echo ${tmp_p_cpu_minimum::-1}` + else + # Mac + tmp_p_cpu_minimum=`echo "${tmp_p_cpu_minimum%?}"` + fi + fi + + tmp_p_cpu_maximum=$(get_valued_from_parsed_json "$data" "\[\"data\",$profile_index,\"cpu_maximum\"\]") + if [[ $tmp_p_cpu_maximum =~ ^[0-9]+$ ]]; then + # Convert to mCore + tmp_p_cpu_maximum=$(( tmp_p_cpu_maximum * 1000 )) + elif [[ $tmp_p_cpu_maximum =~ ^[0-9]+m$ ]]; then + # Remove last 'm' + if [ "$machine_type" = "Linux" ]; then + tmp_p_cpu_maximum=`echo ${tmp_p_cpu_maximum::-1}` + else + # Mac + tmp_p_cpu_maximum=`echo "${tmp_p_cpu_maximum%?}"` + fi + fi + + tmp_p_memory_headroom=$(get_valued_from_parsed_json "$data" "\[\"data\",$profile_index,\"memory_headroom\"\]") + if [[ $tmp_p_memory_headroom =~ ^[0-9]+Mi$ ]] || [[ $tmp_p_memory_headroom =~ ^[0-9]+Gi$ ]]; then + if [ "$machine_type" = "Linux" ]; then + tmp_h=`echo ${tmp_p_memory_headroom::-2}` + else + # Mac + tmp_h=`echo "${tmp_p_memory_headroom%??}"` + fi + fi + if [[ $tmp_p_memory_headroom =~ ^[0-9]+Mi$ ]]; then + # Convert Mi to byte + tmp_p_memory_headroom=$(( tmp_h * 1024 * 1024 )) + elif [[ $tmp_p_memory_headroom =~ ^[0-9]+Gi$ ]]; then + # Convert Gi to byte + tmp_p_memory_headroom=$(( tmp_h * 1024 * 1024 * 1024 )) + fi + + tmp_p_memory_minimum=$(get_valued_from_parsed_json "$data" "\[\"data\",$profile_index,\"memory_minimum\"\]") + if [[ $tmp_p_memory_minimum =~ ^[0-9]+Mi$ ]] || [[ $tmp_p_memory_minimum =~ ^[0-9]+Gi$ ]]; then + if [ "$machine_type" = "Linux" ]; then + tmp_h=`echo ${tmp_p_memory_minimum::-2}` + else + # Mac + tmp_h=`echo "${tmp_p_memory_minimum%??}"` + fi + fi + if [[ $tmp_p_memory_minimum =~ ^[0-9]+Mi$ ]]; then + # Convert Mi to byte + tmp_p_memory_minimum=$(( tmp_h * 1024 * 1024 )) + elif [[ $tmp_p_memory_minimum =~ ^[0-9]+Gi$ ]]; then + # Convert Gi to byte + tmp_p_memory_minimum=$(( tmp_h * 1024 * 1024 * 1024 )) + fi + + tmp_p_memory_maximum=$(get_valued_from_parsed_json "$data" "\[\"data\",$profile_index,\"memory_maximum\"\]") + if [[ $tmp_p_memory_maximum =~ ^[0-9]+Mi$ ]] || [[ $tmp_p_memory_maximum =~ ^[0-9]+Gi$ ]]; then + if [ "$machine_type" = "Linux" ]; then + tmp_h=`echo ${tmp_p_memory_maximum::-2}` + else + # Mac + tmp_h=`echo "${tmp_p_memory_maximum%??}"` + fi + fi + if [[ $tmp_p_memory_maximum =~ ^[0-9]+Mi$ ]]; then + # Convert Mi to byte + tmp_p_memory_maximum=$(( tmp_h * 1024 * 1024 )) + elif [[ $tmp_p_memory_maximum =~ ^[0-9]+Gi$ ]]; then + # Convert Gi to byte + tmp_p_memory_maximum=$(( tmp_h * 1024 * 1024 * 1024 )) + fi + + tmp_p_trigger_condition=$(get_valued_from_parsed_json "$data" "\[\"data\",$profile_index,\"trigger_condition\"\]") + if [ "$tmp_p_trigger_condition" = "-1" ]; then + tmp_p_trigger_condition="" + fi + + profile_array+=( "$tmp_p_name,$tmp_p_recommendation_window,$tmp_p_cpu_headroom,$tmp_p_cpu_minimum,$tmp_p_cpu_maximum,$tmp_p_memory_headroom,$tmp_p_memory_minimum,$tmp_p_memory_maximum,$tmp_p_trigger_condition" ) + done + fi + } + + rest_api_check_cluster_name() + { + show_info "Getting the cluster name of the planning target ..." + cluster_name=$(parse_value_from_target_var "cluster_name") + if [ "$cluster_name" = "" ]; then + err_code="2" + show_error "Failed to get cluster name of the planning target from target_config_info." $err_code + exit $err_code + fi + + exec_cmd="curl -sS -k -X GET \"$api_url/apis/v1/resources/clusters\" -H \"accept: application/json\" -H \"Authorization: Bearer $access_token\"" + rest_output=$(eval $exec_cmd) + if [ "$?" != "0" ]; then + err_code="3" + show_error "Failed to get clusters info using REST API (Command: $exec_cmd)" $err_code + exit $err_code + fi + echo "$rest_output" |grep -q "\"name\":\"$cluster_name\"" + if [ "$?" != "0" ]; then + err_code="3" + show_error "The cluster name ($cluster_name) is not found in REST API return." $err_code + show_detail_to_stderr "REST API output: $rest_output" + exit $err_code + fi + + show_info "cluster_name = $cluster_name" + show_info "Done." + } + + parse_condition() + { + if [[ ! $min_cpu =~ ^[0-9]+$ ]]; then min_cpu=""; fi + if [[ ! $max_cpu =~ ^[0-9]+$ ]]; then max_cpu=""; fi + if [[ $cpu_headroom =~ ^[0-9]+[%]$ ]]; then + # Percentage mode + cpu_headroom_mode="%" + # Remove last character as value + if [ "$machine_type" = "Linux" ]; then + cpu_headroom=`echo ${cpu_headroom::-1}` + else + # Mac + cpu_headroom=`echo "${cpu_headroom%?}"` + fi + elif [[ $cpu_headroom =~ ^[0-9]+$ ]]; then + # Absolute value (mCore) mode + cpu_headroom_mode="m" + else + # No valid value or mode, set inactive value and mode + cpu_headroom="0" + cpu_headroom_mode="m" + fi + if [[ ! $min_memory =~ ^[0-9]+$ ]]; then min_memory=""; fi + if [[ ! $max_memory =~ ^[0-9]+$ ]]; then max_memory=""; fi + if [[ $memory_headroom =~ ^[0-9]+[%]$ ]]; then + # Percentage mode + memory_headroom_mode="%" + # Remove last character as value + if [ "$machine_type" = "Linux" ]; then + memory_headroom=`echo ${memory_headroom::-1}` + else + # Mac + memory_headroom=`echo "${memory_headroom%?}"` + fi + elif [[ $memory_headroom =~ ^[0-9]+$ ]]; then + # Absolute value (byte) mode + memory_headroom_mode="b" + else + # No valid value, set inactive value and mode + memory_headroom="0" + memory_headroom_mode="b" + fi + if [[ ! $trigger_condition =~ ^[0-9]+$ ]]; then trigger_condition=""; fi + [ "$trigger_condition" = "0" ] && trigger_condition="" + + if [ "$readable_granularity" = "daily" ]; then + granularity="3600" + elif [ "$readable_granularity" = "weekly" ]; then + granularity="21600" + elif [ "$readable_granularity" = "monthly" ]; then + granularity="86400" + else + err_code="2" + show_error "Only support planning time interval equals daily/weekly/monthly." $err_code + exit $err_code + fi + + show_info "Time interval = $readable_granularity" + show_info "min_cpu = $min_cpu" + show_info "max_cpu = $max_cpu" + show_info "cpu_headroom = $cpu_headroom" + show_info "cpu_headroom_mode = $cpu_headroom_mode" + show_info "min_memory = $min_memory" + show_info "max_memory = $max_memory" + show_info "memory_headroom = $memory_headroom" + show_info "memory_headroom_mode = $memory_headroom_mode" + show_info "trigger_condition = $trigger_condition" + } + + get_info_from_config() + { + show_info "Getting the $resource_type info of the planning target..." + + resource_name=$(parse_value_from_target_var "resource_name") + if [ "$resource_name" = "" ]; then + err_code="2" + show_error "Failed to get resource name of the planning target from target_config_info." $err_code + exit $err_code + fi + + iac_command=$(parse_value_from_target_var "iac_command") + iac_command="$(echo "$iac_command" | tr '[:upper:]' '[:lower:]')" + if [ "$iac_command" = "" ]; then + err_code="2" + show_error "Failed to get iac_command from target_config_info." $err_code + exit $err_code + elif [ "$iac_command" != "script" ] && [ "$iac_command" != "terraform" ]; then + err_code="2" + show_error "Only support iac_command equals 'script' or 'terraform'." $err_code + exit $err_code + fi + + if [ "$resource_type" = "controller" ]; then + owner_reference_kind=$(parse_value_from_target_var "kind") + if [ "$owner_reference_kind" = "" ]; then + err_code="2" + show_error "Failed to get controller kind of the planning target from target_config_info." $err_code + exit $err_code + fi + + owner_reference_kind="$(echo "$owner_reference_kind" | tr '[:upper:]' '[:lower:]')" + if [ "$owner_reference_kind" = "statefulset" ] && [ "$owner_reference_kind" = "deployment" ] && [ "$owner_reference_kind" = "deploymentconfig" ]; then + err_code="2" + show_error "Only support controller type equals Statefulset/Deployment/DeploymentConfig." $err_code + exit $err_code + fi + + target_namespace=$(parse_value_from_target_var "namespace") + if [ "$target_namespace" = "" ]; then + err_code="2" + show_error "Failed to get namespace of the planning target from target_config_info." $err_code + exit $err_code + fi + elif [ "$resource_type" = "namespace" ]; then + # resource_type = namespace + # target_namespace is resource_name + target_namespace=$resource_name + elif [ "$resource_type" = "application" ]; then + if [ "$iac_command" = "terraform" ]; then + err_code="3" + show_error "terraform in resource_type (application mode) is not yet supported." $err_code + exit $err_code + fi + else + err_code="2" + show_error "Only support resource type equals controller/namespace/application." $err_code + exit $err_code + fi + + readable_granularity=$(parse_value_from_target_var "time_interval") + readable_granularity="$(echo "$readable_granularity" | tr '[:upper:]' '[:lower:]')" + if [ "$resource_type" = "application" ]; then + if [ "$readable_granularity" = "" ]; then + readable_granularity="daily" + app_granularity="daily" + else + app_granularity=$readable_granularity + fi + elif [ "$resource_type" != "application" ] && [ "$readable_granularity" = "" ]; then + err_code="2" + show_error "Failed to get time interval of the planning target from target_config_info." $err_code + exit $err_code + fi + + min_cpu=$(parse_value_from_target_var "min_cpu") + max_cpu=$(parse_value_from_target_var "max_cpu") + cpu_headroom=$(parse_value_from_target_var "cpu_headroom") + min_memory=$(parse_value_from_target_var "min_memory") + max_memory=$(parse_value_from_target_var "max_memory") + memory_headroom=$(parse_value_from_target_var "memory_headroom") + trigger_condition=$(parse_value_from_target_var "trigger_condition") + limits_only=$(parse_value_from_target_var "limits_only") + requests_only=$(parse_value_from_target_var "requests_only") + + if [ "$limits_only" != 'y' ] && [ "$limits_only" != 'n' ]; then + limits_only="n" + fi + if [ "$requests_only" != 'y' ] && [ "$requests_only" != 'n' ]; then + requests_only="n" + fi + + show_info "Cluster name = $cluster_name" + show_info "Resource type = $resource_type" + show_info "Resource name = $resource_name" + if [ "$resource_type" = "controller" ]; then + show_info "Kind = $owner_reference_kind" + show_info "Namespace = $target_namespace" + fi + + parse_condition + + show_info "Done." + } + + + get_valued_from_parsed_json(){ + all_data="$1" + target_string="$2" + echo "$all_data"|grep "$target_string"|awk '{print $2}'|sed 's/"//g' + } + + parse_value_from_planning_for_multiple_conatiners(){ + for container_name in "${container_name_keys[@]}" + do + data=$(tokenize_json "$planning_all"| parse_json_begin) + err_code="$?" + if [ "$err_code" != "0" ]; then + show_error "Failed to parse json output (multiple conatiners)." $err_code + exit $err_code + fi + limit_con_cpu=$(get_valued_from_parsed_json "$data" "\[\"plannings\",0,\"plannings\",0,\"containerPlannings\",\"$container_name\",\"limitPlannings\",\"CPU_MILLICORES_USAGE\",0,\"numValue\"\]") + limit_con_memory=$(get_valued_from_parsed_json "$data" "\[\"plannings\",0,\"plannings\",0,\"containerPlannings\",\"$container_name\",\"limitPlannings\",\"MEMORY_BYTES_USAGE\",0,\"numValue\"\]") + request_con_cpu=$(get_valued_from_parsed_json "$data" "\[\"plannings\",0,\"plannings\",0,\"containerPlannings\",\"$container_name\",\"requestPlannings\",\"CPU_MILLICORES_USAGE\",0,\"numValue\"\]") + request_con_memory=$(get_valued_from_parsed_json "$data" "\[\"plannings\",0,\"plannings\",0,\"containerPlannings\",\"$container_name\",\"requestPlannings\",\"MEMORY_BYTES_USAGE\",0,\"numValue\"\]") + + if [ "$limit_con_cpu" = "" ]; then + err_code="3" + show_error "Failed to parse limit cpu planning value of container ($container_name)." $err_code + exit $err_code + fi + if [ "$limit_con_memory" = "" ]; then + err_code="3" + show_error "Failed to parse limit memory planning value of container ($container_name)." $err_code + exit $err_code + fi + if [ "$request_con_cpu" = "" ]; then + err_code="3" + show_error "Failed to parse request cpu planning value of container ($container_name)." $err_code + exit $err_code + fi + if [ "$request_con_memory" = "" ]; then + err_code="3" + show_error "Failed to parse request memory planning value of container ($container_name)." $err_code + exit $err_code + fi + limit_con_cpu=$(( ($limit_con_cpu + $replica_number - 1)/$replica_number )) + limit_con_memory=$(( ($limit_con_memory + $replica_number - 1)/$replica_number )) + request_con_cpu=$(( ($request_con_cpu + $replica_number - 1)/$replica_number )) + request_con_memory=$(( ($request_con_memory + $replica_number - 1)/$replica_number )) + + container_planning_array+=( "$container_name.limitPlannings.CPU_MILLICORES_USAGE:$limit_con_cpu" ) + container_planning_array+=( "$container_name.limitPlannings.MEMORY_BYTES_USAGE:$limit_con_memory" ) + container_planning_array+=( "$container_name.requestPlannings.CPU_MILLICORES_USAGE:$request_con_cpu" ) + container_planning_array+=( "$container_name.requestPlannings.MEMORY_BYTES_USAGE:$request_con_memory" ) + show_info "-------------- Planning for container ($container_name) --------------" + show_info "resources.limits.cpu = $limit_con_cpu(m)" + show_info "resources.limits.momory = $limit_con_memory(byte)" + show_info "resources.requests.cpu = $request_con_cpu(m)" + show_info "resources.requests.memory = $request_con_memory(byte)" + show_info "-----------------------------------------------------" + done + } + + parse_value_from_planning() + { + target_field="$1" + target_resource="$2" + if [ -z "$target_field" ]; then + err_code="3" + show_error "parse_value_from_planning() target_field parameter can't be empty." $err_code + exit $err_code + elif [ -z "$target_resource" ]; then + err_code="3" + show_error "parse_value_from_planning() target_resource parameter can't be empty." $err_code + exit $err_code + fi + + if [ "$target_field" != "limitPlannings" ] && [ "$target_field" != "requestPlannings" ]; then + err_code="3" + show_error "parse_value_from_planning() target_field can only be either 'limitPlannings' and 'requestPlannings'." $err_code + exit $err_code + fi + + if [ "$target_resource" != "CPU_MILLICORES_USAGE" ] && [ "$target_resource" != "MEMORY_BYTES_USAGE" ]; then + err_code="3" + show_error "parse_value_from_planning() target_field can only be either 'CPU_MILLICORES_USAGE' and 'MEMORY_BYTES_USAGE'." $err_code + exit $err_code + fi + + if [ "$resource_type" = "controller" ]; then + data=$(tokenize_json "$planning_all"| parse_json_begin) + err_code="$?" + if [ "$err_code" != "0" ]; then + show_error "Failed to parse json output (single conatiner)." $err_code + exit $err_code + fi + echo $(get_valued_from_parsed_json "$data" "\[\"plannings\",0,\"plannings\",0,\"$target_field\",\"$target_resource\",0,\"numValue\"\]") + else + echo "$planning_all"|grep -o "\"$target_field\":[^{]*{[^}]*}[^}]*}"|grep -o "\"$target_resource\":[^\[]*\[[^]]*"|grep -o '"numValue":[^"]*"[^"]*"'|cut -d '"' -f4 + fi + } + + get_container_number_and_name_list(){ + if [ "$DEMO_MODE" != "y" ]; then + query_type="${owner_reference_kind}s" + container_str=$($kube_cmd -n $target_namespace get $query_type ${resource_name} -o jsonpath='{.spec.template.spec.containers[*].name}') + if [ "$container_str" = "" ]; then + err_code="3" + show_error "Failed to get container list (namespace:$target_namespace, kind:$query_type, name:${resource_name})" $err_code + exit $err_code + fi + container_array=(`echo "$container_str"`) + container_number=${#container_array[@]} + fi + } + + get_planning_from_api() + { + show_info "Getting planning values for the $resource_type through REST API..." + show_info "Cluster name = $cluster_name" + if [ "$resource_type" = "controller" ]; then + show_info "Kind = $owner_reference_kind" + show_info "Namespace = $target_namespace" + else + # namespace + show_info "Namespace = $target_namespace" + fi + show_info "Resource name = $resource_name" + show_info "Time interval = $readable_granularity" + + # Use 0 as 'now' + interval_start_time="0" + interval_end_time=$(($interval_start_time + $granularity - 1)) + + show_info "Query interval (start) = 0" + show_info "Query interval (end) = $interval_end_time" + + # Use planning here + type="planning" + if [ "$resource_type" = "controller" ]; then + query_type="${owner_reference_kind}s" + exec_cmd="curl -sS -k -X GET \"$api_url/apis/v1/plannings/clusters/$cluster_name/namespaces/$target_namespace/$query_type/${resource_name}?granularity=$granularity&type=$type&limit=1&order=asc&startTime=$interval_start_time&endTime=$interval_end_time\" -H \"accept: application/json\" -H \"Authorization: Bearer $access_token\"" + else + # resource_type = namespace + # Check if namespace is in monitoring state first + exec_cmd="curl -sS -k -X GET \"$api_url/apis/v1/resources/clusters/$cluster_name/namespaces?names=$target_namespace\" -H \"accept: application/json\" -H \"Authorization: Bearer $access_token\"" + rest_output=$(eval $exec_cmd) + if [ "$?" != "0" ]; then + err_code="3" + show_error "Failed to get namespace $target_namespace resource info using REST API (Command: $exec_cmd)" $err_code + exit $err_code + fi + namespace_state="$(echo $rest_output|tr -d '\n'|grep -o "\"name\":.*\"${target_namespace}.*"|grep -o "\"state\":.*\".*\""|cut -d '"' -f4)" + if [ "$namespace_state" != "monitoring" ]; then + err_code="1" + show_error "Namespace $target_namespace is not in 'monitoring' state." $err_code + show_detail_to_stderr "REST API output: $rest_output" + exit $err_code + fi + exec_cmd="curl -sS -k -X GET \"$api_url/apis/v1/plannings/clusters/$cluster_name/namespaces/$target_namespace?granularity=$granularity&type=$type&limit=1&order=asc&startTime=$interval_start_time&endTime=$interval_end_time\" -H \"accept: application/json\" -H \"Authorization: Bearer $access_token\"" + fi + + for repeat in `seq 1 10` + do + rest_output=$(eval $exec_cmd) + if [ "$?" != "0" ]; then + err_code="3" + show_error "Failed to get planning value of $resource_type using REST API (Command: $exec_cmd)" $err_code + exit $err_code + fi + planning_all="$rest_output" + # check if return is '"plannings":[]}' + planning_count=${#planning_all} + if [ "$planning_all" = "" ] || [ "$planning_count" -le "15" ]; then + err_code="1" + show_error "Planning value ($readable_granularity) is empty." $err_code + show_detail_to_stderr "REST API output: ${rest_output}" + exit $err_code + fi + + if [ "$resource_type" = "controller" ]; then + data=$(tokenize_json "$planning_all"| parse_json_begin) + err_code="$?" + if [ "$err_code" != "0" ]; then + show_error "Failed to parse json output (API result)." $err_code + exit $err_code + fi + records=$(echo "$data" |grep "\[\"plannings\",0,\"plannings\",0,\"containerPlannings\"") + container_records_num="$(echo "$records" | cut -d ',' -f6|sort|uniq|wc -l|xargs)" + + if [ "$DEMO_MODE" != "y" ]; then + if [ "0$container_records_num" -ne "0$container_number" ]; then + err_code="3" + show_error "Container number doesn't match (system:planning=$container_number:$container_records_num)" $err_code + exit $err_code + fi + fi + + container_name_keys=($(echo "$records" | cut -d ',' -f6|sort|uniq|sed 's/"//g')) + if [ "$DEMO_MODE" != "y" ]; then + # verify all container name (system) do have key in planning + need_repeat="" + for name in "${container_array[@]}" + do + matched="n" + for id in "${container_name_keys[@]}" + do + if [ "$id" = "$name" ]; then + matched="y" + break + fi + done + if [ "$matched" != "y" ]; then + need_repeat="y" + break + fi + done + + if [ "$need_repeat" = "y" ]; then + if [ "$repeat" = "10" ]; then + err_code="3" + show_error "Can't locate container name ($name) as key inside Federator.ai planning output after repeat $repeat times." $err_code + exit $err_code + fi + sleep 1 + continue + else + break + fi + else + # Demo + break + fi + fi + done + + limits_pod_cpu=$(parse_value_from_planning "limitPlannings" "CPU_MILLICORES_USAGE") + requests_pod_cpu=$(parse_value_from_planning "requestPlannings" "CPU_MILLICORES_USAGE") + limits_pod_memory=$(parse_value_from_planning "limitPlannings" "MEMORY_BYTES_USAGE") + requests_pod_memory=$(parse_value_from_planning "requestPlannings" "MEMORY_BYTES_USAGE") + + if [ "$resource_type" = "controller" ]; then + if [ "$DEMO_MODE" != "y" ]; then + replica_number="$($kube_cmd get $owner_reference_kind $resource_name -n $target_namespace -o json|tr -d '\n'|grep -o "\"spec\":.*"|grep -o "\"replicas\":[^,]*[0-9]*"|head -1|cut -d ':' -f2|xargs)" + + if [ "$replica_number" = "" ]; then + err_code="4" + show_error "Failed to get replica number from controller ($resource_name) in ns $target_namespace" $err_code + exit $err_code + fi + + case $replica_number in + ''|*[!0-9]*) err_code="4" && show_error "Replica number needs to be an integer." $err_code && exit $err_code ;; + *) ;; + esac + + show_info "Controller replica number = $replica_number" + if [ "$replica_number" = "0" ]; then + err_code="4" + show_error "Replica number is zero." $err_code + exit $err_code + fi + else + replica_number="1" + fi + + # Round up the result (planning / replica) + limits_pod_cpu=$(( ($limits_pod_cpu + $replica_number - 1)/$replica_number )) + requests_pod_cpu=$(( ($requests_pod_cpu + $replica_number - 1)/$replica_number )) + limits_pod_memory=$(( ($limits_pod_memory + $replica_number - 1)/$replica_number )) + requests_pod_memory=$(( ($requests_pod_memory + $replica_number - 1)/$replica_number )) + fi + + if [ "$resource_type" = "controller" ] && [ "0$container_records_num" -ge "2" ]; then + parse_value_from_planning_for_multiple_conatiners + fi + + show_info "-------------- Planning for $resource_type --------------" + show_info "resources.limits.cpu = $limits_pod_cpu(m)" + show_info "resources.limits.momory = $limits_pod_memory(byte)" + show_info "resources.requests.cpu = $requests_pod_cpu(m)" + show_info "resources.requests.memory = $requests_pod_memory(byte)" + show_info "-----------------------------------------------------" + + if [ "$limits_pod_cpu" = "" ] || [ "$requests_pod_cpu" = "" ] || [ "$limits_pod_memory" = "" ] || [ "$requests_pod_memory" = "" ]; then + err_code="3" + if [ "$resource_type" = "controller" ]; then + show_error "Failed to get controller ($resource_name) planning. Missing value." $err_code + else + # namespace + show_error "Failed to get namespace ($target_namespace) planning. Missing value." $err_code + fi + exit $err_code + fi + + show_info "Done." + } + + apply_min_max_margin() + { + planning_name="$1" + mode_name="$2" + headroom_name="$3" + min_name="$4" + max_name="$5" + original_value="${!planning_name}" + + if [ "${!mode_name}" = "%" ]; then + # Percentage mode + export $planning_name=$(( (${!planning_name}*(100+${!headroom_name})+99)/100 )) + else + # Absolute value mode + export $planning_name=$(( ${!planning_name} + ${!headroom_name} )) + fi + if [ "${!min_name}" != "" ] && [ "${!min_name}" -gt "${!planning_name}" ]; then + # Assign minimum value + export $planning_name="${!min_name}" + fi + if [ "${!max_name}" != "" ] && [ "${!planning_name}" -gt "${!max_name}" ]; then + # Assign maximum value + export $planning_name="${!max_name}" + fi + + show_info "-------------- Calculate min/max/headroom/default -------------" + show_info "${mode_name} = ${!mode_name}" + show_info "${headroom_name} = ${!headroom_name}" + show_info "${min_name} = ${!min_name}" + show_info "${max_name} = ${!max_name}" + show_info "${planning_name} (before)= ${original_value}" + show_info "${planning_name} (after)= ${!planning_name}" + show_info "---------------------------------------------------------------" + + } + + check_default_value_satisfied() + { + void_mode="x" + void_value="0" + show_info "Verifying default value satisfied..." + apply_min_max_margin "requests_pod_cpu" "void_mode" "void_value" "default_min_cpu" "void" + apply_min_max_margin "requests_pod_memory" "void_mode" "void_value" "default_min_memory" "void" + apply_min_max_margin "limits_pod_cpu" "void_mode" "void_value" "default_min_cpu" "void" + apply_min_max_margin "limits_pod_memory" "void_mode" "void_value" "default_min_memory" "void" + show_info "Done" + } + + compare_trigger_condition_with_difference() + { + before=$1 + after=$2 + trigger_result="" + result=$(awk -v t1="${!before}" -v t2="${!after}" 'BEGIN{printf "%.0f", (t2-t1)/t1 * 100}') + show_info "Comparing current value ($before=${!before}) and planning value ($after=${!after})..." + if [ "$result" -gt "0" ]; then + # planning > current, ignore checking + trigger_result="y" + show_info "planning value is bigger than current value, ignore trigger condition check." + return + fi + # Get absolute value + result=$(echo ${result#-}) + show_info "comp_result=${result}%, trigger_condition=${trigger_condition}%" + if [ "$trigger_condition" -le "$result" ]; then + trigger_result="y" + show_info "$(echo "$before"|awk -F'_' '{print $1"_"$2}') meet the trigger condition." + else + trigger_result="n" + show_info "$(echo "$before"|awk -F'_' '{print $1"_"$2}') will be skipped." + fi + } + + check_trigger_condition_on_all_metrics() + { + show_info "Verifying trigger condition..." + if [ "$trigger_condition" != "" ]; then + if [ "$limit_cpu_before" != "N/A" ]; then + compare_trigger_condition_with_difference "limit_cpu_before_converted" "limits_pod_cpu" + do_limit_cpu="$trigger_result" + else + do_limit_cpu="y" + fi + if [ "$limit_memory_before" != "N/A" ]; then + compare_trigger_condition_with_difference "limit_memory_before_converted" "limits_pod_memory" + do_limit_memory="$trigger_result" + else + do_limit_memory="y" + fi + if [ "$request_cpu_before" != "N/A" ]; then + compare_trigger_condition_with_difference "request_cpu_before_converted" "requests_pod_cpu" + do_request_cpu="$trigger_result" + else + do_request_cpu="y" + fi + if [ "$request_memory_before" != "N/A" ]; then + compare_trigger_condition_with_difference "request_memory_before_converted" "requests_pod_memory" + do_request_memory="$trigger_result" + else + do_request_memory="y" + fi + else + show_info "'trigger_condition' is disabled." + do_limit_cpu="y" + do_limit_memory="y" + do_request_cpu="y" + do_request_memory="y" + fi + + # New rule, if one of action is 'y', let every action become 'y' + # Still reserve limits_only and requests_only + if [ "$do_limit_cpu" = "y" ] || [ "$do_limit_memory" = "y" ] || [ "$do_request_cpu" = "y" ] || [ "$do_request_memory" = "y" ]; then + show_info "One of do action is 'y', set all do actions to 'y'. Still reserve limits_only or requests_only settings." + do_limit_cpu="y" + do_limit_memory="y" + do_request_cpu="y" + do_request_memory="y" + fi + if [ "$limits_only" = "y" ]; then + show_info "'Limits only' is enabled." + do_request_cpu="n" + do_request_memory="n" + fi + + if [ "$requests_only" = "y" ]; then + show_info "'Requests only' is enabled." + do_limit_cpu="n" + do_limit_memory="n" + fi + show_info "----- Final results -----" + show_info "do_limit_cpu : $do_limit_cpu" + show_info "do_limit_memory : $do_limit_memory" + show_info "do_request_cpu : $do_request_cpu" + show_info "do_request_memory: $do_request_memory" + show_info "-------------------------" + show_info "Done." + } + + get_value_from_planning_array(){ + container_name="$1" + type="$2" + metric="$3" + + ret="" + for record in "${container_planning_array[@]}" + do + record_key="${record%%:*}" + record_value=${record#*:} + if [ "$record_key" = "$container_name.$type.$metric" ]; then + # Found record + ret=$record_value + break + fi + done + echo $ret + } + + get_value_from_resource_array(){ + #container_resource_array+=( "$container_name.before.limits.cpu.original:$limit_cpu" ) + container_name="$1" + time="$2" + type="$3" + metric="$4" + modified="$5" + + ret="" + for record in "${container_resource_array[@]}" + do + record_key="${record%%:*}" + record_value=${record#*:} + if [ "$record_key" = "$container_name.$time.$type.$metric.$modified" ]; then + # Found record + ret=$record_value + break + fi + done + echo $ret + } + + do_filter_min_max_headroom(){ + apply_min_max_margin "limits_pod_cpu" "cpu_headroom_mode" "cpu_headroom" "min_cpu" "max_cpu" + apply_min_max_margin "limits_pod_memory" "memory_headroom_mode" "memory_headroom" "min_memory" "max_memory" + apply_min_max_margin "requests_pod_cpu" "cpu_headroom_mode" "cpu_headroom" "min_cpu" "max_cpu" + apply_min_max_margin "requests_pod_memory" "memory_headroom_mode" "memory_headroom" "min_memory" "max_memory" + } + + generate_controller_set_cmd(){ + set_cmd="" + if [ "$do_limit_cpu" = "y" ]; then + if [ "$do_limit_memory" = "y" ]; then + set_cmd="--limits cpu=${limits_pod_cpu}m,memory=${limits_pod_memory}" + else + set_cmd="--limits cpu=${limits_pod_cpu}m" + fi + else + # do_limit_cpu = n + if [ "$do_limit_memory" = "y" ]; then + set_cmd="--limits memory=${limits_pod_memory}" + fi + fi + if [ "$do_request_cpu" = "y" ]; then + if [ "$do_request_memory" = "y" ]; then + set_cmd="$set_cmd --requests cpu=${requests_pod_cpu}m,memory=${requests_pod_memory}" + else + set_cmd="$set_cmd --requests cpu=${requests_pod_cpu}m" + fi + else + # do_request_cpu = n + if [ "$do_request_memory" = "y" ]; then + set_cmd="$set_cmd --requests memory=${requests_pod_memory}" + fi + fi + + # For get_controller_resources_from_kubecmd 'after' mode + if [ "$machine_type" = "Linux" ]; then + [ "$do_limit_cpu" = "n" ] && limits_pod_cpu="${limit_cpu_before::-1}" + [ "$do_request_cpu" = "n" ] && requests_pod_cpu="${request_cpu_before::-1}" + else + # Mac + [ "$do_limit_cpu" = "n" ] && limits_pod_cpu="${limit_cpu_before%?}" + [ "$do_request_cpu" = "n" ] && requests_pod_cpu="${request_cpu_before%?}" + fi + [ "$do_limit_memory" = "n" ] && limits_pod_memory=$limit_memory_before + [ "$do_request_memory" = "n" ] && requests_pod_memory=$request_memory_before + + container_resource_array+=( "$container_name.after.limits.cpu.original:$limits_pod_cpu" ) + container_resource_array+=( "$container_name.after.limits.memory.original:$limits_pod_memory" ) + container_resource_array+=( "$container_name.after.requests.cpu.original:$requests_pod_cpu" ) + container_resource_array+=( "$container_name.after.requests.memory.original:$requests_pod_memory" ) + + if [ "$set_cmd" = "" ]; then + exec_cmd="N/A, execution skipped due to trigger condition is not met." + execution_skipped="y" + else + execution_skipped="n" + if [ "0$container_records_num" -ge "2" ]; then + exec_cmd="$kube_cmd -n $target_namespace set resources $owner_reference_kind $resource_name -c=$container_name $set_cmd" + else + exec_cmd="$kube_cmd -n $target_namespace set resources $owner_reference_kind $resource_name $set_cmd" + fi + fi + container_resource_array+=( "$container_name.after.issue.execute.cmd:$exec_cmd" ) + } + + execute_command(){ + # Optional parameter + local con_name=$1 + + show_info "Issuing cmd:" + show_info "$exec_cmd" + + if [ "$execution_skipped" = "y" ]; then + execution_time="N/A, execution skipped due to trigger condition is not met." + if [ "$con_name" != "" ]; then + container_resource_array+=( "$con_name.after.issue.execute.time:$execution_time" ) + fi + else + if [ "$mode" = "dry_run" ]; then + execution_time="N/A, execution skipped due to --dry-run-only is specified." + show_info "Dry run is enabled, skip execution." + show_info "Done. Dry run is done." + if [ "$con_name" != "" ]; then + container_resource_array+=( "$con_name.after.issue.execute.time:$execution_time" ) + fi + return + fi + + execution_time="$(date -u)" + if [ "$con_name" != "" ]; then + container_resource_array+=( "$con_name.after.issue.execute.time:$execution_time" ) + fi + if [ "$resource_type" = "namespace" ]; then + # Clean other quotas + all_quotas=$($kube_cmd -n $target_namespace get quota -o name|cut -d '/' -f2) + for quota in $(echo "$all_quotas") + do + $kube_cmd -n $target_namespace patch quota $quota --type json --patch "[ { \"op\" : \"remove\" , \"path\" : \"/spec/hard/limits.cpu\"}]" >/dev/null 2>&1 + $kube_cmd -n $target_namespace patch quota $quota --type json --patch "[ { \"op\" : \"remove\" , \"path\" : \"/spec/hard/limits.memory\"}]" >/dev/null 2>&1 + $kube_cmd -n $target_namespace patch quota $quota --type json --patch "[ { \"op\" : \"remove\" , \"path\" : \"/spec/hard/requests.cpu\"}]" >/dev/null 2>&1 + $kube_cmd -n $target_namespace patch quota $quota --type json --patch "[ { \"op\" : \"remove\" , \"path\" : \"/spec/hard/requests.memory\"}]" >/dev/null 2>&1 + done + # Delete previous federator.ai quota + $kube_cmd -n $target_namespace delete quota $quota_name > /dev/null 2>&1 + fi + + eval $exec_cmd 3>&1 1>&2 2>&3 1>>$debug_log | tee -a $debug_log + if [ "${PIPESTATUS[0]}" != "0" ]; then + err_code="5" + if [ "$resource_type" = "controller" ]; then + show_error "Failed to update resources for $owner_reference_kind $resource_name" $err_code + else + show_error "Failed to update quota for namespace $target_namespace" $err_code + fi + exit $err_code + fi + fi + } + + update_target_resources() + { + mode=$1 + if [ "$mode" = "" ]; then + err_code="3" + show_error "update_target_resources() mode parameter can't be empty." $err_code + exit $err_code + fi + + show_info "Updateing $resource_type resources..." + + if [ "$resource_type" = "controller" ] && [ "0$container_records_num" -ge "2" ]; then + + for container_name in "${container_name_keys[@]}" + do + show_info "Calculating min/max/headroom for container ($container_name)..." + limits_pod_cpu=$(get_value_from_planning_array $container_name limitPlannings CPU_MILLICORES_USAGE) + limits_pod_memory=$(get_value_from_planning_array $container_name limitPlannings MEMORY_BYTES_USAGE) + requests_pod_cpu=$(get_value_from_planning_array $container_name requestPlannings CPU_MILLICORES_USAGE) + requests_pod_memory=$(get_value_from_planning_array $container_name requestPlannings MEMORY_BYTES_USAGE) + if [ "$limits_pod_cpu" = "" ] || [ "$requests_pod_cpu" = "" ] || [ "$limits_pod_memory" = "" ] || [ "$requests_pod_memory" = "" ]; then + err_code="3" + show_error "Missing planning values." $err_code + exit $err_code + fi + + do_filter_min_max_headroom + show_info "Done" + + # Make sure default cpu & memory value above existing one + check_default_value_satisfied + + # Make sure trigger condition is met + limit_cpu_before_converted=$(get_value_from_resource_array $container_name before limits cpu converted) + limit_memory_before_converted=$(get_value_from_resource_array $container_name before limits memory converted) + request_cpu_before_converted=$(get_value_from_resource_array $container_name before requests cpu converted) + request_memory_before_converted=$(get_value_from_resource_array $container_name before requests memory converted) + limit_cpu_before=$(get_value_from_resource_array $container_name before limits cpu original) + limit_memory_before=$(get_value_from_resource_array $container_name before limits memory original) + request_cpu_before=$(get_value_from_resource_array $container_name before requests cpu original) + request_memory_before=$(get_value_from_resource_array $container_name before requests memory original) + + # Make sure trigger condition is met + check_trigger_condition_on_all_metrics + + if [ "$iac_command" = "script" ]; then + generate_controller_set_cmd + execute_command $container_name + else + # terraform + err_code="3" + show_error "terraform with multiple container is not yet supported." $err_code + exit $err_code + fi + + done + else + if [ "$limits_pod_cpu" = "" ] || [ "$requests_pod_cpu" = "" ] || [ "$limits_pod_memory" = "" ] || [ "$requests_pod_memory" = "" ]; then + err_code="3" + show_error "Missing planning values." $err_code + exit $err_code + fi + show_info "Calculating min/max/headroom ..." + do_filter_min_max_headroom + show_info "Done" + + # Make sure default cpu & memory value above existing one + check_default_value_satisfied + + # Make sure trigger condition is met + check_trigger_condition_on_all_metrics + + if [ "$iac_command" = "script" ]; then + if [ "$resource_type" = "controller" ]; then + generate_controller_set_cmd + else + # namespace quota + execution_skipped="y" + if [ "$do_limit_cpu" = "n" ]; then + limits_pod_cpu="${limit_cpu_before::-1}" + else + execution_skipped="n" + fi + if [ "$do_limit_memory" = "n" ]; then + limits_pod_memory=$limit_memory_before + else + execution_skipped="n" + fi + if [ "$do_request_cpu" = "n" ]; then + requests_pod_cpu="${request_cpu_before::-1}" + else + execution_skipped="n" + fi + if [ "$do_request_memory" = "n" ]; then + requests_pod_memory=$request_memory_before + else + execution_skipped="n" + fi + + if [ "$execution_skipped" = "y" ]; then + exec_cmd="N/A, execution skipped due to trigger condition is not met." + else + exec_cmd="$kube_cmd -n $target_namespace create quota $quota_name --hard=limits.cpu=${limits_pod_cpu}m,limits.memory=${limits_pod_memory},requests.cpu=${requests_pod_cpu}m,requests.memory=${requests_pod_memory}" + fi + fi + + execute_command + else + # iac_command = terraform + # dry_run = normal + + variable_tf_name="${terraform_path}/federatorai_variables.tf" + auto_tfvars_name="${terraform_path}/federatorai_recommendations.auto.tfvars" + auto_tfvars_previous_name="${terraform_path}/federatorai_recommendations.auto.tfvars.previous" + + create_auto_tfvars + create_variable_tf + + # Print final json output + if [ "$resource_type" = "controller" ]; then + echo -e "{\n \"info\": {\n \"cluster_name\": \"$cluster_name\",\n \"resource_type\": \"$resource_type\",\n \"namespace\": \"$target_namespace\",\n \"resource_name\": \"$resource_name\",\n \"kind\": \"$owner_reference_kind\",\n \"time_interval\": \"$readable_granularity\",\n \"execute_cmd\": \"N/A\",\n \"execution_time\": \"N/A\"\n },\n \"log_file\": \"$debug_log\",\n \"before_execution\": {\n \"limits\": {\n \"cpu\": \"$limit_cpu_before\",\n \"memory\": \"$limit_memory_before\"\n },\n \"requests\": {\n \"cpu\": \"$request_cpu_before\",\n \"memory\": \"$request_memory_before\"\n }\n },\n \"recommended_values\": {\n \"tf_file\": \"$variable_tf_name\",\n \"tfvars_file\": \"$auto_tfvars_name\",\n \"limits\": {\n \"cpu\": \"${limits_pod_cpu}m\",\n \"memory\": \"$limits_pod_memory\"\n },\n \"requests\": {\n \"cpu\": \"${requests_pod_cpu}m\",\n \"memory\": \"$requests_pod_memory\"\n }\n }\n}" | tee -a $debug_log + else + #resource_type = namespace + echo -e "{\n \"info\": {\n \"cluster_name\": \"$cluster_name\",\n \"resource_type\": \"$resource_type\",\n \"resource_name\": \"$target_namespace\",\n \"time_interval\": \"$readable_granularity\",\n \"execute_cmd\": \"N/A\",\n \"execution_time\": \"N/A\"\n },\n \"log_file\": \"$debug_log\",\n \"before_execution\": {\n \"limits\": {\n \"cpu\": \"$limit_cpu_before\",\n \"memory\": \"$limit_memory_before\"\n },\n \"requests\": {\n \"cpu\": \"$request_cpu_before\",\n \"memory\": \"$request_memory_before\"\n }\n },\n \"recommended_values\": {\n \"tf_file\": \"$variable_tf_name\",\n \"tfvars_file\": \"$auto_tfvars_name\",\n \"limits\": {\n \"cpu\": \"${limits_pod_cpu}m\",\n \"memory\": \"$limits_pod_memory\"\n },\n \"requests\": {\n \"cpu\": \"${requests_pod_cpu}m\",\n \"memory\": \"$requests_pod_memory\"\n }\n }\n}" | tee -a $debug_log + fi + fi + fi + + show_info "Done" + } + + create_variable_tf() + { + if [ ! -f "$variable_tf_name" ]; then + echo "variable \"federatorai_recommendations\" {" >> $variable_tf_name + echo " description = \"Recommendations given by Federator.ai\"" >> $variable_tf_name + echo " type = map(map(map(string)))" >> $variable_tf_name + echo "}" >> $variable_tf_name + fi + module_name="${resource_id}_${cluster_name}" + cat $variable_tf_name |grep -q "module \"$module_name\" {" + if [ "$?" != "0" ]; then + echo "" >> $variable_tf_name + echo "module \"$module_name\" {" >> $variable_tf_name + echo " source = \"prophetstor-ai/resource-provision/federatorai\"" >> $variable_tf_name + echo " version = \"5.0.0\"" >> $variable_tf_name + echo " federatorai_resource_id = \"${resource_id}\"" >> $variable_tf_name + echo " federatorai_cluster_name = \"${cluster_name}\"" >> $variable_tf_name + echo " federatorai_recommendations = var.federatorai_recommendations" >> $variable_tf_name + echo "}" >> $variable_tf_name + fi + + show_info "tf file ($variable_tf_name) is generated." + } + + create_auto_tfvars() + { + if [ -f "$auto_tfvars_name" ]; then + mv $auto_tfvars_name $auto_tfvars_previous_name + fi + + if [ "$resource_type" = "controller" ]; then + resource_id="federatorai_${owner_reference_kind}_${resource_name}_${target_namespace}" + else + resource_id="federatorai_namespace_${resource_name}" + fi + + declare -A cluster_resource_map + + # Merge previous into map first + if [ -f "$auto_tfvars_previous_name" ]; then + rec_num="0" + merge_tfvars "" < $auto_tfvars_previous_name + rm -f $auto_tfvars_previous_name > /dev/null 2>&1 + fi + + # Add Current entry + current_time="$(date)" + current_rec="#UpdateTime=\"$current_time\",recommended_cpu_request=\"${requests_pod_cpu}m\",recommended_memory_request=\"$requests_pod_memory\",recommended_cpu_limit=\"${limits_pod_cpu}m\",recommended_memory_limit=\"$limits_pod_memory\"" + cluster_resource_map["federatorai_recommendations,$cluster_name,$resource_id"]="$current_rec" + + # Do export + export_final_tfvars + + show_info "tfvars file ($auto_tfvars_name) is generated." + } + + export_final_tfvars() + { + > $auto_tfvars_name + + cluster_list=$(echo "${!cluster_resource_map[@]}"|tr ' ' '\n'|awk -F',' '{print $2}'|sort|uniq) + + # Generate final tfvars + echo "federatorai_recommendations = {" >> $auto_tfvars_name + for cluster in $(echo $cluster_list) + do + echo " $cluster = {" >> $auto_tfvars_name + for key in "${!cluster_resource_map[@]}" + do + target_cluster=$(echo "$key"|cut -d',' -f2) + if [ "$target_cluster" = "$cluster" ]; then + resource=$(echo "$key"|cut -d',' -f3) + echo " $resource = {" >> $auto_tfvars_name + rec_string=${cluster_resource_map[$key]} + update_time=$(echo $rec_string|grep -o "#UpdateTime=[^\"]*\"[^\"]*\"") + reccpureq=$(echo $rec_string|grep -o "recommended_cpu_request=[^\"]*\"[^\"]*\"") + recmemreq=$(echo $rec_string|grep -o "recommended_memory_request=[^\"]*\"[^\"]*\"") + reccpulim=$(echo $rec_string|grep -o "recommended_cpu_limit=[^\"]*\"[^\"]*\"") + recmemlim=$(echo $rec_string|grep -o "recommended_memory_limit=[^\"]*\"[^\"]*\"") + echo " $update_time" >> $auto_tfvars_name + echo " $reccpureq" >> $auto_tfvars_name + echo " $recmemreq" >> $auto_tfvars_name + echo " $reccpulim" >> $auto_tfvars_name + echo " $recmemlim" >> $auto_tfvars_name + echo " }" >> $auto_tfvars_name + fi + done + echo " }" >> $auto_tfvars_name + done + echo "}" >> $auto_tfvars_name + } + + merge_tfvars() + { + local KEYS + local K + local V + + while true + do + read LINE + if [ "${LINE}" = "" ] + then + return + fi + + if [[ "$LINE" =~ "#UpdateTime" ]]; then + K=`echo ${LINE} | awk -F'=' '{print $1}'` + V=`echo ${LINE} | awk -F'=' '{print $2}'` + else + K=`echo ${LINE} | awk -F'=' '{print $1}' | tr -d '[:space:]'` + V=`echo ${LINE} | awk -F'=' '{print $2}' | tr -d '[:space:]'` + fi + + if [ "${K}" = "}" ] + then + return + else + if [ "$1" = "" ] + then + KEYS="${K}" + else + KEYS="$1,${K}" + fi + + if [ "${V}" = "{" ] + then + merge_tfvars ${KEYS} + else + rec_key=$(echo ${KEYS##*,}) + final_rec_value_string="${final_rec_value_string}${final_rec_value_string:+,}$rec_key=$V" + rec_num=$(($rec_num + 1)) + if [ "$rec_num" = "5" ]; then + final_key=$(echo $KEYS|rev|cut -d',' -f2-|rev) + cluster_resource_map[${final_key}]="$final_rec_value_string" + rec_num="0" + final_rec_value_string="" + fi + fi + fi + done + } + + convert_cpu_unit_to_bytes() + { + unit="$1" + result=$(echo "$unit"|awk ' + /^[0-9.]+$/ { + print $0 * 1000 + exit + } + /^[0-9.]+m$/ { + match($0, /^[0-9.]+/) + mynumber = substr($0,RSTART,RLENGTH) + print mynumber + exit + } + // { + print -1 + } + ') + echo $result + } + + convert_memory_unit_to_bytes() + { + unit="$1" + result=$(echo "$unit"|awk ' + /^[0-9.]+e$/ { + print -1 + exit + } + /^[0-9]+$/ { + print $0 + exit + } + /^[0-9.]+[EPTGMkKi]+$/ { + match($0, /^[0-9.]+/) + myunit = substr($0,RLENGTH+1,length($0)) + mynumber = substr($0,RSTART,RLENGTH) + #print mynumber,myunit + if (myunit == "E") + print mynumber * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 + else if (myunit == "P") + print mynumber * 1000 * 1000 * 1000 * 1000 * 1000 + else if (myunit == "T") + print mynumber * 1000 * 1000 * 1000 * 1000 + else if (myunit == "G") + print mynumber * 1000 * 1000 * 1000 + else if (myunit == "M") + print mynumber * 1000 * 1000 + else if (myunit == "k") + print mynumber * 1000 + else if (myunit == "Ei"||myunit == "EiB") + print mynumber * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 + else if (myunit == "Pi"||myunit == "PiB") + print mynumber * 1024 * 1024 * 1024 * 1024 * 1024 + else if (myunit == "Ti"||myunit == "TiB") + print mynumber * 1024 * 1024 * 1024 * 1024 + else if (myunit == "Gi"||myunit == "GiB") + print mynumber * 1024 * 1024 * 1024 + else if (myunit == "Mi"||myunit == "MiB") + print mynumber * 1024 * 1024 + else if (myunit == "Ki"||myunit == "KiB") + print mynumber * 1024 + else + print -1 + exit + } + /^[0-9.]+[eE][0-9]+$/ { + IGNORECASE = 1; + match($0, /^[0-9.]+/) + myexponumber = substr($0,RLENGTH+2,length($0)) + mynumber = substr($0,RSTART,RLENGTH) + print mynumber * 10 ^ myexponumber + exit + } + /^[0-9.]+[m]+$/ { + match($0, /^[0-9.]+/) + myunit = substr($0,RLENGTH+1,length($0)) + mynumber = substr($0,RSTART,RLENGTH) + printf "%.3f",mynumber /1000 + exit + } + // { + print -1 + } + ') + echo $result + } + + parse_value_from_resource() + { + target_field="$1" + target_resource="$2" + if [ -z "$target_field" ]; then + err_code="3" + show_error "parse_value_from_resource() target_field parameter can't be empty." $err_code + exit $err_code + elif [ -z "$target_resource" ]; then + err_code="3" + show_error "parse_value_from_resource() target_resource parameter can't be empty." $err_code + exit $err_code + fi + + if [ "$target_field" != "limits" ] && [ "$target_field" != "requests" ]; then + err_code="3" + show_error "parse_value_from_resource() target_field can only be either 'limits' and 'requests'." $err_code + exit $err_code + fi + + if [ "$target_resource" != "cpu" ] && [ "$target_resource" != "memory" ]; then + err_code="3" + show_error "parse_value_from_resource() target_field can only be either 'cpu' and 'memory'." $err_code + exit $err_code + fi + + echo "$resources"|grep -o "\"$target_field\":[^{]*{[^}]*}"|grep -o "\"$target_resource\":[^\"]*\"[^\"]*\""|cut -d '"' -f4|head -1 + } + + parse_value_from_quota() + { + target_field="$1" + target_resource="$2" + if [ -z "$target_field" ]; then + err_code="3" + show_error "parse_value_from_quota() target_field parameter can't be empty." $err_code + exit $err_code + elif [ -z "$target_resource" ]; then + err_code="3" + show_error "parse_value_from_quota() target_resource parameter can't be empty." $err_code + exit $err_code + fi + + if [ "$target_field" != "limits" ] && [ "$target_field" != "requests" ]; then + err_code="3" + show_error "parse_value_from_quota() target_field can only be either 'limits' and 'requests'." $err_code + exit $err_code + fi + + if [ "$target_resource" != "cpu" ] && [ "$target_resource" != "memory" ]; then + err_code="3" + show_error "parse_value_from_quota() target_field can only be either 'cpu' and 'memory'." $err_code + exit $err_code + fi + + echo "$quotas"|grep -o "\"$target_field.$target_resource\":[^\"]*\"[^\"]*\""|cut -d '"' -f4 + } + + get_namespace_quota_from_kubecmd() + { + mode=$1 + if [ "$mode" = "" ]; then + err_code="4" + show_error "get_namespace_quota_from_kubecmd() mode parameter can't be empty." $err_code + exit $err_code + fi + + quota_name="${target_namespace}.federator.ai" + + show_info "Getting current namespace quota..." + show_info "Namespace = $target_namespace" + show_info "Quota name = $quota_name" + + if [ "$DEMO_MODE" != "y" ]; then + quotas=$($kube_cmd get quota $quota_name -n $target_namespace -o json 2>/dev/null|tr -d '\n'|grep -o "\"spec\":.*"|grep -o "\"hard\":[^}]*}"|head -1) + limit_cpu=$(parse_value_from_quota "limits" "cpu") + limit_memory=$(parse_value_from_quota "limits" "memory") + request_cpu=$(parse_value_from_quota "requests" "cpu") + request_memory=$(parse_value_from_quota "requests" "memory") + else + limit_cpu="" + limit_memory="" + request_cpu="" + request_memory="" + fi + + if [ "$mode" = "before" ]; then + if [ "$limit_cpu" = "" ]; then + limit_cpu_before="N/A" + else + limit_cpu_before=$limit_cpu + fi + if [ "$limit_memory" = "" ]; then + limit_memory_before="N/A" + else + limit_memory_before=$limit_memory + fi + if [ "$request_cpu" = "" ]; then + request_cpu_before="N/A" + else + request_cpu_before=$request_cpu + fi + if [ "$request_memory" = "" ]; then + request_memory_before="N/A" + else + request_memory_before=$request_memory + fi + show_info "--------- Namespace Quota: Before execution ---------" + show_info "limits:" + show_info " cpu: $limit_cpu_before" + show_info " memory: $limit_memory_before" + show_info "Requests:" + show_info " cpu: $request_cpu_before" + show_info " memory: $request_memory_before" + show_info "-----------------------------------------------------" + else + # mode = "after" + if [ "$do_dry_run" = "y" ]; then + show_info "--------------------- Dry run -----------------------" + # dry run - set resource values from planning results to display + limit_cpu_after="${limits_pod_cpu}m" + limit_memory_after="$limits_pod_memory" + request_cpu_after="${requests_pod_cpu}m" + request_memory_after="$requests_pod_memory" + else + # patch is done + if [ "$limit_cpu" = "" ]; then + limit_cpu_after="N/A" + else + limit_cpu_after=$limit_cpu + fi + if [ "$limit_memory" = "" ]; then + limit_memory_after="N/A" + else + limit_memory_after=$limit_memory + fi + if [ "$request_cpu" = "" ]; then + request_cpu_after="N/A" + else + request_cpu_after=$request_cpu + fi + if [ "$request_memory" = "" ]; then + request_memory_after="N/A" + else + request_memory_after=$request_memory + fi + show_info "--------- Namespace Quota: After execution ----------" + fi + show_info "limits:" + show_info " cpu: $limit_cpu_before -> $limit_cpu_after" + show_info " memory: $limit_memory_before -> $limit_memory_after" + show_info "Requests:" + show_info " cpu: $request_cpu_before -> $request_cpu_after" + show_info " memory: $request_memory_before -> $request_memory_after" + show_info "-----------------------------------------------------" + echo -e "{\n \"info\": {\n \"cluster_name\": \"$cluster_name\",\n \"resource_type\": \"$resource_type\",\n \"resource_name\": \"$target_namespace\",\n \"time_interval\": \"$readable_granularity\",\n \"execute_cmd\": \"$exec_cmd\",\n \"execution_time\": \"$execution_time\"\n },\n \"log_file\": \"$debug_log\",\n \"before_execution\": {\n \"limits\": {\n \"cpu\": \"$limit_cpu_before\",\n \"memory\": \"$limit_memory_before\"\n },\n \"requests\": {\n \"cpu\": \"$request_cpu_before\",\n \"memory\": \"$request_memory_before\"\n }\n },\n \"after_execution\": {\n \"limits\": {\n \"cpu\": \"$limit_cpu_after\",\n \"memory\": \"$limit_memory_after\"\n },\n \"requests\": {\n \"cpu\": \"$request_cpu_after\",\n \"memory\": \"$request_memory_after\"\n }\n }\n}" | tee -a $debug_log + fi + show_info "Done." + } + + get_controller_resources_from_kubecmd() + { + mode=$1 + if [ "$mode" = "" ]; then + err_code="4" + show_error "get_controller_resources_from_kubecmd() mode parameter can't be empty." $err_code + exit $err_code + fi + + get_container_number_and_name_list + + if [ "$DEMO_MODE" = "y" ]; then + container_number=$container_records_num + container_array=("${container_name_keys[@]}") + fi + + if [ "0$container_number" -ge "2" ]; then + show_info "Getting current controller resources (per container)..." + show_info "Namespace = $target_namespace" + show_info "Resource name = $resource_name" + show_info "Kind = $owner_reference_kind" + if [ "$DEMO_MODE" != "y" ]; then + controller_resources="$($kube_cmd get $owner_reference_kind $resource_name -n $target_namespace -o json)" + data=$(tokenize_json "$controller_resources"| parse_json_begin) + err_code="$?" + if [ "$err_code" != "0" ]; then + show_error "Failed to parse json output (controller_resources)." $err_code + exit $err_code + fi + fi + + for container_name in "${container_array[@]}" + do + for index in `seq 0 $(( container_number - 1 ))` + do + name=$(get_valued_from_parsed_json "$data" "\[\"spec\",\"template\",\"spec\",\"containers\",$index,\"name\"") + if [ "$name" = "$container_name" ]; then + limit_cpu=$(get_valued_from_parsed_json "$data" "\[\"spec\",\"template\",\"spec\",\"containers\",$index,\"resources\",\"limits\",\"cpu\"\]") + limit_memory=$(get_valued_from_parsed_json "$data" "\[\"spec\",\"template\",\"spec\",\"containers\",$index,\"resources\",\"limits\",\"memory\"\]") + request_cpu=$(get_valued_from_parsed_json "$data" "\[\"spec\",\"template\",\"spec\",\"containers\",$index,\"resources\",\"requests\",\"cpu\"\]") + request_memory=$(get_valued_from_parsed_json "$data" "\[\"spec\",\"template\",\"spec\",\"containers\",$index,\"resources\",\"requests\",\"memory\"\]") + fi + done + + if [ "$limit_cpu" = "" ]; then + limit_cpu="N/A" + else + limit_cpu_converted=$(convert_cpu_unit_to_bytes "$limit_cpu") + fi + if [ "$limit_memory" = "" ]; then + limit_memory="N/A" + else + limit_memory_converted=$(convert_memory_unit_to_bytes "$limit_memory") + fi + if [ "$request_cpu" = "" ]; then + request_cpu="N/A" + else + request_cpu_converted=$(convert_cpu_unit_to_bytes "$request_cpu") + fi + if [ "$request_memory" = "" ]; then + request_memory="N/A" + else + request_memory_converted=$(convert_memory_unit_to_bytes "$request_memory") + fi + show_info "container ($container_name) resources" + show_info "limits:" + show_info " cpu: $limit_cpu" + show_info " memory: $limit_memory" + show_info "Requests:" + show_info " cpu: $request_cpu" + show_info " memory: $request_memory" + show_info "-----------------------------------------------------" + + if [ "$mode" = "before" ]; then + container_resource_array+=( "$container_name.before.limits.cpu.original:$limit_cpu" ) + container_resource_array+=( "$container_name.before.limits.memory.original:$limit_memory" ) + container_resource_array+=( "$container_name.before.requests.cpu.original:$request_cpu" ) + container_resource_array+=( "$container_name.before.requests.memory.original:$request_memory" ) + container_resource_array+=( "$container_name.before.limits.cpu.converted:$limit_cpu_converted" ) + container_resource_array+=( "$container_name.before.limits.memory.converted:$limit_memory_converted" ) + container_resource_array+=( "$container_name.before.requests.cpu.converted:$request_cpu_converted" ) + container_resource_array+=( "$container_name.before.requests.memory.converted:$request_memory_converted" ) + else + # mode = "after" + if [ "$do_dry_run" = "y" ]; then + show_info "--------------------- Dry run -----------------------" + # dry run - set resource values from planning results to display + limits_pod_cpu=$(get_value_from_resource_array $container_name after limits cpu original) + limits_pod_memory=$(get_value_from_resource_array $container_name after limits memory original) + requests_pod_cpu=$(get_value_from_resource_array $container_name after requests cpu original) + requests_pod_memory=$(get_value_from_resource_array $container_name after requests memory original) + limit_cpu_after="${limits_pod_cpu}m" + limit_memory_after="$limits_pod_memory" + request_cpu_after="${requests_pod_cpu}m" + request_memory_after="$requests_pod_memory" + else + # patch is done + show_info "------------------ After execution ------------------" + limit_cpu_after=$limit_cpu + limit_memory_after=$limit_memory + request_cpu_after=$request_cpu + request_memory_after=$request_memory + fi + limit_cpu_before=$(get_value_from_resource_array $container_name before limits cpu original) + limit_memory_before=$(get_value_from_resource_array $container_name before limits memory original) + request_cpu_before=$(get_value_from_resource_array $container_name before requests cpu original) + request_memory_before=$(get_value_from_resource_array $container_name before requests memory original) + show_info "container ($container_name)" + show_info "limits:" + show_info " cpu: $limit_cpu_before -> $limit_cpu_after" + show_info " memory: $limit_memory_before -> $limit_memory_after" + show_info "Requests:" + show_info " cpu: $request_cpu_before -> $request_cpu_after" + show_info " memory: $request_memory_before -> $request_memory_after" + show_info "-----------------------------------------------------" + if [ "$do_dry_run" = "y" ]; then + # For dry run mode, print every json result + exec_cmd=$(get_value_from_resource_array $container_name after issue execute cmd) + execution_time=$(get_value_from_resource_array $container_name after issue execute time) + echo -e "{\n \"info\": {\n \"cluster_name\": \"$cluster_name\",\n \"resource_type\": \"$resource_type\",\n \"namespace\": \"$target_namespace\",\n \"resource_name\": \"$resource_name\",\n \"kind\": \"$owner_reference_kind\",\n \"time_interval\": \"$readable_granularity\",\n \"execute_cmd\": \"$exec_cmd\",\n \"execution_time\": \"$execution_time\"\n },\n \"log_file\": \"$debug_log\",\n \"before_execution\": {\n \"limits\": {\n \"cpu\": \"$limit_cpu_before\",\n \"memory\": \"$limit_memory_before\"\n },\n \"requests\": {\n \"cpu\": \"$request_cpu_before\",\n \"memory\": \"$request_memory_before\"\n }\n },\n \"after_execution\": {\n \"limits\": {\n \"cpu\": \"$limit_cpu_after\",\n \"memory\": \"$limit_memory_after\"\n },\n \"requests\": {\n \"cpu\": \"$request_cpu_after\",\n \"memory\": \"$request_memory_after\"\n }\n }\n}" | tee -a $debug_log + fi + fi + done + if [ "$mode" = "after" ] && [ "$do_dry_run" != "y" ]; then + # Only display last container execution result for now + echo -e "{\n \"info\": {\n \"cluster_name\": \"$cluster_name\",\n \"resource_type\": \"$resource_type\",\n \"namespace\": \"$target_namespace\",\n \"resource_name\": \"$resource_name\",\n \"kind\": \"$owner_reference_kind\",\n \"time_interval\": \"$readable_granularity\",\n \"execute_cmd\": \"$exec_cmd\",\n \"execution_time\": \"$execution_time\"\n },\n \"log_file\": \"$debug_log\",\n \"before_execution\": {\n \"limits\": {\n \"cpu\": \"$limit_cpu_before\",\n \"memory\": \"$limit_memory_before\"\n },\n \"requests\": {\n \"cpu\": \"$request_cpu_before\",\n \"memory\": \"$request_memory_before\"\n }\n },\n \"after_execution\": {\n \"limits\": {\n \"cpu\": \"$limit_cpu_after\",\n \"memory\": \"$limit_memory_after\"\n },\n \"requests\": {\n \"cpu\": \"$request_cpu_after\",\n \"memory\": \"$request_memory_after\"\n }\n }\n}" | tee -a $debug_log + fi + else + # only one container + show_info "Getting current controller resources..." + show_info "Namespace = $target_namespace" + show_info "Resource name = $resource_name" + show_info "Kind = $owner_reference_kind" + + if [ "$DEMO_MODE" != "y" ]; then + resources=$($kube_cmd get $owner_reference_kind $resource_name -n $target_namespace -o json |tr -d '\n'|grep -o "\"spec\":.*"|grep -o "\"template\":.*"|grep -o "\"spec\":.*"|grep -o "\"containers\":.*"|grep -o "\"resources\":.*") + fi + if [ "$mode" = "before" ]; then + show_info "----------------- Before execution ------------------" + limit_cpu_before=$(parse_value_from_resource "limits" "cpu") + if [ "$limit_cpu_before" = "" ]; then + limit_cpu_before="N/A" + else + limit_cpu_before_converted=$(convert_cpu_unit_to_bytes "$limit_cpu_before") + fi + limit_memory_before=$(parse_value_from_resource "limits" "memory") + if [ "$limit_memory_before" = "" ]; then + limit_memory_before="N/A" + else + limit_memory_before_converted=$(convert_memory_unit_to_bytes "$limit_memory_before") + fi + request_cpu_before=$(parse_value_from_resource "requests" "cpu") + if [ "$request_cpu_before" = "" ]; then + request_cpu_before="N/A" + else + request_cpu_before_converted=$(convert_cpu_unit_to_bytes "$request_cpu_before") + fi + request_memory_before=$(parse_value_from_resource "requests" "memory") + if [ "$request_memory_before" = "" ]; then + request_memory_before="N/A" + else + request_memory_before_converted=$(convert_memory_unit_to_bytes "$request_memory_before") + fi + show_info "limits:" + show_info " cpu: $limit_cpu_before" + show_info " memory: $limit_memory_before" + show_info "Requests:" + show_info " cpu: $request_cpu_before" + show_info " memory: $request_memory_before" + show_info "-----------------------------------------------------" + else + # mode = "after" + if [ "$do_dry_run" = "y" ]; then + show_info "--------------------- Dry run -----------------------" + # dry run - set resource values from planning results to display + limit_cpu_after="${limits_pod_cpu}m" + limit_memory_after="$limits_pod_memory" + request_cpu_after="${requests_pod_cpu}m" + request_memory_after="$requests_pod_memory" + else + # patch is done + show_info "------------------ After execution ------------------" + limit_cpu_after=$(parse_value_from_resource "limits" "cpu") + [ "$limit_cpu_after" = "" ] && limit_cpu_after="N/A" + limit_memory_after=$(parse_value_from_resource "limits" "memory") + [ "$limit_memory_after" = "" ] && limit_memory_after="N/A" + request_cpu_after=$(parse_value_from_resource "requests" "cpu") + [ "$request_cpu_after" = "" ] && request_cpu_after="N/A" + request_memory_after=$(parse_value_from_resource "requests" "memory") + [ "$request_memory_after" = "" ] && request_memory_after="N/A" + fi + + show_info "limits:" + show_info " cpu: $limit_cpu_before -> $limit_cpu_after" + show_info " memory: $limit_memory_before -> $limit_memory_after" + show_info "Requests:" + show_info " cpu: $request_cpu_before -> $request_cpu_after" + show_info " memory: $request_memory_before -> $request_memory_after" + show_info "-----------------------------------------------------" + + echo -e "{\n \"info\": {\n \"cluster_name\": \"$cluster_name\",\n \"resource_type\": \"$resource_type\",\n \"namespace\": \"$target_namespace\",\n \"resource_name\": \"$resource_name\",\n \"kind\": \"$owner_reference_kind\",\n \"time_interval\": \"$readable_granularity\",\n \"execute_cmd\": \"$exec_cmd\",\n \"execution_time\": \"$execution_time\"\n },\n \"log_file\": \"$debug_log\",\n \"before_execution\": {\n \"limits\": {\n \"cpu\": \"$limit_cpu_before\",\n \"memory\": \"$limit_memory_before\"\n },\n \"requests\": {\n \"cpu\": \"$request_cpu_before\",\n \"memory\": \"$request_memory_before\"\n }\n },\n \"after_execution\": {\n \"limits\": {\n \"cpu\": \"$limit_cpu_after\",\n \"memory\": \"$limit_memory_after\"\n },\n \"requests\": {\n \"cpu\": \"$request_cpu_after\",\n \"memory\": \"$request_memory_after\"\n }\n }\n}" | tee -a $debug_log + fi + fi + + show_info "Done." + } + + connection_test() + { + check_rest_api_url + rest_api_login + } + + normal_way(){ + if [ "$resource_type" = "controller" ];then + if [ "$DEMO_MODE" != "y" ]; then + get_controller_resources_from_kubecmd "before" + get_planning_from_api + else + get_planning_from_api + get_controller_resources_from_kubecmd "before" + fi + elif [ "$resource_type" = "namespace" ]; then + get_namespace_quota_from_kubecmd "before" + get_planning_from_api + else + err_code="3" + show_error "Only support resource_type equals 'controller' or 'namespace'." $err_code + exit $err_code + fi + + if [ "$do_dry_run" = "y" ]; then + update_target_resources "dry_run" + else + update_target_resources "normal" + fi + + if [ "$iac_command" = "script" ]; then + if [ "$resource_type" = "controller" ];then + get_controller_resources_from_kubecmd "after" + else + # resource_type = namespace + get_namespace_quota_from_kubecmd "after" + fi + fi + } + + # json parser parameter + NO_HEAD=0 + NORMALIZE_SOLIDUS=0 + BRIEF=1 + LEAFONLY=1 + PRUNE=1 + + while getopts "h-:" o; do + case "${o}" in + -) + case "${OPTARG}" in + dry-run-only) + do_dry_run="y" + ;; + test-connection-only) + do_test_connection="y" + ;; + verbose) + verbose_mode="y" + ;; + log-name) + log_name="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 )) + if [ "$log_name" = "" ]; then + err_code="6" + show_error "Missing --${OPTARG} value" $err_code + exit $err_code + fi + ;; + terraform-path) + terraform_path="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 )) + if [ "$terraform_path" = "" ]; then + err_code="6" + show_error "Missing --${OPTARG} value" $err_code + exit $err_code + fi + ;; + detail-to-stderr) + detail_to_stderr="y" + ;; + help) + show_usage + exit 0 + ;; + *) + err_code="6" + show_error "Unknown option --${OPTARG}" $err_code + exit $err_code + ;; + esac;; + h) + show_usage + exit 0 + ;; + *) + err_code="6" + show_error "Wrong parameter." $err_code + exit $err_code + ;; + esac + done + + if [ "$DEMO_MODE" = "y" ] && [ "$do_dry_run" != "y" ]; then + err_code="6" + show_error "DEMO_MODE env enabled. It can only run with dry run mode" $err_code + exit $err_code + fi + + unameOut="$(uname -s)" + case "${unameOut}" in + Linux*) + machine_type=Linux;; + Darwin*) + machine_type=Mac;; + *) + err_code="6" + show_error "Unsupported machine type (${unameOut})." $err_code + exit $err_code + ;; + esac + + if [ "$FEDERATORAI_FILE_PATH" = "" ]; then + save_path="/opt/federatorai" + else + save_path="$FEDERATORAI_FILE_PATH" + fi + + file_folder="$save_path/auto-provisioning" + realpath() { + [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" + } + + if [ "$log_name" = "" ]; then + log_name="output.log" + debug_log="${file_folder}/${log_name}" + else + if [[ "$log_name" = /* ]]; then + # Absolute path + file_folder="$(dirname "$log_name")" + debug_log="$log_name" + else + # Relative path + if [ "$machine_type" = "Linux" ]; then + file_folder="${file_folder}/$(dirname "$log_name")" + debug_log="${file_folder}/$(basename "$log_name")" + else + parent_folder=$(dirname $log_name) + file_folder="$file_folder/$parent_folder" + debug_log="${file_folder}/$(basename "$log_name")" + fi + fi + fi + + mkdir -p $file_folder + if [ ! -d "$file_folder" ]; then + err_code="6" + show_error "Failed to create folder ($file_folder) to save Federator.ai planning-util files. Consider exporting the env variable \$FEDERATORAI_FILE_PATH to specify the folder path." + exit $err_code + fi + + if [ "$machine_type" = "Linux" ]; then + script_located_path=$(dirname $(readlink -f "$0")) + else + # Mac + script_located_path=$(dirname $(realpath "$0")) + fi + + if [ "$terraform_path" = "" ]; then + terraform_path="$script_located_path" + fi + mkdir -p $terraform_path + if [ ! -d "$terraform_path" ]; then + err_code="6" + show_error "Failed to create terraform folder ($terraform_path) to save Federator.ai planning-util files." $err_code + exit $err_code + fi + + current_location=`pwd` + # mCore + default_min_cpu="50" + # Byte + default_min_memory="10485760" + echo "================================== New Round ======================================" >> $debug_log + echo "Receiving command: '$0 $@'" >> $debug_log + echo "Receiving time: `date -u`" >> $debug_log + + # Check target_config_info variable + check_target_config + + # Get resource type + resource_type=$(parse_value_from_target_var "resource_type") + resource_type="$(echo "$resource_type" | tr '[:upper:]' '[:lower:]')" + + # Parse config info + get_info_from_config + + # Get kubeconfig path + kubeconfig_path=$(parse_value_from_target_var "kubeconfig_path") + + if [ "$DEMO_MODE" != "y" ]; then + if [ "$resource_type" = "controller" ] && [ "$owner_reference_kind" = "deploymentconfig" ]; then + if [ "$kubeconfig_path" = "" ]; then + kube_cmd="oc" + verify_cmd="kubectl" + else + kube_cmd="oc --kubeconfig $kubeconfig_path" + verify_cmd="kubectl --kubeconfig $kubeconfig_path" + fi + cmd_type="oc" + else + if [ "$kubeconfig_path" = "" ]; then + kube_cmd="kubectl" + else + kube_cmd="kubectl --kubeconfig $kubeconfig_path" + fi + cmd_type="kubectl" + fi + + type $cmd_type > /dev/null 2>&1 + if [ "$?" != "0" ];then + err_code="6" + show_error "$cmd_type command is needed for this tool." $err_code + exit $err_code + fi + + if [ "$cmd_type" = "oc" ]; then + # kubectl must exist too + type kubectl > /dev/null 2>&1 + if [ "$?" != "0" ];then + err_code="6" + show_error "kubectl command is needed for this tool." $err_code + exit $err_code + fi + # Still use kubectl version to verify server connection + $verify_cmd version|grep -q "^Server" + else + $kube_cmd version|grep -q "^Server" + fi + + if [ "$?" != "0" ];then + err_code="6" + show_error "Failed to get Kubernetes server info through $cmd_type cmd. Please login first or check your kubeconfig_path config value." $err_code + exit $err_code + fi + else + # Demo mode + kube_cmd="kubectl" + fi + + type curl > /dev/null 2>&1 + if [ "$?" != "0" ];then + err_code="6" + show_error "curl command is needed for this tool." $err_code + exit $err_code + fi + + type awk > /dev/null 2>&1 + if [ "$?" != "0" ];then + err_code="6" + show_error "awk command is needed for this tool." $err_code + exit $err_code + fi + + type base64 > /dev/null 2>&1 + if [ "$?" != "0" ];then + err_code="6" + show_error "base64 command is needed for this tool." $err_code + exit $err_code + fi + + connection_test + if [ "$do_test_connection" = "y" ]; then + echo -e "{\n \"connection_test\": \"passed\",\n \"log_file\": \"$debug_log\"\n}" | tee -a $debug_log + exit 0 + fi + + rest_api_check_cluster_name + + container_resource_array=() + container_planning_array=() + + if [ "$resource_type" = "application" ];then + do_application_way + else + normal_way + fi + planning-util.sh.template.desc: |- + { + "rest_api_url": "", + "login_account": " # required # Federator.ai GUI login account", + "login_password": " # required # Federator.ai GUI login password", + "resource_type": " # required # controller|application|namespace", + "iac_command": " # required # script|terraform", + "kubeconfig_path": " # optional # kubeconfig path", + "planning_target": { + "cluster_name": " # required", + "namespace": " # required if resource_type=controller", + "time_interval": " # required # daily|weekly|monthly", + "resource_name": " # required", + "kind": " # required if resource_type=controller # StatefulSet|Deployment|DeploymentConfig", + "min_cpu": " # optional # mCore", + "max_cpu": " # optional # mCore", + "cpu_headroom": " # optional # 200|20% # Absolute value (mCore) e.g. 200 or Percentage e.g. 20%", + "min_memory": " # optional # byte", + "max_memory": " # optional # byte", + "memory_headroom": " # optional # 209715200|20% # Absolute value (byte) e.g. 209715200 or Percentage e.g. 20%", + "trigger_condition": " # optional # 20 # 20 means 20%" + } + } diff --git a/charts/prophetstor/federatorai/templates/federatorai-rest/deployments.yaml b/charts/prophetstor/federatorai/templates/federatorai-rest/deployments.yaml index 0c1297233..db1611e62 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-rest/deployments.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-rest/deployments.yaml @@ -1,8 +1,15 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-rest @@ -21,92 +28,114 @@ spec: type: RollingUpdate template: metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} - labels: {{ include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} + annotations: +{{- if .Values.global.podAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.podAnnotations "context" .) | nindent 8 }} +{{- end }} + labels: +{{- if .Values.global.podLabels }} +{{- include "render-value" ( dict "value" .Values.global.podLabels "context" .) | nindent 8 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-rest name: federatorai-rest spec: - affinity: {{- include "render-value" ( dict "value" .Values.federatoraiRest.affinity "context" .) | nindent 8 }} + affinity: +{{- if .Values.federatoraiRest.affinity }} +{{- include "render-value" ( dict "value" .Values.federatoraiRest.affinity "context" .) | nindent 8 }} +{{- end }} containers: - - env: - - name: NAMESPACE_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.name - - name: INFLUXDB_ADDRESS - value: https://alameda-influxdb.{{ .Release.Namespace }}.svc:8086 - - name: INFLUXDB_USERNAME - value: admin - - name: INFLUXDB_PASSWORD - value: adminpass - - name: DATAHUB_ADDRESS - value: alameda-datahub.{{ .Release.Namespace }}.svc:50050 - - name: BINDADDRESS - value: :5055 - - name: FEDEMETER_ADDRESS - value: http://fedemeter-api.{{ .Release.Namespace }}.svc:8888/fedemeter-api - - name: FEDEMETER_USERNAME - value: fedemeter - - name: FEDEMETER_PASSWORD - value: $6$pOwGiawPSjz7qLaN$fnMXEhwzWnUw.bOKohdAhB5K5iCCOJJaZXxQkhzH4URsHP8qLTT4QeBPUKjlOAeAHbKsqlf.fyuL2pNRmR6oQD1 - - name: NOTIFIER_USERNAME - value: admin - - name: NOTIFIER_PASSWORD - value: adminpass - - name: NOTIFIER_ADDRESS - value: alameda-rabbitmq.{{ .Release.Namespace }}.svc:5672 - - name: FEDERATORAI_MAXIMUM_LOG_SIZE - value: "1932735283" - image: {{ .Values.global.imageRegistry }}/federatorai-rest-ubi:{{ .Values.global.imageTag }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - livenessProbe: - exec: - command: - - /usr/local/bin/federatorai-rest - - probe - - --type=liveness - failureThreshold: 3 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 5 - name: federatorai-rest - readinessProbe: - exec: - command: - - /usr/local/bin/federatorai-rest - - probe - - --type=readiness - failureThreshold: 3 - initialDelaySeconds: 5 - periodSeconds: 60 - successThreshold: 1 - timeoutSeconds: 5 - resources: - {{- if .Values.global.resourcesEnabled }} - {{ include "render-value" ( dict "value" .Values.federatoraiRest.resources "context" .) | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/log/alameda - name: federatorai-rest-log-storage - imagePullSecrets: {{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} + - env: + - name: NAMESPACE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: INFLUXDB_ADDRESS + value: https://alameda-influxdb.{{ .Release.Namespace }}.svc:8086 + - name: INFLUXDB_USERNAME + value: admin + - name: INFLUXDB_PASSWORD + value: adminpass + - name: DATAHUB_ADDRESS + value: alameda-datahub.{{ .Release.Namespace }}.svc:50050 + - name: BINDADDRESS + value: :5055 + - name: FEDEMETER_ADDRESS + value: http://fedemeter-api.{{ .Release.Namespace }}.svc:8888/fedemeter-api + - name: FEDEMETER_USERNAME + value: fedemeter + - name: FEDEMETER_PASSWORD + value: $6$pOwGiawPSjz7qLaN$fnMXEhwzWnUw.bOKohdAhB5K5iCCOJJaZXxQkhzH4URsHP8qLTT4QeBPUKjlOAeAHbKsqlf.fyuL2pNRmR6oQD1 + - name: NOTIFIER_USERNAME + value: admin + - name: NOTIFIER_PASSWORD + value: adminpass + - name: NOTIFIER_ADDRESS + value: alameda-rabbitmq.{{ .Release.Namespace }}.svc:5672 + - name: FEDERATORAI_MAXIMUM_LOG_SIZE + value: "1932735283" + image: {{ .Values.global.imageRegistry }}/federatorai-rest-ubi:{{ .Values.global.imageTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + livenessProbe: + exec: + command: + - /usr/local/bin/federatorai-rest + - probe + - --type=liveness + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 5 + name: federatorai-rest + readinessProbe: + exec: + command: + - /usr/local/bin/federatorai-rest + - probe + - --type=readiness + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 5 + resources: +{{- if .Values.global.resourcesLimitsEnabled }} + limits: +{{- include "render-value" ( dict "value" .Values.federatoraiRest.resources.limits "context" .) | nindent 14 }} +{{- end }} +{{- if .Values.global.resourcesRequestsEnabled }} + requests: +{{- include "render-value" ( dict "value" .Values.federatoraiRest.resources.requests "context" .) | nindent 14 }} +{{- end }} + volumeMounts: + - mountPath: /var/log/alameda + name: federatorai-rest-log-storage + imagePullSecrets: +{{- if .Values.global.imagePullSecrets }} +{{ include "render-value" ( dict "value" .Values.global.imagePullSecrets "context" .) | nindent 8 }} +{{- end }} securityContext: fsGroup: 1001 - #{#{ include "render-value" ( dict "value" .Values.federatoraiRest.podSecurityContext "context" .) | nindent 10 }} +{{- if .Values.federatoraiRest.podSecurityContext }} +{{- include "render-value" ( dict "value" .Values.federatoraiRest.podSecurityContext "context" .) | nindent 8 }} +{{- end }} serviceAccount: federatorai-rest serviceAccountName: federatorai-rest - tolerations: {{- include "render-value" ( dict "value" .Values.federatoraiRest.tolerations "context" .) | nindent 6 }} + tolerations: +{{- if .Values.federatoraiRest.tolerations }} +{{- include "render-value" ( dict "value" .Values.federatoraiRest.tolerations "context" .) | nindent 6 }} +{{- end }} volumes: - - emptyDir: {} - name: federatorai-rest-data-storage - - name: federatorai-rest-log-storage - persistentVolumeClaim: - claimName: federatorai-rest-log.pvc + - emptyDir: {} + name: federatorai-rest-data-storage + - name: federatorai-rest-log-storage + persistentVolumeClaim: + claimName: federatorai-rest-log.pvc diff --git a/charts/prophetstor/federatorai/templates/federatorai-rest/pvc-log.yaml b/charts/prophetstor/federatorai/templates/federatorai-rest/pvc-log.yaml index 872293ea7..80f20df01 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-rest/pvc-log.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-rest/pvc-log.yaml @@ -1,14 +1,24 @@ +--- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-rest-log.pvc namespace: {{ .Release.Namespace }} spec: - accessModes: {{ .Values.federatoraiRest.persistence.accessModes | toYaml | nindent 2 }} + accessModes: +{{- if .Values.federatoraiRest.persistence.accessModes }} +{{ .Values.federatoraiRest.persistence.accessModes | toYaml | nindent 4 }} +{{- end }} resources: requests: storage: {{ .Values.federatoraiRest.persistence.logStorageSize }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-rest/rolebindings.yaml b/charts/prophetstor/federatorai/templates/federatorai-rest/rolebindings.yaml index a64a03dc0..f0c3ea29e 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-rest/rolebindings.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-rest/rolebindings.yaml @@ -1,8 +1,15 @@ +--- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-rest @@ -12,6 +19,6 @@ roleRef: kind: Role name: federatorai-rest subjects: -- kind: ServiceAccount - name: federatorai-rest - namespace: {{ .Release.Namespace }} + - kind: ServiceAccount + name: federatorai-rest + namespace: {{ .Release.Namespace }} diff --git a/charts/prophetstor/federatorai/templates/federatorai-rest/roles.yaml b/charts/prophetstor/federatorai/templates/federatorai-rest/roles.yaml index 80cd25b2f..e4e738543 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-rest/roles.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-rest/roles.yaml @@ -1,23 +1,38 @@ +--- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-rest namespace: {{ .Release.Namespace }} rules: -- apiGroups: - - "" - resources: - - pods/exec - verbs: - - create -- apiGroups: - - "" - resources: - - pods - verbs: - - get - - list + - apiGroups: + - "" + resources: + - pods/exec + verbs: + - create + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch diff --git a/charts/prophetstor/federatorai/templates/federatorai-rest/serviceaccounts.yaml b/charts/prophetstor/federatorai/templates/federatorai-rest/serviceaccounts.yaml index 2a83195f1..7db5352a1 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-rest/serviceaccounts.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-rest/serviceaccounts.yaml @@ -1,8 +1,15 @@ +--- apiVersion: v1 kind: ServiceAccount metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda name: federatorai-rest diff --git a/charts/prophetstor/federatorai/templates/federatorai-rest/services-loadbalancer.yaml b/charts/prophetstor/federatorai/templates/federatorai-rest/services-loadbalancer.yaml index 1bccf80d1..86f117e24 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-rest/services-loadbalancer.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-rest/services-loadbalancer.yaml @@ -1,12 +1,19 @@ +--- {{- if eq .Values.federatoraiRest.service.type "LoadBalancer" }} apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} {{- with .Values.federatoraiRest.service.annotations }} {{- toYaml . | nindent 4 }} {{- end }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-rest diff --git a/charts/prophetstor/federatorai/templates/federatorai-rest/services-nodeport.yaml b/charts/prophetstor/federatorai/templates/federatorai-rest/services-nodeport.yaml index 9a21e6ad6..aade9c614 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-rest/services-nodeport.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-rest/services-nodeport.yaml @@ -1,12 +1,19 @@ +--- {{- if eq .Values.federatoraiRest.service.type "NodePort" }} apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} {{- with .Values.federatoraiRest.service.annotations }} {{- toYaml . | nindent 4 }} {{- end }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-rest @@ -14,13 +21,13 @@ metadata: namespace: {{ .Release.Namespace }} spec: ports: - - name: restapi-nodeport - {{- if and .Values.federatoraiRest.service.nodePort }} - nodePort: {{ .Values.federatoraiRest.service.nodePort }} - {{- end }} - port: 5056 - protocol: TCP - targetPort: {{ .Values.federatoraiRest.service.targetPort }} + - name: restapi-nodeport + {{- if and .Values.federatoraiRest.service.nodePort }} + nodePort: {{ .Values.federatoraiRest.service.nodePort }} + {{- end }} + port: 5056 + protocol: TCP + targetPort: {{ .Values.federatoraiRest.service.targetPort }} selector: component: federatorai-rest type: NodePort diff --git a/charts/prophetstor/federatorai/templates/federatorai-rest/services.yaml b/charts/prophetstor/federatorai/templates/federatorai-rest/services.yaml index 8e8a286aa..dac93ca19 100644 --- a/charts/prophetstor/federatorai/templates/federatorai-rest/services.yaml +++ b/charts/prophetstor/federatorai/templates/federatorai-rest/services.yaml @@ -1,11 +1,18 @@ +--- apiVersion: v1 kind: Service metadata: - annotations: {{ include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} + annotations: +{{- if .Values.global.commonAnnotations }} +{{- include "render-value" ( dict "value" .Values.global.commonAnnotations "context" .) | nindent 4 }} +{{- end }} {{- with .Values.federatoraiRest.service.annotations }} {{- toYaml . | nindent 4 }} {{- end }} - labels: {{ include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} + labels: +{{- if .Values.global.commonLabels }} +{{- include "render-value" ( dict "value" .Values.global.commonLabels "context" .) | nindent 4 }} +{{- end }} app.kubernetes.io/part-of: federatorai app: alameda component: federatorai-rest @@ -16,18 +23,18 @@ spec: clusterIP: {{ .Values.federatoraiRest.service.clusterIP }} {{- end }} ports: - - name: restapi-http - port: 5055 - protocol: TCP - targetPort: 5055 - - name: restapi-https - port: 5056 - protocol: TCP - targetPort: 5056 - - name: restapi-burrow - port: 5059 - protocol: TCP - targetPort: 5059 + - name: restapi-http + port: 5055 + protocol: TCP + targetPort: 5055 + - name: restapi-https + port: 5056 + protocol: TCP + targetPort: 5056 + - name: restapi-burrow + port: 5059 + protocol: TCP + targetPort: 5059 selector: component: federatorai-rest type: ClusterIP diff --git a/charts/prophetstor/federatorai/values.yaml b/charts/prophetstor/federatorai/values.yaml index 07d2195cb..cee70e2e7 100644 --- a/charts/prophetstor/federatorai/values.yaml +++ b/charts/prophetstor/federatorai/values.yaml @@ -7,8 +7,8 @@ global: imageRegistry: "quay.io/prophetstor" ## @param global.imageTag Image tag of Federator.ai ## For example: - ## imageTag: "v5.1.0-ga" - imageTag: "v5.1.1-ga" + ## imageTag: "v5.1.2-ga" + imageTag: "v5.1.2-gz" ## @param global.imagePullPolicy Specify a imagePullPolicy ## For example: ## imagePullPolicy: "IfNotPresent" @@ -45,10 +45,14 @@ global: ## podLabels: ## k8s-app: federatorai podLabels: {} - ## @param global.resourcesEnabled Boolean to specify if you want to apply resources limits/requests settings + ## @param global.resourcesLimitsEnabled Boolean to specify if you want to apply resources limits settings ## For example: - ## resourcesEnabled: true - resourcesEnabled: false + ## resourcesLimitsEnabled: true + resourcesLimitsEnabled: false + ## @param global.resourcesRequestsEnabled Boolean to specify if you want to apply resources requests settings + ## For example: + ## resourcesRequestsEnabled: true + resourcesRequestsEnabled: false ################################################################### ## Default values for Federator.ai @@ -87,19 +91,19 @@ alamedaAi: ## For example: ## resources: ## limits: - ## cpu: "8" + ## cpu: 8000m ## memory: 8000Mi ## requests: - ## cpu: "2" - ## memory: 500Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## cpu: 2000m + ## memory: 1000Mi + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "8" + cpu: 8000m memory: 8000Mi requests: - cpu: "2" - memory: 500Mi + cpu: 2000m + memory: 1000Mi ## For example: ## tolerations: ## - effect: "NoExecute" @@ -138,15 +142,15 @@ alamedaAiDispatcher: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: ## cpu: 100m ## memory: 100Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: cpu: 100m @@ -189,18 +193,18 @@ alamedaDatahub: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: - ## cpu: 100m + ## cpu: 500m ## memory: 500Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: - cpu: 100m + cpu: 500m memory: 500Mi ## For example: ## tolerations: @@ -213,6 +217,10 @@ alamedaDatahub: tolerations: [] alamedaExecutor: + ## @param alamedaExecutor.enabled Enable deployment of alameda-executor + ## For example: + ## enabled: true + enabled: true ## For example: ## affinity: ## nodeAffinity: @@ -240,18 +248,18 @@ alamedaExecutor: ## For example: ## resources: ## limits: - ## cpu: 4 + ## cpu: 4000m ## memory: 8000Mi ## requests: - ## cpu: 100m + ## cpu: 50m ## memory: 100Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: - cpu: 100m + cpu: 50m memory: 100Mi ## For example: ## tolerations: @@ -295,15 +303,15 @@ alamedaInfluxdb: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 18000Mi ## requests: ## cpu: 500m ## memory: 500Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 18000Mi requests: cpu: 500m @@ -346,15 +354,15 @@ alamedaNotifier: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: ## cpu: 50m ## memory: 100Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: cpu: 50m @@ -392,19 +400,19 @@ alamedaRabbitmq: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: ## cpu: 100m - ## memory: 250Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## memory: 300Mi + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: cpu: 100m - memory: 250Mi + memory: 300Mi ## For example: ## tolerations: ## - effect: "NoExecute" @@ -443,19 +451,19 @@ fedemeterApi: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: - ## cpu: 100m - ## memory: 100Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## cpu: 500m + ## memory: 500Mi + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: - cpu: 100m - memory: 100Mi + cpu: 500m + memory: 500Mi ## For example: ## tolerations: ## - effect: "NoExecute" @@ -498,19 +506,19 @@ fedemeterInfluxdb: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: - ## cpu: 500m - ## memory: 500Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## cpu: 200m + ## memory: 200Mi + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: - cpu: 500m - memory: 500Mi + cpu: 200m + memory: 200Mi ## For example: ## tolerations: ## - effect: "NoExecute" @@ -549,15 +557,15 @@ federatoraiAgent: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: ## cpu: 100m ## memory: 100Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: cpu: 100m @@ -573,6 +581,10 @@ federatoraiAgent: tolerations: [] federatoraiAgentPreloader: + ## @param federatoraiAgentPreloader.enabled Enable deployment of federatorai-agent-preloader + ## For example: + ## enabled: false + enabled: false ## For example: ## affinity: ## nodeAffinity: @@ -590,20 +602,25 @@ federatoraiAgentPreloader: ## For example: ## podSecurityContext: ## runAsUser: 1001 + ## Persistence storage parameters + persistence: + accessModes: + - ReadWriteOnce + logStorageSize: 2Gi ## Pods' Security Context podSecurityContext: {} ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: ## cpu: 100m ## memory: 100Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: cpu: 100m @@ -646,15 +663,15 @@ federatoraiAlertDetector: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: ## cpu: 100m ## memory: 100Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: cpu: 100m @@ -697,15 +714,15 @@ federatoraiAlertManager: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: ## cpu: 100m ## memory: 100Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: cpu: 100m @@ -748,15 +765,15 @@ federatoraiDashboardBackend: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: ## cpu: 100m ## memory: 100Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: cpu: 100m @@ -874,15 +891,15 @@ federatoraiDashboardFrontend: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: ## cpu: 100m ## memory: 100Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: cpu: 100m @@ -976,19 +993,19 @@ federatoraiDataAdapter: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: ## cpu: 100m - ## memory: 100Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## memory: 500Mi + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: cpu: 100m - memory: 100Mi + memory: 500Mi ## For example: ## tolerations: ## - effect: "NoExecute" @@ -1000,6 +1017,10 @@ federatoraiDataAdapter: tolerations: [] federatoraiOperator: + ## @param federatoraiOperator.enabled Enable deployment of federatorai-operator + ## For example: + ## enabled: true + enabled: true ## For example: ## affinity: ## nodeAffinity: @@ -1022,15 +1043,15 @@ federatoraiOperator: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: ## cpu: 100m ## memory: 100Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: cpu: 100m @@ -1077,18 +1098,18 @@ federatoraiPostgresql: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: - ## cpu: 500m + ## cpu: 200m ## memory: 500Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: - cpu: 500m + cpu: 200m memory: 500Mi ## For example: ## tolerations: @@ -1128,15 +1149,15 @@ federatoraiRecommenderDispatcher: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: ## cpu: 100m ## memory: 100Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: cpu: 100m @@ -1183,15 +1204,15 @@ federatoraiRecommenderWorker: ## For example: ## resources: ## limits: - ## cpu: "84 + ## cpu: 4000m ## memory: 8000Mi ## requests: ## cpu: 100m ## memory: 100Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: cpu: 100m @@ -1234,18 +1255,18 @@ federatoraiRest: ## For example: ## resources: ## limits: - ## cpu: "4" + ## cpu: 4000m ## memory: 8000Mi ## requests: - ## cpu: 50m + ## cpu: 100m ## memory: 100Mi - ## Resource requests and limits. Apply if `global.resourcesEnabled` is "true". + ## Resource requests and limits. Apply if `global.resourcesLimitsEnabled` or/and `global.resourcesRequestsEnabled` is/are "true". resources: limits: - cpu: "4" + cpu: 4000m memory: 8000Mi requests: - cpu: 50m + cpu: 100m memory: 100Mi ## Expose REST service for public access service: diff --git a/charts/speedscale/speedscale-operator/Chart.yaml b/charts/speedscale/speedscale-operator/Chart.yaml index 3edc10f92..810c205f3 100644 --- a/charts/speedscale/speedscale-operator/Chart.yaml +++ b/charts/speedscale/speedscale-operator/Chart.yaml @@ -4,7 +4,7 @@ annotations: catalog.cattle.io/kube-version: '>= 1.17.0-0' catalog.cattle.io/release-name: speedscale-operator apiVersion: v1 -appVersion: 1.3.86 +appVersion: 1.3.94 description: Stress test your APIs with real world scenarios. Collect and replay traffic without scripting. home: https://speedscale.com @@ -24,4 +24,4 @@ maintainers: - email: support@speedscale.com name: Speedscale Support name: speedscale-operator -version: 1.3.10 +version: 1.3.12 diff --git a/charts/speedscale/speedscale-operator/README.md b/charts/speedscale/speedscale-operator/README.md index 8d25869dd..e3c7b608e 100644 --- a/charts/speedscale/speedscale-operator/README.md +++ b/charts/speedscale/speedscale-operator/README.md @@ -101,10 +101,10 @@ _See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documen A major chart version change (like v1.2.3 -> v2.0.0) indicates that there is an incompatible breaking change needing manual actions. -### Upgrade to 1.3.10 +### Upgrade to 1.3.12 ```bash -kubectl apply --server-side -f https://raw.githubusercontent.com/speedscale/operator-helm/main/1.3.10/templates/crds/trafficreplays.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/speedscale/operator-helm/main/1.3.12/templates/crds/trafficreplays.yaml ``` ### Upgrade to 1.1.0 diff --git a/charts/speedscale/speedscale-operator/app-readme.md b/charts/speedscale/speedscale-operator/app-readme.md index 8d25869dd..e3c7b608e 100644 --- a/charts/speedscale/speedscale-operator/app-readme.md +++ b/charts/speedscale/speedscale-operator/app-readme.md @@ -101,10 +101,10 @@ _See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documen A major chart version change (like v1.2.3 -> v2.0.0) indicates that there is an incompatible breaking change needing manual actions. -### Upgrade to 1.3.10 +### Upgrade to 1.3.12 ```bash -kubectl apply --server-side -f https://raw.githubusercontent.com/speedscale/operator-helm/main/1.3.10/templates/crds/trafficreplays.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/speedscale/operator-helm/main/1.3.12/templates/crds/trafficreplays.yaml ``` ### Upgrade to 1.1.0 diff --git a/charts/speedscale/speedscale-operator/values.yaml b/charts/speedscale/speedscale-operator/values.yaml index 1124a617d..0a76e14db 100644 --- a/charts/speedscale/speedscale-operator/values.yaml +++ b/charts/speedscale/speedscale-operator/values.yaml @@ -20,7 +20,7 @@ clusterName: "my-cluster" # Speedscale components image settings. image: registry: gcr.io/speedscale - tag: v1.3.86 + tag: v1.3.94 pullPolicy: Always # Log level for Speedscale components. diff --git a/index.yaml b/index.yaml index fcf10325b..078bdfd2b 100644 --- a/index.yaml +++ b/index.yaml @@ -11167,6 +11167,43 @@ entries: - assets/weka/csi-wekafsplugin-0.6.400.tgz version: 0.6.400 datadog: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Datadog + catalog.cattle.io/kube-version: '>=1.10-0' + catalog.cattle.io/release-name: datadog + apiVersion: v1 + appVersion: "7" + created: "2023-06-12T16:18:02.665316569Z" + dependencies: + - condition: clusterAgent.metricsProvider.useDatadogMetrics + name: datadog-crds + repository: https://helm.datadoghq.com + tags: + - install-crds + version: 0.4.7 + - condition: datadog.kubeStateMetricsEnabled + name: kube-state-metrics + repository: https://prometheus-community.github.io/helm-charts + version: 2.13.2 + description: Datadog Agent + digest: 53eceb6e2e9e5bc4a4d8bcbac9d3837aa239409dcfb5f7150fcd103f03ca33f6 + home: https://www.datadoghq.com + icon: https://datadog-live.imgix.net/img/dd_logo_70x75.png + keywords: + - monitoring + - alerting + - metric + maintainers: + - email: support@datadoghq.com + name: Datadog + name: datadog + sources: + - https://app.datadoghq.com/account/settings#agent/kubernetes + - https://github.com/DataDog/datadog-agent + urls: + - assets/datadog/datadog-3.32.1.tgz + version: 3.32.1 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: Datadog @@ -14371,6 +14408,38 @@ entries: - assets/crowdstrike/falcon-sensor-0.9.300.tgz version: 0.9.300 federatorai: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Federator.ai + catalog.cattle.io/kube-version: '>= 1.16.0-0' + catalog.cattle.io/release-name: federatorai + apiVersion: v2 + appVersion: 5.1.2-ga + created: "2023-06-12T16:18:06.254549253Z" + description: Federator.ai helps enterprises optimize cloud resources, maximize + application performance, and save significant cost without excessive over-provisioning + or under-provisioning of resources, meeting the service-level requirements of + their applications. + digest: 0bf3de3c20fb9ed9ff6b12249051f2694316acdda7ae07a6d2a7bb25854c946d + home: https://www.prophetstor.com + icon: https://raw.githubusercontent.com/prophetstor-ai/public/master/images/logo.png + keywords: + - AI + - Resource Orchestration + - NoOps + - AIOps + - Intelligent Workload Management + - Cost Optimization + kubeVersion: '>= 1.16.0-0' + maintainers: + - email: support@prophetstor.com + name: ProphetStor Data Services, Inc. + name: federatorai + sources: + - https://www.prophetstor.com + urls: + - assets/prophetstor/federatorai-5.1.2.tgz + version: 5.1.2 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: Federator.ai @@ -14819,6 +14888,112 @@ entries: - assets/inaccel/fpga-operator-2.5.201.tgz version: 2.5.201 gluu: + - annotations: + artifacthub.io/changes: | + - Chart 5.0.18 official release + artifacthub.io/containsSecurityUpdates: "true" + artifacthub.io/images: | + - name: auth-server + image: ghcr.io/janssenproject/jans/auth-server:1.0.14_dev + - name: auth-server-key-rotation + image: ghcr.io/janssenproject/jans/certmanager:1.0.14_dev + - name: configuration-manager + image: ghcr.io/janssenproject/jans/configurator:1.0.14_dev + - name: config-api + image: ghcr.io/janssenproject/jans/config-api:1.0.14_dev + - name: fido2 + image: ghcr.io/janssenproject/jans/fido2:1.0.14_dev + - name: opendj + image: gluufederation/opendj:5.0.0_dev + - name: persistence + image: ghcr.io/janssenproject/jans/persistence-loader:1.0.14_dev + - name: scim + image: ghcr.io/janssenproject/jans/scim:1.0.14_dev + - name: casa + image: ghcr.io/gluufederation/flex/casa:5.0.0_dev + - name: admin-ui + image: ghcr.io/gluufederation/flex/admin-ui:1.0.14_dev + artifacthub.io/license: Apache-2.0 + artifacthub.io/prerelease: "true" + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Gluu Cloud Identity and Access Management + catalog.cattle.io/kube-version: '>=v1.21.0-0' + catalog.cattle.io/release-name: gluu + apiVersion: v2 + appVersion: 5.0.0 + created: "2023-06-12T16:18:03.106342157Z" + dependencies: + - condition: global.config.enabled + name: config + repository: file://./charts/config + version: 5.0.18 + - condition: global.config-api.enabled + name: config-api + repository: file://./charts/config-api + version: 5.0.18 + - condition: global.opendj.enabled + name: opendj + repository: file://./charts/opendj + version: 5.0.18 + - condition: global.auth-server.enabled + name: auth-server + repository: file://./charts/auth-server + version: 5.0.18 + - condition: global.admin-ui.enabled + name: admin-ui + repository: file://./charts/admin-ui + version: 5.0.18 + - condition: global.fido2.enabled + name: fido2 + repository: file://./charts/fido2 + version: 5.0.18 + - condition: global.scim.enabled + name: scim + repository: file://./charts/scim + version: 5.0.18 + - condition: global.nginx-ingress.enabled + name: nginx-ingress + repository: file://./charts/nginx-ingress + version: 5.0.18 + - condition: global.oxshibboleth.enabled + name: oxshibboleth + repository: file://./charts/oxshibboleth + version: 5.0.18 + - condition: global.oxpassport.enabled + name: oxpassport + repository: file://./charts/oxpassport + version: 5.0.18 + - condition: global.casa.enabled + name: casa + repository: file://./charts/casa + version: 5.0.18 + - condition: global.auth-server-key-rotation.enabled + name: auth-server-key-rotation + repository: file://./charts/auth-server-key-rotation + version: 5.0.18 + - condition: global.persistence.enabled + name: persistence + repository: file://./charts/persistence + version: 5.0.18 + - condition: global.istio.ingress + name: cn-istio-ingress + repository: file://./charts/cn-istio-ingress + version: 5.0.18 + description: Gluu Access and Identity Management + digest: 270b904b009d03710b6a145782b3d609d4fcfc21a056b6504b5c040f185da474 + home: https://www.gluu.org + icon: https://gluu.org/docs/gluu-server/favicon.ico + kubeVersion: '>=v1.21.0-0' + maintainers: + - email: support@gluu.org + name: moabu + name: gluu + sources: + - https://gluu.org/docs/gluu-server + - https://github.com/GluuFederation/flex/flex-cn-setup + urls: + - assets/gluu/gluu-5.0.18.tgz + version: 5.0.18 - annotations: artifacthub.io/changes: | - Chart 5.0.17 official release @@ -17599,6 +17774,62 @@ entries: - assets/jaeger/jaeger-operator-2.36.0.tgz version: 2.36.0 jenkins: + - annotations: + artifacthub.io/category: integration-delivery + artifacthub.io/images: | + - name: jenkins + image: jenkins/jenkins:2.401.1-jdk11 + - name: k8s-sidecar + image: kiwigrid/k8s-sidecar:1.24.4 + - name: inbound-agent + image: jenkins/inbound-agent:3107.v665000b_51092-15 + - name: backup + image: maorfr/kube-tasks:0.2.0 + artifacthub.io/license: Apache-2.0 + artifacthub.io/links: | + - name: Chart Source + url: https://github.com/jenkinsci/helm-charts/tree/main/charts/jenkins + - name: Jenkins + url: https://www.jenkins.io/ + - name: support + url: https://github.com/jenkinsci/helm-charts/issues + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Jenkins + catalog.cattle.io/kube-version: '>=1.14-0' + catalog.cattle.io/release-name: jenkins + apiVersion: v2 + appVersion: 2.401.1 + created: "2023-06-12T16:18:03.560793779Z" + description: Jenkins - Build great things at any scale! The leading open source + automation server, Jenkins provides hundreds of plugins to support building, + deploying and automating any project. + digest: 7b77144e8708036a5067ac900ec9353140bd9fd4392337b48f9c18e3a056e983 + home: https://jenkins.io/ + icon: https://get.jenkins.io/art/jenkins-logo/logo.svg + keywords: + - jenkins + - ci + - devops + maintainers: + - email: maor.friedman@redhat.com + name: maorfr + - email: mail@torstenwalter.de + name: torstenwalter + - email: garridomota@gmail.com + name: mogaal + - email: wmcdona89@gmail.com + name: wmcdona89 + - email: timjacomb1@gmail.com + name: timja + name: jenkins + sources: + - https://github.com/jenkinsci/jenkins + - https://github.com/jenkinsci/docker-inbound-agent + - https://github.com/maorfr/kube-tasks + - https://github.com/jenkinsci/configuration-as-code-plugin + urls: + - assets/jenkins/jenkins-4.3.27.tgz + version: 4.3.27 - annotations: artifacthub.io/category: integration-delivery artifacthub.io/images: | @@ -24712,6 +24943,43 @@ entries: - assets/minio/minio-operator-4.4.1700.tgz version: 4.4.1700 mysql: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: MySQL + catalog.cattle.io/kube-version: '>=1.19-0' + catalog.cattle.io/release-name: mysql + category: Database + licenses: Apache-2.0 + apiVersion: v2 + appVersion: 8.0.33 + created: "2023-06-12T16:18:00.553359655Z" + dependencies: + - name: common + repository: file://./charts/common + tags: + - bitnami-common + version: 2.x.x + description: MySQL is a fast, reliable, scalable, and easy to use open source + relational database system. Designed to handle mission-critical, heavy-load + production applications. + digest: e9e4ed1502a77819bf773bd9caba3426537a5c9c1648b56d67f8c45aa42d2525 + home: https://bitnami.com + icon: https://www.mysql.com/common/logos/logo-mysql-170x115.png + keywords: + - mysql + - database + - sql + - cluster + - high availability + maintainers: + - name: VMware, Inc. + url: https://github.com/bitnami/charts + name: mysql + sources: + - https://github.com/bitnami/charts/tree/main/bitnami/mysql + urls: + - assets/bitnami/mysql-9.10.4.tgz + version: 9.10.4 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: MySQL @@ -29534,6 +29802,44 @@ entries: - assets/portworx/portworx-essentials-2.9.100.tgz version: 2.9.100 postgresql: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: PostgreSQL + catalog.cattle.io/kube-version: '>=1.19-0' + catalog.cattle.io/release-name: postgresql + category: Database + licenses: Apache-2.0 + apiVersion: v2 + appVersion: 15.3.0 + created: "2023-06-12T16:18:00.808250691Z" + dependencies: + - name: common + repository: file://./charts/common + tags: + - bitnami-common + version: 2.x.x + description: PostgreSQL (Postgres) is an open source object-relational database + known for reliability and data integrity. ACID-compliant, it supports foreign + keys, joins, views, triggers and stored procedures. + digest: ae1079af6d4d971c2c98e2fcaaaee4901c2bd0d10ee43a64ab5c2c23a677230c + home: https://bitnami.com + icon: https://wiki.postgresql.org/images/a/a4/PostgreSQL_logo.3colors.svg + keywords: + - postgresql + - postgres + - database + - sql + - replication + - cluster + maintainers: + - name: VMware, Inc. + url: https://github.com/bitnami/charts + name: postgresql + sources: + - https://github.com/bitnami/charts/tree/main/bitnami/postgresql + urls: + - assets/bitnami/postgresql-12.5.7.tgz + version: 12.5.7 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: PostgreSQL @@ -35669,6 +35975,37 @@ entries: - assets/bitnami/spark-6.3.8.tgz version: 6.3.8 speedscale-operator: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Speedscale Operator + catalog.cattle.io/kube-version: '>= 1.17.0-0' + catalog.cattle.io/release-name: speedscale-operator + apiVersion: v1 + appVersion: 1.3.94 + created: "2023-06-12T16:18:06.550236613Z" + description: Stress test your APIs with real world scenarios. Collect and replay + traffic without scripting. + digest: a1f37f1bf9c02ade8db5264ea55c173743cfac0e71c0d9a60d9a793622e9a1ef + home: https://speedscale.com + icon: https://raw.githubusercontent.com/speedscale/assets/main/logo/gold_logo_only.png + keywords: + - speedscale + - test + - testing + - regression + - reliability + - load + - replay + - network + - traffic + kubeVersion: '>= 1.17.0-0' + maintainers: + - email: support@speedscale.com + name: Speedscale Support + name: speedscale-operator + urls: + - assets/speedscale/speedscale-operator-1.3.12.tgz + version: 1.3.12 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: Speedscale Operator

s@Q6g&MFaa--+%E6u$K$NYX#o-dh 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 O0RR6NDc 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