Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / ports.py @ 9c74cc19

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