Introducing the Subnet OVO

This patch is introducing the following OVOs:
- DNSNameServer
- Route
- IPAllocation
- Subnet

Partially-Implements: blueprint adopt-oslo-versioned-objects-for-db
Change-Id: I3fca197098f24f68ea2b2915851c68dc170e781c
This commit is contained in:
Artur Korzeniewski 2016-05-11 15:28:13 +02:00 committed by Ihar Hrachyshka
parent 7327e8c210
commit 563fea3786
5 changed files with 287 additions and 0 deletions

173
neutron/objects/subnet.py Normal file
View File

@ -0,0 +1,173 @@
# 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.
import netaddr
from oslo_versionedobjects import base as obj_base
from oslo_versionedobjects import fields as obj_fields
from neutron.db import models_v2
from neutron.objects import base
from neutron.objects import common_types
@obj_base.VersionedObjectRegistry.register
class DNSNameServer(base.NeutronDbObject):
# Version 1.0: Initial version
VERSION = '1.0'
db_model = models_v2.DNSNameServer
primary_keys = ['address', 'subnet_id']
foreign_keys = {'subnet_id': 'id'}
fields = {
'address': obj_fields.StringField(),
'subnet_id': obj_fields.UUIDField(),
'order': obj_fields.IntegerField()
}
@obj_base.VersionedObjectRegistry.register
class Route(base.NeutronDbObject):
# Version 1.0: Initial version
VERSION = '1.0'
db_model = models_v2.SubnetRoute
primary_keys = ['destination', 'nexthop', 'subnet_id']
foreign_keys = {'subnet_id': 'id'}
fields = {
'subnet_id': obj_fields.UUIDField(),
'destination': obj_fields.IPNetworkField(),
'nexthop': obj_fields.IPAddressField()
}
@classmethod
def modify_fields_from_db(cls, db_obj):
# TODO(korzen) remove this method when IP and CIDR decorator ready
result = super(Route, cls).modify_fields_from_db(db_obj)
if 'destination' in result:
result['destination'] = netaddr.IPNetwork(result['destination'])
if 'nexthop' in result:
result['nexthop'] = netaddr.IPAddress(result['nexthop'])
return result
@classmethod
def modify_fields_to_db(cls, fields):
# TODO(korzen) remove this method when IP and CIDR decorator ready
result = super(Route, cls).modify_fields_to_db(fields)
if 'destination' in result:
result['destination'] = str(result['destination'])
if 'nexthop' in fields:
result['nexthop'] = str(result['nexthop'])
return result
@obj_base.VersionedObjectRegistry.register
class IPAllocationPool(base.NeutronDbObject):
# Version 1.0: Initial version
VERSION = '1.0'
db_model = models_v2.IPAllocationPool
foreign_keys = {'subnet_id': 'id'}
fields_need_translation = {
'start': 'first_ip',
'end': 'last_ip'
}
fields = {
'id': obj_fields.UUIDField(),
'subnet_id': obj_fields.UUIDField(),
'start': obj_fields.IPAddressField(),
'end': obj_fields.IPAddressField()
}
@classmethod
def modify_fields_from_db(cls, db_obj):
# TODO(korzen) remove this method when IP and CIDR decorator ready
result = super(IPAllocationPool, cls).modify_fields_from_db(db_obj)
if 'start' in result:
result['start'] = netaddr.IPAddress(result['start'])
if 'end' in result:
result['end'] = netaddr.IPAddress(result['end'])
return result
@classmethod
def modify_fields_to_db(cls, fields):
# TODO(korzen) remove this method when IP and CIDR decorator ready
result = super(IPAllocationPool, cls).modify_fields_to_db(fields)
if 'first_ip' in result:
result['first_ip'] = str(result['first_ip'])
if 'last_ip' in result:
result['last_ip'] = str(result['last_ip'])
return result
@obj_base.VersionedObjectRegistry.register
class Subnet(base.NeutronDbObject):
# Version 1.0: Initial version
VERSION = '1.0'
db_model = models_v2.Subnet
fields = {
'id': obj_fields.UUIDField(),
'project_id': obj_fields.UUIDField(),
'name': obj_fields.StringField(),
'network_id': obj_fields.UUIDField(),
'subnetpool_id': obj_fields.UUIDField(nullable=True),
'ip_version': common_types.IPVersionEnumField(),
'cidr': obj_fields.IPNetworkField(),
'gateway_ip': obj_fields.IPAddressField(nullable=True),
'allocation_pools': obj_fields.ListOfObjectsField('IPAllocationPool',
nullable=True),
'enable_dhcp': obj_fields.BooleanField(),
'dns_nameservers': obj_fields.ListOfObjectsField('DNSNameServer',
nullable=True),
'host_routes': obj_fields.ListOfObjectsField('Route', nullable=True),
'ipv6_ra_mode': common_types.IPV6ModeEnumField(nullable=True),
'ipv6_address_mode': common_types.IPV6ModeEnumField(nullable=True)
}
synthetic_fields = ['allocation_pools', 'dns_nameservers', 'host_routes']
foreign_keys = {'network_id': 'id'}
fields_need_translation = {
'project_id': 'tenant_id'
}
@classmethod
def modify_fields_from_db(cls, db_obj):
# TODO(korzen) remove this method when IP and CIDR decorator ready
result = super(Subnet, cls).modify_fields_from_db(db_obj)
if 'cidr' in result:
result['cidr'] = netaddr.IPNetwork(result['cidr'])
if 'gateway_ip' in result and result['gateway_ip'] is not None:
result['gateway_ip'] = netaddr.IPAddress(result['gateway_ip'])
return result
@classmethod
def modify_fields_to_db(cls, fields):
# TODO(korzen) remove this method when IP and CIDR decorator ready
result = super(Subnet, cls).modify_fields_to_db(fields)
if 'cidr' in result:
result['cidr'] = str(result['cidr'])
if 'gateway_ip' in result and result['gateway_ip'] is not None:
result['gateway_ip'] = str(result['gateway_ip'])
return result

