From 6622f27c93cf8e75ab18291034551e8691f5accd Mon Sep 17 00:00:00 2001
From: Joseph Schorr <joseph.schorr@coreos.com>
Date: Wed, 23 May 2018 17:08:00 -0400
Subject: [PATCH] Rename oci_model to appr_model

---
 data/{oci_model => appr_model}/__init__.py    |   2 +-
 data/{oci_model => appr_model}/blob.py        |   0
 data/{oci_model => appr_model}/channel.py     |   2 +-
 data/{oci_model => appr_model}/manifest.py    |   2 +-
 .../manifest_list.py                          |   0
 data/{oci_model => appr_model}/package.py     |   2 +-
 data/{oci_model => appr_model}/release.py     |   2 +-
 data/{oci_model => appr_model}/tag.py         |   0
 data/database.py                              | 141 ++-------------
 ..._remove_oci_tables_not_used_by_cnr_the_.py | 167 ++++++++++++++++++
 endpoints/api/repository_models_pre_oci.py    |   7 +-
 endpoints/appr/cnr_backend.py                 |   2 +-
 .../appr/{models_oci.py => models_cnr.py}     |  38 ++--
 endpoints/appr/registry.py                    |   2 +-
 endpoints/appr/test/test_api.py               |   4 +-
 endpoints/appr/test/test_digest_prefix.py     |   2 +-
 initdb.py                                     |   4 +-
 test/test_api_usage.py                        |  12 +-
 util/config/database.py                       |   4 +-
 19 files changed, 222 insertions(+), 171 deletions(-)
 rename data/{oci_model => appr_model}/__init__.py (72%)
 rename data/{oci_model => appr_model}/blob.py (100%)
 rename data/{oci_model => appr_model}/channel.py (97%)
 rename data/{oci_model => appr_model}/manifest.py (97%)
 rename data/{oci_model => appr_model}/manifest_list.py (100%)
 rename data/{oci_model => appr_model}/package.py (97%)
 rename data/{oci_model => appr_model}/release.py (98%)
 rename data/{oci_model => appr_model}/tag.py (100%)
 create mode 100644 data/migrations/versions/5cbbfc95bac7_remove_oci_tables_not_used_by_cnr_the_.py
 rename endpoints/appr/{models_oci.py => models_cnr.py} (88%)

diff --git a/data/oci_model/__init__.py b/data/appr_model/__init__.py
similarity index 72%
rename from data/oci_model/__init__.py
rename to data/appr_model/__init__.py
index 94b4f9bb8..7c9620864 100644
--- a/data/oci_model/__init__.py
+++ b/data/appr_model/__init__.py
@@ -1,4 +1,4 @@
-from data.oci_model import (
+from data.appr_model import (
   blob,
   channel,
   manifest,
diff --git a/data/oci_model/blob.py b/data/appr_model/blob.py
similarity index 100%
rename from data/oci_model/blob.py
rename to data/appr_model/blob.py
diff --git a/data/oci_model/channel.py b/data/appr_model/channel.py
similarity index 97%
rename from data/oci_model/channel.py
rename to data/appr_model/channel.py
index d7e340eb0..e9e3c2d90 100644
--- a/data/oci_model/channel.py
+++ b/data/appr_model/channel.py
@@ -1,5 +1,5 @@
 from data.database import Tag, Channel
-from data.oci_model import tag as tag_model
+from data.appr_model import tag as tag_model
 
 
 def get_channel_releases(repo, channel):
diff --git a/data/oci_model/manifest.py b/data/appr_model/manifest.py
similarity index 97%
rename from data/oci_model/manifest.py
rename to data/appr_model/manifest.py
index a1af680b5..b6c7341ca 100644
--- a/data/oci_model/manifest.py
+++ b/data/appr_model/manifest.py
@@ -5,7 +5,7 @@ import json
 from cnr.models.package_base import get_media_type
 
 from data.database import db_transaction, Manifest, ManifestListManifest, MediaType, Blob, Tag
-from data.oci_model import tag as tag_model
+from data.appr_model import tag as tag_model
 
 
 logger = logging.getLogger(__name__)
diff --git a/data/oci_model/manifest_list.py b/data/appr_model/manifest_list.py
similarity index 100%
rename from data/oci_model/manifest_list.py
rename to data/appr_model/manifest_list.py
diff --git a/data/oci_model/package.py b/data/appr_model/package.py
similarity index 97%
rename from data/oci_model/package.py
rename to data/appr_model/package.py
index 61eae8e20..4e41c6c87 100644
--- a/data/oci_model/package.py
+++ b/data/appr_model/package.py
@@ -4,7 +4,7 @@ from peewee import prefetch
 
 from data import model
 from data.database import Repository, Namespace, Tag, ManifestListManifest
-from data.oci_model import tag as tag_model
+from data.appr_model import tag as tag_model
 
 
 def list_packages_query(namespace=None, media_type=None, search_query=None, username=None):
diff --git a/data/oci_model/release.py b/data/appr_model/release.py
similarity index 98%
rename from data/oci_model/release.py
rename to data/appr_model/release.py
index 890e3e459..82b442f02 100644
--- a/data/oci_model/release.py
+++ b/data/appr_model/release.py
@@ -5,7 +5,7 @@ from cnr.models.package_base import manifest_media_type
 
 from data.database import (db_transaction, get_epoch_timestamp, Manifest, ManifestList, Tag,
                            ManifestListManifest, Blob, ManifestBlob)
-from data.oci_model import (blob as blob_model, manifest as manifest_model,
+from data.appr_model import (blob as blob_model, manifest as manifest_model,
                             manifest_list as manifest_list_model,
                             tag as tag_model)
 
diff --git a/data/oci_model/tag.py b/data/appr_model/tag.py
similarity index 100%
rename from data/oci_model/tag.py
rename to data/appr_model/tag.py
diff --git a/data/database.py b/data/database.py
index 82f472378..e3d249f8b 100644
--- a/data/database.py
+++ b/data/database.py
@@ -471,8 +471,7 @@ class User(BaseModel):
                                  TagManifest, AccessToken, OAuthAccessToken, BlobUpload,
                                  RepositoryNotification, OAuthAuthorizationCode,
                                  RepositoryActionCount, TagManifestLabel, Tag,
-                                 ManifestLabel, BlobUploading, TeamSync,
-                                 RepositorySearchScore, DeletedNamespace} | beta_classes
+                                 TeamSync, RepositorySearchScore, DeletedNamespace} | cnr_classes
       delete_instance_filtered(self, User, delete_nullable, skip_transitive_deletes)
 
 
@@ -620,7 +619,7 @@ class Repository(BaseModel):
     # are cleaned up directly
     skip_transitive_deletes = {RepositoryTag, RepositoryBuild, RepositoryBuildTrigger, BlobUpload,
                                Image, TagManifest, TagManifestLabel, Label, DerivedStorageForImage,
-                               RepositorySearchScore} | beta_classes
+                               RepositorySearchScore} | cnr_classes
 
     delete_instance_filtered(self, Repository, delete_nullable, skip_transitive_deletes)
 
