Skip to content

Commit 7397277

Browse files
manninglucasgvisor-bot
authored andcommitted
Create gcsfuse test image.
This will provide a reliable way to evaluate gVisor's compatibility with GCSFuse features. We can't add this as an automated test because it requires gcloud creds. PiperOrigin-RevId: 896017311
1 parent 140f64c commit 7397277

4 files changed

Lines changed: 335 additions & 0 deletions

File tree

images/fuse/gcs/Dockerfile

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
FROM golang:1.24-bullseye AS builder
2+
3+
# Install gcsfuse from GitHub
4+
RUN go install github.com/googlecloudplatform/gcsfuse/v2@latest
5+
6+
FROM debian:bullseye-slim
7+
8+
RUN apt-get update && apt-get install -y \
9+
fuse \
10+
curl \
11+
ca-certificates \
12+
python3 \
13+
psmisc \
14+
&& rm -rf /var/lib/apt/lists/*
15+
16+
# Copy gcsfuse from builder
17+
COPY --from=builder /go/bin/gcsfuse /usr/local/bin/gcsfuse
18+
19+
# Copy the gcsfuse test script
20+
COPY gcsfuse_test.sh /usr/local/bin/gcsfuse_test.sh
21+
RUN chmod +x /usr/local/bin/gcsfuse_test.sh
22+
23+
# Default to running gcsfuse test
24+
ENTRYPOINT ["/usr/local/bin/gcsfuse_test.sh"]

images/fuse/gcs/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# GCSFUSE gVisor Compatibility Test
2+
3+
This directory contains a test suite for `gcsfuse` compatibility with gVisor.
4+
5+
To run the test, simply execute the `run_test.sh` script:
6+
7+
```bash
8+
./images/fuse/gcs/run_test.sh
9+
```
10+
11+
The script will:
12+
13+
1. Check for gVisor (runsc) and gcloud credentials.
14+
2. Create a temporary GCS bucket.
15+
3. Build the test Docker image.
16+
4. Run the test container using gVisor.
17+
5. Clean up the temporary GCS bucket.
18+
19+
For more details on the manual steps, refer to the script's source code.

images/fuse/gcs/gcsfuse_test.sh

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
#!/bin/bash
2+
# Copyright 2026 The gVisor Authors.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
set -e
17+
18+
# Configurable bucket name via environment variable or argument
19+
BUCKET=${GCS_BUCKET:-gvisor-fuse-test-bucket}
20+
MOUNT_DIR="/mnt/gcs"
21+
22+
mkdir -p "$MOUNT_DIR"
23+
24+
echo "--- GCSFUSE COMPATIBILITY TEST ---"
25+
echo "Bucket: gs://$BUCKET"
26+
echo "Mount point: $MOUNT_DIR"
27+
28+
# gcsfuse flags for testing
29+
# --implicit-dirs is needed for flat buckets to show simulated folders
30+
echo "Mounting..."
31+
32+
gcsfuse -implicit-dirs --log-severity TRACE --foreground "$BUCKET" "$MOUNT_DIR" &
33+
GCSFUSE_PID=$!
34+
35+
# Wait for mount to appear
36+
echo "Waiting for mount..."
37+
SUCCESS=0
38+
for i in {1..20}; do
39+
if mountpoint -q "$MOUNT_DIR"; then
40+
echo "Mounted successfully!"
41+
SUCCESS=1
42+
break
43+
fi
44+
if ! kill -0 "$GCSFUSE_PID" 2>/dev/null; then
45+
echo "gcsfuse process died early."
46+
break
47+
fi
48+
sleep 1
49+
done
50+
51+
if [[ "$SUCCESS" -ne 1 ]]; then
52+
echo "[FAIL] gcsfuse failed to mount the bucket."
53+
exit 1
54+
fi
55+
56+
echo "Running supported file operations..."
57+
58+
TEST_FILE="$MOUNT_DIR/gvisor_test_$(date +%s)"
59+
TEST_DIR="$MOUNT_DIR/testdir_$(date +%s)"
60+
61+
# 1. Directory Operations: mkdir / rmdir / readdir
62+
echo "Testing mkdir..."
63+
if mkdir "$TEST_DIR"; then
64+
echo "[OK] Mkdir"
65+
else
66+
echo "[FAIL] Mkdir"
67+
fi
68+
69+
echo "Testing readdir (ls)..."
70+
if ls "$MOUNT_DIR" | grep -q "testdir_"; then
71+
echo "[OK] Readdir"
72+
else
73+
echo "[FAIL] Readdir"
74+
fi
75+
76+
# 2. File Creation and Basic I/O: creat / open / write / read
77+
echo "Testing write..."
78+
CONTENT="gvisor compatibility test $(date)"
79+
if echo -n "$CONTENT" > "$TEST_FILE"; then
80+
echo "[OK] Write"
81+
else
82+
echo "[FAIL] Write"
83+
fi
84+
85+
echo "Testing read..."
86+
READBACK=$(cat "$TEST_FILE")
87+
if [[ "$READBACK" == "$CONTENT" ]]; then
88+
echo "[OK] Read"
89+
else
90+
echo "[FAIL] Read (Mismatch: got '$READBACK', expected '$CONTENT')"
91+
fi
92+
93+
# 3. File Attributes: stat / utimens / chmod / chown
94+
echo "Testing stat (size)..."
95+
FILE_SIZE=$(stat -c %s "$TEST_FILE")
96+
EXPECTED_SIZE=${#CONTENT}
97+
if [[ "$FILE_SIZE" -eq "$EXPECTED_SIZE" ]]; then
98+
echo "[OK] Stat (Size)"
99+
else
100+
echo "[FAIL] Stat (Size mismatch: expected $EXPECTED_SIZE, got $FILE_SIZE)"
101+
fi
102+
103+
echo "Testing utimens (touch)..."
104+
if touch "$TEST_FILE"; then
105+
echo "[OK] Utimens (touch)"
106+
else
107+
echo "[FAIL] Utimens (touch)"
108+
fi
109+
110+
echo "Testing chmod (ignored but should not error)..."
111+
if chmod 644 "$TEST_FILE"; then
112+
echo "[OK] Chmod"
113+
else
114+
echo "[FAIL] Chmod"
115+
fi
116+
117+
echo "Testing chown (ignored but should not error)..."
118+
if chown "$(id -u):$(id -g)" "$TEST_FILE"; then
119+
echo "[OK] Chown"
120+
else
121+
echo "[FAIL] Chown"
122+
fi
123+
124+
# 4. File Modification: truncate / append
125+
echo "Testing truncate..."
126+
if truncate -s 10 "$TEST_FILE"; then
127+
TRUNCATED_SIZE=$(stat -c %s "$TEST_FILE")
128+
if [[ "$TRUNCATED_SIZE" -eq 10 ]]; then
129+
echo "[OK] Truncate"
130+
else
131+
echo "[FAIL] Truncate (Size mismatch: expected 10, got $TRUNCATED_SIZE)"
132+
fi
133+
else
134+
echo "[FAIL] Truncate"
135+
fi
136+
137+
echo "Testing append..."
138+
echo "append_content" >> "$TEST_FILE"
139+
FINAL_SIZE=$(stat -c %s "$TEST_FILE")
140+
if [[ "$FINAL_SIZE" -gt 10 ]]; then
141+
echo "[OK] Append"
142+
else
143+
echo "[FAIL] Append"
144+
fi
145+
146+
# 5. Symbolic Links: symlink / readlink
147+
echo "Testing symlink..."
148+
LINK_FILE="$MOUNT_DIR/test_link_$(date +%s)"
149+
if ln -s "$TEST_FILE" "$LINK_FILE"; then
150+
if [[ -L "$LINK_FILE" ]] && [[ "$(readlink "$LINK_FILE")" == "$TEST_FILE" ]]; then
151+
echo "[OK] Symlink"
152+
else
153+
echo "[FAIL] Symlink (Creation succeeded but check failed)"
154+
fi
155+
rm "$LINK_FILE"
156+
else
157+
echo "[FAIL] Symlink"
158+
fi
159+
160+
# 6. Renaming: rename
161+
echo "Testing rename (file)..."
162+
RENAMED_FILE="$MOUNT_DIR/renamed_test_$(date +%s)"
163+
if mv "$TEST_FILE" "$RENAMED_FILE"; then
164+
if [[ -f "$RENAMED_FILE" ]] && [[ ! -f "$TEST_FILE" ]]; then
165+
echo "[OK] Rename (File)"
166+
else
167+
echo "[FAIL] Rename (MV succeeded but file state incorrect)"
168+
fi
169+
TEST_FILE=$RENAMED_FILE
170+
else
171+
echo "[FAIL] Rename (File)"
172+
fi
173+
174+
echo "Testing rename (directory)..."
175+
RENAMED_DIR="$MOUNT_DIR/renamed_dir_$(date +%s)"
176+
if mv "$TEST_DIR" "$RENAMED_DIR"; then
177+
if [[ -d "$RENAMED_DIR" ]] && [[ ! -d "$TEST_DIR" ]]; then
178+
echo "[OK] Rename (Directory)"
179+
else
180+
echo "[FAIL] Rename (MV succeeded but dir state incorrect)"
181+
fi
182+
TEST_DIR=$RENAMED_DIR
183+
else
184+
echo "[FAIL] Rename (Directory)"
185+
fi
186+
187+
# 7. File System Info: statfs
188+
echo "Testing statfs (df)..."
189+
if df "$MOUNT_DIR" > /dev/null; then
190+
echo "[OK] Statfs"
191+
else
192+
echo "[FAIL] Statfs"
193+
fi
194+
195+
# 8. Cleanup: unlink / rmdir
196+
echo "Testing unlink (rm)..."
197+
if rm "$TEST_FILE"; then
198+
echo "[OK] Unlink"
199+
else
200+
echo "[FAIL] Unlink"
201+
fi
202+
203+
echo "Testing rmdir..."
204+
if rmdir "$TEST_DIR"; then
205+
echo "[OK] Rmdir"
206+
else
207+
echo "[FAIL] Rmdir"
208+
fi
209+
210+
echo "--- TEST COMPLETE ---"
211+
212+
cleanup() {
213+
echo "Cleaning up..."
214+
umount "$MOUNT_DIR" || true
215+
kill "$GCSFUSE_PID" 2>/dev/null || true
216+
}
217+
trap cleanup EXIT
218+
sleep 2

images/fuse/gcs/run_test.sh

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#!/bin/bash
2+
#
3+
# Copyright 2026 The gVisor Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
# gcs_fuse_test_execution_script - automates GCSFUSE compatibility test with gVisor.
18+
# Sets a unique bucket name, checks for ADC credentials, builds the test
19+
# Docker image, and runs it using the 'runsc' runtime.
20+
21+
set -e
22+
23+
# Configuration
24+
RUNTIME="${GVISOR_RUNTIME:-runsc}"
25+
GCS_BUCKET="gvisor-fuse-test-$(date +%s)"
26+
ADC_PATH="$HOME/.config/gcloud/application_default_credentials.json"
27+
IMAGE_NAME="gcsfuse-tester"
28+
29+
# Find the directory of this script to locate the Dockerfile and test script.
30+
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
31+
32+
# 1. Check for Prerequisites
33+
if ! docker info | grep -q "$RUNTIME"; then
34+
echo "Error: gVisor runtime '$RUNTIME' not found in Docker info."
35+
echo "Please ensure gVisor is installed and configured as a Docker runtime."
36+
exit 1
37+
fi
38+
39+
# Application Default Credentials check.
40+
if [[ ! -f "$ADC_PATH" ]]; then
41+
echo "Application Default Credentials (ADC) not found at $ADC_PATH."
42+
echo "Running 'gcloud auth application-default login'..."
43+
# If the user is running this in a CI environment, then they should
44+
# provide ADC through alternate methods.
45+
gcloud auth application-default login
46+
fi
47+
48+
# 2. Preparation: Create GCS Bucket
49+
echo "Creating GCS bucket: gs://$GCS_BUCKET"
50+
gcloud storage buckets create "gs://$GCS_BUCKET"
51+
52+
# Register a cleanup trap to ensure the bucket is deleted even on failure.
53+
cleanup() {
54+
echo ""
55+
echo "Cleaning up GCS bucket: gs://$GCS_BUCKET"
56+
gcloud storage buckets delete "gs://$GCS_BUCKET" --quiet
57+
}
58+
trap cleanup EXIT
59+
60+
# 3. Build the Image
61+
echo "Building Docker image: $IMAGE_NAME"
62+
docker build -t "$IMAGE_NAME" "$SCRIPT_DIR"
63+
64+
# 4. Run the Test
65+
echo "Running the test with gVisor ($RUNTIME)..."
66+
# We use --privileged to allow mounting within the container.
67+
# We mount the host's ADC into the container to allow gcsfuse to authenticate.
68+
docker run --privileged --runtime="$RUNTIME" \
69+
-e "GCS_BUCKET=$GCS_BUCKET" \
70+
-e "GOOGLE_APPLICATION_CREDENTIALS=/tmp/adc.json" \
71+
-v "$ADC_PATH:/tmp/adc.json" \
72+
"$IMAGE_NAME"
73+
74+
echo "Test successfully completed!"

0 commit comments

Comments
 (0)