Revision 710b1c43

b/snf-cyclades-app/synnefo/api/tests/servers.py
409 409
    def test_create_network_settings(self, mrapi):
410 410
        mrapi().CreateInstance.return_value = 12
411 411
        # Create public network and backend
412
        subnet1 = mfactory.IPv4SubnetFactory()
412
        subnet1 = mfactory.IPv4SubnetFactory(network__userid="test_user")
413 413
        bnet1 = mfactory.BackendNetworkFactory(network=subnet1.network,
414 414
                                               backend=self.backend,
415 415
                                               operstate="ACTIVE")
416
        subnet2 = mfactory.IPv4SubnetFactory()
416
        subnet2 = mfactory.IPv4SubnetFactory(network__userid="test_user")
417 417
        bnet2 = mfactory.BackendNetworkFactory(network=subnet2.network,
418 418
                                               backend=self.backend,
419 419
                                               operstate="ACTIVE")
420
        subnet3 = mfactory.IPv4SubnetFactory(network__userid="test_user")
421
        bnet3 = mfactory.BackendNetworkFactory(network=subnet3.network,
422
                                               backend=self.backend,
423
                                               operstate="ACTIVE")
424
        subnet4 = mfactory.IPv4SubnetFactory(network__userid="test_user")
425
        bnet4 = mfactory.BackendNetworkFactory(network=subnet4.network,
426
                                               backend=self.backend,
427
                                               operstate="ACTIVE")
428 420
        # User requested private networks
429 421
        request = deepcopy(self.request)
430
        request["server"]["networks"] = [bnet3.network.id, bnet4.network.id]
422
        request["server"]["networks"] = [bnet1.network.id, bnet2.network.id]
431 423
        with override_settings(settings,
432 424
                               DEFAULT_INSTANCE_NETWORKS=[
433
                                   "SNF:ANY_PUBLIC",
434
                                   bnet1.network.id,
435
                                   bnet2.network.id]):
425
                                   "SNF:ANY_PUBLIC"]):
436 426
            with mocked_quotaholder():
437 427
                response = self.mypost('servers', 'test_user',
438 428
                                       json.dumps(request), 'json')
439 429
        self.assertEqual(response.status_code, 202)
440 430
        name, args, kwargs = mrapi().CreateInstance.mock_calls[0]
441
        self.assertEqual(len(kwargs["nics"]), 5)
431
        self.assertEqual(len(kwargs["nics"]), 3)
442 432
        self.assertEqual(kwargs["nics"][0]["network"],
443 433
                         self.network.backend_id)
444 434
        self.assertEqual(kwargs["nics"][1]["network"],
445 435
                         bnet1.network.backend_id)
446 436
        self.assertEqual(kwargs["nics"][2]["network"],
447 437
                         bnet2.network.backend_id)
448
        self.assertEqual(kwargs["nics"][3]["network"],
449
                         bnet3.network.backend_id)
450
        self.assertEqual(kwargs["nics"][4]["network"],
451
                         bnet4.network.backend_id)
452 438

  
439
        subnet3 = mfactory.IPv4SubnetFactory(network__public=True,
440
                                             network__floating_ip_pool=True)
441
        bnet3 = mfactory.BackendNetworkFactory(network=subnet3.network,
442
                                               backend=self.backend,
443
                                               operstate="ACTIVE")
453 444
        request["server"]["floating_ips"] = []
454 445
        with override_settings(settings,
455
                               DEFAULT_INSTANCE_NETWORKS=[bnet2.network.id]):
446
                               DEFAULT_INSTANCE_NETWORKS=[bnet3.network.id]):
456 447
            with mocked_quotaholder():
457 448
                response = self.mypost('servers', 'test_user',
458 449
                                       json.dumps(request), 'json')
......
460 451
        name, args, kwargs = mrapi().CreateInstance.mock_calls[1]
461 452
        self.assertEqual(len(kwargs["nics"]), 3)
462 453
        self.assertEqual(kwargs["nics"][0]["network"],
463
                         bnet2.network.backend_id)
464
        self.assertEqual(kwargs["nics"][1]["network"],
465 454
                         bnet3.network.backend_id)
455
        self.assertEqual(kwargs["nics"][1]["network"],
456
                         bnet1.network.backend_id)
466 457
        self.assertEqual(kwargs["nics"][2]["network"],
467
                         bnet4.network.backend_id)
