Commit f8f20840 authored by Christos Stavrakakis's avatar Christos Stavrakakis
Browse files

cyclades: Do not delete networks with floating IPs

Forbid network deletion in case the network has allocated floating IPs,
no matter whether they are used by instances or not. Update
'allocate_floating_ip' API method, to take exclusive lock on network
before reserving a floating IP, to avoid race condition between deleting
a network and reserving an IP address.
parent 8e23ed50
......@@ -133,7 +133,8 @@ def allocate_floating_ip(request):
" 'pool' attribute")
try:
network = Network.objects.get(public=True, deleted=False, id=pool)
objects = Network.objects.select_for_update()
network = objects.get(id=pool, public=True, deleted=False)
except Network.DoesNotExist:
raise faults.ItemNotFound("Pool '%s' does not exist." % pool)
......
......@@ -51,7 +51,10 @@ class Command(BaseCommand):
self.stdout.write('Trying to remove network: %s\n' % str(network))
if network.machines.exists():
raise CommandError('Network is not empty. Can not delete')
raise CommandError('Can not delete: Network has connected VMs.')
if network.floating_ips.filter(deleted=False).exists():
raise CommandError("Can not delete: Network has reserved floating"
" IP addresses.")
network.action = 'DESTROY'
network.save()
......
......@@ -306,6 +306,9 @@ def delete_network(request, network_id):
if net.machines.all(): # Nics attached on network
raise faults.NetworkInUse('Machines are connected to network.')
if net.floating_ips.filter(deleted=False).exists():
raise faults.NetworkInUse("Network has allocated floating IP addresses")
net.action = 'DESTROY'
net.save()
......
......@@ -38,7 +38,7 @@ from synnefo.db.models import FloatingIP
from synnefo.db.models_factory import (FloatingIPFactory, NetworkFactory,
VirtualMachineFactory,
NetworkInterfaceFactory)
from mock import patch
from mock import patch, Mock
URL = "/api/v1.1/os-floating-ips"
......@@ -184,6 +184,23 @@ class FloatingIPAPITest(BaseAPITest):
ips_after = FloatingIP.objects.filter(id=ip.id)
self.assertEqual(len(ips_after), 0)
@patch("synnefo.logic.backend", Mock())
def test_delete_network_with_floating_ips(self):
ip = FloatingIPFactory(machine=None)
net = ip.network
# Can not remove network with floating IPs
with mocked_quotaholder():
response = self.delete("/api/v1.1/networks/%s" % net.id,
net.userid)
self.assertFault(response, 421, "networkInUse")
# But we can with only deleted Floating Ips
ip.deleted = True
ip.save()
with mocked_quotaholder():
response = self.delete("/api/v1.1/networks/%s" % net.id,
net.userid)
self.assertSuccess(response)
POOLS_URL = "/api/v1.1/os-floating-ip-pools"
......
......@@ -112,7 +112,7 @@ def get_vm(server_id):
" available server IDs." % server_id)
def get_network(network_id):
def get_network(network_id, for_update=True):
"""Get a Network object by its ID.
@type network_id: int or string
......@@ -128,8 +128,11 @@ def get_network(network_id):
except Network.InvalidBackendIdError:
raise CommandError("Invalid network ID: %s" % network_id)
networks = Network.objects
if for_update:
networks = networks.select_for_update()
try:
return Network.objects.get(id=network_id)
return networks.get(id=network_id)
except Network.DoesNotExist:
raise CommandError("Network with ID %s not found in DB."
" Use snf-manage network-list to find out"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment