Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/scripts/build-all-images.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ get_image_tag() {

build_images() {
oss_emulator_img="${IMG_REPO}/oss-emulator:e2e"
mooncake_img="${IMG_REPO}/mooncake:e2e"
images=(
"${IMG_REPO}/dataset-controller:${IMAGE_TAG}"
"${IMG_REPO}/application-controller:${IMAGE_TAG}"
Expand All @@ -23,10 +24,12 @@ build_images() {
"${IMG_REPO}/fluid-webhook:${IMAGE_TAG}"
"${IMG_REPO}/fluid-crd-upgrader:${IMAGE_TAG}"
"${oss_emulator_img}"
"${mooncake_img}"
)

make docker-build-all
docker build -t "${oss_emulator_img}" test/gha-e2e/jindo/oss-emulator
docker build -t "${mooncake_img}" test/gha-e2e/mooncake/image

echo ">>> Cleaning docker build caches before loading images to free disk space..."
docker builder prune -a -f
Expand Down
6 changes: 6 additions & 0 deletions .github/scripts/gha-e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,14 @@
bash test/gha-e2e/curvine/test.sh
}

function mooncake_e2e() {

Check warning on line 108 in .github/scripts/gha-e2e.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBibQoex1GfKCzw4A&open=AaAKBibQoex1GfKCzw4A&pullRequest=6164
set -e
bash test/gha-e2e/mooncake/test.sh
}

check_control_plane_status
alluxio_e2e
jindo_e2e
juicefs_e2e
curvine_e2e
mooncake_e2e
29 changes: 29 additions & 0 deletions test/gha-e2e/mooncake/bad_mount_pod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Negative case: without a client component there is no FUSE mount point, so an
# application pod that mounts this Dataset's PVC is bound to fail. Fluid still
# creates the PVC/PV and reports them as Bound, which easily gives the
# impression that they can be mounted, so the docs call this out in their FAQ
# and this test pins the behaviour down.
#
# This pod is expected never to start; it is deleted as soon as the check is done.
apiVersion: v1
kind: Pod
metadata:
name: mooncake-bad-mount
namespace: default
spec:
# The mount keeps being retried anyway, no need to have kubelet restart the
# container over and over
restartPolicy: Never
automountServiceAccountToken: false
containers:
- name: app

Check warning on line 19 in test/gha-e2e/mooncake/bad_mount_pod.yaml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Specify a CPU request for this container.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiaMoex1GfKCzw3g&open=AaAKBiaMoex1GfKCzw3g&pullRequest=6164

Check warning on line 19 in test/gha-e2e/mooncake/bad_mount_pod.yaml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Specify a storage request for this container.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiaMoex1GfKCzw3e&open=AaAKBiaMoex1GfKCzw3e&pullRequest=6164

Check warning on line 19 in test/gha-e2e/mooncake/bad_mount_pod.yaml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Specify a memory limit for this container.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiaMoex1GfKCzw3d&open=AaAKBiaMoex1GfKCzw3d&pullRequest=6164

Check warning on line 19 in test/gha-e2e/mooncake/bad_mount_pod.yaml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Specify a storage limit for this container.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiaMoex1GfKCzw3f&open=AaAKBiaMoex1GfKCzw3f&pullRequest=6164

Check warning on line 19 in test/gha-e2e/mooncake/bad_mount_pod.yaml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Specify a memory request for this container.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiaMoex1GfKCzw3h&open=AaAKBiaMoex1GfKCzw3h&pullRequest=6164
image: busybox:1.36
imagePullPolicy: IfNotPresent
command: ["sleep", "infinity"]
volumeMounts:
- name: mc-vol
mountPath: /data
volumes:
- name: mc-vol
persistentVolumeClaim:
claimName: mooncake-demo
20 changes: 20 additions & 0 deletions test/gha-e2e/mooncake/cacheruntime.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# One worker replica: the CI kind cluster is single-node, so extra replicas would
# show no scheduling difference and only make the case slower. Replica scaling is
# already covered by the curvine case and is not repeated here.
apiVersion: data.fluid.io/v1alpha1
kind: CacheRuntime
metadata:
name: mooncake-demo
namespace: default
spec:
runtimeClassName: mooncake-demo
master:
replicas: 1
worker:
replicas: 1
tieredStore:
levels:
- emptyDir:
quota: 1Gi
high: "0.8"
low: "0.5"
92 changes: 92 additions & 0 deletions test/gha-e2e/mooncake/cacheruntimeclass.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Mooncake is a cache system without POSIX mount semantics: applications talk to
# the cache service directly through its own client, so this topology declares
# only master and worker and omits the client component that would do the
# mounting. That is exactly the scenario this case guards: the controller must
# not panic when the client component is omitted.
#
# Note: do not declare resources on the containers here. When the
# CacheRuntimeClass template sets resources but the CacheRuntime does not,
# syncRuntimeSpec passes the zero value to updateResources, which overwrites the
# template's resources with an empty value. That has two consequences:
# 1. the resources declared in the template are silently dropped and the pod
# ends up with {};
# 2. the patch triggers one ASTS rollout, during which the runtime is briefly
# not-ready, and once the Dataset flips to Failed it does not recover on its
# own (even after the component phase returns to Ready).
apiVersion: data.fluid.io/v1alpha1
kind: CacheRuntimeClass
metadata:
name: mooncake-demo
fileSystemType: mooncakefs
topology:
master:
service:
headless: {}
executionEntries:
reportSummary:
command:
- bash
- -c
- /reportSummary.sh
timeout: 30
template:
spec:
restartPolicy: Always
containers:
- name: master
image: fluidcloudnative/mooncake:e2e
command:
- /custom-entrypoint.sh
args:
- master
- start
imagePullPolicy: IfNotPresent
readinessProbe:
tcpSocket:
port: 50051
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 12
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
ports:
- containerPort: 50051
name: rpc
- containerPort: 8080
name: metadata
- containerPort: 9003
name: metrics
worker:
service:
headless: {}
template:
spec:
restartPolicy: Always
containers:
- name: worker
image: fluidcloudnative/mooncake:e2e
command:
- /custom-entrypoint.sh
args:
- worker
- start
imagePullPolicy: IfNotPresent
readinessProbe:
tcpSocket:
port: 50052
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 12
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
ports:
- containerPort: 50052
name: data
- containerPort: 9300
name: http
16 changes: 16 additions & 0 deletions test/gha-e2e/mooncake/dataset.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Mooncake mounts no underlying storage (UFS); data is written directly into the
# cache by the client. The mountPoint here is only a placeholder: the
# CacheRuntimeClass declares no mountUfs execution entry, so Fluid never performs
# an actual mount.
apiVersion: data.fluid.io/v1alpha1
kind: Dataset
metadata:
name: mooncake-demo
namespace: default
spec:
placement: Shared
accessModes:
- ReadWriteMany
mounts:
- name: mc
mountPoint: "mooncakefs:///"
41 changes: 41 additions & 0 deletions test/gha-e2e/mooncake/image/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# The Mooncake image used by the e2e case.
#
# It is built in-repo rather than pulled from an external registry, for the same
# reason as test/gha-e2e/jindo/oss-emulator: e2e runs on every PR, an external
# image going away turns the whole pipeline red, and the two scripts the image
# provides for Fluid to invoke have to be reviewable.
#
# The only external dependency is Mooncake's official package on PyPI.
# python:3.12.13-slim — slim is required: the full variant carries an extra
# ~700MB build toolchain, growing the image from ~470MB to ~1.9GB, and e2e also
# has to kind-load it onto the node and keep a second copy there.
FROM python:3.12.13-slim@sha256:229a2c5bfa27522db7815ea81f9bed70af17ccb9de9fc7ad142b1877b5830d36

Check warning on line 12 in test/gha-e2e/mooncake/image/Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

This image might run with "root" as the default user. Make sure it is safe here.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiafoex1GfKCzw3q&open=AaAKBiafoex1GfKCzw3q&pullRequest=6164

Check warning on line 12 in test/gha-e2e/mooncake/image/Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use either the version tag or the digest for the image instead of both.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiafoex1GfKCzw3r&open=AaAKBiafoex1GfKCzw3r&pullRequest=6164

RUN apt-get update && apt-get install -y --no-install-recommends \

Check warning on line 14 in test/gha-e2e/mooncake/image/Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Merge this RUN instruction with the consecutive ones.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiafoex1GfKCzw3p&open=AaAKBiafoex1GfKCzw3p&pullRequest=6164
libcurl4 \
libibverbs1 \
rdma-core \
librdmacm1 \
libnuma1 \
liburing2 \
curl \
jq \

Check warning on line 22 in test/gha-e2e/mooncake/image/Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Sort these package names alphanumerically.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiafoex1GfKCzw3s&open=AaAKBiafoex1GfKCzw3s&pullRequest=6164
&& rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir \

Check warning on line 25 in test/gha-e2e/mooncake/image/Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Omitting "--only-binary :all:" can lead to the execution of setup scripts. Make sure it is safe here.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiafoex1GfKCzw3t&open=AaAKBiafoex1GfKCzw3t&pullRequest=6164
mooncake-transfer-engine-non-cuda==0.3.12.post1 \
nvidia-cuda-runtime-cu12

Check warning on line 27 in test/gha-e2e/mooncake/image/Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Using dependencies without locking resolved versions is security-sensitive.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiafoex1GfKCzw3u&open=AaAKBiafoex1GfKCzw3u&pullRequest=6164
Comment on lines +25 to +27

ENV LD_LIBRARY_PATH=/usr/local/lib/python3.12/site-packages/nvidia/cuda_runtime/lib:$LD_LIBRARY_PATH

# 50051 master RPC / 50052 worker data / 8080 metadata service / 9003 master metrics / 9300 worker http
EXPOSE 50051 50052 8080 9003 9300

# The two scripts Fluid invokes:
# custom-entrypoint.sh starts the right process based on the role (master/worker)
# reportSummary.sh collects cache usage and emits it as JSON in the format Fluid expects
COPY custom-entrypoint.sh /custom-entrypoint.sh
COPY reportSummary.sh /reportSummary.sh
RUN chmod +x /custom-entrypoint.sh /reportSummary.sh

CMD ["python3"]
71 changes: 71 additions & 0 deletions test/gha-e2e/mooncake/image/custom-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/bin/sh
# custom-entrypoint.sh
# Usage: /custom-entrypoint.sh <master|worker|client> <start>

set -e

ROLE="$1"
ACTION="$2"

if [ "$ACTION" != "start" ]; then
echo "Error: unsupported action '$ACTION'"

Check warning on line 11 in test/gha-e2e/mooncake/image/custom-entrypoint.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Redirect this error message to stderr (>&2).

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiaYoex1GfKCzw3l&open=AaAKBiaYoex1GfKCzw3l&pullRequest=6164
exit 1
fi

case "$ROLE" in

master)
exec mooncake_master \
-v=1 \
--rpc_interface=eth0 \
--enable_http_metadata_server=true \
--http_metadata_server_host=0.0.0.0 \
--http_metadata_server_port=8080 \
--enable_metadata_cleanup_on_timeout=true \
--client_ttl=10
;;

worker)
# Read the dynamic values from the RuntimeConfig JSON mounted by Fluid
if [ -z "$FLUID_RUNTIME_CONFIG_PATH" ] || [ ! -f "$FLUID_RUNTIME_CONFIG_PATH" ]; then
echo "Error: FLUID_RUNTIME_CONFIG_PATH not set or file not found"

