diff --git a/nova/objects/fixed_ip.py b/nova/objects/fixed_ip.py index 86544c564015..b80e379de6e6 100644 --- a/nova/objects/fixed_ip.py +++ b/nova/objects/fixed_ip.py @@ -18,6 +18,7 @@ from nova.objects import base as obj_base from nova.objects import fields from nova.objects import instance as instance_obj from nova.objects import network as network_obj +from nova.objects import virtual_interface as vif_obj from nova.openstack.common import timeutils @@ -26,7 +27,8 @@ FIXED_IP_OPTIONAL_ATTRS = ['instance', 'network'] class FixedIP(obj_base.NovaPersistentObject, obj_base.NovaObject): # Version 1.0: Initial version - VERSION = '1.0' + # Version 1.1: Added virtual_interface field + VERSION = '1.1' fields = { 'id': fields.IntegerField(), @@ -40,6 +42,8 @@ class FixedIP(obj_base.NovaPersistentObject, obj_base.NovaObject): 'host': fields.StringField(nullable=True), 'instance': fields.ObjectField('Instance', nullable=True), 'network': fields.ObjectField('Network', nullable=True), + 'virtual_interface': fields.ObjectField('VirtualInterface', + nullable=True), } @property @@ -54,6 +58,11 @@ class FixedIP(obj_base.NovaPersistentObject, obj_base.NovaObject): if expected_attrs is None: expected_attrs = [] for field in fixedip.fields: + if field == 'virtual_interface': + # NOTE(danms): This field is only set when doing a + # FixedIPList.get_by_network() because it's a relatively + # special-case thing, so skip it here + continue if field not in FIXED_IP_OPTIONAL_ATTRS: fixedip[field] = db_fixedip[field] # NOTE(danms): Instance could be deleted, and thus None @@ -155,13 +164,15 @@ class FixedIP(obj_base.NovaPersistentObject, obj_base.NovaObject): class FixedIPList(obj_base.ObjectListBase, obj_base.NovaObject): # Version 1.0: Initial version - VERSION = '1.0' + # Version 1.1: Added get_by_network() + VERSION = '1.1' fields = { 'objects': fields.ListOfObjectsField('FixedIP'), } child_versions = { '1.0': '1.0', + '1.1': '1.1', } @obj_base.remotable_classmethod @@ -184,6 +195,38 @@ class FixedIPList(obj_base.ObjectListBase, obj_base.NovaObject): db_fixedips = db.fixed_ips_by_virtual_interface(context, vif_id) return obj_base.obj_make_list(context, cls(), FixedIP, db_fixedips) + @obj_base.remotable_classmethod + def get_by_network(cls, context, network, host=None): + ipinfo = db.network_get_associated_fixed_ips(context, + network['id'], + host=host) + if not ipinfo: + return [] + + fips = cls(context=context, objects=[]) + + for info in ipinfo: + inst = instance_obj.Instance(context=context, + uuid=info['instance_uuid'], + hostname=info['instance_hostname'], + created_at=info['instance_created'], + updated_at=info['instance_updated']) + vif = vif_obj.VirtualInterface(context=context, + id=info['vif_id'], + address=info['vif_address']) + fip = FixedIP(context=context, + address=info['address'], + instance_uuid=info['instance_uuid'], + network_id=info['network_id'], + virtual_interface_id=info['vif_id'], + allocated=info['allocated'], + leased=info['leased'], + instance=inst, + virtual_interface=vif) + fips.objects.append(fip) + fips.obj_reset_changes() + return fips + @obj_base.remotable_classmethod def bulk_create(self, context, fixed_ips): ips = [] diff --git a/nova/tests/objects/test_fixed_ip.py b/nova/tests/objects/test_fixed_ip.py index 235a16878abc..04dd4d2f49fb 100644 --- a/nova/tests/objects/test_fixed_ip.py +++ b/nova/tests/objects/test_fixed_ip.py @@ -12,6 +12,8 @@ # License for the specific language governing permissions and limitations # under the License. +import datetime + import iso8601 import mock import netaddr @@ -44,6 +46,8 @@ fake_fixed_ip = { class _TestFixedIPObject(object): def _compare(self, obj, db_obj): for field in obj.fields: + if field is 'virtual_interface': + continue if field in fixed_ip.FIXED_IP_OPTIONAL_ATTRS: if obj.obj_attr_is_set(field) and db_obj[field] is not None: obj_val = obj[field].uuid @@ -254,6 +258,38 @@ class _TestFixedIPObject(object): [{'address': '192.168.1.1'}, {'address': '192.168.1.2'}]) + @mock.patch('nova.db.network_get_associated_fixed_ips') + def test_get_by_network(self, get): + info = {'address': '1.2.3.4', + 'instance_uuid': 'fake-uuid', + 'network_id': 0, + 'vif_id': 1, + 'vif_address': 'de:ad:be:ee:f0:00', + 'instance_hostname': 'fake-host', + 'instance_updated': datetime.datetime(1955, 11, 5), + 'instance_created': datetime.datetime(1955, 11, 5), + 'allocated': True, + 'leased': True, + } + get.return_value = [info] + fixed_ips = fixed_ip.FixedIPList.get_by_network( + self.context, {'id': 0}, host='fake-host') + get.assert_called_once_with(self.context, 0, host='fake-host') + self.assertEqual(1, len(fixed_ips)) + fip = fixed_ips[0] + self.assertEqual('1.2.3.4', str(fip.address)) + self.assertEqual('fake-uuid', fip.instance_uuid) + self.assertEqual(0, fip.network_id) + self.assertEqual(1, fip.virtual_interface_id) + self.assertTrue(fip.allocated) + self.assertTrue(fip.leased) + self.assertEqual('fake-uuid', fip.instance.uuid) + self.assertEqual('fake-host', fip.instance.hostname) + self.assertIsInstance(fip.instance.created_at, datetime.datetime) + self.assertIsInstance(fip.instance.updated_at, datetime.datetime) + self.assertEqual(1, fip.virtual_interface.id) + self.assertEqual(info['vif_address'], fip.virtual_interface.address) + class TestFixedIPObject(test_objects._LocalTest, _TestFixedIPObject):