@@ -1239,6 +1238,7 @@ class TagManifestLabel(BaseModel):
 class Blob(BaseModel):
   """ Blob represents a content-addressable object stored outside of the database.
       This model is a part of the new OCI/CNR model set.
+      CNR
   """
   digest = CharField(index=True, unique=True)
   media_type = EnumField(MediaType)
@@ -1249,21 +1249,15 @@ class Blob(BaseModel):
 class BlobPlacementLocation(BaseModel):
   """ BlobPlacementLocation is an enumeration of the possible storage locations for Blobs.
       This model is a part of the new OCI/CNR model set.
+      CNR
   """
   name = CharField(index=True, unique=True)
 
 
-class BlobPlacementLocationPreference(BaseModel):
-  """ BlobPlacementLocationPreference is a location to which a user's data will be replicated.
-      This model is a part of the new OCI/CNR model set.
-  """
-  user = QuayUserField(index=True, allows_robots=False)
-  location = EnumField(BlobPlacementLocation)
-
-
 class BlobPlacement(BaseModel):
   """ BlobPlacement represents the location of a Blob.
       This model is a part of the new OCI/CNR model set.
+      CNR
   """
   blob = ForeignKeyField(Blob)
   location = EnumField(BlobPlacementLocation)
@@ -1276,58 +1270,20 @@ class BlobPlacement(BaseModel):
     )
 
 
-class BlobUploading(BaseModel):
-  """ BlobUploading represents the state of a Blob currently being uploaded.
-      This model is a part of the new OCI/CNR model set.
-  """
-  uuid = CharField(index=True, unique=True)
-  created = DateTimeField(default=datetime.now, index=True)
-  repository = ForeignKeyField(Repository, index=True)
-  location = ForeignKeyField(BlobPlacementLocation)
-  byte_count = IntegerField(default=0)
-  uncompressed_byte_count = IntegerField(null=True)
-  chunk_count = IntegerField(default=0)
-  storage_metadata = JSONField(null=True, default={})
-  sha_state = ResumableSHA256Field(null=True, default=resumablehashlib.sha256)
-  piece_sha_state = ResumableSHA1Field(null=True)
-  piece_hashes = Base64BinaryField(null=True)
-
-  class Meta:
-    database = db
-    read_slaves = (read_slave,)
-    indexes = (
-      (('repository', 'uuid'), True),
-    )
-
-
 class Manifest(BaseModel):
   """ Manifest represents the metadata and collection of blobs that comprise a container image.
       This model is a part of the new OCI/CNR model set.
+      CNR
   """
   digest = CharField(index=True, unique=True)
   media_type = EnumField(MediaType)
   manifest_json = JSONField()
 
 
-class ManifestLabel(BaseModel):
-  """ ManifestLabel represents label metadata annotating a Manifest.
-      This model is a part of the new OCI/CNR model set.
-  """
-  repository = ForeignKeyField(Repository, index=True)
-  annotated = ForeignKeyField(Manifest, index=True)
-  label = ForeignKeyField(Label)
-
-  class Meta:
-    database = db
-    read_slaves = (read_slave,)
-    indexes = (
-      (('repository', 'annotated', 'label'), True),
-    )
-
-
 class ManifestBlob(BaseModel):
   """ ManifestBlob is a many-to-many relation table linking Manifests and Blobs.
       This model is a part of the new OCI/CNR model set.
+      CNR
   """
   manifest = ForeignKeyField(Manifest, index=True)
   blob = ForeignKeyField(Blob, index=True)
@@ -1343,6 +1299,7 @@ class ManifestBlob(BaseModel):
 class ManifestList(BaseModel):
   """ ManifestList represents all of the various manifests that compose a Tag.
       This model is a part of the new OCI/CNR model set.
+      CNR
   """
   digest = CharField(index=True, unique=True)
   manifest_list_json = JSONField()
