summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2014-09-25 15:54:49 +0000
committerGerrit Code Review <review@openstack.org>2014-09-25 15:54:49 +0000
commit54482e6f3d89d77bb7633707b56196b09fa71206 (patch)
treefaa49a103e7aea1eb83ca2eff7b4ad0031b7c276
parent941f4a8026b8c5bc4cd034934eaa7cad944d3a81 (diff)
parentfbfeec3d12229eede252b45fbceabd04f507dc21 (diff)
downloaddesignate-54482e6f3d89d77bb7633707b56196b09fa71206.tar.gz
Merge "Make use of SQLA Core in PowerDNS"
-rw-r--r--designate/backend/impl_powerdns/__init__.py310
-rw-r--r--designate/backend/impl_powerdns/models.py78
-rw-r--r--designate/backend/impl_powerdns/tables.py80
-rw-r--r--designate/exceptions.py5
4 files changed, 281 insertions, 192 deletions
diff --git a/designate/backend/impl_powerdns/__init__.py b/designate/backend/impl_powerdns/__init__.py
index 4aa253eb..371ef0bc 100644
--- a/designate/backend/impl_powerdns/__init__.py
+++ b/designate/backend/impl_powerdns/__init__.py
@@ -21,14 +21,13 @@ import threading
from oslo.config import cfg
from oslo.db import options
from sqlalchemy.sql import select
-from sqlalchemy.orm import exc as sqlalchemy_exceptions
from designate.openstack.common import excutils
from designate.openstack.common import log as logging
from designate.i18n import _LC
from designate import exceptions
from designate.backend import base
-from designate.backend.impl_powerdns import models
+from designate.backend.impl_powerdns import tables
from designate.sqlalchemy import session
from designate.sqlalchemy.expressions import InsertFromSelect
@@ -53,6 +52,10 @@ CONF.set_default('connection', 'sqlite:///$state_path/powerdns.sqlite',
group='backend:powerdns')
+def _map_col(keys, col):
+ return dict([(keys[i], col[i]) for i in range(len(keys))])
+
+
class PowerDNSBackend(base.Backend):
__plugin_name__ = 'powerdns'
@@ -77,6 +80,67 @@ class PowerDNSBackend(base.Backend):
return self.local_store.session
+ def _create(self, table, values):
+ query = table.insert()
+
+ resultproxy = self.session.execute(query, values)
+
+ # Refetch the row, for generated columns etc
+ query = select([table])\
+ .where(table.c.id == resultproxy.inserted_primary_key[0])
+ resultproxy = self.session.execute(query)
+
+ return _map_col(query.columns.keys(), resultproxy.fetchone())
+
+ def _update(self, table, values, exc_notfound, id_col=None):
+ if id_col is None:
+ id_col = table.c.id
+
+ query = table.update()\
+ .where(id_col == values[id_col.name])\
+ .values(**values)
+
+ resultproxy = self.session.execute(query)
+
+ if resultproxy.rowcount != 1:
+ raise exc_notfound()
+
+ # Refetch the row, for generated columns etc
+ query = select([table])\
+ .where(id_col == values[id_col.name])
+ resultproxy = self.session.execute(query)
+
+ return _map_col(query.columns.keys(), resultproxy.fetchone())
+
+ def _get(self, table, id_, exc_notfound, id_col=None):
+ if id_col is None:
+ id_col = table.c.id
+
+ query = select([table])\
+ .where(id_col == id_)
+
+ resultproxy = self.session.execute(query)
+
+ results = resultproxy.fetchall()
+
+ if len(results) != 1:
+ raise exc_notfound()
+
+ # Map col keys to values in result
+ return _map_col(query.columns.keys(), results[0])
+
+ def _delete(self, table, id_, exc_notfound, id_col=None):
+ if id_col is None:
+ id_col = table.c.id
+
+ query = table.delete()\
+ .where(id_col == id_)
+
+ resultproxy = self.session.execute(query)
+
+ if resultproxy.rowcount != 1:
+ raise exc_notfound()
+
# TSIG Key Methods
def create_tsigkey(self, context, tsigkey):
"""Create a TSIG Key"""
@@ -84,33 +148,31 @@ class PowerDNSBackend(base.Backend):
if tsigkey['algorithm'] not in TSIG_SUPPORTED_ALGORITHMS:
raise exceptions.NotImplemented('Unsupported algorithm')
- tsigkey_m = models.TsigKey()
-
- tsigkey_m.update({
+ values = {
'designate_id': tsigkey['id'],
'name': tsigkey['name'],
'algorithm': tsigkey['algorithm'],
'secret': base64.b64encode(tsigkey['secret'])
- })
+ }
- tsigkey_m.save(self.session)
+ self._create(tables.tsigkeys, values)
# NOTE(kiall): Prepare and execute query to install this TSIG Key on
# every domain. We use a manual query here since anything
# else would be impossibly slow.
query_select = select([
- models.Domain.__table__.c.id,
+ tables.domains.c.id,
"'TSIG-ALLOW-AXFR'",
"'%s'" % tsigkey['name']]
)
columns = [
- models.DomainMetadata.__table__.c.domain_id,
- models.DomainMetadata.__table__.c.kind,
- models.DomainMetadata.__table__.c.content,
+ tables.domain_metadata.c.domain_id,
+ tables.domain_metadata.c.kind,
+ tables.domain_metadata.c.content,
]
- query = InsertFromSelect(models.DomainMetadata.__table__, query_select,
+ query = InsertFromSelect(tables.domain_metadata, query_select,
columns)
# NOTE(kiall): A TX is required for, at the least, SQLite.
@@ -120,31 +182,42 @@ class PowerDNSBackend(base.Backend):
def update_tsigkey(self, context, tsigkey):
"""Update a TSIG Key"""
- tsigkey_m = self._get_tsigkey(tsigkey['id'])
+ values = self._get(
+ tables.tsigkeys,
+ tsigkey['id'],
+ exceptions.TsigKeyNotFound,
+ id_col=tables.tsigkeys.c.designate_id)
# Store a copy of the original name..
- original_name = tsigkey_m.name
+ original_name = values['name']
- tsigkey_m.update({
+ values.update({
'name': tsigkey['name'],
'algorithm': tsigkey['algorithm'],
'secret': base64.b64encode(tsigkey['secret'])
})
- tsigkey_m.save(self.session)
+ self._update(tables.tsigkeys, values,
+ id_col=tables.tsigkeys.c.designate_id,
+ exc_notfound=exceptions.TsigKeyNotFound)
# If the name changed, Update the necessary DomainMetadata records
if original_name != tsigkey['name']:
- self.session.query(models.DomainMetadata)\
- .filter_by(kind='TSIG-ALLOW-AXFR', content=original_name)\
- .update(content=tsigkey['name'])
+ query = tables.domain_metadata.update()\
+ .where(tables.domain_metadata.c.kind == 'TSIG_ALLOW_AXFR')\
+ .where(tables.domain_metadata.c.content == original_name)
+
+ query.values(content=tsigkey['name'])
+ self.session.execute(query)
def delete_tsigkey(self, context, tsigkey):
"""Delete a TSIG Key"""
try:
# Delete this TSIG Key itself
- tsigkey_m = self._get_tsigkey(tsigkey['id'])
- tsigkey_m.delete(self.session)
+ self._delete(
+ tables.tsigkeys, tsigkey['id'],
+ exceptions.TsigKeyNotFound,
+ id_col=tables.tsigkeys.c.designate_id)
except exceptions.TsigKeyNotFound:
# If the TSIG Key is already gone, that's ok. We're deleting it
# anyway, so just log and continue.
@@ -153,46 +226,58 @@ class PowerDNSBackend(base.Backend):
tsigkey['id'])
return
- # Delete this TSIG Key from every domain's metadata
- self.session.query(models.DomainMetadata)\
- .filter_by(kind='TSIG-ALLOW-AXFR', content=tsigkey['name'])\
- .delete()
+ query = tables.domain_metadata.delete()\
+ .where(tables.domain_metadata.c.kind == 'TSIG-ALLOW-AXFR')\
+ .where(tables.domain_metadata.c.content == tsigkey['name'])
+ self.session.execute(query)
# Domain Methods
def create_domain(self, context, domain):
- servers = self.central_service.find_servers(self.admin_context)
-
- domain_m = models.Domain()
- domain_m.update({
- 'designate_id': domain['id'],
- 'name': domain['name'].rstrip('.'),
- 'master': servers[0]['name'].rstrip('.'),
- 'type': CONF['backend:powerdns'].domain_type,
- 'account': context.tenant
- })
- domain_m.save(self.session)
+ try:
+ self.session.begin()
+ servers = self.central_service.find_servers(self.admin_context)
+
+ domain_values = {
+ 'designate_id': domain['id'],
+ 'name': domain['name'].rstrip('.'),
+ 'master': servers[0]['name'].rstrip('.'),
+ 'type': CONF['backend:powerdns'].domain_type,
+ 'account': context.tenant
+ }
- # Install all TSIG Keys on this domain
- tsigkeys = self.session.query(models.TsigKey).all()
- values = [t.name for t in tsigkeys]
+ domain_ref = self._create(tables.domains, domain_values)
- self._update_domainmetadata(domain_m.id, 'TSIG-ALLOW-AXFR', values)
+ # Install all TSIG Keys on this domain
+ query = select([tables.tsigkeys.c.name])
+ resultproxy = self.session.execute(query)
+ values = [i for i in resultproxy.fetchall()]
- # Install all Also Notify's on this domain
- self._update_domainmetadata(domain_m.id, 'ALSO-NOTIFY',
- CONF['backend:powerdns'].also_notify)
+ self._update_domainmetadata(domain_ref['id'], 'TSIG-ALLOW-AXFR',
+ values)
+
+ # Install all Also Notify's on this domain
+ self._update_domainmetadata(domain_ref['id'], 'ALSO-NOTIFY',
+ CONF['backend:powerdns'].also_notify)
+ except Exception:
+ with excutils.save_and_reraise_exception():
+ self.session.rollback()
+ else:
+ self.session.commit()
def update_domain(self, context, domain):
- domain_m = self._get_domain(domain['id'])
+ domain_ref = self._get(tables.domains, domain['id'],
+ exceptions.DomainNotFound,
+ id_col=tables.domains.c.designate_id)
try:
self.session.begin()
# Update the Records TTLs where necessary
- self.session.query(models.Record)\
- .filter_by(domain_id=domain_m.id, inherit_ttl=True)\
- .update({'ttl': domain['ttl']})
-
+ query = tables.records.update()\
+ .where(tables.records.c.domain_id == domain_ref['id'])
+ query = query.where(tables.records.c.inherit_ttl == True) # noqa\
+ query = query.values(ttl=domain['ttl'])
+ self.session.execute(query)
except Exception:
with excutils.save_and_reraise_exception():
self.session.rollback()
@@ -201,7 +286,9 @@ class PowerDNSBackend(base.Backend):
def delete_domain(self, context, domain):
try:
- domain_m = self._get_domain(domain['id'])
+ domain_ref = self._get(tables.domains, domain['id'],
+ exceptions.DomainNotFound,
+ id_col=tables.domains.c.designate_id)
except exceptions.DomainNotFound:
# If the Domain is already gone, that's ok. We're deleting it
# anyway, so just log and continue.
@@ -210,15 +297,19 @@ class PowerDNSBackend(base.Backend):
domain['id'])
return
- domain_m.delete(self.session)
+ self._delete(tables.domains, domain['id'],
+ exceptions.DomainNotFound,
+ id_col=tables.domains.c.designate_id)
# Ensure the records are deleted
- query = self.session.query(models.Record)
- query.filter_by(domain_id=domain_m.id).delete()
+ query = tables.records.delete()\
+ .where(tables.records.c.domain_id == domain_ref['id'])
+ self.session.execute(query)
# Ensure domainmetadata is deleted
- query = self.session.query(models.DomainMetadata)
- query.filter_by(domain_id=domain_m.id).delete()
+ query = tables.domain_metadata.delete()\
+ .where(tables.domain_metadata.c.domain_id == domain_ref['id'])
+ self.session.execute(query)
# RecordSet Methods
def create_recordset(self, context, domain, recordset):
@@ -251,21 +342,23 @@ class PowerDNSBackend(base.Backend):
def delete_recordset(self, context, domain, recordset):
# Ensure records are deleted
- query = self.session.query(models.Record)
- query.filter_by(designate_recordset_id=recordset['id']).delete()
+ query = tables.records.delete()\
+ .where(tables.records.c.designate_recordset_id == recordset['id'])
+ self.session.execute(query)
# Record Methods
def create_record(self, context, domain, recordset, record):
- domain_m = self._get_domain(domain['id'])
- record_m = models.Record()
+ domain_ref = self._get(tables.domains, domain['id'],
+ exceptions.DomainNotFound,
+ id_col=tables.domains.c.designate_id)
content = self._sanitize_content(recordset['type'], record['data'])
ttl = domain['ttl'] if recordset['ttl'] is None else recordset['ttl']
- record_m.update({
+ record_values = {
'designate_id': record['id'],
'designate_recordset_id': record['recordset_id'],
- 'domain_id': domain_m.id,
+ 'domain_id': domain_ref['id'],
'name': recordset['name'].rstrip('.'),
'type': recordset['type'],
'content': content,
@@ -273,17 +366,17 @@ class PowerDNSBackend(base.Backend):
'inherit_ttl': True if recordset['ttl'] is None else False,
'prio': record['priority'],
'auth': self._is_authoritative(domain, recordset, record)
- })
+ }
- record_m.save(self.session)
+ self._create(tables.records, record_values)
def update_record(self, context, domain, recordset, record):
- record_m = self._get_record(record['id'])
+ record_ref = self._get_record(record['id'])
content = self._sanitize_content(recordset['type'], record['data'])
ttl = domain['ttl'] if recordset['ttl'] is None else recordset['ttl']
- record_m.update({
+ record_ref.update({
'content': content,
'ttl': ttl,
'inherit_ttl': True if recordset['ttl'] is None else False,
@@ -291,11 +384,14 @@ class PowerDNSBackend(base.Backend):
'auth': self._is_authoritative(domain, recordset, record)
})
- record_m.save(self.session)
+ self._update(tables.records, record_ref,
+ exc_notfound=exceptions.RecordNotFound)
def delete_record(self, context, domain, recordset, record):
try:
- record_m = self._get_record(record['id'])
+ record_ref = self._get(tables.records, record['id'],
+ exceptions.RecordNotFound,
+ id_col=tables.records.c.designate_id)
except exceptions.RecordNotFound:
# If the Record is already gone, that's ok. We're deleting it
# anyway, so just log and continue.
@@ -303,7 +399,8 @@ class PowerDNSBackend(base.Backend):
'not present in the backend. ID: %s') %
record['id'])
else:
- record_m.delete(self.session)
+ self._delete(tables.records, record_ref['id'],
+ exceptions.RecordNotFound)
# Internal Methods
def _update_domainmetadata(self, domain_id, kind, values=None,
@@ -312,29 +409,37 @@ class PowerDNSBackend(base.Backend):
# Fetch all current metadata of the specified kind
values = values or []
- query = self.session.query(models.DomainMetadata)
- query = query.filter_by(domain_id=domain_id, kind=kind)
+ query = select([tables.domain_metadata.c.content])\
+ .where(tables.domain_metadata.c.domain_id == domain_id)\
+ .where(tables.domain_metadata.c.kind == kind)
+ resultproxy = self.session.execute(query)
+ results = resultproxy.fetchall()
- metadatas = query.all()
-
- for metadata in metadatas:
- if metadata.content not in values:
+ for metadata_id, content in results:
+ if content not in values:
if delete:
LOG.debug('Deleting stale domain metadata: %r' %
- ([domain_id, kind, metadata.value],))
+ ([domain_id, kind, content],))
# Delete no longer necessary values
- metadata.delete(self.session)
+ # We should never get a notfound here, so UnknownFailure is
+ # a reasonable choice.
+ self._delete(tables.domain_metadata, metadata_id,
+ exceptions.UnknownFailure)
else:
# Remove pre-existing values from the list of values to insert
- values.remove(metadata.content)
+ values.remove(content)
# Insert new values
for value in values:
LOG.debug('Inserting new domain metadata: %r' %
([domain_id, kind, value],))
- m = models.DomainMetadata(domain_id=domain_id, kind=kind,
- content=value)
- m.save(self.session)
+ self._create(
+ tables.domain_metadata,
+ {
+ "domain_id": domain_id,
+ "kind": kind,
+ "content": value
+ })
def _is_authoritative(self, domain, recordset, record):
# NOTE(kiall): See http://doc.powerdns.com/dnssec-modes.html
@@ -352,47 +457,24 @@ class PowerDNSBackend(base.Backend):
return content
- def _get_tsigkey(self, tsigkey_id):
- query = self.session.query(models.TsigKey)
-
- try:
- tsigkey = query.filter_by(designate_id=tsigkey_id).one()
- except sqlalchemy_exceptions.NoResultFound:
- raise exceptions.TsigKeyNotFound('No tsigkey found')
- except sqlalchemy_exceptions.MultipleResultsFound:
- raise exceptions.TsigKeyNotFound('Too many tsigkeys found')
- else:
- return tsigkey
-
- def _get_domain(self, domain_id):
- query = self.session.query(models.Domain)
-
- try:
- domain = query.filter_by(designate_id=domain_id).one()
- except sqlalchemy_exceptions.NoResultFound:
- raise exceptions.DomainNotFound('No domain found')
- except sqlalchemy_exceptions.MultipleResultsFound:
- raise exceptions.DomainNotFound('Too many domains found')
- else:
- return domain
-
- def _get_record(self, record_id=None, domain=None, type=None):
- query = self.session.query(models.Record)
+ def _get_record(self, record_id=None, domain=None, type_=None):
+ query = select([tables.records])
if record_id:
- query = query.filter_by(designate_id=record_id)
+ query = query.where(tables.records.c.designate_id == record_id)
- if type:
- query = query.filter_by(type=type)
+ if type_:
+ query = query.where(tables.records.c.type == type_)
if domain:
- query = query.filter_by(domain_id=domain.id)
+ query = query.where(tables.records.c.domain_id == domain['id'])
- try:
- record = query.one()
- except sqlalchemy_exceptions.NoResultFound:
+ resultproxy = self.session.execute(query)
+ results = resultproxy.fetchall()
+
+ if len(results) < 1:
raise exceptions.RecordNotFound('No record found')
- except sqlalchemy_exceptions.MultipleResultsFound:
+ elif len(results) > 1:
raise exceptions.RecordNotFound('Too many records found')
else:
- return record
+ return _map_col(query.columns.keys(), results[0])
diff --git a/designate/backend/impl_powerdns/models.py b/designate/backend/impl_powerdns/models.py
deleted file mode 100644
index 4485ae1e..00000000
--- a/designate/backend/impl_powerdns/models.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# Copyright 2012 Hewlett-Packard Development Company, L.P. All Rights Reserved.
-# Copyright 2012 Managed I.T.
-#
-# Author: Patrick Galbraith <patg@hp.com>
-# Author: Kiall Mac Innes <kiall@managedit.ie>
-#
-# 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 Column, String, Text, Integer, Boolean
-from sqlalchemy.ext.declarative import declarative_base
-
-from designate.sqlalchemy import models
-from designate.sqlalchemy.types import UUID
-
-
-class Base(models.Base):
- id = Column(Integer, primary_key=True, autoincrement=True)
-
-
-Base = declarative_base(cls=Base)
-
-
-class TsigKey(Base):
- __tablename__ = 'tsigkeys'
-
- designate_id = Column(UUID, nullable=False)
-
- name = Column(String(255), default=None, nullable=True)
- algorithm = Column(String(255), default=None, nullable=True)
- secret = Column(String(255), default=None, nullable=True)
-
-
-class DomainMetadata(Base):
- __tablename__ = 'domainmetadata'
-
- domain_id = Column(Integer(), nullable=False)
- kind = Column(String(16), default=None, nullable=True)
- content = Column(Text())
-
-
-class Domain(Base):
- __tablename__ = 'domains'
-
- designate_id = Column(UUID, nullable=False)
-
- name = Column(String(255), nullable=False, unique=True)
- master = Column(String(255), nullable=True)
- last_check = Column(Integer, default=None, nullable=True)
- type = Column(String(6), nullable=False)
- notified_serial = Column(Integer, default=None, nullable=True)
- account = Column(String(40), default=None, nullable=True)
-
-
-class Record(Base):
- __tablename__ = 'records'
-
- designate_id = Column(UUID, nullable=False)
- designate_recordset_id = Column(UUID, default=None, nullable=True)
-
- domain_id = Column(Integer, default=None, nullable=True)
- name = Column(String(255), default=None, nullable=True)
- type = Column(String(10), default=None, nullable=True)
- content = Column(Text, default=None, nullable=True)
- ttl = Column(Integer, default=None, nullable=True)
- prio = Column(Integer, default=None, nullable=True)
- change_date = Column(Integer, default=None, nullable=True)
- ordername = Column(String(255), default=None, nullable=True)
- auth = Column(Boolean(), default=None, nullable=True)
- inherit_ttl = Column(Boolean(), default=True)
diff --git a/designate/backend/impl_powerdns/tables.py b/designate/backend/impl_powerdns/tables.py
new file mode 100644
index 00000000..7e5a3b39
--- /dev/null
+++ b/designate/backend/impl_powerdns/tables.py
@@ -0,0 +1,80 @@
+# Copyright 2012-2014 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, String, Text, Integer, Boolean
+
+
+from oslo.config import cfg
+
+from designate.sqlalchemy.types import UUID
+
+CONF = cfg.CONF
+
+
+metadata = MetaData()
+
+tsigkeys = Table(
+ 'tsigkeys', metadata,
+ Column('id', Integer(), primary_key=True, autoincrement=True),
+
+ Column('designate_id', UUID(), nullable=False),
+ Column('name', String(255), default=None, nullable=True),
+ Column('algorithm', String(255), default=None, nullable=True),
+ Column('secret', String(255), default=None, nullable=True),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+
+domain_metadata = Table(
+ 'domainmetadata', metadata,
+ Column('id', Integer(), primary_key=True, autoincrement=True),
+
+ Column('domain_id', Integer(), nullable=False),
+ Column('kind', String(16), default=None, nullable=True),
+ Column('content', Text()),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+
+domains = Table(
+ 'domains', metadata,
+ Column('id', Integer, primary_key=True, autoincrement=True),
+
+ Column('designate_id', UUID(), nullable=False),
+ Column('name', String(255), nullable=False, unique=True),
+ Column('master', String(255), nullable=True),
+ Column('last_check', Integer(), default=None, nullable=True),
+ Column('type', String(6), nullable=False),
+ Column('notified_serial', Integer(), default=None, nullable=True),
+ Column('account', String(40), default=None, nullable=True),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+
+records = Table(
+ 'records', metadata,
+ Column('id', Integer, primary_key=True, autoincrement=True),
+
+ Column('designate_id', UUID(), nullable=False),
+ Column('designate_recordset_id', UUID(), default=None, nullable=True),
+ Column('domain_id', Integer(), default=None, nullable=True),
+ Column('name', String(255), default=None, nullable=True),
+ Column('type', String(10), default=None, nullable=True),
+ Column('content', Text(), default=None, nullable=True),
+ Column('ttl', Integer(), default=None, nullable=True),
+ Column('prio', Integer(), default=None, nullable=True),
+ Column('change_date', Integer(), default=None, nullable=True),
+ Column('ordername', String(255), default=None, nullable=True),
+ Column('auth', Boolean(), default=None, nullable=True),
+ Column('inherit_ttl', Boolean(), default=True),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
diff --git a/designate/exceptions.py b/designate/exceptions.py
index e1029e58..97d17fa9 100644
--- a/designate/exceptions.py
+++ b/designate/exceptions.py
@@ -46,6 +46,11 @@ class ConfigurationError(Base):
error_type = 'configuration_error'
+class UnknownFailure(Base):
+ error_code = 500
+ error_type = 'unknown_failure'
+
+
class CommunicationFailure(Base):
error_code = 504
error_type = 'communication_failure'