forked from openedx/xqueue-watcher
-
Notifications
You must be signed in to change notification settings - Fork 0
feat: migrate to uv + add ContainerGrader for Kubernetes/Docker sandboxed grading #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
blarghmatey
wants to merge
20
commits into
master
Choose a base branch
from
chore/migrate-to-uv-and-k8s-container-grader
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+2,904
−448
Open
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
8eada18
chore: migrate from pip-compile to uv for dependency management
blarghmatey 1d5db68
fix: remove AppArmor/codejail hard dependency; make codejail optional
blarghmatey 37100ad
feat: add ContainerGrader for Kubernetes/Docker-based sandboxed grading
blarghmatey a66b703
feat: add grader base Docker image and container entrypoint
blarghmatey 01c65ba
feat: add Kubernetes deployment manifests and Docker Compose local dev
blarghmatey 18c7151
fix: correct grader path handling in ContainerGrader and entrypoint
blarghmatey 0be0926
fix(tests): skip jailed grader tests when codejail is not installed
blarghmatey 3f7944d
fix: address PR review feedback
blarghmatey 1491b29
refactor: replace path-py with stdlib pathlib
blarghmatey cbdcf15
feat: add edx-codejail as optional dependency; document container iso…
blarghmatey 193c043
fix: address second round of PR review feedback
blarghmatey d28da94
refactor: move full grading pipeline into container; add ContainerGra…
blarghmatey 2c3b82f
refactor: replace statsd/newrelic with OpenTelemetry; add 12-factor s…
blarghmatey 22d311c
chore: remove planning doc from git tracking
blarghmatey d524236
chore: remove codecov upload from CI
blarghmatey 16e034b
fix: address PR #14 review feedback
blarghmatey 0495e75
fix: add venv bin to PATH so xqueue-watcher entrypoint resolves
blarghmatey c247b52
feat: add configure_logging() for 12-factor stdout logging
blarghmatey 2e7ab2d
fix: symlink xqueue-watcher into /usr/local/bin for reliable resolution
blarghmatey 5502d68
feat: add env-based defaults for ContainerGrader configuration
blarghmatey File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,27 +1,31 @@ | ||
| name: Upgrade Python Requirements | ||
| name: Update Dependencies | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: "15 15 1/14 * *" | ||
| workflow_dispatch: | ||
| inputs: | ||
| branch: | ||
| description: "Target branch against which to create requirements PR" | ||
| required: true | ||
| default: 'master' | ||
|
|
||
| jobs: | ||
| call-upgrade-python-requirements-workflow: | ||
| uses: openedx/.github/.github/workflows/upgrade-python-requirements.yml@master | ||
| with: | ||
| branch: ${{ github.event.inputs.branch || 'master' }} | ||
| # optional parameters below; fill in if you'd like github or email notifications | ||
| # user_reviewers: "" | ||
| # team_reviewers: "" | ||
| email_address: "aurora-requirements-update@2u-internal.opsgenie.net" | ||
| send_success_notification: true | ||
| secrets: | ||
| requirements_bot_github_token: ${{ secrets.REQUIREMENTS_BOT_GITHUB_TOKEN }} | ||
| requirements_bot_github_email: ${{ secrets.REQUIREMENTS_BOT_GITHUB_EMAIL }} | ||
| edx_smtp_username: ${{ secrets.EDX_SMTP_USERNAME }} | ||
| edx_smtp_password: ${{ secrets.EDX_SMTP_PASSWORD }} | ||
| update-dependencies: | ||
| runs-on: ubuntu-24.04 | ||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v4 | ||
|
|
||
| - name: Update uv.lock | ||
| run: uv lock --upgrade | ||
|
|
||
| - name: Create Pull Request | ||
| uses: peter-evans/create-pull-request@v6 | ||
| with: | ||
| token: ${{ secrets.REQUIREMENTS_BOT_GITHUB_TOKEN }} | ||
| commit-message: "chore: update uv.lock with latest dependency versions" | ||
| title: "chore: update dependencies" | ||
| body: "Automated dependency update via `uv lock --upgrade`." | ||
| branch: "chore/update-dependencies" | ||
| delete-branch: true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,26 +1,40 @@ | ||
| FROM ubuntu:xenial as openedx | ||
| FROM python:3.11-slim AS base | ||
|
|
||
| RUN apt update && \ | ||
| apt install -y git-core language-pack-en apparmor apparmor-utils python python-pip python-dev && \ | ||
| pip install --upgrade pip setuptools && \ | ||
| rm -rf /var/lib/apt/lists/* | ||
| ENV PYTHONDONTWRITEBYTECODE=1 \ | ||
| PYTHONUNBUFFERED=1 \ | ||
| LANG=C.UTF-8 \ | ||
| LC_ALL=C.UTF-8 | ||
|
|
||
| RUN locale-gen en_US.UTF-8 | ||
| ENV LANG en_US.UTF-8 | ||
| ENV LANGUAGE en_US:en | ||
| ENV LC_ALL en_US.UTF-8 | ||
| RUN apt-get update && \ | ||
| apt-get install -y --no-install-recommends git-core && \ | ||
| rm -rf /var/lib/apt/lists/* | ||
|
|
||
| RUN useradd -m --shell /bin/false app | ||
|
|
||
| COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv | ||
|
|
||
|
|
||
| WORKDIR /edx/app/xqueue_watcher | ||
| COPY requirements /edx/app/xqueue_watcher/requirements | ||
| RUN pip install -r requirements/production.txt | ||
|
|
||
| CMD python -m xqueue_watcher -d /edx/etc/xqueue_watcher | ||
| COPY pyproject.toml uv.lock ./ | ||
| RUN uv sync --frozen --no-dev --no-install-project | ||
|
|
||
blarghmatey marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| COPY . /edx/app/xqueue_watcher | ||
| RUN uv sync --frozen --no-dev && \ | ||
| ln -s /edx/app/xqueue_watcher/.venv/bin/xqueue-watcher /usr/local/bin/xqueue-watcher | ||
| # Note: the `codejail` optional extra (edx-codejail) is intentionally omitted | ||
| # from this image. In the Kubernetes deployment, student code runs inside an | ||
| # isolated container (ContainerGrader) — the container boundary provides the | ||
| # sandbox via Linux namespaces, cgroups, capability dropping, network isolation, | ||
| # and a read-only filesystem. codejail (AppArmor + OS-level user-switching) | ||
| # requires host-level AppArmor configuration that is unavailable inside | ||
| # Kubernetes pods and adds no meaningful security benefit on top of container | ||
| # isolation. Install the `codejail` extra only when running the legacy | ||
| # JailedGrader on a bare-metal or VM host with AppArmor configured. | ||
|
|
||
|
|
||
| RUN useradd -m --shell /bin/false app | ||
| USER app | ||
|
|
||
| COPY . /edx/app/xqueue_watcher | ||
| CMD ["xqueue-watcher", "-d", "/etc/xqueue-watcher"] | ||
|
|
||
blarghmatey marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| FROM openedx as edx.org | ||
| RUN pip install newrelic | ||
| CMD newrelic-admin run-program python -m xqueue_watcher -d /edx/etc/xqueue_watcher | ||
| FROM base AS edx.org | ||
| USER app | ||
| CMD ["xqueue-watcher", "-d", "/etc/xqueue-watcher"] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,47 +1,29 @@ | ||
| NODE_BIN=./node_modules/.bin | ||
|
|
||
| help: | ||
| @echo ' ' | ||
| @echo 'Makefile for the xqueue-watcher ' | ||
| @echo ' ' | ||
| @echo 'Usage: ' | ||
| @echo ' make requirements install requirements for local development ' | ||
| @echo ' make test run python unit-tests ' | ||
| @echo ' make clean delete generated byte code and coverage reports ' | ||
| @echo ' ' | ||
|
|
||
| COMMON_CONSTRAINTS_TXT=requirements/common_constraints.txt | ||
| .PHONY: $(COMMON_CONSTRAINTS_TXT) | ||
| $(COMMON_CONSTRAINTS_TXT): | ||
| wget -O "$(@)" https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt || touch "$(@)" | ||
|
|
||
| upgrade: export CUSTOM_COMPILE_COMMAND=make upgrade | ||
| upgrade: $(COMMON_CONSTRAINTS_TXT) | ||
| ## update the requirements/*.txt files with the latest packages satisfying requirements/*.in | ||
| pip install -q -r requirements/pip_tools.txt | ||
| pip-compile --allow-unsafe --rebuild --upgrade -o requirements/pip.txt requirements/pip.in | ||
| pip-compile --upgrade -o requirements/pip_tools.txt requirements/pip_tools.in | ||
| pip install -q -r requirements/pip.txt | ||
| pip install -q -r requirements/pip_tools.txt | ||
| pip-compile --upgrade -o requirements/base.txt requirements/base.in | ||
| pip-compile --upgrade -o requirements/production.txt requirements/production.in | ||
| pip-compile --upgrade -o requirements/test.txt requirements/test.in | ||
| pip-compile --upgrade -o requirements/ci.txt requirements/ci.in | ||
| @echo '' | ||
| @echo 'Makefile for the xqueue-watcher' | ||
| @echo '' | ||
| @echo 'Usage:' | ||
blarghmatey marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| @echo ' make requirements sync dev dependencies with uv' | ||
| @echo ' make test run python unit-tests' | ||
| @echo ' make docker-build build the grader base Docker image' | ||
| @echo ' make local-run run locally with docker-compose' | ||
| @echo ' make clean delete generated byte code' | ||
| @echo '' | ||
|
|
||
| requirements: | ||
| pip install -qr requirements/production.txt --exists-action w | ||
| uv sync | ||
|
|
||
| test.requirements: | ||
| pip install -q -r requirements/test.txt --exists-action w | ||
| test: requirements | ||
| uv run pytest --cov=xqueue_watcher --cov-report=xml tests | ||
|
|
||
| ci.requirements: | ||
| pip install -q -r requirements/ci.txt --exists-action w | ||
| docker-build: | ||
| docker build -t xqueue-watcher:local . | ||
| docker build -t grader-base:local -f grader_support/Dockerfile.base . | ||
|
|
||
| test: test.requirements | ||
| pytest --cov=xqueue_watcher --cov-report=xml tests | ||
| local-run: | ||
| docker compose up | ||
|
|
||
| clean: | ||
| find . -name '*.pyc' -delete | ||
|
|
||
| # Targets in a Makefile which do not produce an output file with the same name as the target name | ||
| .PHONY: help requirements clean | ||
| .PHONY: help requirements test docker-build local-run clean | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| apiVersion: v1 | ||
| kind: ConfigMap | ||
| metadata: | ||
| name: xqueue-watcher-config | ||
| namespace: xqueue-watcher | ||
| labels: | ||
| app.kubernetes.io/name: xqueue-watcher | ||
| app.kubernetes.io/component: watcher | ||
| data: | ||
| # Main watcher settings. See xqueue_watcher/settings.py for all keys. | ||
| xqwatcher.json: | | ||
| { | ||
| "POLL_INTERVAL": 1, | ||
| "LOGIN_POLL_INTERVAL": 5, | ||
| "REQUESTS_TIMEOUT": 5, | ||
| "POLL_TIME": 10 | ||
| } | ||
|
|
||
| # Logging configuration | ||
| logging.json: | | ||
| { | ||
| "version": 1, | ||
| "disable_existing_loggers": false, | ||
| "formatters": { | ||
| "standard": { | ||
| "format": "%(asctime)s %(levelname)s %(name)s %(message)s" | ||
| } | ||
| }, | ||
| "handlers": { | ||
| "console": { | ||
| "class": "logging.StreamHandler", | ||
| "formatter": "standard", | ||
| "stream": "ext://sys.stdout" | ||
| } | ||
| }, | ||
| "root": { | ||
| "handlers": ["console"], | ||
| "level": "INFO" | ||
| } | ||
| } | ||
|
|
||
| # Example queue config — copy this pattern for each course queue. | ||
| # Real configs live in conf.d/ mounted from a separate ConfigMap or Secret. | ||
| example-queue.json.sample: | | ||
| { | ||
| "my-course-queue": { | ||
| "SERVER": "http://xqueue:18040", | ||
| "CONNECTIONS": 2, | ||
| "AUTH": ["xqueue_user", "xqueue_pass"], | ||
| "HANDLERS": [ | ||
| { | ||
| "HANDLER": "xqueue_watcher.containergrader.ContainerGrader", | ||
| "KWARGS": { | ||
| "grader_root": "/graders/my-course/", | ||
| "image": "registry.example.com/my-course-grader:latest", | ||
| "backend": "kubernetes", | ||
| "namespace": "xqueue-watcher", | ||
| "cpu_limit": "500m", | ||
| "memory_limit": "256Mi", | ||
| "timeout": 20 | ||
| } | ||
| } | ||
| ] | ||
| } | ||
| } | ||
| --- | ||
| # Queue-specific configurations: one JSON file per course queue. | ||
| # Operators replace or extend this with real queue names, server URLs, | ||
| # and grader images. AUTH credentials should be injected from a Secret | ||
| # (e.g., via Vault Secrets Operator) rather than stored in this ConfigMap. | ||
| apiVersion: v1 | ||
| kind: ConfigMap | ||
| metadata: | ||
| name: xqueue-watcher-queue-configs | ||
| namespace: xqueue-watcher | ||
| labels: | ||
| app.kubernetes.io/name: xqueue-watcher | ||
| app.kubernetes.io/component: queue-config | ||
| data: | ||
| # Replace with your actual queue configs. Each key becomes a file in | ||
| # /etc/xqueue-watcher/conf.d/ and must end in .json to be picked up. | ||
| example-queue.json: | | ||
| { | ||
| "my-course-queue": { | ||
| "SERVER": "http://xqueue:18040", | ||
| "CONNECTIONS": 2, | ||
| "AUTH": ["xqueue_user", "xqueue_pass"], | ||
| "HANDLERS": [ | ||
| { | ||
| "HANDLER": "xqueue_watcher.containergrader.ContainerGrader", | ||
| "KWARGS": { | ||
| "grader_root": "/graders/my-course/", | ||
| "image": "registry.example.com/my-course-grader:latest", | ||
| "backend": "kubernetes", | ||
| "namespace": "xqueue-watcher", | ||
| "cpu_limit": "500m", | ||
| "memory_limit": "256Mi", | ||
| "timeout": 20 | ||
| } | ||
| } | ||
| ] | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.