@@ -1353,6 +1310,7 @@ class ManifestList(BaseModel):
 class TagKind(BaseModel):
   """ TagKind is a enumtable to reference tag kinds.
       This model is a part of the new OCI/CNR model set.
+      CNR
   """
   name = CharField(index=True, unique=True)
 
@@ -1360,6 +1318,7 @@ class TagKind(BaseModel):
 class Tag(BaseModel):
   """ Tag represents a user-facing alias for referencing a ManifestList.
       This model is a part of the new OCI/CNR model set.
+      CNR
   """
   name = CharField()
   repository = ForeignKeyField(Repository)
@@ -1389,6 +1348,7 @@ Channel = Tag.alias()
 class ManifestListManifest(BaseModel):
   """ ManifestListManifest is a many-to-many relation table linking ManifestLists and Manifests.
       This model is a part of the new OCI/CNR model set.
+      CNR
   """
   manifest_list = ForeignKeyField(ManifestList, index=True)
   manifest = ForeignKeyField(Manifest, index=True)
@@ -1406,79 +1366,6 @@ class ManifestListManifest(BaseModel):
     )
 
 
-class ManifestLayer(BaseModel):
-  """ ManifestLayer represents one of the layers that compose a Manifest.
-      This model is a part of the new OCI/CNR model set.
-  """
-  blob = ForeignKeyField(Blob, index=True)
-  manifest = ForeignKeyField(Manifest)
-  manifest_index = IntegerField(index=True) # index 0 is the last command in a Dockerfile
-  metadata_json = JSONField()
-
-  class Meta:
-    database = db
-    read_slaves = (read_slave,)
-    indexes = (
-      (('manifest', 'manifest_index'), True),
-    )
-
-
-class ManifestLayerDockerV1(BaseModel):
-  """ ManifestLayerDockerV1 is the Docker v1 registry protocol metadata for a ManifestLayer.
-      This model is a part of the new OCI/CNR model set.
-  """
-  manifest_layer = ForeignKeyField(ManifestLayer)
-  image_id = CharField(index=True)
-  checksum = CharField()
-  compat_json = JSONField()
-
-
-class ManifestLayerScan(BaseModel):
-  """ ManifestLayerScan represents the state of security scanning for a ManifestLayer.
-      This model is a part of the new OCI/CNR model set.
-  """
-  layer = ForeignKeyField(ManifestLayer, unique=True)
-  scannable = BooleanField()
-  scanned_by = CharField()
-
-
-class DerivedImage(BaseModel):
-  """ DerivedImage represents a Manifest transcoded into an alternative format.
-      This model is a part of the new OCI/CNR model set.
-  """
-  uuid = CharField(default=uuid_generator, unique=True)
-  source_manifest = ForeignKeyField(Manifest)
-  derived_manifest_json = JSONField()
-  media_type = EnumField(MediaType)
-  blob = ForeignKeyField(Blob, related_name='blob')
-  uniqueness_hash = CharField(index=True, unique=True)
-  signature_blob = ForeignKeyField(Blob, null=True, related_name='signature_blob')
-
-  class Meta:
-    database = db
-    read_slaves = (read_slave,)
-    indexes = (
-      (('source_manifest', 'blob'), True),
-      (('source_manifest', 'media_type', 'uniqueness_hash'), True),
-    )
-
-
-class BitTorrentPieces(BaseModel):
-  """ BitTorrentPieces represents the BitTorrent piece metadata calculated from a Blob.
-      This model is a part of the new OCI/CNR model set.
-  """
-  blob = ForeignKeyField(Blob)
-  pieces = Base64BinaryField()
-  piece_length = IntegerField()
-
-  class Meta:
-    database = db
-    read_slaves = (read_slave,)
-    indexes = (
-      (('blob', 'piece_length'), True),
-    )
-
-
 class AppSpecificAuthToken(BaseModel):
   """ AppSpecificAuthToken represents a token generated by a user for use with an external
       application where putting the user's credentials, even encrypted, is deemed too risky.
@@ -1499,9 +1386,7 @@ class AppSpecificAuthToken(BaseModel):
     )
   
 
-beta_classes = set([ManifestLayerScan, Tag, TagKind, BlobPlacementLocation, ManifestLayer, ManifestList,
-                    BitTorrentPieces, MediaType, Label, ManifestBlob, BlobUploading, Blob,
-                    ManifestLayerDockerV1, BlobPlacementLocationPreference, ManifestListManifest,
-                    Manifest, DerivedImage, BlobPlacement, ManifestLabel])
+cnr_classes = set([Tag, TagKind, BlobPlacementLocation, ManifestList, ManifestBlob, Blob,
+                   ManifestListManifest, Manifest, BlobPlacement])
 is_model = lambda x: inspect.isclass(x) and issubclass(x, BaseModel) and x is not BaseModel
 all_models = [model[1] for model in inspect.getmembers(sys.modules[__name__], is_model)]
diff --git a/data/migrations/versions/5cbbfc95bac7_remove_oci_tables_not_used_by_cnr_the_.py b/data/migrations/versions/5cbbfc95bac7_remove_oci_tables_not_used_by_cnr_the_.py
new file mode 100644
index 000000000..1deb2ac34
--- /dev/null
+++ b/data/migrations/versions/5cbbfc95bac7_remove_oci_tables_not_used_by_cnr_the_.py
@@ -0,0 +1,167 @@
+"""Remove 'oci' tables not used by CNR. The rest will be migrated and renamed.
+
+Revision ID: 5cbbfc95bac7
+Revises: 1783530bee68
+Create Date: 2018-05-23 17:28:40.114433
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '5cbbfc95bac7'
+down_revision = '1783530bee68'
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects import mysql
+from util.migrate import UTF8LongText, UTF8CharField
+
+def upgrade(tables):
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.drop_table('derivedimage')
+    op.drop_table('manifestlabel')
+    op.drop_table('blobplacementlocationpreference')
+    op.drop_table('blobuploading')
+    op.drop_table('bittorrentpieces')
+    op.drop_table('manifestlayerdockerv1')
+    op.drop_table('manifestlayerscan')
+    op.drop_table('manifestlayer')
+    # ### end Alembic commands ###
+
+
+def downgrade(tables):
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.create_table(
+        'manifestlayer',
+        sa.Column('id', sa.Integer(), nullable=False),
+        sa.Column('blob_id', sa.Integer(), nullable=False),
+        sa.Column('manifest_id', sa.Integer(), nullable=False),
+        sa.Column('manifest_index', sa.BigInteger(), nullable=False),
+        sa.Column('metadata_json', UTF8LongText, nullable=False),
+        sa.ForeignKeyConstraint(['blob_id'], ['blob.id'], name=op.f('fk_manifestlayer_blob_id_blob')),
+        sa.ForeignKeyConstraint(['manifest_id'], ['manifest.id'], name=op.f('fk_manifestlayer_manifest_id_manifest')),
+        sa.PrimaryKeyConstraint('id', name=op.f('pk_manifestlayer'))
+    )
+    op.create_index('manifestlayer_manifest_index', 'manifestlayer', ['manifest_index'], unique=False)
+    op.create_index('manifestlayer_manifest_id_manifest_index', 'manifestlayer', ['manifest_id', 'manifest_index'], unique=True)
+    op.create_index('manifestlayer_manifest_id', 'manifestlayer', ['manifest_id'], unique=False)
+    op.create_index('manifestlayer_blob_id', 'manifestlayer', ['blob_id'], unique=False)
+
+    op.create_table(
+        'manifestlayerscan',
+        sa.Column('id', sa.Integer(), nullable=False),
+        sa.Column('layer_id', sa.Integer(), nullable=False),
+        sa.Column('scannable', sa.Boolean(), nullable=False),
+        sa.Column('scanned_by', UTF8CharField(length=255), nullable=False),
+        sa.ForeignKeyConstraint(['layer_id'], ['manifestlayer.id'], name=op.f('fk_manifestlayerscan_layer_id_manifestlayer')),
+        sa.PrimaryKeyConstraint('id', name=op.f('pk_manifestlayerscan'))
+    )
+    
+    op.create_index('manifestlayerscan_layer_id', 'manifestlayerscan', ['layer_id'], unique=True)
+
+    op.create_table(
+        'bittorrentpieces',
+        sa.Column('id', sa.Integer(), nullable=False),
+        sa.Column('blob_id', sa.Integer(), nullable=False),
+        sa.Column('pieces', UTF8LongText, nullable=False),
+        sa.Column('piece_length', sa.BigInteger(), nullable=False),
+        sa.ForeignKeyConstraint(['blob_id'], ['blob.id'], name=op.f('fk_bittorrentpieces_blob_id_blob')),
+        sa.PrimaryKeyConstraint('id', name=op.f('pk_bittorrentpieces'))
+    )
+
+    op.create_index('bittorrentpieces_blob_id_piece_length', 'bittorrentpieces', ['blob_id', 'piece_length'], unique=True)
+    op.create_index('bittorrentpieces_blob_id', 'bittorrentpieces', ['blob_id'], unique=False)
+
+    op.create_table(
+        'blobuploading',
+        sa.Column('id', sa.Integer(), nullable=False),
+        sa.Column('uuid', sa.String(length=255), nullable=False),
+        sa.Column('created', sa.DateTime(), nullable=False),
+        sa.Column('repository_id', sa.Integer(), nullable=False),
+        sa.Column('location_id', sa.Integer(), nullable=False),
+        sa.Column('byte_count', sa.BigInteger(), nullable=False),
+        sa.Column('uncompressed_byte_count', sa.BigInteger(), nullable=True),
+        sa.Column('chunk_count', sa.BigInteger(), nullable=False),
+        sa.Column('storage_metadata', UTF8LongText, nullable=True),
+        sa.Column('sha_state', UTF8LongText, nullable=True),
+        sa.Column('piece_sha_state', UTF8LongText, nullable=True),
+        sa.Column('piece_hashes', UTF8LongText, nullable=True),
+        sa.ForeignKeyConstraint(['location_id'], ['blobplacementlocation.id'], name=op.f('fk_blobuploading_location_id_blobplacementlocation')),
+        sa.ForeignKeyConstraint(['repository_id'], ['repository.id'], name=op.f('fk_blobuploading_repository_id_repository')),
+        sa.PrimaryKeyConstraint('id', name=op.f('pk_blobuploading'))
+    )
+    
+    op.create_index('blobuploading_uuid', 'blobuploading', ['uuid'], unique=True)
+    op.create_index('blobuploading_repository_id_uuid', 'blobuploading', ['repository_id', 'uuid'], unique=True)
+    op.create_index('blobuploading_repository_id', 'blobuploading', ['repository_id'], unique=False)
+    op.create_index('blobuploading_location_id', 'blobuploading', ['location_id'], unique=False)
+    op.create_index('blobuploading_created', 'blobuploading', ['created'], unique=False)
+
+    op.create_table(
+        'manifestlayerdockerv1',
+        sa.Column('id', sa.Integer(), nullable=False),
+        sa.Column('manifest_layer_id', sa.Integer(), nullable=False),
+        sa.Column('image_id', UTF8CharField(length=255), nullable=False),
+        sa.Column('checksum', UTF8CharField(length=255), nullable=False),
+        sa.Column('compat_json', UTF8LongText, nullable=False),
+        sa.ForeignKeyConstraint(['manifest_layer_id'], ['manifestlayer.id'], name=op.f('fk_manifestlayerdockerv1_manifest_layer_id_manifestlayer')),
+        sa.PrimaryKeyConstraint('id', name=op.f('pk_manifestlayerdockerv1'))
+    )
+
+    op.create_index('manifestlayerdockerv1_manifest_layer_id', 'manifestlayerdockerv1', ['manifest_layer_id'], unique=False)
+    op.create_index('manifestlayerdockerv1_image_id', 'manifestlayerdockerv1', ['image_id'], unique=False)
+
+    op.create_table(
+        'manifestlabel',
+        sa.Column('id', sa.Integer(), nullable=False),
+        sa.Column('repository_id', sa.Integer(), nullable=False),
+        sa.Column('annotated_id', sa.Integer(), nullable=False),
+        sa.Column('label_id', sa.Integer(), nullable=False),
+        sa.ForeignKeyConstraint(['annotated_id'], ['manifest.id'], name=op.f('fk_manifestlabel_annotated_id_manifest')),
+        sa.ForeignKeyConstraint(['label_id'], ['label.id'], name=op.f('fk_manifestlabel_label_id_label')),
+        sa.ForeignKeyConstraint(['repository_id'], ['repository.id'], name=op.f('fk_manifestlabel_repository_id_repository')),
+        sa.PrimaryKeyConstraint('id', name=op.f('pk_manifestlabel'))
+    )
+
+    op.create_index('manifestlabel_repository_id_annotated_id_label_id', 'manifestlabel', ['repository_id', 'annotated_id', 'label_id'], unique=True)
+    op.create_index('manifestlabel_repository_id', 'manifestlabel', ['repository_id'], unique=False)
+    op.create_index('manifestlabel_label_id', 'manifestlabel', ['label_id'], unique=False)
+    op.create_index('manifestlabel_annotated_id', 'manifestlabel', ['annotated_id'], unique=False)
+
+    op.create_table(
+        'blobplacementlocationpreference',
+        sa.Column('id', sa.Integer(), nullable=False),
+        sa.Column('user_id', sa.Integer(), nullable=False),
+        sa.Column('location_id', sa.Integer(), nullable=False),
+        sa.ForeignKeyConstraint(['location_id'], ['blobplacementlocation.id'], name=op.f('fk_blobplacementlocpref_locid_blobplacementlocation')),
+        sa.ForeignKeyConstraint(['user_id'], ['user.id'], name=op.f('fk_blobplacementlocationpreference_user_id_user')),
+        sa.PrimaryKeyConstraint('id', name=op.f('pk_blobplacementlocationpreference'))
+    )
+    op.create_index('blobplacementlocationpreference_user_id', 'blobplacementlocationpreference', ['user_id'], unique=False)
+    op.create_index('blobplacementlocationpreference_location_id', 'blobplacementlocationpreference', ['location_id'], unique=False)
+    
+
+    op.create_table(
+        'derivedimage',
+        sa.Column('id', sa.Integer(), nullable=False),
+        sa.Column('uuid', sa.String(length=255), nullable=False),
+        sa.Column('source_manifest_id', sa.Integer(), nullable=False),
+        sa.Column('derived_manifest_json', UTF8LongText, nullable=False),
+        sa.Column('media_type_id', sa.Integer(), nullable=False),
+        sa.Column('blob_id', sa.Integer(), nullable=False),
+        sa.Column('uniqueness_hash', sa.String(length=255), nullable=False),
+        sa.Column('signature_blob_id', sa.Integer(), nullable=True),
+        sa.ForeignKeyConstraint(['blob_id'], ['blob.id'], name=op.f('fk_derivedimage_blob_id_blob')),
+        sa.ForeignKeyConstraint(['media_type_id'], ['mediatype.id'], name=op.f('fk_derivedimage_media_type_id_mediatype')),
+        sa.ForeignKeyConstraint(['signature_blob_id'], ['blob.id'], name=op.f('fk_derivedimage_signature_blob_id_blob')),
+        sa.ForeignKeyConstraint(['source_manifest_id'], ['manifest.id'], name=op.f('fk_derivedimage_source_manifest_id_manifest')),
+        sa.PrimaryKeyConstraint('id', name=op.f('pk_derivedimage'))
+    )
+    op.create_index('derivedimage_uuid', 'derivedimage', ['uuid'], unique=True)
+    op.create_index('derivedimage_uniqueness_hash', 'derivedimage', ['uniqueness_hash'], unique=True)
+    op.create_index('derivedimage_source_manifest_id_media_type_id_uniqueness_hash', 'derivedimage', ['source_manifest_id', 'media_type_id', 'uniqueness_hash'], unique=True)
+    op.create_index('derivedimage_source_manifest_id_blob_id', 'derivedimage', ['source_manifest_id', 'blob_id'], unique=True)
+    op.create_index('derivedimage_source_manifest_id', 'derivedimage', ['source_manifest_id'], unique=False)
+    op.create_index('derivedimage_signature_blob_id', 'derivedimage', ['signature_blob_id'], unique=False)
+    op.create_index('derivedimage_media_type_id', 'derivedimage', ['media_type_id'], unique=False)
+    op.create_index('derivedimage_blob_id', 'derivedimage', ['blob_id'], unique=False)
+    # ### end Alembic commands ###
diff --git a/endpoints/api/repository_models_pre_oci.py b/endpoints/api/repository_models_pre_oci.py
index c42bd7ab7..d394b6d8e 100644
--- a/endpoints/api/repository_models_pre_oci.py
+++ b/endpoints/api/repository_models_pre_oci.py
@@ -3,7 +3,7 @@ from collections import defaultdict
 from datetime import datetime, timedelta
 
 from auth.permissions import ReadRepositoryPermission
