summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--designate/objects/adapters/yaml/base.py10
-rw-r--r--designate/objects/fields.py17
-rw-r--r--designate/objects/ovo_base.py41
-rw-r--r--designate/objects/pool.py74
-rw-r--r--designate/objects/pool_also_notify.py35
-rw-r--r--designate/objects/pool_attribute.py35
-rw-r--r--designate/objects/pool_manager_status.py49
-rw-r--r--designate/objects/pool_nameserver.py35
-rw-r--r--designate/objects/pool_ns_record.py40
-rw-r--r--designate/objects/pool_target.py48
-rw-r--r--designate/objects/pool_target_master.py35
-rw-r--r--designate/objects/pool_target_option.py34
-rw-r--r--designate/objects/zone_export.py4
-rw-r--r--designate/objects/zone_import.py4
-rw-r--r--designate/tests/test_api/test_v2/test_zones.py11
-rw-r--r--designate/tests/test_pool_manager/test_service.py4
-rw-r--r--designate/tests/unit/test_pool.py8
17 files changed, 186 insertions, 298 deletions
diff --git a/designate/objects/adapters/yaml/base.py b/designate/objects/adapters/yaml/base.py
index 4b65a72..a659b80 100644
--- a/designate/objects/adapters/yaml/base.py
+++ b/designate/objects/adapters/yaml/base.py
@@ -51,16 +51,16 @@ class YAMLAdapter(base.DesignateAdapter):
51 obj_key = key 51 obj_key = key
52 # Check if this item is a relation (another DesignateObject that 52 # Check if this item is a relation (another DesignateObject that
53 # will need to be converted itself 53 # will need to be converted itself
54 if object.FIELDS.get(obj_key, {}).get('relation'): 54 if hasattr(object.FIELDS.get(obj_key, {}), 'objname'):
55 # Get a adapter for the nested object 55 # Get a adapter for the nested object
56 # Get the class the object is and get its adapter, then set 56 # Get the class the object is and get its adapter, then set
57 # the item in the dict to the output 57 # the item in the dict to the output
58 r_obj[key] = cls.get_object_adapter( 58 r_obj[key] = cls.get_object_adapter(
59 cls.ADAPTER_FORMAT, 59 cls.ADAPTER_FORMAT,
60 object.FIELDS[obj_key].get('relation_cls')).render( 60 object.FIELDS[obj_key].objname).render(
61 cls.ADAPTER_FORMAT, obj, *args, **kwargs) 61 cls.ADAPTER_FORMAT, obj, *args, **kwargs)
62 elif object.FIELDS.get( 62 elif all(hasattr(object.FIELDS.get(obj_key, {}), attr)
63 obj_key, {}).get('schema', {}).get('type') == 'integer': 63 for attr in ['min', 'max']):
64 r_obj[key] = int(obj) 64 r_obj[key] = int(obj)
65 elif obj is not None: 65 elif obj is not None:
66 # Just attach the damn item if there is no weird edge cases 66 # Just attach the damn item if there is no weird edge cases
diff --git a/designate/objects/fields.py b/designate/objects/fields.py
index 716e5ed..77d221e 100644
--- a/designate/objects/fields.py
+++ b/designate/objects/fields.py
@@ -288,3 +288,20 @@ class BaseObject(ovoo_fields.FieldType):
288 288
289class BaseObjectField(ovoo_fields.AutoTypedField): 289class BaseObjectField(ovoo_fields.AutoTypedField):
290 AUTO_TYPE = BaseObject() 290 AUTO_TYPE = BaseObject()
291
292
293class IPOrHost(IPV4AndV6AddressField):
294 def __init__(self, nullable=False, read_only=False,
295 default=ovoo_fields.UnspecifiedDefault):
296 super(IPOrHost, self).__init__(nullable=nullable,
297 default=default, read_only=read_only)
298
299 def coerce(self, obj, attr, value):
300 try:
301 value = super(IPOrHost, self).coerce(obj, attr, value)
302 except ValueError:
303 if not re.match(StringFields.RE_ZONENAME, value):
304 raise ValueError("%s is not IP address or host name" % value)
305 # we use this field as a string, not need a netaddr.IPAdress
306 # as oslo.versionedobjects is using
307 return str(value)
diff --git a/designate/objects/ovo_base.py b/designate/objects/ovo_base.py
index 5cb265b..ec2e527 100644
--- a/designate/objects/ovo_base.py
+++ b/designate/objects/ovo_base.py
@@ -22,6 +22,8 @@ from oslo_versionedobjects.base import VersionedObjectDictCompat as DictObjectMi
22from designate.i18n import _ 22from designate.i18n import _
23from designate.i18n import _LE 23from designate.i18n import _LE
24from designate.objects import fields 24from designate.objects import fields
25from designate.objects.validation_error import ValidationError
26from designate.objects.validation_error import ValidationErrorList
25from designate import exceptions 27from designate import exceptions
26 28
27LOG = logging.getLogger(__name__) 29LOG = logging.getLogger(__name__)
@@ -209,20 +211,31 @@ class DesignateObject(base.VersionedObject):
209 211
210 def validate(self): 212 def validate(self):
211 self.fields = self.FIELDS 213 self.fields = self.FIELDS
212 try: 214 for name in self.fields:
213 for name in self.fields: 215 field = self.fields[name]
214 field = self.fields[name] 216 if self.obj_attr_is_set(name):
215 if self.obj_attr_is_set(name): 217 value = getattr(self, name) # Check relation
216 value = getattr(self, name) # Check relation 218 if isinstance(value, ListObjectMixin):
217 field.coerce(self, name, value) # Check value 219 for obj in value.objects:
218 if isinstance(value, base.ObjectListBase): 220 obj.validate()
219 for obj in value: 221 else:
220 obj.validate() 222 try:
221 elif not field.nullable: 223 field.coerce(self, name, value) # Check value
222 # Check required is True ~ nullable is False 224 except Exception as e:
223 raise exceptions.InvalidObject 225 raise exceptions.InvalidObject(
224 except Exception: 226 "{} is invalid".format(name))
225 raise exceptions.InvalidObject 227 elif not field.nullable:
228 # Check required is True ~ nullable is False
229 errors = ValidationErrorList()
230 e = ValidationError()
231 e.path = ['records', 0]
232 e.validator = 'required'
233 e.validator_value = [name]
234 e.message = "'%s' is a required property" % name
235 errors.append(e)
236 raise exceptions.InvalidObject(
237 "Provided object does not match "
238 "schema", errors=errors, object=self)
226 239
227 240
228class ListObjectMixin(base.ObjectListBase): 241class ListObjectMixin(base.ObjectListBase):
diff --git a/designate/objects/pool.py b/designate/objects/pool.py
index 677976d..4dc12dc 100644
--- a/designate/objects/pool.py
+++ b/designate/objects/pool.py
@@ -14,64 +14,25 @@
14# License for the specific language governing permissions and limitations 14# License for the specific language governing permissions and limitations
15# under the License. 15# under the License.
16from designate import utils 16from designate import utils
17from designate.objects import base 17from designate.objects import ovo_base as base
18from designate.objects import fields
18 19
19 20
21@base.DesignateRegistry.register
20class Pool(base.DictObjectMixin, base.PersistentObjectMixin, 22class Pool(base.DictObjectMixin, base.PersistentObjectMixin,
21 base.DesignateObject): 23 base.DesignateObject):
22 FIELDS = { 24 fields = {
23 'name': { 25 'name': fields.StringFields(maxLength=50),
24 'schema': { 26 'description': fields.StringFields(nullable=True, maxLength=160),
25 'type': 'string', 27 'tenant_id': fields.StringFields(maxLength=36, nullable=True),
26 'description': 'Pool name', 28 'provisioner': fields.StringFields(nullable=True, maxLength=160),
27 'maxLength': 50, 29 'attributes': fields.ObjectFields('PoolAttributeList', nullable=True),
28 }, 30 'ns_records': fields.ObjectFields('PoolNsRecordList', nullable=True),
29 'immutable': True, 31 'nameservers': fields.ObjectFields('PoolNameserverList',
30 'required': True 32 nullable=True),
31 }, 33 'targets': fields.ObjectFields('PoolTargetList', nullable=True),
32 'description': { 34 'also_notifies': fields.ObjectFields('PoolAlsoNotifyList',
33 'schema': { 35 nullable=True),
34 'type': ['string', 'null'],
35 'description': 'Description for the pool',
36 'maxLength': 160
37 }
38 },
39 'tenant_id': {
40 'schema': {
41 'type': ['string', 'null'],
42 'description': 'Project identifier',
43 'maxLength': 36,
44 },
45 'immutable': True
46 },
47 'provisioner': {
48 'schema': {
49 'type': ['string', 'null'],
50 'description': 'Provisioner used for this pool',
51 'maxLength': 160
52 }
53 },
54 'attributes': {
55 'relation': True,
56 'relation_cls': 'PoolAttributeList',
57 },
58 'ns_records': {
59 'relation': True,
60 'relation_cls': 'PoolNsRecordList',
61 'required': True
62 },
63 'nameservers': {
64 'relation': True,
65 'relation_cls': 'PoolNameserverList'
66 },
67 'targets': {
68 'relation': True,
69 'relation_cls': 'PoolTargetList'
70 },
71 'also_notifies': {
72 'relation': True,
73 'relation_cls': 'PoolAlsoNotifyList'
74 },
75 } 36 }
76 37
77 @classmethod 38 @classmethod
@@ -144,9 +105,14 @@ class Pool(base.DictObjectMixin, base.PersistentObjectMixin,
144 ] 105 ]
145 106
146 107
108@base.DesignateRegistry.register
147class PoolList(base.ListObjectMixin, base.DesignateObject): 109class PoolList(base.ListObjectMixin, base.DesignateObject):
148 LIST_ITEM_TYPE = Pool 110 LIST_ITEM_TYPE = Pool
149 111
112 fields = {
113 'objects': fields.ListOfObjectsField('Pool'),
114 }
115
150 def __contains__(self, pool): 116 def __contains__(self, pool):
151 for p in self.objects: 117 for p in self.objects:
152 if p.id == pool.id: 118 if p.id == pool.id:
diff --git a/designate/objects/pool_also_notify.py b/designate/objects/pool_also_notify.py
index 60ab5d9..8e5c180 100644
--- a/designate/objects/pool_also_notify.py
+++ b/designate/objects/pool_also_notify.py
@@ -12,34 +12,17 @@
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations 13# License for the specific language governing permissions and limitations
14# under the License. 14# under the License.
15from designate.objects import base 15from designate.objects import ovo_base as base
16from designate.objects import fields
16 17
17 18
19@base.DesignateRegistry.register
18class PoolAlsoNotify(base.DictObjectMixin, base.PersistentObjectMixin, 20class PoolAlsoNotify(base.DictObjectMixin, base.PersistentObjectMixin,
19 base.DesignateObject): 21 base.DesignateObject):
20 FIELDS = { 22 fields = {
21 'pool_id': { 23 'pool_id': fields.UUIDFields(nullable=True),
22 'schema': { 24 'host': fields.IPOrHost(),
23 'type': 'string', 25 'port': fields.IntegerFields(minimum=1, maximum=65535),
24 'description': 'Pool identifier',
25 'format': 'uuid',
26 },
27 },
28 'host': {
29 'schema': {
30 'type': 'string',
31 'format': 'ip-or-host',
32 'required': True,
33 },
34 },
35 'port': {
36 'schema': {
37 'type': 'integer',
38 'minimum': 1,
39 'maximum': 65535,
40 'required': True,
41 },
42 }
43 } 26 }
44 27
45 STRING_KEYS = [ 28 STRING_KEYS = [
@@ -47,5 +30,9 @@ class PoolAlsoNotify(base.DictObjectMixin, base.PersistentObjectMixin,
47 ] 30 ]
48 31
49 32
33@base.DesignateRegistry.register
50class PoolAlsoNotifyList(base.ListObjectMixin, base.DesignateObject): 34class PoolAlsoNotifyList(base.ListObjectMixin, base.DesignateObject):
51 LIST_ITEM_TYPE = PoolAlsoNotify 35 LIST_ITEM_TYPE = PoolAlsoNotify
36 fields = {
37 'objects': fields.ListOfObjectsField('PoolAlsoNotify'),
38 }
diff --git a/designate/objects/pool_attribute.py b/designate/objects/pool_attribute.py
index 4bbcead..9b2b70a 100644
--- a/designate/objects/pool_attribute.py
+++ b/designate/objects/pool_attribute.py
@@ -12,33 +12,18 @@
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations 13# License for the specific language governing permissions and limitations
14# under the License. 14# under the License.
15from designate.objects import base 15from designate.objects import ovo_base as base
16from designate.objects import fields
16 17
17 18
19@base.DesignateRegistry.register
18class PoolAttribute(base.DictObjectMixin, base.PersistentObjectMixin, 20class PoolAttribute(base.DictObjectMixin, base.PersistentObjectMixin,
19 base.DesignateObject): 21 base.DesignateObject):
20 FIELDS = { 22 fields = {
21 'pool_id': { 23 'pool_id': fields.UUIDFields(nullable=True),
22 'schema': { 24 'key': fields.StringFields(maxLength=50),
23 'type': 'string', 25 'value': fields.StringFields(maxLength=50)
24 'description': 'Pool identifier', 26
25 'format': 'uuid',
26 },
27 },
28 'key': {
29 'schema': {
30 'type': 'string',
31 'maxLength': 50,
32 },
33 'required': True,
34 },
35 'value': {
36 'schema': {
37 'type': 'string',
38 'maxLength': 50,
39 },
40 'required': True
41 }
42 } 27 }
43 28
44 STRING_KEYS = [ 29 STRING_KEYS = [
@@ -46,5 +31,9 @@ class PoolAttribute(base.DictObjectMixin, base.PersistentObjectMixin,
46 ] 31 ]
47 32
48 33
34@base.DesignateRegistry.register
49class PoolAttributeList(base.AttributeListObjectMixin, base.DesignateObject): 35class PoolAttributeList(base.AttributeListObjectMixin, base.DesignateObject):
50 LIST_ITEM_TYPE = PoolAttribute 36 LIST_ITEM_TYPE = PoolAttribute
37 fields = {
38 'objects': fields.ListOfObjectsField('PoolAttribute'),
39 }
diff --git a/designate/objects/pool_manager_status.py b/designate/objects/pool_manager_status.py
index 65af45a..5373782 100644
--- a/designate/objects/pool_manager_status.py
+++ b/designate/objects/pool_manager_status.py
@@ -13,44 +13,21 @@
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations 14# License for the specific language governing permissions and limitations
15# under the License. 15# under the License.
16from designate.objects import base 16from designate.objects import ovo_base as base
17from designate.objects import fields
17 18
18 19
20@base.DesignateRegistry.register
19class PoolManagerStatus(base.DictObjectMixin, base.PersistentObjectMixin, 21class PoolManagerStatus(base.DictObjectMixin, base.PersistentObjectMixin,
20 base.DesignateObject): 22 base.DesignateObject):
21 FIELDS = { 23 fields = {
22 'nameserver_id': { 24 'nameserver_id': fields.UUIDFields(),
23 'schema': { 25 'zone_id': fields.UUIDFields(),
24 'type': 'string', 26 'status': fields.EnumField(['ACTIVE', 'PENDING', 'ERROR',
25 'format': 'uuid', 27 'SUCCESS', 'COMPLETE'], nullable=True),
26 }, 28 'serial_number': fields.IntegerFields(minimum=0, maximum=4294967295),
27 'required': True 29 'action': fields.EnumField(['CREATE', 'DELETE',
28 }, 30 'UPDATE', 'NONE'], nullable=True),
29 'zone_id': {
30 'schema': {
31 'type': 'string',
32 'format': 'uuid',
33 },
34 'required': True},
35 'status': {
36 'schema': {
37 'type': ['string', 'null'],
38 'enum': ['ACTIVE', 'PENDING', 'ERROR'],
39 },
40 },
41 'serial_number': {
42 'schema': {
43 'type': 'integer',
44 'minimum': 0,
45 'maximum': 4294967295,
46 },
47 },
48 'action': {
49 'schema': {
50 'type': 'string',
51 'enum': ['CREATE', 'DELETE', 'UPDATE', 'NONE'],
52 },
53 }
54 } 31 }
55 32
56 STRING_KEYS = [ 33 STRING_KEYS = [
@@ -58,5 +35,9 @@ class PoolManagerStatus(base.DictObjectMixin, base.PersistentObjectMixin,
58 ] 35 ]
59 36
60 37
38@base.DesignateRegistry.register
61class PoolManagerStatusList(base.ListObjectMixin, base.DesignateObject): 39class PoolManagerStatusList(base.ListObjectMixin, base.DesignateObject):
62 LIST_ITEM_TYPE = PoolManagerStatus 40 LIST_ITEM_TYPE = PoolManagerStatus
41 fields = {
42 'objects': fields.ListOfObjectsField('PoolManagerStatus'),
43 }
diff --git a/designate/objects/pool_nameserver.py b/designate/objects/pool_nameserver.py
index 5eaef25..e11151e 100644
--- a/designate/objects/pool_nameserver.py
+++ b/designate/objects/pool_nameserver.py
@@ -12,34 +12,17 @@
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations 13# License for the specific language governing permissions and limitations
14# under the License. 14# under the License.
15from designate.objects import base 15from designate.objects import ovo_base as base
16from designate.objects import fields
16 17
17 18
19@base.DesignateRegistry.register
18class PoolNameserver(base.DictObjectMixin, base.PersistentObjectMixin, 20class PoolNameserver(base.DictObjectMixin, base.PersistentObjectMixin,
19 base.DesignateObject): 21 base.DesignateObject):
20 FIELDS = { 22 fields = {
21 'pool_id': { 23 'pool_id': fields.UUIDFields(nullable=True),
22 'schema': { 24 'host': fields.IPOrHost(),
23 'type': 'string', 25 'port': fields.IntegerFields(minimum=1, maximum=65535),
24 'description': 'Pool identifier',
25 'format': 'uuid',
26 },
27 },
28 'host': {
29 'schema': {
30 'type': 'string',
31 'format': 'ip-or-host',
32 'required': True,
33 },
34 },
35 'port': {
36 'schema': {
37 'type': 'integer',
38 'minimum': 1,
39 'maximum': 65535,
40 'required': True,
41 },
42 }
43 } 26 }
44 27
45 STRING_KEYS = [ 28 STRING_KEYS = [
@@ -47,5 +30,9 @@ class PoolNameserver(base.DictObjectMixin, base.PersistentObjectMixin,
47 ] 30 ]
48 31
49 32
33@base.DesignateRegistry.register
50class PoolNameserverList(base.ListObjectMixin, base.DesignateObject): 34class PoolNameserverList(base.ListObjectMixin, base.DesignateObject):
51 LIST_ITEM_TYPE = PoolNameserver 35 LIST_ITEM_TYPE = PoolNameserver
36 fields = {
37 'objects': fields.ListOfObjectsField('PoolNameserver'),
38 }
diff --git a/designate/objects/pool_ns_record.py b/designate/objects/pool_ns_record.py
index 26904a6..c6b1954 100644
--- a/designate/objects/pool_ns_record.py
+++ b/designate/objects/pool_ns_record.py
@@ -12,38 +12,18 @@
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations 13# License for the specific language governing permissions and limitations
14# under the License. 14# under the License.
15from designate.objects import base 15from designate.objects import ovo_base as base
16from designate.objects import fields
16 17
17 18
19@base.DesignateRegistry.register
18class PoolNsRecord(base.DictObjectMixin, base.PersistentObjectMixin, 20class PoolNsRecord(base.DictObjectMixin, base.PersistentObjectMixin,
19 base.DesignateObject): 21 base.DesignateObject):
20 FIELDS = { 22 fields = {
21 'pool_id': { 23 'pool_id': fields.UUIDFields(nullable=True),
22 'schema': { 24 'priority': fields.IntegerFields(minimum=1, maximum=10000),
23 'type': 'string', 25 'hostname': fields.DomainField(maxLength=255),
24 'description': 'Pool identifier', 26
25 'format': 'uuid',
26 },
27 },
28 'priority': {
29 'schema': {
30 'type': 'integer',
31 'description': 'NS Record Priority Order',
32 'minimum': 1,
33 'maximum': 10000
34 },
35 'required': True
36 },
37 'hostname': {
38 'schema': {
39 'type': 'string',
40 'description': 'NS Record Hostname',
41 'format': 'domainname',
42 'maxLength': 255,
43 },
44 'immutable': True,
45 'required': True
46 }
47 } 27 }
48 28
49 STRING_KEYS = [ 29 STRING_KEYS = [
@@ -51,5 +31,9 @@ class PoolNsRecord(base.DictObjectMixin, base.PersistentObjectMixin,
51 ] 31 ]
52 32
53 33
34@base.DesignateRegistry.register
54class PoolNsRecordList(base.ListObjectMixin, base.DesignateObject): 35class PoolNsRecordList(base.ListObjectMixin, base.DesignateObject):
55 LIST_ITEM_TYPE = PoolNsRecord 36 LIST_ITEM_TYPE = PoolNsRecord
37 fields = {
38 'objects': fields.ListOfObjectsField('PoolNsRecord'),
39 }
diff --git a/designate/objects/pool_target.py b/designate/objects/pool_target.py
index 828898c..8d8b502 100644
--- a/designate/objects/pool_target.py
+++ b/designate/objects/pool_target.py
@@ -12,43 +12,21 @@
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations 13# License for the specific language governing permissions and limitations
14# under the License. 14# under the License.
15from designate.objects import base 15from designate.objects import ovo_base as base
16from designate.objects import fields
16 17
17 18
19@base.DesignateRegistry.register
18class PoolTarget(base.DictObjectMixin, base.PersistentObjectMixin, 20class PoolTarget(base.DictObjectMixin, base.PersistentObjectMixin,
19 base.DesignateObject): 21 base.DesignateObject):
20 FIELDS = { 22 fields = {
21 'pool_id': { 23 'pool_id': fields.UUIDFields(nullable=True),
22 'schema': { 24 'type': fields.AnyField(nullable=True),
23 'type': 'string', 25 'tsigkey_id': fields.UUIDFields(nullable=True),
24 'description': 'Pool identifier', 26 'description': fields.StringFields(maxLength=160, nullable=True),
25 'format': 'uuid', 27 'masters': fields.ObjectFields('PoolTargetMasterList'),
26 }, 28 'options': fields.ObjectFields('PoolTargetOptionList'),
27 }, 29 'backend': fields.AnyField(nullable=True),
28 'type': {},
29 'tsigkey_id': {
30 'schema': {
31 'type': ['string', 'null'],
32 'description': 'TSIG identifier',
33 'format': 'uuid',
34 },
35 },
36 'description': {
37 'schema': {
38 'type': ['string', 'null'],
39 'description': 'Description for the pool',
40 'maxLength': 160
41 }
42 },
43 'masters': {
44 'relation': True,
45 'relation_cls': 'PoolTargetMasterList'
46 },
47 'options': {
48 'relation': True,
49 'relation_cls': 'PoolTargetOptionList'
50 },
51 'backend': {}
52 } 30 }
53 31
54 STRING_KEYS = [ 32 STRING_KEYS = [
@@ -56,5 +34,9 @@ class PoolTarget(base.DictObjectMixin, base.PersistentObjectMixin,
56 ] 34 ]
57 35
58 36
37@base.DesignateRegistry.register
59class PoolTargetList(base.ListObjectMixin, base.DesignateObject): 38class PoolTargetList(base.ListObjectMixin, base.DesignateObject):
60 LIST_ITEM_TYPE = PoolTarget 39 LIST_ITEM_TYPE = PoolTarget
40 fields = {
41 'objects': fields.ListOfObjectsField('PoolTarget'),
42 }
diff --git a/designate/objects/pool_target_master.py b/designate/objects/pool_target_master.py
index f26d301..957aff7 100644
--- a/designate/objects/pool_target_master.py
+++ b/designate/objects/pool_target_master.py
@@ -12,34 +12,17 @@
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations 13# License for the specific language governing permissions and limitations
14# under the License. 14# under the License.
15from designate.objects import base 15from designate.objects import ovo_base as base
16from designate.objects import fields
16 17
17 18
19@base.DesignateRegistry.register
18class PoolTargetMaster(base.DictObjectMixin, base.PersistentObjectMixin, 20class PoolTargetMaster(base.DictObjectMixin, base.PersistentObjectMixin,
19 base.DesignateObject): 21 base.DesignateObject):
20 FIELDS = { 22 fields = {
21 'pool_target_id': { 23 'pool_target_id': fields.UUIDFields(nullable=True),
22 'schema': { 24 'host': fields.IPOrHost(),
23 'type': 'string', 25 'port': fields.IntegerFields(minimum=1, maximum=65535)
24 'description': 'Pool Target identifier',
25 'format': 'uuid',
26 },
27 },
28 'host': {
29 'schema': {
30 'type': 'string',
31 'format': 'ip-or-host',
32 'required': True,
33 },
34 },
35 'port': {
36 'schema': {
37 'type': 'integer',
38 'minimum': 1,
39 'maximum': 65535,
40 'required': True,
41 },
42 }
43 } 26 }
44 27
45 STRING_KEYS = [ 28 STRING_KEYS = [
@@ -47,5 +30,9 @@ class PoolTargetMaster(base.DictObjectMixin, base.PersistentObjectMixin,
47 ] 30 ]
48 31
49 32
33@base.DesignateRegistry.register
50class PoolTargetMasterList(base.ListObjectMixin, base.DesignateObject): 34class PoolTargetMasterList(base.ListObjectMixin, base.DesignateObject):
51 LIST_ITEM_TYPE = PoolTargetMaster 35 LIST_ITEM_TYPE = PoolTargetMaster
36 fields = {
37 'objects': fields.ListOfObjectsField('PoolTargetMaster'),
38 }
diff --git a/designate/objects/pool_target_option.py b/designate/objects/pool_target_option.py
index 5d19bb0..b349b7e 100644
--- a/designate/objects/pool_target_option.py
+++ b/designate/objects/pool_target_option.py
@@ -12,33 +12,17 @@
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations 13# License for the specific language governing permissions and limitations
14# under the License. 14# under the License.
15from designate.objects import base 15from designate.objects import ovo_base as base
16from designate.objects import fields
16 17
17 18
19@base.DesignateRegistry.register
18class PoolTargetOption(base.DictObjectMixin, base.PersistentObjectMixin, 20class PoolTargetOption(base.DictObjectMixin, base.PersistentObjectMixin,
19 base.DesignateObject): 21 base.DesignateObject):
20 FIELDS = { 22 fields = {
21 'pool_target_id': { 23 'pool_target_id': fields.UUIDFields(nullable=True),
22 'schema': { 24 'key': fields.StringFields(maxLength=255),
23 'type': 'string', 25 'value': fields.AnyField(),
24 'description': 'Pool Target identifier',
25 'format': 'uuid',
26 },
27 },
28 'key': {
29 'schema': {
30 'type': 'string',
31 'maxLength': 255,
32 },
33 'required': True,
34 },
35 'value': {
36 'schema': {
37 'type': 'string',
38 'maxLength': 255,
39 },
40 'required': True
41 }
42 } 26 }
43 27
44 STRING_KEYS = [ 28 STRING_KEYS = [
@@ -46,6 +30,10 @@ class PoolTargetOption(base.DictObjectMixin, base.PersistentObjectMixin,
46 ] 30 ]
47 31
48 32
33@base.DesignateRegistry.register
49class PoolTargetOptionList(base.AttributeListObjectMixin, 34class PoolTargetOptionList(base.AttributeListObjectMixin,
50 base.DesignateObject): 35 base.DesignateObject):
51 LIST_ITEM_TYPE = PoolTargetOption 36 LIST_ITEM_TYPE = PoolTargetOption
37 fields = {
38 'objects': fields.ListOfObjectsField('PoolTargetOption'),
39 }
diff --git a/designate/objects/zone_export.py b/designate/objects/zone_export.py
index a2e5afc..9c1651b 100644
--- a/designate/objects/zone_export.py
+++ b/designate/objects/zone_export.py
@@ -21,11 +21,11 @@ from designate.objects import fields
21class ZoneExport(base.DictObjectMixin, base.PersistentObjectMixin, 21class ZoneExport(base.DictObjectMixin, base.PersistentObjectMixin,
22 base.DesignateObject): 22 base.DesignateObject):
23 fields = { 23 fields = {
24 'status': fields.EnumField( 24 'status': fields.EnumField(nullable=True,
25 valid_values=["ACTIVE", "PENDING", 25 valid_values=["ACTIVE", "PENDING",
26 "DELETED", "ERROR", "COMPLETE"] 26 "DELETED", "ERROR", "COMPLETE"]
27 ), 27 ),
28 'task_type': fields.EnumField( 28 'task_type': fields.EnumField(nullable=True,
29 valid_values=["EXPORT"] 29 valid_values=["EXPORT"]
30 ), 30 ),
31 'tenant_id': fields.StringFields(nullable=True), 31 'tenant_id': fields.StringFields(nullable=True),
diff --git a/designate/objects/zone_import.py b/designate/objects/zone_import.py
index ed91f94..7b7b1ba 100644
--- a/designate/objects/zone_import.py
+++ b/designate/objects/zone_import.py
@@ -21,11 +21,11 @@ from designate.objects import fields
21class ZoneImport(base.DictObjectMixin, base.PersistentObjectMixin, 21class ZoneImport(base.DictObjectMixin, base.PersistentObjectMixin,
22 base.DesignateObject): 22 base.DesignateObject):
23 fields = { 23 fields = {
24 'status': fields.EnumField( 24 'status': fields.EnumField(nullable=True,
25 valid_values=["ACTIVE", "PENDING", 25 valid_values=["ACTIVE", "PENDING",
26 "DELETED", "ERROR", "COMPLETE"] 26 "DELETED", "ERROR", "COMPLETE"]
27 ), 27 ),
28 'task_type': fields.EnumField( 28 'task_type': fields.EnumField(nullable=True,
29 valid_values=["IMPORT"] 29 valid_values=["IMPORT"]
30 ), 30 ),
31 'tenant_id': fields.StringFields(nullable=True), 31 'tenant_id': fields.StringFields(nullable=True),
diff --git a/designate/tests/test_api/test_v2/test_zones.py b/designate/tests/test_api/test_v2/test_zones.py
index f873118..79f235a 100644
--- a/designate/tests/test_api/test_v2/test_zones.py
+++ b/designate/tests/test_api/test_v2/test_zones.py
@@ -519,9 +519,14 @@ class ApiV2ZonesTest(ApiV2TestCase):
519 519
520 def test_update_secondary(self): 520 def test_update_secondary(self):
521 # Create a zone 521 # Create a zone
522 fixture = self.get_zone_fixture('SECONDARY', 0) 522 zone = objects.Zone(
523 523 name='example.com.',
524 zone = objects.Zone(**fixture) 524 type='SECONDARY',
525 masters=objects.ZoneMasterList.from_list([
526 {'host': '1.0.0.0', 'port': 69},
527 {'host': '2.0.0.0', 'port': 69}
528 ])
529 )
525 zone.email = cfg.CONF['service:central'].managed_resource_email 530 zone.email = cfg.CONF['service:central'].managed_resource_email
526 531
527 # Create a zone 532 # Create a zone
diff --git a/designate/tests/test_pool_manager/test_service.py b/designate/tests/test_pool_manager/test_service.py
index 05379bf..4afbdcb 100644
--- a/designate/tests/test_pool_manager/test_service.py
+++ b/designate/tests/test_pool_manager/test_service.py
@@ -350,7 +350,9 @@ class PoolManagerServiceNoopTest(PoolManagerTestCase):
350 zone = self._build_zone('example.org.', 'UPDATE', 'PENDING') 350 zone = self._build_zone('example.org.', 'UPDATE', 'PENDING')
351 self.service._update_zone_on_target = Mock(return_value=True) 351 self.service._update_zone_on_target = Mock(return_value=True)
352 self.service._update_zone_on_also_notify = Mock() 352 self.service._update_zone_on_also_notify = Mock()
353 self.service.pool.also_notifies = ['bogus'] 353 self.service.pool.also_notifies = objects.PoolAlsoNotifyList(
354 objects=[objects.PoolAlsoNotify(host='1.0.0.0', port=1)]
355 )
354 self.service._exceed_or_meet_threshold = Mock(return_value=True) 356 self.service._exceed_or_meet_threshold = Mock(return_value=True)
355 357
356 # cache.retrieve will throw exceptions.PoolManagerStatusNotFound 358 # cache.retrieve will throw exceptions.PoolManagerStatusNotFound
diff --git a/designate/tests/unit/test_pool.py b/designate/tests/unit/test_pool.py
index 03a13ad..c8e6ebe 100644
--- a/designate/tests/unit/test_pool.py
+++ b/designate/tests/unit/test_pool.py
@@ -50,11 +50,11 @@ mock_conf = RoObject(**{
50 also_notifies=['1.0.0.0:1', '2.0.0.0:2'] 50 also_notifies=['1.0.0.0:1', '2.0.0.0:2']
51 ), 51 ),
52 'pool_nameserver:169ca3fc-5924-4a44-8c1f-7efbe52fbd59': RoObject( 52 'pool_nameserver:169ca3fc-5924-4a44-8c1f-7efbe52fbd59': RoObject(
53 host='pool_host_1', 53 host='pool_host_1.example.',
54 port=123 54 port=123
55 ), 55 ),
56 'pool_nameserver:269ca3fc-5924-4a44-8c1f-7efbe52fbd59': RoObject( 56 'pool_nameserver:269ca3fc-5924-4a44-8c1f-7efbe52fbd59': RoObject(
57 host='pool_host_2', 57 host='pool_host_2.example.',
58 port=456 58 port=456
59 ), 59 ),
60 'pool_target:1588652b-50e7-46b9-b688-a9bad40a873e': RoObject( 60 'pool_target:1588652b-50e7-46b9-b688-a9bad40a873e': RoObject(
@@ -91,10 +91,10 @@ class poolTest(oslotest.base.BaseTestCase):
91 [('host', '2.0.0.0'), ('port', 2)]]), 91 [('host', '2.0.0.0'), ('port', 2)]]),
92 ('description', 'Pool built from configuration on foohost'), # noqa 92 ('description', 'Pool built from configuration on foohost'), # noqa
93 ('id', '769ca3fc-5924-4a44-8c1f-7efbe52fbd59'), 93 ('id', '769ca3fc-5924-4a44-8c1f-7efbe52fbd59'),
94 ('nameservers', [[('host', 'pool_host_1'), 94 ('nameservers', [[('host', 'pool_host_1.example.'),
95 ('id', '169ca3fc-5924-4a44-8c1f-7efbe52fbd59'), # noqa 95 ('id', '169ca3fc-5924-4a44-8c1f-7efbe52fbd59'), # noqa
96 ('port', 123)], 96 ('port', 123)],
97 [('host', 'pool_host_2'), 97 [('host', 'pool_host_2.example.'),
98 ('id', '269ca3fc-5924-4a44-8c1f-7efbe52fbd59'), # noqa 98 ('id', '269ca3fc-5924-4a44-8c1f-7efbe52fbd59'), # noqa
99 ('port', 456)]]), 99 ('port', 456)]]),
100 ('targets', [[('id', '1588652b-50e7-46b9-b688-a9bad40a873e'), # noqa 100 ('targets', [[('id', '1588652b-50e7-46b9-b688-a9bad40a873e'), # noqa