Revision 08b079e2

b/snf-cyclades-app/synnefo/api/actions.py
39 39
from django.template.loader import render_to_string
40 40
from django.utils import simplejson as json
41 41

  
42
from synnefo.api.faults import BadRequest, ServiceUnavailable
43
from synnefo.api.util import random_password, get_vm
42
from synnefo.api.faults import BadRequest, ServiceUnavailable, ItemNotFound
43
from synnefo.api.util import random_password, get_vm, get_nic_from_index
44 44
from synnefo.db.models import NetworkInterface
45 45
from synnefo.logic import backend
46 46
from synnefo.logic.utils import get_rsapi_state
......
316 316
    #                       itemNotFound (404),
317 317
    #                       overLimit (413)
318 318

  
319
    server_id = args.get('serverRef', None)
320
    if not server_id:
319
    try: #attachment string: nic-<vm-id>-<nic-index>
320
        server_id = args.get('attachment', None).split('-')[1]
321
        nic_index = args.get('attachment', None).split('-')[2]
322
    except IndexError:
323
        raise BadRequest('Malformed Network Interface Id')
324

  
325
    if not server_id or not nic_index:
321 326
        raise BadRequest('Malformed Request.')
322 327
    vm = get_vm(server_id, request.user_uniq)
323
    backend.disconnect_from_network(vm, net)
328
    nic = get_nic_from_index(vm, nic_index)
329
    backend.disconnect_nic_from_vm(vm, nic)
324 330
    return HttpResponse(status=202)
b/snf-cyclades-app/synnefo/api/common.py
41 41

  
42 42
@api_method()
43 43
def method_not_allowed(request):
44
    raise BadRequest('Method not allowed.')
44
    raise BadRequest('Method not allowed')
b/snf-cyclades-app/synnefo/api/faults.py
62 62

  
63 63
class ServiceUnavailable(Fault):
64 64
    code = 503
65

  
66
class BadMediaType(Fault):
67
    code = 415
b/snf-cyclades-app/synnefo/api/networks.py
84 84
    network_id = str(network.id) if not network.public else 'public'
85 85
    d = {'id': network_id, 'name': network.name}
86 86
    if detail:
87
        d['cidr'] = network.subnet
88
        d['gateway'] = network.gateway
89
        d['dhcp'] = network.dhcp
90
        d['type'] = network.type
87 91
        d['updated'] = util.isoformat(network.updated)
88 92
        d['created'] = util.isoformat(network.created)
89 93
        d['status'] = network.state
90
        servers = [vm.id for vm in network.machines.filter(userid=user_id)]
91
        d['servers'] = {'values': servers}
94

  
95
        attachments = [util.construct_nic_id(nic) for nic in network.nics.filter(machine__userid= user_id)]
96
        d['attachments'] = {'values':attachments}
92 97
    return d
93 98

  
94 99

  
b/snf-cyclades-app/synnefo/api/servers.py
107 107
    else:
108 108
        return method_not_allowed(request)
109 109

  
110

  
111 110
def nic_to_dict(nic):
112 111
    network = nic.network
113 112
    network_id = str(network.id) if not network.public else 'public'
114
    d = {'id': network_id, 'name': network.name, 'mac': nic.mac}
113
    ipv4 = nic.ipv4 if nic.ipv4 else None
114
    ipv6 = nic.ipv6 if nic.ipv6 else None
115

  
116
    d = {'id': util.construct_nic_id(nic), 'network_id': network_id, 'mac_address': nic.mac, 'ipv4': ipv4, 'ipv6': ipv6}
115 117
    if nic.firewall_profile:
116 118
        d['firewallProfile'] = nic.firewall_profile
117
    if nic.ipv4 or nic.ipv6:
118
        d['values'] = []
119
        if nic.ipv4:
120
            d['values'].append({'version': 4, 'addr': nic.ipv4})
121
        if nic.ipv6:
122
            d['values'].append({'version': 6, 'addr': nic.ipv6})
123 119
    return d
124 120

  
125 121

  
......
139 135
        if metadata:
140 136
            d['metadata'] = {'values': metadata}
141 137

  
142
        addresses = [nic_to_dict(nic) for nic in vm.nics.all()]
143
        if addresses:
144
            d['addresses'] = {'values': addresses}
138
        attachments = [nic_to_dict(nic) for nic in vm.nics.all()]
139
        if attachments:
140
            d['attachments'] = {'values': attachments}
145 141
    return d
146 142

  
147 143

  
b/snf-cyclades-app/synnefo/api/tests.py
47 47
from synnefo.logic.utils import get_rsapi_state
48 48

  
49 49
import mock
50
from synnefo.lib import astakos
51

  
52
from contextlib import contextmanager
53

  
54
# This is a hack to override astakos
55
# The global variable ASTAKOS_PATCHED_USER keeps the name of
56
# a dummy user that we provide through replacement of the
57
# corresponding astakos function with a dummy function.
58
ASTAKOS_PATCHED_USER = "user"
59

  
60
@contextmanager
61
def astakos_user(user):
62
    """
63
    Context manager to mock astakos response.
64

  
65
    usage:
66
    with astakos_user("user@user.com"):
67
        .... make api calls .... get_user will act as user@user.com requested the api.
68

  
69
    """
70
    from synnefo.lib import astakos
