Skip to content

Commit 5e4e915

Browse files
General fixes and updates
2 parents 7031c3a + 5833a7f commit 5e4e915

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2790
-2244
lines changed

.github/workflows/cluster-test.yml

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
name: Cluster Test
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- 'manifests/**'
7+
- 'src/**'
8+
- 'Dockerfile'
9+
- 'e2e/**'
10+
workflow_dispatch:
11+
12+
jobs:
13+
cluster-test:
14+
runs-on: ubuntu-latest
15+
timeout-minutes: 20
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v6
19+
20+
- name: Set up Docker Buildx
21+
uses: docker/setup-buildx-action@v3
22+
23+
- name: Build s3proxy image
24+
uses: docker/build-push-action@v6
25+
with:
26+
context: .
27+
load: true
28+
tags: s3proxy:latest
29+
30+
- name: Create Kind cluster
31+
uses: helm/kind-action@v1
32+
with:
33+
node_image: kindest/node:v1.29.2
34+
cluster_name: cluster-test
35+
36+
- name: Load image into Kind
37+
run: kind load docker-image s3proxy:latest --name cluster-test
38+
39+
- name: Create namespace
40+
run: kubectl create namespace s3proxy
41+
42+
- name: Deploy MinIO
43+
run: |
44+
cat <<EOF | kubectl apply -n s3proxy -f -
45+
apiVersion: apps/v1
46+
kind: Deployment
47+
metadata:
48+
name: minio
49+
spec:
50+
replicas: 1
51+
selector:
52+
matchLabels:
53+
app: minio
54+
template:
55+
metadata:
56+
labels:
57+
app: minio
58+
spec:
59+
containers:
60+
- name: minio
61+
image: minio/minio:latest
62+
args: ["server", "/data"]
63+
env:
64+
- name: MINIO_ROOT_USER
65+
value: minioadmin
66+
- name: MINIO_ROOT_PASSWORD
67+
value: minioadmin
68+
ports:
69+
- containerPort: 9000
70+
---
71+
apiVersion: v1
72+
kind: Service
73+
metadata:
74+
name: minio
75+
spec:
76+
selector:
77+
app: minio
78+
ports:
79+
- port: 9000
80+
EOF
81+
kubectl wait --for=condition=ready pod -l app=minio -n s3proxy --timeout=120s
82+
83+
- name: Deploy Redis
84+
run: |
85+
cat <<EOF | kubectl apply -n s3proxy -f -
86+
apiVersion: apps/v1
87+
kind: Deployment
88+
metadata:
89+
name: redis
90+
spec:
91+
replicas: 1
92+
selector:
93+
matchLabels:
94+
app: redis
95+
template:
96+
metadata:
97+
labels:
98+
app: redis
99+
spec:
100+
containers:
101+
- name: redis
102+
image: redis:7-alpine
103+
ports:
104+
- containerPort: 6379
105+
resources:
106+
limits:
107+
memory: 128Mi
108+
cpu: 100m
109+
---
110+
apiVersion: v1
111+
kind: Service
112+
metadata:
113+
name: redis
114+
spec:
115+
selector:
116+
app: redis
117+
ports:
118+
- port: 6379
119+
EOF
120+
kubectl wait --for=condition=ready pod -l app=redis -n s3proxy --timeout=120s
121+
122+
- name: Build Helm dependencies
123+
run: |
124+
helm repo add dandydeveloper https://dandydeveloper.github.io/charts
125+
helm repo update
126+
helm dependency build manifests/
127+
128+
- name: Install s3proxy chart
129+
run: |
130+
helm install s3proxy manifests/ \
131+
--namespace s3proxy \
132+
--set image.repository=s3proxy \
133+
--set image.tag=latest \
134+
--set image.pullPolicy=IfNotPresent \
135+
--set s3.host="http://minio:9000" \
136+
--set secrets.encryptKey="test-encryption-key-32chars!!" \
137+
--set secrets.awsAccessKeyId=minioadmin \
138+
--set secrets.awsSecretAccessKey=minioadmin \
139+
--set redis-ha.enabled=false \
140+
--set externalRedis.url="redis://redis:6379/0" \
141+
--set replicaCount=3 \
142+
--set resources.limits.cpu=100m \
143+
--set resources.requests.cpu=50m \
144+
--wait \
145+
--timeout 5m
146+
147+
- name: Verify pods are running
148+
run: |
149+
kubectl get pods -n s3proxy
150+
POD_COUNT=$(kubectl get pods -n s3proxy -l app.kubernetes.io/name=s3proxy-python --no-headers | grep Running | wc -l)
151+
if [ "$POD_COUNT" -lt 3 ]; then
152+
echo "Expected 3 s3proxy pods, got $POD_COUNT"
153+
exit 1
154+
fi
155+
echo "✓ All 3 s3proxy pods running"
156+
157+
- name: Run load test
158+
run: |
159+
# Save pod names for load balancing check
160+
PODS=$(kubectl get pods -n s3proxy -l app.kubernetes.io/name=s3proxy-python -o jsonpath='{.items[*].metadata.name}')
161+
echo "Found pods: $PODS"
162+
163+
# Save starting log line counts
164+
for pod in $PODS; do
165+
kubectl logs $pod -n s3proxy 2>/dev/null | wc -l > /tmp/$pod.start
166+
done
167+
168+
# Run the load test
169+
kubectl run s3-load-test -n s3proxy --rm -i --restart=Never \
170+
--image=amazon/aws-cli:latest \
171+
--env="AWS_ACCESS_KEY_ID=minioadmin" \
172+
--env="AWS_SECRET_ACCESS_KEY=minioadmin" \
173+
--env="AWS_DEFAULT_REGION=us-east-1" \
174+
--command -- /bin/sh -c '
175+
set -e
176+
ENDPOINT="http://s3proxy-python:4433"
177+
178+
echo "=== Creating test bucket ==="
179+
aws --endpoint-url $ENDPOINT s3 mb s3://load-test-bucket || true
180+
181+
echo "=== Generating 10MB test files ==="
182+
mkdir -p /tmp/testfiles
183+
for i in 1 2 3; do
184+
dd if=/dev/urandom of=/tmp/testfiles/file-$i.bin bs=1M count=10 2>/dev/null &
185+
done
186+
wait
187+
ls -lh /tmp/testfiles/
188+
189+
echo "=== Starting concurrent uploads ==="
190+
START=$(date +%s)
191+
for i in 1 2 3; do
192+
aws --endpoint-url $ENDPOINT s3 cp /tmp/testfiles/file-$i.bin s3://load-test-bucket/file-$i.bin &
193+
done
194+
wait
195+
END=$(date +%s)
196+
echo "=== Uploads complete in $((END - START))s ==="
197+
198+
echo "=== Listing bucket ==="
199+
aws --endpoint-url $ENDPOINT s3 ls s3://load-test-bucket/
200+
201+
echo "=== Downloading and verifying ==="
202+
mkdir -p /tmp/downloads
203+
for i in 1 2 3; do
204+
aws --endpoint-url $ENDPOINT s3 cp s3://load-test-bucket/file-$i.bin /tmp/downloads/file-$i.bin &
205+
done
206+
wait
207+
208+
echo "=== Comparing checksums ==="
209+
ORIG_SUMS=$(md5sum /tmp/testfiles/*.bin | cut -d" " -f1 | sort)
210+
DOWN_SUMS=$(md5sum /tmp/downloads/*.bin | cut -d" " -f1 | sort)
211+
212+
if [ "$ORIG_SUMS" = "$DOWN_SUMS" ]; then
213+
echo "✓ Checksums match - round-trip successful"
214+
else
215+
echo "✗ Checksum mismatch!"
216+
exit 1
217+
fi
218+
219+
echo "=== Verifying encryption ==="
220+
dd if=/dev/urandom of=/tmp/encrypt-test.bin bs=1K count=100 2>/dev/null
221+
ORIG_SIZE=$(stat -c%s /tmp/encrypt-test.bin)
222+
ORIG_MD5=$(md5sum /tmp/encrypt-test.bin | cut -c1-32)
223+
224+
aws --endpoint-url $ENDPOINT s3 cp /tmp/encrypt-test.bin s3://load-test-bucket/encrypt-test.bin
225+
aws --endpoint-url http://minio:9000 s3 cp s3://load-test-bucket/encrypt-test.bin /tmp/raw.bin 2>/dev/null || true
226+
227+
if [ -f /tmp/raw.bin ]; then
228+
RAW_SIZE=$(stat -c%s /tmp/raw.bin)
229+
RAW_MD5=$(md5sum /tmp/raw.bin | cut -c1-32)
230+
EXPECTED_SIZE=$((ORIG_SIZE + 28))
231+
232+
if [ "$RAW_SIZE" = "$EXPECTED_SIZE" ] && [ "$ORIG_MD5" != "$RAW_MD5" ]; then
233+
echo "✓ Encryption verified - size +28 bytes (GCM overhead), content differs"
234+
else
235+
echo "✗ Encryption check failed"
236+
exit 1
237+
fi
238+
fi
239+
240+
echo ""
241+
echo "✓ All tests passed!"
242+
'
243+
244+
- name: Check load balancing
245+
run: |
246+
PODS=$(kubectl get pods -n s3proxy -l app.kubernetes.io/name=s3proxy-python -o jsonpath='{.items[*].metadata.name}')
247+
PODS_HIT=0
248+
249+
for pod in $PODS; do
250+
START_LINE=$(cat /tmp/$pod.start 2>/dev/null || echo "0")
251+
REQUEST_COUNT=$(kubectl logs $pod -n s3proxy 2>/dev/null | tail -n +$((START_LINE + 1)) | grep -cE "GET|POST|PUT|HEAD" || echo "0")
252+
if [ "$REQUEST_COUNT" -gt 0 ]; then
253+
PODS_HIT=$((PODS_HIT + 1))
254+
echo "✓ Pod $pod: received $REQUEST_COUNT requests"
255+
else
256+
echo " Pod $pod: received 0 requests"
257+
fi
258+
done
259+
260+
if [ "$PODS_HIT" -ge 2 ]; then
261+
echo "✓ Load balancing verified - traffic distributed across $PODS_HIT pods"
262+
else
263+
echo "⚠ Traffic went to only $PODS_HIT pod(s)"
264+
fi
265+
266+
- name: Show logs on failure
267+
if: failure()
268+
run: |
269+
echo "=== Pod Status ==="
270+
kubectl get pods -n s3proxy -o wide
271+
echo ""
272+
echo "=== S3Proxy Logs ==="
273+
kubectl logs -l app.kubernetes.io/name=s3proxy-python -n s3proxy --tail=100
274+
echo ""
275+
echo "=== MinIO Logs ==="
276+
kubectl logs -l app=minio -n s3proxy --tail=50
277+
echo ""
278+
echo "=== Events ==="
279+
kubectl get events -n s3proxy --sort-by=.lastTimestamp
Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
11
name: Build and Push Docker Image
22

33
on:
4-
workflow_dispatch:
5-
inputs:
6-
tag:
7-
description: 'Docker image tag'
8-
required: true
9-
type: string
10-
11-
env:
12-
REGISTRY: ghcr.io
13-
IMAGE_NAME: ${{ github.repository }}
4+
push:
5+
branches: [main]
6+
tags: ['v*']
147

158
jobs:
169
build-and-push:
@@ -23,23 +16,33 @@ jobs:
2316
- name: Checkout repository
2417
uses: actions/checkout@v6
2518

19+
- name: Determine tags
20+
id: tags
21+
run: |
22+
OWNER=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')
23+
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
24+
VERSION=${GITHUB_REF#refs/tags/v}
25+
echo "tags=ghcr.io/${OWNER}/s3proxy-python:${VERSION}" >> $GITHUB_OUTPUT
26+
else
27+
echo "tags=ghcr.io/${OWNER}/s3proxy-python:latest" >> $GITHUB_OUTPUT
28+
fi
29+
2630
- name: Set up Docker Buildx
2731
uses: docker/setup-buildx-action@v3
2832

2933
- name: Log in to Container Registry
30-
if: github.event_name != 'pull_request'
3134
uses: docker/login-action@v3.6.0
3235
with:
33-
registry: ${{ env.REGISTRY }}
34-
username: ${{ github.actor }}
36+
registry: ghcr.io
37+
username: ${{ github.repository_owner }}
3538
password: ${{ secrets.GITHUB_TOKEN }}
3639

3740
- name: Build and push Docker image
3841
uses: docker/build-push-action@v6
3942
with:
4043
context: .
41-
push: ${{ github.event_name != 'pull_request' }}
42-
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ inputs.tag }}
44+
push: true
45+
tags: ${{ steps.tags.outputs.tags }}
4346
cache-from: type=gha
4447
cache-to: type=gha,mode=max
4548
platforms: linux/amd64,linux/arm64

0 commit comments

Comments
 (0)