blob: ec7a7c125743772ac5d7b138497894472a53fef7 [file] [log] [blame]
Giorgi Lekveishvili285ab622023-11-22 13:50:45 +04001# Copyright (C) 2022 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import os.path
16
17from copy import deepcopy
18from pathlib import Path
19
20import pytest
21import yaml
22
23import pygit2 as git
24import chromedriver_autoinstaller
25from kubernetes import client
26from selenium import webdriver
27from selenium.webdriver.common.by import By
28
29from .abstract_deployment import AbstractDeployment
30
31
32class TimeOutException(Exception):
33 """Exception to be raised, if some action does not finish in time."""
34
35
36def dict_to_git_config(config_dict):
37 config = ""
38 for section, options in config_dict.items():
39 config += f"[{section}]\n"
40 for key, value in options.items():
41 if isinstance(value, bool):
42 value = "true" if value else "false"
43 elif isinstance(value, list):
44 for opt in value:
45 config += f" {key} = {opt}\n"
46 continue
47 config += f" {key} = {value}\n"
48 return config
49
50
51GERRIT_STARTUP_TIMEOUT = 240
52
53DEFAULT_GERRIT_CONFIG = {
54 "auth": {
55 "type": "LDAP",
56 },
57 "container": {
58 "user": "gerrit",
59 "javaHome": "/usr/lib/jvm/java-11-openjdk",
60 "javaOptions": [
61 "-Djavax.net.ssl.trustStore=/var/gerrit/etc/keystore",
62 "-Xms200m",
63 "-Xmx4g",
64 ],
65 },
66 "gerrit": {
67 "basePath": "git",
68 "canonicalWebUrl": "http://example.com/",
69 "serverId": "gerrit-1",
70 },
71 "httpd": {
72 "listenUrl": "proxy-https://*:8080/",
73 "requestLog": True,
74 "gracefulStopTimeout": "1m",
75 },
76 "index": {"type": "LUCENE", "onlineUpgrade": False},
77 "ldap": {
78 "server": "ldap://openldap.openldap.svc.cluster.local:1389",
79 "accountbase": "dc=example,dc=org",
80 "username": "cn=admin,dc=example,dc=org",
81 },
82 "sshd": {"listenAddress": "off"},
83}
84
85DEFAULT_VALUES = {
86 "gitRepositoryStorage": {"externalPVC": {"use": True, "name": "repo-storage"}},
87 "gitGC": {"logging": {"persistence": {"enabled": False}}},
88 "gerrit": {
89 "etc": {"config": {"gerrit.config": dict_to_git_config(DEFAULT_GERRIT_CONFIG)}}
90 },
91}
92
93
94# pylint: disable=R0902
95class GerritDeployment(AbstractDeployment):
96 def __init__(
97 self,
98 tmp_dir,
99 cluster,
100 storageclass,
101 container_registry,
102 container_org,
103 container_version,
104 ingress_url,
105 ldap_admin_credentials,
106 ldap_credentials,
107 ):
108 super().__init__(tmp_dir)
109 self.cluster = cluster
110 self.storageclass = storageclass
111 self.ldap_credentials = ldap_credentials
112
113 self.chart_name = "gerrit-" + self.namespace
114 self.chart_path = os.path.join(
115 # pylint: disable=E1101
116 Path(git.discover_repository(os.path.realpath(__file__))).parent.absolute(),
117 "helm-charts",
118 "gerrit",
119 )
120
121 self.gerrit_config = deepcopy(DEFAULT_GERRIT_CONFIG)
122 self.chart_opts = deepcopy(DEFAULT_VALUES)
123
124 self._configure_container_images(
125 container_registry, container_org, container_version
126 )
127 self.hostname = f"{self.namespace}.{ingress_url}"
128 self._configure_ingress()
129 self.set_gerrit_config_value(
130 "gerrit", "canonicalWebUrl", f"http://{self.hostname}"
131 )
132 # pylint: disable=W1401
133 self.set_helm_value(
134 "gerrit.etc.secret.secure\.config",
135 dict_to_git_config({"ldap": {"password": ldap_admin_credentials[1]}}),
136 )
137
138 def install(self, wait=True):
139 if self.cluster.helm.is_installed(self.namespace, self.chart_name):
140 self.update()
141 return
142
143 with open(self.values_file, "w", encoding="UTF-8") as f:
144 yaml.dump(self.chart_opts, f)
145
146 self.cluster.create_namespace(self.namespace)
147 self._create_pvc()
148
149 self.cluster.helm.install(
150 self.chart_path,
151 self.chart_name,
152 values_file=self.values_file,
153 fail_on_err=True,
154 namespace=self.namespace,
155 wait=wait,
156 )
157
158 def create_admin_account(self):
159 self.wait_until_ready()
160 chromedriver_autoinstaller.install()
161 options = webdriver.ChromeOptions()
162 options.add_argument("--headless")
163 options.add_argument("--no-sandbox")
164 options.add_argument("--ignore-certificate-errors")
165 options.set_capability("acceptInsecureCerts", True)
166 driver = webdriver.Chrome(
167 options=options,
168 )
169 driver.get(f"http://{self.hostname}/login")
170 user_input = driver.find_element(By.ID, "f_user")
171 user_input.send_keys("gerrit-admin")
172
173 pwd_input = driver.find_element(By.ID, "f_pass")
174 pwd_input.send_keys(self.ldap_credentials["gerrit-admin"])
175
176 submit_btn = driver.find_element(By.ID, "b_signin")
177 submit_btn.click()
178
179 driver.close()
180
181 def update(self):
182 with open(self.values_file, "w", encoding="UTF-8") as f:
183 yaml.dump(self.chart_opts, f)
184
185 self.cluster.helm.upgrade(
186 self.chart_path,
187 self.chart_name,
188 values_file=self.values_file,
189 fail_on_err=True,
190 namespace=self.namespace,
191 )
192
193 def wait_until_ready(self):
194 pod_labels = f"app=gerrit,release={self.chart_name}"
195 finished_in_time = self._wait_for_pod_readiness(
196 pod_labels, timeout=GERRIT_STARTUP_TIMEOUT
197 )
198
199 if not finished_in_time:
200 raise TimeOutException(
201 f"Gerrit pod was not ready in time ({GERRIT_STARTUP_TIMEOUT} s)."
202 )
203
204 def uninstall(self):
205 self.cluster.helm.delete(self.chart_name, namespace=self.namespace)
206 self.cluster.delete_namespace(self.namespace)
207
208 def set_gerrit_config_value(self, section, key, value):
209 if isinstance(self.gerrit_config[section][key], list):
210 self.gerrit_config[section][key].append(value)
211 else:
212 self.gerrit_config[section][key] = value
213 # pylint: disable=W1401
214 self.set_helm_value(
215 "gerrit.etc.config.gerrit\.config", dict_to_git_config(self.gerrit_config)
216 )
217
218 def _set_values_file(self):
219 return os.path.join(self.tmp_dir, "values.yaml")
220
221 def _configure_container_images(
222 self, container_registry, container_org, container_version
223 ):
224 self.set_helm_value("images.registry.name", container_registry)
225 self.set_helm_value("gitGC.image", f"{container_org}/git-gc")
226 self.set_helm_value("gerrit.images.gerritInit", f"{container_org}/gerrit-init")
227 self.set_helm_value("gerrit.images.gerrit", f"{container_org}/gerrit")
228 self.set_helm_value("images.version", container_version)
229
230 def _configure_ingress(self):
231 self.set_helm_value("ingress.enabled", True)
232 self.set_helm_value("ingress.host", self.hostname)
233
234 def _create_pvc(self):
235 core_v1 = client.CoreV1Api()
236 core_v1.create_namespaced_persistent_volume_claim(
237 self.namespace,
238 body=client.V1PersistentVolumeClaim(
239 kind="PersistentVolumeClaim",
240 api_version="v1",
241 metadata=client.V1ObjectMeta(name="repo-storage"),
242 spec=client.V1PersistentVolumeClaimSpec(
243 access_modes=["ReadWriteMany"],
244 storage_class_name=self.storageclass,
245 resources=client.V1ResourceRequirements(
246 requests={"storage": "1Gi"}
247 ),
248 ),
249 ),
250 )
251
252
253@pytest.fixture(scope="class")
254def gerrit_deployment(
255 request, tmp_path_factory, test_cluster, ldap_admin_credentials, ldap_credentials
256):
257 deployment = GerritDeployment(
258 tmp_path_factory.mktemp("gerrit_deployment"),
259 test_cluster,
260 request.config.getoption("--rwm-storageclass").lower(),
261 request.config.getoption("--registry"),
262 request.config.getoption("--org"),
263 request.config.getoption("--tag"),
264 request.config.getoption("--ingress-url"),
265 ldap_admin_credentials,
266 ldap_credentials,
267 )
268
269 yield deployment
270
271 deployment.uninstall()
272
273
274@pytest.fixture(scope="class")
275def default_gerrit_deployment(gerrit_deployment):
276 gerrit_deployment.install()
277 gerrit_deployment.create_admin_account()
278
279 yield gerrit_deployment