Skip to content

Commit 3e23fd1

Browse files
committed
test(volumes): Add K8s based test for block volumes
Add a test based on the existing K8s test (kind) which sets the default devmapper to blockfile, installs longhorn and deploys a Linux container over Qemu and Firecracker to check if block-based mounts were passed and mounted correctly inside the VM. Signed-off-by: Charalampos Mainas <cmainas@nubificus.co.uk>
1 parent 1ea3838 commit 3e23fd1

3 files changed

Lines changed: 206 additions & 185 deletions

File tree

.github/workflows/ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,14 @@ jobs:
7979
solo5_version: 'v0.9.3'
8080
secrets: inherit
8181

82-
kind_test:
82+
kind_overlayfs-test:
8383
if: ${{ inputs.skip-build != 'yes' }}
8484
needs: [build, unit_test]
85-
name: Kubernetes test
86-
uses: ./.github/workflows/kind_test.yml
85+
name: Kubernetes test with overlayfs
86+
uses: ./.github/workflows/k8s_overlayfs_test.yml
8787
with:
8888
ref: ${{ inputs.ref }}
8989
firecracker_version: 'v1.7.0'
9090
solo5_version: 'v0.9.3'
91-
runc_version: '1.3.0'
91+
kind_version: '0.29.0'
9292
secrets: inherit

.github/workflows/kind_test.yml

Lines changed: 84 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,20 @@ on:
2020
solo5_version:
2121
type: string
2222
required: true
23-
runc_version:
23+
kind_version:
2424
required: true
2525
type: string
2626
secrets:
2727
GIT_CLONE_PAT:
2828
required: false
2929
workflow_dispatch:
30+
3031
permissions:
3132
contents: read
3233

3334
jobs:
34-
test:
35-
name: Kubernetes test
35+
setup:
36+
name: Setup Kubernetes using kind and install urunc
3637
runs-on: ${{ matrix.runner }}
3738
strategy:
3839
matrix:
@@ -43,6 +44,27 @@ jobs:
4344
runner: ubuntu-22.04-arm
4445
fail-fast: false
4546
steps:
47+
48+
- name: Validate inputs (prevent command injection)
49+
shell: bash
50+
env:
51+
FIRECRACKER_VERSION: ${{ inputs.firecracker_version }}
52+
SOLO5_VERSION: ${{ inputs.solo5_version }}
53+
KIND_VERSION: ${{ inputs.kind_version }}
54+
run: |
55+
SAFE_FIRECRACKER_VERSION="$FIRECRACKER_VERSION"
56+
SAFE_SOLO5_VERSION="$SOLO5_VERSION"
57+
SAFE_KIND_VERSION="$KIND_VERSION"
58+
59+
for var in SAFE_FIRECRACKER_VERSION SAFE_SOLO5_VERSION SAFE_KIND_VERSION; do
60+
value="${!var}"
61+
if ! [[ "$value" =~ ^v?[0-9]+\.[0-9]+(\.[0-9]+)?$ ]]; then
62+
echo "Invalid format for $var: $value"
63+
exit 1
64+
fi
65+
done
66+
67+
steps:
4668
- name: Harden the runner (Audit all outbound calls)
4769
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
4870
with:
@@ -51,17 +73,17 @@ jobs:
5173
- name: Checkout repository
5274
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
5375

