root / snf-cyclades-app / synnefo / api / ports.py @ 0069a20c
History | View | Annotate | Download (7.3 kB)
1 | 5db2001a | Marios Kogias | # Copyright 2011-2013 GRNET S.A. All rights reserved.
|
---|---|---|---|
2 | 5db2001a | Marios Kogias | #
|
3 | 5db2001a | Marios Kogias | # Redistribution and use in source and binary forms, with or
|
4 | 5db2001a | Marios Kogias | # without modification, are permitted provided that the following
|
5 | 5db2001a | Marios Kogias | # conditions are met:
|
6 | 5db2001a | Marios Kogias | #
|
7 | 5db2001a | Marios Kogias | # 1. Redistributions of source code must retain the above
|
8 | 5db2001a | Marios Kogias | # copyright notice, this list of conditions and the following
|
9 | 5db2001a | Marios Kogias | # disclaimer.
|
10 | 5db2001a | Marios Kogias | #
|
11 | 5db2001a | Marios Kogias | # 2. Redistributions in binary form must reproduce the above
|
12 | 5db2001a | Marios Kogias | # copyright notice, this list of conditions and the following
|
13 | 5db2001a | Marios Kogias | # disclaimer in the documentation and/or other materials
|
14 | 5db2001a | Marios Kogias | # provided with the distribution.
|
15 | 5db2001a | Marios Kogias | #
|
16 | 5db2001a | Marios Kogias | # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
|
17 | 5db2001a | Marios Kogias | # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18 | 5db2001a | Marios Kogias | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
19 | 5db2001a | Marios Kogias | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
|
20 | 5db2001a | Marios Kogias | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
21 | 5db2001a | Marios Kogias | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
22 | 5db2001a | Marios Kogias | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
23 | 5db2001a | Marios Kogias | # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
24 | 5db2001a | Marios Kogias | # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 | 5db2001a | Marios Kogias | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
26 | 5db2001a | Marios Kogias | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27 | 5db2001a | Marios Kogias | # POSSIBILITY OF SUCH DAMAGE.
|
28 | 5db2001a | Marios Kogias | #
|
29 | 5db2001a | Marios Kogias | # The views and conclusions contained in the software and
|
30 | 5db2001a | Marios Kogias | # documentation are those of the authors and should not be
|
31 | 5db2001a | Marios Kogias | # interpreted as representing official policies, either expressed
|
32 | 5db2001a | Marios Kogias | # or implied, of GRNET S.A.
|
33 | 5db2001a | Marios Kogias | |
34 | 593851e0 | Buildbot | from django.conf import settings |
35 | 593851e0 | Buildbot | from django.conf.urls import patterns |
36 | 593851e0 | Buildbot | from django.http import HttpResponse |
37 | 593851e0 | Buildbot | from django.utils import simplejson as json |
38 | 593851e0 | Buildbot | from django.db import transaction |
39 | 593851e0 | Buildbot | from django.db.models import Q |
40 | 593851e0 | Buildbot | from django.template.loader import render_to_string |
41 | 5db2001a | Marios Kogias | |
42 | 5db2001a | Marios Kogias | from snf_django.lib import api |
43 | 5db2001a | Marios Kogias | |
44 | 593851e0 | Buildbot | from synnefo.api import util |
45 | 593851e0 | Buildbot | from synnefo.db.models import NetworkInterface, SecurityGroup, IPAddress |
46 | f16aa9e6 | Marios Kogias | from synnefo.logic import ports |
47 | 593851e0 | Buildbot | |
48 | 593851e0 | Buildbot | from logging import getLogger |
49 | 593851e0 | Buildbot | |
50 | 593851e0 | Buildbot | log = getLogger(__name__) |
51 | 593851e0 | Buildbot | |
52 | 593851e0 | Buildbot | urlpatterns = patterns( |
53 | 593851e0 | Buildbot | 'synnefo.api.ports',
|
54 | 593851e0 | Buildbot | (r'^(?:/|.json|.xml)?$', 'demux'), |
55 | 593851e0 | Buildbot | (r'^/([-\w]+)(?:/|.json|.xml)?$', 'port_demux')) |
56 | 593851e0 | Buildbot | |
57 | 5db2001a | Marios Kogias | |
58 | 593851e0 | Buildbot | def demux(request): |
59 | 593851e0 | Buildbot | if request.method == 'GET': |
60 | 593851e0 | Buildbot | return list_ports(request)
|
61 | 593851e0 | Buildbot | elif request.method == 'POST': |
62 | 593851e0 | Buildbot | return create_port(request)
|
63 | 593851e0 | Buildbot | else:
|
64 | 593851e0 | Buildbot | return api.api_method_not_allowed(request)
|
65 | 593851e0 | Buildbot | |
66 | 593851e0 | Buildbot | |
67 | 5db2001a | Marios Kogias | def port_demux(request, port_id): |
68 | 593851e0 | Buildbot | |
69 | 593851e0 | Buildbot | if request.method == 'GET': |
70 | 5db2001a | Marios Kogias | return get_port_details(request, port_id)
|
71 | 593851e0 | Buildbot | elif request.method == 'DELETE': |
72 | 5db2001a | Marios Kogias | return delete_port(request, port_id)
|
73 | 593851e0 | Buildbot | elif request.method == 'PUT': |
74 | 5db2001a | Marios Kogias | return update_port(request, port_id)
|
75 | 593851e0 | Buildbot | else:
|
76 | 593851e0 | Buildbot | return api.api_method_not_allowed(request)
|
77 | 593851e0 | Buildbot | |
78 | 593851e0 | Buildbot | |
79 | 593851e0 | Buildbot | @api.api_method(http_method='GET', user_required=True, logger=log) |
80 | 593851e0 | Buildbot | def list_ports(request, detail=False): |
81 | 593851e0 | Buildbot | |
82 | 593851e0 | Buildbot | log.debug('list_ports detail=%s', detail)
|
83 | 593851e0 | Buildbot | |
84 | 593851e0 | Buildbot | user_ports = NetworkInterface.objects.filter( |
85 | 593851e0 | Buildbot | network__userid=request.user_uniq) |
86 | 593851e0 | Buildbot | |
87 | 5db2001a | Marios Kogias | port_dicts = [port_to_dict(port, detail) |
88 | 593851e0 | Buildbot | for port in user_ports.order_by('id')] |
89 | 593851e0 | Buildbot | |
90 | 593851e0 | Buildbot | if request.serialization == 'xml': |
91 | 5db2001a | Marios Kogias | data = render_to_string('list_ports.xml', {
|
92 | 5db2001a | Marios Kogias | "ports": port_dicts})
|
93 | 593851e0 | Buildbot | else:
|
94 | 5db2001a | Marios Kogias | data = json.dumps({'ports': port_dicts})
|
95 | 593851e0 | Buildbot | |
96 | 593851e0 | Buildbot | return HttpResponse(data, status=200) |
97 | 593851e0 | Buildbot | |
98 | 593851e0 | Buildbot | |
99 | 593851e0 | Buildbot | @api.api_method(http_method='POST', user_required=True, logger=log) |
100 | 593851e0 | Buildbot | def create_port(request): |
101 | 593851e0 | Buildbot | '''
|
102 | 593851e0 | Buildbot | '''
|
103 | 593851e0 | Buildbot | user_id = request.user_uniq |
104 | 5db2001a | Marios Kogias | req = api.utils.get_request_dict(request) |
105 | 593851e0 | Buildbot | log.info('create_port %s', req)
|
106 | 593851e0 | Buildbot | |
107 | f16aa9e6 | Marios Kogias | port_dict = api.utils.get_attribute(req, "port")
|
108 | f16aa9e6 | Marios Kogias | net_id = api.utils.get_attribute(port_dict, "network_id")
|
109 | f16aa9e6 | Marios Kogias | dev_id = api.utils.get_attribute(port_dict, "device_id")
|
110 | f16aa9e6 | Marios Kogias | |
111 | f16aa9e6 | Marios Kogias | network = util.get_network(net_id, request.user_uniq, non_deleted=True)
|
112 | f16aa9e6 | Marios Kogias | |
113 | f16aa9e6 | Marios Kogias | if network.public:
|
114 | f16aa9e6 | Marios Kogias | raise api.faults.Forbidden('forbidden') |
115 | f16aa9e6 | Marios Kogias | |
116 | f16aa9e6 | Marios Kogias | |
117 | f16aa9e6 | Marios Kogias | vm = util.get_vm(dev_id, request.user_uniq) |
118 | f16aa9e6 | Marios Kogias | |
119 | f16aa9e6 | Marios Kogias | name = api.utils.get_attribute(port_dict, "name", required=False) |
120 | f16aa9e6 | Marios Kogias | |
121 | f16aa9e6 | Marios Kogias | if name is None: |
122 | f16aa9e6 | Marios Kogias | name = ""
|
123 | f16aa9e6 | Marios Kogias | |
124 | f16aa9e6 | Marios Kogias | security_groups = api.utils.get_attribute(port_dict, |
125 | f16aa9e6 | Marios Kogias | "security_groups",
|
126 | f16aa9e6 | Marios Kogias | required=False)
|
127 | f16aa9e6 | Marios Kogias | #validate security groups
|
128 | f16aa9e6 | Marios Kogias | # like get security group from db
|
129 | a1713485 | Marios Kogias | sg_list = [] |
130 | f16aa9e6 | Marios Kogias | if security_groups:
|
131 | f16aa9e6 | Marios Kogias | for gid in security_groups: |
132 | a1713485 | Marios Kogias | sg = util.get_security_group(int(gid))
|
133 | a1713485 | Marios Kogias | sg_list.append(sg) |
134 | f16aa9e6 | Marios Kogias | |
135 | 0069a20c | Marios Kogias | new_port = ports.create(network, vm, security_groups=sg_list) |
136 | 593851e0 | Buildbot | |
137 | 5db2001a | Marios Kogias | response = render_port(request, port_to_dict(new_port), status=201)
|
138 | 593851e0 | Buildbot | |
139 | 593851e0 | Buildbot | return response
|
140 | 593851e0 | Buildbot | |
141 | 593851e0 | Buildbot | |
142 | 5db2001a | Marios Kogias | @api.api_method(http_method='GET', user_required=True, logger=log) |
143 | 5db2001a | Marios Kogias | def get_port_details(request, port_id): |
144 | 5db2001a | Marios Kogias | log.debug('get_port_details %s', port_id)
|
145 | 5db2001a | Marios Kogias | port = util.get_port(port_id, request.user_uniq) |
146 | 5db2001a | Marios Kogias | return render_port(request, port_to_dict(port))
|
147 | 5db2001a | Marios Kogias | |
148 | 5db2001a | Marios Kogias | |
149 | 5db2001a | Marios Kogias | @api.api_method(http_method='PUT', user_required=True, logger=log) |
150 | 5db2001a | Marios Kogias | def update_port(request, port_id): |
151 | 5db2001a | Marios Kogias | '''
|
152 | 5db2001a | Marios Kogias | You can update only name, security_groups
|
153 | 5db2001a | Marios Kogias | '''
|
154 | 5db2001a | Marios Kogias | port = util.get_port(port_id, request.user_uniq, for_update=True)
|
155 | 5db2001a | Marios Kogias | req = api.utils.get_request_dict(request) |
156 | 5db2001a | Marios Kogias | |
157 | 5db2001a | Marios Kogias | port_info = api.utils.get_attribute(req, "port", required=True) |
158 | 5db2001a | Marios Kogias | name = api.utils.get_attribute(port_info, "name", required=False) |
159 | 5db2001a | Marios Kogias | |
160 | 5db2001a | Marios Kogias | if name:
|
161 | 5db2001a | Marios Kogias | port.name = name |
162 | 5db2001a | Marios Kogias | |
163 | 5db2001a | Marios Kogias | security_groups = api.utils.get_attribute(port_info, "security_groups",
|
164 | 5db2001a | Marios Kogias | required=False)
|
165 | 5db2001a | Marios Kogias | if security_groups:
|
166 | 5db2001a | Marios Kogias | sg_list = [] |
167 | 5db2001a | Marios Kogias | #validate security groups
|
168 | 5db2001a | Marios Kogias | for gid in security_groups: |
169 | a1713485 | Marios Kogias | sg = util.get_security_group(int(gid))
|
170 | a1713485 | Marios Kogias | sg_list.append(sg) |
171 | 5db2001a | Marios Kogias | |
172 | 5db2001a | Marios Kogias | #clear the old security groups
|
173 | 5db2001a | Marios Kogias | port.security_groups.clear() |
174 | 5db2001a | Marios Kogias | |
175 | 5db2001a | Marios Kogias | #add the new groups
|
176 | 5db2001a | Marios Kogias | port.security_groups.add(*sg_list) |
177 | 5db2001a | Marios Kogias | |
178 | 5db2001a | Marios Kogias | port.save() |
179 | 5db2001a | Marios Kogias | return render_port(request, port_to_dict(port), 200) |
180 | 5db2001a | Marios Kogias | |
181 | 5db2001a | Marios Kogias | |
182 | 5db2001a | Marios Kogias | @api.api_method(http_method='DELETE', user_required=True, logger=log) |
183 | 5db2001a | Marios Kogias | @transaction.commit_on_success
|
184 | 5db2001a | Marios Kogias | def delete_port(request, port_id): |
185 | 5db2001a | Marios Kogias | log.info('delete_port %s', port_id)
|
186 | 5db2001a | Marios Kogias | port = util.get_port(port_id, request.user_uniq, for_update=True)
|
187 | 5db2001a | Marios Kogias | '''
|
188 | 5db2001a | Marios Kogias | FIXME delete the port
|
189 | 5db2001a | Marios Kogias | skip the backend part...
|
190 | 5db2001a | Marios Kogias | release the ips associated with the port
|
191 | 5db2001a | Marios Kogias | '''
|
192 | 5db2001a | Marios Kogias | return HttpResponse(status=204) |
193 | 5db2001a | Marios Kogias | |
194 | 593851e0 | Buildbot | #util functions
|
195 | 593851e0 | Buildbot | |
196 | 593851e0 | Buildbot | |
197 | 593851e0 | Buildbot | def port_to_dict(port, detail=True): |
198 | 593851e0 | Buildbot | d = {'id': str(port.id), 'name': port.name} |
199 | 593851e0 | Buildbot | if detail:
|
200 | 593851e0 | Buildbot | d['user_id'] = port.network.userid
|
201 | 593851e0 | Buildbot | d['tenant_id'] = port.network.userid
|
202 | 593851e0 | Buildbot | d['device_id'] = str(port.machine.id) |
203 | 593851e0 | Buildbot | d['admin_state_up'] = True |
204 | 593851e0 | Buildbot | d['mac_address'] = port.mac
|
205 | 593851e0 | Buildbot | d['status'] = port.state
|
206 | 593851e0 | Buildbot | d['device_owner'] = port.device_owner
|
207 | 593851e0 | Buildbot | d['network_id'] = str(port.network.id) |
208 | 5db2001a | Marios Kogias | d['updated'] = api.utils.isoformat(port.updated)
|
209 | 5db2001a | Marios Kogias | d['created'] = api.utils.isoformat(port.created)
|
210 | 593851e0 | Buildbot | d['fixed_ips'] = []
|
211 | 593851e0 | Buildbot | for ip in port.ips.all(): |
212 | 593851e0 | Buildbot | d['fixed_ips'].append({"ip_address": ip.address, |
213 | 5db2001a | Marios Kogias | "subnet": str(ip.subnet.id)}) |
214 | 5db2001a | Marios Kogias | sg_list = list(port.security_groups.values_list('id', flat=True)) |
215 | 5db2001a | Marios Kogias | d['security_groups'] = map(str, sg_list) |
216 | 5db2001a | Marios Kogias | |
217 | 593851e0 | Buildbot | return d
|
218 | 593851e0 | Buildbot | |
219 | 593851e0 | Buildbot | |
220 | 593851e0 | Buildbot | def render_port(request, portdict, status=200): |
221 | 593851e0 | Buildbot | if request.serialization == 'xml': |
222 | 5db2001a | Marios Kogias | data = render_to_string('port.xml', {'port': portdict}) |
223 | 593851e0 | Buildbot | else:
|
224 | 593851e0 | Buildbot | data = json.dumps({'port': portdict})
|
225 | 593851e0 | Buildbot | return HttpResponse(data, status=status) |