From 75ac980a2d8d832785aa7e2c740f5bcae9d9ff7c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 5 Sep 2024 00:54:58 +0000 Subject: [PATCH] Added chart versions: codefresh/cf-runtime: - 6.3.57 f5/f5-bigip-ctlr: - 0.0.32 jenkins/jenkins: - 5.5.14 ngrok/kubernetes-ingress-controller: - 0.14.3 --- assets/codefresh/cf-runtime-6.3.57.tgz | Bin 0 -> 43688 bytes assets/f5/f5-bigip-ctlr-0.0.3201.tgz | Bin 0 -> 12957 bytes assets/jenkins/jenkins-5.5.14.tgz | Bin 0 -> 77877 bytes .../kubernetes-ingress-controller-0.14.3.tgz | Bin 0 -> 40100 bytes .../codefresh/cf-runtime/6.3.57/.helmignore | 3 + charts/codefresh/cf-runtime/6.3.57/Chart.yaml | 28 + charts/codefresh/cf-runtime/6.3.57/README.md | 1228 +++++++ .../cf-runtime/6.3.57/README.md.gotmpl | 1007 ++++++ .../6.3.57/files/cleanup-runtime.sh | 37 + .../6.3.57/files/configure-dind-certs.sh | 132 + .../cf-runtime/6.3.57/files/init-runtime.sh | 80 + .../6.3.57/files/reconcile-runtime.sh | 38 + .../_components/app-proxy/_deployment.yaml | 70 + .../_components/app-proxy/_env-vars.yaml | 19 + .../_components/app-proxy/_helpers.tpl | 43 + .../_components/app-proxy/_ingress.yaml | 32 + .../_components/app-proxy/_rbac.yaml | 47 + .../_components/app-proxy/_service.yaml | 17 + .../event-exporter/_deployment.yaml | 62 + .../_components/event-exporter/_env-vars.yaml | 14 + .../_components/event-exporter/_helpers.tpl | 43 + .../_components/event-exporter/_rbac.yaml | 47 + .../_components/event-exporter/_service.yaml | 17 + .../event-exporter/_serviceMontor.yaml | 14 + .../_components/monitor/_deployment.yaml | 70 + .../_components/monitor/_env-vars.yaml | 26 + .../_components/monitor/_helpers.tpl | 42 + .../templates/_components/monitor/_rbac.yaml | 56 + .../_components/monitor/_service.yaml | 17 + .../_components/runner/_deployment.yaml | 103 + .../templates/_components/runner/_helpers.tpl | 42 + .../templates/_components/runner/_rbac.yaml | 53 + .../_init-container.yaml | 30 + .../_main-container.yaml | 28 + .../_sidecar-container.yaml | 22 + .../volume-provisioner/_cronjob.yaml | 58 + .../volume-provisioner/_daemonset.yaml | 98 + .../volume-provisioner/_deployment.yaml | 67 + .../volume-provisioner/_env-vars.yaml | 88 + .../volume-provisioner/_helpers.tpl | 93 + .../_components/volume-provisioner/_rbac.yaml | 71 + .../volume-provisioner/_secret.yaml | 22 + .../volume-provisioner/_storageclass.yaml | 47 + .../cf-runtime/6.3.57/templates/_helpers.tpl | 51 + .../templates/app-proxy/deployment.yaml | 9 + .../6.3.57/templates/app-proxy/ingress.yaml | 9 + .../6.3.57/templates/app-proxy/rbac.yaml | 9 + .../6.3.57/templates/app-proxy/service.yaml | 9 + .../templates/event-exporter/deployment.yaml | 9 + .../6.3.57/templates/event-exporter/rbac.yaml | 9 + .../templates/event-exporter/service.yaml | 11 + .../templates/extra/extra-resources.yaml | 6 + .../templates/extra/runtime-images-cm.yaml | 19 + .../hooks/post-install/cm-update-runtime.yaml | 18 + .../hooks/post-install/job-gencerts-dind.yaml | 68 + .../post-install/job-update-runtime.yaml | 77 + .../post-install/rbac-gencerts-dind.yaml | 37 + .../pre-delete/job-cleanup-resources.yaml | 73 + .../pre-delete/rbac-cleanup-resources.yaml | 46 + .../6.3.57/templates/monitor/deployment.yaml | 9 + .../6.3.57/templates/monitor/rbac.yaml | 9 + .../6.3.57/templates/monitor/service.yaml | 9 + .../templates/other/external-secrets.yaml | 2 + .../6.3.57/templates/other/podMonitor.yaml | 2 + .../templates/other/serviceMonitor.yaml | 2 + .../6.3.57/templates/runner/deployment.yaml | 9 + .../6.3.57/templates/runner/rbac.yaml | 9 + .../6.3.57/templates/runtime/_helpers.tpl | 123 + .../templates/runtime/cm-dind-daemon.yaml | 10 + .../6.3.57/templates/runtime/rbac.yaml | 48 + .../runtime/runtime-env-spec-tmpl.yaml | 211 ++ .../6.3.57/templates/runtime/secret.yaml | 11 + .../6.3.57/templates/runtime/svc-dind.yaml | 16 + .../templates/volume-provisioner/cronjob.yaml | 11 + .../volume-provisioner/daemonset.yaml | 11 + .../volume-provisioner/deployment.yaml | 10 + .../templates/volume-provisioner/rbac.yaml | 9 + .../templates/volume-provisioner/secret.yaml | 10 + .../volume-provisioner/storageclass.yaml | 10 + .../codefresh/cf-runtime/6.3.57/values.yaml | 947 +++++ charts/f5/f5-bigip-ctlr/0.0.3201/.helmignore | 21 + charts/f5/f5-bigip-ctlr/0.0.3201/Chart.yaml | 26 + charts/f5/f5-bigip-ctlr/0.0.3201/README.md | 93 + .../f5/f5-bigip-ctlr/0.0.3201/app-readme.md | 87 + ...5-bigip-ctlr-customresourcedefinitions.yml | 1327 +++++++ .../f5/f5-bigip-ctlr/0.0.3201/questions.yaml | 75 + .../0.0.3201/templates/NOTES.txt | 6 + .../0.0.3201/templates/_helpers.tpl | 64 + .../templates/f5-bigip-ctlr-clusterrole.yaml | 111 + .../f5-bigip-ctlr-clusterrolebinding.yaml | 23 + .../templates/f5-bigip-ctlr-deploy.yaml | 138 + .../f5-bigip-ctlr-ingress-class.yaml | 12 + .../templates/f5-bigip-ctlr-secrets.yaml | 19 + .../f5-bigip-ctlr-serviceaccount.yaml | 17 + charts/f5/f5-bigip-ctlr/0.0.3201/values.yaml | 90 + charts/jenkins/jenkins/5.5.14/CHANGELOG.md | 3098 +++++++++++++++++ charts/jenkins/jenkins/5.5.14/Chart.yaml | 54 + charts/jenkins/jenkins/5.5.14/README.md | 706 ++++ charts/jenkins/jenkins/5.5.14/UPGRADING.md | 148 + charts/jenkins/jenkins/5.5.14/VALUES.md | 316 ++ .../jenkins/jenkins/5.5.14/VALUES.md.gotmpl | 28 + .../jenkins/5.5.14/templates/NOTES.txt | 68 + .../jenkins/5.5.14/templates/_helpers.tpl | 684 ++++ .../5.5.14/templates/auto-reload-config.yaml | 60 + .../5.5.14/templates/config-init-scripts.yaml | 18 + .../jenkins/5.5.14/templates/config.yaml | 92 + .../jenkins/5.5.14/templates/deprecation.yaml | 151 + .../jenkins/5.5.14/templates/home-pvc.yaml | 41 + .../5.5.14/templates/jcasc-config.yaml | 53 + .../5.5.14/templates/jenkins-agent-svc.yaml | 43 + .../jenkins-aws-security-group-policies.yaml | 16 + .../jenkins-controller-alerting-rules.yaml | 26 + .../jenkins-controller-backendconfig.yaml | 24 + .../templates/jenkins-controller-ingress.yaml | 77 + .../jenkins-controller-networkpolicy.yaml | 76 + .../templates/jenkins-controller-pdb.yaml | 34 + .../jenkins-controller-podmonitor.yaml | 30 + .../templates/jenkins-controller-route.yaml | 34 + .../jenkins-controller-secondary-ingress.yaml | 56 + .../jenkins-controller-servicemonitor.yaml | 45 + .../jenkins-controller-statefulset.yaml | 424 +++ .../templates/jenkins-controller-svc.yaml | 56 + .../jenkins/5.5.14/templates/rbac.yaml | 149 + .../5.5.14/templates/secret-additional.yaml | 21 + .../5.5.14/templates/secret-claims.yaml | 29 + .../5.5.14/templates/secret-https-jks.yaml | 20 + .../jenkins/5.5.14/templates/secret.yaml | 20 + .../templates/service-account-agent.yaml | 26 + .../5.5.14/templates/service-account.yaml | 26 + .../5.5.14/templates/tests/jenkins-test.yaml | 49 + .../5.5.14/templates/tests/test-config.yaml | 14 + charts/jenkins/jenkins/5.5.14/values.yaml | 1357 ++++++++ .../0.14.3/.helmignore | 25 + .../0.14.3/CHANGELOG.md | 182 + .../0.14.3/Chart.lock | 6 + .../0.14.3/Chart.yaml | 25 + .../0.14.3/README.md | 94 + .../0.14.3/charts/common/.helmignore | 26 + .../0.14.3/charts/common/Chart.yaml | 23 + .../0.14.3/charts/common/README.md | 235 ++ .../charts/common/templates/_affinities.tpl | 139 + .../charts/common/templates/_capabilities.tpl | 229 ++ .../common/templates/_compatibility.tpl | 42 + .../charts/common/templates/_errors.tpl | 28 + .../charts/common/templates/_images.tpl | 115 + .../charts/common/templates/_ingress.tpl | 73 + .../charts/common/templates/_labels.tpl | 46 + .../0.14.3/charts/common/templates/_names.tpl | 71 + .../charts/common/templates/_resources.tpl | 50 + .../charts/common/templates/_secrets.tpl | 185 + .../charts/common/templates/_storage.tpl | 21 + .../charts/common/templates/_tplvalues.tpl | 38 + .../0.14.3/charts/common/templates/_utils.tpl | 77 + .../charts/common/templates/_warnings.tpl | 109 + .../templates/validations/_cassandra.tpl | 77 + .../common/templates/validations/_mariadb.tpl | 108 + .../common/templates/validations/_mongodb.tpl | 113 + .../common/templates/validations/_mysql.tpl | 108 + .../templates/validations/_postgresql.tpl | 134 + .../common/templates/validations/_redis.tpl | 81 + .../templates/validations/_validations.tpl | 51 + .../0.14.3/charts/common/values.yaml | 8 + .../0.14.3/templates/NOTES.txt | 53 + .../0.14.3/templates/_helpers.tpl | 87 + .../0.14.3/templates/controller-cm.yaml | 16 + .../templates/controller-deployment.yaml | 146 + .../0.14.3/templates/controller-pdb.yaml | 26 + .../0.14.3/templates/controller-rbac.yaml | 96 + .../templates/controller-serviceaccount.yaml | 15 + .../crds/ingress.k8s.ngrok.com_domains.yaml | 105 + .../ingress.k8s.ngrok.com_httpsedges.yaml | 1062 ++++++ .../ingress.k8s.ngrok.com_ippolicies.yaml | 109 + ...ingress.k8s.ngrok.com_ngrokmodulesets.yaml | 1008 ++++++ .../crds/ingress.k8s.ngrok.com_tcpedges.yaml | 132 + .../crds/ingress.k8s.ngrok.com_tlsedges.yaml | 166 + .../crds/ingress.k8s.ngrok.com_tunnels.yaml | 78 + ...ok.k8s.ngrok.com_ngroktrafficpolicies.yaml | 62 + .../0.14.3/templates/credentials-secret.yaml | 11 + .../0.14.3/templates/ingress-class.yaml | 15 + .../templates/rbac/domain_editor_role.yaml | 27 + .../templates/rbac/domain_viewer_role.yaml | 23 + .../templates/rbac/httpsedge_editor_role.yaml | 31 + .../templates/rbac/httpsedge_viewer_role.yaml | 27 + .../templates/rbac/ippolicy_editor_role.yaml | 31 + .../templates/rbac/ippolicy_viewer_role.yaml | 27 + .../rbac/ngrokmoduleset_editor_role.yaml | 31 + .../rbac/ngrokmoduleset_viewer_role.yaml | 27 + .../0.14.3/templates/rbac/role.yaml | 330 ++ .../templates/rbac/tcpedge_editor_role.yaml | 31 + .../templates/rbac/tcpedge_viewer_role.yaml | 27 + .../templates/rbac/tlsedge_editor_role.yaml | 31 + .../templates/rbac/tlsedge_viewer_role.yaml | 27 + .../templates/rbac/tunnel_editor_role.yaml | 27 + .../templates/rbac/tunnel_viewer_role.yaml | 23 + .../0.14.3/values.yaml | 205 ++ index.yaml | 151 +- 196 files changed, 23008 insertions(+), 1 deletion(-) create mode 100644 assets/codefresh/cf-runtime-6.3.57.tgz create mode 100644 assets/f5/f5-bigip-ctlr-0.0.3201.tgz create mode 100644 assets/jenkins/jenkins-5.5.14.tgz create mode 100644 assets/ngrok/kubernetes-ingress-controller-0.14.3.tgz create mode 100644 charts/codefresh/cf-runtime/6.3.57/.helmignore create mode 100644 charts/codefresh/cf-runtime/6.3.57/Chart.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/README.md create mode 100644 charts/codefresh/cf-runtime/6.3.57/README.md.gotmpl create mode 100644 charts/codefresh/cf-runtime/6.3.57/files/cleanup-runtime.sh create mode 100644 charts/codefresh/cf-runtime/6.3.57/files/configure-dind-certs.sh create mode 100644 charts/codefresh/cf-runtime/6.3.57/files/init-runtime.sh create mode 100644 charts/codefresh/cf-runtime/6.3.57/files/reconcile-runtime.sh create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_env-vars.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_ingress.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_service.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_env-vars.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_service.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_serviceMontor.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_env-vars.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_service.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/_deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/_rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/environment-variables/_init-container.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/environment-variables/_main-container.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/environment-variables/_sidecar-container.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_cronjob.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_daemonset.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_env-vars.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_secret.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_storageclass.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/app-proxy/deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/app-proxy/ingress.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/app-proxy/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/app-proxy/service.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/event-exporter/deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/event-exporter/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/event-exporter/service.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/extra/extra-resources.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/extra/runtime-images-cm.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/hooks/post-install/cm-update-runtime.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/hooks/post-install/job-gencerts-dind.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/hooks/post-install/job-update-runtime.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/hooks/post-install/rbac-gencerts-dind.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/hooks/pre-delete/job-cleanup-resources.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/hooks/pre-delete/rbac-cleanup-resources.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/monitor/deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/monitor/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/monitor/service.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/other/external-secrets.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/other/podMonitor.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/other/serviceMonitor.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/runner/deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/runner/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/runtime/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/runtime/cm-dind-daemon.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/runtime/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/runtime/runtime-env-spec-tmpl.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/runtime/secret.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/runtime/svc-dind.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/cronjob.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/daemonset.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/secret.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/storageclass.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.57/values.yaml create mode 100644 charts/f5/f5-bigip-ctlr/0.0.3201/.helmignore create mode 100644 charts/f5/f5-bigip-ctlr/0.0.3201/Chart.yaml create mode 100644 charts/f5/f5-bigip-ctlr/0.0.3201/README.md create mode 100644 charts/f5/f5-bigip-ctlr/0.0.3201/app-readme.md create mode 100644 charts/f5/f5-bigip-ctlr/0.0.3201/crds/f5-bigip-ctlr-customresourcedefinitions.yml create mode 100644 charts/f5/f5-bigip-ctlr/0.0.3201/questions.yaml create mode 100644 charts/f5/f5-bigip-ctlr/0.0.3201/templates/NOTES.txt create mode 100644 charts/f5/f5-bigip-ctlr/0.0.3201/templates/_helpers.tpl create mode 100644 charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-clusterrole.yaml create mode 100644 charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-clusterrolebinding.yaml create mode 100644 charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-deploy.yaml create mode 100644 charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-ingress-class.yaml create mode 100644 charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-secrets.yaml create mode 100644 charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-serviceaccount.yaml create mode 100644 charts/f5/f5-bigip-ctlr/0.0.3201/values.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/CHANGELOG.md create mode 100644 charts/jenkins/jenkins/5.5.14/Chart.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/README.md create mode 100644 charts/jenkins/jenkins/5.5.14/UPGRADING.md create mode 100644 charts/jenkins/jenkins/5.5.14/VALUES.md create mode 100644 charts/jenkins/jenkins/5.5.14/VALUES.md.gotmpl create mode 100644 charts/jenkins/jenkins/5.5.14/templates/NOTES.txt create mode 100644 charts/jenkins/jenkins/5.5.14/templates/_helpers.tpl create mode 100644 charts/jenkins/jenkins/5.5.14/templates/auto-reload-config.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/config-init-scripts.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/config.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/deprecation.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/home-pvc.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/jcasc-config.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/jenkins-agent-svc.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/jenkins-aws-security-group-policies.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-alerting-rules.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-backendconfig.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-ingress.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-networkpolicy.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-pdb.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-podmonitor.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-route.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-secondary-ingress.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-servicemonitor.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-statefulset.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-svc.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/rbac.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/secret-additional.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/secret-claims.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/secret-https-jks.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/secret.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/service-account-agent.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/service-account.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/tests/jenkins-test.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/templates/tests/test-config.yaml create mode 100644 charts/jenkins/jenkins/5.5.14/values.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/.helmignore create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/CHANGELOG.md create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/Chart.lock create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/Chart.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/README.md create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/.helmignore create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/Chart.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/README.md create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_affinities.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_capabilities.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_compatibility.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_errors.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_images.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_ingress.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_labels.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_names.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_resources.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_secrets.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_storage.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_tplvalues.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_utils.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_warnings.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_cassandra.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_mariadb.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_mongodb.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_mysql.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_postgresql.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_redis.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_validations.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/values.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/NOTES.txt create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/_helpers.tpl create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-cm.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-deployment.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-pdb.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-rbac.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-serviceaccount.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_domains.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_httpsedges.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_ippolicies.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_ngrokmodulesets.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_tcpedges.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_tlsedges.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_tunnels.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ngrok.k8s.ngrok.com_ngroktrafficpolicies.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/credentials-secret.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/ingress-class.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/domain_editor_role.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/domain_viewer_role.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/httpsedge_editor_role.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/httpsedge_viewer_role.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/ippolicy_editor_role.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/ippolicy_viewer_role.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/ngrokmoduleset_editor_role.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/ngrokmoduleset_viewer_role.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/role.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tcpedge_editor_role.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tcpedge_viewer_role.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tlsedge_editor_role.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tlsedge_viewer_role.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tunnel_editor_role.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tunnel_viewer_role.yaml create mode 100644 charts/ngrok/kubernetes-ingress-controller/0.14.3/values.yaml diff --git a/assets/codefresh/cf-runtime-6.3.57.tgz b/assets/codefresh/cf-runtime-6.3.57.tgz new file mode 100644 index 0000000000000000000000000000000000000000..6f6389dbe918188394aee6a632cb8878b8a44809 GIT binary patch literal 43688 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 Th135F00960$B?PC0CWKWBW>ob literal 0 HcmV?d00001 diff --git a/assets/jenkins/jenkins-5.5.14.tgz b/assets/jenkins/jenkins-5.5.14.tgz new file mode 100644 index 0000000000000000000000000000000000000000..3d9e3d4a88998bd36abe51bc060f1311a76e9158 GIT binary patch literal 77877 zcmV(&K;ge1iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PMZ%TH`vlDB8dC6k1{KMO8ztgj@EW{jCrJgd!o309Cd2K2?gX zBnI0umYoo4*8a|GoYy-~ay|`REISTRHLKU^wNKMu&jL#t8oCV)jq5$}9~_@m+A|zR z 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 L4ixqT03HPZDz5E3 literal 0 HcmV?d00001 diff --git a/assets/ngrok/kubernetes-ingress-controller-0.14.3.tgz b/assets/ngrok/kubernetes-ingress-controller-0.14.3.tgz new file mode 100644 index 0000000000000000000000000000000000000000..03fe5952ddd31be8358acfbef3cb29d9026ad0c7 GIT binary patch literal 40100 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 literal 0 HcmV?d00001 diff --git a/charts/codefresh/cf-runtime/6.3.57/.helmignore b/charts/codefresh/cf-runtime/6.3.57/.helmignore new file mode 100644 index 000000000..bc71d4240 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/.helmignore @@ -0,0 +1,3 @@ +tests/ +.ci/ +test-values/ \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/Chart.yaml b/charts/codefresh/cf-runtime/6.3.57/Chart.yaml new file mode 100644 index 000000000..978f8f154 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/Chart.yaml @@ -0,0 +1,28 @@ +annotations: + artifacthub.io/changes: | + - kind: fixed + description: "engine image upgraded to 1.174.7 to fix fetching a pipeline yaml from subdirectories for Bitbucket Server" + artifacthub.io/containsSecurityUpdates: "false" + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Codefresh + catalog.cattle.io/kube-version: '>=1.18-0' + catalog.cattle.io/release-name: cf-runtime +apiVersion: v2 +dependencies: +- name: cf-common + repository: file://./charts/cf-common + version: 0.16.0 +description: A Helm chart for Codefresh Runner +home: https://codefresh.io/ +icon: file://assets/icons/cf-runtime.png +keywords: +- codefresh +- runner +kubeVersion: '>=1.18-0' +maintainers: +- name: codefresh + url: https://codefresh-io.github.io/ +name: cf-runtime +sources: +- https://github.com/codefresh-io/venona +version: 6.3.57 diff --git a/charts/codefresh/cf-runtime/6.3.57/README.md b/charts/codefresh/cf-runtime/6.3.57/README.md new file mode 100644 index 000000000..93d069758 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/README.md @@ -0,0 +1,1228 @@ +## Codefresh Runner + +![Version: 6.3.57](https://img.shields.io/badge/Version-6.3.57-informational?style=flat-square) + +Helm chart for deploying [Codefresh Runner](https://codefresh.io/docs/docs/installation/codefresh-runner/) to Kubernetes. + +## Table of Content + +- [Prerequisites](#prerequisites) +- [Get Chart Info](#get-chart-info) +- [Install Chart](#install-chart) +- [Chart Configuration](#chart-configuration) +- [Upgrade Chart](#upgrade-chart) + - [To 2.x](#to-2-x) + - [To 3.x](#to-3-x) + - [To 4.x](#to-4-x) + - [To 5.x](#to-5-x) + - [To 6.x](#to-6-x) +- [Architecture](#architecture) +- [Configuration](#configuration) + - [EBS backend volume configuration in AWS](#ebs-backend-volume-configuration) + - [Azure Disks backend volume configuration in AKS](#azure-disks-backend-volume-configuration) + - [GCE Disks backend volume configuration in GKE](#gce-disks-backend-volume-configuration-in-gke) + - [Custom volume mounts](#custom-volume-mounts) + - [Custom global environment variables](#custom-global-environment-variables) + - [Volume reuse policy](#volume-reuse-policy) + - [Volume cleaners](#volume-cleaners) + - [Rootless DinD](#rootless-dind) + - [ARM](#arm) + - [Openshift](#openshift) + - [On-premise](#on-premise) + +## Prerequisites + +- Kubernetes **1.19+** +- Helm **3.8.0+** + +⚠️⚠️⚠️ +> Since version 6.2.x chart is pushed **only** to OCI registry at `oci://quay.io/codefresh/cf-runtime` + +> Versions prior to 6.2.x are still available in ChartMuseum at `http://chartmuseum.codefresh.io/cf-runtime` + +## Get Chart Info + +```console +helm show all oci://quay.io/codefresh/cf-runtime +``` +See [Use OCI-based registries](https://helm.sh/docs/topics/registries/) + +## Install Chart + +**Important:** only helm3 is supported + +- Specify the following mandatory values + +`values.yaml` +```yaml +# -- Global parameters +# @default -- See below +global: + # -- User token in plain text (required if `global.codefreshTokenSecretKeyRef` is omitted!) + # Ref: https://g.codefresh.io/user/settings (see API Keys) + # Minimal API key scopes: Runner-Installation(read+write), Agent(read+write), Agents(read+write) + codefreshToken: "" + # -- User token that references an existing secret containing API key (required if `global.codefreshToken` is omitted!) + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Account ID (required!) + # Can be obtained here https://g.codefresh.io/2.0/account-settings/account-information + accountId: "" + + # -- K8s context name (required!) + context: "" + # E.g. + # context: prod-ue1-runtime-1 + + # -- Agent Name (optional!) + # If omitted, the following format will be used '{{ .Values.global.context }}_{{ .Release.Namespace }}' + agentName: "" + # E.g. + # agentName: prod-ue1-runtime-1 + + # -- Runtime name (optional!) + # If omitted, the following format will be used '{{ .Values.global.context }}/{{ .Release.Namespace }}' + runtimeName: "" + # E.g. + # runtimeName: prod-ue1-runtime-1/namespace +``` + +- Install chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace codefresh +``` + +## Chart Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). + +## Upgrade Chart + +### To 2.x + +This major release renames and deprecated several values in the chart. Most of the workload templates have been refactored. + +Affected values: +- `dockerRegistry` is deprecated. Replaced with `global.imageRegistry` +- `re` is renamed to `runtime` +- `storage.localVolumeMonitor` is replaced with `volumeProvisioner.dind-lv-monitor` +- `volumeProvisioner.volume-cleanup` is replaced with `volumeProvisioner.dind-volume-cleanup` +- `image` values structure has been updated. Split to `image.registry` `image.repository` `image.tag` +- pod's `annotations` is renamed to `podAnnotations` + +### To 3.x + +⚠️⚠️⚠️ +### READ this before the upgrade! + +This major release adds [runtime-environment](https://codefresh.io/docs/docs/installation/codefresh-runner/#runtime-environment-specification) spec into chart templates. +That means it is possible to set parametes for `dind` and `engine` pods via [values.yaml](./values.yaml). + +**If you had any overrides (i.e. tolerations/nodeSelector/environment variables/etc) added in runtime spec via [codefresh CLI](https://codefresh-io.github.io/cli/) (for example, you did use [get](https://codefresh-io.github.io/cli/runtime-environments/get-runtime-environments/) and [patch](https://codefresh-io.github.io/cli/runtime-environments/apply-runtime-environments/) commands to modify the runtime-environment), you MUST add these into chart's [values.yaml](./values.yaml) for `.Values.runtime.dind` or(and) .`Values.runtime.engine`** + +**For backward compatibility, you can disable updating runtime-environment spec via** `.Values.runtime.patch.enabled=false` + +Affected values: +- added **mandatory** `global.codefreshToken`/`global.codefreshTokenSecretKeyRef` **You must specify it before the upgrade!** +- `runtime.engine` is added +- `runtime.dind` is added +- `global.existingAgentToken` is replaced with `global.agentTokenSecretKeyRef` +- `global.existingDindCertsSecret` is replaced with `global.dindCertsSecretRef` + +### To 4.x + +This major release adds **agentless inCluster** runtime mode (relevant only for [Codefresh On-Premises](#on-premise) users) + +Affected values: +- `runtime.agent` / `runtime.inCluster` / `runtime.accounts` / `runtime.description` are added + +### To 5.x + +This major release converts `.runtime.dind.pvcs` from **list** to **dict** + +> 4.x chart's values example: +```yaml +runtime: + dind: + pvcs: + - name: dind + storageClassName: my-storage-class-name + volumeSize: 32Gi + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +> 5.x chart's values example: +```yaml +runtime: + dind: + pvcs: + dind: + name: dind + storageClassName: my-storage-class-name + volumeSize: 32Gi + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +Affected values: +- `.runtime.dind.pvcs` converted from **list** to **dict** + +### To 6.x + +⚠️⚠️⚠️ +### READ this before the upgrade! + +This major release deprecates previously required `codefresh runner init --generate-helm-values-file`. + +Affected values: +- **Replaced** `.monitor.clusterId` with `.global.context` as **mandatory** value! +- **Deprecated** `.global.agentToken` / `.global.agentTokenSecretKeyRef` +- **Removed** `.global.agentId` +- **Removed** `.global.keys` / `.global.dindCertsSecretRef` +- **Removed** `.global.existingAgentToken` / `existingDindCertsSecret` +- **Removed** `.monitor.clusterId` / `.monitor.token` / `.monitor.existingMonitorToken` + +#### Migrate the Helm chart from version 5.x to 6.x + +Given this is the legacy `generated_values.yaml` values: + +> legacy `generated_values.yaml` +```yaml +{ + "appProxy": { + "enabled": false, + }, + "monitor": { + "enabled": false, + "clusterId": "my-cluster-name", + "token": "1234567890" + }, + "global": { + "namespace": "namespace", + "codefreshHost": "https://g.codefresh.io", + "agentToken": "0987654321", + "agentId": "agent-id-here", + "agentName": "my-cluster-name_my-namespace", + "accountId": "my-account-id", + "runtimeName": "my-cluster-name/my-namespace", + "codefreshToken": "1234567890", + "keys": { + "key": "-----BEGIN RSA PRIVATE KEY-----...", + "csr": "-----BEGIN CERTIFICATE REQUEST-----...", + "ca": "-----BEGIN CERTIFICATE-----...", + "serverCert": "-----BEGIN CERTIFICATE-----..." + } + } +} +``` + +Update `values.yaml` for new chart version: + +> For existing installation for backward compatibility `.Values.global.agentToken/agentTokenSecretKeyRef` **must be provided!** For installation from scratch this value is no longer required. + +> updated `values.yaml` +```yaml +global: + codefreshToken: "1234567890" + accountId: "my-account-id" + context: "my-cluster-name" + agentToken: "0987654321" # MANDATORY when migrating from < 6.x chart version ! + agentName: "my-cluster-name_my-namespace" # optional + runtimeName: "my-cluster-name/my-namespace" # optional +``` + +> **Note!** Though it's still possible to update runtime-environment via [get](https://codefresh-io.github.io/cli/runtime-environments/get-runtime-environments/) and [patch](https://codefresh-io.github.io/cli/runtime-environments/apply-runtime-environments/) commands, it's recommended to enable sidecar container to pull runtime spec from Codefresh API to detect any drift in configuration. + +```yaml +runner: + # -- Sidecar container + # Reconciles runtime spec from Codefresh API for drift detection + sidecar: + enabled: true +``` + +## Architecture + +[Codefresh Runner architecture](https://codefresh.io/docs/docs/installation/codefresh-runner/#codefresh-runner-architecture) + +## Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). + +### EBS backend volume configuration + +`dind-volume-provisioner` should have permissions to create/attach/detach/delete/get EBS volumes + +Minimal IAM policy for `dind-volume-provisioner` + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "ec2:AttachVolume", + "ec2:CreateSnapshot", + "ec2:CreateTags", + "ec2:CreateVolume", + "ec2:DeleteSnapshot", + "ec2:DeleteTags", + "ec2:DeleteVolume", + "ec2:DescribeInstances", + "ec2:DescribeSnapshots", + "ec2:DescribeTags", + "ec2:DescribeVolumes", + "ec2:DetachVolume" + ], + "Resource": "*" + } + ] +} +``` + +There are three options: + +1. Run `dind-volume-provisioner` pod on the node/node-group with IAM role + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + +volumeProvisioner: + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] +``` + +2. Pass static credentials in `.Values.storage.ebs.accessKeyId/accessKeyIdSecretKeyRef` and `.Values.storage.ebs.secretAccessKey/secretAccessKeySecretKeyRef` + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + + # -- Set AWS_ACCESS_KEY_ID for volume-provisioner (optional) + accessKeyId: "" + # -- Existing secret containing AWS_ACCESS_KEY_ID. + accessKeyIdSecretKeyRef: {} + # E.g. + # accessKeyIdSecretKeyRef: + # name: + # key: + + # -- Set AWS_SECRET_ACCESS_KEY for volume-provisioner (optional) + secretAccessKey: "" + # -- Existing secret containing AWS_SECRET_ACCESS_KEY + secretAccessKeySecretKeyRef: {} + # E.g. + # secretAccessKeySecretKeyRef: + # name: + # key: +``` + +3. Assign IAM role to `dind-volume-provisioner` service account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + +volumeProvisioner: + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Additional service account annotations + annotations: + eks.amazonaws.com/role-arn: "arn:aws:iam:::role/" +``` + +### Custom volume mounts + +You can add your own volumes and volume mounts in the runtime environment, so that all pipeline steps will have access to the same set of external files. + +```yaml +runtime: + dind: + userVolumes: + regctl-docker-registry: + name: regctl-docker-registry + secret: + items: + - key: .dockerconfigjson + path: config.json + secretName: regctl-docker-registry + optional: true + userVolumeMounts: + regctl-docker-registry: + name: regctl-docker-registry + mountPath: /home/appuser/.docker/ + readOnly: true + +``` + +### Azure Disks backend volume configuration + +`dind-volume-provisioner` should have permissions to create/delete/get Azure Disks + +Role definition for `dind-volume-provisioner` + +`dind-volume-provisioner-role.json` +```json +{ + "Name": "CodefreshDindVolumeProvisioner", + "Description": "Perform create/delete/get disks", + "IsCustom": true, + "Actions": [ + "Microsoft.Compute/disks/read", + "Microsoft.Compute/disks/write", + "Microsoft.Compute/disks/delete" + + ], + "AssignableScopes": ["/subscriptions/"] +} +``` + +When creating an AKS cluster in Azure there is the option to use a [managed identity](https://learn.microsoft.com/en-us/azure/aks/use-managed-identity) that is assigned to the kubelet. This identity is assigned to the underlying node pool in the AKS cluster and can then be used by the dind-volume-provisioner. + +```console +export ROLE_DEFINITIN_FILE=dind-volume-provisioner-role.json +export SUBSCRIPTION_ID=$(az account show --query "id" | xargs echo ) +export RESOURCE_GROUP= +export AKS_NAME= +export LOCATION=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query location | xargs echo) +export NODES_RESOURCE_GROUP=MC_${RESOURCE_GROUP}_${AKS_NAME}_${LOCATION} +export NODE_SERVICE_PRINCIPAL=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query identityProfile.kubeletidentity.objectId | xargs echo) + +az role definition create --role-definition @${ROLE_DEFINITIN_FILE} +az role assignment create --assignee $NODE_SERVICE_PRINCIPAL --scope /subscriptions/$SUBSCRIPTION_ID/resourceGroups/$NODES_RESOURCE_GROUP --role CodefreshDindVolumeProvisioner +``` + +Deploy Helm chart with the following values: + +`values.yaml` +```yaml +volumeProvisioner: + podSecurityContext: + enabled: true + runAsUser: 0 + runAsGroup: 0 + fsGroup: 0 + +storage: + backend: azuredisk + azuredisk: + availabilityZone: northeurope-1 # replace with your zone + resourceGroup: my-resource-group-name + + mountAzureJson: true + +runtime: + dind: + nodeSelector: + topology.kubernetes.io/zone: northeurope-1 +``` + +### GCE Disks backend volume configuration in GKE + +`dind-volume-provisioner` should have `ComputeEngine.StorageAdmin` permissions + +There are three options: + +1. Run `dind-volume-provisioner` pod on the node/node-group with IAM Service Account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + +volumeProvisioner: + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +2. Pass static credentials in `.Values.storage.gcedisk.serviceAccountJson` (inline) or `.Values.storage.gcedisk.serviceAccountJsonSecretKeyRef` (from your own secret) + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "`pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + # -- Set Google SA JSON key for volume-provisioner (optional) + serviceAccountJson: | + { + "type": "service_account", + "project_id": "...", + "private_key_id": "...", + "private_key": "...", + "client_email": "...", + "client_id": "...", + "auth_uri": "...", + "token_uri": "...", + "auth_provider_x509_cert_url": "...", + "client_x509_cert_url": "..." + } + # -- Existing secret containing containing Google SA JSON key for volume-provisioner (optional) + serviceAccountJsonSecretKeyRef: {} + # E.g.: + # serviceAccountJsonSecretKeyRef: + # name: gce-service-account + # key: service-account.json + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +3. Assign IAM role to `dind-volume-provisioner` service account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "`pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + +volumeProvisioner: + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Additional service account annotations + annotations: + iam.gke.io/gcp-service-account: @.iam.gserviceaccount.com + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +### Custom global environment variables + +You can add your own environment variables to the runtime environment. All pipeline steps have access to the global variables. + +```yaml +runtime: + engine: + userEnvVars: + - name: GITHUB_TOKEN + valueFrom: + secretKeyRef: + name: github-token + key: token +``` + +### Volume reuse policy + +Volume reuse behavior depends on the configuration for `reuseVolumeSelector` in the runtime environment spec. + +```yaml +runtime: + dind: + pvcs: + - name: dind + ... + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +The following options are available: +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName'` - PV can be used by ANY pipeline in the specified account (default). +Benefit: Fewer PVs, resulting in lower costs. Since any PV can be used by any pipeline, the cluster needs to maintain/reserve fewer PVs in its PV pool for Codefresh. +Downside: Since the PV can be used by any pipeline, the PVs could have assets and info from different pipelines, reducing the probability of cache. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,project_id'` - PV can be used by ALL pipelines in your account, assigned to the same project. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id'` - PV can be used only by a single pipeline. +Benefit: More probability of cache without “spam” from other pipelines. +Downside: More PVs to maintain and therefore higher costs. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id,io.codefresh.branch_name'` - PV can be used only by single pipeline AND single branch. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id,trigger'` - PV can be used only by single pipeline AND single trigger. + +### Volume cleaners + +Codefresh pipelines require disk space for: + * [Pipeline Shared Volume](https://codefresh.io/docs/docs/pipelines/introduction-to-codefresh-pipelines/#sharing-the-workspace-between-build-steps) (`/codefresh/volume`, implemented as [docker volume](https://docs.docker.com/storage/volumes/)) + * Docker containers, both running and stopped + * Docker images and cached layers + +Codefresh offers two options to manage disk space and prevent out-of-space errors: +* Use runtime cleaners on Docker images and volumes +* [Set the minimum disk space per pipeline build volume](https://codefresh.io/docs/docs/pipelines/pipelines/#set-minimum-disk-space-for-a-pipeline-build) + +To improve performance by using Docker cache, Codefresh `volume-provisioner` can provision previously used disks with Docker images and pipeline volumes from previously run builds. + +### Types of runtime volume cleaners + +Docker images and volumes must be cleaned on a regular basis. + +* [IN-DIND cleaner](https://github.com/codefresh-io/dind/tree/master/cleaner): Deletes extra Docker containers, volumes, and images in **DIND pod**. +* [External volume cleaner](https://github.com/codefresh-io/dind-volume-cleanup): Deletes unused **external** PVs (EBS, GCE/Azure disks). +* [Local volume cleaner](https://github.com/codefresh-io/dind-volume-utils/blob/master/local-volumes/lv-cleaner.sh): Deletes **local** volumes if node disk space is close to the threshold. + +### IN-DIND cleaner + +**Purpose:** Removes unneeded *docker containers, images, volumes* inside Kubernetes volume mounted on the DIND pod + +**How it runs:** Inside each DIND pod as script + +**Triggered by:** SIGTERM and also during the run when disk usage > 90% (configurable) + +**Configured by:** Environment Variables which can be set in Runtime Environment spec + +**Configuration/Logic:** [README.md](https://github.com/codefresh-io/dind/tree/master/cleaner#readme) + +Override `.Values.runtime.dind.env` if necessary (the following are **defaults**): + +```yaml +runtime: + dind: + env: + CLEAN_PERIOD_SECONDS: '21600' # launch clean if last clean was more than CLEAN_PERIOD_SECONDS seconds ago + CLEAN_PERIOD_BUILDS: '5' # launch clean if last clean was more CLEAN_PERIOD_BUILDS builds since last build + IMAGE_RETAIN_PERIOD: '14400' # do not delete docker images if they have events since current_timestamp - IMAGE_RETAIN_PERIOD + VOLUMES_RETAIN_PERIOD: '14400' # do not delete docker volumes if they have events since current_timestamp - VOLUMES_RETAIN_PERIOD + DISK_USAGE_THRESHOLD: '0.8' # launch clean based on current disk usage DISK_USAGE_THRESHOLD + INODES_USAGE_THRESHOLD: '0.8' # launch clean based on current inodes usage INODES_USAGE_THRESHOLD +``` + +### External volumes cleaner + +**Purpose:** Removes unused *kubernetes volumes and related backend volumes* + +**How it runs:** Runs as `dind-volume-cleanup` CronJob. Installed in case the Runner uses non-local volumes `.Values.storage.backend != local` + +**Triggered by:** CronJob every 10min (configurable) + +**Configuration:** + +Set `codefresh.io/volume-retention` for dinds' PVCs: + +```yaml +runtime: + dind: + pvcs: + dind: + ... + annotations: + codefresh.io/volume-retention: 7d +``` + +Or override environment variables for `dind-volume-cleanup` cronjob: + +```yaml +volumeProvisioner: + dind-volume-cleanup: + env: + RETENTION_DAYS: 7 # clean volumes that were last used more than `RETENTION_DAYS` (default is 4) ago +``` + +### Local volumes cleaner + +**Purpose:** Deletes local volumes when node disk space is close to the threshold + +**How it runs:** Runs as `dind-lv-monitor` DaemonSet. Installed in case the Runner uses local volumes `.Values.storage.backend == local` + +**Triggered by:** Disk space usage or inode usage that exceeds thresholds (configurable) + +**Configuration:** + +Override environment variables for `dind-lv-monitor` daemonset: + +```yaml +volumeProvisioner: + dind-lv-monitor: + env: + KB_USAGE_THRESHOLD: 60 # default 80 (percentage) + INODE_USAGE_THRESHOLD: 60 # default 80 +``` + +### Rootless DinD + +DinD pod runs a `priviliged` container with **rootfull** docker. +To run the docker daemon as non-root user (**rootless** mode), change dind image tag: + +`values.yaml` +```yaml +runtime: + dind: + image: + tag: rootless +``` + +### ARM + +With the Codefresh Runner, you can run native ARM64v8 builds. + +> **Note!** +> You cannot run both amd64 and arm64 images within the same pipeline. As one pipeline can map only to one runtime, you can run either amd64 or arm64 within the same pipeline. + +Provide `nodeSelector` and(or) `tolerations` for dind pods: + +`values.yaml` +```yaml +runtime: + dind: + nodeSelector: + arch: arm64 + tolerations: + - key: arch + operator: Equal + value: arm64 + effect: NoSchedule +``` + +### Openshift + +To install Codefresh Runner on OpenShift use the following `values.yaml` example + +```yaml +runner: + podSecurityContext: + enabled: false + +volumeProvisioner: + podSecurityContext: + enabled: false + env: + PRIVILEGED_CONTAINER: true + dind-lv-monitor: + containerSecurityContext: + enabled: true + privileged: true + volumePermissions: + enabled: true + securityContext: + privileged: true + runAsUser: auto +``` + +Grant `privileged` SCC to `cf-runtime-runner` and `cf-runtime-volume-provisioner` service accounts. + +```console +oc adm policy add-scc-to-user privileged system:serviceaccount:codefresh:cf-runtime-runner + +oc adm policy add-scc-to-user privileged system:serviceaccount:codefresh:cf-runtime-volume-provisioner +``` + +### On-premise + +If you have [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) deployed, you can install Codefresh Runner in **agentless** mode. + +**What is agentless mode?** + +Agent (aka venona) is Runner component which responsible for calling Codefresh API to run builds and create dind/engine pods and pvc objects. Agent can only be assigned to a single account, thus you can't share one runtime across multiple accounts. However, with **agentless** mode it's possible to register the runtime as **system**-type runtime so it's registered on the platform level and can be assigned/shared across multiple accounts. + +**What are the prerequisites?** +- You have a running [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) control-plane environment +- You have a Codefresh API token with platform **Admin** permissions scope + +### How to deploy agentless runtime when it's on the SAME k8s cluster as On-Premises control-plane environment? + +- Enable cluster-level permissions for cf-api (On-Premises control-plane component) + +> `values.yaml` for [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) Helm chart +```yaml +cfapi: + ... + # -- Enable ClusterRole/ClusterRoleBinding + rbac: + namespaced: false +``` + +- Set the following values for Runner Helm chart + +`.Values.global.codefreshHost=...` \ +`.Values.global.codefreshToken=...` \ +`.Values.global.runtimeName=system/...` \ +`.Values.runtime.agent=false` \ +`.Values.runtime.inCluster=true` + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart +```yaml +global: + # -- URL of Codefresh On-Premises Platform + codefreshHost: "https://myonprem.somedomain.com" + # -- User token in plain text with Admin permission scope + codefreshToken: "" + # -- User token that references an existing secret containing API key. + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Distinguished runtime name + # (for On-Premise only; mandatory!) Must be prefixed with "system/..." + runtimeName: "system/prod-ue1-some-cluster-name" + +# -- Set runtime parameters +runtime: + # -- (for On-Premise only; mandatory!) Disable agent + agent: false + # -- (for On-Premise only; optional) Set inCluster runtime (default: `true`) + # `inCluster=true` flag is set when Runtime and On-Premises control-plane are run on the same cluster + # `inCluster=false` flag is set when Runtime and On-Premises control-plane are on different clusters + inCluster: true + # -- (for On-Premise only; optional) Assign accounts to runtime (list of account ids; default is empty) + # Accounts can be assigned to the runtime in Codefresh UI later so you can kepp it empty. + accounts: [] + # -- Set parent runtime to inherit. + runtimeExtends: [] +``` + +- Install the chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace cf-runtime +``` + +- Verify the runtime and run test pipeline + +Go to [https:///admin/runtime-environments/system](https:///admin/runtime-environments/system) to check the runtime. Assign it to the required account(s). Run test pipeline on it. + +### How to deploy agentless runtime when it's on the DIFFERENT k8s cluster than On-Premises control-plane environment? + +In this case, it's required to mount runtime cluster's `KUBECONFIG` into On-Premises `cf-api` deployment + +- Create the neccessary RBAC resources + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart +```yaml +extraResources: +- apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + name: codefresh-role + namespace: '{{ .Release.Namespace }}' + rules: + - apiGroups: [""] + resources: ["pods", "persistentvolumeclaims", "persistentvolumes"] + verbs: ["list", "watch", "get", "create", "patch", "delete"] + - apiGroups: ["snapshot.storage.k8s.io"] + resources: ["volumesnapshots"] + verbs: ["list", "watch", "get", "create", "patch", "delete"] +- apiVersion: v1 + kind: ServiceAccount + metadata: + name: codefresh-runtime-user + namespace: '{{ .Release.Namespace }}' +- apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + name: codefresh-runtime-user + namespace: '{{ .Release.Namespace }}' + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: codefresh-role + subjects: + - kind: ServiceAccount + name: codefresh-runtime-user + namespace: '{{ .Release.Namespace }}' +- apiVersion: v1 + kind: Secret + metadata: + name: codefresh-runtime-user-token + namespace: '{{ .Release.Namespace }}' + annotations: + kubernetes.io/service-account.name: codefresh-runtime-user + type: kubernetes.io/service-account-token +``` + +- Set up the following environment variables to create a `KUBECONFIG` file + +```shell +NAMESPACE=cf-runtime +CLUSTER_NAME=prod-ue1-some-cluster-name +CURRENT_CONTEXT=$(kubectl config current-context) + +USER_TOKEN_VALUE=$(kubectl -n cf-runtime get secret/codefresh-runtime-user-token -o=go-template='{{.data.token}}' | base64 --decode) +CURRENT_CLUSTER=$(kubectl config view --raw -o=go-template='{{range .contexts}}{{if eq .name "'''${CURRENT_CONTEXT}'''"}}{{ index .context "cluster" }}{{end}}{{end}}') +CLUSTER_CA=$(kubectl config view --raw -o=go-template='{{range .clusters}}{{if eq .name "'''${CURRENT_CLUSTER}'''"}}"{{with index .cluster "certificate-authority-data" }}{{.}}{{end}}"{{ end }}{{ end }}') +CLUSTER_SERVER=$(kubectl config view --raw -o=go-template='{{range .clusters}}{{if eq .name "'''${CURRENT_CLUSTER}'''"}}{{ .cluster.server }}{{end}}{{ end }}') + +export -p USER_TOKEN_VALUE CURRENT_CONTEXT CURRENT_CLUSTER CLUSTER_CA CLUSTER_SERVER CLUSTER_NAME +``` + +- Create a kubeconfig file + +```console +cat << EOF > $CLUSTER_NAME-kubeconfig +apiVersion: v1 +kind: Config +current-context: ${CLUSTER_NAME} +contexts: +- name: ${CLUSTER_NAME} + context: + cluster: ${CLUSTER_NAME} + user: codefresh-runtime-user + namespace: ${NAMESPACE} +clusters: +- name: ${CLUSTER_NAME} + cluster: + certificate-authority-data: ${CLUSTER_CA} + server: ${CLUSTER_SERVER} +users: +- name: ${CLUSTER_NAME} + user: + token: ${USER_TOKEN_VALUE} +EOF +``` + +- **Switch context to On-Premises control-plane cluster**. Create k8s secret (via any tool like [ESO](https://external-secrets.io/v0.4.4/), `kubectl`, etc ) containing runtime cluster's `KUBECONFG` created in previous step. + +```shell +NAMESPACE=codefresh +kubectl create secret generic dind-runtime-clusters --from-file=$CLUSTER_NAME=$CLUSTER_NAME-kubeconfig -n $NAMESPACE +``` + +- Mount secret containing runtime cluster's `KUBECONFG` into cf-api in On-Premises control-plane cluster + +> `values.yaml` for [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) helm chart +```yaml +cf-api: + ... + volumes: + dind-clusters: + enabled: true + type: secret + nameOverride: dind-runtime-clusters + optional: true +``` +> volumeMount `/etc/kubeconfig` is already configured in cf-api Helm chart template. No need to specify it. + +- Set the following values for Runner helm chart + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart + +`.Values.global.codefreshHost=...` \ +`.Values.global.codefreshToken=...` \ +`.Values.global.runtimeName=system/...` \ +`.Values.runtime.agent=false` \ +`.Values.runtime.inCluster=false` + +**Important!** +`.Values.global.name` ("system/" prefix is ignored!) should match the cluster name (key in `dind-runtime-clusters` secret created previously) +```yaml +global: + # -- URL of Codefresh On-Premises Platform + codefreshHost: "https://myonprem.somedomain.com" + # -- User token in plain text with Admin permission scope + codefreshToken: "" + # -- User token that references an existing secret containing API key. + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Distinguished runtime name + # (for On-Premise only; mandatory!) Must be prefixed with "system/..." + name: "system/prod-ue1-some-cluster-name" + +# -- Set runtime parameters +runtime: + # -- (for On-Premise only; mandatory!) Disable agent + agent: false + # -- (for On-Premise only; optional) Set inCluster runtime (default: `true`) + # `inCluster=true` flag is set when Runtime and On-Premises control-plane are run on the same cluster + # `inCluster=false` flag is set when Runtime and On-Premises control-plane are on different clusters + inCluster: false + # -- (for On-Premise only; optional) Assign accounts to runtime (list of account ids; default is empty) + # Accounts can be assigned to the runtime in Codefresh UI later so you can kepp it empty. + accounts: [] + # -- (optional) Set parent runtime to inherit. + runtimeExtends: [] +``` + +- Install the chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace cf-runtime +``` + +- Verify the runtime and run test pipeline + +Go to [https:///admin/runtime-environments/system](https:///admin/runtime-environments/system) to see the runtime. Assign it to the required account(s). + +## Requirements + +| Repository | Name | Version | +|------------|------|---------| +| oci://quay.io/codefresh/charts | cf-common | 0.16.0 | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| appProxy.affinity | object | `{}` | Set affinity | +| appProxy.enabled | bool | `false` | Enable app-proxy | +| appProxy.env | object | `{}` | Add additional env vars | +| appProxy.image | object | `{"registry":"quay.io","repository":"codefresh/cf-app-proxy","tag":"0.0.47"}` | Set image | +| appProxy.ingress.annotations | object | `{}` | Set extra annotations for ingress object | +| appProxy.ingress.class | string | `""` | Set ingress class | +| appProxy.ingress.host | string | `""` | Set DNS hostname the ingress will use | +| appProxy.ingress.pathPrefix | string | `""` | Set path prefix for ingress (keep empty for default `/` path) | +| appProxy.ingress.tlsSecret | string | `""` | Set k8s tls secret for the ingress object | +| appProxy.nodeSelector | object | `{}` | Set node selector | +| appProxy.podAnnotations | object | `{}` | Set pod annotations | +| appProxy.podSecurityContext | object | `{}` | Set security context for the pod | +| appProxy.rbac | object | `{"create":true,"namespaced":true,"rules":[]}` | RBAC parameters | +| appProxy.rbac.create | bool | `true` | Create RBAC resources | +| appProxy.rbac.namespaced | bool | `true` | Use Role(true)/ClusterRole(true) | +| appProxy.rbac.rules | list | `[]` | Add custom rule to the role | +| appProxy.readinessProbe | object | See below | Readiness probe configuration | +| appProxy.replicasCount | int | `1` | Set number of pods | +| appProxy.resources | object | `{}` | Set requests and limits | +| appProxy.serviceAccount | object | `{"annotations":{},"create":true,"name":"","namespaced":true}` | Service Account parameters | +| appProxy.serviceAccount.annotations | object | `{}` | Additional service account annotations | +| appProxy.serviceAccount.create | bool | `true` | Create service account | +| appProxy.serviceAccount.name | string | `""` | Override service account name | +| appProxy.serviceAccount.namespaced | bool | `true` | Use Role(true)/ClusterRole(true) | +| appProxy.tolerations | list | `[]` | Set tolerations | +| appProxy.updateStrategy | object | `{"type":"RollingUpdate"}` | Upgrade strategy | +| dockerRegistry | string | `""` | | +| event-exporter | object | See below | Event exporter parameters | +| event-exporter.affinity | object | `{}` | Set affinity | +| event-exporter.enabled | bool | `false` | Enable event-exporter | +| event-exporter.env | object | `{}` | Add additional env vars | +| event-exporter.image | object | `{"registry":"docker.io","repository":"codefresh/k8s-event-exporter","tag":"latest"}` | Set image | +| event-exporter.nodeSelector | object | `{}` | Set node selector | +| event-exporter.podAnnotations | object | `{}` | Set pod annotations | +| event-exporter.podSecurityContext | object | See below | Set security context for the pod | +| event-exporter.rbac | object | `{"create":true,"rules":[]}` | RBAC parameters | +| event-exporter.rbac.create | bool | `true` | Create RBAC resources | +| event-exporter.rbac.rules | list | `[]` | Add custom rule to the role | +| event-exporter.replicasCount | int | `1` | Set number of pods | +| event-exporter.resources | object | `{}` | Set resources | +| event-exporter.serviceAccount | object | `{"annotations":{},"create":true,"name":""}` | Service Account parameters | +| event-exporter.serviceAccount.annotations | object | `{}` | Additional service account annotations | +| event-exporter.serviceAccount.create | bool | `true` | Create service account | +| event-exporter.serviceAccount.name | string | `""` | Override service account name | +| event-exporter.tolerations | list | `[]` | Set tolerations | +| event-exporter.updateStrategy | object | `{"type":"Recreate"}` | Upgrade strategy | +| extraResources | list | `[]` | Array of extra objects to deploy with the release | +| fullnameOverride | string | `""` | String to fully override cf-runtime.fullname template | +| global | object | See below | Global parameters | +| global.accountId | string | `""` | Account ID (required!) Can be obtained here https://g.codefresh.io/2.0/account-settings/account-information | +| global.agentName | string | `""` | Agent Name (optional!) If omitted, the following format will be used `{{ .Values.global.context }}_{{ .Release.Namespace }}` | +| global.agentToken | string | `""` | DEPRECATED Agent token in plain text. !!! MUST BE provided if migrating from < 6.x chart version | +| global.agentTokenSecretKeyRef | object | `{}` | DEPRECATED Agent token that references an existing secret containing API key. !!! MUST BE provided if migrating from < 6.x chart version | +| global.codefreshHost | string | `"https://g.codefresh.io"` | URL of Codefresh Platform (required!) | +| global.codefreshToken | string | `""` | User token in plain text (required if `global.codefreshTokenSecretKeyRef` is omitted!) Ref: https://g.codefresh.io/user/settings (see API Keys) Minimal API key scopes: Runner-Installation(read+write), Agent(read+write), Agents(read+write) | +| global.codefreshTokenSecretKeyRef | object | `{}` | User token that references an existing secret containing API key (required if `global.codefreshToken` is omitted!) | +| global.context | string | `""` | K8s context name (required!) | +| global.imagePullSecrets | list | `[]` | Global Docker registry secret names as array | +| global.imageRegistry | string | `""` | Global Docker image registry | +| global.runtimeName | string | `""` | Runtime name (optional!) If omitted, the following format will be used `{{ .Values.global.context }}/{{ .Release.Namespace }}` | +| monitor.affinity | object | `{}` | Set affinity | +| monitor.enabled | bool | `false` | Enable monitor Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#install-monitoring-component | +| monitor.env | object | `{}` | Add additional env vars | +| monitor.image | object | `{"registry":"quay.io","repository":"codefresh/cf-k8s-agent","tag":"1.3.17"}` | Set image | +| monitor.nodeSelector | object | `{}` | Set node selector | +| monitor.podAnnotations | object | `{}` | Set pod annotations | +| monitor.podSecurityContext | object | `{}` | | +| monitor.rbac | object | `{"create":true,"namespaced":true,"rules":[]}` | RBAC parameters | +| monitor.rbac.create | bool | `true` | Create RBAC resources | +| monitor.rbac.namespaced | bool | `true` | Use Role(true)/ClusterRole(true) | +| monitor.rbac.rules | list | `[]` | Add custom rule to the role | +| monitor.readinessProbe | object | See below | Readiness probe configuration | +| monitor.replicasCount | int | `1` | Set number of pods | +| monitor.resources | object | `{}` | Set resources | +| monitor.serviceAccount | object | `{"annotations":{},"create":true,"name":""}` | Service Account parameters | +| monitor.serviceAccount.annotations | object | `{}` | Additional service account annotations | +| monitor.serviceAccount.create | bool | `true` | Create service account | +| monitor.serviceAccount.name | string | `""` | Override service account name | +| monitor.tolerations | list | `[]` | Set tolerations | +| monitor.updateStrategy | object | `{"type":"RollingUpdate"}` | Upgrade strategy | +| nameOverride | string | `""` | String to partially override cf-runtime.fullname template (will maintain the release name) | +| podMonitor | object | See below | Add podMonitor (for engine pods) | +| podMonitor.main.enabled | bool | `false` | Enable pod monitor for engine pods | +| podMonitor.runner.enabled | bool | `false` | Enable pod monitor for runner pod | +| podMonitor.volume-provisioner.enabled | bool | `false` | Enable pod monitor for volumeProvisioner pod | +| re | object | `{}` | | +| runner | object | See below | Runner parameters | +| runner.affinity | object | `{}` | Set affinity | +| runner.enabled | bool | `true` | Enable the runner | +| runner.env | object | `{}` | Add additional env vars | +| runner.image | object | `{"registry":"quay.io","repository":"codefresh/venona","tag":"1.10.2"}` | Set image | +| runner.init | object | `{"image":{"registry":"quay.io","repository":"codefresh/cli","tag":"0.85.0-rootless"},"resources":{"limits":{"cpu":"1","memory":"512Mi"},"requests":{"cpu":"0.2","memory":"256Mi"}}}` | Init container | +| runner.nodeSelector | object | `{}` | Set node selector | +| runner.podAnnotations | object | `{}` | Set pod annotations | +| runner.podSecurityContext | object | See below | Set security context for the pod | +| runner.rbac | object | `{"create":true,"rules":[]}` | RBAC parameters | +| runner.rbac.create | bool | `true` | Create RBAC resources | +| runner.rbac.rules | list | `[]` | Add custom rule to the role | +| runner.readinessProbe | object | See below | Readiness probe configuration | +| runner.replicasCount | int | `1` | Set number of pods | +| runner.resources | object | `{}` | Set requests and limits | +| runner.serviceAccount | object | `{"annotations":{},"create":true,"name":""}` | Service Account parameters | +| runner.serviceAccount.annotations | object | `{}` | Additional service account annotations | +| runner.serviceAccount.create | bool | `true` | Create service account | +| runner.serviceAccount.name | string | `""` | Override service account name | +| runner.sidecar | object | `{"enabled":false,"env":{"RECONCILE_INTERVAL":300},"image":{"registry":"quay.io","repository":"codefresh/codefresh-shell","tag":"0.0.2"},"resources":{}}` | Sidecar container Reconciles runtime spec from Codefresh API for drift detection | +| runner.tolerations | list | `[]` | Set tolerations | +| runner.updateStrategy | object | `{"type":"RollingUpdate"}` | Upgrade strategy | +| runtime | object | See below | Set runtime parameters | +| runtime.accounts | list | `[]` | (for On-Premise only) Assign accounts to runtime (list of account ids) | +| runtime.agent | bool | `true` | (for On-Premise only) Enable agent | +| runtime.description | string | `""` | Runtime description | +| runtime.dind | object | `{"affinity":{},"env":{"DOCKER_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE":true},"image":{"pullPolicy":"IfNotPresent","registry":"quay.io","repository":"codefresh/dind","tag":"26.1.4-1.28.7"},"nodeSelector":{},"podAnnotations":{},"podLabels":{},"pvcs":{"dind":{"annotations":{},"name":"dind","reuseVolumeSelector":"codefresh-app,io.codefresh.accountName","reuseVolumeSortOrder":"pipeline_id","storageClassName":"{{ include \"dind-volume-provisioner.storageClassName\" . }}","volumeSize":"16Gi"}},"resources":{"limits":{"cpu":"400m","memory":"800Mi"},"requests":null},"schedulerName":"","serviceAccount":"codefresh-engine","tolerations":[],"userAccess":true,"userVolumeMounts":{},"userVolumes":{}}` | Parameters for DinD (docker-in-docker) pod (aka "runtime" pod). | +| runtime.dind.affinity | object | `{}` | Set affinity | +| runtime.dind.env | object | `{"DOCKER_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE":true}` | Set additional env vars. | +| runtime.dind.image | object | `{"pullPolicy":"IfNotPresent","registry":"quay.io","repository":"codefresh/dind","tag":"26.1.4-1.28.7"}` | Set dind image. | +| runtime.dind.nodeSelector | object | `{}` | Set node selector. | +| runtime.dind.podAnnotations | object | `{}` | Set pod annotations. | +| runtime.dind.podLabels | object | `{}` | Set pod labels. | +| runtime.dind.pvcs | object | `{"dind":{"annotations":{},"name":"dind","reuseVolumeSelector":"codefresh-app,io.codefresh.accountName","reuseVolumeSortOrder":"pipeline_id","storageClassName":"{{ include \"dind-volume-provisioner.storageClassName\" . }}","volumeSize":"16Gi"}}` | PV claim spec parametes. | +| runtime.dind.pvcs.dind | object | `{"annotations":{},"name":"dind","reuseVolumeSelector":"codefresh-app,io.codefresh.accountName","reuseVolumeSortOrder":"pipeline_id","storageClassName":"{{ include \"dind-volume-provisioner.storageClassName\" . }}","volumeSize":"16Gi"}` | Default dind PVC parameters | +| runtime.dind.pvcs.dind.annotations | object | `{}` | PV annotations. | +| runtime.dind.pvcs.dind.name | string | `"dind"` | PVC name prefix. Keep `dind` as default! Don't change! | +| runtime.dind.pvcs.dind.reuseVolumeSelector | string | `"codefresh-app,io.codefresh.accountName"` | PV reuse selector. Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#volume-reuse-policy | +| runtime.dind.pvcs.dind.storageClassName | string | `"{{ include \"dind-volume-provisioner.storageClassName\" . }}"` | PVC storage class name. Change ONLY if you need to use storage class NOT from Codefresh volume-provisioner | +| runtime.dind.pvcs.dind.volumeSize | string | `"16Gi"` | PVC size. | +| runtime.dind.resources | object | `{"limits":{"cpu":"400m","memory":"800Mi"},"requests":null}` | Set dind resources. | +| runtime.dind.schedulerName | string | `""` | Set scheduler name. | +| runtime.dind.serviceAccount | string | `"codefresh-engine"` | Set service account for pod. | +| runtime.dind.tolerations | list | `[]` | Set tolerations. | +| runtime.dind.userAccess | bool | `true` | Keep `true` as default! | +| runtime.dind.userVolumeMounts | object | `{}` | Add extra volume mounts | +| runtime.dind.userVolumes | object | `{}` | Add extra volumes | +| runtime.dindDaemon | object | See below | DinD pod daemon config | +| runtime.engine | object | `{"affinity":{},"command":["npm","run","start"],"env":{"CONTAINER_LOGGER_EXEC_CHECK_INTERVAL_MS":1000,"DOCKER_REQUEST_TIMEOUT_MS":30000,"FORCE_COMPOSE_SERIAL_PULL":false,"LOGGER_LEVEL":"debug","LOG_OUTGOING_HTTP_REQUESTS":false,"METRICS_PROMETHEUS_COLLECT_PROCESS_METRICS":false,"METRICS_PROMETHEUS_ENABLED":true,"METRICS_PROMETHEUS_ENABLE_LEGACY_METRICS":false,"METRICS_PROMETHEUS_HOST":"0.0.0.0","METRICS_PROMETHEUS_PORT":9100},"image":{"pullPolicy":"IfNotPresent","registry":"quay.io","repository":"codefresh/engine","tag":"1.174.7"},"nodeSelector":{},"podAnnotations":{},"podLabels":{},"resources":{"limits":{"cpu":"1000m","memory":"2048Mi"},"requests":{"cpu":"100m","memory":"128Mi"}},"runtimeImages":{"COMPOSE_IMAGE":"quay.io/codefresh/compose:v2.28.1-1.5.0","CONTAINER_LOGGER_IMAGE":"quay.io/codefresh/cf-container-logger:1.11.6","COSIGN_IMAGE_SIGNER_IMAGE":"quay.io/codefresh/cf-cosign-image-signer:2.4.0-cf.1","CR_6177_FIXER":"quay.io/codefresh/alpine:edge","DOCKER_BUILDER_IMAGE":"quay.io/codefresh/cf-docker-builder:1.3.13","DOCKER_PULLER_IMAGE":"quay.io/codefresh/cf-docker-puller:8.0.17","DOCKER_PUSHER_IMAGE":"quay.io/codefresh/cf-docker-pusher:6.0.16","DOCKER_TAG_PUSHER_IMAGE":"quay.io/codefresh/cf-docker-tag-pusher:1.3.14","FS_OPS_IMAGE":"quay.io/codefresh/fs-ops:1.2.3","GC_BUILDER_IMAGE":"quay.io/codefresh/cf-gc-builder:0.5.3","GIT_CLONE_IMAGE":"quay.io/codefresh/cf-git-cloner:10.1.28","KUBE_DEPLOY":"quay.io/codefresh/cf-deploy-kubernetes:16.1.11","PIPELINE_DEBUGGER_IMAGE":"quay.io/codefresh/cf-debugger:1.3.0","TEMPLATE_ENGINE":"quay.io/codefresh/pikolo:0.14.1"},"schedulerName":"","serviceAccount":"codefresh-engine","tolerations":[],"userEnvVars":[],"workflowLimits":{"MAXIMUM_ALLOWED_TIME_BEFORE_PRE_STEPS_SUCCESS":600,"MAXIMUM_ALLOWED_WORKFLOW_AGE_BEFORE_TERMINATION":86400,"MAXIMUM_ELECTED_STATE_AGE_ALLOWED":900,"MAXIMUM_RETRY_ATTEMPTS_ALLOWED":20,"MAXIMUM_TERMINATING_STATE_AGE_ALLOWED":900,"MAXIMUM_TERMINATING_STATE_AGE_ALLOWED_WITHOUT_UPDATE":300,"TIME_ENGINE_INACTIVE_UNTIL_TERMINATION":300,"TIME_ENGINE_INACTIVE_UNTIL_UNHEALTHY":60,"TIME_INACTIVE_UNTIL_TERMINATION":2700}}` | Parameters for Engine pod (aka "pipeline" orchestrator). | +| runtime.engine.affinity | object | `{}` | Set affinity | +| runtime.engine.command | list | `["npm","run","start"]` | Set container command. | +| runtime.engine.env | object | `{"CONTAINER_LOGGER_EXEC_CHECK_INTERVAL_MS":1000,"DOCKER_REQUEST_TIMEOUT_MS":30000,"FORCE_COMPOSE_SERIAL_PULL":false,"LOGGER_LEVEL":"debug","LOG_OUTGOING_HTTP_REQUESTS":false,"METRICS_PROMETHEUS_COLLECT_PROCESS_METRICS":false,"METRICS_PROMETHEUS_ENABLED":true,"METRICS_PROMETHEUS_ENABLE_LEGACY_METRICS":false,"METRICS_PROMETHEUS_HOST":"0.0.0.0","METRICS_PROMETHEUS_PORT":9100}` | Set additional env vars. | +| runtime.engine.env.CONTAINER_LOGGER_EXEC_CHECK_INTERVAL_MS | int | `1000` | Interval to check the exec status in the container-logger | +| runtime.engine.env.DOCKER_REQUEST_TIMEOUT_MS | int | `30000` | Timeout while doing requests to the Docker daemon | +| runtime.engine.env.FORCE_COMPOSE_SERIAL_PULL | bool | `false` | If "true", composition images will be pulled sequentially | +| runtime.engine.env.LOGGER_LEVEL | string | `"debug"` | Level of logging for engine | +| runtime.engine.env.LOG_OUTGOING_HTTP_REQUESTS | bool | `false` | Enable debug-level logging of outgoing HTTP/HTTPS requests | +| runtime.engine.env.METRICS_PROMETHEUS_COLLECT_PROCESS_METRICS | bool | `false` | Enable collecting process metrics | +| runtime.engine.env.METRICS_PROMETHEUS_ENABLED | bool | `true` | Enable emitting metrics from engine | +| runtime.engine.env.METRICS_PROMETHEUS_ENABLE_LEGACY_METRICS | bool | `false` | Enable legacy metrics | +| runtime.engine.env.METRICS_PROMETHEUS_HOST | string | `"0.0.0.0"` | Host for Prometheus metrics server | +| runtime.engine.env.METRICS_PROMETHEUS_PORT | int | `9100` | Port for Prometheus metrics server | +| runtime.engine.image | object | `{"pullPolicy":"IfNotPresent","registry":"quay.io","repository":"codefresh/engine","tag":"1.174.7"}` | Set image. | +| runtime.engine.nodeSelector | object | `{}` | Set node selector. | +| runtime.engine.podAnnotations | object | `{}` | Set pod annotations. | +| runtime.engine.podLabels | object | `{}` | Set pod labels. | +| runtime.engine.resources | object | `{"limits":{"cpu":"1000m","memory":"2048Mi"},"requests":{"cpu":"100m","memory":"128Mi"}}` | Set resources. | +| runtime.engine.runtimeImages | object | See below. | Set system(base) runtime images. | +| runtime.engine.schedulerName | string | `""` | Set scheduler name. | +| runtime.engine.serviceAccount | string | `"codefresh-engine"` | Set service account for pod. | +| runtime.engine.tolerations | list | `[]` | Set tolerations. | +| runtime.engine.userEnvVars | list | `[]` | Set extra env vars | +| runtime.engine.workflowLimits | object | `{"MAXIMUM_ALLOWED_TIME_BEFORE_PRE_STEPS_SUCCESS":600,"MAXIMUM_ALLOWED_WORKFLOW_AGE_BEFORE_TERMINATION":86400,"MAXIMUM_ELECTED_STATE_AGE_ALLOWED":900,"MAXIMUM_RETRY_ATTEMPTS_ALLOWED":20,"MAXIMUM_TERMINATING_STATE_AGE_ALLOWED":900,"MAXIMUM_TERMINATING_STATE_AGE_ALLOWED_WITHOUT_UPDATE":300,"TIME_ENGINE_INACTIVE_UNTIL_TERMINATION":300,"TIME_ENGINE_INACTIVE_UNTIL_UNHEALTHY":60,"TIME_INACTIVE_UNTIL_TERMINATION":2700}` | Set workflow limits. | +| runtime.engine.workflowLimits.MAXIMUM_ALLOWED_TIME_BEFORE_PRE_STEPS_SUCCESS | int | `600` | Maximum time allowed to the engine to wait for the pre-steps (aka "Initializing Process") to succeed; seconds. | +| runtime.engine.workflowLimits.MAXIMUM_ALLOWED_WORKFLOW_AGE_BEFORE_TERMINATION | int | `86400` | Maximum time for workflow execution; seconds. | +| runtime.engine.workflowLimits.MAXIMUM_ELECTED_STATE_AGE_ALLOWED | int | `900` | Maximum time allowed to workflow to spend in "elected" state; seconds. | +| runtime.engine.workflowLimits.MAXIMUM_RETRY_ATTEMPTS_ALLOWED | int | `20` | Maximum retry attempts allowed for workflow. | +| runtime.engine.workflowLimits.MAXIMUM_TERMINATING_STATE_AGE_ALLOWED | int | `900` | Maximum time allowed to workflow to spend in "terminating" state until force terminated; seconds. | +| runtime.engine.workflowLimits.MAXIMUM_TERMINATING_STATE_AGE_ALLOWED_WITHOUT_UPDATE | int | `300` | Maximum time allowed to workflow to spend in "terminating" state without logs activity until force terminated; seconds. | +| runtime.engine.workflowLimits.TIME_ENGINE_INACTIVE_UNTIL_TERMINATION | int | `300` | Time since the last health check report after which workflow is terminated; seconds. | +| runtime.engine.workflowLimits.TIME_ENGINE_INACTIVE_UNTIL_UNHEALTHY | int | `60` | Time since the last health check report after which the engine is considered unhealthy; seconds. | +| runtime.engine.workflowLimits.TIME_INACTIVE_UNTIL_TERMINATION | int | `2700` | Time since the last workflow logs activity after which workflow is terminated; seconds. | +| runtime.gencerts | object | See below | Parameters for `gencerts-dind` post-upgrade/install hook | +| runtime.inCluster | bool | `true` | (for On-Premise only) Set inCluster runtime | +| runtime.patch | object | See below | Parameters for `runtime-patch` post-upgrade/install hook | +| runtime.rbac | object | `{"create":true,"rules":[]}` | RBAC parameters | +| runtime.rbac.create | bool | `true` | Create RBAC resources | +| runtime.rbac.rules | list | `[]` | Add custom rule to the engine role | +| runtime.runtimeExtends | list | `["system/default/hybrid/k8s_low_limits"]` | Set parent runtime to inherit. Should not be changes. Parent runtime is controlled from Codefresh side. | +| runtime.serviceAccount | object | `{"annotations":{},"create":true}` | Set annotation on engine Service Account Ref: https://codefresh.io/docs/docs/administration/codefresh-runner/#injecting-aws-arn-roles-into-the-cluster | +| serviceMonitor | object | See below | Add serviceMonitor | +| serviceMonitor.main.enabled | bool | `false` | Enable service monitor for dind pods | +| storage.azuredisk.cachingMode | string | `"None"` | | +| storage.azuredisk.skuName | string | `"Premium_LRS"` | Set storage type (`Premium_LRS`) | +| storage.backend | string | `"local"` | Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) | +| storage.ebs.accessKeyId | string | `""` | Set AWS_ACCESS_KEY_ID for volume-provisioner (optional) Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#dind-volume-provisioner-permissions | +| storage.ebs.accessKeyIdSecretKeyRef | object | `{}` | Existing secret containing AWS_ACCESS_KEY_ID. | +| storage.ebs.availabilityZone | string | `"us-east-1a"` | Set EBS volumes availability zone (required) | +| storage.ebs.encrypted | string | `"false"` | Enable encryption (optional) | +| storage.ebs.kmsKeyId | string | `""` | Set KMS encryption key ID (optional) | +| storage.ebs.secretAccessKey | string | `""` | Set AWS_SECRET_ACCESS_KEY for volume-provisioner (optional) Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#dind-volume-provisioner-permissions | +| storage.ebs.secretAccessKeySecretKeyRef | object | `{}` | Existing secret containing AWS_SECRET_ACCESS_KEY | +| storage.ebs.volumeType | string | `"gp2"` | Set EBS volume type (`gp2`/`gp3`/`io1`) (required) | +| storage.fsType | string | `"ext4"` | Set filesystem type (`ext4`/`xfs`) | +| storage.gcedisk.availabilityZone | string | `"us-west1-a"` | Set GCP volume availability zone | +| storage.gcedisk.serviceAccountJson | string | `""` | Set Google SA JSON key for volume-provisioner (optional) | +| storage.gcedisk.serviceAccountJsonSecretKeyRef | object | `{}` | Existing secret containing containing Google SA JSON key for volume-provisioner (optional) | +| storage.gcedisk.volumeType | string | `"pd-ssd"` | Set GCP volume backend type (`pd-ssd`/`pd-standard`) | +| storage.local.volumeParentDir | string | `"/var/lib/codefresh/dind-volumes"` | Set volume path on the host filesystem | +| storage.mountAzureJson | bool | `false` | | +| volumeProvisioner | object | See below | Volume Provisioner parameters | +| volumeProvisioner.affinity | object | `{}` | Set affinity | +| volumeProvisioner.dind-lv-monitor | object | See below | `dind-lv-monitor` DaemonSet parameters (local volumes cleaner) | +| volumeProvisioner.enabled | bool | `true` | Enable volume-provisioner | +| volumeProvisioner.env | object | `{}` | Add additional env vars | +| volumeProvisioner.image | object | `{"registry":"quay.io","repository":"codefresh/dind-volume-provisioner","tag":"1.35.0"}` | Set image | +| volumeProvisioner.nodeSelector | object | `{}` | Set node selector | +| volumeProvisioner.podAnnotations | object | `{}` | Set pod annotations | +| volumeProvisioner.podSecurityContext | object | See below | Set security context for the pod | +| volumeProvisioner.rbac | object | `{"create":true,"rules":[]}` | RBAC parameters | +| volumeProvisioner.rbac.create | bool | `true` | Create RBAC resources | +| volumeProvisioner.rbac.rules | list | `[]` | Add custom rule to the role | +| volumeProvisioner.replicasCount | int | `1` | Set number of pods | +| volumeProvisioner.resources | object | `{}` | Set resources | +| volumeProvisioner.serviceAccount | object | `{"annotations":{},"create":true,"name":""}` | Service Account parameters | +| volumeProvisioner.serviceAccount.annotations | object | `{}` | Additional service account annotations | +| volumeProvisioner.serviceAccount.create | bool | `true` | Create service account | +| volumeProvisioner.serviceAccount.name | string | `""` | Override service account name | +| volumeProvisioner.tolerations | list | `[]` | Set tolerations | +| volumeProvisioner.updateStrategy | object | `{"type":"Recreate"}` | Upgrade strategy | + diff --git a/charts/codefresh/cf-runtime/6.3.57/README.md.gotmpl b/charts/codefresh/cf-runtime/6.3.57/README.md.gotmpl new file mode 100644 index 000000000..96e5ca574 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/README.md.gotmpl @@ -0,0 +1,1007 @@ +## Codefresh Runner + +{{ template "chart.versionBadge" . }}{{ template "chart.typeBadge" . }}{{ template "chart.appVersionBadge" . }} + +Helm chart for deploying [Codefresh Runner](https://codefresh.io/docs/docs/installation/codefresh-runner/) to Kubernetes. + +## Table of Content + +- [Prerequisites](#prerequisites) +- [Get Chart Info](#get-chart-info) +- [Install Chart](#install-chart) +- [Chart Configuration](#chart-configuration) +- [Upgrade Chart](#upgrade-chart) + - [To 2.x](#to-2-x) + - [To 3.x](#to-3-x) + - [To 4.x](#to-4-x) + - [To 5.x](#to-5-x) + - [To 6.x](#to-6-x) +- [Architecture](#architecture) +- [Configuration](#configuration) + - [EBS backend volume configuration in AWS](#ebs-backend-volume-configuration) + - [Azure Disks backend volume configuration in AKS](#azure-disks-backend-volume-configuration) + - [GCE Disks backend volume configuration in GKE](#gce-disks-backend-volume-configuration-in-gke) + - [Custom volume mounts](#custom-volume-mounts) + - [Custom global environment variables](#custom-global-environment-variables) + - [Volume reuse policy](#volume-reuse-policy) + - [Volume cleaners](#volume-cleaners) + - [Rootless DinD](#rootless-dind) + - [ARM](#arm) + - [Openshift](#openshift) + - [On-premise](#on-premise) + +## Prerequisites + +- Kubernetes **1.19+** +- Helm **3.8.0+** + +⚠️⚠️⚠️ +> Since version 6.2.x chart is pushed **only** to OCI registry at `oci://quay.io/codefresh/cf-runtime` + +> Versions prior to 6.2.x are still available in ChartMuseum at `http://chartmuseum.codefresh.io/cf-runtime` + +## Get Chart Info + +```console +helm show all oci://quay.io/codefresh/cf-runtime +``` +See [Use OCI-based registries](https://helm.sh/docs/topics/registries/) + +## Install Chart + +**Important:** only helm3 is supported + +- Specify the following mandatory values + +`values.yaml` +```yaml +# -- Global parameters +# @default -- See below +global: + # -- User token in plain text (required if `global.codefreshTokenSecretKeyRef` is omitted!) + # Ref: https://g.codefresh.io/user/settings (see API Keys) + # Minimal API key scopes: Runner-Installation(read+write), Agent(read+write), Agents(read+write) + codefreshToken: "" + # -- User token that references an existing secret containing API key (required if `global.codefreshToken` is omitted!) + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Account ID (required!) + # Can be obtained here https://g.codefresh.io/2.0/account-settings/account-information + accountId: "" + + # -- K8s context name (required!) + context: "" + # E.g. + # context: prod-ue1-runtime-1 + + # -- Agent Name (optional!) + # If omitted, the following format will be used '{{ `{{ .Values.global.context }}_{{ .Release.Namespace }}` }}' + agentName: "" + # E.g. + # agentName: prod-ue1-runtime-1 + + # -- Runtime name (optional!) + # If omitted, the following format will be used '{{ `{{ .Values.global.context }}/{{ .Release.Namespace }}` }}' + runtimeName: "" + # E.g. + # runtimeName: prod-ue1-runtime-1/namespace +``` + +- Install chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace codefresh +``` + +## Chart Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). + +## Upgrade Chart + +### To 2.x + +This major release renames and deprecated several values in the chart. Most of the workload templates have been refactored. + +Affected values: +- `dockerRegistry` is deprecated. Replaced with `global.imageRegistry` +- `re` is renamed to `runtime` +- `storage.localVolumeMonitor` is replaced with `volumeProvisioner.dind-lv-monitor` +- `volumeProvisioner.volume-cleanup` is replaced with `volumeProvisioner.dind-volume-cleanup` +- `image` values structure has been updated. Split to `image.registry` `image.repository` `image.tag` +- pod's `annotations` is renamed to `podAnnotations` + +### To 3.x + +⚠️⚠️⚠️ +### READ this before the upgrade! + +This major release adds [runtime-environment](https://codefresh.io/docs/docs/installation/codefresh-runner/#runtime-environment-specification) spec into chart templates. +That means it is possible to set parametes for `dind` and `engine` pods via [values.yaml](./values.yaml). + +**If you had any overrides (i.e. tolerations/nodeSelector/environment variables/etc) added in runtime spec via [codefresh CLI](https://codefresh-io.github.io/cli/) (for example, you did use [get](https://codefresh-io.github.io/cli/runtime-environments/get-runtime-environments/) and [patch](https://codefresh-io.github.io/cli/runtime-environments/apply-runtime-environments/) commands to modify the runtime-environment), you MUST add these into chart's [values.yaml](./values.yaml) for `.Values.runtime.dind` or(and) .`Values.runtime.engine`** + +**For backward compatibility, you can disable updating runtime-environment spec via** `.Values.runtime.patch.enabled=false` + +Affected values: +- added **mandatory** `global.codefreshToken`/`global.codefreshTokenSecretKeyRef` **You must specify it before the upgrade!** +- `runtime.engine` is added +- `runtime.dind` is added +- `global.existingAgentToken` is replaced with `global.agentTokenSecretKeyRef` +- `global.existingDindCertsSecret` is replaced with `global.dindCertsSecretRef` + +### To 4.x + +This major release adds **agentless inCluster** runtime mode (relevant only for [Codefresh On-Premises](#on-premise) users) + +Affected values: +- `runtime.agent` / `runtime.inCluster` / `runtime.accounts` / `runtime.description` are added + +### To 5.x + +This major release converts `.runtime.dind.pvcs` from **list** to **dict** + +> 4.x chart's values example: +```yaml +runtime: + dind: + pvcs: + - name: dind + storageClassName: my-storage-class-name + volumeSize: 32Gi + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +> 5.x chart's values example: +```yaml +runtime: + dind: + pvcs: + dind: + name: dind + storageClassName: my-storage-class-name + volumeSize: 32Gi + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +Affected values: +- `.runtime.dind.pvcs` converted from **list** to **dict** + +### To 6.x + +⚠️⚠️⚠️ +### READ this before the upgrade! + +This major release deprecates previously required `codefresh runner init --generate-helm-values-file`. + +Affected values: +- **Replaced** `.monitor.clusterId` with `.global.context` as **mandatory** value! +- **Deprecated** `.global.agentToken` / `.global.agentTokenSecretKeyRef` +- **Removed** `.global.agentId` +- **Removed** `.global.keys` / `.global.dindCertsSecretRef` +- **Removed** `.global.existingAgentToken` / `existingDindCertsSecret` +- **Removed** `.monitor.clusterId` / `.monitor.token` / `.monitor.existingMonitorToken` + +#### Migrate the Helm chart from version 5.x to 6.x + +Given this is the legacy `generated_values.yaml` values: + +> legacy `generated_values.yaml` +```yaml +{ + "appProxy": { + "enabled": false, + }, + "monitor": { + "enabled": false, + "clusterId": "my-cluster-name", + "token": "1234567890" + }, + "global": { + "namespace": "namespace", + "codefreshHost": "https://g.codefresh.io", + "agentToken": "0987654321", + "agentId": "agent-id-here", + "agentName": "my-cluster-name_my-namespace", + "accountId": "my-account-id", + "runtimeName": "my-cluster-name/my-namespace", + "codefreshToken": "1234567890", + "keys": { + "key": "-----BEGIN RSA PRIVATE KEY-----...", + "csr": "-----BEGIN CERTIFICATE REQUEST-----...", + "ca": "-----BEGIN CERTIFICATE-----...", + "serverCert": "-----BEGIN CERTIFICATE-----..." + } + } +} +``` + +Update `values.yaml` for new chart version: + +> For existing installation for backward compatibility `.Values.global.agentToken/agentTokenSecretKeyRef` **must be provided!** For installation from scratch this value is no longer required. + +> updated `values.yaml` +```yaml +global: + codefreshToken: "1234567890" + accountId: "my-account-id" + context: "my-cluster-name" + agentToken: "0987654321" # MANDATORY when migrating from < 6.x chart version ! + agentName: "my-cluster-name_my-namespace" # optional + runtimeName: "my-cluster-name/my-namespace" # optional +``` + +> **Note!** Though it's still possible to update runtime-environment via [get](https://codefresh-io.github.io/cli/runtime-environments/get-runtime-environments/) and [patch](https://codefresh-io.github.io/cli/runtime-environments/apply-runtime-environments/) commands, it's recommended to enable sidecar container to pull runtime spec from Codefresh API to detect any drift in configuration. + +```yaml +runner: + # -- Sidecar container + # Reconciles runtime spec from Codefresh API for drift detection + sidecar: + enabled: true +``` + +## Architecture + +[Codefresh Runner architecture](https://codefresh.io/docs/docs/installation/codefresh-runner/#codefresh-runner-architecture) + +## Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). + +### EBS backend volume configuration + +`dind-volume-provisioner` should have permissions to create/attach/detach/delete/get EBS volumes + +Minimal IAM policy for `dind-volume-provisioner` + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "ec2:AttachVolume", + "ec2:CreateSnapshot", + "ec2:CreateTags", + "ec2:CreateVolume", + "ec2:DeleteSnapshot", + "ec2:DeleteTags", + "ec2:DeleteVolume", + "ec2:DescribeInstances", + "ec2:DescribeSnapshots", + "ec2:DescribeTags", + "ec2:DescribeVolumes", + "ec2:DetachVolume" + ], + "Resource": "*" + } + ] +} +``` + +There are three options: + +1. Run `dind-volume-provisioner` pod on the node/node-group with IAM role + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + +volumeProvisioner: + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] +``` + +2. Pass static credentials in `.Values.storage.ebs.accessKeyId/accessKeyIdSecretKeyRef` and `.Values.storage.ebs.secretAccessKey/secretAccessKeySecretKeyRef` + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + + # -- Set AWS_ACCESS_KEY_ID for volume-provisioner (optional) + accessKeyId: "" + # -- Existing secret containing AWS_ACCESS_KEY_ID. + accessKeyIdSecretKeyRef: {} + # E.g. + # accessKeyIdSecretKeyRef: + # name: + # key: + + # -- Set AWS_SECRET_ACCESS_KEY for volume-provisioner (optional) + secretAccessKey: "" + # -- Existing secret containing AWS_SECRET_ACCESS_KEY + secretAccessKeySecretKeyRef: {} + # E.g. + # secretAccessKeySecretKeyRef: + # name: + # key: +``` + +3. Assign IAM role to `dind-volume-provisioner` service account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + +volumeProvisioner: + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Additional service account annotations + annotations: + eks.amazonaws.com/role-arn: "arn:aws:iam:::role/" +``` + +### Custom volume mounts + +You can add your own volumes and volume mounts in the runtime environment, so that all pipeline steps will have access to the same set of external files. + +```yaml +runtime: + dind: + userVolumes: + regctl-docker-registry: + name: regctl-docker-registry + secret: + items: + - key: .dockerconfigjson + path: config.json + secretName: regctl-docker-registry + optional: true + userVolumeMounts: + regctl-docker-registry: + name: regctl-docker-registry + mountPath: /home/appuser/.docker/ + readOnly: true + +``` + +### Azure Disks backend volume configuration + +`dind-volume-provisioner` should have permissions to create/delete/get Azure Disks + +Role definition for `dind-volume-provisioner` + +`dind-volume-provisioner-role.json` +```json +{ + "Name": "CodefreshDindVolumeProvisioner", + "Description": "Perform create/delete/get disks", + "IsCustom": true, + "Actions": [ + "Microsoft.Compute/disks/read", + "Microsoft.Compute/disks/write", + "Microsoft.Compute/disks/delete" + + ], + "AssignableScopes": ["/subscriptions/"] +} +``` + +When creating an AKS cluster in Azure there is the option to use a [managed identity](https://learn.microsoft.com/en-us/azure/aks/use-managed-identity) that is assigned to the kubelet. This identity is assigned to the underlying node pool in the AKS cluster and can then be used by the dind-volume-provisioner. + +```console +export ROLE_DEFINITIN_FILE=dind-volume-provisioner-role.json +export SUBSCRIPTION_ID=$(az account show --query "id" | xargs echo ) +export RESOURCE_GROUP= +export AKS_NAME= +export LOCATION=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query location | xargs echo) +export NODES_RESOURCE_GROUP=MC_${RESOURCE_GROUP}_${AKS_NAME}_${LOCATION} +export NODE_SERVICE_PRINCIPAL=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query identityProfile.kubeletidentity.objectId | xargs echo) + +az role definition create --role-definition @${ROLE_DEFINITIN_FILE} +az role assignment create --assignee $NODE_SERVICE_PRINCIPAL --scope /subscriptions/$SUBSCRIPTION_ID/resourceGroups/$NODES_RESOURCE_GROUP --role CodefreshDindVolumeProvisioner +``` + +Deploy Helm chart with the following values: + +`values.yaml` +```yaml +volumeProvisioner: + podSecurityContext: + enabled: true + runAsUser: 0 + runAsGroup: 0 + fsGroup: 0 + +storage: + backend: azuredisk + azuredisk: + availabilityZone: northeurope-1 # replace with your zone + resourceGroup: my-resource-group-name + + mountAzureJson: true + +runtime: + dind: + nodeSelector: + topology.kubernetes.io/zone: northeurope-1 +``` + +### GCE Disks backend volume configuration in GKE + +`dind-volume-provisioner` should have `ComputeEngine.StorageAdmin` permissions + +There are three options: + +1. Run `dind-volume-provisioner` pod on the node/node-group with IAM Service Account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + +volumeProvisioner: + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +2. Pass static credentials in `.Values.storage.gcedisk.serviceAccountJson` (inline) or `.Values.storage.gcedisk.serviceAccountJsonSecretKeyRef` (from your own secret) + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "`pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + # -- Set Google SA JSON key for volume-provisioner (optional) + serviceAccountJson: | + { + "type": "service_account", + "project_id": "...", + "private_key_id": "...", + "private_key": "...", + "client_email": "...", + "client_id": "...", + "auth_uri": "...", + "token_uri": "...", + "auth_provider_x509_cert_url": "...", + "client_x509_cert_url": "..." + } + # -- Existing secret containing containing Google SA JSON key for volume-provisioner (optional) + serviceAccountJsonSecretKeyRef: {} + # E.g.: + # serviceAccountJsonSecretKeyRef: + # name: gce-service-account + # key: service-account.json + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +3. Assign IAM role to `dind-volume-provisioner` service account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "`pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + +volumeProvisioner: + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Additional service account annotations + annotations: + iam.gke.io/gcp-service-account: @.iam.gserviceaccount.com + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +### Custom global environment variables + +You can add your own environment variables to the runtime environment. All pipeline steps have access to the global variables. + +```yaml +runtime: + engine: + userEnvVars: + - name: GITHUB_TOKEN + valueFrom: + secretKeyRef: + name: github-token + key: token +``` + +### Volume reuse policy + +Volume reuse behavior depends on the configuration for `reuseVolumeSelector` in the runtime environment spec. + +```yaml +runtime: + dind: + pvcs: + - name: dind + ... + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +The following options are available: +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName'` - PV can be used by ANY pipeline in the specified account (default). +Benefit: Fewer PVs, resulting in lower costs. Since any PV can be used by any pipeline, the cluster needs to maintain/reserve fewer PVs in its PV pool for Codefresh. +Downside: Since the PV can be used by any pipeline, the PVs could have assets and info from different pipelines, reducing the probability of cache. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,project_id'` - PV can be used by ALL pipelines in your account, assigned to the same project. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id'` - PV can be used only by a single pipeline. +Benefit: More probability of cache without “spam” from other pipelines. +Downside: More PVs to maintain and therefore higher costs. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id,io.codefresh.branch_name'` - PV can be used only by single pipeline AND single branch. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id,trigger'` - PV can be used only by single pipeline AND single trigger. + +### Volume cleaners + +Codefresh pipelines require disk space for: + * [Pipeline Shared Volume](https://codefresh.io/docs/docs/pipelines/introduction-to-codefresh-pipelines/#sharing-the-workspace-between-build-steps) (`/codefresh/volume`, implemented as [docker volume](https://docs.docker.com/storage/volumes/)) + * Docker containers, both running and stopped + * Docker images and cached layers + +Codefresh offers two options to manage disk space and prevent out-of-space errors: +* Use runtime cleaners on Docker images and volumes +* [Set the minimum disk space per pipeline build volume](https://codefresh.io/docs/docs/pipelines/pipelines/#set-minimum-disk-space-for-a-pipeline-build) + +To improve performance by using Docker cache, Codefresh `volume-provisioner` can provision previously used disks with Docker images and pipeline volumes from previously run builds. + +### Types of runtime volume cleaners + +Docker images and volumes must be cleaned on a regular basis. + +* [IN-DIND cleaner](https://github.com/codefresh-io/dind/tree/master/cleaner): Deletes extra Docker containers, volumes, and images in **DIND pod**. +* [External volume cleaner](https://github.com/codefresh-io/dind-volume-cleanup): Deletes unused **external** PVs (EBS, GCE/Azure disks). +* [Local volume cleaner](https://github.com/codefresh-io/dind-volume-utils/blob/master/local-volumes/lv-cleaner.sh): Deletes **local** volumes if node disk space is close to the threshold. + +### IN-DIND cleaner + +**Purpose:** Removes unneeded *docker containers, images, volumes* inside Kubernetes volume mounted on the DIND pod + +**How it runs:** Inside each DIND pod as script + +**Triggered by:** SIGTERM and also during the run when disk usage > 90% (configurable) + +**Configured by:** Environment Variables which can be set in Runtime Environment spec + +**Configuration/Logic:** [README.md](https://github.com/codefresh-io/dind/tree/master/cleaner#readme) + +Override `.Values.runtime.dind.env` if necessary (the following are **defaults**): + +```yaml +runtime: + dind: + env: + CLEAN_PERIOD_SECONDS: '21600' # launch clean if last clean was more than CLEAN_PERIOD_SECONDS seconds ago + CLEAN_PERIOD_BUILDS: '5' # launch clean if last clean was more CLEAN_PERIOD_BUILDS builds since last build + IMAGE_RETAIN_PERIOD: '14400' # do not delete docker images if they have events since current_timestamp - IMAGE_RETAIN_PERIOD + VOLUMES_RETAIN_PERIOD: '14400' # do not delete docker volumes if they have events since current_timestamp - VOLUMES_RETAIN_PERIOD + DISK_USAGE_THRESHOLD: '0.8' # launch clean based on current disk usage DISK_USAGE_THRESHOLD + INODES_USAGE_THRESHOLD: '0.8' # launch clean based on current inodes usage INODES_USAGE_THRESHOLD +``` + +### External volumes cleaner + +**Purpose:** Removes unused *kubernetes volumes and related backend volumes* + +**How it runs:** Runs as `dind-volume-cleanup` CronJob. Installed in case the Runner uses non-local volumes `.Values.storage.backend != local` + +**Triggered by:** CronJob every 10min (configurable) + +**Configuration:** + +Set `codefresh.io/volume-retention` for dinds' PVCs: + +```yaml +runtime: + dind: + pvcs: + dind: + ... + annotations: + codefresh.io/volume-retention: 7d +``` + +Or override environment variables for `dind-volume-cleanup` cronjob: + +```yaml +volumeProvisioner: + dind-volume-cleanup: + env: + RETENTION_DAYS: 7 # clean volumes that were last used more than `RETENTION_DAYS` (default is 4) ago +``` + +### Local volumes cleaner + +**Purpose:** Deletes local volumes when node disk space is close to the threshold + +**How it runs:** Runs as `dind-lv-monitor` DaemonSet. Installed in case the Runner uses local volumes `.Values.storage.backend == local` + +**Triggered by:** Disk space usage or inode usage that exceeds thresholds (configurable) + +**Configuration:** + +Override environment variables for `dind-lv-monitor` daemonset: + +```yaml +volumeProvisioner: + dind-lv-monitor: + env: + KB_USAGE_THRESHOLD: 60 # default 80 (percentage) + INODE_USAGE_THRESHOLD: 60 # default 80 +``` + +### Rootless DinD + +DinD pod runs a `priviliged` container with **rootfull** docker. +To run the docker daemon as non-root user (**rootless** mode), change dind image tag: + +`values.yaml` +```yaml +runtime: + dind: + image: + tag: rootless +``` + +### ARM + +With the Codefresh Runner, you can run native ARM64v8 builds. + +> **Note!** +> You cannot run both amd64 and arm64 images within the same pipeline. As one pipeline can map only to one runtime, you can run either amd64 or arm64 within the same pipeline. + +Provide `nodeSelector` and(or) `tolerations` for dind pods: + +`values.yaml` +```yaml +runtime: + dind: + nodeSelector: + arch: arm64 + tolerations: + - key: arch + operator: Equal + value: arm64 + effect: NoSchedule +``` + +### Openshift + +To install Codefresh Runner on OpenShift use the following `values.yaml` example + +```yaml +runner: + podSecurityContext: + enabled: false + +volumeProvisioner: + podSecurityContext: + enabled: false + env: + PRIVILEGED_CONTAINER: true + dind-lv-monitor: + containerSecurityContext: + enabled: true + privileged: true + volumePermissions: + enabled: true + securityContext: + privileged: true + runAsUser: auto +``` + +Grant `privileged` SCC to `cf-runtime-runner` and `cf-runtime-volume-provisioner` service accounts. + +```console +oc adm policy add-scc-to-user privileged system:serviceaccount:codefresh:cf-runtime-runner + +oc adm policy add-scc-to-user privileged system:serviceaccount:codefresh:cf-runtime-volume-provisioner +``` + +### On-premise + +If you have [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) deployed, you can install Codefresh Runner in **agentless** mode. + +**What is agentless mode?** + +Agent (aka venona) is Runner component which responsible for calling Codefresh API to run builds and create dind/engine pods and pvc objects. Agent can only be assigned to a single account, thus you can't share one runtime across multiple accounts. However, with **agentless** mode it's possible to register the runtime as **system**-type runtime so it's registered on the platform level and can be assigned/shared across multiple accounts. + +**What are the prerequisites?** +- You have a running [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) control-plane environment +- You have a Codefresh API token with platform **Admin** permissions scope + + +### How to deploy agentless runtime when it's on the SAME k8s cluster as On-Premises control-plane environment? + +- Enable cluster-level permissions for cf-api (On-Premises control-plane component) + +> `values.yaml` for [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) Helm chart +```yaml +cfapi: + ... + # -- Enable ClusterRole/ClusterRoleBinding + rbac: + namespaced: false +``` + +- Set the following values for Runner Helm chart + +`.Values.global.codefreshHost=...` \ +`.Values.global.codefreshToken=...` \ +`.Values.global.runtimeName=system/...` \ +`.Values.runtime.agent=false` \ +`.Values.runtime.inCluster=true` + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart +```yaml +global: + # -- URL of Codefresh On-Premises Platform + codefreshHost: "https://myonprem.somedomain.com" + # -- User token in plain text with Admin permission scope + codefreshToken: "" + # -- User token that references an existing secret containing API key. + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Distinguished runtime name + # (for On-Premise only; mandatory!) Must be prefixed with "system/..." + runtimeName: "system/prod-ue1-some-cluster-name" + +# -- Set runtime parameters +runtime: + # -- (for On-Premise only; mandatory!) Disable agent + agent: false + # -- (for On-Premise only; optional) Set inCluster runtime (default: `true`) + # `inCluster=true` flag is set when Runtime and On-Premises control-plane are run on the same cluster + # `inCluster=false` flag is set when Runtime and On-Premises control-plane are on different clusters + inCluster: true + # -- (for On-Premise only; optional) Assign accounts to runtime (list of account ids; default is empty) + # Accounts can be assigned to the runtime in Codefresh UI later so you can kepp it empty. + accounts: [] + # -- Set parent runtime to inherit. + runtimeExtends: [] +``` + +- Install the chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace cf-runtime +``` + +- Verify the runtime and run test pipeline + +Go to [https:///admin/runtime-environments/system](https:///admin/runtime-environments/system) to check the runtime. Assign it to the required account(s). Run test pipeline on it. + + +### How to deploy agentless runtime when it's on the DIFFERENT k8s cluster than On-Premises control-plane environment? + +In this case, it's required to mount runtime cluster's `KUBECONFIG` into On-Premises `cf-api` deployment + +- Create the neccessary RBAC resources + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart +```yaml +extraResources: +- apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + name: codefresh-role + namespace: '{{ "{{ .Release.Namespace }}" }}' + rules: + - apiGroups: [""] + resources: ["pods", "persistentvolumeclaims", "persistentvolumes"] + verbs: ["list", "watch", "get", "create", "patch", "delete"] + - apiGroups: ["snapshot.storage.k8s.io"] + resources: ["volumesnapshots"] + verbs: ["list", "watch", "get", "create", "patch", "delete"] +- apiVersion: v1 + kind: ServiceAccount + metadata: + name: codefresh-runtime-user + namespace: '{{ "{{ .Release.Namespace }}" }}' +- apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + name: codefresh-runtime-user + namespace: '{{ "{{ .Release.Namespace }}" }}' + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: codefresh-role + subjects: + - kind: ServiceAccount + name: codefresh-runtime-user + namespace: '{{ "{{ .Release.Namespace }}" }}' +- apiVersion: v1 + kind: Secret + metadata: + name: codefresh-runtime-user-token + namespace: '{{ "{{ .Release.Namespace }}" }}' + annotations: + kubernetes.io/service-account.name: codefresh-runtime-user + type: kubernetes.io/service-account-token +``` + +- Set up the following environment variables to create a `KUBECONFIG` file + +```shell +NAMESPACE=cf-runtime +CLUSTER_NAME=prod-ue1-some-cluster-name +CURRENT_CONTEXT=$(kubectl config current-context) + +USER_TOKEN_VALUE=$(kubectl -n cf-runtime get secret/codefresh-runtime-user-token -o=go-template='{{ `{{.data.token}}` }}' | base64 --decode) +CURRENT_CLUSTER=$(kubectl config view --raw -o=go-template='{{ `{{range .contexts}}{{if eq .name "'''${CURRENT_CONTEXT}'''"}}{{ index .context "cluster" }}{{end}}{{end}}` }}') +CLUSTER_CA=$(kubectl config view --raw -o=go-template='{{ `{{range .clusters}}{{if eq .name "'''${CURRENT_CLUSTER}'''"}}"{{with index .cluster "certificate-authority-data" }}{{.}}{{end}}"{{ end }}{{ end }}` }}') +CLUSTER_SERVER=$(kubectl config view --raw -o=go-template='{{ `{{range .clusters}}{{if eq .name "'''${CURRENT_CLUSTER}'''"}}{{ .cluster.server }}{{end}}{{ end }}` }}') + +export -p USER_TOKEN_VALUE CURRENT_CONTEXT CURRENT_CLUSTER CLUSTER_CA CLUSTER_SERVER CLUSTER_NAME +``` + +- Create a kubeconfig file + +```console +cat << EOF > $CLUSTER_NAME-kubeconfig +apiVersion: v1 +kind: Config +current-context: ${CLUSTER_NAME} +contexts: +- name: ${CLUSTER_NAME} + context: + cluster: ${CLUSTER_NAME} + user: codefresh-runtime-user + namespace: ${NAMESPACE} +clusters: +- name: ${CLUSTER_NAME} + cluster: + certificate-authority-data: ${CLUSTER_CA} + server: ${CLUSTER_SERVER} +users: +- name: ${CLUSTER_NAME} + user: + token: ${USER_TOKEN_VALUE} +EOF +``` + +- **Switch context to On-Premises control-plane cluster**. Create k8s secret (via any tool like [ESO](https://external-secrets.io/v0.4.4/), `kubectl`, etc ) containing runtime cluster's `KUBECONFG` created in previous step. + +```shell +NAMESPACE=codefresh +kubectl create secret generic dind-runtime-clusters --from-file=$CLUSTER_NAME=$CLUSTER_NAME-kubeconfig -n $NAMESPACE +``` + +- Mount secret containing runtime cluster's `KUBECONFG` into cf-api in On-Premises control-plane cluster + +> `values.yaml` for [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) helm chart +```yaml +cf-api: + ... + volumes: + dind-clusters: + enabled: true + type: secret + nameOverride: dind-runtime-clusters + optional: true +``` +> volumeMount `/etc/kubeconfig` is already configured in cf-api Helm chart template. No need to specify it. + +- Set the following values for Runner helm chart + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart + +`.Values.global.codefreshHost=...` \ +`.Values.global.codefreshToken=...` \ +`.Values.global.runtimeName=system/...` \ +`.Values.runtime.agent=false` \ +`.Values.runtime.inCluster=false` + +**Important!** +`.Values.global.name` ("system/" prefix is ignored!) should match the cluster name (key in `dind-runtime-clusters` secret created previously) +```yaml +global: + # -- URL of Codefresh On-Premises Platform + codefreshHost: "https://myonprem.somedomain.com" + # -- User token in plain text with Admin permission scope + codefreshToken: "" + # -- User token that references an existing secret containing API key. + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Distinguished runtime name + # (for On-Premise only; mandatory!) Must be prefixed with "system/..." + name: "system/prod-ue1-some-cluster-name" + +# -- Set runtime parameters +runtime: + # -- (for On-Premise only; mandatory!) Disable agent + agent: false + # -- (for On-Premise only; optional) Set inCluster runtime (default: `true`) + # `inCluster=true` flag is set when Runtime and On-Premises control-plane are run on the same cluster + # `inCluster=false` flag is set when Runtime and On-Premises control-plane are on different clusters + inCluster: false + # -- (for On-Premise only; optional) Assign accounts to runtime (list of account ids; default is empty) + # Accounts can be assigned to the runtime in Codefresh UI later so you can kepp it empty. + accounts: [] + # -- (optional) Set parent runtime to inherit. + runtimeExtends: [] +``` + +- Install the chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace cf-runtime +``` + +- Verify the runtime and run test pipeline + +Go to [https:///admin/runtime-environments/system](https:///admin/runtime-environments/system) to see the runtime. Assign it to the required account(s). + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.valuesSection" . }} + diff --git a/charts/codefresh/cf-runtime/6.3.57/files/cleanup-runtime.sh b/charts/codefresh/cf-runtime/6.3.57/files/cleanup-runtime.sh new file mode 100644 index 000000000..c1fc5f368 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/files/cleanup-runtime.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +echo "-----" +echo "API_HOST: ${API_HOST}" +echo "AGENT_NAME: ${AGENT_NAME}" +echo "RUNTIME_NAME: ${RUNTIME_NAME}" +echo "AGENT: ${AGENT}" +echo "AGENT_SECRET_NAME: ${AGENT_SECRET_NAME}" +echo "DIND_SECRET_NAME: ${DIND_SECRET_NAME}" +echo "-----" + +auth() { + codefresh auth create-context --api-key ${API_TOKEN} --url ${API_HOST} +} + +remove_runtime() { + if [ "$AGENT" == "true" ]; then + codefresh delete re ${RUNTIME_NAME} || true + else + codefresh delete sys-re ${RUNTIME_NAME} || true + fi +} + +remove_agent() { + codefresh delete agent ${AGENT_NAME} || true +} + +remove_secrets() { + kubectl patch secret $(kubectl get secret -l codefresh.io/internal=true | awk 'NR>1{print $1}' | xargs) -p '{"metadata":{"finalizers":null}}' --type=merge || true + kubectl delete secret $AGENT_SECRET_NAME || true + kubectl delete secret $DIND_SECRET_NAME || true +} + +auth +remove_runtime +remove_agent +remove_secrets \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/files/configure-dind-certs.sh b/charts/codefresh/cf-runtime/6.3.57/files/configure-dind-certs.sh new file mode 100644 index 000000000..a1092eb1e --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/files/configure-dind-certs.sh @@ -0,0 +1,132 @@ +#!/usr/bin/env bash +# + +#--- +fatal() { + echo "ERROR: $1" + exit 1 +} + +msg() { echo -e "\e[32mINFO ---> $1\e[0m"; } +err() { echo -e "\e[31mERR ---> $1\e[0m" ; return 1; } + +exit_trap () { + local lc="$BASH_COMMAND" rc=$? + if [ $rc != 0 ]; then + if [[ -n "$SLEEP_ON_ERROR" ]]; then + echo -e "\nSLEEP_ON_ERROR is set - Sleeping to fix error" + sleep $SLEEP_ON_ERROR + fi + fi +} +trap exit_trap EXIT + +usage() { + echo "Usage: + $0 [-n | --namespace] [--server-cert-cn] [--server-cert-extra-sans] codefresh-api-host codefresh-api-token + +Example: + $0 -n workflow https://g.codefresh.io 21341234.423141234.412431234 + +" +} + +# Args +while [[ $1 =~ ^(-(n|h)|--(namespace|server-cert-cn|server-cert-extra-sans|help)) ]] +do + key=$1 + value=$2 + + case $key in + -h|--help) + usage + exit + ;; + -n|--namespace) + NAMESPACE="$value" + shift + ;; + --server-cert-cn) + SERVER_CERT_CN="$value" + shift + ;; + --server-cert-extra-sans) + SERVER_CERT_EXTRA_SANS="$value" + shift + ;; + esac + shift # past argument or value +done + +API_HOST=${1:-"$CF_API_HOST"} +API_TOKEN=${2:-"$CF_API_TOKEN"} + +[[ -z "$API_HOST" ]] && usage && fatal "Missing API_HOST" +[[ -z "$API_TOKEN" ]] && usage && fatal "Missing token" + + +API_SIGN_PATH=${API_SIGN_PATH:-"api/custom_clusters/signServerCerts"} + +NAMESPACE=${NAMESPACE:-default} +RELEASE=${RELEASE:-cf-runtime} + +DIR=$(dirname $0) +TMPDIR=/tmp/codefresh/ + +TMP_CERTS_FILE_ZIP=$TMPDIR/cf-certs.zip +TMP_CERTS_HEADERS_FILE=$TMPDIR/cf-certs-response-headers.txt +CERTS_DIR=$TMPDIR/ssl +SRV_TLS_CA_CERT=${CERTS_DIR}/ca.pem +SRV_TLS_KEY=${CERTS_DIR}/server-key.pem +SRV_TLS_CSR=${CERTS_DIR}/server-cert.csr +SRV_TLS_CERT=${CERTS_DIR}/server-cert.pem +CF_SRV_TLS_CERT=${CERTS_DIR}/cf-server-cert.pem +CF_SRV_TLS_CA_CERT=${CERTS_DIR}/cf-ca.pem +mkdir -p $TMPDIR $CERTS_DIR + +K8S_CERT_SECRET_NAME=codefresh-certs-server +echo -e "\n------------------\nGenerating server tls certificates ... " + +SERVER_CERT_CN=${SERVER_CERT_CN:-"docker.codefresh.io"} +SERVER_CERT_EXTRA_SANS="${SERVER_CERT_EXTRA_SANS}" +### + + openssl genrsa -out $SRV_TLS_KEY 4096 || fatal "Failed to generate openssl key " + openssl req -subj "/CN=${SERVER_CERT_CN}" -new -key $SRV_TLS_KEY -out $SRV_TLS_CSR || fatal "Failed to generate openssl csr " + GENERATE_CERTS=true + CSR=$(sed ':a;N;$!ba;s/\n/\\n/g' ${SRV_TLS_CSR}) + + SERVER_CERT_SANS="IP:127.0.0.1,DNS:dind,DNS:*.dind.${NAMESPACE},DNS:*.dind.${NAMESPACE}.svc${KUBE_DOMAIN},DNS:*.cf-cd.com,DNS:*.codefresh.io" + if [[ -n "${SERVER_CERT_EXTRA_SANS}" ]]; then + SERVER_CERT_SANS=${SERVER_CERT_SANS},${SERVER_CERT_EXTRA_SANS} + fi + echo "{\"reqSubjectAltName\": \"${SERVER_CERT_SANS}\", \"csr\": \"${CSR}\" }" > ${TMPDIR}/sign_req.json + + rm -fv ${TMP_CERTS_HEADERS_FILE} ${TMP_CERTS_FILE_ZIP} + + SIGN_STATUS=$(curl -k -sSL -d @${TMPDIR}/sign_req.json -H "Content-Type: application/json" -H "Authorization: ${API_TOKEN}" -H "Expect: " \ + -o ${TMP_CERTS_FILE_ZIP} -D ${TMP_CERTS_HEADERS_FILE} -w '%{http_code}' ${API_HOST}/${API_SIGN_PATH} ) + + echo "Sign request completed with HTTP_STATUS_CODE=$SIGN_STATUS" + if [[ $SIGN_STATUS != 200 ]]; then + echo "ERROR: Cannot sign certificates" + if [[ -f ${TMP_CERTS_FILE_ZIP} ]]; then + mv ${TMP_CERTS_FILE_ZIP} ${TMP_CERTS_FILE_ZIP}.error + cat ${TMP_CERTS_FILE_ZIP}.error + fi + exit 1 + fi + unzip -o -d ${CERTS_DIR}/ ${TMP_CERTS_FILE_ZIP} || fatal "Failed to unzip certificates to ${CERTS_DIR} " + cp -v ${CF_SRV_TLS_CA_CERT} $SRV_TLS_CA_CERT || fatal "received ${TMP_CERTS_FILE_ZIP} does not contains ca.pem" + cp -v ${CF_SRV_TLS_CERT} $SRV_TLS_CERT || fatal "received ${TMP_CERTS_FILE_ZIP} does not contains cf-server-cert.pem" + + +echo -e "\n------------------\nCreating certificate secret " + +kubectl -n $NAMESPACE create secret generic $K8S_CERT_SECRET_NAME \ + --from-file=$SRV_TLS_CA_CERT \ + --from-file=$SRV_TLS_KEY \ + --from-file=$SRV_TLS_CERT \ + --dry-run=client -o yaml | kubectl apply --overwrite -f - +kubectl -n $NAMESPACE label --overwrite secret ${K8S_CERT_SECRET_NAME} codefresh.io/internal=true +kubectl -n $NAMESPACE patch secret $K8S_CERT_SECRET_NAME -p '{"metadata": {"finalizers": ["kubernetes"]}}' diff --git a/charts/codefresh/cf-runtime/6.3.57/files/init-runtime.sh b/charts/codefresh/cf-runtime/6.3.57/files/init-runtime.sh new file mode 100644 index 000000000..eb3488af1 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/files/init-runtime.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +echo "-----" +echo "API_HOST: ${API_HOST}" +echo "AGENT_NAME: ${AGENT_NAME}" +echo "KUBE_CONTEXT: ${KUBE_CONTEXT}" +echo "KUBE_NAMESPACE: ${KUBE_NAMESPACE}" +echo "OWNER_NAME: ${OWNER_NAME}" +echo "RUNTIME_NAME: ${RUNTIME_NAME}" +echo "SECRET_NAME: ${SECRET_NAME}" +echo "-----" + +create_agent_secret() { + + kubectl apply -f - < $1\e[0m"; } +err() { echo -e "\e[31mERR ---> $1\e[0m" ; return 1; } + + +if [ -z "${USER_CODEFRESH_TOKEN}" ]; then + err "missing codefresh user token. must supply \".global.codefreshToken\" if agent-codefresh-token does not exist" + exit 1 +fi + +codefresh auth create-context --api-key ${USER_CODEFRESH_TOKEN} --url ${API_HOST} + +while true; do + msg "Reconciling ${RUNTIME_NAME} runtime" + + sleep $RECONCILE_INTERVAL + + codefresh get re \ + --name ${RUNTIME_NAME} \ + -o yaml \ + | yq 'del(.version, .metadata.changedBy, .metadata.creationTime)' > /tmp/runtime.yaml + + kubectl get cm ${CONFIGMAP_NAME} -n ${KUBE_NAMESPACE} -o yaml \ + | yq 'del(.metadata.resourceVersion, .metadata.uid)' \ + | yq eval '.data["runtime.yaml"] = load_str("/tmp/runtime.yaml")' \ + | kubectl apply -f - +done diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_deployment.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_deployment.yaml new file mode 100644 index 000000000..26f3576b7 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_deployment.yaml @@ -0,0 +1,70 @@ +{{- define "app-proxy.resources.deployment" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "app-proxy.fullname" . }} + labels: + {{- include "app-proxy.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicasCount }} + strategy: + type: {{ .Values.updateStrategy.type }} + selector: + matchLabels: + {{- include "app-proxy.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "app-proxy.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "app-proxy.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: app-proxy + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + env: + {{- include "app-proxy.environment-variables" . | nindent 8 }} + ports: + - name: http + containerPort: 3000 + readinessProbe: + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + httpGet: + path: /health + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + volumes: + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_env-vars.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_env-vars.yaml new file mode 100644 index 000000000..c9b9a0e36 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_env-vars.yaml @@ -0,0 +1,19 @@ +{{- define "app-proxy.environment-variables.defaults" }} +PORT: 3000 +{{- end }} + +{{- define "app-proxy.environment-variables.calculated" }} +CODEFRESH_HOST: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} +{{- with .Values.ingress.pathPrefix }} +API_PATH_PREFIX: {{ . | quote }} +{{- end }} +{{- end }} + +{{- define "app-proxy.environment-variables" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- $defaults := (include "app-proxy.environment-variables.defaults" . | fromYaml) }} +{{- $calculated := (include "app-proxy.environment-variables.calculated" . | fromYaml) }} +{{- $overrides := .Values.env }} +{{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} +{{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_helpers.tpl b/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_helpers.tpl new file mode 100644 index 000000000..2d4272ca9 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_helpers.tpl @@ -0,0 +1,43 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "app-proxy.name" -}} + {{- printf "%s-%s" (include "cf-runtime.name" .) "app-proxy" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "app-proxy.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "app-proxy" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "app-proxy.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: app-proxy +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "app-proxy.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: app-proxy +{{- end }} + + +{{/* +Create the name of the service account to use +*/}} +{{- define "app-proxy.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "app-proxy.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_ingress.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_ingress.yaml new file mode 100644 index 000000000..d7860b363 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_ingress.yaml @@ -0,0 +1,32 @@ +{{- define "app-proxy.resources.ingress" -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "app-proxy.fullname" . }} + labels: {{- include "app-proxy.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.class (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.class }} + {{- end }} + {{- if .Values.ingress.tlsSecret }} + tls: + - hosts: + - {{ .Values.ingress.host }} + secretName: {{ .Values.tlsSecret }} + {{- end }} + rules: + - host: {{ .Values.ingress.host }} + http: + paths: + - path: {{ .Values.ingress.pathPrefix | default "/" }} + pathType: ImplementationSpecific + backend: + service: + name: {{ include "app-proxy.fullname" . }} + port: + number: 80 +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_rbac.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_rbac.yaml new file mode 100644 index 000000000..87bd869ba --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_rbac.yaml @@ -0,0 +1,47 @@ +{{- define "app-proxy.resources.rbac" -}} +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "app-proxy.serviceAccountName" . }} + labels: + {{- include "app-proxy.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if .Values.rbac.create }} +kind: {{ .Values.rbac.namespaced | ternary "Role" "ClusterRole" }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "app-proxy.fullname" . }} + labels: + {{- include "app-proxy.labels" . | nindent 4 }} +rules: + - apiGroups: [ "" ] + resources: [ "secrets" ] + verbs: [ "get" ] +{{- with .Values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +kind: {{ .Values.rbac.namespaced | ternary "RoleBinding" "ClusterRoleBinding" }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "app-proxy.fullname" . }} + labels: + {{- include "app-proxy.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "app-proxy.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: Role + name: {{ include "app-proxy.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_service.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_service.yaml new file mode 100644 index 000000000..4c3a93bf2 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/app-proxy/_service.yaml @@ -0,0 +1,17 @@ +{{- define "app-proxy.resources.service" -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "app-proxy.fullname" . }} + labels: + {{- include "app-proxy.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 3000 + selector: + {{- include "app-proxy.selectorLabels" . | nindent 4 }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_deployment.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_deployment.yaml new file mode 100644 index 000000000..62588b4d3 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_deployment.yaml @@ -0,0 +1,62 @@ +{{- define "event-exporter.resources.deployment" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "event-exporter.fullname" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicasCount }} + strategy: + type: {{ .Values.updateStrategy.type }} + selector: + matchLabels: + {{- include "event-exporter.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "event-exporter.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "event-exporter.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: event-exporter + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + args: [--running-in-cluster=true] + env: + {{- include "event-exporter.environment-variables" . | nindent 8 }} + ports: + - name: metrics + containerPort: 9102 + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + volumes: + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_env-vars.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_env-vars.yaml new file mode 100644 index 000000000..d28d0776f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_env-vars.yaml @@ -0,0 +1,14 @@ +{{- define "event-exporter.environment-variables.defaults" }} +{{- end }} + +{{- define "event-exporter.environment-variables.calculated" }} +{{- end }} + +{{- define "event-exporter.environment-variables" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- $defaults := (include "event-exporter.environment-variables.defaults" . | fromYaml) }} +{{- $calculated := (include "event-exporter.environment-variables.calculated" . | fromYaml) }} +{{- $overrides := .Values.env }} +{{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} +{{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_helpers.tpl b/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_helpers.tpl new file mode 100644 index 000000000..5b8b5eff7 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_helpers.tpl @@ -0,0 +1,43 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "event-exporter.name" -}} + {{- printf "%s-%s" (include "cf-runtime.name" .) "event-exporter" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "event-exporter.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "event-exporter" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "event-exporter.labels" -}} +{{ include "cf-runtime.labels" . }} +app: event-exporter +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "event-exporter.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +app: event-exporter +{{- end }} + + +{{/* +Create the name of the service account to use +*/}} +{{- define "event-exporter.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "event-exporter.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_rbac.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_rbac.yaml new file mode 100644 index 000000000..69d7b6b2f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_rbac.yaml @@ -0,0 +1,47 @@ +{{- define "event-exporter.resources.rbac" -}} +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "event-exporter.serviceAccountName" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if .Values.rbac.create }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "event-exporter.fullname" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: [events] + verbs: [get, list, watch] +{{- with .Values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "event-exporter.fullname" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "event-exporter.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ include "event-exporter.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_service.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_service.yaml new file mode 100644 index 000000000..6fa29ec1a --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_service.yaml @@ -0,0 +1,17 @@ +{{- define "event-exporter.resources.service" -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "event-exporter.fullname" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - name: metrics + port: 9102 + targetPort: metrics + protocol: TCP + selector: + {{- include "event-exporter.selectorLabels" . | nindent 4 }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_serviceMontor.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_serviceMontor.yaml new file mode 100644 index 000000000..6092443f0 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/event-exporter/_serviceMontor.yaml @@ -0,0 +1,14 @@ +{{- define "event-exporter.resources.serviceMonitor" -}} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "event-exporter.fullname" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} +spec: + endpoints: + - port: metrics + selector: + matchLabels: + {{- include "event-exporter.selectorLabels" . | nindent 6 }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_deployment.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_deployment.yaml new file mode 100644 index 000000000..7efa6557b --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_deployment.yaml @@ -0,0 +1,70 @@ +{{- define "monitor.resources.deployment" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "monitor.fullname" . }} + labels: + {{- include "monitor.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicasCount }} + strategy: + type: {{ .Values.updateStrategy.type }} + selector: + matchLabels: + {{- include "monitor.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "monitor.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "monitor.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: monitor + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + env: + {{- include "monitor.environment-variables" . | nindent 8 }} + ports: + - name: http + containerPort: 9020 + readinessProbe: + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + httpGet: + path: /api/ping + port: 9020 + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + volumes: + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_env-vars.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_env-vars.yaml new file mode 100644 index 000000000..f58c7fa25 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_env-vars.yaml @@ -0,0 +1,26 @@ +{{- define "monitor.environment-variables.defaults" }} +SERVICE_NAME: {{ include "monitor.fullname" . }} +PORT: 9020 +HELM3: true +NODE_OPTIONS: "--max_old_space_size=4096" +{{- end }} + +{{- define "monitor.environment-variables.calculated" }} +API_TOKEN: {{ include "runtime.installation-token-env-var-value" . | nindent 2 }} +CLUSTER_ID: {{ include "runtime.runtime-environment-spec.context-name" . }} +API_URL: {{ include "runtime.runtime-environment-spec.codefresh-host" . }}/api/k8s-monitor/events +ACCOUNT_ID: {{ .Values.global.accountId }} +NAMESPACE: {{ .Release.Namespace }} +{{- if .Values.rbac.namespaced }} +ROLE_BINDING: true +{{- end }} +{{- end }} + +{{- define "monitor.environment-variables" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- $defaults := (include "monitor.environment-variables.defaults" . | fromYaml) }} +{{- $calculated := (include "monitor.environment-variables.calculated" . | fromYaml) }} +{{- $overrides := .Values.env }} +{{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} +{{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_helpers.tpl b/charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_helpers.tpl new file mode 100644 index 000000000..71cc1c027 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_helpers.tpl @@ -0,0 +1,42 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "monitor.name" -}} + {{- printf "%s-%s" (include "cf-runtime.name" .) "monitor" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "monitor.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "monitor" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "monitor.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: monitor +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "monitor.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: monitor +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "monitor.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "monitor.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_rbac.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_rbac.yaml new file mode 100644 index 000000000..88204796a --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_rbac.yaml @@ -0,0 +1,56 @@ +{{- define "monitor.resources.rbac" -}} +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "monitor.serviceAccountName" . }} + labels: + {{- include "monitor.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if .Values.rbac.create }} +kind: {{ .Values.rbac.namespaced | ternary "Role" "ClusterRole" }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "monitor.fullname" . }} + labels: + {{- include "monitor.labels" . | nindent 4 }} +rules: + - apiGroups: [ "" ] + resources: [ "*" ] + verbs: [ "get", "list", "watch", "create", "delete" ] + - apiGroups: [ "" ] + resources: [ "pods" ] + verbs: [ "get", "list", "watch", "create", "deletecollection" ] + - apiGroups: [ "extensions" ] + resources: [ "*" ] + verbs: [ "get", "list", "watch" ] + - apiGroups: [ "apps" ] + resources: [ "*" ] + verbs: [ "get", "list", "watch" ] +{{- with .Values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +kind: {{ .Values.rbac.namespaced | ternary "RoleBinding" "ClusterRoleBinding" }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "monitor.fullname" . }} + labels: + {{- include "monitor.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "monitor.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: {{ .Values.rbac.namespaced | ternary "Role" "ClusterRole" }} + name: {{ include "monitor.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_service.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_service.yaml new file mode 100644 index 000000000..f6ae9bb0f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/monitor/_service.yaml @@ -0,0 +1,17 @@ +{{- define "monitor.resources.service" -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "monitor.fullname" . }} + labels: + {{- include "monitor.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 9020 + selector: + {{- include "monitor.selectorLabels" . | nindent 4 }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/_deployment.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/_deployment.yaml new file mode 100644 index 000000000..e1fb9439a --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/_deployment.yaml @@ -0,0 +1,103 @@ +{{- define "runner.resources.deployment" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "runner.fullname" . }} + labels: + {{- include "runner.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicasCount }} + strategy: + type: {{ .Values.updateStrategy.type }} + selector: + matchLabels: + {{- include "runner.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "runner.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "runner.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + initContainers: + - name: init + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.init.image "context" .) }} + imagePullPolicy: {{ .Values.init.image.pullPolicy | default "IfNotPresent" }} + command: + - /bin/bash + args: + - -ec + - | {{ .Files.Get "files/init-runtime.sh" | nindent 10 }} + env: + {{- include "runner-init.environment-variables" . | nindent 8 }} + {{- with .Values.init.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + containers: + - name: runner + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "IfNotPresent" }} + env: + {{- include "runner.environment-variables" . | nindent 8 }} + ports: + - name: http + containerPort: 8080 + readinessProbe: + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + httpGet: + path: /health + port: http + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- with .Values.extraVolumeMounts }} + volumeMounts: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.sidecar.enabled }} + - name: reconcile-runtime + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.sidecar.image "context" .) }} + imagePullPolicy: {{ .Values.sidecar.image.pullPolicy | default "IfNotPresent" }} + command: + - /bin/bash + args: + - -ec + - | {{ .Files.Get "files/reconcile-runtime.sh" | nindent 10 }} + env: + {{- include "runner-sidecar.environment-variables" . | nindent 8 }} + {{- with .Values.sidecar.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.extraVolumes }} + volumes: + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/_helpers.tpl b/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/_helpers.tpl new file mode 100644 index 000000000..2608cb67e --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/_helpers.tpl @@ -0,0 +1,42 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "runner.name" -}} + {{- printf "%s-%s" (include "cf-runtime.name" .) "runner" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "runner.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "runner" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "runner.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: runner +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "runner.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: runner +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "runner.serviceAccountName" -}} + {{- if .Values.serviceAccount.create }} + {{- default (include "runner.fullname" .) .Values.serviceAccount.name }} + {{- else }} + {{- default "default" .Values.serviceAccount.name }} + {{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/_rbac.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/_rbac.yaml new file mode 100644 index 000000000..d95b958d5 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/_rbac.yaml @@ -0,0 +1,53 @@ +{{- define "runner.resources.rbac" -}} +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "runner.serviceAccountName" . }} + labels: + {{- include "runner.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if .Values.rbac.create }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "runner.fullname" . }} + labels: + {{- include "runner.labels" . | nindent 4 }} +rules: + - apiGroups: [ "" ] + resources: [ "pods", "persistentvolumeclaims" ] + verbs: [ "get", "create", "delete", patch ] + - apiGroups: [ "" ] + resources: [ "configmaps", "secrets" ] + verbs: [ "get", "create", "update", patch ] + - apiGroups: [ "apps" ] + resources: [ "deployments" ] + verbs: [ "get" ] +{{- with .Values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "runner.fullname" . }} + labels: + {{- include "runner.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "runner.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: Role + name: {{ include "runner.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/environment-variables/_init-container.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/environment-variables/_init-container.yaml new file mode 100644 index 000000000..6dda110f7 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/environment-variables/_init-container.yaml @@ -0,0 +1,30 @@ +{{- define "runner-init.environment-variables.defaults" }} +HOME: /tmp +{{- end }} + +{{- define "runner-init.environment-variables.calculated" }} +AGENT_NAME: {{ include "runtime.runtime-environment-spec.agent-name" . }} +API_HOST: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} +AGENT_CODEFRESH_TOKEN: + valueFrom: + secretKeyRef: + name: {{ include "runner.fullname" . }} + key: agent-codefresh-token + optional: true +EXISTING_AGENT_CODEFRESH_TOKEN: {{ include "runtime.agent-token-env-var-value" . | nindent 2 }} +KUBE_CONTEXT: {{ include "runtime.runtime-environment-spec.context-name" . }} +KUBE_NAMESPACE: {{ .Release.Namespace }} +OWNER_NAME: {{ include "runner.fullname" . }} +RUNTIME_NAME: {{ include "runtime.runtime-environment-spec.runtime-name" . }} +SECRET_NAME: {{ include "runner.fullname" . }} +USER_CODEFRESH_TOKEN: {{ include "runtime.installation-token-env-var-value" . | nindent 2 }} +{{- end }} + +{{- define "runner-init.environment-variables" }} + {{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} + {{- $defaults := (include "runner-init.environment-variables.defaults" . | fromYaml) }} + {{- $calculated := (include "runner-init.environment-variables.calculated" . | fromYaml) }} + {{- $overrides := .Values.env }} + {{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/environment-variables/_main-container.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/environment-variables/_main-container.yaml new file mode 100644 index 000000000..4d3f0304e --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/environment-variables/_main-container.yaml @@ -0,0 +1,28 @@ +{{- define "runner.environment-variables.defaults" }} +AGENT_MODE: InCluster +SELF_DEPLOYMENT_NAME: + valueFrom: + fieldRef: + fieldPath: metadata.name +{{- end }} + +{{- define "runner.environment-variables.calculated" }} +AGENT_ID: {{ include "runtime.runtime-environment-spec.agent-name" . }} +CODEFRESH_HOST: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} +CODEFRESH_IN_CLUSTER_RUNTIME: {{ include "runtime.runtime-environment-spec.runtime-name" . }} +CODEFRESH_TOKEN: + valueFrom: + secretKeyRef: + name: {{ include "runner.fullname" . }} + key: agent-codefresh-token +DOCKER_REGISTRY: {{ .Values.global.imageRegistry }} +{{- end }} + +{{- define "runner.environment-variables" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- $defaults := (include "runner.environment-variables.defaults" . | fromYaml) }} +{{- $calculated := (include "runner.environment-variables.calculated" . | fromYaml) }} +{{- $overrides := .Values.env }} +{{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} +{{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/environment-variables/_sidecar-container.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/environment-variables/_sidecar-container.yaml new file mode 100644 index 000000000..3adcbe5d4 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/runner/environment-variables/_sidecar-container.yaml @@ -0,0 +1,22 @@ +{{- define "runner-sidecar.environment-variables.defaults" }} +HOME: /tmp +{{- end }} + +{{- define "runner-sidecar.environment-variables.calculated" }} +API_HOST: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} +USER_CODEFRESH_TOKEN: {{ include "runtime.installation-token-env-var-value" . | nindent 2 }} +KUBE_CONTEXT: {{ include "runtime.runtime-environment-spec.context-name" . }} +KUBE_NAMESPACE: {{ .Release.Namespace }} +OWNER_NAME: {{ include "runner.fullname" . }} +RUNTIME_NAME: {{ include "runtime.runtime-environment-spec.runtime-name" . }} +CONFIGMAP_NAME: {{ printf "%s-%s" (include "runtime.fullname" .) "spec" }} +{{- end }} + +{{- define "runner-sidecar.environment-variables" }} + {{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} + {{- $defaults := (include "runner-sidecar.environment-variables.defaults" . | fromYaml) }} + {{- $calculated := (include "runner-sidecar.environment-variables.calculated" . | fromYaml) }} + {{- $overrides := .Values.sidecar.env }} + {{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_cronjob.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_cronjob.yaml new file mode 100644 index 000000000..20bd2d56e --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_cronjob.yaml @@ -0,0 +1,58 @@ +{{- define "dind-volume-provisioner.resources.cronjob" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- if not (eq .Values.storage.backend "local") }} +apiVersion: batch/v1 +kind: CronJob +metadata: + name: {{ include "dind-volume-cleanup.fullname" . }} + labels: + {{- include "dind-volume-cleanup.labels" . | nindent 4 }} +spec: + concurrencyPolicy: {{ .Values.concurrencyPolicy }} + schedule: {{ .Values.schedule | quote }} + successfulJobsHistoryLimit: {{ .Values.successfulJobsHistory }} + failedJobsHistoryLimit: {{ .Values.failedJobsHistory }} + {{- with .Values.suspend }} + suspend: {{ . }} + {{- end }} + jobTemplate: + spec: + template: + metadata: + labels: + {{- include "dind-volume-cleanup.selectorLabels" . | nindent 12 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 12 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 10 }} + serviceAccountName: {{ include "dind-volume-provisioner.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + restartPolicy: {{ .Values.restartPolicy | default "Never" }} + containers: + - name: dind-volume-cleanup + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + env: + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" .Values.env "context" .) | nindent 12 }} + - name: PROVISIONED_BY + value: {{ include "dind-volume-provisioner.volumeProvisionerName" . }} + resources: + {{- toYaml .Values.resources | nindent 14 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_daemonset.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_daemonset.yaml new file mode 100644 index 000000000..cb463231d --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_daemonset.yaml @@ -0,0 +1,98 @@ +{{- define "dind-volume-provisioner.resources.daemonset" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $localVolumeParentDir := .Values.storage.local.volumeParentDir }} +{{- if eq .Values.storage.backend "local" }} +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "dind-lv-monitor.fullname" . }} + labels: + {{- include "dind-lv-monitor.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "dind-lv-monitor.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "dind-lv-monitor.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "dind-volume-provisioner.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.volumePermissions.enabled }} + initContainers: + - name: volume-permissions + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.volumePermissions.image "context" .) }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | default "Always" }} + command: + - /bin/sh + args: + - -ec + - | + chown -R {{ .Values.podSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} {{ $localVolumeParentDir }} + volumeMounts: + - mountPath: {{ $localVolumeParentDir }} + name: dind-volume-dir + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + securityContext: {{- omit .Values.volumePermissions.securityContext "runAsUser" | toYaml | nindent 10 }} + {{- else }} + securityContext: {{- .Values.volumePermissions.securityContext | toYaml | nindent 10 }} + {{- end }} + resources: + {{- toYaml .Values.volumePermissions.resources | nindent 10 }} + {{- end }} + containers: + - name: dind-lv-monitor + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 10 }} + {{- end }} + command: + - /home/dind-volume-utils/bin/local-volumes-agent + env: + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" .Values.env "context" .) | nindent 10 }} + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: VOLUME_PARENT_DIR + value: {{ $localVolumeParentDir }} + resources: + {{- toYaml .Values.resources | nindent 10 }} + volumeMounts: + - mountPath: {{ $localVolumeParentDir }} + readOnly: false + name: dind-volume-dir + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + volumes: + - name: dind-volume-dir + hostPath: + path: {{ $localVolumeParentDir }} + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_deployment.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_deployment.yaml new file mode 100644 index 000000000..9252b4520 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_deployment.yaml @@ -0,0 +1,67 @@ +{{- define "dind-volume-provisioner.resources.deployment" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "dind-volume-provisioner.fullname" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicasCount }} + strategy: + type: {{ .Values.updateStrategy.type }} + selector: + matchLabels: + {{- include "dind-volume-provisioner.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "dind-volume-provisioner.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "dind-volume-provisioner.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: dind-volume-provisioner + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + command: + - /usr/local/bin/dind-volume-provisioner + - -v=4 + - --resync-period=50s + env: + {{- include "dind-volume-provisioner.environment-variables" . | nindent 8 }} + ports: + - name: http + containerPort: 8080 + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + {{- include "dind-volume-provisioner.volumeMounts.calculated" . | nindent 8 }} + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + volumes: + {{- include "dind-volume-provisioner.volumes.calculated" . | nindent 6 }} + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_env-vars.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_env-vars.yaml new file mode 100644 index 000000000..e1f5dfe60 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_env-vars.yaml @@ -0,0 +1,88 @@ +{{- define "dind-volume-provisioner.environment-variables.defaults" }} +{{- end }} + +{{- define "dind-volume-provisioner.environment-variables.calculated" }} +DOCKER_REGISTRY: {{ .Values.global.imageRegistry }} +PROVISIONER_NAME: {{ include "dind-volume-provisioner.volumeProvisionerName" . }} + +{{- if or .Values.storage.ebs.accessKeyId .Values.storage.ebs.accessKeyIdSecretKeyRef }} +AWS_ACCESS_KEY_ID: + {{- if .Values.storage.ebs.accessKeyId }} + valueFrom: + secretKeyRef: + name: {{ include "dind-volume-provisioner.fullname" . }} + key: aws_access_key_id + {{- else if .Values.storage.ebs.accessKeyIdSecretKeyRef }} + valueFrom: + secretKeyRef: + {{- .Values.storage.ebs.accessKeyIdSecretKeyRef | toYaml | nindent 6 }} + {{- end }} +{{- end }} + +{{- if or .Values.storage.ebs.secretAccessKey .Values.storage.ebs.secretAccessKeySecretKeyRef }} +AWS_SECRET_ACCESS_KEY: + {{- if .Values.storage.ebs.secretAccessKey }} + valueFrom: + secretKeyRef: + name: {{ include "dind-volume-provisioner.fullname" . }} + key: aws_secret_access_key + {{- else if .Values.storage.ebs.secretAccessKeySecretKeyRef }} + valueFrom: + secretKeyRef: + {{- .Values.storage.ebs.secretAccessKeySecretKeyRef | toYaml | nindent 6 }} + {{- end }} +{{- end }} + +{{- if or .Values.storage.gcedisk.serviceAccountJson .Values.storage.gcedisk.serviceAccountJsonSecretKeyRef }} +GOOGLE_APPLICATION_CREDENTIALS: {{ printf "/etc/dind-volume-provisioner/credentials/%s" (.Values.storage.gcedisk.serviceAccountJsonSecretKeyRef.key | default "google-service-account.json") }} +{{- end }} + +{{- if and .Values.storage.mountAzureJson }} +AZURE_CREDENTIAL_FILE: /etc/kubernetes/azure.json +CLOUDCONFIG_AZURE: /etc/kubernetes/azure.json +{{- end }} + +{{- end }} + +{{- define "dind-volume-provisioner.environment-variables" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- $defaults := (include "dind-volume-provisioner.environment-variables.defaults" . | fromYaml) }} +{{- $calculated := (include "dind-volume-provisioner.environment-variables.calculated" . | fromYaml) }} +{{- $overrides := .Values.env }} +{{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} +{{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} + + +{{- define "dind-volume-provisioner.volumes.calculated" }} + {{- if .Values.storage.gcedisk.serviceAccountJson }} +- name: credentials + secret: + secretName: {{ include "dind-volume-provisioner.fullname" . }} + optional: true + {{- else if .Values.storage.gcedisk.serviceAccountJsonSecretKeyRef }} +- name: credentials + secret: + secretName: {{ .Values.storage.gcedisk.serviceAccountJsonSecretKeyRef.name }} + optional: true + {{- end }} + {{- if .Values.storage.mountAzureJson }} +- name: azure-json + hostPath: + path: /etc/kubernetes/azure.json + type: File + {{- end }} +{{- end }} + +{{- define "dind-volume-provisioner.volumeMounts.calculated" }} + {{- if or .Values.storage.gcedisk.serviceAccountJson .Values.storage.gcedisk.serviceAccountJsonSecretKeyRef }} +- name: credentials + readOnly: true + mountPath: "/etc/dind-volume-provisioner/credentials" + {{- end }} + {{- if .Values.storage.mountAzureJson }} +- name: azure-json + readOnly: true + mountPath: "/etc/kubernetes/azure.json" + {{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_helpers.tpl b/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_helpers.tpl new file mode 100644 index 000000000..e3d3a0d3f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_helpers.tpl @@ -0,0 +1,93 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "dind-volume-provisioner.name" -}} + {{- printf "%s-%s" (include "cf-runtime.name" .) "volume-provisioner" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "dind-volume-provisioner.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "volume-provisioner" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{- define "dind-volume-cleanup.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "volume-cleanup" | trunc 52 | trimSuffix "-" }} +{{- end }} + +{{- define "dind-lv-monitor.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "lv-monitor" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Provisioner name for storage class +*/}} +{{- define "dind-volume-provisioner.volumeProvisionerName" }} + {{- printf "codefresh.io/dind-volume-provisioner-runner-%s" .Release.Namespace }} +{{- end }} + +{{/* +Common labels for dind-lv-monitor +*/}} +{{- define "dind-lv-monitor.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: lv-monitor +{{- end }} + +{{/* +Selector labels for dind-lv-monitor +*/}} +{{- define "dind-lv-monitor.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: lv-monitor +{{- end }} + +{{/* +Common labels for dind-volume-provisioner +*/}} +{{- define "dind-volume-provisioner.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: volume-provisioner +{{- end }} + +{{/* +Selector labels for dind-volume-provisioner +*/}} +{{- define "dind-volume-provisioner.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: volume-provisioner +{{- end }} + +{{/* +Common labels for dind-volume-cleanup +*/}} +{{- define "dind-volume-cleanup.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: pv-cleanup +{{- end }} + +{{/* +Common labels for dind-volume-cleanup +*/}} +{{- define "dind-volume-cleanup.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: pv-cleanup +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "dind-volume-provisioner.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "dind-volume-provisioner.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{- define "dind-volume-provisioner.storageClassName" }} +{{- printf "dind-local-volumes-runner-%s" .Release.Namespace }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_rbac.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_rbac.yaml new file mode 100644 index 000000000..fbcbc684f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_rbac.yaml @@ -0,0 +1,71 @@ +{{- define "dind-volume-provisioner.resources.rbac" -}} +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "dind-volume-provisioner.serviceAccountName" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if .Values.rbac.create }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "dind-volume-provisioner.fullname" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} +rules: + - apiGroups: [ "" ] + resources: [ "persistentvolumes" ] + verbs: [ "get", "list", "watch", "create", "delete", "patch" ] + - apiGroups: [ "" ] + resources: [ "persistentvolumeclaims" ] + verbs: [ "get", "list", "watch", "update", "delete" ] + - apiGroups: [ "storage.k8s.io" ] + resources: [ "storageclasses" ] + verbs: [ "get", "list", "watch" ] + - apiGroups: [ "" ] + resources: [ "events" ] + verbs: [ "list", "watch", "create", "update", "patch" ] + - apiGroups: [ "" ] + resources: [ "secrets" ] + verbs: [ "get", "list" ] + - apiGroups: [ "" ] + resources: [ "nodes" ] + verbs: [ "get", "list", "watch" ] + - apiGroups: [ "" ] + resources: [ "pods" ] + verbs: [ "get", "list", "watch", "create", "delete", "patch" ] + - apiGroups: [ "" ] + resources: [ "endpoints" ] + verbs: [ "get", "list", "watch", "create", "update", "delete" ] + - apiGroups: [ "coordination.k8s.io" ] + resources: [ "leases" ] + verbs: [ "get", "create", "update" ] +{{- with .Values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "dind-volume-provisioner.fullname" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "dind-volume-provisioner.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ include "dind-volume-provisioner.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_secret.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_secret.yaml new file mode 100644 index 000000000..f361a7991 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_secret.yaml @@ -0,0 +1,22 @@ +{{- define "dind-volume-provisioner.resources.secret" -}} +{{- if or .Values.storage.ebs.accessKeyId .Values.storage.ebs.secretAccessKey .Values.storage.gcedisk.serviceAccountJson }} +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ include "dind-volume-provisioner.fullname" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} +stringData: + {{- with .Values.storage.gcedisk.serviceAccountJson }} + google-service-account.json: | +{{- . | nindent 4 }} + {{- end }} + {{- with .Values.storage.ebs.accessKeyId }} + aws_access_key_id: {{ . }} + {{- end }} + {{- with .Values.storage.ebs.secretAccessKey }} + aws_secret_access_key: {{ . }} + {{- end }} +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_storageclass.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_storageclass.yaml new file mode 100644 index 000000000..62e910c87 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_components/volume-provisioner/_storageclass.yaml @@ -0,0 +1,47 @@ +{{- define "dind-volume-provisioner.resources.storageclass" -}} +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + {{/* has to be exactly that */}} + name: {{ include "dind-volume-provisioner.storageClassName" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} +provisioner: {{ include "dind-volume-provisioner.volumeProvisionerName" . }} +parameters: +{{- if eq .Values.storage.backend "local" }} + volumeBackend: local + volumeParentDir: {{ .Values.storage.local.volumeParentDir }} +{{- else if eq .Values.storage.backend "gcedisk" }} + volumeBackend: {{ .Values.storage.backend }} + type: {{ .Values.storage.gcedisk.volumeType | default "pd-ssd" }} + zone: {{ required ".Values.storage.gcedisk.availabilityZone is required" .Values.storage.gcedisk.availabilityZone }} + fsType: {{ .Values.storage.fsType | default "ext4" }} +{{- else if or (eq .Values.storage.backend "ebs") (eq .Values.storage.backend "ebs-csi")}} + volumeBackend: {{ .Values.storage.backend }} + VolumeType: {{ .Values.storage.ebs.volumeType | default "gp3" }} + AvailabilityZone: {{ required ".Values.storage.ebs.availabilityZone is required" .Values.storage.ebs.availabilityZone }} + fsType: {{ .Values.storage.fsType | default "ext4" }} + encrypted: {{ .Values.storage.ebs.encrypted | default "false" | quote }} + {{- with .Values.storage.ebs.kmsKeyId }} + kmsKeyId: {{ . | quote }} + {{- end }} + {{- with .Values.storage.ebs.iops }} + iops: {{ . | quote }} + {{- end }} + {{- with .Values.storage.ebs.throughput }} + throughput: {{ . | quote }} + {{- end }} +{{- else if or (eq .Values.storage.backend "azuredisk") (eq .Values.storage.backend "azuredisk-csi")}} + volumeBackend: {{ .Values.storage.backend }} + kind: managed + skuName: {{ .Values.storage.azuredisk.skuName | default "Premium_LRS" }} + fsType: {{ .Values.storage.fsType | default "ext4" }} + cachingMode: {{ .Values.storage.azuredisk.cachingMode | default "None" }} + {{- with .Values.storage.azuredisk.availabilityZone }} + availabilityZone: {{ . | quote }} + {{- end }} + {{- with .Values.storage.azuredisk.resourceGroup }} + resourceGroup: {{ . | quote }} + {{- end }} +{{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/_helpers.tpl b/charts/codefresh/cf-runtime/6.3.57/templates/_helpers.tpl new file mode 100644 index 000000000..72f44e36a --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/_helpers.tpl @@ -0,0 +1,51 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "cf-runtime.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "cf-runtime.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "cf-runtime.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "cf-runtime.labels" -}} +helm.sh/chart: {{ include "cf-runtime.chart" . }} +{{ include "cf-runtime.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "cf-runtime.selectorLabels" -}} +app.kubernetes.io/name: {{ include "cf-runtime.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/app-proxy/deployment.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/app-proxy/deployment.yaml new file mode 100644 index 000000000..90341b305 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/app-proxy/deployment.yaml @@ -0,0 +1,9 @@ +{{- $appProxyContext := deepCopy . }} +{{- $_ := set $appProxyContext "Values" (get .Values "appProxy") }} +{{- $_ := set $appProxyContext.Values "global" (get .Values "global") }} +{{- $_ := set $appProxyContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $appProxyContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $appProxyContext.Values.enabled }} +{{- include "app-proxy.resources.deployment" $appProxyContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/app-proxy/ingress.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/app-proxy/ingress.yaml new file mode 100644 index 000000000..56ab5e95e --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/app-proxy/ingress.yaml @@ -0,0 +1,9 @@ +{{- $appProxyContext := deepCopy . }} +{{- $_ := set $appProxyContext "Values" (get .Values "appProxy") }} +{{- $_ := set $appProxyContext.Values "global" (get .Values "global") }} +{{- $_ := set $appProxyContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $appProxyContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $appProxyContext.Values.enabled }} +{{- include "app-proxy.resources.ingress" $appProxyContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/app-proxy/rbac.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/app-proxy/rbac.yaml new file mode 100644 index 000000000..4db87dcb4 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/app-proxy/rbac.yaml @@ -0,0 +1,9 @@ +{{- $appProxyContext := deepCopy . }} +{{- $_ := set $appProxyContext "Values" (get .Values "appProxy") }} +{{- $_ := set $appProxyContext.Values "global" (get .Values "global") }} +{{- $_ := set $appProxyContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $appProxyContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $appProxyContext.Values.enabled }} +{{- include "app-proxy.resources.rbac" $appProxyContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/app-proxy/service.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/app-proxy/service.yaml new file mode 100644 index 000000000..0b9d85ec0 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/app-proxy/service.yaml @@ -0,0 +1,9 @@ +{{- $appProxyContext := deepCopy . }} +{{- $_ := set $appProxyContext "Values" (get .Values "appProxy") }} +{{- $_ := set $appProxyContext.Values "global" (get .Values "global") }} +{{- $_ := set $appProxyContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $appProxyContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $appProxyContext.Values.enabled }} +{{- include "app-proxy.resources.service" $appProxyContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/event-exporter/deployment.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/event-exporter/deployment.yaml new file mode 100644 index 000000000..494288240 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/event-exporter/deployment.yaml @@ -0,0 +1,9 @@ +{{- $eventExporterContext := deepCopy . }} +{{- $_ := set $eventExporterContext "Values" (get .Values "event-exporter") }} +{{- $_ := set $eventExporterContext.Values "global" (get .Values "global") }} +{{- $_ := set $eventExporterContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $eventExporterContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $eventExporterContext.Values.enabled }} +{{- include "event-exporter.resources.deployment" $eventExporterContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/event-exporter/rbac.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/event-exporter/rbac.yaml new file mode 100644 index 000000000..6a9bf5c65 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/event-exporter/rbac.yaml @@ -0,0 +1,9 @@ +{{- $eventExporterContext := deepCopy . }} +{{- $_ := set $eventExporterContext "Values" (get .Values "event-exporter") }} +{{- $_ := set $eventExporterContext.Values "global" (get .Values "global") }} +{{- $_ := set $eventExporterContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $eventExporterContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $eventExporterContext.Values.enabled }} +{{- include "event-exporter.resources.rbac" $eventExporterContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/event-exporter/service.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/event-exporter/service.yaml new file mode 100644 index 000000000..c5d856dfe --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/event-exporter/service.yaml @@ -0,0 +1,11 @@ +{{- $eventExporterContext := deepCopy . }} +{{- $_ := set $eventExporterContext "Values" (get .Values "event-exporter") }} +{{- $_ := set $eventExporterContext.Values "global" (get .Values "global") }} +{{- $_ := set $eventExporterContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $eventExporterContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $eventExporterContext.Values.enabled }} +{{- include "event-exporter.resources.service" $eventExporterContext }} +--- +{{- include "event-exporter.resources.serviceMonitor" $eventExporterContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/extra/extra-resources.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/extra/extra-resources.yaml new file mode 100644 index 000000000..1a9777c64 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/extra/extra-resources.yaml @@ -0,0 +1,6 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} + +{{- range .Values.extraResources }} +--- +{{ include (printf "%s.tplrender" $cfCommonTplSemver) (dict "Values" . "context" $) }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/extra/runtime-images-cm.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/extra/runtime-images-cm.yaml new file mode 100644 index 000000000..f269c84b2 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/extra/runtime-images-cm.yaml @@ -0,0 +1,19 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.engine.runtimeImages }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + {{- /* dummy template just to list runtime images */}} + name: {{ include "runtime.fullname" . }}-images + labels: + {{- include "runtime.labels" . | nindent 4 }} + annotations: + {{- with $values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +data: + images: | + {{- range $key, $val := $values }} + image: {{ $val }} + {{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/hooks/post-install/cm-update-runtime.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/hooks/post-install/cm-update-runtime.yaml new file mode 100644 index 000000000..46a306c56 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/hooks/post-install/cm-update-runtime.yaml @@ -0,0 +1,18 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.patch }} +{{- if $values.enabled }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ include "runtime.fullname" . }}-spec + labels: + {{- include "runtime.labels" . | nindent 4 }} + annotations: + {{- with $values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +data: + runtime.yaml: | + {{ include "runtime.runtime-environment-spec.template" . | nindent 4 | trim }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/hooks/post-install/job-gencerts-dind.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/hooks/post-install/job-gencerts-dind.yaml new file mode 100644 index 000000000..4a08a229c --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/hooks/post-install/job-gencerts-dind.yaml @@ -0,0 +1,68 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.gencerts }} +{{- if and $values.enabled }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "runtime.fullname" . }}-gencerts-dind + labels: + {{- include "runtime.labels" . | nindent 4 }} + annotations: + helm.sh/hook: post-install,post-upgrade + helm.sh/hook-weight: "3" + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + {{- with $values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with $values.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ . }} + {{- end }} + {{- with $values.backoffLimit }} + backoffLimit: {{ . | int }} + {{- end }} + template: + metadata: + name: {{ include "runtime.fullname" . }}-gencerts-dind + labels: + {{- include "runtime.labels" . | nindent 8 }} + spec: + {{- if $values.rbac.enabled }} + serviceAccountName: {{ template "runtime.fullname" . }}-gencerts-dind + {{- end }} + securityContext: + {{- toYaml $values.podSecurityContext | nindent 8 }} + containers: + - name: gencerts-dind + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" $values.image "context" .) }} + imagePullPolicy: {{ $values.image.pullPolicy | default "Always" }} + command: + - "/bin/bash" + args: + - -ec + - | {{ .Files.Get "files/configure-dind-certs.sh" | nindent 10 }} + env: + - name: NAMESPACE + value: {{ .Release.Namespace }} + - name: RELEASE + value: {{ .Release.Name }} + - name: CF_API_HOST + value: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} + - name: CF_API_TOKEN + {{- include "runtime.installation-token-env-var-value" . | indent 10}} + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $values.env "context" .) | nindent 8 }} + {{- with $values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + restartPolicy: OnFailure +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/hooks/post-install/job-update-runtime.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/hooks/post-install/job-update-runtime.yaml new file mode 100644 index 000000000..955e882d7 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/hooks/post-install/job-update-runtime.yaml @@ -0,0 +1,77 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.patch }} +{{- if $values.enabled }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "runtime.fullname" . }}-patch + labels: + {{- include "runtime.labels" . | nindent 4 }} + annotations: + helm.sh/hook: post-install,post-upgrade + helm.sh/hook-weight: "5" + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + {{- with $values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with $values.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ . }} + {{- end }} + {{- with $values.backoffLimit }} + backoffLimit: {{ . | int }} + {{- end }} + template: + metadata: + name: {{ include "runtime.fullname" . }}-patch + labels: + {{- include "runtime.labels" . | nindent 8 }} + spec: + securityContext: + {{- toYaml $values.podSecurityContext | nindent 8 }} + containers: + - name: patch-runtime + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" $values.image "context" .) }} + imagePullPolicy: {{ $values.image.pullPolicy | default "Always" }} + command: + - "/bin/bash" + args: + - -ec + - | + codefresh auth create-context --api-key $API_KEY --url $API_HOST + cat /usr/share/extras/runtime.yaml + codefresh get re +{{- if .Values.runtime.agent }} + codefresh patch re -f /usr/share/extras/runtime.yaml +{{- else }} + codefresh patch sys-re -f /usr/share/extras/runtime.yaml +{{- end }} + env: + - name: API_KEY + {{- include "runtime.installation-token-env-var-value" . | indent 10}} + - name: API_HOST + value: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $values.env "context" .) | nindent 8 }} + volumeMounts: + - name: config + mountPath: /usr/share/extras/runtime.yaml + subPath: runtime.yaml + {{- with $values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + restartPolicy: OnFailure + volumes: + - name: config + configMap: + name: {{ include "runtime.fullname" . }}-spec +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/hooks/post-install/rbac-gencerts-dind.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/hooks/post-install/rbac-gencerts-dind.yaml new file mode 100644 index 000000000..4907dac38 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/hooks/post-install/rbac-gencerts-dind.yaml @@ -0,0 +1,37 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.gencerts }} +{{- if and $values.enabled }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "runtime.fullname" . }}-gencerts-dind + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "runtime.fullname" . }}-gencerts-dind + namespace: {{ .Release.Namespace }} +rules: + - apiGroups: + - "" + resources: + - secrets + - configmaps + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "runtime.fullname" . }}-gencerts-dind + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "runtime.fullname" . }}-gencerts-dind +subjects: + - kind: ServiceAccount + name: {{ include "runtime.fullname" . }}-gencerts-dind + namespace: {{ .Release.Namespace }} +{{ end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/hooks/pre-delete/job-cleanup-resources.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/hooks/pre-delete/job-cleanup-resources.yaml new file mode 100644 index 000000000..0e3c7659f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/hooks/pre-delete/job-cleanup-resources.yaml @@ -0,0 +1,73 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.patch }} +{{- if and $values.enabled }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "runtime.fullname" . }}-cleanup + labels: + {{- include "runtime.labels" . | nindent 4 }} + annotations: + helm.sh/hook: pre-delete + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation + {{- with $values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with $values.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ . }} + {{- end }} + {{- with $values.backoffLimit }} + backoffLimit: {{ . | int }} + {{- end }} + template: + metadata: + name: {{ include "runtime.fullname" . }}-cleanup + labels: + {{- include "runtime.labels" . | nindent 8 }} + spec: + {{- if $values.rbac.enabled }} + serviceAccountName: {{ template "runtime.fullname" . }}-cleanup + {{- end }} + securityContext: + {{- toYaml $values.podSecurityContext | nindent 8 }} + containers: + - name: cleanup + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" $values.image "context" .) }} + imagePullPolicy: {{ $values.image.pullPolicy | default "Always" }} + command: + - "/bin/bash" + args: + - -ec + - | {{ .Files.Get "files/cleanup-runtime.sh" | nindent 10 }} + env: + - name: AGENT_NAME + value: {{ include "runtime.runtime-environment-spec.agent-name" . }} + - name: RUNTIME_NAME + value: {{ include "runtime.runtime-environment-spec.runtime-name" . }} + - name: API_HOST + value: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} + - name: API_TOKEN + {{- include "runtime.installation-token-env-var-value" . | indent 10}} + - name: AGENT + value: {{ .Values.runtime.agent | quote }} + - name: AGENT_SECRET_NAME + value: {{ include "runner.fullname" . }} + - name: DIND_SECRET_NAME + value: codefresh-certs-server + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $values.env "context" .) | nindent 8 }} + {{- with $values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + restartPolicy: OnFailure +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/hooks/pre-delete/rbac-cleanup-resources.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/hooks/pre-delete/rbac-cleanup-resources.yaml new file mode 100644 index 000000000..468ec2212 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/hooks/pre-delete/rbac-cleanup-resources.yaml @@ -0,0 +1,46 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.patch }} +{{- if and $values.enabled }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "runtime.fullname" . }}-cleanup + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "runtime.fullname" . }}-cleanup + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed +rules: + - apiGroups: + - "*" + resources: + - "*" + verbs: + - "*" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "runtime.fullname" . }}-cleanup + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "runtime.fullname" . }}-cleanup +subjects: + - kind: ServiceAccount + name: {{ include "runtime.fullname" . }}-cleanup + namespace: {{ .Release.Namespace }} +{{ end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/monitor/deployment.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/monitor/deployment.yaml new file mode 100644 index 000000000..00c9fb2f9 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/monitor/deployment.yaml @@ -0,0 +1,9 @@ +{{- $monitorContext := deepCopy . }} +{{- $_ := set $monitorContext "Values" (get .Values "monitor") }} +{{- $_ := set $monitorContext.Values "global" (get .Values "global") }} +{{- $_ := set $monitorContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $monitorContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $monitorContext.Values.enabled }} +{{- include "monitor.resources.deployment" $monitorContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/monitor/rbac.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/monitor/rbac.yaml new file mode 100644 index 000000000..f9812d565 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/monitor/rbac.yaml @@ -0,0 +1,9 @@ +{{- $monitorContext := deepCopy . }} +{{- $_ := set $monitorContext "Values" (get .Values "monitor") }} +{{- $_ := set $monitorContext.Values "global" (get .Values "global") }} +{{- $_ := set $monitorContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $monitorContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $monitorContext.Values.enabled }} +{{- include "monitor.resources.rbac" $monitorContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/monitor/service.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/monitor/service.yaml new file mode 100644 index 000000000..f99706614 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/monitor/service.yaml @@ -0,0 +1,9 @@ +{{- $monitorContext := deepCopy . }} +{{- $_ := set $monitorContext "Values" (get .Values "monitor") }} +{{- $_ := set $monitorContext.Values "global" (get .Values "global") }} +{{- $_ := set $monitorContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $monitorContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $monitorContext.Values.enabled }} +{{- include "monitor.resources.service" $monitorContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/other/external-secrets.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/other/external-secrets.yaml new file mode 100644 index 000000000..dc24e24e5 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/other/external-secrets.yaml @@ -0,0 +1,2 @@ +{{ $templateName := printf "cf-common-%s.external-secrets" (index .Subcharts "cf-common").Chart.Version }} +{{- include $templateName . -}} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/other/podMonitor.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/other/podMonitor.yaml new file mode 100644 index 000000000..4319b722b --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/other/podMonitor.yaml @@ -0,0 +1,2 @@ +{{ $templateName := printf "cf-common-%s.podMonitor" (index .Subcharts "cf-common").Chart.Version }} +{{- include $templateName . -}} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/other/serviceMonitor.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/other/serviceMonitor.yaml new file mode 100644 index 000000000..29f890fe2 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/other/serviceMonitor.yaml @@ -0,0 +1,2 @@ +{{ $templateName := printf "cf-common-%s.serviceMonitor" (index .Subcharts "cf-common").Chart.Version }} +{{- include $templateName . -}} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/runner/deployment.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/runner/deployment.yaml new file mode 100644 index 000000000..85777c487 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/runner/deployment.yaml @@ -0,0 +1,9 @@ +{{- $runnerContext := deepCopy . }} +{{- $_ := set $runnerContext "Values" (get .Values "runner") }} +{{- $_ := set $runnerContext.Values "global" (get .Values "global") }} +{{- $_ := set $runnerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $runnerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $runnerContext.Values.enabled .Values.runtime.agent }} +{{- include "runner.resources.deployment" $runnerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/runner/rbac.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/runner/rbac.yaml new file mode 100644 index 000000000..d5f8c1323 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/runner/rbac.yaml @@ -0,0 +1,9 @@ +{{- $runnerContext := deepCopy . }} +{{- $_ := set $runnerContext "Values" (get .Values "runner") }} +{{- $_ := set $runnerContext.Values "global" (get .Values "global") }} +{{- $_ := set $runnerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $runnerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $runnerContext.Values.enabled .Values.runtime.agent }} +{{- include "runner.resources.rbac" $runnerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/runtime/_helpers.tpl b/charts/codefresh/cf-runtime/6.3.57/templates/runtime/_helpers.tpl new file mode 100644 index 000000000..6ba04fcc3 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/runtime/_helpers.tpl @@ -0,0 +1,123 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "runtime.name" -}} + {{- printf "%s" (include "cf-runtime.name" .) | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "runtime.fullname" -}} + {{- printf "%s" (include "cf-runtime.fullname" .) | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "runtime.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: runtime +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "runtime.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: runtime +{{- end }} + +{{/* +Return runtime image (classic runtime) with private registry prefix +*/}} +{{- define "runtime.runtimeImageName" -}} + {{- if .registry -}} + {{- $imageName := (trimPrefix "quay.io/" .imageFullName) -}} + {{- printf "%s/%s" .registry $imageName -}} + {{- else -}} + {{- printf "%s" .imageFullName -}} + {{- end -}} +{{- end -}} + +{{/* +Environment variable value of Codefresh installation token +*/}} +{{- define "runtime.installation-token-env-var-value" -}} + {{- if .Values.global.codefreshToken }} +valueFrom: + secretKeyRef: + name: {{ include "runtime.installation-token-secret-name" . }} + key: codefresh-api-token + {{- else if .Values.global.codefreshTokenSecretKeyRef }} +valueFrom: + secretKeyRef: + {{- .Values.global.codefreshTokenSecretKeyRef | toYaml | nindent 4 }} + {{- end }} +{{- end }} + +{{/* +Environment variable value of Codefresh agent token +*/}} +{{- define "runtime.agent-token-env-var-value" -}} + {{- if .Values.global.agentToken }} +{{- printf "%s" .Values.global.agentToken | toYaml }} + {{- else if .Values.global.agentTokenSecretKeyRef }} +valueFrom: + secretKeyRef: + {{- .Values.global.agentTokenSecretKeyRef | toYaml | nindent 4 }} + {{- end }} +{{- end }} + +{{/* +Print Codefresh API token secret name +*/}} +{{- define "runtime.installation-token-secret-name" }} +{{- print "codefresh-user-token" }} +{{- end }} + +{{/* +Print Codefresh host +*/}} +{{- define "runtime.runtime-environment-spec.codefresh-host" }} +{{- if and (not .Values.global.codefreshHost) }} + {{- fail "ERROR: .global.codefreshHost is required" }} +{{- else }} + {{- printf "%s" (trimSuffix "/" .Values.global.codefreshHost) }} +{{- end }} +{{- end }} + +{{/* +Print runtime-environment name +*/}} +{{- define "runtime.runtime-environment-spec.runtime-name" }} +{{- if and (not .Values.global.runtimeName) }} + {{- printf "%s/%s" .Values.global.context .Release.Namespace }} +{{- else }} + {{- printf "%s" .Values.global.runtimeName }} +{{- end }} +{{- end }} + +{{/* +Print agent name +*/}} +{{- define "runtime.runtime-environment-spec.agent-name" }} +{{- if and (not .Values.global.agentName) }} + {{- printf "%s_%s" .Values.global.context .Release.Namespace }} +{{- else }} + {{- printf "%s" .Values.global.agentName }} +{{- end }} +{{- end }} + +{{/* +Print context +*/}} +{{- define "runtime.runtime-environment-spec.context-name" }} +{{- if and (not .Values.global.context) }} + {{- fail "ERROR: .global.context is required" }} +{{- else }} + {{- printf "%s" .Values.global.context }} +{{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/runtime/cm-dind-daemon.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/runtime/cm-dind-daemon.yaml new file mode 100644 index 000000000..fc7f92905 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/runtime/cm-dind-daemon.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + {{- /* has to be a constant */}} + name: codefresh-dind-config + labels: + {{- include "runtime.labels" . | nindent 4 }} +data: + daemon.json: | +{{ coalesce .Values.re.dindDaemon .Values.runtime.dindDaemon | toPrettyJson | indent 4 }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/runtime/rbac.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/runtime/rbac.yaml new file mode 100644 index 000000000..a51b12526 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/runtime/rbac.yaml @@ -0,0 +1,48 @@ +{{ $values := .Values.runtime }} +--- +{{- if or $values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- /* has to be a constant */}} + name: codefresh-engine + labels: + {{- include "runtime.labels" . | nindent 4 }} + {{- with $values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if $values.rbac.create }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: codefresh-engine + labels: + {{- include "runner.labels" . | nindent 4 }} +rules: + - apiGroups: [ "" ] + resources: [ "secrets" ] + verbs: [ "get" ] +{{- with $values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and $values.serviceAccount.create $values.rbac.create }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: codefresh-engine + labels: + {{- include "runner.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: codefresh-engine +roleRef: + kind: Role + name: codefresh-engine + apiGroup: rbac.authorization.k8s.io +{{- end }} + diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/runtime/runtime-env-spec-tmpl.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/runtime/runtime-env-spec-tmpl.yaml new file mode 100644 index 000000000..c0ae0ff82 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/runtime/runtime-env-spec-tmpl.yaml @@ -0,0 +1,211 @@ +{{- define "runtime.runtime-environment-spec.template" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version -}} +{{- $kubeconfigFilePath := (include "runtime.runtime-environment-spec.runtime-name" .) -}} +{{- $name := (include "runtime.runtime-environment-spec.runtime-name" .) -}} +{{- $engineContext := .Values.runtime.engine -}} +{{- $dindContext := .Values.runtime.dind -}} +{{- $imageRegistry := .Values.global.imageRegistry -}} +metadata: + name: {{ include "runtime.runtime-environment-spec.runtime-name" . }} + agent: {{ .Values.runtime.agent }} +runtimeScheduler: + type: KubernetesPod + {{- if $engineContext.image }} + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" $engineContext.image "context" .) | squote }} + {{- end }} + imagePullPolicy: {{ $engineContext.image.pullPolicy }} + {{- with $engineContext.command }} + command: {{- toYaml . | nindent 4 }} + {{- end }} + envVars: + {{- with $engineContext.env }} + {{- range $key, $val := . }} + {{- if or (kindIs "bool" $val) (kindIs "int" $val) (kindIs "float64" $val) }} + {{ $key }}: {{ $val | squote }} + {{- else }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- end }} + COMPOSE_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.COMPOSE_IMAGE) | squote }} + CONTAINER_LOGGER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.CONTAINER_LOGGER_IMAGE) | squote }} + DOCKER_BUILDER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.DOCKER_BUILDER_IMAGE) | squote }} + DOCKER_PULLER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.DOCKER_PULLER_IMAGE) | squote }} + DOCKER_PUSHER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.DOCKER_PUSHER_IMAGE) | squote }} + DOCKER_TAG_PUSHER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.DOCKER_TAG_PUSHER_IMAGE) | squote }} + FS_OPS_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.FS_OPS_IMAGE) | squote }} + GIT_CLONE_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.GIT_CLONE_IMAGE) | squote }} + KUBE_DEPLOY: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.KUBE_DEPLOY) | squote }} + PIPELINE_DEBUGGER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.PIPELINE_DEBUGGER_IMAGE) | squote }} + TEMPLATE_ENGINE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.TEMPLATE_ENGINE) | squote }} + CR_6177_FIXER: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.CR_6177_FIXER) | squote }} + GC_BUILDER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.GC_BUILDER_IMAGE) | squote }} + COSIGN_IMAGE_SIGNER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.COSIGN_IMAGE_SIGNER_IMAGE) | squote }} + {{- with $engineContext.userEnvVars }} + userEnvVars: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $engineContext.workflowLimits }} + workflowLimits: {{- toYaml . | nindent 4 }} + {{- end }} + cluster: + namespace: {{ .Release.Namespace }} + serviceAccount: {{ $engineContext.serviceAccount }} + {{- if .Values.runtime.agent }} + clusterProvider: + accountId: {{ .Values.global.accountId }} + selector: {{ include "runtime.runtime-environment-spec.context-name" . }} + {{- else }} + {{- if .Values.runtime.inCluster }} + inCluster: true + kubeconfigFilePath: null + {{- else }} + name: {{ $name }} + kubeconfigFilePath: {{ printf "/etc/kubeconfig/%s" $kubeconfigFilePath }} + {{- end }} + {{- end }} + {{- with $engineContext.nodeSelector }} + nodeSelector: {{- toYaml . | nindent 6 }} + {{- end }} + {{- with $engineContext.affinity }} + affinity: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $engineContext.tolerations }} + tolerations: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $engineContext.podAnnotations }} + annotations: + {{- range $key, $val := . }} + {{ $key }}: {{ $val | squote }} + {{- end }} + {{- end }} + {{- with $engineContext.podLabels }} + labels: {{- toYaml . | nindent 4 }} + {{- end }} + {{- if $engineContext.schedulerName }} + schedulerName: {{ $engineContext.schedulerName }} + {{- end }} + resources: + {{- if $engineContext.resources}} + {{- toYaml $engineContext.resources | nindent 4 }} + {{- end }} +dockerDaemonScheduler: + type: DindKubernetesPod + {{- if $dindContext.image }} + dindImage: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" $dindContext.image "context" .) | squote }} + {{- end }} + imagePullPolicy: {{ $dindContext.image.pullPolicy }} + {{- with $dindContext.userAccess }} + userAccess: {{ . }} + {{- end }} + {{- with $dindContext.env }} + envVars: + {{- range $key, $val := . }} + {{- if or (kindIs "bool" $val) (kindIs "int" $val) (kindIs "float64" $val) }} + {{ $key }}: {{ $val | squote }} + {{- else }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- end }} + cluster: + namespace: {{ .Release.Namespace }} + serviceAccount: {{ $dindContext.serviceAccount }} + {{- if .Values.runtime.agent }} + clusterProvider: + accountId: {{ .Values.global.accountId }} + selector: {{ include "runtime.runtime-environment-spec.context-name" . }} + {{- else }} + {{- if .Values.runtime.inCluster }} + inCluster: true + kubeconfigFilePath: null + {{- else }} + name: {{ $name }} + kubeconfigFilePath: {{ printf "/etc/kubeconfig/%s" $kubeconfigFilePath }} + {{- end }} + {{- end }} + {{- with $dindContext.nodeSelector }} + nodeSelector: {{- toYaml . | nindent 6 }} + {{- end }} + {{- with $dindContext.affinity }} + affinity: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $dindContext.tolerations }} + tolerations: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $dindContext.podAnnotations }} + annotations: + {{- range $key, $val := . }} + {{ $key }}: {{ $val | squote }} + {{- end }} + {{- end }} + {{- with $dindContext.podLabels }} + labels: {{- toYaml . | nindent 4 }} + {{- end }} + {{- if $dindContext.schedulerName }} + schedulerName: {{ $dindContext.schedulerName }} + {{- end }} + {{- if $dindContext.pvcs }} + pvcs: + {{- range $index, $pvc := $dindContext.pvcs }} + - name: {{ $pvc.name }} + reuseVolumeSelector: {{ $pvc.reuseVolumeSelector | squote }} + reuseVolumeSortOrder: {{ $pvc.reuseVolumeSortOrder }} + storageClassName: {{ include (printf "%v.tplrender" $cfCommonTplSemver) (dict "Values" $pvc.storageClassName "context" $) }} + volumeSize: {{ $pvc.volumeSize }} + {{- with $pvc.annotations }} + annotations: {{ . | toYaml | nindent 8 }} + {{- end }} + {{- end }} + {{- end }} + defaultDindResources: + {{- with $dindContext.resources }} + {{- if not .requests }} + limits: {{- toYaml .limits | nindent 6 }} + requests: null + {{- else }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} + {{- with $dindContext.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ . }} + {{- end }} + {{- with $dindContext.userVolumeMounts }} + userVolumeMounts: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $dindContext.userVolumes }} + userVolumes: {{- toYaml . | nindent 4 }} + {{- end }} + {{- if and (not .Values.runtime.agent) }} + clientCertPath: /etc/ssl/cf/ + volumeMounts: + codefresh-certs-server: + name: codefresh-certs-server + mountPath: /etc/ssl/cf + readOnly: false + volumes: + codefresh-certs-server: + name: codefresh-certs-server + secret: + secretName: codefresh-certs-server + {{- end }} +extends: {{- toYaml .Values.runtime.runtimeExtends | nindent 2 }} + {{- if .Values.runtime.description }} +description: {{ .Values.runtime.description }} + {{- else }} +description: null + {{- end }} +{{- if .Values.global.accountId }} +accountId: {{ .Values.global.accountId }} +{{- end }} +{{- if not .Values.runtime.agent }} +accounts: {{- toYaml .Values.runtime.accounts | nindent 2 }} +{{- end }} +{{- if .Values.appProxy.enabled }} +appProxy: + externalIP: >- + {{ printf "https://%s%s" .Values.appProxy.ingress.host (.Values.appProxy.ingress.pathPrefix | default "/") }} +{{- end }} +{{- if not .Values.runtime.agent }} +systemHybrid: true +{{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/runtime/secret.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/runtime/secret.yaml new file mode 100644 index 000000000..2366d3ccf --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/runtime/secret.yaml @@ -0,0 +1,11 @@ +{{- if and .Values.global.codefreshToken }} +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ include "runtime.installation-token-secret-name" . }} + labels: + {{- include "runtime.labels" . | nindent 4 }} +stringData: + codefresh-api-token: {{ .Values.global.codefreshToken }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/runtime/svc-dind.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/runtime/svc-dind.yaml new file mode 100644 index 000000000..098edb4e8 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/runtime/svc-dind.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + {{- include "runtime.labels" . | nindent 4 }} + app: dind + {{/* has to be a constant */}} + name: dind +spec: + ports: + - name: "dind-port" + port: 1300 + protocol: TCP + clusterIP: None + selector: + app: dind diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/cronjob.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/cronjob.yaml new file mode 100644 index 000000000..db955bc77 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/cronjob.yaml @@ -0,0 +1,11 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values.volumeProvisioner "dind-volume-cleanup") }} +{{- $_ := set $volumeProvisionerContext.Values "serviceAccount" (get .Values.volumeProvisioner "serviceAccount") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "storage" (get .Values "storage") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $volumeProvisionerContext.Values.enabled .Values.volumeProvisioner.enabled }} +{{- include "dind-volume-provisioner.resources.cronjob" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/daemonset.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/daemonset.yaml new file mode 100644 index 000000000..39927149e --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/daemonset.yaml @@ -0,0 +1,11 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values.volumeProvisioner "dind-lv-monitor") }} +{{- $_ := set $volumeProvisionerContext.Values "serviceAccount" (get .Values.volumeProvisioner "serviceAccount") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "storage" (get .Values "storage") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $volumeProvisionerContext.Values.enabled .Values.volumeProvisioner.enabled }} +{{- include "dind-volume-provisioner.resources.daemonset" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/deployment.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/deployment.yaml new file mode 100644 index 000000000..522fa8791 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/deployment.yaml @@ -0,0 +1,10 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values "volumeProvisioner") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "storage" (get .Values "storage") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $volumeProvisionerContext.Values.enabled }} +{{- include "dind-volume-provisioner.resources.deployment" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/rbac.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/rbac.yaml new file mode 100644 index 000000000..f3ae9609f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/rbac.yaml @@ -0,0 +1,9 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values "volumeProvisioner") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $volumeProvisionerContext.Values.enabled }} +{{- include "dind-volume-provisioner.resources.rbac" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/secret.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/secret.yaml new file mode 100644 index 000000000..accf601d1 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/secret.yaml @@ -0,0 +1,10 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values "volumeProvisioner") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "storage" (get .Values "storage") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $volumeProvisionerContext.Values.enabled }} +{{- include "dind-volume-provisioner.resources.secret" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/storageclass.yaml b/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/storageclass.yaml new file mode 100644 index 000000000..77a7602da --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/templates/volume-provisioner/storageclass.yaml @@ -0,0 +1,10 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values "volumeProvisioner") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "storage" (get .Values "storage") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $volumeProvisionerContext.Values.enabled }} +{{- include "dind-volume-provisioner.resources.storageclass" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.57/values.yaml b/charts/codefresh/cf-runtime/6.3.57/values.yaml new file mode 100644 index 000000000..11e4e3a99 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.57/values.yaml @@ -0,0 +1,947 @@ +# -- String to partially override cf-runtime.fullname template (will maintain the release name) +nameOverride: "" +# -- String to fully override cf-runtime.fullname template +fullnameOverride: "" + +# -- Global parameters +# @default -- See below +global: + # -- Global Docker image registry + imageRegistry: "" + # -- Global Docker registry secret names as array + imagePullSecrets: [] + + # -- URL of Codefresh Platform (required!) + codefreshHost: "https://g.codefresh.io" + # -- User token in plain text (required if `global.codefreshTokenSecretKeyRef` is omitted!) + # Ref: https://g.codefresh.io/user/settings (see API Keys) + # Minimal API key scopes: Runner-Installation(read+write), Agent(read+write), Agents(read+write) + codefreshToken: "" + # -- User token that references an existing secret containing API key (required if `global.codefreshToken` is omitted!) + codefreshTokenSecretKeyRef: {} + + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Account ID (required!) + # Can be obtained here https://g.codefresh.io/2.0/account-settings/account-information + accountId: "" + + # -- K8s context name (required!) + context: "" + # E.g. + # context: prod-ue1-runtime-1 + + # -- Agent Name (optional!) + # If omitted, the following format will be used `{{ .Values.global.context }}_{{ .Release.Namespace }}` + agentName: "" + # E.g. + # agentName: prod-ue1-runtime-1 + + # -- Runtime name (optional!) + # If omitted, the following format will be used `{{ .Values.global.context }}/{{ .Release.Namespace }}` + runtimeName: "" + # E.g. + # runtimeName: prod-ue1-runtime-1/namespace + + # -- DEPRECATED Agent token in plain text. + # !!! MUST BE provided if migrating from < 6.x chart version + agentToken: "" + # -- DEPRECATED Agent token that references an existing secret containing API key. + # !!! MUST BE provided if migrating from < 6.x chart version + agentTokenSecretKeyRef: {} + # E.g. + # agentTokenSecretKeyRef: + # name: my-codefresh-agent-secret + # key: codefresh-agent-token + +# DEPRECATED -- Use `.Values.global.imageRegistry` instead +dockerRegistry: "" + +# DEPRECATED -- Use `.Values.runtime` instead +re: {} + +# -- Runner parameters +# @default -- See below +runner: + # -- Enable the runner + enabled: true + # -- Set number of pods + replicasCount: 1 + # -- Upgrade strategy + updateStrategy: + type: RollingUpdate + # -- Set pod annotations + podAnnotations: {} + + # -- Set image + image: + registry: quay.io + repository: codefresh/venona + tag: 1.10.2 + + # -- Init container + init: + image: + registry: quay.io + repository: codefresh/cli + tag: 0.85.0-rootless + + resources: + limits: + memory: 512Mi + cpu: '1' + requests: + memory: 256Mi + cpu: '0.2' + + # -- Sidecar container + # Reconciles runtime spec from Codefresh API for drift detection + sidecar: + enabled: false + image: + registry: quay.io + repository: codefresh/codefresh-shell + tag: 0.0.2 + env: + RECONCILE_INTERVAL: 300 + resources: {} + + # -- Add additional env vars + env: {} + # E.g. + # env: + # WORKFLOW_CONCURRENCY: 50 # The number of workflow creation and termination tasks the Runner can handle in parallel. Defaults to 50 + + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Override service account name + name: "" + # -- Additional service account annotations + annotations: {} + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Add custom rule to the role + rules: [] + + # -- Set security context for the pod + # @default -- See below + podSecurityContext: + enabled: true + runAsUser: 10001 + runAsGroup: 10001 + fsGroup: 10001 + + # -- Readiness probe configuration + # @default -- See below + readinessProbe: + failureThreshold: 5 + initialDelaySeconds: 5 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 5 + + # -- Set requests and limits + resources: {} + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] + # -- Set affinity + affinity: {} + +# -- Volume Provisioner parameters +# @default -- See below +volumeProvisioner: + # -- Enable volume-provisioner + enabled: true + # -- Set number of pods + replicasCount: 1 + # -- Upgrade strategy + updateStrategy: + type: Recreate + # -- Set pod annotations + podAnnotations: {} + + # -- Set image + image: + registry: quay.io + repository: codefresh/dind-volume-provisioner + tag: 1.35.0 + # -- Add additional env vars + env: {} + # E.g. + # env: + # THREADINESS: 4 # The number of PVC requests the dind-volume-provisioner can process in parallel. Defaults to 4 + + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Override service account name + name: "" + # -- Additional service account annotations + annotations: {} + # E.g. + # serviceAccount: + # annotations: + # eks.amazonaws.com/role-arn: "arn:aws:iam:::role/" + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Add custom rule to the role + rules: [] + + # -- Set security context for the pod + # @default -- See below + podSecurityContext: + enabled: true + runAsUser: 3000 + runAsGroup: 3000 + fsGroup: 3000 + + # -- Set node selector + nodeSelector: {} + # -- Set resources + resources: {} + # -- Set tolerations + tolerations: [] + # -- Set affinity + affinity: {} + + # -- `dind-lv-monitor` DaemonSet parameters + # (local volumes cleaner) + # @default -- See below + dind-lv-monitor: + enabled: true + image: + registry: quay.io + repository: codefresh/dind-volume-utils + tag: 1.29.4 + podAnnotations: {} + podSecurityContext: + enabled: true + runAsUser: 1000 + fsGroup: 1000 + containerSecurityContext: {} + env: {} + resources: {} + nodeSelector: {} + tolerations: + - key: 'codefresh/dind' + operator: 'Exists' + effect: 'NoSchedule' + volumePermissions: + enabled: true + image: + registry: docker.io + repository: alpine + tag: 3.18 + resources: {} + securityContext: + runAsUser: 0 # auto + + # `dind-volume-cleanup` CronJob parameters + # (external volumes cleaner) + # @default -- See below + dind-volume-cleanup: + enabled: true + image: + registry: quay.io + repository: codefresh/dind-volume-cleanup + tag: 1.2.0 + env: {} + concurrencyPolicy: Forbid + schedule: "*/10 * * * *" + successfulJobsHistory: 3 + failedJobsHistory: 1 + suspend: false + podAnnotations: {} + podSecurityContext: + enabled: true + fsGroup: 3000 + runAsGroup: 3000 + runAsUser: 3000 + nodeSelector: {} + affinity: {} + tolerations: [] + +# Storage parameters for volume-provisioner +# @default -- See below +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: local + # -- Set filesystem type (`ext4`/`xfs`) + fsType: "ext4" + + # Storage parametrs example for local volumes on the K8S nodes filesystem (i.e. `storage.backend=local`) + # https://kubernetes.io/docs/concepts/storage/volumes/#local + # @default -- See below + local: + # -- Set volume path on the host filesystem + volumeParentDir: /var/lib/codefresh/dind-volumes + + # Storage parameters example for aws ebs disks (i.e. `storage.backend=ebs`/`storage.backend=ebs-csi`) + # https://aws.amazon.com/ebs/ + # https://codefresh.io/docs/docs/installation/codefresh-runner/#aws-backend-volume-configuration + # @default -- See below + ebs: + # -- Set EBS volume type (`gp2`/`gp3`/`io1`) (required) + volumeType: "gp2" + # -- Set EBS volumes availability zone (required) + availabilityZone: "us-east-1a" + # -- Enable encryption (optional) + encrypted: "false" + # -- Set KMS encryption key ID (optional) + kmsKeyId: "" + + # -- Set AWS_ACCESS_KEY_ID for volume-provisioner (optional) + # Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#dind-volume-provisioner-permissions + accessKeyId: "" + # -- Existing secret containing AWS_ACCESS_KEY_ID. + accessKeyIdSecretKeyRef: {} + # E.g. + # accessKeyIdSecretKeyRef: + # name: + # key: + + # -- Set AWS_SECRET_ACCESS_KEY for volume-provisioner (optional) + # Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#dind-volume-provisioner-permissions + secretAccessKey: "" + # -- Existing secret containing AWS_SECRET_ACCESS_KEY + secretAccessKeySecretKeyRef: {} + # E.g. + # secretAccessKeySecretKeyRef: + # name: + # key: + + # E.g. + # ebs: + # volumeType: gp3 + # availabilityZone: us-east-1c + # encrypted: false + # iops: "5000" + # # I/O operations per second. Only effetive when gp3 volume type is specified. + # # Default value - 3000. + # # Max - 16,000 + # throughput: "500" + # # Throughput in MiB/s. Only effective when gp3 volume type is specified. + # # Default value - 125. + # # Max - 1000. + # ebs: + # volumeType: gp2 + # availabilityZone: us-east-1c + # encrypted: true + # kmsKeyId: "1234abcd-12ab-34cd-56ef-1234567890ab" + # accessKeyId: "MYKEYID" + # secretAccessKey: "MYACCESSKEY" + + # Storage parameters example for gce disks + # https://cloud.google.com/compute/docs/disks#pdspecs + # https://codefresh.io/docs/docs/installation/codefresh-runner/#gke-google-kubernetes-engine-backend-volume-configuration + # @default -- See below + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "pd-ssd" + # -- Set GCP volume availability zone + availabilityZone: "us-west1-a" + # -- Set Google SA JSON key for volume-provisioner (optional) + serviceAccountJson: "" + # -- Existing secret containing containing Google SA JSON key for volume-provisioner (optional) + serviceAccountJsonSecretKeyRef: {} + # E.g. + # gcedisk: + # volumeType: pd-ssd + # availabilityZone: us-central1-c + # serviceAccountJson: |- + # { + # "type": "service_account", + # "project_id": "...", + # "private_key_id": "...", + # "private_key": "...", + # "client_email": "...", + # "client_id": "...", + # "auth_uri": "...", + # "token_uri": "...", + # "auth_provider_x509_cert_url": "...", + # "client_x509_cert_url": "..." + # } + + # Storage parameters example for Azure Disks + # https://codefresh.io/docs/docs/installation/codefresh-runner/#install-codefresh-runner-on-azure-kubernetes-service-aks + # @default -- See below + azuredisk: + # -- Set storage type (`Premium_LRS`) + skuName: Premium_LRS + cachingMode: None + # availabilityZone: northeurope-1 + # resourceGroup: + # DiskIOPSReadWrite: 500 + # DiskMBpsReadWrite: 100 + + mountAzureJson: false + +# -- Set runtime parameters +# @default -- See below + +runtime: + # -- Set annotation on engine Service Account + # Ref: https://codefresh.io/docs/docs/administration/codefresh-runner/#injecting-aws-arn-roles-into-the-cluster + serviceAccount: + create: true + annotations: {} + # E.g. + # serviceAccount: + # annotations: + # eks.amazonaws.com/role-arn: "arn:aws:iam:::role/" + + # -- Set parent runtime to inherit. + # Should not be changes. Parent runtime is controlled from Codefresh side. + runtimeExtends: + - system/default/hybrid/k8s_low_limits + # -- Runtime description + description: "" + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Add custom rule to the engine role + rules: [] + + # -- (for On-Premise only) Enable agent + agent: true + # -- (for On-Premise only) Set inCluster runtime + inCluster: true + # -- (for On-Premise only) Assign accounts to runtime (list of account ids) + accounts: [] + + # -- Parameters for DinD (docker-in-docker) pod (aka "runtime" pod). + dind: + # -- Set dind image. + image: + registry: quay.io + repository: codefresh/dind + tag: 26.1.4-1.28.7 # use `latest-rootless/rootless/26.1.4-1.28.7-rootless` tags for rootless-dind + pullPolicy: IfNotPresent + # -- Set dind resources. + resources: + requests: null + limits: + cpu: 400m + memory: 800Mi + # -- PV claim spec parametes. + pvcs: + # -- Default dind PVC parameters + dind: + # -- PVC name prefix. + # Keep `dind` as default! Don't change! + name: dind + # -- PVC storage class name. + # Change ONLY if you need to use storage class NOT from Codefresh volume-provisioner + storageClassName: '{{ include "dind-volume-provisioner.storageClassName" . }}' + # -- PVC size. + volumeSize: 16Gi + # -- PV reuse selector. + # Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#volume-reuse-policy + reuseVolumeSelector: codefresh-app,io.codefresh.accountName + reuseVolumeSortOrder: pipeline_id + # -- PV annotations. + annotations: {} + # E.g.: + # annotations: + # codefresh.io/volume-retention: 7d + # -- Set additional env vars. + env: + DOCKER_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE: true + # -- Set pod annotations. + podAnnotations: {} + # -- Set pod labels. + podLabels: {} + # -- Set node selector. + nodeSelector: {} + # -- Set affinity + affinity: {} + # -- Set tolerations. + tolerations: [] + # -- Set scheduler name. + schedulerName: "" + # -- Set service account for pod. + serviceAccount: codefresh-engine + # -- Keep `true` as default! + userAccess: true + # -- Add extra volumes + userVolumes: {} + # E.g.: + # userVolumes: + # regctl-docker-registry: + # name: regctl-docker-registry + # secret: + # items: + # - key: .dockerconfigjson + # path: config.json + # secretName: regctl-docker-registry + # optional: true + # -- Add extra volume mounts + userVolumeMounts: {} + # E.g.: + # userVolumeMounts: + # regctl-docker-registry: + # name: regctl-docker-registry + # mountPath: /home/appuser/.docker/ + # readOnly: true + + # -- Parameters for Engine pod (aka "pipeline" orchestrator). + engine: + # -- Set image. + image: + registry: quay.io + repository: codefresh/engine + tag: 1.174.7 + pullPolicy: IfNotPresent + # -- Set container command. + command: + - npm + - run + - start + # -- Set resources. + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 1000m + memory: 2048Mi + # -- Set system(base) runtime images. + # @default -- See below. + runtimeImages: + COMPOSE_IMAGE: quay.io/codefresh/compose:v2.28.1-1.5.0 + CONTAINER_LOGGER_IMAGE: quay.io/codefresh/cf-container-logger:1.11.6 + DOCKER_BUILDER_IMAGE: quay.io/codefresh/cf-docker-builder:1.3.13 + DOCKER_PULLER_IMAGE: quay.io/codefresh/cf-docker-puller:8.0.17 + DOCKER_PUSHER_IMAGE: quay.io/codefresh/cf-docker-pusher:6.0.16 + DOCKER_TAG_PUSHER_IMAGE: quay.io/codefresh/cf-docker-tag-pusher:1.3.14 + FS_OPS_IMAGE: quay.io/codefresh/fs-ops:1.2.3 + GIT_CLONE_IMAGE: quay.io/codefresh/cf-git-cloner:10.1.28 + KUBE_DEPLOY: quay.io/codefresh/cf-deploy-kubernetes:16.1.11 + PIPELINE_DEBUGGER_IMAGE: quay.io/codefresh/cf-debugger:1.3.0 + TEMPLATE_ENGINE: quay.io/codefresh/pikolo:0.14.1 + CR_6177_FIXER: 'quay.io/codefresh/alpine:edge' + GC_BUILDER_IMAGE: 'quay.io/codefresh/cf-gc-builder:0.5.3' + COSIGN_IMAGE_SIGNER_IMAGE: 'quay.io/codefresh/cf-cosign-image-signer:2.4.0-cf.1' + # -- Set additional env vars. + env: + # -- Interval to check the exec status in the container-logger + CONTAINER_LOGGER_EXEC_CHECK_INTERVAL_MS: 1000 + # -- Timeout while doing requests to the Docker daemon + DOCKER_REQUEST_TIMEOUT_MS: 30000 + # -- If "true", composition images will be pulled sequentially + FORCE_COMPOSE_SERIAL_PULL: false + # -- Level of logging for engine + LOGGER_LEVEL: debug + # -- Enable debug-level logging of outgoing HTTP/HTTPS requests + LOG_OUTGOING_HTTP_REQUESTS: false + # -- Enable emitting metrics from engine + METRICS_PROMETHEUS_ENABLED: true + # -- Enable legacy metrics + METRICS_PROMETHEUS_ENABLE_LEGACY_METRICS: false + # -- Enable collecting process metrics + METRICS_PROMETHEUS_COLLECT_PROCESS_METRICS: false + # -- Host for Prometheus metrics server + METRICS_PROMETHEUS_HOST: '0.0.0.0' + # -- Port for Prometheus metrics server + METRICS_PROMETHEUS_PORT: 9100 + # -- Set workflow limits. + workflowLimits: + # -- Maximum time allowed to the engine to wait for the pre-steps (aka "Initializing Process") to succeed; seconds. + MAXIMUM_ALLOWED_TIME_BEFORE_PRE_STEPS_SUCCESS: 600 + # -- Maximum time for workflow execution; seconds. + MAXIMUM_ALLOWED_WORKFLOW_AGE_BEFORE_TERMINATION: 86400 + # -- Maximum time allowed to workflow to spend in "elected" state; seconds. + MAXIMUM_ELECTED_STATE_AGE_ALLOWED: 900 + # -- Maximum retry attempts allowed for workflow. + MAXIMUM_RETRY_ATTEMPTS_ALLOWED: 20 + # -- Maximum time allowed to workflow to spend in "terminating" state until force terminated; seconds. + MAXIMUM_TERMINATING_STATE_AGE_ALLOWED: 900 + # -- Maximum time allowed to workflow to spend in "terminating" state without logs activity until force terminated; seconds. + MAXIMUM_TERMINATING_STATE_AGE_ALLOWED_WITHOUT_UPDATE: 300 + # -- Time since the last health check report after which workflow is terminated; seconds. + TIME_ENGINE_INACTIVE_UNTIL_TERMINATION: 300 + # -- Time since the last health check report after which the engine is considered unhealthy; seconds. + TIME_ENGINE_INACTIVE_UNTIL_UNHEALTHY: 60 + # -- Time since the last workflow logs activity after which workflow is terminated; seconds. + TIME_INACTIVE_UNTIL_TERMINATION: 2700 + # -- Set pod annotations. + podAnnotations: {} + # -- Set pod labels. + podLabels: {} + # -- Set node selector. + nodeSelector: {} + # -- Set affinity + affinity: {} + # -- Set tolerations. + tolerations: [] + # -- Set scheduler name. + schedulerName: "" + # -- Set service account for pod. + serviceAccount: codefresh-engine + # -- Set extra env vars + userEnvVars: [] + # E.g. + # userEnvVars: + # - name: GITHUB_TOKEN + # valueFrom: + # secretKeyRef: + # name: github-token + # key: token + + # -- Parameters for `runtime-patch` post-upgrade/install hook + # @default -- See below + patch: + enabled: true + image: + registry: quay.io + repository: codefresh/cli + tag: 0.85.0-rootless + rbac: + enabled: true + annotations: {} + affinity: {} + nodeSelector: {} + podSecurityContext: {} + resources: {} + tolerations: [] + ttlSecondsAfterFinished: 180 + env: + HOME: /tmp + + # -- Parameters for `gencerts-dind` post-upgrade/install hook + # @default -- See below + gencerts: + enabled: true + image: + registry: quay.io + repository: codefresh/kubectl + tag: 1.28.4 + rbac: + enabled: true + annotations: {} + affinity: {} + nodeSelector: {} + podSecurityContext: {} + resources: {} + tolerations: [] + ttlSecondsAfterFinished: 180 + + # -- DinD pod daemon config + # @default -- See below + dindDaemon: + hosts: + - unix:///var/run/docker.sock + - tcp://0.0.0.0:1300 + tlsverify: true + tls: true + tlscacert: /etc/ssl/cf-client/ca.pem + tlscert: /etc/ssl/cf/server-cert.pem + tlskey: /etc/ssl/cf/server-key.pem + insecure-registries: + - 192.168.99.100:5000 + metrics-addr: 0.0.0.0:9323 + experimental: true + +# App-Proxy parameters +# Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#app-proxy-installation +# @default -- See below +appProxy: + # -- Enable app-proxy + enabled: false + # -- Set number of pods + replicasCount: 1 + # -- Upgrade strategy + updateStrategy: + type: RollingUpdate + # -- Set pod annotations + podAnnotations: {} + + # -- Set image + image: + registry: quay.io + repository: codefresh/cf-app-proxy + tag: 0.0.47 + # -- Add additional env vars + env: {} + + # Set app-proxy ingress parameters + # @default -- See below + ingress: + # -- Set path prefix for ingress (keep empty for default `/` path) + pathPrefix: "" + # -- Set ingress class + class: "" + # -- Set DNS hostname the ingress will use + host: "" + # -- Set k8s tls secret for the ingress object + tlsSecret: "" + # -- Set extra annotations for ingress object + annotations: {} + # E.g. + # ingress: + # pathPrefix: "/cf-app-proxy" + # class: "nginx" + # host: "mydomain.com" + # tlsSecret: "tls-cert-app-proxy" + # annotations: + # nginx.ingress.kubernetes.io/whitelist-source-range: 123.123.123.123/130 + + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Override service account name + name: "" + # -- Use Role(true)/ClusterRole(true) + namespaced: true + # -- Additional service account annotations + annotations: {} + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Use Role(true)/ClusterRole(true) + namespaced: true + # -- Add custom rule to the role + rules: [] + + # -- Set security context for the pod + podSecurityContext: {} + + # -- Readiness probe configuration + # @default -- See below + readinessProbe: + failureThreshold: 5 + initialDelaySeconds: 5 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 5 + + # -- Set requests and limits + resources: {} + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] + # -- Set affinity + affinity: {} + +# Monitor parameters +# @default -- See below +monitor: + # -- Enable monitor + # Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#install-monitoring-component + enabled: false + + # -- Set number of pods + replicasCount: 1 + # -- Upgrade strategy + updateStrategy: + type: RollingUpdate + # -- Set pod annotations + podAnnotations: {} + + # -- Set image + image: + registry: quay.io + repository: codefresh/cf-k8s-agent + tag: 1.3.17 + # -- Add additional env vars + env: {} + + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Override service account name + name: "" + # -- Additional service account annotations + annotations: {} + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Use Role(true)/ClusterRole(true) + namespaced: true + # -- Add custom rule to the role + rules: [] + + # -- Readiness probe configuration + # @default -- See below + readinessProbe: + failureThreshold: 5 + initialDelaySeconds: 5 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 5 + + podSecurityContext: {} + + # -- Set node selector + nodeSelector: {} + # -- Set resources + resources: {} + # -- Set tolerations + tolerations: [] + # -- Set affinity + affinity: {} + +# -- Add serviceMonitor +# @default -- See below +serviceMonitor: + main: + # -- Enable service monitor for dind pods + enabled: false + nameOverride: dind + selector: + matchLabels: + app: dind + endpoints: + - path: /metrics + targetPort: 9100 + relabelings: + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + +# -- Add podMonitor (for engine pods) +# @default -- See below +podMonitor: + main: + # -- Enable pod monitor for engine pods + enabled: false + nameOverride: engine + selector: + matchLabels: + app: runtime + podMetricsEndpoints: + - path: /metrics + targetPort: 9100 + + runner: + # -- Enable pod monitor for runner pod + enabled: false + nameOverride: runner + selector: + matchLabels: + codefresh.io/application: runner + podMetricsEndpoints: + - path: /metrics + targetPort: 8080 + + volume-provisioner: + # -- Enable pod monitor for volumeProvisioner pod + enabled: false + nameOverride: volume-provisioner + selector: + matchLabels: + codefresh.io/application: volume-provisioner + podMetricsEndpoints: + - path: /metrics + targetPort: 8080 + +# -- Event exporter parameters +# @default -- See below +event-exporter: + # -- Enable event-exporter + enabled: false + # -- Set number of pods + replicasCount: 1 + # -- Upgrade strategy + updateStrategy: + type: Recreate + # -- Set pod annotations + podAnnotations: {} + + # -- Set image + image: + registry: docker.io + repository: codefresh/k8s-event-exporter + tag: latest + # -- Add additional env vars + env: {} + + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Override service account name + name: "" + # -- Additional service account annotations + annotations: {} + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Add custom rule to the role + rules: [] + + # -- Set security context for the pod + # @default -- See below + podSecurityContext: + enabled: false + + # -- Set node selector + nodeSelector: {} + # -- Set resources + resources: {} + # -- Set tolerations + tolerations: [] + # -- Set affinity + affinity: {} + +# -- Array of extra objects to deploy with the release +extraResources: [] +# E.g. +# extraResources: +# - apiVersion: rbac.authorization.k8s.io/v1 +# kind: ClusterRole +# metadata: +# name: codefresh-role +# rules: +# - apiGroups: [ "*"] +# resources: ["*"] +# verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +# - apiVersion: v1 +# kind: ServiceAccount +# metadata: +# name: codefresh-user +# namespace: "{{ .Release.Namespace }}" +# - apiVersion: rbac.authorization.k8s.io/v1 +# kind: ClusterRoleBinding +# metadata: +# name: codefresh-user +# roleRef: +# apiGroup: rbac.authorization.k8s.io +# kind: ClusterRole +# name: codefresh-role +# subjects: +# - kind: ServiceAccount +# name: codefresh-user +# namespace: "{{ .Release.Namespace }}" +# - apiVersion: v1 +# kind: Secret +# type: kubernetes.io/service-account-token +# metadata: +# name: codefresh-user-token +# namespace: "{{ .Release.Namespace }}" +# annotations: +# kubernetes.io/service-account.name: "codefresh-user" diff --git a/charts/f5/f5-bigip-ctlr/0.0.3201/.helmignore b/charts/f5/f5-bigip-ctlr/0.0.3201/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/charts/f5/f5-bigip-ctlr/0.0.3201/.helmignore @@ -0,0 +1,21 @@ +# 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 +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/charts/f5/f5-bigip-ctlr/0.0.3201/Chart.yaml b/charts/f5/f5-bigip-ctlr/0.0.3201/Chart.yaml new file mode 100644 index 000000000..c4c47bd13 --- /dev/null +++ b/charts/f5/f5-bigip-ctlr/0.0.3201/Chart.yaml @@ -0,0 +1,26 @@ +annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: F5 Container Ingress Services for Kubernetes and + OpenShift + catalog.cattle.io/kube-version: '>=1.20-0' + catalog.cattle.io/release-name: f5-bigip-ctlr +apiVersion: v1 +description: Deploy the F5 Networks BIG-IP Controller for Kubernetes and OpenShift + (k8s-bigip-ctlr). +home: https://www.f5.com/products/automation-and-orchestration/container-ingress-services +icon: file://assets/icons/f5-bigip-ctlr.png +keywords: +- F5 +- BIG-IP +- Containers +- Kubernetes +- OpenShift +kubeVersion: '>=1.20-0' +maintainers: +- email: f5_cis_operators@f5.com + name: F5CISSupport +name: f5-bigip-ctlr +sources: +- https://github.com/F5Networks/k8s-bigip-ctlr +- https://github.com/F5Networks/charts +version: 0.0.3201 diff --git a/charts/f5/f5-bigip-ctlr/0.0.3201/README.md b/charts/f5/f5-bigip-ctlr/0.0.3201/README.md new file mode 100644 index 000000000..0dc941a99 --- /dev/null +++ b/charts/f5/f5-bigip-ctlr/0.0.3201/README.md @@ -0,0 +1,93 @@ +# Helm Chart for the F5 Container Ingress Services + +This chart simplifies repeatable, versioned deployment of the [Container Ingress Services](https://clouddocs.f5.com/containers/latest/). + +### Prerequisites +- Refer to [CIS Prerequisites](https://clouddocs.f5.com/containers/latest/userguide/cis-helm.html#prerequisites) to install Container Ingress Services on Kubernetes or Openshift +- [Helm 3](https://helm.sh/docs/intro/) should be installed. + + +## Installing CIS Using Helm Charts + +This is the simplest way to install the CIS on OpenShift/Kubernetes cluster. Helm is a package manager for Kubernetes. Helm is Kubernetes version of yum or apt. Helm deploys something called charts, which you can think of as a packaged application. It is a collection of all your versioned, pre-configured application resources which can be deployed as one unit. This chart creates a Deployment for one Pod containing the [k8s-bigip-ctlr](https://clouddocs.f5.com/containers/latest/), it's supporting RBAC, Service Account and Custom Resources Definition installations. + +## Installing the Chart + +- (Optional) Add BIG-IP credentials as K8S secrets. + +For Kubernetes, use the following command: + +```kubectl create secret generic f5-bigip-ctlr-login -n kube-system --from-literal=username=admin --from-literal=password=``` + +For OpenShift, use the following command: + +```oc create secret generic f5-bigip-ctlr-login -n kube-system --from-literal=username=admin --from-literal=password=``` + +- Add the CIS chart repository in Helm using following command: + +```helm repo add f5-stable https://f5networks.github.io/charts/stable``` + +- Create values.yaml as shown in [examples](https://github.com/F5Networks/charts/tree/master/example_values/f5-bigip-ctlr): + +- Install the Helm chart if BIGIP credential secrets created manually using the following command: + +```helm install -f values.yaml f5-stable/f5-bigip-ctlr``` + +- Install the Helm chart with skip crds if BIGIP credential secrets created manually (without custom resource definitions installations) + +```helm install --skip-crds -f values.yaml f5-stable/f5-bigip-ctlr``` + +- If you want to create the BIGIP credential secret with helm charts use the following command: + +```helm install --set bigip_secret.create="true" --set bigip_secret.username=$BIGIP_USERNAME --set bigip_secret.password=$BIGIP_PASSWORD -f values.yaml f5-stable/f5-bigip-ctlr``` + +## Chart parameters: + +Parameter | Required | Description | Default +----------|-------------|-------------|-------- +bigip_login_secret | Optional | Secret that contains BIG-IP login credentials | f5-bigip-ctlr-login +args.bigip_url | Required | The management IP for your BIG-IP device | **Required**, no default +args.bigip_partition | Required | BIG-IP partition the CIS Controller will manage | f5-bigip-ctlr +args.namespaces | Optional | List of Kubernetes namespaces which CIS will monitor | empty +bigip_secret.create | Optional | Create kubernetes secret using username and password | false +bigip_secret.username | Optional | bigip username to create the kubernetes secret | empty +bigip_secret.password | Optional | bigip password to create the kubernetes secret | empty +rbac.create | Optional | Create ClusterRole and ClusterRoleBinding | true +serviceAccount.name | Optional | name of the ServiceAccount for CIS controller | f5-bigip-ctlr-serviceaccount +serviceAccount.create | Optional | Create service account for the CIS controller | true +namespace | Optional | name of namespace CIS will use to create deployment and other resources | kube-system +image.user | Optional | CIS Controller image repository username | f5networks +image.repo | Optional | CIS Controller image repository name | k8s-bigip-ctlr +image.pullPolicy | Optional | CIS Controller image pull policy | Always +image.pullSecrets | Optional | List of secrets of container registry to pull image | empty +version | Optional | CIS Controller image tag | latest +nodeSelector | Optional | dictionary of Node selector labels | empty +tolerations | Optional | Array of labels | empty +limits_cpu | Optional | CPU limits for the pod | 100m +limits_memory | Optional | Memory limits for the pod | 512Mi +requests_cpu | Optional | CPU request for the pod | 100m +requests_memory | Optional | Memory request for the pod | 512Mi +affinity | Optional | Dictionary of affinity | empty +securityContext | Optional | Dictionary of deployment securityContext | empty +podSecurityContext | Optional | Dictionary of pod securityContext | empty +ingressClass.ingressClassName | Optional | Name of ingress class | f5 +ingressClass.isDefaultIngressController | Optional | CIS will monitor all the ingresses resource if set true | false +ingressClass.create | Optional | Create ingress class | true + +Note: bigip_login_secret and bigip_secret are mutually exclusive, if both are defined in values.yaml file bigip_secret will be given priority. + + +See the CIS documentation for a full list of args supported for CIS [CIS Configuration Options](https://clouddocs.f5.com/containers/latest/userguide/config-parameters.html) + +> **Note:** Helm value names cannot include the character `-` which is commonly used in the names of parameters passed to the controller. To accomodate Helm, the parameter names in `values.yaml` use `_` and then replace them with `-` when rendering. +> e.g. `args.bigip_url` is rendered as `bigip-url` as required by the CIS Controller. + + +If you have a specific use case for F5 products in the Kubernetes environment that would benefit from a curated chart, please [open an issue](https://github.com/F5Networks/charts/issues) describing your use case and providing example resources. + +## Uninstalling Helm Chart + +Run the following command to uninstall the chart. + +```helm uninstall ``` + diff --git a/charts/f5/f5-bigip-ctlr/0.0.3201/app-readme.md b/charts/f5/f5-bigip-ctlr/0.0.3201/app-readme.md new file mode 100644 index 000000000..6f28ef779 --- /dev/null +++ b/charts/f5/f5-bigip-ctlr/0.0.3201/app-readme.md @@ -0,0 +1,87 @@ +# Helm Chart for the F5 Container Ingress Services + +This chart simplifies repeatable, versioned deployment of the [Container Ingress Services](https://clouddocs.f5.com/containers/latest/). + +### Prerequisites +- Refer to [CIS Prerequisites](https://clouddocs.f5.com/containers/latest/userguide/cis-helm.html#prerequisites) to install Container Ingress Services on Kubernetes or Openshift +- [Helm 3](https://helm.sh/docs/intro/) should be installed. + + +## Installing CIS Using Helm Charts + +This is the simplest way to install the CIS on OpenShift/Kubernetes cluster. Helm is a package manager for Kubernetes. Helm is Kubernetes version of yum or apt. Helm deploys something called charts, which you can think of as a packaged application. It is a collection of all your versioned, pre-configured application resources which can be deployed as one unit. This chart creates a Deployment for one Pod containing the [k8s-bigip-ctlr](https://clouddocs.f5.com/containers/latest/), it's supporting RBAC, Service Account and Custom Resources Definition installations. + +## Installing the Chart + +- Add BIG-IP credentials as K8S secrets. + +For Kubernetes, use the following command: + +```kubectl create secret generic f5-bigip-ctlr-login -n kube-system --from-literal=username=admin --from-literal=password=``` + +For OpenShift, use the following command: + +```oc create secret generic f5-bigip-ctlr-login -n kube-system --from-literal=username=admin --from-literal=password=``` + +- Add the CIS chart repository in Helm using following command: + +```helm repo add f5-stable https://f5networks.github.io/charts/stable``` + +- Create values.yaml as shown in [examples](https://github.com/F5Networks/charts/tree/master/example_values/f5-bigip-ctlr): + +- Install the Helm chart using the following command: + +```helm install -f values.yaml f5-stable/f5-bigip-ctlr``` + +- Install the Helm chart with skip crds (without custom resource definitions installations) + +```helm install --skip-crds -f values.yaml f5-stable/f5-bigip-ctlr``` + +## Chart parameters: + +Parameter | Required | Description | Default +----------|-------------|-------------|-------- +bigip_login_secret | Required | Secret that contains BIG-IP login credentials | f5-bigip-ctlr-login +args.bigip_url | Required | The management IP for your BIG-IP device | **Required**, no default +args.bigip_partition | Required | BIG-IP partition the CIS Controller will manage | f5-bigip-ctlr +args.namespaces | Optional | List of Kubernetes namespaces which CIS will monitor | empty +rbac.create | Optional | Create ClusterRole and ClusterRoleBinding | true +serviceAccount.name | Optional | name of the ServiceAccount for CIS controller | f5-bigip-ctlr-serviceaccount +serviceAccount.create | Optional | Create service account for the CIS controller | true +namespace | Optional | name of namespace CIS will use to create deployment and other resources | kube-system +image.user | Optional | CIS Controller image repository username | f5networks +image.repo | Optional | CIS Controller image repository name | k8s-bigip-ctlr +image.pullPolicy | Optional | CIS Controller image pull policy | Always +image.pullSecrets | Optional | List of secrets of container registry to pull image | empty +version | Optional | CIS Controller image tag | latest +nodeSelector | Optional | dictionary of Node selector labels | empty +tolerations | Optional | Array of labels | empty +limits_cpu | Optional | CPU limits for the pod | 100m +limits_memory | Optional | Memory limits for the pod | 512Mi +requests_cpu | Optional | CPU request for the pod | 100m +requests_memory | Optional | Memory request for the pod | 512Mi +affinity | Optional | Dictionary of affinity | empty +securityContext | Optional | Dictionary of securityContext | empty +ingressClass.ingressClassName | Optional | Name of ingress class | f5 +ingressClass.defaultIngressController | Optional | CIS will monitor all the ingresses resource if set true | false +ingressClass.create | Optional | Create ingress class | true + + + + + + +See the CIS documentation for a full list of args supported for CIS [CIS Configuration Options](https://clouddocs.f5.com/containers/latest/userguide/config-parameters.html) + +> **Note:** Helm value names cannot include the character `-` which is commonly used in the names of parameters passed to the controller. To accomodate Helm, the parameter names in `values.yaml` use `_` and then replace them with `-` when rendering. +> e.g. `args.bigip_url` is rendered as `bigip-url` as required by the CIS Controller. + + +If you have a specific use case for F5 products in the Kubernetes environment that would benefit from a curated chart, please [open an issue](https://github.com/F5Networks/charts/issues) describing your use case and providing example resources. + +## Uninstalling Helm Chart + +Run the following command to uninstall the chart. + +```helm uninstall ``` + diff --git a/charts/f5/f5-bigip-ctlr/0.0.3201/crds/f5-bigip-ctlr-customresourcedefinitions.yml b/charts/f5/f5-bigip-ctlr/0.0.3201/crds/f5-bigip-ctlr-customresourcedefinitions.yml new file mode 100644 index 000000000..2274573d3 --- /dev/null +++ b/charts/f5/f5-bigip-ctlr/0.0.3201/crds/f5-bigip-ctlr-customresourcedefinitions.yml @@ -0,0 +1,1327 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + app.kubernetes.io/instance: f5-bigip-ctlr + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: f5-bigip-ctlr + name: virtualservers.cis.f5.com +spec: + group: cis.f5.com + names: + kind: VirtualServer + plural: virtualservers + shortNames: + - vs + singular: virtualserver + scope: Namespaced + versions: + - + name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + partition: + type: string + pattern: '^[a-zA-Z]+[-A-z0-9_.]+$' + host: + type: string + pattern: '^(([a-zA-Z0-9\*]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$' + hostAliases: + type: array + items: + type: string + pattern: '^(([a-zA-Z0-9\*]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$' + hostGroup: + type: string + pattern: '^[a-zA-Z]+[-A-z0-9_.:]*[A-z0-9]*$' + hostGroupVirtualServerName: + type: string + pattern: '^[a-zA-Z]+([A-z0-9-_+])*([A-z0-9])$' + httpTraffic: + type: string + enum: [allow, none, redirect] + ipamLabel: + type: string + pattern: '^[a-zA-Z]+[-A-z0-9_.:]+[A-z0-9]+$' + bigipRouteDomain: + type: integer + minimum: 0 + maximum: 65535 + default: 0 + snat: + type: string + pattern: '^$|^\/?[a-zA-Z]+([-A-z0-9_+]+\/)*([-A-z0-9_.:]+\/?)+$' + connectionMirroring: + type: string + enum: [ none, L4 ] + tlsProfileName: + type: string + pattern: '^[a-zA-Z]+[-A-z0-9_.:]+[A-z0-9]+$' + persistenceProfile: + type: string + pattern: '^\/?[a-zA-Z]+([-A-z0-9_+]+\/)*([-A-z0-9_.:]+\/?)*$' + hostPersistence: + type: object + properties: + method: + type: string + enum: [ sourceAddress, destinationAddress, cookieInsert, cookieRewrite, cookiePassive, cookieHash, universal, hash, carp, none ] + metaData: + type: object + properties: + name: + type: string + key: + type: string + netmask: + type: string + pattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])|(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$' + timeout: + type: integer + minimum: 1 + maximum: 65535 + offset: + type: integer + minimum: 1 + maximum: 65535 + length: + type: integer + minimum: 1 + maximum: 65535 + expiry: + type: string + pattern: '^((?:(?:[0-9]+d))|(?:(?:[0-9]+d)?((?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?)))$' + required: + - method + htmlProfile: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + profiles: + type: object + properties: + tcp: + type: object + properties: + client: + type: string + pattern: '^\/([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + server: + type: string + pattern: '^\/([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + http2: + type: object + properties: + client: + type: string + pattern: '^\/([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + server: + type: string + pattern: '^\/([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + dos: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + profileAccess: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + policyPerRequestAccess: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + botDefense: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + policyName: + type: string + pattern: '^[a-zA-Z]+[-A-z0-9_.:]+[A-z0-9]+$' + rewriteAppRoot: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)*([-A-z0-9_.:]+\/?)*$' + waf: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + profileMultiplex: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + profileAdapt: + type: object + properties: + request: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + response: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + allowVlans: + items: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.]+\/?)*$' + type: array + allowSourceRange: + items: + type: string + type: array + httpMrfRoutingEnabled: + type: boolean + iRules: + type: array + items: + type: string + pattern: '^none$|^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + serviceAddress: + type: array + maxItems: 1 + items: + type: object + properties: + arpEnabled: + type: boolean + icmpEcho: + type: string + enum: [enable, disable, selective] + routeAdvertisement: + type: string + enum: [enable, disable, selective, always, any, all] + spanningEnabled: + type: boolean + trafficGroup: + type: string + pattern: '^\/([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + defaultPool: + type: object + properties: + name: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + service: + type: string + pattern: '[a-z]([-a-z0-9]*[a-z0-9])?' + servicePort: + x-kubernetes-int-or-string: true + anyOf: + - type: integer + - type: string + serviceNamespace: + type: string + pattern: '^[a-zA-Z]+([-A-z0-9_.+:])*([A-z0-9])+$' + loadBalancingMethod: + type: string + pattern: '^[a-z]+[a-z_-]+[a-z]+$' + nodeMemberLabel: + type: string + pattern: '^[a-zA-Z0-9][-A-Za-z0-9_.\/]{0,61}[a-zA-Z0-9]=[a-zA-Z0-9][-A-Za-z0-9_.]{0,61}[a-zA-Z0-9]$' + monitors: + type: array + items: + type: object + properties: + type: + type: string + enum: [ tcp, udp, http, https ] + interval: + type: integer + timeout: + type: integer + targetPort: + type: integer + name: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + reference: + type: string + enum: [ bigip ] + send: + type: string + recv: + type: string + sslProfile: + type: string + pattern: '^\/([A-z0-9-_+]+\/)+([A-z0-9]+\/?)*$' + reference: + type: string + enum: [ bigip, service ] + reselectTries: + type: integer + minimum: 0 + maximum: 65535 + serviceDownAction: + type: string + required: + - reference + pools: + type: array + items: + type: object + properties: + name: + type: string + pattern: '^[a-zA-Z]+([-A-z0-9_.+:])*([A-z0-9])+$' + path: + type: string + pattern: '^\/([A-z0-9-_+]+\/)*([-A-z0-9_.:]+\/?)*$' + service: + type: string + pattern: '[a-z]([-a-z0-9]*[a-z0-9])?' + weight: + type: integer + minimum: 0 + maximum: 256 + alternateBackends: + type: array + items: + type: object + properties: + service: + type: string + pattern: '[a-z]([-a-z0-9]*[a-z0-9])?' + serviceNamespace: + type: string + pattern: '^[a-zA-Z]+([-A-z0-9_.+:])*([A-z0-9])+$' + weight: + type: integer + minimum: 0 + maximum: 256 + required: + - service + loadBalancingMethod: + type: string + pattern: '^[a-z]+[a-z_-]+[a-z]+$' + nodeMemberLabel: + type: string + pattern: '^[a-zA-Z0-9][-A-Za-z0-9_.\/]{0,61}[a-zA-Z0-9]=[a-zA-Z0-9][-A-Za-z0-9_.]{0,61}[a-zA-Z0-9]$' + servicePort: + x-kubernetes-int-or-string: true + anyOf: + - type: integer + - type: string + rewrite: + type: string + pattern: '^\/([A-z0-9-_+]+\/)*([-A-z0-9_.:]+\/?)*$' + hostRewrite: + type: string + pattern: '^(([a-zA-Z0-9\*]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$' + waf: + type: string + pattern: '^\/([A-z0-9-_+]+\/)+([A-z0-9]+\/?)*$' + serviceNamespace: + type: string + pattern: '^[a-zA-Z]+([-A-z0-9_.+:])*([A-z0-9])+$' + monitor: + type: object + properties: + type: + type: string + enum: [http, https, tcp] + send: + type: string + recv: + type: string + interval: + type: integer + timeout: + type: integer + targetPort: + type: integer + name: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + reference: + type: string + enum: [bigip] + sslProfile: + type: string + pattern: '^\/([A-z0-9-_+]+\/)+([A-z0-9]+\/?)*$' + monitors: + type: array + items: + type: object + properties: + type: + type: string + enum: [ http, https, tcp ] + send: + type: string + recv: + type: string + interval: + type: integer + timeout: + type: integer + targetPort: + type: integer + name: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + reference: + type: string + enum: [bigip] + sslProfile: + type: string + pattern: '^\/([A-z0-9-_+]+\/)+([A-z0-9]+\/?)*$' + minimumMonitors: + x-kubernetes-int-or-string: true + anyOf: + - type: integer + - type: string + reselectTries: + type: integer + minimum: 0 + maximum: 65535 + serviceDownAction: + type: string + extendedServiceReferences: + type: array + items: + type: object + properties: + clusterName: + type: string + service: + type: string + pattern: '[a-z]([-a-z0-9]*[a-z0-9])?' + namespace: + type: string + servicePort: + x-kubernetes-int-or-string: true + anyOf: + - type: integer + - type: string + weight: + type: integer + minimum: 0 + maximum: 256 + required: + - service + - servicePort + virtualServerAddress: + type: string + pattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])|(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$' + additionalVirtualServerAddresses: + type: array + items: + type: string + pattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])|(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$' + virtualServerName: + type: string + pattern: '^[a-zA-Z]+([A-z0-9-_+])*([A-z0-9])$' + virtualServerHTTPPort: + type: integer + minimum: 1 + maximum: 65535 + virtualServerHTTPSPort: + type: integer + minimum: 1 + maximum: 65535 + x-kubernetes-validations: + - rule: "!has(self.partition) || self.partition != 'Common'" + message: "The partition cannot be 'Common' if specified." + status: + type: object + properties: + vsAddress: + type: string + default: None + status: + type: string + default: Pending + additionalPrinterColumns: + - name: host + type: string + description: hostname + jsonPath: .spec.host + - name: tlsProfileName + type: string + description: TLS Profile attached + jsonPath: .spec.tlsProfileName + - name: httpTraffic + type: string + description: Http Traffic Termination + jsonPath: .spec.httpTraffic + - name: IPAddress + type: string + description: IP address of virtualServer + jsonPath: .spec.virtualServerAddress + - name: ipamLabel + type: string + description: ipamLabel for virtual server + jsonPath: .spec.ipamLabel + - name: IPAMVSAddress + type: string + description: IP address of virtualServer + jsonPath: .status.vsAddress + - name: STATUS + type: string + description: status of VirtualServer + jsonPath: .status.status + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + subresources: + status: {} + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + app.kubernetes.io/instance: f5-bigip-ctlr + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: f5-bigip-ctlr + name: tlsprofiles.cis.f5.com +spec: + group: cis.f5.com + names: + kind: TLSProfile + plural: tlsprofiles + shortNames: + - tls + singular: tlsprofile + scope: Namespaced + versions: + - + name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + tlsCipher: + type: object + properties: + tlsVersion: + type: string + enum: ["1.0", "1.1", "1.2", "1.3"] + disableTLSVersions: + type: array + items: + type: string + enum: ["1.0", "1.1", "1.2", "1.3"] + ciphers: + type: string + cipherGroup: + type: string + hosts: + type: array + items: + type: string + pattern: '^(([a-zA-Z0-9\*]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$' + tls: + type: object + properties: + termination: + type: string + enum: [edge, reencrypt, passthrough] + clientSSL: + type: string + pattern: '^\/?[a-zA-Z]+([-A-z0-9_+]+\/)*([-A-z0-9_.:]+\/?)*$' + clientSSLs: + type: array + items: + type: string + pattern: '^\/?[a-zA-Z]+([-A-z0-9_+]+\/)*([-A-z0-9_.:]+\/?)*$' + serverSSL: + type: string + pattern: '^\/?[a-zA-Z]+([-A-z0-9_+]+\/)*([-A-z0-9_.:]+\/?)*$' + serverSSLs: + type: array + items: + type: string + pattern: '^\/?[a-zA-Z]+([-A-z0-9_+]+\/)*([-A-z0-9_.:]+\/?)*$' + reference: + type: string + enum: [bigip, secret, hybrid] + clientSSLParams: + type: object + properties: + renegotiationEnabled: + type: boolean + default: true + profileReference: + type: string + enum: [ bigip, secret ] + serverSSLParams: + type: object + properties: + renegotiationEnabled: + type: boolean + default: true + profileReference: + type: string + enum: [ bigip, secret ] + required: + - termination + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + app.kubernetes.io/instance: f5-bigip-ctlr + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: f5-bigip-ctlr + name: transportservers.cis.f5.com +spec: + group: cis.f5.com + names: + kind: TransportServer + plural: transportservers + shortNames: + - ts + singular: transportserver + scope: Namespaced + versions: + - + name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + partition: + type: string + pattern: '^[a-zA-Z]+[-A-z0-9_.]+$' + virtualServerAddress: + type: string + pattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])|(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$' + virtualServerPort: + type: integer + minimum: 1 + maximum: 65535 + virtualServerName: + type: string + pattern: '^[a-zA-Z]+([A-z0-9-_+])*([A-z0-9])$' + host: + type: string + pattern: '^(([a-zA-Z0-9\*]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$' + hostGroup: + type: string + pattern: '^[a-zA-Z]+[-A-z0-9_.:]*[A-z0-9]*$' + policyName: + type: string + pattern: '^([A-z0-9-_+])*([A-z0-9])$' + mode: + type: string + enum: [standard, performance] + type: + type: string + enum: [tcp, udp, sctp] + snat: + type: string + pattern: '^$|^\/?[a-zA-Z]+([-A-z0-9_+]+\/)*([-A-z0-9_.:]+\/?)+$' + connectionMirroring: + type: string + enum: [ none, L4 ] + profiles: + type: object + properties: + tcp: + type: object + properties: + client: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + server: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + persistenceProfile: + type: string + pattern: '^\/?[a-zA-Z]+([-A-z0-9_+]+\/)*([-A-z0-9_.:]+\/?)*$' + dos: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + profileL4: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + allowVlans: + items: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.]+\/?)*$' + type: array + iRules: + type: array + items: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + ipamLabel: + type: string + pattern: '^[a-zA-Z]+[-A-z0-9_.:]+[A-z0-9]+$' + bigipRouteDomain: + type: integer + minimum: 0 + maximum: 65535 + default: 0 + serviceAddress: + type: array + maxItems: 1 + items: + type: object + properties: + arpEnabled: + type: boolean + icmpEcho: + type: string + enum: [enable, disable, selective] + routeAdvertisement: + type: string + enum: [enable, disable, selective, always, any, all] + spanningEnabled: + type: boolean + trafficGroup: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + pool: + type: object + properties: + name: + type: string + pattern: '^[a-zA-Z]+([-A-z0-9_.+:])*([A-z0-9])+$' + service: + type: string + pattern: '[a-z]([-a-z0-9]*[a-z0-9])?' + servicePort: + x-kubernetes-int-or-string: true + anyOf: + - type: integer + - type: string + weight: + type: integer + minimum: 0 + maximum: 100 + alternateBackends: + type: array + items: + type: object + properties: + service: + type: string + pattern: '[a-z]([-a-z0-9]*[a-z0-9])?' + serviceNamespace: + type: string + pattern: '^[a-zA-Z]+([-A-z0-9_.+:])*([A-z0-9])+$' + weight: + type: integer + minimum: 0 + maximum: 100 + required: + - service + serviceNamespace: + type: string + pattern: '^[a-zA-Z]+([-A-z0-9_.+:])*([A-z0-9])+$' + loadBalancingMethod: + type: string + pattern: '^[a-z]+[a-z_-]+[a-z]+$' + nodeMemberLabel: + type: string + pattern: '^[a-zA-Z0-9][-A-Za-z0-9_.\/]{0,61}[a-zA-Z0-9]=[a-zA-Z0-9][-A-Za-z0-9_.]{0,61}[a-zA-Z0-9]$' + monitor: + type: object + properties: + type: + type: string + enum: [tcp, udp, http, https] + interval: + type: integer + timeout: + type: integer + targetPort: + type: integer + name: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + reference: + type: string + enum: [bigip] + send: + type: string + recv: + type: string + monitors: + type: array + items: + type: object + properties: + type: + type: string + enum: [ tcp, udp, http, https ] + interval: + type: integer + timeout: + type: integer + targetPort: + type: integer + name: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + reference: + type: string + enum: [bigip] + send: + type: string + recv: + type: string + reselectTries: + type: integer + minimum: 0 + maximum: 65535 + serviceDownAction: + type: string + extendedServiceReferences: + type: array + items: + type: object + properties: + clusterName: + type: string + service: + type: string + pattern: '[a-z]([-a-z0-9]*[a-z0-9])?' + namespace: + type: string + servicePort: + x-kubernetes-int-or-string: true + anyOf: + - type: integer + - type: string + weight: + type: integer + minimum: 0 + maximum: 100 + required: + - service + - servicePort + required: + - virtualServerPort + - pool + - mode + x-kubernetes-validations: + - rule: "!has(self.partition) || self.partition != 'Common'" + message: "The partition cannot be 'Common' if specified." + status: + type: object + properties: + vsAddress: + type: string + default: None + status: + type: string + default: Pending + additionalPrinterColumns: + - name: virtualServerAddress + type: string + description: IP address of virtualServer + jsonPath: .spec.virtualServerAddress + - name: virtualServerPort + type: integer + description: Port of virtualServer + jsonPath: .spec.virtualServerPort + - name: pool + type: string + description: Name of service + jsonPath: .spec.pool.service + - name: poolPort + type: string + description: Port of service + jsonPath: .spec.pool.servicePort + - name: ipamLabel + type: string + description: ipamLabel for transport server + jsonPath: .spec.ipamLabel + - name: IPAMVSAddress + type: string + description: IP address of transport server + jsonPath: .status.vsAddress + - name: STATUS + type: string + description: status of TransportServer + jsonPath: .status.status + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + subresources: + status: { } +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + app.kubernetes.io/instance: f5-bigip-ctlr + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: f5-bigip-ctlr + name: externaldnses.cis.f5.com +spec: + group: cis.f5.com + names: + kind: ExternalDNS + plural: externaldnses + shortNames: + - edns + singular: externaldns + scope: Namespaced + versions: + - + name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + domainName: + type: string + pattern: '^(([a-zA-Z0-9\*]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$' + dnsRecordType: + type: string + pattern: 'A' + loadBalanceMethod: + type: string + pattern: '^[a-z]+[a-z_-]+[a-z]+$' + clientSubnetPreferred: + type: boolean + persistenceEnabled: + type: boolean + persistCidrIpv4: + type: integer + minimum: 0 + maximum: 32 + persistCidrIpv6: + type: integer + minimum: 0 + maximum: 128 + ttlPersistence: + type: integer + format: int64 + minimum: 0 + maximum: 4294967295 + pools: + type: array + items: + type: object + properties: + dataServerName: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + dnsRecordType: + type: string + pattern: 'A' + loadBalanceMethod: + type: string + pattern: '^[a-z]+[a-z_-]+[a-z]+$' + lbModeFallback: + type: string + pattern: '^[a-z]+[a-z_-]+[a-z]+$' + order: + type: integer + ratio: + type: integer + monitor: + type: object + properties: + type: + type: string + enum: [http, https, tcp] + send: + type: string + recv: + type: string + interval: + type: integer + timeout: + type: integer + required: + - type + - interval + monitors: + type: array + items: + type: object + properties: + type: + type: string + enum: [http, https, tcp] + send: + type: string + recv: + type: string + interval: + type: integer + timeout: + type: integer + required: + - type + - interval + required: + - dataServerName + required: + - domainName + additionalPrinterColumns: + - name: domainName + type: string + description: Domain name of virtual server resource + jsonPath: .spec.domainName + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + - name: CREATED ON + type: string + jsonPath: .metadata.creationTimestamp +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + app.kubernetes.io/instance: f5-bigip-ctlr + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: f5-bigip-ctlr + name: ingresslinks.cis.f5.com +spec: + group: cis.f5.com + names: + kind: IngressLink + shortNames: + - il + singular: ingresslink + plural: ingresslinks + scope: Namespaced + versions: + - + name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + partition: + type: string + pattern: '^[a-zA-Z]+[-A-z0-9_.]+$' + virtualServerAddress: + type: string + pattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$' + host: + type: string + pattern: '^(([a-zA-Z0-9\*]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$' + ipamLabel: + type: string + pattern: '^[a-zA-Z]+[-A-z0-9_.:]+[A-z0-9]+$' + bigipRouteDomain: + type: integer + minimum: 0 + maximum: 65535 + default: 0 + iRules: + type: array + items: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + selector: + properties: + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-validations: + - rule: "!has(self.partition) || self.partition != 'Common'" + message: "The partition cannot be 'Common' if specified." + status: + type: object + properties: + vsAddress: + type: string + additionalPrinterColumns: + - name: IPAMVSAddress + type: string + description: IP address of virtualServer + jsonPath: .status.vsAddress + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + subresources: + status: { } +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + app.kubernetes.io/instance: f5-bigip-ctlr + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: f5-bigip-ctlr + name: policies.cis.f5.com +spec: + group: cis.f5.com + names: + kind: Policy + shortNames: + - plc + singular: policy + plural: policies + scope: Namespaced + versions: + - + name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + l7Policies: + type: object + properties: + waf: + type: string + pattern: '^\/([A-z0-9-_+]+\/)+([A-z0-9]+\/?)*$' + profileAccess: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + policyPerRequestAccess: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + profileAdapt: + type: object + properties: + request: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + response: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + l3Policies: + type: object + properties: + dos: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + botDefense: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + firewallPolicy: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([A-z0-9]+\/?)*$' + ipIntelligencePolicy: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + allowSourceRange: + items: + type: string + type: array + allowVlans: + items: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)*([A-z0-9-_.\s]+\/?)*$' + type: array + ltmPolicies: + type: object + properties: + insecure: + type: string + pattern: '^\/[a-zA-Z]+([-A-z0-9_+:]+\/)+([A-z0-9]+\/?)*$' + secure: + type: string + pattern: '^\/[a-zA-Z]+([-A-z0-9_+:]+\/)+([A-z0-9]+\/?)*$' + priority: + type: string + enum: [low, high] + iRules: + type: object + properties: + insecure: + type: string + pattern: '^none$|^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + secure: + type: string + pattern: '^none$|^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + priority: + type: string + enum: [ low, high ] + iRuleList: + type: array + items: + type: string + pattern: '^none$|^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + defaultPool: + type: object + properties: + name: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + service: + type: string + pattern: '[a-z]([-a-z0-9]*[a-z0-9])?' + servicePort: + x-kubernetes-int-or-string: true + anyOf: + - type: integer + - type: string + serviceNamespace: + type: string + pattern: '^[a-zA-Z]+([-A-z0-9_.+:])*([A-z0-9])+$' + loadBalancingMethod: + type: string + pattern: '^[a-z]+[a-z_-]+[a-z]+$' + nodeMemberLabel: + type: string + pattern: '^[a-zA-Z0-9][-A-Za-z0-9_.\/]{0,61}[a-zA-Z0-9]=[a-zA-Z0-9][-A-Za-z0-9_.]{0,61}[a-zA-Z0-9]$' + monitors: + type: array + items: + type: object + properties: + type: + type: string + enum: [ tcp, udp, http, https ] + interval: + type: integer + timeout: + type: integer + targetPort: + type: integer + name: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + reference: + type: string + enum: [ bigip ] + send: + type: string + recv: + type: string + sslProfile: + type: string + pattern: '^\/([A-z0-9-_+]+\/)+([A-z0-9]+\/?)*$' + reference: + type: string + enum: [ bigip, service ] + reselectTries: + type: integer + minimum: 0 + maximum: 65535 + serviceDownAction: + type: string + required: + - reference + profiles: + type: object + properties: + tcp: + type: object + properties: + client: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + server: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + udp: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + http: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + http2: + type: object + properties: + client: + type: string + pattern: '^\/([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + server: + type: string + pattern: '^\/([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + persistenceProfile: + type: string + pattern: '^\/?[a-zA-Z]+([-A-z0-9_+]+\/)*([-A-z0-9_.:]+\/?)*$' + profileL4: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + profileWebSocket: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + profileMultiplex: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + rewriteProfile: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([A-z0-9]+\/?)*$' + logProfiles: + items: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)*([-A-z0-9._\s]+\/?)*$' + type: array + httpMrfRoutingEnabled: + type: boolean + sslProfiles: + type: object + properties: + clientProfiles: + items: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + type: array + serverProfiles: + items: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + type: array + analyticsProfiles: + type: object + properties: + http: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + htmlProfile: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + ftpProfile: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + autoLastHop: + type: string + enum: [ default, auto, disable ] + snat: + type: string + pattern: '^$|^\/?[a-zA-Z]+([-A-z0-9_+]+\/)*([-A-z0-9_.:]+\/?)+$' + poolSettings: + type: object + properties: + reselectTries: + type: integer + minimum: 0 + maximum: 65535 + serviceDownAction: + type: string + slowRampTime: + type: integer + minimum: 0 + maximum: 900 + multiPoolPersistence: + type: object + properties: + method: + type: string + enum: [ uieSourceAddress, hashSourceAddress ] + timeOut: + type: integer + minimum: 1 + default: 180 diff --git a/charts/f5/f5-bigip-ctlr/0.0.3201/questions.yaml b/charts/f5/f5-bigip-ctlr/0.0.3201/questions.yaml new file mode 100644 index 000000000..4d276dfbd --- /dev/null +++ b/charts/f5/f5-bigip-ctlr/0.0.3201/questions.yaml @@ -0,0 +1,75 @@ +questions: +- variable: bigip_login_secret + required: true + type: string + label: "Name of the k8s secret object with BIG-IP login credentials." +- variable: args.bigip_url + required: true + type: string + label: "BIG-IP Management IP/URL" +- variable: args.bigip_partition + required: true + type: string + label: "BIG-IP Partition" +- variable: image.user + type: string + label: "Image Repository where CIS image is hosted" +- variable: image.repo + type: string + label: "CIS image name" +- variable: version + type: string + label: "CIS version tag." + default: "latest" +- variable: args.pool_member_type + type: string + label: "Type of BIG-IP Pool members to create." + default: "nodeport" +- variable: args.node_poll_interval + type: string + label: "In seconds, the interval at which the CIS polls the cluster to find all node members." + default: "30" +- variable: args.verify_interval + type: string + label: "In seconds, the interval at which the CIS verifies that the BIG-IP configuration matches the state of the orchestration system." + default: "30" +- variable: args.agent + type: string + label: "Specify the agent for CIS to communicate with BIG-IP. CCCL or AS3" + default: "as3" +- variable: args.custom_resource_mode + type: string + label: "Set 'true' to process CRD resources. Supported in AS3 agent. When true ConfigMaps, Routes, and Ingress are not processed by CIS." + default: "false" +- variable: args.ipam + type: string + label: "Specify if CIS provides the ability to interface with F5 IPAM Controller (FIC). Valid with agent AS3." + default: "false" +- variable: args.disable_teems + type: string + label: "If true, analytics data is not sent to F5." + default: "false" +- variable: args.hubmode + type: string + label: "When `true`, ConfigMaps with Services in same and different namespace are processed. CIS >= 2.5.0+. Valid with agent AS3." + default: "false" +- variable: args.default_route_domain + type: string + label: "Set default Route Domain for Custom resources. Valid with agent AS3." + default: "0" +- variable: args.filter_tenants + type: string + label: "Specify to use tenant filtering API for AS3 declaration. This allows CIS to process each AS3 Tenant separately. Compatible with ConfigMap only. Valid with agent AS3. CIS >= 2.7" + default: "false" +- variable: args.enable_ipv6 + type: string + label: "When set to true, it enables IPv6 network support. CIS >= 2.7." + default: "false" +- variable: args.log_level + type: string + label: "Configured the log level. INFO, DEBUG, CRITICAL, WARNING, ERROR." + default: "INFO" +- variable: args.log_as3_response + type: string + label: "When set to true, adds the body of AS3 API response in Controller logs." + default: "false" diff --git a/charts/f5/f5-bigip-ctlr/0.0.3201/templates/NOTES.txt b/charts/f5/f5-bigip-ctlr/0.0.3201/templates/NOTES.txt new file mode 100644 index 000000000..302512a9b --- /dev/null +++ b/charts/f5/f5-bigip-ctlr/0.0.3201/templates/NOTES.txt @@ -0,0 +1,6 @@ +Container Ingress Services controller: {{ .Release.Name }} + +Controller Documentation: +- Kubernetes: https://clouddocs.f5.com/containers/latest/userguide/kubernetes/ +- OpenShift: https://clouddocs.f5.com/containers/latest/userguide/openshift/ + diff --git a/charts/f5/f5-bigip-ctlr/0.0.3201/templates/_helpers.tpl b/charts/f5/f5-bigip-ctlr/0.0.3201/templates/_helpers.tpl new file mode 100644 index 000000000..7ce05d2ef --- /dev/null +++ b/charts/f5/f5-bigip-ctlr/0.0.3201/templates/_helpers.tpl @@ -0,0 +1,64 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "f5-bigip-ctlr.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for deployment. +*/}} +{{- define "deployment.apiVersion" -}} +{{- if semverCompare ">=1.9-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "apps/v1" -}} +{{- else -}} +{{- print "extensions/v1beta1" -}} +{{- end -}} +{{- end -}} + +{{/* +Check for user given namespace or give kube-system +*/}} +{{- define "f5-bigip-ctlr.namespace" -}} +{{- if hasKey .Values "namespace" -}} +{{- .Values.namespace -}} +{{- else -}} +{{- print "kube-system" -}} +{{- end -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "f5-bigip-ctlr.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "f5-bigip-ctlr.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + + {{/* +Create the name of the service account to use +*/}} +{{- define "f5-bigip-ctlr.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "f5-bigip-ctlr.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-clusterrole.yaml b/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-clusterrole.yaml new file mode 100644 index 000000000..c60eb6eb8 --- /dev/null +++ b/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-clusterrole.yaml @@ -0,0 +1,111 @@ +{{- if .Values.rbac.create -}} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "f5-bigip-ctlr.fullname" . }} + labels: + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/name: {{ template "f5-bigip-ctlr.name" . }} + app: {{ template "f5-bigip-ctlr.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +rules: + - apiGroups: + - '' + - extensions + - networking.k8s.io + - route.openshift.io + resources: + - nodes + - services + - endpoints + - namespaces + - ingresses + - pods + - ingressclasses + - policies + - routes + verbs: + - get + - list + - watch + - apiGroups: + - '' + - extensions + - networking.k8s.io + - route.openshift.io + resources: + - configmaps + - events + - ingresses/status + - services/status + - routes/status + verbs: + - get + - list + - watch + - update + - create + - patch + - apiGroups: + - cis.f5.com + resources: + - virtualservers + - virtualservers/status + - tlsprofiles + - transportservers + - transportservers/status + - ingresslinks + - ingresslinks/status + - externaldnses + - policies + verbs: + - get + - list + - watch + - update + - patch + - apiGroups: + - '' + - extensions + resources: + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - config.openshift.io/v1 + resources: + - network + verbs: + - list +{{- if .Values.args.ipam }} + - apiGroups: + - fic.f5.com + resources: + - ipams + - ipams/status + verbs: + - get + - list + - watch + - update + - create + - patch + - delete + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - list + - watch + - update + - create + - patch +{{- end }} +{{- end }} diff --git a/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-clusterrolebinding.yaml b/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-clusterrolebinding.yaml new file mode 100644 index 000000000..aba54704d --- /dev/null +++ b/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-clusterrolebinding.yaml @@ -0,0 +1,23 @@ +{{- if .Values.rbac.create -}} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "f5-bigip-ctlr.fullname" . }} + namespace: {{ template "f5-bigip-ctlr.namespace" . }} + labels: + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/name: {{ template "f5-bigip-ctlr.name" . }} + app: {{ template "f5-bigip-ctlr.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "f5-bigip-ctlr.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ template "f5-bigip-ctlr.serviceAccountName" . }} + namespace: {{ template "f5-bigip-ctlr.namespace" . }} +{{- end -}} diff --git a/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-deploy.yaml b/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-deploy.yaml new file mode 100644 index 000000000..e7481f44c --- /dev/null +++ b/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-deploy.yaml @@ -0,0 +1,138 @@ +{{- if or (not .Values.args.bigip_url) (not .Values.args.bigip_partition) }} +{{/* +Generate errors for missing required values. +*/}} +# {{required "BIG-IP url not specified - add to Values or pass with `--set` " .Values.args.bigip_url }} +# {{required "BIG-IP partition not specified - add to Values or pass with `--set` " .Values.args.bigip_partition }} +{{- else -}} +apiVersion: {{ template "deployment.apiVersion" . }} +kind: Deployment +metadata: + name: {{ template "f5-bigip-ctlr.fullname" . }} + namespace: {{ template "f5-bigip-ctlr.namespace" . }} + labels: + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/name: {{ template "f5-bigip-ctlr.name" . }} + app: {{ template "f5-bigip-ctlr.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "-" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + app: {{ template "f5-bigip-ctlr.name" . }} + template: + metadata: + labels: + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/name: {{ template "f5-bigip-ctlr.name" . }} + app: {{ template "f5-bigip-ctlr.name" . }} + release: {{ .Release.Name }} + spec: +{{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} +{{- end }} + serviceAccountName: {{ template "f5-bigip-ctlr.serviceAccountName" . }} +{{- if .Values.image.pullSecrets }} + imagePullSecrets: + {{- range $pullSecret := .Values.image.pullSecrets }} + - name: {{ $pullSecret }} + {{- end }} +{{- end }} + securityContext: + {{- $securityContext := .Values.securityContext | default dict }} + {{- if $securityContext.runAsUser }} + runAsUser: {{ $securityContext.runAsUser }} + {{- else }} + runAsUser: 1000 + {{- end }} + {{- $securityContext := .Values.securityContext | default dict }} + {{- if $securityContext.runAsGroup }} + runAsGroup: {{ $securityContext.runAsGroup }} + {{- else }} + runAsGroup: 1000 + {{- end }} + {{- $securityContext := .Values.securityContext | default dict }} + {{- if $securityContext.fsGroup }} + fsGroup: {{ $securityContext.fsGroup }} + {{- else }} + fsGroup: 1000 + {{- end }} + containers: + - name: {{ template "f5-bigip-ctlr.name" . }} + image: "{{ .Values.image.user }}/{{ .Values.image.repo }}:{{ .Values.version }}" + {{- if .Values.podSecurityContext }} + securityContext: +{{ toYaml .Values.podSecurityContext | indent 12 }} + {{- end }} + livenessProbe: + failureThreshold: 3 + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 15 + periodSeconds: 15 + successThreshold: 1 + timeoutSeconds: 15 + readinessProbe: + failureThreshold: 3 + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 15 + volumeMounts: + - name: bigip-creds + mountPath: "/tmp/creds" + readOnly: true + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + - /app/bin/k8s-bigip-ctlr + args: +{{- if .Values.ingressClass.ingressClassName }} + - --ingress-class={{ .Values.ingressClass.ingressClassName | default "f5" }} +{{- end }} + - --credentials-directory + - /tmp/creds + {{- $ns := .Values.args.namespaces }} + {{- range $key, $value := .Values.args }} + {{- if eq $key "namespaces" }} + {{- range $ns}} + - --namespace={{ . }} + {{- end }} + {{- else }} + - --{{ $key | replace "_" "-"}}={{ $value }} + {{- end }} + {{- end }} + resources: + limits: + cpu: {{ .Values.limits_cpu | default "100m" }} + memory: {{ .Values.limits_memory | default "512Mi" }} + requests: + cpu: {{ .Values.requests_cpu | default "100m" }} + memory: {{ .Values.requests_memory | default "512Mi" }} +{{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} +{{- end }} +{{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6}} +{{- end }} + volumes: + - name: bigip-creds + secret: + {{- if .Values.bigip_secret.create }} + secretName: f5-bigip-ctlr-login + {{- else }} + secretName: {{ .Values.bigip_login_secret }} + {{- end }} +{{- end }} diff --git a/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-ingress-class.yaml b/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-ingress-class.yaml new file mode 100644 index 000000000..2105a219a --- /dev/null +++ b/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-ingress-class.yaml @@ -0,0 +1,12 @@ +{{- if .Values.ingressClass.create -}} + +apiVersion: networking.k8s.io/v1 +kind: IngressClass +metadata: + name: {{ .Values.ingressClass.ingressClassName | default "f5" }} + annotations: + ingressclass.kubernetes.io/is-default-class: "{{ .Values.ingressClass.isDefaultIngressController | default false }}" +spec: + controller: f5.com/cntr-ingress-svcs + +{{- end -}} diff --git a/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-secrets.yaml b/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-secrets.yaml new file mode 100644 index 000000000..181415835 --- /dev/null +++ b/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-secrets.yaml @@ -0,0 +1,19 @@ +{{- if .Values.bigip_secret.create -}} +apiVersion: v1 +kind: Secret +metadata: + name: f5-bigip-ctlr-login + namespace: {{ template "f5-bigip-ctlr.namespace" . }} + labels: + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/name: {{ template "f5-bigip-ctlr.name" . }} + app: {{ template "f5-bigip-ctlr.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +type: Opaque +data: + username: {{ .Values.bigip_secret.username | b64enc | quote }} + password: {{ .Values.bigip_secret.password | b64enc | quote }} +{{- end -}} \ No newline at end of file diff --git a/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-serviceaccount.yaml b/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-serviceaccount.yaml new file mode 100644 index 000000000..5729a8bc1 --- /dev/null +++ b/charts/f5/f5-bigip-ctlr/0.0.3201/templates/f5-bigip-ctlr-serviceaccount.yaml @@ -0,0 +1,17 @@ +{{- if .Values.rbac.create -}} +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "f5-bigip-ctlr.serviceAccountName" . }} + namespace: {{ template "f5-bigip-ctlr.namespace" . }} + labels: + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/name: {{ template "f5-bigip-ctlr.name" . }} + app: {{ template "f5-bigip-ctlr.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- end -}} +{{- end -}} diff --git a/charts/f5/f5-bigip-ctlr/0.0.3201/values.yaml b/charts/f5/f5-bigip-ctlr/0.0.3201/values.yaml new file mode 100644 index 000000000..d9952d45a --- /dev/null +++ b/charts/f5/f5-bigip-ctlr/0.0.3201/values.yaml @@ -0,0 +1,90 @@ +# For additional information on installing the k8-bigip-ctlr please see: +# Kubernetes: https://clouddocs.f5.com/containers/latest/userguide/kubernetes/#cis-installation +# OpenShift: https://clouddocs.f5.com/containers/latest/userguide/openshift/#cis-installation +# +# access / permissions / RBAC +# To create a secret using kubectl see +# https://clouddocs.f5.com/containers/latest/userguide/kubernetes/#installing-cis-manually +bigip_login_secret: f5-bigip-ctlr-login + +bigip_secret: + create: false + username: + password: + +rbac: + create: true +serviceAccount: + # Specifies whether a service account should be created + create: true + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: f5-bigip-ctlr-serviceaccount +# This namespace is where the Controller lives; +namespace: kube-system + +ingressClass: + create: true + ingressClassName: f5 + isDefaultIngressController: true +args: + # See https://clouddocs.f5.com/containers/latest/userguide/config-parameters.html + # NOTE: helm has difficulty with values using `-`; `_` are used for naming + # and are replaced with `-` during rendering. + # REQUIRED Params + bigip_url: ~ + bigip_partition: f5-bigip-ctlr + # OPTIONAL PARAMS -- uncomment and provide values for those you wish to use. + # verify_interval: + # node-poll_interval: + # log_level: + # python_basedir: ~ + # VXLAN + # openshift_sdn_name: + # flannel_name: + # KUBERNETES + # default_ingress_ip: + # kubeconfig: + # namespaces: ["foo", "bar"] + # namespace_label: + # node_label_selector: + # pool_member_type: + # resolve_ingress_names: + # running_in_cluster: + # use_node_internal: + # use_secrets: + # insecure: true + # custom-resource-mode: true + # log-as3-response: true + # gtm-bigip-password + # gtm-bigip-url + # gtm-bigip-username + # ipam : true + +image: + # Use the tag to target a specific version of the Controller + user: f5networks + repo: k8s-bigip-ctlr + pullPolicy: Always +version: latest +# affinity: +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchExpressions: +# - key: kubernetes.io/arch +# operator: Exists +# securityContext: +# runAsUser: 1000 +# runAsGroup: 3000 +# fsGroup: 2000 +# If you want to specify resources, uncomment the following +# limits_cpu: 100m +# limits_memory: 512Mi +# requests_cpu: 100m +# requests_memory: 512Mi +# Set podSecurityContext for Pod Security Admission and Pod Security Standards +# podSecurityContext: +# runAsUser: 1000 +# runAsGroup: 1000 +# privileged: true diff --git a/charts/jenkins/jenkins/5.5.14/CHANGELOG.md b/charts/jenkins/jenkins/5.5.14/CHANGELOG.md new file mode 100644 index 000000000..cb39db71c --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/CHANGELOG.md @@ -0,0 +1,3098 @@ +# Changelog + +This file documents all notable changes to the Jenkins Helm Chart. +The release numbering uses [semantic versioning](http://semver.org). + +Use the following links to reference issues, PRs, and commits prior to v2.6.0. + +* Issue: `https://github.com/helm/charts/issues/[issue#]` +* PR: `https://github.com/helm/charts/pull/[pr#]` +* Commit: `https://github.com/helm/charts/commit/[commit]/stable/jenkins` + +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. + +## 5.5.14 + +Update `jenkins/jenkins` to version `2.462.2-jdk17` + +## 5.5.13 + +Update `docker.io/kiwigrid/k8s-sidecar` to version `1.27.6` + +## 5.5.12 + +Update `configuration-as-code` to version `1850.va_a_8c31d3158b_` + +## 5.5.11 + +Update `configuration-as-code` to version `1849.v3a_d20568000a_` + +## 5.5.10 + +Update `git` to version `5.4.1` + +## 5.5.9 + +Update `git` to version `5.4.0` + +## 5.5.8 + +Add `agent.garbageCollection` to support setting [kubernetes plugin garbage collection](https://plugins.jenkins.io/kubernetes/#plugin-content-garbage-collection-beta). + +## 5.5.7 + +Update `kubernetes` to version `4285.v50ed5f624918` + +## 5.5.6 + +Add `agent.useDefaultServiceAccount` to support omitting setting `serviceAccount` in the default pod template from `serviceAgentAccount.name`. +Add `agent.serviceAccount` to support setting the default pod template value. + +## 5.5.5 + +Update `jenkins/inbound-agent` to version `3261.v9c670a_4748a_9-1` + +## 5.5.4 + +Update `jenkins/jenkins` to version `2.462.1-jdk17` + +## 5.5.3 + +Update `git` to version `5.3.0` + +## 5.5.2 + +Update `kubernetes` to version `4280.vd919fa_528c7e` + +## 5.5.1 + +Update `kubernetes` to version `4265.v78b_d4a_1c864a_` + +## 5.5.0 + +Introduce capability of set skipTlsVerify and usageRestricted flags in additionalClouds + + +## 5.4.4 + +Update CHANGELOG.md, README.md, and UPGRADING.md for linting + +## 5.4.3 + +Update `configuration-as-code` to version `1836.vccda_4a_122a_a_e` + +## 5.4.2 + +Update `docker.io/kiwigrid/k8s-sidecar` to version `1.27.5` + +## 5.4.1 + +Update `jenkins/jenkins` to version `2.452.3` + +## 5.4.0 + +Introduce capability of additional mountPaths and logging file paths for config reload container + +## 5.3.6 + +Update `workflow-aggregator` to version `600.vb_57cdd26fdd7` + +## 5.3.5 + +Update `kubernetes` to version `4253.v7700d91739e5` + +## 5.3.4 + +Update `jenkins/jenkins` to version `2.452.3-jdk17` +## 5.3.3 + +Update `jenkins/inbound-agent` to version `3256.v88a_f6e922152-1` + +## 5.3.2 + +Update `kubernetes` to version `4248.vfa_9517757b_b_a_` + +## 5.3.1 + +Fix Tiltfile deprecated value reference + +## 5.3.0 + +Add `controller.topologySpreadConstraints` + +## 5.2.2 + +Update `kubernetes` to version `4246.v5a_12b_1fe120e` + +## 5.2.1 + +Update `jenkins/jenkins` to version `2.452.2-jdk17` + +## 5.2.0 + +Add `agent.inheritYamlMergeStrategy` to allow configuring this setting on the default agent pod template. + +## 5.1.31 + +Update `kubernetes` to version `4245.vf5b_83f1fee6e` + +## 5.1.30 + +Add `controller.JCasC.configMapAnnotations` to allow setting annotations on the JCasC ConfigMaps. + +## 5.1.29 + +Update `docker.io/kiwigrid/k8s-sidecar` to version `1.27.4` + +## 5.1.28 + +Update `docker.io/kiwigrid/k8s-sidecar` to version `1.27.3` + +## 5.1.27 + +Update `kubernetes` to version `4244.v4fb_b_00994a_90` + +## 5.1.26 + +Update `kubernetes` to version `4238.v41b_3ef14a_5d8` + +## 5.1.25 + +Update `kubernetes` to version `4236.vc06f753c3234` + +## 5.1.24 + +Update `kubernetes` to version `4234.vdf3e78112369` + +## 5.1.23 + +Update `kubernetes` to version `4233.vb_67a_0e11a_039` + +## 5.1.22 + +Update `configuration-as-code` to version `1810.v9b_c30a_249a_4c` + +## 5.1.21 + +Update `kubernetes` to version `4231.vb_a_6b_8936497d` + +## 5.1.20 + +Update `kubernetes` to version `4230.vceef11cb_ca_37` + +## 5.1.19 + +Update `docker.io/kiwigrid/k8s-sidecar` to version `1.27.2` + +## 5.1.18 + +Update `configuration-as-code` to version `1807.v0175eda_00a_20` + +## 5.1.17 + +Update `jenkins/inbound-agent` to version `3248.v65ecb_254c298-1` + +## 5.1.16 + +Update `configuration-as-code` to version `1805.v1455f39c04cf` + +## 5.1.15 + +Update `jenkins/jenkins` to version `2.452.1-jdk17` + +## 5.1.14 + +Update `kubernetes` to version `4219.v40ff98cfb_d6f` + +## 5.1.13 + +Update `docker.io/kiwigrid/k8s-sidecar` to version `1.27.1` + +## 5.1.12 + +Update `git` to version `5.2.2` + +## 5.1.11 + +Update `kubernetes` to version `4214.vf10083a_42e70` + +## 5.1.10 + +Update `kubernetes` to version `4211.v08850dd0dfa_3` + +## 5.1.9 + +Update `docker.io/kiwigrid/k8s-sidecar` to version `1.26.2` + +## 5.1.8 + +Update `kubernetes` to version `4209.vc646b_71e5269` + +## 5.1.7 + +Update `kubernetes` to version `4208.v4017b_a_27a_d67` + +## 5.1.6 + +Update `jenkins/jenkins` to version `2.440.3-jdk17` + +## 5.1.5 + +Fix Prometheus controller name. + +## 5.1.4 + +Update `docker.io/bats/bats` to version `1.11.0` + +## 5.1.3 + +Update `jenkins/jenkins` to version `2.440.2-jdk17` + +## 5.1.2 + +Update `kubernetes` to version `4203.v1dd44f5b_1cf9` + +## 5.1.1 + +Update `kubernetes` to version `4199.va_1647c280eb_2` + +## 5.1.0 + +Add `agent.restrictedPssSecurityContext` to automatically inject in the jnlp container a securityContext that is suitable for the use of the restricted Pod Security Standard + +## 5.0.20 + +Update `docker.io/kiwigrid/k8s-sidecar` to version `1.26.1` + +## 5.0.19 + +Introduced helm-docs to automatically generate `values.yaml` documentation. + +## 5.0.18 + +Update `kubernetes` to version `4193.vded98e56cc25` + +## 5.0.17 + +Update `docker.io/kiwigrid/k8s-sidecar` to version `1.26.0` + +## 5.0.16 + +Enable support for deleting plugin configuration files at startup. + +## 5.0.15 + +Fixed changelog entries for previous version bumps + + +## 5.0.14 + +Update `jenkins/jenkins` to version `2.440.1-jdk17` + +## 5.0.13 + +Update `docker.io/kiwigrid/k8s-sidecar` to version `1.25.4` + +## 5.0.12 + +Fix controller.sidecars.additionalSidecarContainers renaming and add tests + +## 5.0.11 + +* Add controller.sidecars.configAutoReload.scheme to specify protocol scheme when connecting Jenkins configuration-as-code reload endpoint +* Add controller.sidecars.configAutoReload.skipTlsVerify to force the k8s-sidecar container to skip TLS verification when connecting to an HTTPS Jenkins configuration-as-code reload endpoint + +## 5.0.10 + +Update `jenkins/inbound-agent` to version `3206.vb_15dcf73f6a_9-3` + +## 5.0.9 + +Update `kubernetes` to version `4186.v1d804571d5d4` + +## 5.0.8 + +Update `configuration-as-code` to version `1775.v810dc950b_514` + +## 5.0.7 + +Update `docker.io/kiwigrid/k8s-sidecar` to version `docker.io/kiwigrid/k8s-sidecar` + +## 5.0.6 + +Removed `docker.io` prefix from inbound-agent image + +## 5.0.5 + +Prefixed artifacthub.io/images with `docker.io` + +## 5.0.4 + +Updated super-linter to v6. Updated README.md and CHANGELOG.md to fix linting issues. + +## 5.0.2 + +Update `git` to version `5.2.1` + +## 5.0.1 + +Update `docker.io/bats/bats` to version `v1.10.0` + +## 5.0.0 + + > [!CAUTION] + > Several fields have been renamed or removed. See [UPGRADING.md](./UPGRADING.md#to-500) + +The Helm Chart is now updated automatically via [Renovate](https://docs.renovatebot.com/) + +## 4.12.1 + +Update Jenkins image and appVersion to jenkins lts release version 2.426.3 + +## 4.12.0 + +Add support for [generic ephemeral storage](https://github.com/jenkinsci/kubernetes-plugin/pull/1489) in `agent.volumes` and `agents.workspaceVolume`. + +| plugin | old version | new version | +|------------|---------------------|--------------------| +| kubernetes | 4029.v5712230ccb_f8 | 4174.v4230d0ccd951 | + +## 4.11.2 + +Fixed documentation for controller.initScripts. + +## 4.11.1 + +Updated helm-unittest and made unittests compatible. + +## 4.11.0 + +Add multi-cloud support. + +## 4.10.0 + +Bumped Jenkins inbound agent from 3107.v665000b_51092-15 to 3192.v713e3b_039fb_e-5. + +## 4.9.2 + +Update Jenkins image and appVersion to jenkins lts release version 2.426.2 + + +Notes about [Artifact Hub](https://artifacthub.io/packages/helm/jenkinsci/jenkins?modal=changelog) changelog processing: +- Remove empty lines +- Keep only ASCII characters (no emojis) +- One change per line +- Remove table(s) (lines starting by "|") +- Backticks aren't rendered on artifacthub.io changelog + +## 4.9.1 + +Restore artifact hub notes location in CHANGELOG.md + +## 4.9.0 + +Update base images from JDK 11 to JDK 17. + +## 4.8.6 + +Proper `artifacthub.io/changes` changelog annotation preprocessing. + +## 4.8.5 + +Fix `artifacthub.io/changes` changelog annotation added to the released chart. + +## 4.8.4 + +Add `artifacthub.io/changes` changelog annotation to the released chart. + +## 4.8.3 + +Update Jenkins image and appVersion to jenkins lts release version 2.426.1 + +## 4.8.2 + +Add the ability to modify `retentionTimeout` and `waitForPodSec` default value in JCasC + +## 4.8.1 + +Reintroduces changes from 4.7.0 (reverted in 4.7.1), with additional fixes: + +- METHOD is now allowed in `env` and is not duplicated anymore +- No calls to JCasC reload endpoint from the init container + +## 4.8.0 + +Adds support for ephemeralStorage request and limit in Kubernetes plugin JCasC template + +## 4.7.4 + +Add the config-init-script checksum into the controller statefullset pod annotations to trigger restart of the pod in case of updated init scripts. + +## 4.7.3 + +Update Jenkins image and appVersion to jenkins lts release version 2.414.3 + +## 4.7.1 + +Changes in 4.7.0 were reverted. + +## 4.7.0 + +Runs `config-reload` as an init container, in addition to the sidecar container, to ensure that JCasC YAMLs are present before the main Jenkins container starts. This should fix some race conditions and crashes on startup. + +## 4.6.7 + +Change jenkins-test image label to match the other jenkins images + +## 4.6.5 + +Update Jenkins image and appVersion to jenkins lts release version 2.414.2 + +## 4.6.4 + +Introducing TPL function on variables related to hostname in `./charts/jenkins/templates/jenkins-controller-ingress.yaml` + +## 4.6.3 + +Add values to documentation + +## 4.6.2 + +Update word from hundreds to over 1800 to align with blurb at . + +## 4.6.1 + +Update `configuration-as-code` plugin to fix dependency issues with `azure-ad` plugin + +## 4.6.0 + +Added `.Values.controller.httpsKeyStore.jenkinsHttpsJksSecretKey` to allow overriding the default secret key containing the JKS file. +Added `.Values.controller.httpsKeyStore.jenkinsHttpsJksPasswordSecretName` to allow getting the JKS password from a different secret. +Added `.Values.controller.httpsKeyStore.jenkinsHttpsJksPasswordSecretKey` to allow overriding the default secret key containing the JKS password. + +## 4.5.1 + +Update Jenkins image and appVersion to jenkins lts release version 2.414.1 + + +## 4.5.0 + +Added `.Values.persistence.dataSource` to allow cloning home PVC from existing dataSource. + +## 4.4.2 + +Update Jenkins image and appVersion to jenkins lts release version 2.401.3 + + +## 4.4.1 + +Added `.Values.agent.jnlpregistry` to allow agents to be configured with private registry. + +## 4.4.0 + +Add config keys for liveness probes on agent containers. + + +## 4.3.30 + +Update Jenkins version in controller test matching LTS version + +## 4.3.29 + +Update Jenkins image and appVersion to jenkins lts release version 2.401.2 + + +## 4.3.28 + +Allow the kubernetes API server URL to be configurable. + +## 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 + + +## 4.3.23 + +Update Jenkins image and appVersion to jenkins lts release version 2.387.3 + + +## 4.3.22 + + +Bump chart version. + +## 4.3.21 + + +Document building charts for weekly releases. + +## 4.3.20 + + +Enhance repository appearance and miscellaneous cleanup. + +## 4.3.19 + + +Comply with superlinter rules and address ShellCheck issues. + +## 4.3.18 + + +Bump kiwigrid/k8s-sidecar from 1.15.0 to 1.23.1. + +## 4.3.17 + + +Bump jenkins/inbound-agent from 4.11.2-4 to 3107.v665000b_51092-5. + +## 4.3.16 + + +Update bundled plugins: +- [ldap](https://plugins.jenkins.io/ldap/): From 2.5 to 671.v2a_9192a_7419d +- [kubernetes](https://plugins.jenkins.io/kubernetes/): From 3734.v562b_b_a_627ea_c to 3900.va_dce992317b_4 +- [workflow-aggregator](https://plugins.jenkins.io/workflow-aggregator/): From 590.v6a_d052e5a_a_b_5 to 590.v6a_d052e5a_a_b_5 +- [configuration-as-code](https://plugins.jenkins.io/configuration-as-code/): From 1569.vb_72405b_80249 to 1625.v27444588cc3d + +## 4.3.15 + + +Update bats from 1.2.1 to 1.9.0. + +## 4.3.14 + + +Update various GH actions, typo fixes, and miscellaneous chores. + +## 4.3.13 + + +Bump helm-unittest from 0.2.8 to 0.2.11. + +## 4.3.12 + + +Update wording in values.yml. + +## 4.3.11 + +Update Jenkins image and appVersion to jenkins lts release version 2.387.2 + + +## 4.3.10 + +Correct incorrect env var definition +Disable volume mount if disableSecretMount enabled + +## 4.3.9 + +Document `.Values.agent.directConnection` in readme. +Add default value for `.Values.agent.directConnection` to `values.yaml` + +## 4.3.8 + +Added `.Values.agent.directConnection` to allow agents to be configured to connect direct to the JNLP port on the +controller, preventing the need for an external HTTP endpoint for this purpose. + +## 4.3.7 + +Added `.Values.controller.shareProcessNamespace` and `.Values.controller.httpsKeyStore.disableSecretMount` to enable sourcing TLS certs from external issuers + +## 4.3.6 + +Update Jenkins image and appVersion to jenkins lts release version 2.387.1 + +## 4.3.5 + +Added `.Values.helmtest.bats.image` and `.Values.helmtest.bats.image` to allow unit tests to be configurable. Fixes [https://github.com/jenkinsci/helm-charts/issues/683] + +## 4.3.4 + +Update Jenkins image and appVersion to jenkins lts release version 2.375.3 + + +## 4.3.3 + +Removed hardcoding of chart version in tests to make maintenance easier + +## 4.3.2 + +Added `.Values.serviceAccount.extraLabels` on Service Account +Added `.Values.serviceAccountAgent.extraLabels` on Agent's Service Account + + +## 4.3.0 + +Moved use of `.Values.containerEnv` within `jenkins` Container to top of `env` block to allow for subsequent Environment Variables to reference these additional ones. + +## 4.2.21 + +Update Jenkins image and appVersion to jenkins lts release version 2.375.2 + + +## 4.2.20 + +Fixed the `controller.prometheus.metricRelabelings` being unable to convert the value to the ServiceMonitor. +Added `controller.prometheus.relabelings` to allow relabling before scrape. +Added default values for `controller.prometheus.relabelings` and `controller.prometheus.metricRelabelings`. + +## 4.2.19 + +CronJob API version upgraded to batch/v1 + +## 4.2.18 + +Added option to set secretEnvVars. + +## 4.2.17 + +Update Jenkins image and appVersion to jenkins lts release version 2.375.1 + + +## 4.2.16 + +Fixed chart notes not rendering Jenkins URL with prefix when `controller.jenkinsUriPrefix` is set. +Fixed chart notes not rendering Jenkins URL with `https` when `controller.ingress.tls` or `controller.controller.httpsKeyStore.enable` is set. +Fixed chart notes rendering wrong JCasC URL when not using `controller.ingress`. + +## 4.2.15 + +Update Jenkins image and appVersion to jenkins lts release version 2.361.4 + +## 4.2.14 + +Added option to mount all keys from an existing k8s secret + +## 4.2.13 + +Adding `tpl` to `controller.additionalExistingSecrets` + +## 4.2.12 + +Update Jenkins image and appVersion to jenkins lts release version 2.361.3 + + +## 4.2.11 + +Update default plugin versions + +| plugin | old version | new version | +|-----------------------|-----------------------|------------------------| +| kubernetes | 3706.vdfb_d599579f3 | 3734.v562b_b_a_627ea_c | +| git | 4.11.5 | 4.13.0 | +| configuration-as-code | 1512.vb_79d418d5fc8 | 1569.vb_72405b_80249 | + +## 4.2.10 +Fix grammar and typos + +## 4.2.9 +Update Jenkins image and appVersion to jenkins lts release version 2.361.2 + +## 4.2.8 +Modify the condition to trigger copying jenkins_config files when configAutoReload option is disabled during Jenkins initialization + +## 4.2.7 +Support for remote URL for configuration + +## 4.2.6 +Add option to set hostnetwork for agents + +## 4.2.5 +Add an extra optional argument to extraPorts in order to specify targetPort + +## 4.2.4 +Remove k8s capibility requirements when setting priority class for controller + +## 4.2.3 Update plugin versions + +| plugin | old version | new version | +| --------------------- | --------------------- | --------------------- | +| kubernetes | 3600.v144b_cd192ca_a_ | 3706.vdfb_d599579f3 | +| workflow-aggregator | 581.v0c46fa_697ffd | 590.v6a_d052e5a_a_b_5 | +| configuration-as-code | 1429.v09b_044a_c93de | 1512.vb_79d418d5fc8 | +| git | 4.11.3 | 4.11.5 | + +Resolve version conflict between default install of plugins. + +## 4.2.2 + +Support Google Managed Prometheus + +## 4.2.1 + +Remove option to provide command and args of agent as YAML. This feature was never supported by the Jenkins Kubernetes +plugin. + +## 4.2.0 + +Add option to provide additional containers to agents + +## 4.1.18 + +Update Jenkins image and appVersion to jenkins lts release version 2.361.1 + + +## 4.1.17 + +Update Jenkins casc default settings to allow `security` configs to be provided + + +## 4.1.16 + +Update Jenkins image and appVersion to jenkins lts release version 2.346.3 + + +## 4.1.15 + +`projectNamingStrategy` is configurable in default config. + +## 4.1.14 + +If `installPlugins` is disabled, don't create unused plugins volume. + +## 4.1.13 + +Update Jenkins image and appVersion to jenkins lts release version 2.346.2 + + +## 4.1.12 + +If keystore is defined, it is now also made available in the initContainer. + +## 4.1.11 + +JCasC ConfigMaps now generate their name from the `jenkins.casc.configName` helper + +## 4.1.10 + +Update Jenkins image and appVersion to jenkins lts release version 2.346.1 + + +## 4.1.9 + +Allow setting `imagePullSecret` for backup job via `backup.imagePullSecretName` + +## 4.1.8 + +Fix path of projected secrets from `additionalExistingSecrets`. + +## 4.1.7 + +Update readme with explanation on the required environmental variable `AWS_REGION` in case of using an S3 bucket. + +## 4.1.6 + +project adminSecret, additionalSecrets and additionalExistingSecrets instead of mount with subPath + +## 4.1.5 + +Update readme to fix `JAVA_OPTS` name. + +## 4.1.4 +Update plugins + +## 4.1.3 +Update jenkins-controller-statefulset projected volumes definition + +## 4.1.1 +Added 'controller.prometheus.metricRelabelings' to allow relabling and dropping unused prometheus metrics + +## 4.1.0 + +Added `controller.sidecars.configAutoReload.envFrom`, `controller.initContainerEnvFrom`, `controller.containerEnvFrom` + +## 4.0.1 + +No code changes - CI updated to run unit tests using Helm 3.8.2. + +## 4.0.0 + +Removes automatic `remotingSecurity` setting when using a container tag older than `2.326` (introduced in [`3.11.7`](#3117)). If you're using a version older than `2.326`, you should explicitly set `.controller.legacyRemotingSecurityEnabled` to `true`. + +## 3.12.2 + +Update Jenkins image and appVersion to jenkins lts release version 2.332.3 + +## 3.12.1 + +Make namespace configurable for agents and additional agents. + +## 3.12.0 + +Added a flag for disabling the default Jenkins Agent configuration. + +## 3.11.10 + +Update Jenkins image and appVersion to jenkins lts release version 2.332.2 + +## 3.11.9 Bump configuration-as-code plugin version + +| plugin | old version | new version | +| --------------------- | ----------- | ----------- | +| configuration-as-code | 1.51 | 1414.v878271fc496f | + +## 3.11.8 + +Make [externalTrafficPolicy](https://kubernetes.io/docs/concepts/services-networking/service/#traffic-policies) and `loadBalancerSourceRanges` fields customizable for Agent listener service via `controller.agentListenerExternalTrafficPolicy` and `controller.loadBalancerSourceRanges`. + +## 3.11.7 + +Removed Configuration as Code `remotingSecurity` section for Jenkins 2.326 or newer. See [Documentation](https://www.jenkins.io/redirect/AdminWhitelistRule) to learn more. + +## 3.11.6 + +Update Jenkins image and appVersion to jenkins lts release version 2.332.1 + + +## 3.11.5 + +Change Backup Role name function call to match the RoleDef function call in the Backup RoleBinding + +## 3.11.4 + +Update Jenkins image and appVersion to jenkins lts release version 2.319.3 + + +## 3.11.3 + +Update kiwigrid/k8s-sidecar:1.15.0 +Update jenkins/inbound-agent:4.11.2-4 + +## 3.11.2 + +Improve example for workspaceVolume. Clarify that this is not a list. + +## 3.11.1 + +Update configuration-as-code plugin to 1.55.1 + + +## 3.11.0 + +Update default plugin versions + +| plugin | old version | new version | +| --------------------- | ----------- | ----------- | +| kubernetes | 1.31.1 | 1.31.3 | +| git | 4.10.1 | 4.10.2 | + +## 3.10.3 + +Update Jenkins image and appVersion to jenkins lts release version 2.319.2 + + +## 3.10.2 + +Fix definition of startupProbe when deploying on a Kubernetes cluster < 1.16 + +## 3.10.1 + +correct VALUES_SUMMARY.md for installLatestPlugins + +## 3.10.0 + +Update default plugin versions + +| plugin | old version | new version | +| --------------------- | ----------- | ----------- | +| kubernetes | 1.30.11 | 1.31.1 | +| git | 4.10.0 | 4.10.1 | +| configuration-as-code | 1.54 | 1.55 | + +## 3.9.4 + +Add JAVA_OPTIONS to the readme so proxy settings get picked by jenkins-plugin-cli + +## 3.9.3 + +Fix config reload request URL when httpsKeystore in use + +## 3.9.2 + +Update Jenkins image and appVersion to jenkins lts release version 2.319.1 +Update following plugins: + +* kubernetes:1.30.11 +* git:4.10.0 +* configuration-as-code:1.54 + +## 3.9.1 + +Adding `tpl` to `controller.overrideArgs` + +## 3.9.0 + +Added containerSecurityContext + +## 3.8.9 + +Fix mounting of HTTPS keystore secret when httpsKeyStore is enabled + +## 3.8.8 + +Update Jenkins image and appVersion to jenkins lts release version 2.303.3 + +## 3.8.7 + +Adding `tpl` to `initScripts` + +## 3.8.6 + +Add `controller.tagLabel` to specify the label for the image tag, for example `jdk11` or `alpine` + +## 3.8.5 + +Move jenkins web root outside of home dir + +## 3.8.4 + +Add `controller.initConfigMap` to pass pre-existing `init.groovy.d` ConfigMaps to the controller + +## 3.8.3 + +Update missed reference to jenkins/inbound-agent:4.11-1 + +## 3.8.2 + +Update jenkins/inbound-agent:4.11-1 + +## 3.8.1 + +Update jenkins/inbound-agent:4.10-3 + +## 3.8.0 + +Update kiwigrid/k8s-sidecar:1.14.2 + +## 3.7.1 + +Update git and casc plugins versions + +## 3.7.0 + +Added the option to create AWS SecurityGroupPolicy resources + +## 3.6.2 + +Fix httpsKeyStore mount when `controller.httpsKeyStore.enable` is `true` + +## 3.6.1 + +Update Jenkins image and appVersion to jenkins lts release version 2.303.2 + + +## 3.6.0 +Support custom agent pod labels + +## 3.5.20 +Disallow ingress on port 50000 when agent listener is disabled + +## 3.5.19 +Add support for specifying termination-log behaviour for Jenkins controller + +## 3.5.18 +Add support for creating a Pod Disruption Budget for Jenkins controller + +## 3.5.17 +Update workdingDir to `/home/jenkins/agent` + +## 3.5.16 +Update location of icon (wiki.jenkins.io is down) + +## 3.5.15 +Add support for adding labels to the Jenkins home Persistent Volume Claim (pvc) + +## 3.5.14 + +* Updated versions of default plugins +* Use verbose logging during plugin installation +* download the latest version of all plugin dependencies (Fixes #442) + +## 3.5.13 + +Update Jenkins image and appVersion to jenkins lts release version 2.303.1 + +## 3.5.12 + +Added extended documentation for Backup and Restore. + +## 3.5.11 + +Sanitized the Jenkins Label + +## 3.5.10 + +Fixed `controller.customJenkinsLabels` not getting templated into the controller `labelString:` field in JCasC + +## 3.5.9 + +Update Jenkins image and appVersion to jenkins lts release version 2.289.3 + + +## 3.5.8 + +Add parameter `backup.serviceAccount.create` to disable service account creation for backup service and `backup.serviceAccount.name` to allow change of the SA name. +`backup.annotations` was moved to `backup.serviceAccount.annotations` + +## 3.5.7 + +Enable setting `controller.serviceExternalTrafficPolicy` to set [the standard Service option](https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip). `externalTrafficPolicy` denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints. + +## 3.5.6 + +Add optional `controller.initContainerResources`, if set, it will change resources allocation for init controller, overwise the `controller.resources` will be used + +## 3.5.5 + +Allow to configure nodeUsageMode via `agent.nodeUsageMode` + +## 3.5.4 + +Update tests to work with unittest 0.2.6 + +## 3.5.3 + +Update Jenkins image and appVersion to jenkins lts release version 2.289.2 + +## 3.5.2 + +Enable setting `controller.installLatestSpecifiedPlugins` to set whether to download the latest dependencies of any plugin that is requested to have the latest version. + +## 3.5.1 +Fix activeDeadlineSeconds wrong type bug in jenkins-backup-cronjob template + +## 3.5.0 + +Allow `controller.podAnnotations` to be render as a template + +## 3.4.1 + +Allow showRawYaml for the default agent's pod template to be customized. + +## 3.4.0 + +configAutoReload container updated from `kiwigrid/k8s-sidecar:0.1.275` to `kiwigrid/k8s-sidecar:1.12.2` + +## 3.3.23 + +Make `controller.ingress.resourceRootUrl` compatible with API version networking.k8s.io/v1 on k8s >= 1.19.x + +## 3.3.22 + +Update Jenkins image and appVersion to jenkins lts release version 2.289.1 + +## 3.3.21 +`persistence.mounts` additionally mount to init container to allow custom CA certificate keystore + +## 3.3.18 +Added `controller.overrideArgs` so any cli argument can be passed to the WAR. + +## 3.3.17 +Correct docs on disabling plugin installation + +## 3.3.16 +Support generating `SecretClaim` resources in order to read secrets from HashiCorp Vault into Kubernetes using `kube-vault-controller`. + +## 3.3.15 +Prevent `controller.httpsKeyStore` from improperly being quoted, leading to an invalid location on disk + +## 3.3.14 +Correct docs on disabling plugin installation + +## 3.3.13 +Update plugins + +## 3.3.12 +Add `controller.additionalExistingSecrets` property + +## 3.3.11 +Add support for disabling the Agent listener service via `controller.agentListenerEnabled`. + +## 3.3.10 +Update Jenkins image and appVersion to jenkins lts release version 2.277.4 + +## 3.3.9 +* Change helper template so user defined `agent.jenkinsUrl` value will always be used, if set +* Simplify logic for `jenkinsUrl` and `jenkinsTunnel` generation: always use fully qualified address + +## 3.3.8 +Update Jenkins image and appVersion to jenkins lts release version 2.277.3 + +## 3.3.7 +fix controller-ingress line feed bug + +## 3.3.6 + +Update Git plugin version to v4.7.1 +Update ldap plugin version to v2.5 + +## 3.3.5 + +Use tpl function for environment vars. Fixes [https://github.com/jenkinsci/helm-charts/issues/324] + +## 3.3.4 + +Update Jenkins image and appVersion to jenkins lts release version 2.277.2 + + +## 3.3.3 + +Enable setting `controller.installLatestPlugins` to set whether to download the minimum required version of all dependencies. + +## 3.3.2 + +Add `controller.additionalSecrets` documentation + +## 3.3.1 + +Add `controller.additionalSecrets` property + +## 3.3.0 + +Change default Jenkins image to `jdk11` variant + +## 3.2.6 + +Add missing `controller.jenkinsUrlProtocol` property + +## 3.2.5 + +Add additional metadata `artifacthub.io/images` for artifacthub + +## 3.2.4 +Update Jenkins image and appVersion to jenkins lts release version 2.277.1 +Update Git plugin version to v4.6.0 +Update kubernetes plugin version to v1.29.2 + +## 3.2.3 + +Fix rendering `controller.ingress.path` + +## 3.2.2 + +Added description for `controller.jenkinsUrl` value + +## 3.2.1 + +Enable setting ImagePullSecrets to controller and agent service accounts. + +## 3.2.0 + +Calculate consistent unique agent IDs to be used in pod templates. Fixes [https://github.com/jenkinsci/helm-charts/issues/270] + +## 3.1.15 + +Fix documentation for the kubernetes probes + +## 3.1.14 + +Typo in documentation + +## 3.1.13 + +Update Jenkins image and appVersion to jenkins lts release version 2.263.4 + +## 3.1.12 + +Added GitHub Action to automate the updating of LTS releases. + +## 3.1.11 + +Enable setting controller.updateStrategy to change the update strategy for StatefulSet + +## 3.1.10 + +Fixed issue for the AgentListener where it was not possible to attribute a NodePort + +## 3.1.9 + +Upgrade kubernetes plugin to 1.29.0 and CasC plugin to 1.47 + +## 3.1.8 + +Fix init scripts config map name + +## 3.1.7 + +Fix missing newline when `httpsKeyStore` is enabled + +## 3.1.6 + +Mount controller init scripts from ConfigMap + +## 3.1.5 + +Fix `namespaceOverride` not applied when loading JCasC + +## 3.1.4 + +Update Git plugin version to v4.5.2 + +## 3.1.3 + +Update Jenkins image and appVersion to jenkins lts release version 2.263.3 + +## 3.1.2 + +Enable setting maxRequestsPerHostStr to change the max concurrent connections to Kubernetes API + +## 3.1.1 + +Update Jenkins image and appVersion to jenkins lts release version 2.263.2 + +## 3.1.0 + +* Added `.Values.controller.podSecurityContextOverride` and `.Values.backup.podSecurityContextOverride`. +* Added simple default values tests for `jenkins-backup-cronjob.yaml`. + +## 3.0.14 + +Enable to only backup job folder instead of whole jenkins + +## 3.0.13 + +Improve Documentation around JCasc and Custom Image + +## 3.0.12 + +Added GitHub Action testing on Kind 1.16, 1.17, 1.18, 1.19 & 1.20 + +## 3.0.11 + +Fixes & unit tests for Ingress resources on Kubernetes 1.19 and above + +## 3.0.10 + +Ingress resources on Kubernetes 1.19 (or above) are created with the version `networking.k8s.io/v1` + +## 3.0.9 + +Added support for backing up to Azure Blob Storage. + +## 3.0.8 + +* Typo in documentation + +## 3.0.7 + +* Add support for setting default agent workspaceVolume + +## 3.0.6 + +Use 2.263.1 image + +## 3.0.5 + +* Update appVersion to reflect new jenkins lts release version 2.263.1 + +## 3.0.4 + +* Fix documentation for additional secret mounts + +## 3.0.3 + +* Update `README.md` with explanation on how to mount additional secrets + +## 3.0.2 + +* Fix `.Values.controller.tolerations` and `.Values.controller.nodeSelector` variable names in templates\jenkins-backup-cronjob.yaml + +## 3.0.1 + +* added 'runAsNonroot' to security context + +## 3.0.0 + +* Chart uses StatefulSet instead of Deployment +* XML configuration was removed in favor of JCasC +* chart migrated to helm 3.0.0 (apiVersion v2) +* offending terms have been removed +* values have been renamed and re-ordered to make it easier to use +* already deprecated items have been removed +* componentName for the controller is now `jenkins-controller` +* componentName for the agent is now `jenkins-agent` +* container names are now + * `init` for the init container which downloads Jenkins plugins + * `jenkins` for the Jenkins controller + * `config-reload` for the sidecar container which automatically reloads JCasC +* Updated UI tests to use official `bats/bats` image instead of `dduportal/bats` + +For migration instructions from previous versions and additional information check README.md. + +## 2.19.0 + +* Use lts version 2.249.3 +* Update kubernetes, workflow-aggregator, git and configuration-as-code plugins. +* Fail apply_config.sh script if an error occurs. + +## 2.18.2 + +Fix: `master.javaOpts` issue with quoted values + +## 2.18.1 + +Recommend installing plugins in custom image + +## 2.18.0 + +Removed /tmp volume. Making /tmp a volume causes permission issues with jmap/jstack on certain Kubernetes clusters + +## 2.17.1 + +Fix location of jenkins.war file. +It is located in `/usr/share/jenkins/jenkins.war` and can be fonfigured via `master.jenkinsWar`. + +## 2.17.0 + +Add support for plugin-installation-manager-tool + +## 2.16.0 + +Added Startup probe for Jenkins pod when Kubernetes cluster is 1.16 or newer + +## 2.15.5 + +scriptApproval is taken into account when enableXmlConfig is false. + +## 2.15.4 + +Add Tilt support for easier helm chart development. + +## 2.15.3 + +Fix error on missing `ingress.paths` value + +## 2.15.2 + +Added documentation for ingress and jenkins URL + +## 2.15.1 + +Fix priorityClassName entry in values.yaml file + +## 2.15.0 + +Added support for disabling the helm.sh/chart annotation + +## 2.14.0 + +Added support for annotations in podTemplates + +## 2.13.2 + +Add nodeSelector in the backup pod +Fix tolerations in the backup pod + +## 2.13.1 + +Update list of maintainers + +## 2.13.0 + +Added Support for websockets in the default Jcasc config +Added trailing slash to JENKINS_URL env var + +## 2.12.2 + +Added unit tests for most resources in the Helm chart. + +## 2.12.1 + +Helm chart readme update + +## 2.12.0 + +Add option to configure securityContext capabilities + +## 2.11.0 + +Added configurable security context for jenkins backup CronJob and annotations to its serviceaccount. + +## 2.10.0 + +Make activeDeadlineSeconds for backup job configurable + +## 2.9.0 + +Make namespace of PrometheusRule configurable + +## 2.8.2 + +Bumped configuration-as-code plugin version from 1.41 to 1.43. +See [configuration-as-code plugin issue #1478](https://github.com/jenkinsci/configuration-as-code-plugin/issues/1478) + +## 2.8.1 + +Fix indentation of JAVA_OPTS + +## 2.8.0 + +Add support for helm unittest and include first tests + +## 2.7.2 + +Target port of container `jenkins-sc-config` taken the value from values.yaml. + +## 2.7.0 + +Add a secondary ingress template for those who want a second ingress with different labels or annotations or whatever else. + +Example: You want /github-webhook to be on a public ingress, while the main Jenkins intance to be on a private locked down ingress. + +## 2.6.5 + +Update configScripts example + +## 2.6.4 + +Add timja as a maintainer + +## 2.6.3 + +Update k8s-sidecar image to 0.1.193 + +## 2.6.2 + +Only mount empty dir secrets-dir if either `master.enableXmlConfig` or `master.secretsFilesSecret` is set +Fixes #19 + +## 2.6.1 Do not render empty JCasC templates + +## 2.6.0 First release in jenkinsci GitHub org + +Updated readme for new location + +## 2.5.2 + +Fix as per JENKINS-47112 + +## 2.5.1 + +Support Jenkins Resource Root URL + +## 2.5.0 + +Add an option to specify that Jenkins master should be initialized only once, during first install. + +## 2.4.1 + +Reorder readme parameters into sections to facilitate chart usage and maintenance + +## 2.4.0 Update default agent image + +`jenkins/jnlp-slave` is deprected and `jenkins/inbound-agent` should be used instead. +Also updated it to newest version (4.3-4). + +## 2.3.3 correct templating of master.slaveJenkinsUrl + +Fixes #22708 + +## 2.3.2 Fix wrong value for overwritePluginsFromImage + +Fixes #23003 +Fixes #22633 + +Also fixes indentation for #23114 + +## 2.3.1 + +Always mount {{ .Values.master.jenkinsRef }}/secrets/ directory. Previous it +was mounted only when `master.enableXmlConfig` was enabled. + +## 2.3.0 + +Add an option to specify pod based on labels that can connect to master if NetworkPolicy is enabled + +## 2.2.0 increase retry for config auto reload + +Configure `REQ_RETRY_CONNECT` to `10` to give Jenkins more time to start up. + + +Value can be configured via `master.sidecars.configAutoReload.reqRetryConnect` + +## 2.1.2 updated readme + +## 2.1.1 update credentials-binding plugin to 1.23 + +## 2.1.0 + +Add support to set `runAsUser` and `runAsGroup` for `agent`. + +## 2.0.1 + +Only render authorizationStrategy and securityRealm when values are set. + +## 2.0.0 Configuration as Code now default + container does not run as root anymore + +The readme contains more details for this update. +Please note that the updated values contain breaking changes. + +## 1.27.0 Update plugin versions & sidecar container + +| plugin | old version | new version | +| --------------------- | ----------- | ----------- | +| kubernetes | 1.25.3 | 1.25.7 | +| workflow-job | 2.38 | 2.39 | +| credentials-binding | 1.21 | 1.22 | +| configuration-as-code | 1.39 | 1.41 | + +configAutoReload container updated from `kiwigrid/k8s-sidecar:0.1.132` to `kiwigrid/k8s-sidecar:0.1.144` + +## 1.26.0 + +Add support to override `workingDir` for default pod template + +## 1.25.0 + +Add support for installing plugins in addition to the chart's default plugins via `master.additionalPlugins` + +## 1.24.0 + +Allow configuration of yamlMergeStrategy via `agent.yamlMergeStrategy` + +## 1.23.2 + +In the `jenkins.xml.podTemplate` helper function, allow templating of all string values under `agent.volumes` except `type` by rendering them with the `tpl` function + +## 1.23.1 + +Added auto detection for Ingress API version + +## 1.23.0 + +Allow to use an existing secret for the jenkins admin credentials + +## 1.22.0 + +Add support for UI security in the default JCasC via `master.JCasC.securityRealm` and `master.JCasC.authorizationStrategy` which deny anonymous access by default + +## 1.21.3 + +Render `agent.envVars` in kubernetes pod template JCasC + +## 1.21.2 + +Cleanup `agent.yamlTemplate` rendering in kubernetes pod template XML configuration + +## 1.21.1 + +Render `agent.nodeSelector` in the kubernetes pod template JCasC + +## 1.21.0 + +Add support for overriding Ingress paths via `master.ingress.paths` + +## 1.20.0 + +Add the following options for configuring the Kubernetes plugin. + +- master.slaveDefaultsProviderTemplate +- master.slaveJenkinsUrl +- master.slaveJenkinsTunnel +- master.slaveConnectTimeout +- master.slaveReadTimeout + +## 1.19.0 + +Add support for disabling remember me via `master.disableRememberMe` +Add support for using a different markup formatter via `master.markupFormatter` + +## 1.18.1 + +Add support for executor mode configuraton with `master.executorMode`. + +## 1.18.0 Make installation of configuration-as-code plugin explicit + +Instead of configuring the configuration-as-code plugin version via +`master.JCasC.pluginVersion` it is now installed via `master.installPlugins` + +## 1.17.2 + +Allow templating of `serviceAccount.annotations` and `serviceAccountAgent.annotations` by rendering them with the `tpl` function + +## 1.17.1 + +Add support for Persistent Volume Claim (PVC) in `agent.volumes` + +## 1.17.0 + +Render `agent.volumes` in kubernetes pod template JCasC + +## 1.16.2 + +Reverts 1.16.1 as it introduced an error #22047 + +## 1.16.1 + +Fixed a bug with master.runAsUser variable due to use wrong type for comparison. + +## 1.16.0 + +Add `master.overwritePluginsFromImage` to allow support for jenkins plugins installed in the master image to persist. + +## 1.15.0 Update plugin versions & sidecar container + +| plugin | old version | new version | +| --------------------- | ----------- | ----------- | +| kubernetes | 1.25.1 | 1.25.3 | +| workflow-job | 2.36 | 2.38 | +| git | 4.2.0 | 4.2.2 | +| configuration-as-code | 1.36 | 1.39 | + +configAutoReload container updated from `kiwigrid/k8s-sidecar:0.1.20` to `kiwigrid/k8s-sidecar:0.1.132` + +## 1.14.0 + +support auto-reload container environment variables configuration + +## 1.13.3 + +Fix wrong indent in tolerations + +## 1.13.2 + +Add support for custom ClusterIP + +## 1.13.1 + +Fix `agent.yamlTemplate` rendering in kubernetes pod template JCasC + +## 1.13.0 + +Add `master.networkPolicy.internalAgents` and `master.networkPolicy.externalAgents` stanzas to fine grained controls over where internal/external agents can connect from. Internal ones are allowed based on pod labels and (optionally) namespaces, and external ones are allowed based on IP ranges. + +## 1.12.0 Support additional agents + +Add support for easy configuration of additional agents which inherit values from `agent`. + +## 1.11.3 + +Update the kubernetes plugin from 1.24.1 to 1.25.1 and grant 'watch' permission to 'events' which is required since this plugin version. + +## 1.11.2 Configure agent.args in values.yaml + +## 1.11.1 Support for master.additionalConfig + +Fixed a bug with jenkinsHome variable in range block when master.additionalConfig is set - Helm cannot evaluate field Values in type interface {}. + +## 1.11.0 Add support for configuring custom pod templates + +Add `agent.podTemplates` option for declaring custom pod templates in the default configured kubernetes cloud. + +## 1.10.1 Only copy JCasC files if there are any + +The chart always tried to copy Configuration as Code configs even if there are none. That resulted in an error which is resolved with this. + +## 1.10.0 Remove configuration-as-code-support plugins + +In recent version of configuration-as-code-plugin this is no longer necessary. + +## 1.9.24 + +Update JCasC auto-reload docs and remove stale SSH key references from version "1.8.0 JCasC auto reload works without SSH keys" + +## 1.9.23 Support jenkinsUriPrefix when JCasC is enabled + +Fixed a bug in the configuration as code reload URL, where it wouldn't work with a jenkinsUriPrefix set. + +## 1.9.22 + +Add `master.jenkinsHome` and `master.jenkinsRef` options to use docker images derivates from Jenkins + +## 1.9.21 + +Add `master.terminationGracePeriodSeconds` option + +## 1.9.20 + +Update default plugins + +- kubernetes:1.24.1 +- workflow-job:2.36 +- workflow-aggregator:2.6 +- credentials-binding:1.21 +- git:4.2.0 +- configuration-as-code:1.36 + +## 1.9.19 + +Update docs for Helm 3 + +## 1.9.18 + +Make `jenkins-home` attachable to Azure Disks without pvc + +```yaml + volumes: + - name: jenkins-home + azureDisk: + kind: Managed + diskName: myAKSDisk + diskURI: /subscriptions//resourceGroups/MC_myAKSCluster_myAKSCluster_eastus/providers/Microsoft.Compute/disks/myAKSDisk +``` + +## 1.9.16 + +Fix PodLabel for NetworkPolicy to work if enabled + +## 1.9.14 + +Properly fix case sense in `Values.master.overwriteConfig` in `config.yaml` + +## 1.9.13 + +Fix case sense in `Values.master.overwriteConfig` in `config.yaml` + +## 1.9.12 + +Scriptapprovals are overwritten when overwriteConfig is enabled + +## 1.9.10 + +Added documentation for `persistence.storageClass`. + +## 1.9.9 +Make `master.deploymentAnnotation` configurable. + +## 1.9.8 + +Make `agent.slaveConnectTimeout` configurable: by increasing this value Jenkins will not cancel&ask k8s for a pod again, while it's on `ContainerCreating`. Useful when you have big images or autoscaling takes some time. + +## 1.9.7 Update plugin versions + +| plugin | old version | new version | +|-----------------------|-------------|-------------| +| kubernetes | 1.18.2 | 1.21.2 | +| workflow-job | 2.33 | 2.36 | +| credentials-binding | 1.19 | 1.20 | +| git | 3.11.0 | 4.0.0 | +| configuration-as-code | 1.27 | 1.32 | + +## 1.9.6 + +Enables jenkins to use keystore inorder to have native ssl support #17790 + +## 1.9.5 Enable remoting security + +`Manage Jenkins` -> `Configure Global Security` -> `Enable Agent → Master Access Control` is now enabled via configuration as code plugin + +## 1.9.4 Option to set existing secret with Google Application Default Credentials + +Google application credentials are kept in a file, which has to be mounted to a pod. You can set `gcpcredentials` in `existingSecret` as follows: + +```yaml + existingSecret: + jenkins-service-account: + gcpcredentials: application_default_credentials.json +``` + +Helm template then creates the necessary volume mounts and `GOOGLE_APPLICATION_CREDENTIALS` environmental variable. + +## 1.9.3 Fix `JAVA_OPTS` when config auto-reload is enabled + +## 1.9.2 Add support for kubernetes-credentials-provider-plugin + +[kubernetes-credentials-provider-plugin](https://jenkinsci.github.io/kubernetes-credentials-provider-plugin/) needs permissions to get/watch/list kubernetes secrets in the namespaces where Jenkins is running. + +The necessary role binding can be created using `rbac.readSecrets` when `rbac.create` is `true`. + +To quote from the plugin documentation: + +> Because granting these permissions for secrets is not something that should be done lightly it is highly advised for security reasons that you both create a unique service account to run Jenkins as, and run Jenkins in a unique namespace. + +Therefor this is disabled by default. + +## 1.9.1 Update kubernetes plugin URL + +## 1.9.0 Change default serviceType to ClusterIP + +## 1.8.2 + +Revert fix in `1.7.10` since direct connection is now disabled by default. + +## 1.8.1 + +Add `master.schedulerName` to allow setting a Kubernetes custom scheduler + +## 1.8.0 JCasC auto reload works without SSH keys + +We make use of the fact that the Jenkins Configuration as Code Plugin can be triggered via http `POST` to `JENKINS_URL/configuration-as-code/reload`and a pre-shared key. +The sidecar container responsible for reloading config changes is now `kiwigrid/k8s-sidecar:0.1.20` instead of it's fork `shadwell/k8s-sidecar`. + +References: + +- [Triggering Configuration Reload](https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/docs/features/configurationReload.md) +- [kiwigrid/k8s-sidecar](https://hub.docker.com/r/kiwigrid/k8s-sidecar) + +`master.sidecars.configAutoReload.enabled` now works using `casc.reload.token` + +## 1.7.10 + +Disable direct connection in default configuration (when kubernetes plugin version >= 1.20.2). +Note: In case direct connection is going to be used `jenkins/jnlp-slave` needs to be version `3.35-5` or newer. + +## 1.7.9 + +Prevented Jenkins Setup Wizard on new installations + +## 1.7.8 + +Extend extraPorts to be opened on the Service object, not just the container. + +## 1.7.7 + +Add persistentvolumeclaim permission to the role to support new dynamic pvc workspaces. + +## 1.7.6 + +Updated `master.slaveKubernetesNamespace` to parse helm templates. +Defined an sensible empty value to the following variables, to silence invalid warnings: + +- master.extraPorts +- master.scriptApproval +- master.initScripts +- master.JCasC.configScripts +- master.sidecars.other +- agent.envVars +- agent.volumes + +## 1.7.5 + +Fixed an issue where the JCasC won't run if JCasC auto-reload is enabled [issue #17135](https://github.com/helm/charts/issues/17135) + +## 1.7.4 + +Comments out JCasC example of jenkins.systemMessage so that it can be used by end users. Previously, an attempt to set systemMessage causes Jenkins to startup, citing duplicate JCasC settings for systemMessage [issue #13333](https://github.com/helm/charts/issues/13333) + +## 1.7.2 + +Update kubernetes-plugin to version 1.18.2 which fixes frequently encountered [JENKINS-59000](https://issues.jenkins-ci.org/plugins/servlet/mobile#issue/JENKINS-59000) + +## 1.7.1 + +Update the default requirements for jenkins-agent to 512Mi which fixes frequently encountered [issue #3723](https://github.com/helm/charts/issues/3723) + +## 1.7.0 + +[Jenkins Configuration as Code Plugin](https://github.com/jenkinsci/configuration-as-code-plugin) default configuration can now be enabled via `master.JCasC.defaultConfig`. + +JCasC default configuration includes: + +- Jenkins URL +- Admin email `master.jenkinsAdminEmail` +- crumbIssuer +- disableRememberMe: false +- mode: NORMAL +- numExecutors: {{ .Values.master.numExecutors }} +- projectNamingStrategy: "standard" +- kubernetes plugin + - containerCapStr via `agent.containerCap` + - jenkinsTunnel + - jenkinsUrl + - maxRequestsPerHostStr: "32" + - name: "kubernetes" + - namespace + - serverUrl: `"https://kubernetes.default"` + - template + - containers + - alwaysPullImage: `agent.alwaysPullImage` + - args + - command + - envVars + - image: `agent.image:agent.imageTag` + - name: `.agent.sideContainerName` + - privileged: `.agent.privileged` + - resourceLimitCpu: `agent.resources.limits.cpu` + - resourceLimitMemory: `agent.resources.limits.memory` + - resourceRequestCpu: `agent.resources.requests.cpu` + - resourceRequestMemory: `agent.resources.requests.memory` + - ttyEnabled: `agent.TTYEnabled` + - workingDir: "/home/jenkins" + - idleMinutes: `agent.idleMinutes` + - instanceCap: 2147483647 + - imagePullSecrets: + - name: `.agent.imagePullSecretName` + - label + - name + - nodeUsageMode: "NORMAL" + - podRetention: `agent.podRetention` + - serviceAccount + - showRawYaml: true + - slaveConnectTimeoutStr: "100" + - yaml: `agent.yamlTemplate` + - yamlMergeStrategy: "override" +- security: + - apiToken: + - creationOfLegacyTokenEnabled: false + - tokenGenerationOnCreationEnabled: false + - usageStatisticsEnabled: true + +Example `values.yaml` which enables JCasC, it's default config and configAutoReload: + +```yaml +master: + JCasC: + enabled: true + defaultConfig: true + sidecars: + configAutoReload: + enabled: true +``` + +add master.JCasC.defaultConfig and configure location + +- JCasC configuration is stored in template `jenkins.casc.defaults` + so that it can be used in `config.yaml` and `jcasc-config.yaml` + depending on if configAutoReload is enabled or not + +- Jenkins Location (URL) is configured to provide a startin point + for the config + +## 1.6.1 + +Print error message when `master.sidecars.configAutoReload.enabled` is `true`, but the admin user can't be found to configure the SSH key. + +## 1.6.0 + +Add support for Google Cloud Storage for backup CronJob (migrating from nuvo/kube-tasks to maorfr/kube-tasks) + +## 1.5.9 + +Fixed a warning when sidecar resources are provided through a parent chart or override values + +## 1.5.8 + +Fixed an issue when master.enableXmlConfig is set to false: Always mount jenkins-secrets volume if secretsFilesSecret is set (#16512) + +## 1.5.7 + +added initial changelog (#16324) +commit: cee2ebf98 + +## 1.5.6 + +enable xml config misspelling (#16477) +commit: a125b99f9 + +## 1.5.5 + +Jenkins master label (#16469) +commit: 4802d14c9 + +## 1.5.4 + +add option enableXmlConfig (#16346) +commit: 387d97a4c + +## 1.5.3 + +extracted "jenkins.URL" into template (#16347) +commit: f2fdf5332 + +## 1.5.2 + +Fix backups when deployment has custom name (#16279) +commit: 16b89bfff + +## 1.5.1 + +Ability to set custom namespace for ServiceMonitor (#16145) +commit: 18ee6cf01 + +## 1.5.0 + +update Jenkins plugins to fix security issue (#16069) +commit: 603cf2d2b + +## 1.4.3 + +Use fixed container name (#16068) +commit: b3e4b4a49 + +## 1.4.2 + +Provide default job value (#15963) +commit: c462e2017 + +## 1.4.1 + +Add Jenkins backendconfig values (#15471) +commit: 7cc9b54c7 + +## 1.4.0 + +Change the value name for docker image tags - standartise to helm preferred value name - tag; this also allows auto-deployments using weaveworks flux (#15565) +commit: 5c3d920e7 + +## 1.3.6 + +jenkins deployment port should be target port (#15503) +commit: 83909ebe3 + +## 1.3.5 + +Add support for namespace specification (#15202) +commit: e773201a6 + +## 1.3.4 + +Adding sub-path option for scraping (#14833) +commit: e04021154 + +## 1.3.3 + +Add existingSecret to Jenkins backup AWS credentials (#13392) +commit: d9374f57d + +## 1.3.2 + +Fix JCasC version (#14992) +commit: 26a6d2b99 + +## 1.3.1 + +Update affinity for a backup cronjob (#14886) +commit: c21ed8331 + +## 1.3.0 + +only install casc support plugin when needed (#14862) +commit: a56fc0540 + +## 1.2.2 + +DNS Zone customization (#14775) +commit: da2910073 + +## 1.2.1 + +only render comment if configAutoReload is enabled (#14754) +commit: e07ead283 + +## 1.2.0 + +update plugins to latest version (#14744) +commit: 84336558e + +## 1.1.24 + +add example for EmptyDir volume (#14499) +commit: cafb60209 + +## 1.1.23 + +check if installPlugins is set before using it (#14168) +commit: 1218f0359 + +## 1.1.22 + +Support servicemonitor and alerting rules (#14124) +commit: e15a27f48 + +## 1.1.21 + +Fix: healthProbe timeouts mapping to initial delay (#13875) +commit: 825b32ece + +## 1.1.20 + +Properly handle overwrite config for additional configs (#13915) +commit: 18ce9b558 + +## 1.1.18 + +update maintainer (#13897) +commit: 223002b27 + +## 1.1.17 + +add apiVersion (#13795) +commit: cd1e5c35a + +## 1.1.16 + +allow changing of the target port to support TLS termination sidecar (#13576) +commit: a34d3bbcc + +## 1.1.15 + +fix wrong pod selector in jenkins-backup (#13542) +commit: b5df4fd7e + +## 1.1.14 + +allow templating of customInitContainers (#13536) +commit: d1e1421f4 + +## 1.1.13 + +fix #13467 (wrong deprecation message) (#13511) +commit: fbe28fa1c + +## 1.1.12 + +Correct customInitContainers Name example. (#13405) +commit: 6c6e40405 + +## 1.1.11 + +fix master.runAsUser, master.fsGroup examples (#13389) +commit: 2d7e5bf72 + +## 1.1.10 + +Ability to specify raw yaml template (#13319) +commit: 77aaa9a5f + +## 1.1.9 + +correct NOTES.txt - use master.ingress.hostname (#13318) +commit: b08ef6280 + +## 1.1.8 + +explain how to upgrade major versions (#13273) +commit: e7617a97e + +## 1.1.7 + +Add support for idleMinutes and serviceAccount (#13263) +commit: 4595ee033 + +## 1.1.6 + +Use same JENKINS_URL no matter if slaves use different namespace (#12564) +commit: 94c90339f + +## 1.1.5 + +fix deprecation checks (#13224) +commit: c7d2f8105 + +## 1.1.4 + +Fix issue introduced in #13136 (#13232) +commit: 0dbcded2e + +## 1.1.3 + +fix chart errors (#13197) +commit: 692a1e3da + +## 1.1.2 + +correct selector for jenkins pod (#13200) +commit: 4537e7fda + +## 1.1.1 + +Fix rendering of customInitContainers and lifecycle for Jenkins helm chart (#13189) +commit: e8f6b0ada + +## 1.1.0 + +Add support for openshift route in jenkins (#12973) +commit: 48c58a430 + +## 1.0.0 + +helm chart best practices (#13136) +commit: b02ae3f48 + +### Breaking changes + +- values have been renamed to follow helm chart best practices for naming conventions so + that all variables start with a lowercase letter and words are separated with camelcase + +- all resources are now using recommended standard labels + + +As a result of the label changes also the selectors of the deployment have been updated. +Those are immutable so trying an updated will cause an error like: + +```text +Error: Deployment.apps "jenkins" is invalid: spec.selector: Invalid value: v1.LabelSelector{MatchLabels:map[string]string{"app.kubernetes.io/component":"jenkins-master", "app.kubernetes.io/instance":"jenkins"}, MatchExpressions:[]v1.LabelSelectorRequirement(nil)}: field is immutable +``` + +In order to upgrade, delete the Jenkins Deployment before upgrading: + +```console +kubectl delete deploy jenkins +``` + +## 0.40.0 + +Allow to override jenkins location protocol (#12257) +commit: 18a830626 + +## 0.39.0 + +Add possibility to add custom init-container and lifecycle for master-container (#13062) +commit: 14d043593 + +## 0.38.0 + +Support `priorityClassName` on Master Deployment (#13069) +commit: e896c62bc + +## 0.37.3 + +Add support for service account annotations in jenkins (#12969) +commit: b22774e2f + +## 0.37.2 + +fix: add hostName to ingress in values.yaml (#12946) +commit: 041045e9b + +## 0.37.1 + +Update to match actual defaults in value.yaml (#12904) +commit: 73b6d37eb + +## 0.37.0 + +Support multiple Jenkins instances in same namespace (#12748) +commit: 32ff2f343 + +## 0.36.5 + +Fix wrong comment in values.yaml (#12761) +commit: 9db8ced23 + +## 0.36.4 + +Re-add value for Ingress API Version (#12753) +commit: ecb7791b5 + +## 0.36.3 + +allow templating of volumes (#12734) +commit: adbda2ca6 + +## 0.36.2 + +Fix self-introduced whitespace bug (#12528) +commit: eec1678eb + +## 0.36.1 + +Add flag to overwrite jobs definition from values.yaml (#12427) +commit: fd349b2fc + +## 0.36.0 + +Replace OwnSshKey with AdminSshKey (#12140) (#12466) +commit: 80a8c9eb6 + +## 0.35.2 + +add note for breaking changes (#12203) +commit: e779c5a54 + +## 0.35.1 + +Allow Jenkins to run with READONLYROOTFS psp (#12338) +commit: 7c419e191 + +## 0.35.0 + +Jenkins OverwriteConfig setting also overwrites init scripts (#9468) +commit: 501335b76 + +## 0.34.1 + +Fix typo on hostname variable (#12156) +commit: 3d337d8dd + +## 0.34.0 + +Allow ingress without host rule (#11960) +commit: ddc966d1e + +## 0.33.2 + +Improve documentation - clarify that rbac is needed for autoreload (#11739) +commit: 9d75a5c34 + +## 0.33.1 + +use object for rollingUpdate (#11909) +commit: cb9cf21e8 + +## 0.33.0 + +Add hostAliases (#11701) +commit: 0b89e1094 + +## 0.32.10 + +Fix slave jnlp port always being reset when container is restarted (#11685) +commit: d7d51797b + +## 0.32.9 + +add ingress Hostname an ApiVersion to docs (#11576) +commit: 4d3e77137 + +## 0.32.8 + +Support custom master pod labels in deployment (#9714) (#11511) +commit: 9de96faa0 + +## 0.32.7 + +Fix Markdown syntax in readme (#11496) +commit: a32221a95 + +## 0.32.6 + +Added custom labels on jenkins ingress (#11466) +commit: c875d2b9b + +## 0.32.5 + +fix typo in default jenkins agent image fixes #11356 (#11463) +commit: 30adb9a91 + +## 0.32.4 + +fix incorrect Deployment when using sidecars (#11413) +commit: 362b4cef8 + +## 0.32.3 + +[]: #10131 (#11411) +commit: 49cb72055 + +## 0.32.2 + +Option to expose the slave listener port as host port (#11187) +commit: 2f85a9663 + +## 0.32.1 + +Updating Jenkins deployment fails appears rollingUpdate needs to be (#11166) +commit: 07fc9dbde + +## 0.32.0 + +Merge Sidecard configs (#11339) +commit: 3696090b9 + +## 0.31.0 + +Add option to overwrite plugins (#11231) +commit: 0e9aa00a5 + +## 0.30.0 + +Added slave Pod env vars (#8743) +commit: 1499f6608 + +## 0.29.3 + +revert indentation to previous working version (#11293) +commit: 61662f17a + +## 0.29.2 + +allow running sidecar containers for Jenkins master (#10950) +commit: 9084ce54a + +## 0.29.1 + +Indent lines related to EnableRawHtmlMarkupFormatter (#11252) +commit: 20b310c08 + +## 0.29.0 + +Jenkins Configuration as Code (#9057) +commit: c3e8c0b17 + +## 0.28.11 + +Allow to enable OWASP Markup Formatter Plugin (#10851) +commit: 9486e5ddf + +## 0.28.10 + +Fixes #1341 -- update Jenkins chart documentation (#10290) +commit: 411c81cd0 + +## 0.28.9 + +Quoted JavaOpts values (#10671) +commit: 926a843a8 + +## 0.28.8 + +Support custom labels in deployment (#9714) (#10533) +commit: 3e00b47fa + +## 0.28.7 + +separate test resources (#10597) +commit: 7b7ae2d11 + +## 0.28.6 + +allow customizing livenessProbe periodSeconds (#10534) +commit: 3c94d250d + +## 0.28.5 + +Add role kind option (#8498) +commit: e791ad124 + +## 0.28.4 + +workaround for busybox's cp (Closes: #10471) (#10497) +commit: 0d51a4187 + +## 0.28.3 + +fix parsing java options (#10140) +commit: 9448d0293 + +## 0.28.2 + +Fix job definitions in standard values.yaml (#10184) +commit: 6b6355ae7 + +## 0.28.1 + +add numExecutors as a variable in values file (#10236) +commit: d5ea2050f + +## 0.28.0 + +various (#10223) +commit: e17d2a65d + +## 0.27.0 + +add backup cronjob (#10095) +commit: 863ead8db + +## 0.26.2 + +add namespace flag for port-forwarding in jenkins notes (#10399) +commit: 846b589a9 + +## 0.26.1 + +- fixes #10267 when executed with helm template - otherwise produces an invalid template. (#10403) + commit: 266f9d839 + +## 0.26.0 + +Add subPath for jenkins-home mount (#9671) +commit: a9c76ac9b + +## 0.25.1 + +update readme to indicate the correct image that is used by default (#9915) +commit: 6aba9631c + +## 0.25.0 + +Add ability to manually set Jenkins URL (#7405) +commit: a0178fcb4 + +## 0.24.0 + +Make AuthorizationStrategy configurable (#9567) +commit: 06545b226 + +## 0.23.0 + +Update Jenkins public chart (#9296) +commit: 4e5f5918b + +## 0.22.0 + +allow to override jobs (#9004) +commit: dca9f9ab9 + +## 0.21.0 + +Simple implementation of the option to define the ingress path to the jenkins service (#8101) +commit: 013159609 + +## 0.20.2 + +Cosmetic change to remove necessity of changing "appVersion" for every new LTS release (#8866) +commit: f52af042a + +## 0.20.1 + +Added ExtraPorts to open in the master pod (#7759) +commit: 78858a2fb + +## 0.19.1 + +Fix component label in NOTES.txt ... (#8300) +commit: c5494dbfe + +## 0.19.0 + +Kubernetes 1.9 support as well as automatic apiVersion detection (#7988) +commit: 6853ad364 + +## 0.18.1 + +Respect SlaveListenerPort value in config.xml (#7220) +commit: 0a5ddac35 + +## 0.18.0 + +Allow replacement of Jenkins config with configMap. (#7450) +commit: c766da3de + +## 0.17.0 + +Add option to allow host networking (#7530) +commit: dc2eeff32 + +## 0.16.25 + +add custom jenkins labels to the build agent (#7167) +commit: 3ecde5dbf + +## 0.16.24 + +Move kubernetes and job plugins to latest versions (#7438) +commit: 019e39456 + +## 0.16.23 + +Add different Deployment Strategies based on persistence (#6132) +commit: e0a20b0b9 + +## 0.16.22 + +avoid linting errors when adding Values.Ingress.Annotations (#7425) +commit: 99eacc854 + +## 0.16.21 + +bump appVersion to reflect new jenkins lts release version 2.121.3 (#7217) +commit: 296df165d + +## 0.16.20 + +Configure kubernetes plugin for including namespace value (#7164) +commit: c0dc6cc48 + +## 0.16.19 + +make pod retention policy setting configurable (#6962) +commit: e614c1033 + +## 0.16.18 + +Update plugins version (#6988) +commit: bf8180018 + +## 0.16.17 + +Add Master.AdminPassword in readme (#6987) +commit: 13e754ad7 + +## 0.16.16 + +Added jenkins location configuration (#6573) +commit: 79de7026c + +## 0.16.15 + +use generic env var, not oracle specific env var (#6116) +commit: 6084ab4a4 + +## 0.16.14 + +Allow to specify resource requests and limits on initContainers (#6723) +commit: 942a33b1a + +## 0.16.13 + +Added support for NodePort service type for jenkens agent svc (#6571) +commit: 89a213c2b + +## 0.16.12 + +Added ability to configure multiple LoadBalancerSourceRanges (#6243) +commit: 01604ddbc + +## 0.16.11 + +Removing ContainerPort configuration as at the moment it does not work when you change this setting (#6411) +commit: e1c0468bd + +## 0.16.9 + +Fix jobs parsing for configmap by adding toYaml to jobs.yaml template (#3747) +commit: b2542a123 + +## 0.16.8 + +add jenkinsuriprefix in healthprobes (#5737) +commit: 435d7a7b9 + +## 0.16.7 + +Added the ability to switch from ClusterRoleBinding to RoleBinding. (#6190) +commit: dde03ede0 + +## 0.16.6 + +Make jenkins master pod security context optional (#6122) +commit: 63653fd59 + +## 0.16.5 + +Rework resources requests and limits (#6077) (#6077) +commit: e738f99d0 + +## 0.16.4 + +Add jenkins master pod annotations (#6313) +commit: 5e7325721 + +## 0.16.3 + +Split Jenkins readiness and liveness probe periods (#5704) +commit: fc6100c38 + +## 0.16.1 + +fix typo in jenkins readme (#5228) +commit: 3cd3f4b8b + +## 0.16.0 + +Inherit existing plugins from Jenkins image (#5409) +commit: fd93bff82 + +## 0.15.1 + +Allow NetworkPolicy.ApiVersion and Master.Ingress.ApiVersion to Differ (#5103) +commit: 78ee4ba15 + +## 0.15.0 + +Secure Defaults (#5026) +commit: 0fe90b520 + +## 0.14.6 + +Wait for up to 2 minutes before failing liveness check (#5161) +commit: 2cd3fc481 + +## 0.14.5 + +correct ImageTag setting (#4371) +commit: 8ea04174d + +## 0.14.4 + +Update jenkins/README.md (#4559) +commit: d4e6352dd + +## 0.14.3 + +Bump appVersion (#4177) +commit: 605d3d441 + +## 0.14.2 + +Master.InitContainerEnv: Init Container Env Vars (#3495) +commit: c64abe27d + +## 0.14.1 + +Allow more configuration of Jenkins agent service (#4028) +commit: fc82f39b2 + +## 0.14.0 + +Add affinity settings (#3839) +commit: 64e82fa6a + +## 0.13.5 + +bump test timeouts (#3886) +commit: cd05dd99c + +## 0.13.4 + +Add OWNERS to jenkins chart (#3881) +commit: 1c106b9c8 + +## 0.13.3 + +Add fullnameOverride support (#3705) +commit: ec8080839 + +## 0.13.2 + +Update README.md (#3638) +commit: f6d274c37 + +## 0.13.1 + +Lower initial healthcheck delay (#3463) +commit: 9b99db67c + +## 0.13.0 + +Provision credentials.xml, secrets files and jobs (#3316) +commit: d305c5961 + +## 0.12.1 + +fix the default value for nodeUsageMode. (#3299) +commit: b68d19516 + +## 0.12.0 + +Recreate pods when CustomConfigMap is true and there are changes to the ConfigMap (which is how the vanilla chart works) (#3181) +commit: 86d29f804 + +## 0.11.1 + +Optionally adds liveness and readiness probes to jenkins (#3245) +commit: 8b9aa73ee + +## 0.11.0 + +Feature/run jenkins as non root user (#2899) +commit: 8918f4175 + +## 0.10.3 + +template the version to keep them synced (#3084) +commit: 35e7fa49a + +## 0.10.2 + +Update Chart.yaml +commit: e3e617a0b + +## 0.10.1 + +Merge branch 'master' into jenkins-test-timeout +commit: 9a230a6b1 + +Double retry count for Jenkins test +commit: 129c8e824 + +Jenkins: Update readme | Master.ServiceAnnotations (#2757) +commit: 6571810bc + +## 0.10.0 + +Update Jenkins images and plugins (#2496) +commit: 2e2622682 + +## 0.9.4 + +Updating to remove the `.lock` directory as well (#2747) +commit: 6e676808f + +## 0.9.3 + +Use variable for service port when testing (#2666) +commit: d044f99be + +## 0.9.2 + +Review jenkins networkpolicy docs (#2618) +commit: 49911e458 + +Add image pull secrets to jenkins templates (#1389) +commit: 4dfae21fd + +## 0.9.1 + +Added persistent volume claim annotations (#2619) +commit: ac9e5306e + +Fix failing CI lint (#2758) +commit: 26f709f0e + +## 0.9.0 + +namespace defined templates with chart name (#2140) +commit: 408ae0b3f + +## 0.8.9 + +added useSecurity and adminUser to params (#1903) +commit: 39d2a03cd + +Use storageClassName for jenkins. (#1997) +commit: 802f6449b + +## 0.8.8 + +Remove old plugin locks before installing plugins (#1746) +commit: 6cd7b8ff4 + +promote initContainrs to podspec (#1740) +commit: fecc804fc + +## 0.8.7 + +add optional LoadBalancerIP option. (#1568) +commit: d39f11408 + +## 0.8.6 + +Fix bad key in values.yaml (#1633) +commit: dc27e5af3 + +## 0.8.5 + +Update Jenkins to support node selectors for agents. (#1532) +commit: 4af5810ff + +## 0.8.4 + +Add support for supplying JENKINS_OPTS and/or URI prefix (#1405) +commit: 6a331901a + +## 0.8.3 + +Add serviceAccountName to deployment (#1477) +commit: 0dc349b44 + +## 0.8.2 + +Remove path from ingress specification to allow other paths (#1599) +commit: e727f6b32 + +Update git plugin to 3.4.0 for CVE-2017-1000084 (#1505) +commit: 03482f995 + +## 0.8.1 + +Use consistent whitespace in template placeholders (#1437) +commit: 912f50c71 + +add configurable service annotations #1234 (#1244) +commit: 286861ca8 + +## 0.8.0 + +Jenkins v0.8.0 (#1385) +commit: 0009a2393 + +## 0.7.4 + +Use imageTag as version in config map (#1333) +commit: e8bb6ebb4 + +## 0.7.3 + +Add NetworkPolicy to Jenkins (#1228) +commit: 572b36c6d + +## 0.7.2 + +- Workflow plugin pin (#1178) + commit: ac3a0c7bc + +## 0.7.1 + +copy over plugins.txt in case of update (#1222) +commit: 75b5b1174 + +## 0.7.0 + +add jmx option (#964) +commit: 6ae8d1945 + +## 0.6.4 + +update jenkins to latest LTS 2.46.3 (#1182) +commit: ad90b4c27 + +## 0.6.3 + +Update chart maints to gh u/n (#1107) +commit: f357b77ed + +## 0.6.2 + +Add Agent.Privileged option (#957) +commit: 2cf4aced2 + +## 0.6.1 + +Upgrade jenkins to 2.46.2 (#971) +commit: 41bd742b4 + +## 0.6.0 + +Smoke test for Jenkins Chart (#944) +commit: 110441054 + +## 0.5.1 + +removed extra space from hardcoded password (#925) +commit: 85a9b9123 + +## 0.5.0 + +move config to init-container allowing use of upstream containers (#921) +commit: 1803c3d33 + +## 0.4.1 + +add ability to toggle jnlp-agent podTemplate generation (#918) +commit: accd53203 + +## 0.4.0 + +Jenkins add script approval (#916) +commit: c1746656e + +## 0.3.1 + +Update Jenkins to Latest LTS fixes #731 (#733) +commit: e9a3aed8b + +## 0.3.0 + +Added option to add Jenkins init scripts (#617) +commit: b889623d0 + +## 0.2.0 + +Add existing PVC (#716) +commit: 05271f145 + +## 0.1.15 + +use Master.ServicePort in config.xml (#769) +commit: f351f4b16 + +## 0.1.14 + +Added option to disable security on master node (#403) +commit: 3a6113d18 + +## 0.1.13 + +Added: extra mount points support for jenkins master (#474) +commit: fab0f7eb1 + +## 0.1.12 + +fix storageclass config typo (#548) +commit: 6fc0ff242 + +## 0.1.10 + +Changed default value of Kubernetes Cloud name to match one in kubernetes plugin (#404) +commit: 68351304a + +Add support for overriding the Jenkins ConfigMap (#524) +commit: f97ca53b1 + +## 0.1.9 + +Added jenkins-master ingress support (#402) +commit: d76a09588 + +## 0.1.8 + +Change description (#553) +commit: 91f5c24e1 + +Removed default Persistence.StorageClass: generic (#530) +commit: c87494c10 + +Update to the recommended pvc patterns. (#448) +commit: a7fc595aa + +Remove helm.sh/created annotations (#505) +commit: f380da2fb + +## 0.1.7 + +add support for explicit NodePort on jenkins chart (#342) +commit: f63c188da + +Add configurable loadBalancerSourceRanges for jenkins chart (#360) +commit: 44007c50e + +Update Jenkins version to current LTS (2.19.4) and Kubernetes Plugin to 0.10 (#341) +commit: 6c8678167 + +## 0.1.6 + +Add imagePullPolicy to init container (#295) +commit: 103ee1952 + +## 0.1.5 + +bump chart version with PVC metadata label additions +commit: 4aa9cf5b1 + +## 0.1.4 + +removed `*` from `jenkins/templates/NOTES.txt` +commit: 76212230b + +apply standard metadata labels to PVC's +commit: 58b730836 + +specify namespace in `kubectl get svc` commands in NOTES.txt +commit: 7d3287e81 + +Update Jenkins version to current LTS (#194) +commit: 2c0404049 + +## 0.1.1 + +escape fixed +commit: 2026e1d15 + +.status.loadBalancer.ingress[0].ip is empty in AWS +commit: 1810e37f4 + +.status.loadBalancer.ingress[0].ip is empty in AWS +commit: 3cbd3ced6 + +Remove 'Getting Started:' from various NOTES.txt. (#181) +commit: 2f63fd524 + +docs(\*): update readmes to reference chart repos (#119) +commit: c7d1bff05 + +## 0.1.0 + +Move first batch of PVC charts to stable +commit: d745f4879 diff --git a/charts/jenkins/jenkins/5.5.14/Chart.yaml b/charts/jenkins/jenkins/5.5.14/Chart.yaml new file mode 100644 index 000000000..f11d9db4e --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/Chart.yaml @@ -0,0 +1,54 @@ +annotations: + artifacthub.io/category: integration-delivery + artifacthub.io/changes: | + - Update `jenkins/jenkins` to version `2.462.2-jdk17` + artifacthub.io/images: | + - name: jenkins + image: docker.io/jenkins/jenkins:2.462.2-jdk17 + - name: k8s-sidecar + image: docker.io/kiwigrid/k8s-sidecar:1.27.6 + - name: inbound-agent + image: jenkins/inbound-agent:3261.v9c670a_4748a_9-1 + 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.462.2 +description: 'Jenkins - Build great things at any scale! As the leading open source + automation server, Jenkins provides over 1800 plugins to support building, deploying + and automating any project. ' +home: https://www.jenkins.io/ +icon: file://assets/icons/jenkins.svg +keywords: +- jenkins +- ci +- devops +kubeVersion: '>=1.14-0' +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 +type: application +version: 5.5.14 diff --git a/charts/jenkins/jenkins/5.5.14/README.md b/charts/jenkins/jenkins/5.5.14/README.md new file mode 100644 index 000000000..4ddd1faa4 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/README.md @@ -0,0 +1,706 @@ +# Jenkins + +[![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/jenkins)](https://artifacthub.io/packages/helm/jenkinsci/jenkins) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) +[![Releases downloads](https://img.shields.io/github/downloads/jenkinsci/helm-charts/total.svg)](https://github.com/jenkinsci/helm-charts/releases) +[![Join the chat at https://app.gitter.im/#/room/#jenkins-ci:matrix.org](https://badges.gitter.im/badge.svg)](https://app.gitter.im/#/room/#jenkins-ci:matrix.org) + +[Jenkins](https://www.jenkins.io/) is the leading open source automation server, Jenkins provides over 1800 plugins to support building, deploying and automating any project. + +This chart installs a Jenkins server which spawns agents on [Kubernetes](http://kubernetes.io) utilizing the [Jenkins Kubernetes plugin](https://plugins.jenkins.io/kubernetes/). + +Inspired by the awesome work of [Carlos Sanchez](https://github.com/carlossg). + +## Get Repository Info + +```console +helm repo add jenkins https://charts.jenkins.io +helm repo update +``` + +_See [`helm repo`](https://helm.sh/docs/helm/helm_repo/) for command documentation._ + +## Install Chart + +```console +# Helm 3 +$ helm install [RELEASE_NAME] jenkins/jenkins [flags] +``` + +_See [configuration](#configuration) below._ + +_See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._ + +## Uninstall Chart + +```console +# Helm 3 +$ helm uninstall [RELEASE_NAME] +``` + +This removes all the Kubernetes components associated with the chart and deletes the release. + +_See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall/) for command documentation._ + +## Upgrade Chart + +```console +# Helm 3 +$ helm upgrade [RELEASE_NAME] jenkins/jenkins [flags] +``` + +_See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documentation._ + +Visit the chart's [CHANGELOG](https://github.com/jenkinsci/helm-charts/blob/main/charts/jenkins/CHANGELOG.md) to view the chart's release history. +For migration between major version check [migration guide](#migration-guide). + +## Building weekly releases + +The default charts target Long-Term-Support (LTS) releases of Jenkins. +To use other versions the easiest way is to update the image tag to the version you want. +You can also rebuild the chart if you want the `appVersion` field to match. + +## Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). +To see all configurable options with detailed comments, visit the chart's [values.yaml](https://github.com/jenkinsci/helm-charts/blob/main/charts/jenkins/values.yaml), or run these configuration commands: + +```console +# Helm 3 +$ helm show values jenkins/jenkins +``` + +For a summary of all configurable options, see [VALUES_SUMMARY.md](https://github.com/jenkinsci/helm-charts/blob/main/charts/jenkins/VALUES_SUMMARY.md). + +### Configure Security Realm and Authorization Strategy + +This chart configured a `securityRealm` and `authorizationStrategy` as shown below: + +```yaml +controller: + JCasC: + securityRealm: |- + local: + allowsSignup: false + enableCaptcha: false + users: + - id: "${chart-admin-username}" + name: "Jenkins Admin" + password: "${chart-admin-password}" + authorizationStrategy: |- + loggedInUsersCanDoAnything: + allowAnonymousRead: false +``` + +With the configuration above there is only a single user. +This is fine for getting started quickly, but it needs to be adjusted for any serious environment. + +So you should adjust this to suite your needs. +That could be using LDAP / OIDC / .. as authorization strategy and use globalMatrix as authorization strategy to configure more fine-grained permissions. + +### Consider using a custom image + +This chart allows the user to specify plugins which should be installed. However, for production use cases one should consider to build a custom Jenkins image which has all required plugins pre-installed. +This way you can be sure which plugins Jenkins is using when starting up and you avoid trouble in case of connectivity issues to the Jenkins update site. + +The [docker repository](https://github.com/jenkinsci/docker) for the Jenkins image contains [documentation](https://github.com/jenkinsci/docker#preinstalling-plugins) how to do it. + +Here is an example how that can be done: + +```Dockerfile +FROM jenkins/jenkins:lts +RUN jenkins-plugin-cli --plugins kubernetes workflow-aggregator git configuration-as-code +``` + +NOTE: If you want a reproducible build then you should specify a non-floating tag for the image `jenkins/jenkins:2.249.3` and specify plugin versions. + +Once you built the image and pushed it to your registry you can specify it in your values file like this: + +```yaml +controller: + image: "registry/my-jenkins" + tag: "v1.2.3" + installPlugins: false +``` + +Notice: `installPlugins` is set to false to disable plugin download. In this case, the image `registry/my-jenkins:v1.2.3` must have the plugins specified as default value for [the `controller.installPlugins` directive](https://github.com/jenkinsci/helm-charts/blob/main/charts/jenkins/VALUES_SUMMARY.md#jenkins-plugins) to ensure that the configuration side-car system works as expected. + +In case you are using a private registry you can use 'imagePullSecretName' to specify the name of the secret to use when pulling the image: + +```yaml +controller: + image: "registry/my-jenkins" + tag: "v1.2.3" + imagePullSecretName: registry-secret + installPlugins: false +``` + +### External URL Configuration + +If you are using the ingress definitions provided by this chart via the `controller.ingress` block the configured hostname will be the ingress hostname starting with `https://` or `http://` depending on the `tls` configuration. +The Protocol can be overwritten by specifying `controller.jenkinsUrlProtocol`. + +If you are not using the provided ingress you can specify `controller.jenkinsUrl` to change the URL definition. + +### Configuration as Code + +Jenkins Configuration as Code (JCasC) is now a standard component in the Jenkins project. +To allow JCasC's configuration from the helm values, the plugin [`configuration-as-code`](https://plugins.jenkins.io/configuration-as-code/) must be installed in the Jenkins Controller's Docker image (which is the case by default as specified by the [default value of the directive `controller.installPlugins`](https://github.com/jenkinsci/helm-charts/blob/main/charts/jenkins/VALUES_SUMMARY.md#jenkins-plugins)). + +JCasc configuration is passed through Helm values under the key `controller.JCasC`. +The section ["Jenkins Configuration as Code (JCasC)" of the page "VALUES_SUMMARY.md"](https://github.com/jenkinsci/helm-charts/blob/main/charts/jenkins/VALUES_SUMMARY.md#jenkins-configuration-as-code-jcasc) lists all the possible directives. + +In particular, you may specify custom JCasC scripts by adding sub-key under the `controller.JCasC.configScripts` for each configuration area where each corresponds to a plugin or section of the UI. + +The sub-keys (prior to `|` character) are only labels used to give the section a meaningful name. +The only restriction is they must conform to RFC 1123 definition of a DNS label, so they may only contain lowercase letters, numbers, and hyphens. + +Each key will become the name of a configuration yaml file on the controller in `/var/jenkins_home/casc_configs` (by default) and will be processed by the Configuration as Code Plugin during Jenkins startup. + +The lines after each `|` become the content of the configuration yaml file. + +The first line after this is a JCasC root element, e.g. jenkins, credentials, etc. + +Best reference is the Documentation link here: `https:///configuration-as-code`. + +The example below sets custom systemMessage: + +```yaml +controller: + JCasC: + configScripts: + welcome-message: | + jenkins: + systemMessage: Welcome to our CI\CD server. +``` + +More complex example that creates ldap settings: + +```yaml +controller: + JCasC: + configScripts: + ldap-settings: | + jenkins: + securityRealm: + ldap: + configurations: + - server: ldap.acme.com + rootDN: dc=acme,dc=uk + managerPasswordSecret: ${LDAP_PASSWORD} + groupMembershipStrategy: + fromUserRecord: + attributeName: "memberOf" +``` + +Keep in mind that default configuration file already contains some values that you won't be able to override under configScripts section. + +For example, you can not configure Jenkins URL and System Admin email address like this because of conflicting configuration error. + +Incorrect: + +```yaml +controller: + JCasC: + configScripts: + jenkins-url: | + unclassified: + location: + url: https://example.com/jenkins + adminAddress: example@mail.com +``` + +Correct: + +```yaml +controller: + jenkinsUrl: https://example.com/jenkins + jenkinsAdminEmail: example@mail.com +``` + +Further JCasC examples can be found [here](https://github.com/jenkinsci/configuration-as-code-plugin/tree/master/demos). + +#### 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 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: + +```yaml +jenkins: + controller: + jenkinsUrlProtocol: https + installPlugins: false + ... +``` + +In a second file (e.g values_jenkins_casc.yaml), you can define a section of your config scripts: + +```yaml +jenkins: + controller: + JCasC: + configScripts: + jenkinsCasc: | + jenkins: + disableRememberMe: false + mode: NORMAL + ... +``` + +And keep extending your config scripts by creating more files (so not all config scripts are located in one yaml file for better maintenance): + +values_jenkins_unclassified.yaml + +```yaml +jenkins: + controller: + JCasC: + configScripts: + unclassifiedCasc: | + unclassified: + ... +``` + +When installing, you provide all relevant yaml files (e.g `helm install -f values_main.yaml -f values_jenkins_casc.yaml -f values_jenkins_unclassified.yaml ...`). Instead of updating the `CASC_JENKINS_CONFIG` environment variable to include multiple paths, multiple CasC yaml files will be created in the same path `var/jenkins_home/casc_configs`. + +#### Config as Code With or Without Auto-Reload + +Config as Code changes (to `controller.JCasC.configScripts`) can either force a new pod to be created and only be applied at next startup, or can be auto-reloaded on-the-fly. +If you set `controller.sidecars.configAutoReload.enabled` to `true`, a second, auxiliary container will be installed into the Jenkins controller pod, known as a "sidecar". +This watches for changes to configScripts, copies the content onto the Jenkins file-system and issues a POST to `http:///reload-configuration-as-code` with a pre-shared key. +You can monitor this sidecar's logs using command `kubectl logs -c config-reload -f`. +If you want to enable auto-reload then you also need to configure rbac as the container which triggers the reload needs to watch the config maps: + +```yaml +controller: + sidecars: + configAutoReload: + enabled: true +rbac: + create: true +``` + +### Allow Limited HTML Markup in User-Submitted Text + +Some third-party systems (e.g. GitHub) use HTML-formatted data in their payload sent to a Jenkins webhook (e.g. URL of a pull-request being built). +To display such data as processed HTML instead of raw text set `controller.enableRawHtmlMarkupFormatter` to true. +This option requires installation of the [OWASP Markup Formatter Plugin (antisamy-markup-formatter)](https://plugins.jenkins.io/antisamy-markup-formatter/). +This plugin is **not** installed by default but may be added to `controller.additionalPlugins`. + +### Change max connections to Kubernetes API +When using agents with containers other than JNLP, The kubernetes plugin will communicate with those containers using the Kubernetes API. this changes the maximum concurrent connections +```yaml +agent: + maxRequestsPerHostStr: "32" +``` +This will change the configuration of the kubernetes "cloud" (as called by jenkins) that is created automatically as part of this helm chart. + +### Change container cleanup timeout API +For tasks that use very large images, this timeout can be increased to avoid early termination of the task while the Kubernetes pod is still deploying. +```yaml +agent: + retentionTimeout: "32" +``` +This will change the configuration of the kubernetes "cloud" (as called by jenkins) that is created automatically as part of this helm chart. + +### Change seconds to wait for pod to be running +This will change how long Jenkins will wait (seconds) for pod to be in running state. +```yaml +agent: + waitForPodSec: "32" +``` +This will change the configuration of the kubernetes "cloud" (as called by jenkins) that is created automatically as part of this helm chart. + +### Mounting Volumes into Agent Pods + +Your Jenkins Agents will run as pods, and it's possible to inject volumes where needed: + +```yaml +agent: + volumes: + - type: Secret + secretName: jenkins-mysecrets + mountPath: /var/run/secrets/jenkins-mysecrets +``` + +The supported volume types are: `ConfigMap`, `EmptyDir`, `HostPath`, `Nfs`, `PVC`, `Secret`. +Each type supports a different set of configurable attributes, defined by [the corresponding Java class](https://github.com/jenkinsci/kubernetes-plugin/tree/master/src/main/java/org/csanchez/jenkins/plugins/kubernetes/volumes). + +### NetworkPolicy + +To make use of the NetworkPolicy resources created by default, install [a networking plugin that implements the Kubernetes NetworkPolicy spec](https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy#before-you-begin). + +[Install](#install-chart) helm chart with network policy enabled by setting `networkPolicy.enabled` to `true`. + +You can use `controller.networkPolicy.internalAgents` and `controller.networkPolicy.externalAgents` stanzas for fine-grained controls over where internal/external agents can connect from. +Internal ones are allowed based on pod labels and (optionally) namespaces, and external ones are allowed based on IP ranges. + +### Script approval list + +`controller.scriptApproval` allows to pass function signatures that will be allowed in pipelines. +Example: + +```yaml +controller: + scriptApproval: + - "method java.util.Base64$Decoder decode java.lang.String" + - "new java.lang.String byte[]" + - "staticMethod java.util.Base64 getDecoder" +``` + +### Custom Labels + +`controller.serviceLabels` can be used to add custom labels in `jenkins-controller-svc.yaml`. +For example: + +```yaml +ServiceLabels: + expose: true +``` + +### Persistence + +The Jenkins image stores persistence under `/var/jenkins_home` path of the container. +A dynamically managed Persistent Volume Claim is used to keep the data across deployments, by default. +This is known to work in GCE, AWS, and minikube. Alternatively, a previously configured Persistent Volume Claim can be used. + +It is possible to mount several volumes using `persistence.volumes` and `persistence.mounts` parameters. +See additional `persistence` values using [configuration commands](#configuration). + +#### Existing PersistentVolumeClaim + +1. Create the PersistentVolume +2. Create the PersistentVolumeClaim +3. [Install](#install-chart) the chart, setting `persistence.existingClaim` to `PVC_NAME` + +#### Long Volume Attach/Mount Times + +Certain volume type and filesystem format combinations may experience long +attach/mount times, [10 or more minutes][K8S_VOLUME_TIMEOUT], when using +`fsGroup`. This issue may result in the following entries in the pod's event +history: + +```console +Warning FailedMount 38m kubelet, aks-default-41587790-2 Unable to attach or mount volumes: unmounted volumes=[jenkins-home], unattached volumes=[plugins plugin-dir jenkins-token-rmq2g sc-config-volume tmp jenkins-home jenkins-config secrets-dir]: timed out waiting for the condition +``` + +In these cases, experiment with replacing `fsGroup` with +`supplementalGroups` in the pod's `securityContext`. This can be achieved by +setting the `controller.podSecurityContextOverride` Helm chart value to +something like: + +```yaml +controller: + podSecurityContextOverride: + runAsNonRoot: true + runAsUser: 1000 + supplementalGroups: [1000] +``` + +This issue has been reported on [azureDisk with ext4][K8S_VOLUME_TIMEOUT] and +on [Alibaba cloud][K8S_VOLUME_TIMEOUT_ALIBABA]. + +[K8S_VOLUME_TIMEOUT]: https://github.com/kubernetes/kubernetes/issues/67014 +[K8S_VOLUME_TIMEOUT_ALIBABA]: https://github.com/kubernetes/kubernetes/issues/67014#issuecomment-698770511 + +#### Storage Class + +It is possible to define which storage class to use, by setting `persistence.storageClass` to `[customStorageClass]`. +If set to a dash (`-`), dynamic provisioning is disabled. +If the storage class is set to null or left undefined (`""`), the default provisioner is used (gp2 on AWS, standard on GKE, AWS & OpenStack). + +### Additional Secrets + +Additional secrets and Additional Existing Secrets, +can be mounted into the Jenkins controller through the chart or created using `controller.additionalSecrets` or `controller.additionalExistingSecrets`. +A common use case might be identity provider credentials if using an external LDAP or OIDC-based identity provider. +The secret may then be referenced in JCasC configuration (see [JCasC configuration](#configuration-as-code)). + +`values.yaml` controller section, referencing mounted secrets: +```yaml +controller: + # the 'name' and 'keyName' are concatenated with a '-' in between, so for example: + # an existing secret "secret-credentials" and a key inside it named "github-password" should be used in Jcasc as ${secret-credentials-github-password} + # 'name' and 'keyName' must be lowercase RFC 1123 label must consist of lower case alphanumeric characters or '-', + # and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc') + # existingSecret existing secret "secret-credentials" and a key inside it named "github-username" should be used in Jcasc as ${github-username} + # When using existingSecret no need to specify the keyName under additionalExistingSecrets. + existingSecret: secret-credentials + + additionalExistingSecrets: + - name: secret-credentials + keyName: github-username + - name: secret-credentials + keyName: github-password + - name: secret-credentials + keyName: token + + additionalSecrets: + - name: client_id + value: abc123 + - name: client_secret + value: xyz999 + JCasC: + securityRealm: | + oic: + clientId: ${client_id} + clientSecret: ${client_secret} + ... + configScripts: + jenkins-casc-configs: | + credentials: + system: + domainCredentials: + - credentials: + - string: + description: "github access token" + id: "github_app_token" + scope: GLOBAL + secret: ${secret-credentials-token} + - usernamePassword: + description: "github access username password" + id: "github_username_pass" + password: ${secret-credentials-github-password} + scope: GLOBAL + username: ${secret-credentials-github-username} +``` + +For more information, see [JCasC documentation](https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/docs/features/secrets.adoc#kubernetes-secrets). + +### Secret Claims from HashiCorp Vault + +It's possible for this chart to generate `SecretClaim` resources in order to automatically create and maintain Kubernetes `Secrets` from HashiCorp [Vault](https://www.vaultproject.io/) via [`kube-vault-controller`](https://github.com/roboll/kube-vault-controller) + +These `Secrets` can then be referenced in the same manner as Additional Secrets above. + +This can be achieved by defining required Secret Claims within `controller.secretClaims`, as follows: +```yaml +controller: + secretClaims: + - name: jenkins-secret + path: secret/path + - name: jenkins-short-ttl + path: secret/short-ttl-path + renew: 60 +``` + +### RBAC + +RBAC is enabled by default. If you want to disable it you will need to set `rbac.create` to `false`. + +### Adding Custom Pod Templates + +It is possible to add custom pod templates for the default configured kubernetes cloud. +Add a key under `agent.podTemplates` for each pod template. Each key (prior to `|` character) is just a label, and can be any value. +Keys are only used to give the pod template a meaningful name. The only restriction is they may only contain RFC 1123 \ DNS label characters: lowercase letters, numbers, and hyphens. Each pod template can contain multiple containers. +There's no need to add the _jnlp_ container since the kubernetes plugin will automatically inject it into the pod. +For this pod templates configuration to be loaded the following values must be set: + +```yaml +controller.JCasC.defaultConfig: true +``` + +The example below creates a python pod template in the kubernetes cloud: + +```yaml +agent: + podTemplates: + python: | + - name: python + label: jenkins-python + serviceAccount: jenkins + containers: + - name: python + image: python:3 + command: "/bin/sh -c" + args: "cat" + ttyEnabled: true + privileged: true + resourceRequestCpu: "400m" + resourceRequestMemory: "512Mi" + resourceLimitCpu: "1" + resourceLimitMemory: "1024Mi" +``` + +Best reference is `https:///configuration-as-code/reference#Cloud-kubernetes`. + +### Adding Pod Templates Using additionalAgents + +`additionalAgents` may be used to configure additional kubernetes pod templates. +Each additional agent corresponds to `agent` in terms of the configurable values and inherits all values from `agent` so you only need to specify values which differ. +For example: + +```yaml +agent: + podName: default + customJenkinsLabels: default + # set resources for additional agents to inherit + resources: + limits: + cpu: "1" + memory: "2048Mi" + +additionalAgents: + maven: + podName: maven + customJenkinsLabels: maven + # An example of overriding the jnlp container + # sideContainerName: jnlp + image: jenkins/jnlp-agent-maven + tag: latest + python: + podName: python + customJenkinsLabels: python + sideContainerName: python + image: python + tag: "3" + command: "/bin/sh -c" + args: "cat" + TTYEnabled: true +``` + +### Ingress Configuration + +This chart provides ingress resources configurable via the `controller.ingress` block. + +The simplest configuration looks like the following: + +```yaml +controller: + ingress: + enabled: true + paths: [] + apiVersion: "extensions/v1beta1" + hostName: jenkins.example.com +``` + +This snippet configures an ingress rule for exposing jenkins at `jenkins.example.com` + +You can define labels and annotations via `controller.ingress.labels` and `controller.ingress.annotations` respectively. +Additionally, you can configure the ingress tls via `controller.ingress.tls`. +By default, this ingress rule exposes all paths. +If needed this can be overwritten by specifying the wanted paths in `controller.ingress.paths` + +If you want to configure a secondary ingress e.g. you don't want the jenkins instance exposed but still want to receive webhooks you can configure `controller.secondaryingress`. +The secondaryingress doesn't expose anything by default and has to be configured via `controller.secondaryingress.paths`: + +```yaml +controller: + ingress: + enabled: true + apiVersion: "extensions/v1beta1" + hostName: "jenkins.internal.example.com" + annotations: + kubernetes.io/ingress.class: "internal" + secondaryingress: + enabled: true + apiVersion: "extensions/v1beta1" + hostName: "jenkins-scm.example.com" + annotations: + kubernetes.io/ingress.class: "public" + paths: + - /github-webhook +``` + +## Prometheus Metrics + +If you want to expose Prometheus metrics you need to install the [Jenkins Prometheus Metrics Plugin](https://github.com/jenkinsci/prometheus-plugin). +It will expose an endpoint (default `/prometheus`) with metrics where a Prometheus Server can scrape. + +If you have implemented [Prometheus Operator](https://github.com/prometheus-operator/prometheus-operator), you can set `controller.prometheus.enabled` to `true` to configure a `ServiceMonitor` and `PrometheusRule`. +If you want to further adjust alerting rules you can do so by configuring `controller.prometheus.alertingrules` + +If you have implemented Prometheus without using the operator, you can leave `controller.prometheus.enabled` set to `false`. + +### Running Behind a Forward Proxy + +The controller pod uses an Init Container to install plugins etc. If you are behind a corporate proxy it may be useful to set `controller.initContainerEnv` to add environment variables such as `http_proxy`, so that these can be downloaded. + +Additionally, you may want to add env vars for the init container, the Jenkins container, and the JVM (`controller.javaOpts`): + +```yaml +controller: + initContainerEnv: + - name: http_proxy + value: "http://192.168.64.1:3128" + - name: https_proxy + value: "http://192.168.64.1:3128" + - name: no_proxy + value: "" + - name: JAVA_OPTS + value: "-Dhttps.proxyHost=proxy_host_name_without_protocol -Dhttps.proxyPort=3128" + containerEnv: + - name: http_proxy + value: "http://192.168.64.1:3128" + - name: https_proxy + value: "http://192.168.64.1:3128" + javaOpts: >- + -Dhttp.proxyHost=192.168.64.1 + -Dhttp.proxyPort=3128 + -Dhttps.proxyHost=192.168.64.1 + -Dhttps.proxyPort=3128 +``` + +### HTTPS Keystore Configuration + +[This configuration](https://wiki.jenkins.io/pages/viewpage.action?pageId=135468777) enables jenkins to use keystore in order to serve HTTPS. +Here is the [value file section](https://wiki.jenkins.io/pages/viewpage.action?pageId=135468777#RunningJenkinswithnativeSSL/HTTPS-ConfigureJenkinstouseHTTPSandtheJKSkeystore) related to keystore configuration. +Keystore itself should be placed in front of `jenkinsKeyStoreBase64Encoded` key and in base64 encoded format. To achieve that after having `keystore.jks` file simply do this: `cat keystore.jks | base64` and paste the output in front of `jenkinsKeyStoreBase64Encoded`. +After enabling `httpsKeyStore.enable` make sure that `httpPort` and `targetPort` are not the same, as `targetPort` will serve HTTPS. +Do not set `controller.httpsKeyStore.httpPort` to `-1` because it will cause readiness and liveliness prob to fail. +If you already have a kubernetes secret that has keystore and its password you can specify its' name in front of `jenkinsHttpsJksSecretName`, You need to remember that your secret should have proper data key names `jenkins-jks-file` (or override the key name using `jenkinsHttpsJksSecretKey`) +and `https-jks-password` (or override the key name using `jenkinsHttpsJksPasswordSecretKey`; additionally you can make it get the password from a different secret using `jenkinsHttpsJksPasswordSecretName`). Example: + +```yaml +controller: + httpsKeyStore: + enable: true + jenkinsHttpsJksSecretName: '' + httpPort: 8081 + path: "/var/jenkins_keystore" + fileName: "keystore.jks" + password: "changeit" + jenkinsKeyStoreBase64Encoded: '' +``` +### AWS Security Group Policies + +To create SecurityGroupPolicies set `awsSecurityGroupPolicies.enabled` to true and add your policies. Each policy requires a `name`, array of `securityGroupIds` and a `podSelector`. Example: + +```yaml +awsSecurityGroupPolicies: + enabled: true + policies: + - name: "jenkins-controller" + securityGroupIds: + - sg-123456789 + podSelector: + matchExpressions: + - key: app.kubernetes.io/component + operator: In + values: + - jenkins-controller +``` + +### Agent Direct Connection + +Set `directConnection` to `true` to allow agents to connect directly to a given TCP port without having to negotiate a HTTP(S) connection. This can allow you to have agent connections without an external HTTP(S) port. Example: + +```yaml +agent: + jenkinsTunnel: "jenkinsci-agent:50000" + directConnection: true +``` + +## Migration Guide + +### From stable repository + +Upgrade an existing release from `stable/jenkins` to `jenkins/jenkins` seamlessly by ensuring you have the latest [repository info](#get-repository-info) and running the [upgrade commands](#upgrade-chart) specifying the `jenkins/jenkins` chart. + +### Major Version Upgrades + +Chart release versions follow [SemVer](../../CONTRIBUTING.md#versioning), where a MAJOR version change (example `1.0.0` -> `2.0.0`) indicates an incompatible breaking change needing manual actions. + +See [UPGRADING.md](./UPGRADING.md) for a list of breaking changes diff --git a/charts/jenkins/jenkins/5.5.14/UPGRADING.md b/charts/jenkins/jenkins/5.5.14/UPGRADING.md new file mode 100644 index 000000000..0ff90112d --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/UPGRADING.md @@ -0,0 +1,148 @@ +# Upgrade Notes + +## To 5.0.0 +- `controller.image`, `controller.tag`, and `controller.tagLabel` have been removed. If you want to overwrite the image you now need to configure any or all of: + - `controller.image.registry` + - `controller.image.repository` + - `controller.image.tag` + - `controller.image.tagLabel` +- `controller.imagePullPolicy` has been removed. If you want to overwrite the pull policy you now need to configure `controller.image.pullPolicy`. +- `controller.sidecars.configAutoReload.image` has been removed. If you want to overwrite the configAutoReload image you now need to configure any or all of: + - `controller.sidecars.configAutoReload.image.registry` + - `controller.sidecars.configAutoReload.image.repository` + - `controller.sidecars.configAutoReload.image.tag` +- `controller.sidecars.other` has been renamed to `controller.sidecars.additionalSidecarContainers`. +- `agent.image` and `agent.tag` have been removed. If you want to overwrite the agent image you now need to configure any or all of: + - `agent.image.repository` + - `agent.image.tag` + - The registry can still be overwritten by `agent.jnlpregistry` +- `agent.additionalContainers[*].image` has been renamed to `agent.additionalContainers[*].image.repository` +- `agent.additionalContainers[*].tag` has been renamed to `agent.additionalContainers[*].image.tag` +- `additionalAgents.*.image` has been renamed to `additionalAgents.*.image.repository` +- `additionalAgents.*.tag` has been renamed to `additionalAgents.*.image.tag` +- `additionalClouds.*.additionalAgents.*.image` has been renamed to `additionalClouds.*.additionalAgents.*.image.repository` +- `additionalClouds.*.additionalAgents.*.tag` has been renamed to `additionalClouds.*.additionalAgents.*.image.tag` +- `helmtest.bats.image` has been split up to: + - `helmtest.bats.image.registry` + - `helmtest.bats.image.repository` + - `helmtest.bats.image.tag` +- `controller.adminUsername` and `controller.adminPassword` have been renamed to `controller.admin.username` and `controller.admin.password` respectively +- `controller.adminSecret` has been renamed to `controller.admin.createSecret` +- `backup.*` was unmaintained and has thus been removed. See the following page for alternatives: [Kubernetes Backup and Migrations](https://nubenetes.com/kubernetes-backup-migrations/). + +## To 4.0.0 +Removes automatic `remotingSecurity` setting when using a container tag older than `2.326` (introduced in [`3.11.7`](./CHANGELOG.md#3117)). If you're using a version older than `2.326`, you should explicitly set `.controller.legacyRemotingSecurityEnabled` to `true`. + +## To 3.0.0 + +* Check `securityRealm` and `authorizationStrategy` and adjust it. + Otherwise, your configured users and permissions will be overridden. +* You need to use helm version 3 as the `Chart.yaml` uses `apiVersion: v2`. +* All XML configuration options have been removed. + In case those are still in use you need to migrate to configuration as code. + Upgrade guide to 2.0.0 contains pointers how to do that. +* Jenkins is now using a `StatefulSet` instead of a `Deployment` +* terminology has been adjusted that's also reflected in values.yaml + The following values from `values.yaml` have been renamed: + + * `master` => `controller` + * `master.useSecurity` => `controller.adminSecret` + * `master.slaveListenerPort` => `controller.agentListenerPort` + * `master.slaveHostPort` => `controller.agentListenerHostPort` + * `master.slaveKubernetesNamespace` => `agent.namespace` + * `master.slaveDefaultsProviderTemplate` => `agent.defaultsProviderTemplate` + * `master.slaveJenkinsUrl` => `agent.jenkinsUrl` + * `master.slaveJenkinsTunnel` => `agent.jenkinsTunnel` + * `master.slaveConnectTimeout` => `agent.kubernetesConnectTimeout` + * `master.slaveReadTimeout` => `agent.kubernetesReadTimeout` + * `master.slaveListenerServiceAnnotations` => `controller.agentListenerServiceAnnotations` + * `master.slaveListenerServiceType` => `controller.agentListenerServiceType` + * `master.slaveListenerLoadBalancerIP` => `controller.agentListenerLoadBalancerIP` + * `agent.slaveConnectTimeout` => `agent.connectTimeout` +* Removed values: + + * `master.imageTag`: use `controller.image` and `controller.tag` instead + * `slave.imageTag`: use `agent.image` and `agent.tag` instead + +## To 2.0.0 + +Configuration as Code is now default + container does not run as root anymore. + +### Configuration as Code new default + +Configuration is done via [Jenkins Configuration as Code Plugin](https://github.com/jenkinsci/configuration-as-code-plugin) by default. +That means that changes in values which result in a configuration change are always applied. +In contrast, the XML configuration was only applied during the first start and never altered. + +:exclamation::exclamation::exclamation: +Attention: +This also means if you manually altered configuration then this will most likely be reset to what was configured by default. +It also applies to `securityRealm` and `authorizationStrategy` as they are also configured using configuration as code. +:exclamation::exclamation::exclamation: + +### Image does not run as root anymore + +It's not recommended to run containers in Kubernetes as `root`. + +❗Attention: If you had not configured a different user before then you need to ensure that your image supports the user and group ID configured and also manually change permissions of all files so that Jenkins is still able to use them. + +### Summary of updated values + +As version 2.0.0 only updates default values and nothing else it's still possible to migrate to this version and opt out of some or all new defaults. +All you have to do is ensure the old values are set in your installation. + +Here we show which values have changed and the previous default values: + +```yaml +controller: + runAsUser: 1000 # was unset before + fsGroup: 1000 # was unset before + JCasC: + enabled: true # was false + defaultConfig: true # was false + sidecars: + configAutoReload: + enabled: true # was false +``` + +### Migration steps + +Migration instructions heavily depend on your current setup. +So think of the list below more as a general guideline of what should be done. + +- Ensure that the Jenkins image you are using contains a user with ID 1000 and a group with the same ID. + That's the case for `jenkins/jenkins:lts` image, which the chart uses by default +- Make a backup of your existing installation especially the persistent volume +- Ensure that you have the configuration as code plugin installed +- Export your current settings via the plugin: + `Manage Jenkins` -> `Configuration as Code` -> `Download Configuration` +- prepare your values file for the update e.g. add additional configuration as code setting that you need. + The export taken from above might be a good starting point for this. + In addition, the [demos](https://github.com/jenkinsci/configuration-as-code-plugin/tree/master/demos) from the plugin itself are quite useful. +- Test drive those setting on a separate installation +- Put Jenkins to Quiet Down mode so that it does not accept new jobs + `/quietDown` +- Change permissions of all files and folders to the new user and group ID: + + ```console + kubectl exec -it -c jenkins /bin/bash + chown -R 1000:1000 /var/jenkins_home + ``` + +- Update Jenkins + +## To 1.0.0 + +Breaking changes: + +- Values have been renamed to follow [helm recommended naming conventions](https://helm.sh/docs/chart_best_practices/#naming-conventions) so that all variables start with a lowercase letter and words are separated with camelcase +- All resources are now using [helm recommended standard labels](https://helm.sh/docs/chart_best_practices/#standard-labels) + +As a result of the label changes also the selectors of the deployment have been updated. +Those are immutable so trying an updated will cause an error like: + +```console +Error: Deployment.apps "jenkins" is invalid: spec.selector: Invalid value: v1.LabelSelector{MatchLabels:map[string]string{"app.kubernetes.io/component":"jenkins-controller", "app.kubernetes.io/instance":"jenkins"}, MatchExpressions:[]v1.LabelSelectorRequirement(nil)}: field is immutable +``` + +In order to upgrade, [uninstall](./README.md#uninstall-chart) the Jenkins Deployment before upgrading: diff --git a/charts/jenkins/jenkins/5.5.14/VALUES.md b/charts/jenkins/jenkins/5.5.14/VALUES.md new file mode 100644 index 000000000..31c312ec0 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/VALUES.md @@ -0,0 +1,316 @@ +# Jenkins + +## Configuration + +The following tables list the configurable parameters of the Jenkins chart and their default values. + +## Values + +| Key | Type | Description | Default | +|:----|:-----|:---------|:------------| +| [additionalAgents](./values.yaml#L1189) | object | Configure additional | `{}` | +| [additionalClouds](./values.yaml#L1214) | object | | `{}` | +| [agent.TTYEnabled](./values.yaml#L1095) | bool | Allocate pseudo tty to the side container | `false` | +| [agent.additionalContainers](./values.yaml#L1142) | list | Add additional containers to the agents | `[]` | +| [agent.alwaysPullImage](./values.yaml#L988) | bool | Always pull agent container image before build | `false` | +| [agent.annotations](./values.yaml#L1138) | object | Annotations to apply to the pod | `{}` | +| [agent.args](./values.yaml#L1089) | string | Arguments passed to command to execute | `"${computer.jnlpmac} ${computer.name}"` | +| [agent.command](./values.yaml#L1087) | string | Command to execute when side container starts | `nil` | +| [agent.componentName](./values.yaml#L956) | string | | `"jenkins-agent"` | +| [agent.connectTimeout](./values.yaml#L1136) | int | Timeout in seconds for an agent to be online | `100` | +| [agent.containerCap](./values.yaml#L1097) | int | Max number of agents to launch | `10` | +| [agent.customJenkinsLabels](./values.yaml#L953) | list | Append Jenkins labels to the agent | `[]` | +| [agent.defaultsProviderTemplate](./values.yaml#L907) | string | The name of the pod template to use for providing default values | `""` | +| [agent.directConnection](./values.yaml#L959) | bool | | `false` | +| [agent.disableDefaultAgent](./values.yaml#L1160) | bool | Disable the default Jenkins Agent configuration | `false` | +| [agent.enabled](./values.yaml#L905) | bool | Enable Kubernetes plugin jnlp-agent podTemplate | `true` | +| [agent.envVars](./values.yaml#L1070) | list | Environment variables for the agent Pod | `[]` | +| [agent.garbageCollection.enabled](./values.yaml#L1104) | bool | When enabled, Jenkins will periodically check for orphan pods that have not been touched for the given timeout period and delete them. | `false` | +| [agent.garbageCollection.namespaces](./values.yaml#L1106) | string | Namespaces to look at for garbage collection, in addition to the default namespace defined for the cloud. One namespace per line. | `""` | +| [agent.garbageCollection.timeout](./values.yaml#L1111) | int | Timeout value for orphaned pods | `300` | +| [agent.hostNetworking](./values.yaml#L967) | bool | Enables the agent to use the host network | `false` | +| [agent.idleMinutes](./values.yaml#L1114) | int | Allows the Pod to remain active for reuse until the configured number of minutes has passed since the last step was executed on it | `0` | +| [agent.image.repository](./values.yaml#L946) | string | Repository to pull the agent jnlp image from | `"jenkins/inbound-agent"` | +| [agent.image.tag](./values.yaml#L948) | string | Tag of the image to pull | `"3261.v9c670a_4748a_9-1"` | +| [agent.imagePullSecretName](./values.yaml#L955) | string | Name of the secret to be used to pull the image | `nil` | +| [agent.inheritYamlMergeStrategy](./values.yaml#L1134) | bool | Controls whether the defined yaml merge strategy will be inherited if another defined pod template is configured to inherit from the current one | `false` | +| [agent.jenkinsTunnel](./values.yaml#L923) | string | Overrides the Kubernetes Jenkins tunnel | `nil` | +| [agent.jenkinsUrl](./values.yaml#L919) | string | Overrides the Kubernetes Jenkins URL | `nil` | +| [agent.jnlpregistry](./values.yaml#L943) | string | Custom registry used to pull the agent jnlp image from | `nil` | +| [agent.kubernetesConnectTimeout](./values.yaml#L929) | int | The connection timeout in seconds for connections to Kubernetes API. The minimum value is 5 | `5` | +| [agent.kubernetesReadTimeout](./values.yaml#L931) | int | The read timeout in seconds for connections to Kubernetes API. The minimum value is 15 | `15` | +| [agent.livenessProbe](./values.yaml#L978) | object | | `{}` | +| [agent.maxRequestsPerHostStr](./values.yaml#L933) | string | The maximum concurrent connections to Kubernetes API | `"32"` | +| [agent.namespace](./values.yaml#L939) | string | Namespace in which the Kubernetes agents should be launched | `nil` | +| [agent.nodeSelector](./values.yaml#L1081) | object | Node labels for pod assignment | `{}` | +| [agent.nodeUsageMode](./values.yaml#L951) | string | | `"NORMAL"` | +| [agent.podLabels](./values.yaml#L941) | object | Custom Pod labels (an object with `label-key: label-value` pairs) | `{}` | +| [agent.podName](./values.yaml#L1099) | string | Agent Pod base name | `"default"` | +| [agent.podRetention](./values.yaml#L997) | string | | `"Never"` | +| [agent.podTemplates](./values.yaml#L1170) | object | Configures extra pod templates for the default kubernetes cloud | `{}` | +| [agent.privileged](./values.yaml#L961) | bool | Agent privileged container | `false` | +| [agent.resources](./values.yaml#L969) | object | Resources allocation (Requests and Limits) | `{"limits":{"cpu":"512m","memory":"512Mi"},"requests":{"cpu":"512m","memory":"512Mi"}}` | +| [agent.restrictedPssSecurityContext](./values.yaml#L994) | bool | Set a restricted securityContext on jnlp containers | `false` | +| [agent.retentionTimeout](./values.yaml#L935) | int | Time in minutes after which the Kubernetes cloud plugin will clean up an idle worker that has not already terminated | `5` | +| [agent.runAsGroup](./values.yaml#L965) | string | Configure container group | `nil` | +| [agent.runAsUser](./values.yaml#L963) | string | Configure container user | `nil` | +| [agent.secretEnvVars](./values.yaml#L1074) | list | Mount a secret as environment variable | `[]` | +| [agent.serviceAccount](./values.yaml#L915) | string | Override the default service account | `serviceAccountAgent.name` if `agent.useDefaultServiceAccount` is `true` | +| [agent.showRawYaml](./values.yaml#L1001) | bool | | `true` | +| [agent.sideContainerName](./values.yaml#L1091) | string | Side container name | `"jnlp"` | +| [agent.skipTlsVerify](./values.yaml#L925) | bool | Disables the verification of the controller certificate on remote connection. This flag correspond to the "Disable https certificate check" flag in kubernetes plugin UI | `false` | +| [agent.usageRestricted](./values.yaml#L927) | bool | Enable the possibility to restrict the usage of this agent to specific folder. This flag correspond to the "Restrict pipeline support to authorized folders" flag in kubernetes plugin UI | `false` | +| [agent.useDefaultServiceAccount](./values.yaml#L911) | bool | Use `serviceAccountAgent.name` as the default value for defaults template `serviceAccount` | `true` | +| [agent.volumes](./values.yaml#L1008) | list | Additional volumes | `[]` | +| [agent.waitForPodSec](./values.yaml#L937) | int | Seconds to wait for pod to be running | `600` | +| [agent.websocket](./values.yaml#L958) | bool | Enables agent communication via websockets | `false` | +| [agent.workingDir](./values.yaml#L950) | string | Configure working directory for default agent | `"/home/jenkins/agent"` | +| [agent.workspaceVolume](./values.yaml#L1043) | object | Workspace volume (defaults to EmptyDir) | `{}` | +| [agent.yamlMergeStrategy](./values.yaml#L1132) | string | Defines how the raw yaml field gets merged with yaml definitions from inherited pod templates. Possible values: "merge" or "override" | `"override"` | +| [agent.yamlTemplate](./values.yaml#L1121) | string | The raw yaml of a Pod API Object to merge into the agent spec | `""` | +| [awsSecurityGroupPolicies.enabled](./values.yaml#L1340) | bool | | `false` | +| [awsSecurityGroupPolicies.policies[0].name](./values.yaml#L1342) | string | | `""` | +| [awsSecurityGroupPolicies.policies[0].podSelector](./values.yaml#L1344) | object | | `{}` | +| [awsSecurityGroupPolicies.policies[0].securityGroupIds](./values.yaml#L1343) | list | | `[]` | +| [checkDeprecation](./values.yaml#L1337) | bool | Checks if any deprecated values are used | `true` | +| [clusterZone](./values.yaml#L21) | string | Override the cluster name for FQDN resolving | `"cluster.local"` | +| [controller.JCasC.authorizationStrategy](./values.yaml#L533) | string | Jenkins Config as Code Authorization Strategy-section | `"loggedInUsersCanDoAnything:\n allowAnonymousRead: false"` | +| [controller.JCasC.configMapAnnotations](./values.yaml#L538) | object | Annotations for the JCasC ConfigMap | `{}` | +| [controller.JCasC.configScripts](./values.yaml#L507) | object | List of Jenkins Config as Code scripts | `{}` | +| [controller.JCasC.configUrls](./values.yaml#L504) | list | Remote URLs for configuration files. | `[]` | +| [controller.JCasC.defaultConfig](./values.yaml#L498) | bool | Enables default Jenkins configuration via configuration as code plugin | `true` | +| [controller.JCasC.overwriteConfiguration](./values.yaml#L502) | bool | Whether Jenkins Config as Code should overwrite any existing configuration | `false` | +| [controller.JCasC.security](./values.yaml#L514) | object | Jenkins Config as Code security-section | `{"apiToken":{"creationOfLegacyTokenEnabled":false,"tokenGenerationOnCreationEnabled":false,"usageStatisticsEnabled":true}}` | +| [controller.JCasC.securityRealm](./values.yaml#L522) | string | Jenkins Config as Code Security Realm-section | `"local:\n allowsSignup: false\n enableCaptcha: false\n users:\n - id: \"${chart-admin-username}\"\n name: \"Jenkins Admin\"\n password: \"${chart-admin-password}\""` | +| [controller.additionalExistingSecrets](./values.yaml#L459) | list | List of additional existing secrets to mount | `[]` | +| [controller.additionalPlugins](./values.yaml#L409) | list | List of plugins to install in addition to those listed in controller.installPlugins | `[]` | +| [controller.additionalSecrets](./values.yaml#L468) | list | List of additional secrets to create and mount | `[]` | +| [controller.admin.createSecret](./values.yaml#L91) | bool | Create secret for admin user | `true` | +| [controller.admin.existingSecret](./values.yaml#L94) | string | The name of an existing secret containing the admin credentials | `""` | +| [controller.admin.password](./values.yaml#L81) | string | Admin password created as a secret if `controller.admin.createSecret` is true | `` | +| [controller.admin.passwordKey](./values.yaml#L86) | string | The key in the existing admin secret containing the password | `"jenkins-admin-password"` | +| [controller.admin.userKey](./values.yaml#L84) | string | The key in the existing admin secret containing the username | `"jenkins-admin-user"` | +| [controller.admin.username](./values.yaml#L78) | string | Admin username created as a secret if `controller.admin.createSecret` is true | `"admin"` | +| [controller.affinity](./values.yaml#L660) | object | Affinity settings | `{}` | +| [controller.agentListenerEnabled](./values.yaml#L318) | bool | Create Agent listener service | `true` | +| [controller.agentListenerExternalTrafficPolicy](./values.yaml#L328) | string | Traffic Policy of for the agentListener service | `nil` | +| [controller.agentListenerHostPort](./values.yaml#L322) | string | Host port to listen for agents | `nil` | +| [controller.agentListenerLoadBalancerIP](./values.yaml#L358) | string | Static IP for the agentListener LoadBalancer | `nil` | +| [controller.agentListenerLoadBalancerSourceRanges](./values.yaml#L330) | list | Allowed inbound IP for the agentListener service | `["0.0.0.0/0"]` | +| [controller.agentListenerNodePort](./values.yaml#L324) | string | Node port to listen for agents | `nil` | +| [controller.agentListenerPort](./values.yaml#L320) | int | Listening port for agents | `50000` | +| [controller.agentListenerServiceAnnotations](./values.yaml#L353) | object | Annotations for the agentListener service | `{}` | +| [controller.agentListenerServiceType](./values.yaml#L350) | string | Defines how to expose the agentListener service | `"ClusterIP"` | +| [controller.backendconfig.annotations](./values.yaml#L763) | object | backendconfig annotations | `{}` | +| [controller.backendconfig.apiVersion](./values.yaml#L757) | string | backendconfig API version | `"extensions/v1beta1"` | +| [controller.backendconfig.enabled](./values.yaml#L755) | bool | Enables backendconfig | `false` | +| [controller.backendconfig.labels](./values.yaml#L761) | object | backendconfig labels | `{}` | +| [controller.backendconfig.name](./values.yaml#L759) | string | backendconfig name | `nil` | +| [controller.backendconfig.spec](./values.yaml#L765) | object | backendconfig spec | `{}` | +| [controller.cloudName](./values.yaml#L487) | string | Name of default cloud configuration. | `"kubernetes"` | +| [controller.clusterIp](./values.yaml#L217) | string | k8s service clusterIP. Only used if serviceType is ClusterIP | `nil` | +| [controller.componentName](./values.yaml#L34) | string | Used for label app.kubernetes.io/component | `"jenkins-controller"` | +| [controller.containerEnv](./values.yaml#L150) | list | Environment variables for Jenkins Container | `[]` | +| [controller.containerEnvFrom](./values.yaml#L147) | list | Environment variable sources for Jenkins Container | `[]` | +| [controller.containerSecurityContext](./values.yaml#L205) | object | Allow controlling the securityContext for the jenkins container | `{"allowPrivilegeEscalation":false,"readOnlyRootFilesystem":true,"runAsGroup":1000,"runAsUser":1000}` | +| [controller.csrf.defaultCrumbIssuer.enabled](./values.yaml#L339) | bool | Enable the default CSRF Crumb issuer | `true` | +| [controller.csrf.defaultCrumbIssuer.proxyCompatability](./values.yaml#L341) | bool | Enable proxy compatibility | `true` | +| [controller.customInitContainers](./values.yaml#L541) | list | Custom init-container specification in raw-yaml format | `[]` | +| [controller.customJenkinsLabels](./values.yaml#L68) | list | Append Jenkins labels to the controller | `[]` | +| [controller.disableRememberMe](./values.yaml#L59) | bool | Disable use of remember me | `false` | +| [controller.disabledAgentProtocols](./values.yaml#L333) | list | Disabled agent protocols | `["JNLP-connect","JNLP2-connect"]` | +| [controller.enableRawHtmlMarkupFormatter](./values.yaml#L429) | bool | Enable HTML parsing using OWASP Markup Formatter Plugin (antisamy-markup-formatter) | `false` | +| [controller.executorMode](./values.yaml#L65) | string | Sets the executor mode of the Jenkins node. Possible values are "NORMAL" or "EXCLUSIVE" | `"NORMAL"` | +| [controller.existingSecret](./values.yaml#L456) | string | | `nil` | +| [controller.extraPorts](./values.yaml#L388) | list | Optionally configure other ports to expose in the controller container | `[]` | +| [controller.fsGroup](./values.yaml#L186) | int | Deprecated in favor of `controller.podSecurityContextOverride`. uid that will be used for persistent volume. | `1000` | +| [controller.googlePodMonitor.enabled](./values.yaml#L826) | bool | | `false` | +| [controller.googlePodMonitor.scrapeEndpoint](./values.yaml#L831) | string | | `"/prometheus"` | +| [controller.googlePodMonitor.scrapeInterval](./values.yaml#L829) | string | | `"60s"` | +| [controller.healthProbes](./values.yaml#L248) | bool | Enable Kubernetes Probes configuration configured in `controller.probes` | `true` | +| [controller.hostAliases](./values.yaml#L779) | list | Allows for adding entries to Pod /etc/hosts | `[]` | +| [controller.hostNetworking](./values.yaml#L70) | bool | | `false` | +| [controller.httpsKeyStore.disableSecretMount](./values.yaml#L847) | bool | | `false` | +| [controller.httpsKeyStore.enable](./values.yaml#L838) | bool | Enables HTTPS keystore on jenkins controller | `false` | +| [controller.httpsKeyStore.fileName](./values.yaml#L855) | string | Jenkins keystore filename which will appear under controller.httpsKeyStore.path | `"keystore.jks"` | +| [controller.httpsKeyStore.httpPort](./values.yaml#L851) | int | HTTP Port that Jenkins should listen to along with HTTPS, it also serves as the liveness and readiness probes port. | `8081` | +| [controller.httpsKeyStore.jenkinsHttpsJksPasswordSecretKey](./values.yaml#L846) | string | Name of the key in the secret that contains the JKS password | `"https-jks-password"` | +| [controller.httpsKeyStore.jenkinsHttpsJksPasswordSecretName](./values.yaml#L844) | string | Name of the secret that contains the JKS password, if it is not in the same secret as the JKS file | `""` | +| [controller.httpsKeyStore.jenkinsHttpsJksSecretKey](./values.yaml#L842) | string | Name of the key in the secret that already has ssl keystore | `"jenkins-jks-file"` | +| [controller.httpsKeyStore.jenkinsHttpsJksSecretName](./values.yaml#L840) | string | Name of the secret that already has ssl keystore | `""` | +| [controller.httpsKeyStore.jenkinsKeyStoreBase64Encoded](./values.yaml#L860) | string | Base64 encoded Keystore content. Keystore must be converted to base64 then being pasted here | `nil` | +| [controller.httpsKeyStore.password](./values.yaml#L857) | string | Jenkins keystore password | `"password"` | +| [controller.httpsKeyStore.path](./values.yaml#L853) | string | Path of HTTPS keystore file | `"/var/jenkins_keystore"` | +| [controller.image.pullPolicy](./values.yaml#L47) | string | Controller image pull policy | `"Always"` | +| [controller.image.registry](./values.yaml#L37) | string | Controller image registry | `"docker.io"` | +| [controller.image.repository](./values.yaml#L39) | string | Controller image repository | `"jenkins/jenkins"` | +| [controller.image.tag](./values.yaml#L42) | string | Controller image tag override; i.e., tag: "2.440.1-jdk17" | `nil` | +| [controller.image.tagLabel](./values.yaml#L45) | string | Controller image tag label | `"jdk17"` | +| [controller.imagePullSecretName](./values.yaml#L49) | string | Controller image pull secret | `nil` | +| [controller.ingress.annotations](./values.yaml#L702) | object | Ingress annotations | `{}` | +| [controller.ingress.apiVersion](./values.yaml#L698) | string | Ingress API version | `"extensions/v1beta1"` | +| [controller.ingress.enabled](./values.yaml#L681) | bool | Enables ingress | `false` | +| [controller.ingress.hostName](./values.yaml#L715) | string | Ingress hostname | `nil` | +| [controller.ingress.labels](./values.yaml#L700) | object | Ingress labels | `{}` | +| [controller.ingress.path](./values.yaml#L711) | string | Ingress path | `nil` | +| [controller.ingress.paths](./values.yaml#L685) | list | Override for the default Ingress paths | `[]` | +| [controller.ingress.resourceRootUrl](./values.yaml#L717) | string | Hostname to serve assets from | `nil` | +| [controller.ingress.tls](./values.yaml#L719) | list | Ingress TLS configuration | `[]` | +| [controller.initConfigMap](./values.yaml#L446) | string | Name of the existing ConfigMap that contains init scripts | `nil` | +| [controller.initContainerEnv](./values.yaml#L141) | list | Environment variables for Init Container | `[]` | +| [controller.initContainerEnvFrom](./values.yaml#L137) | list | Environment variable sources for Init Container | `[]` | +| [controller.initContainerResources](./values.yaml#L128) | object | Resources allocation (Requests and Limits) for Init Container | `{}` | +| [controller.initScripts](./values.yaml#L442) | object | Map of groovy init scripts to be executed during Jenkins controller start | `{}` | +| [controller.initializeOnce](./values.yaml#L414) | bool | Initialize only on first installation. Ensures plugins do not get updated inadvertently. Requires `persistence.enabled` to be set to `true` | `false` | +| [controller.installLatestPlugins](./values.yaml#L403) | bool | Download the minimum required version or latest version of all dependencies | `true` | +| [controller.installLatestSpecifiedPlugins](./values.yaml#L406) | bool | Set to true to download the latest version of any plugin that is requested to have the latest version | `false` | +| [controller.installPlugins](./values.yaml#L395) | list | List of Jenkins plugins to install. If you don't want to install plugins, set it to `false` | `["kubernetes:4285.v50ed5f624918","workflow-aggregator:600.vb_57cdd26fdd7","git:5.4.1","configuration-as-code:1850.va_a_8c31d3158b_"]` | +| [controller.javaOpts](./values.yaml#L156) | string | Append to `JAVA_OPTS` env var | `nil` | +| [controller.jenkinsAdminEmail](./values.yaml#L96) | string | Email address for the administrator of the Jenkins instance | `nil` | +| [controller.jenkinsHome](./values.yaml#L101) | string | Custom Jenkins home path | `"/var/jenkins_home"` | +| [controller.jenkinsOpts](./values.yaml#L158) | string | Append to `JENKINS_OPTS` env var | `nil` | +| [controller.jenkinsRef](./values.yaml#L106) | string | Custom Jenkins reference path | `"/usr/share/jenkins/ref"` | +| [controller.jenkinsUriPrefix](./values.yaml#L173) | string | Root URI Jenkins will be served on | `nil` | +| [controller.jenkinsUrl](./values.yaml#L168) | string | Set Jenkins URL if you are not using the ingress definitions provided by the chart | `nil` | +| [controller.jenkinsUrlProtocol](./values.yaml#L165) | string | Set protocol for Jenkins URL; `https` if `controller.ingress.tls`, `http` otherwise | `nil` | +| [controller.jenkinsWar](./values.yaml#L109) | string | | `"/usr/share/jenkins/jenkins.war"` | +| [controller.jmxPort](./values.yaml#L385) | string | Open a port, for JMX stats | `nil` | +| [controller.legacyRemotingSecurityEnabled](./values.yaml#L361) | bool | Whether legacy remoting security should be enabled | `false` | +| [controller.lifecycle](./values.yaml#L51) | object | Lifecycle specification for controller-container | `{}` | +| [controller.loadBalancerIP](./values.yaml#L376) | string | Optionally assign a known public LB IP | `nil` | +| [controller.loadBalancerSourceRanges](./values.yaml#L372) | list | Allowed inbound IP addresses | `["0.0.0.0/0"]` | +| [controller.markupFormatter](./values.yaml#L433) | string | Yaml of the markup formatter to use | `"plainText"` | +| [controller.nodePort](./values.yaml#L223) | string | k8s node port. Only used if serviceType is NodePort | `nil` | +| [controller.nodeSelector](./values.yaml#L647) | object | Node labels for pod assignment | `{}` | +| [controller.numExecutors](./values.yaml#L62) | int | Set Number of executors | `0` | +| [controller.overwritePlugins](./values.yaml#L418) | bool | Overwrite installed plugins on start | `false` | +| [controller.overwritePluginsFromImage](./values.yaml#L422) | bool | Overwrite plugins that are already installed in the controller image | `true` | +| [controller.podAnnotations](./values.yaml#L668) | object | Annotations for controller pod | `{}` | +| [controller.podDisruptionBudget.annotations](./values.yaml#L312) | object | | `{}` | +| [controller.podDisruptionBudget.apiVersion](./values.yaml#L310) | string | Policy API version | `"policy/v1beta1"` | +| [controller.podDisruptionBudget.enabled](./values.yaml#L305) | bool | Enable Kubernetes Pod Disruption Budget configuration | `false` | +| [controller.podDisruptionBudget.labels](./values.yaml#L313) | object | | `{}` | +| [controller.podDisruptionBudget.maxUnavailable](./values.yaml#L315) | string | Number of pods that can be unavailable. Either an absolute number or a percentage | `"0"` | +| [controller.podLabels](./values.yaml#L241) | object | Custom Pod labels (an object with `label-key: label-value` pairs) | `{}` | +| [controller.podSecurityContextOverride](./values.yaml#L202) | string | Completely overwrites the contents of the pod security context, ignoring the values provided for `runAsUser`, `fsGroup`, and `securityContextCapabilities` | `nil` | +| [controller.priorityClassName](./values.yaml#L665) | string | The name of a `priorityClass` to apply to the controller pod | `nil` | +| [controller.probes.livenessProbe.failureThreshold](./values.yaml#L266) | int | Set the failure threshold for the liveness probe | `5` | +| [controller.probes.livenessProbe.httpGet.path](./values.yaml#L269) | string | Set the Pod's HTTP path for the liveness probe | `"{{ default \"\" .Values.controller.jenkinsUriPrefix }}/login"` | +| [controller.probes.livenessProbe.httpGet.port](./values.yaml#L271) | string | Set the Pod's HTTP port to use for the liveness probe | `"http"` | +| [controller.probes.livenessProbe.initialDelaySeconds](./values.yaml#L280) | string | Set the initial delay for the liveness probe in seconds | `nil` | +| [controller.probes.livenessProbe.periodSeconds](./values.yaml#L273) | int | Set the time interval between two liveness probes executions in seconds | `10` | +| [controller.probes.livenessProbe.timeoutSeconds](./values.yaml#L275) | int | Set the timeout for the liveness probe in seconds | `5` | +| [controller.probes.readinessProbe.failureThreshold](./values.yaml#L284) | int | Set the failure threshold for the readiness probe | `3` | +| [controller.probes.readinessProbe.httpGet.path](./values.yaml#L287) | string | Set the Pod's HTTP path for the liveness probe | `"{{ default \"\" .Values.controller.jenkinsUriPrefix }}/login"` | +| [controller.probes.readinessProbe.httpGet.port](./values.yaml#L289) | string | Set the Pod's HTTP port to use for the readiness probe | `"http"` | +| [controller.probes.readinessProbe.initialDelaySeconds](./values.yaml#L298) | string | Set the initial delay for the readiness probe in seconds | `nil` | +| [controller.probes.readinessProbe.periodSeconds](./values.yaml#L291) | int | Set the time interval between two readiness probes executions in seconds | `10` | +| [controller.probes.readinessProbe.timeoutSeconds](./values.yaml#L293) | int | Set the timeout for the readiness probe in seconds | `5` | +| [controller.probes.startupProbe.failureThreshold](./values.yaml#L253) | int | Set the failure threshold for the startup probe | `12` | +| [controller.probes.startupProbe.httpGet.path](./values.yaml#L256) | string | Set the Pod's HTTP path for the startup probe | `"{{ default \"\" .Values.controller.jenkinsUriPrefix }}/login"` | +| [controller.probes.startupProbe.httpGet.port](./values.yaml#L258) | string | Set the Pod's HTTP port to use for the startup probe | `"http"` | +| [controller.probes.startupProbe.periodSeconds](./values.yaml#L260) | int | Set the time interval between two startup probes executions in seconds | `10` | +| [controller.probes.startupProbe.timeoutSeconds](./values.yaml#L262) | int | Set the timeout for the startup probe in seconds | `5` | +| [controller.projectNamingStrategy](./values.yaml#L425) | string | | `"standard"` | +| [controller.prometheus.alertingRulesAdditionalLabels](./values.yaml#L812) | object | Additional labels to add to the PrometheusRule object | `{}` | +| [controller.prometheus.alertingrules](./values.yaml#L810) | list | Array of prometheus alerting rules | `[]` | +| [controller.prometheus.enabled](./values.yaml#L795) | bool | Enables prometheus service monitor | `false` | +| [controller.prometheus.metricRelabelings](./values.yaml#L822) | list | | `[]` | +| [controller.prometheus.prometheusRuleNamespace](./values.yaml#L814) | string | Set a custom namespace where to deploy PrometheusRule resource | `""` | +| [controller.prometheus.relabelings](./values.yaml#L820) | list | | `[]` | +| [controller.prometheus.scrapeEndpoint](./values.yaml#L805) | string | The endpoint prometheus should get metrics from | `"/prometheus"` | +| [controller.prometheus.scrapeInterval](./values.yaml#L801) | string | How often prometheus should scrape metrics | `"60s"` | +| [controller.prometheus.serviceMonitorAdditionalLabels](./values.yaml#L797) | object | Additional labels to add to the service monitor object | `{}` | +| [controller.prometheus.serviceMonitorNamespace](./values.yaml#L799) | string | Set a custom namespace where to deploy ServiceMonitor resource | `nil` | +| [controller.resources](./values.yaml#L115) | object | Resource allocation (Requests and Limits) | `{"limits":{"cpu":"2000m","memory":"4096Mi"},"requests":{"cpu":"50m","memory":"256Mi"}}` | +| [controller.route.annotations](./values.yaml#L774) | object | Route annotations | `{}` | +| [controller.route.enabled](./values.yaml#L770) | bool | Enables openshift route | `false` | +| [controller.route.labels](./values.yaml#L772) | object | Route labels | `{}` | +| [controller.route.path](./values.yaml#L776) | string | Route path | `nil` | +| [controller.runAsUser](./values.yaml#L183) | int | Deprecated in favor of `controller.podSecurityContextOverride`. uid that jenkins runs with. | `1000` | +| [controller.schedulerName](./values.yaml#L643) | string | Name of the Kubernetes scheduler to use | `""` | +| [controller.scriptApproval](./values.yaml#L437) | list | List of groovy functions to approve | `[]` | +| [controller.secondaryingress.annotations](./values.yaml#L737) | object | | `{}` | +| [controller.secondaryingress.apiVersion](./values.yaml#L735) | string | | `"extensions/v1beta1"` | +| [controller.secondaryingress.enabled](./values.yaml#L729) | bool | | `false` | +| [controller.secondaryingress.hostName](./values.yaml#L744) | string | | `nil` | +| [controller.secondaryingress.labels](./values.yaml#L736) | object | | `{}` | +| [controller.secondaryingress.paths](./values.yaml#L732) | list | | `[]` | +| [controller.secondaryingress.tls](./values.yaml#L745) | string | | `nil` | +| [controller.secretClaims](./values.yaml#L480) | list | List of `SecretClaim` resources to create | `[]` | +| [controller.securityContextCapabilities](./values.yaml#L192) | object | | `{}` | +| [controller.serviceAnnotations](./values.yaml#L230) | object | Jenkins controller service annotations | `{}` | +| [controller.serviceExternalTrafficPolicy](./values.yaml#L227) | string | | `nil` | +| [controller.serviceLabels](./values.yaml#L236) | object | Labels for the Jenkins controller-service | `{}` | +| [controller.servicePort](./values.yaml#L219) | int | k8s service port | `8080` | +| [controller.serviceType](./values.yaml#L214) | string | k8s service type | `"ClusterIP"` | +| [controller.shareProcessNamespace](./values.yaml#L124) | bool | | `false` | +| [controller.sidecars.additionalSidecarContainers](./values.yaml#L625) | list | Configures additional sidecar container(s) for the Jenkins controller | `[]` | +| [controller.sidecars.configAutoReload.additionalVolumeMounts](./values.yaml#L571) | list | Enables additional volume mounts for the config auto-reload container | `[]` | +| [controller.sidecars.configAutoReload.containerSecurityContext](./values.yaml#L620) | object | Enable container security context | `{"allowPrivilegeEscalation":false,"readOnlyRootFilesystem":true}` | +| [controller.sidecars.configAutoReload.enabled](./values.yaml#L554) | bool | Enables Jenkins Config as Code auto-reload | `true` | +| [controller.sidecars.configAutoReload.env](./values.yaml#L602) | object | Environment variables for the Jenkins Config as Code auto-reload container | `{}` | +| [controller.sidecars.configAutoReload.envFrom](./values.yaml#L600) | list | Environment variable sources for the Jenkins Config as Code auto-reload container | `[]` | +| [controller.sidecars.configAutoReload.folder](./values.yaml#L613) | string | | `"/var/jenkins_home/casc_configs"` | +| [controller.sidecars.configAutoReload.image.registry](./values.yaml#L557) | string | Registry for the image that triggers the reload | `"docker.io"` | +| [controller.sidecars.configAutoReload.image.repository](./values.yaml#L559) | string | Repository of the image that triggers the reload | `"kiwigrid/k8s-sidecar"` | +| [controller.sidecars.configAutoReload.image.tag](./values.yaml#L561) | string | Tag for the image that triggers the reload | `"1.27.6"` | +| [controller.sidecars.configAutoReload.imagePullPolicy](./values.yaml#L562) | string | | `"IfNotPresent"` | +| [controller.sidecars.configAutoReload.logging](./values.yaml#L577) | object | Config auto-reload logging settings | `{"configuration":{"backupCount":3,"formatter":"JSON","logLevel":"INFO","logToConsole":true,"logToFile":false,"maxBytes":1024,"override":false}}` | +| [controller.sidecars.configAutoReload.logging.configuration.override](./values.yaml#L581) | bool | Enables custom log config utilizing using the settings below. | `false` | +| [controller.sidecars.configAutoReload.reqRetryConnect](./values.yaml#L595) | int | How many connection-related errors to retry on | `10` | +| [controller.sidecars.configAutoReload.resources](./values.yaml#L563) | object | | `{}` | +| [controller.sidecars.configAutoReload.scheme](./values.yaml#L590) | string | The scheme to use when connecting to the Jenkins configuration as code endpoint | `"http"` | +| [controller.sidecars.configAutoReload.skipTlsVerify](./values.yaml#L592) | bool | Skip TLS verification when connecting to the Jenkins configuration as code endpoint | `false` | +| [controller.sidecars.configAutoReload.sleepTime](./values.yaml#L597) | string | How many seconds to wait before updating config-maps/secrets (sets METHOD=SLEEP on the sidecar) | `nil` | +| [controller.sidecars.configAutoReload.sshTcpPort](./values.yaml#L611) | int | | `1044` | +| [controller.statefulSetAnnotations](./values.yaml#L670) | object | Annotations for controller StatefulSet | `{}` | +| [controller.statefulSetLabels](./values.yaml#L232) | object | Jenkins controller custom labels for the StatefulSet | `{}` | +| [controller.targetPort](./values.yaml#L221) | int | k8s target port | `8080` | +| [controller.terminationGracePeriodSeconds](./values.yaml#L653) | string | Set TerminationGracePeriodSeconds | `nil` | +| [controller.terminationMessagePath](./values.yaml#L655) | string | Set the termination message path | `nil` | +| [controller.terminationMessagePolicy](./values.yaml#L657) | string | Set the termination message policy | `nil` | +| [controller.testEnabled](./values.yaml#L834) | bool | Can be used to disable rendering controller test resources when using helm template | `true` | +| [controller.tolerations](./values.yaml#L651) | list | Toleration labels for pod assignment | `[]` | +| [controller.topologySpreadConstraints](./values.yaml#L677) | object | Topology spread constraints | `{}` | +| [controller.updateStrategy](./values.yaml#L674) | object | Update strategy for StatefulSet | `{}` | +| [controller.usePodSecurityContext](./values.yaml#L176) | bool | Enable pod security context (must be `true` if podSecurityContextOverride, runAsUser or fsGroup are set) | `true` | +| [credentialsId](./values.yaml#L27) | string | The Jenkins credentials to access the Kubernetes API server. For the default cluster it is not needed. | `nil` | +| [fullnameOverride](./values.yaml#L13) | string | Override the full resource names | `jenkins-(release-name)` or `jenkins` if the release-name is `jenkins` | +| [helmtest.bats.image.registry](./values.yaml#L1353) | string | Registry of the image used to test the framework | `"docker.io"` | +| [helmtest.bats.image.repository](./values.yaml#L1355) | string | Repository of the image used to test the framework | `"bats/bats"` | +| [helmtest.bats.image.tag](./values.yaml#L1357) | string | Tag of the image to test the framework | `"1.11.0"` | +| [kubernetesURL](./values.yaml#L24) | string | The URL of the Kubernetes API server | `"https://kubernetes.default"` | +| [nameOverride](./values.yaml#L10) | string | Override the resource name prefix | `Chart.Name` | +| [namespaceOverride](./values.yaml#L16) | string | Override the deployment namespace | `Release.Namespace` | +| [networkPolicy.apiVersion](./values.yaml#L1283) | string | NetworkPolicy ApiVersion | `"networking.k8s.io/v1"` | +| [networkPolicy.enabled](./values.yaml#L1278) | bool | Enable the creation of NetworkPolicy resources | `false` | +| [networkPolicy.externalAgents.except](./values.yaml#L1297) | list | A list of IP sub-ranges to be excluded from the allowlisted IP range | `[]` | +| [networkPolicy.externalAgents.ipCIDR](./values.yaml#L1295) | string | The IP range from which external agents are allowed to connect to controller, i.e., 172.17.0.0/16 | `nil` | +| [networkPolicy.internalAgents.allowed](./values.yaml#L1287) | bool | Allow internal agents (from the same cluster) to connect to controller. Agent pods will be filtered based on PodLabels | `true` | +| [networkPolicy.internalAgents.namespaceLabels](./values.yaml#L1291) | object | A map of labels (keys/values) that agents namespaces must have to be able to connect to controller | `{}` | +| [networkPolicy.internalAgents.podLabels](./values.yaml#L1289) | object | A map of labels (keys/values) that agent pods must have to be able to connect to controller | `{}` | +| [persistence.accessMode](./values.yaml#L1253) | string | The PVC access mode | `"ReadWriteOnce"` | +| [persistence.annotations](./values.yaml#L1249) | object | Annotations for the PVC | `{}` | +| [persistence.dataSource](./values.yaml#L1259) | object | Existing data source to clone PVC from | `{}` | +| [persistence.enabled](./values.yaml#L1233) | bool | Enable the use of a Jenkins PVC | `true` | +| [persistence.existingClaim](./values.yaml#L1239) | string | Provide the name of a PVC | `nil` | +| [persistence.labels](./values.yaml#L1251) | object | Labels for the PVC | `{}` | +| [persistence.mounts](./values.yaml#L1271) | list | Additional mounts | `[]` | +| [persistence.size](./values.yaml#L1255) | string | The size of the PVC | `"8Gi"` | +| [persistence.storageClass](./values.yaml#L1247) | string | Storage class for the PVC | `nil` | +| [persistence.subPath](./values.yaml#L1264) | string | SubPath for jenkins-home mount | `nil` | +| [persistence.volumes](./values.yaml#L1266) | list | Additional volumes | `[]` | +| [rbac.create](./values.yaml#L1303) | bool | Whether RBAC resources are created | `true` | +| [rbac.readSecrets](./values.yaml#L1305) | bool | Whether the Jenkins service account should be able to read Kubernetes secrets | `false` | +| [renderHelmLabels](./values.yaml#L30) | bool | Enables rendering of the helm.sh/chart label to the annotations | `true` | +| [serviceAccount.annotations](./values.yaml#L1315) | object | Configures annotations for the ServiceAccount | `{}` | +| [serviceAccount.create](./values.yaml#L1309) | bool | Configures if a ServiceAccount with this name should be created | `true` | +| [serviceAccount.extraLabels](./values.yaml#L1317) | object | Configures extra labels for the ServiceAccount | `{}` | +| [serviceAccount.imagePullSecretName](./values.yaml#L1319) | string | Controller ServiceAccount image pull secret | `nil` | +| [serviceAccount.name](./values.yaml#L1313) | string | | `nil` | +| [serviceAccountAgent.annotations](./values.yaml#L1330) | object | Configures annotations for the agent ServiceAccount | `{}` | +| [serviceAccountAgent.create](./values.yaml#L1324) | bool | Configures if an agent ServiceAccount should be created | `false` | +| [serviceAccountAgent.extraLabels](./values.yaml#L1332) | object | Configures extra labels for the agent ServiceAccount | `{}` | +| [serviceAccountAgent.imagePullSecretName](./values.yaml#L1334) | string | Agent ServiceAccount image pull secret | `nil` | +| [serviceAccountAgent.name](./values.yaml#L1328) | string | The name of the agent ServiceAccount to be used by access-controlled resources | `nil` | diff --git a/charts/jenkins/jenkins/5.5.14/VALUES.md.gotmpl b/charts/jenkins/jenkins/5.5.14/VALUES.md.gotmpl new file mode 100644 index 000000000..21080e35a --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/VALUES.md.gotmpl @@ -0,0 +1,28 @@ +# Jenkins + +## Configuration + +The following tables list the configurable parameters of the Jenkins chart and their default values. + +{{- define "chart.valueDefaultColumnRender" -}} +{{- $defaultValue := (trimAll "`" (default .Default .AutoDefault) | replace "\n" "") -}} +`{{- $defaultValue | replace "\n" "" -}}` +{{- end -}} + +{{- define "chart.typeColumnRender" -}} +{{- .Type -}} +{{- end -}} + +{{- define "chart.valueDescription" -}} +{{- default .Description .AutoDescription }} +{{- end -}} + +{{- define "chart.valuesTable" -}} +| Key | Type | Description | Default | +|:----|:-----|:---------|:------------| +{{- range .Values }} +| [{{ .Key }}](./values.yaml#L{{ .LineNumber }}) | {{ template "chart.typeColumnRender" . }} | {{ template "chart.valueDescription" . }} | {{ template "chart.valueDefaultColumnRender" . }} | +{{- end }} +{{- end }} + +{{ template "chart.valuesSection" . }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/NOTES.txt b/charts/jenkins/jenkins/5.5.14/templates/NOTES.txt new file mode 100644 index 000000000..953dd2606 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/NOTES.txt @@ -0,0 +1,68 @@ +{{- $prefix := .Values.controller.jenkinsUriPrefix | default "" -}} +{{- $url := "" -}} +1. Get your '{{ .Values.controller.admin.username }}' user password by running: + kubectl exec --namespace {{ template "jenkins.namespace" . }} -it svc/{{ template "jenkins.fullname" . }} -c jenkins -- /bin/cat /run/secrets/additional/chart-admin-password && echo +{{- if .Values.controller.ingress.hostName -}} +{{- if .Values.controller.ingress.tls -}} +{{- $url = print "https://" .Values.controller.ingress.hostName $prefix -}} +{{- else -}} +{{- $url = print "http://" .Values.controller.ingress.hostName $prefix -}} +{{- end }} +2. Visit {{ $url }} +{{- else }} +2. Get the Jenkins URL to visit by running these commands in the same shell: +{{- if contains "NodePort" .Values.controller.serviceType }} + export NODE_PORT=$(kubectl get --namespace {{ template "jenkins.namespace" . }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "jenkins.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ template "jenkins.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}") +{{- if .Values.controller.httpsKeyStore.enable -}} +{{- $url = print "https://$NODE_IP:$NODE_PORT" $prefix -}} +{{- else -}} +{{- $url = print "http://$NODE_IP:$NODE_PORT" $prefix -}} +{{- end }} + echo {{ $url }} + +{{- else if contains "LoadBalancer" .Values.controller.serviceType }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get svc --namespace {{ template "jenkins.namespace" . }} -w {{ template "jenkins.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ template "jenkins.namespace" . }} {{ template "jenkins.fullname" . }} --template "{{ "{{ range (index .status.loadBalancer.ingress 0) }}{{ . }}{{ end }}" }}") +{{- if .Values.controller.httpsKeyStore.enable -}} +{{- $url = print "https://$SERVICE_IP:" .Values.controller.servicePort $prefix -}} +{{- else -}} +{{- $url = print "http://$SERVICE_IP:" .Values.controller.servicePort $prefix -}} +{{- end }} + echo {{ $url }} + +{{- else if contains "ClusterIP" .Values.controller.serviceType -}} +{{- if .Values.controller.httpsKeyStore.enable -}} +{{- $url = print "https://127.0.0.1:" .Values.controller.servicePort $prefix -}} +{{- else -}} +{{- $url = print "http://127.0.0.1:" .Values.controller.servicePort $prefix -}} +{{- end }} + echo {{ $url }} + kubectl --namespace {{ template "jenkins.namespace" . }} port-forward svc/{{template "jenkins.fullname" . }} {{ .Values.controller.servicePort }}:{{ .Values.controller.servicePort }} +{{- end }} +{{- end }} + +3. Login with the password from step 1 and the username: {{ .Values.controller.admin.username }} +4. Configure security realm and authorization strategy +5. Use Jenkins Configuration as Code by specifying configScripts in your values.yaml file, see documentation: {{ $url }}/configuration-as-code and examples: https://github.com/jenkinsci/configuration-as-code-plugin/tree/master/demos + +For more information on running Jenkins on Kubernetes, visit: +https://cloud.google.com/solutions/jenkins-on-container-engine + +For more information about Jenkins Configuration as Code, visit: +https://jenkins.io/projects/jcasc/ + +{{ if and (eq .Values.controller.image.repository "jenkins/jenkins") (eq .Values.controller.image.registry "docker.io") }} +NOTE: Consider using a custom image with pre-installed plugins +{{- else if .Values.controller.installPlugins }} +NOTE: Consider disabling `installPlugins` if your image already contains plugins. +{{- end }} + +{{- if .Values.persistence.enabled }} +{{- else }} +################################################################################# +###### WARNING: Persistence is disabled!!! You will lose your data when ##### +###### the Jenkins pod is terminated. ##### +################################################################################# +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/_helpers.tpl b/charts/jenkins/jenkins/5.5.14/templates/_helpers.tpl new file mode 100644 index 000000000..dd3895b65 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/_helpers.tpl @@ -0,0 +1,684 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "jenkins.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Expand the label of the chart. +*/}} +{{- define "jenkins.label" -}} +{{- printf "%s-%s" (include "jenkins.name" .) .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + + +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts. +*/}} +{{- define "jenkins.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "jenkins.agent.namespace" -}} + {{- if .Values.agent.namespace -}} + {{- tpl .Values.agent.namespace . -}} + {{- else -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} + {{- end -}} +{{- end -}} + + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "jenkins.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Returns the admin password +https://github.com/helm/charts/issues/5167#issuecomment-619137759 +*/}} +{{- define "jenkins.password" -}} + {{- if .Values.controller.admin.password -}} + {{- .Values.controller.admin.password | b64enc | quote }} + {{- else -}} + {{- $secret := (lookup "v1" "Secret" .Release.Namespace (include "jenkins.fullname" .)).data -}} + {{- if $secret -}} + {{/* + Reusing current password since secret exists + */}} + {{- index $secret ( .Values.controller.admin.passwordKey | default "jenkins-admin-password" ) -}} + {{- else -}} + {{/* + Generate new password + */}} + {{- randAlphaNum 22 | b64enc | quote }} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Returns the Jenkins URL +*/}} +{{- define "jenkins.url" -}} +{{- if .Values.controller.jenkinsUrl }} + {{- .Values.controller.jenkinsUrl }} +{{- else }} + {{- if .Values.controller.ingress.hostName }} + {{- if .Values.controller.ingress.tls }} + {{- default "https" .Values.controller.jenkinsUrlProtocol }}://{{ tpl .Values.controller.ingress.hostName $ }}{{ default "" .Values.controller.jenkinsUriPrefix }} + {{- else }} + {{- default "http" .Values.controller.jenkinsUrlProtocol }}://{{ tpl .Values.controller.ingress.hostName $ }}{{ default "" .Values.controller.jenkinsUriPrefix }} + {{- end }} + {{- else }} + {{- default "http" .Values.controller.jenkinsUrlProtocol }}://{{ template "jenkins.fullname" . }}:{{.Values.controller.servicePort}}{{ default "" .Values.controller.jenkinsUriPrefix }} + {{- end}} +{{- end}} +{{- end -}} + +{{/* +Returns configuration as code default config +*/}} +{{- define "jenkins.casc.defaults" -}} +jenkins: + {{- $configScripts := toYaml .Values.controller.JCasC.configScripts }} + {{- if and (.Values.controller.JCasC.authorizationStrategy) (not (contains "authorizationStrategy:" $configScripts)) }} + authorizationStrategy: + {{- tpl .Values.controller.JCasC.authorizationStrategy . | nindent 4 }} + {{- end }} + {{- if and (.Values.controller.JCasC.securityRealm) (not (contains "securityRealm:" $configScripts)) }} + securityRealm: + {{- tpl .Values.controller.JCasC.securityRealm . | nindent 4 }} + {{- end }} + disableRememberMe: {{ .Values.controller.disableRememberMe }} + {{- if .Values.controller.legacyRemotingSecurityEnabled }} + remotingSecurity: + enabled: true + {{- end }} + mode: {{ .Values.controller.executorMode }} + numExecutors: {{ .Values.controller.numExecutors }} + {{- if not (kindIs "invalid" .Values.controller.customJenkinsLabels) }} + labelString: "{{ join " " .Values.controller.customJenkinsLabels }}" + {{- end }} + {{- if .Values.controller.projectNamingStrategy }} + {{- if kindIs "string" .Values.controller.projectNamingStrategy }} + projectNamingStrategy: "{{ .Values.controller.projectNamingStrategy }}" + {{- else }} + projectNamingStrategy: + {{- toYaml .Values.controller.projectNamingStrategy | nindent 4 }} + {{- end }} + {{- end }} + markupFormatter: + {{- if .Values.controller.enableRawHtmlMarkupFormatter }} + rawHtml: + disableSyntaxHighlighting: true + {{- else }} + {{- toYaml .Values.controller.markupFormatter | nindent 4 }} + {{- end }} + clouds: + - kubernetes: + containerCapStr: "{{ .Values.agent.containerCap }}" + {{- if .Values.agent.garbageCollection.enabled }} + garbageCollection: + {{- if .Values.agent.garbageCollection.namespaces }} + namespaces: |- + {{- .Values.agent.garbageCollection.namespaces | nindent 10 }} + {{- end }} + timeout: "{{ .Values.agent.garbageCollection.timeout }}" + {{- end }} + {{- if .Values.agent.jnlpregistry }} + jnlpregistry: "{{ .Values.agent.jnlpregistry }}" + {{- end }} + defaultsProviderTemplate: "{{ .Values.agent.defaultsProviderTemplate }}" + connectTimeout: "{{ .Values.agent.kubernetesConnectTimeout }}" + readTimeout: "{{ .Values.agent.kubernetesReadTimeout }}" + {{- if .Values.agent.directConnection }} + directConnection: true + {{- else }} + {{- if .Values.agent.jenkinsUrl }} + jenkinsUrl: "{{ tpl .Values.agent.jenkinsUrl . }}" + {{- else }} + jenkinsUrl: "http://{{ template "jenkins.fullname" . }}.{{ template "jenkins.namespace" . }}.svc.{{.Values.clusterZone}}:{{.Values.controller.servicePort}}{{ default "" .Values.controller.jenkinsUriPrefix }}" + {{- end }} + {{- if not .Values.agent.websocket }} + {{- if .Values.agent.jenkinsTunnel }} + jenkinsTunnel: "{{ tpl .Values.agent.jenkinsTunnel . }}" + {{- else }} + jenkinsTunnel: "{{ template "jenkins.fullname" . }}-agent.{{ template "jenkins.namespace" . }}.svc.{{.Values.clusterZone}}:{{ .Values.controller.agentListenerPort }}" + {{- end }} + {{- else }} + webSocket: true + {{- end }} + {{- end }} + skipTlsVerify: {{ .Values.agent.skipTlsVerify | default false}} + usageRestricted: {{ .Values.agent.usageRestricted | default false}} + maxRequestsPerHostStr: {{ .Values.agent.maxRequestsPerHostStr | quote }} + retentionTimeout: {{ .Values.agent.retentionTimeout | quote }} + waitForPodSec: {{ .Values.agent.waitForPodSec | quote }} + name: "{{ .Values.controller.cloudName }}" + namespace: "{{ template "jenkins.agent.namespace" . }}" + restrictedPssSecurityContext: {{ .Values.agent.restrictedPssSecurityContext }} + serverUrl: "{{ .Values.kubernetesURL }}" + credentialsId: "{{ .Values.credentialsId }}" + {{- if .Values.agent.enabled }} + podLabels: + - key: "jenkins/{{ .Release.Name }}-{{ .Values.agent.componentName }}" + value: "true" + {{- range $key, $val := .Values.agent.podLabels }} + - key: {{ $key | quote }} + value: {{ $val | quote }} + {{- end }} + templates: + {{- if not .Values.agent.disableDefaultAgent }} + {{- include "jenkins.casc.podTemplate" . | nindent 8 }} + {{- end }} + {{- if .Values.additionalAgents }} + {{- /* save .Values.agent */}} + {{- $agent := .Values.agent }} + {{- range $name, $additionalAgent := .Values.additionalAgents }} + {{- $additionalContainersEmpty := and (hasKey $additionalAgent "additionalContainers") (empty $additionalAgent.additionalContainers) }} + {{- /* merge original .Values.agent into additional agent to ensure it at least has the default values */}} + {{- $additionalAgent := merge $additionalAgent $agent }} + {{- /* clear list of additional containers in case it is configured empty for this agent (merge might have overwritten that) */}} + {{- if $additionalContainersEmpty }} + {{- $_ := set $additionalAgent "additionalContainers" list }} + {{- end }} + {{- /* set .Values.agent to $additionalAgent */}} + {{- $_ := set $.Values "agent" $additionalAgent }} + {{- include "jenkins.casc.podTemplate" $ | nindent 8 }} + {{- end }} + {{- /* restore .Values.agent */}} + {{- $_ := set .Values "agent" $agent }} + {{- end }} + {{- if .Values.agent.podTemplates }} + {{- range $key, $val := .Values.agent.podTemplates }} + {{- tpl $val $ | nindent 8 }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.additionalClouds }} + {{- /* save root */}} + {{- $oldRoot := deepCopy $ }} + {{- range $name, $additionalCloud := .Values.additionalClouds }} + {{- $newRoot := deepCopy $ }} + {{- /* clear additionalAgents from the copy if override set to `true` */}} + {{- if .additionalAgentsOverride }} + {{- $_ := set $newRoot.Values "additionalAgents" list}} + {{- end}} + {{- $newValues := merge $additionalCloud $newRoot.Values }} + {{- $_ := set $newRoot "Values" $newValues }} + {{- /* clear additionalClouds from the copy */}} + {{- $_ := set $newRoot.Values "additionalClouds" list }} + {{- with $newRoot}} + - kubernetes: + containerCapStr: "{{ .Values.agent.containerCap }}" + {{- if .Values.agent.jnlpregistry }} + jnlpregistry: "{{ .Values.agent.jnlpregistry }}" + {{- end }} + defaultsProviderTemplate: "{{ .Values.agent.defaultsProviderTemplate }}" + connectTimeout: "{{ .Values.agent.kubernetesConnectTimeout }}" + readTimeout: "{{ .Values.agent.kubernetesReadTimeout }}" + {{- if .Values.agent.directConnection }} + directConnection: true + {{- else }} + {{- if .Values.agent.jenkinsUrl }} + jenkinsUrl: "{{ tpl .Values.agent.jenkinsUrl . }}" + {{- else }} + jenkinsUrl: "http://{{ template "jenkins.fullname" . }}.{{ template "jenkins.namespace" . }}.svc.{{.Values.clusterZone}}:{{.Values.controller.servicePort}}{{ default "" .Values.controller.jenkinsUriPrefix }}" + {{- end }} + {{- if not .Values.agent.websocket }} + {{- if .Values.agent.jenkinsTunnel }} + jenkinsTunnel: "{{ tpl .Values.agent.jenkinsTunnel . }}" + {{- else }} + jenkinsTunnel: "{{ template "jenkins.fullname" . }}-agent.{{ template "jenkins.namespace" . }}.svc.{{.Values.clusterZone}}:{{ .Values.controller.agentListenerPort }}" + {{- end }} + {{- else }} + webSocket: true + {{- end }} + {{- end }} + skipTlsVerify: {{ .Values.agent.skipTlsVerify | default false}} + usageRestricted: {{ .Values.agent.usageRestricted | default false}} + maxRequestsPerHostStr: {{ .Values.agent.maxRequestsPerHostStr | quote }} + retentionTimeout: {{ .Values.agent.retentionTimeout | quote }} + waitForPodSec: {{ .Values.agent.waitForPodSec | quote }} + name: {{ $name | quote }} + namespace: "{{ template "jenkins.agent.namespace" . }}" + restrictedPssSecurityContext: {{ .Values.agent.restrictedPssSecurityContext }} + serverUrl: "{{ .Values.kubernetesURL }}" + credentialsId: "{{ .Values.credentialsId }}" + {{- if .Values.agent.enabled }} + podLabels: + - key: "jenkins/{{ .Release.Name }}-{{ .Values.agent.componentName }}" + value: "true" + {{- range $key, $val := .Values.agent.podLabels }} + - key: {{ $key | quote }} + value: {{ $val | quote }} + {{- end }} + templates: + {{- if not .Values.agent.disableDefaultAgent }} + {{- include "jenkins.casc.podTemplate" . | nindent 8 }} + {{- end }} + {{- if .Values.additionalAgents }} + {{- /* save .Values.agent */}} + {{- $agent := .Values.agent }} + {{- range $name, $additionalAgent := .Values.additionalAgents }} + {{- $additionalContainersEmpty := and (hasKey $additionalAgent "additionalContainers") (empty $additionalAgent.additionalContainers) }} + {{- /* merge original .Values.agent into additional agent to ensure it at least has the default values */}} + {{- $additionalAgent := merge $additionalAgent $agent }} + {{- /* clear list of additional containers in case it is configured empty for this agent (merge might have overwritten that) */}} + {{- if $additionalContainersEmpty }} + {{- $_ := set $additionalAgent "additionalContainers" list }} + {{- end }} + {{- /* set .Values.agent to $additionalAgent */}} + {{- $_ := set $.Values "agent" $additionalAgent }} + {{- include "jenkins.casc.podTemplate" $ | nindent 8 }} + {{- end }} + {{- /* restore .Values.agent */}} + {{- $_ := set .Values "agent" $agent }} + {{- end }} + {{- with .Values.agent.podTemplates }} + {{- range $key, $val := . }} + {{- tpl $val $ | nindent 8 }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- /* restore root */}} + {{- $_ := set $ "Values" $oldRoot.Values }} + {{- end }} + {{- if .Values.controller.csrf.defaultCrumbIssuer.enabled }} + crumbIssuer: + standard: + excludeClientIPFromCrumb: {{ if .Values.controller.csrf.defaultCrumbIssuer.proxyCompatability }}true{{ else }}false{{- end }} + {{- end }} +{{- include "jenkins.casc.security" . }} +{{- with .Values.controller.scriptApproval }} + scriptApproval: + approvedSignatures: + {{- range $key, $val := . }} + - "{{ $val }}" + {{- end }} +{{- end }} +unclassified: + location: + {{- with .Values.controller.jenkinsAdminEmail }} + adminAddress: {{ . }} + {{- end }} + url: {{ template "jenkins.url" . }} +{{- end -}} + +{{/* +Returns a name template to be used for jcasc configmaps, using +suffix passed in at call as index 0 +*/}} +{{- define "jenkins.casc.configName" -}} +{{- $name := index . 0 -}} +{{- $root := index . 1 -}} +"{{- include "jenkins.fullname" $root -}}-jenkins-{{ $name }}" +{{- end -}} + +{{/* +Returns kubernetes pod template configuration as code +*/}} +{{- define "jenkins.casc.podTemplate" -}} +- name: "{{ .Values.agent.podName }}" + namespace: "{{ template "jenkins.agent.namespace" . }}" +{{- if .Values.agent.annotations }} + annotations: + {{- range $key, $value := .Values.agent.annotations }} + - key: {{ $key }} + value: {{ $value | quote }} + {{- end }} +{{- end }} + id: {{ sha256sum (toYaml .Values.agent) }} + containers: + - name: "{{ .Values.agent.sideContainerName }}" + alwaysPullImage: {{ .Values.agent.alwaysPullImage }} + args: "{{ .Values.agent.args | replace "$" "^$" }}" + {{- with .Values.agent.command }} + command: {{ . }} + {{- end }} + envVars: + - envVar: + {{- if .Values.agent.directConnection }} + key: "JENKINS_DIRECT_CONNECTION" + {{- if .Values.agent.jenkinsTunnel }} + value: "{{ tpl .Values.agent.jenkinsTunnel . }}" + {{- else }} + value: "{{ template "jenkins.fullname" . }}-agent.{{ template "jenkins.namespace" . }}.svc.{{.Values.clusterZone}}:{{ .Values.controller.agentListenerPort }}" + {{- end }} + {{- else }} + key: "JENKINS_URL" + {{- if .Values.agent.jenkinsUrl }} + value: {{ tpl .Values.agent.jenkinsUrl . }} + {{- else }} + value: "http://{{ template "jenkins.fullname" . }}.{{ template "jenkins.namespace" . }}.svc.{{.Values.clusterZone}}:{{.Values.controller.servicePort}}{{ default "/" .Values.controller.jenkinsUriPrefix }}" + {{- end }} + {{- end }} + image: "{{ .Values.agent.image.repository }}:{{ .Values.agent.image.tag }}" + {{- if .Values.agent.livenessProbe }} + livenessProbe: + execArgs: {{.Values.agent.livenessProbe.execArgs | quote}} + failureThreshold: {{.Values.agent.livenessProbe.failureThreshold}} + initialDelaySeconds: {{.Values.agent.livenessProbe.initialDelaySeconds}} + periodSeconds: {{.Values.agent.livenessProbe.periodSeconds}} + successThreshold: {{.Values.agent.livenessProbe.successThreshold}} + timeoutSeconds: {{.Values.agent.livenessProbe.timeoutSeconds}} + {{- end }} + privileged: "{{- if .Values.agent.privileged }}true{{- else }}false{{- end }}" + resourceLimitCpu: {{.Values.agent.resources.limits.cpu}} + resourceLimitMemory: {{.Values.agent.resources.limits.memory}} + {{- with .Values.agent.resources.limits.ephemeralStorage }} + resourceLimitEphemeralStorage: {{.}} + {{- end }} + resourceRequestCpu: {{.Values.agent.resources.requests.cpu}} + resourceRequestMemory: {{.Values.agent.resources.requests.memory}} + {{- with .Values.agent.resources.requests.ephemeralStorage }} + resourceRequestEphemeralStorage: {{.}} + {{- end }} + {{- with .Values.agent.runAsUser }} + runAsUser: {{ . }} + {{- end }} + {{- with .Values.agent.runAsGroup }} + runAsGroup: {{ . }} + {{- end }} + ttyEnabled: {{ .Values.agent.TTYEnabled }} + workingDir: {{ .Values.agent.workingDir }} +{{- range $additionalContainers := .Values.agent.additionalContainers }} + - name: "{{ $additionalContainers.sideContainerName }}" + alwaysPullImage: {{ $additionalContainers.alwaysPullImage | default $.Values.agent.alwaysPullImage }} + args: "{{ $additionalContainers.args | replace "$" "^$" }}" + {{- with $additionalContainers.command }} + command: {{ . }} + {{- end }} + envVars: + - envVar: + key: "JENKINS_URL" + {{- if $additionalContainers.jenkinsUrl }} + value: {{ tpl ($additionalContainers.jenkinsUrl) . }} + {{- else }} + value: "http://{{ template "jenkins.fullname" $ }}.{{ template "jenkins.namespace" $ }}.svc.{{ $.Values.clusterZone }}:{{ $.Values.controller.servicePort }}{{ default "/" $.Values.controller.jenkinsUriPrefix }}" + {{- end }} + image: "{{ $additionalContainers.image.repository }}:{{ $additionalContainers.image.tag }}" + {{- if $additionalContainers.livenessProbe }} + livenessProbe: + execArgs: {{$additionalContainers.livenessProbe.execArgs | quote}} + failureThreshold: {{$additionalContainers.livenessProbe.failureThreshold}} + initialDelaySeconds: {{$additionalContainers.livenessProbe.initialDelaySeconds}} + periodSeconds: {{$additionalContainers.livenessProbe.periodSeconds}} + successThreshold: {{$additionalContainers.livenessProbe.successThreshold}} + timeoutSeconds: {{$additionalContainers.livenessProbe.timeoutSeconds}} + {{- end }} + privileged: "{{- if $additionalContainers.privileged }}true{{- else }}false{{- end }}" + resourceLimitCpu: {{ if $additionalContainers.resources }}{{ $additionalContainers.resources.limits.cpu }}{{ else }}{{ $.Values.agent.resources.limits.cpu }}{{ end }} + resourceLimitMemory: {{ if $additionalContainers.resources }}{{ $additionalContainers.resources.limits.memory }}{{ else }}{{ $.Values.agent.resources.limits.memory }}{{ end }} + resourceRequestCpu: {{ if $additionalContainers.resources }}{{ $additionalContainers.resources.requests.cpu }}{{ else }}{{ $.Values.agent.resources.requests.cpu }}{{ end }} + resourceRequestMemory: {{ if $additionalContainers.resources }}{{ $additionalContainers.resources.requests.memory }}{{ else }}{{ $.Values.agent.resources.requests.memory }}{{ end }} + {{- if or $additionalContainers.runAsUser $.Values.agent.runAsUser }} + runAsUser: {{ $additionalContainers.runAsUser | default $.Values.agent.runAsUser }} + {{- end }} + {{- if or $additionalContainers.runAsGroup $.Values.agent.runAsGroup }} + runAsGroup: {{ $additionalContainers.runAsGroup | default $.Values.agent.runAsGroup }} + {{- end }} + ttyEnabled: {{ $additionalContainers.TTYEnabled | default $.Values.agent.TTYEnabled }} + workingDir: {{ $additionalContainers.workingDir | default $.Values.agent.workingDir }} +{{- end }} +{{- if or .Values.agent.envVars .Values.agent.secretEnvVars }} + envVars: + {{- range $index, $var := .Values.agent.envVars }} + - envVar: + key: {{ $var.name }} + value: {{ tpl $var.value $ }} + {{- end }} + {{- range $index, $var := .Values.agent.secretEnvVars }} + - secretEnvVar: + key: {{ $var.key }} + secretName: {{ $var.secretName }} + secretKey: {{ $var.secretKey }} + optional: {{ $var.optional | default false }} + {{- end }} +{{- end }} + idleMinutes: {{ .Values.agent.idleMinutes }} + instanceCap: 2147483647 + {{- if .Values.agent.hostNetworking }} + hostNetwork: {{ .Values.agent.hostNetworking }} + {{- end }} + {{- if .Values.agent.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.agent.imagePullSecretName }} + {{- end }} + label: "{{ .Release.Name }}-{{ .Values.agent.componentName }} {{ .Values.agent.customJenkinsLabels | join " " }}" +{{- if .Values.agent.nodeSelector }} + nodeSelector: + {{- $local := dict "first" true }} + {{- range $key, $value := .Values.agent.nodeSelector }} + {{- if $local.first }} {{ else }},{{ end }} + {{- $key }}={{ tpl $value $ }} + {{- $_ := set $local "first" false }} + {{- end }} +{{- end }} + nodeUsageMode: {{ quote .Values.agent.nodeUsageMode }} + podRetention: {{ .Values.agent.podRetention }} + showRawYaml: {{ .Values.agent.showRawYaml }} +{{- $asaname := default (include "jenkins.serviceAccountAgentName" .) .Values.agent.serviceAccount -}} +{{- if or (.Values.agent.useDefaultServiceAccount) (.Values.agent.serviceAccount) }} + serviceAccount: "{{ $asaname }}" +{{- end }} + slaveConnectTimeoutStr: "{{ .Values.agent.connectTimeout }}" +{{- if .Values.agent.volumes }} + volumes: + {{- range $index, $volume := .Values.agent.volumes }} + -{{- if (eq $volume.type "ConfigMap") }} configMapVolume: + {{- else if (eq $volume.type "EmptyDir") }} emptyDirVolume: + {{- else if (eq $volume.type "EphemeralVolume") }} genericEphemeralVolume: + {{- else if (eq $volume.type "HostPath") }} hostPathVolume: + {{- else if (eq $volume.type "Nfs") }} nfsVolume: + {{- else if (eq $volume.type "PVC") }} persistentVolumeClaim: + {{- else if (eq $volume.type "Secret") }} secretVolume: + {{- else }} {{ $volume.type }}: + {{- end }} + {{- range $key, $value := $volume }} + {{- if not (eq $key "type") }} + {{ $key }}: {{ if kindIs "string" $value }}{{ tpl $value $ | quote }}{{ else }}{{ $value }}{{ end }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} +{{- if .Values.agent.workspaceVolume }} + workspaceVolume: + {{- if (eq .Values.agent.workspaceVolume.type "DynamicPVC") }} + dynamicPVC: + {{- else if (eq .Values.agent.workspaceVolume.type "EmptyDir") }} + emptyDirWorkspaceVolume: + {{- else if (eq .Values.agent.workspaceVolume.type "EphemeralVolume") }} + genericEphemeralVolume: + {{- else if (eq .Values.agent.workspaceVolume.type "HostPath") }} + hostPathWorkspaceVolume: + {{- else if (eq .Values.agent.workspaceVolume.type "Nfs") }} + nfsWorkspaceVolume: + {{- else if (eq .Values.agent.workspaceVolume.type "PVC") }} + persistentVolumeClaimWorkspaceVolume: + {{- else }} + {{ .Values.agent.workspaceVolume.type }}: + {{- end }} + {{- range $key, $value := .Values.agent.workspaceVolume }} + {{- if not (eq $key "type") }} + {{ $key }}: {{ if kindIs "string" $value }}{{ tpl $value $ | quote }}{{ else }}{{ $value }}{{ end }} + {{- end }} + {{- end }} +{{- end }} +{{- if .Values.agent.yamlTemplate }} + yaml: |- + {{- tpl (trim .Values.agent.yamlTemplate) . | nindent 4 }} +{{- end }} + yamlMergeStrategy: {{ .Values.agent.yamlMergeStrategy }} + inheritYamlMergeStrategy: {{ .Values.agent.inheritYamlMergeStrategy }} +{{- end -}} + +{{- define "jenkins.kubernetes-version" -}} + {{- if .Values.controller.installPlugins -}} + {{- range .Values.controller.installPlugins -}} + {{- if hasPrefix "kubernetes:" . }} + {{- $split := splitList ":" . }} + {{- printf "%s" (index $split 1 ) -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- define "jenkins.casc.security" }} +security: +{{- with .Values.controller.JCasC }} +{{- if .security }} + {{- .security | toYaml | nindent 2 }} +{{- end }} +{{- end }} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "jenkins.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "jenkins.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the service account for Jenkins agents to use +*/}} +{{- define "jenkins.serviceAccountAgentName" -}} +{{- if .Values.serviceAccountAgent.create -}} + {{ default (printf "%s-%s" (include "jenkins.fullname" .) "agent") .Values.serviceAccountAgent.name }} +{{- else -}} + {{ default "default" .Values.serviceAccountAgent.name }} +{{- end -}} +{{- end -}} + +{{/* +Create a full tag name for controller image +*/}} +{{- define "controller.image.tag" -}} +{{- if .Values.controller.image.tagLabel -}} + {{- default (printf "%s-%s" .Chart.AppVersion .Values.controller.image.tagLabel) .Values.controller.image.tag -}} +{{- else -}} + {{- default .Chart.AppVersion .Values.controller.image.tag -}} +{{- end -}} +{{- end -}} + +{{/* +Create the HTTP port for interacting with the controller +*/}} +{{- define "controller.httpPort" -}} +{{- if .Values.controller.httpsKeyStore.enable -}} + {{- .Values.controller.httpsKeyStore.httpPort -}} +{{- else -}} + {{- .Values.controller.targetPort -}} +{{- end -}} +{{- end -}} + +{{- define "jenkins.configReloadContainer" -}} +{{- $root := index . 0 -}} +{{- $containerName := index . 1 -}} +{{- $containerType := index . 2 -}} +- name: {{ $containerName }} + image: "{{ $root.Values.controller.sidecars.configAutoReload.image.registry }}/{{ $root.Values.controller.sidecars.configAutoReload.image.repository }}:{{ $root.Values.controller.sidecars.configAutoReload.image.tag }}" + imagePullPolicy: {{ $root.Values.controller.sidecars.configAutoReload.imagePullPolicy }} + {{- if $root.Values.controller.sidecars.configAutoReload.containerSecurityContext }} + securityContext: {{- toYaml $root.Values.controller.sidecars.configAutoReload.containerSecurityContext | nindent 4 }} + {{- end }} + {{- if $root.Values.controller.sidecars.configAutoReload.envFrom }} + envFrom: +{{ (tpl (toYaml $root.Values.controller.sidecars.configAutoReload.envFrom) $root) | indent 4 }} + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: LABEL + value: "{{ template "jenkins.fullname" $root }}-jenkins-config" + - name: FOLDER + value: "{{ $root.Values.controller.sidecars.configAutoReload.folder }}" + - name: NAMESPACE + value: '{{ $root.Values.controller.sidecars.configAutoReload.searchNamespace | default (include "jenkins.namespace" $root) }}' + {{- if eq $containerType "init" }} + - name: METHOD + value: "LIST" + {{- else if $root.Values.controller.sidecars.configAutoReload.sleepTime }} + - name: METHOD + value: "SLEEP" + - name: SLEEP_TIME + value: "{{ $root.Values.controller.sidecars.configAutoReload.sleepTime }}" + {{- end }} + {{- if eq $containerType "sidecar" }} + - name: REQ_URL + value: "{{- default "http" $root.Values.controller.sidecars.configAutoReload.scheme }}://localhost:{{- include "controller.httpPort" $root -}}{{- $root.Values.controller.jenkinsUriPrefix -}}/reload-configuration-as-code/?casc-reload-token=$(POD_NAME)" + - name: REQ_METHOD + value: "POST" + - name: REQ_RETRY_CONNECT + value: "{{ $root.Values.controller.sidecars.configAutoReload.reqRetryConnect }}" + {{- if $root.Values.controller.sidecars.configAutoReload.skipTlsVerify }} + - name: REQ_SKIP_TLS_VERIFY + value: "true" + {{- end }} + {{- end }} + + {{- if $root.Values.controller.sidecars.configAutoReload.env }} + {{- range $envVarItem := $root.Values.controller.sidecars.configAutoReload.env -}} + {{- if or (ne $containerType "init") (ne .name "METHOD") }} +{{- (tpl (toYaml (list $envVarItem)) $root) | nindent 4 }} + {{- end -}} + {{- end -}} + {{- end }} + {{- if $root.Values.controller.sidecars.configAutoReload.logging.configuration.override }} + - name: LOG_CONFIG + value: "{{ $root.Values.controller.jenkinsHome }}/auto-reload/auto-reload-config.yaml" + {{- end }} + + resources: +{{ toYaml $root.Values.controller.sidecars.configAutoReload.resources | indent 4 }} + volumeMounts: + - name: sc-config-volume + mountPath: {{ $root.Values.controller.sidecars.configAutoReload.folder | quote }} + - name: jenkins-home + mountPath: {{ $root.Values.controller.jenkinsHome }} + {{- if $root.Values.persistence.subPath }} + subPath: {{ $root.Values.persistence.subPath }} + {{- end }} + {{- if $root.Values.controller.sidecars.configAutoReload.logging.configuration.override }} + - name: auto-reload-config + mountPath: {{ $root.Values.controller.jenkinsHome }}/auto-reload + - name: auto-reload-config-logs + mountPath: {{ $root.Values.controller.jenkinsHome }}/auto-reload-logs + {{- end }} + {{- if $root.Values.controller.sidecars.configAutoReload.additionalVolumeMounts }} +{{ (tpl (toYaml $root.Values.controller.sidecars.configAutoReload.additionalVolumeMounts) $root) | indent 4 }} + {{- end }} + +{{- end -}} diff --git a/charts/jenkins/jenkins/5.5.14/templates/auto-reload-config.yaml b/charts/jenkins/jenkins/5.5.14/templates/auto-reload-config.yaml new file mode 100644 index 000000000..8c177d7f3 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/auto-reload-config.yaml @@ -0,0 +1,60 @@ +{{- if .Values.controller.sidecars.configAutoReload.logging.configuration.override }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "jenkins.fullname" . }}-auto-reload-config + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": {{ template "jenkins.name" . }} + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ .Chart.Name }}-{{ .Chart.Version }}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ $.Release.Service }}" + "app.kubernetes.io/instance": "{{ $.Release.Name }}" + "app.kubernetes.io/component": "{{ $.Values.controller.componentName }}" +data: + auto-reload-config.yaml: |- + version: 1 + disable_existing_loggers: false + root: + level: {{ .Values.controller.sidecars.configAutoReload.logging.configuration.logLevel }} + handlers: + {{- if .Values.controller.sidecars.configAutoReload.logging.configuration.logToConsole}} + - console + {{- end }} + {{- if .Values.controller.sidecars.configAutoReload.logging.configuration.logToFile }} + - file + {{- end }} + handlers: + {{- if .Values.controller.sidecars.configAutoReload.logging.configuration.logToConsole}} + console: + class: logging.StreamHandler + level: {{ .Values.controller.sidecars.configAutoReload.logging.configuration.logLevel }} + formatter: {{ .Values.controller.sidecars.configAutoReload.logging.configuration.formatter }} + {{- end }} + {{- if .Values.controller.sidecars.configAutoReload.logging.configuration.logToFile }} + file: + class : logging.handlers.RotatingFileHandler + formatter: {{ .Values.controller.sidecars.configAutoReload.logging.configuration.formatter }} + filename: {{ .Values.controller.jenkinsHome }}/auto-reload-logs/file.log + maxBytes: {{ .Values.controller.sidecars.configAutoReload.logging.configuration.maxBytes }} + backupCount: {{ .Values.controller.sidecars.configAutoReload.logging.configuration.backupCount }} + {{- end }} + formatters: + JSON: + "()": logger.JsonFormatter + format: "%(levelname)s %(message)s" + rename_fields: + message: msg + levelname: level + LOGFMT: + "()": logger.LogfmtFormatter + keys: + - time + - level + - msg + mapping: + time: asctime + level: levelname + msg: message + {{- end }} \ No newline at end of file diff --git a/charts/jenkins/jenkins/5.5.14/templates/config-init-scripts.yaml b/charts/jenkins/jenkins/5.5.14/templates/config-init-scripts.yaml new file mode 100644 index 000000000..7dd253cc3 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/config-init-scripts.yaml @@ -0,0 +1,18 @@ +{{- if .Values.controller.initScripts -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "jenkins.fullname" . }}-init-scripts + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +data: +{{- range $key, $val := .Values.controller.initScripts }} + init{{ $key }}.groovy: |- +{{ tpl $val $ | indent 4 }} +{{- end }} +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/config.yaml b/charts/jenkins/jenkins/5.5.14/templates/config.yaml new file mode 100644 index 000000000..5de0b9f72 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/config.yaml @@ -0,0 +1,92 @@ +{{- $jenkinsHome := .Values.controller.jenkinsHome -}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "jenkins.fullname" . }} + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +data: + apply_config.sh: |- + set -e +{{- if .Values.controller.initializeOnce }} + if [ -f {{ .Values.controller.jenkinsHome }}/initialization-completed ]; then + echo "controller was previously initialized, refusing to re-initialize" + exit 0 + fi +{{- end }} + echo "disable Setup Wizard" + # Prevent Setup Wizard when JCasC is enabled + echo $JENKINS_VERSION > {{ .Values.controller.jenkinsHome }}/jenkins.install.UpgradeWizard.state + echo $JENKINS_VERSION > {{ .Values.controller.jenkinsHome }}/jenkins.install.InstallUtil.lastExecVersion +{{- if .Values.controller.overwritePlugins }} + echo "remove all plugins from shared volume" + # remove all plugins from shared volume + rm -rf {{ .Values.controller.jenkinsHome }}/plugins/* +{{- end }} +{{- if .Values.controller.JCasC.overwriteConfiguration }} + echo "deleting all XML config files" + rm -f {{ .Values.controller.jenkinsHome }}/config.xml + rm -f {{ .Values.controller.jenkinsHome }}/*plugins*.xml + find {{ .Values.controller.jenkinsHome }} -maxdepth 1 -type f -iname '*configuration*.xml' -exec rm -f {} \; +{{- end }} +{{- if .Values.controller.installPlugins }} + echo "download plugins" + # Install missing plugins + cp /var/jenkins_config/plugins.txt {{ .Values.controller.jenkinsHome }}; + rm -rf {{ .Values.controller.jenkinsRef }}/plugins/*.lock + version () { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; } + if [ -f "{{ .Values.controller.jenkinsWar }}" ] && [ -n "$(command -v jenkins-plugin-cli)" 2>/dev/null ] && [ $(version $(jenkins-plugin-cli --version)) -ge $(version "2.1.1") ]; then + jenkins-plugin-cli --verbose --war "{{ .Values.controller.jenkinsWar }}" --plugin-file "{{ .Values.controller.jenkinsHome }}/plugins.txt" --latest {{ .Values.controller.installLatestPlugins }}{{- if .Values.controller.installLatestSpecifiedPlugins }} --latest-specified{{- end }}; + else + /usr/local/bin/install-plugins.sh `echo $(cat {{ .Values.controller.jenkinsHome }}/plugins.txt)`; + fi + echo "copy plugins to shared volume" + # Copy plugins to shared volume + yes n | cp -i {{ .Values.controller.jenkinsRef }}/plugins/* /var/jenkins_plugins/; +{{- end }} + {{- if not .Values.controller.sidecars.configAutoReload.enabled }} + echo "copy configuration as code files" + mkdir -p {{ .Values.controller.jenkinsHome }}/casc_configs; + rm -rf {{ .Values.controller.jenkinsHome }}/casc_configs/* + {{- if or .Values.controller.JCasC.defaultConfig .Values.controller.JCasC.configScripts }} + cp -v /var/jenkins_config/*.yaml {{ .Values.controller.jenkinsHome }}/casc_configs + {{- end }} + {{- end }} + echo "finished initialization" +{{- if .Values.controller.initializeOnce }} + touch {{ .Values.controller.jenkinsHome }}/initialization-completed +{{- end }} + {{- if not .Values.controller.sidecars.configAutoReload.enabled }} +# Only add config to this script if we aren't auto-reloading otherwise the pod will restart upon each config change: +{{- if .Values.controller.JCasC.defaultConfig }} + jcasc-default-config.yaml: |- + {{- include "jenkins.casc.defaults" . |nindent 4}} +{{- end }} +{{- range $key, $val := .Values.controller.JCasC.configScripts }} + {{ $key }}.yaml: |- +{{ tpl $val $| indent 4 }} +{{- end }} +{{- end }} + plugins.txt: |- +{{- if .Values.controller.installPlugins }} + {{- range $installPlugin := .Values.controller.installPlugins }} + {{- $installPlugin | nindent 4 }} + {{- end }} + {{- range $addlPlugin := .Values.controller.additionalPlugins }} + {{- /* duplicate plugin check */}} + {{- range $installPlugin := $.Values.controller.installPlugins }} + {{- if eq (splitList ":" $addlPlugin | first) (splitList ":" $installPlugin | first) }} + {{- $message := print "[PLUGIN CONFLICT] controller.additionalPlugins contains '" $addlPlugin "'" }} + {{- $message := print $message " but controller.installPlugins already contains '" $installPlugin "'." }} + {{- $message := print $message " Override controller.installPlugins to use '" $addlPlugin "' plugin." }} + {{- fail $message }} + {{- end }} + {{- end }} + {{- $addlPlugin | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/deprecation.yaml b/charts/jenkins/jenkins/5.5.14/templates/deprecation.yaml new file mode 100644 index 000000000..f54017ce4 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/deprecation.yaml @@ -0,0 +1,151 @@ +{{- if .Values.checkDeprecation }} + {{- if .Values.master }} + {{ fail "`master` does no longer exist. It has been renamed to `controller`" }} + {{- end }} + + {{- if .Values.controller.imageTag }} + {{ fail "`controller.imageTag` does no longer exist. Please use `controller.image.tag` instead" }} + {{- end }} + + {{- if .Values.controller.slaveListenerPort }} + {{ fail "`controller.slaveListenerPort` does no longer exist. It has been renamed to `controller.agentListenerPort`" }} + {{- end }} + + {{- if .Values.controller.slaveHostPort }} + {{ fail "`controller.slaveHostPort` does no longer exist. It has been renamed to `controller.agentListenerHostPort`" }} + {{- end }} + + {{- if .Values.controller.slaveKubernetesNamespace }} + {{ fail "`controller.slaveKubernetesNamespace` does no longer exist. It has been renamed to `agent.namespace`" }} + {{- end }} + + {{- if .Values.controller.slaveDefaultsProviderTemplate }} + {{ fail "`controller.slaveDefaultsProviderTemplate` does no longer exist. It has been renamed to `agent.defaultsProviderTemplate`" }} + {{- end }} + + {{- if .Values.controller.useSecurity }} + {{ fail "`controller.useSecurity` does no longer exist. It has been renamed to `controller.adminSecret`" }} + {{- end }} + + {{- if .Values.controller.slaveJenkinsUrl }} + {{ fail "`controller.slaveJenkinsUrl` does no longer exist. It has been renamed to `agent.jenkinsUrl`" }} + {{- end }} + + {{- if .Values.controller.slaveJenkinsTunnel }} + {{ fail "`controller.slaveJenkinsTunnel` does no longer exist. It has been renamed to `agent.jenkinsTunnel`" }} + {{- end }} + + {{- if .Values.controller.slaveConnectTimeout }} + {{ fail "`controller.slaveConnectTimeout` does no longer exist. It has been renamed to `agent.kubernetesConnectTimeout`" }} + {{- end }} + + {{- if .Values.controller.slaveReadTimeout }} + {{ fail "`controller.slaveReadTimeout` does no longer exist. It has been renamed to `agent.kubernetesReadTimeout`" }} + {{- end }} + + {{- if .Values.controller.slaveListenerServiceType }} + {{ fail "`controller.slaveListenerServiceType` does no longer exist. It has been renamed to `controller.agentListenerServiceType`" }} + {{- end }} + + {{- if .Values.controller.slaveListenerLoadBalancerIP }} + {{ fail "`controller.slaveListenerLoadBalancerIP` does no longer exist. It has been renamed to `controller.agentListenerLoadBalancerIP`" }} + {{- end }} + + {{- if .Values.controller.slaveListenerServiceAnnotations }} + {{ fail "`controller.slaveListenerServiceAnnotations` does no longer exist. It has been renamed to `controller.agentListenerServiceAnnotations`" }} + {{- end }} + + {{- if .Values.agent.slaveConnectTimeout }} + {{ fail "`agent.slaveConnectTimeout` does no longer exist. It has been renamed to `agent.connectTimeout`" }} + {{- end }} + + {{- if .Values.NetworkPolicy }} + + {{- if .Values.NetworkPolicy.Enabled }} + {{ fail "`NetworkPolicy.Enabled` does no longer exist. It has been renamed to `networkPolicy.enabled`" }} + {{- end }} + + {{- if .Values.NetworkPolicy.ApiVersion }} + {{ fail "`NetworkPolicy.ApiVersion` does no longer exist. It has been renamed to `networkPolicy.apiVersion`" }} + {{- end }} + + {{ fail "NetworkPolicy.* values have been renamed, please check the documentation" }} + {{- end }} + + + {{- if .Values.rbac.install }} + {{ fail "`rbac.install` does no longer exist. It has been renamed to `rbac.create` and is enabled by default!" }} + {{- end }} + + {{- if .Values.rbac.serviceAccountName }} + {{ fail "`rbac.serviceAccountName` does no longer exist. It has been renamed to `serviceAccount.name`" }} + {{- end }} + + {{- if .Values.rbac.serviceAccountAnnotations }} + {{ fail "`rbac.serviceAccountAnnotations` does no longer exist. It has been renamed to `serviceAccount.annotations`" }} + {{- end }} + + {{- if .Values.rbac.roleRef }} + {{ fail "`rbac.roleRef` does no longer exist. RBAC roles are now generated, please check the documentation" }} + {{- end }} + + {{- if .Values.rbac.roleKind }} + {{ fail "`rbac.roleKind` does no longer exist. RBAC roles are now generated, please check the documentation" }} + {{- end }} + + {{- if .Values.rbac.roleBindingKind }} + {{ fail "`rbac.roleBindingKind` does no longer exist. RBAC roles are now generated, please check the documentation" }} + {{- end }} + + {{- if .Values.controller.JCasC.pluginVersion }} + {{ fail "controller.JCasC.pluginVersion has been deprecated, please use controller.installPlugins instead" }} + {{- end }} + + {{- if .Values.controller.deploymentLabels }} + {{ fail "`controller.deploymentLabels` does no longer exist. It has been renamed to `controller.statefulSetLabels`" }} + {{- end }} + + {{- if .Values.controller.deploymentAnnotations }} + {{ fail "`controller.deploymentAnnotations` does no longer exist. It has been renamed to `controller.statefulSetAnnotations`" }} + {{- end }} + + {{- if .Values.controller.rollingUpdate }} + {{ fail "`controller.rollingUpdate` does no longer exist. It is no longer relevant, since a StatefulSet is used for the Jenkins controller" }} + {{- end }} + + {{- if .Values.controller.tag }} + {{ fail "`controller.tag` no longer exists. It has been renamed to `controller.image.tag'" }} + {{- end }} + + {{- if .Values.controller.tagLabel }} + {{ fail "`controller.tagLabel` no longer exists. It has been renamed to `controller.image.tagLabel`" }} + {{- end }} + + {{- if .Values.controller.adminSecret }} + {{ fail "`controller.adminSecret` no longer exists. It has been renamed to `controller.admin.createSecret`" }} + {{- end }} + + {{- if .Values.controller.adminUser }} + {{ fail "`controller.adminUser` no longer exists. It has been renamed to `controller.admin.username`" }} + {{- end }} + + {{- if .Values.controller.adminPassword }} + {{ fail "`controller.adminPassword` no longer exists. It has been renamed to `controller.admin.password`" }} + {{- end }} + + {{- if .Values.controller.sidecars.other }} + {{ fail "`controller.sidecars.other` no longer exists. It has been renamed to `controller.sidecars.additionalSidecarContainers`" }} + {{- end }} + + {{- if .Values.agent.tag }} + {{ fail "`controller.agent.tag` no longer exists. It has been renamed to `controller.agent.image.tag`" }} + {{- end }} + + {{- if .Values.backup }} + {{ fail "`controller.backup` no longer exists." }} + {{- end }} + + {{- if .Values.helmtest.bats.tag }} + {{ fail "`helmtest.bats.tag` no longer exists. It has been renamed to `helmtest.bats.image.tag`" }} + {{- end }} +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/home-pvc.yaml b/charts/jenkins/jenkins/5.5.14/templates/home-pvc.yaml new file mode 100644 index 000000000..f417d23ad --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/home-pvc.yaml @@ -0,0 +1,41 @@ +{{- if not (contains "jenkins-home" (quote .Values.persistence.volumes)) }} +{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) -}} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: +{{- if .Values.persistence.annotations }} + annotations: +{{ toYaml .Values.persistence.annotations | indent 4 }} +{{- end }} + name: {{ template "jenkins.fullname" . }} + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +{{- if .Values.persistence.labels }} +{{ toYaml .Values.persistence.labels | indent 4 }} +{{- end }} +spec: +{{- if .Values.persistence.dataSource }} + dataSource: +{{ toYaml .Values.persistence.dataSource | indent 4 }} +{{- end }} + accessModes: + - {{ .Values.persistence.accessMode | quote }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} +{{- if .Values.persistence.storageClass }} +{{- if (eq "-" .Values.persistence.storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: "{{ .Values.persistence.storageClass }}" +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/jcasc-config.yaml b/charts/jenkins/jenkins/5.5.14/templates/jcasc-config.yaml new file mode 100644 index 000000000..f51444525 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/jcasc-config.yaml @@ -0,0 +1,53 @@ +{{- $root := . }} +{{- if .Values.controller.sidecars.configAutoReload.enabled }} +{{- range $key, $val := .Values.controller.JCasC.configScripts }} +{{- if $val }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "jenkins.casc.configName" (list (printf "config-%s" $key) $ )}} + namespace: {{ template "jenkins.namespace" $root }} + labels: + "app.kubernetes.io/name": {{ template "jenkins.name" $root}} + {{- if $root.Values.renderHelmLabels }} + "helm.sh/chart": "{{ $root.Chart.Name }}-{{ $root.Chart.Version }}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ $.Release.Service }}" + "app.kubernetes.io/instance": "{{ $.Release.Name }}" + "app.kubernetes.io/component": "{{ $.Values.controller.componentName }}" + {{ template "jenkins.fullname" $root }}-jenkins-config: "true" +{{- if $root.Values.controller.JCasC.configMapAnnotations }} + annotations: +{{ toYaml $root.Values.controller.JCasC.configMapAnnotations | indent 4 }} +{{- end }} +data: + {{ $key }}.yaml: |- +{{ tpl $val $| indent 4 }} +{{- end }} +{{- end }} +{{- if .Values.controller.JCasC.defaultConfig }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "jenkins.casc.configName" (list "jcasc-config" $ )}} + namespace: {{ template "jenkins.namespace" $root }} + labels: + "app.kubernetes.io/name": {{ template "jenkins.name" $root}} + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ $root.Chart.Name }}-{{ $root.Chart.Version }}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ $.Release.Service }}" + "app.kubernetes.io/instance": "{{ $.Release.Name }}" + "app.kubernetes.io/component": "{{ $.Values.controller.componentName }}" + {{ template "jenkins.fullname" $root }}-jenkins-config: "true" +{{- if $root.Values.controller.JCasC.configMapAnnotations }} + annotations: +{{ toYaml $root.Values.controller.JCasC.configMapAnnotations | indent 4 }} +{{- end }} +data: + jcasc-default-config.yaml: |- + {{- include "jenkins.casc.defaults" . | nindent 4 }} +{{- end}} +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/jenkins-agent-svc.yaml b/charts/jenkins/jenkins/5.5.14/templates/jenkins-agent-svc.yaml new file mode 100644 index 000000000..4440b91f8 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/jenkins-agent-svc.yaml @@ -0,0 +1,43 @@ +{{- if .Values.controller.agentListenerEnabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "jenkins.fullname" . }}-agent + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" + {{- if .Values.controller.agentListenerServiceAnnotations }} + annotations: + {{- toYaml .Values.controller.agentListenerServiceAnnotations | nindent 4 }} + {{- end }} +spec: + {{- if .Values.controller.agentListenerExternalTrafficPolicy }} + externalTrafficPolicy: {{.Values.controller.agentListenerExternalTrafficPolicy}} + {{- end }} + ports: + - port: {{ .Values.controller.agentListenerPort }} + targetPort: {{ .Values.controller.agentListenerPort }} + {{- if (and (eq .Values.controller.agentListenerServiceType "NodePort") (not (empty .Values.controller.agentListenerNodePort))) }} + nodePort: {{ .Values.controller.agentListenerNodePort }} + {{- end }} + name: agent-listener + selector: + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + type: {{ .Values.controller.agentListenerServiceType }} + {{if eq .Values.controller.agentListenerServiceType "LoadBalancer"}} +{{- if .Values.controller.agentListenerLoadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{ toYaml .Values.controller.agentListenerLoadBalancerSourceRanges | indent 4 }} +{{- end }} + {{- end }} + {{- if and (eq .Values.controller.agentListenerServiceType "LoadBalancer") (.Values.controller.agentListenerLoadBalancerIP) }} + loadBalancerIP: {{ .Values.controller.agentListenerLoadBalancerIP }} + {{- end }} + {{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/jenkins-aws-security-group-policies.yaml b/charts/jenkins/jenkins/5.5.14/templates/jenkins-aws-security-group-policies.yaml new file mode 100644 index 000000000..2f6e7a13d --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/jenkins-aws-security-group-policies.yaml @@ -0,0 +1,16 @@ +{{- if .Values.awsSecurityGroupPolicies.enabled -}} +{{- range .Values.awsSecurityGroupPolicies.policies -}} +apiVersion: vpcresources.k8s.aws/v1beta1 +kind: SecurityGroupPolicy +metadata: + name: {{ .name }} + namespace: {{ template "jenkins.namespace" $ }} +spec: + podSelector: + {{- toYaml .podSelector | nindent 6}} + securityGroups: + groupIds: + {{- toYaml .securityGroupIds | nindent 6}} +--- +{{- end -}} +{{- end -}} diff --git a/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-alerting-rules.yaml b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-alerting-rules.yaml new file mode 100644 index 000000000..3fd806172 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-alerting-rules.yaml @@ -0,0 +1,26 @@ +{{- if and .Values.controller.prometheus.enabled .Values.controller.prometheus.alertingrules }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ template "jenkins.fullname" . }} +{{- if .Values.controller.prometheus.prometheusRuleNamespace }} + namespace: {{ .Values.controller.prometheus.prometheusRuleNamespace }} +{{- else }} + namespace: {{ template "jenkins.namespace" . }} +{{- end }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" + {{- range $key, $val := .Values.controller.prometheus.alertingRulesAdditionalLabels }} + {{ $key }}: {{ $val | quote }} + {{- end}} +spec: + groups: +{{ toYaml .Values.controller.prometheus.alertingrules | indent 2 }} +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-backendconfig.yaml b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-backendconfig.yaml new file mode 100644 index 000000000..0e8a566fc --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-backendconfig.yaml @@ -0,0 +1,24 @@ +{{- if .Values.controller.backendconfig.enabled }} +apiVersion: {{ .Values.controller.backendconfig.apiVersion }} +kind: BackendConfig +metadata: + name: {{ .Values.controller.backendconfig.name }} + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +{{- if .Values.controller.backendconfig.labels }} +{{ toYaml .Values.controller.backendconfig.labels | indent 4 }} +{{- end }} +{{- if .Values.controller.backendconfig.annotations }} + annotations: +{{ toYaml .Values.controller.backendconfig.annotations | indent 4 }} +{{- end }} +spec: +{{ toYaml .Values.controller.backendconfig.spec | indent 2 }} +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-ingress.yaml b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-ingress.yaml new file mode 100644 index 000000000..b3b344ff8 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-ingress.yaml @@ -0,0 +1,77 @@ +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if .Values.controller.ingress.enabled }} +{{- if semverCompare ">=1.19-0" $kubeTargetVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" $kubeTargetVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: {{ .Values.controller.ingress.apiVersion }} +{{- end }} +kind: Ingress +metadata: + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +{{- if .Values.controller.ingress.labels }} +{{ toYaml .Values.controller.ingress.labels | indent 4 }} +{{- end }} +{{- if .Values.controller.ingress.annotations }} + annotations: +{{ toYaml .Values.controller.ingress.annotations | indent 4 }} +{{- end }} + name: {{ template "jenkins.fullname" . }} +spec: +{{- if .Values.controller.ingress.ingressClassName }} + ingressClassName: {{ .Values.controller.ingress.ingressClassName | quote }} +{{- end }} + rules: + - http: + paths: +{{- if empty (.Values.controller.ingress.paths) }} + - backend: +{{- if semverCompare ">=1.19-0" $kubeTargetVersion }} + service: + name: {{ template "jenkins.fullname" . }} + port: + number: {{ .Values.controller.servicePort }} + pathType: ImplementationSpecific +{{- else }} + serviceName: {{ template "jenkins.fullname" . }} + servicePort: {{ .Values.controller.servicePort }} +{{- end }} +{{- if .Values.controller.ingress.path }} + path: {{ .Values.controller.ingress.path }} +{{- end -}} +{{- else }} +{{ tpl (toYaml .Values.controller.ingress.paths | indent 6) . }} +{{- end -}} +{{- if .Values.controller.ingress.hostName }} + host: {{ tpl .Values.controller.ingress.hostName . | quote }} +{{- end }} +{{- if .Values.controller.ingress.resourceRootUrl }} + - http: + paths: + - backend: +{{- if semverCompare ">=1.19-0" $kubeTargetVersion }} + service: + name: {{ template "jenkins.fullname" . }} + port: + number: {{ .Values.controller.servicePort }} + pathType: ImplementationSpecific +{{- else }} + serviceName: {{ template "jenkins.fullname" . }} + servicePort: {{ .Values.controller.servicePort }} +{{- end }} + host: {{ tpl .Values.controller.ingress.resourceRootUrl . | quote }} +{{- end }} +{{- if .Values.controller.ingress.tls }} + tls: +{{ tpl (toYaml .Values.controller.ingress.tls ) . | indent 4 }} +{{- end -}} +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-networkpolicy.yaml b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-networkpolicy.yaml new file mode 100644 index 000000000..82835f2bd --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-networkpolicy.yaml @@ -0,0 +1,76 @@ +{{- if .Values.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: {{ .Values.networkPolicy.apiVersion }} +metadata: + name: "{{ .Release.Name }}-{{ .Values.controller.componentName }}" + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +spec: + podSelector: + matchLabels: + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + ingress: + # Allow web access to the UI + - ports: + - port: {{ .Values.controller.targetPort }} + {{- if .Values.controller.agentListenerEnabled }} + # Allow inbound connections from agents + - from: + {{- if .Values.networkPolicy.internalAgents.allowed }} + - podSelector: + matchLabels: + "jenkins/{{ .Release.Name }}-{{ .Values.agent.componentName }}": "true" + {{- range $k,$v:= .Values.networkPolicy.internalAgents.podLabels }} + {{ $k }}: {{ $v }} + {{- end }} + {{- if .Values.networkPolicy.internalAgents.namespaceLabels }} + namespaceSelector: + matchLabels: + {{- range $k,$v:= .Values.networkPolicy.internalAgents.namespaceLabels }} + {{ $k }}: {{ $v }} + {{- end }} + {{- end }} + {{- end }} + {{- if or .Values.networkPolicy.externalAgents.ipCIDR .Values.networkPolicy.externalAgents.except }} + - ipBlock: + cidr: {{ required "ipCIDR is required if you wish to allow external agents to connect to Jenkins Controller." .Values.networkPolicy.externalAgents.ipCIDR }} + {{- if .Values.networkPolicy.externalAgents.except }} + except: + {{- range .Values.networkPolicy.externalAgents.except }} + - {{ . }} + {{- end }} + {{- end }} + {{- end }} + ports: + - port: {{ .Values.controller.agentListenerPort }} + {{- end }} +{{- if .Values.agent.enabled }} +--- +kind: NetworkPolicy +apiVersion: {{ .Values.networkPolicy.apiVersion }} +metadata: + name: "{{ .Release.Name }}-{{ .Values.agent.componentName }}" + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +spec: + podSelector: + matchLabels: + # DefaultDeny + "jenkins/{{ .Release.Name }}-{{ .Values.agent.componentName }}": "true" +{{- end }} +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-pdb.yaml b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-pdb.yaml new file mode 100644 index 000000000..9dc1fafe2 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-pdb.yaml @@ -0,0 +1,34 @@ +{{- if .Values.controller.podDisruptionBudget.enabled }} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if semverCompare ">=1.21-0" $kubeTargetVersion -}} +apiVersion: policy/v1 +{{- else if semverCompare ">=1.5-0" $kubeTargetVersion -}} +apiVersion: policy/v1beta1 +{{- else -}} +apiVersion: {{ .Values.controller.podDisruptionBudget.apiVersion }} +{{- end }} +kind: PodDisruptionBudget +metadata: + name: {{ template "jenkins.fullname" . }}-pdb + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" + {{- if .Values.controller.podDisruptionBudget.labels -}} + {{ toYaml .Values.controller.podDisruptionBudget.labels | nindent 4 }} + {{- end }} + {{- if .Values.controller.podDisruptionBudget.annotations }} + annotations: {{ toYaml .Values.controller.podDisruptionBudget.annotations | nindent 4 }} + {{- end }} +spec: + maxUnavailable: {{ .Values.controller.podDisruptionBudget.maxUnavailable }} + selector: + matchLabels: + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-podmonitor.yaml b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-podmonitor.yaml new file mode 100644 index 000000000..9a04019c3 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-podmonitor.yaml @@ -0,0 +1,30 @@ +{{- if .Values.controller.googlePodMonitor.enabled }} +apiVersion: monitoring.googleapis.com/v1 +kind: PodMonitoring + +metadata: + name: {{ template "jenkins.fullname" . }} +{{- if .Values.controller.googlePodMonitor.serviceMonitorNamespace }} + namespace: {{ .Values.controller.googlePodMonitor.serviceMonitorNamespace }} +{{- else }} + namespace: {{ template "jenkins.namespace" . }} +{{- end }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" + +spec: + endpoints: + - interval: {{ .Values.controller.googlePodMonitor.scrapeInterval }} + port: http + path: {{ .Values.controller.jenkinsUriPrefix }}{{ .Values.controller.googlePodMonitor.scrapeEndpoint }} + selector: + matchLabels: + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-route.yaml b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-route.yaml new file mode 100644 index 000000000..3550380ee --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-route.yaml @@ -0,0 +1,34 @@ +{{- if .Values.controller.route.enabled }} +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + namespace: {{ template "jenkins.namespace" . }} + labels: + app: {{ template "jenkins.fullname" . }} + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" + component: "{{ .Release.Name }}-{{ .Values.controller.componentName }}" +{{- if .Values.controller.route.labels }} +{{ toYaml .Values.controller.route.labels | indent 4 }} +{{- end }} +{{- if .Values.controller.route.annotations }} + annotations: +{{ toYaml .Values.controller.route.annotations | indent 4 }} +{{- end }} + name: {{ template "jenkins.fullname" . }} +spec: + host: {{ .Values.controller.route.path }} + port: + targetPort: http + tls: + insecureEdgeTerminationPolicy: Redirect + termination: edge + to: + kind: Service + name: {{ template "jenkins.fullname" . }} + weight: 100 + wildcardPolicy: None +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-secondary-ingress.yaml b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-secondary-ingress.yaml new file mode 100644 index 000000000..c63e48229 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-secondary-ingress.yaml @@ -0,0 +1,56 @@ +{{- if .Values.controller.secondaryingress.enabled }} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- $serviceName := include "jenkins.fullname" . -}} +{{- $servicePort := .Values.controller.servicePort -}} +{{- if semverCompare ">=1.19-0" $kubeTargetVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" $kubeTargetVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: {{ .Values.controller.secondaryingress.apiVersion }} +{{- end }} +kind: Ingress +metadata: + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" + {{- if .Values.controller.secondaryingress.labels -}} + {{ toYaml .Values.controller.secondaryingress.labels | nindent 4 }} + {{- end }} + {{- if .Values.controller.secondaryingress.annotations }} + annotations: {{ toYaml .Values.controller.secondaryingress.annotations | nindent 4 }} + {{- end }} + name: {{ template "jenkins.fullname" . }}-secondary +spec: +{{- if .Values.controller.secondaryingress.ingressClassName }} + ingressClassName: {{ .Values.controller.secondaryingress.ingressClassName | quote }} +{{- end }} + rules: + - host: {{ .Values.controller.secondaryingress.hostName }} + http: + paths: + {{- range .Values.controller.secondaryingress.paths }} + - path: {{ . | quote }} + backend: +{{ if semverCompare ">=1.19-0" $kubeTargetVersion }} + service: + name: {{ $serviceName }} + port: + number: {{ $servicePort }} + pathType: ImplementationSpecific +{{ else }} + serviceName: {{ $serviceName }} + servicePort: {{ $servicePort }} +{{ end }} + {{- end}} +{{- if .Values.controller.secondaryingress.tls }} + tls: +{{ toYaml .Values.controller.secondaryingress.tls | indent 4 }} +{{- end -}} +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-servicemonitor.yaml b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-servicemonitor.yaml new file mode 100644 index 000000000..8710b2bc9 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- if and .Values.controller.prometheus.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor + +metadata: + name: {{ template "jenkins.fullname" . }} +{{- if .Values.controller.prometheus.serviceMonitorNamespace }} + namespace: {{ .Values.controller.prometheus.serviceMonitorNamespace }} +{{- else }} + namespace: {{ template "jenkins.namespace" . }} +{{- end }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" + {{- range $key, $val := .Values.controller.prometheus.serviceMonitorAdditionalLabels }} + {{ $key }}: {{ $val | quote }} + {{- end}} + +spec: + endpoints: + - interval: {{ .Values.controller.prometheus.scrapeInterval }} + port: http + path: {{ .Values.controller.jenkinsUriPrefix }}{{ .Values.controller.prometheus.scrapeEndpoint }} + {{- with .Values.controller.prometheus.relabelings }} + relabelings: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.controller.prometheus.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 6 }} + {{- end }} + jobLabel: {{ template "jenkins.fullname" . }} + namespaceSelector: + matchNames: + - "{{ template "jenkins.namespace" $ }}" + selector: + matchLabels: + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-statefulset.yaml b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-statefulset.yaml new file mode 100644 index 000000000..50e61acf1 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-statefulset.yaml @@ -0,0 +1,424 @@ +{{- if .Capabilities.APIVersions.Has "apps/v1" }} +apiVersion: apps/v1 +{{- else }} +apiVersion: apps/v1beta1 +{{- end }} +kind: StatefulSet +metadata: + name: {{ template "jenkins.fullname" . }} + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" + {{- range $key, $val := .Values.controller.statefulSetLabels }} + {{ $key }}: {{ $val | quote }} + {{- end}} + {{- if .Values.controller.statefulSetAnnotations }} + annotations: +{{ toYaml .Values.controller.statefulSetAnnotations | indent 4 }} + {{- end }} +spec: + serviceName: {{ template "jenkins.fullname" . }} + replicas: 1 + selector: + matchLabels: + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + {{- if .Values.controller.updateStrategy }} + updateStrategy: +{{ toYaml .Values.controller.updateStrategy | indent 4 }} + {{- end }} + template: + metadata: + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" + {{- range $key, $val := .Values.controller.podLabels }} + {{ $key }}: {{ $val | quote }} + {{- end}} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/config.yaml") . | sha256sum }} + {{- if .Values.controller.initScripts }} + checksum/config-init-scripts: {{ include (print $.Template.BasePath "/config-init-scripts.yaml") . | sha256sum }} + {{- end }} + {{- if .Values.controller.podAnnotations }} +{{ tpl (toYaml .Values.controller.podAnnotations | indent 8) . }} + {{- end }} + spec: + {{- if .Values.controller.schedulerName }} + schedulerName: {{ .Values.controller.schedulerName }} + {{- end }} + {{- if .Values.controller.nodeSelector }} + nodeSelector: +{{ toYaml .Values.controller.nodeSelector | indent 8 }} + {{- end }} + {{- if .Values.controller.tolerations }} + tolerations: +{{ toYaml .Values.controller.tolerations | indent 8 }} + {{- end }} + {{- if .Values.controller.affinity }} + affinity: +{{ toYaml .Values.controller.affinity | indent 8 }} + {{- end }} + {{- if .Values.controller.topologySpreadConstraints }} + topologySpreadConstraints: +{{ toYaml .Values.controller.topologySpreadConstraints | indent 8 }} + {{- end }} + {{- if quote .Values.controller.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.controller.terminationGracePeriodSeconds }} + {{- end }} + {{- if .Values.controller.priorityClassName }} + priorityClassName: {{ .Values.controller.priorityClassName }} + {{- end }} + {{- if .Values.controller.shareProcessNamespace }} + shareProcessNamespace: true + {{- end }} +{{- if .Values.controller.usePodSecurityContext }} + securityContext: + {{- if kindIs "map" .Values.controller.podSecurityContextOverride }} + {{- tpl (toYaml .Values.controller.podSecurityContextOverride | nindent 8) . -}} + {{- else }} + {{/* The rest of this section should be replaced with the contents of this comment one the runAsUser, fsGroup, and securityContextCapabilities Helm chart values have been removed: + runAsUser: 1000 + fsGroup: 1000 + runAsNonRoot: true + */}} + runAsUser: {{ default 0 .Values.controller.runAsUser }} + {{- if and (.Values.controller.runAsUser) (.Values.controller.fsGroup) }} + {{- if not (eq (int .Values.controller.runAsUser) 0) }} + fsGroup: {{ .Values.controller.fsGroup }} + runAsNonRoot: true + {{- end }} + {{- if .Values.controller.securityContextCapabilities }} + capabilities: + {{- toYaml .Values.controller.securityContextCapabilities | nindent 10 }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} + serviceAccountName: "{{ template "jenkins.serviceAccountName" . }}" +{{- if .Values.controller.hostNetworking }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet +{{- end }} + {{- if .Values.controller.hostAliases }} + hostAliases: + {{- toYaml .Values.controller.hostAliases | nindent 8 }} + {{- end }} + initContainers: +{{- if .Values.controller.customInitContainers }} +{{ tpl (toYaml .Values.controller.customInitContainers) . | indent 8 }} +{{- end }} + +{{- if .Values.controller.sidecars.configAutoReload.enabled }} +{{- include "jenkins.configReloadContainer" (list $ "config-reload-init" "init") | nindent 8 }} +{{- end}} + + - name: "init" + image: "{{ .Values.controller.image.registry }}/{{ .Values.controller.image.repository }}:{{- include "controller.image.tag" . -}}" + imagePullPolicy: "{{ .Values.controller.image.pullPolicy }}" + {{- if .Values.controller.containerSecurityContext }} + securityContext: {{- toYaml .Values.controller.containerSecurityContext | nindent 12 }} + {{- end }} + command: [ "sh", "/var/jenkins_config/apply_config.sh" ] + {{- if .Values.controller.initContainerEnvFrom }} + envFrom: +{{ (tpl (toYaml .Values.controller.initContainerEnvFrom) .) | indent 12 }} + {{- end }} + {{- if .Values.controller.initContainerEnv }} + env: +{{ (tpl (toYaml .Values.controller.initContainerEnv) .) | indent 12 }} + {{- end }} + resources: +{{- if .Values.controller.initContainerResources }} +{{ toYaml .Values.controller.initContainerResources | indent 12 }} +{{- else }} +{{ toYaml .Values.controller.resources | indent 12 }} +{{- end }} + volumeMounts: + {{- if .Values.persistence.mounts }} +{{ toYaml .Values.persistence.mounts | indent 12 }} + {{- end }} + - mountPath: {{ .Values.controller.jenkinsHome }} + name: jenkins-home + {{- if .Values.persistence.subPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + - mountPath: /var/jenkins_config + name: jenkins-config + {{- if .Values.controller.installPlugins }} + {{- if .Values.controller.overwritePluginsFromImage }} + - mountPath: {{ .Values.controller.jenkinsRef }}/plugins + name: plugins + {{- end }} + - mountPath: /var/jenkins_plugins + name: plugin-dir + - mountPath: /tmp + name: tmp-volume + {{- end }} + {{- if or .Values.controller.initScripts .Values.controller.initConfigMap }} + - mountPath: {{ .Values.controller.jenkinsHome }}/init.groovy.d + name: init-scripts + {{- end }} + {{- if and .Values.controller.httpsKeyStore.enable (not .Values.controller.httpsKeyStore.disableSecretMount) }} + {{- $httpsJKSDirPath := printf "%s" .Values.controller.httpsKeyStore.path }} + - mountPath: {{ $httpsJKSDirPath }} + name: jenkins-https-keystore + {{- end }} + containers: + - name: jenkins + image: "{{ .Values.controller.image.registry }}/{{ .Values.controller.image.repository }}:{{- include "controller.image.tag" . -}}" + imagePullPolicy: "{{ .Values.controller.image.pullPolicy }}" + {{- if .Values.controller.containerSecurityContext }} + securityContext: {{- toYaml .Values.controller.containerSecurityContext | nindent 12 }} + {{- end }} + {{- if .Values.controller.overrideArgs }} + args: [ + {{- range $overrideArg := .Values.controller.overrideArgs }} + "{{- tpl $overrideArg $ }}", + {{- end }} + ] + {{- else if .Values.controller.httpsKeyStore.enable }} + {{- $httpsJKSFilePath := printf "%s/%s" .Values.controller.httpsKeyStore.path .Values.controller.httpsKeyStore.fileName }} + args: [ "--httpPort={{.Values.controller.httpsKeyStore.httpPort}}", "--httpsPort={{.Values.controller.targetPort}}", '--httpsKeyStore={{ $httpsJKSFilePath }}', "--httpsKeyStorePassword=$(JENKINS_HTTPS_KEYSTORE_PASSWORD)" ] + {{- else }} + args: [ "--httpPort={{.Values.controller.targetPort}}"] + {{- end }} + {{- if .Values.controller.lifecycle }} + lifecycle: +{{ toYaml .Values.controller.lifecycle | indent 12 }} + {{- end }} +{{- if .Values.controller.terminationMessagePath }} + terminationMessagePath: {{ .Values.controller.terminationMessagePath }} +{{- end }} +{{- if .Values.controller.terminationMessagePolicy }} + terminationMessagePolicy: {{ .Values.controller.terminationMessagePolicy }} +{{- end }} + {{- if .Values.controller.containerEnvFrom }} + envFrom: +{{ (tpl ( toYaml .Values.controller.containerEnvFrom) .) | indent 12 }} + {{- end }} + env: + {{- if .Values.controller.containerEnv }} +{{ (tpl ( toYaml .Values.controller.containerEnv) .) | indent 12 }} + {{- end }} + {{- if or .Values.controller.additionalSecrets .Values.controller.existingSecret .Values.controller.additionalExistingSecrets .Values.controller.admin.createSecret }} + - name: SECRETS + value: /run/secrets/additional + {{- end }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: JAVA_OPTS + value: >- + {{ if .Values.controller.sidecars.configAutoReload.enabled }} -Dcasc.reload.token=$(POD_NAME) {{ end }}{{ default "" .Values.controller.javaOpts }} + - name: JENKINS_OPTS + value: >- + {{ if .Values.controller.jenkinsUriPrefix }}--prefix={{ .Values.controller.jenkinsUriPrefix }} {{ end }} --webroot=/var/jenkins_cache/war {{ default "" .Values.controller.jenkinsOpts}} + - name: JENKINS_SLAVE_AGENT_PORT + value: "{{ .Values.controller.agentListenerPort }}" + {{- if .Values.controller.httpsKeyStore.enable }} + - name: JENKINS_HTTPS_KEYSTORE_PASSWORD + {{- if not .Values.controller.httpsKeyStore.disableSecretMount }} + valueFrom: + secretKeyRef: + name: {{ if .Values.controller.httpsKeyStore.jenkinsHttpsJksPasswordSecretName }} {{ .Values.controller.httpsKeyStore.jenkinsHttpsJksPasswordSecretName }} {{ else if .Values.controller.httpsKeyStore.jenkinsHttpsJksSecretName }} {{ .Values.controller.httpsKeyStore.jenkinsHttpsJksSecretName }} {{ else }} {{ template "jenkins.fullname" . }}-https-jks {{ end }} + key: "{{ .Values.controller.httpsKeyStore.jenkinsHttpsJksPasswordSecretKey }}" + {{- else }} + value: {{ .Values.controller.httpsKeyStore.password }} + {{- end }} + {{- end }} + + - name: CASC_JENKINS_CONFIG + value: {{ .Values.controller.sidecars.configAutoReload.folder | default (printf "%s/casc_configs" (.Values.controller.jenkinsRef)) }}{{- if .Values.controller.JCasC.configUrls }},{{ join "," .Values.controller.JCasC.configUrls }}{{- end }} + ports: + {{- if .Values.controller.httpsKeyStore.enable }} + - containerPort: {{.Values.controller.httpsKeyStore.httpPort}} + {{- else }} + - containerPort: {{.Values.controller.targetPort}} + {{- end }} + name: http + - containerPort: {{ .Values.controller.agentListenerPort }} + name: agent-listener + {{- if .Values.controller.agentListenerHostPort }} + hostPort: {{ .Values.controller.agentListenerHostPort }} + {{- end }} + {{- if .Values.controller.jmxPort }} + - containerPort: {{ .Values.controller.jmxPort }} + name: jmx + {{- end }} +{{- range $index, $port := .Values.controller.extraPorts }} + - containerPort: {{ $port.port }} + name: {{ $port.name }} +{{- end }} +{{- if and .Values.controller.healthProbes .Values.controller.probes}} + {{- if semverCompare ">=1.16-0" .Capabilities.KubeVersion.GitVersion }} + startupProbe: +{{ tpl (toYaml .Values.controller.probes.startupProbe | indent 12) .}} + {{- end }} + livenessProbe: +{{ tpl (toYaml .Values.controller.probes.livenessProbe | indent 12) .}} + readinessProbe: +{{ tpl (toYaml .Values.controller.probes.readinessProbe | indent 12) .}} +{{- end }} + resources: +{{ toYaml .Values.controller.resources | indent 12 }} + volumeMounts: +{{- if .Values.persistence.mounts }} +{{ toYaml .Values.persistence.mounts | indent 12 }} +{{- end }} + {{- if and .Values.controller.httpsKeyStore.enable (not .Values.controller.httpsKeyStore.disableSecretMount) }} + {{- $httpsJKSDirPath := printf "%s" .Values.controller.httpsKeyStore.path }} + - mountPath: {{ $httpsJKSDirPath }} + name: jenkins-https-keystore + {{- end }} + - mountPath: {{ .Values.controller.jenkinsHome }} + name: jenkins-home + readOnly: false + {{- if .Values.persistence.subPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + - mountPath: /var/jenkins_config + name: jenkins-config + readOnly: true + {{- if .Values.controller.installPlugins }} + - mountPath: {{ .Values.controller.jenkinsRef }}/plugins/ + name: plugin-dir + readOnly: false + {{- end }} + {{- if or .Values.controller.initScripts .Values.controller.initConfigMap }} + - mountPath: {{ .Values.controller.jenkinsHome }}/init.groovy.d + name: init-scripts + {{- end }} + {{- if .Values.controller.sidecars.configAutoReload.enabled }} + - name: sc-config-volume + mountPath: {{ .Values.controller.sidecars.configAutoReload.folder | default (printf "%s/casc_configs" (.Values.controller.jenkinsRef)) }} + {{- end }} + {{- if or .Values.controller.additionalSecrets .Values.controller.existingSecret .Values.controller.additionalExistingSecrets .Values.controller.admin.createSecret }} + - name: jenkins-secrets + mountPath: /run/secrets/additional + readOnly: true + {{- end }} + - name: jenkins-cache + mountPath: /var/jenkins_cache + - mountPath: /tmp + name: tmp-volume + +{{- if .Values.controller.sidecars.configAutoReload.enabled }} +{{- include "jenkins.configReloadContainer" (list $ "config-reload" "sidecar") | nindent 8 }} +{{- end}} + + +{{- if .Values.controller.sidecars.additionalSidecarContainers}} +{{ tpl (toYaml .Values.controller.sidecars.additionalSidecarContainers | indent 8) .}} +{{- end }} + + volumes: +{{- if .Values.persistence.volumes }} +{{ tpl (toYaml .Values.persistence.volumes | indent 6) . }} +{{- end }} + {{- if .Values.controller.sidecars.configAutoReload.logging.configuration.override }} + - name: auto-reload-config + configMap: + name: {{ template "jenkins.fullname" . }}-auto-reload-config + - name: auto-reload-config-logs + emptyDir: {} + {{- end }} + {{- if .Values.controller.installPlugins }} + {{- if .Values.controller.overwritePluginsFromImage }} + - name: plugins + emptyDir: {} + {{- end }} + {{- end }} + {{- if and .Values.controller.initScripts .Values.controller.initConfigMap }} + - name: init-scripts + projected: + sources: + - configMap: + name: {{ template "jenkins.fullname" . }}-init-scripts + - configMap: + name: {{ .Values.controller.initConfigMap }} + {{- else if .Values.controller.initConfigMap }} + - name: init-scripts + configMap: + name: {{ .Values.controller.initConfigMap }} + {{- else if .Values.controller.initScripts }} + - name: init-scripts + configMap: + name: {{ template "jenkins.fullname" . }}-init-scripts + {{- end }} + - name: jenkins-config + configMap: + name: {{ template "jenkins.fullname" . }} + {{- if .Values.controller.installPlugins }} + - name: plugin-dir + emptyDir: {} + {{- end }} + {{- if or .Values.controller.additionalSecrets .Values.controller.existingSecret .Values.controller.additionalExistingSecrets .Values.controller.admin.createSecret }} + - name: jenkins-secrets + projected: + sources: + {{- if .Values.controller.additionalSecrets }} + - secret: + name: {{ template "jenkins.fullname" . }}-additional-secrets + {{- end }} + {{- if .Values.controller.additionalExistingSecrets }} + {{- range $key, $value := .Values.controller.additionalExistingSecrets }} + - secret: + name: {{ tpl $value.name $ }} + items: + - key: {{ tpl $value.keyName $ }} + path: {{ tpl $value.name $ }}-{{ tpl $value.keyName $ }} + {{- end }} + {{- end }} + {{- if .Values.controller.admin.createSecret }} + - secret: + name: {{ .Values.controller.admin.existingSecret | default (include "jenkins.fullname" .) }} + items: + - key: {{ .Values.controller.admin.userKey | default "jenkins-admin-user" }} + path: chart-admin-username + - key: {{ .Values.controller.admin.passwordKey | default "jenkins-admin-password" }} + path: chart-admin-password + {{- end }} + {{- if .Values.controller.existingSecret }} + - secret: + name: {{ .Values.controller.existingSecret }} + {{- end }} + {{- end }} + - name: jenkins-cache + emptyDir: {} + {{- if not (contains "jenkins-home" (quote .Values.persistence.volumes)) }} + - name: jenkins-home + {{- if .Values.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ .Values.persistence.existingClaim | default (include "jenkins.fullname" .) }} + {{- else }} + emptyDir: {} + {{- end -}} + {{- end }} + - name: sc-config-volume + emptyDir: {} + - name: tmp-volume + emptyDir: {} + + {{- if and .Values.controller.httpsKeyStore.enable (not .Values.controller.httpsKeyStore.disableSecretMount) }} + - name: jenkins-https-keystore + secret: + secretName: {{ if .Values.controller.httpsKeyStore.jenkinsHttpsJksSecretName }} {{ .Values.controller.httpsKeyStore.jenkinsHttpsJksSecretName }} {{ else }} {{ template "jenkins.fullname" . }}-https-jks {{ end }} + items: + - key: {{ .Values.controller.httpsKeyStore.jenkinsHttpsJksSecretKey }} + path: {{ .Values.controller.httpsKeyStore.fileName }} + {{- end }} + +{{- if .Values.controller.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.controller.imagePullSecretName }} +{{- end -}} diff --git a/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-svc.yaml b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-svc.yaml new file mode 100644 index 000000000..a83466ce3 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/jenkins-controller-svc.yaml @@ -0,0 +1,56 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{template "jenkins.fullname" . }} + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" + {{- if .Values.controller.serviceLabels }} +{{ toYaml .Values.controller.serviceLabels | indent 4 }} + {{- end }} +{{- if .Values.controller.serviceAnnotations }} + annotations: +{{ toYaml .Values.controller.serviceAnnotations | indent 4 }} +{{- end }} +spec: + {{- if .Values.controller.serviceExternalTrafficPolicy }} + externalTrafficPolicy: {{.Values.controller.serviceExternalTrafficPolicy}} + {{- end }} + {{- if (and (eq .Values.controller.serviceType "ClusterIP") (not (empty .Values.controller.clusterIP))) }} + clusterIP: {{.Values.controller.clusterIP}} + {{- end }} + ports: + - port: {{.Values.controller.servicePort}} + name: http + targetPort: {{ .Values.controller.targetPort }} + {{- if (and (eq .Values.controller.serviceType "NodePort") (not (empty .Values.controller.nodePort))) }} + nodePort: {{.Values.controller.nodePort}} + {{- end }} +{{- range $index, $port := .Values.controller.extraPorts }} + - port: {{ $port.port }} + name: {{ $port.name }} + {{- if $port.targetPort }} + targetPort: {{ $port.targetPort }} + {{- else }} + targetPort: {{ $port.port }} + {{- end -}} +{{- end }} + selector: + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + type: {{.Values.controller.serviceType}} + {{if eq .Values.controller.serviceType "LoadBalancer"}} +{{- if .Values.controller.loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{ toYaml .Values.controller.loadBalancerSourceRanges | indent 4 }} +{{- end }} + {{if .Values.controller.loadBalancerIP}} + loadBalancerIP: {{.Values.controller.loadBalancerIP}} + {{end}} + {{end}} diff --git a/charts/jenkins/jenkins/5.5.14/templates/rbac.yaml b/charts/jenkins/jenkins/5.5.14/templates/rbac.yaml new file mode 100644 index 000000000..581cb8d48 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/rbac.yaml @@ -0,0 +1,149 @@ +{{ if .Values.rbac.create }} +{{- $serviceName := include "jenkins.fullname" . -}} + +# This role is used to allow Jenkins scheduling of agents via Kubernetes plugin. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ $serviceName }}-schedule-agents + namespace: {{ template "jenkins.agent.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +rules: +- apiGroups: [""] + resources: ["pods", "pods/exec", "pods/log", "persistentvolumeclaims", "events"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["pods", "pods/exec", "persistentvolumeclaims"] + verbs: ["create", "delete", "deletecollection", "patch", "update"] + +--- + +# We bind the role to the Jenkins service account. The role binding is created in the namespace +# where the agents are supposed to run. +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ $serviceName }}-schedule-agents + namespace: {{ template "jenkins.agent.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ $serviceName }}-schedule-agents +subjects: +- kind: ServiceAccount + name: {{ template "jenkins.serviceAccountName" .}} + namespace: {{ template "jenkins.namespace" . }} + +--- + +{{- if .Values.rbac.readSecrets }} +# This is needed if you want to use https://jenkinsci.github.io/kubernetes-credentials-provider-plugin/ +# as it needs permissions to get/watch/list Secrets +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "jenkins.fullname" . }}-read-secrets + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ $serviceName }}-read-secrets + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "jenkins.fullname" . }}-read-secrets +subjects: + - kind: ServiceAccount + name: {{ template "jenkins.serviceAccountName" . }} + namespace: {{ template "jenkins.namespace" . }} + +--- +{{- end}} + +{{- if .Values.controller.sidecars.configAutoReload.enabled }} +# The sidecar container which is responsible for reloading configuration changes +# needs permissions to watch ConfigMaps +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "jenkins.fullname" . }}-casc-reload + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "watch", "list"] + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ $serviceName }}-watch-configmaps + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "jenkins.fullname" . }}-casc-reload +subjects: +- kind: ServiceAccount + name: {{ template "jenkins.serviceAccountName" . }} + namespace: {{ template "jenkins.namespace" . }} + +{{- end}} + +{{ end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/secret-additional.yaml b/charts/jenkins/jenkins/5.5.14/templates/secret-additional.yaml new file mode 100644 index 000000000..d1908aa9b --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/secret-additional.yaml @@ -0,0 +1,21 @@ +{{- if .Values.controller.additionalSecrets -}} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "jenkins.fullname" . }}-additional-secrets + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +type: Opaque +data: +{{- range .Values.controller.additionalSecrets }} + {{ .name }}: {{ .value | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/secret-claims.yaml b/charts/jenkins/jenkins/5.5.14/templates/secret-claims.yaml new file mode 100644 index 000000000..e8b6d6c8e --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/secret-claims.yaml @@ -0,0 +1,29 @@ +{{- if .Values.controller.secretClaims -}} +{{- $r := .Release -}} +{{- $v := .Values -}} +{{- $chart := printf "%s-%s" .Chart.Name .Chart.Version -}} +{{- $namespace := include "jenkins.namespace" . -}} +{{- $serviceName := include "jenkins.fullname" . -}} +{{ range .Values.controller.secretClaims }} +--- +kind: SecretClaim +apiVersion: vaultproject.io/v1 +metadata: + name: {{ $serviceName }}-{{ .name | default .path | lower }} + namespace: {{ $namespace }} + labels: + "app.kubernetes.io/name": '{{ $serviceName }}' + {{- if $v.renderHelmLabels }} + "helm.sh/chart": "{{ $chart }}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ $r.Service }}" + "app.kubernetes.io/instance": "{{ $r.Name }}" + "app.kubernetes.io/component": "{{ $v.controller.componentName }}" +spec: + type: {{ .type | default "Opaque" }} + path: {{ .path }} +{{- if .renew }} + renew: {{ .renew }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/jenkins/jenkins/5.5.14/templates/secret-https-jks.yaml b/charts/jenkins/jenkins/5.5.14/templates/secret-https-jks.yaml new file mode 100644 index 000000000..5348de41e --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/secret-https-jks.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.controller.httpsKeyStore.enable ( not .Values.controller.httpsKeyStore.jenkinsHttpsJksSecretName ) (not .Values.controller.httpsKeyStore.disableSecretMount) -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "jenkins.fullname" . }}-https-jks + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +type: Opaque +data: + jenkins-jks-file: | +{{ .Values.controller.httpsKeyStore.jenkinsKeyStoreBase64Encoded | indent 4 }} + https-jks-password: {{ .Values.controller.httpsKeyStore.password | b64enc }} +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/secret.yaml b/charts/jenkins/jenkins/5.5.14/templates/secret.yaml new file mode 100644 index 000000000..cc6ace179 --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/secret.yaml @@ -0,0 +1,20 @@ +{{- if and (not .Values.controller.admin.existingSecret) (.Values.controller.admin.createSecret) -}} + +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "jenkins.fullname" . }} + namespace: {{ template "jenkins.namespace" . }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +type: Opaque +data: + jenkins-admin-password: {{ template "jenkins.password" . }} + jenkins-admin-user: {{ .Values.controller.admin.username | b64enc | quote }} +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/service-account-agent.yaml b/charts/jenkins/jenkins/5.5.14/templates/service-account-agent.yaml new file mode 100644 index 000000000..48f08ba6c --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/service-account-agent.yaml @@ -0,0 +1,26 @@ +{{ if .Values.serviceAccountAgent.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "jenkins.serviceAccountAgentName" . }} + namespace: {{ template "jenkins.agent.namespace" . }} +{{- if .Values.serviceAccountAgent.annotations }} + annotations: +{{ tpl (toYaml .Values.serviceAccountAgent.annotations) . | indent 4 }} +{{- end }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +{{- if .Values.serviceAccountAgent.extraLabels }} +{{ tpl (toYaml .Values.serviceAccountAgent.extraLabels) . | indent 4 }} +{{- end }} +{{- if .Values.serviceAccountAgent.imagePullSecretName }} +imagePullSecrets: + - name: {{ .Values.serviceAccountAgent.imagePullSecretName }} +{{- end -}} +{{ end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/service-account.yaml b/charts/jenkins/jenkins/5.5.14/templates/service-account.yaml new file mode 100644 index 000000000..b44eb488c --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/service-account.yaml @@ -0,0 +1,26 @@ +{{ if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "jenkins.serviceAccountName" . }} + namespace: {{ template "jenkins.namespace" . }} +{{- if .Values.serviceAccount.annotations }} + annotations: +{{ tpl (toYaml .Values.serviceAccount.annotations) . | indent 4 }} +{{- end }} + labels: + "app.kubernetes.io/name": '{{ template "jenkins.name" .}}' + {{- if .Values.renderHelmLabels }} + "helm.sh/chart": "{{ template "jenkins.label" .}}" + {{- end }} + "app.kubernetes.io/managed-by": "{{ .Release.Service }}" + "app.kubernetes.io/instance": "{{ .Release.Name }}" + "app.kubernetes.io/component": "{{ .Values.controller.componentName }}" +{{- if .Values.serviceAccount.extraLabels }} +{{ tpl (toYaml .Values.serviceAccount.extraLabels) . | indent 4 }} +{{- end }} +{{- if .Values.serviceAccount.imagePullSecretName }} +imagePullSecrets: + - name: {{ .Values.serviceAccount.imagePullSecretName }} +{{- end -}} +{{ end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/tests/jenkins-test.yaml b/charts/jenkins/jenkins/5.5.14/templates/tests/jenkins-test.yaml new file mode 100644 index 000000000..12a935ecc --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/tests/jenkins-test.yaml @@ -0,0 +1,49 @@ +{{- if .Values.controller.testEnabled }} +apiVersion: v1 +kind: Pod +metadata: + name: "{{ .Release.Name }}-ui-test-{{ randAlphaNum 5 | lower }}" + namespace: {{ template "jenkins.namespace" . }} + annotations: + "helm.sh/hook": test-success +spec: + {{- if .Values.controller.nodeSelector }} + nodeSelector: +{{ toYaml .Values.controller.nodeSelector | indent 4 }} + {{- end }} + {{- if .Values.controller.tolerations }} + tolerations: +{{ toYaml .Values.controller.tolerations | indent 4 }} + {{- end }} + initContainers: + - name: "test-framework" + image: "{{ .Values.helmtest.bats.image.registry }}/{{ .Values.helmtest.bats.image.repository }}:{{ .Values.helmtest.bats.image.tag }}" + command: + - "bash" + - "-c" + args: + - | + # copy bats to tools dir + set -ex + cp -R /opt/bats /tools/bats/ + volumeMounts: + - mountPath: /tools + name: tools + containers: + - name: {{ .Release.Name }}-ui-test + image: "{{ .Values.controller.image.registry }}/{{ .Values.controller.image.repository }}:{{- include "controller.image.tag" . -}}" + command: ["/tools/bats/bin/bats", "-t", "/tests/run.sh"] + volumeMounts: + - mountPath: /tests + name: tests + readOnly: true + - mountPath: /tools + name: tools + volumes: + - name: tests + configMap: + name: {{ template "jenkins.fullname" . }}-tests + - name: tools + emptyDir: {} + restartPolicy: Never +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/templates/tests/test-config.yaml b/charts/jenkins/jenkins/5.5.14/templates/tests/test-config.yaml new file mode 100644 index 000000000..12c5b3a0d --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/templates/tests/test-config.yaml @@ -0,0 +1,14 @@ +{{- if .Values.controller.testEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "jenkins.fullname" . }}-tests + namespace: {{ template "jenkins.namespace" . }} + annotations: + "helm.sh/hook": test +data: + run.sh: |- + @test "Testing Jenkins UI is accessible" { + curl --retry 48 --retry-delay 10 {{ template "jenkins.fullname" . }}:{{ .Values.controller.servicePort }}{{ default "" .Values.controller.jenkinsUriPrefix }}/login + } +{{- end }} diff --git a/charts/jenkins/jenkins/5.5.14/values.yaml b/charts/jenkins/jenkins/5.5.14/values.yaml new file mode 100644 index 000000000..c7c9067ff --- /dev/null +++ b/charts/jenkins/jenkins/5.5.14/values.yaml @@ -0,0 +1,1357 @@ +# Default values for jenkins. +# This is a YAML-formatted file. +# Declare name/value pairs to be passed into your templates. +# name: value + +## Overrides for generated resource names +# See templates/_helpers.tpl +# -- Override the resource name prefix +# @default -- `Chart.Name` +nameOverride: +# -- Override the full resource names +# @default -- `jenkins-(release-name)` or `jenkins` if the release-name is `jenkins` +fullnameOverride: +# -- Override the deployment namespace +# @default -- `Release.Namespace` +namespaceOverride: + +# For FQDN resolving of the controller service. Change this value to match your existing configuration. +# ref: https://github.com/kubernetes/dns/blob/master/docs/specification.md +# -- Override the cluster name for FQDN resolving +clusterZone: "cluster.local" + +# -- The URL of the Kubernetes API server +kubernetesURL: "https://kubernetes.default" + +# -- The Jenkins credentials to access the Kubernetes API server. For the default cluster it is not needed. +credentialsId: + +# -- Enables rendering of the helm.sh/chart label to the annotations +renderHelmLabels: true + +controller: + # -- Used for label app.kubernetes.io/component + componentName: "jenkins-controller" + image: + # -- Controller image registry + registry: "docker.io" + # -- Controller image repository + repository: "jenkins/jenkins" + + # -- Controller image tag override; i.e., tag: "2.440.1-jdk17" + tag: + + # -- Controller image tag label + tagLabel: jdk17 + # -- Controller image pull policy + pullPolicy: "Always" + # -- Controller image pull secret + imagePullSecretName: + # -- Lifecycle specification for controller-container + lifecycle: {} + # postStart: + # exec: + # command: + # - "uname" + # - "-a" + + # -- Disable use of remember me + disableRememberMe: false + + # -- Set Number of executors + numExecutors: 0 + + # -- Sets the executor mode of the Jenkins node. Possible values are "NORMAL" or "EXCLUSIVE" + executorMode: "NORMAL" + + # -- Append Jenkins labels to the controller + customJenkinsLabels: [] + + hostNetworking: false + + # When enabling LDAP or another non-Jenkins identity source, the built-in admin account will no longer exist. + # If you disable the non-Jenkins identity store and instead use the Jenkins internal one, + # you should revert controller.admin.username to your preferred admin user: + admin: + + # -- Admin username created as a secret if `controller.admin.createSecret` is true + username: "admin" + # -- Admin password created as a secret if `controller.admin.createSecret` is true + # @default -- + password: + + # -- The key in the existing admin secret containing the username + userKey: jenkins-admin-user + # -- The key in the existing admin secret containing the password + passwordKey: jenkins-admin-password + + # The default configuration uses this secret to configure an admin user + # If you don't need that user or use a different security realm, then you can disable it + # -- Create secret for admin user + createSecret: true + + # -- The name of an existing secret containing the admin credentials + existingSecret: "" + # -- Email address for the administrator of the Jenkins instance + jenkinsAdminEmail: + + # This value should not be changed unless you use your custom image of jenkins or any derived from. + # If you want to use Cloudbees Jenkins Distribution docker, you should set jenkinsHome: "/var/cloudbees-jenkins-distribution" + # -- Custom Jenkins home path + jenkinsHome: "/var/jenkins_home" + + # This value should not be changed unless you use your custom image of jenkins or any derived from. + # If you want to use Cloudbees Jenkins Distribution docker, you should set jenkinsRef: "/usr/share/cloudbees-jenkins-distribution/ref" + # -- Custom Jenkins reference path + jenkinsRef: "/usr/share/jenkins/ref" + + # Path to the jenkins war file which is used by jenkins-plugin-cli. + jenkinsWar: "/usr/share/jenkins/jenkins.war" + # Override the default arguments passed to the war + # overrideArgs: + # - --httpPort=8080 + + # -- Resource allocation (Requests and Limits) + resources: + requests: + cpu: "50m" + memory: "256Mi" + limits: + cpu: "2000m" + memory: "4096Mi" + + # Share process namespace to allow sidecar containers to interact with processes in other containers in the same pod + shareProcessNamespace: false + + # Overrides the init container default values + # -- Resources allocation (Requests and Limits) for Init Container + initContainerResources: {} + # initContainerResources: + # requests: + # cpu: "50m" + # memory: "256Mi" + # limits: + # cpu: "2000m" + # memory: "4096Mi" + # -- Environment variable sources for Init Container + initContainerEnvFrom: [] + + # useful for i.e., http_proxy + # -- Environment variables for Init Container + initContainerEnv: [] + # initContainerEnv: + # - name: http_proxy + # value: "http://192.168.64.1:3128" + + # -- Environment variable sources for Jenkins Container + containerEnvFrom: [] + + # -- Environment variables for Jenkins Container + containerEnv: [] + # - name: http_proxy + # value: "http://192.168.64.1:3128" + + # Set min/max heap here if needed with "-Xms512m -Xmx512m" + # -- Append to `JAVA_OPTS` env var + javaOpts: + # -- Append to `JENKINS_OPTS` env var + jenkinsOpts: + + # If you are using the ingress definitions provided by this chart via the `controller.ingress` block, + # the configured hostname will be the ingress hostname starting with `https://` + # or `http://` depending on the `tls` configuration. + # The Protocol can be overwritten by specifying `controller.jenkinsUrlProtocol`. + # -- Set protocol for Jenkins URL; `https` if `controller.ingress.tls`, `http` otherwise + jenkinsUrlProtocol: + + # -- Set Jenkins URL if you are not using the ingress definitions provided by the chart + jenkinsUrl: + + # If you set this prefix and use ingress controller, then you might want to set the ingress path below + # I.e., "/jenkins" + # -- Root URI Jenkins will be served on + jenkinsUriPrefix: + + # -- Enable pod security context (must be `true` if podSecurityContextOverride, runAsUser or fsGroup are set) + usePodSecurityContext: true + + # Note that `runAsUser`, `fsGroup`, and `securityContextCapabilities` are + # being deprecated and replaced by `podSecurityContextOverride`. + # Set runAsUser to 1000 to let Jenkins run as non-root user 'jenkins', which exists in 'jenkins/jenkins' docker image. + # When configuring runAsUser to a different value than 0 also set fsGroup to the same value: + # -- Deprecated in favor of `controller.podSecurityContextOverride`. uid that jenkins runs with. + runAsUser: 1000 + + # -- Deprecated in favor of `controller.podSecurityContextOverride`. uid that will be used for persistent volume. + fsGroup: 1000 + + # If you have PodSecurityPolicies that require dropping of capabilities as suggested by CIS K8s benchmark, put them here + # securityContextCapabilities: + # drop: + # - NET_RAW + securityContextCapabilities: {} + + # In the case of mounting an ext4 filesystem, it might be desirable to use `supplementalGroups` instead of `fsGroup` in + # the `securityContext` block: https://github.com/kubernetes/kubernetes/issues/67014#issuecomment-589915496 + # podSecurityContextOverride: + # runAsUser: 1000 + # runAsNonRoot: true + # supplementalGroups: [1000] + # capabilities: {} + # -- Completely overwrites the contents of the pod security context, ignoring the values provided for `runAsUser`, `fsGroup`, and `securityContextCapabilities` + podSecurityContextOverride: ~ + + # -- Allow controlling the securityContext for the jenkins container + containerSecurityContext: + runAsUser: 1000 + runAsGroup: 1000 + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + + # For minikube, set this to NodePort, elsewhere uses LoadBalancer + # Use ClusterIP if your setup includes ingress controller + # -- k8s service type + serviceType: ClusterIP + + # -- k8s service clusterIP. Only used if serviceType is ClusterIP + clusterIp: + # -- k8s service port + servicePort: 8080 + # -- k8s target port + targetPort: 8080 + # -- k8s node port. Only used if serviceType is NodePort + nodePort: + + # Use Local to preserve the client source IP and avoids a second hop for LoadBalancer and NodePort type services, + # but risks potentially imbalanced traffic spreading. + serviceExternalTrafficPolicy: + + # -- Jenkins controller service annotations + serviceAnnotations: {} + # -- Jenkins controller custom labels for the StatefulSet + statefulSetLabels: {} + # foo: bar + # bar: foo + # -- Labels for the Jenkins controller-service + serviceLabels: {} + # service.beta.kubernetes.io/aws-load-balancer-backend-protocol: https + + # Put labels on Jenkins controller pod + # -- Custom Pod labels (an object with `label-key: label-value` pairs) + podLabels: {} + + # Enable Kubernetes Startup, Liveness and Readiness Probes + # if Startup Probe is supported, enable it too + # ~ 2 minutes to allow Jenkins to restart when upgrading plugins. Set ReadinessTimeout to be shorter than LivenessTimeout. + # ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes + # -- Enable Kubernetes Probes configuration configured in `controller.probes` + healthProbes: true + + probes: + startupProbe: + # -- Set the failure threshold for the startup probe + failureThreshold: 12 + httpGet: + # -- Set the Pod's HTTP path for the startup probe + path: '{{ default "" .Values.controller.jenkinsUriPrefix }}/login' + # -- Set the Pod's HTTP port to use for the startup probe + port: http + # -- Set the time interval between two startup probes executions in seconds + periodSeconds: 10 + # -- Set the timeout for the startup probe in seconds + timeoutSeconds: 5 + + livenessProbe: + # -- Set the failure threshold for the liveness probe + failureThreshold: 5 + httpGet: + # -- Set the Pod's HTTP path for the liveness probe + path: '{{ default "" .Values.controller.jenkinsUriPrefix }}/login' + # -- Set the Pod's HTTP port to use for the liveness probe + port: http + # -- Set the time interval between two liveness probes executions in seconds + periodSeconds: 10 + # -- Set the timeout for the liveness probe in seconds + timeoutSeconds: 5 + + # If Startup Probe is not supported on your Kubernetes cluster, you might want to use "initialDelaySeconds" instead. + # It delays the initial liveness probe while Jenkins is starting + # -- Set the initial delay for the liveness probe in seconds + initialDelaySeconds: + + readinessProbe: + # -- Set the failure threshold for the readiness probe + failureThreshold: 3 + httpGet: + # -- Set the Pod's HTTP path for the liveness probe + path: '{{ default "" .Values.controller.jenkinsUriPrefix }}/login' + # -- Set the Pod's HTTP port to use for the readiness probe + port: http + # -- Set the time interval between two readiness probes executions in seconds + periodSeconds: 10 + # -- Set the timeout for the readiness probe in seconds + timeoutSeconds: 5 + + # If Startup Probe is not supported on your Kubernetes cluster, you might want to use "initialDelaySeconds" instead. + # It delays the initial readiness probe while Jenkins is starting + # -- Set the initial delay for the readiness probe in seconds + initialDelaySeconds: + + # PodDisruptionBudget config + podDisruptionBudget: + # ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ + + # -- Enable Kubernetes Pod Disruption Budget configuration + enabled: false + + # For Kubernetes v1.5+, use 'policy/v1beta1' + # For Kubernetes v1.21+, use 'policy/v1' + # -- Policy API version + apiVersion: "policy/v1beta1" + + annotations: {} + labels: {} + # -- Number of pods that can be unavailable. Either an absolute number or a percentage + maxUnavailable: "0" + + # -- Create Agent listener service + agentListenerEnabled: true + # -- Listening port for agents + agentListenerPort: 50000 + # -- Host port to listen for agents + agentListenerHostPort: + # -- Node port to listen for agents + agentListenerNodePort: + + # ref: https://kubernetes.io/docs/concepts/services-networking/service/#traffic-policies + # -- Traffic Policy of for the agentListener service + agentListenerExternalTrafficPolicy: + # -- Allowed inbound IP for the agentListener service + agentListenerLoadBalancerSourceRanges: + - 0.0.0.0/0 + # -- Disabled agent protocols + disabledAgentProtocols: + - JNLP-connect + - JNLP2-connect + csrf: + defaultCrumbIssuer: + # -- Enable the default CSRF Crumb issuer + enabled: true + # -- Enable proxy compatibility + proxyCompatability: true + + # Kubernetes service type for the JNLP agent service + # agentListenerServiceType is the Kubernetes Service type for the JNLP agent service, + # either 'LoadBalancer', 'NodePort', or 'ClusterIP' + # Note if you set this to 'LoadBalancer', you *must* define annotations to secure it. By default, + # this will be an external load balancer and allowing inbound 0.0.0.0/0, a HUGE + # security risk: https://github.com/kubernetes/charts/issues/1341 + # -- Defines how to expose the agentListener service + agentListenerServiceType: "ClusterIP" + + # -- Annotations for the agentListener service + agentListenerServiceAnnotations: {} + + # Optionally, assign an IP to the LoadBalancer agentListenerService LoadBalancer + # GKE users: only regional static IPs will work for Service Load balancer. + # -- Static IP for the agentListener LoadBalancer + agentListenerLoadBalancerIP: + + # -- Whether legacy remoting security should be enabled + legacyRemotingSecurityEnabled: false + + # Example of a 'LoadBalancer'-type agent listener with annotations securing it + # agentListenerServiceType: LoadBalancer + # agentListenerServiceAnnotations: + # service.beta.kubernetes.io/aws-load-balancer-internal: "True" + # service.beta.kubernetes.io/load-balancer-source-ranges: "172.0.0.0/8, 10.0.0.0/8" + + # LoadBalancerSourcesRange is a list of allowed CIDR values, which are combined with ServicePort to + # set allowed inbound rules on the security group assigned to the controller load balancer + # -- Allowed inbound IP addresses + loadBalancerSourceRanges: + - 0.0.0.0/0 + + # -- Optionally assign a known public LB IP + loadBalancerIP: + + # Optionally configure a JMX port. This requires additional javaOpts, for example, + # javaOpts: > + # -Dcom.sun.management.jmxremote.port=4000 + # -Dcom.sun.management.jmxremote.authenticate=false + # -Dcom.sun.management.jmxremote.ssl=false + # jmxPort: 4000 + # -- Open a port, for JMX stats + jmxPort: + + # -- Optionally configure other ports to expose in the controller container + extraPorts: [] + # - name: BuildInfoProxy + # port: 9000 + # targetPort: 9010 (Optional: Use to explicitly set targetPort if different from port) + + # Plugins will be installed during Jenkins controller start + # -- List of Jenkins plugins to install. If you don't want to install plugins, set it to `false` + installPlugins: + - kubernetes:4285.v50ed5f624918 + - workflow-aggregator:600.vb_57cdd26fdd7 + - git:5.4.1 + - configuration-as-code:1850.va_a_8c31d3158b_ + + # If set to false, Jenkins will download the minimum required version of all dependencies. + # -- Download the minimum required version or latest version of all dependencies + installLatestPlugins: true + + # -- Set to true to download the latest version of any plugin that is requested to have the latest version + installLatestSpecifiedPlugins: false + + # -- List of plugins to install in addition to those listed in controller.installPlugins + additionalPlugins: [] + + # Without this; whenever the controller gets restarted (Evicted, etc.) it will fetch plugin updates that have the potential to cause breakage. + # Note that for this to work, `persistence.enabled` needs to be set to `true` + # -- Initialize only on first installation. Ensures plugins do not get updated inadvertently. Requires `persistence.enabled` to be set to `true` + initializeOnce: false + + # Enable to always override the installed plugins with the values of 'controller.installPlugins' on upgrade or redeployment. + # -- Overwrite installed plugins on start + overwritePlugins: false + + # Configures if plugins bundled with `controller.image` should be overwritten with the values of 'controller.installPlugins' on upgrade or redeployment. + # -- Overwrite plugins that are already installed in the controller image + overwritePluginsFromImage: true + + # Configures the restrictions for naming projects. Set this key to null or empty to skip it in the default config. + projectNamingStrategy: standard + + # Useful with ghprb plugin. The OWASP plugin is not installed by default, please update controller.installPlugins. + # -- Enable HTML parsing using OWASP Markup Formatter Plugin (antisamy-markup-formatter) + enableRawHtmlMarkupFormatter: false + + # This is ignored if enableRawHtmlMarkupFormatter is true + # -- Yaml of the markup formatter to use + markupFormatter: plainText + + # Used to approve a list of groovy functions in pipelines used the script-security plugin. Can be viewed under /scriptApproval + # -- List of groovy functions to approve + scriptApproval: [] + # - "method groovy.json.JsonSlurperClassic parseText java.lang.String" + # - "new groovy.json.JsonSlurperClassic" + + # -- Map of groovy init scripts to be executed during Jenkins controller start + initScripts: {} + # test: |- + # print 'adding global pipeline libraries, register properties, bootstrap jobs...' + # -- Name of the existing ConfigMap that contains init scripts + initConfigMap: + + # 'name' is a name of an existing secret in the same namespace as jenkins, + # 'keyName' is the name of one of the keys inside the current secret. + # the 'name' and 'keyName' are concatenated with a '-' in between, so for example: + # an existing secret "secret-credentials" and a key inside it named "github-password" should be used in JCasC as ${secret-credentials-github-password} + # 'name' and 'keyName' must be lowercase RFC 1123 label must consist of lower case alphanumeric characters or '-', + # and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc') + # existingSecret existing secret "secret-credentials" and a key inside it named "github-username" should be used in JCasC as ${github-username} + # When using existingSecret no need to specify the keyName under additionalExistingSecrets. + existingSecret: + + # -- List of additional existing secrets to mount + additionalExistingSecrets: [] + # ref: https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/docs/features/secrets.adoc#kubernetes-secrets + # additionalExistingSecrets: + # - name: secret-name-1 + # keyName: username + # - name: secret-name-1 + # keyName: password + + # -- List of additional secrets to create and mount + additionalSecrets: [] + # ref: https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/docs/features/secrets.adoc#kubernetes-secrets + # additionalSecrets: + # - name: nameOfSecret + # value: secretText + + # Generate SecretClaim resources to create Kubernetes secrets from HashiCorp Vault using kube-vault-controller. + # 'name' is the name of the secret that will be created in Kubernetes. The Jenkins fullname is prepended to this value. + # 'path' is the fully qualified path to the secret in Vault + # 'type' is an optional Kubernetes secret type. The default is 'Opaque' + # 'renew' is an optional secret renewal time in seconds + # -- List of `SecretClaim` resources to create + secretClaims: [] + # - name: secretName # required + # path: testPath # required + # type: kubernetes.io/tls # optional + # renew: 60 # optional + + # -- Name of default cloud configuration. + cloudName: "kubernetes" + + # Below is the implementation of Jenkins Configuration as Code. Add a key under configScripts for each configuration area, + # where each corresponds to a plugin or section of the UI. Each key (prior to | character) is just a label, and can be any value. + # Keys are only used to give the section a meaningful name. The only restriction is they may only contain RFC 1123 \ DNS label + # characters: lowercase letters, numbers, and hyphens. The keys become the name of a configuration yaml file on the controller in + # /var/jenkins_home/casc_configs (by default) and will be processed by the Configuration as Code Plugin. The lines after each | + # become the content of the configuration yaml file. The first line after this is a JCasC root element, e.g., jenkins, credentials, + # etc. Best reference is https:///configuration-as-code/reference. The example below creates a welcome message: + JCasC: + # -- Enables default Jenkins configuration via configuration as code plugin + defaultConfig: true + + # If true, the init container deletes all the plugin config files and Jenkins Config as Code overwrites any existing configuration + # -- Whether Jenkins Config as Code should overwrite any existing configuration + overwriteConfiguration: false + # -- Remote URLs for configuration files. + configUrls: [] + # - https://acme.org/jenkins.yaml + # -- List of Jenkins Config as Code scripts + configScripts: {} + # welcome-message: | + # jenkins: + # systemMessage: Welcome to our CI\CD server. This Jenkins is configured and managed 'as code'. + + # Allows adding to the top-level security JCasC section. For legacy purposes, by default, the chart includes apiToken configurations + # -- Jenkins Config as Code security-section + security: + apiToken: + creationOfLegacyTokenEnabled: false + tokenGenerationOnCreationEnabled: false + usageStatisticsEnabled: true + + # Ignored if securityRealm is defined in controller.JCasC.configScripts + # -- Jenkins Config as Code Security Realm-section + securityRealm: |- + local: + allowsSignup: false + enableCaptcha: false + users: + - id: "${chart-admin-username}" + name: "Jenkins Admin" + password: "${chart-admin-password}" + + # Ignored if authorizationStrategy is defined in controller.JCasC.configScripts + # -- Jenkins Config as Code Authorization Strategy-section + authorizationStrategy: |- + loggedInUsersCanDoAnything: + allowAnonymousRead: false + + # -- Annotations for the JCasC ConfigMap + configMapAnnotations: {} + + # -- Custom init-container specification in raw-yaml format + customInitContainers: [] + # - name: custom-init + # image: "alpine:3" + # imagePullPolicy: Always + # command: [ "uname", "-a" ] + + sidecars: + configAutoReload: + # If enabled: true, Jenkins Configuration as Code will be reloaded on-the-fly without a reboot. + # If false or not-specified, 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. + # -- Enables Jenkins Config as Code auto-reload + enabled: true + image: + # -- Registry for the image that triggers the reload + registry: docker.io + # -- Repository of the image that triggers the reload + repository: kiwigrid/k8s-sidecar + # -- Tag for the image that triggers the reload + tag: 1.27.6 + imagePullPolicy: IfNotPresent + resources: {} + # limits: + # cpu: 100m + # memory: 100Mi + # requests: + # cpu: 50m + # memory: 50Mi + # -- Enables additional volume mounts for the config auto-reload container + additionalVolumeMounts: [] + # - name: auto-reload-config + # mountPath: /var/config/logger + # - name: auto-reload-logs + # mountPath: /var/log/auto_reload + # -- Config auto-reload logging settings + logging: + # See default settings https://github.com/kiwigrid/k8s-sidecar/blob/master/src/logger.py + configuration: + # -- Enables custom log config utilizing using the settings below. + override: false + logLevel: INFO + formatter: JSON + logToConsole: true + logToFile: false + maxBytes: 1024 + backupCount: 3 + + # -- The scheme to use when connecting to the Jenkins configuration as code endpoint + scheme: http + # -- Skip TLS verification when connecting to the Jenkins configuration as code endpoint + skipTlsVerify: false + + # -- How many connection-related errors to retry on + reqRetryConnect: 10 + # -- How many seconds to wait before updating config-maps/secrets (sets METHOD=SLEEP on the sidecar) + sleepTime: + + # -- Environment variable sources for the Jenkins Config as Code auto-reload container + envFrom: [] + # -- Environment variables for the Jenkins Config as Code auto-reload container + env: {} + # - name: REQ_TIMEOUT + # value: "30" + + # SSH port value can be set to any unused TCP port. The default, 1044, is a non-standard SSH port that has been chosen at random. + # This is only used to reload JCasC config from the sidecar container running in the Jenkins controller pod. + # This TCP port will not be open in the pod (unless you specifically configure this), so Jenkins will not be + # accessible via SSH from outside the pod. Note if you use non-root pod privileges (runAsUser & fsGroup), + # this must be > 1024: + sshTcpPort: 1044 + # folder in the pod that should hold the collected dashboards: + folder: "/var/jenkins_home/casc_configs" + + # If specified, the sidecar will search for JCasC config-maps inside this namespace. + # Otherwise, the namespace in which the sidecar is running will be used. + # It's also possible to specify ALL to search in all namespaces: + # searchNamespace: + # -- Enable container security context + containerSecurityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + + # -- Configures additional sidecar container(s) for the Jenkins controller + additionalSidecarContainers: [] + ## The example below runs the client for https://smee.io as sidecar container next to Jenkins, + ## that allows triggering build behind a secure firewall. + ## https://jenkins.io/blog/2019/01/07/webhook-firewalls/#triggering-builds-with-webhooks-behind-a-secure-firewall + ## + ## Note: To use it you should go to https://smee.io/new and update the url to the generated one. + # - name: smee + # image: docker.io/twalter/smee-client:1.0.2 + # args: ["--port", "{{ .Values.controller.servicePort }}", "--path", "/github-webhook/", "--url", "https://smee.io/new"] + # resources: + # limits: + # cpu: 50m + # memory: 128Mi + # requests: + # cpu: 10m + # memory: 32Mi + + # -- Name of the Kubernetes scheduler to use + schedulerName: "" + + # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + # -- Node labels for pod assignment + nodeSelector: {} + + # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#taints-and-tolerations-beta-feature + # -- Toleration labels for pod assignment + tolerations: [] + # -- Set TerminationGracePeriodSeconds + terminationGracePeriodSeconds: + # -- Set the termination message path + terminationMessagePath: + # -- Set the termination message policy + terminationMessagePolicy: + + # -- Affinity settings + affinity: {} + + # Leverage a priorityClass to ensure your pods survive resource shortages + # ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ + # -- The name of a `priorityClass` to apply to the controller pod + priorityClassName: + + # -- Annotations for controller pod + podAnnotations: {} + # -- Annotations for controller StatefulSet + statefulSetAnnotations: {} + + # ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies + # -- Update strategy for StatefulSet + updateStrategy: {} + + # -- Topology spread constraints + topologySpreadConstraints: {} + + ingress: + # -- Enables ingress + enabled: false + + # Override for the default paths that map requests to the backend + # -- Override for the default Ingress paths + paths: [] + # - backend: + # serviceName: ssl-redirect + # servicePort: use-annotation + # - backend: + # serviceName: >- + # {{ template "jenkins.fullname" . }} + # # Don't use string here, use only integer value! + # servicePort: 8080 + + # For Kubernetes v1.14+, use 'networking.k8s.io/v1beta1' + # For Kubernetes v1.19+, use 'networking.k8s.io/v1' + # -- Ingress API version + apiVersion: "extensions/v1beta1" + # -- Ingress labels + labels: {} + # -- Ingress annotations + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName + # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress + # ingressClassName: nginx + + # Set this path to jenkinsUriPrefix above or use annotations to rewrite path + # -- Ingress path + path: + + # configures the hostname e.g. jenkins.example.com + # -- Ingress hostname + hostName: + # -- Hostname to serve assets from + resourceRootUrl: + # -- Ingress TLS configuration + tls: [] + # - secretName: jenkins.cluster.local + # hosts: + # - jenkins.cluster.local + + # often you want to have your controller all locked down and private, + # but you still want to get webhooks from your SCM + # A secondary ingress will let you expose different urls + # with a different configuration + secondaryingress: + enabled: false + # paths you want forwarded to the backend + # ex /github-webhook + paths: [] + # For Kubernetes v1.14+, use 'networking.k8s.io/v1beta1' + # For Kubernetes v1.19+, use 'networking.k8s.io/v1' + apiVersion: "extensions/v1beta1" + labels: {} + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName + # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress + # ingressClassName: nginx + # configures the hostname e.g., jenkins-external.example.com + hostName: + tls: + # - secretName: jenkins-external.example.com + # hosts: + # - jenkins-external.example.com + + # If you're running on GKE and need to configure a backendconfig + # to finish ingress setup, use the following values. + # Docs: https://cloud.google.com/kubernetes-engine/docs/concepts/backendconfig + backendconfig: + # -- Enables backendconfig + enabled: false + # -- backendconfig API version + apiVersion: "extensions/v1beta1" + # -- backendconfig name + name: + # -- backendconfig labels + labels: {} + # -- backendconfig annotations + annotations: {} + # -- backendconfig spec + spec: {} + + # Openshift route + route: + # -- Enables openshift route + enabled: false + # -- Route labels + labels: {} + # -- Route annotations + annotations: {} + # -- Route path + path: + + # -- Allows for adding entries to Pod /etc/hosts + hostAliases: [] + # ref: https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ + # hostAliases: + # - ip: 192.168.50.50 + # hostnames: + # - something.local + # - ip: 10.0.50.50 + # hostnames: + # - other.local + + # Expose Prometheus metrics + prometheus: + # If enabled, add the prometheus plugin to the list of plugins to install + # https://plugins.jenkins.io/prometheus + + # -- Enables prometheus service monitor + enabled: false + # -- Additional labels to add to the service monitor object + serviceMonitorAdditionalLabels: {} + # -- Set a custom namespace where to deploy ServiceMonitor resource + serviceMonitorNamespace: + # -- How often prometheus should scrape metrics + scrapeInterval: 60s + + # Defaults to the default endpoint used by the prometheus plugin + # -- The endpoint prometheus should get metrics from + scrapeEndpoint: /prometheus + + # See here: https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/ + # The `groups` root object is added by default, add the rule entries + # -- Array of prometheus alerting rules + alertingrules: [] + # -- Additional labels to add to the PrometheusRule object + alertingRulesAdditionalLabels: {} + # -- Set a custom namespace where to deploy PrometheusRule resource + prometheusRuleNamespace: "" + + # RelabelConfigs to apply to samples before scraping. Prometheus Operator automatically adds + # relabelings for a few standard Kubernetes fields. The original scrape job’s name + # is available via the __tmp_prometheus_job_name label. + # More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config + relabelings: [] + # MetricRelabelConfigs to apply to samples before ingestion. + metricRelabelings: [] + + googlePodMonitor: + # If enabled, It creates Google Managed Prometheus scraping config + enabled: false + # Set a custom namespace where to deploy PodMonitoring resource + # serviceMonitorNamespace: "" + scrapeInterval: 60s + # This is the default endpoint used by the prometheus plugin + scrapeEndpoint: /prometheus + + # -- Can be used to disable rendering controller test resources when using helm template + testEnabled: true + + httpsKeyStore: + # -- Enables HTTPS keystore on jenkins controller + enable: false + # -- Name of the secret that already has ssl keystore + jenkinsHttpsJksSecretName: "" + # -- Name of the key in the secret that already has ssl keystore + jenkinsHttpsJksSecretKey: "jenkins-jks-file" + # -- Name of the secret that contains the JKS password, if it is not in the same secret as the JKS file + jenkinsHttpsJksPasswordSecretName: "" + # -- Name of the key in the secret that contains the JKS password + jenkinsHttpsJksPasswordSecretKey: "https-jks-password" + disableSecretMount: false + + # When HTTPS keystore is enabled, servicePort and targetPort will be used as HTTPS port + # -- HTTP Port that Jenkins should listen to along with HTTPS, it also serves as the liveness and readiness probes port. + httpPort: 8081 + # -- Path of HTTPS keystore file + path: "/var/jenkins_keystore" + # -- Jenkins keystore filename which will appear under controller.httpsKeyStore.path + fileName: "keystore.jks" + # -- Jenkins keystore password + password: "password" + + # -- Base64 encoded Keystore content. Keystore must be converted to base64 then being pasted here + jenkinsKeyStoreBase64Encoded: + # Convert keystore.jks files content to base64 > $ cat keystore.jks | base64 +# /u3+7QAAAAIAAAABAAAAAQANamVua2luc2NpLmNvbQAAAW2r/b1ZAAAFATCCBP0wDgYKKwYBBAEq +# AhEBAQUABIIE6QbCqasvoHS0pSwYqSvdydMCB9t+VNfwhFIiiuAelJfO5sSe2SebJbtwHgLcRz1Z +# gMtWgOSFdl3bWSzA7vrW2LED52h+jXLYSWvZzuDuh8hYO85m10ikF6QR+dTi4jra0whIFDvq3pxe +# TnESxEsN+DvbZM3jA3qsjQJSeISNpDjO099dqQvHpnCn18lyk7J4TWJ8sOQQb1EM2zDAfAOSqA/x +# QuPEFl74DlY+5DIk6EBvpmWhaMSvXzWZACGA0sYqa157dq7O0AqmuLG/EI5EkHETO4CrtBW+yLcy +# 2dUCXOMA+j+NjM1BjrQkYE5vtSfNO6lFZcISyKo5pTFlcA7ut0Fx2nZ8GhHTn32CpeWwNcZBn1gR +# pZVt6DxVVkhTAkMLhR4rL2wGIi/1WRs23ZOLGKtyDNvDHnQyDiQEoJGy9nAthA8aNHa3cfdF10vB +# Drb19vtpFHmpvKEEhpk2EBRF4fTi644Fuhu2Ied6118AlaPvEea+n6G4vBz+8RWuVCmZjLU+7h8l +# Hy3/WdUPoIL5eW7Kz+hS+sRTFzfu9C48dMkQH3a6f3wSY+mufizNF9U298r98TnYy+PfDJK0bstG +# Ph6yPWx8DGXKQBwrhWJWXI6JwZDeC5Ny+l8p1SypTmAjpIaSW3ge+KgcL6Wtt1R5hUV1ajVwVSUi +# HF/FachKqPqyLJFZTGjNrxnmNYpt8P1d5JTvJfmfr55Su/P9n7kcyWp7zMcb2Q5nlXt4tWogOHLI +# OzEWKCacbFfVHE+PpdrcvCVZMDzFogIq5EqGTOZe2poPpBVE+1y9mf5+TXBegy5HToLWvmfmJNTO +# NCDuBjgLs2tdw2yMPm4YEr57PnMX5gGTC3f2ZihXCIJDCRCdQ9sVBOjIQbOCzxFXkVITo0BAZhCi +# Yz61wt3Ud8e//zhXWCkCsSV+IZCxxPzhEFd+RFVjW0Nm9hsb2FgAhkXCjsGROgoleYgaZJWvQaAg +# UyBzMmKDPKTllBHyE3Gy1ehBNGPgEBChf17/9M+j8pcm1OmlM434ctWQ4qW7RU56//yq1soFY0Te +# fu2ei03a6m68fYuW6s7XEEK58QisJWRAvEbpwu/eyqfs7PsQ+zSgJHyk2rO95IxdMtEESb2GRuoi +# Bs+AHNdYFTAi+GBWw9dvEgqQ0Mpv0//6bBE/Fb4d7b7f56uUNnnE7mFnjGmGQN+MvC62pfwfvJTT +# EkT1iZ9kjM9FprTFWXT4UmO3XTvesGeE50sV9YPm71X4DCQwc4KE8vyuwj0s6oMNAUACW2ClU9QQ +# y0tRpaF1tzs4N42Q5zl0TzWxbCCjAtC3u6xf+c8MCGrr7DzNhm42LOQiHTa4MwX4x96q7235oiAU +# iQqSI/hyF5yLpWw4etyUvsx2/0/0wkuTU1FozbLoCWJEWcPS7QadMrRRISxHf0YobIeQyz34regl +# t1qSQ3dCU9D6AHLgX6kqllx4X0fnFq7LtfN7fA2itW26v+kAT2QFZ3qZhINGfofCja/pITC1uNAZ +# gsJaTMcQ600krj/ynoxnjT+n1gmeqThac6/Mi3YlVeRtaxI2InL82ZuD+w/dfY9OpPssQjy3xiQa +# jPuaMWXRxz/sS9syOoGVH7XBwKrWpQcpchozWJt40QV5DslJkclcr8aC2AGlzuJMTdEgz1eqV0+H +# bAXG9HRHN/0eJTn1/QAAAAEABVguNTA5AAADjzCCA4swggJzAhRGqVxH4HTLYPGO4rzHcCPeGDKn +# xTANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCY2ExEDAOBgNVBAgMB29udGFyaW8xEDAOBgNV +# BAcMB3Rvcm9udG8xFDASBgNVBAoMC2plbmtpbnN0ZXN0MRkwFwYDVQQDDBBqZW5raW5zdGVzdC5p +# bmZvMR0wGwYJKoZIhvcNAQkBFg50ZXN0QHRlc3QuaW5mbzAeFw0xOTEwMDgxNTI5NTVaFw0xOTEx +# MDcxNTI5NTVaMIGBMQswCQYDVQQGEwJjYTEQMA4GA1UECAwHb250YXJpbzEQMA4GA1UEBwwHdG9y +# b250bzEUMBIGA1UECgwLamVua2luc3Rlc3QxGTAXBgNVBAMMEGplbmtpbnN0ZXN0LmluZm8xHTAb +# BgkqhkiG9w0BCQEWDnRlc3RAdGVzdC5pbmZvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +# AQEA02q352JTHGvROMBhSHvSv+vnoOTDKSTz2aLQn0tYrIRqRo+8bfmMjXuhkwZPSnCpvUGNAJ+w +# Jrt/dqMoYUjCBkjylD/qHmnXN5EwS1cMg1Djh65gi5JJLFJ7eNcoSsr/0AJ+TweIal1jJSP3t3PF +# 9Uv21gm6xdm7HnNK66WpUUXLDTKaIs/jtagVY1bLOo9oEVeLN4nT2CYWztpMvdCyEDUzgEdDbmrP +# F5nKUPK5hrFqo1Dc5rUI4ZshL3Lpv398aMxv6n2adQvuL++URMEbXXBhxOrT6rCtYzbcR5fkwS9i +# d3Br45CoWOQro02JAepoU0MQKY5+xQ4Bq9Q7tB9BAwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAe +# 4xc+mSvKkrKBHg9/zpkWgZUiOp4ENJCi8H4tea/PCM439v6y/kfjT/okOokFvX8N5aa1OSz2Vsrl +# m8kjIc6hiA7bKzT6lb0EyjUShFFZ5jmGVP4S7/hviDvgB5yEQxOPpumkdRP513YnEGj/o9Pazi5h +# /MwpRxxazoda9r45kqQpyG+XoM4pB+Fd3JzMc4FUGxfVPxJU4jLawnJJiZ3vqiSyaB0YyUL+Er1Q +# 6NnqtR4gEBF0ZVlQmkycFvD4EC2boP943dLqNUvop+4R3SM1QMM6P5u8iTXtHd/VN4MwMyy1wtog +# hYAzODo1Jt59pcqqKJEas0C/lFJEB3frw4ImNx5fNlJYOpx+ijfQs9m39CevDq0= + +agent: + # -- Enable Kubernetes plugin jnlp-agent podTemplate + enabled: true + # -- The name of the pod template to use for providing default values + defaultsProviderTemplate: "" + + # Useful for not including a serviceAccount in the template if `false` + # -- Use `serviceAccountAgent.name` as the default value for defaults template `serviceAccount` + useDefaultServiceAccount: true + + # -- Override the default service account + # @default -- `serviceAccountAgent.name` if `agent.useDefaultServiceAccount` is `true` + serviceAccount: + + # For connecting to the Jenkins controller + # -- Overrides the Kubernetes Jenkins URL + jenkinsUrl: + + # connects to the specified host and port, instead of connecting directly to the Jenkins controller + # -- Overrides the Kubernetes Jenkins tunnel + jenkinsTunnel: + # -- Disables the verification of the controller certificate on remote connection. This flag correspond to the "Disable https certificate check" flag in kubernetes plugin UI + skipTlsVerify: false + # -- Enable the possibility to restrict the usage of this agent to specific folder. This flag correspond to the "Restrict pipeline support to authorized folders" flag in kubernetes plugin UI + usageRestricted: false + # -- The connection timeout in seconds for connections to Kubernetes API. The minimum value is 5 + kubernetesConnectTimeout: 5 + # -- The read timeout in seconds for connections to Kubernetes API. The minimum value is 15 + kubernetesReadTimeout: 15 + # -- The maximum concurrent connections to Kubernetes API + maxRequestsPerHostStr: "32" + # -- Time in minutes after which the Kubernetes cloud plugin will clean up an idle worker that has not already terminated + retentionTimeout: 5 + # -- Seconds to wait for pod to be running + waitForPodSec: 600 + # -- Namespace in which the Kubernetes agents should be launched + namespace: + # -- Custom Pod labels (an object with `label-key: label-value` pairs) + podLabels: {} + # -- Custom registry used to pull the agent jnlp image from + jnlpregistry: + image: + # -- Repository to pull the agent jnlp image from + repository: "jenkins/inbound-agent" + # -- Tag of the image to pull + tag: "3261.v9c670a_4748a_9-1" + # -- Configure working directory for default agent + workingDir: "/home/jenkins/agent" + nodeUsageMode: "NORMAL" + # -- Append Jenkins labels to the agent + customJenkinsLabels: [] + # -- Name of the secret to be used to pull the image + imagePullSecretName: + componentName: "jenkins-agent" + # -- Enables agent communication via websockets + websocket: false + directConnection: false + # -- Agent privileged container + privileged: false + # -- Configure container user + runAsUser: + # -- Configure container group + runAsGroup: + # -- Enables the agent to use the host network + hostNetworking: false + # -- Resources allocation (Requests and Limits) + resources: + requests: + cpu: "512m" + memory: "512Mi" + # ephemeralStorage: + limits: + cpu: "512m" + memory: "512Mi" + # ephemeralStorage: + livenessProbe: {} +# execArgs: "cat /tmp/healthy" +# failureThreshold: 3 +# initialDelaySeconds: 0 +# periodSeconds: 10 +# successThreshold: 1 +# timeoutSeconds: 1 + + # You may want to change this to true while testing a new image + # -- Always pull agent container image before build + alwaysPullImage: false + # When using Pod Security Admission in the Agents namespace with the restricted Pod Security Standard, + # the jnlp container cannot be scheduled without overriding its container definition with a securityContext. + # This option allows to automatically inject in the jnlp container a securityContext + # that is suitable for the use of the restricted Pod Security Standard. + # -- Set a restricted securityContext on jnlp containers + restrictedPssSecurityContext: false + # Controls how agent pods are retained after the Jenkins build completes + # Possible values: Always, Never, OnFailure + podRetention: "Never" + # Disable if you do not want the Yaml the agent pod template to show up + # in the job Console Output. This can be helpful for either security reasons + # or simply to clean up the output to make it easier to read. + showRawYaml: true + + # You can define the volumes that you want to mount for this container + # Allowed types are: ConfigMap, EmptyDir, EphemeralVolume, HostPath, Nfs, PVC, Secret + # Configure the attributes as they appear in the corresponding Java class for that type + # https://github.com/jenkinsci/kubernetes-plugin/tree/master/src/main/java/org/csanchez/jenkins/plugins/kubernetes/volumes + # -- Additional volumes + volumes: [] + # - type: ConfigMap + # configMapName: myconfigmap + # mountPath: /var/myapp/myconfigmap + # - type: EmptyDir + # mountPath: /var/myapp/myemptydir + # memory: false + # - type: EphemeralVolume + # mountPath: /var/myapp/myephemeralvolume + # accessModes: ReadWriteOnce + # requestsSize: 10Gi + # storageClassName: mystorageclass + # - type: HostPath + # hostPath: /var/lib/containers + # mountPath: /var/myapp/myhostpath + # - type: Nfs + # mountPath: /var/myapp/mynfs + # readOnly: false + # serverAddress: "192.0.2.0" + # serverPath: /var/lib/containers + # - type: PVC + # claimName: mypvc + # mountPath: /var/myapp/mypvc + # readOnly: false + # - type: Secret + # defaultMode: "600" + # mountPath: /var/myapp/mysecret + # secretName: mysecret + # Pod-wide environment, these vars are visible to any container in the agent pod + + # You can define the workspaceVolume that you want to mount for this container + # Allowed types are: DynamicPVC, EmptyDir, EphemeralVolume, HostPath, Nfs, PVC + # Configure the attributes as they appear in the corresponding Java class for that type + # https://github.com/jenkinsci/kubernetes-plugin/tree/master/src/main/java/org/csanchez/jenkins/plugins/kubernetes/volumes/workspace + # -- Workspace volume (defaults to EmptyDir) + workspaceVolume: {} + ## DynamicPVC example + # - type: DynamicPVC + # configMapName: myconfigmap + ## EmptyDir example + # - type: EmptyDir + # memory: false + ## EphemeralVolume example + # - type: EphemeralVolume + # accessModes: ReadWriteOnce + # requestsSize: 10Gi + # storageClassName: mystorageclass + ## HostPath example + # - type: HostPath + # hostPath: /var/lib/containers + ## NFS example + # - type: Nfs + # readOnly: false + # serverAddress: "192.0.2.0" + # serverPath: /var/lib/containers + ## PVC example + # - type: PVC + # claimName: mypvc + # readOnly: false + + # Pod-wide environment, these vars are visible to any container in the agent pod + # -- Environment variables for the agent Pod + envVars: [] + # - name: PATH + # value: /usr/local/bin + # -- Mount a secret as environment variable + secretEnvVars: [] + # - key: PATH + # optional: false # default: false + # secretKey: MY-K8S-PATH + # secretName: my-k8s-secret + + # -- Node labels for pod assignment + nodeSelector: {} + # Key Value selectors. Ex: + # nodeSelector + # jenkins-agent: v1 + + # -- Command to execute when side container starts + command: + # -- Arguments passed to command to execute + args: "${computer.jnlpmac} ${computer.name}" + # -- Side container name + sideContainerName: "jnlp" + + # Doesn't allocate pseudo TTY by default + # -- Allocate pseudo tty to the side container + TTYEnabled: false + # -- Max number of agents to launch + containerCap: 10 + # -- Agent Pod base name + podName: "default" + + # Enables garbage collection of orphan pods for this Kubernetes cloud. (beta) + garbageCollection: + # -- When enabled, Jenkins will periodically check for orphan pods that have not been touched for the given timeout period and delete them. + enabled: false + # -- Namespaces to look at for garbage collection, in addition to the default namespace defined for the cloud. One namespace per line. + namespaces: "" + # namespaces: |- + # namespaceOne + # namespaceTwo + # -- Timeout value for orphaned pods + timeout: 300 + + # -- Allows the Pod to remain active for reuse until the configured number of minutes has passed since the last step was executed on it + idleMinutes: 0 + + + # The raw yaml of a Pod API Object, for example, this allows usage of toleration for agent pods. + # https://github.com/jenkinsci/kubernetes-plugin#using-yaml-to-define-pod-templates + # https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + # -- The raw yaml of a Pod API Object to merge into the agent spec + yamlTemplate: "" + # yamlTemplate: |- + # apiVersion: v1 + # kind: Pod + # spec: + # tolerations: + # - key: "key" + # operator: "Equal" + # value: "value" + + # -- Defines how the raw yaml field gets merged with yaml definitions from inherited pod templates. Possible values: "merge" or "override" + yamlMergeStrategy: "override" + # -- Controls whether the defined yaml merge strategy will be inherited if another defined pod template is configured to inherit from the current one + inheritYamlMergeStrategy: false + # -- Timeout in seconds for an agent to be online + connectTimeout: 100 + # -- Annotations to apply to the pod + annotations: {} + + # Containers specified here are added to all agents. Set key empty to remove container from additional agents. + # -- Add additional containers to the agents + additionalContainers: [] + # - sideContainerName: dind + # image: + # repository: docker + # tag: dind + # command: dockerd-entrypoint.sh + # args: "" + # privileged: true + # resources: + # requests: + # cpu: 500m + # memory: 1Gi + # limits: + # cpu: 1 + # memory: 2Gi + + # Useful when configuring agents only with the podTemplates value, since the default podTemplate populated by values mentioned above will be excluded in the rendered template. + # -- Disable the default Jenkins Agent configuration + disableDefaultAgent: false + + # Below is the implementation of custom pod templates for the default configured kubernetes cloud. + # Add a key under podTemplates for each pod template. Each key (prior to | character) is just a label, and can be any value. + # Keys are only used to give the pod template a meaningful name. The only restriction is they may only contain RFC 1123 \ DNS label + # characters: lowercase letters, numbers, and hyphens. Each pod template can contain multiple containers. + # For this pod templates configuration to be loaded, the following values must be set: + # controller.JCasC.defaultConfig: true + # Best reference is https:///configuration-as-code/reference#Cloud-kubernetes. The example below creates a python pod template. + # -- Configures extra pod templates for the default kubernetes cloud + podTemplates: {} + # python: | + # - name: python + # label: jenkins-python + # serviceAccount: jenkins + # containers: + # - name: python + # image: python:3 + # command: "/bin/sh -c" + # args: "cat" + # ttyEnabled: true + # privileged: true + # resourceRequestCpu: "400m" + # resourceRequestMemory: "512Mi" + # resourceLimitCpu: "1" + # resourceLimitMemory: "1024Mi" + +# Inherits all values from `agent` so you only need to specify values which differ +# -- Configure additional +additionalAgents: {} +# maven: +# podName: maven +# customJenkinsLabels: maven +# # An example of overriding the jnlp container +# # sideContainerName: jnlp +# image: +# repository: jenkins/jnlp-agent-maven +# tag: latest +# python: +# podName: python +# customJenkinsLabels: python +# sideContainerName: python +# image: +# repository: python +# tag: "3" +# command: "/bin/sh -c" +# args: "cat" +# TTYEnabled: true + +# Here you can add additional clouds +# They inherit all values from the default cloud (including the main agent), so +# you only need to specify values which differ. If you want to override +# default additionalAgents with the additionalClouds.additionalAgents set +# additionalAgentsOverride to `true`. +additionalClouds: {} +# remote-cloud-1: +# kubernetesURL: https://api.remote-cloud.com +# additionalAgentsOverride: true +# additionalAgents: +# maven-2: +# podName: maven-2 +# customJenkinsLabels: maven +# # An example of overriding the jnlp container +# # sideContainerName: jnlp +# image: +# repository: jenkins/jnlp-agent-maven +# tag: latest +# namespace: my-other-maven-namespace +# remote-cloud-2: +# kubernetesURL: https://api.remote-cloud.com + +persistence: + # -- Enable the use of a Jenkins PVC + enabled: true + + # A manually managed Persistent Volume and Claim + # Requires persistence.enabled: true + # If defined, PVC must be created manually before volume will be bound + # -- Provide the name of a PVC + existingClaim: + + # jenkins data Persistent Volume Storage Class + # If defined, storageClassName: + # If set to "-", storageClassName: "", which disables dynamic provisioning + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default provisioner (gp2 on AWS, standard on GKE, AWS & OpenStack) + # -- Storage class for the PVC + storageClass: + # -- Annotations for the PVC + annotations: {} + # -- Labels for the PVC + labels: {} + # -- The PVC access mode + accessMode: "ReadWriteOnce" + # -- The size of the PVC + size: "8Gi" + + # ref: https://kubernetes.io/docs/concepts/storage/volume-pvc-datasource/ + # -- Existing data source to clone PVC from + dataSource: {} + # name: PVC-NAME + # kind: PersistentVolumeClaim + + # -- SubPath for jenkins-home mount + subPath: + # -- Additional volumes + volumes: [] + # - name: nothing + # emptyDir: {} + + # -- Additional mounts + mounts: [] + # - mountPath: /var/nothing + # name: nothing + # readOnly: true + +networkPolicy: + # -- Enable the creation of NetworkPolicy resources + enabled: false + + # For Kubernetes v1.4, v1.5 and v1.6, use 'extensions/v1beta1' + # For Kubernetes v1.7, use 'networking.k8s.io/v1' + # -- NetworkPolicy ApiVersion + apiVersion: networking.k8s.io/v1 + # You can allow agents to connect from both within the cluster (from within specific/all namespaces) AND/OR from a given external IP range + internalAgents: + # -- Allow internal agents (from the same cluster) to connect to controller. Agent pods will be filtered based on PodLabels + allowed: true + # -- A map of labels (keys/values) that agent pods must have to be able to connect to controller + podLabels: {} + # -- A map of labels (keys/values) that agents namespaces must have to be able to connect to controller + namespaceLabels: {} + # project: myproject + externalAgents: + # -- The IP range from which external agents are allowed to connect to controller, i.e., 172.17.0.0/16 + ipCIDR: + # -- A list of IP sub-ranges to be excluded from the allowlisted IP range + except: [] + # - 172.17.1.0/24 + +## Install Default RBAC roles and bindings +rbac: + # -- Whether RBAC resources are created + create: true + # -- Whether the Jenkins service account should be able to read Kubernetes secrets + readSecrets: false + +serviceAccount: + # -- Configures if a ServiceAccount with this name should be created + create: true + + # The name of the ServiceAccount is autogenerated by default + # -- The name of the ServiceAccount to be used by access-controlled resources + name: + # -- Configures annotations for the ServiceAccount + annotations: {} + # -- Configures extra labels for the ServiceAccount + extraLabels: {} + # -- Controller ServiceAccount image pull secret + imagePullSecretName: + + +serviceAccountAgent: + # -- Configures if an agent ServiceAccount should be created + create: false + + # If not set and create is true, a name is generated using the fullname template + # -- The name of the agent ServiceAccount to be used by access-controlled resources + name: + # -- Configures annotations for the agent ServiceAccount + annotations: {} + # -- Configures extra labels for the agent ServiceAccount + extraLabels: {} + # -- Agent ServiceAccount image pull secret + imagePullSecretName: + +# -- Checks if any deprecated values are used +checkDeprecation: true + +awsSecurityGroupPolicies: + enabled: false + policies: + - name: "" + securityGroupIds: [] + podSelector: {} + +# Here you can configure unit tests values when executing the helm unittest in the CONTRIBUTING.md +helmtest: + # A testing framework for bash + bats: + # Bash Automated Testing System (BATS) + image: + # -- Registry of the image used to test the framework + registry: "docker.io" + # -- Repository of the image used to test the framework + repository: "bats/bats" + # -- Tag of the image to test the framework + tag: "1.11.0" diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/.helmignore b/charts/ngrok/kubernetes-ingress-controller/0.14.3/.helmignore new file mode 100644 index 000000000..faa119839 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/.helmignore @@ -0,0 +1,25 @@ +# Source: https://github.com/helm/helm/blob/main/pkg/repo/repotest/testdata/examplechart/.helmignore +# 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 +*~ +# Various IDEs +.project +.idea/ +*.tmproj + +# helmtest plugin tests +tests diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/CHANGELOG.md b/charts/ngrok/kubernetes-ingress-controller/0.14.3/CHANGELOG.md new file mode 100644 index 000000000..dfdf46985 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/CHANGELOG.md @@ -0,0 +1,182 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.14.3 +**Full Changelog**: https://github.com/ngrok/kubernetes-ingress-controller/compare/helm-chart-0.14.2...helm-chart-0.14.3 + +### Changed + +- Update `icon` location in `Chart.yaml`. This is a passive change as we migrate to our helm repository to `charts.ngrok.com`. + + +## 0.14.2 +**Full Changelog**: https://github.com/ngrok/kubernetes-ingress-controller/compare/helm-chart-0.14.1...helm-chart-0.14.2 + +### Added + +- feat: Ability to specify cluster domain [#339](https://github.com/ngrok/kubernetes-ingress-controller/pull/339). Thank you, @fr6nco ! + +### Changed + +- Bump image version from `0.12.1` to `0.12.2` + +## 0.14.1 +**Full Changelog**: https://github.com/ngrok/kubernetes-ingress-controller/compare/helm-chart-0.14.0...helm-chart-0.14.1 + +### Changed + +- Bump image version from `0.12.0` to `0.12.1` + +## 0.14.0 +**Full Changelog**: https://github.com/ngrok/kubernetes-ingress-controller/compare/helm-chart-0.13.0...helm-chart-0.14.0 + +### Added + +- feat: Auto-provision domain for TLS Edges [#386]( https://github.com/ngrok/kubernetes-ingress-controller/pull/386) +- feat: Support for Load Balancer services [#387](https://github.com/ngrok/kubernetes-ingress-controller/pull/387) +- feat: Support TLS termination in modulesets for Load Balancer Services [388](https://github.com/ngrok/kubernetes-ingress-controller/pull/388) + +## 0.13.0 + +**Full Changelog**: https://github.com/ngrok/kubernetes-ingress-controller/compare/helm-chart-0.12.4...helm-chart-0.13.0 + +**Important**: If you are upgrading from a previous version and are using `helm install` or `helm upgrade`, you will need to manually apply the changes to the CRDs. This is because the CRDs are not [updated automatically when the chart is updated](https://helm.sh/docs/chart_best_practices/custom_resource_definitions/#some-caveats-and-explanations). To do this, apply the contents of the `crds` directory in the chart to your cluster. + +Ex (from the root of the repository): +```shell +kubectl apply -f ./helm/ingress-controller/templates/crds/ +``` + +### Added + +- root-cas setting [#371](https://github.com/ngrok/kubernetes-ingress-controller/pull/371) + Takes an install option for `--set rootCAs=host` and plumb the isHostCA check into the caCerts for it to just get the host certs. +- feat: Add support for mutualTLS [#373](https://github.com/ngrok/kubernetes-ingress-controller/pull/373) + +### Changed + +- Update nix flake, go version, and Makefile dep versions [#379](https://github.com/ngrok/kubernetes-ingress-controller/pull/379) + +## 0.12.4 + +- Add the `apiURL` value. + This sets the ngrok API endpoint used by the controller. + It corresponds to the `--api-url` argument to the manager binary. + +- Update to version 0.10.4 of the ingress controller. + See its changes [here](../../CHANGELOG.md#0104). + +## 0.12.1 + +- Update to version 0.10.1 of the ingress controller, which includes: + - IPPolicy controller wasn't applying the attached rules, leaving the IP policy in its current state [#315](https://github.com/ngrok/kubernetes-ingress-controller/pull/315) + +## 0.12.0 + +- Update to version 0.10.0 of the ingress controller, this includes: + - TLSEdge support - see the [TCP and TLS Edges Guide](https://github.com/ngrok/kubernetes-ingress-controller/blob/main/docs/user-guide/tcp-tls-edges.md) for more details. + - A fix for renegotiating TLS backends + +## 0.11.0 + +** Important ** This version of the controller changes the ownership model for https edge and tunnel CRs. To ease out the transition to the new ownership, make sure to run `migrate-edges.sh` and `migrate-tunnels.sh` scripts before installing the new version. + +### Changed +- Specify IPPolicyRule action as an enum of (allow,deny) as part of [#260](https://github.com/ngrok/kubernetes-ingress-controller/pull/260) +- Handle special case for changing auth types that causes an error during state transition [#259](https://github.com/ngrok/kubernetes-ingress-controller/pull/259) +- Better handling when changing pathType between 'Exact' and 'Prefix' [#262](https://github.com/ngrok/kubernetes-ingress-controller/pull/262) +- Update ngrok-go to 1.4.0 [#298](https://github.com/ngrok/kubernetes-ingress-controller/pull/298) +- Tunnels are now unique in their respective namespace, not across the cluster [#281](https://github.com/ngrok/kubernetes-ingress-controller/pull/281) +- The CRs that ingress controller creates are uniquely marked and managed by it. Other CRs created manually are no longer deleted when the ingress controller is not using them [#267](https://github.com/ngrok/kubernetes-ingress-controller/issues/267); fixed for tunnel in [#285](https://github.com/ngrok/kubernetes-ingress-controller/pull/285) and for https edges in [#286](https://github.com/ngrok/kubernetes-ingress-controller/pull/286) +- Better error handling and retry, specifically for the case where we try to create an https edge for a domain which is not created yet [#283](https://github.com/ngrok/kubernetes-ingress-controller/issues/283); fixed in [#288](https://github.com/ngrok/kubernetes-ingress-controller/pull/288) +- Watch and apply ngrok module set CR changes [#287](https://github.com/ngrok/kubernetes-ingress-controller/issues/287); fixed in [#290](https://github.com/ngrok/kubernetes-ingress-controller/pull/290) +- Label https edges and tunnels with service UID to make them more unique within ngrok [#291](https://github.com/ngrok/kubernetes-ingress-controller/issues/291); fixed in [#293](https://github.com/ngrok/kubernetes-ingress-controller/pull/293) and [#302](https://github.com/ngrok/kubernetes-ingress-controller/pull/302) + +### Added +- Add support for configuring pod affinities, pod disruption budget, and priorityClassName [#258](https://github.com/ngrok/kubernetes-ingress-controller/pull/258) +- The controller stopping at the first resource create [#270](https://github.com/ngrok/kubernetes-ingress-controller/pull/270) +- Using `make deploy` now requires `NGROK_AUTHTOKEN` and `NGROK_API_KEY` to be set [#292](https://github.com/ngrok/kubernetes-ingress-controller/pull/292) + +## 0.10.0 + +### Added +- Support HTTPS backends via service annotation [#238](https://github.com/ngrok/kubernetes-ingress-controller/pull/238) + +### Changed +- Normalize all ngrok `.io` TLD to `.app` TLD [#240](https://github.com/ngrok/kubernetes-ingress-controller/pull/240) +- Chart Icon + +### Fixed +- Add namespace to secret [#244](https://github.com/ngrok/kubernetes-ingress-controller/pull/244). Thank you for the contribution, @vincetse! + +## 0.9.0 +### Added +- Add a 'podLabels' option to the helm chart [#212](https://github.com/ngrok/kubernetes-ingress-controller/pull/212). +- Permission to `get`,`list`, and `watch` `services` [#222](https://github.com/ngrok-kubernetes-ingress-controller/pull/222). + +## 0.8.0 +### Changed +- Log Level configuration to helm chart [#199](https://github.com/ngrok/kubernetes-ingress-controller/pull/199). +- Bump default controller image to use `0.6.0` release [#204](https://github.com/ngrok/kubernetes-ingress-controller/pull/204). + +### Fixed +- update default-container annotation so logs work correctly [#197](https://github.com/ngrok/kubernetes-ingress-controller/pull/197) + +## 0.7.0 + +### Added +- Update `NgrokModuleSet` and `HTTPSEdge` CRD to support SAML and OAuth + +### Changed +- Update appVersion to `0.5.0` to match the latest release of the controller. + +## 0.6.1 +### Fixed +- Default the image tag to the chart's `appVersion` for predictable installs. Previously, the helm chart would default to the `latest` image tag which can have breaking changes, notably with CRDs. + +## 0.6.0 +### Changed +- Ingress Class has Default set to false [#109](https://github.com/ngrok/kubernetes-ingress-controller/pull/109) + +### Added +- Allow controller name to be configured to support multiple ngrok ingress classes [#159](https://github.com/ngrok/kubernetes-ingress-controller/pull/159) +- Allow the controller to be configured to only watch a single namespace [#157](https://github.com/ngrok/kubernetes-ingress-controller/pull/157) +- Pass key/value pairs to helm that get added as json string metadata in ngrok api resources [#156](https://github.com/ngrok/kubernetes-ingress-controller/pull/156) +- Add IP Policy CRD and IP Policy Route Module [#120](https://github.com/ngrok/kubernetes-ingress-controller/pull/120) +- Load certs from the directory `"/etc/ssl/certs/ngrok/"` for ngrok-go if present [#111](https://github.com/ngrok/kubernetes-ingress-controller/pull/111) + +## 0.5.0 +### Changed +- Renamed chart from `ngrok-ingress-controller` to `kubernetes-ingress-controller`. +- Added CRDs for `domains`, `tcpedges`, and `httpsedges`. + +## 0.4.0 +### Added +- `serverAddr` flag to override the ngrok tunnel server address +- `extraVolumes` to add an arbitrary set of volumes to the controller pod +- `extraVolumeMounts` to add an arbitrary set of volume mounts to the controller container + +## 0.3.1 +### Fixed +- Fixes rendering of `NOTES.txt` when installing via helm + +## 0.3.0 +### Changed + +- Moved from calling ngrok-agent sidecar to using the ngrok-go library in the controller process. +- Moved `apiKey` and `authtoken` to `credentials.apiKey` and `credentials.authtoken` respectively. +- `credentialSecrets.name` is now `credentials.secret.name` +- Changed replicas to 1 by default to work better for default/demo setup. + +## 0.2.0 +### Added + +- Support for different values commonly found in helm charts + +# 0.1.0 + +TODO diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/Chart.lock b/charts/ngrok/kubernetes-ingress-controller/0.14.3/Chart.lock new file mode 100644 index 000000000..fc5340d2b --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common + repository: https://charts.bitnami.com/bitnami + version: 2.22.0 +digest: sha256:3c3a2f2c075dd8282147f1a611979a67dd40ce82a27698e16b3315eb9a94d059 +generated: "2024-08-09T14:49:27.42058351-05:00" diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/Chart.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/Chart.yaml new file mode 100644 index 000000000..2d4828f41 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/Chart.yaml @@ -0,0 +1,25 @@ +annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: ngrok Ingress Controller + catalog.cattle.io/release-name: kubernetes-ingress-controller +apiVersion: v2 +appVersion: 0.12.2 +dependencies: +- name: common + repository: file://./charts/common + tags: + - bitnami-common + version: 2.x.x +description: A Kubernetes ingress controller built using ngrok. +home: https://ngrok.com +icon: file://assets/icons/kubernetes-ingress-controller.svg +keywords: +- ngrok +- networking +- ingress +- edge +- api gateway +name: kubernetes-ingress-controller +sources: +- https://github.com/ngrok/kubernetes-ingress-controller +version: 0.14.3 diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/README.md b/charts/ngrok/kubernetes-ingress-controller/0.14.3/README.md new file mode 100644 index 000000000..fe5d39160 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/README.md @@ -0,0 +1,94 @@ +# ngrok Ingress Controller + +This is the helm chart to install the ngrok ingress controller + +# Usage + +## Prerequisites + +The cluster Must be setup with a secret named `ngrok-ingress-controller-credentials` with the following keys: +* AUTHTOKEN +* API\_KEY + +## Install the controller with helm + +[Helm](https://helm.sh) must be installed to use the charts. Please refer to +Helm's [documentation](https://helm.sh/docs) to get started. + +Once Helm has been set up correctly, add the repo as follows: + +`helm repo add ngrok https://charts.ngrok.com` + +If you had already added this repo earlier, run `helm repo update` to retrieve +the latest versions of the packages. You can then run `helm search repo ngrok` to see the charts. + +To install the ngrok-ingress-controller chart: + +`helm install my-ngrok-ingress-controller ngrok/kubernetes-ingress-controller` + +To uninstall the chart: + +`helm delete my-ngrok-ingress-controller` + + +## Parameters + +### Common parameters + +| Name | Description | Value | +| ------------------- | ----------------------------------------------------- | ----- | +| `nameOverride` | String to partially override generated resource names | `""` | +| `fullnameOverride` | String to fully override generated resource names | `""` | +| `commonLabels` | Labels to add to all deployed objects | `{}` | +| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | + + +### Controller parameters + +| Name | Description | Value | +| ------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | +| `podAnnotations` | Used to apply custom annotations to the ingress pods. | `{}` | +| `podLabels` | Used to apply custom labels to the ingress pods. | `{}` | +| `replicaCount` | The number of controllers to run. | `1` | +| `image.registry` | The ngrok ingress controller image registry. | `docker.io` | +| `image.repository` | The ngrok ingress controller image repository. | `ngrok/kubernetes-ingress-controller` | +| `image.tag` | The ngrok ingress controller image tag. Defaults to the chart's appVersion if not specified | `""` | +| `image.pullPolicy` | The ngrok ingress controller image pull policy. | `IfNotPresent` | +| `image.pullSecrets` | An array of imagePullSecrets to be used when pulling the image. | `[]` | +| `ingressClass.name` | The name of the ingress class to use. | `ngrok` | +| `ingressClass.create` | Whether to create the ingress class. | `true` | +| `ingressClass.default` | Whether to set the ingress class as default. | `false` | +| `controllerName` | The name of the controller to look for matching ingress classes | `k8s.ngrok.com/ingress-controller` | +| `watchNamespace` | The namespace to watch for ingress resources. Defaults to all | `""` | +| `credentials.secret.name` | The name of the secret the credentials are in. If not provided, one will be generated using the helm release name. | `""` | +| `credentials.apiKey` | Your ngrok API key. If provided, it will be will be written to the secret and the authtoken must be provided as well. | `""` | +| `credentials.authtoken` | Your ngrok authtoken. If provided, it will be will be written to the secret and the apiKey must be provided as well. | `""` | +| `region` | ngrok region to create tunnels in. Defaults to connect to the closest geographical region. | `""` | +| `rootCAs` | Set to "trusted" for the ngrok agent CA or "host" to trust the host's CA. Defaults to "trusted". | `""` | +| `serverAddr` | This is the address of the ngrok server to connect to. You should set this if you are using a custom ingress address. | `""` | +| `clusterDomain` | Injects the cluster domain name for service discovery. | `svc.cluster.local` | +| `apiURL` | This is the URL of the ngrok API. You should set this if you are using a custom API URL. | `""` | +| `metaData` | This is a map of key/value pairs that will be added as meta data to all ngrok api resources created | `{}` | +| `affinity` | Affinity for the controller pod assignment | `{}` | +| `podAffinityPreset` | Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `nodeAffinityPreset.type` | Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `nodeAffinityPreset.key` | Node label key to match. Ignored if `affinity` is set. | `""` | +| `nodeAffinityPreset.values` | Node label values to match. Ignored if `affinity` is set. | `[]` | +| `priorityClassName` | Priority class for pod scheduling | `""` | +| `podDisruptionBudget.create` | Enable a Pod Disruption Budget creation | `false` | +| `podDisruptionBudget.minAvailable` | Minimum number/percentage of pods that should remain scheduled | `""` | +| `podDisruptionBudget.maxUnavailable` | Maximum number/percentage of pods that may be made unavailable | `1` | +| `resources.limits` | The resources limits for the container | `{}` | +| `resources.requests` | The requested resources for the container | `{}` | +| `extraVolumes` | An array of extra volumes to add to the controller. | `[]` | +| `extraVolumeMounts` | An array of extra volume mounts to add to the controller. | `[]` | +| `extraEnv` | an object of extra environment variables to add to the controller. | `{}` | +| `serviceAccount.create` | Specifies whether a ServiceAccount should be created | `true` | +| `serviceAccount.name` | The name of the ServiceAccount to use. | `""` | +| `serviceAccount.annotations` | Additional annotations to add to the ServiceAccount | `{}` | +| `log.level` | The level to log at. One of 'debug', 'info', or 'error'. | `info` | +| `log.stacktraceLevel` | The level to report stacktrace logs one of 'info' or 'error'. | `error` | +| `log.format` | The log format to use. One of console, json. | `json` | +| `lifecycle` | an object containing lifecycle configuration | `{}` | + diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/.helmignore b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/.helmignore new file mode 100644 index 000000000..d0e10845d --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/.helmignore @@ -0,0 +1,26 @@ +# 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 +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ +# img folder +img/ +# Changelog +CHANGELOG.md diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/Chart.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/Chart.yaml new file mode 100644 index 000000000..0c8fdb526 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/Chart.yaml @@ -0,0 +1,23 @@ +annotations: + category: Infrastructure + licenses: Apache-2.0 +apiVersion: v2 +appVersion: 2.22.0 +description: A Library Helm Chart for grouping common logic between bitnami charts. + This chart is not deployable by itself. +home: https://bitnami.com +icon: https://bitnami.com/downloads/logos/bitnami-mark.png +keywords: +- common +- helper +- template +- function +- bitnami +maintainers: +- name: Broadcom, Inc. All Rights Reserved. + url: https://github.com/bitnami/charts +name: common +sources: +- https://github.com/bitnami/charts/tree/main/bitnami/common +type: library +version: 2.22.0 diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/README.md b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/README.md new file mode 100644 index 000000000..fee26c991 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/README.md @@ -0,0 +1,235 @@ +# Bitnami Common Library Chart + +A [Helm Library Chart](https://helm.sh/docs/topics/library_charts/#helm) for grouping common logic between Bitnami charts. + +## TL;DR + +```yaml +dependencies: + - name: common + version: 2.x.x + repository: oci://registry-1.docker.io/bitnamicharts +``` + +```console +helm dependency update +``` + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "common.names.fullname" . }} +data: + myvalue: "Hello World" +``` + +Looking to use our applications in production? Try [VMware Tanzu Application Catalog](https://bitnami.com/enterprise), the commercial edition of the Bitnami catalog. + +## Introduction + +This chart provides a common template helpers which can be used to develop new charts using [Helm](https://helm.sh) package manager. + +Bitnami charts can be used with [Kubeapps](https://kubeapps.dev/) for deployment and management of Helm Charts in clusters. + +## Prerequisites + +- Kubernetes 1.23+ +- Helm 3.8.0+ + +## Parameters + +## Special input schemas + +### ImageRoot + +```yaml +registry: + type: string + description: Docker registry where the image is located + example: docker.io + +repository: + type: string + description: Repository and image name + example: bitnami/nginx + +tag: + type: string + description: image tag + example: 1.16.1-debian-10-r63 + +pullPolicy: + type: string + description: Specify a imagePullPolicy. Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + +pullSecrets: + type: array + items: + type: string + description: Optionally specify an array of imagePullSecrets (evaluated as templates). + +debug: + type: boolean + description: Set to true if you would like to see extra information on logs + example: false + +## An instance would be: +# registry: docker.io +# repository: bitnami/nginx +# tag: 1.16.1-debian-10-r63 +# pullPolicy: IfNotPresent +# debug: false +``` + +### Persistence + +```yaml +enabled: + type: boolean + description: Whether enable persistence. + example: true + +storageClass: + type: string + description: Ghost data Persistent Volume Storage Class, If set to "-", storageClassName: "" which disables dynamic provisioning. + example: "-" + +accessMode: + type: string + description: Access mode for the Persistent Volume Storage. + example: ReadWriteOnce + +size: + type: string + description: Size the Persistent Volume Storage. + example: 8Gi + +path: + type: string + description: Path to be persisted. + example: /bitnami + +## An instance would be: +# enabled: true +# storageClass: "-" +# accessMode: ReadWriteOnce +# size: 8Gi +# path: /bitnami +``` + +### ExistingSecret + +```yaml +name: + type: string + description: Name of the existing secret. + example: mySecret +keyMapping: + description: Mapping between the expected key name and the name of the key in the existing secret. + type: object + +## An instance would be: +# name: mySecret +# keyMapping: +# password: myPasswordKey +``` + +#### Example of use + +When we store sensitive data for a deployment in a secret, some times we want to give to users the possibility of using theirs existing secrets. + +```yaml +# templates/secret.yaml +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "common.names.fullname" . }} + labels: + app: {{ include "common.names.fullname" . }} +type: Opaque +data: + password: {{ .Values.password | b64enc | quote }} + +# templates/dpl.yaml +--- +... + env: + - name: PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "common.secrets.name" (dict "existingSecret" .Values.existingSecret "context" $) }} + key: {{ include "common.secrets.key" (dict "existingSecret" .Values.existingSecret "key" "password") }} +... + +# values.yaml +--- +name: mySecret +keyMapping: + password: myPasswordKey +``` + +### ValidateValue + +#### NOTES.txt + +```console +{{- $validateValueConf00 := (dict "valueKey" "path.to.value00" "secret" "secretName" "field" "password-00") -}} +{{- $validateValueConf01 := (dict "valueKey" "path.to.value01" "secret" "secretName" "field" "password-01") -}} + +{{ include "common.validations.values.multiple.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }} +``` + +If we force those values to be empty we will see some alerts + +```console +helm install test mychart --set path.to.value00="",path.to.value01="" + 'path.to.value00' must not be empty, please add '--set path.to.value00=$PASSWORD_00' to the command. To get the current value: + + export PASSWORD_00=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-00}" | base64 -d) + + 'path.to.value01' must not be empty, please add '--set path.to.value01=$PASSWORD_01' to the command. To get the current value: + + export PASSWORD_01=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-01}" | base64 -d) +``` + +## Upgrading + +### To 1.0.0 + +[On November 13, 2020, Helm v2 support was formally finished](https://github.com/helm/charts#status-of-the-project), this major version is the result of the required changes applied to the Helm Chart to be able to incorporate the different features added in Helm v3 and to be consistent with the Helm project itself regarding the Helm v2 EOL. + +#### What changes were introduced in this major version? + +- Previous versions of this Helm Chart use `apiVersion: v1` (installable by both Helm 2 and 3), this Helm Chart was updated to `apiVersion: v2` (installable by Helm 3 only). [Here](https://helm.sh/docs/topics/charts/#the-apiversion-field) you can find more information about the `apiVersion` field. +- Use `type: library`. [Here](https://v3.helm.sh/docs/faq/#library-chart-support) you can find more information. +- The different fields present in the *Chart.yaml* file has been ordered alphabetically in a homogeneous way for all the Bitnami Helm Charts + +#### Considerations when upgrading to this version + +- If you want to upgrade to this version from a previous one installed with Helm v3, you shouldn't face any issues +- If you want to upgrade to this version using Helm v2, this scenario is not supported as this version doesn't support Helm v2 anymore +- If you installed the previous version with Helm v2 and wants to upgrade to this version with Helm v3, please refer to the [official Helm documentation](https://helm.sh/docs/topics/v2_v3_migration/#migration-use-cases) about migrating from Helm v2 to v3 + +#### Useful links + +- +- +- + +## License + +Copyright © 2024 Broadcom. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_affinities.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_affinities.tpl new file mode 100644 index 000000000..c2d290792 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_affinities.tpl @@ -0,0 +1,139 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} + +{{/* +Return a soft nodeAffinity definition +{{ include "common.affinities.nodes.soft" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes.soft" -}} +preferredDuringSchedulingIgnoredDuringExecution: + - preference: + matchExpressions: + - key: {{ .key }} + operator: In + values: + {{- range .values }} + - {{ . | quote }} + {{- end }} + weight: 1 +{{- end -}} + +{{/* +Return a hard nodeAffinity definition +{{ include "common.affinities.nodes.hard" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes.hard" -}} +requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: {{ .key }} + operator: In + values: + {{- range .values }} + - {{ . | quote }} + {{- end }} +{{- end -}} + +{{/* +Return a nodeAffinity definition +{{ include "common.affinities.nodes" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes" -}} + {{- if eq .type "soft" }} + {{- include "common.affinities.nodes.soft" . -}} + {{- else if eq .type "hard" }} + {{- include "common.affinities.nodes.hard" . -}} + {{- end -}} +{{- end -}} + +{{/* +Return a topologyKey definition +{{ include "common.affinities.topologyKey" (dict "topologyKey" "BAR") -}} +*/}} +{{- define "common.affinities.topologyKey" -}} +{{ .topologyKey | default "kubernetes.io/hostname" -}} +{{- end -}} + +{{/* +Return a soft podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods.soft" (dict "component" "FOO" "customLabels" .Values.podLabels "extraMatchLabels" .Values.extraMatchLabels "topologyKey" "BAR" "extraPodAffinityTerms" .Values.extraPodAffinityTerms "context" $) -}} +*/}} +{{- define "common.affinities.pods.soft" -}} +{{- $component := default "" .component -}} +{{- $customLabels := default (dict) .customLabels -}} +{{- $extraMatchLabels := default (dict) .extraMatchLabels -}} +{{- $extraPodAffinityTerms := default (list) .extraPodAffinityTerms -}} +preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" ( dict "customLabels" $customLabels "context" .context )) | nindent 10 }} + {{- if not (empty $component) }} + {{ printf "app.kubernetes.io/component: %s" $component }} + {{- end }} + {{- range $key, $value := $extraMatchLabels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} + weight: 1 + {{- range $extraPodAffinityTerms }} + - podAffinityTerm: + labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" ( dict "customLabels" $customLabels "context" $.context )) | nindent 10 }} + {{- if not (empty $component) }} + {{ printf "app.kubernetes.io/component: %s" $component }} + {{- end }} + {{- range $key, $value := .extraMatchLabels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} + weight: {{ .weight | default 1 -}} + {{- end -}} +{{- end -}} + +{{/* +Return a hard podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods.hard" (dict "component" "FOO" "customLabels" .Values.podLabels "extraMatchLabels" .Values.extraMatchLabels "topologyKey" "BAR" "extraPodAffinityTerms" .Values.extraPodAffinityTerms "context" $) -}} +*/}} +{{- define "common.affinities.pods.hard" -}} +{{- $component := default "" .component -}} +{{- $customLabels := default (dict) .customLabels -}} +{{- $extraMatchLabels := default (dict) .extraMatchLabels -}} +{{- $extraPodAffinityTerms := default (list) .extraPodAffinityTerms -}} +requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" ( dict "customLabels" $customLabels "context" .context )) | nindent 8 }} + {{- if not (empty $component) }} + {{ printf "app.kubernetes.io/component: %s" $component }} + {{- end }} + {{- range $key, $value := $extraMatchLabels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} + {{- range $extraPodAffinityTerms }} + - labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" ( dict "customLabels" $customLabels "context" $.context )) | nindent 8 }} + {{- if not (empty $component) }} + {{ printf "app.kubernetes.io/component: %s" $component }} + {{- end }} + {{- range $key, $value := .extraMatchLabels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} + {{- end -}} +{{- end -}} + +{{/* +Return a podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.pods" -}} + {{- if eq .type "soft" }} + {{- include "common.affinities.pods.soft" . -}} + {{- else if eq .type "hard" }} + {{- include "common.affinities.pods.hard" . -}} + {{- end -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_capabilities.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_capabilities.tpl new file mode 100644 index 000000000..2fe81d32d --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_capabilities.tpl @@ -0,0 +1,229 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} + +{{/* +Return the target Kubernetes version +*/}} +{{- define "common.capabilities.kubeVersion" -}} +{{- default (default .Capabilities.KubeVersion.Version .Values.kubeVersion) ((.Values.global).kubeVersion) -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for poddisruptionbudget. +*/}} +{{- define "common.capabilities.policy.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.21-0" $kubeVersion) -}} +{{- print "policy/v1beta1" -}} +{{- else -}} +{{- print "policy/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for networkpolicy. +*/}} +{{- define "common.capabilities.networkPolicy.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.7-0" $kubeVersion) -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "networking.k8s.io/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for cronjob. +*/}} +{{- define "common.capabilities.cronjob.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.21-0" $kubeVersion) -}} +{{- print "batch/v1beta1" -}} +{{- else -}} +{{- print "batch/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for daemonset. +*/}} +{{- define "common.capabilities.daemonset.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for deployment. +*/}} +{{- define "common.capabilities.deployment.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for statefulset. +*/}} +{{- define "common.capabilities.statefulset.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} +{{- print "apps/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for ingress. +*/}} +{{- define "common.capabilities.ingress.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if (.Values.ingress).apiVersion -}} +{{- .Values.ingress.apiVersion -}} +{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} +{{- print "extensions/v1beta1" -}} +{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.19-0" $kubeVersion) -}} +{{- print "networking.k8s.io/v1beta1" -}} +{{- else -}} +{{- print "networking.k8s.io/v1" -}} +{{- end }} +{{- end -}} + +{{/* +Return the appropriate apiVersion for RBAC resources. +*/}} +{{- define "common.capabilities.rbac.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.17-0" $kubeVersion) -}} +{{- print "rbac.authorization.k8s.io/v1beta1" -}} +{{- else -}} +{{- print "rbac.authorization.k8s.io/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for CRDs. +*/}} +{{- define "common.capabilities.crd.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.19-0" $kubeVersion) -}} +{{- print "apiextensions.k8s.io/v1beta1" -}} +{{- else -}} +{{- print "apiextensions.k8s.io/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for APIService. +*/}} +{{- define "common.capabilities.apiService.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.10-0" $kubeVersion) -}} +{{- print "apiregistration.k8s.io/v1beta1" -}} +{{- else -}} +{{- print "apiregistration.k8s.io/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for Horizontal Pod Autoscaler. +*/}} +{{- define "common.capabilities.hpa.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" .context -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.23-0" $kubeVersion) -}} +{{- if .beta2 -}} +{{- print "autoscaling/v2beta2" -}} +{{- else -}} +{{- print "autoscaling/v2beta1" -}} +{{- end -}} +{{- else -}} +{{- print "autoscaling/v2" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for Vertical Pod Autoscaler. +*/}} +{{- define "common.capabilities.vpa.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" .context -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.23-0" $kubeVersion) -}} +{{- if .beta2 -}} +{{- print "autoscaling/v2beta2" -}} +{{- else -}} +{{- print "autoscaling/v2beta1" -}} +{{- end -}} +{{- else -}} +{{- print "autoscaling/v2" -}} +{{- end -}} +{{- end -}} + +{{/* +Returns true if PodSecurityPolicy is supported +*/}} +{{- define "common.capabilities.psp.supported" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if or (empty $kubeVersion) (semverCompare "<1.25-0" $kubeVersion) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Returns true if AdmissionConfiguration is supported +*/}} +{{- define "common.capabilities.admissionConfiguration.supported" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if or (empty $kubeVersion) (not (semverCompare "<1.23-0" $kubeVersion)) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for AdmissionConfiguration. +*/}} +{{- define "common.capabilities.admissionConfiguration.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.23-0" $kubeVersion) -}} +{{- print "apiserver.config.k8s.io/v1alpha1" -}} +{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.25-0" $kubeVersion) -}} +{{- print "apiserver.config.k8s.io/v1beta1" -}} +{{- else -}} +{{- print "apiserver.config.k8s.io/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for PodSecurityConfiguration. +*/}} +{{- define "common.capabilities.podSecurityConfiguration.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.23-0" $kubeVersion) -}} +{{- print "pod-security.admission.config.k8s.io/v1alpha1" -}} +{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.25-0" $kubeVersion) -}} +{{- print "pod-security.admission.config.k8s.io/v1beta1" -}} +{{- else -}} +{{- print "pod-security.admission.config.k8s.io/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Returns true if the used Helm version is 3.3+. +A way to check the used Helm version was not introduced until version 3.3.0 with .Capabilities.HelmVersion, which contains an additional "{}}" structure. +This check is introduced as a regexMatch instead of {{ if .Capabilities.HelmVersion }} because checking for the key HelmVersion in <3.3 results in a "interface not found" error. +**To be removed when the catalog's minimun Helm version is 3.3** +*/}} +{{- define "common.capabilities.supportsHelmVersion" -}} +{{- if regexMatch "{(v[0-9])*[^}]*}}$" (.Capabilities | toString ) }} + {{- true -}} +{{- end -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_compatibility.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_compatibility.tpl new file mode 100644 index 000000000..eb4061d7d --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_compatibility.tpl @@ -0,0 +1,42 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} + +{{/* +Return true if the detected platform is Openshift +Usage: +{{- include "common.compatibility.isOpenshift" . -}} +*/}} +{{- define "common.compatibility.isOpenshift" -}} +{{- if .Capabilities.APIVersions.Has "security.openshift.io/v1" -}} +{{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Render a compatible securityContext depending on the platform. By default it is maintained as it is. In other platforms like Openshift we remove default user/group values that do not work out of the box with the restricted-v1 SCC +Usage: +{{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.containerSecurityContext "context" $) -}} +*/}} +{{- define "common.compatibility.renderSecurityContext" -}} +{{- $adaptedContext := .secContext -}} + +{{- if (((.context.Values.global).compatibility).openshift) -}} + {{- if or (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "force") (and (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "auto") (include "common.compatibility.isOpenshift" .context)) -}} + {{/* Remove incompatible user/group values that do not work in Openshift out of the box */}} + {{- $adaptedContext = omit $adaptedContext "fsGroup" "runAsUser" "runAsGroup" -}} + {{- if not .secContext.seLinuxOptions -}} + {{/* If it is an empty object, we remove it from the resulting context because it causes validation issues */}} + {{- $adaptedContext = omit $adaptedContext "seLinuxOptions" -}} + {{- end -}} + {{- end -}} +{{- end -}} +{{/* Remove fields that are disregarded when running the container in privileged mode */}} +{{- if $adaptedContext.privileged -}} + {{- $adaptedContext = omit $adaptedContext "capabilities" "seLinuxOptions" -}} +{{- end -}} +{{- omit $adaptedContext "enabled" | toYaml -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_errors.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_errors.tpl new file mode 100644 index 000000000..e96536519 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_errors.tpl @@ -0,0 +1,28 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Through error when upgrading using empty passwords values that must not be empty. + +Usage: +{{- $validationError00 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password00" "secret" "secretName" "field" "password-00") -}} +{{- $validationError01 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password01" "secret" "secretName" "field" "password-01") -}} +{{ include "common.errors.upgrade.passwords.empty" (dict "validationErrors" (list $validationError00 $validationError01) "context" $) }} + +Required password params: + - validationErrors - String - Required. List of validation strings to be return, if it is empty it won't throw error. + - context - Context - Required. Parent context. +*/}} +{{- define "common.errors.upgrade.passwords.empty" -}} + {{- $validationErrors := join "" .validationErrors -}} + {{- if and $validationErrors .context.Release.IsUpgrade -}} + {{- $errorString := "\nPASSWORDS ERROR: You must provide your current passwords when upgrading the release." -}} + {{- $errorString = print $errorString "\n Note that even after reinstallation, old credentials may be needed as they may be kept in persistent volume claims." -}} + {{- $errorString = print $errorString "\n Further information can be obtained at https://docs.bitnami.com/general/how-to/troubleshoot-helm-chart-issues/#credential-errors-while-upgrading-chart-releases" -}} + {{- $errorString = print $errorString "\n%s" -}} + {{- printf $errorString $validationErrors | fail -}} + {{- end -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_images.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_images.tpl new file mode 100644 index 000000000..76bb7ce44 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_images.tpl @@ -0,0 +1,115 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Return the proper image name. +If image tag and digest are not defined, termination fallbacks to chart appVersion. +{{ include "common.images.image" ( dict "imageRoot" .Values.path.to.the.image "global" .Values.global "chart" .Chart ) }} +*/}} +{{- define "common.images.image" -}} +{{- $registryName := default .imageRoot.registry ((.global).imageRegistry) -}} +{{- $repositoryName := .imageRoot.repository -}} +{{- $separator := ":" -}} +{{- $termination := .imageRoot.tag | toString -}} + +{{- if not .imageRoot.tag }} + {{- if .chart }} + {{- $termination = .chart.AppVersion | toString -}} + {{- end -}} +{{- end -}} +{{- if .imageRoot.digest }} + {{- $separator = "@" -}} + {{- $termination = .imageRoot.digest | toString -}} +{{- end -}} +{{- if $registryName }} + {{- printf "%s/%s%s%s" $registryName $repositoryName $separator $termination -}} +{{- else -}} + {{- printf "%s%s%s" $repositoryName $separator $termination -}} +{{- end -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names (deprecated: use common.images.renderPullSecrets instead) +{{ include "common.images.pullSecrets" ( dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "global" .Values.global) }} +*/}} +{{- define "common.images.pullSecrets" -}} + {{- $pullSecrets := list }} + + {{- range ((.global).imagePullSecrets) -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets .name -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets . -}} + {{- end }} + {{- end -}} + + {{- range .images -}} + {{- range .pullSecrets -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets .name -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets . -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- if (not (empty $pullSecrets)) -}} +imagePullSecrets: + {{- range $pullSecrets | uniq }} + - name: {{ . }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names evaluating values as templates +{{ include "common.images.renderPullSecrets" ( dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "context" $) }} +*/}} +{{- define "common.images.renderPullSecrets" -}} + {{- $pullSecrets := list }} + {{- $context := .context }} + + {{- range (($context.Values.global).imagePullSecrets) -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" $context)) -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" $context)) -}} + {{- end -}} + {{- end -}} + + {{- range .images -}} + {{- range .pullSecrets -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" $context)) -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" $context)) -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- if (not (empty $pullSecrets)) -}} +imagePullSecrets: + {{- range $pullSecrets | uniq }} + - name: {{ . }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Return the proper image version (ingores image revision/prerelease info & fallbacks to chart appVersion) +{{ include "common.images.version" ( dict "imageRoot" .Values.path.to.the.image "chart" .Chart ) }} +*/}} +{{- define "common.images.version" -}} +{{- $imageTag := .imageRoot.tag | toString -}} +{{/* regexp from https://github.com/Masterminds/semver/blob/23f51de38a0866c5ef0bfc42b3f735c73107b700/version.go#L41-L44 */}} +{{- if regexMatch `^([0-9]+)(\.[0-9]+)?(\.[0-9]+)?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?$` $imageTag -}} + {{- $version := semver $imageTag -}} + {{- printf "%d.%d.%d" $version.Major $version.Minor $version.Patch -}} +{{- else -}} + {{- print .chart.AppVersion -}} +{{- end -}} +{{- end -}} + diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_ingress.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_ingress.tpl new file mode 100644 index 000000000..7d2b87985 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_ingress.tpl @@ -0,0 +1,73 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} + +{{/* +Generate backend entry that is compatible with all Kubernetes API versions. + +Usage: +{{ include "common.ingress.backend" (dict "serviceName" "backendName" "servicePort" "backendPort" "context" $) }} + +Params: + - serviceName - String. Name of an existing service backend + - servicePort - String/Int. Port name (or number) of the service. It will be translated to different yaml depending if it is a string or an integer. + - context - Dict - Required. The context for the template evaluation. +*/}} +{{- define "common.ingress.backend" -}} +{{- $apiVersion := (include "common.capabilities.ingress.apiVersion" .context) -}} +{{- if or (eq $apiVersion "extensions/v1beta1") (eq $apiVersion "networking.k8s.io/v1beta1") -}} +serviceName: {{ .serviceName }} +servicePort: {{ .servicePort }} +{{- else -}} +service: + name: {{ .serviceName }} + port: + {{- if typeIs "string" .servicePort }} + name: {{ .servicePort }} + {{- else if or (typeIs "int" .servicePort) (typeIs "float64" .servicePort) }} + number: {{ .servicePort | int }} + {{- end }} +{{- end -}} +{{- end -}} + +{{/* +Print "true" if the API pathType field is supported +Usage: +{{ include "common.ingress.supportsPathType" . }} +*/}} +{{- define "common.ingress.supportsPathType" -}} +{{- if (semverCompare "<1.18-0" (include "common.capabilities.kubeVersion" .)) -}} +{{- print "false" -}} +{{- else -}} +{{- print "true" -}} +{{- end -}} +{{- end -}} + +{{/* +Returns true if the ingressClassname field is supported +Usage: +{{ include "common.ingress.supportsIngressClassname" . }} +*/}} +{{- define "common.ingress.supportsIngressClassname" -}} +{{- if semverCompare "<1.18-0" (include "common.capabilities.kubeVersion" .) -}} +{{- print "false" -}} +{{- else -}} +{{- print "true" -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if cert-manager required annotations for TLS signed +certificates are set in the Ingress annotations +Ref: https://cert-manager.io/docs/usage/ingress/#supported-annotations +Usage: +{{ include "common.ingress.certManagerRequest" ( dict "annotations" .Values.path.to.the.ingress.annotations ) }} +*/}} +{{- define "common.ingress.certManagerRequest" -}} +{{ if or (hasKey .annotations "cert-manager.io/cluster-issuer") (hasKey .annotations "cert-manager.io/issuer") (hasKey .annotations "kubernetes.io/tls-acme") }} + {{- true -}} +{{- end -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_labels.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_labels.tpl new file mode 100644 index 000000000..0a0cc5488 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_labels.tpl @@ -0,0 +1,46 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} + +{{/* +Kubernetes standard labels +{{ include "common.labels.standard" (dict "customLabels" .Values.commonLabels "context" $) -}} +*/}} +{{- define "common.labels.standard" -}} +{{- if and (hasKey . "customLabels") (hasKey . "context") -}} +{{- $default := dict "app.kubernetes.io/name" (include "common.names.name" .context) "helm.sh/chart" (include "common.names.chart" .context) "app.kubernetes.io/instance" .context.Release.Name "app.kubernetes.io/managed-by" .context.Release.Service -}} +{{- with .context.Chart.AppVersion -}} +{{- $_ := set $default "app.kubernetes.io/version" . -}} +{{- end -}} +{{ template "common.tplvalues.merge" (dict "values" (list .customLabels $default) "context" .context) }} +{{- else -}} +app.kubernetes.io/name: {{ include "common.names.name" . }} +helm.sh/chart: {{ include "common.names.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- with .Chart.AppVersion }} +app.kubernetes.io/version: {{ . | quote }} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Labels used on immutable fields such as deploy.spec.selector.matchLabels or svc.spec.selector +{{ include "common.labels.matchLabels" (dict "customLabels" .Values.podLabels "context" $) -}} + +We don't want to loop over custom labels appending them to the selector +since it's very likely that it will break deployments, services, etc. +However, it's important to overwrite the standard labels if the user +overwrote them on metadata.labels fields. +*/}} +{{- define "common.labels.matchLabels" -}} +{{- if and (hasKey . "customLabels") (hasKey . "context") -}} +{{ merge (pick (include "common.tplvalues.render" (dict "value" .customLabels "context" .context) | fromYaml) "app.kubernetes.io/name" "app.kubernetes.io/instance") (dict "app.kubernetes.io/name" (include "common.names.name" .context) "app.kubernetes.io/instance" .context.Release.Name ) | toYaml }} +{{- else -}} +app.kubernetes.io/name: {{ include "common.names.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_names.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_names.tpl new file mode 100644 index 000000000..ba8395685 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_names.tpl @@ -0,0 +1,71 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "common.names.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "common.names.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "common.names.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create a default fully qualified dependency name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +Usage: +{{ include "common.names.dependency.fullname" (dict "chartName" "dependency-chart-name" "chartValues" .Values.dependency-chart "context" $) }} +*/}} +{{- define "common.names.dependency.fullname" -}} +{{- if .chartValues.fullnameOverride -}} +{{- .chartValues.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .chartName .chartValues.nameOverride -}} +{{- if contains $name .context.Release.Name -}} +{{- .context.Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .context.Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts. +*/}} +{{- define "common.names.namespace" -}} +{{- default .Release.Namespace .Values.namespaceOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a fully qualified app name adding the installation's namespace. +*/}} +{{- define "common.names.fullname.namespace" -}} +{{- printf "%s-%s" (include "common.names.fullname" .) (include "common.names.namespace" .) | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_resources.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_resources.tpl new file mode 100644 index 000000000..d8a43e1c2 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_resources.tpl @@ -0,0 +1,50 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} + +{{/* +Return a resource request/limit object based on a given preset. +These presets are for basic testing and not meant to be used in production +{{ include "common.resources.preset" (dict "type" "nano") -}} +*/}} +{{- define "common.resources.preset" -}} +{{/* The limits are the requests increased by 50% (except ephemeral-storage and xlarge/2xlarge sizes)*/}} +{{- $presets := dict + "nano" (dict + "requests" (dict "cpu" "100m" "memory" "128Mi" "ephemeral-storage" "50Mi") + "limits" (dict "cpu" "150m" "memory" "192Mi" "ephemeral-storage" "2Gi") + ) + "micro" (dict + "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") + "limits" (dict "cpu" "375m" "memory" "384Mi" "ephemeral-storage" "2Gi") + ) + "small" (dict + "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") + "limits" (dict "cpu" "750m" "memory" "768Mi" "ephemeral-storage" "2Gi") + ) + "medium" (dict + "requests" (dict "cpu" "500m" "memory" "1024Mi" "ephemeral-storage" "50Mi") + "limits" (dict "cpu" "750m" "memory" "1536Mi" "ephemeral-storage" "2Gi") + ) + "large" (dict + "requests" (dict "cpu" "1.0" "memory" "2048Mi" "ephemeral-storage" "50Mi") + "limits" (dict "cpu" "1.5" "memory" "3072Mi" "ephemeral-storage" "2Gi") + ) + "xlarge" (dict + "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") + "limits" (dict "cpu" "3.0" "memory" "6144Mi" "ephemeral-storage" "2Gi") + ) + "2xlarge" (dict + "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") + "limits" (dict "cpu" "6.0" "memory" "12288Mi" "ephemeral-storage" "2Gi") + ) + }} +{{- if hasKey $presets .type -}} +{{- index $presets .type | toYaml -}} +{{- else -}} +{{- printf "ERROR: Preset key '%s' invalid. Allowed values are %s" .type (join "," (keys $presets)) | fail -}} +{{- end -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_secrets.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_secrets.tpl new file mode 100644 index 000000000..801918ce3 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_secrets.tpl @@ -0,0 +1,185 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Generate secret name. + +Usage: +{{ include "common.secrets.name" (dict "existingSecret" .Values.path.to.the.existingSecret "defaultNameSuffix" "mySuffix" "context" $) }} + +Params: + - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user + to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility. + +info: https://github.com/bitnami/charts/tree/main/bitnami/common#existingsecret + - defaultNameSuffix - String - Optional. It is used only if we have several secrets in the same deployment. + - context - Dict - Required. The context for the template evaluation. +*/}} +{{- define "common.secrets.name" -}} +{{- $name := (include "common.names.fullname" .context) -}} + +{{- if .defaultNameSuffix -}} +{{- $name = printf "%s-%s" $name .defaultNameSuffix | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- with .existingSecret -}} +{{- if not (typeIs "string" .) -}} +{{- with .name -}} +{{- $name = . -}} +{{- end -}} +{{- else -}} +{{- $name = . -}} +{{- end -}} +{{- end -}} + +{{- printf "%s" $name -}} +{{- end -}} + +{{/* +Generate secret key. + +Usage: +{{ include "common.secrets.key" (dict "existingSecret" .Values.path.to.the.existingSecret "key" "keyName") }} + +Params: + - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user + to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility. + +info: https://github.com/bitnami/charts/tree/main/bitnami/common#existingsecret + - key - String - Required. Name of the key in the secret. +*/}} +{{- define "common.secrets.key" -}} +{{- $key := .key -}} + +{{- if .existingSecret -}} + {{- if not (typeIs "string" .existingSecret) -}} + {{- if .existingSecret.keyMapping -}} + {{- $key = index .existingSecret.keyMapping $.key -}} + {{- end -}} + {{- end }} +{{- end -}} + +{{- printf "%s" $key -}} +{{- end -}} + +{{/* +Generate secret password or retrieve one if already created. + +Usage: +{{ include "common.secrets.passwords.manage" (dict "secret" "secret-name" "key" "keyName" "providedValues" (list "path.to.password1" "path.to.password2") "length" 10 "strong" false "chartName" "chartName" "context" $) }} + +Params: + - secret - String - Required - Name of the 'Secret' resource where the password is stored. + - key - String - Required - Name of the key in the secret. + - providedValues - List - Required - The path to the validating value in the values.yaml, e.g: "mysql.password". Will pick first parameter with a defined value. + - length - int - Optional - Length of the generated random password. + - strong - Boolean - Optional - Whether to add symbols to the generated random password. + - chartName - String - Optional - Name of the chart used when said chart is deployed as a subchart. + - context - Context - Required - Parent context. + - failOnNew - Boolean - Optional - Default to true. If set to false, skip errors adding new keys to existing secrets. + - skipB64enc - Boolean - Optional - Default to false. If set to true, no the secret will not be base64 encrypted. + - skipQuote - Boolean - Optional - Default to false. If set to true, no quotes will be added around the secret. +The order in which this function returns a secret password: + 1. Already existing 'Secret' resource + (If a 'Secret' resource is found under the name provided to the 'secret' parameter to this function and that 'Secret' resource contains a key with the name passed as the 'key' parameter to this function then the value of this existing secret password will be returned) + 2. Password provided via the values.yaml + (If one of the keys passed to the 'providedValues' parameter to this function is a valid path to a key in the values.yaml and has a value, the value of the first key with a value will be returned) + 3. Randomly generated secret password + (A new random secret password with the length specified in the 'length' parameter will be generated and returned) + +*/}} +{{- define "common.secrets.passwords.manage" -}} + +{{- $password := "" }} +{{- $subchart := "" }} +{{- $chartName := default "" .chartName }} +{{- $passwordLength := default 10 .length }} +{{- $providedPasswordKey := include "common.utils.getKeyFromList" (dict "keys" .providedValues "context" $.context) }} +{{- $providedPasswordValue := include "common.utils.getValueFromKey" (dict "key" $providedPasswordKey "context" $.context) }} +{{- $secretData := (lookup "v1" "Secret" (include "common.names.namespace" .context) .secret).data }} +{{- if $secretData }} + {{- if hasKey $secretData .key }} + {{- $password = index $secretData .key | b64dec }} + {{- else if not (eq .failOnNew false) }} + {{- printf "\nPASSWORDS ERROR: The secret \"%s\" does not contain the key \"%s\"\n" .secret .key | fail -}} + {{- end -}} +{{- end }} + +{{- if not $password }} + {{- if $providedPasswordValue }} + {{- $password = $providedPasswordValue | toString }} + {{- else }} + {{- if .context.Values.enabled }} + {{- $subchart = $chartName }} + {{- end -}} + + {{- if not (eq .failOnNew false) }} + {{- $requiredPassword := dict "valueKey" $providedPasswordKey "secret" .secret "field" .key "subchart" $subchart "context" $.context -}} + {{- $requiredPasswordError := include "common.validations.values.single.empty" $requiredPassword -}} + {{- $passwordValidationErrors := list $requiredPasswordError -}} + {{- include "common.errors.upgrade.passwords.empty" (dict "validationErrors" $passwordValidationErrors "context" $.context) -}} + {{- end }} + + {{- if .strong }} + {{- $subStr := list (lower (randAlpha 1)) (randNumeric 1) (upper (randAlpha 1)) | join "_" }} + {{- $password = randAscii $passwordLength }} + {{- $password = regexReplaceAllLiteral "\\W" $password "@" | substr 5 $passwordLength }} + {{- $password = printf "%s%s" $subStr $password | toString | shuffle }} + {{- else }} + {{- $password = randAlphaNum $passwordLength }} + {{- end }} + {{- end -}} +{{- end -}} +{{- if not .skipB64enc }} +{{- $password = $password | b64enc }} +{{- end -}} +{{- if .skipQuote -}} +{{- printf "%s" $password -}} +{{- else -}} +{{- printf "%s" $password | quote -}} +{{- end -}} +{{- end -}} + +{{/* +Reuses the value from an existing secret, otherwise sets its value to a default value. + +Usage: +{{ include "common.secrets.lookup" (dict "secret" "secret-name" "key" "keyName" "defaultValue" .Values.myValue "context" $) }} + +Params: + - secret - String - Required - Name of the 'Secret' resource where the password is stored. + - key - String - Required - Name of the key in the secret. + - defaultValue - String - Required - The path to the validating value in the values.yaml, e.g: "mysql.password". Will pick first parameter with a defined value. + - context - Context - Required - Parent context. + +*/}} +{{- define "common.secrets.lookup" -}} +{{- $value := "" -}} +{{- $secretData := (lookup "v1" "Secret" (include "common.names.namespace" .context) .secret).data -}} +{{- if and $secretData (hasKey $secretData .key) -}} + {{- $value = index $secretData .key -}} +{{- else if .defaultValue -}} + {{- $value = .defaultValue | toString | b64enc -}} +{{- end -}} +{{- if $value -}} +{{- printf "%s" $value -}} +{{- end -}} +{{- end -}} + +{{/* +Returns whether a previous generated secret already exists + +Usage: +{{ include "common.secrets.exists" (dict "secret" "secret-name" "context" $) }} + +Params: + - secret - String - Required - Name of the 'Secret' resource where the password is stored. + - context - Context - Required - Parent context. +*/}} +{{- define "common.secrets.exists" -}} +{{- $secret := (lookup "v1" "Secret" (include "common.names.namespace" .context) .secret) }} +{{- if $secret }} + {{- true -}} +{{- end -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_storage.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_storage.tpl new file mode 100644 index 000000000..aa75856c0 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_storage.tpl @@ -0,0 +1,21 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} + +{{/* +Return the proper Storage Class +{{ include "common.storage.class" ( dict "persistence" .Values.path.to.the.persistence "global" $) }} +*/}} +{{- define "common.storage.class" -}} +{{- $storageClass := (.global).storageClass | default .persistence.storageClass | default (.global).defaultStorageClass | default "" -}} +{{- if $storageClass -}} + {{- if (eq "-" $storageClass) -}} + {{- printf "storageClassName: \"\"" -}} + {{- else -}} + {{- printf "storageClassName: %s" $storageClass -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_tplvalues.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_tplvalues.tpl new file mode 100644 index 000000000..c84d72c80 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_tplvalues.tpl @@ -0,0 +1,38 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Renders a value that contains template perhaps with scope if the scope is present. +Usage: +{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $ ) }} +{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $ "scope" $app ) }} +*/}} +{{- define "common.tplvalues.render" -}} +{{- $value := typeIs "string" .value | ternary .value (.value | toYaml) }} +{{- if contains "{{" (toJson .value) }} + {{- if .scope }} + {{- tpl (cat "{{- with $.RelativeScope -}}" $value "{{- end }}") (merge (dict "RelativeScope" .scope) .context) }} + {{- else }} + {{- tpl $value .context }} + {{- end }} +{{- else }} + {{- $value }} +{{- end }} +{{- end -}} + +{{/* +Merge a list of values that contains template after rendering them. +Merge precedence is consistent with http://masterminds.github.io/sprig/dicts.html#merge-mustmerge +Usage: +{{ include "common.tplvalues.merge" ( dict "values" (list .Values.path.to.the.Value1 .Values.path.to.the.Value2) "context" $ ) }} +*/}} +{{- define "common.tplvalues.merge" -}} +{{- $dst := dict -}} +{{- range .values -}} +{{- $dst = include "common.tplvalues.render" (dict "value" . "context" $.context "scope" $.scope) | fromYaml | merge $dst -}} +{{- end -}} +{{ $dst | toYaml }} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_utils.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_utils.tpl new file mode 100644 index 000000000..d53c74aa2 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_utils.tpl @@ -0,0 +1,77 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Print instructions to get a secret value. +Usage: +{{ include "common.utils.secret.getvalue" (dict "secret" "secret-name" "field" "secret-value-field" "context" $) }} +*/}} +{{- define "common.utils.secret.getvalue" -}} +{{- $varname := include "common.utils.fieldToEnvVar" . -}} +export {{ $varname }}=$(kubectl get secret --namespace {{ include "common.names.namespace" .context | quote }} {{ .secret }} -o jsonpath="{.data.{{ .field }}}" | base64 -d) +{{- end -}} + +{{/* +Build env var name given a field +Usage: +{{ include "common.utils.fieldToEnvVar" dict "field" "my-password" }} +*/}} +{{- define "common.utils.fieldToEnvVar" -}} + {{- $fieldNameSplit := splitList "-" .field -}} + {{- $upperCaseFieldNameSplit := list -}} + + {{- range $fieldNameSplit -}} + {{- $upperCaseFieldNameSplit = append $upperCaseFieldNameSplit ( upper . ) -}} + {{- end -}} + + {{ join "_" $upperCaseFieldNameSplit }} +{{- end -}} + +{{/* +Gets a value from .Values given +Usage: +{{ include "common.utils.getValueFromKey" (dict "key" "path.to.key" "context" $) }} +*/}} +{{- define "common.utils.getValueFromKey" -}} +{{- $splitKey := splitList "." .key -}} +{{- $value := "" -}} +{{- $latestObj := $.context.Values -}} +{{- range $splitKey -}} + {{- if not $latestObj -}} + {{- printf "please review the entire path of '%s' exists in values" $.key | fail -}} + {{- end -}} + {{- $value = ( index $latestObj . ) -}} + {{- $latestObj = $value -}} +{{- end -}} +{{- printf "%v" (default "" $value) -}} +{{- end -}} + +{{/* +Returns first .Values key with a defined value or first of the list if all non-defined +Usage: +{{ include "common.utils.getKeyFromList" (dict "keys" (list "path.to.key1" "path.to.key2") "context" $) }} +*/}} +{{- define "common.utils.getKeyFromList" -}} +{{- $key := first .keys -}} +{{- $reverseKeys := reverse .keys }} +{{- range $reverseKeys }} + {{- $value := include "common.utils.getValueFromKey" (dict "key" . "context" $.context ) }} + {{- if $value -}} + {{- $key = . }} + {{- end -}} +{{- end -}} +{{- printf "%s" $key -}} +{{- end -}} + +{{/* +Checksum a template at "path" containing a *single* resource (ConfigMap,Secret) for use in pod annotations, excluding the metadata (see #18376). +Usage: +{{ include "common.utils.checksumTemplate" (dict "path" "/configmap.yaml" "context" $) }} +*/}} +{{- define "common.utils.checksumTemplate" -}} +{{- $obj := include (print .context.Template.BasePath .path) .context | fromYaml -}} +{{ omit $obj "apiVersion" "kind" "metadata" | toYaml | sha256sum }} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_warnings.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_warnings.tpl new file mode 100644 index 000000000..e4dbecde2 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/_warnings.tpl @@ -0,0 +1,109 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Warning about using rolling tag. +Usage: +{{ include "common.warnings.rollingTag" .Values.path.to.the.imageRoot }} +*/}} +{{- define "common.warnings.rollingTag" -}} + +{{- if and (contains "bitnami/" .repository) (not (.tag | toString | regexFind "-r\\d+$|sha256:")) }} +WARNING: Rolling tag detected ({{ .repository }}:{{ .tag }}), please note that it is strongly recommended to avoid using rolling tags in a production environment. ++info https://docs.vmware.com/en/VMware-Tanzu-Application-Catalog/services/tutorials/GUID-understand-rolling-tags-containers-index.html +{{- end }} +{{- end -}} + +{{/* +Warning about replaced images from the original. +Usage: +{{ include "common.warnings.modifiedImages" (dict "images" (list .Values.path.to.the.imageRoot) "context" $) }} +*/}} +{{- define "common.warnings.modifiedImages" -}} +{{- $affectedImages := list -}} +{{- $printMessage := false -}} +{{- $originalImages := .context.Chart.Annotations.images -}} +{{- range .images -}} + {{- $fullImageName := printf (printf "%s/%s:%s" .registry .repository .tag) -}} + {{- if not (contains $fullImageName $originalImages) }} + {{- $affectedImages = append $affectedImages (printf "%s/%s:%s" .registry .repository .tag) -}} + {{- $printMessage = true -}} + {{- end -}} +{{- end -}} +{{- if $printMessage }} + +⚠ SECURITY WARNING: Original containers have been substituted. This Helm chart was designed, tested, and validated on multiple platforms using a specific set of Bitnami and Tanzu Application Catalog containers. Substituting other containers is likely to cause degraded security and performance, broken chart features, and missing environment variables. + +Substituted images detected: +{{- range $affectedImages }} + - {{ . }} +{{- end }} +{{- end -}} +{{- end -}} + +{{/* +Warning about not setting the resource object in all deployments. +Usage: +{{ include "common.warnings.resources" (dict "sections" (list "path1" "path2") context $) }} +Example: +{{- include "common.warnings.resources" (dict "sections" (list "csiProvider.provider" "server" "volumePermissions" "") "context" $) }} +The list in the example assumes that the following values exist: + - csiProvider.provider.resources + - server.resources + - volumePermissions.resources + - resources +*/}} +{{- define "common.warnings.resources" -}} +{{- $values := .context.Values -}} +{{- $printMessage := false -}} +{{ $affectedSections := list -}} +{{- range .sections -}} + {{- if eq . "" -}} + {{/* Case where the resources section is at the root (one main deployment in the chart) */}} + {{- if not (index $values "resources") -}} + {{- $affectedSections = append $affectedSections "resources" -}} + {{- $printMessage = true -}} + {{- end -}} + {{- else -}} + {{/* Case where the are multiple resources sections (more than one main deployment in the chart) */}} + {{- $keys := split "." . -}} + {{/* We iterate through the different levels until arriving to the resource section. Example: a.b.c.resources */}} + {{- $section := $values -}} + {{- range $keys -}} + {{- $section = index $section . -}} + {{- end -}} + {{- if not (index $section "resources") -}} + {{/* If the section has enabled=false or replicaCount=0, do not include it */}} + {{- if and (hasKey $section "enabled") -}} + {{- if index $section "enabled" -}} + {{/* enabled=true */}} + {{- $affectedSections = append $affectedSections (printf "%s.resources" .) -}} + {{- $printMessage = true -}} + {{- end -}} + {{- else if and (hasKey $section "replicaCount") -}} + {{/* We need a casting to int because number 0 is not treated as an int by default */}} + {{- if (gt (index $section "replicaCount" | int) 0) -}} + {{/* replicaCount > 0 */}} + {{- $affectedSections = append $affectedSections (printf "%s.resources" .) -}} + {{- $printMessage = true -}} + {{- end -}} + {{- else -}} + {{/* Default case, add it to the affected sections */}} + {{- $affectedSections = append $affectedSections (printf "%s.resources" .) -}} + {{- $printMessage = true -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} +{{- if $printMessage }} + +WARNING: There are "resources" sections in the chart not set. Using "resourcesPreset" is not recommended for production. For production installations, please set the following values according to your workload needs: +{{- range $affectedSections }} + - {{ . }} +{{- end }} ++info https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +{{- end -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_cassandra.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_cassandra.tpl new file mode 100644 index 000000000..3f41ff8fc --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_cassandra.tpl @@ -0,0 +1,77 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Validate Cassandra required passwords are not empty. + +Usage: +{{ include "common.validations.values.cassandra.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where Cassandra values are stored, e.g: "cassandra-passwords-secret" + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.cassandra.passwords" -}} + {{- $existingSecret := include "common.cassandra.values.existingSecret" . -}} + {{- $enabled := include "common.cassandra.values.enabled" . -}} + {{- $dbUserPrefix := include "common.cassandra.values.key.dbUser" . -}} + {{- $valueKeyPassword := printf "%s.password" $dbUserPrefix -}} + + {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "cassandra-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for existingSecret. + +Usage: +{{ include "common.cassandra.values.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.cassandra.values.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.cassandra.dbUser.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.dbUser.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for enabled cassandra. + +Usage: +{{ include "common.cassandra.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.cassandra.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.cassandra.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for the key dbUser + +Usage: +{{ include "common.cassandra.values.key.dbUser" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.cassandra.values.key.dbUser" -}} + {{- if .subchart -}} + cassandra.dbUser + {{- else -}} + dbUser + {{- end -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_mariadb.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_mariadb.tpl new file mode 100644 index 000000000..6ea8c0f45 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_mariadb.tpl @@ -0,0 +1,108 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Validate MariaDB required passwords are not empty. + +Usage: +{{ include "common.validations.values.mariadb.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where MariaDB values are stored, e.g: "mysql-passwords-secret" + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.mariadb.passwords" -}} + {{- $existingSecret := include "common.mariadb.values.auth.existingSecret" . -}} + {{- $enabled := include "common.mariadb.values.enabled" . -}} + {{- $architecture := include "common.mariadb.values.architecture" . -}} + {{- $authPrefix := include "common.mariadb.values.key.auth" . -}} + {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} + {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} + {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} + {{- $valueKeyReplicationPassword := printf "%s.replicationPassword" $authPrefix -}} + + {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mariadb-root-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} + + {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} + {{- if not (empty $valueUsername) -}} + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mariadb-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + {{- end -}} + + {{- if (eq $architecture "replication") -}} + {{- $requiredReplicationPassword := dict "valueKey" $valueKeyReplicationPassword "secret" .secret "field" "mariadb-replication-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredReplicationPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for existingSecret. + +Usage: +{{ include "common.mariadb.values.auth.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.auth.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.mariadb.auth.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.auth.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for enabled mariadb. + +Usage: +{{ include "common.mariadb.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.mariadb.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.mariadb.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for architecture + +Usage: +{{ include "common.mariadb.values.architecture" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.architecture" -}} + {{- if .subchart -}} + {{- .context.Values.mariadb.architecture -}} + {{- else -}} + {{- .context.Values.architecture -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for the key auth + +Usage: +{{ include "common.mariadb.values.key.auth" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.key.auth" -}} + {{- if .subchart -}} + mariadb.auth + {{- else -}} + auth + {{- end -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_mongodb.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_mongodb.tpl new file mode 100644 index 000000000..d4cd38cbb --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_mongodb.tpl @@ -0,0 +1,113 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Validate MongoDB® required passwords are not empty. + +Usage: +{{ include "common.validations.values.mongodb.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where MongoDB® values are stored, e.g: "mongodb-passwords-secret" + - subchart - Boolean - Optional. Whether MongoDB® is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.mongodb.passwords" -}} + {{- $existingSecret := include "common.mongodb.values.auth.existingSecret" . -}} + {{- $enabled := include "common.mongodb.values.enabled" . -}} + {{- $authPrefix := include "common.mongodb.values.key.auth" . -}} + {{- $architecture := include "common.mongodb.values.architecture" . -}} + {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} + {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} + {{- $valueKeyDatabase := printf "%s.database" $authPrefix -}} + {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} + {{- $valueKeyReplicaSetKey := printf "%s.replicaSetKey" $authPrefix -}} + {{- $valueKeyAuthEnabled := printf "%s.enabled" $authPrefix -}} + + {{- $authEnabled := include "common.utils.getValueFromKey" (dict "key" $valueKeyAuthEnabled "context" .context) -}} + + {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") (eq $authEnabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mongodb-root-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} + + {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} + {{- $valueDatabase := include "common.utils.getValueFromKey" (dict "key" $valueKeyDatabase "context" .context) }} + {{- if and $valueUsername $valueDatabase -}} + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mongodb-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + {{- end -}} + + {{- if (eq $architecture "replicaset") -}} + {{- $requiredReplicaSetKey := dict "valueKey" $valueKeyReplicaSetKey "secret" .secret "field" "mongodb-replica-set-key" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredReplicaSetKey -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for existingSecret. + +Usage: +{{ include "common.mongodb.values.auth.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MongoDb is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.auth.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.mongodb.auth.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.auth.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for enabled mongodb. + +Usage: +{{ include "common.mongodb.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.mongodb.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.mongodb.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for the key auth + +Usage: +{{ include "common.mongodb.values.key.auth" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MongoDB® is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.key.auth" -}} + {{- if .subchart -}} + mongodb.auth + {{- else -}} + auth + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for architecture + +Usage: +{{ include "common.mongodb.values.architecture" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MongoDB® is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.architecture" -}} + {{- if .subchart -}} + {{- .context.Values.mongodb.architecture -}} + {{- else -}} + {{- .context.Values.architecture -}} + {{- end -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_mysql.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_mysql.tpl new file mode 100644 index 000000000..924812a93 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_mysql.tpl @@ -0,0 +1,108 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Validate MySQL required passwords are not empty. + +Usage: +{{ include "common.validations.values.mysql.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where MySQL values are stored, e.g: "mysql-passwords-secret" + - subchart - Boolean - Optional. Whether MySQL is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.mysql.passwords" -}} + {{- $existingSecret := include "common.mysql.values.auth.existingSecret" . -}} + {{- $enabled := include "common.mysql.values.enabled" . -}} + {{- $architecture := include "common.mysql.values.architecture" . -}} + {{- $authPrefix := include "common.mysql.values.key.auth" . -}} + {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} + {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} + {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} + {{- $valueKeyReplicationPassword := printf "%s.replicationPassword" $authPrefix -}} + + {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mysql-root-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} + + {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} + {{- if not (empty $valueUsername) -}} + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mysql-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + {{- end -}} + + {{- if (eq $architecture "replication") -}} + {{- $requiredReplicationPassword := dict "valueKey" $valueKeyReplicationPassword "secret" .secret "field" "mysql-replication-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredReplicationPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for existingSecret. + +Usage: +{{ include "common.mysql.values.auth.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MySQL is used as subchart or not. Default: false +*/}} +{{- define "common.mysql.values.auth.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.mysql.auth.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.auth.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for enabled mysql. + +Usage: +{{ include "common.mysql.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.mysql.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.mysql.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for architecture + +Usage: +{{ include "common.mysql.values.architecture" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MySQL is used as subchart or not. Default: false +*/}} +{{- define "common.mysql.values.architecture" -}} + {{- if .subchart -}} + {{- .context.Values.mysql.architecture -}} + {{- else -}} + {{- .context.Values.architecture -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for the key auth + +Usage: +{{ include "common.mysql.values.key.auth" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MySQL is used as subchart or not. Default: false +*/}} +{{- define "common.mysql.values.key.auth" -}} + {{- if .subchart -}} + mysql.auth + {{- else -}} + auth + {{- end -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_postgresql.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_postgresql.tpl new file mode 100644 index 000000000..0fa0b1467 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_postgresql.tpl @@ -0,0 +1,134 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Validate PostgreSQL required passwords are not empty. + +Usage: +{{ include "common.validations.values.postgresql.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where postgresql values are stored, e.g: "postgresql-passwords-secret" + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.postgresql.passwords" -}} + {{- $existingSecret := include "common.postgresql.values.existingSecret" . -}} + {{- $enabled := include "common.postgresql.values.enabled" . -}} + {{- $valueKeyPostgresqlPassword := include "common.postgresql.values.key.postgressPassword" . -}} + {{- $valueKeyPostgresqlReplicationEnabled := include "common.postgresql.values.key.replicationPassword" . -}} + {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + {{- $requiredPostgresqlPassword := dict "valueKey" $valueKeyPostgresqlPassword "secret" .secret "field" "postgresql-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPostgresqlPassword -}} + + {{- $enabledReplication := include "common.postgresql.values.enabled.replication" . -}} + {{- if (eq $enabledReplication "true") -}} + {{- $requiredPostgresqlReplicationPassword := dict "valueKey" $valueKeyPostgresqlReplicationEnabled "secret" .secret "field" "postgresql-replication-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPostgresqlReplicationPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to decide whether evaluate global values. + +Usage: +{{ include "common.postgresql.values.use.global" (dict "key" "key-of-global" "context" $) }} +Params: + - key - String - Required. Field to be evaluated within global, e.g: "existingSecret" +*/}} +{{- define "common.postgresql.values.use.global" -}} + {{- if .context.Values.global -}} + {{- if .context.Values.global.postgresql -}} + {{- index .context.Values.global.postgresql .key | quote -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for existingSecret. + +Usage: +{{ include "common.postgresql.values.existingSecret" (dict "context" $) }} +*/}} +{{- define "common.postgresql.values.existingSecret" -}} + {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "existingSecret" "context" .context) -}} + + {{- if .subchart -}} + {{- default (.context.Values.postgresql.existingSecret | quote) $globalValue -}} + {{- else -}} + {{- default (.context.Values.existingSecret | quote) $globalValue -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for enabled postgresql. + +Usage: +{{ include "common.postgresql.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.postgresql.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.postgresql.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for the key postgressPassword. + +Usage: +{{ include "common.postgresql.values.key.postgressPassword" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.key.postgressPassword" -}} + {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "postgresqlUsername" "context" .context) -}} + + {{- if not $globalValue -}} + {{- if .subchart -}} + postgresql.postgresqlPassword + {{- else -}} + postgresqlPassword + {{- end -}} + {{- else -}} + global.postgresql.postgresqlPassword + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for enabled.replication. + +Usage: +{{ include "common.postgresql.values.enabled.replication" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.enabled.replication" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.postgresql.replication.enabled -}} + {{- else -}} + {{- printf "%v" .context.Values.replication.enabled -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for the key replication.password. + +Usage: +{{ include "common.postgresql.values.key.replicationPassword" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.key.replicationPassword" -}} + {{- if .subchart -}} + postgresql.replication.password + {{- else -}} + replication.password + {{- end -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_redis.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_redis.tpl new file mode 100644 index 000000000..f4778256d --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_redis.tpl @@ -0,0 +1,81 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + + +{{/* vim: set filetype=mustache: */}} +{{/* +Validate Redis® required passwords are not empty. + +Usage: +{{ include "common.validations.values.redis.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where redis values are stored, e.g: "redis-passwords-secret" + - subchart - Boolean - Optional. Whether redis is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.redis.passwords" -}} + {{- $enabled := include "common.redis.values.enabled" . -}} + {{- $valueKeyPrefix := include "common.redis.values.keys.prefix" . -}} + {{- $standarizedVersion := include "common.redis.values.standarized.version" . }} + + {{- $existingSecret := ternary (printf "%s%s" $valueKeyPrefix "auth.existingSecret") (printf "%s%s" $valueKeyPrefix "existingSecret") (eq $standarizedVersion "true") }} + {{- $existingSecretValue := include "common.utils.getValueFromKey" (dict "key" $existingSecret "context" .context) }} + + {{- $valueKeyRedisPassword := ternary (printf "%s%s" $valueKeyPrefix "auth.password") (printf "%s%s" $valueKeyPrefix "password") (eq $standarizedVersion "true") }} + {{- $valueKeyRedisUseAuth := ternary (printf "%s%s" $valueKeyPrefix "auth.enabled") (printf "%s%s" $valueKeyPrefix "usePassword") (eq $standarizedVersion "true") }} + + {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $useAuth := include "common.utils.getValueFromKey" (dict "key" $valueKeyRedisUseAuth "context" .context) -}} + {{- if eq $useAuth "true" -}} + {{- $requiredRedisPassword := dict "valueKey" $valueKeyRedisPassword "secret" .secret "field" "redis-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRedisPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for enabled redis. + +Usage: +{{ include "common.redis.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.redis.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.redis.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right prefix path for the values + +Usage: +{{ include "common.redis.values.key.prefix" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether redis is used as subchart or not. Default: false +*/}} +{{- define "common.redis.values.keys.prefix" -}} + {{- if .subchart -}}redis.{{- else -}}{{- end -}} +{{- end -}} + +{{/* +Checks whether the redis chart's includes the standarizations (version >= 14) + +Usage: +{{ include "common.redis.values.standarized.version" (dict "context" $) }} +*/}} +{{- define "common.redis.values.standarized.version" -}} + + {{- $standarizedAuth := printf "%s%s" (include "common.redis.values.keys.prefix" .) "auth" -}} + {{- $standarizedAuthValues := include "common.utils.getValueFromKey" (dict "key" $standarizedAuth "context" .context) }} + + {{- if $standarizedAuthValues -}} + {{- true -}} + {{- end -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_validations.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_validations.tpl new file mode 100644 index 000000000..7cdee6170 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/templates/validations/_validations.tpl @@ -0,0 +1,51 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Validate values must not be empty. + +Usage: +{{- $validateValueConf00 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-00") -}} +{{- $validateValueConf01 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-01") -}} +{{ include "common.validations.values.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }} + +Validate value params: + - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password" + - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret" + - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password" +*/}} +{{- define "common.validations.values.multiple.empty" -}} + {{- range .required -}} + {{- include "common.validations.values.single.empty" (dict "valueKey" .valueKey "secret" .secret "field" .field "context" $.context) -}} + {{- end -}} +{{- end -}} + +{{/* +Validate a value must not be empty. + +Usage: +{{ include "common.validations.value.empty" (dict "valueKey" "mariadb.password" "secret" "secretName" "field" "my-password" "subchart" "subchart" "context" $) }} + +Validate value params: + - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password" + - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret" + - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password" + - subchart - String - Optional - Name of the subchart that the validated password is part of. +*/}} +{{- define "common.validations.values.single.empty" -}} + {{- $value := include "common.utils.getValueFromKey" (dict "key" .valueKey "context" .context) }} + {{- $subchart := ternary "" (printf "%s." .subchart) (empty .subchart) }} + + {{- if not $value -}} + {{- $varname := "my-value" -}} + {{- $getCurrentValue := "" -}} + {{- if and .secret .field -}} + {{- $varname = include "common.utils.fieldToEnvVar" . -}} + {{- $getCurrentValue = printf " To get the current value:\n\n %s\n" (include "common.utils.secret.getvalue" .) -}} + {{- end -}} + {{- printf "\n '%s' must not be empty, please add '--set %s%s=$%s' to the command.%s" .valueKey $subchart .valueKey $varname $getCurrentValue -}} + {{- end -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/values.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/values.yaml new file mode 100644 index 000000000..de2cac57d --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/charts/common/values.yaml @@ -0,0 +1,8 @@ +# Copyright Broadcom, Inc. All Rights Reserved. +# SPDX-License-Identifier: APACHE-2.0 + +## bitnami/common +## It is required by CI/CD tools and processes. +## @skip exampleValue +## +exampleValue: common-chart diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/NOTES.txt b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/NOTES.txt new file mode 100644 index 000000000..3b5bf2823 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/NOTES.txt @@ -0,0 +1,53 @@ +================================================================================ +The ngrok Ingress controller has been deployed as a Deployment type to your +cluster. + +If you haven't yet, create some Ingress resources in your cluster and they will +be automatically configured on the internet using ngrok. + + +{{- $found := false }} +{{- range $svcIndex, $service := (lookup "v1" "Service" "" "").items }} + {{- if not $found }} + {{- range $portMapIdx, $portMap := $service.spec.ports }} + {{- if eq $portMap.port 80 443 }} + {{- if ne $service.metadata.name "kubernetes" }} + {{- $found = true -}} + {{- $randomStr := randAlphaNum 8 | lower }} + +One example, taken from your cluster, is the Service: + {{ $service.metadata.name | quote }} + +You can make this accessible via ngrok with the following manifest: +-------------------------------------------------------------------------------- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ $service.metadata.name }} + namespace: {{ $service.metadata.namespace }} +spec: + ingressClassName: ngrok + rules: + - host: {{ $service.metadata.name -}}-{{- $randomStr -}}.ngrok.app + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ $service.metadata.name }} + port: + number: {{ $portMap.port }} +-------------------------------------------------------------------------------- +Applying this manifest will make the service {{ $service.metadata.name | quote }} +available on the public internet at "https://{{ $service.metadata.name -}}-{{- $randomStr -}}.ngrok.app/". + {{- end }} + {{- end }} + {{- end }} + {{- end}} +{{- end }} + +Once done, view your edges in the Dashboard https://dashboard.ngrok.com/cloud-edge/edges +Find the tunnels running in your cluster here https://dashboard.ngrok.com/tunnels/agents + +If you have any questions or feedback, please join us in https://ngrok.com/slack and let us know! diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/_helpers.tpl b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/_helpers.tpl new file mode 100644 index 000000000..c5be41cb2 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/_helpers.tpl @@ -0,0 +1,87 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "kubernetes-ingress-controller.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "kubernetes-ingress-controller.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "kubernetes-ingress-controller.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create a default name for the credentials secret name using the helm release +*/}} +{{- define "kubernetes-ingress-controller.credentialsSecretName" -}} +{{- if .Values.credentials.secret.name -}} +{{- .Values.credentials.secret.name -}} +{{- else -}} +{{- printf "%s-credentials" (include "kubernetes-ingress-controller.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "kubernetes-ingress-controller.labels" -}} +helm.sh/chart: {{ include "kubernetes-ingress-controller.chart" . }} +{{ include "kubernetes-ingress-controller.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/part-of: {{ template "kubernetes-ingress-controller.name" . }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- if .Values.commonLabels}} +{{ toYaml .Values.commonLabels }} +{{- end }} +{{- end -}} + +{{/* +Selector labels +*/}} +{{- define "kubernetes-ingress-controller.selectorLabels" -}} +app.kubernetes.io/name: {{ include "kubernetes-ingress-controller.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} + +{{/* +Create the name of the controller service account to use +*/}} +{{- define "kubernetes-ingress-controller.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "kubernetes-ingress-controller.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Return the ngrok/ingress-controller image name +*/}} +{{- define "kubernetes-ingress-controller.image" -}} +{{- $registryName := .Values.image.registry -}} +{{- $repositoryName := .Values.image.repository -}} +{{- $tag := .Values.image.tag | default .Chart.AppVersion | toString -}} +{{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} +{{- end -}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-cm.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-cm.yaml new file mode 100644 index 000000000..88728341c --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-cm.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "kubernetes-ingress-controller.fullname" . }}-manager-config + namespace: {{ .Release.Namespace }} +data: + controller_manager_config.yaml: | + apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 + kind: ControllerManagerConfig + health: + healthProbeBindAddress: :8081 + metrics: + bindAddress: 127.0.0.1:8080 + leaderElection: + leaderElect: true + resourceName: {{ include "kubernetes-ingress-controller.fullname" . }}-leader diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-deployment.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-deployment.yaml new file mode 100644 index 000000000..e6358fb0e --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-deployment.yaml @@ -0,0 +1,146 @@ +{{- $component := "controller" }} +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + {{- include "kubernetes-ingress-controller.labels" . | nindent 4 }} + app.kubernetes.io/component: {{ $component }} + name: {{ include "kubernetes-ingress-controller.fullname" . }}-manager + namespace: {{ .Release.Namespace }} + annotations: + checksum/controller-role: {{ include (print $.Template.BasePath "/rbac/role.yaml") . | sha256sum }} + checksum/rbac: {{ include (print $.Template.BasePath "/controller-rbac.yaml") . | sha256sum }} +spec: + replicas: {{.Values.replicaCount}} + selector: + matchLabels: + {{- include "kubernetes-ingress-controller.selectorLabels" . | nindent 6 }} + {{- if .Values.podLabels }} + {{- toYaml .Values.podLabels | nindent 6 }} + {{- end }} + app.kubernetes.io/component: {{ $component }} + template: + metadata: + annotations: + {{- if .Values.podAnnotations }} + {{- toYaml .Values.podAnnotations | nindent 8 }} + {{- end }} + prometheus.io/path: /metrics + prometheus.io/port: '8080' + prometheus.io/scrape: 'true' + checksum/controller-role: {{ include (print $.Template.BasePath "/rbac/role.yaml") . | sha256sum }} + checksum/rbac: {{ include (print $.Template.BasePath "/controller-rbac.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/credentials-secret.yaml") . | sha256sum }} + labels: + {{- include "kubernetes-ingress-controller.selectorLabels" . | nindent 8 }} + {{- if .Values.podLabels }} + {{- toYaml .Values.podLabels | nindent 8 }} + {{- end }} + app.kubernetes.io/component: {{ $component }} + spec: + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- if .Values.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAffinityPreset "component" $component "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset "component" $component "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.nodeAffinityPreset.type "key" .Values.nodeAffinityPreset.key "values" .Values.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + serviceAccountName: {{ template "kubernetes-ingress-controller.serviceAccountName" . }} + {{- if .Values.image.pullSecrets }} + imagePullSecrets: + {{- toYaml .Values.image.pullSecrets | nindent 8 }} + {{- end }} + containers: + - name: ngrok-ingress-controller + image: {{ include "kubernetes-ingress-controller.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + - /manager + args: + {{- if .Values.region }} + - --region={{ .Values.region}} + {{- end }} + {{- if .Values.apiURL }} + - --api-url={{ .Values.apiURL}} + {{- end }} + {{- if .Values.rootCAs }} + - --root-cas={{ .Values.rootCAs}} + {{- end }} + {{- if .Values.serverAddr }} + - --server-addr={{ .Values.serverAddr}} + {{- end }} + {{- if .Values.metaData }} + - --metadata={{- $metadataArgs := list -}} + {{- range $key, $value := .Values.metaData }} + {{- $metadataArgs = append $metadataArgs (printf "%s=%s" $key $value) -}} + {{- end }} + {{- $metadataArgs | join "," }} + {{- end }} + - --controller-name={{ .Values.controllerName }} + {{- if .Values.watchNamespace }} + - --watch-namespace={{ .Values.watchNamespace}} + {{- end }} + {{- if .Values.useExperimentalGatewayApi }} + - --use-experimental-gateway-api={{ .Values.useExperimentalGatewayApi }} + {{- end }} + - --zap-log-level={{ .Values.log.level }} + - --zap-stacktrace-level={{ .Values.log.stacktraceLevel }} + - --zap-encoder={{ .Values.log.format }} + - --health-probe-bind-address=:8081 + - --metrics-bind-address=:8080 + - --election-id={{ include "kubernetes-ingress-controller.fullname" . }}-leader + - --manager-name={{ include "kubernetes-ingress-controller.fullname" . }}-manager + {{- if .Values.clusterDomain }} + - --cluster-domain={{ .Values.clusterDomain }} + {{- end }} + securityContext: + allowPrivilegeEscalation: false + env: + - name: NGROK_API_KEY + valueFrom: + secretKeyRef: + key: API_KEY + name: {{ include "kubernetes-ingress-controller.credentialsSecretName" . }} + - name: NGROK_AUTHTOKEN + valueFrom: + secretKeyRef: + key: AUTHTOKEN + name: {{ include "kubernetes-ingress-controller.credentialsSecretName" . }} + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- range $key, $value := .Values.extraEnv }} + - name: {{ $key }} + value: {{- toYaml $value | nindent 12 }} + {{- end }} + {{- if .Values.extraVolumeMounts }} + volumeMounts: + {{ toYaml .Values.extraVolumeMounts | nindent 10 }} + {{- end }} + {{- if .Values.lifecycle }} + lifecycle: + {{ toYaml .Values.lifecycle | nindent 10 }} + {{- end }} + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + {{- toYaml .Values.resources | nindent 10 }} + {{- if .Values.extraVolumes }} + volumes: + {{ toYaml .Values.extraVolumes | nindent 6 }} + {{- end }} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-pdb.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-pdb.yaml new file mode 100644 index 000000000..7046631ac --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-pdb.yaml @@ -0,0 +1,26 @@ +{{- if .Values.podDisruptionBudget.create }} +{{ $component := "controller"}} +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "kubernetes-ingress-controller.fullname" . }}-controller-pdb + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "kubernetes-ingress-controller.labels" . | nindent 4 }} + app.kubernetes.io/component: {{ $component }} +spec: + {{- if .Values.podDisruptionBudget.minAvailable }} + minAvailable: {{ .Values.podDisruptionBudget.minAvailable }} + {{- end }} + {{- if .Values.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} + {{- end }} + selector: + matchLabels: + {{- include "kubernetes-ingress-controller.selectorLabels" . | nindent 6 }} + {{- if .Values.podLabels }} + {{- toYaml .Values.podLabels | nindent 6 }} + {{- end }} + app.kubernetes.io/component: {{ $component }} +{{- end }} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-rbac.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-rbac.yaml new file mode 100644 index 000000000..82fade5c7 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-rbac.yaml @@ -0,0 +1,96 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ngrok-ingress-controller-leader-election-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: ngrok-ingress-controller-proxy-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ngrok-ingress-controller-leader-election-rolebinding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ngrok-ingress-controller-leader-election-role +subjects: +- kind: ServiceAccount + name: {{ template "kubernetes-ingress-controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ngrok-ingress-controller-manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: ngrok-ingress-controller-manager-role +subjects: +- kind: ServiceAccount + name: {{ template "kubernetes-ingress-controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ngrok-ingress-controller-proxy-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: ngrok-ingress-controller-proxy-role +subjects: +- kind: ServiceAccount + name: {{ template "kubernetes-ingress-controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-serviceaccount.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-serviceaccount.yaml new file mode 100644 index 000000000..d80a5d8c9 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/controller-serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.serviceAccount.create -}} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "kubernetes-ingress-controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "kubernetes-ingress-controller.labels" . | nindent 4 }} + app.kubernetes.io/component: controller + {{- if .Values.serviceAccount.annotations }} + annotations: + {{- toYaml .Values.serviceAccount.annotations | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_domains.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_domains.yaml new file mode 100644 index 000000000..ab02a958e --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_domains.yaml @@ -0,0 +1,105 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: domains.ingress.k8s.ngrok.com +spec: + group: ingress.k8s.ngrok.com + names: + kind: Domain + listKind: DomainList + plural: domains + singular: domain + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Domain ID + jsonPath: .status.id + name: ID + type: string + - description: Region + jsonPath: .status.region + name: Region + type: string + - description: Domain + jsonPath: .status.domain + name: Domain + type: string + - description: CNAME Target + jsonPath: .status.cnameTarget + name: CNAME Target + type: string + - description: Age + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Domain is the Schema for the domains API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: DomainSpec defines the desired state of Domain + properties: + description: + default: Created by kubernetes-ingress-controller + description: Description is a human-readable description of the object + in the ngrok API/Dashboard + type: string + domain: + description: Domain is the domain name to reserve + type: string + metadata: + default: '{"owned-by":"kubernetes-ingress-controller"}' + description: Metadata is a string of arbitrary data associated with + the object in the ngrok API/Dashboard + type: string + region: + description: Region is the region in which to reserve the domain + type: string + required: + - domain + type: object + status: + description: DomainStatus defines the observed state of Domain + properties: + cnameTarget: + description: CNAMETarget is the CNAME target for the domain + type: string + domain: + description: Domain is the domain that was reserved + type: string + id: + description: ID is the unique identifier of the domain + type: string + region: + description: Region is the region in which the domain was created + type: string + uri: + description: URI of the reserved domain API resource + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_httpsedges.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_httpsedges.yaml new file mode 100644 index 000000000..ffafa4232 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_httpsedges.yaml @@ -0,0 +1,1062 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: httpsedges.ingress.k8s.ngrok.com +spec: + group: ingress.k8s.ngrok.com + names: + kind: HTTPSEdge + listKind: HTTPSEdgeList + plural: httpsedges + singular: httpsedge + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: HTTPSEdge is the Schema for the httpsedges API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: HTTPSEdgeSpec defines the desired state of HTTPSEdge + properties: + description: + default: Created by kubernetes-ingress-controller + description: Description is a human-readable description of the object + in the ngrok API/Dashboard + type: string + hostports: + description: Hostports is a list of hostports served by this edge + items: + type: string + type: array + metadata: + default: '{"owned-by":"kubernetes-ingress-controller"}' + description: Metadata is a string of arbitrary data associated with + the object in the ngrok API/Dashboard + type: string + mutualTLS: + properties: + certificateAuthorities: + description: |- + List of CA IDs that will be used to validate incoming connections to the + edge. + items: + type: string + type: array + type: object + routes: + description: Routes is a list of routes served by this edge + items: + properties: + backend: + description: |- + Backend is the definition for the tunnel group backend + that serves traffic for this edge + properties: + description: + default: Created by kubernetes-ingress-controller + description: Description is a human-readable description + of the object in the ngrok API/Dashboard + type: string + labels: + additionalProperties: + type: string + description: Labels to watch for tunnels on this backend + type: object + metadata: + default: '{"owned-by":"kubernetes-ingress-controller"}' + description: Metadata is a string of arbitrary data associated + with the object in the ngrok API/Dashboard + type: string + type: object + circuitBreaker: + description: CircuitBreaker is a circuit breaker configuration + to apply to this route + properties: + errorThresholdPercentage: + anyOf: + - type: integer + - type: string + description: Error threshold percentage should be between + 0 - 1.0, not 0-100.0 + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + numBuckets: + description: Integer number of buckets into which metrics + are retained. Max 128. + format: int32 + maximum: 128 + minimum: 1 + type: integer + rollingWindow: + description: Statistical rolling window duration that metrics + are retained for. + format: duration + type: string + trippedDuration: + description: Duration after which the circuit is tripped + to wait before re-evaluating upstream health + format: duration + type: string + volumeThreshold: + description: |- + Integer number of requests in a rolling window that will trip the circuit. + Helpful if traffic volume is low. + format: int32 + type: integer + type: object + compression: + description: Compression is whether or not to enable compression + for this route + properties: + enabled: + description: Enabled is whether or not to enable compression + for this endpoint + type: boolean + type: object + description: + default: Created by kubernetes-ingress-controller + description: Description is a human-readable description of + the object in the ngrok API/Dashboard + type: string + headers: + description: Headers are request/response headers to apply to + this route + properties: + request: + description: Request headers are the request headers module + configuration or null + properties: + add: + additionalProperties: + type: string + description: |- + a map of header key to header value that will be injected into the HTTP Request + before being sent to the upstream application server + type: object + remove: + description: |- + a list of header names that will be removed from the HTTP Request before being + sent to the upstream application server + items: + type: string + type: array + type: object + response: + description: Response headers are the response headers module + configuration or null + properties: + add: + additionalProperties: + type: string + description: |- + a map of header key to header value that will be injected into the HTTP Response + returned to the HTTP client + type: object + remove: + description: |- + a list of header names that will be removed from the HTTP Response returned to + the HTTP client + items: + type: string + type: array + type: object + type: object + ipRestriction: + description: IPRestriction is an IPRestriction to apply to this + route + properties: + policies: + items: + type: string + type: array + type: object + match: + description: Match is the value to match against the request + path + type: string + matchType: + description: 'MatchType is the type of match to use for this + route. Valid values are:' + enum: + - exact_path + - path_prefix + type: string + metadata: + default: '{"owned-by":"kubernetes-ingress-controller"}' + description: Metadata is a string of arbitrary data associated + with the object in the ngrok API/Dashboard + type: string + oauth: + description: OAuth configuration to apply to this route + properties: + amazon: + description: configuration for using amazon as the identity + provider + properties: + authCheckInterval: + description: |- + Duration after which ngrok guarantees it will refresh user + state from the identity provider and recheck whether the user is still + authorized to access the endpoint. This is the preferred tunable to use to + enforce a minimum amount of time after which a revoked user will no longer be + able to access the resource. + format: duration + type: string + clientId: + description: |- + the OAuth app client ID. retrieve it from the identity provider's dashboard + where you created your own OAuth app. optional. if unspecified, ngrok will use + its own managed oauth application which has additional restrictions. see the + OAuth module docs for more details. if present, clientSecret must be present as + well. + type: string + clientSecret: + description: |- + the OAuth app client secret. retrieve if from the identity provider's dashboard + where you created your own OAuth app. optional, see all of the caveats in the + docs for clientId. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + emailAddresses: + description: |- + a list of email addresses of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + emailDomains: + description: |- + a list of email domains of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + Integer number of seconds of the maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + scopes: + description: |- + a list of provider-specific OAuth scopes with the permissions your OAuth app + would like to ask for. these may not be set if you are using the ngrok-managed + oauth app (i.e. you must pass both client_id and client_secret to set scopes) + items: + type: string + type: array + type: object + facebook: + description: configuration for using facebook as the identity + provider + properties: + authCheckInterval: + description: |- + Duration after which ngrok guarantees it will refresh user + state from the identity provider and recheck whether the user is still + authorized to access the endpoint. This is the preferred tunable to use to + enforce a minimum amount of time after which a revoked user will no longer be + able to access the resource. + format: duration + type: string + clientId: + description: |- + the OAuth app client ID. retrieve it from the identity provider's dashboard + where you created your own OAuth app. optional. if unspecified, ngrok will use + its own managed oauth application which has additional restrictions. see the + OAuth module docs for more details. if present, clientSecret must be present as + well. + type: string + clientSecret: + description: |- + the OAuth app client secret. retrieve if from the identity provider's dashboard + where you created your own OAuth app. optional, see all of the caveats in the + docs for clientId. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + emailAddresses: + description: |- + a list of email addresses of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + emailDomains: + description: |- + a list of email domains of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + Integer number of seconds of the maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + scopes: + description: |- + a list of provider-specific OAuth scopes with the permissions your OAuth app + would like to ask for. these may not be set if you are using the ngrok-managed + oauth app (i.e. you must pass both client_id and client_secret to set scopes) + items: + type: string + type: array + type: object + github: + description: configuration for using github as the identity + provider + properties: + authCheckInterval: + description: |- + Duration after which ngrok guarantees it will refresh user + state from the identity provider and recheck whether the user is still + authorized to access the endpoint. This is the preferred tunable to use to + enforce a minimum amount of time after which a revoked user will no longer be + able to access the resource. + format: duration + type: string + clientId: + description: |- + the OAuth app client ID. retrieve it from the identity provider's dashboard + where you created your own OAuth app. optional. if unspecified, ngrok will use + its own managed oauth application which has additional restrictions. see the + OAuth module docs for more details. if present, clientSecret must be present as + well. + type: string + clientSecret: + description: |- + the OAuth app client secret. retrieve if from the identity provider's dashboard + where you created your own OAuth app. optional, see all of the caveats in the + docs for clientId. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + emailAddresses: + description: |- + a list of email addresses of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + emailDomains: + description: |- + a list of email domains of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + Integer number of seconds of the maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + organizations: + description: |- + a list of github org identifiers. users who are members of any of the listed + organizations will be allowed access. identifiers should be the organization's + 'slug' + items: + type: string + type: array + scopes: + description: |- + a list of provider-specific OAuth scopes with the permissions your OAuth app + would like to ask for. these may not be set if you are using the ngrok-managed + oauth app (i.e. you must pass both client_id and client_secret to set scopes) + items: + type: string + type: array + teams: + description: |- + a list of github teams identifiers. users will be allowed access to the endpoint + if they are a member of any of these teams. identifiers should be in the 'slug' + format qualified with the org name, e.g. org-name/team-name + items: + type: string + type: array + type: object + gitlab: + description: configuration for using gitlab as the identity + provider + properties: + authCheckInterval: + description: |- + Duration after which ngrok guarantees it will refresh user + state from the identity provider and recheck whether the user is still + authorized to access the endpoint. This is the preferred tunable to use to + enforce a minimum amount of time after which a revoked user will no longer be + able to access the resource. + format: duration + type: string + clientId: + description: |- + the OAuth app client ID. retrieve it from the identity provider's dashboard + where you created your own OAuth app. optional. if unspecified, ngrok will use + its own managed oauth application which has additional restrictions. see the + OAuth module docs for more details. if present, clientSecret must be present as + well. + type: string + clientSecret: + description: |- + the OAuth app client secret. retrieve if from the identity provider's dashboard + where you created your own OAuth app. optional, see all of the caveats in the + docs for clientId. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + emailAddresses: + description: |- + a list of email addresses of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + emailDomains: + description: |- + a list of email domains of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + Integer number of seconds of the maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + scopes: + description: |- + a list of provider-specific OAuth scopes with the permissions your OAuth app + would like to ask for. these may not be set if you are using the ngrok-managed + oauth app (i.e. you must pass both client_id and client_secret to set scopes) + items: + type: string + type: array + type: object + google: + description: configuration for using google as the identity + provider + properties: + authCheckInterval: + description: |- + Duration after which ngrok guarantees it will refresh user + state from the identity provider and recheck whether the user is still + authorized to access the endpoint. This is the preferred tunable to use to + enforce a minimum amount of time after which a revoked user will no longer be + able to access the resource. + format: duration + type: string + clientId: + description: |- + the OAuth app client ID. retrieve it from the identity provider's dashboard + where you created your own OAuth app. optional. if unspecified, ngrok will use + its own managed oauth application which has additional restrictions. see the + OAuth module docs for more details. if present, clientSecret must be present as + well. + type: string + clientSecret: + description: |- + the OAuth app client secret. retrieve if from the identity provider's dashboard + where you created your own OAuth app. optional, see all of the caveats in the + docs for clientId. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + emailAddresses: + description: |- + a list of email addresses of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + emailDomains: + description: |- + a list of email domains of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + Integer number of seconds of the maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + scopes: + description: |- + a list of provider-specific OAuth scopes with the permissions your OAuth app + would like to ask for. these may not be set if you are using the ngrok-managed + oauth app (i.e. you must pass both client_id and client_secret to set scopes) + items: + type: string + type: array + type: object + linkedin: + description: configuration for using linkedin as the identity + provider + properties: + authCheckInterval: + description: |- + Duration after which ngrok guarantees it will refresh user + state from the identity provider and recheck whether the user is still + authorized to access the endpoint. This is the preferred tunable to use to + enforce a minimum amount of time after which a revoked user will no longer be + able to access the resource. + format: duration + type: string + clientId: + description: |- + the OAuth app client ID. retrieve it from the identity provider's dashboard + where you created your own OAuth app. optional. if unspecified, ngrok will use + its own managed oauth application which has additional restrictions. see the + OAuth module docs for more details. if present, clientSecret must be present as + well. + type: string + clientSecret: + description: |- + the OAuth app client secret. retrieve if from the identity provider's dashboard + where you created your own OAuth app. optional, see all of the caveats in the + docs for clientId. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + emailAddresses: + description: |- + a list of email addresses of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + emailDomains: + description: |- + a list of email domains of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + Integer number of seconds of the maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + scopes: + description: |- + a list of provider-specific OAuth scopes with the permissions your OAuth app + would like to ask for. these may not be set if you are using the ngrok-managed + oauth app (i.e. you must pass both client_id and client_secret to set scopes) + items: + type: string + type: array + type: object + microsoft: + description: configuration for using microsoft as the identity + provider + properties: + authCheckInterval: + description: |- + Duration after which ngrok guarantees it will refresh user + state from the identity provider and recheck whether the user is still + authorized to access the endpoint. This is the preferred tunable to use to + enforce a minimum amount of time after which a revoked user will no longer be + able to access the resource. + format: duration + type: string + clientId: + description: |- + the OAuth app client ID. retrieve it from the identity provider's dashboard + where you created your own OAuth app. optional. if unspecified, ngrok will use + its own managed oauth application which has additional restrictions. see the + OAuth module docs for more details. if present, clientSecret must be present as + well. + type: string + clientSecret: + description: |- + the OAuth app client secret. retrieve if from the identity provider's dashboard + where you created your own OAuth app. optional, see all of the caveats in the + docs for clientId. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + emailAddresses: + description: |- + a list of email addresses of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + emailDomains: + description: |- + a list of email domains of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + Integer number of seconds of the maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + scopes: + description: |- + a list of provider-specific OAuth scopes with the permissions your OAuth app + would like to ask for. these may not be set if you are using the ngrok-managed + oauth app (i.e. you must pass both client_id and client_secret to set scopes) + items: + type: string + type: array + type: object + twitch: + description: configuration for using twitch as the identity + provider + properties: + authCheckInterval: + description: |- + Duration after which ngrok guarantees it will refresh user + state from the identity provider and recheck whether the user is still + authorized to access the endpoint. This is the preferred tunable to use to + enforce a minimum amount of time after which a revoked user will no longer be + able to access the resource. + format: duration + type: string + clientId: + description: |- + the OAuth app client ID. retrieve it from the identity provider's dashboard + where you created your own OAuth app. optional. if unspecified, ngrok will use + its own managed oauth application which has additional restrictions. see the + OAuth module docs for more details. if present, clientSecret must be present as + well. + type: string + clientSecret: + description: |- + the OAuth app client secret. retrieve if from the identity provider's dashboard + where you created your own OAuth app. optional, see all of the caveats in the + docs for clientId. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + emailAddresses: + description: |- + a list of email addresses of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + emailDomains: + description: |- + a list of email domains of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + Integer number of seconds of the maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + scopes: + description: |- + a list of provider-specific OAuth scopes with the permissions your OAuth app + would like to ask for. these may not be set if you are using the ngrok-managed + oauth app (i.e. you must pass both client_id and client_secret to set scopes) + items: + type: string + type: array + type: object + type: object + oidc: + description: OIDC is the OpenID Connect configuration to apply + to this route + properties: + clientId: + description: The OIDC app's client ID and OIDC audience. + type: string + clientSecret: + description: The OIDC app's client secret. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + issuer: + description: URL of the OIDC "OpenID provider". This is + the base URL used for discovery. + type: string + maximumDuration: + description: |- + The maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + scopes: + description: The set of scopes to request from the OIDC + identity provider. + items: + type: string + type: array + type: object + policy: + description: raw json policy string that was applied to the + ngrok API + type: object + x-kubernetes-preserve-unknown-fields: true + saml: + description: SAML is the SAML configuration to apply to this + route + properties: + allowIdpInitiated: + description: |- + If true, the IdP may initiate a login directly (e.g. the user does not need to + visit the endpoint first and then be redirected). The IdP should set the + RelayState parameter to the target URL of the resource they want the user to be + redirected to after the SAML login assertion has been processed. + type: boolean + authorizedGroups: + description: |- + If present, only users who are a member of one of the listed groups may access + the target endpoint. + items: + type: string + type: array + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + forceAuthn: + description: |- + If true, indicates that whenever we redirect a user to the IdP for + authentication that the IdP must prompt the user for authentication credentials + even if the user already has a valid session with the IdP. + type: boolean + idpMetadata: + description: |- + The full XML IdP EntityDescriptor. Your IdP may provide this to you as a a file + to download or as a URL. + type: string + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + The maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + nameidFormat: + description: |- + Defines the name identifier format the SP expects the IdP to use in its + assertions to identify subjects. If unspecified, a default value of + urn:oasis:names:tc:SAML:2.0:nameid-format:persistent will be used. A subset of + the allowed values enumerated by the SAML specification are supported. + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + type: object + webhookVerification: + description: WebhookVerification is webhook verification configuration + to apply to this route + properties: + provider: + description: |- + a string indicating which webhook provider will be sending webhooks to this + endpoint. Value must be one of the supported providers defined at + https://ngrok.com/docs/http/webhook-verification/#supported-providers + type: string + secret: + description: |- + SecretRef is a reference to a secret containing the secret used to validate + requests from the given provider. All providers except AWS SNS require a secret + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + type: object + required: + - match + - matchType + type: object + type: array + tlsTermination: + description: TLSTermination is the TLS termination configuration for + this edge + properties: + minVersion: + description: MinVersion is the minimum TLS version to allow for + connections to the edge + type: string + type: object + type: object + status: + description: HTTPSEdgeStatus defines the observed state of HTTPSEdge + properties: + id: + description: ID is the unique identifier for this edge + type: string + routes: + items: + properties: + backend: + description: |- + Backend stores the status of the tunnel group backend, + mainly the ID of the backend + properties: + id: + description: ID is the unique identifier for this backend + type: string + type: object + id: + description: ID is the unique identifier for this route + type: string + match: + type: string + matchType: + type: string + uri: + description: URI is the URI for this route + type: string + type: object + type: array + uri: + description: URI is the URI for this edge + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_ippolicies.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_ippolicies.yaml new file mode 100644 index 000000000..1508f7602 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_ippolicies.yaml @@ -0,0 +1,109 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: ippolicies.ingress.k8s.ngrok.com +spec: + group: ingress.k8s.ngrok.com + names: + kind: IPPolicy + listKind: IPPolicyList + plural: ippolicies + singular: ippolicy + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: IPPolicy ID + jsonPath: .status.id + name: ID + type: string + - description: Age + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: IPPolicy is the Schema for the ippolicies API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: IPPolicySpec defines the desired state of IPPolicy + properties: + description: + default: Created by kubernetes-ingress-controller + description: Description is a human-readable description of the object + in the ngrok API/Dashboard + type: string + metadata: + default: '{"owned-by":"kubernetes-ingress-controller"}' + description: Metadata is a string of arbitrary data associated with + the object in the ngrok API/Dashboard + type: string + rules: + description: Rules is a list of rules that belong to the policy + items: + properties: + action: + enum: + - allow + - deny + type: string + cidr: + type: string + description: + default: Created by kubernetes-ingress-controller + description: Description is a human-readable description of + the object in the ngrok API/Dashboard + type: string + metadata: + default: '{"owned-by":"kubernetes-ingress-controller"}' + description: Metadata is a string of arbitrary data associated + with the object in the ngrok API/Dashboard + type: string + type: object + type: array + type: object + status: + description: IPPolicyStatus defines the observed state of IPPolicy + properties: + id: + description: |- + INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + Important: Run "make" to regenerate code after modifying this file + type: string + rules: + items: + properties: + action: + type: string + cidr: + type: string + id: + type: string + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_ngrokmodulesets.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_ngrokmodulesets.yaml new file mode 100644 index 000000000..ef4a5a8c7 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_ngrokmodulesets.yaml @@ -0,0 +1,1008 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: ngrokmodulesets.ingress.k8s.ngrok.com +spec: + group: ingress.k8s.ngrok.com + names: + kind: NgrokModuleSet + listKind: NgrokModuleSetList + plural: ngrokmodulesets + singular: ngrokmoduleset + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: NgrokModuleSet is the Schema for the ngrokmodules API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + modules: + properties: + circuitBreaker: + description: CircuitBreaker configuration for this module set + properties: + errorThresholdPercentage: + anyOf: + - type: integer + - type: string + description: Error threshold percentage should be between 0 - + 1.0, not 0-100.0 + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + numBuckets: + description: Integer number of buckets into which metrics are + retained. Max 128. + format: int32 + maximum: 128 + minimum: 1 + type: integer + rollingWindow: + description: Statistical rolling window duration that metrics + are retained for. + format: duration + type: string + trippedDuration: + description: Duration after which the circuit is tripped to wait + before re-evaluating upstream health + format: duration + type: string + volumeThreshold: + description: |- + Integer number of requests in a rolling window that will trip the circuit. + Helpful if traffic volume is low. + format: int32 + type: integer + type: object + compression: + description: Compression configuration for this module set + properties: + enabled: + description: Enabled is whether or not to enable compression for + this endpoint + type: boolean + type: object + headers: + description: Header configuration for this module set + properties: + request: + description: Request headers are the request headers module configuration + or null + properties: + add: + additionalProperties: + type: string + description: |- + a map of header key to header value that will be injected into the HTTP Request + before being sent to the upstream application server + type: object + remove: + description: |- + a list of header names that will be removed from the HTTP Request before being + sent to the upstream application server + items: + type: string + type: array + type: object + response: + description: Response headers are the response headers module + configuration or null + properties: + add: + additionalProperties: + type: string + description: |- + a map of header key to header value that will be injected into the HTTP Response + returned to the HTTP client + type: object + remove: + description: |- + a list of header names that will be removed from the HTTP Response returned to + the HTTP client + items: + type: string + type: array + type: object + type: object + ipRestriction: + description: IPRestriction configuration for this module set + properties: + policies: + items: + type: string + type: array + type: object + mutualTLS: + description: MutualTLS configuration for this module set + properties: + certificateAuthorities: + description: |- + List of CA IDs that will be used to validate incoming connections to the + edge. + items: + type: string + type: array + type: object + oauth: + description: OAuth configuration for this module set + properties: + amazon: + description: configuration for using amazon as the identity provider + properties: + authCheckInterval: + description: |- + Duration after which ngrok guarantees it will refresh user + state from the identity provider and recheck whether the user is still + authorized to access the endpoint. This is the preferred tunable to use to + enforce a minimum amount of time after which a revoked user will no longer be + able to access the resource. + format: duration + type: string + clientId: + description: |- + the OAuth app client ID. retrieve it from the identity provider's dashboard + where you created your own OAuth app. optional. if unspecified, ngrok will use + its own managed oauth application which has additional restrictions. see the + OAuth module docs for more details. if present, clientSecret must be present as + well. + type: string + clientSecret: + description: |- + the OAuth app client secret. retrieve if from the identity provider's dashboard + where you created your own OAuth app. optional, see all of the caveats in the + docs for clientId. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + emailAddresses: + description: |- + a list of email addresses of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + emailDomains: + description: |- + a list of email domains of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + Integer number of seconds of the maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + scopes: + description: |- + a list of provider-specific OAuth scopes with the permissions your OAuth app + would like to ask for. these may not be set if you are using the ngrok-managed + oauth app (i.e. you must pass both client_id and client_secret to set scopes) + items: + type: string + type: array + type: object + facebook: + description: configuration for using facebook as the identity + provider + properties: + authCheckInterval: + description: |- + Duration after which ngrok guarantees it will refresh user + state from the identity provider and recheck whether the user is still + authorized to access the endpoint. This is the preferred tunable to use to + enforce a minimum amount of time after which a revoked user will no longer be + able to access the resource. + format: duration + type: string + clientId: + description: |- + the OAuth app client ID. retrieve it from the identity provider's dashboard + where you created your own OAuth app. optional. if unspecified, ngrok will use + its own managed oauth application which has additional restrictions. see the + OAuth module docs for more details. if present, clientSecret must be present as + well. + type: string + clientSecret: + description: |- + the OAuth app client secret. retrieve if from the identity provider's dashboard + where you created your own OAuth app. optional, see all of the caveats in the + docs for clientId. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + emailAddresses: + description: |- + a list of email addresses of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + emailDomains: + description: |- + a list of email domains of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + Integer number of seconds of the maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + scopes: + description: |- + a list of provider-specific OAuth scopes with the permissions your OAuth app + would like to ask for. these may not be set if you are using the ngrok-managed + oauth app (i.e. you must pass both client_id and client_secret to set scopes) + items: + type: string + type: array + type: object + github: + description: configuration for using github as the identity provider + properties: + authCheckInterval: + description: |- + Duration after which ngrok guarantees it will refresh user + state from the identity provider and recheck whether the user is still + authorized to access the endpoint. This is the preferred tunable to use to + enforce a minimum amount of time after which a revoked user will no longer be + able to access the resource. + format: duration + type: string + clientId: + description: |- + the OAuth app client ID. retrieve it from the identity provider's dashboard + where you created your own OAuth app. optional. if unspecified, ngrok will use + its own managed oauth application which has additional restrictions. see the + OAuth module docs for more details. if present, clientSecret must be present as + well. + type: string + clientSecret: + description: |- + the OAuth app client secret. retrieve if from the identity provider's dashboard + where you created your own OAuth app. optional, see all of the caveats in the + docs for clientId. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + emailAddresses: + description: |- + a list of email addresses of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + emailDomains: + description: |- + a list of email domains of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + Integer number of seconds of the maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + organizations: + description: |- + a list of github org identifiers. users who are members of any of the listed + organizations will be allowed access. identifiers should be the organization's + 'slug' + items: + type: string + type: array + scopes: + description: |- + a list of provider-specific OAuth scopes with the permissions your OAuth app + would like to ask for. these may not be set if you are using the ngrok-managed + oauth app (i.e. you must pass both client_id and client_secret to set scopes) + items: + type: string + type: array + teams: + description: |- + a list of github teams identifiers. users will be allowed access to the endpoint + if they are a member of any of these teams. identifiers should be in the 'slug' + format qualified with the org name, e.g. org-name/team-name + items: + type: string + type: array + type: object + gitlab: + description: configuration for using gitlab as the identity provider + properties: + authCheckInterval: + description: |- + Duration after which ngrok guarantees it will refresh user + state from the identity provider and recheck whether the user is still + authorized to access the endpoint. This is the preferred tunable to use to + enforce a minimum amount of time after which a revoked user will no longer be + able to access the resource. + format: duration + type: string + clientId: + description: |- + the OAuth app client ID. retrieve it from the identity provider's dashboard + where you created your own OAuth app. optional. if unspecified, ngrok will use + its own managed oauth application which has additional restrictions. see the + OAuth module docs for more details. if present, clientSecret must be present as + well. + type: string + clientSecret: + description: |- + the OAuth app client secret. retrieve if from the identity provider's dashboard + where you created your own OAuth app. optional, see all of the caveats in the + docs for clientId. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + emailAddresses: + description: |- + a list of email addresses of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + emailDomains: + description: |- + a list of email domains of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + Integer number of seconds of the maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + scopes: + description: |- + a list of provider-specific OAuth scopes with the permissions your OAuth app + would like to ask for. these may not be set if you are using the ngrok-managed + oauth app (i.e. you must pass both client_id and client_secret to set scopes) + items: + type: string + type: array + type: object + google: + description: configuration for using google as the identity provider + properties: + authCheckInterval: + description: |- + Duration after which ngrok guarantees it will refresh user + state from the identity provider and recheck whether the user is still + authorized to access the endpoint. This is the preferred tunable to use to + enforce a minimum amount of time after which a revoked user will no longer be + able to access the resource. + format: duration + type: string + clientId: + description: |- + the OAuth app client ID. retrieve it from the identity provider's dashboard + where you created your own OAuth app. optional. if unspecified, ngrok will use + its own managed oauth application which has additional restrictions. see the + OAuth module docs for more details. if present, clientSecret must be present as + well. + type: string + clientSecret: + description: |- + the OAuth app client secret. retrieve if from the identity provider's dashboard + where you created your own OAuth app. optional, see all of the caveats in the + docs for clientId. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + emailAddresses: + description: |- + a list of email addresses of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + emailDomains: + description: |- + a list of email domains of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + Integer number of seconds of the maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + scopes: + description: |- + a list of provider-specific OAuth scopes with the permissions your OAuth app + would like to ask for. these may not be set if you are using the ngrok-managed + oauth app (i.e. you must pass both client_id and client_secret to set scopes) + items: + type: string + type: array + type: object + linkedin: + description: configuration for using linkedin as the identity + provider + properties: + authCheckInterval: + description: |- + Duration after which ngrok guarantees it will refresh user + state from the identity provider and recheck whether the user is still + authorized to access the endpoint. This is the preferred tunable to use to + enforce a minimum amount of time after which a revoked user will no longer be + able to access the resource. + format: duration + type: string + clientId: + description: |- + the OAuth app client ID. retrieve it from the identity provider's dashboard + where you created your own OAuth app. optional. if unspecified, ngrok will use + its own managed oauth application which has additional restrictions. see the + OAuth module docs for more details. if present, clientSecret must be present as + well. + type: string + clientSecret: + description: |- + the OAuth app client secret. retrieve if from the identity provider's dashboard + where you created your own OAuth app. optional, see all of the caveats in the + docs for clientId. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + emailAddresses: + description: |- + a list of email addresses of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + emailDomains: + description: |- + a list of email domains of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + Integer number of seconds of the maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + scopes: + description: |- + a list of provider-specific OAuth scopes with the permissions your OAuth app + would like to ask for. these may not be set if you are using the ngrok-managed + oauth app (i.e. you must pass both client_id and client_secret to set scopes) + items: + type: string + type: array + type: object + microsoft: + description: configuration for using microsoft as the identity + provider + properties: + authCheckInterval: + description: |- + Duration after which ngrok guarantees it will refresh user + state from the identity provider and recheck whether the user is still + authorized to access the endpoint. This is the preferred tunable to use to + enforce a minimum amount of time after which a revoked user will no longer be + able to access the resource. + format: duration + type: string + clientId: + description: |- + the OAuth app client ID. retrieve it from the identity provider's dashboard + where you created your own OAuth app. optional. if unspecified, ngrok will use + its own managed oauth application which has additional restrictions. see the + OAuth module docs for more details. if present, clientSecret must be present as + well. + type: string + clientSecret: + description: |- + the OAuth app client secret. retrieve if from the identity provider's dashboard + where you created your own OAuth app. optional, see all of the caveats in the + docs for clientId. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + emailAddresses: + description: |- + a list of email addresses of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + emailDomains: + description: |- + a list of email domains of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + Integer number of seconds of the maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + scopes: + description: |- + a list of provider-specific OAuth scopes with the permissions your OAuth app + would like to ask for. these may not be set if you are using the ngrok-managed + oauth app (i.e. you must pass both client_id and client_secret to set scopes) + items: + type: string + type: array + type: object + twitch: + description: configuration for using twitch as the identity provider + properties: + authCheckInterval: + description: |- + Duration after which ngrok guarantees it will refresh user + state from the identity provider and recheck whether the user is still + authorized to access the endpoint. This is the preferred tunable to use to + enforce a minimum amount of time after which a revoked user will no longer be + able to access the resource. + format: duration + type: string + clientId: + description: |- + the OAuth app client ID. retrieve it from the identity provider's dashboard + where you created your own OAuth app. optional. if unspecified, ngrok will use + its own managed oauth application which has additional restrictions. see the + OAuth module docs for more details. if present, clientSecret must be present as + well. + type: string + clientSecret: + description: |- + the OAuth app client secret. retrieve if from the identity provider's dashboard + where you created your own OAuth app. optional, see all of the caveats in the + docs for clientId. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + emailAddresses: + description: |- + a list of email addresses of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + emailDomains: + description: |- + a list of email domains of users authenticated by identity provider who are + allowed access to the endpoint + items: + type: string + type: array + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + Integer number of seconds of the maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + scopes: + description: |- + a list of provider-specific OAuth scopes with the permissions your OAuth app + would like to ask for. these may not be set if you are using the ngrok-managed + oauth app (i.e. you must pass both client_id and client_secret to set scopes) + items: + type: string + type: array + type: object + type: object + oidc: + description: OIDC configuration for this module set + properties: + clientId: + description: The OIDC app's client ID and OIDC audience. + type: string + clientSecret: + description: The OIDC app's client secret. + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + issuer: + description: URL of the OIDC "OpenID provider". This is the base + URL used for discovery. + type: string + maximumDuration: + description: |- + The maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + scopes: + description: The set of scopes to request from the OIDC identity + provider. + items: + type: string + type: array + type: object + policy: + description: Policy configuration for this module set + properties: + enabled: + description: Determines if the rule will be applied to traffic + type: boolean + inbound: + description: Inbound traffic rule + items: + properties: + actions: + description: Actions + items: + properties: + config: + type: object + x-kubernetes-preserve-unknown-fields: true + type: + type: string + type: object + type: array + expressions: + description: Expressions + items: + type: string + type: array + name: + description: Name + type: string + type: object + type: array + outbound: + description: Outbound traffic rule + items: + properties: + actions: + description: Actions + items: + properties: + config: + type: object + x-kubernetes-preserve-unknown-fields: true + type: + type: string + type: object + type: array + expressions: + description: Expressions + items: + type: string + type: array + name: + description: Name + type: string + type: object + type: array + type: object + saml: + description: SAML configuration for this module set + properties: + allowIdpInitiated: + description: |- + If true, the IdP may initiate a login directly (e.g. the user does not need to + visit the endpoint first and then be redirected). The IdP should set the + RelayState parameter to the target URL of the resource they want the user to be + redirected to after the SAML login assertion has been processed. + type: boolean + authorizedGroups: + description: |- + If present, only users who are a member of one of the listed groups may access + the target endpoint. + items: + type: string + type: array + cookiePrefix: + description: |- + the prefix of the session cookie that ngrok sets on the http client to cache + authentication. default is 'ngrok.' + type: string + forceAuthn: + description: |- + If true, indicates that whenever we redirect a user to the IdP for + authentication that the IdP must prompt the user for authentication credentials + even if the user already has a valid session with the IdP. + type: boolean + idpMetadata: + description: |- + The full XML IdP EntityDescriptor. Your IdP may provide this to you as a a file + to download or as a URL. + type: string + inactivityTimeout: + description: |- + Duration of inactivity after which if the user has not accessed + the endpoint, their session will time out and they will be forced to + reauthenticate. + format: duration + type: string + maximumDuration: + description: |- + The maximum duration of an authenticated session. + After this period is exceeded, a user must reauthenticate. + format: duration + type: string + nameidFormat: + description: |- + Defines the name identifier format the SP expects the IdP to use in its + assertions to identify subjects. If unspecified, a default value of + urn:oasis:names:tc:SAML:2.0:nameid-format:persistent will be used. A subset of + the allowed values enumerated by the SAML specification are supported. + type: string + optionsPassthrough: + description: |- + Do not enforce authentication on HTTP OPTIONS requests. necessary if you are + supporting CORS. + type: boolean + type: object + tlsTermination: + description: TLSTermination configuration for this module set + properties: + minVersion: + description: MinVersion is the minimum TLS version to allow for + connections to the edge + type: string + terminateAt: + description: |- + TerminateAt determines where the TLS connection should be terminated. + "edge" if the ngrok edge should terminate TLS traffic, "upstream" if TLS + traffic should be passed through to the upstream ngrok agent / + application server for termination. + type: string + type: object + webhookVerification: + description: WebhookVerification configuration for this module set + properties: + provider: + description: |- + a string indicating which webhook provider will be sending webhooks to this + endpoint. Value must be one of the supported providers defined at + https://ngrok.com/docs/http/webhook-verification/#supported-providers + type: string + secret: + description: |- + SecretRef is a reference to a secret containing the secret used to validate + requests from the given provider. All providers except AWS SNS require a secret + properties: + key: + description: Key in the secret to use + type: string + name: + description: Name of the Kubernetes secret + type: string + type: object + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_tcpedges.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_tcpedges.yaml new file mode 100644 index 000000000..020162081 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_tcpedges.yaml @@ -0,0 +1,132 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: tcpedges.ingress.k8s.ngrok.com +spec: + group: ingress.k8s.ngrok.com + names: + kind: TCPEdge + listKind: TCPEdgeList + plural: tcpedges + singular: tcpedge + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Domain ID + jsonPath: .status.id + name: ID + type: string + - description: Hostports + jsonPath: .status.hostports + name: Hostports + type: string + - description: Tunnel Group Backend ID + jsonPath: .status.backend.id + name: Backend ID + type: string + - description: Age + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: TCPEdge is the Schema for the tcpedges API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: TCPEdgeSpec defines the desired state of TCPEdge + properties: + backend: + description: |- + Backend is the definition for the tunnel group backend + that serves traffic for this edge + properties: + description: + default: Created by kubernetes-ingress-controller + description: Description is a human-readable description of the + object in the ngrok API/Dashboard + type: string + labels: + additionalProperties: + type: string + description: Labels to watch for tunnels on this backend + type: object + metadata: + default: '{"owned-by":"kubernetes-ingress-controller"}' + description: Metadata is a string of arbitrary data associated + with the object in the ngrok API/Dashboard + type: string + type: object + description: + default: Created by kubernetes-ingress-controller + description: Description is a human-readable description of the object + in the ngrok API/Dashboard + type: string + ipRestriction: + description: IPRestriction is an IPRestriction to apply to this edge + properties: + policies: + items: + type: string + type: array + type: object + metadata: + default: '{"owned-by":"kubernetes-ingress-controller"}' + description: Metadata is a string of arbitrary data associated with + the object in the ngrok API/Dashboard + type: string + policy: + description: raw json policy string that was applied to the ngrok + API + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + status: + description: TCPEdgeStatus defines the observed state of TCPEdge + properties: + backend: + description: |- + Backend stores the status of the tunnel group backend, + mainly the ID of the backend + properties: + id: + description: ID is the unique identifier for this backend + type: string + type: object + hostports: + description: Hostports served by this edge + items: + type: string + type: array + id: + description: ID is the unique identifier for this edge + type: string + uri: + description: URI is the URI of the edge + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_tlsedges.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_tlsedges.yaml new file mode 100644 index 000000000..4aa99d3d0 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_tlsedges.yaml @@ -0,0 +1,166 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: tlsedges.ingress.k8s.ngrok.com +spec: + group: ingress.k8s.ngrok.com + names: + kind: TLSEdge + listKind: TLSEdgeList + plural: tlsedges + singular: tlsedge + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Domain ID + jsonPath: .status.id + name: ID + type: string + - description: Hostports + jsonPath: .status.hostports + name: Hostports + type: string + - description: Tunnel Group Backend ID + jsonPath: .status.backend.id + name: Backend ID + type: string + - description: Age + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: TLSEdge is the Schema for the tlsedges API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: TLSEdgeSpec defines the desired state of TLSEdge + properties: + backend: + description: |- + Backend is the definition for the tunnel group backend + that serves traffic for this edge + properties: + description: + default: Created by kubernetes-ingress-controller + description: Description is a human-readable description of the + object in the ngrok API/Dashboard + type: string + labels: + additionalProperties: + type: string + description: Labels to watch for tunnels on this backend + type: object + metadata: + default: '{"owned-by":"kubernetes-ingress-controller"}' + description: Metadata is a string of arbitrary data associated + with the object in the ngrok API/Dashboard + type: string + type: object + description: + default: Created by kubernetes-ingress-controller + description: Description is a human-readable description of the object + in the ngrok API/Dashboard + type: string + hostports: + description: Hostports is a list of hostports served by this edge + items: + type: string + type: array + ipRestriction: + description: IPRestriction is an IPRestriction to apply to this edge + properties: + policies: + items: + type: string + type: array + type: object + metadata: + default: '{"owned-by":"kubernetes-ingress-controller"}' + description: Metadata is a string of arbitrary data associated with + the object in the ngrok API/Dashboard + type: string + mutualTls: + properties: + certificateAuthorities: + description: |- + List of CA IDs that will be used to validate incoming connections to the + edge. + items: + type: string + type: array + type: object + policy: + description: raw json policy string that was applied to the ngrok + API + type: object + x-kubernetes-preserve-unknown-fields: true + tlsTermination: + properties: + minVersion: + description: MinVersion is the minimum TLS version to allow for + connections to the edge + type: string + terminateAt: + description: |- + TerminateAt determines where the TLS connection should be terminated. + "edge" if the ngrok edge should terminate TLS traffic, "upstream" if TLS + traffic should be passed through to the upstream ngrok agent / + application server for termination. + type: string + type: object + type: object + status: + description: TLSEdgeStatus defines the observed state of TLSEdge + properties: + backend: + description: |- + Backend stores the status of the tunnel group backend, + mainly the ID of the backend + properties: + id: + description: ID is the unique identifier for this backend + type: string + type: object + cnameTargets: + additionalProperties: + type: string + description: Map of hostports to the ngrok assigned CNAME targets + type: object + hostports: + description: Hostports served by this edge + items: + type: string + type: array + id: + description: ID is the unique identifier for this edge + type: string + uri: + description: URI is the URI of the edge + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_tunnels.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_tunnels.yaml new file mode 100644 index 000000000..e440dbdc3 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ingress.k8s.ngrok.com_tunnels.yaml @@ -0,0 +1,78 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: tunnels.ingress.k8s.ngrok.com +spec: + group: ingress.k8s.ngrok.com + names: + kind: Tunnel + listKind: TunnelList + plural: tunnels + singular: tunnel + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Service/port to forward to + jsonPath: .spec.forwardsTo + name: ForwardsTo + type: string + - description: Age + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Tunnel is the Schema for the tunnels API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: TunnelSpec defines the desired state of Tunnel + properties: + appProtocol: + description: The appProtocol for the backend. Currently only supports + `http2` + type: string + backend: + description: The configuration for backend connections to services + properties: + protocol: + type: string + type: object + forwardsTo: + description: ForwardsTo is the name and port of the service to forward + traffic to + type: string + labels: + additionalProperties: + type: string + description: Labels are key/value pairs that are attached to the tunnel + type: object + type: object + status: + description: TunnelStatus defines the observed state of Tunnel + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ngrok.k8s.ngrok.com_ngroktrafficpolicies.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ngrok.k8s.ngrok.com_ngroktrafficpolicies.yaml new file mode 100644 index 000000000..463f92757 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/crds/ngrok.k8s.ngrok.com_ngroktrafficpolicies.yaml @@ -0,0 +1,62 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: ngroktrafficpolicies.ngrok.k8s.ngrok.com +spec: + group: ngrok.k8s.ngrok.com + names: + kind: NgrokTrafficPolicy + listKind: NgrokTrafficPolicyList + plural: ngroktrafficpolicies + singular: ngroktrafficpolicy + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: NgrokTrafficPolicy is the Schema for the ngroktrafficpolicies + API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: NgrokTrafficPolicySpec defines the desired state of NgrokTrafficPolicy + properties: + policy: + description: The raw json encoded policy that was applied to the ngrok + API + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + status: + description: NgrokTrafficPolicyStatus defines the observed state of NgrokTrafficPolicy + properties: + policy: + description: The raw json encoded policy that was applied to the ngrok + API + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/credentials-secret.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/credentials-secret.yaml new file mode 100644 index 000000000..c6c7286ea --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/credentials-secret.yaml @@ -0,0 +1,11 @@ +{{- if or (not (empty .Values.credentials.apiKey)) (not (empty .Values.credentials.authtoken)) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "kubernetes-ingress-controller.credentialsSecretName" .}} + namespace: {{ .Release.Namespace }} +type: Opaque +data: + API_KEY: {{ required "An ngrok API key is required" .Values.credentials.apiKey | b64enc }} + AUTHTOKEN: {{ required "An ngrok Authtoken is required" .Values.credentials.authtoken | b64enc }} +{{ end }} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/ingress-class.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/ingress-class.yaml new file mode 100644 index 000000000..0932b4705 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/ingress-class.yaml @@ -0,0 +1,15 @@ +{{- if .Values.ingressClass.create -}} +apiVersion: networking.k8s.io/v1 +kind: IngressClass +metadata: + labels: + {{- include "kubernetes-ingress-controller.labels" . | nindent 4 }} + app.kubernetes.io/component: controller + name: {{ .Values.ingressClass.name }} + {{- if .Values.ingressClass.default }} + annotations: + ingressclass.kubernetes.io/is-default-class: "true" + {{- end }} +spec: + controller: {{ .Values.controllerName }} +{{- end}} diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/domain_editor_role.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/domain_editor_role.yaml new file mode 100644 index 000000000..88e527a3f --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/domain_editor_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to edit domains. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "kubernetes-ingress-controller.labels" . | nindent 4 }} + app.kubernetes.io/component: rbac + name: {{ include "kubernetes-ingress-controller.fullname" . }}-domain-editor-role +rules: +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - domains + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - domains/status + verbs: + - get diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/domain_viewer_role.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/domain_viewer_role.yaml new file mode 100644 index 000000000..bf5f5196e --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/domain_viewer_role.yaml @@ -0,0 +1,23 @@ +# permissions for end users to view domains. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "kubernetes-ingress-controller.labels" . | nindent 4 }} + app.kubernetes.io/component: rbac + name: {{ include "kubernetes-ingress-controller.fullname" . }}-domain-viewer-role +rules: +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - domains + verbs: + - get + - list + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - domains/status + verbs: + - get diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/httpsedge_editor_role.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/httpsedge_editor_role.yaml new file mode 100644 index 000000000..d4d383154 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/httpsedge_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit httpsedges. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: httpsedge-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: ngrok-ingress-controller + app.kubernetes.io/part-of: ngrok-ingress-controller + app.kubernetes.io/managed-by: kustomize + name: httpsedge-editor-role +rules: +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - httpsedges + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - httpsedges/status + verbs: + - get diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/httpsedge_viewer_role.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/httpsedge_viewer_role.yaml new file mode 100644 index 000000000..8d01cd726 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/httpsedge_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view httpsedges. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: httpsedge-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: ngrok-ingress-controller + app.kubernetes.io/part-of: ngrok-ingress-controller + app.kubernetes.io/managed-by: kustomize + name: httpsedge-viewer-role +rules: +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - httpsedges + verbs: + - get + - list + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - httpsedges/status + verbs: + - get diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/ippolicy_editor_role.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/ippolicy_editor_role.yaml new file mode 100644 index 000000000..a8aa5ebe6 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/ippolicy_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit ippolicies. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: ippolicy-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: ngrok-ingress-controller + app.kubernetes.io/part-of: ngrok-ingress-controller + app.kubernetes.io/managed-by: kustomize + name: ippolicy-editor-role +rules: +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - ippolicies + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - ippolicies/status + verbs: + - get diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/ippolicy_viewer_role.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/ippolicy_viewer_role.yaml new file mode 100644 index 000000000..a83a34ab6 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/ippolicy_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view ippolicies. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: ippolicy-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: ngrok-ingress-controller + app.kubernetes.io/part-of: ngrok-ingress-controller + app.kubernetes.io/managed-by: kustomize + name: ippolicy-viewer-role +rules: +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - ippolicies + verbs: + - get + - list + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - ippolicies/status + verbs: + - get diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/ngrokmoduleset_editor_role.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/ngrokmoduleset_editor_role.yaml new file mode 100644 index 000000000..c8d5f1631 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/ngrokmoduleset_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit ngrokmodulesets. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: ngrokmoduleset-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: kubernetes-ingress-controller + app.kubernetes.io/part-of: kubernetes-ingress-controller + app.kubernetes.io/managed-by: kustomize + name: ngrokmoduleset-editor-role +rules: +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - ngrokmodulesets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - ngrokmodulesets/status + verbs: + - get diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/ngrokmoduleset_viewer_role.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/ngrokmoduleset_viewer_role.yaml new file mode 100644 index 000000000..a9948ad44 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/ngrokmoduleset_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view ngrokmodulesets. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: ngrokmoduleset-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: kubernetes-ingress-controller + app.kubernetes.io/part-of: kubernetes-ingress-controller + app.kubernetes.io/managed-by: kustomize + name: ngrokmoduleset-viewer-role +rules: +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - ngrokmodulesets + verbs: + - get + - list + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - ngrokmodulesets/status + verbs: + - get diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/role.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/role.yaml new file mode 100644 index 000000000..4b05ac606 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/role.yaml @@ -0,0 +1,330 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: ngrok-ingress-controller-manager-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - delete + - get + - list + - update + - watch +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - update + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - services + verbs: + - get + - list + - update + - watch +- apiGroups: + - "" + resources: + - services/status + verbs: + - get + - list + - patch + - update + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - gatewayclasses + verbs: + - get + - list + - update + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - gatewayclasses/status + verbs: + - get + - list + - update + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - gateways + verbs: + - get + - list + - update + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - gateways/status + verbs: + - get + - list + - update + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - httproutes + verbs: + - get + - list + - update + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - httproutes/status + verbs: + - get + - list + - update + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - domains + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - domains/finalizers + verbs: + - update +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - domains/status + verbs: + - get + - patch + - update +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - httpsedges + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - httpsedges/finalizers + verbs: + - update +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - httpsedges/status + verbs: + - get + - patch + - update +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - ippolicies + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - ippolicies/finalizers + verbs: + - update +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - ippolicies/status + verbs: + - get + - patch + - update +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - ngrokmodulesets + verbs: + - get + - list + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tcpedges + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tcpedges/finalizers + verbs: + - update +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tcpedges/status + verbs: + - get + - patch + - update +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tlsedges + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tlsedges/finalizers + verbs: + - update +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tlsedges/status + verbs: + - get + - patch + - update +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tunnels + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tunnels/finalizers + verbs: + - update +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tunnels/status + verbs: + - get + - patch + - update +- apiGroups: + - networking.k8s.io + resources: + - ingressclasses + verbs: + - get + - list + - watch +- apiGroups: + - networking.k8s.io + resources: + - ingresses + verbs: + - get + - list + - update + - watch +- apiGroups: + - networking.k8s.io + resources: + - ingresses/status + verbs: + - get + - list + - update + - watch +- apiGroups: + - ngrok.k8s.ngrok.com + resources: + - ngroktrafficpolicies + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ngrok.k8s.ngrok.com + resources: + - ngroktrafficpolicies/finalizers + verbs: + - update +- apiGroups: + - ngrok.k8s.ngrok.com + resources: + - ngroktrafficpolicies/status + verbs: + - get + - patch + - update diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tcpedge_editor_role.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tcpedge_editor_role.yaml new file mode 100644 index 000000000..2e49847f8 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tcpedge_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit tcpedges. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: tcpedge-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: ngrok-ingress-controller + app.kubernetes.io/part-of: ngrok-ingress-controller + app.kubernetes.io/managed-by: kustomize + name: tcpedge-editor-role +rules: +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tcpedges + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tcpedges/status + verbs: + - get diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tcpedge_viewer_role.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tcpedge_viewer_role.yaml new file mode 100644 index 000000000..b8eb5ef1f --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tcpedge_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view tcpedges. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: tcpedge-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: ngrok-ingress-controller + app.kubernetes.io/part-of: ngrok-ingress-controller + app.kubernetes.io/managed-by: kustomize + name: tcpedge-viewer-role +rules: +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tcpedges + verbs: + - get + - list + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tcpedges/status + verbs: + - get diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tlsedge_editor_role.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tlsedge_editor_role.yaml new file mode 100644 index 000000000..9d0523191 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tlsedge_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit tlsedges. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: tlsedge-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: ngrok-ingress-controller + app.kubernetes.io/part-of: ngrok-ingress-controller + app.kubernetes.io/managed-by: kustomize + name: tlsedge-editor-role +rules: +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tlsedges + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tlsedges/status + verbs: + - get diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tlsedge_viewer_role.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tlsedge_viewer_role.yaml new file mode 100644 index 000000000..a9eb99d91 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tlsedge_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view tlsedges. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: tlsedge-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: ngrok-ingress-controller + app.kubernetes.io/part-of: ngrok-ingress-controller + app.kubernetes.io/managed-by: kustomize + name: tlsedge-viewer-role +rules: +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tlsedges + verbs: + - get + - list + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tlsedges/status + verbs: + - get diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tunnel_editor_role.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tunnel_editor_role.yaml new file mode 100644 index 000000000..ab7275165 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tunnel_editor_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to edit tunnels. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "kubernetes-ingress-controller.labels" . | nindent 4 }} + app.kubernetes.io/component: rbac + name: {{ include "kubernetes-ingress-controller.fullname" . }}-tunnel-editor-role +rules: +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tunnels + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tunnels/status + verbs: + - get diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tunnel_viewer_role.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tunnel_viewer_role.yaml new file mode 100644 index 000000000..dfdb4b6f0 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/templates/rbac/tunnel_viewer_role.yaml @@ -0,0 +1,23 @@ +# permissions for end users to view tunnels. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "kubernetes-ingress-controller.labels" . | nindent 4 }} + app.kubernetes.io/component: rbac + name: {{ include "kubernetes-ingress-controller.fullname" . }}-tunnel-viewer-role +rules: +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tunnels + verbs: + - get + - list + - watch +- apiGroups: + - ingress.k8s.ngrok.com + resources: + - tunnels/status + verbs: + - get diff --git a/charts/ngrok/kubernetes-ingress-controller/0.14.3/values.yaml b/charts/ngrok/kubernetes-ingress-controller/0.14.3/values.yaml new file mode 100644 index 000000000..d179331d6 --- /dev/null +++ b/charts/ngrok/kubernetes-ingress-controller/0.14.3/values.yaml @@ -0,0 +1,205 @@ +## @section Common parameters +## + +## @param nameOverride String to partially override generated resource names +## @param fullnameOverride String to fully override generated resource names +## @param commonLabels Labels to add to all deployed objects +## @param commonAnnotations Annotations to add to all deployed objects +## +nameOverride: "" +fullnameOverride: "" +commonLabels: {} +commonAnnotations: {} + +## @section Controller parameters +## + +## @param podAnnotations Used to apply custom annotations to the ingress pods. +## @param podLabels Used to apply custom labels to the ingress pods. +## +podAnnotations: {} +podLabels: {} + +## @param replicaCount The number of controllers to run. +## A minimum of 2 is recommended in production for HA. +## +replicaCount: 1 + +## @param image.registry The ngrok ingress controller image registry. +## @param image.repository The ngrok ingress controller image repository. +## @param image.tag The ngrok ingress controller image tag. Defaults to the chart's appVersion if not specified +## @param image.pullPolicy The ngrok ingress controller image pull policy. +## @param image.pullSecrets An array of imagePullSecrets to be used when pulling the image. +image: + registry: docker.io + repository: ngrok/kubernetes-ingress-controller + tag: "" + pullPolicy: IfNotPresent + ## Example + ## pullSecrets: + ## - name: my-imagepull-secret + ## + pullSecrets: [] + +## @param ingressClass.name The name of the ingress class to use. +## @param ingressClass.create Whether to create the ingress class. +## @param ingressClass.default Whether to set the ingress class as default. +ingressClass: + name: ngrok + create: true + default: false + +## @param controllerName The name of the controller to look for matching ingress classes +controllerName: "k8s.ngrok.com/ingress-controller" + +## @param watchNamespace The namespace to watch for ingress resources. Defaults to all +watchNamespace: "" + +## @param credentials.secret.name The name of the secret the credentials are in. If not provided, one will be generated using the helm release name. +## @param credentials.apiKey Your ngrok API key. If provided, it will be will be written to the secret and the authtoken must be provided as well. +## @param credentials.authtoken Your ngrok authtoken. If provided, it will be will be written to the secret and the apiKey must be provided as well. +credentials: + secret: + name: "" + apiKey: "" + authtoken: "" + +## @param region ngrok region to create tunnels in. Defaults to connect to the closest geographical region. +region: "" + +## @param rootCAs Set to "trusted" for the ngrok agent CA or "host" to trust the host's CA. Defaults to "trusted". +rootCAs: "" + +## @param serverAddr This is the address of the ngrok server to connect to. You should set this if you are using a custom ingress address. +serverAddr: "" + +## @param clusterDomain Injects the cluster domain name for service discovery. +clusterDomain: svc.cluster.local + +## @param apiURL This is the URL of the ngrok API. You should set this if you are using a custom API URL. +apiURL: "" + +## @param metaData This is a map of key/value pairs that will be added as meta data to all ngrok api resources created +metaData: {} + +## @param affinity Affinity for the controller pod assignment +## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity +## Note: podAffinityPreset, podAntiAffinityPreset, and nodeAffinityPreset will be ignored when it's set +## +affinity: {} +## @param podAffinityPreset Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` +## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity +## +podAffinityPreset: "" +## @param podAntiAffinityPreset Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` +## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity +## +podAntiAffinityPreset: soft +## Node affinity preset +## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity +## +nodeAffinityPreset: + ## @param nodeAffinityPreset.type Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param nodeAffinityPreset.key Node label key to match. Ignored if `affinity` is set. + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## @param nodeAffinityPreset.values Node label values to match. Ignored if `affinity` is set. + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + +## @param priorityClassName Priority class for pod scheduling +## ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass +priorityClassName: "" + +## Pod Disruption Budget configuration +## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ +## @param podDisruptionBudget.create Enable a Pod Disruption Budget creation +## @param podDisruptionBudget.minAvailable Minimum number/percentage of pods that should remain scheduled +## @param podDisruptionBudget.maxUnavailable Maximum number/percentage of pods that may be made unavailable +## +podDisruptionBudget: + create: false + minAvailable: "" + maxUnavailable: 1 + +## Controller container resource requests and limits +## ref: https://kubernetes.io/docs/user-guide/compute-resources/ +## We usually recommend not to specify default resources and to leave this as a conscious +## choice for the user. This also increases chances charts run on environments with little +## resources, such as Minikube. If you do want to specify resources, uncomment the following +## lines, adjust them as necessary, and remove the curly braces after 'resources:'. +## @param resources.limits The resources limits for the container +## @param resources.requests The requested resources for the container +## +resources: + ## Example: + ## limits: + ## cpu: 100m + ## memory: 128Mi + ## + limits: {} + ## Examples: + ## requests: + ## cpu: 100m + ## memory: 128Mi + ## + requests: {} + + +## @param extraVolumes An array of extra volumes to add to the controller. +extraVolumes: [] +## @param extraVolumeMounts An array of extra volume mounts to add to the controller. +extraVolumeMounts: [] +## +## Example: +## +## extraVolumes: +## - name: test-volume +## emptyDir: {} +## extraVolumeMounts: +## - name: test-volume +## mountPath: /test-volume + + +## @param extraEnv an object of extra environment variables to add to the controller. +extraEnv: {} +## Example: +## MY_VAR: test +## MY_SECRET_VAR: +## secretKeyRef: +## key: test-key +## value: test-value + +## Controller Service Account Settings +## @param serviceAccount.create Specifies whether a ServiceAccount should be created +## @param serviceAccount.name The name of the ServiceAccount to use. +## If not set and create is true, a name is generated using the fullname template +## @param serviceAccount.annotations Additional annotations to add to the ServiceAccount +## +serviceAccount: + create: true + name: "" + annotations: {} + + +## Logging configuration +## @param log.level The level to log at. One of 'debug', 'info', or 'error'. +## @param log.stacktraceLevel The level to report stacktrace logs one of 'info' or 'error'. +## @param log.format The log format to use. One of console, json. +log: + format: json + level: info + stacktraceLevel: error + +## @param lifecycle an object containing lifecycle configuration +## ref: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/ +## +lifecycle: {} diff --git a/index.yaml b/index.yaml index 19ab7937d..5cff53bd1 100644 --- a/index.yaml +++ b/index.yaml @@ -4039,6 +4039,38 @@ entries: - assets/cerbos/cerbos-0.37.0.tgz version: 0.37.0 cf-runtime: + - annotations: + artifacthub.io/changes: | + - kind: fixed + description: "engine image upgraded to 1.174.7 to fix fetching a pipeline yaml from subdirectories for Bitbucket Server" + artifacthub.io/containsSecurityUpdates: "false" + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Codefresh + catalog.cattle.io/kube-version: '>=1.18-0' + catalog.cattle.io/release-name: cf-runtime + apiVersion: v2 + created: "2024-09-05T00:52:16.444807972Z" + dependencies: + - name: cf-common + repository: file://./charts/cf-common + version: 0.16.0 + description: A Helm chart for Codefresh Runner + digest: 775a530517479a0aefa0ef75d98004dfc2568ebe9278ead60c8d90bb3b283166 + home: https://codefresh.io/ + icon: file://assets/icons/cf-runtime.png + keywords: + - codefresh + - runner + kubeVersion: '>=1.18-0' + maintainers: + - name: codefresh + url: https://codefresh-io.github.io/ + name: cf-runtime + sources: + - https://github.com/codefresh-io/venona + urls: + - assets/codefresh/cf-runtime-6.3.57.tgz + version: 6.3.57 - annotations: artifacthub.io/changes: | - kind: security @@ -11036,6 +11068,36 @@ entries: - assets/linux-polska/ezd-crd-1.3.1.tgz version: 1.3.1 f5-bigip-ctlr: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: F5 Container Ingress Services for Kubernetes + and OpenShift + catalog.cattle.io/kube-version: '>=1.20-0' + catalog.cattle.io/release-name: f5-bigip-ctlr + apiVersion: v1 + created: "2024-09-05T00:52:16.758604757Z" + description: Deploy the F5 Networks BIG-IP Controller for Kubernetes and OpenShift + (k8s-bigip-ctlr). + digest: 583db6e9d45053c2364bbc5d0fd319bcb92d5393dea10487d3a5d28098f30ce4 + home: https://www.f5.com/products/automation-and-orchestration/container-ingress-services + icon: file://assets/icons/f5-bigip-ctlr.png + keywords: + - F5 + - BIG-IP + - Containers + - Kubernetes + - OpenShift + kubeVersion: '>=1.20-0' + maintainers: + - email: f5_cis_operators@f5.com + name: F5CISSupport + name: f5-bigip-ctlr + sources: + - https://github.com/F5Networks/k8s-bigip-ctlr + - https://github.com/F5Networks/charts + urls: + - assets/f5/f5-bigip-ctlr-0.0.3201.tgz + version: 0.0.3201 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: F5 Container Ingress Services for Kubernetes @@ -15322,6 +15384,64 @@ entries: - assets/intel/intel-device-plugins-sgx-0.26.1.tgz version: 0.26.1 jenkins: + - annotations: + artifacthub.io/category: integration-delivery + artifacthub.io/changes: | + - Update `jenkins/jenkins` to version `2.462.2-jdk17` + artifacthub.io/images: | + - name: jenkins + image: docker.io/jenkins/jenkins:2.462.2-jdk17 + - name: k8s-sidecar + image: docker.io/kiwigrid/k8s-sidecar:1.27.6 + - name: inbound-agent + image: jenkins/inbound-agent:3261.v9c670a_4748a_9-1 + 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.462.2 + created: "2024-09-05T00:52:17.348756914Z" + description: 'Jenkins - Build great things at any scale! As the leading open source + automation server, Jenkins provides over 1800 plugins to support building, deploying + and automating any project. ' + digest: d391c7a0e73e25afb9c4f96445611d3783ed25f23ccde841b990712e9fc1113c + home: https://www.jenkins.io/ + icon: file://assets/icons/jenkins.svg + keywords: + - jenkins + - ci + - devops + kubeVersion: '>=1.14-0' + 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 + type: application + urls: + - assets/jenkins/jenkins-5.5.14.tgz + version: 5.5.14 - annotations: artifacthub.io/category: integration-delivery artifacthub.io/changes: | @@ -21307,6 +21427,35 @@ entries: - assets/kubemq/kubemq-crds-2.3.7.tgz version: 2.3.7 kubernetes-ingress-controller: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: ngrok Ingress Controller + catalog.cattle.io/release-name: kubernetes-ingress-controller + apiVersion: v2 + appVersion: 0.12.2 + created: "2024-09-05T00:52:19.78542124Z" + dependencies: + - name: common + repository: file://./charts/common + tags: + - bitnami-common + version: 2.x.x + description: A Kubernetes ingress controller built using ngrok. + digest: eb3f51e8da534e9e019bd7b71be0a56cd8c92cb12d08a4166aa536cc7ad8d4f7 + home: https://ngrok.com + icon: file://assets/icons/kubernetes-ingress-controller.svg + keywords: + - ngrok + - networking + - ingress + - edge + - api gateway + name: kubernetes-ingress-controller + sources: + - https://github.com/ngrok/kubernetes-ingress-controller + urls: + - assets/ngrok/kubernetes-ingress-controller-0.14.3.tgz + version: 0.14.3 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: ngrok Ingress Controller @@ -41570,4 +41719,4 @@ entries: urls: - assets/netfoundry/ziti-host-1.5.1.tgz version: 1.5.1 -generated: "2024-09-04T00:51:35.207093482Z" +generated: "2024-09-05T00:52:16.055528733Z"