54-
- name: Install base dependencies
55-
run: |
56-
sudo apt-get update
57-
sudo apt-get install -y git wget build-essential libseccomp-dev pkg-config bc make
5876
- name: Install kind
77+
env:
78+
KIND_VERSION: ${{ inputs.kind_version }}
79+
run: |
5980
run: |
6081
ARCH=$(uname -m)
82+
SAFE_KIND="${KIND_VERSION}"
6183
if [ "$ARCH" = "x86_64" ]; then
62-
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.29.0/kind-linux-amd64
84+
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v${SAFE_KIND}/kind-linux-amd64
6385
elif [ "$ARCH" = "aarch64" ]; then
64-
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.29.0/kind-linux-arm64
86+
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v${SAFE_KIND}/kind-linux-arm64
6587
else
6688
echo "Unsupported architecture: $ARCH"
6789
exit 1
@@ -97,32 +119,46 @@ jobs:
97119
- name: Create kind cluster
98120
run: |
99121
sudo kind create cluster --name urunc-test --config kind-config.yaml
100-
- name: Install dependencies inside kind node
122+
123+
- name: Install kubectl
101124
run: |
102-
docker exec urunc-test-control-plane apt-get update
103-
docker exec urunc-test-control-plane apt-get install -y git wget build-essential libseccomp-dev pkg-config bc
125+
ARCH=$(uname -m)
126+
if [ "$ARCH" = "x86_64" ]; then
127+
KUBECTL_ARCH="amd64"
128+
elif [ "$ARCH" = "aarch64" ]; then
129+
KUBECTL_ARCH="arm64"
130+
else
131+
echo "Unsupported architecture: $ARCH"
132+
exit 1
133+
fi
134+
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/${KUBECTL_ARCH}/kubectl"
135+
chmod +x kubectl
136+
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
104137
105-
- name: Install runc inside kind node
138+
- name: Set up kubectl config
106139
run: |
107-
docker exec urunc-test-control-plane bash -c '
108-
if ! which runc; then
109-
wget -q https://github.com/opencontainers/runc/releases/download/v${{ inputs.runc_version }}/runc.$(dpkg --print-architecture)
110-
install -m 755 runc.$(dpkg --print-architecture) /usr/local/sbin/runc
111-
rm -f ./runc.$(dpkg --print-architecture)
112-
fi
113-
'
140+
mkdir -p ~/.kube
141+
kind get kubeconfig --name urunc-test > ~/.kube/config
142+
chmod 600 ~/.kube/config
143+
export KUBECONFIG=~/.kube/config
144+
kubectl config use-context kind-urunc-test
145+
kubectl wait --for=condition=Ready nodes --all --timeout=200s
146+
kubectl cluster-info
114147
115-
- name: Configure containerd inside kind node
148+
- name: Create RuntimeClass
116149
run: |
117-
docker exec urunc-test-control-plane bash -c '
118-
systemctl status containerd || containerd &
119-
mkdir -p /etc/containerd
120-
containerd config default > /etc/containerd/config.toml
121-
'
122-
- name: Set snapshotter to overlayfs
150+
cat <<EOF | kubectl apply -f -
151+
kind: RuntimeClass
152+
apiVersion: node.k8s.io/v1
153+
metadata:
154+
name: urunc
155+
handler: urunc
156+
EOF
157+
158+
- name: Install base dependencies inside kind
123159
run: |
124-
docker exec urunc-test-control-plane bash -c \
125-
'sed -i "s/snapshotter = \"devmapper\"/snapshotter = \"overlayfs\"/g" /etc/containerd/config.toml'
160+
docker exec urunc-test-control-plane apt-get update
161+
docker exec urunc-test-control-plane apt-get install -y git wget build-essential libseccomp-dev pkg-config bc
126162
127163
- name: Download urunc artifact
128164
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
@@ -136,9 +172,6 @@ jobs:
136172
name: containerd-shim-urunc-v2_${{ matrix.arch }}-${{ github.run_id }}
137173
path: ./artifacts
138174