Check warning on line 31 in test/gha-e2e/mooncake/image/custom-entrypoint.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Redirect this error message to stderr (>&2).

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiaYoex1GfKCzw3m&open=AaAKBiaYoex1GfKCzw3m&pullRequest=6164
exit 1
fi

CONFIG=$(cat "$FLUID_RUNTIME_CONFIG_PATH")

MASTER_SVC=$(echo "$CONFIG" | jq -r '.master.service.name')
WORKER_SVC=$(echo "$CONFIG" | jq -r '.worker.service.name')
QUOTA=$(echo "$CONFIG" | jq -r '.worker.tieredStoreLevels[0].quotas[0] // "1GiB"')

# Quota format conversion: Fluid hands over K8s-style "1Gi", Mooncake wants "1GB"
SEGMENT_SIZE=$(echo "$QUOTA" | sed 's/Gi$/GB/; s/Mi$/MB/')

NAMESPACE="${FLUID_DATASET_NAMESPACE:-default}"
MASTER_ADDR="${MASTER_SVC}.${NAMESPACE}.svc.cluster.local:50051"
METADATA_ADDR="http://${MASTER_SVC}.${NAMESPACE}.svc.cluster.local:8080/metadata"
WORKER_HOST="${POD_NAME}.${WORKER_SVC}.${NAMESPACE}.svc.cluster.local"

