Revision 7c714455

b/snf-cyclades-app/synnefo/api/servers.py
154 154
        metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
155 155
        d['metadata'] = metadata
156 156

  
157
        vm_nics = vm.nics.filter(state="ACTIVE").order_by("index")
157
        vm_nics = vm.nics.filter(state="ACTIVE").order_by("id")
158 158
        attachments = map(nic_to_dict, vm_nics)
159 159
        d['attachments'] = attachments
160 160
        d['addresses'] = attachments_to_addresses(attachments)
......
515 515
    log.debug('list_addresses_by_network %s %s', server_id, network_id)
516 516
    machine = util.get_vm(server_id, request.user_uniq)
517 517
    network = util.get_network(network_id, request.user_uniq)
518
    nics = machine.nics.filter(network=network, state="ACTIVE").all()
518
    nics = machine.nics.filter(network=network, state="ACTIVE")
519 519
    addresses = attachments_to_addresses(map(nic_to_dict, nics))
520 520

  
521 521
    if request.serialization == 'xml':
......
871 871
    if attachment is None:
872 872
        raise faults.BadRequest("Missing 'attachment' attribute.")
873 873
    try:
874
        # attachment string: nic-<vm-id>-<nic-index>
875
        _, server_id, nic_index = attachment.split("-", 2)
874
        # attachment string: nic-<vm-id>-<nic-id>
875
        _, server_id, nic_id = attachment.split("-", 2)
876 876
        server_id = int(server_id)
877
        nic_index = int(nic_index)
877
        nic_id = int(nic_id)
878 878
    except (ValueError, TypeError):
879 879
        raise faults.BadRequest("Invalid 'attachment' attribute.")
880 880

  
881 881
    vm = util.get_vm(server_id, request.user_uniq, non_suspended=True)
882
    servers.disconnect(vm, nic_index=nic_index)
882
    nic = util.get_nic(vm, nic_id)
883
    servers.disconnect(vm, nic)
883 884

  
884 885
    return HttpResponse(status=202)
885 886

  
b/snf-cyclades-app/synnefo/api/tests/networks.py
93 93
            self.assertEqual(db_net.gateway6, api_net['gateway6'])
94 94
            self.assertEqual(db_net.dhcp, api_net['dhcp'])
95 95
            self.assertEqual(db_net.public, api_net['public'])
