Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
17 changes: 17 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Image tag for image containing e2e tests
E2E_TEST_IMAGE_VERSION ?= latest
E2E_TEST_IMAGE ?= quay.io/opendatahub/codeflare-sdk-tests:${E2E_TEST_IMAGE_VERSION}

# Build the test image
.PHONY: build-test-image
build-test-image:
@echo "Building test image: $(E2E_TEST_IMAGE)"
# Build the Docker image using podman
podman build -f images/tests/Dockerfile -t $(E2E_TEST_IMAGE) .

# Push the test image
.PHONY: push-test-image
push-test-image:
@echo "Pushing test image: $(E2E_TEST_IMAGE)"
podman push $(E2E_TEST_IMAGE)

128 changes: 128 additions & 0 deletions images/tests/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Multi-stage build for Python tests with oc CLI
FROM python:3.12-slim AS builder

# Install system dependencies needed for building
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
build-essential \
&& rm -rf /var/lib/apt/lists/*

# Install Poetry
ENV POETRY_VERSION=1.8.3 \
POETRY_HOME="/opt/poetry" \
POETRY_VIRTUALENVS_IN_PROJECT=true \
POETRY_NO_INTERACTION=1 \
POETRY_CACHE_DIR=/tmp/poetry_cache

ENV PATH="$POETRY_HOME/bin:$PATH"

RUN pip install --no-cache-dir "poetry==$POETRY_VERSION"

# ============================================================================
# Base Directory: /codeflare-sdk
# This is the root directory where all project files will be located.
# Similar to kuberay structure, all source code and tests are under /codeflare-sdk
# ============================================================================
WORKDIR /codeflare-sdk

# Copy dependency files
COPY pyproject.toml poetry.lock* ./

# Install dependencies (including test dependencies)
RUN poetry install --no-root --with test && rm -rf $POETRY_CACHE_DIR

# Runtime stage
FROM python:3.12-slim

# Install system dependencies for runtime
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*

# Install OpenShift CLI (oc)
RUN curl -L https://mirror.openshift.com/pub/openshift-v4/clients/oc/latest/linux/oc.tar.gz | \
tar -xz -C /usr/local/bin && \
chmod +x /usr/local/bin/oc && \
oc version --client

# Install Poetry for runtime (needed for poetry run command)
ENV POETRY_VERSION=1.8.3 \
POETRY_HOME="/opt/poetry" \
POETRY_VIRTUALENVS_IN_PROJECT=true \
POETRY_NO_INTERACTION=1

ENV PATH="$POETRY_HOME/bin:/codeflare-sdk/.venv/bin:$PATH"

RUN pip install --no-cache-dir "poetry==$POETRY_VERSION"

# ============================================================================
# Base Directory: /codeflare-sdk
# This is the root directory where all project files will be located.
# Similar to kuberay structure, all source code and tests are under /codeflare-sdk
# ============================================================================
WORKDIR /codeflare-sdk

# Copy virtual environment from builder
COPY --from=builder /codeflare-sdk/.venv /codeflare-sdk/.venv

# Copy project files
COPY pyproject.toml poetry.lock* ./
COPY README.md ./
COPY src/ ./src/
COPY tests/ ./tests/

# Copy test runner script, entrypoint, and RBAC file
COPY images/tests/run-tests.sh /codeflare-sdk/run-tests.sh
COPY images/tests/entrypoint.sh /codeflare-sdk/entrypoint.sh
COPY images/tests/rbac-test-user-permissions.yaml /codeflare-sdk/images/tests/rbac-test-user-permissions.yaml
RUN chmod +x /codeflare-sdk/run-tests.sh /codeflare-sdk/entrypoint.sh

# Install the codeflare_sdk package in editable mode so it can be imported
# This is needed because we used --no-root in the builder stage
WORKDIR /codeflare-sdk
RUN /codeflare-sdk/.venv/bin/pip install -e .

# ============================================================================
# Working Directory: /codeflare-sdk
# Tests expect to run from the project root so relative paths like ./tests/e2e/ work correctly
# ============================================================================
WORKDIR /codeflare-sdk

ENV KUBECONFIG=/codeflare-sdk/tests/.kube/config

# ============================================================================
# Test Results Directory: /codeflare-sdk/tests/results
# This directory will contain pytest output files (JUnit XML, coverage, etc.)
# Mount this as a volume when running the container to access test results
# ============================================================================
RUN mkdir -p /codeflare-sdk/tests/results

# ============================================================================
# Environment File Setup
# The containerEnvFile should be passed via --env-file parameter when running
# the container. Expected environment variables:
# TEST_USER_USERNAME, TEST_USER_PASSWORD
# OCP_ADMIN_USER_USERNAME, OCP_ADMIN_USER_PASSWORD
# Example: podman run --env-file containerEnvFile codeflare-sdk-tests
# ============================================================================

# ============================================================================
# Default Command (can be overridden when running the container)
# This CMD runs the test wrapper script which handles:
# - Extracting OpenShift API URL from kubeconfig
# - Applying RBAC policies
# - Logging in with TEST_USER
# - Running tests
# - Logging in with OCP_ADMIN_USER after tests
# - Cleaning up RBAC
# To override it, just provide your command after the image name:
# podman run --env-file containerEnvFile codeflare-sdk-tests poetry run pytest tests/e2e/specific_test.py
# ============================================================================
# Set entrypoint to handle -- separator arguments
ENTRYPOINT ["/codeflare-sdk/entrypoint.sh"]
# Default command (can be overridden, but entrypoint will handle it)
CMD []

6 changes: 6 additions & 0 deletions images/tests/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/sh
# Entrypoint script that handles -- separator in podman commands
# Passes all arguments to run-tests.sh which will forward them to pytest

exec /codeflare-sdk/run-tests.sh "$@"

175 changes: 175 additions & 0 deletions images/tests/rbac-test-user-permissions.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
---
# RBAC permissions for test user to run e2e tests
# Apply this as cluster-admin before running tests:
# oc apply -f images/tests/rbac-test-user-permissions.yaml
# OR
# kubectl apply -f images/tests/rbac-test-user-permissions.yaml
#
# The username "TEST_USER_USERNAME_PLACEHOLDER" will be replaced at runtime with the actual test username

# For OpenShift: Grant self-provisioner role (allows namespace creation)
# This is the recommended approach for OpenShift
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-user-self-provisioner
# For OpenShift, you can also use: oc adm policy add-cluster-role-to-user self-provisioner TEST_USER_USERNAME_PLACEHOLDER
subjects:
- kind: User
name: TEST_USER_USERNAME_PLACEHOLDER
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: self-provisioner
apiGroup: rbac.authorization.k8s.io
---
# Alternative: Grant admin role (more permissive, use if self-provisioner doesn't work)
# For OpenShift, you can also use: oc adm policy add-cluster-role-to-user admin TEST_USER_USERNAME_PLACEHOLDER
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-user-admin
subjects:
- kind: User
name: TEST_USER_USERNAME_PLACEHOLDER
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
---
# For Kubernetes: Grant cluster-admin role (allows all operations including namespace creation)
# This is more permissive but ensures all test operations work
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-user-cluster-admin
subjects:
- kind: User
name: TEST_USER_USERNAME_PLACEHOLDER
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
---
# Additional permissions for Kueue resources (if needed)
# This allows the user to create/manage Kueue CustomResources
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: test-user-kueue-admin
rules:
- apiGroups:
- kueue.x-k8s.io
resources:
- clusterqueues
- resourceflavors
- localqueues
- workloads
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-user-kueue-admin
subjects:
- kind: User
name: TEST_USER_USERNAME_PLACEHOLDER
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: test-user-kueue-admin
apiGroup: rbac.authorization.k8s.io
---
# Permissions for RayCluster and RayJob CustomResources
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: test-user-ray-admin
rules:
- apiGroups:
- ray.io
resources:
- rayclusters
- rayjobs
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-user-ray-admin
subjects:
- kind: User
name: TEST_USER_USERNAME_PLACEHOLDER
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: test-user-ray-admin
apiGroup: rbac.authorization.k8s.io
---
# Comprehensive RBAC role for Kueue batch operations
# This role provides permissions for namespaces, Kueue, Ray, and core Kubernetes resources
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kueue-batch-user-role
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["create", "get", "list", "watch"]
- apiGroups: ["kueue.x-k8s.io"]
resources: ["clusterqueues", "resourceflavors", "localqueues"]
verbs: ["create", "get", "list", "watch", "update", "patch", "delete"]
- apiGroups: ["ray.io"]
resources: ["rayclusters", "rayjobs"]
verbs: ["create", "get", "list", "watch", "update", "patch", "delete"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["create", "get", "list", "watch", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["pods", "services", "configmaps", "secrets"]
verbs: ["create", "get", "list", "watch", "update", "patch", "delete"]
---
# ClusterRoleBinding for authenticated users (group-based)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kueue-batch-user-rolebinding
subjects:
- kind: Group
apiGroup: rbac.authorization.k8s.io
name: 'system:authenticated'
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kueue-batch-user-role
---
# ClusterRoleBinding for specific test user
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kueue-batch-user-specific-rolebinding
subjects:
- kind: User
apiGroup: rbac.authorization.k8s.io
name: 'TEST_USER_USERNAME_PLACEHOLDER'
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kueue-batch-user-role

Loading
Loading