Revision d0545590

b/snf-cyclades-app/conf/20-snf-cyclades-app-api.conf
49 49
#DEFAULT_MAC_FILTERED_BRIDGE = 'prv0'
50 50
#
51 51
#
52
## Firewall tags should contain '%d' to be filled with the NIC
53
## index.
54
#GANETI_FIREWALL_ENABLED_TAG = 'synnefo:network:0:protected'
55
#GANETI_FIREWALL_DISABLED_TAG = 'synnefo:network:0:unprotected'
56
#GANETI_FIREWALL_PROTECTED_TAG = 'synnefo:network:0:limited'
52
## Firewall tags should contain '%s' to be filled with the NIC
53
## ID.
54
#GANETI_FIREWALL_ENABLED_TAG = 'synnefo:network:%s:protected'
55
#GANETI_FIREWALL_DISABLED_TAG = 'synnefo:network:%s:unprotected'
56
#GANETI_FIREWALL_PROTECTED_TAG = 'synnefo:network:%s:limited'
57 57
#
58 58
## The default firewall profile that will be in effect if no tags are defined
59 59
#DEFAULT_FIREWALL_PROFILE = 'DISABLED'
b/snf-cyclades-app/synnefo/api/servers.py
756 756
    profile = args.get("profile")
757 757
    if profile is None:
758 758
        raise faults.BadRequest("Missing 'profile' attribute")
759
    index = args.get("index", 0)
760
    servers.set_firewall_profile(vm, profile=profile, index=index)
759
    nic_id = args.get("nic")
760
    if nic_id is None:
761
        raise faults.BadRequest("Missing 'nic' attribute")
762
    nic = util.get_nic(vm, nic_id)
763
    servers.set_firewall_profile(vm, profile=profile, nic=nic)
761 764
    return HttpResponse(status=202)
762 765

  
763 766

  
b/snf-cyclades-app/synnefo/api/tests/servers.py
672 672
        request = {'firewallProfile': {'profile': 'PROTECTED'}}
673 673
        response = self.mypost('servers/%d/action' % vm.id,
674 674
                               vm.userid, json.dumps(request), 'json')
675
        self.assertEqual(response.status_code, 202)
675
        self.assertBadRequest(response)
676
        request = {'firewallProfile': {'profile': 'PROTECTED', "nic": "10"}}
677
        response = self.mypost('servers/%d/action' % vm.id,
678
                               vm.userid, json.dumps(request), 'json')
679
        self.assertItemNotFound(response)
680
        nic = mfactory.NetworkInterfaceFactory(machine=vm)
681
        request = {'firewallProfile': {'profile': 'PROTECTED', "nic": nic.id}}
682
        response = self.mypost('servers/%d/action' % vm.id,
683
                               vm.userid, json.dumps(request), 'json')
684
        self.assertSuccess(response)
676 685
        mrapi().ModifyInstance.assert_called_once()
677 686

  
678 687
    def test_unsupported_firewall(self, mrapi, mimage):
b/snf-cyclades-app/synnefo/api/util.py
176 176
    image["metadata"] = dict((key.upper(), val)
177 177
                             for key, val in properties.items())
178 178

  
179

  
180 179
    return image
181 180

  
182 181

  
......
286 285

  
287 286

  
288 287
def get_nic(vm, nic_id):
288
    """Get a VMs NIC by its ID."""
289 289
    try:
290 290
        return vm.nics.get(id=nic_id)
291 291
    except NetworkInterface.DoesNotExist:
292
        raise faults.ItemNotFound('Server not connected to this network.')
292
        raise faults.ItemNotFound("NIC '%s' not found" % nic_id)
293 293

  
294 294

  
295 295
def render_metadata(request, metadata, use_values=False, status=200):
b/snf-cyclades-app/synnefo/app_settings/default/api.py
49 49

  
50 50

  
51 51
# Firewalling. Firewall tags should contain '%d' to be filled with the NIC
52
# index.
53
GANETI_FIREWALL_ENABLED_TAG = 'synnefo:network:%d:protected'
54
GANETI_FIREWALL_DISABLED_TAG = 'synnefo:network:%d:unprotected'
55
GANETI_FIREWALL_PROTECTED_TAG = 'synnefo:network:%d:limited'
52
# ID.
53
GANETI_FIREWALL_ENABLED_TAG = 'synnefo:network:%s:protected'
54
GANETI_FIREWALL_DISABLED_TAG = 'synnefo:network:%s:unprotected'
55
GANETI_FIREWALL_PROTECTED_TAG = 'synnefo:network:%s:limited'
56 56

  
57 57
# The default firewall profile that will be in effect if no tags are defined
58 58
DEFAULT_FIREWALL_PROFILE = 'DISABLED'
b/snf-cyclades-app/synnefo/logic/backend.py
844 844

  
845 845
    with pooled_rapi_client(vm) as client:
