-
Story
-
Resolution: Unresolved
-
Undefined
-
None
-
None
-
None
[Data Model] Add Architecture Filter to RepoMirrorConfig
Summary
Add database schema support for storing architecture filter configuration on repository mirrors. This allows users to specify which architectures (e.g., amd64, arm64) should be mirrored from multi-architecture images, enabling storage savings by excluding unnecessary platforms.
Acceptance Criteria
- [ ] RepoMirrorConfig model includes architecture_filter field storing list of architectures to mirror
- [ ] Empty/null architecture filter means "mirror all architectures" (backwards compatible)
- [ ] Alembic migration creates the new column with proper defaults
- [ ] Migration is reversible (downgrade removes the column)
- [ ] Model functions can read/write architecture filter configuration
- [ ] Existing mirrors without architecture config continue to work unchanged
Technical Requirements
Database Changes
File: data/database.py
Add new field to RepoMirrorConfig class (around line 2056):
class RepoMirrorConfig(BaseModel): # ... existing fields ... # Architecture filter for multi-arch images. JSON array of architecture strings. # Empty array or null means mirror all architectures. # Example: ["amd64", "arm64"] architecture_filter = JSONField(default=[], null=True)
Migration
File: data/migrations/versions/XXXX_add_mirror_architecture_filter.py
Create new Alembic migration following the pattern in 5248ddf35167_repository_mirror.py:
"""Add architecture_filter to repomirrorconfig Revision ID: <generated> Revises: <previous> Create Date: <date> """ import sqlalchemy as sa from alembic import op revision = "<generated>" down_revision = "<previous>" def upgrade(op, tables, tester): op.add_column( "repomirrorconfig", sa.Column("architecture_filter", sa.Text(), nullable=True) ) def downgrade(op, tables, tester): op.drop_column("repomirrorconfig", "architecture_filter")
Model Functions
File: data/model/repo_mirror.py
Add helper functions for architecture filter management:
def get_architecture_filter(repository):
"""
Returns the architecture filter for a repository mirror, or None if not configured.
Returns empty list if mirror should include all architectures.
"""
mirror = get_mirror(repository)
if mirror is None:
return None
return mirror.architecture_filter or []
def set_architecture_filter(repository, architectures):
"""
Sets the architecture filter for a repository mirror.
Args:
repository: Repository model instance
architectures: List of architecture strings (e.g., ["amd64", "arm64"]) or empty list for all
"""
# Validate architectures
valid_archs = {"amd64", "arm64", "ppc64le", "s390x", "386", "riscv64"}
for arch in architectures:
if arch not in valid_archs:
raise ValueError(f"Invalid architecture: {arch}")
mirror = get_mirror(repository)
if mirror is None:
raise ValueError("Repository does not have mirroring configured")
mirror.architecture_filter = architectures
mirror.save()
return mirror
Implementation Notes
Existing Patterns to Follow
- JSONField usage: See external_registry_config in RepoMirrorConfig for JSON field pattern
- Migration pattern: Follow 5248ddf35167_repository_mirror.py for migration structure
- Model functions: Follow patterns in data/model/repo_mirror.py for function signatures and error handling
Architecture Values
Standard OCI architecture values to support:
- amd64 (x86_64)
- arm64 (aarch64)
- ppc64le
- s390x
- 386 (i386/i686)
- riscv64
Edge Cases
- Empty list [] = mirror all architectures (default behavior)
- null = same as empty list (backwards compatibility)
- Single architecture ["amd64"] = only mirror that architecture
- Multiple architectures ["amd64", "arm64"] = mirror selected architectures
Backwards Compatibility
- Existing mirrors without architecture_filter set should continue to work
- Default value ensures all architectures are mirrored if not configured
- No changes to existing mirror behavior unless explicitly configured
Dependencies
- None (foundational story)
Testing Requirements
Unit Tests
File: data/model/test/test_repo_mirror.py (create or extend)
def test_get_architecture_filter_not_configured():
"""Test getting architecture filter when not set returns empty list."""
def test_get_architecture_filter_configured():
"""Test getting architecture filter when set returns correct list."""
def test_set_architecture_filter_valid():
"""Test setting valid architecture filter."""
def test_set_architecture_filter_invalid_arch():
"""Test setting invalid architecture raises ValueError."""
def test_set_architecture_filter_empty_for_all():
"""Test setting empty list mirrors all architectures."""
Migration Tests
Follow pattern from existing migration tests to verify:
- Column is added correctly
- Default value is applied to existing rows
- Downgrade removes column
Definition of Done
- [ ] Code implemented and follows project conventions
- [ ] All acceptance criteria met
- [ ] Unit tests written and passing
- [ ] Migration tested (upgrade and downgrade)
- [ ] No regressions in existing mirroring functionality
- [ ] Code reviewed and approved