Merge "Keep deleted domains in the DB"

This commit is contained in:
Jenkins 2013-06-24 21:30:33 +00:00 committed by Gerrit Code Review
commit 83b331e561
5 changed files with 131 additions and 41 deletions

View File

@ -13,8 +13,11 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from sqlalchemy import Column, DateTime
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import object_mapper
from sqlalchemy.types import CHAR
from designate.openstack.common import timeutils
from designate import exceptions
@ -82,3 +85,15 @@ class Base(object):
if not k[0] == '_'])
local.update(joined)
return local.iteritems()
class SoftDeleteMixin(object):
deleted = Column(CHAR(32), nullable=False, default="0")
deleted_at = Column(DateTime, nullable=True, default=None)
def soft_delete(self, session=None):
""" Mark this object as deleted. """
self.deleted = self.id
self.deleted_at = timeutils.utcnow()
self.save(session=session)

View File

@ -21,6 +21,7 @@ from designate.openstack.common import log as logging
from designate import exceptions
from designate.storage import base
from designate.storage.impl_sqlalchemy import models
from designate.sqlalchemy.models import SoftDeleteMixin
from designate.sqlalchemy.session import get_session
from designate.sqlalchemy.session import get_engine
from designate.sqlalchemy.session import SQLOPTS
@ -64,6 +65,16 @@ class SQLAlchemyStorage(base.Storage):
return query
def _apply_deleted_criteria(self, context, model, query):
if issubclass(model, SoftDeleteMixin):
if context.show_deleted:
LOG.debug('Including deleted items in query results')
else:
LOG.debug('Filtering deleted items from query results')
query = query.filter(model.deleted == "0")
return query
# Quota Methods
def create_quota(self, context, values):
quota = models.Quota()
@ -281,6 +292,19 @@ class SQLAlchemyStorage(base.Storage):
return self.session.query(distinct(models.Domain.tenant_id)).count()
# Domain Methods
def _find_domains(self, context, criterion, one=False):
query = self.session.query(models.Domain)
query = self._apply_criterion(models.Domain, query, criterion)
query = self._apply_deleted_criteria(context, models.Domain, query)
if one:
try:
return query.one()
except (exc.NoResultFound, exc.MultipleResultsFound):
raise exceptions.DomainNotFound()
else:
return query.all()
def create_domain(self, context, values):
domain = models.Domain()
@ -294,54 +318,26 @@ class SQLAlchemyStorage(base.Storage):
return dict(domain)
def get_domains(self, context, criterion=None):
query = self.session.query(models.Domain)
query = self._apply_criterion(models.Domain, query, criterion)
domains = self._find_domains(context, criterion)
try:
result = query.all()
except exc.NoResultFound:
LOG.debug('No results found')
return []
else:
return [dict(o) for o in result]
def _get_domain(self, context, domain_id):
query = self.session.query(models.Domain)
domain = query.get(domain_id)
if not domain:
raise exceptions.DomainNotFound(domain_id)
else:
return domain
return [dict(d) for d in domains]
def get_domain(self, context, domain_id):
domain = self._get_domain(context, domain_id)
domain = self._find_domains(context, {'id': domain_id}, True)
return dict(domain)
def _find_domains(self, context, criterion, one=False):
query = self.session.query(models.Domain)
query = self._apply_criterion(models.Domain, query, criterion)
if one:
try:
domain = query.one()
return dict(domain)
except (exc.NoResultFound, exc.MultipleResultsFound):
raise exceptions.DomainNotFound()
else:
domains = query.all()
return [dict(d) for d in domains]
def find_domains(self, context, criterion):
return self._find_domains(context, criterion)
domains = self._find_domains(context, criterion)
return [dict(d) for d in domains]
def find_domain(self, context, criterion):
return self._find_domains(context, criterion, one=True)
domain = self._find_domains(context, criterion, one=True)
return dict(domain)
def update_domain(self, context, domain_id, values):
domain = self._get_domain(context, domain_id)
domain = self._find_domains(context, {'id': domain_id}, True)
domain.update(values)
@ -353,13 +349,15 @@ class SQLAlchemyStorage(base.Storage):
return dict(domain)
def delete_domain(self, context, domain_id):
domain = self._get_domain(context, domain_id)
domain = self._find_domains(context, {'id': domain_id}, True)
domain.delete(self.session)
domain.soft_delete(self.session)
def count_domains(self, context, criterion=None):
query = self.session.query(models.Domain)
query = self._apply_criterion(models.Domain, query, criterion)
query = self._apply_deleted_criteria(context, models.Domain, query)
return query.count()
# Record Methods