846 846
        jobID = client.ModifyInstance(**kwargs)
847
        # If the NIC has a tag for a firewall profile it must be deleted,
848
        # otherwise it may affect another NIC. XXX: Deleting the tag should
849
        # depend on the removing the NIC, but currently RAPI client does not
850
        # support this, this may result in clearing the firewall profile
851
        # without successfully removing the NIC. This issue will be fixed with
852
        # use of NIC UUIDs.
853 847
        firewall_profile = nic.firewall_profile
854 848
        if firewall_profile and firewall_profile != "DISABLED":
855
            tag = _firewall_tags[firewall_profile] % nic.index
849
            tag = _firewall_tags[firewall_profile] % nic.backend_uuid
856 850
            client.DeleteInstanceTags(vm.backend_vm_id, [tag],
857 851
                                      dry_run=settings.TEST)
858 852

  
859 853
        return jobID
860 854

  
861 855

  
862
def set_firewall_profile(vm, profile, index=0):
856
def set_firewall_profile(vm, profile, nic):
857
    uuid = nic.backend_uuid
863 858
    try:
864
        tag = _firewall_tags[profile] % index
859
        tag = _firewall_tags[profile] % uuid
865 860
    except KeyError:
866 861
        raise ValueError("Unsopported Firewall Profile: %s" % profile)
867 862

  
868
    log.debug("Setting tag of VM %s, NIC index %d, to %s", vm, index, profile)
863
    log.debug("Setting tag of VM %s, NIC %s, to %s", vm, nic, profile)
869 864

  
870 865
    with pooled_rapi_client(vm) as client:
871 866
        # Delete previous firewall tags
872 867
        old_tags = client.GetInstanceTags(vm.backend_vm_id)
873
        delete_tags = [(t % index) for t in _firewall_tags.values()
874
                       if (t % index) in old_tags]
868
        delete_tags = [(t % uuid) for t in _firewall_tags.values()
869
                       if (t % uuid) in old_tags]
875 870
        if delete_tags:
876 871
            client.DeleteInstanceTags(vm.backend_vm_id, delete_tags,
877 872
                                      dry_run=settings.TEST)
b/snf-cyclades-app/synnefo/logic/reconciliation.py
454 454
            if len(t) != 4:
455 455
                logger.error("Malformed synefo tag %s", tag)
456 456
                continue
457
            try:
458
                index = int(t[2])
459
                nics[index]['firewall'] = t[3]
460
            except ValueError:
461
                logger.error("Malformed synnefo tag %s", tag)
462
            except IndexError:
463
                logger.error("Found tag %s for non-existent NIC %d",
464
                             tag, index)
457
            nic_name = t[2]
458
            firewall = t[3]
459
            [nic.setdefault("firewall", firewall)
460
             for nic in nics if nic["name"] == nic_name]
465 461
    return nics
466 462

  
467 463

  
b/snf-cyclades-app/synnefo/logic/servers.py
337 337

  
338 338

  
339 339
@server_command("SET_FIREWALL_PROFILE")
340
def set_firewall_profile(vm, profile, index=0):
341
    log.info("Setting VM %s, NIC index %s, firewall %s", vm, index, profile)
340
def set_firewall_profile(vm, profile, nic):
341
    log.info("Setting VM %s, NIC %s, firewall %s", vm, nic, profile)
342 342

  
343 343
    if profile not in [x[0] for x in NetworkInterface.FIREWALL_PROFILES]:
344 344
        raise faults.BadRequest("Unsupported firewall profile")
345
    backend.set_firewall_profile(vm, profile=profile, index=index)
345
    backend.set_firewall_profile(vm, profile=profile, nic=nic)
346 346
    return None
347 347

  
348 348

  
b/snf-cyclades-gtools/synnefo/ganeti/eventd.py
138 138
            if len(t) != 4:
139 139
                logger.error("Malformed synefo tag %s", tag)
140 140
                continue
141
            try:
142
                index = int(t[2])
143
                nics[index]['firewall'] = t[3]
144
            except ValueError:
145
                logger.error("Malformed synnefo tag %s", tag)
146
            except IndexError:
147
                logger.error("Found tag %s for non-existent NIC %d",
148
                             tag, index)
141
            nic_name = t[2]
142
            firewall = t[3]
143
            [nic.setdefault("firewall", firewall)
144
             for nic in nics if nic["name"] == nic_name]
149 145
    return nics
150 146

  
151 147

  

Also available in: Unified diff