Skip to content

Commit cc2ed82

Browse files
committed
Implement build-and-test Github Actions CI using AWS spot instances
1 parent 2ba5d7e commit cc2ed82

File tree

4 files changed

+182
-0
lines changed

4 files changed

+182
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name: Build And Test (x86-64)
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
build-and-test-x86-64:
7+
uses: rr-debugger/rr/.github/workflows/build-and-test.yml@main
8+
with:
9+
architecture: x86_64
10+
instance_type: c5.9xlarge

.github/workflows/build-and-test.yml

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
name: Build And Test
2+
3+
# Based on
4+
# https://blog.devgenius.io/create-register-and-terminate-ec2-spot-instances-via-github-actions-aef473b8a00f
5+
6+
on:
7+
workflow_call:
8+
inputs:
9+
architecture:
10+
required: true
11+
type: string
12+
instance_type:
13+
required: true
14+
type: string
15+
16+
env:
17+
EC2_SUBNET_ID: subnet-0a01360e53f586ff8 # rr-testing
18+
EC2_SECURITY_GROUP_ID: sg-072c6deccd49e89c8 # rr-testing
19+
EC2_SPOT_INSTANCE_PRICE: "1.00"
20+
AWS_ROLE_ARN: arn:aws:iam::019859450731:role/SpotInstanceManager
21+
AWS_REGION: us-east-2
22+
RUNNER_VERSION: "2.316.1"
23+
24+
jobs:
25+
start-runner:
26+
name: Start Runner
27+
permissions:
28+
id-token: write
29+
runs-on: ubuntu-latest
30+
outputs:
31+
EC2_HOST: ${{ env.EC2_HOST }}
32+
EC2_INSTANCE_ID: ${{ env.EC2_INSTANCE_ID }}
33+
steps:
34+
- name: "Run :: Configure AWS credentials"
35+
uses: aws-actions/configure-aws-credentials@v4
36+
with:
37+
role-to-assume: ${{ env.AWS_ROLE_ARN }}
38+
role-session-name: pipeline-assume-role-session
39+
aws-region: ${{ env.AWS_REGION }}
40+
41+
- name: "Run :: Create and register AWS spot instance"
42+
run: |2-
43+
# Get GitHub Actions runner registration token
44+
response=$(curl -s -X POST -H 'Accept: application/vnd.github+json' -H 'Authorization: Bearer ${{ env.pat }}' -H 'X-GitHub-Api-Version: 2022-11-28' https://api.github.com/repos/${GITHUB_REPOSITORY}/actions/runners/registration-token)
45+
RUNNER_REG_TOKEN=$(echo "$response" | jq -r .token)
46+
47+
if [ $RUNNER_REG_TOKEN != "null" ]; then
48+
USER_DATA="#!/bin/bash
49+
50+
# Make sure the VM doesn't run for more than an hour
51+
shutdown +60
52+
53+
apt-get update -y
54+
apt-get dist-upgrade -f -y
55+
56+
# Install GitHub Actions runner
57+
mkdir /home/ubuntu/actions-runner && cd /home/ubuntu/actions-runner
58+
curl -o actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz -L https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz
59+
echo \"Github Runner Installed\"
60+
# Extract the installer
61+
tar xzf ./actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz
62+
echo \"Github Runner Installer Extracted\"
63+
64+
# Run GitHub Actions runner configuration
65+
yes '' | ./config.sh --url https://github.com/${GITHUB_REPOSITORY} --token $RUNNER_REG_TOKEN --labels ${{ inputs.architecture }}_${{github.sha}}
66+
echo \"Github Runner Configured\"
67+
68+
# Run GitHub Actions runner
69+
yes '' | ./run.sh
70+
echo \"Github Runner UP!\"
71+
"
72+
73+
IMAGE_ID=$(aws ec2 describe-images --owners 099720109477 --filters 'Name=architecture,Values=${{ inputs.architecture }}' 'Name=name,Values=ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-*' | jq .Images[0].ImageId)
74+
echo "IMAGE_ID :: $IMAGE_ID"
75+
76+
ENCODED_USER_DATA=$(echo -n "$USER_DATA" | sed 's/^[[:space:]]*//' | base64 -w 0)
77+
echo "ENCODED_USER_DATA :: $ENCODED_USER_DATA"
78+
LAUNCH_SPECIFICATION_JSON={\"InstanceInitiatedShutdownBehavior\":\"terminate\",\"ImageId\":$IMAGE_ID,\"InstanceType\":\"${{ inputs.instance_type }}\",\"KeyName\":\"QWENKey\",\"SecurityGroupIds\":[\"${{ env.EC2_SECURITY_GROUP_ID }}\"],\"SubnetId\":\"${{ env.EC2_SUBNET_ID }}\",\"UserData\":\"$ENCODED_USER_DATA\"}
79+
echo "LAUNCH_SPECIFICATION_JSON :: $LAUNCH_SPECIFICATION_JSON"
80+
81+
REQUEST_ID=$(aws ec2 request-spot-instances --spot-price "${{ env.EC2_SPOT_INSTANCE_PRICE }}" --instance-count 1 --type "one-time" --launch-specification $LAUNCH_SPECIFICATION_JSON --query 'SpotInstanceRequests[0].SpotInstanceRequestId' --output text)
82+
aws ec2 wait spot-instance-request-fulfilled --spot-instance-request-ids $REQUEST_ID
83+
INSTANCE_ID=$(aws ec2 describe-spot-instance-requests --spot-instance-request-ids $REQUEST_ID --query 'SpotInstanceRequests[*].InstanceId' --output text)
84+
HOSTNAME=$(aws ec2 describe-instances --instance-ids $INSTANCE_ID --query 'Reservations[0].Instances[0].PublicDnsName' --output text)
85+
86+
echo "EC2_HOST=$HOSTNAME" >> $GITHUB_ENV
87+
echo "EC2_INSTANCE_ID=$INSTANCE_ID" >> $GITHUB_ENV
88+
else
89+
echo "$response"
90+
exit 1
91+
fi
92+
93+
build-and-test:
94+
name: Build And Test
95+
permissions:
96+
contents: read
97+
runs-on:
98+
labels: ${{ inputs.architecture }}_${{github.sha}}
99+
needs:
100+
- start-runner
101+
steps:
102+
- name: Start
103+
run: |2-
104+
echo " Starting GitHub Action!" &&
105+
echo "STEPS_CAN_PROCEED=true" >> $GITHUB_ENV
106+
107+
- name: "Run :: Checkout repository"
108+
uses: actions/checkout@v2
109+
110+
- name: "Run :: Build"
111+
run: ./scripts/github-actions-build.sh
112+
113+
- name: "Run :: Test"
114+
run: ./scripts/github-actions-test.sh
115+
116+
stop-runner:
117+
name: Stop Runner
118+
permissions:
119+
id-token: write
120+
runs-on: ubuntu-latest
121+
needs:
122+
- start-runner
123+
- compose-job
124+
if: ${{ always() }}
125+
steps:
126+
- name: "Run :: Configure AWS credentials"
127+
uses: aws-actions/configure-aws-credentials@v4
128+
with:
129+
role-to-assume: ${{ env.AWS_ROLE_ARN }}
130+
role-session-name: pipeline-assume-role-session
131+
aws-region: ${{ env.AWS_REGION }}
132+
133+
- name: "Run :: Terminate and unregister AWS spot instance"
134+
run: |2-
135+
aws ec2 terminate-instances --instance-ids ${{ needs.start-runner.outputs.EC2_INSTANCE_ID }}
136+
gh_runner_label=${{ needs.start-runner.outputs.EC2_RUNNER }}
137+
response=$(curl -X GET https://api.github.com/repos/${GITHUB_REPOSITORY}/actions/runners -H 'Authorization: Bearer ${{ env.pat }}'
138+
)
139+
offline_runners=$(echo "$response" | jq '.runners | map(select((.labels? | any(.name == "${{ inputs.architecture }}_${{github.sha}}"))))')
140+
echo "Offline Runners :: $offline_runners"
141+
142+
echo "Attempting to remove offline runners..."
143+
for runner in $(echo "$offline_runners" | jq -r '.[].id'); do
144+
echo "Triggering action for runner ID: $runner"
145+
curl -X DELETE https://api.github.com/repos/${GITHUB_REPOSITORY}/actions/runners/$runner -H 'Authorization: Bearer ${{ env.pat }}'
146+
done

scripts/github-actions-build.sh

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/bin/bash
2+
3+
set +x # echo commands
4+
set -e # default to exiting on error"
5+
6+
uname -a
7+
8+
sudo apt-get install -y rpm ccache cmake g++ pkg-config zlib1g-dev git python-dev-is-python3 libacl1-dev ninja-build manpages-dev capnproto libcapnp-dev gdb lldb python3-pexpect
9+
10+
mkdir obj
11+
cd obj
12+
cmake -G Ninja -DCMAKE_BUILD_TYPE=DEBUG -Dstaticlibs=FALSE ..
13+
ninja

scripts/github-actions-test.sh

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/bin/bash
2+
3+
set +x # echo commands
4+
set -e # default to exiting on error"
5+
6+
# Enable perf events for rr
7+
echo 0 | sudo tee /proc/sys/kernel/perf_event_paranoid
8+
# Enable ptrace-attach to any process. This lets us get more data when tests fail.
9+
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
10+
# Disable AppArmor restrictions on user namespaces, which our tests need to use
11+
(echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns) || true
12+
let halfproc=`nproc`/2
13+
ctest -j$halfproc --verbose

0 commit comments

Comments
 (0)