Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / ports.py @ 8b178e6b

History | View | Annotate | Download (7.9 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 86961519 Christos Stavrakakis
#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.template.loader import render_to_string
40 5db2001a Marios Kogias
41 5db2001a Marios Kogias
from snf_django.lib import api
42 5db2001a Marios Kogias
43 593851e0 Buildbot
from synnefo.api import util
44 86961519 Christos Stavrakakis
from synnefo.db.models import NetworkInterface
45 f16aa9e6 Marios Kogias
from synnefo.logic import ports
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 86961519 Christos Stavrakakis
        machine__userid=request.user_uniq)
85 593851e0 Buildbot
86 5db2001a Marios Kogias
    port_dicts = [port_to_dict(port, detail)
87 9f6760ee Christos Stavrakakis
                  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
def create_port(request):
100 593851e0 Buildbot
    user_id = request.user_uniq
101 5db2001a Marios Kogias
    req = api.utils.get_request_dict(request)
102 593851e0 Buildbot
    log.info('create_port %s', req)
103 593851e0 Buildbot
104 f16aa9e6 Marios Kogias
    port_dict = api.utils.get_attribute(req, "port")
105 f16aa9e6 Marios Kogias
    net_id = api.utils.get_attribute(port_dict, "network_id")
106 f16aa9e6 Marios Kogias
    dev_id = api.utils.get_attribute(port_dict, "device_id")
107 f16aa9e6 Marios Kogias
108 9f6760ee Christos Stavrakakis
    network = util.get_network(net_id, user_id, non_deleted=True)
109 f16aa9e6 Marios Kogias
110 9c74cc19 Marios Kogias
    ipaddress = None
111 f16aa9e6 Marios Kogias
    if network.public:
112 9c74cc19 Marios Kogias
        fixed_ips = api.utils.get_attribute(port_dict, "fixed_ips",
113 9c74cc19 Marios Kogias
                                            required=True)
114 9c74cc19 Marios Kogias
        fip_address = api.utils.get_attribute(fixed_ips[0], 'ip_address',
115 9c74cc19 Marios Kogias
                                              required=True)
116 9c74cc19 Marios Kogias
        ipaddress = util.get_floating_ip_by_address(user_id, fip_address,
117 b968e8e6 Christos Stavrakakis
                                                    for_update=True)
118 9c74cc19 Marios Kogias
        if ipaddress.network.id != network.id:
119 b968e8e6 Christos Stavrakakis
            raise api.faults.Conflict("Floating IP address %s does not belong"
120 8b388efe Christos Stavrakakis
                                      " to network %s."
121 8b388efe Christos Stavrakakis
                                      % (fip_address, net_id))
122 f16aa9e6 Marios Kogias
123 b968e8e6 Christos Stavrakakis
    vm = util.get_vm(dev_id, user_id, for_update=True, non_deleted=True,
124 b968e8e6 Christos Stavrakakis
                     non_suspended=True)
125 f16aa9e6 Marios Kogias
126 f16aa9e6 Marios Kogias
    name = api.utils.get_attribute(port_dict, "name", required=False)
127 f16aa9e6 Marios Kogias
    if name is None:
128 f16aa9e6 Marios Kogias
        name = ""
129 f16aa9e6 Marios Kogias
130 f16aa9e6 Marios Kogias
    security_groups = api.utils.get_attribute(port_dict,
131 f16aa9e6 Marios Kogias
                                              "security_groups",
132 f16aa9e6 Marios Kogias
                                              required=False)
133 f16aa9e6 Marios Kogias
    #validate security groups
134 f16aa9e6 Marios Kogias
    # like get security group from db
135 a1713485 Marios Kogias
    sg_list = []
136 f16aa9e6 Marios Kogias
    if security_groups:
137 f16aa9e6 Marios Kogias
        for gid in security_groups:
138 a1713485 Marios Kogias
            sg = util.get_security_group(int(gid))
139 a1713485 Marios Kogias
            sg_list.append(sg)
140 f16aa9e6 Marios Kogias
141 9c74cc19 Marios Kogias
    new_port = ports.create(network, vm, ipaddress, security_groups=sg_list)
142 593851e0 Buildbot
143 5db2001a Marios Kogias
    response = render_port(request, port_to_dict(new_port), status=201)
144 593851e0 Buildbot
145 593851e0 Buildbot
    return response
146 593851e0 Buildbot
147 593851e0 Buildbot
148 5db2001a Marios Kogias
@api.api_method(http_method='GET', user_required=True, logger=log)
149 5db2001a Marios Kogias
def get_port_details(request, port_id):
150 5db2001a Marios Kogias
    log.debug('get_port_details %s', port_id)
151 5db2001a Marios Kogias
    port = util.get_port(port_id, request.user_uniq)
152 5db2001a Marios Kogias
    return render_port(request, port_to_dict(port))
153 5db2001a Marios Kogias
154 5db2001a Marios Kogias
155 5db2001a Marios Kogias
@api.api_method(http_method='PUT', user_required=True, logger=log)
156 5db2001a Marios Kogias
def update_port(request, port_id):
157 5db2001a Marios Kogias
    '''
158 5db2001a Marios Kogias
    You can update only name, security_groups
159 5db2001a Marios Kogias
    '''
160 5db2001a Marios Kogias
    port = util.get_port(port_id, request.user_uniq, for_update=True)
161 5db2001a Marios Kogias
    req = api.utils.get_request_dict(request)
162 5db2001a Marios Kogias
163 5db2001a Marios Kogias
    port_info = api.utils.get_attribute(req, "port", required=True)
164 5db2001a Marios Kogias
    name = api.utils.get_attribute(port_info, "name", required=False)
165 5db2001a Marios Kogias
166 5db2001a Marios Kogias
    if name:
167 5db2001a Marios Kogias
        port.name = name
168 5db2001a Marios Kogias
169 5db2001a Marios Kogias
    security_groups = api.utils.get_attribute(port_info, "security_groups",
170 5db2001a Marios Kogias
                                              required=False)
171 5db2001a Marios Kogias
    if security_groups:
172 5db2001a Marios Kogias
        sg_list = []
173 5db2001a Marios Kogias
        #validate security groups
174 5db2001a Marios Kogias
        for gid in security_groups:
175 a1713485 Marios Kogias
            sg = util.get_security_group(int(gid))
176 a1713485 Marios Kogias
            sg_list.append(sg)
177 5db2001a Marios Kogias
178 5db2001a Marios Kogias
        #clear the old security groups
179 5db2001a Marios Kogias
        port.security_groups.clear()
180 5db2001a Marios Kogias
181 5db2001a Marios Kogias
        #add the new groups
182 5db2001a Marios Kogias
        port.security_groups.add(*sg_list)
183 5db2001a Marios Kogias
184 5db2001a Marios Kogias
    port.save()
185 5db2001a Marios Kogias
    return render_port(request, port_to_dict(port), 200)
186 5db2001a Marios Kogias
187 5db2001a Marios Kogias
188 5db2001a Marios Kogias
@api.api_method(http_method='DELETE', user_required=True, logger=log)
189 5db2001a Marios Kogias
@transaction.commit_on_success
190 5db2001a Marios Kogias
def delete_port(request, port_id):
191 5db2001a Marios Kogias
    log.info('delete_port %s', port_id)
192 86961519 Christos Stavrakakis
    user_id = request.user_uniq
193 86961519 Christos Stavrakakis
    port = util.get_port(port_id, user_id, for_update=True)
194 86961519 Christos Stavrakakis
    ports.delete(port)
195 5db2001a Marios Kogias
    return HttpResponse(status=204)
196 5db2001a Marios Kogias
197 593851e0 Buildbot
#util functions
198 593851e0 Buildbot
199 593851e0 Buildbot
200 593851e0 Buildbot
def port_to_dict(port, detail=True):
201 593851e0 Buildbot
    d = {'id': str(port.id), 'name': port.name}
202 593851e0 Buildbot
    if detail:
203 86961519 Christos Stavrakakis
        user_id = port.machine.id
204 86961519 Christos Stavrakakis
        d['user_id'] = user_id
205 86961519 Christos Stavrakakis
        d['tenant_id'] = user_id
206 593851e0 Buildbot
        d['device_id'] = str(port.machine.id)
207 86961519 Christos Stavrakakis
        # TODO: Change this based on the status of VM
208 593851e0 Buildbot
        d['admin_state_up'] = True
209 593851e0 Buildbot
        d['mac_address'] = port.mac
210 593851e0 Buildbot
        d['status'] = port.state
211 593851e0 Buildbot
        d['device_owner'] = port.device_owner
212 593851e0 Buildbot
        d['network_id'] = str(port.network.id)
213 5db2001a Marios Kogias
        d['updated'] = api.utils.isoformat(port.updated)
214 5db2001a Marios Kogias
        d['created'] = api.utils.isoformat(port.created)
215 593851e0 Buildbot
        d['fixed_ips'] = []
216 593851e0 Buildbot
        for ip in port.ips.all():
217 593851e0 Buildbot
            d['fixed_ips'].append({"ip_address": ip.address,
218 9f6760ee Christos Stavrakakis
                                   "subnet": str(ip.subnet.id)})
219 5db2001a Marios Kogias
        sg_list = list(port.security_groups.values_list('id', flat=True))
220 5db2001a Marios Kogias
        d['security_groups'] = map(str, sg_list)
221 5db2001a Marios Kogias
222 593851e0 Buildbot
    return d
223 593851e0 Buildbot
224 593851e0 Buildbot
225 593851e0 Buildbot
def render_port(request, portdict, status=200):
226 593851e0 Buildbot
    if request.serialization == 'xml':
227 5db2001a Marios Kogias
        data = render_to_string('port.xml', {'port': portdict})
228 593851e0 Buildbot
    else:
229 593851e0 Buildbot
        data = json.dumps({'port': portdict})
230 593851e0 Buildbot
    return HttpResponse(data, status=status)