Merge "Add cronjob to regularly delete logs to gerrit-replica chart"
diff --git a/.gitignore b/.gitignore
index 873bf67..8a09c99 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@
 
 __pycache__
 .pytest_cache
+*.pyc
diff --git a/container-images/gerrit-init/Dockerfile b/container-images/gerrit-init/Dockerfile
index 1cfa326..d730b95 100644
--- a/container-images/gerrit-init/Dockerfile
+++ b/container-images/gerrit-init/Dockerfile
@@ -13,10 +13,10 @@
     pip3 install --no-cache --upgrade pip setuptools wheel pipenv && \
     pipenv install --python 3.7.3 --system
 
-COPY tools/* /var/tools/
+COPY tools /var/tools/
 COPY config/* /var/config/
 
 USER gerrit
 
-ENTRYPOINT ["/var/tools/gerrit_init.py", "-s", "/var/gerrit"]
-CMD ["-c", "/var/config/default.config.yaml"]
+ENTRYPOINT ["python3", "/var/tools/gerrit-initializer"]
+CMD ["-s", "/var/gerrit", "-c", "/var/config/default.config.yaml", "init"]
diff --git a/container-images/gerrit-init/README.md b/container-images/gerrit-init/README.md
index 3f92f43..caeb030 100644
--- a/container-images/gerrit-init/README.md
+++ b/container-images/gerrit-init/README.md
@@ -15,22 +15,14 @@
 
 ## Start
 
-* start the container via start script `/var/tools/gerrit_init.py`
+* start the container via start script `python3 /var/tools/gerrit-initializer init`
 
-The `download_plugins.py`-script
-
-* parses required plugins from config file
-* removes unwanted plugins
-* installs and updates plugins not packaged in Gerrit's war-file
-* plugin files are validated using SHA1
-* plugin files may optionally be cached
-
-The `gerrit_init.py`-script
+The `main.py init`-command
 
 * reads configuration from gerrit.config (via `gerrit_config_parser.py`)
 * initializes Gerrit
 
-The `validate_notedb.py`-script
+The `main.py validate_notedb`-command
 
 * validates and waits for the repository `All-Projects.git` with the refs
 `refs/meta/config`.
diff --git a/container-images/gerrit-init/tools/gerrit-initializer/__main__.py b/container-images/gerrit-init/tools/gerrit-initializer/__main__.py
new file mode 100644
index 0000000..e49cc31
--- /dev/null
+++ b/container-images/gerrit-init/tools/gerrit-initializer/__main__.py
@@ -0,0 +1,18 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from main import main
+
+if __name__ == "__main__":
+    main()
diff --git a/container-images/gerrit-init/tools/gerrit-initializer/initializer/__init__.py b/container-images/gerrit-init/tools/gerrit-initializer/initializer/__init__.py
new file mode 100644
index 0000000..2230656
--- /dev/null
+++ b/container-images/gerrit-init/tools/gerrit-initializer/initializer/__init__.py
@@ -0,0 +1,13 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/container-images/gerrit-init/tools/gerrit-initializer/initializer/config/__init__.py b/container-images/gerrit-init/tools/gerrit-initializer/initializer/config/__init__.py
new file mode 100644
index 0000000..2230656
--- /dev/null
+++ b/container-images/gerrit-init/tools/gerrit-initializer/initializer/config/__init__.py
@@ -0,0 +1,13 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/container-images/gerrit-init/tools/init_config.py b/container-images/gerrit-init/tools/gerrit-initializer/initializer/config/init_config.py
similarity index 100%
rename from container-images/gerrit-init/tools/init_config.py
rename to container-images/gerrit-init/tools/gerrit-initializer/initializer/config/init_config.py
diff --git a/container-images/gerrit-init/tools/gerrit-initializer/initializer/helpers/__init__.py b/container-images/gerrit-init/tools/gerrit-initializer/initializer/helpers/__init__.py
new file mode 100644
index 0000000..2230656
--- /dev/null
+++ b/container-images/gerrit-init/tools/gerrit-initializer/initializer/helpers/__init__.py
@@ -0,0 +1,13 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/container-images/gerrit-init/tools/git_config_parser.py b/container-images/gerrit-init/tools/gerrit-initializer/initializer/helpers/git.py
similarity index 100%
rename from container-images/gerrit-init/tools/git_config_parser.py
rename to container-images/gerrit-init/tools/gerrit-initializer/initializer/helpers/git.py
diff --git a/container-images/gerrit-init/tools/log.py b/container-images/gerrit-init/tools/gerrit-initializer/initializer/helpers/log.py
similarity index 100%
rename from container-images/gerrit-init/tools/log.py
rename to container-images/gerrit-init/tools/gerrit-initializer/initializer/helpers/log.py
diff --git a/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/__init__.py b/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/__init__.py
new file mode 100644
index 0000000..2230656
--- /dev/null
+++ b/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/__init__.py
@@ -0,0 +1,13 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/container-images/gerrit-init/tools/download_plugins.py b/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/download_plugins.py
similarity index 91%
rename from container-images/gerrit-init/tools/download_plugins.py
rename to container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/download_plugins.py
index 9984dc1..d2c8e16 100755
--- a/container-images/gerrit-init/tools/download_plugins.py
+++ b/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/download_plugins.py
@@ -14,7 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import argparse
 import hashlib
 import os
 import shutil
@@ -24,10 +23,9 @@
 
 import requests
 
-from init_config import InitConfig
-from log import get_logger
+from ..helpers import log
 
-LOG = get_logger("init")
+LOG = log.get_logger("init")
 MAX_LOCK_LIFETIME = 60
 MAX_CACHED_VERSIONS = 5
 
@@ -239,29 +237,3 @@
         CachedPluginInstaller if config.plugin_cache_enabled else PluginInstaller
     )
     return plugin_installer(site, config)
-
-
-# pylint: disable=C0103
-if __name__ == "__main__":
-    parser = argparse.ArgumentParser()
-    parser.add_argument(
-        "-s",
-        "--site",
-        help="Path to Gerrit site",
-        dest="site",
-        action="store",
-        default="/var/gerrit",
-        required=True,
-    )
-    parser.add_argument(
-        "-c",
-        "--config",
-        help="Path to configuration file for init process.",
-        dest="config",
-        action="store",
-        required=True,
-    )
-    args = parser.parse_args()
-
-    config = InitConfig().parse(args.config)
-    get_installer(args.site, config).execute()
diff --git a/container-images/gerrit-init/tools/gerrit_init.py b/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/init.py
similarity index 81%
rename from container-images/gerrit-init/tools/gerrit_init.py
rename to container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/init.py
index f598d55..367d5fe 100755
--- a/container-images/gerrit-init/tools/gerrit_init.py
+++ b/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/init.py
@@ -1,5 +1,3 @@
-#!/usr/bin/python3
-
 # Copyright (C) 2018 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,17 +12,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import argparse
 import os
 import subprocess
 import sys
 
-from download_plugins import get_installer
-from git_config_parser import GitConfigParser
-from init_config import InitConfig
-from log import get_logger
+from ..helpers import git, log
+from .download_plugins import get_installer
 
-LOG = get_logger("init")
+LOG = log.get_logger("init")
 
 
 class GerritInit:
@@ -41,7 +36,7 @@
         gerrit_config_path = os.path.join(self.site, "etc/gerrit.config")
 
         if os.path.exists(gerrit_config_path):
-            return GitConfigParser(gerrit_config_path)
+            return git.GitConfigParser(gerrit_config_path)
 
         return None
 
@@ -131,31 +126,3 @@
                 init_process.returncode,
             )
             sys.exit(1)
-
-
-# pylint: disable=C0103
-if __name__ == "__main__":
-    parser = argparse.ArgumentParser()
-    parser.add_argument(
-        "-s",
-        "--site",
-        help="Path to Gerrit site",
-        dest="site",
-        action="store",
-        default="/var/gerrit",
-        required=True,
-    )
-    parser.add_argument(
-        "-c",
-        "--config",
-        help="Path to configuration file for init process.",
-        dest="config",
-        action="store",
-        required=True,
-    )
-    args = parser.parse_args()
-
-    config = InitConfig().parse(args.config)
-
-    init = GerritInit(args.site, config)
-    init.execute()
diff --git a/container-images/gerrit-init/tools/gerrit_reindex.py b/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/reindex.py
similarity index 83%
rename from container-images/gerrit-init/tools/gerrit_reindex.py
rename to container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/reindex.py
index 99ac70d..ac4ae9a 100755
--- a/container-images/gerrit-init/tools/gerrit_reindex.py
+++ b/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/reindex.py
@@ -15,7 +15,6 @@
 # limitations under the License.
 
 import abc
-import argparse
 import enum
 import os.path
 import subprocess
@@ -23,11 +22,9 @@
 
 import requests
 
-from git_config_parser import GitConfigParser
-from init_config import InitConfig
-from log import get_logger
+from ..helpers import git, log
 
-LOG = get_logger("reindex")
+LOG = log.get_logger("reindex")
 
 
 class IndexType(enum.Enum):
@@ -50,7 +47,7 @@
     def _parse_gerrit_index_config(self):
         indices = dict()
         if os.path.exists(self.index_config_path):
-            config = GitConfigParser(self.index_config_path)
+            config = git.GitConfigParser(self.index_config_path)
             options = config.list()
             for opt in options:
                 name, version = opt["subsection"].rsplit("_", 1)
@@ -138,7 +135,7 @@
 class GerritElasticSearchReindexer(GerritAbstractReindexer):
     def _get_elasticsearch_config(self):
         es_config = dict()
-        gerrit_config = GitConfigParser(
+        gerrit_config = git.GitConfigParser(
             os.path.join(self.gerrit_site_path, "etc", "gerrit.config")
         )
         es_config["prefix"] = gerrit_config.get(
@@ -172,7 +169,7 @@
 
 
 def get_reindexer(gerrit_site_path, config):
-    gerrit_config = GitConfigParser(
+    gerrit_config = git.GitConfigParser(
         os.path.join(gerrit_site_path, "etc", "gerrit.config")
     )
     index_type = gerrit_config.get("index.type", default=IndexType.LUCENE.name)
@@ -184,38 +181,3 @@
         return GerritElasticSearchReindexer(gerrit_site_path, config)
 
     raise RuntimeError("Unknown index type %s." % index_type)
-
-
-# pylint: disable=C0103
-if __name__ == "__main__":
-    parser = argparse.ArgumentParser()
-    parser.add_argument(
-        "-s",
-        "--site",
-        help="Path to Gerrit site",
-        dest="site",
-        action="store",
-        default="/var/gerrit",
-        required=True,
-    )
-    parser.add_argument(
-        "-f",
-        "--force",
-        help="Reindex even if indices are ready.",
-        dest="force",
-        action="store_true",
-    )
-    parser.add_argument(
-        "-c",
-        "--config",
-        help="Path to configuration file for init process.",
-        dest="config",
-        action="store",
-        required=True,
-    )
-    args = parser.parse_args()
-
-    config = InitConfig().parse(args.config)
-
-    reindexer = get_reindexer(args.site, config)
-    reindexer.start(args.force)
diff --git a/container-images/gerrit-init/tools/validate_notedb.py b/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/validate_notedb.py
old mode 100755
new mode 100644
similarity index 81%
rename from container-images/gerrit-init/tools/validate_notedb.py
rename to container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/validate_notedb.py
index 1d23474..8601fcb
--- a/container-images/gerrit-init/tools/validate_notedb.py
+++ b/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/validate_notedb.py
@@ -1,5 +1,4 @@
 #!/usr/bin/python3
-
 # Copyright (C) 2018 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,14 +13,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import argparse
 import os
 import subprocess
 import time
 
-from log import get_logger
+from ..helpers import log
 
-LOG = get_logger("init")
+LOG = log.get_logger("init")
 
 
 class NoteDbValidator:
@@ -61,21 +59,3 @@
                 while not self._test_ref_exists(repo, ref):
                     time.sleep(1)
                 LOG.info("Found ref %s in repo %s.", ref, repo)
-
-
-# pylint: disable=C0103
-if __name__ == "__main__":
-    parser = argparse.ArgumentParser()
-    parser.add_argument(
-        "-s",
-        "--site",
-        help="Path to Gerrit site",
-        dest="site",
-        action="store",
-        default="/var/gerrit",
-        required=True,
-    )
-    args = parser.parse_args()
-
-    init = NoteDbValidator(args.site)
-    init.execute()
diff --git a/container-images/gerrit-init/tools/gerrit-initializer/main.py b/container-images/gerrit-init/tools/gerrit-initializer/main.py
new file mode 100755
index 0000000..b4f6726
--- /dev/null
+++ b/container-images/gerrit-init/tools/gerrit-initializer/main.py
@@ -0,0 +1,93 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+import argparse
+
+from initializer.tasks import download_plugins, init, reindex, validate_notedb
+from initializer.config.init_config import InitConfig
+
+
+def _run_download_plugins(args):
+    config = InitConfig().parse(args.config)
+    download_plugins.get_installer(args.site, config).execute()
+
+
+def _run_init(args):
+    config = InitConfig().parse(args.config)
+    init.GerritInit(args.site, config).execute()
+
+
+def _run_reindex(args):
+    config = InitConfig().parse(args.config)
+    reindex.get_reindexer(args.site, config).start(args.force)
+
+
+def _run_validate_notedb(args):
+    validate_notedb.NoteDbValidator(args.site).execute()
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        "-s",
+        "--site",
+        help="Path to Gerrit site",
+        dest="site",
+        action="store",
+        default="/var/gerrit",
+        required=True,
+    )
+    parser.add_argument(
+        "-c",
+        "--config",
+        help="Path to configuration file for init process.",
+        dest="config",
+        action="store",
+        required=True,
+    )
+
+    subparsers = parser.add_subparsers()
+
+    parser_download_plugins = subparsers.add_parser(
+        "download-plugins", help="Download plugins"
+    )
+    parser_download_plugins.set_defaults(func=_run_download_plugins)
+
+    parser_init = subparsers.add_parser("init", help="Initialize Gerrit site")
+    parser_init.set_defaults(func=_run_init)
+
+    parser_reindex = subparsers.add_parser("reindex", help="Reindex Gerrit indexes")
+    parser_reindex.add_argument(
+        "-f",
+        "--force",
+        help="Reindex even if indices are ready.",
+        dest="force",
+        action="store_true",
+    )
+    parser_reindex.set_defaults(func=_run_reindex)
+
+    parser_validate_notedb = subparsers.add_parser(
+        "validate-notedb", help="Validate NoteDB"
+    )
+    parser_validate_notedb.set_defaults(func=_run_validate_notedb)
+
+    args = parser.parse_args()
+    args.func(args)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/helm-charts/gerrit-replica/README.md b/helm-charts/gerrit-replica/README.md
index 4637a01..843dfac 100644
--- a/helm-charts/gerrit-replica/README.md
+++ b/helm-charts/gerrit-replica/README.md
@@ -356,6 +356,7 @@
 | `gerritReplica.maxUnavailable`                | Max. percentage or number of pods allowed to be unavailable at a time                               | `100%`                                                                          |
 | `gerritReplica.livenessProbe`                 | Configuration of the liveness probe timings                                                         | `{initialDelaySeconds: 60, periodSeconds: 5}`                                   |
 | `gerritReplica.readinessProbe`                | Configuration of the readiness probe timings                                                        | `{initialDelaySeconds: 10, periodSeconds: 10}`                                  |
+| `gerritReplica.startupProbe`                  | Configuration of the startup probe timings                                                          | `{initialDelaySeconds: 10, periodSeconds: 5}`                                   |
 | `gerritReplica.resources`                     | Configure the amount of resources the pod requests/is allowed                                       | `requests.cpu: 1`                                                               |
 |                                               |                                                                                                     | `requests.memory: 5Gi`                                                          |
 |                                               |                                                                                                     | `limits.cpu: 1`                                                                 |
diff --git a/helm-charts/gerrit-replica/templates/gerrit-replica.deployment.yaml b/helm-charts/gerrit-replica/templates/gerrit-replica.deployment.yaml
index 417813d..a0ab62d 100644
--- a/helm-charts/gerrit-replica/templates/gerrit-replica.deployment.yaml
+++ b/helm-charts/gerrit-replica/templates/gerrit-replica.deployment.yaml
@@ -84,9 +84,10 @@
         - -ce
         args:
         - |
-          /var/tools/gerrit_init.py \
+          python3 /var/tools/gerrit-initializer \
             -c /var/config/gerrit-init.yaml \
-            -s /var/gerrit
+            -s /var/gerrit \
+            init
 
           # The git repositories and logs will be mounted from a volume
           [ -L /var/gerrit/git ] || rm -rf /var/gerrit/git
@@ -132,7 +133,10 @@
             ln -sf /var/mnt/logs /var/gerrit/
           fi
 
-          /var/tools/validate_notedb.py -s /var/gerrit
+          python3 /var/tools/gerrit-initializer \
+            -c /var/config/gerrit-init.yaml \
+            -s /var/gerrit \
+            validate-notedb
         env:
         - name: POD_NAME
           valueFrom:
@@ -209,6 +213,11 @@
             path: /config/server/healthcheck~status
             port: http
 {{ toYaml .Values.gerritReplica.readinessProbe | indent 10 }}
+        startupProbe:
+          httpGet:
+            path: /config/server/healthcheck~status
+            port: http
+{{ toYaml .Values.gerritReplica.startupProbe | indent 10 }}
         resources:
 {{ toYaml .Values.gerritReplica.resources | indent 10 }}
       {{ if .Values.promtailSidecar.enabled -}}
@@ -297,11 +306,6 @@
         secret:
           secretName: {{ .Release.Name }}-tls-ca
       {{- end }}
-      {{ if .Values.gerritReplica.service.ssh.enabled -}}
-      - name: gerrit-replica-ssh
-        secret:
-          secretName: {{ .Release.Name }}-gerrit-replica-ssh-secret
-      {{- end }}
       {{ if .Values.promtailSidecar.enabled -}}
       - name: promtail-config
         configMap:
diff --git a/helm-charts/gerrit-replica/templates/git-repositories-init.job.yaml b/helm-charts/gerrit-replica/templates/git-repositories-init.job.yaml
index 48ace53..e8ed20b 100644
--- a/helm-charts/gerrit-replica/templates/git-repositories-init.job.yaml
+++ b/helm-charts/gerrit-replica/templates/git-repositories-init.job.yaml
@@ -64,9 +64,10 @@
           ln -sf /var/config/gerrit.config /var/gerrit/etc/gerrit.config
           ln -sf /var/mnt/git /var/gerrit/
 
-          /var/tools/gerrit_init.py \
+          python3 /var/tools/gerrit-initializer \
             -c /var/config/gerrit-init.yaml \
-            -s /var/gerrit
+            -s /var/gerrit \
+            init
         env:
         - name: POD_NAME
           valueFrom:
diff --git a/helm-charts/gerrit-replica/values.yaml b/helm-charts/gerrit-replica/values.yaml
index 5b3bef1..58fafd0 100644
--- a/helm-charts/gerrit-replica/values.yaml
+++ b/helm-charts/gerrit-replica/values.yaml
@@ -239,6 +239,10 @@
     initialDelaySeconds: 10
     periodSeconds: 10
 
+  startupProbe:
+    initialDelaySeconds: 10
+    periodSeconds: 30
+
   # The memory limit has to be higher than the configures heap-size for Java!
   resources:
     requests:
diff --git a/helm-charts/gerrit/README.md b/helm-charts/gerrit/README.md
index 4b0ba8a..dc12a04 100644
--- a/helm-charts/gerrit/README.md
+++ b/helm-charts/gerrit/README.md
@@ -232,35 +232,39 @@
 future.
 ***
 
-| Parameter                              | Description                                                                                         | Default                                                                                  |
-|----------------------------------------|-----------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
-| `gerrit.images.gerritInit`             | Image name of the Gerrit init container image                                                       | `k8s-gerrit/gerrit-init`                                                                 |
-| `gerrit.images.gerrit`                 | Image name of the Gerrit container image                                                            | `k8s-gerrit/gerrit`                                                                      |
-| `gerrit.replicas`                      | Number of replica pods to deploy                                                                    | `1`                                                                                      |
-| `gerrit.updatePartition`               | Number of pods to update simultaneously                                                             | `1`                                                                                      |
-| `gerrit.resources`                     | Configure the amount of resources the pod requests/is allowed                                       | `requests.cpu: 1`                                                                        |
-|                                        |                                                                                                     | `requests.memory: 5Gi`                                                                   |
-|                                        |                                                                                                     | `limits.cpu: 1`                                                                          |
-|                                        |                                                                                                     | `limits.memory: 6Gi`                                                                     |
-| `gerrit.persistence.enabled`           | Whether to persist the Gerrit site                                                                  | `true`                                                                                   |
-| `gerrit.persistence.size`              | Storage size for persisted Gerrit site                                                              | `10Gi`                                                                                   |
-| `gerrit.livenessProbe`                 | Configuration of the liveness probe timings                                                         | `{initialDelaySeconds: 30, periodSeconds: 5}`                                            |
-| `gerrit.readinessProbe`                | Configuration of the readiness probe timings                                                        | `{initialDelaySeconds: 5, periodSeconds: 1}`                                             |
-| `gerrit.networkPolicy.ingress`         | Custom ingress-network policy for gerrit pods                                                       | `nil`                                                                                    |
-| `gerrit.networkPolicy.egress`          | Custom egress-network policy for gerrit pods                                                        | `nil`                                                                                    |
-| `gerrit.service.type`                  | Which kind of Service to deploy                                                                     | `NodePort`                                                                               |
-| `gerrit.service.http.port`             | Port over which to expose HTTP                                                                      | `80`                                                                                     |
-| `gerrit.keystore`                      | base64-encoded Java keystore (`cat keystore.jks | base64`) to be used by Gerrit, when using SSL     | `nil`                                                                                    |
-| `gerrit.index.type`                    | Index type used by Gerrit (either `lucene` or `elasticsearch`)                                      | `lucene`                                                                                 |
-| `gerrit.plugins.packaged`              | List of Gerrit plugins that are packaged into the Gerrit-war-file to install                        | `["commit-message-length-validator", "download-commands", "replication", "reviewnotes"]` |
-| `gerrit.plugins.downloaded`            | List of Gerrit plugins that will be downloaded                                                      | `nil`                                                                                    |
-| `gerrit.plugins.downloaded[0].name`    | Name of plugin                                                                                      | `nil`                                                                                    |
-| `gerrit.plugins.downloaded[0].url`     | Download url of plugin                                                                              | `nil`                                                                                    |
-| `gerrit.plugins.downloaded[0].sha1`    | SHA1 sum of plugin jar used to ensure file integrity and version (optional)                         | `nil`                                                                                    |
-| `gerrit.plugins.cache.enabled`         | Whether to cache downloaded plugins                                                                 | `false`                                                                                  |
-| `gerrit.plugins.cache.size`            | Size of the volume used to store cached plugins                                                     | `1Gi`                                                                                    |
-| `gerrit.etc.config`                    | Map of config files (e.g. `gerrit.config`) that will be mounted to `$GERRIT_SITE/etc`by a ConfigMap | `{gerrit.config: ..., replication.config: ...}`[see here](#Gerrit-config-files)          |
-| `gerrit.etc.secret`                    | Map of config files (e.g. `secure.config`) that will be mounted to `$GERRIT_SITE/etc`by a Secret    | `{secure.config: ...}` [see here](#Gerrit-config-files)                                  |
+| Parameter                           | Description                                                                                         | Default                                                                                  |
+|-------------------------------------|-----------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
+| `gerrit.images.gerritInit`          | Image name of the Gerrit init container image                                                       | `k8s-gerrit/gerrit-init`                                                                 |
+| `gerrit.images.gerrit`              | Image name of the Gerrit container image                                                            | `k8s-gerrit/gerrit`                                                                      |
+| `gerrit.replicas`                   | Number of replica pods to deploy                                                                    | `1`                                                                                      |
+| `gerrit.updatePartition`            | Number of pods to update simultaneously                                                             | `1`                                                                                      |
+| `gerrit.resources`                  | Configure the amount of resources the pod requests/is allowed                                       | `requests.cpu: 1`                                                                        |
+|                                     |                                                                                                     | `requests.memory: 5Gi`                                                                   |
+|                                     |                                                                                                     | `limits.cpu: 1`                                                                          |
+|                                     |                                                                                                     | `limits.memory: 6Gi`                                                                     |
+| `gerrit.persistence.enabled`        | Whether to persist the Gerrit site                                                                  | `true`                                                                                   |
+| `gerrit.persistence.size`           | Storage size for persisted Gerrit site                                                              | `10Gi`                                                                                   |
+| `gerrit.livenessProbe`              | Configuration of the liveness probe timings                                                         | `{initialDelaySeconds: 30, periodSeconds: 5}`                                            |
+| `gerrit.readinessProbe`             | Configuration of the readiness probe timings                                                        | `{initialDelaySeconds: 5, periodSeconds: 1}`                                             |
+| `gerrit.startupProbe`               | Configuration of the startup probe timings                                                          | `{initialDelaySeconds: 10, periodSeconds: 5}`                                            |
+| `gerrit.networkPolicy.ingress`      | Custom ingress-network policy for gerrit pods                                                       | `nil`                                                                                    |
+| `gerrit.networkPolicy.egress`       | Custom egress-network policy for gerrit pods                                                        | `nil`                                                                                    |
+| `gerrit.service.type`               | Which kind of Service to deploy                                                                     | `NodePort`                                                                               |
+| `gerrit.service.http.port`          | Port over which to expose HTTP                                                                      | `80`                                                                                     |
+| `gerrit.service.ssh.enabled`        | Whether to enable SSH                                                                               | `false`                                                                                  |
+| `gerrit.service.ssh.port`           | Port over which to expose SSH                                                                       | `29418`                                                                                  |
+| `gerrit.service.ssh.rsaKey`         | Private SSH key in RSA format                                                                       | `-----BEGIN RSA PRIVATE KEY-----`                                                        |
+| `gerrit.keystore`                   | base64-encoded Java keystore (`cat keystore.jks | base64`) to be used by Gerrit, when using SSL     | `nil`                                                                                    |
+| `gerrit.index.type`                 | Index type used by Gerrit (either `lucene` or `elasticsearch`)                                      | `lucene`                                                                                 |
+| `gerrit.plugins.packaged`           | List of Gerrit plugins that are packaged into the Gerrit-war-file to install                        | `["commit-message-length-validator", "download-commands", "replication", "reviewnotes"]` |
+| `gerrit.plugins.downloaded`         | List of Gerrit plugins that will be downloaded                                                      | `nil`                                                                                    |
+| `gerrit.plugins.downloaded[0].name` | Name of plugin                                                                                      | `nil`                                                                                    |
+| `gerrit.plugins.downloaded[0].url`  | Download url of plugin                                                                              | `nil`                                                                                    |
+| `gerrit.plugins.downloaded[0].sha1` | SHA1 sum of plugin jar used to ensure file integrity and version (optional)                         | `nil`                                                                                    |
+| `gerrit.plugins.cache.enabled`      | Whether to cache downloaded plugins                                                                 | `false`                                                                                  |
+| `gerrit.plugins.cache.size`         | Size of the volume used to store cached plugins                                                     | `1Gi`                                                                                    |
+| `gerrit.etc.config`                 | Map of config files (e.g. `gerrit.config`) that will be mounted to `$GERRIT_SITE/etc`by a ConfigMap | `{gerrit.config: ..., replication.config: ...}`[see here](#Gerrit-config-files)          |
+| `gerrit.etc.secret`                 | Map of config files (e.g. `secure.config`) that will be mounted to `$GERRIT_SITE/etc`by a Secret    | `{secure.config: ...}` [see here](#Gerrit-config-files)                                  |
 
 ### Gerrit config files
 
diff --git a/helm-charts/gerrit/templates/gerrit.secrets.yaml b/helm-charts/gerrit/templates/gerrit.secrets.yaml
index 4d67840..9ccb233 100644
--- a/helm-charts/gerrit/templates/gerrit.secrets.yaml
+++ b/helm-charts/gerrit/templates/gerrit.secrets.yaml
@@ -11,6 +11,9 @@
   {{ if .Values.gerrit.keystore -}}
   keystore: {{ .Values.gerrit.keystore }}
   {{- end }}
+  {{ if .Values.gerrit.service.ssh.enabled -}}
+  ssh_host_rsa_key: {{ .Values.gerrit.service.ssh.rsaKey | b64enc }}
+  {{- end }}
   {{- range $key, $value := .Values.gerrit.etc.secret }}
   {{ $key }}: {{ $value | b64enc }}
   {{- end }}
diff --git a/helm-charts/gerrit/templates/gerrit.service.yaml b/helm-charts/gerrit/templates/gerrit.service.yaml
index 4fab1ef..dc51f8e 100644
--- a/helm-charts/gerrit/templates/gerrit.service.yaml
+++ b/helm-charts/gerrit/templates/gerrit.service.yaml
@@ -13,6 +13,11 @@
   - name: http
     port: {{ .http.port }}
     targetPort: 8080
+  {{- if .ssh.enabled }}
+  - name: ssh
+    port: {{ .ssh.port }}
+    targetPort: 29418
+  {{- end }}
   selector:
     app: gerrit
   type: {{ .type }}
diff --git a/helm-charts/gerrit/templates/gerrit.stateful-set.yaml b/helm-charts/gerrit/templates/gerrit.stateful-set.yaml
index 55b6cba..e22c71b 100644
--- a/helm-charts/gerrit/templates/gerrit.stateful-set.yaml
+++ b/helm-charts/gerrit/templates/gerrit.stateful-set.yaml
@@ -75,9 +75,14 @@
             fi
           done
 
-          /var/tools/gerrit_init.py \
+          python3 /var/tools/gerrit-initializer \
             -c /var/config/gerrit-init.yaml \
-            -s /var/gerrit
+            -s /var/gerrit \
+            init
+
+          {{ if .Values.gerrit.service.ssh.enabled -}}
+          rm -f /var/gerrit/etc/ssh_host*key*
+          {{- end }}
 
           symlink_config_to_site
 
@@ -87,9 +92,12 @@
 
           # TODO (Thomas): Do not enforce offline-reindexing, when online-reindexing
           # is configured.
-          /var/tools/gerrit_reindex.py $FLAGS \
+          python3 /var/tools/gerrit-initializer \
             -c /var/config/gerrit-init.yaml \
-            -s /var/gerrit
+            -s /var/gerrit \
+            reindex \
+            $FLAGS
+
         volumeMounts:
         - name: gerrit-site
           mountPath: "/var/gerrit"
@@ -122,6 +130,10 @@
         ports:
         - name: gerrit-port
           containerPort: 8080
+        {{- if .Values.gerrit.service.ssh.enabled }}
+        - name: gerrit-ssh
+          containerPort: 29418
+        {{- end }}
         volumeMounts:
         - name: gerrit-site
           mountPath: "/var/gerrit"
@@ -147,6 +159,11 @@
             path: /config/server/healthcheck~status
             port: gerrit-port
 {{ toYaml .Values.gerrit.readinessProbe | indent 10 }}
+        startupProbe:
+          httpGet:
+            path: /config/server/healthcheck~status
+            port: gerrit-port
+{{ toYaml .Values.gerrit.startupProbe | indent 10 }}
       volumes:
       {{ if not .Values.gerrit.persistence.enabled -}}
       - name: gerrit-site
diff --git a/helm-charts/gerrit/values.yaml b/helm-charts/gerrit/values.yaml
index 506227a..a61b777 100644
--- a/helm-charts/gerrit/values.yaml
+++ b/helm-charts/gerrit/values.yaml
@@ -134,6 +134,10 @@
     initialDelaySeconds: 5
     periodSeconds: 1
 
+  startupProbe:
+    initialDelaySeconds: 10
+    periodSeconds: 30
+
   # The general NetworkPolicy rules implemented by this chart may be too restrictive
   # for some setups, e.g. when trying to replicate to a Gerrit replica. Here
   # custom rules may be added to whitelist some additional connections.
@@ -154,6 +158,13 @@
     type: NodePort
     http:
       port: 80
+    ssh:
+      enabled: false
+      port: 29418
+      rsaKey: |-
+        -----BEGIN RSA PRIVATE KEY-----
+
+        -----END RSA PRIVATE KEY-----
 
   # `gerrit.keystore` expects a base64-encoded Java-keystore
   # Since Java keystores are binary files, adding the unencoded content and
diff --git a/tests/container-images/gerrit-init/test_container_integration_gerrit_init.py b/tests/container-images/gerrit-init/test_container_integration_gerrit_init.py
index 9de4043..566f8f7 100644
--- a/tests/container-images/gerrit-init/test_container_integration_gerrit_init.py
+++ b/tests/container-images/gerrit-init/test_container_integration_gerrit_init.py
@@ -128,7 +128,7 @@
         )
 
         exit_code, _ = container_run_endless.exec_run(
-            "/var/tools/gerrit_init.py -s /var/gerrit -c /var/config/init.yaml"
+            "python3 /var/tools/gerrit-initializer -s /var/gerrit -c /var/config/init.yaml init"
         )
         assert exit_code == 0
 
@@ -150,7 +150,7 @@
         )
 
         exit_code, _ = container_run_endless.exec_run(
-            "/var/tools/gerrit_init.py -s /var/gerrit -c /var/config/init.yaml"
+            "python3 /var/tools/gerrit-initializer -s /var/gerrit -c /var/config/init.yaml init"
         )
         assert exit_code == 0
 
diff --git a/tests/container-images/gerrit-init/test_container_integration_gerrit_init_reindexing.py b/tests/container-images/gerrit-init/test_container_integration_gerrit_init_reindexing.py
index cc097dd..8f50e50 100644
--- a/tests/container-images/gerrit-init/test_container_integration_gerrit_init_reindexing.py
+++ b/tests/container-images/gerrit-init/test_container_integration_gerrit_init_reindexing.py
@@ -62,7 +62,7 @@
             os.path.join(temp_site, "index", "gerrit_index.config")
         )
         exit_code, _ = container_run_endless.exec_run(
-            "/var/tools/gerrit_init.py -s /var/gerrit -c /var/config/default.config.yaml"
+            "python3 /var/tools/gerrit-initializer -s /var/gerrit -c /var/config/default.config.yaml init"
         )
         assert exit_code == 0
         expected_files = ["gerrit_index.config"] + self._get_indices(
@@ -74,7 +74,7 @@
         timestamp_index_dir = os.path.getctime(os.path.join(temp_site, "index"))
 
         exit_code, _ = container_run_endless.exec_run(
-            "/var/tools/gerrit_reindex.py -s /var/gerrit -c /var/config/default.config.yaml"
+            "python3 /var/tools/gerrit-initializer -s /var/gerrit -c /var/config/default.config.yaml reindex"
         )
         assert exit_code == 0
         assert timestamp_index_dir == os.path.getctime(os.path.join(temp_site, "index"))
@@ -83,12 +83,12 @@
         self, container_run_endless, temp_site
     ):
         container_run_endless.exec_run(
-            "/var/tools/gerrit_init.py -s /var/gerrit -c /var/config/default.config.yaml"
+            "python3 /var/tools/gerrit-initializer -s /var/gerrit -c /var/config/default.config.yaml init"
         )
         os.remove(os.path.join(temp_site, "index", "gerrit_index.config"))
 
         exit_code, _ = container_run_endless.exec_run(
-            "/var/tools/gerrit_reindex.py -s /var/gerrit -c /var/config/default.config.yaml"
+            "python3 /var/tools/gerrit-initializer -s /var/gerrit -c /var/config/default.config.yaml reindex"
         )
         assert exit_code == 0
 
@@ -97,7 +97,7 @@
 
     def test_gerrit_init_fixes_unready_indices(self, container_run_endless):
         container_run_endless.exec_run(
-            "/var/tools/gerrit_init.py -s /var/gerrit -c /var/config/default.config.yaml"
+            "python3 /var/tools/gerrit-initializer -s /var/gerrit -c /var/config/default.config.yaml init"
         )
 
         indices = self._get_indices(container_run_endless)
@@ -107,7 +107,7 @@
         )
 
         exit_code, _ = container_run_endless.exec_run(
-            "/var/tools/gerrit_reindex.py -s /var/gerrit -c /var/config/default.config.yaml"
+            "python3 /var/tools/gerrit-initializer -s /var/gerrit -c /var/config/default.config.yaml reindex"
         )
         assert exit_code == 0
 
@@ -116,7 +116,7 @@
 
     def test_gerrit_init_fixes_outdated_indices(self, container_run_endless, temp_site):
         container_run_endless.exec_run(
-            "/var/tools/gerrit_init.py -s /var/gerrit -c /var/config/default.config.yaml"
+            "python3 /var/tools/gerrit-initializer -s /var/gerrit -c /var/config/default.config.yaml init"
         )
 
         index = self._get_indices(container_run_endless)[0]
@@ -129,7 +129,7 @@
         )
 
         exit_code, _ = container_run_endless.exec_run(
-            "/var/tools/gerrit_reindex.py -s /var/gerrit -c /var/config/default.config.yaml"
+            "python3 /var/tools/gerrit-initializer -s /var/gerrit -c /var/config/default.config.yaml reindex"
         )
         assert exit_code == 0
 
diff --git a/tests/container-images/gerrit-init/test_container_structure_gerrit_init.py b/tests/container-images/gerrit-init/test_container_structure_gerrit_init.py
index 1098c82..ab259c9 100755
--- a/tests/container-images/gerrit-init/test_container_structure_gerrit_init.py
+++ b/tests/container-images/gerrit-init/test_container_structure_gerrit_init.py
@@ -27,11 +27,8 @@
 @pytest.fixture(
     scope="function",
     params=[
-        "/var/tools/download_plugins.py",
-        "/var/tools/gerrit_init.py",
-        "/var/tools/gerrit_reindex.py",
-        "/var/tools/git_config_parser.py",
-        "/var/tools/init_config.py",
+        "/var/tools/gerrit-initializer/__main__.py",
+        "/var/tools/gerrit-initializer/main.py",
     ],
 )
 def expected_script(request):
@@ -74,4 +71,4 @@
 def test_gerrit_init_has_entrypoint(gerrit_init_image):
     entrypoint = gerrit_init_image.attrs["ContainerConfig"]["Entrypoint"]
     assert len(entrypoint) >= 1
-    assert entrypoint == ["/var/tools/gerrit_init.py", "-s", "/var/gerrit"]
+    assert entrypoint == ["python3", "/var/tools/gerrit-initializer"]