415 lines
13 KiB
Markdown
415 lines
13 KiB
Markdown
|
|
# Extension Registry Service
|
||
|
|
|
||
|
|
A high-performance Rust microservice that provides a unified REST API for extension discovery, versioning, and download from multiple Git-based sources and OCI registries.
|
||
|
|
|
||
|
|
> **Source**: `provisioning/platform/crates/extension-registry/`
|
||
|
|
|
||
|
|
## Features
|
||
|
|
|
||
|
|
- **Multi-Backend Source Support**: Fetch extensions from Gitea, Forgejo, and GitHub releases
|
||
|
|
- **Multi-Registry Distribution Support**: Distribute extensions to Zot, Harbor, Docker Hub, GHCR, Quay, and other OCI-compliant registries
|
||
|
|
- **Unified REST API**: Single API for all extension operations across all backends
|
||
|
|
- **Smart Caching**: LRU cache with TTL to reduce backend API calls
|
||
|
|
- **Prometheus Metrics**: Built-in metrics for monitoring
|
||
|
|
- **Health Monitoring**: Parallel health checks for all backends with aggregated status
|
||
|
|
- **Aggregation & Fallback**: Intelligent request routing with aggregation and fallback strategies
|
||
|
|
- **Type-Safe**: Strong typing for extension metadata
|
||
|
|
- **Async/Await**: High-performance async operations with Tokio
|
||
|
|
- **Backward Compatible**: Old single-instance configs auto-migrate to new multi-instance format
|
||
|
|
|
||
|
|
## Architecture
|
||
|
|
|
||
|
|
### Dual-Trait System
|
||
|
|
|
||
|
|
The extension registry uses a trait-based architecture separating source and distribution backends:
|
||
|
|
|
||
|
|
```plaintext
|
||
|
|
┌────────────────────────────────────────────────────────────────────┐
|
||
|
|
│ Extension Registry API │
|
||
|
|
│ (axum) │
|
||
|
|
├────────────────────────────────────────────────────────────────────┤
|
||
|
|
│ │
|
||
|
|
│ ┌─ SourceClients ────────────┐ ┌─ DistributionClients ────────┐ │
|
||
|
|
│ │ │ │ │ │
|
||
|
|
│ │ • Gitea (Git releases) │ │ • OCI Registries │ │
|
||
|
|
│ │ • Forgejo (Git releases) │ │ - Zot │ │
|
||
|
|
│ │ • GitHub (Releases API) │ │ - Harbor │ │
|
||
|
|
│ │ │ │ - Docker Hub │ │
|
||
|
|
│ │ Strategy: Aggregation + │ │ - GHCR / Quay │ │
|
||
|
|
│ │ Fallback across all sources │ │ - Any OCI-compliant │ │
|
||
|
|
│ │ │ │ │ │
|
||
|
|
│ └─────────────────────────────┘ └──────────────────────────────┘ │
|
||
|
|
│ │
|
||
|
|
│ ┌─ LRU Cache ───────────────────────────────────────────────────┐ │
|
||
|
|
│ │ • Metadata cache (with TTL) │ │
|
||
|
|
│ │ • List cache (with TTL) │ │
|
||
|
|
│ │ • Version cache (version strings only) │ │
|
||
|
|
│ └───────────────────────────────────────────────────────────────┘ │
|
||
|
|
│ │
|
||
|
|
└────────────────────────────────────────────────────────────────────┘
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
### Request Strategies
|
||
|
|
|
||
|
|
#### Aggregation Strategy (list_extensions, list_versions, search)
|
||
|
|
|
||
|
|
1. **Parallel Execution**: Spawn concurrent tasks for all source and distribution clients
|
||
|
|
2. **Merge Results**: Combine results from all backends
|
||
|
|
3. **Deduplication**: Remove duplicates, preferring more recent versions
|
||
|
|
4. **Pagination**: Apply limit/offset to merged results
|
||
|
|
5. **Caching**: Store merged results with composite cache key
|
||
|
|
|
||
|
|
#### Fallback Strategy (get_extension, download_extension)
|
||
|
|
|
||
|
|
1. **Sequential Retry**: Try source clients first (in configured order)
|
||
|
|
2. **Distribution Fallback**: If all sources fail, try distribution clients
|
||
|
|
3. **Return First Success**: Return result from first successful client
|
||
|
|
4. **Caching**: Cache successful result with backend-specific key
|
||
|
|
|
||
|
|
## Installation
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd provisioning/platform/extension-registry
|
||
|
|
cargo build --release
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
## Configuration
|
||
|
|
|
||
|
|
### Single-Instance Configuration (Legacy - Auto-Migrated)
|
||
|
|
|
||
|
|
Old format is automatically migrated to new multi-instance format:
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[server]
|
||
|
|
host = "0.0.0.0"
|
||
|
|
port = 8082
|
||
|
|
|
||
|
|
# Single Gitea instance (auto-migrated to sources.gitea[0])
|
||
|
|
[gitea]
|
||
|
|
url = "https://gitea.example.com"
|
||
|
|
organization = "provisioning-extensions"
|
||
|
|
token_path = "/path/to/gitea-token.txt"
|
||
|
|
|
||
|
|
# Single OCI registry (auto-migrated to distributions.oci[0])
|
||
|
|
[oci]
|
||
|
|
registry = "registry.example.com"
|
||
|
|
namespace = "provisioning"
|
||
|
|
auth_token_path = "/path/to/oci-token.txt"
|
||
|
|
|
||
|
|
[cache]
|
||
|
|
capacity = 1000
|
||
|
|
ttl_seconds = 300
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
### Multi-Instance Configuration (Recommended)
|
||
|
|
|
||
|
|
New format supporting multiple backends of each type:
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[server]
|
||
|
|
host = "0.0.0.0"
|
||
|
|
port = 8082
|
||
|
|
workers = 4
|
||
|
|
enable_cors = false
|
||
|
|
enable_compression = true
|
||
|
|
|
||
|
|
# Multiple Gitea sources
|
||
|
|
[sources.gitea]
|
||
|
|
|
||
|
|
[[sources.gitea]]
|
||
|
|
id = "internal-gitea"
|
||
|
|
url = "https://gitea.internal.example.com"
|
||
|
|
organization = "provisioning"
|
||
|
|
token_path = "/etc/secrets/gitea-internal-token.txt"
|
||
|
|
timeout_seconds = 30
|
||
|
|
verify_ssl = true
|
||
|
|
|
||
|
|
[[sources.gitea]]
|
||
|
|
id = "public-gitea"
|
||
|
|
url = "https://gitea.public.example.com"
|
||
|
|
organization = "extensions"
|
||
|
|
token_path = "/etc/secrets/gitea-public-token.txt"
|
||
|
|
timeout_seconds = 30
|
||
|
|
verify_ssl = true
|
||
|
|
|
||
|
|
# Forgejo sources (API compatible with Gitea)
|
||
|
|
[sources.forgejo]
|
||
|
|
|
||
|
|
[[sources.forgejo]]
|
||
|
|
id = "community-forgejo"
|
||
|
|
url = "https://forgejo.community.example.com"
|
||
|
|
organization = "provisioning"
|
||
|
|
token_path = "/etc/secrets/forgejo-token.txt"
|
||
|
|
timeout_seconds = 30
|
||
|
|
verify_ssl = true
|
||
|
|
|
||
|
|
# GitHub sources
|
||
|
|
[sources.github]
|
||
|
|
|
||
|
|
[[sources.github]]
|
||
|
|
id = "org-github"
|
||
|
|
organization = "my-organization"
|
||
|
|
token_path = "/etc/secrets/github-token.txt"
|
||
|
|
timeout_seconds = 30
|
||
|
|
verify_ssl = true
|
||
|
|
|
||
|
|
# Multiple OCI distribution registries
|
||
|
|
[distributions.oci]
|
||
|
|
|
||
|
|
[[distributions.oci]]
|
||
|
|
id = "internal-zot"
|
||
|
|
registry = "zot.internal.example.com"
|
||
|
|
namespace = "extensions"
|
||
|
|
timeout_seconds = 30
|
||
|
|
verify_ssl = true
|
||
|
|
|
||
|
|
[[distributions.oci]]
|
||
|
|
id = "public-harbor"
|
||
|
|
registry = "harbor.public.example.com"
|
||
|
|
namespace = "extensions"
|
||
|
|
auth_token_path = "/etc/secrets/harbor-token.txt"
|
||
|
|
timeout_seconds = 30
|
||
|
|
verify_ssl = true
|
||
|
|
|
||
|
|
[[distributions.oci]]
|
||
|
|
id = "docker-hub"
|
||
|
|
registry = "docker.io"
|
||
|
|
namespace = "myorg"
|
||
|
|
auth_token_path = "/etc/secrets/docker-hub-token.txt"
|
||
|
|
timeout_seconds = 30
|
||
|
|
verify_ssl = true
|
||
|
|
|
||
|
|
# Cache configuration
|
||
|
|
[cache]
|
||
|
|
capacity = 1000
|
||
|
|
ttl_seconds = 300
|
||
|
|
enable_metadata_cache = true
|
||
|
|
enable_list_cache = true
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
### Configuration Notes
|
||
|
|
|
||
|
|
- **Backend Identifiers**: Use `id` field to uniquely identify each backend instance (auto-generated if omitted)
|
||
|
|
- **Gitea/Forgejo Compatible**: Both use same config format; organization field is required for Git repos
|
||
|
|
- **GitHub Configuration**: Uses organization as owner; token_path points to GitHub Personal Access Token
|
||
|
|
- **OCI Registries**: Support any OCI-compliant registry (Zot, Harbor, Docker Hub, GHCR, Quay, etc.)
|
||
|
|
- **Optional Fields**: `id`, `verify_ssl`, `timeout_seconds` have sensible defaults
|
||
|
|
- **Token Files**: Should contain only the token with no extra whitespace; permissions should be `0600`
|
||
|
|
|
||
|
|
### Environment Variable Overrides
|
||
|
|
|
||
|
|
Legacy environment variable support (for backward compatibility):
|
||
|
|
|
||
|
|
```bash
|
||
|
|
REGISTRY_SERVER_HOST=127.0.0.1
|
||
|
|
REGISTRY_SERVER_PORT=8083
|
||
|
|
REGISTRY_SERVER_WORKERS=8
|
||
|
|
REGISTRY_GITEA_URL=https://gitea.example.com
|
||
|
|
REGISTRY_GITEA_ORG=extensions
|
||
|
|
REGISTRY_GITEA_TOKEN_PATH=/path/to/token
|
||
|
|
REGISTRY_OCI_REGISTRY=registry.example.com
|
||
|
|
REGISTRY_OCI_NAMESPACE=extensions
|
||
|
|
REGISTRY_CACHE_CAPACITY=2000
|
||
|
|
REGISTRY_CACHE_TTL=600
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
## API Endpoints
|
||
|
|
|
||
|
|
### Extension Operations
|
||
|
|
|
||
|
|
#### List Extensions
|
||
|
|
|
||
|
|
```bash
|
||
|
|
GET /api/v1/extensions?type=provider&limit=10
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
#### Get Extension
|
||
|
|
|
||
|
|
```bash
|
||
|
|
GET /api/v1/extensions/{type}/{name}
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
#### List Versions
|
||
|
|
|
||
|
|
```bash
|
||
|
|
GET /api/v1/extensions/{type}/{name}/versions
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
#### Download Extension
|
||
|
|
|
||
|
|
```bash
|
||
|
|
GET /api/v1/extensions/{type}/{name}/{version}
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
#### Search Extensions
|
||
|
|
|
||
|
|
```bash
|
||
|
|
GET /api/v1/extensions/search?q=kubernetes&type=taskserv
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
### System Endpoints
|
||
|
|
|
||
|
|
#### Health Check
|
||
|
|
|
||
|
|
```bash
|
||
|
|
GET /api/v1/health
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
**Response** (with multi-backend aggregation):
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"status": "healthy|degraded|unhealthy",
|
||
|
|
"version": "0.1.0",
|
||
|
|
"uptime": 3600,
|
||
|
|
"backends": {
|
||
|
|
"gitea": {
|
||
|
|
"enabled": true,
|
||
|
|
"healthy": true,
|
||
|
|
"error": null
|
||
|
|
},
|
||
|
|
"oci": {
|
||
|
|
"enabled": true,
|
||
|
|
"healthy": true,
|
||
|
|
"error": null
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
**Status Values**:
|
||
|
|
- `healthy`: All configured backends are healthy
|
||
|
|
- `degraded`: At least one backend is healthy, but some are failing
|
||
|
|
- `unhealthy`: No backends are responding
|
||
|
|
|
||
|
|
#### Metrics
|
||
|
|
|
||
|
|
```bash
|
||
|
|
GET /api/v1/metrics
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
#### Cache Statistics
|
||
|
|
|
||
|
|
```bash
|
||
|
|
GET /api/v1/cache/stats
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
**Response**:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"metadata_hits": 1024,
|
||
|
|
"metadata_misses": 256,
|
||
|
|
"list_hits": 512,
|
||
|
|
"list_misses": 128,
|
||
|
|
"version_hits": 2048,
|
||
|
|
"version_misses": 512,
|
||
|
|
"size": 4096
|
||
|
|
}
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
## Extension Naming Conventions
|
||
|
|
|
||
|
|
### Gitea Repositories
|
||
|
|
|
||
|
|
- **Providers**: `{name}_prov` (for example, `aws_prov`)
|
||
|
|
- **Task Services**: `{name}_taskserv` (for example, `kubernetes_taskserv`)
|
||
|
|
- **Clusters**: `{name}_cluster` (for example, `buildkit_cluster`)
|
||
|
|
|
||
|
|
### OCI Artifacts
|
||
|
|
|
||
|
|
- **Providers**: `{namespace}/{name}-provider`
|
||
|
|
- **Task Services**: `{namespace}/{name}-taskserv`
|
||
|
|
- **Clusters**: `{namespace}/{name}-cluster`
|
||
|
|
|
||
|
|
## Deployment
|
||
|
|
|
||
|
|
### Docker
|
||
|
|
|
||
|
|
```bash
|
||
|
|
docker build -t extension-registry:latest .
|
||
|
|
docker run -d -p 8082:8082 -v $(pwd)/config.toml:/app/config.toml:ro extension-registry:latest
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
### Kubernetes
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
apiVersion: apps/v1
|
||
|
|
kind: Deployment
|
||
|
|
metadata:
|
||
|
|
name: extension-registry
|
||
|
|
spec:
|
||
|
|
replicas: 3
|
||
|
|
template:
|
||
|
|
spec:
|
||
|
|
containers:
|
||
|
|
- name: extension-registry
|
||
|
|
image: extension-registry:latest
|
||
|
|
ports:
|
||
|
|
- containerPort: 8082
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
## Migration Guide: Single to Multi-Instance
|
||
|
|
|
||
|
|
### Automatic Migration
|
||
|
|
|
||
|
|
Old single-instance configs are automatically detected and migrated to the new multi-instance format during startup:
|
||
|
|
|
||
|
|
1. **Detection**: Registry checks if old-style fields (`gitea`, `oci`) contain values
|
||
|
|
2. **Migration**: Single instances are moved to new Vec-based format (`sources.gitea[0]`, `distributions.oci[0]`)
|
||
|
|
3. **Logging**: Migration event is logged for audit purposes
|
||
|
|
4. **Transparency**: No user action required; old configs continue to work
|
||
|
|
|
||
|
|
### Before Migration
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[gitea]
|
||
|
|
url = "https://gitea.example.com"
|
||
|
|
organization = "extensions"
|
||
|
|
token_path = "/path/to/token"
|
||
|
|
|
||
|
|
[oci]
|
||
|
|
registry = "registry.example.com"
|
||
|
|
namespace = "extensions"
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
### After Migration (Automatic)
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[sources.gitea]
|
||
|
|
[[sources.gitea]]
|
||
|
|
url = "https://gitea.example.com"
|
||
|
|
organization = "extensions"
|
||
|
|
token_path = "/path/to/token"
|
||
|
|
|
||
|
|
[distributions.oci]
|
||
|
|
[[distributions.oci]]
|
||
|
|
registry = "registry.example.com"
|
||
|
|
namespace = "extensions"
|
||
|
|
```plaintext
|
||
|
|
|
||
|
|
### Gradual Upgrade Path
|
||
|
|
|
||
|
|
To adopt the new format manually:
|
||
|
|
|
||
|
|
1. **Backup current config** - Keep old format as reference
|
||
|
|
2. **Adopt new format** - Replace old fields with new structure
|
||
|
|
3. **Test** - Verify all backends are reachable and extensions are discovered
|
||
|
|
4. **Add new backends** - Use new format to add Forgejo, GitHub, or additional OCI registries
|
||
|
|
5. **Remove old fields** - Delete deprecated `gitea` and `oci` top-level sections
|
||
|
|
|
||
|
|
### Benefits of Upgrading
|
||
|
|
|
||
|
|
- **Multiple Sources**: Support Gitea, Forgejo, and GitHub simultaneously
|
||
|
|
- **Multiple Registries**: Distribute to multiple OCI registries
|
||
|
|
- **Better Resilience**: If one backend fails, others continue to work
|
||
|
|
- **Flexible Configuration**: Each backend can have different credentials and timeouts
|
||
|
|
- **Future-Proof**: New backends can be added without config restructuring
|
||
|
|
|
||
|
|
## Related Documentation
|
||
|
|
|
||
|
|
- **Extension Development**: [Module System](../development/extensions.md)
|
||
|
|
- **Extension Development Quickstart**: [Getting Started Guide](../guides/extension-development-quickstart.md)
|
||
|
|
- **ADR-005**: [Extension Framework Architecture](../architecture/adr/adr-005-extension-framework.md)
|
||
|
|
- **OCI Registry Integration**: [OCI Registry Guide](../integration/oci-registry-guide.md)
|