update charts
diff --git a/charts/k8s-gerrit/tests/fixtures/__init__.py b/charts/k8s-gerrit/tests/fixtures/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/charts/k8s-gerrit/tests/fixtures/__init__.py
diff --git a/charts/k8s-gerrit/tests/fixtures/cluster.py b/charts/k8s-gerrit/tests/fixtures/cluster.py
new file mode 100644
index 0000000..eb94968
--- /dev/null
+++ b/charts/k8s-gerrit/tests/fixtures/cluster.py
@@ -0,0 +1,144 @@
+# pylint: disable=W0613
+
+# Copyright (C) 2022 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 base64
+import json
+import warnings
+
+from kubernetes import client, config
+
+import pytest
+
+from .helm.client import HelmClient
+
+
+class Cluster:
+ def __init__(self, kube_config):
+ self.kube_config = kube_config
+
+ self.image_pull_secrets = []
+ self.namespaces = []
+
+ context = self._load_kube_config()
+ self.helm = HelmClient(self.kube_config, context)
+
+ def _load_kube_config(self):
+ config.load_kube_config(config_file=self.kube_config)
+ _, context = config.list_kube_config_contexts(config_file=self.kube_config)
+ return context["name"]
+
+ def _apply_image_pull_secrets(self, namespace):
+ for ips in self.image_pull_secrets:
+ try:
+ client.CoreV1Api().create_namespaced_secret(namespace, ips)
+ except client.rest.ApiException as exc:
+ if exc.status == 409 and exc.reason == "Conflict":
+ warnings.warn(
+ "Kubernetes Cluster not empty. Image pull secret already exists."
+ )
+ else:
+ raise exc
+
+ def add_container_registry(self, secret_name, url, user, pwd):
+ data = {
+ "auths": {
+ url: {
+ "auth": base64.b64encode(str.encode(f"{user}:{pwd}")).decode(
+ "utf-8"
+ )
+ }
+ }
+ }
+ metadata = client.V1ObjectMeta(name=secret_name)
+ self.image_pull_secrets.append(
+ client.V1Secret(
+ api_version="v1",
+ kind="Secret",
+ metadata=metadata,
+ type="kubernetes.io/dockerconfigjson",
+ data={
+ ".dockerconfigjson": base64.b64encode(
+ json.dumps(data).encode()
+ ).decode("utf-8")
+ },
+ )
+ )
+
+ def create_namespace(self, name):
+ namespace_metadata = client.V1ObjectMeta(name=name)
+ namespace_body = client.V1Namespace(
+ kind="Namespace", api_version="v1", metadata=namespace_metadata
+ )
+ client.CoreV1Api().create_namespace(body=namespace_body)
+ self.namespaces.append(name)
+ self._apply_image_pull_secrets(name)
+
+ def delete_namespace(self, name):
+ if name not in self.namespaces:
+ return
+
+ client.CoreV1Api().delete_namespace(name, body=client.V1DeleteOptions())
+ self.namespaces.remove(name)
+
+ def cleanup(self):
+ while self.namespaces:
+ self.helm.delete_all(
+ namespace=self.namespaces[0],
+ )
+ self.delete_namespace(self.namespaces[0])
+
+
+@pytest.fixture(scope="session")
+def test_cluster(request):
+ kube_config = request.config.getoption("--kubeconfig")
+
+ test_cluster = Cluster(kube_config)
+ test_cluster.add_container_registry(
+ "image-pull-secret",
+ request.config.getoption("--registry"),
+ request.config.getoption("--registry-user"),
+ request.config.getoption("--registry-pwd"),
+ )
+
+ yield test_cluster
+
+ test_cluster.cleanup()
+
+
+@pytest.fixture(scope="session")
+def ldap_credentials(test_cluster):
+ ldap_secret = client.CoreV1Api().read_namespaced_secret(
+ "openldap-users", namespace="openldap"
+ )
+ users = base64.b64decode(ldap_secret.data["users"]).decode("utf-8").split(",")
+ passwords = (
+ base64.b64decode(ldap_secret.data["passwords"]).decode("utf-8").split(",")
+ )
+ credentials = {}
+ for i, user in enumerate(users):
+ credentials[user] = passwords[i]
+
+ yield credentials
+
+
+@pytest.fixture(scope="session")
+def ldap_admin_credentials(test_cluster):
+ ldap_secret = client.CoreV1Api().read_namespaced_secret(
+ "openldap-admin", namespace="openldap"
+ )
+ password = base64.b64decode(ldap_secret.data["adminpassword"]).decode("utf-8")
+
+ yield ("admin", password)
diff --git a/charts/k8s-gerrit/tests/fixtures/credentials.py b/charts/k8s-gerrit/tests/fixtures/credentials.py
new file mode 100644
index 0000000..de39dc1
--- /dev/null
+++ b/charts/k8s-gerrit/tests/fixtures/credentials.py
@@ -0,0 +1,39 @@
+# pylint: disable=W0613
+
+# Copyright (C) 2022 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 os
+
+import pytest
+
+from passlib.apache import HtpasswdFile
+
+import utils
+
+
+@pytest.fixture(scope="session")
+def credentials_dir(tmp_path_factory):
+ return tmp_path_factory.mktemp("creds")
+
+
+@pytest.fixture(scope="session")
+def htpasswd(credentials_dir):
+ basic_auth_creds = {"user": "admin", "password": utils.create_random_string(16)}
+ htpasswd_file = HtpasswdFile(os.path.join(credentials_dir, ".htpasswd"), new=True)
+ htpasswd_file.set_password(basic_auth_creds["user"], basic_auth_creds["password"])
+ htpasswd_file.save()
+ basic_auth_creds["htpasswd_string"] = htpasswd_file.to_string()
+ basic_auth_creds["htpasswd_file"] = credentials_dir
+ yield basic_auth_creds
diff --git a/charts/k8s-gerrit/tests/fixtures/helm/__init__.py b/charts/k8s-gerrit/tests/fixtures/helm/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/charts/k8s-gerrit/tests/fixtures/helm/__init__.py
diff --git a/charts/k8s-gerrit/tests/fixtures/helm/abstract_deployment.py b/charts/k8s-gerrit/tests/fixtures/helm/abstract_deployment.py
new file mode 100644
index 0000000..517cfe2
--- /dev/null
+++ b/charts/k8s-gerrit/tests/fixtures/helm/abstract_deployment.py
@@ -0,0 +1,99 @@
+import abc
+import random
+import re
+import string
+
+from time import time
+
+from kubernetes import client
+
+
+class AbstractDeployment(abc.ABC):
+ def __init__(self, tmp_dir):
+ self.tmp_dir = tmp_dir
+ self.namespace = "".join(
+ [random.choice(string.ascii_letters) for n in range(8)]
+ ).lower()
+ self.values_file = self._set_values_file()
+ self.chart_opts = {}
+
+ @abc.abstractmethod
+ def install(self, wait=True):
+ pass
+
+ @abc.abstractmethod
+ def update(self):
+ pass
+
+ @abc.abstractmethod
+ def uninstall(self):
+ pass
+
+ @abc.abstractmethod
+ def _set_values_file(self):
+ pass
+
+ def set_helm_value(self, combined_key, value):
+ nested_keys = re.split(r"(?<!\\)\.", combined_key)
+ dct_pointer = self.chart_opts
+ for key in nested_keys[:-1]:
+ # pylint: disable=W1401
+ key.replace("\.", ".")
+ dct_pointer = dct_pointer.setdefault(key, {})
+ # pylint: disable=W1401
+ dct_pointer[nested_keys[-1].replace("\.", ".")] = value
+
+ def _wait_for_pod_readiness(self, pod_labels, timeout=180):
+ """Helper function that can be used to wait for all pods with a given set of
+ labels to be ready.
+
+ Arguments:
+ pod_labels {str} -- Label selector string to be used to select pods.
+ (https://kubernetes.io/docs/concepts/overview/working-with-objects/\
+ labels/#label-selectors)
+
+ Keyword Arguments:
+ timeout {int} -- Time in seconds to wait for the pod status to become ready.
+ (default: {180})
+
+ Returns:
+ boolean -- Whether pods were ready in time.
+ """
+
+ def check_pod_readiness():
+ core_v1 = client.CoreV1Api()
+ pod_list = core_v1.list_pod_for_all_namespaces(
+ watch=False, label_selector=pod_labels
+ )
+ for pod in pod_list.items:
+ for condition in pod.status.conditions:
+ if condition.type != "Ready" and condition.status != "True":
+ return False
+ return True
+
+ return self._exec_fn_with_timeout(check_pod_readiness, limit=timeout)
+
+ def _exec_fn_with_timeout(self, func, limit=60):
+ """Helper function that executes a given function until it returns True or a
+ given time limit is reached.
+
+ Arguments:
+ func {function} -- Function to execute. The function can return some output
+ (or None) and as a second return value a boolean indicating,
+ whether the event the function was waiting for has happened.
+
+ Keyword Arguments:
+ limit {int} -- Maximum time in seconds to wait for a positive response of
+ the function (default: {60})
+
+ Returns:
+ boolean -- False, if the timeout was reached
+ any -- Last output of fn
+ """
+
+ timeout = time() + limit
+ while time() < timeout:
+ is_finished = func()
+ if is_finished:
+ return True
+ return False
diff --git a/charts/k8s-gerrit/tests/fixtures/helm/client.py b/charts/k8s-gerrit/tests/fixtures/helm/client.py
new file mode 100644
index 0000000..eb3285f
--- /dev/null
+++ b/charts/k8s-gerrit/tests/fixtures/helm/client.py
@@ -0,0 +1,202 @@
+# 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 json
+import subprocess
+
+
+class HelmClient:
+ def __init__(self, kubeconfig, kubecontext):
+ """Wrapper for Helm CLI.
+
+ Arguments:
+ kubeconfig {str} -- Path to kubeconfig-file describing the cluster to
+ connect to.
+ kubecontext {str} -- Name of the context to use.
+ """
+
+ self.kubeconfig = kubeconfig
+ self.kubecontext = kubecontext
+
+ def _exec_command(self, cmd, fail_on_err=True):
+ base_cmd = [
+ "helm",
+ "--kubeconfig",
+ self.kubeconfig,
+ "--kube-context",
+ self.kubecontext,
+ ]
+ return subprocess.run(
+ base_cmd + cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ check=fail_on_err,
+ text=True,
+ )
+
+ def install(
+ self,
+ chart,
+ name,
+ values_file=None,
+ set_values=None,
+ namespace=None,
+ fail_on_err=True,
+ wait=True,
+ ):
+ """Installs a chart on the cluster
+
+ Arguments:
+ chart {str} -- Release name or path of a helm chart
+ name {str} -- Name with which the chart will be installed on the cluster
+
+ Keyword Arguments:
+ values_file {str} -- Path to a custom values.yaml file (default: {None})
+ set_values {dict} -- Dictionary containing key-value-pairs that are used
+ to overwrite values in the values.yaml-file.
+ (default: {None})
+ namespace {str} -- Namespace to install the release into (default: {default})
+ fail_on_err {bool} -- Whether to fail with an exception if the installation
+ fails (default: {True})
+ wait {bool} -- Whether to wait for all pods to be ready (default: {True})
+
+ Returns:
+ CompletedProcess -- CompletedProcess-object returned by subprocess
+ containing details about the result and output of the
+ executed command.
+ """
+
+ helm_cmd = ["install", name, chart, "--dependency-update"]
+ if values_file:
+ helm_cmd.extend(("-f", values_file))
+ if set_values:
+ opt_list = [f"{k}={v}" for k, v in set_values.items()]
+ helm_cmd.extend(("--set", ",".join(opt_list)))
+ if namespace:
+ helm_cmd.extend(("--namespace", namespace))
+ if wait:
+ helm_cmd.append("--wait")
+ return self._exec_command(helm_cmd, fail_on_err)
+
+ def list(self, namespace=None):
+ """Lists helm charts installed on the cluster.
+
+ Keyword Arguments:
+ namespace {str} -- Kubernetes namespace (default: {None})
+
+ Returns:
+ list -- List of helm chart realeases installed on the cluster.
+ """
+
+ helm_cmd = ["list", "--all", "--output", "json"]
+ if namespace:
+ helm_cmd.extend(("--namespace", namespace))
+ output = self._exec_command(helm_cmd).stdout
+ return json.loads(output)
+
+ def upgrade(
+ self,
+ chart,
+ name,
+ namespace,
+ values_file=None,
+ set_values=None,
+ reuse_values=True,
+ fail_on_err=True,
+ ):
+ """Updates a chart on the cluster
+
+ Arguments:
+ chart {str} -- Release name or path of a helm chart
+ name {str} -- Name with which the chart will be installed on the cluster
+ namespace {str} -- Kubernetes namespace
+
+ Keyword Arguments:
+ values_file {str} -- Path to a custom values.yaml file (default: {None})
+ set_values {dict} -- Dictionary containing key-value-pairs that are used
+ to overwrite values in the values.yaml-file.
+ (default: {None})
+ reuse_values {bool} -- Whether to reuse existing not overwritten values
+ (default: {True})
+ fail_on_err {bool} -- Whether to fail with an exception if the installation
+ fails (default: {True})
+
+ Returns:
+ CompletedProcess -- CompletedProcess-object returned by subprocess
+ containing details about the result and output of the
+ executed command.
+ """
+ helm_cmd = ["upgrade", name, chart, "--namespace", namespace, "--wait"]
+ if values_file:
+ helm_cmd.extend(("-f", values_file))
+ if reuse_values:
+ helm_cmd.append("--reuse-values")
+ if set_values:
+ opt_list = [f"{k}={v}" for k, v in set_values.items()]
+ helm_cmd.extend(("--set", ",".join(opt_list)))
+ return self._exec_command(helm_cmd, fail_on_err)
+
+ def delete(self, name, namespace=None):
+ """Deletes a chart from the cluster
+
+ Arguments:
+ name {str} -- Name of the chart to delete
+
+ Keyword Arguments:
+ namespace {str} -- Kubernetes namespace (default: {None})
+
+ Returns:
+ CompletedProcess -- CompletedProcess-object returned by subprocess
+ containing details about the result and output of
+ the executed command.
+ """
+
+ if name not in self.list(namespace):
+ return None
+
+ helm_cmd = ["delete", name]
+ if namespace:
+ helm_cmd.extend(("--namespace", namespace))
+ return self._exec_command(helm_cmd)
+
+ def delete_all(self, namespace=None, exceptions=None):
+ """Deletes all charts on the cluster
+
+ Keyword Arguments:
+ namespace {str} -- Kubernetes namespace (default: {None})
+ exceptions {list} -- List of chart names not to delete (default: {None})
+ """
+
+ charts = self.list(namespace)
+ for chart in charts:
+ if exceptions and chart["name"] in exceptions:
+ continue
+ self.delete(chart["name"], namespace)
+
+ def is_installed(self, namespace, chart):
+ """Checks if a chart is installed in the cluster
+
+ Keyword Arguments:
+ namespace {str} -- Kubernetes namespace
+ chart {str} -- Name of the chart
+
+ Returns:
+ bool -- Whether the chart is installed
+ """
+
+ for installed_chart in self.list(namespace):
+ if installed_chart["name"] == chart:
+ return True
+
+ return False
diff --git a/charts/k8s-gerrit/tests/fixtures/helm/gerrit.py b/charts/k8s-gerrit/tests/fixtures/helm/gerrit.py
new file mode 100644
index 0000000..ec7a7c1
--- /dev/null
+++ b/charts/k8s-gerrit/tests/fixtures/helm/gerrit.py
@@ -0,0 +1,279 @@
+# Copyright (C) 2022 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 os.path
+
+from copy import deepcopy
+from pathlib import Path
+
+import pytest
+import yaml
+
+import pygit2 as git
+import chromedriver_autoinstaller
+from kubernetes import client
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+
+from .abstract_deployment import AbstractDeployment
+
+
+class TimeOutException(Exception):
+ """Exception to be raised, if some action does not finish in time."""
+
+
+def dict_to_git_config(config_dict):
+ config = ""
+ for section, options in config_dict.items():
+ config += f"[{section}]\n"
+ for key, value in options.items():
+ if isinstance(value, bool):
+ value = "true" if value else "false"
+ elif isinstance(value, list):
+ for opt in value:
+ config += f" {key} = {opt}\n"
+ continue
+ config += f" {key} = {value}\n"
+ return config
+
+
+GERRIT_STARTUP_TIMEOUT = 240
+
+DEFAULT_GERRIT_CONFIG = {
+ "auth": {
+ "type": "LDAP",
+ },
+ "container": {
+ "user": "gerrit",
+ "javaHome": "/usr/lib/jvm/java-11-openjdk",
+ "javaOptions": [
+ "-Djavax.net.ssl.trustStore=/var/gerrit/etc/keystore",
+ "-Xms200m",
+ "-Xmx4g",
+ ],
+ },
+ "gerrit": {
+ "basePath": "git",
+ "canonicalWebUrl": "http://example.com/",
+ "serverId": "gerrit-1",
+ },
+ "httpd": {
+ "listenUrl": "proxy-https://*:8080/",
+ "requestLog": True,
+ "gracefulStopTimeout": "1m",
+ },
+ "index": {"type": "LUCENE", "onlineUpgrade": False},
+ "ldap": {
+ "server": "ldap://openldap.openldap.svc.cluster.local:1389",
+ "accountbase": "dc=example,dc=org",
+ "username": "cn=admin,dc=example,dc=org",
+ },
+ "sshd": {"listenAddress": "off"},
+}
+
+DEFAULT_VALUES = {
+ "gitRepositoryStorage": {"externalPVC": {"use": True, "name": "repo-storage"}},
+ "gitGC": {"logging": {"persistence": {"enabled": False}}},
+ "gerrit": {
+ "etc": {"config": {"gerrit.config": dict_to_git_config(DEFAULT_GERRIT_CONFIG)}}
+ },
+}
+
+
+# pylint: disable=R0902
+class GerritDeployment(AbstractDeployment):
+ def __init__(
+ self,
+ tmp_dir,
+ cluster,
+ storageclass,
+ container_registry,
+ container_org,
+ container_version,
+ ingress_url,
+ ldap_admin_credentials,
+ ldap_credentials,
+ ):
+ super().__init__(tmp_dir)
+ self.cluster = cluster
+ self.storageclass = storageclass
+ self.ldap_credentials = ldap_credentials
+
+ self.chart_name = "gerrit-" + self.namespace
+ self.chart_path = os.path.join(
+ # pylint: disable=E1101
+ Path(git.discover_repository(os.path.realpath(__file__))).parent.absolute(),
+ "helm-charts",
+ "gerrit",
+ )
+
+ self.gerrit_config = deepcopy(DEFAULT_GERRIT_CONFIG)
+ self.chart_opts = deepcopy(DEFAULT_VALUES)
+
+ self._configure_container_images(
+ container_registry, container_org, container_version
+ )
+ self.hostname = f"{self.namespace}.{ingress_url}"
+ self._configure_ingress()
+ self.set_gerrit_config_value(
+ "gerrit", "canonicalWebUrl", f"http://{self.hostname}"
+ )
+ # pylint: disable=W1401
+ self.set_helm_value(
+ "gerrit.etc.secret.secure\.config",
+ dict_to_git_config({"ldap": {"password": ldap_admin_credentials[1]}}),
+ )
+
+ def install(self, wait=True):
+ if self.cluster.helm.is_installed(self.namespace, self.chart_name):
+ self.update()
+ return
+
+ with open(self.values_file, "w", encoding="UTF-8") as f:
+ yaml.dump(self.chart_opts, f)
+
+ self.cluster.create_namespace(self.namespace)
+ self._create_pvc()
+
+ self.cluster.helm.install(
+ self.chart_path,
+ self.chart_name,
+ values_file=self.values_file,
+ fail_on_err=True,
+ namespace=self.namespace,
+ wait=wait,
+ )
+
+ def create_admin_account(self):
+ self.wait_until_ready()
+ chromedriver_autoinstaller.install()
+ options = webdriver.ChromeOptions()
+ options.add_argument("--headless")
+ options.add_argument("--no-sandbox")
+ options.add_argument("--ignore-certificate-errors")
+ options.set_capability("acceptInsecureCerts", True)
+ driver = webdriver.Chrome(
+ options=options,
+ )
+ driver.get(f"http://{self.hostname}/login")
+ user_input = driver.find_element(By.ID, "f_user")
+ user_input.send_keys("gerrit-admin")
+
+ pwd_input = driver.find_element(By.ID, "f_pass")
+ pwd_input.send_keys(self.ldap_credentials["gerrit-admin"])
+
+ submit_btn = driver.find_element(By.ID, "b_signin")
+ submit_btn.click()
+
+ driver.close()
+
+ def update(self):
+ with open(self.values_file, "w", encoding="UTF-8") as f:
+ yaml.dump(self.chart_opts, f)
+
+ self.cluster.helm.upgrade(
+ self.chart_path,
+ self.chart_name,
+ values_file=self.values_file,
+ fail_on_err=True,
+ namespace=self.namespace,
+ )
+
+ def wait_until_ready(self):
+ pod_labels = f"app=gerrit,release={self.chart_name}"
+ finished_in_time = self._wait_for_pod_readiness(
+ pod_labels, timeout=GERRIT_STARTUP_TIMEOUT
+ )
+
+ if not finished_in_time:
+ raise TimeOutException(
+ f"Gerrit pod was not ready in time ({GERRIT_STARTUP_TIMEOUT} s)."
+ )
+
+ def uninstall(self):
+ self.cluster.helm.delete(self.chart_name, namespace=self.namespace)
+ self.cluster.delete_namespace(self.namespace)
+
+ def set_gerrit_config_value(self, section, key, value):
+ if isinstance(self.gerrit_config[section][key], list):
+ self.gerrit_config[section][key].append(value)
+ else:
+ self.gerrit_config[section][key] = value
+ # pylint: disable=W1401
+ self.set_helm_value(
+ "gerrit.etc.config.gerrit\.config", dict_to_git_config(self.gerrit_config)
+ )
+
+ def _set_values_file(self):
+ return os.path.join(self.tmp_dir, "values.yaml")
+
+ def _configure_container_images(
+ self, container_registry, container_org, container_version
+ ):
+ self.set_helm_value("images.registry.name", container_registry)
+ self.set_helm_value("gitGC.image", f"{container_org}/git-gc")
+ self.set_helm_value("gerrit.images.gerritInit", f"{container_org}/gerrit-init")
+ self.set_helm_value("gerrit.images.gerrit", f"{container_org}/gerrit")
+ self.set_helm_value("images.version", container_version)
+
+ def _configure_ingress(self):
+ self.set_helm_value("ingress.enabled", True)
+ self.set_helm_value("ingress.host", self.hostname)
+
+ def _create_pvc(self):
+ core_v1 = client.CoreV1Api()
+ core_v1.create_namespaced_persistent_volume_claim(
+ self.namespace,
+ body=client.V1PersistentVolumeClaim(
+ kind="PersistentVolumeClaim",
+ api_version="v1",
+ metadata=client.V1ObjectMeta(name="repo-storage"),
+ spec=client.V1PersistentVolumeClaimSpec(
+ access_modes=["ReadWriteMany"],
+ storage_class_name=self.storageclass,
+ resources=client.V1ResourceRequirements(
+ requests={"storage": "1Gi"}
+ ),
+ ),
+ ),
+ )
+
+
+@pytest.fixture(scope="class")
+def gerrit_deployment(
+ request, tmp_path_factory, test_cluster, ldap_admin_credentials, ldap_credentials
+):
+ deployment = GerritDeployment(
+ tmp_path_factory.mktemp("gerrit_deployment"),
+ test_cluster,
+ request.config.getoption("--rwm-storageclass").lower(),
+ request.config.getoption("--registry"),
+ request.config.getoption("--org"),
+ request.config.getoption("--tag"),
+ request.config.getoption("--ingress-url"),
+ ldap_admin_credentials,
+ ldap_credentials,
+ )
+
+ yield deployment
+
+ deployment.uninstall()
+
+
+@pytest.fixture(scope="class")
+def default_gerrit_deployment(gerrit_deployment):
+ gerrit_deployment.install()
+ gerrit_deployment.create_admin_account()
+
+ yield gerrit_deployment