blob: 7122e367f6e6f74f71fb76d0686758ba7bbd8cd4 [file] [log] [blame]
# 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")
capabilities = webdriver.DesiredCapabilities.CHROME.copy()
capabilities["acceptInsecureCerts"] = True
driver = webdriver.Chrome(
chrome_options=options,
desired_capabilities=capabilities,
)
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