Add Tag, TagKind and ManifestChild tables in prep for new data model
This commit is contained in:
parent
053d918d67
commit
c0653ef2ad
3 changed files with 156 additions and 3 deletions
|
@ -1385,6 +1385,58 @@ class Manifest(BaseModel):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TagKind(BaseModel):
|
||||||
|
""" TagKind describes the various kinds of tags that can be found in the registry.
|
||||||
|
"""
|
||||||
|
name = CharField(index=True, unique=True)
|
||||||
|
|
||||||
|
|
||||||
|
class Tag(BaseModel):
|
||||||
|
""" Tag represents a user-facing alias for referencing a Manifest or as an alias to another tag.
|
||||||
|
"""
|
||||||
|
name = CharField()
|
||||||
|
repository = ForeignKeyField(Repository)
|
||||||
|
manifest = ForeignKeyField(Manifest, null=True)
|
||||||
|
lifetime_start_ms = BigIntegerField(default=get_epoch_timestamp_ms)
|
||||||
|
lifetime_end_ms = BigIntegerField(null=True, index=True)
|
||||||
|
hidden = BooleanField(default=False)
|
||||||
|
reverted = BooleanField(default=False)
|
||||||
|
tag_kind = EnumField(TagKind)
|
||||||
|
linked_tag = ForeignKeyField('self', null=True, backref='tag_parents')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
database = db
|
||||||
|
read_slaves = (read_slave,)
|
||||||
|
indexes = (
|
||||||
|
(('repository', 'name'), False),
|
||||||
|
(('repository', 'name', 'hidden'), False),
|
||||||
|
(('repository', 'name', 'tag_kind'), False),
|
||||||
|
|
||||||
|
# This unique index prevents deadlocks when concurrently moving and deleting tags
|
||||||
|
(('repository', 'name', 'lifetime_end_ms'), True),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ManifestChild(BaseModel):
|
||||||
|
""" ManifestChild represents a relationship between a manifest and its child manifest(s).
|
||||||
|
Multiple manifests can share the same children. Note that since Manifests are stored
|
||||||
|
per-repository, the repository here is a bit redundant, but we do so to make cleanup easier.
|
||||||
|
"""
|
||||||
|
repository = ForeignKeyField(Repository)
|
||||||
|
manifest = ForeignKeyField(Manifest)
|
||||||
|
child_manifest = ForeignKeyField(Manifest)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
database = db
|
||||||
|
read_slaves = (read_slave,)
|
||||||
|
indexes = (
|
||||||
|
(('repository', 'manifest'), False),
|
||||||
|
(('repository', 'child_manifest'), False),
|
||||||
|
(('repository', 'manifest', 'child_manifest'), False),
|
||||||
|
(('manifest', 'child_manifest'), True),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ManifestLabel(BaseModel):
|
class ManifestLabel(BaseModel):
|
||||||
""" ManifestLabel represents a label applied to a Manifest, within a repository.
|
""" ManifestLabel represents a label applied to a Manifest, within a repository.
|
||||||
Note that since Manifests are stored per-repository, the repository here is
|
Note that since Manifests are stored per-repository, the repository here is
|
||||||
|
@ -1470,7 +1522,8 @@ class TagManifestLabelMap(BaseModel):
|
||||||
appr_classes = set([ApprTag, ApprTagKind, ApprBlobPlacementLocation, ApprManifestList,
|
appr_classes = set([ApprTag, ApprTagKind, ApprBlobPlacementLocation, ApprManifestList,
|
||||||
ApprManifestBlob, ApprBlob, ApprManifestListManifest, ApprManifest,
|
ApprManifestBlob, ApprBlob, ApprManifestListManifest, ApprManifest,
|
||||||
ApprBlobPlacement])
|
ApprBlobPlacement])
|
||||||
v22_classes = set([Manifest, ManifestLabel, ManifestBlob, ManifestLegacyImage])
|
v22_classes = set([Manifest, ManifestLabel, ManifestBlob, ManifestLegacyImage, TagKind,
|
||||||
|
ManifestChild, Tag])
|
||||||
transition_classes = set([TagManifestToManifest, TagManifestLabelMap])
|
transition_classes = set([TagManifestToManifest, TagManifestLabelMap])
|
||||||
|
|
||||||
is_model = lambda x: inspect.isclass(x) and issubclass(x, BaseModel) and x is not BaseModel
|
is_model = lambda x: inspect.isclass(x) and issubclass(x, BaseModel) and x is not BaseModel
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
"""Add Tag, TagKind and ManifestChild tables
|
||||||
|
|
||||||
|
Revision ID: 10f45ee2310b
|
||||||
|
Revises: 13411de1c0ff
|
||||||
|
Create Date: 2018-10-29 15:22:53.552216
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '10f45ee2310b'
|
||||||
|
down_revision = '13411de1c0ff'
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from util.migrate import UTF8CharField
|
||||||
|
|
||||||
|
def upgrade(tables, tester):
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('tagkind',
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('name', sa.String(length=255), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint('id', name=op.f('pk_tagkind'))
|
||||||
|
)
|
||||||
|
op.create_index('tagkind_name', 'tagkind', ['name'], unique=True)
|
||||||
|
op.create_table('manifestchild',
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('repository_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('manifest_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('child_manifest_id', sa.Integer(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['child_manifest_id'], ['manifest.id'], name=op.f('fk_manifestchild_child_manifest_id_manifest')),
|
||||||
|
sa.ForeignKeyConstraint(['manifest_id'], ['manifest.id'], name=op.f('fk_manifestchild_manifest_id_manifest')),
|
||||||
|
sa.ForeignKeyConstraint(['repository_id'], ['repository.id'], name=op.f('fk_manifestchild_repository_id_repository')),
|
||||||
|
sa.PrimaryKeyConstraint('id', name=op.f('pk_manifestchild'))
|
||||||
|
)
|
||||||
|
op.create_index('manifestchild_child_manifest_id', 'manifestchild', ['child_manifest_id'], unique=False)
|
||||||
|
op.create_index('manifestchild_manifest_id', 'manifestchild', ['manifest_id'], unique=False)
|
||||||
|
op.create_index('manifestchild_manifest_id_child_manifest_id', 'manifestchild', ['manifest_id', 'child_manifest_id'], unique=True)
|
||||||
|
op.create_index('manifestchild_repository_id', 'manifestchild', ['repository_id'], unique=False)
|
||||||
|
op.create_index('manifestchild_repository_id_child_manifest_id', 'manifestchild', ['repository_id', 'child_manifest_id'], unique=False)
|
||||||
|
op.create_index('manifestchild_repository_id_manifest_id', 'manifestchild', ['repository_id', 'manifest_id'], unique=False)
|
||||||
|
op.create_index('manifestchild_repository_id_manifest_id_child_manifest_id', 'manifestchild', ['repository_id', 'manifest_id', 'child_manifest_id'], unique=False)
|
||||||
|
op.create_table('tag',
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('name', UTF8CharField(length=255), nullable=False),
|
||||||
|
sa.Column('repository_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('manifest_id', sa.Integer(), nullable=True),
|
||||||
|
sa.Column('lifetime_start_ms', sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column('lifetime_end_ms', sa.BigInteger(), nullable=True),
|
||||||
|
sa.Column('hidden', sa.Boolean(), nullable=False, server_default=sa.sql.expression.false()),
|
||||||
|
sa.Column('reverted', sa.Boolean(), nullable=False, server_default=sa.sql.expression.false()),
|
||||||
|
sa.Column('tag_kind_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('linked_tag_id', sa.Integer(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['linked_tag_id'], ['tag.id'], name=op.f('fk_tag_linked_tag_id_tag')),
|
||||||
|
sa.ForeignKeyConstraint(['manifest_id'], ['manifest.id'], name=op.f('fk_tag_manifest_id_manifest')),
|
||||||
|
sa.ForeignKeyConstraint(['repository_id'], ['repository.id'], name=op.f('fk_tag_repository_id_repository')),
|
||||||
|
sa.ForeignKeyConstraint(['tag_kind_id'], ['tagkind.id'], name=op.f('fk_tag_tag_kind_id_tagkind')),
|
||||||
|
sa.PrimaryKeyConstraint('id', name=op.f('pk_tag'))
|
||||||
|
)
|
||||||
|
op.create_index('tag_lifetime_end_ms', 'tag', ['lifetime_end_ms'], unique=False)
|
||||||
|
op.create_index('tag_linked_tag_id', 'tag', ['linked_tag_id'], unique=False)
|
||||||
|
op.create_index('tag_manifest_id', 'tag', ['manifest_id'], unique=False)
|
||||||
|
op.create_index('tag_repository_id', 'tag', ['repository_id'], unique=False)
|
||||||
|
op.create_index('tag_repository_id_name', 'tag', ['repository_id', 'name'], unique=False)
|
||||||
|
op.create_index('tag_repository_id_name_hidden', 'tag', ['repository_id', 'name', 'hidden'], unique=False)
|
||||||
|
op.create_index('tag_repository_id_name_lifetime_end_ms', 'tag', ['repository_id', 'name', 'lifetime_end_ms'], unique=True)
|
||||||
|
op.create_index('tag_repository_id_name_tag_kind_id', 'tag', ['repository_id', 'name', 'tag_kind_id'], unique=False)
|
||||||
|
op.create_index('tag_tag_kind_id', 'tag', ['tag_kind_id'], unique=False)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
op.bulk_insert(tables.tagkind,
|
||||||
|
[
|
||||||
|
{'name': 'tag'},
|
||||||
|
])
|
||||||
|
|
||||||
|
# ### population of test data ### #
|
||||||
|
tester.populate_table('tag', [
|
||||||
|
('repository_id', tester.TestDataType.Foreign('repository')),
|
||||||
|
('tag_kind_id', tester.TestDataType.Foreign('tagkind')),
|
||||||
|
('name', tester.TestDataType.String),
|
||||||
|
('manifest_id', tester.TestDataType.Foreign('manifest')),
|
||||||
|
('lifetime_start_ms', tester.TestDataType.BigInteger),
|
||||||
|
])
|
||||||
|
|
||||||
|
tester.populate_table('manifestchild', [
|
||||||
|
('repository_id', tester.TestDataType.Foreign('repository')),
|
||||||
|
('manifest_id', tester.TestDataType.Foreign('manifest')),
|
||||||
|
('child_manifest_id', tester.TestDataType.Foreign('manifest')),
|
||||||
|
])
|
||||||
|
# ### end population of test data ### #
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(tables, tester):
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_table('tag')
|
||||||
|
op.drop_table('manifestchild')
|
||||||
|
op.drop_table('tagkind')
|
||||||
|
# ### end Alembic commands ###
|
|
@ -20,7 +20,8 @@ from data.database import (db, all_models, Role, TeamRole, Visibility, LoginServ
|
||||||
QuayRegion, QuayService, UserRegion, OAuthAuthorizationCode,
|
QuayRegion, QuayService, UserRegion, OAuthAuthorizationCode,
|
||||||
ServiceKeyApprovalType, MediaType, LabelSourceType, UserPromptKind,
|
ServiceKeyApprovalType, MediaType, LabelSourceType, UserPromptKind,
|
||||||
RepositoryKind, User, DisableReason, DeletedNamespace, appr_classes,
|
RepositoryKind, User, DisableReason, DeletedNamespace, appr_classes,
|
||||||
ApprTagKind, ApprBlobPlacementLocation, Repository)
|
ApprTagKind, ApprBlobPlacementLocation, Repository, Tag, TagKind,
|
||||||
|
ManifestChild)
|
||||||
from data import model
|
from data import model
|
||||||
from data.queue import WorkQueue
|
from data.queue import WorkQueue
|
||||||
from data.registry_model import registry_model
|
from data.registry_model import registry_model
|
||||||
|
@ -450,6 +451,8 @@ def initialize_database():
|
||||||
DisableReason.create(name='successive_build_failures')
|
DisableReason.create(name='successive_build_failures')
|
||||||
DisableReason.create(name='successive_build_internal_errors')
|
DisableReason.create(name='successive_build_internal_errors')
|
||||||
|
|
||||||
|
TagKind.create(name='tag')
|
||||||
|
|
||||||
|
|
||||||
def wipe_database():
|
def wipe_database():
|
||||||
logger.debug('Wiping all data from the DB.')
|
logger.debug('Wiping all data from the DB.')
|
||||||
|
@ -910,7 +913,7 @@ def populate_database(minimal=False, with_storage=False):
|
||||||
model.repositoryactioncount.update_repository_score(to_count)
|
model.repositoryactioncount.update_repository_score(to_count)
|
||||||
|
|
||||||
|
|
||||||
WHITELISTED_EMPTY_MODELS = ['DeletedNamespace', 'LogEntry2']
|
WHITELISTED_EMPTY_MODELS = ['DeletedNamespace', 'LogEntry2', 'Tag', 'ManifestChild']
|
||||||
|
|
||||||
def find_models_missing_data():
|
def find_models_missing_data():
|
||||||
# As a sanity check we are going to make sure that all db tables have some data, unless explicitly
|
# As a sanity check we are going to make sure that all db tables have some data, unless explicitly
|
||||||
|
|
Reference in a new issue