diff options
| author | Jenkins <jenkins@review.openstack.org> | 2012-08-15 07:56:20 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2012-08-15 07:56:20 +0000 |
| commit | e5a8033888fa3e772598eb856fa7ac9c7189f45f (patch) | |
| tree | 2ec601b9313b9f90dc7074ba958eff8754022b4b | |
| parent | a301ff6dfd2a43ddb712eb69f4fb266dd3bc2b25 (diff) | |
| parent | 8c2daea590df4fb3f6877c21007afedc889e1416 (diff) | |
| download | nova-e5a8033888fa3e772598eb856fa7ac9c7189f45f.tar.gz nova-e5a8033888fa3e772598eb856fa7ac9c7189f45f.tar.xz nova-e5a8033888fa3e772598eb856fa7ac9c7189f45f.zip | |
Merge "Uniqueness checks for floating ip addresses."
| -rwxr-xr-x | bin/nova-manage | 16 | ||||
| -rw-r--r-- | nova/db/api.py | 5 | ||||
| -rw-r--r-- | nova/db/sqlalchemy/api.py | 28 | ||||
| -rw-r--r-- | nova/exception.py | 14 | ||||
| -rw-r--r-- | nova/tests/api/openstack/compute/contrib/test_floating_ips.py | 47 |
5 files changed, 90 insertions, 20 deletions
diff --git a/bin/nova-manage b/bin/nova-manage index 14861b826..7005c7fcf 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -431,11 +431,17 @@ class FloatingIpCommands(object): pool = FLAGS.default_floating_pool if not interface: interface = FLAGS.public_interface - for address in self.address_to_hosts(ip_range): - db.floating_ip_create(admin_context, - {'address': str(address), - 'pool': pool, - 'interface': interface}) + + ips = ({'address': str(address), 'pool': pool, 'interface': interface} + for address in self.address_to_hosts(ip_range)) + try: + db.floating_ip_bulk_create(admin_context, ips) + except exception.FloatingIpExists as exc: + # NOTE(simplylizz): Maybe logging would be better here + # instead of printing, but logging isn't used here and I + # don't know why. + print('error: %s' % exc) + sys.exit(1) @args('--ip_range', dest="ip_range", metavar='<range>', help='IP range') def delete(self, ip_range): diff --git a/nova/db/api.py b/nova/db/api.py index 1df1e970c..ceb361722 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -282,6 +282,11 @@ def floating_ip_allocate_address(context, project_id, pool): return IMPL.floating_ip_allocate_address(context, project_id, pool) +def floating_ip_bulk_create(context, ips): + """Create a lot of floating ips from the values dictionary.""" + return IMPL.floating_ip_bulk_create(context, ips) + + def floating_ip_create(context, values): """Create a floating ip from the values dictionary.""" return IMPL.floating_ip_create(context, values) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 1c8248a53..85f5d8f48 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -757,10 +757,34 @@ def floating_ip_allocate_address(context, project_id, pool): @require_context -def floating_ip_create(context, values): +def floating_ip_bulk_create(context, ips): + session = get_session() + with session.begin(): + for ip in ips: + floating_ip_create(context, ip, session) + + +@require_context +def floating_ip_create(context, values, session=None): + if not session: + session = get_session() + floating_ip_ref = models.FloatingIp() floating_ip_ref.update(values) - floating_ip_ref.save() + + # check uniqueness for not deleted addresses + if not floating_ip_ref.deleted: + try: + floating_ip = floating_ip_get_by_address(context, + floating_ip_ref.address, + session) + except exception.FloatingIpNotFoundForAddress: + pass + else: + if floating_ip.id != floating_ip_ref.id: + raise exception.FloatingIpExists(**dict(floating_ip_ref)) + + floating_ip_ref.save(session=session) return floating_ip_ref['address'] diff --git a/nova/exception.py b/nova/exception.py index de8982488..9beadd2df 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -639,6 +639,15 @@ class NoFixedIpsDefined(NotFound): message = _("Zero fixed ips could be found.") +#TODO(bcwaldon): EOL this exception! +class Duplicate(NovaException): + pass + + +class FloatingIpExists(Duplicate): + message = _("Floating ip %(address)s already exists.") + + class FloatingIpNotFound(NotFound): message = _("Floating ip not found for id %(id)s.") @@ -907,11 +916,6 @@ class RotationRequiredForBackup(NovaException): message = _("Rotation param is required for backup image_type") -#TODO(bcwaldon): EOL this exception! -class Duplicate(NovaException): - pass - - class KeyPairExists(Duplicate): message = _("Key pair %(key_name)s already exists.") diff --git a/nova/tests/api/openstack/compute/contrib/test_floating_ips.py b/nova/tests/api/openstack/compute/contrib/test_floating_ips.py index db1364c3b..ce43c0ffa 100644 --- a/nova/tests/api/openstack/compute/contrib/test_floating_ips.py +++ b/nova/tests/api/openstack/compute/contrib/test_floating_ips.py @@ -105,14 +105,23 @@ def get_instance_by_floating_ip_addr(self, context, address): class FloatingIpTest(test.TestCase): floating_ip = "10.10.10.10" + floating_ip_2 = "10.10.10.11" - def _create_floating_ip(self): + def _create_floating_ips(self, floating_ips=None): """Create a floating ip object.""" - host = "fake_host" - return db.floating_ip_create(self.context, - {'address': self.floating_ip, - 'pool': 'nova', - 'host': host}) + if floating_ips is None: + floating_ips = [self.floating_ip] + elif not isinstance(floating_ips, (list, tuple)): + floating_ips = [floating_ips] + + def make_ip_dict(ip): + """Shortcut for creating floating ip dict.""" + return + + dict_ = {'pool': 'nova', 'host': 'fake_host'} + return db.floating_ip_bulk_create( + self.context, [dict(address=ip, **dict_) for ip in floating_ips], + ) def _delete_floating_ip(self): db.floating_ip_destroy(self.context, self.floating_ip) @@ -144,7 +153,7 @@ class FloatingIpTest(test.TestCase): fake_instance_get) self.context = context.get_admin_context() - self._create_floating_ip() + self._create_floating_ips() self.controller = floating_ips.FloatingIPController() self.manager = floating_ips.FloatingIPActionController() @@ -154,7 +163,7 @@ class FloatingIpTest(test.TestCase): super(FloatingIpTest, self).tearDown() def test_translate_floating_ip_view(self): - floating_ip_address = self._create_floating_ip() + floating_ip_address = self.floating_ip floating_ip = db.floating_ip_get_by_address(self.context, floating_ip_address) floating_ip['fixed_ip'] = None @@ -226,6 +235,28 @@ class FloatingIpTest(test.TestCase): self.assertEqual(res_dict['floating_ip']['ip'], '10.10.10.10') self.assertEqual(res_dict['floating_ip']['instance_id'], FAKE_UUID) + def test_recreation_of_floating_ip(self): + self._delete_floating_ip() + self._create_floating_ips() + + def test_floating_ip_in_bulk_creation(self): + self._delete_floating_ip() + + self._create_floating_ips([self.floating_ip, self.floating_ip_2]) + all_ips = db.floating_ip_get_all(self.context) + ip_list = [ip['address'] for ip in all_ips] + self.assertIn(self.floating_ip, ip_list) + self.assertIn(self.floating_ip_2, ip_list) + + def test_fail_floating_ip_in_bulk_creation(self): + self.assertRaises(exception.FloatingIpExists, + self._create_floating_ips, + [self.floating_ip, self.floating_ip_2]) + all_ips = db.floating_ip_get_all(self.context) + ip_list = [ip['address'] for ip in all_ips] + self.assertIn(self.floating_ip, ip_list) + self.assertNotIn(self.floating_ip_2, ip_list) + # test floating ip allocate/release(deallocate) def test_floating_ip_allocate_no_free_ips(self): def fake_call(*args, **kwargs): |