458
                         bnet2.network.backend_id)
468 459

  
469 460
        # test invalid network in DEFAULT_INSTANCE_NETWORKS
470 461
        with override_settings(settings, DEFAULT_INSTANCE_NETWORKS=[42]):
......
480 471
            response = self.mypost('servers', 'test_user',
481 472
                                   json.dumps(request), 'json')
482 473
        self.assertFault(response, 403, "forbidden")
474

  
483 475
        # test wrong user
484 476
        request = deepcopy(self.request)
485
        request["server"]["networks"] = [bnet3.network.id]
477
        request["server"]["networks"] = [bnet1.network.id]
486 478
        with override_settings(settings,
487 479
                               DEFAULT_INSTANCE_NETWORKS=["SNF:ANY_PUBLIC"]):
488 480
            with mocked_quotaholder():
......
492 484

  
493 485
        # Test floating IPs
494 486
        request = deepcopy(self.request)
495
        request["server"]["networks"] = [bnet4.network.id]
487
        request["server"]["networks"] = [bnet1.network.id]
496 488
        fp1 = mfactory.FloatingIPFactory(address="10.0.0.2",
497 489
                                         userid="test_user",
490
                                         network=self.network,
498 491
                                         nic=None)
499 492
        fp2 = mfactory.FloatingIPFactory(address="10.0.0.3",
500 493
                                         userid="test_user",
494
                                         network=self.network,
501 495
                                         nic=None)
502 496
        request["server"]["floating_ips"] = [fp1.address, fp2.address]
503 497
        with override_settings(settings,
......
521 515
        self.assertEqual(kwargs["nics"][2]["network"], fp2.network.backend_id)
522 516
        self.assertEqual(kwargs["nics"][2]["ip"], fp2.address)
523 517
        self.assertEqual(kwargs["nics"][3]["network"],
524
                         bnet4.network.backend_id)
518
                         bnet1.network.backend_id)
525 519

  
526 520
    def test_create_server_no_flavor(self, mrapi):
527 521
        request = deepcopy(self.request)
b/snf-cyclades-app/synnefo/api/util.py
47 47

  
48 48
from snf_django.lib.api import faults
49 49
from synnefo.db.models import (Flavor, VirtualMachine, VirtualMachineMetadata,
50
                               Network, BackendNetwork, NetworkInterface,
51
                               BridgePoolTable, MacPrefixPoolTable, Backend,
52
                               IPAddress)
53
from synnefo.db.pools import EmptyPool
50
                               Network, NetworkInterface, BridgePoolTable,
51
                               MacPrefixPoolTable, IPAddress, IPPoolTable)
52
from synnefo.db import pools
54 53

  
55 54
from synnefo.plankton.utils import image_backend
56 55

  
......
223 222
            raise faults.BadRequest("Network has been deleted.")
224 223
        return network
225 224
    except (ValueError, Network.DoesNotExist):
226
        raise faults.ItemNotFound('Network not found.')
225
        raise faults.ItemNotFound('Network %s not found.' % network_id)
227 226

  
228 227

  
229 228
def get_port(port_id, user_id, for_update=False):
......
245 244
        raise faults.ItemNotFound('Port not found.')
246 245

  
247 246

  
248
def get_floating_ip(user_id, ipv4, for_update=False):
247
def get_floating_ip_by_address(userid, address, for_update=False):
249 248
    try:
250 249
        objects = IPAddress.objects
251 250
        if for_update:
252 251
            objects = objects.select_for_update()
253
        return objects.get(userid=user_id, ipv4=ipv4, deleted=False)
252
        return objects.get(userid=userid, floating_ip=True,
253
                           address=address, deleted=False)
254 254
    except IPAddress.DoesNotExist:
255 255
        raise faults.ItemNotFound("Floating IP does not exist.")
256 256

  
257 257

  
258
def allocate_public_address(backend, userid):
259
    """Get a public IP for any available network of a backend."""
260
    # Guarantee exclusive access to backend, because accessing the IP pools of
261
    # the backend networks may result in a deadlock with backend allocator
262
    # which also checks that backend networks have a free IP.
263
    backend = Backend.objects.select_for_update().get(id=backend.id)
264
    public_networks = backend_public_networks(backend)
265
    return get_free_ip(public_networks, userid)
258
def get_floating_ip_by_id(userid, floating_ip_id, for_update=False):
259
    try:
260
        objects = IPAddress.objects
