forked from vipulgupta2048/github-actions-observability
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtrigger_and_verify.py
More file actions
152 lines (130 loc) · 5.1 KB
/
trigger_and_verify.py
File metadata and controls
152 lines (130 loc) · 5.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/env python3
"""
trigger_and_verify.py
This script:
- Checks or creates a GitHub webhook for a repository pointing to our Tunnel URL (/events)
- Triggers a GitHub Actions workflow dispatch
- Polls the OpenTelemetry Collector Prometheus endpoint for github_actions_workflow_runs_total metric
- Polls the Prometheus server to verify the metric is scraped
"""
import os
import sys
import time
import requests
from urllib.parse import urljoin
def load_env():
from dotenv import load_dotenv
load_dotenv()
def get_github_headers(token):
return {
'Authorization': f'token {token}',
'Accept': 'application/vnd.github.v3+json'
}
def ensure_webhook(owner, repo, tunnel_url, secret, token):
hooks_url = f'https://api.github.com/repos/{owner}/{repo}/hooks'
headers = get_github_headers(token)
resp = requests.get(hooks_url, headers=headers)
resp.raise_for_status()
hooks = resp.json()
target_url = tunnel_url.rstrip('/') + '/events'
for hook in hooks:
cfg = hook.get('config', {})
if cfg.get('url') == target_url:
print(f"Found existing webhook (id={hook['id']}) pointing to {target_url}")
return
print(f"Creating new webhook for {owner}/{repo} -> {target_url}")
data = {
'name': 'web',
'active': True,
'events': ['workflow_runs'],
'config': {
'url': target_url,
'content_type': 'json',
'secret': secret
}
}
create_resp = requests.post(hooks_url, headers=headers, json=data)
create_resp.raise_for_status()
print(f"Webhook created: {create_resp.json()['id']}")
def get_workflow_id(owner, repo, workflow_name, token):
url = f'https://api.github.com/repos/{owner}/{repo}/actions/workflows'
r = requests.get(url, headers=get_github_headers(token))
r.raise_for_status()
workflows = r.json().get('workflows', [])
for wf in workflows:
if wf.get('name') == workflow_name or wf.get('path').endswith(workflow_name):
return wf['id']
raise ValueError(f"Workflow '{workflow_name}' not found in {owner}/{repo}")
def trigger_workflow(owner, repo, workflow_id, ref, inputs, token):
url = f'https://api.github.com/repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches'
data = {'ref': ref}
if inputs:
data['inputs'] = inputs
r = requests.post(url, headers=get_github_headers(token), json=data)
if r.status_code == 204:
print('Workflow dispatch triggered')
else:
r.raise_for_status()
def poll_collector_metric(threshold=1, timeout=60):
url = 'http://localhost:9464/metrics'
start = time.time()
while time.time() - start < timeout:
try:
r = requests.get(url)
r.raise_for_status()
if 'github_actions_workflow_runs_total' in r.text:
# parse simple count
for line in r.text.splitlines():
if line.startswith('github_actions_workflow_runs_total'):
val = float(line.split()[-1])
print(f"Collector metric value: {val}")
if val >= threshold:
return True
except Exception:
pass
time.sleep(5)
return False
def poll_prometheus(query, prometheus_url='http://localhost:9090', timeout=60):
url = f'{prometheus_url}/api/v1/query'
start = time.time()
while time.time() - start < timeout:
try:
r = requests.get(url, params={'query': query})
r.raise_for_status()
data = r.json().get('data', {}).get('result', [])
if data and float(data[0]['value'][1]) > 0:
print(f"Prometheus metric '{query}' value: {data[0]['value'][1]}")
return True
except Exception as e:
pass
time.sleep(5)
return False
def main():
if len(sys.argv) < 2:
print("Usage: trigger_and_verify.py <workflow_name>")
sys.exit(1)
workflow_name = sys.argv[1]
load_env()
token = os.getenv('GITHUB_TOKEN')
secret = os.getenv('GITHUB_WEBHOOK_SECRET')
tunnel_url = os.getenv('TUNNEL_URL') or os.getenv('GITHUB_WEBHOOK_URL')
owner = os.getenv('GITHUB_ORG', 'your_github_org')
repo = os.getenv('GITHUB_REPO', 'your_repo')
ref = os.getenv('GITHUB_REF', 'main')
if not all([token, secret, tunnel_url]):
print('Please set GITHUB_TOKEN, GITHUB_WEBHOOK_SECRET, and TUNNEL_URL in your environment')
sys.exit(1)
ensure_webhook(owner, repo, tunnel_url, secret, token)
wf_id = get_workflow_id(owner, repo, workflow_name, token)
trigger_workflow(owner, repo, wf_id, ref, {}, token)
print('Waiting for collector metric...')
if not poll_collector_metric():
print('ERROR: collector did not record workflow metric in time')
sys.exit(1)
print('Waiting for Prometheus scrape...')
if not poll_prometheus('github_actions_workflow_runs_total'):
print('ERROR: Prometheus did not scrape metric in time')
sys.exit(1)
print('SUCCESS: end-to-end pipeline verified')
if __name__ == '__main__':
main()