mirror of
https://github.com/quay/quay.git
synced 2026-01-27 18:42:52 +03:00
3.9 KiB
3.9 KiB
Architecture & Patterns
Backend Structure
├── app.py # Flask application factory
├── endpoints/
│ ├── api/ # REST API v1
│ │ ├── __init__.py # API setup, decorators, helpers
│ │ ├── repository.py # Repository endpoints
│ │ ├── user.py # User endpoints
│ │ ├── organization.py # Organization endpoints
│ │ └── ...
│ ├── v2/ # OCI/Docker Registry v2
│ │ ├── __init__.py # V2 setup, decorators
│ │ ├── manifest.py # Manifest operations
│ │ ├── blob.py # Blob operations
│ │ └── ...
│ └── decorators.py # Shared permission decorators
├── data/
│ ├── database.py # DB connection, session
│ ├── model/ # SQLAlchemy models
│ └── migrations/ # Alembic migrations
├── auth/
│ ├── permissions.py # Permission classes
│ ├── credentials.py # Credential validation
│ └── registry_jwt_auth.py # JWT for registry
├── storage/
│ ├── cloud.py # S3/GCS storage
│ ├── azurestorage.py # Azure blob storage
│ ├── swift.py # OpenStack Swift
│ └── local.py # Local filesystem
└── workers/ # Background processors
├── gcworker/ # Garbage collection
├── repomirrorworker/ # Repository mirroring
└── securityworker/ # Clair integration
Request Flow
Request → Flask → Middleware → Endpoint Decorator → Handler → Model → Database
│ │
│ └── Permission check (auth/permissions.py)
└── Auth validation (auth/credentials.py)
Key Patterns
Permission Decorators
# endpoints/decorators.py
@require_repo_read # Read access to repository
@require_repo_write # Write access to repository
@require_repo_admin # Admin access to repository
Repository Access
# endpoints/api/__init__.py
from endpoints.api import RepositoryParamResource
class MyEndpoint(RepositoryParamResource):
# Automatically parses namespace/repository from URL
def get(self, namespace, repository):
repo = model.repository.get_repository(namespace, repository)
Data Models
# data/model/repository.py
from data.database import db
def get_repository(namespace, repository):
return Repository.query.filter_by(
namespace_user=namespace,
name=repository
).first()
Error Handling
# endpoints/exception.py
from endpoints.exception import NotFound, Unauthorized, InvalidRequest
if not repo:
raise NotFound()
Workers
Background job processors in workers/:
| Worker | Purpose |
|---|---|
gcworker |
Garbage collection |
repomirrorworker |
Repository mirroring |
securityworker |
Clair vulnerability scanning |
buildlogsarchiver |
Archive build logs |
notificationworker |
Send notifications |
storagereplication |
Geo-replicate storage |
Workers run as gunicorn sub-processes in local dev for hot-reload.
Storage Backends
storage/ implements multiple backends:
cloud.py- S3, GCS, Cloudflare R2azurestorage.py- Azure Blob Storageswift.py- OpenStack Swiftlocal.py- Local filesystem
DistributedStorage in distributedstorage.py handles failover between backends.
Configuration
# config.py - Configuration loading
from util.config import config
# Access config values
db_uri = config.get('DB_URI')
Config validated against JSON Schema in config-tool/utils/generate/schema.json.