echo "Starting worker: master=$MASTER_ADDR, segment_size=$SEGMENT_SIZE, host=$WORKER_HOST"

exec mooncake_client \
--host="$WORKER_HOST" \
--port=50052 \
--global_segment_size="$SEGMENT_SIZE" \
--master_server_address="$MASTER_ADDR" \
--metadata_server="$METADATA_ADDR" \

Check warning on line 56 in test/gha-e2e/mooncake/image/custom-entrypoint.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Make sure that using clear-text protocols is safe here.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiaYoex1GfKCzw3k&open=AaAKBiaYoex1GfKCzw3k&pullRequest=6164
Comment on lines +51 to +56
--protocol=tcp \
--enable_http_server=true \
--http_port=9300
;;

client)
echo "Error: client role not yet implemented for Mooncake"

Check warning on line 63 in test/gha-e2e/mooncake/image/custom-entrypoint.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Redirect this error message to stderr (>&2).

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiaYoex1GfKCzw3n&open=AaAKBiaYoex1GfKCzw3n&pullRequest=6164
exit 1
;;

*)
echo "Error: unknown role '$ROLE'"

Check warning on line 68 in test/gha-e2e/mooncake/image/custom-entrypoint.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Redirect this error message to stderr (>&2).

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiaYoex1GfKCzw3o&open=AaAKBiaYoex1GfKCzw3o&pullRequest=6164
exit 1
;;
esac
47 changes: 47 additions & 0 deletions test/gha-e2e/mooncake/image/reportSummary.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/bin/bash
set -euo pipefail

