Statistics
| Branch: | Tag: | Revision:

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)