71
    orig_method = astakos.get_user
72
    
73
    global ASTAKOS_PATCHED_USER
74
    ASTAKOS_PATCHED_USER = user
75
    def dummy_get_user(request, *args, **kwargs):
76
        global ASTAKOS_PATCHED_USER
77
        request.user = {'username': ASTAKOS_PATCHED_USER, 'groups': []}
78
        request.user_uniq = ASTAKOS_PATCHED_USER
79
    astakos.get_user = dummy_get_user
80
    yield
81
    astakos.get_user = orig_method
50 82

  
51 83
class AaiClient(Client):
52 84
    def request(self, **request):
53 85
        request['HTTP_X_AUTH_TOKEN'] = '0000'
54 86
        return super(AaiClient, self).request(**request)
55 87

  
88
class NetworksTest(TestCase):
89
    
90
    fixtures = ['network_test_data']
91

  
92
    def test_attachments_list(self):
93
        with astakos_user("admin@adminland.com"):
94
            r = self.client.get("/api/v1.1/networks")
95
            data = json.loads(r.content)
96
            self.assertEqual(data["networks"]["values"][1]["name"], "network4admin")
97
            #import pdb; pdb.set_trace()
98
            self.assertEqual(len(data["networks"]["values"]), 2)
99
        with astakos_user("user1@userland.com"):
100
            r = self.client.get("/api/v1.1/networks")
101
            data = json.loads(r.content)
102
            self.assertEqual(data["networks"]["values"][1]["name"], "network4user1")
103
            #import pdb; pdb.set_trace()
104
            self.assertEqual(len(data["networks"]["values"]), 2)
105

  
106
    def test_create_network(self):
107
        with astakos_user("admin@adminland.com"):
108
            r = self.client.post("/api/v1.1/networks")
109

  
110
class ServersTest(TestCase):
111

  
112
    fixtures = ['network_test_data']
113

  
114
    def test_attachments_list(self):
115
        with astakos_user("admin@adminland.com"):
116
            r = self.client.get("/api/v1.1/servers")
117
            data = json.loads(r.content)
118
            self.assertEqual(data["servers"]["values"][0]["id"], 1001)
119
            self.assertEqual(len(data["servers"]["values"]), 1)
120
            r = self.client.get("/api/v1.1/servers/1001")
121

  
56 122

  
57 123
class TestQuota(TestCase):
58 124

  
......
636 702
        return reply['networks']['values']
637 703

  
638 704
    def create_network(self, name):
639
        path = '/api/v1.1/networks'
640
        data = json.dumps({'network': {'name': name}})
641
        response = self.client.post(path, data, content_type='application/json')
642
        self.assertEqual(response.status_code, 202)
643
        reply = json.loads(response.content)
644
        self.assertEqual(reply.keys(), ['network'])
645
        return reply
705
        with astakos_user("admin@adminland.com"):
706
            path = '/api/v1.1/networks'
707
            data = json.dumps({'network': {'name': name}})
708
            response = self.client.post(path, data, content_type='application/json')
709
            self.assertEqual(response.status_code, 202)
710
            reply = json.loads(response.content)
711
            self.assertEqual(reply.keys(), ['network'])
712
            return reply
646 713

  
647 714
    def get_network_details(self, network_id):
648 715
        path = '/api/v1.1/networks/%s' % network_id
b/snf-cyclades-app/synnefo/api/util.py
55 55
from django.utils.cache import add_never_cache_headers
56 56

  
57 57
from synnefo.api.faults import (Fault, BadRequest, BuildInProgress,
58
                                ItemNotFound, ServiceUnavailable, Unauthorized)
58
                                ItemNotFound, ServiceUnavailable, Unauthorized, BadMediaType)
59 59
from synnefo.db.models import (Flavor, VirtualMachine, VirtualMachineMetadata,
60 60
                               Network, NetworkInterface)
61 61
from synnefo.lib.astakos import get_user
......
214 214
    except NetworkInterface.DoesNotExist:
215 215
        raise ItemNotFound('Server not connected to this network.')
216 216

  
217
def get_nic_from_index(vm, nic_index):
218
    """Returns the nic_index-th nic of a vm
219
       Error Response Codes: itemNotFound (404), badMediaType (415)
220
    """
221
    matching_nics = vm.nics.filter(index=nic_index)
222
    matching_nics_len = len(matching_nics)
223
    if matching_nics_len < 1:
224
        raise  ItemNotFound('NIC not found on VM')
225
    elif matching_nics_len > 1:
226
        raise BadMediaType('NIC index conflict on VM')
227
    nic = matching_nics[0]
228
    return nic
217 229

  
218 230
def get_request_dict(request):
219 231
    """Returns data sent by the client as a python dict."""
......
321 333
                    raise Unauthorized('No user found.')
322 334
                if http_method and request.method != http_method:
323 335
                    raise BadRequest('Method not allowed.')
324

  
336
                
325 337
                resp = func(request, *args, **kwargs)
326 338
                update_response_headers(request, resp)
327 339
                return resp
......
339 351
                return render_fault(request, fault)
340 352
        return wrapper
341 353
    return decorator
354

  
355
def construct_nic_id(nic):
356
    return "-".join(["nic", unicode(nic.machine.id), unicode(nic.index)])

Also available in: Unified diff