View File

@ -0,0 +1,64 @@
# Copyright 2013 Hewlett-Packard Development Company, L.P.
#
# Author: Kiall Mac Innes <kiall@hp.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from sqlalchemy import MetaData, Table, Column, DateTime
from sqlalchemy.types import CHAR
from migrate.changeset.constraint import UniqueConstraint
meta = MetaData()
def upgrade(migrate_engine):
meta.bind = migrate_engine
domains_table = Table('domains', meta, autoload=True)
# Create the new columns
deleted_column = Column('deleted', CHAR(32), nullable=False, default="0")
deleted_column.create(domains_table, populate_default=True)
deleted_at_column = Column('deleted_at', DateTime, nullable=True,
default=None)
deleted_at_column.create(domains_table, populate_default=True)
# Drop the old single column unique
domains_table.c.name.alter(unique=False)
# Add a new multi-column unique index
constraint = UniqueConstraint('name', 'deleted', name='unique_domain_name',
table=domains_table)
constraint.create()
def downgrade(migrate_engine):
meta.bind = migrate_engine
domains_table = Table('domains', meta, autoload=True)
# Drop the multi-column unique index
constraint = UniqueConstraint('name', 'deleted', name='unique_domain_name',
table=domains_table)
constraint.drop()
# Revert to single column unique
domains_table.c.name.alter(unique=True)
# Drop the deleted columns
deleted_column = Column('deleted', CHAR(32), nullable=True, default=None)
deleted_column.drop(domains_table)
deleted_at_column = Column('deleted_at', DateTime, nullable=True,
default=None)
deleted_at_column.drop(domains_table)

View File

@ -25,6 +25,7 @@ from designate.openstack.common import timeutils
from designate.openstack.common.uuidutils import generate_uuid
from designate.sqlalchemy.types import UUID
from designate.sqlalchemy.models import Base as CommonBase
from designate.sqlalchemy.models import SoftDeleteMixin
from sqlalchemy.ext.declarative import declarative_base
LOG = logging.getLogger(__name__)
@ -66,12 +67,15 @@ class Server(Base):
name = Column(String(255), nullable=False, unique=True)
class Domain(Base):
class Domain(SoftDeleteMixin, Base):
__tablename__ = 'domains'
__table_args__ = (
UniqueConstraint('name', 'deleted', name='unique_domain_name'),
)
tenant_id = Column(String(36), default=None, nullable=True)
name = Column(String(255), nullable=False, unique=True)
name = Column(String(255), nullable=False)
email = Column(String(255), nullable=False)
ttl = Column(Integer, default=3600, nullable=False)

View File

@ -584,6 +584,15 @@ class StorageTestCase(TestCase):
uuid = 'caf771fc-6b05-4891-bee1-c2a48621f57b'
self.storage.get_domain(self.admin_context, uuid)
def test_get_deleted_domain(self):
context = self.get_admin_context()
context.show_deleted = True
_, domain = self.create_domain()
self.storage.delete_domain(self.admin_context, domain['id'])
self.storage.get_domain(context, domain['id'])
def test_find_domain_criterion(self):
_, domain_one = self.create_domain(0)
_, domain_two = self.create_domain(1)