|
17 | 17 | import json |
18 | 18 | import os |
19 | 19 | import random |
| 20 | +import shutil |
20 | 21 | import signal |
21 | 22 | import subprocess |
22 | 23 | import time |
|
25 | 26 | from enum import Enum |
26 | 27 | from typing import Any |
27 | 28 |
|
| 29 | +import requests |
28 | 30 | import yaml |
29 | 31 | from semver.version import Version |
30 | 32 |
|
|
41 | 43 | from materialize.mzcompose.services.orchestratord import Orchestratord |
42 | 44 | from materialize.mzcompose.services.testdrive import Testdrive |
43 | 45 | from materialize.util import all_subclasses |
44 | | -from materialize.version_list import get_all_self_managed_versions |
| 46 | +from materialize.version_list import ( |
| 47 | + get_all_self_managed_versions, |
| 48 | + get_self_managed_versions, |
| 49 | +) |
45 | 50 |
|
46 | 51 | SERVICES = [ |
47 | 52 | Testdrive(), |
@@ -1127,6 +1132,236 @@ class Action(Enum): |
1127 | 1132 | UpgradeChain = "upgrade-chain" |
1128 | 1133 |
|
1129 | 1134 |
|
| 1135 | +def workflow_defaults(c: Composition, parser: WorkflowArgumentParser) -> None: |
| 1136 | + parser.add_argument( |
| 1137 | + "--tag", |
| 1138 | + type=str, |
| 1139 | + help="Custom version tag to use", |
| 1140 | + ) |
| 1141 | + args = parser.parse_args() |
| 1142 | + |
| 1143 | + current_version = get_tag(args.tag) |
| 1144 | + |
| 1145 | + # Following https://materialize.com/docs/self-managed/v25.2/installation/install-on-local-kind/ |
| 1146 | + for version in reversed(get_self_managed_versions() + [current_version]): |
| 1147 | + dir = "my-local-mz" |
| 1148 | + if os.path.exists(dir): |
| 1149 | + shutil.rmtree(dir) |
| 1150 | + os.mkdir(dir) |
| 1151 | + spawn.runv(["kind", "delete", "cluster"]) |
| 1152 | + spawn.runv(["kind", "create", "cluster"]) |
| 1153 | + spawn.runv( |
| 1154 | + [ |
| 1155 | + "kubectl", |
| 1156 | + "label", |
| 1157 | + "node", |
| 1158 | + "kind-control-plane", |
| 1159 | + "materialize.cloud/disk=true", |
| 1160 | + ] |
| 1161 | + ) |
| 1162 | + spawn.runv( |
| 1163 | + [ |
| 1164 | + "kubectl", |
| 1165 | + "label", |
| 1166 | + "node", |
| 1167 | + "kind-control-plane", |
| 1168 | + "materialize.cloud/swap=true", |
| 1169 | + ] |
| 1170 | + ) |
| 1171 | + spawn.runv( |
| 1172 | + [ |
| 1173 | + "kubectl", |
| 1174 | + "label", |
| 1175 | + "node", |
| 1176 | + "kind-control-plane", |
| 1177 | + "workload=materialize-instance", |
| 1178 | + ] |
| 1179 | + ) |
| 1180 | + |
| 1181 | + shutil.copyfile( |
| 1182 | + "misc/helm-charts/operator/values.yaml", |
| 1183 | + os.path.join(dir, "sample-values.yaml"), |
| 1184 | + ) |
| 1185 | + files = { |
| 1186 | + "sample-postgres.yaml": "misc/helm-charts/testing/postgres.yaml", |
| 1187 | + "sample-minio.yaml": "misc/helm-charts/testing/minio.yaml", |
| 1188 | + "sample-materialize.yaml": "misc/helm-charts/testing/materialize.yaml", |
| 1189 | + } |
| 1190 | + |
| 1191 | + for file, path in files.items(): |
| 1192 | + if version == current_version: |
| 1193 | + shutil.copyfile(path, os.path.join(dir, file)) |
| 1194 | + else: |
| 1195 | + url = f"https://raw.githubusercontent.com/MaterializeInc/materialize/refs/tags/{version}/{path}" |
| 1196 | + response = requests.get(url) |
| 1197 | + assert ( |
| 1198 | + response.status_code == 200 |
| 1199 | + ), f"Failed to download {file} from {url}: {response.status_code}" |
| 1200 | + with open(os.path.join(dir, file), "wb") as f: |
| 1201 | + f.write(response.content) |
| 1202 | + |
| 1203 | + spawn.runv( |
| 1204 | + [ |
| 1205 | + "helm", |
| 1206 | + "repo", |
| 1207 | + "add", |
| 1208 | + "materialize", |
| 1209 | + "https://materializeinc.github.io/materialize", |
| 1210 | + ] |
| 1211 | + ) |
| 1212 | + spawn.runv(["helm", "repo", "update", "materialize"]) |
| 1213 | + spawn.runv( |
| 1214 | + [ |
| 1215 | + "helm", |
| 1216 | + "install", |
| 1217 | + "my-materialize-operator", |
| 1218 | + MZ_ROOT / "misc" / "helm-charts" / "operator", |
| 1219 | + "--namespace=materialize", |
| 1220 | + "--create-namespace", |
| 1221 | + "--version", |
| 1222 | + "v25.3.0", |
| 1223 | + "--set", |
| 1224 | + "observability.podMetrics.enabled=true", |
| 1225 | + "-f", |
| 1226 | + os.path.join(dir, "sample-values.yaml"), |
| 1227 | + ] |
| 1228 | + ) |
| 1229 | + spawn.runv( |
| 1230 | + ["kubectl", "apply", "-f", os.path.join(dir, "sample-postgres.yaml")] |
| 1231 | + ) |
| 1232 | + spawn.runv(["kubectl", "apply", "-f", os.path.join(dir, "sample-minio.yaml")]) |
| 1233 | + spawn.runv(["kubectl", "get", "all", "-n", "materialize"]) |
| 1234 | + spawn.runv( |
| 1235 | + [ |
| 1236 | + "helm", |
| 1237 | + "repo", |
| 1238 | + "add", |
| 1239 | + "metrics-server", |
| 1240 | + "https://kubernetes-sigs.github.io/metrics-server/", |
| 1241 | + ] |
| 1242 | + ) |
| 1243 | + spawn.runv(["helm", "repo", "update", "metrics-server"]) |
| 1244 | + spawn.runv( |
| 1245 | + [ |
| 1246 | + "helm", |
| 1247 | + "install", |
| 1248 | + "metrics-server", |
| 1249 | + "metrics-server/metrics-server", |
| 1250 | + "--namespace", |
| 1251 | + "kube-system", |
| 1252 | + "--set", |
| 1253 | + "args={--kubelet-insecure-tls,--kubelet-preferred-address-types=InternalIP,Hostname,ExternalIP}", |
| 1254 | + ] |
| 1255 | + ) |
| 1256 | + for i in range(120): |
| 1257 | + try: |
| 1258 | + spawn.capture( |
| 1259 | + [ |
| 1260 | + "kubectl", |
| 1261 | + "get", |
| 1262 | + "crd", |
| 1263 | + "materializes.materialize.cloud", |
| 1264 | + "-n", |
| 1265 | + "materialize", |
| 1266 | + "-o", |
| 1267 | + "name", |
| 1268 | + ], |
| 1269 | + stderr=subprocess.DEVNULL, |
| 1270 | + ) |
| 1271 | + break |
| 1272 | + |
| 1273 | + except subprocess.CalledProcessError: |
| 1274 | + pass |
| 1275 | + time.sleep(1) |
| 1276 | + else: |
| 1277 | + raise ValueError("Never completed") |
| 1278 | + |
| 1279 | + with open(os.path.join(dir, "sample-materialize.yaml")) as f: |
| 1280 | + materialize_setup = list(yaml.load_all(f, Loader=yaml.Loader)) |
| 1281 | + assert len(materialize_setup) == 3 |
| 1282 | + |
| 1283 | + if version == current_version: |
| 1284 | + materialize_setup[2]["spec"]["environmentdImageRef"] = get_image( |
| 1285 | + c.compose["services"]["environmentd"]["image"], args.tag |
| 1286 | + ) |
| 1287 | + # Self-managed v25.1/2 don't require a license key yet |
| 1288 | + materialize_setup[1]["stringData"]["license_key"] = os.environ[ |
| 1289 | + "MZ_CI_LICENSE_KEY" |
| 1290 | + ] |
| 1291 | + else: |
| 1292 | + # TODO: Remove this part once environmentId is set in older versions |
| 1293 | + materialize_setup[2]["spec"][ |
| 1294 | + "environmentId" |
| 1295 | + ] = "12345678-1234-1234-1234-123456789013" |
| 1296 | + |
| 1297 | + with open(os.path.join(dir, "sample-materialize.yaml"), "w") as f: |
| 1298 | + yaml.dump_all(materialize_setup, f, default_flow_style=False) |
| 1299 | + |
| 1300 | + spawn.runv( |
| 1301 | + ["kubectl", "apply", "-f", os.path.join(dir, "sample-materialize.yaml")] |
| 1302 | + ) |
| 1303 | + |
| 1304 | + for i in range(240): |
| 1305 | + try: |
| 1306 | + data = json.loads( |
| 1307 | + spawn.capture( |
| 1308 | + [ |
| 1309 | + "kubectl", |
| 1310 | + "get", |
| 1311 | + "pod", |
| 1312 | + "-n", |
| 1313 | + "materialize-environment", |
| 1314 | + "-o", |
| 1315 | + "json", |
| 1316 | + ] |
| 1317 | + ) |
| 1318 | + ) |
| 1319 | + expected_pods = { |
| 1320 | + "environmentd": 1, |
| 1321 | + "clusterd": 2, |
| 1322 | + "balancerd": 2, |
| 1323 | + "console": 2, |
| 1324 | + } |
| 1325 | + for item in data.get("items", []): |
| 1326 | + for container in item.get("status", {}).get( |
| 1327 | + "containerStatuses", [] |
| 1328 | + ): |
| 1329 | + name = container.get("name") |
| 1330 | + assert name in expected_pods, f"Unexpected pod {name}" |
| 1331 | + state = container.get("state", {}) |
| 1332 | + if "running" in state: |
| 1333 | + expected_pods[name] -= 1 |
| 1334 | + assert all( |
| 1335 | + value >= 0 for value in expected_pods.values() |
| 1336 | + ), f"Incorrect number of pods of some type: {expected_pods}" |
| 1337 | + if all(value == 0 for value in expected_pods.values()): |
| 1338 | + spawn.runv( |
| 1339 | + [ |
| 1340 | + "kubectl", |
| 1341 | + "get", |
| 1342 | + "pod", |
| 1343 | + "-n", |
| 1344 | + "materialize-environment", |
| 1345 | + ] |
| 1346 | + ) |
| 1347 | + break |
| 1348 | + |
| 1349 | + except subprocess.CalledProcessError: |
| 1350 | + pass |
| 1351 | + time.sleep(1) |
| 1352 | + else: |
| 1353 | + spawn.runv( |
| 1354 | + [ |
| 1355 | + "kubectl", |
| 1356 | + "get", |
| 1357 | + "pod", |
| 1358 | + "-n", |
| 1359 | + "materialize-environment", |
| 1360 | + ] |
| 1361 | + ) |
| 1362 | + raise ValueError("Never completed") |
| 1363 | + |
| 1364 | + |
1130 | 1365 | def workflow_default(c: Composition, parser: WorkflowArgumentParser) -> None: |
1131 | 1366 | parser.add_argument( |
1132 | 1367 | "--recreate-cluster", |
|
0 commit comments