View File

@ -300,3 +300,7 @@ def reset_random_seed():
# at the same time get the same values from RNG
seed = time.time() + os.getpid()
random.seed(seed)
def get_random_ipv6_mode():
return random.choice(constants.IPV6_MODES)

View File

@ -30,6 +30,7 @@ from neutron.db import models_v2
from neutron.objects import base
from neutron.objects import common_types
from neutron.objects.db import api as obj_db_api
from neutron.objects import subnet
from neutron.tests import base as test_base
from neutron.tests import tools
@ -242,6 +243,7 @@ FIELD_TYPE_VALUE_GENERATOR_MAP = {
obj_fields.DateTimeField: timeutils.utcnow,
obj_fields.IPAddressField: tools.get_random_ip_address,
common_types.MACAddressField: tools.get_random_EUI,
common_types.IPV6ModeEnumField: tools.get_random_ipv6_mode,
}
@ -640,6 +642,21 @@ class BaseDbObjectTestCase(_BaseObjectTestCase):
models_v2.Network,
{'name': 'test-network1'})
def _create_test_subnet(self, network):
test_subnet = {
'tenant_id': uuidutils.generate_uuid(),
'name': 'test-subnet1',
'network_id': network['id'],
'ip_version': 4,
'cidr': '10.0.0.0/24',
'gateway_ip': '10.0.0.1',
'enable_dhcp': 1,
'ipv6_ra_mode': None,
'ipv6_address_mode': None
}
self._subnet = subnet.Subnet(self.context, **test_subnet)
self._subnet.create()
def _create_test_port(self, network):
# TODO(ihrachys): replace with port.create() once we get an object
# implementation for ports

View File

@ -27,13 +27,17 @@ from neutron.tests import tools
# corresponding version bump in the affected objects.
object_data = {
'AddressScope': '1.0-681cb915f973c92350fe2c797dec2ea4',
'DNSNameServer': '1.0-bf87a85327e2d812d1666ede99d9918b',
'ExtraDhcpOpt': '1.0-632f689cbeb36328995a7aed1d0a78d3',
'IPAllocationPool': '1.0-371016a6480ed0b4299319cb46d9215d',
'PortSecurity': '1.0-cf5b382a0112080ec4e0f23f697c7ab2',
'AllowedAddressPair': '1.0-0d7380d7d4a32f72e6ae509af1476297',
'QosBandwidthLimitRule': '1.1-4e44a8f5c2895ab1278399f87b40a13d',
'QosDscpMarkingRule': '1.1-0313c6554b34fd10c753cb63d638256c',
'QosRuleType': '1.1-8a53fef4c6a43839d477a85b787d22ce',
'QosPolicy': '1.1-721fa60ea8f0e8f15d456d6e917dfe59',
'Route': '1.0-a9883a63b416126f9e345523ec09483b',
'Subnet': '1.0-12618b7d5dc7a69e2a05e9d6b15e9382',
'SubnetPool': '1.0-320598830183ee739cbc9f32ebc26bba',
'SubnetPoolPrefix': '1.0-13c15144135eb869faa4a76dc3ee3b6c',
}

View File

@ -0,0 +1,89 @@
# 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.
import itertools
from neutron.objects import subnet
from neutron.tests.unit.objects import test_base as obj_test_base
from neutron.tests.unit import testlib_api
class IPAllocationPoolObjectIfaceTestCase(
obj_test_base.BaseObjectIfaceTestCase):
_test_class = subnet.IPAllocationPool
class IPAllocationPoolDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
testlib_api.SqlTestCase):
_test_class = subnet.IPAllocationPool
def setUp(self):
super(IPAllocationPoolDbObjectTestCase, self).setUp()
self._create_test_network()
self._create_test_subnet(self._network)
for obj in itertools.chain(self.db_objs, self.obj_fields):
obj['subnet_id'] = self._subnet['id']
class DNSNameServerObjectIfaceTestCase(obj_test_base.BaseObjectIfaceTestCase):
_test_class = subnet.DNSNameServer
class DNSNameServerDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
testlib_api.SqlTestCase):
_test_class = subnet.DNSNameServer
def setUp(self):
super(DNSNameServerDbObjectTestCase, self).setUp()
self._create_test_network()
self._create_test_subnet(self._network)
for obj in itertools.chain(self.db_objs, self.obj_fields):
obj['subnet_id'] = self._subnet['id']
class RouteObjectIfaceTestCase(obj_test_base.BaseObjectIfaceTestCase):
_test_class = subnet.Route
class RouteDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
testlib_api.SqlTestCase):
_test_class = subnet.Route
def setUp(self):
super(RouteDbObjectTestCase, self).setUp()
self._create_test_network()
self._create_test_subnet(self._network)
for obj in itertools.chain(self.db_objs, self.obj_fields):
obj['subnet_id'] = self._subnet['id']
class SubnetObjectIfaceTestCase(obj_test_base.BaseObjectIfaceTestCase):
_test_class = subnet.Subnet
class SubnetDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
testlib_api.SqlTestCase):
_test_class = subnet.Subnet
def setUp(self):
super(SubnetDbObjectTestCase, self).setUp()
self._create_test_network()
for obj in itertools.chain(self.db_objs, self.obj_fields):
obj['network_id'] = self._network['id']