Skip to content

Commit 55ef9f1

Browse files
feat(deployment): add sequencer readiness check stage to system test workflow
1 parent e113bb8 commit 55ef9f1

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed

.github/workflows/consolidated_system_test.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ jobs:
114114
- name: Set default namespace
115115
run: kubectl config set-context --current --namespace ${{ env.namespace }}
116116

117+
- name: Run readiness check
118+
run: pipenv run python ./scripts/system_tests/readiness_check.py --deployment_config_path ${{ env.deployment_config_path }} --namespace ${{ env.namespace }}
119+
117120
- name: Get container logs
118121
if: always()
119122
run: |
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import argparse
2+
import os
3+
from kubernetes import client, config
4+
from kubernetes.client.rest import ApiException
5+
from pathlib import Path
6+
import json
7+
import sys
8+
import time
9+
10+
11+
def check_manifest_files(deployment_config_path: str, workspace: str):
12+
with open(deployment_config_path, "r", encoding="utf-8") as f:
13+
deployment_config = json.load(f)
14+
15+
services = deployment_config["services"]
16+
17+
for service in services:
18+
service_name = service["name"]
19+
controller = service["controller"]
20+
service_name_lower = service_name.lower()
21+
controller_lower = controller.lower()
22+
23+
manifest_path = (
24+
Path(workspace)
25+
/ f"deployments/sequencer/dist/sequencer-{service_name_lower}/{controller}.sequencer-{service_name_lower}-{controller_lower}.k8s.yaml"
26+
)
27+
28+
if not manifest_path.exists():
29+
print(
30+
f"❌ Manifest {manifest_path} for {service_name_lower} not found. Aborting..."
31+
)
32+
try:
33+
dir_listing = list(manifest_path.parent.iterdir())
34+
print(
35+
f"Contents of {manifest_path.parent}: {[str(f) for f in dir_listing]}"
36+
)
37+
except FileNotFoundError:
38+
print(f"(Directory {manifest_path.parent} does not exist)")
39+
sys.exit(1)
40+
41+
42+
def wait_for_services_ready(deployment_config_path: str, namespace: str):
43+
config.load_kube_config() # Or load_incluster_config() if inside a pod
44+
45+
with open(deployment_config_path, "r", encoding="utf-8") as f:
46+
deployment_config = json.load(f)
47+
48+
services = deployment_config["services"]
49+
50+
apps_v1 = client.AppsV1Api()
51+
52+
for service in services:
53+
service_name = service["name"]
54+
controller = service["controller"]
55+
service_name_lower = service_name.lower()
56+
controller_lower = controller.lower()
57+
resource_name = f"sequencer-{service_name_lower}-{controller_lower}"
58+
59+
print(f"🔍 Checking {controller_lower}: {resource_name}")
60+
61+
try:
62+
if controller_lower == "statefulset":
63+
obj = apps_v1.read_namespaced_stateful_set(
64+
resource_name, namespace=namespace
65+
)
66+
elif controller_lower == "deployment":
67+
obj = apps_v1.read_namespaced_deployment(
68+
resource_name, namespace=namespace
69+
)
70+
else:
71+
print(f"❌ Unknown controller: {controller}. Skipping...")
72+
continue
73+
except ApiException as e:
74+
if e.status == 404:
75+
print(f"❌ {controller} {resource_name} not found. Skipping...")
76+
continue
77+
else:
78+
raise
79+
80+
# Describe & status info (light equivalent of kubectl describe)
81+
print(
82+
f"🔍 {controller} {resource_name} status: replicas={obj.status.replicas}, ready={obj.status.ready_replicas}"
83+
)
84+
85+
print(f"⏳ Waiting for {controller_lower}/{resource_name} to become ready...")
86+
87+
timeout_seconds = 180
88+
poll_interval = 5
89+
elapsed = 0
90+
91+
while elapsed < timeout_seconds:
92+
try:
93+
if controller_lower == "statefulset":
94+
status = apps_v1.read_namespaced_stateful_set_status(
95+
resource_name, namespace
96+
).status
97+
ready = status.ready_replicas or 0
98+
desired = status.replicas or 0
99+
else: # deployment
100+
status = apps_v1.read_namespaced_deployment_status(
101+
resource_name, namespace
102+
).status
103+
ready = status.ready_replicas or 0
104+
desired = status.replicas or 0
105+
106+
if ready == desired and ready > 0:
107+
print(f"✅ {controller} {resource_name} is ready.")
108+
break
109+
except ApiException as e:
110+
print(f"❌ Error while checking status: {e}")
111+
112+
time.sleep(poll_interval)
113+
elapsed += poll_interval
114+
else:
115+
print(
116+
f"⚠️ Timeout waiting for {controller} {resource_name} to become ready."
117+
)
118+
sys.exit(1)
119+
120+
121+
if __name__ == "__main__":
122+
parser = argparse.ArgumentParser(
123+
description="Check manifest files and wait for K8s services to be ready."
124+
)
125+
parser.add_argument(
126+
"--deployment_config_path", help="Path to the deployment config JSON file"
127+
)
128+
parser.add_argument(
129+
"--namespace",
130+
help="Kubernetes namespace",
131+
)
132+
args = parser.parse_args()
133+
134+
github_workspace = os.environ["GITHUB_WORKSPACE"]
135+
136+
check_manifest_files(args.deployment_config_path, github_workspace)
137+
wait_for_services_ready(args.deployment_config_path, namespace=args.namespace)
138+
print("✅ All sequencer services are ready.")

0 commit comments

Comments
 (0)