261
        if for_update:
262
            objects = objects.select_for_update()
263
        return objects.get(id=floating_ip_id, floating_ip=True, userid=userid,
264
                           deleted=False)
265
    except IPAddress.DoesNotExist:
266
        raise faults.ItemNotFound("Floating IP %s does not exist." %
267
                                  floating_ip_id)
266 268

  
267 269

  
268
def backend_public_networks(backend):
269
    """Return available public networks of the backend.
270
def allocate_ip_from_pools(pool_rows, userid, address=None, floating_ip=False):
271
    """Try to allocate a value from a number of pools.
270 272

  
271
    Iterator for non-deleted public networks that are available
272
    to the specified backend.
273
    This function takes as argument a number of PoolTable objects and tries to
274
    allocate a value from them. If all pools are empty EmptyPool is raised.
273 275

  
274 276
    """
275
    bnets = BackendNetwork.objects.filter(backend=backend,
276
                                          network__public=True,
277
                                          network__deleted=False,
278
                                          network__floating_ip_pool=False,
279
                                          network__drained=False)
280
    return [b.network for b in bnets]
281

  
282

  
283
def get_free_ip(networks, userid):
284
    for network in networks:
277
    for pool_row in pool_rows:
278
        pool = pool_row.pool
285 279
        try:
286
            return network.allocate_address(userid=userid)
287
        except faults.OverLimit:
280
            value = pool.get(value=address)
281
            pool.save()
282
            subnet = pool_row.subnet
283
            ipaddress = IPAddress.objects.create(subnet=subnet,
284
                                                 network=subnet.network,
285
                                                 userid=userid,
286
                                                 address=value,
287
                                                 floating_ip=floating_ip)
288
            return ipaddress
289
        except pools.EmptyPool:
288 290
            pass
289
    msg = "Can not allocate public IP. Public networks are full."
290
    log.error(msg)
291
    raise faults.OverLimit(msg)
291
    raise pools.EmptyPool("No more IP addresses available on pools %s" %
292
                          pool_rows)
293

  
294

  
295
def allocate_ip(network, userid, address=None, floating_ip=False):
296
    """Try to allocate an IP from networks IP pools."""
297
    ip_pools = IPPoolTable.objects.select_for_update()\
298
        .filter(subnet__network=network)
299
    try:
300
        return allocate_ip_from_pools(ip_pools, userid, address=address,
301
                                      floating_ip=floating_ip)
302
    except pools.EmptyPool:
303
        raise faults.Conflict("No more IP addresses available on network %s"
304
                              % network.id)
305
    except pools.ValueNotAvailable:
306
        raise faults.Conflict("IP address %s is already used." % address)
307

  
308

  
309
def allocate_public_ip(userid, floating_ip=False, backend=None):
310
    """Try to allocate a public or floating IP address.
292 311

  
312
    Try to allocate a a public IPv4 address from one of the available networks.
313
    If 'floating_ip' is set, only networks which are floating IP pools will be
314
    used and the IPAddress that will be created will be marked as a floating
315
    IP. If 'backend' is set, only the networks that exist in this backend will
316
    be used.
