root / snf-cyclades-app / synnefo / api / ports.py @ ab6d1a2f
History | View | Annotate | Download (8.7 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 | 593851e0 | Buildbot | |
47 | 593851e0 | Buildbot | from logging import getLogger |
48 | 593851e0 | Buildbot | |
49 | 593851e0 | Buildbot | log = getLogger(__name__) |
50 | 593851e0 | Buildbot | |
51 | 593851e0 | Buildbot | urlpatterns = patterns( |
52 | 593851e0 | Buildbot | 'synnefo.api.ports',
|
53 | 593851e0 | Buildbot | (r'^(?:/|.json|.xml)?$', 'demux'), |
54 | 593851e0 | Buildbot | (r'^/([-\w]+)(?:/|.json|.xml)?$', 'port_demux')) |
55 | 593851e0 | Buildbot | |
56 | 5db2001a | Marios Kogias | |
57 | 593851e0 | Buildbot | def demux(request): |
58 | 593851e0 | Buildbot | if request.method == 'GET': |
59 | 593851e0 | Buildbot | return list_ports(request)
|
60 | 593851e0 | Buildbot | elif request.method == 'POST': |
61 | 593851e0 | Buildbot | return create_port(request)
|
62 | 593851e0 | Buildbot | else:
|
63 | 593851e0 | Buildbot | return api.api_method_not_allowed(request)
|
64 | 593851e0 | Buildbot | |
65 | 593851e0 | Buildbot | |
66 | 5db2001a | Marios Kogias | def port_demux(request, port_id): |
67 | 593851e0 | Buildbot | |
68 | 593851e0 | Buildbot | if request.method == 'GET': |
69 | 5db2001a | Marios Kogias | return get_port_details(request, port_id)
|
70 | 593851e0 | Buildbot | elif request.method == 'DELETE': |
71 | 5db2001a | Marios Kogias | return delete_port(request, port_id)
|
72 | 593851e0 | Buildbot | elif request.method == 'PUT': |
73 | 5db2001a | Marios Kogias | return update_port(request, port_id)
|
74 | 593851e0 | Buildbot | else:
|
75 | 593851e0 | Buildbot | return api.api_method_not_allowed(request)
|
76 | 593851e0 | Buildbot | |
77 | 593851e0 | Buildbot | |
78 | 593851e0 | Buildbot | @api.api_method(http_method='GET', user_required=True, logger=log) |
79 | 593851e0 | Buildbot | def list_ports(request, detail=False): |
80 | 593851e0 | Buildbot | |
81 | 593851e0 | Buildbot | log.debug('list_ports detail=%s', detail)
|
82 | 593851e0 | Buildbot | |
83 | 593851e0 | Buildbot | user_ports = NetworkInterface.objects.filter( |
84 | 593851e0 | Buildbot | network__userid=request.user_uniq) |
85 | 593851e0 | Buildbot | |
86 | 5db2001a | Marios Kogias | port_dicts = [port_to_dict(port, detail) |
87 | 593851e0 | Buildbot | for port in user_ports.order_by('id')] |
88 | 593851e0 | Buildbot | |
89 | 593851e0 | Buildbot | if request.serialization == 'xml': |
90 | 5db2001a | Marios Kogias | data = render_to_string('list_ports.xml', {
|
91 | 5db2001a | Marios Kogias | "ports": port_dicts})
|
92 | 593851e0 | Buildbot | else:
|
93 | 5db2001a | Marios Kogias | data = json.dumps({'ports': port_dicts})
|
94 | 593851e0 | Buildbot | |
95 | 593851e0 | Buildbot | return HttpResponse(data, status=200) |
96 | 593851e0 | Buildbot | |
97 | 593851e0 | Buildbot | |
98 | 593851e0 | Buildbot | @api.api_method(http_method='POST', user_required=True, logger=log) |
99 | 593851e0 | Buildbot | @transaction.commit_manually
|
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 | try:
|
107 | 5db2001a | Marios Kogias | port_dict = api.utils.get_attribute(req, "port")
|
108 | 5db2001a | Marios Kogias | net_id = api.utils.get_attribute(port_dict, "network_id")
|
109 | 5db2001a | Marios Kogias | dev_id = api.utils.get_attribute(port_dict, "device_id")
|
110 | 593851e0 | Buildbot | |
111 | a3b8aaf6 | Marios Kogias | network = util.get_network(net_id, request.user_uniq, non_deleted=True)
|
112 | a3b8aaf6 | Marios Kogias | |
113 | a3b8aaf6 | Marios Kogias | if network.public:
|
114 | a3b8aaf6 | Marios Kogias | raise api.faults.Forbidden('forbidden') |
115 | a3b8aaf6 | Marios Kogias | |
116 | a3b8aaf6 | Marios Kogias | if network.state != 'ACTIVE': |
117 | a3b8aaf6 | Marios Kogias | raise api.faults.Conflict('Network build in process') |
118 | 593851e0 | Buildbot | |
119 | 593851e0 | Buildbot | vm = util.get_vm(dev_id, request.user_uniq) |
120 | 593851e0 | Buildbot | |
121 | 5db2001a | Marios Kogias | name = api.utils.get_attribute(port_dict, "name", required=False) |
122 | 5db2001a | Marios Kogias | |
123 | 5db2001a | Marios Kogias | if name is None: |
124 | 5db2001a | Marios Kogias | name = ""
|
125 | 593851e0 | Buildbot | |
126 | 593851e0 | Buildbot | sg_list = [] |
127 | 5db2001a | Marios Kogias | security_groups = api.utils.get_attribute(port_dict, |
128 | 5db2001a | Marios Kogias | "security_groups",
|
129 | 5db2001a | Marios Kogias | required=False)
|
130 | 5db2001a | Marios Kogias | #validate security groups
|
131 | 5db2001a | Marios Kogias | # like get security group from db
|
132 | 5db2001a | Marios Kogias | if security_groups:
|
133 | 5db2001a | Marios Kogias | for gid in security_groups: |
134 | 593851e0 | Buildbot | try:
|
135 | 593851e0 | Buildbot | sg = SecurityGroup.objects.get(id=int(gid))
|
136 | 593851e0 | Buildbot | sg_list.append(sg) |
137 | 593851e0 | Buildbot | except (ValueError, SecurityGroup.DoesNotExist): |
138 | 593851e0 | Buildbot | raise api.faults.ItemNotFound("Not valid security group") |
139 | 593851e0 | Buildbot | |
140 | 593851e0 | Buildbot | #create the port
|
141 | 593851e0 | Buildbot | new_port = NetworkInterface.objects.create(name=name, |
142 | 5db2001a | Marios Kogias | network=network, |
143 | 593851e0 | Buildbot | machine=vm, |
144 | 593851e0 | Buildbot | device_owner="vm",
|
145 | 593851e0 | Buildbot | state="BUILDING")
|
146 | 593851e0 | Buildbot | #add the security groups
|
147 | 593851e0 | Buildbot | new_port.security_groups.add(*sg_list) |
148 | 593851e0 | Buildbot | |
149 | 5db2001a | Marios Kogias | #add new port to every subnet of the network
|
150 | 5db2001a | Marios Kogias | for subn in network.subnets.all(): |
151 | 593851e0 | Buildbot | IPAddress.objects.create(subnet=subn, |
152 | 5db2001a | Marios Kogias | network=network, |
153 | 593851e0 | Buildbot | nic=new_port, |
154 | 593851e0 | Buildbot | userid=user_id, |
155 | 5db2001a | Marios Kogias | # FIXME
|
156 | 5db2001a | Marios Kogias | address="192.168.0." + str(subn.id)) |
157 | 593851e0 | Buildbot | |
158 | 593851e0 | Buildbot | except:
|
159 | 593851e0 | Buildbot | transaction.rollback() |
160 | 593851e0 | Buildbot | log.info("roll")
|
161 | 593851e0 | Buildbot | raise
|
162 | 593851e0 | Buildbot | |
163 | 593851e0 | Buildbot | else:
|
164 | 593851e0 | Buildbot | transaction.commit() |
165 | 593851e0 | Buildbot | log.info("commit")
|
166 | 593851e0 | Buildbot | |
167 | 5db2001a | Marios Kogias | response = render_port(request, port_to_dict(new_port), status=201)
|
168 | 593851e0 | Buildbot | |
169 | 593851e0 | Buildbot | return response
|
170 | 593851e0 | Buildbot | |
171 | 593851e0 | Buildbot | |
172 | 5db2001a | Marios Kogias | @api.api_method(http_method='GET', user_required=True, logger=log) |
173 | 5db2001a | Marios Kogias | def get_port_details(request, port_id): |
174 | 5db2001a | Marios Kogias | log.debug('get_port_details %s', port_id)
|
175 | 5db2001a | Marios Kogias | port = util.get_port(port_id, request.user_uniq) |
176 | 5db2001a | Marios Kogias | return render_port(request, port_to_dict(port))
|
177 | 5db2001a | Marios Kogias | |
178 | 5db2001a | Marios Kogias | |
179 | 5db2001a | Marios Kogias | @api.api_method(http_method='PUT', user_required=True, logger=log) |
180 | 5db2001a | Marios Kogias | def update_port(request, port_id): |
181 | 5db2001a | Marios Kogias | '''
|
182 | 5db2001a | Marios Kogias | You can update only name, security_groups
|
183 | 5db2001a | Marios Kogias | '''
|
184 | 5db2001a | Marios Kogias | port = util.get_port(port_id, request.user_uniq, for_update=True)
|
185 | 5db2001a | Marios Kogias | req = api.utils.get_request_dict(request) |
186 | 5db2001a | Marios Kogias | |
187 | 5db2001a | Marios Kogias | port_info = api.utils.get_attribute(req, "port", required=True) |
188 | 5db2001a | Marios Kogias | name = api.utils.get_attribute(port_info, "name", required=False) |
189 | 5db2001a | Marios Kogias | |
190 | 5db2001a | Marios Kogias | if name:
|
191 | 5db2001a | Marios Kogias | port.name = name |
192 | 5db2001a | Marios Kogias | |
193 | 5db2001a | Marios Kogias | security_groups = api.utils.get_attribute(port_info, "security_groups",
|
194 | 5db2001a | Marios Kogias | required=False)
|
195 | 5db2001a | Marios Kogias | if security_groups:
|
196 | 5db2001a | Marios Kogias | sg_list = [] |
197 | 5db2001a | Marios Kogias | #validate security groups
|
198 | 5db2001a | Marios Kogias | # like get security group from db
|
199 | 5db2001a | Marios Kogias | for gid in security_groups: |
200 | 5db2001a | Marios Kogias | try:
|
201 | 5db2001a | Marios Kogias | sg = SecurityGroup.objects.get(id=int(gid))
|
202 | 5db2001a | Marios Kogias | sg_list.append(sg) |
203 | 5db2001a | Marios Kogias | except (ValueError, SecurityGroup.DoesNotExist): |
204 | 5db2001a | Marios Kogias | raise api.faults.ItemNotFound("Not valid security group") |
205 | 5db2001a | Marios Kogias | |
206 | 5db2001a | Marios Kogias | #clear the old security groups
|
207 | 5db2001a | Marios Kogias | port.security_groups.clear() |
208 | 5db2001a | Marios Kogias | |
209 | 5db2001a | Marios Kogias | #add the new groups
|
210 | 5db2001a | Marios Kogias | port.security_groups.add(*sg_list) |
211 | 5db2001a | Marios Kogias | |
212 | 5db2001a | Marios Kogias | port.save() |
213 | 5db2001a | Marios Kogias | return render_port(request, port_to_dict(port), 200) |
214 | 5db2001a | Marios Kogias | |
215 | 5db2001a | Marios Kogias | |
216 | 5db2001a | Marios Kogias | @api.api_method(http_method='DELETE', user_required=True, logger=log) |
217 | 5db2001a | Marios Kogias | @transaction.commit_on_success
|
218 | 5db2001a | Marios Kogias | def delete_port(request, port_id): |
219 | 5db2001a | Marios Kogias | log.info('delete_port %s', port_id)
|
220 | 5db2001a | Marios Kogias | port = util.get_port(port_id, request.user_uniq, for_update=True)
|
221 | 5db2001a | Marios Kogias | '''
|
222 | 5db2001a | Marios Kogias | FIXME delete the port
|
223 | 5db2001a | Marios Kogias | skip the backend part...
|
224 | 5db2001a | Marios Kogias | release the ips associated with the port
|
225 | 5db2001a | Marios Kogias | '''
|
226 | 5db2001a | Marios Kogias | return HttpResponse(status=204) |
227 | 5db2001a | Marios Kogias | |
228 | 593851e0 | Buildbot | #util functions
|
229 | 593851e0 | Buildbot | |
230 | 593851e0 | Buildbot | |
231 | 593851e0 | Buildbot | def port_to_dict(port, detail=True): |
232 | 593851e0 | Buildbot | d = {'id': str(port.id), 'name': port.name} |
233 | 593851e0 | Buildbot | if detail:
|
234 | 593851e0 | Buildbot | d['user_id'] = port.network.userid
|
235 | 593851e0 | Buildbot | d['tenant_id'] = port.network.userid
|
236 | 593851e0 | Buildbot | d['device_id'] = str(port.machine.id) |
237 | 593851e0 | Buildbot | d['admin_state_up'] = True |
238 | 593851e0 | Buildbot | d['mac_address'] = port.mac
|
239 | 593851e0 | Buildbot | d['status'] = port.state
|
240 | 593851e0 | Buildbot | d['device_owner'] = port.device_owner
|
241 | 593851e0 | Buildbot | d['network_id'] = str(port.network.id) |
242 | 5db2001a | Marios Kogias | d['updated'] = api.utils.isoformat(port.updated)
|
243 | 5db2001a | Marios Kogias | d['created'] = api.utils.isoformat(port.created)
|
244 | 593851e0 | Buildbot | d['fixed_ips'] = []
|
245 | 593851e0 | Buildbot | for ip in port.ips.all(): |
246 | 593851e0 | Buildbot | d['fixed_ips'].append({"ip_address": ip.address, |
247 | 5db2001a | Marios Kogias | "subnet": str(ip.subnet.id)}) |
248 | 5db2001a | Marios Kogias | sg_list = list(port.security_groups.values_list('id', flat=True)) |
249 | 5db2001a | Marios Kogias | d['security_groups'] = map(str, sg_list) |
250 | 5db2001a | Marios Kogias | |
251 | 593851e0 | Buildbot | return d
|
252 | 593851e0 | Buildbot | |
253 | 593851e0 | Buildbot | |
254 | 593851e0 | Buildbot | def render_port(request, portdict, status=200): |
255 | 593851e0 | Buildbot | if request.serialization == 'xml': |
256 | 5db2001a | Marios Kogias | data = render_to_string('port.xml', {'port': portdict}) |
257 | 593851e0 | Buildbot | else:
|
258 | 593851e0 | Buildbot | data = json.dumps({'port': portdict})
|
259 | 593851e0 | Buildbot | return HttpResponse(data, status=status) |