Skip to content

Commit eeb5244

Browse files
authored
Switch to custom fc repo; Improve build system (#3)
1 parent 052ef1a commit eeb5244

File tree

8 files changed

+264
-118
lines changed

8 files changed

+264
-118
lines changed

.github/workflows/build.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Build Firecracker Versions
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
version:
7+
required: true
8+
type: string
9+
hash:
10+
required: true
11+
type: string
12+
version_name:
13+
required: true
14+
type: string
15+
workflow_dispatch:
16+
17+
jobs:
18+
build:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v4
22+
- name: Build Firecracker ${{ inputs.version_name }}
23+
run: ./build.sh "${{ inputs.version }}" "${{ inputs.hash }}" "${{ inputs.version_name }}"
24+
- uses: actions/upload-artifact@v4
25+
with:
26+
name: firecracker-${{ inputs.version_name }}
27+
path: builds/
28+
retention-days: 7

.github/workflows/fc-versions.yml

Lines changed: 73 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2,105 +2,109 @@ name: FC Versions
22

33
on:
44
push:
5+
workflow_dispatch:
6+
7+
concurrency:
8+
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
9+
cancel-in-progress: true
510

611
permissions:
712
id-token: write
813
contents: write
914

1015
jobs:
11-
publish:
12-
name: Build Firecracker and upload
13-
runs-on: ubuntu-22.04
16+
prepare:
17+
runs-on: ubuntu-latest
18+
outputs:
19+
matrix: ${{ steps.set-matrix.outputs.matrix }}
1420
steps:
15-
- name: Checkout repository
16-
uses: actions/checkout@v4
21+
- uses: actions/checkout@v4
22+
- name: Parse versions and resolve hashes
23+
id: set-matrix
24+
run: |
25+
versions_json=$(./scripts/parse-versions-with-hash.sh firecracker_versions.txt)
26+
echo "matrix=$versions_json" >> $GITHUB_OUTPUT
1727
18-
- uses: actions/create-github-app-token@v1
19-
id: app-token
20-
with:
21-
app-id: ${{ vars.VERSION_BUMPER_APPID }}
22-
private-key: ${{ secrets.VERSION_BUMPER_SECRET }}
28+
build:
29+
needs: prepare
30+
uses: ./.github/workflows/build.yml
31+
strategy:
32+
fail-fast: true
33+
matrix:
34+
include: ${{ fromJson(needs.prepare.outputs.matrix) }}
35+
with:
36+
version: ${{ matrix.version }}
37+
hash: ${{ matrix.hash }}
38+
version_name: ${{ matrix.version_name }}
2339

24-
- name: Get the last release
25-
id: last_release
26-
continue-on-error: true
27-
uses: cardinalby/git-get-release-action@v1
40+
check-ci:
41+
needs: prepare
42+
runs-on: ubuntu-latest
43+
outputs:
44+
ci_passed: ${{ steps.ci-check.outputs.ci_passed }}
45+
steps:
46+
- uses: actions/checkout@v4
47+
- name: Check CI status
48+
id: ci-check
2849
env:
29-
GITHUB_TOKEN: ${{ github.token }}
30-
with:
31-
latest: true
32-
prerelease: false
33-
draft: false
50+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
51+
run: |
52+
output=$(./scripts/check-fc-ci.sh '${{ needs.prepare.outputs.matrix }}')
53+
echo "$output"
54+
ci_passed=$(echo "$output" | grep "^ci_passed=" | cut -d= -f2)
55+
echo "ci_passed=$ci_passed" >> $GITHUB_OUTPUT
3456
35-
- name: Get next version
36-
id: get-version
57+
publish:
58+
name: Collect and upload builds
59+
needs: [build, check-ci]
60+
runs-on: ubuntu-22.04
61+
steps:
62+
- uses: actions/checkout@v4
63+
with:
64+
fetch-depth: 0
65+
- uses: actions/download-artifact@v4
66+
with:
67+
path: builds
68+
pattern: firecracker-*
69+
merge-multiple: true
70+
- name: CI check result
3771
run: |
38-
if [ "${{ steps.last_release.outputs.tag_name }}" == "" ]; then
39-
echo "No previous release found, starting with v0.0.1"
40-
echo "version=v0.0.1" >> $GITHUB_OUTPUT
41-
else
42-
version=${{ steps.last_release.outputs.tag_name }}
43-
result=$(echo ${version} | awk -F. -v OFS=. '{$NF += 1 ; print}')
44-
echo "version=$result" >> $GITHUB_OUTPUT
72+
if [[ "${{ needs.check-ci.outputs.ci_passed }}" != "true" ]]; then
73+
echo "⚠️ CI checks did not pass - skipping GCS upload and release"
4574
fi
4675
47-
- name: Test next version
48-
run: echo "Next version is ${{ steps.get-version.outputs.version }}"
49-
5076
- name: Setup Service Account
77+
if: github.ref_name == 'main' && needs.check-ci.outputs.ci_passed == 'true'
5178
uses: google-github-actions/auth@v2
5279
with:
5380
project_id: ${{ secrets.GCP_PROJECT_ID }}
5481
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
5582

56-
- name: Build firecrackers
57-
run: sudo make build
58-
59-
- name: Upload firecrackers as artifact
60-
if: github.ref_name != 'main'
61-
uses: actions/upload-artifact@v4
62-
with:
63-
name: firecracker-${{ github.run_id }}
64-
path: ./builds
65-
retention-days: 7
66-
6783
- name: Upload firecrackers to GCS
68-
if: github.ref_name == 'main'
84+
if: github.ref_name == 'main' && needs.check-ci.outputs.ci_passed == 'true'
6985
uses: "google-github-actions/upload-cloud-storage@v1"
7086
with:
7187
path: "./builds"
7288
destination: ${{ vars.GCP_BUCKET_NAME }}/firecrackers
7389
gzip: false
7490
parent: false
7591

76-
- name: Create Git tag
77-
if: github.ref_name == 'main'
78-
run: |
79-
git config user.name "github-actions"
80-
git config user.email "[email protected]"
81-
git tag ${{ steps.get-version.outputs.version }}
82-
git push origin ${{ steps.get-version.outputs.version }}
92+
- name: Create releases
93+
if: github.ref_name == 'main' && needs.check-ci.outputs.ci_passed == 'true'
8394
env:
8495
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
85-
86-
87-
- name: Prepare release assets
88-
if: github.ref_name == 'main'
8996
run: |
90-
mkdir -p release-assets
97+
git config user.name "github-actions"
98+
git config user.email "[email protected]"
9199
for dir in ./builds/*/; do
92-
name=$(basename "$dir")
93-
cp "$dir/vmlinux.bin" "release-assets/${name}.bin"
100+
version_name=$(basename "$dir")
101+
if git rev-parse "refs/tags/$version_name" >/dev/null 2>&1 || gh release view "$version_name" >/dev/null 2>&1; then
102+
continue
103+
fi
104+
git tag "$version_name"
105+
git push origin "$version_name"
106+
gh release create "$version_name" \
107+
--title "Firecracker $version_name" \
108+
--notes "Firecracker build: $version_name" \
109+
"$dir/firecracker#${version_name}"
94110
done
95-
env:
96-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
97-
98-
- name: Upload Release Asset
99-
if: github.ref_name == 'main'
100-
uses: softprops/action-gh-release@v2
101-
env:
102-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
103-
with:
104-
name: Firecrackers ${{ steps.get-version.outputs.version }}
105-
tag_name: ${{ steps.get-version.outputs.version }}
106-
files: "./release-assets/*"

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ linux/
33
.env
44
.terraform
55
.tfplan
6+
.env

Makefile

Lines changed: 0 additions & 13 deletions
This file was deleted.

README.md

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,31 @@
1-
# fc-kernels
1+
# fc-versions
22

33
## Overview
44

5-
This project automates the building of custom Firecracker. It supports building specific firecracker versions and uploading the resulting binaries to a Google Cloud Storage (GCS) bucket.
5+
This project automates the building of custom Firecracker versions. It supports building specific firecracker versions and uploading the resulting binaries to a Google Cloud Storage (GCS) bucket.
66

77
## Prerequisites
88

99
- Linux environment (for building firecracker)
1010

11-
## Building Kernels
11+
## Building Firecrackers
1212

13-
1. **Configure firecracker versions:**
14-
- Edit `firecracker_versions.txt` to specify which kernel versions to build (one per line, e.g., `<last_tag-prelease>-<first-8-letters-of-the-specific-commit>`).
13+
The `firecracker_versions.txt` file specifies which versions to build:
1514

16-
2. **Build:**
17-
```sh
18-
make build
19-
# or directly
20-
./build.sh
21-
```
22-
The built kernels will be placed in `builds/vmlinux-<version>/vmlinux.bin`.
15+
- Edit `firecracker_versions.txt` to specify firecracker versions (one per line)
16+
- Versions can be tags (e.g., `v1.10.1`) or tag with shorthash (e.g., `v1.12.1_abcdef12`)
17+
- On every push, GitHub Actions will automatically:
18+
1. Parse versions from `firecracker_versions.txt` and resolve commit hashes
19+
2. Build each version in parallel
20+
3. Check CI status for each version
21+
4. Upload successful builds to GCS and create GitHub releases (on main branch)
2322

24-
## Development Workflow
25-
- On every push, GitHub Actions will automatically build the kernels and save it as an artifact.
23+
## Scripts
24+
25+
- `build.sh <version> <hash> <version_name>` - Builds a single Firecracker version
26+
- `scripts/parse-versions-with-hash.sh` - Parses versions and resolves commit hashes
27+
- `scripts/check-fc-ci.sh <versions_json>` - Checks CI status for parsed versions
2628

2729
## License
2830

29-
This project is licensed under the Apache License 2.0. See [LICENSE](LICENSE) for details.
31+
This project is licensed under the Apache License 2.0. See [LICENSE](LICENSE) for details.

build.sh

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,36 @@
22

33
set -euo pipefail
44

5-
function build_version {
6-
local version=$1
7-
echo "Starting build for Firecracker commit: $version"
5+
FIRECRACKER_REPO_URL="https://github.com/e2b-dev/firecracker.git"
86

9-
echo "Checking out repo for Firecracker at commit: $version"
10-
git checkout "${version}"
7+
if [[ $# -lt 3 ]]; then
8+
echo "Usage: $0 <version> <hash> <version_name>" >&2
9+
exit 1
10+
fi
1111

12-
# The format will be: latest_tag_latest_commit_hash — v1.7.0-dev_g8bb88311
13-
version_name=$(git describe --tags --abbrev=0 $(git rev-parse HEAD))_$(git rev-parse --short HEAD)
14-
echo "Version name: $version_name"
12+
version="$1"
13+
fullhash="$2"
14+
version_name="$3"
1515

16-
echo "Building Firecracker version: $version_name"
17-
tools/devtool -y build --release
16+
git clone $FIRECRACKER_REPO_URL firecracker
17+
cd firecracker
1818

19-
echo "Copying finished build to builds directory"
20-
mkdir -p "../builds/${version_name}"
21-
cp build/cargo_target/x86_64-unknown-linux-musl/release/firecracker "../builds/${version_name}/firecracker"
22-
}
19+
if [[ "$version" =~ ^([^_]+)_([0-9a-fA-F]+)$ ]]; then
20+
tag="${BASH_REMATCH[1]}"
21+
git checkout "$tag"
22+
if ! git merge-base --is-ancestor "$tag" "$fullhash"; then
23+
echo "Error: shorthash is not a descendant of tag $tag" >&2
24+
exit 1
25+
fi
26+
git checkout "$fullhash"
27+
else
28+
git checkout "$fullhash"
29+
fi
2330

24-
echo "Cloning the Firecracker repository"
25-
git clone https://github.com/firecracker-microvm/firecracker.git firecracker
26-
cd firecracker
31+
tools/devtool -y build --release -- --bin firecracker
2732

28-
grep -v '^ *#' <../firecracker_versions.txt | while IFS= read -r version; do
29-
build_version "$version"
30-
done
33+
mkdir -p "../builds/${version_name}"
34+
cp build/cargo_target/x86_64-unknown-linux-musl/release/firecracker "../builds/${version_name}/firecracker"
3135

3236
cd ..
33-
rm -rf firecracker
37+
rm -rf firecracker

scripts/check-fc-ci.sh

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
FIRECRACKER_REPO_API="e2b-dev/firecracker"
6+
7+
if [[ $# -lt 1 ]]; then
8+
echo "Usage: $0 <versions_json>" >&2
9+
exit 1
10+
fi
11+
12+
versions_json="$1"
13+
14+
all_passed=true
15+
failed_versions=""
16+
17+
while IFS='|' read -r version commit_hash version_name; do
18+
status_response=$(gh api "/repos/${FIRECRACKER_REPO_API}/commits/${commit_hash}/status" 2>/dev/null || echo '{"state":"unknown","total_count":0}')
19+
status=$(echo "$status_response" | jq -r '.state')
20+
status_count=$(echo "$status_response" | jq -r '.total_count')
21+
22+
check_response=$(gh api "/repos/${FIRECRACKER_REPO_API}/commits/${commit_hash}/check-runs" 2>/dev/null || echo '{"total_count":0}')
23+
check_count=$(echo "$check_response" | jq -r '.total_count')
24+
check_conclusion=$(echo "$check_response" | jq -r '
25+
if .total_count == 0 then "no_checks"
26+
elif ([.check_runs[].status] | any(. == "in_progress" or . == "queued")) then "pending"
27+
elif ([.check_runs[].conclusion] | any(. == "failure" or . == "cancelled" or . == "timed_out")) then "failure"
28+
elif ([.check_runs[].conclusion] | all(. == "success" or . == "skipped" or . == "neutral")) then "success"
29+
else "unknown"
30+
end
31+
')
32+
33+
if [[ "$status" == "failure" ]] || [[ "$check_conclusion" == "failure" ]]; then
34+
echo " ❌ CI failed for $version_name"
35+
all_passed=false
36+
failed_versions="${failed_versions}${version_name} "
37+
elif [[ "$check_conclusion" == "pending" ]] || ([[ "$status" == "pending" ]] && [[ "$status_count" -gt 0 ]]); then
38+
echo " ⏳ CI still running for $version_name"
39+
all_passed=false
40+
failed_versions="${failed_versions}${version_name}(pending) "
41+
elif [[ "$status" == "unknown" ]] && [[ "$check_conclusion" == "unknown" ]]; then
42+
echo " ⚠️ Could not verify CI status for $version_name (API error)"
43+
all_passed=false
44+
failed_versions="${failed_versions}${version_name}(unknown) "
45+
elif [[ "$status" == "success" ]] || [[ "$check_conclusion" == "success" ]]; then
46+
echo " ✅ CI passed for $version_name"
47+
elif [[ "$status_count" -eq 0 ]] && [[ "$check_count" -eq 0 ]]; then
48+
echo " ℹ️ No CI checks found for $version_name (assuming OK)"
49+
elif [[ "$status" == "pending" ]] && [[ "$status_count" -eq 0 ]] && [[ "$check_conclusion" == "no_checks" ]]; then
50+
echo " ℹ️ No CI checks found for $version_name (assuming OK)"
51+
else
52+
echo " ⚠️ Unexpected CI state for $version_name: status=$status, check_conclusion=$check_conclusion"
53+
all_passed=false
54+
failed_versions="${failed_versions}${version_name}(unexpected) "
55+
fi
56+
done < <(echo "$versions_json" | jq -r '.[] | "\(.version)|\(.hash)|\(.version_name)"')
57+
58+
echo ""
59+
[[ "$all_passed" == "true" ]] && echo "ci_passed=true" || echo "ci_passed=false"

0 commit comments

Comments
 (0)