Revision 92d2d1ce snf-cyclades-app/synnefo/logic/servers.py

b/snf-cyclades-app/synnefo/logic/servers.py
13 13
from synnefo.logic import backend
14 14
from synnefo.logic.backend_allocator import BackendAllocator
15 15
from synnefo.db.models import (NetworkInterface, VirtualMachine, Network,
16
                               VirtualMachineMetadata, IPAddress)
16
                               VirtualMachineMetadata, IPAddress, Subnet)
17
from synnefo.db import query as db_query
17 18

  
18 19
from vncauthproxy.client import request_forwarding as request_vnc_forwarding
19 20

  
......
242 243
    """
243 244
    attachments = []
244 245
    for network_id in settings.DEFAULT_INSTANCE_NETWORKS:
245
        network, address = None, None
246
        network, ipaddress = None, None
246 247
        if network_id == "SNF:ANY_PUBLIC":
247
            network, address = util.allocate_public_address(backend=vm.backend)
248
            ipaddress = util.allocate_public_address(backend=vm.backend,
249
                                                     userid=userid)
250
            network = ipaddress.network
248 251
        else:
249 252
            try:
250 253
                network = Network.objects.get(id=network_id, deleted=False)
......
254 257
                      " network '%s'" % network_id
255 258
                log.error(msg)
256 259
                raise Exception(msg)
257
            if network.subnet is not None and network.dhcp:
258
                address = util.get_network_free_address(network)
259
        attachments.append((network, address))
260
            try:
261
                subnet = network.subnets.get(ipversion=4, dhcp=True)
262
                ipaddress = util.get_network_free_address(subnet, userid)
263
            except Subnet.DoesNotExist:
264
                ipaddress = None
265
        attachments.append((network, ipaddress))
260 266
    for address in floating_ips:
261
        floating_ip = add_floating_ip_to_vm(vm=vm, address=address)
262
        network = floating_ip.network
263
        attachments.append((network, address))
267
        floating_ip = get_floating_ip(userid=vm.userid, address=address)
268
        attachments.append((floating_ip.network, floating_ip))
264 269
    for network_id in private_networks:
265
        network, address = None, None
266 270
        network = util.get_network(network_id, userid, non_deleted=True)
267 271
        if network.public:
268 272
            raise faults.Forbidden("Can not connect to public network")
269
        if network.dhcp:
270
            address = util.get_network_free_address(network)
271
        attachments.append((network, address))
273
        attachments.append((network, ipaddress))
272 274

  
273 275
    nics = []
274
    for index, (network, address) in enumerate(attachments):
276
    for index, (network, ipaddress) in enumerate(attachments):
275 277
        # Create VM's public NIC. Do not wait notification form ganeti
276 278
        # hooks to create this NIC, because if the hooks never run (e.g.
277 279
        # building error) the VM's public IP address will never be
278 280
        # released!
279
        nic = NetworkInterface.objects.create(machine=vm, network=network,
280
                                              index=index, ipv4=address,
281
        nic = NetworkInterface.objects.create(userid=userid, machine=vm,
282
                                              network=network, index=index,
281 283
                                              state="BUILDING")
284
        if ipaddress is not None:
285
            ipaddress.nic = nic
286
            ipaddress.save()
282 287
        nics.append(nic)
283 288
    return nics
284 289

  
......
427 432

  
428 433
@server_command("CONNECT")
429 434
def add_floating_ip(vm, address):
430
    floating_ip = add_floating_ip_to_vm(vm, address)
435
    floating_ip = get_floating_ip(userid=vm.userid, address=address)
431 436
    nic = NetworkInterface.objects.create(machine=vm,
432 437
                                          network=floating_ip.network,
433 438
                                          ipv4=floating_ip.ipv4,
......
438 443
    return backend.connect_to_network(vm, nic)
439 444

  
440 445

  
441
def add_floating_ip_to_vm(vm, address):
442
    """Get a floating IP by it's address and add it to VirtualMachine.
446
def get_floating_ip(userid, address):
447
    """Get a floating IP by it's address.
443 448

  
444
    Helper function for looking up a IPAddress by it's address and associating
445
    it with a VirtualMachine object (without adding the NIC in the Ganeti
446
    backend!). This function also checks if the floating IP is currently used
447
    by any instance and if it is available in the Backend that hosts the VM.
449
    Helper function for looking up a IPAddress by it's address. This function
450
    also checks if the floating IP is currently used by any instance.
448 451

  
449 452
    """
450
    user_id = vm.userid
451 453
    try:
452 454
        # Get lock in VM, to guarantee that floating IP will only by assigned
453 455
        # once
454
        floating_ip = IPAddress.objects.select_for_update()\
455
                                        .get(userid=user_id, ipv4=address,
456
                                             deleted=False)
456
        floating_ip = db_query.get_user_floating_ip(userid=userid,
457
                                                    address=address,
458
                                                    for_update=True)
457 459
    except IPAddress.DoesNotExist:
458
        raise faults.ItemNotFound("Floating IP '%s' does not exist" % address)
460
        raise faults.ItemNotFound("Floating IP with address '%s' does not"
461
                                  " exist" % address)
459 462

  
460
    if floating_ip.in_use():
463
    if floating_ip.nic is not None:
461 464
        raise faults.Conflict("Floating IP '%s' already in use" %
462 465
                              floating_ip.id)
463 466

  
464
    bnet = floating_ip.network.backend_networks.filter(backend=vm.backend_id)
465
    if not bnet.exists():
466
        msg = "Network '%s' is a floating IP pool, but it not connected"\
467
              " to backend '%s'" % (floating_ip.network, vm.backend)
468
        raise faults.ServiceUnavailable(msg)
469

  
470
    floating_ip.machine = vm
471
    floating_ip.save()
472 467
    return floating_ip
473 468

  
474 469

  
475 470
@server_command("DISCONNECT")
476 471
def remove_floating_ip(vm, address):
477
    user_id = vm.userid
478 472
    try:
479
        floating_ip = IPAddress.objects.select_for_update()\
480
                                        .get(userid=user_id, ipv4=address,
481
                                             deleted=False, machine=vm)
473
        floating_ip = db_query.get_server_floating_ip(server=vm,
474
                                                      address=address,
475
                                                      for_update=True)
482 476
    except IPAddress.DoesNotExist:
483
        raise faults.ItemNotFound("Floating IP '%s' does not exist" % address)
484

  
485
    try:
486
        nic = NetworkInterface.objects.get(machine=vm, ipv4=address)
487
    except NetworkInterface.DoesNotExist:
488
        raise faults.ItemNotFound("Floating IP '%s' is not attached to"
489
                                  "VM '%s'" % (floating_ip, vm))
477
        raise faults.BadRequest("Server '%s' has no floating ip with"
478
                                " address '%s'" % (vm, address))
490 479

  
480
    nic = floating_ip.nic
491 481
    log.info("Removing NIC %s from VM %s. Floating IP '%s'", str(nic.index),
492 482
             vm, floating_ip)
493 483

  

Also available in: Unified diff