139-
- name: List artifacts dir
140-
run: ls -lR ./artifacts
141-
142175
- name: Copy and install urunc binaries
143176
run: |
144177
docker exec urunc-test-control-plane mkdir -p /urunc-temp
@@ -165,23 +198,27 @@ jobs:
165198
run: |
166199
docker exec urunc-test-control-plane apt-get install -y qemu-system
167200
168-
169201
- name: Install Firecracker inside kind node
202+
if: matrix.arch == 'amd64'
203+
env:
204+
FC_VERSION: ${{ inputs.firecracker_version }}
170205
run: |
171-
FC_VERSION="${{ inputs.firecracker_version }}"
206+
SAFE_FC="${FC_VERSION}"
172207
docker exec urunc-test-control-plane bash -c '
173208
ARCH=$(uname -m)
174-
echo "Downloading Firecracker version: '"$FC_VERSION"'"
175-
curl -fsSL https://github.com/firecracker-microvm/firecracker/releases/download/'"$FC_VERSION"'/firecracker-'"$FC_VERSION"'-${ARCH}.tgz | tar -xz
176-
install -m 755 release-'"$FC_VERSION"'-${ARCH}/firecracker-'"$FC_VERSION"'-${ARCH} /usr/local/bin/firecracker
209+
echo "Downloading Firecracker version: '"$SAVE_FC"'"
210+
curl -fsSL https://github.com/firecracker-microvm/firecracker/releases/download/'"$SAFE_FC"'/firecracker-'"$SAFE_FC"'-${ARCH}.tgz | tar -xz
211+
install -m 755 release-'"$SAFE_FC"'-${ARCH}/firecracker-'"$SAFE_FC"'-${ARCH} /usr/local/bin/firecracker
177212
firecracker --version
178213
'
179214
180215
- name: Install Solo5 inside kind node
216+
env:
217+
SOLO5_VERSION: ${{ inputs.solo5_version }}
181218
run: |
182-
SOLO5_VERSION="${{ inputs.solo5_version }}"
219+
SAFE_SOLO5="${SOLO5_VERSION}"
183220
docker exec urunc-test-control-plane bash -c '
184-
git clone -b "'"$SOLO5_VERSION"'" https://github.com/Solo5/solo5.git
221+
git clone -b "'"$SAFE_SOLO5"'" https://github.com/Solo5/solo5.git
185222
cd solo5
186223
./configure.sh && make -j$(nproc)
187224
install -m 755 tenders/hvt/solo5-hvt /usr/local/bin/
@@ -191,153 +228,19 @@ jobs:
191228
solo5-hvt --version
192229
'
193230
231+
- name: Configure containerd inside kind node
232+
run: |
233+
docker exec urunc-test-control-plane bash -c '
234+
systemctl status containerd || containerd &
235+
mkdir -p /etc/containerd
236+
containerd config default > /etc/containerd/config.toml
237+
'
238+
194239
- name: Add urunc to containerd config
195240
run: |
196241
docker exec urunc-test-control-plane bash -c "cat <<'EOF' >> /etc/containerd/config.toml
197242
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.urunc]
198243
runtime_type = \"io.containerd.urunc.v2\"
199244
container_annotations = [\"com.urunc.unikernel.*\"]
200245
pod_annotations = [\"com.urunc.unikernel.*\"]
201-
snapshotter = \"overlayfs\"
202246
EOF"
203-
204-
205-
- name: Restart containerd inside urunc-test-control-plane
206-
run: |
207-
docker exec urunc-test-control-plane bash -c "
208-
systemctl stop containerd
209-
rm -f /var/lib/containerd/io.containerd.metadata.v1.bolt/meta.db
210-
systemctl restart containerd
211-
sleep 10
212-
systemctl status containerd
213-
"
214-
- name: Verify urunc installation
215-
run: |
216-
docker exec urunc-test-control-plane bash -c '
217-
ls -la /usr/local/bin/urunc*
218-
ls -la /usr/local/bin/containerd-shim-urunc-v2*
219-
containerd --version
220-
'
221-
222-
- name: Install kubectl
223-
run: |
224-
ARCH=$(uname -m)
225-
if [ "$ARCH" = "x86_64" ]; then
226-
KUBECTL_ARCH="amd64"
227-
elif [ "$ARCH" = "aarch64" ]; then
228-
KUBECTL_ARCH="arm64"
229-
else
230-
echo "Unsupported architecture: $ARCH"
231-
exit 1
232-
fi
233-
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/${KUBECTL_ARCH}/kubectl"
234-
chmod +x kubectl
235-
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
236-
237-
- name: Set up kubectl config
238-
run: |
239-
mkdir -p ~/.kube
240-
kind get kubeconfig --name urunc-test > ~/.kube/config
241-
chmod 600 ~/.kube/config
242-
export KUBECONFIG=~/.kube/config
243-
kubectl config use-context kind-urunc-test
244-
kubectl wait --for=condition=Ready nodes --all --timeout=200s
245-
kubectl cluster-info
246-
247-
- name: Create RuntimeClass
248-
run: |
249-
cat <<EOF | kubectl apply -f -
250-
kind: RuntimeClass
251-
apiVersion: node.k8s.io/v1
252-
metadata:
253-
name: urunc
254-
handler: urunc
255-
EOF
256-
- name: Deploy hello world unikernel (amd64)
257-
if: matrix.arch == 'amd64'
258-
run: |
259-
cat <<EOF | kubectl apply -f -
260-
apiVersion: v1
261-
kind: Pod
262-
metadata:
263-
name: hello-spt-rumprun-block
264-
labels:
265-
run: hello-spt-rumprun-block
266-
spec:
267-
runtimeClassName: urunc
268-
restartPolicy: Never
269-
containers:
270-
- name: hello-spt-rumprun-block
271-
image: harbor.nbfc.io/nubificus/urunc/hello-spt-rumprun-block:latest
272-
imagePullPolicy: Always
273-
ports:
274-
- containerPort: 80
275-
protocol: TCP
276-
resources:
277-
requests:
278-
cpu: 10m
279-
EOF
280-
281-
- name: Verify hello-spt-rumprun-block deployment
282-
if: matrix.arch == 'amd64'
283-
run: |
284-
kubectl wait --for=condition=Succeeded pod/hello-spt-rumprun-block --timeout=180s || true
285-
kubectl logs hello-spt-rumprun-block | tee /tmp/logs.txt
286-
if ! grep "Hello world" /tmp/logs.txt; then
287-
echo "=== LOGS ==="
288-
cat /tmp/logs.txt
289-
exit 1
290-
fi
291-
kubectl describe pod hello-spt-rumprun-block || true
292-
293-
294-
- name: Deploy hello world unikernel (arm64)
295-
if: matrix.arch == 'arm64'
296-
run: |
297-
cat <<EOF | kubectl apply -f -
298-
apiVersion: v1
299-
kind: Pod
300-
metadata:
301-
name: hello-spt-rumprun-block
302-
labels:
303-
run: hello-spt-rumprun-block
304-
spec:
305-
runtimeClassName: urunc
306-
restartPolicy: Never
307-
containers:
308-
- name: hello-spt-rumprun-block
309-
image: harbor.nbfc.io/nubificus/urunc/hello-spt-rumprun-block:latest
310-
imagePullPolicy: Always
311-
ports:
312-
- containerPort: 80
313-
protocol: TCP
314-
resources:
315-
requests:
316-
cpu: 10m
317-
EOF
318-
319-
- name: Verify hello world deployment (arm64)
320-
if: matrix.arch == 'arm64'
321-
run: |
322-
kubectl wait --for=condition=Succeeded pod/hello-spt-rumprun-block --timeout=180s || true
323-
kubectl logs hello-spt-rumprun-block | tee /tmp/logs.txt
324-
grep "Hello world" /tmp/logs.txt
325-
kubectl describe pod hello-spt-rumprun-block || true
326-
327-
- name: Debug pod failure
328-
if: failure()
329-
run: |
330-
echo "=== Debugging failure ==="
331-
echo "=== Describe Pod ==="
332-
if [ "${{ matrix.arch }}" = "amd64" ]; then
333-
echo "=== Debugging hello-spt-rumprun-block (amd64) ==="
334-
kubectl describe pod hello-spt-rumprun-block || true
335-
echo "=== Logs ==="
336-
kubectl logs hello-spt-rumprun-block || true
337-
else
338-
echo "=== Debugging hello-spt-rumprun-block (arm64) ==="
339-
kubectl describe pod hello-spt-rumprun-block || true
340-
echo "=== Logs ==="
341-
kubectl logs hello-spt-rumprun-block || true
342-
fi
343-

0 commit comments

Comments
 (0)