317

  
318
    """
293 319

  
294
def get_network_free_address(network, userid):
295
    """Reserve an IP address from the IP Pool of the network."""
320
    ip_pool_rows = IPPoolTable.objects.select_for_update()\
321
        .prefetch_related("subnet__network")\
322
        .filter(subnet__deleted=False)\
323
        .filter(subnet__network__public=True)\
324
        .filter(subnet__network__drained=False)
325
    if floating_ip:
326
        ip_pool_rows = ip_pool_rows\
327
            .filter(subnet__network__floating_ip_pool=True)
328
    if backend is not None:
329
        ip_pool_rows = ip_pool_rows\
330
            .filter(subnet__network__backend_networks__backend=backend)
296 331

  
297 332
    try:
298
        return network.allocate_address(userid=userid)
299
    except EmptyPool:
300
        raise faults.OverLimit("Network %s is full." % network.backend_id)
333
        return allocate_ip_from_pools(ip_pool_rows, userid,
334
                                      floating_ip=floating_ip)
335
    except pools.EmptyPool:
336
        ip_type = "floating" if floating_ip else "public"
337
        log_msg = "Failed to allocate a %s IP. Reason:" % ip_type
338
        if ip_pool_rows:
339
            log_msg += " No network exists."
340
        else:
341
            log_msg += " All network are full."
342
        if backend is not None:
343
            log_msg += " Backend: %s" % backend
344
        log.error(log_msg)
345
        exception_msg = "Can not allocate a %s IP address." % ip_type
346
        raise faults.ServiceUnavailable(exception_msg)
347

  
348

  
349
def backend_has_free_public_ip(backend):
350
    """Check if a backend has a free public IPv4 address."""
351
    ip_pool_rows = IPPoolTable.objects.select_for_update()\
352
        .filter(subnet__network__public=True)\
353
        .filter(subnet__network__drained=False)\
354
        .filter(subnet__deleted=False)\
355
        .filter(subnet__network__backend_networks__backend=backend)
356
    for pool_row in ip_pool_rows:
357
        pool = pool_row.pool
358
        if pool.empty():
359
            continue
360
        else:
361
            return True
362

  
363

  
364
def backend_public_networks(backend):
365
    return Network.objects.filter(deleted=False, public=True,
366
                                  backend_networks__backend=backend)
301 367

  
302 368

  
303 369
def get_vm_nic(vm, nic_id):
b/snf-cyclades-app/synnefo/logic/backend_allocator.py
31 31
import datetime
32 32
from django.utils import importlib
33 33

  
34
from synnefo.settings import (BACKEND_ALLOCATOR_MODULE, BACKEND_REFRESH_MIN,
35
                              BACKEND_PER_USER,
36
                              DEFAULT_INSTANCE_NETWORKS)
34
from django.conf import settings
37 35
from synnefo.db.models import Backend
38
from synnefo.logic.backend import update_backend_resources
39
from synnefo.api.util import backend_public_networks
36
from synnefo.logic import backend as backend_mod
37
from synnefo.api import util
40 38

  
41 39
log = logging.getLogger(__name__)
42 40

  
......
47 45
    """
48 46
    def __init__(self):
49 47
        self.strategy_mod =\
50
            importlib.import_module(BACKEND_ALLOCATOR_MODULE)
48
            importlib.import_module(settings.BACKEND_ALLOCATOR_MODULE)
51 49

  
52 50
    def allocate(self, userid, flavor):
53 51
        """Allocate a vm of the specified flavor to a backend.
......
114 112
    backends = backends.filter(offline=False, drained=False,
115 113
                               disk_templates__contains=disk_template)
116 114
    backends = list(backends)
117
    if "SNF:ANY_PUBLIC" in DEFAULT_INSTANCE_NETWORKS:
118
        backends = filter(lambda x: has_free_ip(x), backends)
115
    if "SNF:ANY_PUBLIC" in settings.DEFAULT_INSTANCE_NETWORKS:
116
        backends = filter(lambda x: util.backend_has_free_public_ip(x),
117
                          backends)
119 118
    return backends
120 119

  
121 120

  
122
def has_free_ip(backend):
123
    """Find if Backend has any free public IP."""
124
    for network in backend_public_networks(backend):
125
        if not network.get_pool().empty():
126
            return True
127
    log.warning("No available network in backend %r", backend)
128
    return False
129

  
130

  
131 121
def flavor_disk(flavor):
132 122
    """ Get flavor's 'real' disk size
