Revision 72dea98f snf-cyclades-app/synnefo/logic/backend.py

b/snf-cyclades-app/synnefo/logic/backend.py
35 35
from datetime import datetime
36 36

  
37 37
from synnefo.db.models import (Backend, VirtualMachine, Network,
38
                               FloatingIP,
38 39
                               BackendNetwork, BACKEND_STATUSES,
39 40
                               pooled_rapi_client, VirtualMachineDiagnostic,
40 41
                               Flavor)
......
160 161
        # See ticket #799 for all the details.
161 162
        if status == 'success' or (status == 'error' and
162 163
                                   vm.operstate == 'ERROR'):
163
            _process_net_status(vm, etime, nics=[])
164
            # VM has been deleted. Release the instance IPs
165
            release_instance_ips(vm, [])
166
            # And delete the releated NICs (must be performed after release!)
167
            vm.nics.all().delete()
164 168
            vm.deleted = True
165 169
            vm.operstate = state_for_success
166 170
            vm.backendtime = etime
......
220 224
    # guarantee that no deadlock will occur with Backend allocator.
221 225
    Backend.objects.select_for_update().get(id=vm.backend_id)
222 226

  
223
    release_instance_nics(vm)
227
    # NICs have changed. Release the instance IPs
228
    release_instance_ips(vm, ganeti_nics)
229
    # And delete the releated NICs (must be performed after release!)
230
    vm.nics.all().delete()
224 231

  
225 232
    for nic in ganeti_nics:
226 233
        ipv4 = nic.get('ipv4', '')
......
286 293
    return False
287 294

  
288 295

  
289
def release_instance_nics(vm):
290
    for nic in vm.nics.all():
291
        net = nic.network
292
        if nic.ipv4:
293
            net.release_address(nic.ipv4)
294
        nic.delete()
295
        net.save()
296
def release_instance_ips(vm, ganeti_nics):
297
    old_addresses = set(vm.nics.values_list("network", "ipv4"))
298
    new_addresses = set(map(lambda nic: (nic["network"], nic["ipv4"]),
299
                            ganeti_nics))
300
    to_release = old_addresses - new_addresses
301
    for (network_id, ipv4) in to_release:
302
        if ipv4:
303
            net = Network.objects.get(id=network_id)
304
            # Important: Take exclusive lock in pool before checking if there
305
            # is a floating IP with this ipv4 address, otherwise there is a
306
            # race condition, where you may release a floating IP that has been
307
            # created after search floating IPs and before you get exclusively
308
            # the pool
309
            pool = net.get_pool()
310
            try:
311
                floating_ip = net.floating_ips.select_for_update()\
312
                                              .get(ipv4=ipv4, machine=vm,
313
                                                   deleted=False)
314
                floating_ip.machine = None
315
                floating_ip.save()
316
            except FloatingIP.DoesNotExist:
317
                net.release_address(ipv4)
318
                pool.save()
296 319

  
297 320

  
298 321
@transaction.commit_on_success

Also available in: Unified diff