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