133 123

  
......
164 154
    """
165 155

  
166 156
    now = datetime.datetime.now()
167
    delta = datetime.timedelta(minutes=BACKEND_REFRESH_MIN)
157
    delta = datetime.timedelta(minutes=settings.BACKEND_REFRESH_MIN)
168 158
    for b in backends:
169 159
        if now > b.updated + delta:
170 160
            log.debug("Updating resources of backend %r. Last Updated %r",
171 161
                      b, b.updated)
172
            update_backend_resources(b)
162
            backend_mod.update_backend_resources(b)
173 163

  
174 164

  
175 165
def get_backend_for_user(userid):
176 166
    """Find fixed Backend for user based on BACKEND_PER_USER setting."""
177 167

  
178
    backend = BACKEND_PER_USER.get(userid)
168
    backend = settings.BACKEND_PER_USER.get(userid)
179 169

  
180 170
    if not backend:
181 171
        return None
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:
b/snf-cyclades-app/synnefo/logic/tests/servers.py
61 61
        self.assertEqual(models.VirtualMachine.objects.count(), 0)
62 62

  
63 63
        subnet = mfactory.IPv4SubnetFactory(network__public=True)
64
        mfactory.BackendNetworkFactory(network=subnet.network)
64
        bn = mfactory.BackendNetworkFactory(network=subnet.network)
65
        backend = bn.backend
65 66

  
66 67
        # error in nics
67 68
        req = deepcopy(kwargs)
......
94 95
        self.assertEqual(vm.task, "BUILD")
95 96

  
96 97
        # test connect in IPv6 only network
97
        subnet = mfactory.IPv6SubnetFactory()
98
        subnet = mfactory.IPv6SubnetFactory(network__public=True)
98 99
        net = subnet.network
99
        mfactory.BackendNetworkFactory(network=net)
100
        mfactory.BackendNetworkFactory(network=net, backend=backend,
101
                                       operstate="ACTIVE")
100 102
        with override_settings(settings,
101 103
                               DEFAULT_INSTANCE_NETWORKS=[str(net.id)]):
102 104
            with mocked_quotaholder():
......
114 116
class ServerTest(TransactionTestCase):
115 117
    def test_connect_network(self, mrapi):
116 118
        # Common connect
117
        subnet = mfactory.IPv4SubnetFactory(network__flavor="CUSTOM",
118
                                            cidr="192.168.2.0/24",
119
                                            gateway="192.168.2.1",
120
                                            dhcp=True)
121
        net = subnet.network
122
        vm = mfactory.VirtualMachineFactory(operstate="STARTED")
123
        mfactory.BackendNetworkFactory(network=net, backend=vm.backend)
124
        mrapi().ModifyInstance.return_value = 42
125
        servers.connect(vm, net)
126
        pool = net.get_pool(locked=False)
127
        self.assertFalse(pool.is_available("192.168.2.2"))
128
        args, kwargs = mrapi().ModifyInstance.call_args
129
        nics = kwargs["nics"][0]
130
        self.assertEqual(kwargs["instance"], vm.backend_vm_id)
131
        self.assertEqual(nics[0], "add")
132
        self.assertEqual(nics[1], "-1")
133
        self.assertEqual(nics[2]["ip"], "192.168.2.2")
134
        self.assertEqual(nics[2]["network"], net.backend_id)
135

  
136
        # no dhcp
137
        vm = mfactory.VirtualMachineFactory(operstate="STARTED")
138
        subnet = mfactory.IPv4SubnetFactory(cidr="192.168.2.0/24",
139
                                            gateway="192.168.2.1",
140
                                            dhcp=False)
141
        net = subnet.network
142
        mfactory.BackendNetworkFactory(network=net, backend=vm.backend)
143
        servers.connect(vm, net)
144
        pool = net.get_pool(locked=False)
145
        self.assertTrue(pool.is_available("192.168.2.2"))
146
        args, kwargs = mrapi().ModifyInstance.call_args
147
        nics = kwargs["nics"][0]
148
        self.assertEqual(kwargs["instance"], vm.backend_vm_id)
149
        self.assertEqual(nics[0], "add")
150
        self.assertEqual(nics[1], "-1")
151
        self.assertEqual(nics[2]["ip"], None)
152
        self.assertEqual(nics[2]["network"], net.backend_id)
119
        for dhcp in [True, False]:
120
            subnet = mfactory.IPv4SubnetFactory(network__flavor="CUSTOM",
121
                                                cidr="192.168.2.0/24",
122
                                                gateway="192.168.2.1",
123
                                                dhcp=True)
124
            net = subnet.network
125
            vm = mfactory.VirtualMachineFactory(operstate="STARTED")
126
            mfactory.BackendNetworkFactory(network=net, backend=vm.backend)
127
            mrapi().ModifyInstance.return_value = 42
128
            servers.connect(vm, net)
129
            pool = net.get_pool(locked=False)
130
            self.assertFalse(pool.is_available("192.168.2.2"))
131
            args, kwargs = mrapi().ModifyInstance.call_args
132
            nics = kwargs["nics"][0]
133
            self.assertEqual(kwargs["instance"], vm.backend_vm_id)
134
            self.assertEqual(nics[0], "add")
135
            self.assertEqual(nics[1], "-1")
136
            self.assertEqual(nics[2]["ip"], "192.168.2.2")
137
            self.assertEqual(nics[2]["network"], net.backend_id)
153 138

  
154 139
        # Test connect to IPv6 only network
155 140
        vm = mfactory.VirtualMachineFactory(operstate="STARTED")

Also available in: Unified diff