96
            db_nics = ["nic-%d-%d" % (nic.machine.id, nic.index) for nic in
96
            db_nics = ["nic-%d-%d" % (nic.machine.id, nic.id) for nic in
97 97
                       db_net.nics.filter(machine__userid=db_net.userid)]
98 98
            self.assertEqual(db_nics, api_net['attachments'])
99 99

  
......
407 407
        net = mfactory.NetworkFactory(state='ACTIVE', userid=user)
408 408
        nic = mfactory.NetworkInterfaceFactory(machine=vm, network=net)
409 409
        mrapi().ModifyInstance.return_value = 1
410
        request = {'remove': {'attachment': 'nic-%s-%s' % (vm.id, nic.index)}}
410
        request = {'remove': {'attachment': 'nic-%s-%s' % (vm.id, nic.id)}}
411 411
        response = self.mypost('networks/%d/action' % net.id,
412 412
                               net.userid, json.dumps(request), 'json')
413 413
        self.assertEqual(response.status_code, 202)
414
        self.assertTrue(NetworkInterface.objects.get(id=nic.id).dirty)
415 414
        vm.task = None
416 415
        vm.task_job_id = None
417 416
        vm.save()
418
        # Remove dirty nic
419
        response = self.mypost('networks/%d/action' % net.id,
420
                               net.userid, json.dumps(request), 'json')
421
        self.assertFault(response, 409, 'buildInProgress')
422 417

  
423 418
    def test_remove_nic_malformed(self, mrapi):
424 419
        user = 'userr'
......
426 421
        net = mfactory.NetworkFactory(state='ACTIVE', userid=user)
427 422
        nic = mfactory.NetworkInterfaceFactory(machine=vm, network=net)
428 423
        request = {'remove':
429
                    {'att234achment': 'nic-%s-%s' % (vm.id, nic.index)}
424
                    {'att234achment': 'nic-%s-%s' % (vm.id, nic.id)}
430 425
                  }
431 426
        response = self.mypost('networks/%d/action' % net.id,
432 427
                               net.userid, json.dumps(request), 'json')
b/snf-cyclades-app/synnefo/api/tests/servers.py
144 144
        self.assertEqual(api_nic['ipv4'], nic.ipv4)
145 145
        self.assertEqual(api_nic['ipv6'], nic.ipv6)
146 146
        self.assertEqual(api_nic['OS-EXT-IPS:type'], "fixed")
147
        self.assertEqual(api_nic['id'], 'nic-%s-%s' % (db_vm.id, nic.index))
147
        self.assertEqual(api_nic['id'], 'nic-%s-%s' % (db_vm.id, nic.id))
148 148
        api_address = server["addresses"]
149 149
        self.assertEqual(api_address[str(net.id)], [
150 150
            {"version": 4, "addr": nic.ipv4, "OS-EXT-IPS:type": "fixed"},
b/snf-cyclades-app/synnefo/api/util.py
285 285
    return address
286 286

  
287 287

  
288
def get_nic(machine, network):
288
def get_nic(vm, nic_id):
289 289
    try:
290
        return NetworkInterface.objects.get(machine=machine, network=network)
290
        return vm.nics.get(id=nic_id)
291 291
    except NetworkInterface.DoesNotExist:
292 292
        raise faults.ItemNotFound('Server not connected to this network.')
293 293

  
294 294

  
295
def get_nic_from_index(vm, nic_index):
296
    """Returns the nic_index-th nic of a vm
297
       Error Response Codes: itemNotFound (404), badMediaType (415)
298
    """
299
    matching_nics = vm.nics.filter(index=nic_index)
300
    matching_nics_len = len(matching_nics)
301
    if matching_nics_len < 1:
302
        raise faults.ItemNotFound('NIC not found on VM')
303
    elif matching_nics_len > 1:
304
        raise faults.BadMediaType('NIC index conflict on VM')
305
    nic = matching_nics[0]
306
    return nic
307

  
308

  
309 295
def render_metadata(request, metadata, use_values=False, status=200):
310 296
    if request.serialization == 'xml':
311 297
        data = render_to_string('metadata.xml', {'metadata': metadata})
......
328 314

  
329 315

  
330 316
def construct_nic_id(nic):
331
    return "-".join(["nic", unicode(nic.machine.id), unicode(nic.index)])
317
    return "-".join(["nic", unicode(nic.machine.id), unicode(nic.id)])
332 318

  
333 319

  
334 320
def verify_personality(personality):
b/snf-cyclades-app/synnefo/db/models.py
374 374
        get_latest_by = 'created'
375 375

  
376 376
    def __unicode__(self):
377
        return "<vm: %s>" % str(self.id)
377
        return u"<vm:%s@backend:%s>" % (self.id, self.backend_id)
378 378

  
379 379
    # Error classes
380 380
    class InvalidBackendIdError(Exception):
......
687 687
    ipv6 = models.CharField(max_length=100, null=True)
688 688
    firewall_profile = models.CharField(choices=FIREWALL_PROFILES,
689 689
                                        max_length=30, null=True)
690
    dirty = models.BooleanField(default=False)
691 690
    state = models.CharField(max_length=32, null=False, default="ACTIVE",
692 691
                             choices=STATES)
693 692

  
693
    @property
694
    def backend_uuid(self):
695
        """Return the backend id by prepending backend-prefix."""
696
        return "%snic-%s" % (settings.BACKEND_PREFIX_ID, str(self.id))
697

  
694 698
    def __unicode__(self):
695 699
        return "<%s:vm:%s network:%s ipv4:%s ipv6:%s>" % \
696
            (self.index, self.machine_id, self.network_id, self.ipv4,
700
            (self.id, self.machine_id, self.network_id, self.ipv4,
697 701
             self.ipv6)
698 702

  
699 703
    @property
b/snf-cyclades-app/synnefo/logic/backend.py
239 239
        if ipv4:
240 240
            net.reserve_address(ipv4)
241 241

  
242
        nic['dirty'] = False
243 242
        vm.nics.create(**nic)
244 243
        # Dummy save the network, because UI uses changed-since for VMs
245 244
        # and Networks in order to show the VM NICs
......
512 511
        kw['disks'][0]['provider'] = provider
513 512
        kw['disks'][0]['origin'] = flavor.disk_origin
514 513

  
515
    kw['nics'] = [{"network": nic.network.backend_id, "ip": nic.ipv4}
514
    kw['nics'] = [{"name": nic.backend_uuid,
515
                   "network": nic.network.backend_id,
516
                   "ip": nic.ipv4}
516 517
                  for nic in nics]
517 518
    backend = vm.backend
518 519
    depend_jobs = []
......
779 780

  
780 781
    depends = [[job, ["success", "error", "canceled"]] for job in depend_jobs]
781 782

  
782
    nic = {'ip': nic.ipv4, 'network': network.backend_id}
783
    nic = {'name': nic.backend_uuid,
784
           'network': network.backend_id,
785
           'ip': nic.ipv4}
783 786

  
784
    log.debug("Connecting NIC %s to VM %s", nic, vm)
787
    log.debug("Adding NIC %s to VM %s", nic, vm)
785 788

  
786 789
    kwargs = {
787 790
        "instance": vm.backend_vm_id,
......
798 801

  
799 802

  
800 803
def disconnect_from_network(vm, nic):
801
    log.debug("Removing nic of VM %s, with index %s", vm, str(nic.index))
804
    log.debug("Removing NIC %s of VM %s", nic, vm)
802 805

  
803 806
    kwargs = {
804 807
        "instance": vm.backend_vm_id,
b/snf-cyclades-app/synnefo/logic/servers.py
355 355
    if network.subnet is not None and network.dhcp:
356 356
        # Get a free IP from the address pool.
357 357
        address = util.get_network_free_address(network)
358

  
359
    log.info("Connecting VM %s to Network %s(%s)", vm, network, address)
360

  
361
    nic = NetworkInterface.objects.create(machine=vm,
362
                                          network=network,
363
                                          ipv4=address,
364
                                          state="BUILDING")
358
    nic = NetworkInterface.objects.create(machine=vm, network=network,
359
                                          ipv4=address, state="BUILDING")
360
    log.info("Connecting VM %s to Network %s. NIC: %s", vm, network, nic)
365 361

  
366 362
    return backend.connect_to_network(vm, nic)
367 363

  
368 364

  
369 365
@server_command("DISCONNECT")
370
def disconnect(vm, nic_index):
371
    nic = util.get_nic_from_index(vm, nic_index)
372

  
373
    log.info("Removing NIC %s from VM %s", str(nic.index), vm)
374

  
375
    if nic.dirty:
376
        raise faults.BuildInProgress('Machine is busy.')
377
    else:
378
        vm.nics.all().update(dirty=True)
379

  
366
def disconnect(vm, nic):
367
    log.info("Removing NIC %s from VM %s", nic, vm)
380 368
    return backend.disconnect_from_network(vm, nic)
381 369

  
382 370

  

Also available in: Unified diff