Revision 710b1c43 snf-cyclades-app/synnefo/logic/servers.py

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

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

  
......
241 241
    networks defined by the user.
242 242

  
243 243
    """
244
    attachments = []
244
    nics = []
245 245
    for network_id in settings.DEFAULT_INSTANCE_NETWORKS:
246
        network, ipaddress = None, None
247 246
        if network_id == "SNF:ANY_PUBLIC":
248
            ipaddress = util.allocate_public_address(backend=vm.backend,
249
                                                     userid=userid)
250
            network = ipaddress.network
247
            ipaddress = util.allocate_public_ip(userid=userid,
248
                                                backend=vm.backend)
249
            nic, ipaddress = create_nic(vm, ipaddress=ipaddress)
251 250
        else:
252 251
            try:
253
                network = Network.objects.get(id=network_id, deleted=False)
254
            except Network.DoesNotExist:
252
                network = util.get_network(network_id, userid,
253
                                           non_deleted=True)
254
            except faults.ItemNotFound:
255 255
                msg = "Invalid configuration. Setting"\
256 256
                      " 'DEFAULT_INSTANCE_NETWORKS' contains invalid"\
257 257
                      " network '%s'" % network_id
258 258
                log.error(msg)
259
                raise Exception(msg)
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))
259
                raise faults.InternalServerError(msg)
260
            nic, ipaddress = create_nic(vm, network=network)
261
        nics.append(nic)
266 262
    for address in floating_ips:
267
        floating_ip = get_floating_ip(userid=vm.userid, address=address)
268
        attachments.append((floating_ip.network, floating_ip))
263
        floating_ip = util.get_floating_ip_by_address(vm.userid, address,
264
                                                      for_update=True)
265
        nic, ipaddress = create_nic(vm, ipaddress=floating_ip)
266
        nics.append(nic)
269 267
    for network_id in private_networks:
270 268
        network = util.get_network(network_id, userid, non_deleted=True)
271 269
        if network.public:
272 270
            raise faults.Forbidden("Can not connect to public network")
273
        attachments.append((network, ipaddress))
274

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

  
290 278

  
279
def create_nic(vm, network=None, ipaddress=None, address=None):
280
    """Helper functions for create NIC objects.
281

  
282
    Create a NetworkInterface connecting a VirtualMachine to a network with the
283
    IPAddress specified. If no 'ipaddress' is passed and the network has an
284
    IPv4 subnet, then an IPv4 address will be automatically be allocated.
285

  
286
    """
287
    userid = vm.userid
288

  
289
    if ipaddress is None:
290
        if network.subnets.filter(ipversion=4).exists():
291
            try:
292
                ipaddress = util.allocate_ip(network, userid=userid,
293
                                             address=address)
294
            except pools.ValueNotAvailable:
295
                raise faults.badRequest("Address '%s' is not available." %
296
                                        address)
297

  
298
    if ipaddress is not None and ipaddress.nic is not None:
299
        raise faults.Conflict("IP address '%s' already in use" %
300
                              ipaddress.address)
301

  
302
    if network is None:
303
        network = ipaddress.network
304
    elif network.state != 'ACTIVE':
305
        # TODO: What if is in settings ?
306
        raise faults.BuildInProgress('Network not active yet')
307

  
308
    nic = NetworkInterface.objects.create(machine=vm, network=network,
309
                                          state="BUILDING")
310
    if ipaddress is not None:
311
        ipaddress.nic = nic
312
        ipaddress.save()
313

  
314
    return nic, ipaddress
315

  
316

  
291 317
@server_command("DESTROY")
292 318
def destroy(vm):
293 319
    log.info("Deleting VM %s", vm)
......
353 379

  
354 380
@server_command("CONNECT")
355 381
def connect(vm, network):
356
    if network.state != 'ACTIVE':
357
        raise faults.BuildInProgress('Network not active yet')
382
    nic, ipaddress = create_nic(vm, network)
358 383

  
359
    address = None
360
    try:
361
        subnet = network.subnets.get(ipversion=4, dhcp=True)
362
        address = util.get_network_free_address(subnet, userid=vm.userid)
363
    except Subnet.DoesNotExist:
364
        subnet = None
365

  
366
    nic = NetworkInterface.objects.create(machine=vm, network=network,
367
                                          state="BUILDING")
368
    if address is not None:
369
        address.nic = nic
370
        address.save()
371
    log.info("Connecting VM %s to Network %s. NIC: %s", vm, network, nic)
384
    log.info("Creating NIC %s with IPAddress %s", nic, ipaddress)
372 385

  
373 386
    return backend.connect_to_network(vm, nic)
374 387

  
......
437 450

  
438 451
@server_command("CONNECT")
439 452
def add_floating_ip(vm, address):
440
    floating_ip = get_floating_ip(userid=vm.userid, address=address)
441
    nic = NetworkInterface.objects.create(machine=vm,
442
                                          network=floating_ip.network,
443
                                          ipv4=floating_ip.ipv4,
444
                                          ip_type="FLOATING",
445
                                          state="BUILDING")
446
    log.info("Connecting VM %s to floating IP %s. NIC: %s", vm, floating_ip,
447
             nic)
453
    # Use for_update, to guarantee that floating IP will only by assigned once
454
    # and that it can not be released will it is being attached!
455
    floating_ip = util.get_floating_ip_by_address(vm.userid, address,
456
                                                  for_update=True)
457
    nic, floating_ip = create_nic(vm, ipaddress=floating_ip)
458
    log.info("Created NIC %s with floating IP %s", nic, floating_ip)
448 459
    return backend.connect_to_network(vm, nic)
449 460

  
450 461

  
451
def get_floating_ip(userid, address):
452
    """Get a floating IP by it's address.
453

  
454
    Helper function for looking up a IPAddress by it's address. This function
455
    also checks if the floating IP is currently used by any instance.
456

  
457
    """
458
    try:
459
        # Get lock in VM, to guarantee that floating IP will only by assigned
460
        # once
461
        floating_ip = db_query.get_user_floating_ip(userid=userid,
462
                                                    address=address,
463
                                                    for_update=True)
464
    except IPAddress.DoesNotExist:
465
        raise faults.ItemNotFound("Floating IP with address '%s' does not"
466
                                  " exist" % address)
467

  
468
    if floating_ip.nic is not None:
469
        raise faults.Conflict("Floating IP '%s' already in use" %
470
                              floating_ip.id)
471

  
472
    return floating_ip
473

  
474

  
475 462
@server_command("DISCONNECT")
476 463
def remove_floating_ip(vm, address):
477 464
    try:

Also available in: Unified diff