-from data import model, oci_model
+from data import model, appr_model
 from endpoints.api.repository_models_interface import RepositoryDataInterface, RepositoryBaseElement, Repository, \
   ApplicationRepository, ImageRepositoryRepository, Tag, Channel, Release, Count
 
@@ -142,10 +142,9 @@ class PreOCIModel(RepositoryDataInterface):
       repo.namespace_user.organization, repo.namespace_user.removed_tag_expiration_s, None, None,
       False, False, False)
 
-    # Note: This is *temporary* code for the new OCI model stuff.
     if base.kind_name == 'application':
-      channels = oci_model.channel.get_repo_channels(repo)
-      releases = oci_model.release.get_release_objs(repo)
+      channels = appr_model.channel.get_repo_channels(repo)
+      releases = appr_model.release.get_release_objs(repo)
       releases_channels_map = defaultdict(list)
       return ApplicationRepository(
         base, [_create_channel(channel, releases_channels_map) for channel in channels], [
diff --git a/endpoints/appr/cnr_backend.py b/endpoints/appr/cnr_backend.py
index 3ba4820ee..711d1bfe2 100644
--- a/endpoints/appr/cnr_backend.py
+++ b/endpoints/appr/cnr_backend.py
@@ -8,7 +8,7 @@ from cnr.models.package_base import PackageBase, manifest_media_type
 
 from flask import request
 from app import storage
-from endpoints.appr.models_oci import model
+from endpoints.appr.models_cnr import model
 
 
 class Blob(BlobBase):
diff --git a/endpoints/appr/models_oci.py b/endpoints/appr/models_cnr.py
similarity index 88%
rename from endpoints/appr/models_oci.py
rename to endpoints/appr/models_cnr.py
index 3f1c7d19c..d473e911c 100644
--- a/endpoints/appr/models_oci.py
+++ b/endpoints/appr/models_cnr.py
@@ -7,7 +7,7 @@ from cnr.exception import raise_package_not_found, raise_channel_not_found
 import data.model
 
 from app import storage, authentication
-from data import oci_model
+from data import appr_model
 from data.database import Tag, Manifest, MediaType, Blob, Repository, Channel
 from endpoints.appr.models_interface import (
   ApplicationManifest, ApplicationRelease, ApplicationSummaryView, AppRegistryDataInterface,
@@ -47,7 +47,7 @@ def _application(package):
   return repo
 
 
-class OCIAppModel(AppRegistryDataInterface):
+class CNRAppModel(AppRegistryDataInterface):
   def log_action(self, event_name, namespace_name, repo_name=None, analytics_name=None,
                  analytics_sample=1, metadata=None):
     metadata = {} if metadata is None else metadata
@@ -70,7 +70,7 @@ class OCIAppModel(AppRegistryDataInterface):
     """
 
     views = []
-    for repo in oci_model.package.list_packages_query(namespace, media_type, search,
+    for repo in appr_model.package.list_packages_query(namespace, media_type, search,
                                                       username=username):
       releases = [t.name for t in repo.tag_set_prefetch]
       if not releases:
@@ -81,7 +81,7 @@ class OCIAppModel(AppRegistryDataInterface):
       if with_channels:
         channels = [
           ChannelView(name=chan.name, current=chan.linked_tag.name)
-          for chan in oci_model.channel.get_repo_channels(repo)]
+          for chan in appr_model.channel.get_repo_channels(repo)]
 
       app_name = _join_package_name(repo.namespace_user.username, repo.name)
       manifests = self.list_manifests(app_name, available_releases[0])
@@ -137,7 +137,7 @@ class OCIAppModel(AppRegistryDataInterface):
         Todo:
           * Paginate
     """
-    return oci_model.release.get_releases(_application(package_name), media_type)
+    return appr_model.release.get_releases(_application(package_name), media_type)
 
   def list_manifests(self, package_name, release=None):
     """ Returns the list of all manifests of an Application.
@@ -147,7 +147,7 @@ class OCIAppModel(AppRegistryDataInterface):
     """
     try:
       repo = _application(package_name)
-      return list(oci_model.manifest.get_manifest_types(repo, release))
+      return list(appr_model.manifest.get_manifest_types(repo, release))
     except (Repository.DoesNotExist, Tag.DoesNotExist):
       raise_package_not_found(package_name, release)
 
@@ -157,7 +157,7 @@ class OCIAppModel(AppRegistryDataInterface):
     """
     repo = _application(package_name)
     try:
-      tag, manifest, blob = oci_model.release.get_app_release(repo, release, media_type)
+      tag, manifest, blob = appr_model.release.get_app_release(repo, release, media_type)
       created_at = _timestamp_to_iso(tag.lifetime_start)
 
       blob_descriptor = BlobDescriptor(digest=_strip_sha256_header(blob.digest),
@@ -178,7 +178,7 @@ class OCIAppModel(AppRegistryDataInterface):
     path = cnrblob.upload_url(cnrblob.digest)
     locations = storage.preferred_locations
     storage.stream_write(locations, path, fp, 'application/x-gzip')
-    db_blob = oci_model.blob.get_or_create_blob(cnrblob.digest, cnrblob.size, content_media_type,
+    db_blob = appr_model.blob.get_or_create_blob(cnrblob.digest, cnrblob.size, content_media_type,
                                                 locations)
     return BlobDescriptor(mediaType=content_media_type,
                           digest=_strip_sha256_header(db_blob.digest), size=db_blob.size, urls=[])
@@ -193,7 +193,7 @@ class OCIAppModel(AppRegistryDataInterface):
     repo = data.model.repository.get_or_create_repository(ns, name, user, visibility=visibility,
                                                      repo_kind='application')
     tag_name = package.release
-    oci_model.release.create_app_release(repo, tag_name,
+    appr_model.release.create_app_release(repo, tag_name,
                                          package.manifest(), manifest['content']['digest'], force)
 
   def delete_release(self, package_name, release, media_type):
@@ -202,7 +202,7 @@ class OCIAppModel(AppRegistryDataInterface):
     """
     repo = _application(package_name)
     try:
-      oci_model.release.delete_app_release(repo, release, media_type)
+      appr_model.release.delete_app_release(repo, release, media_type)
     except (Channel.DoesNotExist, Tag.DoesNotExist, MediaType.DoesNotExist):
       raise_package_not_found(package_name, release, media_type)
 
@@ -213,7 +213,7 @@ class OCIAppModel(AppRegistryDataInterface):
   def channel_exists(self, package_name, channel_name):
     """ Returns true if channel exists """
     repo = _application(package_name)
-    return oci_model.tag.tag_exists(repo, channel_name, "channel")
+    return appr_model.tag.tag_exists(repo, channel_name, "channel")
 
   def delete_channel(self, package_name, channel_name):
     """ Delete an AppChannel
@@ -222,14 +222,14 @@ class OCIAppModel(AppRegistryDataInterface):
     """
     repo = _application(package_name)
     try:
-      oci_model.channel.delete_channel(repo, channel_name)
+      appr_model.channel.delete_channel(repo, channel_name)
     except (Channel.DoesNotExist, Tag.DoesNotExist):
       raise_channel_not_found(package_name, channel_name)
 
   def list_channels(self, package_name):
     """ Returns all AppChannel for a package """
     repo = _application(package_name)
-    channels = oci_model.channel.get_repo_channels(repo)
+    channels = appr_model.channel.get_repo_channels(repo)
     return [ChannelView(name=chan.name, current=chan.linked_tag.name) for chan in channels]
 
   def fetch_channel(self, package_name, channel_name, with_releases=True):
@@ -237,12 +237,12 @@ class OCIAppModel(AppRegistryDataInterface):
     repo = _application(package_name)
 
     try:
-      channel = oci_model.channel.get_channel(repo, channel_name)
+      channel = appr_model.channel.get_channel(repo, channel_name)
     except (Channel.DoesNotExist, Tag.DoesNotExist):
       raise_channel_not_found(package_name, channel_name)
 
     if with_releases:
-      releases = oci_model.channel.get_channel_releases(repo, channel)
+      releases = appr_model.channel.get_channel_releases(repo, channel)
       chanview = ChannelReleasesView(
         current=channel.linked_tag.name, name=channel.name,
         releases=[channel.linked_tag.name] + [c.name for c in releases])
@@ -254,7 +254,7 @@ class OCIAppModel(AppRegistryDataInterface):
   def list_release_channels(self, package_name, release, active=True):
     repo = _application(package_name)
     try:
-      channels = oci_model.channel.get_tag_channels(repo, release, active=active)
+      channels = appr_model.channel.get_tag_channels(repo, release, active=active)
       return [ChannelView(name=c.name, current=c.linked_tag.name) for c in channels]
     except (Channel.DoesNotExist, Tag.DoesNotExist):
       raise_package_not_found(package_name, release)
@@ -265,11 +265,11 @@ class OCIAppModel(AppRegistryDataInterface):
       A new AppChannel with the release
     """
     repo = _application(package_name)
-    channel = oci_model.channel.create_or_update_channel(repo, channel_name, release)
+    channel = appr_model.channel.create_or_update_channel(repo, channel_name, release)
     return ChannelView(current=channel.linked_tag.name, name=channel.name)
 
   def get_blob_locations(self, digest):
-    return oci_model.blob.get_blob_locations(digest)
+    return appr_model.blob.get_blob_locations(digest)
 
 
-model = OCIAppModel()
+model = CNRAppModel()
diff --git a/endpoints/appr/registry.py b/endpoints/appr/registry.py
index d98996a46..dae4f1799 100644
--- a/endpoints/appr/registry.py
+++ b/endpoints/appr/registry.py
@@ -17,7 +17,7 @@ from auth.permissions import CreateRepositoryPermission, ModifyRepositoryPermiss
 from endpoints.appr import appr_bp, require_app_repo_read, require_app_repo_write
 from endpoints.appr.cnr_backend import Blob, Channel, Package, User
 from endpoints.appr.decorators import disallow_for_image_repository
-from endpoints.appr.models_oci import model
+from endpoints.appr.models_cnr import model
 from endpoints.decorators import anon_allowed, anon_protect
 from util.names import REPOSITORY_NAME_REGEX, TAG_REGEX
 
diff --git a/endpoints/appr/test/test_api.py b/endpoints/appr/test/test_api.py
index b3064e681..ae40ea0aa 100644
--- a/endpoints/appr/test/test_api.py
+++ b/endpoints/appr/test/test_api.py
@@ -6,13 +6,13 @@ from cnr.tests.conftest import *
 from cnr.tests.test_apiserver import BaseTestServer
 from cnr.tests.test_models import CnrTestModels
 
-import data.oci_model.blob as oci_blob
+import data.appr_model.blob as oci_blob
 
 from data.database import User
 from data.model import organization, user
 from endpoints.appr import registry # Needed to register the endpoint
 from endpoints.appr.cnr_backend import Channel, Package, QuayDB
-from endpoints.appr.models_oci import model as oci_app_model
+from endpoints.appr.models_cnr import model as oci_app_model
 
 from test.fixtures import *
 
diff --git a/endpoints/appr/test/test_digest_prefix.py b/endpoints/appr/test/test_digest_prefix.py
index d98d4a248..089becd43 100644
--- a/endpoints/appr/test/test_digest_prefix.py
+++ b/endpoints/appr/test/test_digest_prefix.py
@@ -1,5 +1,5 @@
 import pytest
-from endpoints.appr.models_oci import _strip_sha256_header
+from endpoints.appr.models_cnr import _strip_sha256_header
 
 
 @pytest.mark.parametrize('digest,expected', [
diff --git a/initdb.py b/initdb.py
index c80fc1b60..f368684f8 100644
--- a/initdb.py
+++ b/initdb.py
@@ -14,7 +14,7 @@ from uuid import UUID, uuid4
 from threading import Event
 
 from email.utils import formatdate
-from data.database import (db, all_models, beta_classes, Role, TeamRole, Visibility, LoginService,
+from data.database import (db, all_models, cnr_classes, Role, TeamRole, Visibility, LoginService,
                            BuildTriggerService, AccessTokenKind, LogEntryKind, ImageStorageLocation,
                            ImageStorageTransformation, ImageStorageSignatureKind,
                            ExternalNotificationEvent, ExternalNotificationMethod, NotificationKind,
@@ -906,7 +906,7 @@ def find_models_missing_data():
   # whitelisted.
   models_missing_data = set()
   for one_model in all_models:
-    if one_model in beta_classes:
+    if one_model in cnr_classes:
       continue
 
     try:
diff --git a/test/test_api_usage.py b/test/test_api_usage.py
index 8a673175a..6ccd868ac 100644
--- a/test/test_api_usage.py
+++ b/test/test_api_usage.py
@@ -26,7 +26,7 @@ from endpoints.webhooks import webhooks
 from app import app, config_provider, all_queues, dockerfile_build_queue, notification_queue
 from buildtrigger.basehandler import BuildTriggerHandler
 from initdb import setup_database_for_testing, finished_database_for_testing
-from data import database, model, oci_model
+from data import database, model, appr_model
 from data.database import RepositoryActionCount, Repository as RepositoryTable
 from test.helpers import assert_action_logged
 from util.secscan.fake import fake_security_scanner
@@ -2153,11 +2153,11 @@ class TestDeleteRepository(ApiTestCase):
     # Add some data for the repository, in addition to is already existing images and tags.
     repository = model.repository.get_repository(ADMIN_ACCESS_USER, 'complex')
 
-    # Add some new-style tags and linked tags.
-    base_tag = oci_model.tag.create_or_update_tag(repository, 'somebasetag')
-    base_tag2 = oci_model.tag.create_or_update_tag(repository, 'somebasetag2')
-    oci_model.tag.create_or_update_tag(repository, 'somelinkedtag', linked_tag=base_tag)
-    oci_model.tag.create_or_update_tag(repository, 'somelinkedtag2', linked_tag=base_tag2)
+    # Add some CNR tags and linked tags.
+    base_tag = appr_model.tag.create_or_update_tag(repository, 'somebasetag')
+    base_tag2 = appr_model.tag.create_or_update_tag(repository, 'somebasetag2')
+    appr_model.tag.create_or_update_tag(repository, 'somelinkedtag', linked_tag=base_tag)
+    appr_model.tag.create_or_update_tag(repository, 'somelinkedtag2', linked_tag=base_tag2)
 
     # Create some access tokens.
     access_token = model.token.create_access_token(repository, 'read')
diff --git a/util/config/database.py b/util/config/database.py
index 585dfd13d..5180f9401 100644
--- a/util/config/database.py
+++ b/util/config/database.py
@@ -1,4 +1,4 @@
-from data import model, oci_model
+from data import model, appr_model
 
 
 def sync_database_with_config(config):
@@ -7,4 +7,4 @@ def sync_database_with_config(config):
   location_names = config.get('DISTRIBUTED_STORAGE_CONFIG', {}).keys()
   if location_names:
     model.image.ensure_image_locations(*location_names)
-    oci_model.blob.ensure_blob_locations(*location_names)
+    appr_model.blob.ensure_blob_locations(*location_names)