Skip to content

Commit 41dbc81

Browse files
committed
set-matrix: query github for runners status
1 parent 3309d68 commit 41dbc81

File tree

3 files changed

+106
-24
lines changed

3 files changed

+106
-24
lines changed

.github/scripts/matrix.py

Lines changed: 87 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
import os
44
import dataclasses
55
import json
6+
import requests
67

78
from enum import Enum
8-
from typing import Any, Dict, List, Final, Set, Union
9+
from typing import Any, Dict, List, Final, Set, Union, Optional
910

1011
MANAGED_OWNER: Final[str] = "kernel-patches"
1112
MANAGED_REPOS: Final[Set[str]] = {
@@ -66,22 +67,14 @@ class BuildConfig:
6667
run_veristat: bool = False
6768
parallel_tests: bool = False
6869
build_release: bool = False
70+
build_runs_on: Optional[List[str]] = dataclasses.field(default_factory=lambda: [DEFAULT_RUNNER])
6971

7072
@property
7173
def runs_on(self) -> List[str]:
7274
if is_managed_repo():
7375
return DEFAULT_SELF_HOSTED_RUNNER_TAGS + [self.arch.value]
7476
return [DEFAULT_RUNNER]
7577

76-
@property
77-
def build_runs_on(self) -> List[str]:
78-
if is_managed_repo():
79-
# Build s390x on x86_64
80-
return DEFAULT_SELF_HOSTED_RUNNER_TAGS + [
81-
self.arch.value == "s390x" and Arch.X86_64.value or self.arch.value,
82-
]
83-
return [DEFAULT_RUNNER]
84-
8578
@property
8679
def tests(self) -> Dict[str, Any]:
8780
tests_list = [
@@ -158,38 +151,115 @@ def generate_test_config(test: str) -> Dict[str, Union[str, int]]:
158151
return config
159152

160153

154+
def query_runners() -> Optional[List[Dict[str, Any]]]:
155+
token = os.environ["GITHUB_TOKEN"]
156+
headers = {
157+
"Authorization": f"token {token}",
158+
"Accept": "application/vnd.github.v3+json"
159+
}
160+
owner = os.environ["GITHUB_REPOSITORY_OWNER"]
161+
url = f"https://api.github.com/orgs/{owner}/actions/runners"
162+
# GitHub returns 30 runners per page, fetch all
163+
all_runners = []
164+
try:
165+
while url:
166+
response = requests.get(url, headers=headers)
167+
if response.status_code != 200:
168+
return None
169+
data = response.json()
170+
all_runners.extend(data.get('runners', []))
171+
# Check for next page URL in Link header
172+
url = None
173+
if 'Link' in response.headers:
174+
links = requests.utils.parse_header_links(response.headers['Link'])
175+
for link in links:
176+
if link['rel'] == 'next':
177+
url = link['url']
178+
break
179+
return all_runners
180+
except Exception as e:
181+
print(f"Warning: Failed to query runner status: {e}")
182+
return None
183+
184+
185+
def is_x86_64_runner(runner: Dict[str, Any]) -> bool:
186+
labels = [label['name'] for label in runner['labels']]
187+
for label in DEFAULT_SELF_HOSTED_RUNNER_TAGS:
188+
if label not in labels:
189+
return False
190+
return 'x86_64' in labels
191+
192+
193+
def x86_64_runners_too_busy() -> bool:
194+
195+
print(f"is_managed_repo(): {is_managed_repo()}")
196+
197+
if not is_managed_repo():
198+
return False
199+
200+
runners = query_runners()
201+
if not runners:
202+
print("Warning: failed to query runner status from GitHub")
203+
return False
204+
205+
x86_64_runners = [r for r in runners if is_x86_64_runner(r)]
206+
n_busy = 0
207+
n_idle = 0
208+
n_offline = 0
209+
for runner in x86_64_runners:
210+
if runner['status'] == 'online':
211+
if runner['busy']:
212+
n_busy += 1
213+
else:
214+
n_idle += 1
215+
else:
216+
n_offline += 1
217+
too_busy = n_idle == 0 or (n_busy / (n_idle + n_busy)) > 0.8
218+
219+
print(f"GitHub says we have {len(x86_64_runners)} x86_64 runners")
220+
print(f"Busy: {n_busy}, Idle: {n_idle}, Offline: {n_offline}")
221+
print(f"x86_64 runners too busy: {too_busy}")
222+
223+
return too_busy
224+
225+
161226
if __name__ == "__main__":
227+
228+
if x86_64_runners_too_busy():
229+
# this value is checked for in kernel-build.yml
230+
x86_64_builder = ['codebuild']
231+
else:
232+
x86_64_builder = DEFAULT_SELF_HOSTED_RUNNER_TAGS + [Arch.X86_64.value]
233+
162234
matrix = [
163235
BuildConfig(
164236
arch=Arch.X86_64,
165237
toolchain=Toolchain(compiler=Compiler.GCC, version=DEFAULT_LLVM_VERSION),
166238
run_veristat=True,
167239
parallel_tests=True,
240+
build_runs_on=x86_64_builder,
168241
),
169242
BuildConfig(
170243
arch=Arch.X86_64,
171244
toolchain=Toolchain(compiler=Compiler.LLVM, version=DEFAULT_LLVM_VERSION),
172245
build_release=True,
246+
build_runs_on=x86_64_builder,
173247
),
174248
BuildConfig(
175249
arch=Arch.X86_64,
176250
toolchain=Toolchain(compiler=Compiler.LLVM, version=18),
177251
build_release=True,
252+
build_runs_on=x86_64_builder,
178253
),
179254
BuildConfig(
180255
arch=Arch.AARCH64,
181256
toolchain=Toolchain(compiler=Compiler.GCC, version=DEFAULT_LLVM_VERSION),
257+
build_runs_on=DEFAULT_SELF_HOSTED_RUNNER_TAGS + [Arch.AARCH64.value],
182258
),
183-
# BuildConfig(
184-
# arch=Arch.AARCH64,
185-
# toolchain=Toolchain(
186-
# compiler=Compiler.LLVM,
187-
# version=DEFAULT_LLVM_VERSION
188-
# ),
189-
# ),
190259
BuildConfig(
191260
arch=Arch.S390X,
192261
toolchain=Toolchain(compiler=Compiler.GCC, version=DEFAULT_LLVM_VERSION),
262+
build_runs_on=x86_64_builder,
193263
),
194264
]
195265

.github/workflows/kernel-build.yml

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,12 @@ on:
4242
jobs:
4343
build:
4444
name: build for ${{ inputs.arch }} with ${{ inputs.toolchain_full }}${{ inputs.release && '-O2' || '' }}
45-
runs-on:
46-
- codebuild-gha-runner-poc-${{ github.run_id }}-${{ github.run_attempt }}
45+
runs-on: >-
46+
${{
47+
contains(fromJSON(inputs.runs_on), 'codebuild')
48+
&& format('codebuild-gha-runner-poc-{0}-{1}', github.run_id, github.run_attempt)
49+
|| inputs.runs_on
50+
}}
4751
env:
4852
ARTIFACTS_ARCHIVE: "vmlinux-${{ inputs.arch }}-${{ inputs.toolchain_full }}.tar.zst"
4953
BPF_NEXT_BASE_BRANCH: 'master'
@@ -54,6 +58,7 @@ jobs:
5458
KERNEL_ROOT: ${{ github.workspace }}
5559
REPO_PATH: ""
5660
REPO_ROOT: ${{ github.workspace }}
61+
RUNNER_TYPE: ${{ contains(fromJSON(inputs.runs_on), 'codebuild') && 'codebuild' || 'self-hosted' }}
5762
steps:
5863
- uses: actions/checkout@v4
5964
with:
@@ -98,12 +103,14 @@ jobs:
98103
llvm-version: ${{ inputs.llvm-version }}
99104
pahole: master
100105

101-
# We have to setup qemu+binfmt in order to enable cross-compation of selftests.
102-
# During selftests build, freshly built bpftool is executed.
103-
# On bare-metal and s390x hosts binfmt is pre-configured.
104-
- name: Set up Docker
106+
# We have to setup qemu+binfmt in order to enable cross-compation of selftests.
107+
# During selftests build, freshly built bpftool is executed.
108+
# On self-hosted bare-metal hosts binfmt is pre-configured.
109+
- if: ${{ env.RUNNER_TYPE == 'codebuild' }}
110+
name: Set up docker
105111
uses: docker/setup-docker-action@v4
106-
- name: Setup binfmt and qemu
112+
- if: ${{ env.RUNNER_TYPE == 'codebuild' }}
113+
name: Setup binfmt and qemu
107114
uses: docker/setup-qemu-action@v3
108115
with:
109116
image: tonistiigi/binfmt:qemu-v9.2.0

.github/workflows/test.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ jobs:
1919
# This could be somehow fixed long term by making this action/workflow re-usable and letting the called
2020
# specify what to run on.
2121
runs-on: ${{ github.repository_owner == 'kernel-patches' && 'x86_64' || 'ubuntu-latest' }}
22+
permissions:
23+
actions: read
2224
outputs:
2325
build-matrix: ${{ steps.set-matrix-impl.outputs.build_matrix }}
2426
steps:
@@ -27,6 +29,9 @@ jobs:
2729
sparse-checkout: |
2830
.github
2931
ci
32+
- name: Install python requests
33+
shell: bash
34+
run: pip3 install requests
3035
- id: set-matrix-impl
3136
run: |
3237
python3 .github/scripts/matrix.py

0 commit comments

Comments
 (0)