RAW=$(curl -s http://localhost:9003/metrics/summary)

if [ -z "$RAW" ]; then

Check failure on line 6 in test/gha-e2e/mooncake/image/reportSummary.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiaSoex1GfKCzw3i&open=AaAKBiaSoex1GfKCzw3i&pullRequest=6164
echo "Error: empty response from metrics endpoint" >&2
exit 1
fi

# Extract the "Mem Storage: 0 B / 2.00 GB (0.0%)" part
MEM_LINE=$(echo "$RAW" | grep -oE 'Mem Storage: [^|]+' || true)

CACHED_RAW=$(echo "$MEM_LINE" | sed -E 's/Mem Storage: ([^/]+) \/.*/\1/' | xargs)
CAPACITY_RAW=$(echo "$MEM_LINE" | sed -E 's/.*\/ ([^(]+) \(.*/\1/' | xargs)
PERCENT_RAW=$(echo "$MEM_LINE" | grep -oE '\([0-9.]+%\)' | tr -d '()%')

# Unit format conversion ("2.00 GB" -> "2.00GiB")
normalize_unit() {
echo "$1" | sed -E 's/ ?GB$/GiB/; s/ ?MB$/MiB/; s/ ?B$/B/' | tr -d ' '

Check warning on line 20 in test/gha-e2e/mooncake/image/reportSummary.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Assign this positional parameter to a local variable.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAKBiaSoex1GfKCzw3j&open=AaAKBiaSoex1GfKCzw3j&pullRequest=6164
}
CACHED=$(normalize_unit "$CACHED_RAW")
CACHE_CAPACITY=$(normalize_unit "$CAPACITY_RAW")

# The number of keys is used as fileNum
FILE_NUM=$(echo "$RAW" | grep -oE 'Keys: [0-9]+' | grep -oE '[0-9]+' || echo "0")

# Approximate the hit ratio from the success rate of Get requests
GET_STATS=$(echo "$RAW" | grep -oE 'Get=[0-9.]+/[0-9.]+' || echo "Get=0.00/0.00")
GET_SUCCESS=$(echo "$GET_STATS" | cut -d= -f2 | cut -d/ -f1)
GET_TOTAL=$(echo "$GET_STATS" | cut -d/ -f2)
HIT_RATIO=$(awk -v s="$GET_SUCCESS" -v t="$GET_TOTAL" \
'BEGIN{ if (t>0) printf "%.0f", (s/t*100); else print "0" }')

# Mooncake has no real underlying UFS total, so use the cache capacity instead
UFS_TOTAL="$CACHE_CAPACITY"

cat <<EOF
{
"cached": "$CACHED",
"cachedPercentage": "$PERCENT_RAW",
"cacheCapacity": "$CACHE_CAPACITY",
"cacheHitRatio": "$HIT_RATIO",
"fileNum": "$FILE_NUM",
"ufsTotal": "$UFS_TOTAL"
}
EOF
Loading