update charts
diff --git a/charts/k8s-gerrit/Documentation/developer-guide.md b/charts/k8s-gerrit/Documentation/developer-guide.md
new file mode 100644
index 0000000..0e5fc5f
--- /dev/null
+++ b/charts/k8s-gerrit/Documentation/developer-guide.md
@@ -0,0 +1,83 @@
+# Developer Guide
+
+[TOC]
+
+## Code Review
+
+This project uses Gerrit for code review:
+https://gerrit-review.googlesource.com/
+which uses the ["git push" workflow][1] with server
+https://gerrit.googlesource.com/k8s-gerrit. You will need a
+[generated cookie][2].
+
+Gerrit depends on "Change-Id" annotations in your commit message.
+If you try to push a commit without one, it will explain how to
+install the proper git-hook:
+
+```
+curl -Lo `git rev-parse --git-dir`/hooks/commit-msg \
+ https://gerrit-review.googlesource.com/tools/hooks/commit-msg
+chmod +x `git rev-parse --git-dir`/hooks/commit-msg
+```
+
+Before you create your local commit (which you'll push to Gerrit)
+you will need to set your email to match your Gerrit account:
+
+```
+git config --local --add user.email foo@bar.com
+```
+
+Normally you will create code reviews by pushing for master:
+
+```
+git push origin HEAD:refs/for/master
+```
+
+## Developing container images
+
+When changing or creating container images, keep the image size as small as
+possible. This reduces storage space needed for images, the upload time and most
+importantly the download time, which improves startup time of pods.
+
+Some good practices are listed here:
+
+- **Chain commands:** Each `RUN`-command creates a new layer in the docker image.
+Each layer increases the total image size. Thus, reducing the number of layers,
+can also reduce the image size.
+
+- **Clean up after package installation:** The package installation creates a
+number of cache files, which should be removed after installation. In Ubuntu/Debian-
+based images use the following snippet (This requires `apt-get update` before
+each package installation!):
+
+```docker
+RUN apt-get update && \
+ apt get install -y <packages> && \
+ apt-get clean && \
+ rm -rf /var/lib/apt/lists/*
+```
+
+In Alpine based images use the `--no-cache`-flag of `apk`.
+
+- **Clean up temporary files immediately:** If temporary files are created by a
+command remove them in the same command chain.
+
+- **Use multi stage builds:** If some complicated build processes are needed for
+building parts of the container image, of which only the final product is needed,
+use [multi stage builds][3]
+
+
+[1]: https://gerrit-review.googlesource.com/Documentation/user-upload.html#_git_push
+[2]: https://gerrit.googlesource.com/new-password
+[3]: https://docs.docker.com/develop/develop-images/multistage-build/
+
+## Writing clean python code
+
+When writing python code, either for tests or for scripts, use `black` and `pylint`
+to ensure a clean code style. They can be run by the following commands:
+
+```sh
+pipenv install --dev
+pipenv run black $(find . -name '*.py')
+pipenv run pylint $(find . -name '*.py')
+```
diff --git a/charts/k8s-gerrit/Documentation/istio.md b/charts/k8s-gerrit/Documentation/istio.md
new file mode 100644
index 0000000..1803b32
--- /dev/null
+++ b/charts/k8s-gerrit/Documentation/istio.md
@@ -0,0 +1,40 @@
+# Istio
+
+Istio provides an alternative way to control ingress traffic into the cluster.
+In addition, it allows to finetune the traffic inside the cluster and provides
+a huge repertoire of load balancing and routing mechanisms.
+
+***note
+Currently, only the Gerrit replica chart allows using istio out of the box.
+***
+
+## Install istio
+
+An example configuration based on the default profile provided by istio can be
+found under `./istio/src/`. Some values will have to be adapted to the respective
+system. These are marked by comments tagged with `TO_BE_CHANGED`.
+To install istio with this configuration, run:
+
+```sh
+kubectl apply -f istio/istio-system-namespace.yaml
+istioctl install -f istio/gerrit.profile.yaml
+```
+
+To install Gerrit using istio for networking, the namespace running Gerrit has to
+be configured to enable sidecar injection, by setting the `istio-injection: enabled`
+label. An example for such a namespace can be found at `./istio/namespace.yaml`.
+
+## Uninstall istio
+
+To uninstall istio, run:
+
+```sh
+istioctl uninstall -f istio/gerrit.profile.yaml
+```
+
+## Restricting access to a list of allowed IPs
+
+In development setups, it might be wanted to allow access to the setup only from
+specified IPs. This can be done by patching the `spec.loadBalancerSourceRanges`
+value of the service used for the IngressGateway. A patch doing that can be
+uncommented in `istio/gerrit.profile.yaml`.
diff --git a/charts/k8s-gerrit/Documentation/minikube.md b/charts/k8s-gerrit/Documentation/minikube.md
new file mode 100644
index 0000000..18af7cc
--- /dev/null
+++ b/charts/k8s-gerrit/Documentation/minikube.md
@@ -0,0 +1,207 @@
+# Running Gerrit on Kubernetes using Minikube
+
+To test Gerrit on Kubernetes locally, a one-node cluster can be set up using
+Minikube. Minikube provides basic Kubernetes functionality and allows to quickly
+deploy and evaluate a Kubernetes deployment.
+This tutorial will guide through setting up Minikube to deploy the gerrit and
+gerrit-replica helm charts to it. Note, that due to limited compute
+resources on a single local machine and the restricted functionality of Minikube,
+the full functionality of the charts might not be usable.
+
+## Installing Kubectl and Minikube
+
+To use Minikube, a hypervisor is needed. A good non-commercial solution is HyperKit.
+The Minikube project provides binaries to install the driver:
+
+```sh
+curl -LO https://storage.googleapis.com/minikube/releases/latest/docker-machine-driver-hyperkit \
+ && sudo install -o root -g wheel -m 4755 docker-machine-driver-hyperkit /usr/local/bin/
+```
+
+To manage Kubernetes clusters, the Kubectl CLI tool will be needed. A detailed
+guide how to do that for all supported OSs can be found
+[here](https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-with-homebrew-on-macos).
+On OSX hombrew can be used for installation:
+
+```sh
+brew install kubernetes-cli
+```
+
+Finally, Minikube can be installed. Download the latest binary
+[here](https://github.com/kubernetes/minikube/releases). To install it on OSX, run:
+
+```sh
+VERSION=1.1.0
+curl -Lo minikube https://storage.googleapis.com/minikube/releases/v$VERSION/minikube-darwin-amd64 && \
+ chmod +x minikube && \
+ sudo cp minikube /usr/local/bin/ && \
+ rm minikube
+```
+
+## Starting a Minikube cluster
+
+For a more detailed overview over the features of Minikube refer to the
+[official documentation](https://kubernetes.io/docs/setup/minikube/). If a
+hypervisor driver other than virtual box (e.g. hyperkit) is used, set the
+`--vm-driver` option accordingly:
+
+```sh
+minikube config set vm-driver hyperkit
+```
+
+The gerrit and gerrit-replica charts are configured to work with the default
+resource limits configured for minikube (2 cpus and 2Gi RAM). If more resources
+are desired (e.g. to speed up deployment startup or for more resource intensive
+tests), configure the resource limits using:
+
+```sh
+minikube config set memory 4096
+minikube config set cpus 4
+```
+
+To install a full Gerrit and Gerrit replica setup with reasonable startup
+times, Minikube will need about 9.5 GB of RAM and 3-4 CPUs! But the more the
+better.
+
+To start a Minikube cluster simply run:
+
+```sh
+minikube start
+```
+
+Starting up the cluster will take a while. The installation should automatically
+configure kubectl to connect to the Minikube cluster. Run the following command
+to test whether the cluster is up:
+
+```sh
+kubectl get nodes
+
+NAME STATUS ROLES AGE VERSION
+minikube Ready master 1h v1.14.2
+```
+
+The helm-charts use ingresses, which can be used in Minikube by enabling the
+ingress addon:
+
+```sh
+minikube addons enable ingress
+```
+
+Since for testing there will probably no usable host names configured to point
+to the minikube installation, the traffic to the hostnames configured in the
+Ingress definition needs to be redirected to Minikube by editing the `/etc/hosts`-
+file, adding a line containing the Minikube IP and a whitespace-delimited list
+of all the hostnames:
+
+```sh
+echo "$(minikube ip) primary.gerrit backend.gerrit replica.gerrit" | sudo tee -a /etc/hosts
+```
+
+The host names (e.g. `primary.gerrit`) are the defaults, when using the values.yaml
+files provided as and example for minikube. Change them accordingly, if a different
+one is chosen.
+This will only redirect traffic from the computer running Minikube.
+
+To see whether all cluster components are ready, run:
+
+```sh
+kubectl get pods --all-namespaces
+```
+
+The status of all components should be `Ready`. The kubernetes dashboard giving
+an overview over all cluster components, can be opened by executing:
+
+```sh
+minikube dashboard
+```
+
+## Install helm
+
+Helm is needed to install and manage the helm charts. To install the helm client
+on your local machine (running OSX), run:
+
+```sh
+brew install kubernetes-helm
+```
+
+A guide for all suported OSs can be found [here](https://docs.helm.sh/using_helm/#installing-helm).
+
+## Start an NFS-server
+
+The helm-charts need a volume with ReadWriteMany access mode to store
+git-repositories. This guide will use the nfs-server-provisioner chart to provide
+NFS-volumes directly in the cluster. A basic configuration file for the nfs-server-
+provisioner-chart is provided in the supplements-directory. It can be installed
+by running:
+
+```sh
+helm install nfs \
+ stable/nfs-server-provisioner \
+ -f ./supplements/nfs.minikube.values.yaml
+```
+
+## Installing the gerrit helm chart
+
+A configuration file to configure the gerrit chart is provided at
+`./supplements/gerrit.minikube.values.yaml`. To install the gerrit
+chart on Minikube, run:
+
+```sh
+helm install gerrit \
+ ./helm-charts/gerrit \
+ -f ./supplements/gerrit.minikube.values.yaml
+```
+
+Startup may take some time, especially when allowing only a small amount of
+resources to the containers. Check progress with `kubectl get pods -w` until
+it says that the pod `gerrit-gerrit-stateful-set-0` is `Running`.
+Then use `kubectl logs -f gerrit-gerrit-stateful-set-0` to follow
+the startup process of Gerrit until a line like this shows that Gerrit is ready:
+
+```sh
+[2019-06-04 15:24:25,914] [main] INFO com.google.gerrit.pgm.Daemon : Gerrit Code Review 2.16.8-86-ga831ebe687 ready
+```
+
+To open Gerrit's UI, run:
+
+```sh
+open http://primary.gerrit
+```
+
+## Installing the gerrit-replica helm chart
+
+A custom configuration file to configure the gerrit-replica chart is provided at
+`./supplements/gerrit-replica.minikube.values.yaml`. Install it by running:
+
+```sh
+helm install gerrit-replica \
+ ./helm-charts/gerrit-replica \
+ -f ./supplements/gerrit-replica.minikube.values.yaml
+```
+
+The replica will start up, which can be followed by running:
+
+```sh
+kubectl logs -f gerrit-replica-gerrit-replica-deployment-<id>
+```
+
+Replication of repositories has to be started on the Gerrit, e.g. by making
+a change in the respective repositories. Only then previous changes to the
+repositories will be available on the replica.
+
+## Cleanup
+
+Shut down minikube:
+
+```sh
+minikube stop
+```
+
+Delete the minikube cluster:
+
+```sh
+minikube delete
+```
+
+Remove the line added to `/etc/hosts`. If Minikube is restarted, the cluster will
+get a new IP and the `/etc/hosts`-entry has to be adjusted.
diff --git a/charts/k8s-gerrit/Documentation/operator-api-reference.md b/charts/k8s-gerrit/Documentation/operator-api-reference.md
new file mode 100644
index 0000000..5d03cf5
--- /dev/null
+++ b/charts/k8s-gerrit/Documentation/operator-api-reference.md
@@ -0,0 +1,1160 @@
+# Gerrit Operator - API Reference
+
+- [Gerrit Operator - API Reference](#gerrit-operator---api-reference)
+ - [General Remarks](#general-remarks)
+ - [Inheritance](#inheritance)
+ - [GerritCluster](#gerritcluster)
+ - [Gerrit](#gerrit)
+ - [Receiver](#receiver)
+ - [GitGarbageCollection](#gitgarbagecollection)
+ - [GerritNetwork](#gerritnetwork)
+ - [GerritClusterSpec](#gerritclusterspec)
+ - [GerritClusterStatus](#gerritclusterstatus)
+ - [StorageConfig](#storageconfig)
+ - [GerritStorageConfig](#gerritstorageconfig)
+ - [StorageClassConfig](#storageclassconfig)
+ - [NfsWorkaroundConfig](#nfsworkaroundconfig)
+ - [SharedStorage](#sharedstorage)
+ - [PluginCacheConfig](#plugincacheconfig)
+ - [ExternalPVCConfig](#externalpvcconfig)
+ - [ContainerImageConfig](#containerimageconfig)
+ - [BusyBoxImage](#busyboximage)
+ - [GerritRepositoryConfig](#gerritrepositoryconfig)
+ - [GerritClusterIngressConfig](#gerritclusteringressconfig)
+ - [GerritIngressTlsConfig](#gerritingresstlsconfig)
+ - [GerritIngressAmbassadorConfig](#gerritingressambassadorconfig)
+ - [GlobalRefDbConfig](#globalrefdbconfig)
+ - [RefDatabase](#refdatabase)
+ - [SpannerRefDbConfig](#spannerrefdbconfig)
+ - [ZookeeperRefDbConfig](#zookeeperrefdbconfig)
+ - [GerritTemplate](#gerrittemplate)
+ - [GerritTemplateSpec](#gerrittemplatespec)
+ - [GerritProbe](#gerritprobe)
+ - [GerritServiceConfig](#gerritserviceconfig)
+ - [GerritSite](#gerritsite)
+ - [GerritModule](#gerritmodule)
+ - [GerritPlugin](#gerritplugin)
+ - [GerritMode](#gerritmode)
+ - [GerritDebugConfig](#gerritdebugconfig)
+ - [GerritSpec](#gerritspec)
+ - [GerritStatus](#gerritstatus)
+ - [IngressConfig](#ingressconfig)
+ - [ReceiverTemplate](#receivertemplate)
+ - [ReceiverTemplateSpec](#receivertemplatespec)
+ - [ReceiverSpec](#receiverspec)
+ - [ReceiverStatus](#receiverstatus)
+ - [ReceiverProbe](#receiverprobe)
+ - [ReceiverServiceConfig](#receiverserviceconfig)
+ - [GitGarbageCollectionSpec](#gitgarbagecollectionspec)
+ - [GitGarbageCollectionStatus](#gitgarbagecollectionstatus)
+ - [GitGcState](#gitgcstate)
+ - [GerritNetworkSpec](#gerritnetworkspec)
+ - [NetworkMember](#networkmember)
+ - [NetworkMemberWithSsh](#networkmemberwithssh)
+
+## General Remarks
+
+### Inheritance
+
+Some objects inherit the fields of other objects. In this case the section will
+contain an **Extends:** label to link to the parent object, but it will not repeat
+inherited fields.
+
+## GerritCluster
+
+---
+
+**Group**: gerritoperator.google.com \
+**Version**: v1alpha17 \
+**Kind**: GerritCluster
+
+---
+
+
+| Field | Type | Description |
+|---|---|---|
+| `apiVersion` | `String` | APIVersion of this resource |
+| `kind` | `String` | Kind of this resource |
+| `metadata` | [`ObjectMeta`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#objectmeta-v1-meta) | Metadata of the resource |
+| `spec` | [`GerritClusterSpec`](#gerritclusterspec) | Specification for GerritCluster |
+| `status` | [`GerritClusterStatus`](#gerritclusterstatus) | Status for GerritCluster |
+
+Example:
+
+```yaml
+apiVersion: "gerritoperator.google.com/v1alpha17"
+kind: GerritCluster
+metadata:
+ name: gerrit
+spec:
+ containerImages:
+ imagePullSecrets: []
+ imagePullPolicy: Always
+ gerritImages:
+ registry: docker.io
+ org: k8sgerrit
+ tag: latest
+ busyBox:
+ registry: docker.io
+ tag: latest
+
+ storage:
+ storageClasses:
+ readWriteOnce: default
+ readWriteMany: shared-storage
+ nfsWorkaround:
+ enabled: false
+ chownOnStartup: false
+ idmapdConfig: |-
+ [General]
+ Verbosity = 0
+ Domain = localdomain.com
+
+ [Mapping]
+ Nobody-User = nobody
+ Nobody-Group = nogroup
+
+ sharedStorage:
+ externalPVC:
+ enabled: false
+ claimName: ""
+ size: 1Gi
+ volumeName: ""
+ selector:
+ matchLabels:
+ volume-type: ssd
+ aws-availability-zone: us-east-1
+
+ pluginCache:
+ enabled: false
+
+ ingress:
+ enabled: true
+ host: example.com
+ annotations: {}
+ tls:
+ enabled: false
+ secret: ""
+ ambassador:
+ id: []
+ createHost: false
+
+ refdb:
+ database: NONE
+ spanner:
+ projectName: ""
+ instance: ""
+ database: ""
+ zookeeper:
+ connectString: ""
+ rootNode: ""
+
+ serverId: ""
+
+ gerrits:
+ - metadata:
+ name: gerrit
+ labels:
+ app: gerrit
+ spec:
+ serviceAccount: gerrit
+
+ tolerations:
+ - key: key1
+ operator: Equal
+ value: value1
+ effect: NoSchedule
+
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: disktype
+ operator: In
+ values:
+ - ssd
+
+ topologySpreadConstraints: []
+ - maxSkew: 1
+ topologyKey: zone
+ whenUnsatisfiable: DoNotSchedule
+ labelSelector:
+ matchLabels:
+ foo: bar
+
+ priorityClassName: ""
+
+ replicas: 1
+ updatePartition: 0
+
+ resources:
+ requests:
+ cpu: 1
+ memory: 5Gi
+ limits:
+ cpu: 1
+ memory: 6Gi
+
+ startupProbe:
+ initialDelaySeconds: 0
+ periodSeconds: 10
+ timeoutSeconds: 1
+ successThreshold: 1
+ failureThreshold: 3
+
+ readinessProbe:
+ initialDelaySeconds: 0
+ periodSeconds: 10
+ timeoutSeconds: 1
+ successThreshold: 1
+ failureThreshold: 3
+
+ livenessProbe:
+ initialDelaySeconds: 0
+ periodSeconds: 10
+ timeoutSeconds: 1
+ successThreshold: 1
+ failureThreshold: 3
+
+ gracefulStopTimeout: 30
+
+ service:
+ type: NodePort
+ httpPort: 80
+ sshPort: 29418
+
+ mode: REPLICA
+
+ debug:
+ enabled: false
+ suspend: false
+
+ site:
+ size: 1Gi
+
+ plugins:
+ # Installs a packaged plugin
+ - name: delete-project
+
+ # Downloads and installs a plugin
+ - name: javamelody
+ url: https://gerrit-ci.gerritforge.com/view/Plugins-stable-3.6/job/plugin-javamelody-bazel-master-stable-3.6/lastSuccessfulBuild/artifact/bazel-bin/plugins/javamelody/javamelody.jar
+ sha1: 40ffcd00263171e373a24eb6a311791b2924707c
+
+ # If the `installAsLibrary` option is set to `true` the plugin's jar-file will
+ # be symlinked to the lib directory and thus installed as a library as well.
+ - name: saml
+ url: https://gerrit-ci.gerritforge.com/view/Plugins-stable-3.6/job/plugin-saml-bazel-master-stable-3.6/lastSuccessfulBuild/artifact/bazel-bin/plugins/saml/saml.jar
+ sha1: 6dfe8292d46b179638586e6acf671206f4e0a88b
+ installAsLibrary: true
+
+ libs:
+ - name: global-refdb
+ url: https://example.com/global-refdb.jar
+ sha1: 3d533a536b0d4e0184f824478c24bc8dfe896d06
+
+ configFiles:
+ gerrit.config: |-
+ [gerrit]
+ serverId = gerrit-1
+ disableReverseDnsLookup = true
+ [index]
+ type = LUCENE
+ [auth]
+ type = DEVELOPMENT_BECOME_ANY_ACCOUNT
+ [httpd]
+ requestLog = true
+ gracefulStopTimeout = 1m
+ [transfer]
+ timeout = 120 s
+ [user]
+ name = Gerrit Code Review
+ email = gerrit@example.com
+ anonymousCoward = Unnamed User
+ [container]
+ javaOptions = -Xms200m
+ javaOptions = -Xmx4g
+
+ secretRef: gerrit-secure-config
+
+ receiver:
+ metadata:
+ name: receiver
+ labels:
+ app: receiver
+ spec:
+ tolerations:
+ - key: key1
+ operator: Equal
+ value: value2
+ effect: NoSchedule
+
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: disktype
+ operator: In
+ values:
+ - ssd
+
+ topologySpreadConstraints: []
+ - maxSkew: 1
+ topologyKey: zone
+ whenUnsatisfiable: DoNotSchedule
+ labelSelector:
+ matchLabels:
+ foo: bar
+
+ priorityClassName: ""
+
+ replicas: 2
+ maxSurge: 1
+ maxUnavailable: 1
+
+ resources:
+ requests:
+ cpu: 1
+ memory: 5Gi
+ limits:
+ cpu: 1
+ memory: 6Gi
+
+ readinessProbe:
+ initialDelaySeconds: 0
+ periodSeconds: 10
+ timeoutSeconds: 1
+ successThreshold: 1
+ failureThreshold: 3
+
+ livenessProbe:
+ initialDelaySeconds: 0
+ periodSeconds: 10
+ timeoutSeconds: 1
+ successThreshold: 1
+ failureThreshold: 3
+
+ service:
+ type: NodePort
+ httpPort: 80
+
+ credentialSecretRef: receiver-credentials
+```
+
+## Gerrit
+
+---
+
+**Group**: gerritoperator.google.com \
+**Version**: v1alpha17 \
+**Kind**: Gerrit
+
+---
+
+
+| Field | Type | Description |
+|---|---|---|
+| `apiVersion` | `String` | APIVersion of this resource |
+| `kind` | `String` | Kind of this resource |
+| `metadata` | [`ObjectMeta`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#objectmeta-v1-meta) | Metadata of the resource |
+| `spec` | [`GerritSpec`](#gerritspec) | Specification for Gerrit |
+| `status` | [`GerritStatus`](#gerritstatus) | Status for Gerrit |
+
+Example:
+
+```yaml
+apiVersion: "gerritoperator.google.com/v1alpha17"
+kind: Gerrit
+metadata:
+ name: gerrit
+spec:
+ serviceAccount: gerrit
+
+ tolerations:
+ - key: key1
+ operator: Equal
+ value: value1
+ effect: NoSchedule
+
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: disktype
+ operator: In
+ values:
+ - ssd
+
+ topologySpreadConstraints:
+ - maxSkew: 1
+ topologyKey: zone
+ whenUnsatisfiable: DoNotSchedule
+ labelSelector:
+ matchLabels:
+ foo: bar
+
+ priorityClassName: ""
+
+ replicas: 1
+ updatePartition: 0
+
+ resources:
+ requests:
+ cpu: 1
+ memory: 5Gi
+ limits:
+ cpu: 1
+ memory: 6Gi
+
+ startupProbe:
+ initialDelaySeconds: 0
+ periodSeconds: 10
+ timeoutSeconds: 1
+ successThreshold: 1
+ failureThreshold: 3
+
+ readinessProbe:
+ initialDelaySeconds: 0
+ periodSeconds: 10
+ timeoutSeconds: 1
+ successThreshold: 1
+ failureThreshold: 3
+
+ livenessProbe:
+ initialDelaySeconds: 0
+ periodSeconds: 10
+ timeoutSeconds: 1
+ successThreshold: 1
+ failureThreshold: 3
+
+ gracefulStopTimeout: 30
+
+ service:
+ type: NodePort
+ httpPort: 80
+ sshPort: 29418
+
+ mode: PRIMARY
+
+ debug:
+ enabled: false
+ suspend: false
+
+ site:
+ size: 1Gi
+
+ plugins:
+ # Installs a plugin packaged into the gerrit.war file
+ - name: delete-project
+
+ # Downloads and installs a plugin
+ - name: javamelody
+ url: https://gerrit-ci.gerritforge.com/view/Plugins-stable-3.6/job/plugin-javamelody-bazel-master-stable-3.6/lastSuccessfulBuild/artifact/bazel-bin/plugins/javamelody/javamelody.jar
+ sha1: 40ffcd00263171e373a24eb6a311791b2924707c
+
+ # If the `installAsLibrary` option is set to `true` the plugin jar-file will
+ # be symlinked to the lib directory and thus installed as a library as well.
+ - name: saml
+ url: https://gerrit-ci.gerritforge.com/view/Plugins-stable-3.6/job/plugin-saml-bazel-master-stable-3.6/lastSuccessfulBuild/artifact/bazel-bin/plugins/saml/saml.jar
+ sha1: 6dfe8292d46b179638586e6acf671206f4e0a88b
+ installAsLibrary: true
+
+ libs:
+ - name: global-refdb
+ url: https://example.com/global-refdb.jar
+ sha1: 3d533a536b0d4e0184f824478c24bc8dfe896d06
+
+ configFiles:
+ gerrit.config: |-
+ [gerrit]
+ serverId = gerrit-1
+ disableReverseDnsLookup = true
+ [index]
+ type = LUCENE
+ [auth]
+ type = DEVELOPMENT_BECOME_ANY_ACCOUNT
+ [httpd]
+ requestLog = true
+ gracefulStopTimeout = 1m
+ [transfer]
+ timeout = 120 s
+ [user]
+ name = Gerrit Code Review
+ email = gerrit@example.com
+ anonymousCoward = Unnamed User
+ [container]
+ javaOptions = -Xms200m
+ javaOptions = -Xmx4g
+
+ secretRef: gerrit-secure-config
+
+ serverId: ""
+
+ containerImages:
+ imagePullSecrets: []
+ imagePullPolicy: Always
+ gerritImages:
+ registry: docker.io
+ org: k8sgerrit
+ tag: latest
+ busyBox:
+ registry: docker.io
+ tag: latest
+
+ storage:
+ storageClasses:
+ readWriteOnce: default
+ readWriteMany: shared-storage
+ nfsWorkaround:
+ enabled: false
+ chownOnStartup: false
+ idmapdConfig: |-
+ [General]
+ Verbosity = 0
+ Domain = localdomain.com
+
+ [Mapping]
+ Nobody-User = nobody
+ Nobody-Group = nogroup
+
+ sharedStorage:
+ externalPVC:
+ enabled: false
+ claimName: ""
+ size: 1Gi
+ volumeName: ""
+ selector:
+ matchLabels:
+ volume-type: ssd
+ aws-availability-zone: us-east-1
+
+ pluginCache:
+ enabled: false
+
+ ingress:
+ host: example.com
+ tlsEnabled: false
+
+ refdb:
+ database: NONE
+ spanner:
+ projectName: ""
+ instance: ""
+ database: ""
+ zookeeper:
+ connectString: ""
+ rootNode: ""
+```
+
+## Receiver
+
+---
+
+**Group**: gerritoperator.google.com \
+**Version**: v1alpha6 \
+**Kind**: Receiver
+
+---
+
+
+| Field | Type | Description |
+|---|---|---|
+| `apiVersion` | `String` | APIVersion of this resource |
+| `kind` | `String` | Kind of this resource |
+| `metadata` | [`ObjectMeta`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#objectmeta-v1-meta) | Metadata of the resource |
+| `spec` | [`ReceiverSpec`](#receiverspec) | Specification for Receiver |
+| `status` | [`ReceiverStatus`](#receiverstatus) | Status for Receiver |
+
+Example:
+
+```yaml
+apiVersion: "gerritoperator.google.com/v1alpha6"
+kind: Receiver
+metadata:
+ name: receiver
+spec:
+ tolerations:
+ - key: key1
+ operator: Equal
+ value: value1
+ effect: NoSchedule
+
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: disktype
+ operator: In
+ values:
+ - ssd
+
+ topologySpreadConstraints:
+ - maxSkew: 1
+ topologyKey: zone
+ whenUnsatisfiable: DoNotSchedule
+ labelSelector:
+ matchLabels:
+ foo: bar
+
+ priorityClassName: ""
+
+ replicas: 1
+ maxSurge: 1
+ maxUnavailable: 1
+
+ resources:
+ requests:
+ cpu: 1
+ memory: 5Gi
+ limits:
+ cpu: 1
+ memory: 6Gi
+
+ readinessProbe:
+ initialDelaySeconds: 0
+ periodSeconds: 10
+ timeoutSeconds: 1
+ successThreshold: 1
+ failureThreshold: 3
+
+ livenessProbe:
+ initialDelaySeconds: 0
+ periodSeconds: 10
+ timeoutSeconds: 1
+ successThreshold: 1
+ failureThreshold: 3
+
+ service:
+ type: NodePort
+ httpPort: 80
+
+ credentialSecretRef: apache-credentials
+
+ containerImages:
+ imagePullSecrets: []
+ imagePullPolicy: Always
+ gerritImages:
+ registry: docker.io
+ org: k8sgerrit
+ tag: latest
+ busyBox:
+ registry: docker.io
+ tag: latest
+
+ storage:
+ storageClasses:
+ readWriteOnce: default
+ readWriteMany: shared-storage
+ nfsWorkaround:
+ enabled: false
+ chownOnStartup: false
+ idmapdConfig: |-
+ [General]
+ Verbosity = 0
+ Domain = localdomain.com
+
+ [Mapping]
+ Nobody-User = nobody
+ Nobody-Group = nogroup
+
+ sharedStorage:
+ externalPVC:
+ enabled: false
+ claimName: ""
+ size: 1Gi
+ volumeName: ""
+ selector:
+ matchLabels:
+ volume-type: ssd
+ aws-availability-zone: us-east-1
+
+ ingress:
+ host: example.com
+ tlsEnabled: false
+```
+
+## GitGarbageCollection
+
+---
+
+**Group**: gerritoperator.google.com \
+**Version**: v1alpha1 \
+**Kind**: GitGarbageCollection
+
+---
+
+
+| Field | Type | Description |
+|---|---|---|
+| `apiVersion` | `String` | APIVersion of this resource |
+| `kind` | `String` | Kind of this resource |
+| `metadata` | [`ObjectMeta`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#objectmeta-v1-meta) | Metadata of the resource |
+| `spec` | [`GitGarbageCollectionSpec`](#gitgarbagecollectionspec) | Specification for GitGarbageCollection |
+| `status` | [`GitGarbageCollectionStatus`](#gitgarbagecollectionstatus) | Status for GitGarbageCollection |
+
+Example:
+
+```yaml
+apiVersion: "gerritoperator.google.com/v1alpha1"
+kind: GitGarbageCollection
+metadata:
+ name: gitgc
+spec:
+ cluster: gerrit
+ schedule: "*/5 * * * *"
+
+ projects: []
+
+ resources:
+ requests:
+ cpu: 100m
+ memory: 256Mi
+ limits:
+ cpu: 100m
+ memory: 256Mi
+
+ tolerations:
+ - key: key1
+ operator: Equal
+ value: value1
+ effect: NoSchedule
+
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: disktype
+ operator: In
+ values:
+ - ssd
+```
+
+## GerritNetwork
+
+---
+
+**Group**: gerritoperator.google.com \
+**Version**: v1alpha2 \
+**Kind**: GerritNetwork
+
+---
+
+
+| Field | Type | Description |
+|---|---|---|
+| `apiVersion` | `String` | APIVersion of this resource |
+| `kind` | `String` | Kind of this resource |
+| `metadata` | [`ObjectMeta`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#objectmeta-v1-meta) | Metadata of the resource |
+| `spec` | [`GerritNetworkSpec`](#gerritnetworkspec) | Specification for GerritNetwork |
+
+Example:
+
+```yaml
+apiVersion: "gerritoperator.google.com/v1alpha2"
+kind: GerritNetwork
+metadata:
+ name: gerrit-network
+spec:
+ ingress:
+ enabled: true
+ host: example.com
+ annotations: {}
+ tls:
+ enabled: false
+ secret: ""
+ receiver:
+ name: receiver
+ httpPort: 80
+ primaryGerrit: {}
+ # name: gerrit-primary
+ # httpPort: 80
+ # httpPort: 29418
+ gerritReplica:
+ name: gerrit
+ httpPort: 80
+ httpPort: 29418
+```
+
+## GerritClusterSpec
+
+| Field | Type | Description |
+|---|---|---|
+| `storage` | [`GerritStorageConfig`](#gerritstorageconfig) | Storage used by Gerrit instances |
+| `containerImages` | [`ContainerImageConfig`](#containerimageconfig) | Container images used inside GerritCluster |
+| `ingress` | [`GerritClusterIngressConfig`](#gerritclusteringressconfig) | Ingress traffic handling in GerritCluster |
+| `refdb` | [`GlobalRefDbConfig`](#globalrefdbconfig) | The Global RefDB used by Gerrit |
+| `serverId` | `String` | The serverId to be used for all Gerrit instances (default: `<namespace>/<name>`) |
+| `gerrits` | [`GerritTemplate`](#gerrittemplate)-Array | A list of Gerrit instances to be installed in the GerritCluster. Only a single primary Gerrit and a single Gerrit Replica is permitted. |
+| `receiver` | [`ReceiverTemplate`](#receivertemplate) | A Receiver instance to be installed in the GerritCluster. |
+
+## GerritClusterStatus
+
+| Field | Type | Description |
+|---|---|---|
+| `members` | `Map<String, List<String>>` | A map listing all Gerrit and Receiver instances managed by the GerritCluster by name |
+
+## StorageConfig
+
+| Field | Type | Description |
+|---|---|---|
+| `storageClasses` | [`StorageClassConfig`](#storageclassconfig) | StorageClasses used in the GerritCluster |
+| `sharedStorage` | [`SharedStorage`](#sharedstorage) | Volume used for resources shared between Gerrit instances except git repositories |
+
+## GerritStorageConfig
+
+Extends [StorageConfig](#StorageConfig).
+
+| Field | Type | Description |
+|---|---|---|
+| `pluginCache` | [`PluginCacheConfig`](#plugincacheconfig) | Configuration of cache for downloaded plugins |
+
+## StorageClassConfig
+
+| Field | Type | Description |
+|---|---|---|
+| `readWriteOnce` | `String` | Name of a StorageClass allowing ReadWriteOnce access. (default: `default`) |
+| `readWriteMany` | `String` | Name of a StorageClass allowing ReadWriteMany access. (default: `shared-storage`) |
+| `nfsWorkaround` | [`NfsWorkaroundConfig`](#nfsworkaroundconfig) | NFS is not well supported by Kubernetes. These options provide a workaround to ensure correct file ownership and id mapping |
+
+## NfsWorkaroundConfig
+
+| Field | Type | Description |
+|---|---|---|
+| `enabled` | `boolean` | If enabled, below options might be used. (default: `false`) |
+| `chownOnStartup` | `boolean` | If enabled, the ownership of the mounted NFS volumes will be set on pod startup. Note that this is not done recursively. It is expected that all data already present in the volume was created by the user used in accessing containers. (default: `false`) |
+| `idmapdConfig` | `String` | The idmapd.config file can be used to e.g. configure the ID domain. This might be necessary for some NFS servers to ensure correct mapping of user and group IDs. (optional) |
+
+## SharedStorage
+
+| Field | Type | Description |
+|---|---|---|
+| `externalPVC` | [`ExternalPVCConfig`](#externalpvcconfig) | Configuration regarding the use of an external / manually created PVC |
+| `size` | [`Quantity`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#quantity-resource-core) | Size of the volume (mandatory) |
+| `volumeName` | `String` | Name of a specific persistent volume to claim (optional) |
+| `selector` | [`LabelSelector`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#labelselector-v1-meta) | Selector to select a specific persistent volume (optional) |
+
+## PluginCacheConfig
+
+| Field | Type | Description |
+|---|---|---|
+| `enabled` | `boolean` | If enabled, downloaded plugins will be cached. (default: `false`) |
+
+## ExternalPVCConfig
+
+| Field | Type | Description |
+|---|---|---|
+| `enabled` | `boolean` | If enabled, a provided PVC will be used instead of creating one. (default: `false`) |
+| `claimName` | `String` | Name of the PVC to be used. |
+
+## ContainerImageConfig
+
+| Field | Type | Description |
+|---|---|---|
+| `imagePullPolicy` | `String` | Image pull policy (https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) to be used in all containers. (default: `Always`) |
+| `imagePullSecrets` | [`LocalObjectReference`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#localobjectreference-v1-core)-Array | List of names representing imagePullSecrets available in the cluster. These secrets will be added to all pods. (optional) |
+| `busyBox` | [`BusyBoxImage`](#busyboximage) | The busybox container is used for some init containers |
+| `gerritImages` | [`GerritRepositoryConfig`](#gerritrepositoryconfig) | The container images in this project are tagged with the output of git describe. All container images are published for each version, even when the image itself was not updated. This ensures that all containers work well together. Here, the data on how to get those images can be configured. |
+
+## BusyBoxImage
+
+| Field | Type | Description |
+|---|---|---|
+| `registry` | `String` | The registry from which to pull the "busybox" image. (default: `docker.io`) |
+| `tag` | `String` | The tag/version of the "busybox" image. (default: `latest`) |
+
+## GerritRepositoryConfig
+
+| Field | Type | Description |
+|---|---|---|
+| `registry` | `String` | The registry from which to pull the images. (default: `docker.io`) |
+| `org` | `String` | The organization in the registry containing the images. (default: `k8sgerrit`) |
+| `tag` | `String` | The tag/version of the images. (default: `latest`) |
+
+## GerritClusterIngressConfig
+
+| Field | Type | Description |
+|---|---|---|
+| `enabled` | `boolean` | Whether to configure an ingress provider to manage the ingress traffic in the GerritCluster (default: `false`) |
+| `host` | `string` | Hostname to be used by the ingress. For each Gerrit deployment a new subdomain using the name of the respective Gerrit CustomResource will be used. |
+| `annotations` | `Map<String, String>` | Annotations to be set for the ingress. This allows to configure the ingress further by e.g. setting the ingress class. This will be only used for type INGRESS and ignored otherwise. (optional) |
+| `tls` | [`GerritIngressTlsConfig`](#gerritingresstlsconfig) | Configuration of TLS to be used in the ingress |
+| `ambassador` | [`GerritIngressAmbassadorConfig`](#gerritingressambassadorconfig) | Ambassador configuration. Only relevant when the INGRESS environment variable is set to "ambassador" in the operator |
+
+## GerritIngressTlsConfig
+
+| Field | Type | Description |
+|---|---|---|
+| `enabled` | `boolean` | Whether to use TLS (default: `false`) |
+| `secret` | `String` | Name of the secret containing the TLS key pair. The certificate should be a wildcard certificate allowing for all subdomains under the given host. |
+
+## GerritIngressAmbassadorConfig
+
+| Field | Type | Description |
+|---|---|---|
+| `id` | `List<String>` | The operator uses the ids specified in `ambassadorId` to set the [ambassador_id](https://www.getambassador.io/docs/edge-stack/1.14/topics/running/running#ambassador_id) spec field in the Ambassador CustomResources it creates (`Mapping`, `TLSContext`). (optional) |
+| `createHost`| `boolean` | Specify whether you want the operator to create a `Host` resource. This will be required if you don't have a wildcard host set up in your cluster. Default is `false`. (optional) |
+
+## GlobalRefDbConfig
+
+Note, that the operator will not deploy or operate the database used for the
+global refdb. It will only configure Gerrit to use it.
+
+| Field | Type | Description |
+|---|---|---|
+| `database` | [`RefDatabase`](#refdatabase) | Which database to use for the global refdb. Choices: `NONE`, `SPANNER`, `ZOOKEEPER`. (default: `NONE`) |
+| `spanner` | [`SpannerRefDbConfig`](#spannerrefdbconfig) | Configuration of spanner. Only used if spanner was configured to be used for the global refdb. |
+| `zookeeper` | [`ZookeeperRefDbConfig`](#zookeeperrefdbconfig) | Configuration of zookeeper. Only used, if zookeeper was configured to be used for the global refdb. |
+
+## RefDatabase
+
+| Value | Description|
+|---|---|
+| `NONE` | No global refdb will be used. Not allowed, if a primary Gerrit with 2 or more instances will be installed. |
+| `SPANNER` | Spanner will be used as a global refdb |
+| `ZOOKEEPER` | Zookeeper will be used as a global refdb |
+
+## SpannerRefDbConfig
+
+Note that the spanner ref-db plugin requires google credentials to be mounted to /var/gerrit/etc/gcp-credentials.json. Instructions for generating those credentials can be found [here](https://developers.google.com/workspace/guides/create-credentials) and may be provided in the optional secretRef in [`GerritTemplateSpec`](#gerrittemplatespec).
+
+| Field | Type | Description |
+|---|---|---|
+| `projectName` | `String` | Spanner project name to be used |
+| `instance` | `String` | Spanner instance name to be used |
+| `database` | `String` | Spanner database name to be used |
+
+## ZookeeperRefDbConfig
+
+| Field | Type | Description |
+|---|---|---|
+| `connectString` | `String` | Hostname and port of the zookeeper instance to be used, e.g. `zookeeper.example.com:2181` |
+| `rootNode` | `String` | Root node that will be used to store the global refdb data. Will be set automatically, if `GerritCluster` is being used. |
+
+## GerritTemplate
+
+| Field | Type | Description |
+|---|---|---|
+| `metadata` | [`ObjectMeta`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#objectmeta-v1-meta) | Metadata of the resource. A name is mandatory. Labels can optionally be defined. Other fields like the namespace are ignored. |
+| `spec` | [`GerritTemplateSpec`](#gerrittemplatespec) | Specification for GerritTemplate |
+
+## GerritTemplateSpec
+
+| Field | Type | Description |
+|---|---|---|
+| `serviceAccount` | `String` | ServiceAccount to be used by Gerrit. Required for service discovery when using the high-availability plugin |
+| `tolerations` | [`Toleration`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core)-Array | Pod tolerations (optional) |
+| `affinity` | [`Affinity`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core) | Pod affinity (optional) |
+| `topologySpreadConstraints` | [`TopologySpreadConstraint`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#topologyspreadconstraint-v1-core)-Array | Pod topology spread constraints (optional) |
+| `priorityClassName` | `String` | [PriorityClass](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/) to be used with the pod (optional) |
+| `replicas` | `int` | Number of pods running Gerrit in the StatefulSet (default: 1) |
+| `updatePartition` | `int` | Ordinal at which to start updating pods. Pods with a lower ordinal will not be updated. (default: 0) |
+| `resources` | [`ResourceRequirements`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#resourcerequirements-v1-core) | Resource requirements for the Gerrit container |
+| `startupProbe` | [`GerritProbe`](#gerritprobe) | [Startup probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes). The action will be set by the operator. All other probe parameters can be set. |
+| `readinessProbe` | [`GerritProbe`](#gerritprobe) | [Readiness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes). The action will be set by the operator. All other probe parameters can be set. |
+| `livenessProbe` | [`GerritProbe`](#gerritprobe) | [Liveness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes). The action will be set by the operator. All other probe parameters can be set. |
+| `gracefulStopTimeout` | `long` | Seconds the pod is allowed to shutdown until it is forcefully killed (default: 30) |
+| `service` | [`GerritServiceConfig`](#gerritserviceconfig) | Configuration for the service used to manage network access to the StatefulSet |
+| `site` | [`GerritSite`](#gerritsite) | Configuration concerning the Gerrit site directory |
+| `plugins` | [`GerritPlugin`](#gerritplugin)-Array | List of Gerrit plugins to install. These plugins can either be packaged in the Gerrit war-file or they will be downloaded. (optional) |
+| `libs` | [`GerritModule`](#gerritmodule)-Array | List of Gerrit library modules to install. These lib modules will be downloaded. (optional) |
+| `configFiles` | `Map<String, String>` | Configuration files for Gerrit that will be mounted into the Gerrit site's etc-directory (gerrit.config is mandatory) |
+| `secretRef` | `String` | Name of secret containing configuration files, e.g. secure.config, that will be mounted into the Gerrit site's etc-directory (optional) |
+| `mode` | [`GerritMode`](#gerritmode) | In which mode Gerrit should be run. (default: PRIMARY) |
+| `debug` | [`GerritDebugConfig`](#gerritdebugconfig) | Enable the debug-mode for Gerrit |
+
+## GerritProbe
+
+**Extends:** [`Probe`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#probe-v1-core)
+
+The fields `exec`, `grpc`, `httpGet` and `tcpSocket` cannot be set manually anymore
+compared to the parent object. All other options can still be configured.
+
+## GerritServiceConfig
+
+| Field | Type | Description |
+|---|---|---|
+| `type` | `String` | Service type (default: `NodePort`) |
+| `httpPort` | `int` | Port used for HTTP requests (default: `80`) |
+| `sshPort` | `Integer` | Port used for SSH requests (optional; if unset, SSH access is disabled). If Istio is used, the Gateway will be automatically configured to accept SSH requests. If an Ingress controller is used, SSH requests will only be served by the Service itself! |
+
+## GerritSite
+
+| Field | Type | Description |
+|---|---|---|
+| `size` | [`Quantity`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#quantity-resource-core) | Size of the volume used to persist not otherwise persisted site components (e.g. git repositories are persisted in a dedicated volume) (mandatory) |
+
+## GerritModule
+
+| Field | Type | Description |
+|---|---|---|
+| `name` | `String` | Name of the module/plugin |
+| `url` | `String` | URL of the module/plugin, if it should be downloaded. If the URL is not set, the plugin is expected to be packaged in the war-file (not possible for lib-modules). (optional) |
+| `sha1` | `String` | SHA1-checksum of the module/plugin JAR-file. (mandatory, if `url` is set) |
+
+## GerritPlugin
+
+**Extends:** [`GerritModule`](#gerritmodule)
+
+| Field | Type | Description |
+|---|---|---|
+| `installAsLibrary` | `boolean` | Some plugins also need to be installed as a library. If set to `true` the plugin JAR will be symlinked to the `lib`-directory in the Gerrit site. (default: `false`) |
+
+## GerritMode
+
+| Value | Description|
+|---|---|
+| `PRIMARY` | A primary Gerrit |
+| `REPLICA` | A Gerrit Replica, which only serves git fetch/clone requests |
+
+## GerritDebugConfig
+
+These options allow to debug Gerrit. It will enable debugging in all pods and
+expose the port 8000 in the container. Port-forwarding is required to connect the
+debugger.
+Note, that all pods will be restarted to enable the debugger. Also, if `suspend`
+is enabled, ensure that the lifecycle probes are configured accordingly to prevent
+pod restarts before Gerrit is ready.
+
+| Field | Type | Description |
+|---|---|---|
+| `enabled` | `boolean` | Whether to enable debugging. (default: `false`) |
+| `suspend` | `boolean` | Whether to suspend Gerrit on startup. (default: `false`) |
+
+## GerritSpec
+
+**Extends:** [`GerritTemplateSpec`](#gerrittemplatespec)
+
+| Field | Type | Description |
+|---|---|---|
+| `storage` | [`GerritStorageConfig`](#gerritstorageconfig) | Storage used by Gerrit instances |
+| `containerImages` | [`ContainerImageConfig`](#containerimageconfig) | Container images used inside GerritCluster |
+| `ingress` | [`IngressConfig`](#ingressconfig) | Ingress configuration for Gerrit |
+| `refdb` | [`GlobalRefDbConfig`](#globalrefdbconfig) | The Global RefDB used by Gerrit |
+| `serverId` | `String` | The serverId to be used for all Gerrit instances |
+
+## GerritStatus
+
+| Field | Type | Description |
+|---|---|---|
+| `ready` | `boolean` | Whether the Gerrit instance is ready |
+| `appliedConfigMapVersions` | `Map<String, String>` | Versions of each ConfigMap currently mounted into Gerrit pods |
+| `appliedSecretVersions` | `Map<String, String>` | Versions of each secret currently mounted into Gerrit pods |
+
+## IngressConfig
+
+| Field | Type | Description |
+|---|---|---|
+| `host` | `string` | Hostname that is being used by the ingress provider for this Gerrit instance. |
+| `tlsEnabled` | `boolean` | Whether the ingress provider enables TLS. (default: `false`) |
+
+## ReceiverTemplate
+
+| Field | Type | Description |
+|---|---|---|
+| `metadata` | [`ObjectMeta`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#objectmeta-v1-meta) | Metadata of the resource. A name is mandatory. Labels can optionally be defined. Other fields like the namespace are ignored. |
+| `spec` | [`ReceiverTemplateSpec`](#receivertemplatespec) | Specification for ReceiverTemplate |
+
+## ReceiverTemplateSpec
+
+| Field | Type | Description |
+|---|---|---|
+| `tolerations` | [`Toleration`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core)-Array | Pod tolerations (optional) |
+| `affinity` | [`Affinity`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core) | Pod affinity (optional) |
+| `topologySpreadConstraints` | [`TopologySpreadConstraint`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#topologyspreadconstraint-v1-core)-Array | Pod topology spread constraints (optional) |
+| `priorityClassName` | `String` | [PriorityClass](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/) to be used with the pod (optional) |
+| `replicas` | `int` | Number of pods running the receiver in the Deployment (default: 1) |
+| `maxSurge` | `IntOrString` | Ordinal or percentage of pods that are allowed to be created in addition during rolling updates. (default: `1`) |
+| `maxUnavailable` | `IntOrString` | Ordinal or percentage of pods that are allowed to be unavailable during rolling updates. (default: `1`) |
+| `resources` | [`ResourceRequirements`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#resourcerequirements-v1-core) | Resource requirements for the Receiver container |
+| `readinessProbe` | [`ReceiverProbe`](#receiverprobe) | [Readiness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes). The action will be set by the operator. All other probe parameters can be set. |
+| `livenessProbe` | [`ReceiverProbe`](#receiverprobe) | [Liveness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes). The action will be set by the operator. All other probe parameters can be set. |
+| `service` | [`ReceiverServiceConfig`](#receiverserviceconfig) | Configuration for the service used to manage network access to the Deployment |
+| `credentialSecretRef` | `String` | Name of the secret containing the .htpasswd file used to configure basic authentication within the Apache server (mandatory) |
+
+## ReceiverSpec
+
+**Extends:** [`ReceiverTemplateSpec`](#receivertemplatespec)
+
+| Field | Type | Description |
+|---|---|---|
+| `storage` | [`StorageConfig`](#storageconfig) | Storage used by Gerrit/Receiver instances |
+| `containerImages` | [`ContainerImageConfig`](#containerimageconfig) | Container images used inside GerritCluster |
+| `ingress` | [`IngressConfig`](#ingressconfig) | Ingress configuration for Gerrit |
+
+## ReceiverStatus
+
+| Field | Type | Description |
+|---|---|---|
+| `ready` | `boolean` | Whether the Receiver instance is ready |
+| `appliedCredentialSecretVersion` | `String` | Version of credential secret currently mounted into Receiver pods |
+
+## ReceiverProbe
+
+**Extends:** [`Probe`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#probe-v1-core)
+
+The fields `exec`, `grpc`, `httpGet` and `tcpSocket` cannot be set manually anymore
+compared to the parent object. All other options can still be configured.
+
+## ReceiverServiceConfig
+
+| Field | Type | Description |
+|---|---|---|
+| `type` | `String` | Service type (default: `NodePort`) |
+| `httpPort` | `int` | Port used for HTTP requests (default: `80`) |
+
+## GitGarbageCollectionSpec
+
+| Field | Type | Description |
+|---|---|---|
+| `cluster` | `string` | Name of the Gerrit cluster this Gerrit is a part of. (mandatory) |
+| `tolerations` | [`Toleration`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core)-Array | Pod tolerations (optional) |
+| `affinity` | [`Affinity`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core) | Pod affinity (optional) |
+| `schedule` | `string` | Cron schedule defining when to run git gc (mandatory) |
+| `projects` | `Set<String>` | List of projects to gc. If omitted, all projects not handled by other Git GC jobs will be gc'ed. Only one job gc'ing all projects can exist. (default: `[]`) |
+| `resources` | [`ResourceRequirements`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#resourcerequirements-v1-core) | Resource requirements for the GitGarbageCollection container |
+
+## GitGarbageCollectionStatus
+
+| Field | Type | Description |
+|---|---|---|
+| `replicateAll` | `boolean` | Whether this GitGarbageCollection handles all projects |
+| `excludedProjects` | `Set<String>` | List of projects that were excluded from this GitGarbageCollection, since they are handled by other Jobs |
+| `state` | [`GitGcState`](#gitgcstate) | State of the GitGarbageCollection |
+
+## GitGcState
+
+| Value | Description|
+|---|---|
+| `ACTIVE` | GitGarbageCollection is scheduled |
+| `INACTIVE` | GitGarbageCollection is not scheduled |
+| `CONFLICT` | GitGarbageCollection conflicts with another GitGarbageCollection |
+| `ERROR` | Controller failed to schedule GitGarbageCollection |
+
+## GerritNetworkSpec
+
+| Field | Type | Description |
+|---|---|---|
+| `ingress` | [`GerritClusterIngressConfig`](#gerritclusteringressconfig) | Ingress traffic handling in GerritCluster |
+| `receiver` | [`NetworkMember`](#networkmember) | Receiver in the network. |
+| `primaryGerrit` | [`NetworkMemberWithSsh`](#networkmemberwithssh) | Primary Gerrit in the network. |
+| `gerritReplica` | [`NetworkMemberWithSsh`](#networkmemberwithssh) | Gerrit Replica in the network. |
+
+## NetworkMember
+
+| Field | Type | Description |
+|------------|----------|----------------------------|
+| `name` | `String` | Name of the network member |
+| `httpPort` | `int` | Port used for HTTP(S) |
+
+## NetworkMemberWithSsh
+
+**Extends:** [`NetworkMember`](#networkmember)
+
+| Field | Type | Description |
+|-----------|-------|-------------------|
+| `sshPort` | `int` | Port used for SSH |
diff --git a/charts/k8s-gerrit/Documentation/operator.md b/charts/k8s-gerrit/Documentation/operator.md
new file mode 100644
index 0000000..919e217
--- /dev/null
+++ b/charts/k8s-gerrit/Documentation/operator.md
@@ -0,0 +1,440 @@
+# Gerrit Operator
+
+1. [Gerrit Operator](#gerrit-operator)
+ 1. [Build](#build)
+ 2. [Versioning](#versioning)
+ 3. [Publish](#publish)
+ 4. [Tests](#tests)
+ 5. [Prerequisites](#prerequisites)
+ 1. [Shared Storage (ReadWriteMany)](#shared-storage-readwritemany)
+ 2. [Ingress provider](#ingress-provider)
+ 6. [Deploy](#deploy)
+ 1. [Using helm charts](#using-helm-charts)
+ 1. [gerrit-operator-crds](#gerrit-operator-crds)
+ 2. [gerrit-operator](#gerrit-operator-1)
+ 2. [Without the helm charts](#without-the-helm-charts)
+ 7. [CustomResources](#customresources)
+ 1. [GerritCluster](#gerritcluster)
+ 2. [Gerrit](#gerrit)
+ 3. [GitGarbageCollection](#gitgarbagecollection)
+ 4. [Receiver](#receiver)
+ 5. [GerritNetwork](#gerritnetwork)
+ 8. [Configuration of Gerrit](#configuration-of-gerrit)
+
+## Build
+
+For this step, you need Java 11 and Maven installed.
+
+To build all components of the operator run:
+
+```sh
+cd operator
+mvn clean install
+```
+
+This step compiles the Java source code into `.class` bytecode files in a newly
+generated `operator/target` folder. A `gerrit-operator` image is also created
+locally. Moreover, the CRD helm chart is updated with the latest CRDs as part of
+this build step.
+
+The jar-version and container image tag can be set using the `revision` property:
+
+```sh
+mvn clean install -Drevision=$(git describe --always --dirty)
+```
+
+## Versioning
+
+The Gerrit Operator is still in an early state of development. The operator is
+thus at the moment not semantically versioned. The CustomResources are as of now
+independently versioned, i.e. the `GerritCluster` resource can have a different
+version than the `GitGarbageCollection` resource, although they are in the same
+group. At the moment, only the current version will be supported by the operator,
+i.e. there won't be a migration path. As soon as the API reaches some stability,
+this will change.
+
+## Publish
+
+Currently, there does not exist a container image for the operator in the
+`docker.io/k8sgerrit` registry. You must build your own image in order to run
+the operator in your cluster. To publish the container image of the Gerrit
+Operator:
+
+1. Update the `docker.registry` and `docker.org` tags in the `operator/pom.xml`
+file to point to your own Docker registry and org that you have permissions to
+push to.
+
+```xml
+<docker.registry>my-registry</docker.registry>
+<docker.org>my-org</docker.org>
+```
+
+2. run the following commands:
+
+```sh
+cd operator
+mvn clean install -P publish
+```
+
+This will build the operator source code, create an image out of the
+built artifacts, and publish this image to the registry specified in the
+`pom.xml` file. The built image is multi-platform - it will run on both `amd64`
+and `arm64` architectures. It is okay to run this build command from an ARM
+Mac.
+
+## Tests
+
+Executing the E2E tests has a few infrastructure requirements that have to be
+provided:
+
+- An (unused) Kubernetes cluster
+- The 'default' StorageClass that supports ReadWriteOnce access. It has to be
+ possible to provision volumes using this StorageClass.
+- A StorageClass that supports ReadWriteMany access. It has to be possible to
+ provision volumes using this StorageClass. Such a StorageClass could be provided
+ by the [NFS-subdir-provisioner chart](https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner).
+- An [Nginx Ingress Controller](https://github.com/kubernetes/ingress-nginx)
+- An installation of [OpenLDAP](../supplements/test-cluster/ldap/openldap.yaml)
+ with at least one user.
+- Istio installed with the [profile](../istio/gerrit.profile.yaml) provided by
+ this project
+- A secret containing valid certificates for the given hostnames. For istio this
+ secret has to be named `tls-secret` and be present in the `istio-system` namespace.
+ For the Ingress controller, the secret has to be either set as the default
+ secret to be used or somehow automatically be provided in the namespaces created
+ by the tests and named `tls-secret`, e.g. by using Gardener to manage DNS and
+ certificates.
+
+A sample setup for components required in the cluster is provided under
+`$REPO_ROOT/supplements/test-cluster`. Some configuration has to be done manually
+(marked by `#TODO`) and the `deploy.sh`-script can be used to install/update all
+components.
+
+In addition, some properties have to be set to configure the tests:
+
+- `rwmStorageClass`: Name of the StorageClass providing RWM-access (default:nfs-client)
+- `registry`: Registry to pull container images from
+- `RegistryOrg`: Organization of the container images
+- `tag`: Container tag
+- `registryUser`: User for the container registry
+- `registryPwd`: Password for the container registry
+- `ingressDomain`: Domain to be used for the ingress
+- `istioDomain`: Domain to be used for istio
+- `ldapAdminPwd`: Admin password for LDAP server
+- `gerritUser`: Username of a user in LDAP
+- `gerritPwd`: The password of `gerritUser`
+
+The properties should be set in the `test.properties` file. Alternatively, a
+path of a properties file can be configured by using the
+`-Dproperties=<path to properties file>`-option.
+
+To run all E2E tests, use:
+
+```sh
+cd operator
+mvn clean install -P integration-test -Dproperties=<path to properties file>
+```
+
+Note, that running the E2E tests will also involve pushing the container image
+to the repository configured in the properties file.
+
+## Prerequisites
+
+Deploying Gerrit using the operator requires some additional prerequisites to be
+fulfilled:
+
+### Shared Storage (ReadWriteMany)
+
+Gerrit instances share the repositories and other data using shared volumes. Thus,
+a StorageClass and a suitable provisioner have to be available in the cluster.
+An example for such a provisioner would be the
+[NFS-subdir-external-provisioner](https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner).
+
+### Ingress provider
+
+The Gerrit Operator will also set up network routing rules and an ingress point
+for the Gerrit instances it manages. The network routing rules ensure that requests
+will be routed to the intended GerritCluster component, e.g. in case a primary
+Gerrit and a Gerrit Replica exist in the cluster, git fetch/clone requests will
+be sent to the Gerrit Replica and all other requests to the primary Gerrit.
+
+You may specify the ingress provider by setting the `INGRESS` environment
+variable in the operator Deployment manifest. That is, the choice of an ingress
+provider is an operator-level setting. However, you may specify some ingress
+configuration options (host, tls, etc) at the `GerritCluster` level, via
+[GerritClusterIngressConfig](operator-api-reference.md#gerritclusteringressconfig).
+
+The Gerrit Operator currently supports the following Ingress providers:
+
+- **NONE**
+
+ The operator will install no Ingress components. Services will still be available.
+ No prerequisites are required for this case.
+
+ If `spec.ingress.enabled` is set to `true` in GerritCluster, the operator will
+ still configure network related options like `http.listenUrl` in Gerrit based on
+ the other options in `spec.ingress`.
+
+- **INGRESS**
+
+ The operator will install an Ingress. Currently only the
+ [Nginx-Ingress-Controller](https://docs.nginx.com/nginx-ingress-controller/) is
+ supported, which will have to be installed in the cluster and has to be configured
+ to [allow snippet configurations](https://docs.nginx.com/nginx-ingress-controller/configuration/ingress-resources/advanced-configuration-with-snippets/).
+ An example of a working deployment can be found [here](../supplements/test-cluster/ingress/).
+
+ SSH support is not fully managed by the operator, since it has to be enabled and
+ [configured in the nginx ingress controller itself](https://kubernetes.github.io/ingress-nginx/user-guide/exposing-tcp-udp-services/).
+
+- **ISTIO**
+
+ The operator supports the use of [Istio](https://istio.io/) as a service mesh.
+ An example on how to set up Istio can be found [here](../istio/gerrit.profile.yaml).
+
+- **AMBASSADOR**
+
+ The operator also supports [Ambassador](https://www.getambassador.io/) for
+ setting up ingress to the Gerrits deployed by the operator. If you use
+ Ambassador's "Edge Stack" or "Emissary Ingress" to provide ingress to your k8s
+ services, you should set INGRESS=AMBASSADOR. Currently, SSH is not directly
+ supported when using INGRESS=AMBASSADOR.
+
+
+## Deploy
+You will need to have admin privileges for your k8s cluster in order to be able
+to deploy the following resources.
+
+You may choose to deploy the operator resources using helm, or directly via
+`kubectl apply`.
+
+### Using helm charts
+Make sure you have [helm](https://helm.sh/) installed in your environment.
+
+There are two relevant helm charts.
+
+#### gerrit-operator-crds
+
+This chart installs the CRDs (k8s API extensions) to your k8s cluster. No chart
+values need to be modified. The build initiated by the `mvn install` command
+from the [Publish](#publish) section includes a step that updates the CRDs in
+this helm chart to reflect any changes made to them in the operator source code.
+The CRDs installed are: GerritCluster, Gerrit, GitGarbageCollection, Receiver.
+
+You do not need to manually `helm install` this chart; this chart is installed
+as a dependency of the second `gerrit-operator` helm chart as described in the
+next subheading.
+
+#### gerrit-operator
+
+This chart installs the `gerrit-operator-crds` chart as a dependency, and the
+following k8s resources:
+- Deployment
+- ServiceAccount
+- ClusterRole
+- ClusterRoleBinding
+
+The operator itself creates a Service resource and a
+ValidationWebhookConfigurations resource behind the scenes.
+
+You will need to modify the values in `helm-charts/gerrit-operator/values.yaml`
+to point the chart to the registry/org that is hosting the Docker container
+image for the operator (from the [Publish](#publish) step earlier). Now,
+
+run:
+```sh
+# Create a namespace for the gerrit-operator
+kubectl create ns gerrit-operator
+
+# Build the gerrit-operator-crds chart and store it in the charts/ subdirectory
+helm dependency build helm-charts/gerrit-operator/
+
+# Install the gerrit-operator-crds chart and the gerrit-operator chart
+helm -n gerrit-operator install gerrit-operator helm-charts/gerrit-operator/
+```
+
+The chart itself, and all the bundled namespaced resources, are installed in the
+`gerrit-operator` namespace, as per the `-n` option in the helm command.
+
+### Without the helm charts
+
+First all CustomResourceDefinitions have to be deployed:
+
+```sh
+kubectl apply -f operator/target/classes/META-INF/fabric8/*-v1.yml
+```
+
+Note that these do not include the -v1beta1.yaml files, as those are for old
+Kubernetes versions.
+
+The operator requires a Java Keystore with a keypair inside to allow TLS
+verification for Kubernetes Admission Webhooks. To create a keystore and
+encode it with base64, run:
+
+```sh
+keytool \
+ -genkeypair \
+ -alias operator \
+ -keystore keystore \
+ -keyalg RSA \
+ -keysize 2048 \
+ -validity 3650
+cat keystore | base64 -b 0
+```
+
+Add the result to the Secret in `k8s/operator.yaml` (see comments in the file)
+and also add the base64-encoded password for the keystore to the secret.
+
+Then the operator and associated RBAC rules can be deployed:
+
+```sh
+kubectl apply -f operator/k8s/rbac.yaml
+kubectl apply -f operator/k8s/operator.yaml
+```
+
+`k8s/operator.yaml` contains a basic deployment of the operator. Resources,
+docker image name etc. might have to be adapted. For example, the ingress
+provider has to be configured by setting the `INGRESS` environment variable
+in `operator/k8s/operator.yaml` to either `NONE`, `INGRESS`, `ISTIO`, or
+`AMBASSADOR`.
+
+## CustomResources
+
+The operator manages several CustomResources that are described in more detail
+below.
+
+The API reference for all CustomResources can be found [here](operator-api-reference.md).
+
+### GerritCluster
+
+The GerritCluster CustomResource installs one or multiple Gerrit instances. The
+operator takes over managing the state of all Gerrit instances within the cluster
+and ensures that the state stays in sync. To this end it manages additional
+resources that are shared between Gerrit instances or are required to synchronize
+the state between Gerrit instances. These additional resources include:
+
+- storage
+- network / service mesh
+
+Installing Gerrit with the GerritCluster resource is highly recommended over using
+the [Gerrit](#gerrit) CustomResource directly, even if only a single deployment is
+installed, since this reduces the requirements that have to be managed manually.
+The same holds true for the [Receiver](#receiver) CustomResource, which without
+a Gerrit instance using the same site provides little value.
+
+For now, only a single Gerrit CustomResource using each [mode](./operator-api-reference.md#gerritmode)
+can be deployed in a GerritCluster, e.g. one primary Gerrit and one Gerrit Replica.
+The reason for that is, that there is currently no sharding implemented and thus
+multiple deployments don't bring any more value than just scaling the existing
+deployment. Instead of a primary Gerrit also a Receiver can be installed.
+
+### Gerrit
+
+The Gerrit CustomResource deploys a Gerrit, which can run in multiple modes.
+
+The Gerrit-CustomResource is mainly meant to be used by the GerritCluster-reconciler
+to install Gerrit-instances managed by a GerritCluster. Gerrit-CustomResources
+can however also be applied separately. Note, that the Gerrit operator will then
+not create any storage resources or setup any network resources in addition to
+the service.
+
+### GitGarbageCollection
+
+The GitGarbageCollection-CustomResource is used by the operator to set up CronJobs
+that regularly run Git garbage collection on the git repositories that are served
+by a GerritCluster.
+
+A GitGarbageCollection can either handle all repositories, if no specific repository
+is configured or a selected set of repositories. Multiple GitGarbageCollections
+can exist as part of the same GerritCluster, but no two GitGarbageCollections
+can work on the same project. This is prevented in three ways:
+
+- ValidationWebhooks will prohibit the creation of a second GitGarbageCollection
+ that does not specify projects, i.e. that would work on all projects.
+- Projects for which a GitGarbageCollections that specifically selects it exists
+ will be excluded from the GitGarbageCollection that works on all projects, if
+ it exists.
+- ValidationWebhooks will prohibit the creation of a GitGarbageCollection that
+ specifies a project that was already specified by another GitGarbageCollection.
+
+### Receiver
+
+**NOTE:** A Receiver should never be installed for a GerritCluster that is already
+managing a primary Gerrit to avoid conflicts when writing into repositories.
+
+The Receiver-CustomResource installs a Deployment running Apache with a git-http-
+backend that is meant to receive pushes performed by Gerrit's replication plugin.
+It can only be installed into a GerritCluster that does not include a primary
+Gerrit, but only Gerrit Replicas.
+
+The Receiver-CustomResource is mainly meant to be used by the GerritCluster-reconciler
+to install a Receiver-instance managed by a GerritCluster. Receiver-CustomResources
+can however also be applied separately. Note, that the Gerrit operator will then
+not create any storage resources or setup any network resources in addition to
+the service.
+
+### GerritNetwork
+
+The GerritNetwork CustomResource deploys network components depending on the
+configured ingress provider to enable ingress traffic to GerritCluster components.
+
+The GerritNetwork CustomResource is not meant to be installed manually, but will
+be created by the Gerrit Operator based on the GerritCluster CustomResource.
+
+## Configuration of Gerrit
+
+The operator takes care of all configuration in Gerrit that depends on the
+infrastructure, i.e. Kubernetes and the GerritCluster. This avoids duplicated
+configuration and misconfiguration.
+
+This means that some options in the gerrit.config are not allowed to be changed.
+If these values are set and are not matching the expected value, a ValidationWebhook
+will reject the resource creation/update. Thus, it is best to not set these values
+at all. To see which values the operator assigned check the ConfigMap created by
+the operator for the respective Gerrit.
+
+These options are:
+
+- `cache.directory`
+
+ This should stay in the volume mounted to contain the Gerrit site and will
+ thus be set to `cache`.
+
+- `container.javaHome`
+
+ This has to be set to `/usr/lib/jvm/java-11-openjdk-amd64`, since this is
+ the path of the Java installation in the container.
+
+- `container.javaOptions = -Djavax.net.ssl.trustStore`
+
+ The keystore will be mounted to `/var/gerrit/etc/keystore`.
+
+- `container.replica`
+
+ This has to be set in the Gerrit-CustomResource under `spec.isReplica`.
+
+- `container.user`
+
+ The technical user in the Gerrit container is called `gerrit`.
+
+- `gerrit.basePath`
+
+ The git repositories are mounted to `/var/gerrit/git` in the container.
+
+- `gerrit.canonicalWebUrl`
+
+ The canonical web URL has to be set to the hostname used by the Ingress/Istio.
+
+- `httpd.listenURL`
+
+ This has to be set to `proxy-http://*:8080/` or `proxy-https://*:8080`,
+ depending of TLS is enabled in the Ingress or not, otherwise the Jetty
+ servlet will run into an endless redirect loop.
+
+- `sshd.advertisedAddress`
+
+ This is only enforced, if Istio is enabled. It can be configured otherwise.
+
+- `sshd.listenAddress`
+
+ Since the container port for SSH is fixed, this will be set automatically.
+ If no SSH port is configured in the service, the SSHD is disabled.
diff --git a/charts/k8s-gerrit/Documentation/roadmap.md b/charts/k8s-gerrit/Documentation/roadmap.md
new file mode 100644
index 0000000..9af175a
--- /dev/null
+++ b/charts/k8s-gerrit/Documentation/roadmap.md
@@ -0,0 +1,207 @@
+# Roadmap
+
+## General
+
+### Planned features
+
+- **Automated verification process**: Run tests automatically to verify changes. \
+ \
+ Most tests in the project require a Kubernetes cluster and some additional
+ prerequisites, e.g. istio. Currently, the Gerrit OpenSOurce community does not
+ have these resources. At SAP, we plan to run verification in our internal systems,
+ which won't be publicly viewable, but could already vote. Builds would only
+ be triggered, if a maintainer votes `+1` on the `Build-Approved`-label. \
+ \
+ Builds can be moved to a public CI at a later point in time.
+
+- **Automated publishing of container images**: Publishing container images will
+ happen automatically on ref-updated using a CI.
+
+- **Support for multiple Gerrit versions**: All currently supported Gerrit versions
+ will also be supported in k8s-gerrit. \
+ \
+ Currently, container images used by this project are only published for a single
+ Gerrit version, which is updated on an irregular schedule. Introducing stable
+ branches for each gerrit version will allow to maintain container images for
+ multiple Gerrit versions. Gerrit binaries will be updated with each official
+ release and more frequently on `master`. This will be (at least partially)
+ automated.
+
+- **Integration test suite**: A test suite that can be used to test a GerritCluster. \
+ \
+ A GerritCluster running in a Kubernetes cluster consists of multiple components.
+ Having a suite of automated tests would greatly help to verify deployments in
+ development landscapes before going productive.
+
+## Gerrit Operator
+
+### Version 1.0
+
+#### Implemented features
+
+- **High-availability**: Primary Gerrit StatefulSets will have limited support for
+ horizontal scaling. \
+ \
+ Scaling has been enabled using the [high-availability plugin](https://gerrit.googlesource.com/plugins/high-availability/).
+ Primary Gerrits will run in Active/Active configuration. Currently, two primary
+ Gerrit instances, i.e. 2 pods in a StatefulSet, are supported
+
+- **Global RefDB support**: Global RefDB is required for Active/Active configurations
+ of multiple primary Gerrits. \
+ \
+ The [Global RefDB](https://gerrit.googlesource.com/modules/global-refdb) support
+ is required for high-availability as described in the previous point. The
+ Gerrit Operator automatically sets up Gerrit to use a Global RefDB
+ implementation. The following implementations are supported:
+ - [spanner-refdb](https://gerrit.googlesource.com/plugins/spanner-refdb)
+ - [zookeeper-refdb](https://gerrit.googlesource.com/plugins/zookeeper-refdb)
+
+ \
+ The Gerrit Operator does not set up the database used for the Global RefDB. It
+ does however manage plugin/module installation and configuration in Gerrit.
+
+- **Full support for Nginx**: The integration of Ingresses managed by the Nginx
+ ingress controller now supports automated routing. \
+ \
+ Instead of requiring users to use different subdomains for the different Gerrit
+ deployments in the GerritCluster, requests are now automatically routed to the
+ respective deployments. SSH has still to be set up manually, since this requires
+ setting up the routing in the Nginx ingress controller itself.
+
+#### Planned features
+
+- **Versioning of CRDs**: Provide migration paths between API changes in CRDs. \
+ \
+ At the moment updates to the CRD are done without providing a migration path.
+ This means a complete reinstallation of CRDS, Operator, CRs and dependent resources
+ is required. This is not acceptable in a productive environment. Thus,
+ the operator will always support the last two versions of each CRD, if applicable,
+ and provide a migration path between those versions.
+
+- **Log collection**: Support addition of sidecar running a log collection agent
+ to send logs of all components to some logging stack. \
+ \
+ Planned supported log collectors:
+ - [OpenTelemetry agent](https://opentelemetry.io/docs/collector/deployment/agent/)
+ - Option to add a custom sidecar
+
+- **Support for additional Ingress controllers**: Add support for setting up routing
+ configurations for additional Ingress controllers \
+ \
+ Additional ingress controllers might include:
+ - [Ambassador](https://www.getambassador.io/products/edge-stack/api-gateway)
+
+### Version 1.x
+
+#### Potential features
+
+- **Support for additional log collection agents**: \
+ \
+ Additional log collection agents might include:
+ - fluentbit
+ - Option to add a custom sidecar
+
+- **Additional ValidationWebhooks**: Proactively avoid unsupported configurations. \
+ \
+ ValidationWebhooks are already used to avoid accepting unsupported configurations,
+ e.g. deploying more than one primary Gerrit CustomResource per GerritCluster.
+ So far not all such cases are covered. Thus, the set of validations will be
+ further expanded.
+
+- **Better test coverage**: More tests are required to find bugs earlier.
+
+- **Automated reload of plugins**: Reload plugins on configuration change. \
+ \
+ Configuration changes in plugins typically don't require a restart of Gerrit,
+ but just to reload the plugin. To avoid unnecessary downtime of pods, the
+ Gerrit Operator will only reload affected plugins and not restart all pods, if
+ only the plugin's configuration changed.
+
+- **Externalized (re-)indexing**: Alleviate load caused by online reindexing. \
+ \
+ On large Gerrit sites online reindexing due to schema migrations `a)` or initialization `b)`
+ of a new site might take up to weeks and use a lot of resources, which might
+ cause performance issues. This is not acceptable in production. The current
+ plan to solve this issue is to implement a separate Gerrit deployment (GerritIndexer)
+ that is not exposed to clients and that takes over the task of online reindexing.
+ The GerritIndexer will mount the same repositories and will share events via
+ the high-availability plugin. However, it will access repositories in read-only
+ mode. \
+ This solves the above named scenarios as follows: \
+ \
+ a) **Schema migrations**: If a Gerrit update including a schema migration for
+ an index is applied, the Gerrit instances serving clients will be configured
+ to continue to use the old schema. Online reindexing will be disabled in
+ those instances. The GerritIndexer will have online reindexing enabled and
+ will start to build the new index version. As soon as it is finished, i.e.
+ it could start to use the new index version as read index, it will make a
+ copy of the new index and publish it, e.g. using a shared filesystem. A
+ restart of the Gerrit instances serving other clients will be triggered.
+ During this restart the new index will be copied into the site. Since there
+ may have been updated index entries since the new index version was published
+ indexing of entries updated in the meantime will be triggered. \
+ \
+ b) **Initialization of a new site**: If Gerrit is horizontally scaled, it will
+ be started with an empty index, i.e. it has to build the complete index. To
+ avoid this, the GerritIndexer deployment will continuously keep a copy of the
+ indexes up-to-date. It will regularly be stopped and a copy of the index will
+ be stored in a shared volume. This can be used as a base for new instances, which
+ then only have to update index entries that were changed in the meantime.
+
+- **Autoscaling**: Automatically scale Gerrit deployments based on usage. \
+ \
+ Metrics like available workers in the thread pools could be used to decide to
+ scale the Gerrit deployment horizontally. This would allow to dynamically adapt
+ to the current load. This helps to save costs and resources.
+
+### Version 2.0
+
+#### Potential features
+
+- **Multi region support**: Support setups that are distributed over multiple regions. \
+ \
+ Supporting Gerrit installations that are distributed over multiple regions would
+ allow to serve clients all over the world without large differences in latency
+ and would also improve availability and reduce the risks of data loss. \
+ Such a setup could be achieved by using the [multi-site setup](https://gerrit.googlesource.com/plugins/multi-site/).
+
+- **Remove the dependency on shared storage**: Use completely independent sites
+ instead of sharing a filesystem for some site components. \
+ \
+ NFS and other shared filesystems potentially might cause performance issues on
+ larger Gerrit installations due to latencies. A potential solution might be
+ to use the [multi-site setup](https://gerrit.googlesource.com/plugins/multi-site/)
+ to separate the sites of all instances and to use events and replication to
+ share the state
+
+- **Shared index**: Using an external centralized index, e.g. OpenSearch instead
+ of x copies of a Lucene index. \
+ \
+ Maintaining x copies of an index, where x is the number of Gerrit instances in
+ a gerritCluster, is unnecessarily expensive, since the same write transactions
+ have to be potentially done x times. Using a single centralized index would
+ resolve this issue.
+
+- **Shared cache**: Using an external centralized cache for all Gerrit instances. \
+ \
+ Using a single cache for all Gerrit instances will reduce the number of
+ computations for each Gerrit instance, since not every instance will have to
+ keep its own copy up-to-date.
+
+- **Sharding**: Shard a site based on repositories. \
+ \
+ Repositories served by a single GerritCluster might be quite diverse, e.g. ranging
+ from a few kilobytes to several gigabytes or repositories seeing high traffic
+ and other barely being fetched. It is not trivial to configure Gerrit to work
+ optimally for all repositories. Being able to shard at least the Gerrit Replicas
+ would help to optimally serve all repositories.
+
+## Helm charts
+
+Only limited support is planned for the `gerrit` and `gerrit-replica` helm-charts
+as soon as the Gerrit Operator reaches version 1.0. The reason is that the double
+maintenance of all features would not be feasible with the current number of
+contributors. The Gerrit Operator will support all features that are provided by
+the helm charts. If community members would like to adopt maintainership of the
+helm-charts, this would be very much appreciated and the helm-charts could then
+continued to be supported.