Merge pull request #497 from coreos-inc/delrepofix
Fix interleaved repo delete with RAC via a transaction
This commit is contained in:
commit
b91660f87b
3 changed files with 36 additions and 13 deletions
|
@ -119,6 +119,7 @@ db = Proxy()
|
|||
read_slave = Proxy()
|
||||
db_random_func = CallableProxy()
|
||||
db_for_update = CallableProxy()
|
||||
db_transaction = CallableProxy()
|
||||
|
||||
|
||||
def validate_database_url(url, db_kwargs, connect_timeout=5):
|
||||
|
@ -164,6 +165,10 @@ def configure(config_object):
|
|||
if read_slave_uri is not None:
|
||||
read_slave.initialize(_db_from_url(read_slave_uri, db_kwargs))
|
||||
|
||||
def _db_transaction():
|
||||
return config_object['DB_TRANSACTION_FACTORY'](db)
|
||||
|
||||
db_transaction.initialize(_db_transaction)
|
||||
|
||||
def random_string_generator(length=16):
|
||||
def random_string():
|
||||
|
@ -373,14 +378,15 @@ class Repository(BaseModel):
|
|||
return sorted_models.index(cmp_fk.model_class.__name__)
|
||||
filtered_ops.sort(key=sorted_model_key)
|
||||
|
||||
for query, fk in filtered_ops:
|
||||
model = fk.model_class
|
||||
if fk.null and not delete_nullable:
|
||||
model.update(**{fk.name: None}).where(query).execute()
|
||||
else:
|
||||
model.delete().where(query).execute()
|
||||
with db_transaction():
|
||||
for query, fk in filtered_ops:
|
||||
model = fk.model_class
|
||||
if fk.null and not delete_nullable:
|
||||
model.update(**{fk.name: None}).where(query).execute()
|
||||
else:
|
||||
model.delete().where(query).execute()
|
||||
|
||||
return self.delete().where(self._pk_expr()).execute()
|
||||
return self.delete().where(self._pk_expr()).execute()
|
||||
|
||||
class Star(BaseModel):
|
||||
user = ForeignKeyField(User, index=True)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from data.database import db
|
||||
from data.database import db, db_transaction
|
||||
|
||||
|
||||
class DataModelException(Exception):
|
||||
|
@ -80,10 +80,6 @@ class Config(object):
|
|||
config = Config()
|
||||
|
||||
|
||||
def db_transaction():
|
||||
return config.app_config['DB_TRANSACTION_FACTORY'](db)
|
||||
|
||||
|
||||
# There MUST NOT be any circular dependencies between these subsections. If there are fix it by
|
||||
# moving the minimal number of things to _basequery
|
||||
# TODO document the methods and modules for each one of the submodules below.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# coding=utf-8
|
||||
|
||||
import unittest
|
||||
import datetime
|
||||
import json as py_json
|
||||
|
||||
from urllib import urlencode
|
||||
|
@ -15,6 +16,7 @@ from endpoints.trigger import BuildTriggerHandler
|
|||
from app import app
|
||||
from initdb import setup_database_for_testing, finished_database_for_testing
|
||||
from data import database, model
|
||||
from data.database import RepositoryActionCount
|
||||
|
||||
from endpoints.api.team import TeamMember, TeamMemberList, TeamMemberInvite, OrganizationTeam
|
||||
from endpoints.api.tag import RepositoryTagImages, RepositoryTag, RevertTag, ListRepositoryTags
|
||||
|
@ -1468,6 +1470,10 @@ class TestDeleteRepository(ApiTestCase):
|
|||
def test_deleterepo(self):
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
|
||||
# Verify the repo exists.
|
||||
self.getResponse(Repository,
|
||||
params=dict(repository=self.SIMPLE_REPO))
|
||||
|
||||
self.deleteResponse(Repository, params=dict(repository=self.SIMPLE_REPO))
|
||||
|
||||
# Verify the repo was deleted.
|
||||
|
@ -1478,6 +1484,10 @@ class TestDeleteRepository(ApiTestCase):
|
|||
def test_deleterepo2(self):
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
|
||||
# Verify the repo exists.
|
||||
self.getResponse(Repository,
|
||||
params=dict(repository=self.COMPLEX_REPO))
|
||||
|
||||
self.deleteResponse(Repository, params=dict(repository=self.COMPLEX_REPO))
|
||||
|
||||
# Verify the repo was deleted.
|
||||
|
@ -1488,7 +1498,11 @@ class TestDeleteRepository(ApiTestCase):
|
|||
def test_populate_and_delete_repo(self):
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
|
||||
# Make sure the repository has come images and tags.
|
||||
# Verify the repo exists.
|
||||
self.getResponse(Repository,
|
||||
params=dict(repository=self.COMPLEX_REPO))
|
||||
|
||||
# Make sure the repository has some images and tags.
|
||||
self.assertTrue(len(list(model.image.get_repository_images(ADMIN_ACCESS_USER, 'complex'))) > 0)
|
||||
self.assertTrue(len(list(model.tag.list_repository_tags(ADMIN_ACCESS_USER, 'complex'))) > 0)
|
||||
|
||||
|
@ -1524,6 +1538,13 @@ class TestDeleteRepository(ApiTestCase):
|
|||
model.repository.create_email_authorization_for_repo(ADMIN_ACCESS_USER, 'complex', 'a@b.com')
|
||||
model.repository.create_email_authorization_for_repo(ADMIN_ACCESS_USER, 'complex', 'b@c.com')
|
||||
|
||||
# Create some repository action count entries.
|
||||
RepositoryActionCount.create(repository=repository, date=datetime.datetime.now(), count=1)
|
||||
RepositoryActionCount.create(repository=repository,
|
||||
date=datetime.datetime.now() - datetime.timedelta(days=1), count=2)
|
||||
RepositoryActionCount.create(repository=repository,
|
||||
date=datetime.datetime.now() - datetime.timedelta(days=3), count=6)
|
||||
|
||||
# Delete the repository.
|
||||
self.deleteResponse(Repository, params=dict(repository=self.COMPLEX_REPO))
|
||||
|
||||
|
|
Reference in a new issue