From 9691dd53024b4a9d9c5ed6ae2876cd4c110fbbee Mon Sep 17 00:00:00 2001 From: Branden Cobb Date: Mon, 7 Jun 2021 16:20:46 -0600 Subject: [PATCH] move to upstream sonarqube chart --- chart/CHANGELOG.md | 88 ++++ chart/Chart.yaml | 14 +- chart/Kptfile | 11 + chart/OWNERS | 4 + chart/README.md | 359 +++++++------- chart/charts/ingress-nginx-3.29.0.tgz | Bin 0 -> 24197 bytes chart/requirements.lock | 7 +- chart/requirements.yaml | 15 +- chart/templates/NOTES.txt | 4 +- chart/templates/_helpers.tpl | 54 ++- .../templates/change-admin-password-hook.yml | 5 +- chart/templates/deployment.yaml | 52 ++- chart/templates/ingress.yaml | 30 +- chart/templates/init-fs.yaml | 14 + chart/templates/install-plugins.yaml | 17 +- chart/templates/prometheus-config.yaml | 14 + chart/templates/secret.yaml | 18 +- chart/templates/service.yaml | 3 + chart/templates/sonarqube-scc.yaml | 2 +- chart/templates/sonarqube-sts.yaml | 437 ++++++++++++++++++ chart/templates/tests/sonarqube-test.yaml | 47 ++ chart/tests/cypress/sonarqube-health.spec.js | 1 + chart/values.yaml | 137 ++++-- 23 files changed, 1073 insertions(+), 260 deletions(-) create mode 100644 chart/CHANGELOG.md create mode 100644 chart/Kptfile create mode 100644 chart/OWNERS create mode 100644 chart/charts/ingress-nginx-3.29.0.tgz create mode 100644 chart/templates/init-fs.yaml create mode 100644 chart/templates/prometheus-config.yaml mode change 100644 => 100755 chart/templates/service.yaml create mode 100644 chart/templates/sonarqube-sts.yaml create mode 100644 chart/templates/tests/sonarqube-test.yaml diff --git a/chart/CHANGELOG.md b/chart/CHANGELOG.md new file mode 100644 index 0000000..6bfa7ee --- /dev/null +++ b/chart/CHANGELOG.md @@ -0,0 +1,88 @@ +# SonarQube Chart Changelog +All changes to this chart will be documented in this file. + +## [1.0.8] +* fix typo in initfs +* fix plugin installation init container permissions +* fix duplicated mount point for conf when sonar.properties are defined + +## [1.0.7] +* fix invalid yaml render in `secret.yaml` when using external postgresql + +## [1.0.6] +* added `prometheusExporter.downloadURL` (custom download URL for the agent jar) + +## [1.0.5] +* replace `rjkernick/alpine-wget` with `curlimages/curl` +* update `install-plugins` script +* fix possible issue with prometheus init container and `env` set in the `values.yaml` + +## [1.0.4] +* fix for missing `serviceAccountName` in STS deployment kind + +## [1.0.3] +* fixed prometheus config volume mount if disabled +* switched from wget to curl image per default for downloading agent +* added support for proxy envs + +## [1.0.2] +* added option to configure CE java opts separately + +## [1.0.1] +* fixed missing conditional that was introduced in 0.9.2.2 to sonarqube-sts.yaml +* updated default application version to 8.9 + +## [1.0.0] +* changed default deployment from replica set to statefull set +* added default support for prometheus jmx exporter +* added init filesystem container +* added nginx-ingress as optional dependency +* updated application version to 8.8-community +* improved readiness/startup and liveness probes +* improved documentation + +## [0.9.6.2] +* Change order of env variables to better support 7.9-lts + +## [0.9.6.1] +* Add support for setting custom annotations in admin hook job. + +## [0.9.6.0] +* Add the possibility of definining the secret key name of the postgres password. + +## [0.9.5.0] +* Add Ingress default backend for GCE class + +## [0.9.2.3] +* Added namespace to port-foward command in notes. + +## [0.9.2.2] +* Added a condition to deployment.yaml so that `wait-for-db` initContainer is only created if `postgresql.enabled=true` + +## [0.9.2.1] +* Updated the configuration table to include the additional keys added in release 9.2.0. + +## [0.9.2.0] +* Added functionality for deployments to OpenShift clusters. + * .Values.OpenShift flag to signify if deploying to OpenShift. + * Ability to have chart generate an SCC allowing the init-sysctl container to run as privileged. + * Setting of a seperate securityContext section for the main SonarQube container to avoid running as root. + * Exposing additional `postreSQL` keys in values.yaml to support configuring postgres to run under standard "restricted" or "anyuid"/"nonroot" SCCs on OpenShift. +* Added initContainer `wait-for-db` to await postgreSQL successful startup before starting SonarQube, to avoid race conditions. + +## [0.9.1.1] +* Update SonarQube to 8.5.1. +* **Fix:** Purge plugins directory before download. + +## [0.9.0.0] +* Update SonarQube to 8.5. +* **Breaking change:** Rework init containers. + * Move global defaults from `plugins` section to `initContainers`. + * Update container images. +* **Deprecation:** `elasticsearch.configureNode` in favor of `initSysctl.enabled`. +* Rework sysctl with support for custom values. +* Rework plugins installation via `opt/sonarqube/extensions/downloads` folder that is handled by SonarQube itself. + * **Breaking change:** remove `plugins.deleteDefaultPlugins` as SonarQube stores bundled plugins out of `opt/sonarqube/extensions`. +* Rename deprecated `SONARQUBE_` environment variables to `SONAR_` ones. +* **Breaking change:** Rename `enabledTests` to `tests.enabled`. +* Add `terminationGracePeriodSeconds`. diff --git a/chart/Chart.yaml b/chart/Chart.yaml index 162b121..d5f7c9c 100644 --- a/chart/Chart.yaml +++ b/chart/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v1 -appVersion: 8.7.1-community name: sonarqube description: SonarQube is an open sourced code quality scanning tool -version: 9.2.6-bb.12 +version: 1.0.8-bb.0 +appVersion: 8.9-community keywords: - coverage - security @@ -13,11 +13,5 @@ icon: https://www.sonarqube.org/assets/logo-31ad3115b1b4b120f3d1efd63e6b13ac9f1f sources: - https://github.com/SonarSource/docker-sonarqube maintainers: - - name: rjkernick - email: rjkernick@gmail.com - - name: tsiddique - email: tsiddique@live.com -dependencies: - - name: gluon - version: "0.1.1" - repository: "oci://registry.dso.mil/platform-one/big-bang/apps/library-charts/gluon" + - name: tobias-trabelsi-sonarsource + email: tobias.trabelsi+helm@sonarsource.com \ No newline at end of file diff --git a/chart/Kptfile b/chart/Kptfile new file mode 100644 index 0000000..988a88c --- /dev/null +++ b/chart/Kptfile @@ -0,0 +1,11 @@ +apiVersion: kpt.dev/v1alpha1 +kind: Kptfile +metadata: + name: sonarqube +upstream: + type: git + git: + commit: af0ae8e5ea1bc7d635a048c1507556948c1a0fe0 + repo: https://github.com/SonarSource/helm-chart-sonarqube + directory: /charts/sonarqube + ref: master diff --git a/chart/OWNERS b/chart/OWNERS new file mode 100644 index 0000000..dc80d0d --- /dev/null +++ b/chart/OWNERS @@ -0,0 +1,4 @@ +approvers: +- tobias-trabelsi-sonarsource +reviewers: +- tobias-trabelsi-sonarsource diff --git a/chart/README.md b/chart/README.md index 4b9415f..fe3ad65 100644 --- a/chart/README.md +++ b/chart/README.md @@ -2,176 +2,223 @@ [SonarQube](https://www.sonarqube.org/) is an open sourced code quality scanning tool. -This chart was pulled from: https://github.com/Oteemo/charts/tree/master/charts/sonarqube - ## Introduction This chart bootstraps a SonarQube instance with a PostgreSQL database. -## Prerequisites +Please note that this chart only supports SonarQube Community, Developer, and Enterprise Editions. + +## Compatibility -- Kubernetes 1.10+ +| SonarQube Version | Kubernetes Version | Helm Chart Version | +|-------------------|--------------------|--------------------| +| 8.8, 8.9 | 1.19, 1.20, 1.21 | 1.0 | ## Installing the chart To install the chart: ```bash -helm repo add oteemocharts https://oteemo.github.io/charts -helm install oteemocharts/sonarqube +git clone https://github.com/SonarSource/helm-chart-sonarqube.git +cd helm-chart-sonarqube/charts/sonarqube +helm dependency update +kubectl create namespace sonarqube +helm upgrade --install -f values.yaml -n sonarqube sonarqube ./ ``` -The above command deploys Sonarqube on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation. - -For OpenShift installations; if you wish for the chart to create the required SCC for the privileged initContainer, and run PostgreSQL under the restricted SCC use the following `set` statements: -```bash -helm repo add oteemocharts https://oteemo.github.io/charts -helm install oteemocharts/sonarqube --set OpenShift.enabled=true,\ - serviceAccount.create=true,\ - postgresql.serviceAccount.enabled=true,\ - postgresql.securityContext.enabled=false,\ - postgresql.volumePermissions.enabled=true,\ - postgresql.volumePermissions.securityContext.runAsUser="auto" -``` +The above command deploys Sonarqube on the Kubernetes cluster in the default configuration in the sonarqube namespace. The [configuration](#configuration) section lists the parameters that can be configured during installation. The default login is admin/admin. +## How to use it + +Take some time to read the Deploy on [SonarQube on Kubernetes](https://docs.sonarqube.org/latest/setup/sonarqube-on-kubernetes/) page. +SonarQube deployment on Kubernetes has been tested with the recommendations and constraints documented there, and deployment has some limitations. + ## Uninstalling the chart To uninstall/delete the deployment: ```bash $ helm list -NAME REVISION UPDATED STATUS CHART NAMESPACE -kindly-newt 1 Mon Oct 2 15:05:44 2017 DEPLOYED sonarqube-0.1.0 default +NAME REVISION UPDATED STATUS CHART NAMESPACE +kindly-newt 1 Mon Oct 2 15:05:44 2017 DEPLOYED sonarqube-0.1.0 sonarqube $ helm delete kindly-newt ``` -## Ingress Paths +## Ingress + +### Path + +Some cloud may need the path to be `/*` instead of `/.` Try this first if you are having issues getting traffic through the ingress. + +### Default Backend + +if you use GCP as a cloud provider you need to set a default backend to avoid useless default backend created by the gce controller. To add this default backend you must set "ingress.class" annotation with "gce" or "gce-internal" value. -Some cloud may need the path to be /* instead of /. Try this first if you are having issues getting traffic through the ingress. +Example: + +```yaml +--- +ingress: + enabled: true + hosts: + - name: sonarqube.example.com + path: "/*" + annotations: + kubernetes.io/ingress.class: "gce-internal" + kubernetes.io/ingress.allow-http: "false" +``` ## Configuration The following table lists the configurable parameters of the Sonarqube chart and their default values. -| Parameter | Description | Default | -| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | -| `replicaCount` | Number of replicas deployed | `1` | -| `deploymentStrategy` | Deployment strategy | `{}` | -| `priorityClassName` | Schedule pods on priority (commented out) | `"high-priority"` | -| `schedulerName` | Kubernetes scheduler name | None | -| `OpenShift.enabled` | Define if this deployment is for OpenShift | `false` | -| `OpenShift.createSCC` | If this deployment is for OpenShift, define if SCC should be created for sonarqube pod | `true` | -| `image.repository` | image repository | `sonarqube` | -| `image.tag` | `sonarqube` image tag. | `8.5.1-community` | -| `image.pullPolicy` | Image pull policy | `IfNotPresent` | -| `image.pullSecret` | imagePullSecret to use for private repository (commented out) | `my-repo-secret` | -| `securityContext.fsGroup` | Group applied to mounted directories/files | `1000` | -| `containerSecurityContext.runAsUser` | User to run containers in sonarqube pod as, unless overwritten (such as for init-sysctl container) | `1000` | -| `elasticsearch.configureNode` | [DEPRECATED] Use initSysctl.enabled instead. | `true` | -| `elasticsearch.bootstrapChecks` | Enables/disables Elasticsearch bootstrap checks | `true` | -| `service.type` | Kubernetes service type | `ClusterIP` | -| `service.externalPort` | Kubernetes service port | `9000` | -| `service.internalPort` | Kubernetes container port | `9000` | -| `service.labels` | Kubernetes service labels | None | -| `service.annotations` | Kubernetes service annotations | None | -| `service.loadBalancerSourceRanges` | Kubernetes service LB Allowed inbound IP addresses | None | -| `service.loadBalancerIP` | Kubernetes service LB Optional fixed external IP | None | -| `ingress.enabled` | Flag for enabling ingress | false | -| `ingress.labels` | Ingress additional labels | `{}` | -| `ingress.hosts[0].name` | Hostname to your SonarQube installation | `sonar.organization.com` | -| `ingress.hosts[0].path` | Path within the URL structure | / | -| `ingress.hosts[0].serviceName` | Optional field to override the default serviceName of a path | None | -| `ingress.hosts[0].servicePort` | Optional field to override the default servicePort of a path | None | -| `ingress.tls` | Ingress secrets for TLS certificates | `[]` | -| `affinity` | Node / Pod affinities | `{}` | -| `tolerations` | List of node taints to tolerate | `[]` | -| `nodeSelector` | Node labels for pod assignment | `{}` | -| `hostAliases` | Aliases for IPs in /etc/hosts | `[]` | -| `readinessProbe.initialDelaySecond` | ReadinessProbe initial delay for SonarQube checking | `60` | -| `readinessProbe.periodSeconds` | ReadinessProbe period between checking SonarQube | `30` | -| `readinessProbe.failureThreshold` | ReadinessProbe thresold for marking as failed | `6` | -| `readinessProbe.sonarWebContext` | SonarQube web context for readinessProbe | / | -| `livenessProbe.initialDelaySecond` | LivenessProbe initial delay for SonarQube checking | `60` | -| `livenessProbe.periodSeconds` | LivenessProbe period between checking SonarQube | `30` | -| `livenessProbe.sonarWebContext` | SonarQube web context for livenessProbe | / | -| `initContainers.image` | Change init container image | `busybox:1.32` | -| `initContainers.securityContext` | SecurityContext for init containers | `nil` | -| `initContainers.resources` | Resources for init containers | `{}` | -| `caCerts.image` | Change init CA certificates container image | `adoptopenjdk/openjdk11:alpine` | -| `caCerts.secret` | Name of the secret containing additional CA certificates | `nil` | -| `initSysctl.enabled` | Modify k8s worker to conform to system requirements | `true` | -| `initSysctl.vmMaxMapCount` | Set init sysctl container vm.max_map_count | `524288` | -| `initSysctl.fsFileMax` | Set init sysctl container fs.file-max | `131072` | -| `initSysctl.nofile` | Set init sysctl container open file descriptors limit | `131072` | -| `initSysctl.nproc` | Set init sysctl container open threads limit | `8192 ` | -| `initSysctl.image` | Change init sysctl container image | `busybox:1.32` | -| `initSysctl.securityContext` | InitSysctl container security context | `{privileged: true}` | -| `initSysctl.resources` | InitSysctl container resource requests & limits | `{}` | -| `plugins.install` | List of plugins to install | `[]` | -| `plugins.lib` | Plugins libray | `[]` | -| `plugins.resources` | Plugin Pod resource requests & limits | `{}` | -| `plugins.httpProxy` | For use behind a corporate proxy when downloading plugins | "" | -| `plugins.httpsProxy` | For use behind a corporate proxy when downloading plugins | "" | -| `plugins.noProxy` | For use behind a corporate proxy when downloading plugins | "" | -| `plugins.image` | Image for plugins container | "" | -| `plugins.resources` | Resources for plugins container | "" | -| `plugins.netrcCreds` | Name of the secret containing .netrc file to use creds when downloading plugins | "" | -| `jvmOpts` | Values to add to SONARQUBE_WEB_JVM_OPTS | `""` | -| `env` | Environment variables to attach to the pods | `nil` | -| `annotations` | Sonarqube Pod annotations | `{}` | -| `resources` | Sonarqube Pod resource requests & limits | `{}` | -| `persistence.enabled` | Flag for enabling persistent storage | false | -| `persistence.annotations` | Kubernetes pvc annotations | `{}` | -| `persistence.existingClaim` | Do not create a new PVC but use this one | None | -| `persistence.storageClass` | Storage class to be used | "" | -| `persistence.accessMode` | Volumes access mode to be set | `ReadWriteOnce` | -| `persistence.size` | Size of the volume | 10Gi | -| `persistence.volumes` | Specify extra volumes. Refer to ".spec.volumes" specification | [] | -| `persistence.mounts` | Specify extra mounts. Refer to ".spec.containers.volumeMounts" specification | [] | -| `emptyDir` | Configuration of resources for `emptyDir` | `{}` | -| `sonarProperties` | Custom `sonar.properties` file | None | -| `sonarSecretProperties` | Additional `sonar.properties` file to load from a secret | None | -| `sonarSecretKey` | Name of existing secret used for settings encryption | None | -| `jdbcDatabaseType` | Type of the JDBC Database driver | `postgreql` | -| `jdbcUrlOverride` | Overrides default JDBC URL creation | None | -| `postgresql.enabled` | Set to `false` to use external server | `true` | -| `postgresql.existingSecret` | Secret containing the password of the external Postgresql server | `null` | -| `postgresql.postgresqlServer` | Hostname of the external Postgresql server | `null` | -| `postgresql.postgresqlUsername` | Postgresql database user | `sonarUser` | -| `postgresql.postgresqlPassword` | Postgresql database password | `sonarPass` | -| `postgresql.postgresqlDatabase` | Postgresql database name | `sonarDB` | -| `postgresql.service.port` | Postgresql port | `5432` | -| `postgresql.resources.requests.memory`| Postgresql memory request | `256Mi` | -| `postgresql.resources.requests.cpu` | Postgresql cpu request | `250m` | -| `postgresql.resources.limits.memory` | Postgresql memory limit | `2Gi` | -| `postgresql.resources.limits.cpu` | Postgresql cpu limit | `2` | -| `postgresql.persistence.enabled` | Postgresql persistence en/disabled | `true` | -| `postgresql.persistence.accessMode` | Postgresql persistence accessMode | `ReadWriteOnce` | -| `postgresql.persistence.size` | Postgresql persistence size | `20Gi` | -| `postgresql.persistence.storageClass` | Postgresql persistence storageClass | `""` | -| `postgresql.securityContext.enabled` | Postgresql securityContext en/disabled | `true` | -| `postgresql.securityContext.fsGroup` | Postgresql securityContext fsGroup | `1001` | -| `postgresql.securityContext.runAsUser`| Postgresql securityContext runAsUser | `1001` | -| `postgresql.volumePermissions.enabled`| Postgres vol permissions en/disabled | `false` | -| `postgresql.volumePermissions.securityContext.runAsUser`| Postgres vol permissions secContext runAsUser | `0` | -| `postgresql.shmVolume.chmod.enabled` | Postgresql shared memory vol en/disabled | `false` | -| `postgresql.serivceAccount.enabled` | Postgresql service Account creation en/disabled | `false` | -| `postgresql.serivceAccount.name` | Postgresql service Account name (commented out) | `""` | -| `podLabels` | Map of labels to add to the pods | `{}` | -| `sonarqubeFolder` | Directory name of Sonarqube | `/opt/sonarqube` | -| `tests.enabled` | Flag that allows tests to be excluded from generated yaml | true | -| `tests.image` | Change init test container image | `dduportal/bats:0.4.0` | -| `serviceAccount.create` | If set to true, create a serviceAccount | false | -| `serviceAccount.name` | Name of the serviceAccount to create/use | `sonarqube-sonarqube` | -| `serviceAccount.annotations` | Additional serviceAccount annotations | `{}` | -| `extraConfig.secrets` | A list of `Secret`s (which must contain key/value pairs) which may be loaded into the Scanner as environment variables | `[]` | -| `extraConfig.configmaps` | A list of `ConfigMap`s (which must contain key/value pairs) which may be loaded into the Scanner as environment variables | `[]` | -| `account.adminPassword` | Custom admin password | `"admin"` | -| `account.currentAdminPassword` | Current admin password | `"admin"` | -| `curlContainerImage` | Curl container image | `"curlimages/curl:latest"` | -| `terminationGracePeriodSeconds` | Configuration of `terminationGracePeriodSeconds` | `60` | +| Parameter | Description | Default | +| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | +| `deploymentType` | Deployment Type | `StatefulSet` | +| `replicaCount` | Number of replicas deployed | `1` | +| `deploymentStrategy` | Deployment strategy | `{}` | +| `priorityClassName` | Schedule pods on priority (commented out) | `"high-priority"` | +| `schedulerName` | Kubernetes scheduler name | None | +| `OpenShift.enabled` | Define if this deployment is for OpenShift | `false` | +| `OpenShift.createSCC` | If this deployment is for OpenShift, define if SCC should be created for sonarqube pod | `true` | +| `image.repository` | image repository | `sonarqube` | +| `image.tag` | `sonarqube` image tag. | `8.8-community` | +| `image.pullPolicy` | Image pull policy | `IfNotPresent` | +| `image.pullSecret` | imagePullSecret to use for private repository (commented out) | `my-repo-secret` | +| `securityContext.fsGroup` | Group applied to mounted directories/files | `1000` | +| `containerSecurityContext.runAsUser` | User to run containers in sonarqube pod as, unless overwritten (such as for init-sysctl container) | `1000` | +| `elasticsearch.configureNode` | [DEPRECATED] Use initSysctl.enabled instead. | `true` | +| `elasticsearch.bootstrapChecks` | Enables/disables Elasticsearch bootstrap checks | `true` | +| `nginx.enabled` | Also install Nginx Ingress Helm | `false` | +| `service.type` | Kubernetes service type | `ClusterIP` | +| `service.externalPort` | Kubernetes service port | `9000` | +| `service.internalPort` | Kubernetes container port | `9000` | +| `service.labels` | Kubernetes service labels | None | +| `service.annotations` | Kubernetes service annotations | None | +| `service.loadBalancerSourceRanges` | Kubernetes service LB Allowed inbound IP addresses | None | +| `service.loadBalancerIP` | Kubernetes service LB Optional fixed external IP | None | +| `ingress.enabled` | Flag for enabling ingress | false | +| `ingress.labels` | Ingress additional labels | `{}` | +| `ingress.hosts[0].name` | Hostname to your SonarQube installation | `sonarqube.your-org.com` | +| `ingress.hosts[0].path` | Path within the URL structure | / | +| `ingress.hosts[0].serviceName` | Optional field to override the default serviceName of a path | None | +| `ingress.hosts[0].servicePort` | Optional field to override the default servicePort of a path | None | +| `ingress.tls` | Ingress secrets for TLS certificates | `[]` | +| `affinity` | Node / Pod affinities | `{}` | +| `tolerations` | List of node taints to tolerate | `[]` | +| `nodeSelector` | Node labels for pod assignment | `{}` | +| `hostAliases` | Aliases for IPs in /etc/hosts | `[]` | +| `readinessProbe.initialDelaySecond` | ReadinessProbe initial delay for SonarQube checking | `60` | +| `readinessProbe.periodSeconds` | ReadinessProbe period between checking SonarQube | `30` | +| `readinessProbe.failureThreshold` | ReadinessProbe thresold for marking as failed | `6` | +| `readinessProbe.sonarWebContext` | SonarQube web context for readinessProbe | / | +| `livenessProbe.initialDelaySecond` | LivenessProbe initial delay for SonarQube checking | `60` | +| `livenessProbe.periodSeconds` | LivenessProbe period between checking SonarQube | `30` | +| `livenessProbe.sonarWebContext` | SonarQube web context for livenessProbe | / | +| `livenessProbe.failureThreshold` | LivenessProbe thresold for marking as dead | `6` | +| `startupProbe.initialDelaySecond` | StartupProbe initial delay for SonarQube checking | `30` | +| `startupProbe.periodSeconds` | StartupProbe period between checking SonarQube | `10` | +| `startupProbe.sonarWebContext` | SonarQube web context for StartupProbe | / | +| `startupProbe.failureThreshold` | StartupProbe thresold for marking as failed | `24` | +| `initContainers.image` | Change init container image | `busybox:1.32` | +| `initContainers.securityContext` | SecurityContext for init containers | `nil` | +| `initContainers.resources` | Resources for init containers | `{}` | +| `extraInitContainers` | Extra init containers to e.g. download required artifacts | `{}` | +| `caCerts.image` | Change init CA certificates container image | `adoptopenjdk/openjdk11:alpine` | +| `caCerts.secret` | Name of the secret containing additional CA certificates | `nil` | +| `initSysctl.enabled` | Modify k8s worker to conform to system requirements | `true` | +| `initSysctl.vmMaxMapCount` | Set init sysctl container vm.max_map_count | `524288` | +| `initSysctl.fsFileMax` | Set init sysctl container fs.file-max | `131072` | +| `initSysctl.nofile` | Set init sysctl container open file descriptors limit | `131072` | +| `initSysctl.nproc` | Set init sysctl container open threads limit | `8192 ` | +| `initSysctl.image` | Change init sysctl container image | `busybox:1.32` | +| `initSysctl.securityContext` | InitSysctl container security context | `{privileged: true}` | +| `initSysctl.resources` | InitSysctl container resource requests & limits | `{}` | +| `initFs.enabled` | Enable file permission change with init container | true | +| `initFs.image` | InitFS container image | `busybox:1.32` | +| `initFs.securityContext.privileged` | InitFS container needs to run privileged | true | +| `prometheusExporter.enabled` | Use the Prometheus JMX exporter | true | +| `prometheusExporter.version` | jmx_prometheus_javaagent version to download from Maven Central | `0.15.0` | +| `prometheusExporter.downloadURL` | Alternative full download URL for the jmx_prometheus_javaagent.jar (overrides `prometheusExporter.version`) | "" | +| `prometheusExporter.config` | Prometheus JMX exporter config yaml | see `values.yaml` | +| `prometheusExporter.httpProxy` | HTTP proxy for downloading JMX agent | `""` | +| `prometheusExporter.httpsProxy` | HTTPS proxy for downloading JMX agent | `""` | +| `prometheusExporter.noProxy` | No proxy for downloading JMX agent | `""` | +| `prometheusExporter.securityContext` | Security context for downloading the jmx agent | see `values.yaml` | +| `plugins.install` | List of plugins to install | `[]` | +| `plugins.lib` | Plugins libray | `[]` | +| `plugins.resources` | Plugin Pod resource requests & limits | `{}` | +| `plugins.httpProxy` | For use behind a corporate proxy when downloading plugins | "" | +| `plugins.httpsProxy` | For use behind a corporate proxy when downloading plugins | "" | +| `plugins.noProxy` | For use behind a corporate proxy when downloading plugins | "" | +| `plugins.image` | Image for plugins container | "" | +| `plugins.resources` | Resources for plugins container | "" | +| `plugins.netrcCreds` | Name of the secret containing .netrc file to use creds when downloading plugins | "" | +| `plugins.noCheckCertificate` | Flag to not check server's certificate when downloading plugins | `false` | +| `plugins.securityContext` | Security context for the container to download plugins | see `values.yaml` | +| `jvmOpts` | Values to add to SONARQUBE_WEB_JVM_OPTS | `""` | +| `jvmCEOpts` | Values to add to SONAR_CE_JAVAOPTS | `""` | +| `monitoringPasscode` | Value for sonar.web.systemPasscode. needed for liveness probes | `"define_it"` | +| `env` | Environment variables to attach to the pods | `nil` | +| `annotations` | Sonarqube Pod annotations | `{}` | +| `resources.requests.memory` | Sonarqube memory request | `2Gi` | +| `resources.requests.cpu` | Sonarqube cpu request | `400m` | +| `resources.limits.memory` | Sonarqube memory limit | `4096M` | +| `resources.limits.cpu` | Sonarqube cpu limit | `800m` | +| `persistence.enabled` | Flag for enabling persistent storage | false | +| `persistence.annotations` | Kubernetes pvc annotations | `{}` | +| `persistence.existingClaim` | Do not create a new PVC but use this one | None | +| `persistence.storageClass` | Storage class to be used | "" | +| `persistence.accessMode` | Volumes access mode to be set | `ReadWriteOnce` | +| `persistence.size` | Size of the volume | 5Gi | +| `persistence.volumes` | Specify extra volumes. Refer to ".spec.volumes" specification | [] | +| `persistence.mounts` | Specify extra mounts. Refer to ".spec.containers.volumeMounts" specification | [] | +| `emptyDir` | Configuration of resources for `emptyDir` | `{}` | +| `sonarProperties` | Custom `sonar.properties` file | None | +| `sonarSecretProperties` | Additional `sonar.properties` file to load from a secret | None | +| `sonarSecretKey` | Name of existing secret used for settings encryption | None | +| `jdbcDatabaseType` | Type of the JDBC Database driver | `postgreql` | +| `jdbcUrlOverride` | Overrides default JDBC URL creation | None | +| `postgresql.enabled` | Set to `false` to use external server | `true` | +| `postgresql.existingSecret` | Secret containing the password of the external Postgresql server | `null` | +| `postgresql.existingSecretPasswordKey` | Secret Key containing the password of the external Postgresql server | `postgresql-password` | +| `postgresql.postgresqlServer` | Hostname of the external Postgresql server | `null` | +| `postgresql.postgresqlUsername` | Postgresql database user | `sonarUser` | +| `postgresql.postgresqlPassword` | Postgresql database password | `sonarPass` | +| `postgresql.postgresqlDatabase` | Postgresql database name | `sonarDB` | +| `postgresql.service.port` | Postgresql port | `5432` | +| `postgresql.resources.requests.memory` | Postgresql memory request | `256Mi` | +| `postgresql.resources.requests.cpu` | Postgresql cpu request | `250m` | +| `postgresql.resources.limits.memory` | Postgresql memory limit | `2Gi` | +| `postgresql.resources.limits.cpu` | Postgresql cpu limit | `2` | +| `postgresql.persistence.enabled` | Postgresql persistence en/disabled | `true` | +| `postgresql.persistence.accessMode` | Postgresql persistence accessMode | `ReadWriteOnce` | +| `postgresql.persistence.size` | Postgresql persistence size | `20Gi` | +| `postgresql.persistence.storageClass` | Postgresql persistence storageClass | `""` | +| `postgresql.securityContext.enabled` | Postgresql securityContext en/disabled | `true` | +| `postgresql.securityContext.fsGroup` | Postgresql securityContext fsGroup | `1001` | +| `postgresql.securityContext.runAsUser` | Postgresql securityContext runAsUser | `1001` | +| `postgresql.volumePermissions.enabled` | Postgres vol permissions en/disabled | `false` | +| `postgresql.volumePermissions.securityContext.runAsUser` | Postgres vol permissions secContext runAsUser | `0` | +| `postgresql.shmVolume.chmod.enabled` | Postgresql shared memory vol en/disabled | `false` | +| `postgresql.serivceAccount.enabled` | Postgresql service Account creation en/disabled | `false` | +| `postgresql.serivceAccount.name` | Postgresql service Account name (commented out) | `""` | +| `podLabels` | Map of labels to add to the pods | `{}` | +| `sonarqubeFolder` | Directory name of Sonarqube | `/opt/sonarqube` | +| `tests.enabled` | Flag that allows tests to be excluded from generated yaml | true | +| `tests.image` | Change init test container image | `dduportal/bats:0.4.0` | +| `serviceAccount.create` | If set to true, create a serviceAccount | false | +| `serviceAccount.name` | Name of the serviceAccount to create/use | `sonarqube-sonarqube` | +| `serviceAccount.annotations` | Additional serviceAccount annotations | `{}` | +| `extraConfig.secrets` | A list of `Secret`s (which must contain key/value pairs) which may be loaded into the Scanner as environment variables | `[]` | +| `extraConfig.configmaps` | A list of `ConfigMap`s (which must contain key/value pairs) which may be loaded into the Scanner as environment variables | `[]` | +| `account.adminPassword` | Custom admin password | `"admin"` | +| `account.currentAdminPassword` | Current admin password | `"admin"` | +| `curlContainerImage` | Curl container image | `"curlimages/curl:latest"` | +| `adminJobAnnotations` | Custom annotations for admin hook Job | `{}` | +| `terminationGracePeriodSeconds` | Configuration of `terminationGracePeriodSeconds` | `60` | You can also configure values for the PostgreSQL database via the Postgresql [Chart](https://hub.helm.sh/charts/bitnami/postgresql) @@ -213,13 +260,11 @@ Since SonarQube comes bundled with an Elasticsearch instance, some [bootstrap ch This chart offers the option to use an initContainer in privilaged mode to automatically set certain kernel settings on the kube worker. While this can ensure proper functionality of Elasticsearch, modifying the underlying kernel settings on the Kubernetes node can impact other users. It may be best to work with your cluster administrator to either provide specific nodes with the proper kernel settings, or ensure they are set cluster wide. -To enable auto-configuration of the kube worker node, set `elasticsearch.configureNode` to `true`. This is the default behavior, so you do not need to explicitly set this. +To enable auto-configuration of the kube worker node, set `elasticsearch.configureNode` to `true`. This is the default behavior, so you do not need to explicitly set this. This will run `sysctl -w vm.max_map_count=262144` on the worker where the sonarqube pod(s) get scheduled. This needs to be set to `262144` but normally defaults to `65530`. Other kernel settings are recommended by the [docker image](https://hub.docker.com/_/sonarqube/#requirements), but the defaults work fine in most cases. -To disable worker node configuration, set `elasticsearch.configureNode` to `false`. Note that if node configuration is not enabled, then you will likely need to also disable the Elasticsearch bootstrap checks. These can be explicitly disabled by setting `elasticsearch.bootstrapChecks` to `false`. - -### As of 7.9 Mysql is no longer supported, so it has been removed from the chart +To disable worker node configuration, set `elasticsearch.configureNode` to `false`. Note that if node configuration is not enabled, then you will likely need to also disable the Elasticsearch bootstrap checks. These can be explicitly disabled by setting `elasticsearch.bootstrapChecks` to `false`. ### Extra Config @@ -229,20 +274,20 @@ In such environments, configuration may be read, via environment variables, from 1. Create a `ConfigMap` (or `Secret`) containing key/value pairs, as expected by Sonarqube - ```yaml - apiVersion: v1 - kind: ConfigMap - metadata: - name: external-sonarqube-opts - data: - SONARQUBE_JDBC_USERNAME: foo - SONARQUBE_JDBC_URL: jdbc:postgresql://db.example.com:5432/sonar - ``` + ```yaml + apiVersion: v1 + kind: ConfigMap + metadata: + name: external-sonarqube-opts + data: + SONARQUBE_JDBC_USERNAME: foo + SONARQUBE_JDBC_URL: jdbc:postgresql://db.example.com:5432/sonar + ``` 2. Set the following in your `values.yaml` (using the key `extraConfig.secrets` to reference `Secret`s) - ```yaml - extraConfig: - configmaps: - - external-sonarqube-opts - ``` + ```yaml + extraConfig: + configmaps: + - external-sonarqube-opts + ``` diff --git a/chart/charts/ingress-nginx-3.29.0.tgz b/chart/charts/ingress-nginx-3.29.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..791f8fe6bf54b35032434eed21388d693e0f9f9b GIT binary patch literal 24197 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 R;UfS5|Nktq44wem0ssJW{@DNk literal 0 HcmV?d00001 diff --git a/chart/requirements.lock b/chart/requirements.lock index f7b92aa..4e98a2f 100644 --- a/chart/requirements.lock +++ b/chart/requirements.lock @@ -1,6 +1,9 @@ dependencies: +- name: ingress-nginx + repository: https://kubernetes.github.io/ingress-nginx + version: 3.29.0 - name: gluon repository: oci://registry.dso.mil/platform-one/big-bang/apps/library-charts/gluon version: 0.1.1 -digest: sha256:cf1107c00a11cde8074a39624643312fe85ee11250bb7d9380e3787bde0af0f7 -generated: "2021-05-25T13:09:48.372995-06:00" +digest: sha256:1ff95a59506ab376f44593d141fd1472b248f30d2a8b151ee041bb6a4ff319d1 +generated: "2021-06-07T16:19:44.1121955-06:00" diff --git a/chart/requirements.yaml b/chart/requirements.yaml index db53d78..c47ac94 100644 --- a/chart/requirements.yaml +++ b/chart/requirements.yaml @@ -1,5 +1,12 @@ dependencies: - - name: postgresql - version: 8.6.4 - repository: file://./deps/postgresql - condition: postgresql.enabled +- name: postgresql + version: 8.6.4 + repository: file://./deps/postgresql + condition: postgresql.enabled +- name: ingress-nginx + version: 3.29.0 + repository: https://kubernetes.github.io/ingress-nginx + condition: nginx.enabled +- name: gluon + version: "0.1.1" + repository: "oci://registry.dso.mil/platform-one/big-bang/apps/library-charts/gluon" \ No newline at end of file diff --git a/chart/templates/NOTES.txt b/chart/templates/NOTES.txt index 1633b45..571015f 100644 --- a/chart/templates/NOTES.txt +++ b/chart/templates/NOTES.txt @@ -1,9 +1,10 @@ -{{- if not .Values.istio.enabled }} 1. Get the application URL by running these commands: {{- if .Values.ingress.enabled }} {{- range .Values.ingress.hosts }} http://{{ .name }} {{- end }} +{{- else if .Values.istio.enabled }} + https://sonarqube.{{ .Values.hostname }} {{- else if contains "NodePort" .Values.service.type }} export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "sonarqube.fullname" . }}) export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") @@ -18,4 +19,3 @@ echo "Visit http://127.0.0.1:8080 to use your application" kubectl port-forward $POD_NAME 8080:{{ .Values.service.externalPort }} -n {{ .Release.Namespace }} {{- end }} -{{- end }} \ No newline at end of file diff --git a/chart/templates/_helpers.tpl b/chart/templates/_helpers.tpl index 8059ff8..157d41d 100644 --- a/chart/templates/_helpers.tpl +++ b/chart/templates/_helpers.tpl @@ -43,13 +43,24 @@ Set postgresql.secret {{- define "postgresql.secret" -}} {{- if .Values.postgresql.existingSecret -}} {{- .Values.postgresql.existingSecret -}} -{{- else if .Values.postgresql.enabled -}} -{{- template "postgresql.fullname" . -}} -{{- else -}} +{{- else if .Values.postgresql.enabled -}} +{{- template "postgresql.fullname" . -}} +{{- else -}} {{- template "sonarqube.fullname" . -}} {{- end -}} {{- end -}} +{{/* +Set postgresql.secretKey +*/}} +{{- define "postgresql.secretPasswordKey" -}} +{{- if and .Values.postgresql.existingSecretPasswordKey .Values.postgresql.existingSecret -}} +{{- .Values.postgresql.existingSecretPasswordKey -}} +{{- else -}} +{{- "postgresql-password" -}} +{{- end -}} +{{- end -}} + {{/* Set postgresql.useInternalSecret */}} @@ -61,6 +72,43 @@ true {{- end -}} {{- end -}} +{{/* +Set sonarqube.jvmOpts +*/}} +{{- define "sonarqube.jvmOpts" -}} +{{- if and .Values.caCerts .Values.prometheusExporter.enabled -}} +{{ printf "-javaagent:%s/data/jmx_prometheus_javaagent.jar=8000:%s/conf/prometheus-config.yaml -Djavax.net.ssl.trustStore=%s/certs/cacerts %s" .Values.sonarqubeFolder .Values.sonarqubeFolder .Values.sonarqubeFolder .Values.jvmOpts | trim | quote }} +{{- else if .Values.caCerts -}} +{{ printf "-Djavax.net.ssl.trustStore=%s/certs/cacerts %s" .Values.sonarqubeFolder .Values.jvmOpts | trim | quote }} +{{- else if .Values.prometheusExporter.enabled -}} +{{ printf "-javaagent:%s/data/jmx_prometheus_javaagent.jar=8000:%s/conf/prometheus-config.yaml %s" .Values.sonarqubeFolder .Values.sonarqubeFolder .Values.jvmOpts | trim | quote }} +{{- else -}} +{{ printf "%s" .Values.jvmOpts }} +{{- end -}} +{{- end -}} + +{{/* +Set sonarqube.jvmCEOpts +*/}} +{{- define "sonarqube.jvmCEOpts" -}} +{{- if .Values.caCerts -}} +{{ printf "-Djavax.net.ssl.trustStore=%s/certs/cacerts %s" .Values.sonarqubeFolder .Values.jvmCeOpts | trim | quote }} +{{- else -}} +{{ printf "%s" .Values.jvmCeOpts }} +{{- end -}} +{{- end -}} + +{{/* +Set prometheusExporter.downloadURL +*/}} +{{- define "prometheusExporter.downloadURL" -}} +{{- if .Values.prometheusExporter.downloadURL -}} +{{ printf "%s" .Values.prometheusExporter.downloadURL }} +{{- else -}} +{{ printf "https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/%s/jmx_prometheus_javaagent-%s.jar" .Values.prometheusExporter.version .Values.prometheusExporter.version }} +{{- end -}} +{{- end -}} + {{/* Create chart name and version as used by the chart label. */}} diff --git a/chart/templates/change-admin-password-hook.yml b/chart/templates/change-admin-password-hook.yml index f3010b8..6cfae7d 100644 --- a/chart/templates/change-admin-password-hook.yml +++ b/chart/templates/change-admin-password-hook.yml @@ -15,6 +15,9 @@ metadata: annotations: "helm.sh/hook": post-install "helm.sh/hook-delete-policy": hook-succeeded + {{- range $key, $value := .Values.adminJobAnnotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} spec: template: metadata: @@ -31,6 +34,6 @@ spec: containers: - name: {{ template "sonarqube.fullname" . }}-change-default-admin-password image: {{ default "curlimages/curl:latest" .Values.curlContainerImage }} - command: ["sh", "-c", 'until curl -v --connect-timeout 100 {{ template "sonarqube.fullname" . }}:{{ default 9000 .Values.service.internalPort }}/api/system/status | grep -w UP; do sleep 10; done; curl -v --connect-timeout 100 -u admin:{{ default "admin" .Values.account.currentAdminPassword }} -X POST "{{ template "sonarqube.fullname" . }}:{{ default 9000 .Values.service.internalPort }}/api/users/change_password?login=admin&previousPassword={{ default "admin" .Values.account.currentAdminPassword }}&password={{ default "admin" .Values.account.adminPassword }}"'] + command: ["sh", "-c", 'until curl -v --connect-timeout 100 {{ template "sonarqube.fullname" . }}:{{ default 9000 .Values.service.internalPort }}/api/system/status | grep -w UP; do sleep 10; done; curl -v --connect-timeout 100 -u admin:{{ default "admin" .Values.account.currentAdminPassword }} -X POST "{{ template "sonarqube.fullname" . }}:{{ default 9000 .Values.service.internalPort }}/api/users/change_password?login=admin&previousPassword={{ .Values.account.currentAdminPassword | default "admin" | urlquery }}&password={{ .Values.account.adminPassword | default "admin" | urlquery }}"'] {{- end }} {{- end }} diff --git a/chart/templates/deployment.yaml b/chart/templates/deployment.yaml index da69ad2..860ce97 100644 --- a/chart/templates/deployment.yaml +++ b/chart/templates/deployment.yaml @@ -1,3 +1,4 @@ +{{- if eq .Values.deploymentType "Deployment"}} apiVersion: apps/v1 kind: Deployment metadata: @@ -58,11 +59,13 @@ spec: imagePullSecrets: - name: {{ .Values.image.pullSecret }} {{- end }} - {{- if or .Values.caCerts .Values.initSysctl.enabled .Values.elasticsearch.configureNode .Values.plugins.install .Values.postgresql.enabled (and .Values.sonarProperties .Values.sonarSecretProperties) }} initContainers: + {{- if .Values.extraInitContainers }} +{{ toYaml .Values.extraInitContainers | indent 8 }} + {{- end }} {{- if .Values.caCerts }} - name: ca-certs - image: {{ default "adoptopenjdk/openjdk11:alpine" .Values.caCerts.image }} + image: {{ default "registry1.dso.mil/ironbank/redhat/openjdk/openjdk11:1.11" .Values.caCerts.image }} imagePullPolicy: {{ .Values.image.pullPolicy }} command: ["sh"] args: ["-c", "cp -f \"${JAVA_HOME}/lib/security/cacerts\" /tmp/certs/cacerts; if [ \"$(ls /tmp/secrets/ca-certs)\" ]; then for f in /tmp/secrets/ca-certs/*; do keytool -importcert -file \"${f}\" -alias \"$(basename \"${f}\")\" -keystore /tmp/certs/cacerts -storepass changeit -trustcacerts -noprompt; done; fi;"] @@ -106,7 +109,7 @@ spec: {{- end }} {{- if .Values.plugins.install }} - name: install-plugins - image: {{ default "registry.dso.mil/platform-one/big-bang/apps/developer-tools/sonarqube/alpine-wget:latest" .Values.plugins.image }} + image: {{ default "registry1.dso.mil/ironbank/sonarsource/sonarqube/sonarqube8-community:8.9-community" .Values.plugins.image }} imagePullPolicy: {{ .Values.image.pullPolicy }} command: ["sh", "-e", @@ -130,8 +133,14 @@ spec: {{- end }} resources: {{ toYaml (default .Values.initContainers.resources .Values.plugins.resource) | indent 12 }} - {{- with .Values.env }} env: + - name: http_proxy + value: {{ default "" .Values.plugins.httpProxy }} + - name: https_proxy + value: {{ default "" .Values.plugins.httpsProxy }} + - name: no_proxy + value: {{ default "" .Values.plugins.noProxy }} + {{- with .Values.env }} {{- . | toYaml | trim | nindent 12 }} {{- end }} {{- end }} @@ -164,16 +173,12 @@ spec: {{- end }} {{- if .Values.postgresql.enabled }} - name: "wait-for-db" - image: registry1.dso.mil/ironbank/opensource/postgres/postgresql96:9.6.20 + image: {{ default "registry.dso.mil/platform-one/big-bang/apps/developer-tools/sonarqube/busybox:1.32" .Values.initContainers.image }} imagePullPolicy: {{ .Values.image.pullPolicy }} resources: {{ toYaml .Values.initContainers.resources | indent 12 }} - command: ["/bin/sh", "-c", "until pg_isready -h {{ .Release.Name}}-postgresql -p 5432 -U {{ .Values.postgresql.postgresqlUsername }}; do sleep 2; done"] - env: - - name: POSTGRES_HOST_AUTH_METHOD - value: "trust" - {{- end }} - {{- end }} + command: ["/bin/sh", "-c", "for i in $(seq 1 200); do nc -z -w3 {{ .Release.Name}}-postgresql 5432 && exit 0 || sleep 2; done; exit 1"] + {{- end }} {{- if .Values.priorityClassName }} priorityClassName: {{ .Values.priorityClassName }} {{- end }} @@ -202,24 +207,18 @@ spec: containerPort: {{ .Values.service.internalPort }} protocol: TCP env: - {{- with .Values.env }} - {{- . | toYaml | trim | nindent 12 }} - {{- end }} - name: SONAR_WEB_JAVAOPTS - {{- if .Values.caCerts }} - value: {{ printf "-Djavax.net.ssl.trustStore=%s/certs/cacerts %s" .Values.sonarqubeFolder .Values.jvmOpts | trim | quote }} - {{- else }} - value: "{{ .Values.jvmOpts }}" - {{- end }} - {{- if .Values.caCerts }} + value: {{ template "sonarqube.jvmOpts" . }} - name: SONAR_CE_JAVAOPTS - value: {{ printf "-Djavax.net.ssl.trustStore=%s/certs/cacerts" .Values.sonarqubeFolder | trim | quote }} - {{- end }} + value: {{ template "sonarqube.jvmCEOpts" . }} - name: SONAR_JDBC_PASSWORD valueFrom: secretKeyRef: name: {{ template "postgresql.secret" . }} - key: postgresql-password + key: {{ template "postgresql.secretPasswordKey" . }} + {{- with .Values.env }} + {{- . | toYaml | trim | nindent 12 }} + {{- end }} envFrom: - configMapRef: name: {{ template "sonarqube.fullname" . }}-postgres-config @@ -271,7 +270,11 @@ spec: - mountPath: {{ .Values.sonarqubeFolder }}/data name: sonarqube subPath: data - {{- if .Values.plugins.install }} + {{- if .Values.persistence.enabled }} + - mountPath: {{ .Values.sonarqubeFolder }}/extensions + name: sonarqube + subPath: extensions + {{- else if .Values.plugins.install }} - mountPath: {{ .Values.sonarqubeFolder }}/extensions/downloads name: sonarqube subPath: extensions/downloads @@ -371,3 +374,4 @@ spec: - name : concat-dir emptyDir: {{- toYaml .Values.emptyDir | nindent 10 -}} {{- end }} +{{- end }} diff --git a/chart/templates/ingress.yaml b/chart/templates/ingress.yaml index 11d8c2b..fe6dc93 100644 --- a/chart/templates/ingress.yaml +++ b/chart/templates/ingress.yaml @@ -1,7 +1,9 @@ {{- if .Values.ingress.enabled -}} {{- $serviceName := include "sonarqube.fullname" . -}} {{- $servicePort := .Values.service.externalPort -}} -{{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" }} +{{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }} +apiVersion: networking.k8s.io/v1 +{{ else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" }} apiVersion: networking.k8s.io/v1beta1 {{ else }} apiVersion: extensions/v1beta1 @@ -23,7 +25,32 @@ metadata: {{ $key }}: {{ $value | quote }} {{- end }} {{- end }} +{{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }} spec: + rules: + {{- range .Values.ingress.hosts }} + - host: {{ printf "%s" .name }} + http: + paths: + - backend: + service: + name: {{ default $serviceName .serviceName }} + port: + number: {{ default $servicePort .servicePort }} + path: {{ .path}} + pathType: ImplementationSpecific + {{- end }} +{{ else }} +spec: + {{- if .Values.ingress.annotations }} + {{- range $key, $value := .Values.ingress.annotations }} + {{- if and (eq $key "kubernetes.io/ingress.class") (contains $value "gce") }} + backend: + serviceName: {{ default $serviceName .serviceName }} + servicePort: {{ default $servicePort .servicePort }} + {{- end }} + {{- end }} + {{- end }} rules: {{- range .Values.ingress.hosts }} - host: {{ .name }} @@ -34,6 +61,7 @@ spec: serviceName: {{ default $serviceName .serviceName }} servicePort: {{ default $servicePort .servicePort }} {{- end -}} +{{ end -}} {{- if .Values.ingress.tls }} tls: {{ toYaml .Values.ingress.tls | indent 4 }} diff --git a/chart/templates/init-fs.yaml b/chart/templates/init-fs.yaml new file mode 100644 index 0000000..bb5026f --- /dev/null +++ b/chart/templates/init-fs.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "sonarqube.fullname" . }}-init-fs + labels: + app: {{ template "sonarqube.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + init_fs.sh: |- + {{- if .Values.persistence.enabled }} + chown -R {{ .Values.persistence.uid }}: {{ .Values.sonarqubeFolder }} + {{- end }} diff --git a/chart/templates/install-plugins.yaml b/chart/templates/install-plugins.yaml index 618653a..eefc4b9 100644 --- a/chart/templates/install-plugins.yaml +++ b/chart/templates/install-plugins.yaml @@ -9,21 +9,12 @@ metadata: heritage: {{ .Release.Service }} data: install_plugins.sh: |- - {{- if .Values.plugins.httpProxy }} - export http_proxy={{ .Values.plugins.httpProxy }} - {{- end }} - {{- if .Values.plugins.httpsProxy }} - export https_proxy={{ .Values.plugins.httpsProxy }} - {{- end }} - {{- if .Values.plugins.noProxy }} - export no_proxy={{ .Values.plugins.noProxy }} - {{- end }} {{- if .Values.plugins.install }} [ -e {{ .Values.sonarqubeFolder }}/extensions/downloads/* ] && rm {{ .Values.sonarqubeFolder }}/extensions/downloads/* - {{ range $index, $val := .Values.plugins.install }} - echo {{ $val | quote }} >> {{ $.Values.sonarqubeFolder }}/extensions/downloads/list{{ end }} - cat {{ .Values.sonarqubeFolder }}/extensions/downloads/list | xargs -n 1 -P 8 wget --directory-prefix {{ .Values.sonarqubeFolder }}/extensions/downloads --no-verbose - rm {{ .Values.sonarqubeFolder }}/extensions/downloads/list + cd {{ .Values.sonarqubeFolder }}/extensions/downloads + {{- range $index, $val := .Values.plugins.install }} + curl {{ if $.Values.plugins.noCheckCertificate }}--insecure{{ end }} -fsSLO {{ $val | quote }} + {{- end }} {{- end }} {{- if .Values.plugins.lib }} {{- range $index, $val := .Values.plugins.lib }} diff --git a/chart/templates/prometheus-config.yaml b/chart/templates/prometheus-config.yaml new file mode 100644 index 0000000..84481d5 --- /dev/null +++ b/chart/templates/prometheus-config.yaml @@ -0,0 +1,14 @@ +{{- if .Values.prometheusExporter.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "sonarqube.fullname" . }}-prometheus-config + labels: + app: {{ template "sonarqube.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + prometheus-config.yaml: |- +{{ toYaml .Values.prometheusExporter.config | indent 8 }} +{{- end }} \ No newline at end of file diff --git a/chart/templates/secret.yaml b/chart/templates/secret.yaml index 220be8e..0df976a 100644 --- a/chart/templates/secret.yaml +++ b/chart/templates/secret.yaml @@ -10,5 +10,19 @@ metadata: heritage: {{ .Release.Service }} type: Opaque data: - postgresql-password: {{ .Values.postgresql.postgresqlPassword | b64enc | quote }} -{{- end -}} + {{ template "postgresql.secretPasswordKey" . }}: {{ .Values.postgresql.postgresqlPassword | b64enc | quote }} +{{- end }} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "sonarqube.fullname" . }}-monitoring-passcode + labels: + app: {{ template "sonarqube.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +type: Opaque +data: + SONAR_WEB_SYSTEMPASSCODE: {{ .Values.monitoringPasscode | b64enc | quote }} \ No newline at end of file diff --git a/chart/templates/service.yaml b/chart/templates/service.yaml old mode 100644 new mode 100755 index c61fe09..3824edf --- a/chart/templates/service.yaml +++ b/chart/templates/service.yaml @@ -23,6 +23,9 @@ spec: targetPort: http protocol: TCP name: http + {{- if .Values.service.nodePort }} + nodePort: {{ .Values.service.nodePort }} + {{- end }} selector: app: {{ template "sonarqube.name" . }} release: {{ .Release.Name }} diff --git a/chart/templates/sonarqube-scc.yaml b/chart/templates/sonarqube-scc.yaml index 151dff3..7f5ed6d 100644 --- a/chart/templates/sonarqube-scc.yaml +++ b/chart/templates/sonarqube-scc.yaml @@ -60,4 +60,4 @@ users: - system:serviceaccount:{{ .Release.Namespace }}:{{ .Release.Name }}-postgresql {{- end }} -{{- end }} +{{- end }} \ No newline at end of file diff --git a/chart/templates/sonarqube-sts.yaml b/chart/templates/sonarqube-sts.yaml new file mode 100644 index 0000000..8f1ec43 --- /dev/null +++ b/chart/templates/sonarqube-sts.yaml @@ -0,0 +1,437 @@ +{{- if eq .Values.deploymentType "StatefulSet"}} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ template "sonarqube.fullname" . }} + labels: + app: {{ template "sonarqube.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + app.kubernetes.io/name: {{ template "sonarqube.name" . }}-{{ template "sonarqube.fullname" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/part-of: sonarqube + app.kubernetes.io/component: {{ template "sonarqube.fullname" . }} + app.kubernetes.io/version: {{ .Values.image.tag | quote }} +spec: + replicas: 1 + serviceName: {{ template "sonarqube.fullname" . }} + selector: + matchLabels: + app: {{ template "sonarqube.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "sonarqube.name" . }} + release: {{ .Release.Name }} +{{- with .Values.podLabels }} +{{ toYaml . | indent 8 }} +{{- end }} + annotations: + checksum/init-sysctl: {{ include (print $.Template.BasePath "/init-sysctl.yaml") . | sha256sum }} + checksum/init-fs: {{ include (print $.Template.BasePath "/init-fs.yaml") . | sha256sum }} + checksum/plugins: {{ include (print $.Template.BasePath "/install-plugins.yaml") . | sha256sum }} + checksum/config: {{ include (print $.Template.BasePath "/config.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} +{{- if .Values.annotations}} + {{- range $key, $value := .Values.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +{{- end }} + spec: + {{- if .Values.image.pullSecret }} + imagePullSecrets: + - name: {{ .Values.image.pullSecret }} + {{- end }} + initContainers: + {{- if .Values.extraInitContainers }} +{{ toYaml .Values.extraInitContainers | indent 8 }} + {{- end }} + {{- if .Values.postgresql.enabled }} + - name: "wait-for-db" + image: {{ default "registry.dso.mil/platform-one/big-bang/apps/developer-tools/sonarqube/busybox:1.32" .Values.initContainers.image }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + resources: +{{ toYaml .Values.initContainers.resources | indent 12 }} + command: ["/bin/sh", "-c", "for i in $(seq 1 200); do nc -z -w3 {{ .Release.Name}}-postgresql 5432 && exit 0 || sleep 2; done; exit 1"] + {{- end }} + {{- if or .Values.initSysctl.enabled .Values.elasticsearch.configureNode }} + {{- if .Values.caCerts }} + - name: ca-certs + image: {{ default "registry1.dso.mil/ironbank/redhat/openjdk/openjdk11:1.11" .Values.caCerts.image }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: ["sh"] + args: ["-c", "cp -f \"${JAVA_HOME}/lib/security/cacerts\" /tmp/certs/cacerts; if [ \"$(ls /tmp/secrets/ca-certs)\" ]; then for f in /tmp/secrets/ca-certs/*; do keytool -importcert -file \"${f}\" -alias \"$(basename \"${f}\")\" -keystore /tmp/certs/cacerts -storepass changeit -trustcacerts -noprompt; done; fi;"] + {{- if $securityContext := .Values.initContainers.securityContext }} + securityContext: +{{ toYaml $securityContext | indent 12 }} + {{- end }} + resources: +{{ toYaml .Values.initContainers.resources | indent 12 }} + volumeMounts: + - mountPath: /tmp/certs + name: sonarqube + subPath: certs + - mountPath: /tmp/secrets/ca-certs + name: ca-certs + {{- with .Values.env }} + env: + {{- . | toYaml | trim | nindent 12 }} + {{- end }} + {{- end }} + - name: init-sysctl + image: {{ default "registry.dso.mil/platform-one/big-bang/apps/developer-tools/sonarqube/busybox:1.32" .Values.initSysctl.image }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if $securityContext := (default .Values.initContainers.securityContext .Values.initSysctl.securityContext) }} + securityContext: +{{ toYaml $securityContext | indent 12 }} + {{- end }} + resources: +{{ toYaml (default .Values.initContainers.resources .Values.initSysctl.resources) | indent 12 }} + command: ["sh", + "-e", + "/tmp/scripts/init_sysctl.sh"] + volumeMounts: + - name: init-sysctl + mountPath: /tmp/scripts/ + {{- with .Values.env }} + env: + {{- . | toYaml | trim | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.prometheusExporter.enabled }} + - name: inject-prometheus-exporter + image: {{ default "registry1.dso.mil/ironbank/sonarsource/sonarqube/sonarqube8-community:8.9-community" .Values.prometheusExporter.image }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if $securityContext := (default .Values.initContainers.securityContext .Values.prometheusExporter.securityContext) }} + securityContext: +{{ toYaml $securityContext | indent 12 }} + {{- end }} + resources: +{{ toYaml (default .Values.initContainers.resources .Values.prometheusExporter.resources) | indent 12 }} + command: ["/bin/sh","-c"] + args: ["curl -s {{ template "prometheusExporter.downloadURL" . }} --output /data/jmx_prometheus_javaagent.jar -v"] + volumeMounts: + - mountPath: /data + name: sonarqube + subPath: data + env: + - name: http_proxy + value: {{ default "" .Values.prometheusExporter.httpProxy }} + - name: https_proxy + value: {{ default "" .Values.prometheusExporter.httpsProxy }} + - name: no_proxy + value: {{ default "" .Values.prometheusExporter.noProxy }} + {{- with .Values.env }} + {{- . | toYaml | trim | nindent 12 }} + {{- end }} + {{- end }} + {{- if and .Values.persistence.enabled .Values.initFs.enabled }} + - name: init-fs + image: {{ default "registry.dso.mil/platform-one/big-bang/apps/developer-tools/sonarqube/busybox:1.32" .Values.initFs.image }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if $securityContext := (default .Values.initContainers.securityContext .Values.initFs.securityContext) }} + securityContext: +{{ toYaml $securityContext | indent 12 }} + {{- end }} + resources: +{{ toYaml (default .Values.initContainers.resources .Values.initFs.resources) | indent 12 }} + command: ["sh", + "-e", + "/tmp/scripts/init_fs.sh"] + volumeMounts: + - name: init-fs + mountPath: /tmp/scripts/ +{{- if .Values.persistence.mounts }} +{{ toYaml .Values.persistence.mounts | indent 12 }} +{{- end }} + {{- if .Values.caCerts }} + - mountPath: {{ .Values.sonarqubeFolder }}/certs + name: sonarqube + subPath: certs + {{- end }} + - mountPath: {{ .Values.sonarqubeFolder }}/data + name: sonarqube + subPath: data + {{- if .Values.persistence.enabled }} + - mountPath: {{ .Values.sonarqubeFolder }}/extensions + name: sonarqube + subPath: extensions + {{- else if .Values.plugins.install }} + - mountPath: {{ .Values.sonarqubeFolder }}/extensions/downloads + name: sonarqube + subPath: extensions/downloads + {{- end }} + {{- if .Values.plugins.lib }} + {{- range $index, $val := .Values.plugins.lib }} + - mountPath: {{ $.Values.sonarqubeFolder }}/lib/common/{{ $val }} + name: sonarqube + subPath: lib/common/{{ $val }} + {{- end }} + {{- end }} + - mountPath: {{ .Values.sonarqubeFolder }}/temp + name: sonarqube + subPath: temp + - mountPath: {{ .Values.sonarqubeFolder }}/logs + name: sonarqube + subPath: logs + - mountPath: /tmp + name: tmp-dir + {{- end }} + {{- if .Values.plugins.install }} + - name: install-plugins + image: {{ default "registry1.dso.mil/ironbank/sonarsource/sonarqube/sonarqube8-community:8.9-community" .Values.plugins.image }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: ["sh", + "-e", + "/tmp/scripts/install_plugins.sh"] + volumeMounts: + - mountPath: {{ .Values.sonarqubeFolder }}/extensions/downloads + name: sonarqube + subPath: extensions/downloads + - mountPath: {{ .Values.sonarqubeFolder }}/lib/common + name: sonarqube + subPath: lib/common + - name: install-plugins + mountPath: /tmp/scripts/ + {{- if .Values.plugins.netrcCreds }} + - name: plugins-netrc-file + mountPath: /root + {{- end }} + {{- if $securityContext := (default .Values.initContainers.securityContext .Values.plugins.securityContext) }} + securityContext: +{{ toYaml $securityContext | indent 12 }} + {{- end }} + resources: +{{ toYaml (default .Values.initContainers.resources .Values.plugins.resource) | indent 12 }} + env: + - name: http_proxy + value: {{ default "" .Values.plugins.httpProxy }} + - name: https_proxy + value: {{ default "" .Values.plugins.httpsProxy }} + - name: no_proxy + value: {{ default "" .Values.plugins.noProxy }} + {{- with .Values.env }} + {{- . | toYaml | trim | nindent 12 }} + {{- end }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.internalPort }} + protocol: TCP + resources: +{{ toYaml (default .Values.resources .Values.resource) | indent 12 }} + env: + - name: SONAR_WEB_JAVAOPTS + value: {{ template "sonarqube.jvmOpts" . }} + - name: SONAR_CE_JAVAOPTS + value: {{ template "sonarqube.jvmCEOpts" . }} + - name: SONAR_JDBC_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "postgresql.secret" . }} + key: {{ template "postgresql.secretPasswordKey" . }} + - name: SONAR_WEB_SYSTEMPASSCODE + valueFrom: + secretKeyRef: + name: {{ template "sonarqube.fullname" . }}-monitoring-passcode + key: SONAR_WEB_SYSTEMPASSCODE + {{- with .Values.env }} + {{- . | toYaml | trim | nindent 12 }} + {{- end }} + envFrom: + - configMapRef: + name: {{ template "sonarqube.fullname" . }}-postgres-config +{{- range .Values.extraConfig.secrets }} + - secretRef: + name: {{ . }} +{{- end }} +{{- range .Values.extraConfig.configmaps }} + - configMapRef: + name: {{ . }} +{{- end }} + livenessProbe: + httpGet: + path: {{ .Values.livenessProbe.sonarWebContext }}api/system/status + port: http + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + readinessProbe: + httpGet: + path: {{ .Values.readinessProbe.sonarWebContext }}api/system/status + port: http + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + startupProbe: + httpGet: + scheme: HTTP + path: {{ .Values.readinessProbe.sonarWebContext }}api/system/status + port: 9000 + initialDelaySeconds: {{ .Values.startupProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.startupProbe.periodSeconds }} + failureThreshold: {{ .Values.startupProbe.failureThreshold }} + {{- if .Values.containerSecurityContext }} + securityContext: +{{- toYaml .Values.containerSecurityContext | nindent 12 }} + {{- end }} + volumeMounts: +{{- if .Values.persistence.mounts }} +{{ toYaml .Values.persistence.mounts | indent 12 }} +{{- end }} + {{- if and .Values.sonarProperties .Values.sonarSecretProperties }} + - mountPath: {{ .Values.sonarqubeFolder }}/conf/sonar.properties + subPath: sonar.properties + name: concat-dir + {{- else if or .Values.sonarProperties (not .Values.elasticsearch.bootstrapChecks) }} + - mountPath: {{ .Values.sonarqubeFolder }}/conf/sonar.properties + subPath: sonar.properties + name: config + {{- end }} + {{- if .Values.sonarSecretKey }} + - mountPath: {{ .Values.sonarqubeFolder }}/secret/ + name: secret + {{- end }} + {{- if .Values.caCerts }} + - mountPath: {{ .Values.sonarqubeFolder }}/certs + name: sonarqube + subPath: certs + {{- end }} + - mountPath: {{ .Values.sonarqubeFolder }}/data + name: sonarqube + subPath: data + {{- if .Values.persistence.enabled }} + - mountPath: {{ .Values.sonarqubeFolder }}/extensions + name: sonarqube + subPath: extensions + {{- else if .Values.plugins.install }} + - mountPath: {{ .Values.sonarqubeFolder }}/extensions/downloads + name: sonarqube + subPath: extensions/downloads + {{- end }} + {{- if .Values.plugins.lib }} + {{- range $index, $val := .Values.plugins.lib }} + - mountPath: {{ $.Values.sonarqubeFolder }}/lib/common/{{ $val }} + name: sonarqube + subPath: lib/common/{{ $val }} + {{- end }} + {{- end }} + - mountPath: {{ .Values.sonarqubeFolder }}/temp + name: sonarqube + subPath: temp + - mountPath: {{ .Values.sonarqubeFolder }}/logs + name: sonarqube + subPath: logs + - mountPath: /tmp + name: tmp-dir + {{- if .Values.prometheusExporter.enabled }} + - mountPath: {{ .Values.sonarqubeFolder }}/conf/prometheus-config.yaml + subPath: prometheus-config.yaml + name: prometheus-config + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.serviceAccount.create }} + {{- if .Values.serviceAccount.name }} + serviceAccountName: {{ .Values.serviceAccount.name }} + {{- else }} + serviceAccountName: {{ include "sonarqube.fullname" . }} + {{- end }} + {{- end }} + volumes: +{{- if .Values.persistence.volumes }} +{{ tpl (toYaml .Values.persistence.volumes | indent 6) . }} +{{- end }} + {{- if or .Values.sonarProperties (not .Values.elasticsearch.bootstrapChecks) }} + - name: config + configMap: + name: {{ template "sonarqube.fullname" . }}-config + items: + - key: sonar.properties + path: sonar.properties + {{- end }} + {{- if .Values.sonarSecretProperties }} + - name: secret-config + secret: + secretName: {{ .Values.sonarSecretProperties }} + items: + - key: secret.properties + path: secret.properties + {{- end }} + {{- if .Values.sonarSecretKey }} + - name: secret + secret: + secretName: {{ .Values.sonarSecretKey }} + items: + - key: sonar-secret.txt + path: sonar-secret.txt + {{- end }} + {{- if .Values.caCerts }} + - name: ca-certs + secret: + secretName: {{ .Values.caCerts.secret }} + {{- end }} + {{- if .Values.plugins.netrcCreds }} + - name: plugins-netrc-file + secret: + secretName: {{ .Values.plugins.netrcCreds }} + items: + - key: netrc + path: .netrc + {{- end }} + - name: init-sysctl + configMap: + name: {{ template "sonarqube.fullname" . }}-init-sysctl + items: + - key: init_sysctl.sh + path: init_sysctl.sh + - name: init-fs + configMap: + name: {{ template "sonarqube.fullname" . }}-init-fs + items: + - key: init_fs.sh + path: init_fs.sh + - name: install-plugins + configMap: + name: {{ template "sonarqube.fullname" . }}-install-plugins + items: + - key: install_plugins.sh + path: install_plugins.sh + {{- if .Values.prometheusExporter.enabled }} + - name: prometheus-config + configMap: + name: {{ template "sonarqube.fullname" . }}-prometheus-config + items: + - key: prometheus-config.yaml + path: prometheus-config.yaml + {{- end }} + - name: sonarqube + {{- if .Values.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ if .Values.persistence.existingClaim }}{{ .Values.persistence.existingClaim }}{{- else }}{{ template "sonarqube.fullname" . }}{{- end }} + {{- else }} + emptyDir: {{- toYaml .Values.emptyDir | nindent 10 }} + {{- end }} + - name : tmp-dir + emptyDir: {{- toYaml .Values.emptyDir | nindent 10 }} + {{- if .Values.sonarSecretProperties }} + - name : concat-dir + emptyDir: {{- toYaml .Values.emptyDir | nindent 10 -}} + {{- end }} +{{- end }} diff --git a/chart/templates/tests/sonarqube-test.yaml b/chart/templates/tests/sonarqube-test.yaml new file mode 100644 index 0000000..9ecef43 --- /dev/null +++ b/chart/templates/tests/sonarqube-test.yaml @@ -0,0 +1,47 @@ +{{- if .Values.tests.enabled -}} +apiVersion: v1 +kind: Pod +metadata: + name: "{{ .Release.Name }}-ui-test" + annotations: + "helm.sh/hook": test-success + labels: + app: {{ template "sonarqube.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + initContainers: + - name: "bats" + image: "bats/bats:1.2.1" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: ["bash", "-c"] + args: + - |- + set -ex + cp -R /opt/bats /tools/bats/ + volumeMounts: + - mountPath: /tools + name: tools + containers: + - name: {{ .Release.Name }}-ui-test + image: {{ default "bitnami/minideb-extras" .Values.tests.image }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: [ + "/tools/bats/bin/bats", + "--tap", + "/tests/run.sh"] + volumeMounts: + - mountPath: /tests + name: tests + readOnly: true + - mountPath: /tools + name: tools + volumes: + - name: tests + configMap: + name: {{ template "sonarqube.fullname" . }}-tests + - name: tools + emptyDir: {{ toYaml .Values.emptyDir | nindent 6 }} + restartPolicy: Never +{{- end -}} diff --git a/chart/tests/cypress/sonarqube-health.spec.js b/chart/tests/cypress/sonarqube-health.spec.js index 91dcead..5325684 100644 --- a/chart/tests/cypress/sonarqube-health.spec.js +++ b/chart/tests/cypress/sonarqube-health.spec.js @@ -10,6 +10,7 @@ describe('Basic Sonarqube', function() { cy.get('input[name="password"]').type(Cypress.env('newpassword')) cy.get('input[name="password_confirmation"]').type(Cypress.env('newpassword')) cy.get('button[id="change-password"]').click() + cy.contains("I understand the risk").click() cy.scrollTo('topRight') cy.get('a[class="dropdown-toggle navbar-avatar"]').click() cy.contains("My Account").click() diff --git a/chart/values.yaml b/chart/values.yaml index 7bb5d87..28a1aa0 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -1,6 +1,11 @@ # Default values for sonarqube. # This is a YAML-formatted file. # Declare variables to be passed into your templates. + +deploymentType: "StatefulSet" + +# If the deployment Type is set to Deployment sonarqube is deployed as a replica set +# There should not be more than 1 sonarqube instance connected to the same database replicaCount: 1 # This will use the default deployment strategy unless it is overriden @@ -20,12 +25,11 @@ OpenShift: image: repository: registry.dso.mil/platform-one/big-bang/apps/developer-tools/sonarqube/sonarqube8-community-bb - tag: 8.7.1-community-bb + tag: 8.9-community-bb pullPolicy: IfNotPresent # If using a private repository, the name of the imagePullSecret to use pullSecret: private-registry - # Set security context for sonarqube pod securityContext: fsGroup: 1000 @@ -41,6 +45,10 @@ elasticsearch: configureNode: false bootstrapChecks: true +# also install the nginx ingress helm chart +nginx: + enabled: false + service: type: ClusterIP externalPort: 9000 @@ -56,7 +64,7 @@ ingress: enabled: false # Used to create an Ingress record. hosts: - - name: sonar.example.com + - name: sonarqube.your-org.com # Different clouds or configurations might need /* as the default path path: / # For additional control over serviceName and servicePort @@ -84,11 +92,21 @@ affinity: {} # Tolerations for pod assignment # Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ +# taint a node with the following command to mark it as not schedulable for new pods +# kubectl taint nodes sonarqube=true:NoSchedule +# The following statement will tolerate this taint and as such reverse a node for sonarqube tolerations: [] +# - key: "sonarqube" +# operator: "Equal" +# value: "true" +# effect: "NoSchedule" # Node labels for pod assignment # Ref: https://kubernetes.io/docs/user-guide/node-selection/ +# add a label to a node with the following command +# kubectl label node sonarqube=true nodeSelector: {} +# sonarqube: "true" # hostAliases allows the modification of the hosts file inside a container hostAliases: [] @@ -108,15 +126,24 @@ readinessProbe: livenessProbe: initialDelaySeconds: 60 periodSeconds: 30 + failureThreshold: 6 # If an ingress *path* other than the root (/) is defined, it should be reflected here # A trailing "/" must be included sonarWebContext: / # sonarWebContext: /sonarqube/ # If an ingress *path* is defined, it should be reflected here # sonar.web.context: /sonarqube +startupProbe: + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 24 + # If an ingress *path* other than the root (/) is defined, it should be reflected here + # A trailing "/" must be included + sonarWebContext: / + # sonarWebContext: /sonarqube/ initContainers: - # image: registry.dso.mil/platform-one/big-bang/apps/developer-tools/sonarqube/busybox:1.32 + # image: busybox:1.32 # We allow the init containers to have a separate security context declaration because # the initContainer may not require the same as SonarQube. # securityContext: {} @@ -124,12 +151,15 @@ initContainers: # the initContainer does not take as much resources. resources: {} +extraInitContainers: {} +# Extra init containers to e.g. download required artifacts + ## Provide a secret containing one or more certificate files in the keys that will be added to cacerts ## The cacerts file will be set via SONARQUBE_WEB_JVM_OPTS and SONAR_CE_JAVAOPTS ## -# caCerts: +## caCerts: # image: adoptopenjdk/openjdk11:alpine - # secret: my-secret + # secret: your-secret initSysctl: enabled: false @@ -137,11 +167,36 @@ initSysctl: fsFileMax: 131072 nofile: 131072 nproc: 8192 - # image: registry.dso.mil/platform-one/big-bang/apps/developer-tools/sonarqube/busybox:1.32 + # image: busybox:1.32 securityContext: privileged: true # resources: {} +initFs: + enabled: false + # image: busybox:1.32 + securityContext: + privileged: true + +prometheusExporter: + enabled: false + # jmx_prometheus_javaagent version to download from Maven Central + version: "0.15.0" + # Alternative full download URL for the jmx_prometheus_javaagent.jar (overrides prometheusExporter.version) + # downloadURL: "" + config: + rules: + - pattern: ".*" + # image: curlimages/curl:7.76.1 + # For use behind a corporate proxy when downloading prometheus + # httpProxy: "" + # httpsProxy: "" + # noProxy: "" + # Setting the security context to root as the /data volume is owned by root at this stage + securityContext: + runAsUser: 0 + runAsGroup: 0 + # List of plugins to install. # For example: # plugins: @@ -149,11 +204,7 @@ initSysctl: # - "https://github.com/AmadeusITGroup/sonar-stash/releases/download/1.3.0/sonar-stash-plugin-1.3.0.jar" # - "https://github.com/SonarSource/sonar-ldap/releases/download/2.2-RC3/sonar-ldap-plugin-2.2.0.601.jar" plugins: - install: -# - https://github.com/dependency-check/dependency-check-sonar-plugin/releases/download/1.2.6/sonar-dependency-check-plugin-1.2.6.jar -# - https://github.com/SonarOpenCommunity/sonar-cxx/releases/download/cxx-1.3.2/sonar-c-plugin-1.3.2.1853.jar -# - https://github.com/SonarOpenCommunity/sonar-cxx/releases/download/cxx-1.3.2/sonar-cxx-plugin-1.3.2.1853.jar -# - https://github.com/dmeiners88/sonarqube-prometheus-exporter/releases/download/v1.0.0-SNAPSHOT-2018-07-04/sonar-prometheus-exporter-1.0.0-SNAPSHOT.jar + install: [] lib: [] # For use behind a corporate proxy when downloading plugins @@ -161,17 +212,30 @@ plugins: # httpsProxy: "" # noProxy: "" - # image: registry.dso.mil/platform-one/big-bang/apps/developer-tools/sonarqube/alpine-wget:latest + # image: curlimages/curl:7.76.1 # resources: {} # .netrc secret file with a key "netrc" to use basic auth while downloading plugins # netrcCreds: "" + # Set to true to not validate the server's certificate to download plugin + noCheckCertificate: false + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + ## Values to add to SONARQUBE_WEB_JVM_OPTS ## # jvmOpts: "-Djava.net.preferIPv4Stack=true" jvmOpts: "" +## Values to add to SONAR_CE_JAVAOPTS +jvmCeOpts: "" + +## a monitoring passcode needs to be defined in order to get reasonable probe results +# not setting the monitoring passcode will result in a deployment that will never be ready +monitoringPasscode: "define_it" + ## Environment variables to attach to the pods ## # env: @@ -181,17 +245,16 @@ jvmOpts: "" # Set annotations for pods annotations: {} -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:'. -# limits: -# cpu: 100m -# memory: 128Mi -# requests: -# cpu: 100m -# memory: 128Mi +## We usually don't make specific ressource recommandations, as they are heavily dependend on +## The usage of SonarQube and the surrounding infrastructure. +## Adjust these values to your needs, but make sure that the memory limit is never under 4 GB +resources: + limits: + cpu: 800m + memory: 4096M + requests: + cpu: 400m + memory: 2Gi persistence: enabled: false ## Set annotations on pvc @@ -209,7 +272,8 @@ persistence: ## storageClass: accessMode: ReadWriteOnce - size: 10Gi + size: 5Gi + uid: 1000 ## Specify extra volumes. Refer to ".spec.volumes" specification : https://kubernetes.io/fr/docs/concepts/storage/volumes/ volumes: [] @@ -224,20 +288,10 @@ emptyDir: {} # A custom sonar.properties file can be provided via dictionary. # For example: -sonarProperties: - sonar.forceAuthentication: true -# SAML SSO config -# sonar.core.serverBaseURL: -# sonar.auth.saml.enabled: false -# sonar.auth.saml.applicationId: -# sonar.auth.saml.providerName: -# sonar.auth.saml.providerId: -# sonar.auth.saml.loginUrl: -# sonar.auth.saml.certificate.secured: -# sonar.auth.saml.user.login: -# sonar.auth.saml.user.name: -# sonar.auth.saml.user.email: -# sonar.auth.saml.group.name: +# sonarProperties: +# sonar.forceAuthentication: true +# sonar.security.realm: LDAP +# ldap.url: ldaps://organization.com # Additional sonar properties to load from a secret with a key "secret.properties" (must be a string) # sonarSecretProperties: @@ -265,6 +319,7 @@ postgresql: # instance, set enabled to false and provide the name of the secret on the # line below: # existingSecret: "" + # existingSecretPasswordKey: "postgresql-password" postgresqlUsername: "sonarUser" postgresqlPassword: "sonarPass" postgresqlDatabase: "sonarDB" @@ -316,7 +371,7 @@ sonarqubeFolder: /opt/sonarqube tests: enabled: false - # image: registry.dso.mil/platform-one/big-bang/apps/developer-tools/sonarqube/minideb-extras:latest + # image: bitnami/minideb-extras serviceAccount: create: false @@ -351,6 +406,7 @@ extraConfig: # adminPassword: admin # currentAdminPassword: admin # curlContainerImage: curlimages/curl:latest +# adminJobAnnotations: {} terminationGracePeriodSeconds: 60 @@ -369,6 +425,7 @@ istio: - istio-system/main hosts: - sonarqube.{{ .Values.hostname }} + monitoring: enabled: false -- GitLab