Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (7.2 kB)

1
# Copyright 2011-2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
from django.conf import settings
35
from django.conf.urls import patterns
36
from django.http import HttpResponse
37
from django.utils import simplejson as json
38
from django.db import transaction
39
from django.template.loader import render_to_string
40

    
41
from snf_django.lib import api
42

    
43
from synnefo.api import util
44
from synnefo.db.models import NetworkInterface, SecurityGroup, IPAddress
45
from synnefo.logic import ports
46

    
47
from logging import getLogger
48

    
49
log = getLogger(__name__)
50

    
51
urlpatterns = patterns(
52
    'synnefo.api.ports',
53
    (r'^(?:/|.json|.xml)?$', 'demux'),
54
    (r'^/([-\w]+)(?:/|.json|.xml)?$', 'port_demux'))
55

    
56

    
57
def demux(request):
58
    if request.method == 'GET':
59
        return list_ports(request)
60
    elif request.method == 'POST':
61
        return create_port(request)
62
    else:
63
        return api.api_method_not_allowed(request)
64

    
65

    
66
def port_demux(request, port_id):
67

    
68
    if request.method == 'GET':
69
        return get_port_details(request, port_id)
70
    elif request.method == 'DELETE':
71
        return delete_port(request, port_id)
72
    elif request.method == 'PUT':
73
        return update_port(request, port_id)
74
    else:
75
        return api.api_method_not_allowed(request)
76

    
77

    
78
@api.api_method(http_method='GET', user_required=True, logger=log)
79
def list_ports(request, detail=False):
80

    
81
    log.debug('list_ports detail=%s', detail)
82

    
83
    user_ports = NetworkInterface.objects.filter(
84
        network__userid=request.user_uniq)
85

    
86
    port_dicts = [port_to_dict(port, detail)
87
                  for port in user_ports.order_by('id')]
88

    
89
    if request.serialization == 'xml':
90
        data = render_to_string('list_ports.xml', {
91
            "ports": port_dicts})
92
    else:
93
        data = json.dumps({'ports': port_dicts})
94

    
95
    return HttpResponse(data, status=200)
96

    
97

    
98
@api.api_method(http_method='POST', user_required=True, logger=log)
99
def create_port(request):
100
    user_id = request.user_uniq
101
    req = api.utils.get_request_dict(request)
102
    log.info('create_port %s', req)
103

    
104
    port_dict = api.utils.get_attribute(req, "port")
105
    net_id = api.utils.get_attribute(port_dict, "network_id")
106
    dev_id = api.utils.get_attribute(port_dict, "device_id")
107

    
108
    network = util.get_network(net_id, user_id, non_deleted=True)
109

    
110
    if network.public:
111
        raise api.faults.Forbidden('forbidden')
112

    
113
    vm = util.get_vm(dev_id, user_id)
114

    
115
    name = api.utils.get_attribute(port_dict, "name", required=False)
116

    
117
    if name is None:
118
        name = ""
119

    
120
    security_groups = api.utils.get_attribute(port_dict,
121
                                              "security_groups",
122
                                              required=False)
123
    #validate security groups
124
    # like get security group from db
125
    sg_list = []
126
    if security_groups:
127
        for gid in security_groups:
128
            sg = util.get_security_group(int(gid))
129
            sg_list.append(sg)
130

    
131
    new_port = ports.create(network, vm, security_groups=sg_list)
132

    
133
    response = render_port(request, port_to_dict(new_port), status=201)
134

    
135
    return response
136

    
137

    
138
@api.api_method(http_method='GET', user_required=True, logger=log)
139
def get_port_details(request, port_id):
140
    log.debug('get_port_details %s', port_id)
141
    port = util.get_port(port_id, request.user_uniq)
142
    return render_port(request, port_to_dict(port))
143

    
144

    
145
@api.api_method(http_method='PUT', user_required=True, logger=log)
146
def update_port(request, port_id):
147
    '''
148
    You can update only name, security_groups
149
    '''
150
    port = util.get_port(port_id, request.user_uniq, for_update=True)
151
    req = api.utils.get_request_dict(request)
152

    
153
    port_info = api.utils.get_attribute(req, "port", required=True)
154
    name = api.utils.get_attribute(port_info, "name", required=False)
155

    
156
    if name:
157
        port.name = name
158

    
159
    security_groups = api.utils.get_attribute(port_info, "security_groups",
160
                                              required=False)
161
    if security_groups:
162
        sg_list = []
163
        #validate security groups
164
        for gid in security_groups:
165
            sg = util.get_security_group(int(gid))
166
            sg_list.append(sg)
167

    
168
        #clear the old security groups
169
        port.security_groups.clear()
170

    
171
        #add the new groups
172
        port.security_groups.add(*sg_list)
173

    
174
    port.save()
175
    return render_port(request, port_to_dict(port), 200)
176

    
177

    
178
@api.api_method(http_method='DELETE', user_required=True, logger=log)
179
@transaction.commit_on_success
180
def delete_port(request, port_id):
181
    log.info('delete_port %s', port_id)
182
    port = util.get_port(port_id, request.user_uniq, for_update=True)
183
    '''
184
    FIXME delete the port
185
    skip the backend part...
186
    release the ips associated with the port
187
    '''
188
    return HttpResponse(status=204)
189

    
190
#util functions
191

    
192

    
193
def port_to_dict(port, detail=True):
194
    d = {'id': str(port.id), 'name': port.name}
195
    if detail:
196
        d['user_id'] = port.network.userid
197
        d['tenant_id'] = port.network.userid
198
        d['device_id'] = str(port.machine.id)
199
        d['admin_state_up'] = True
200
        d['mac_address'] = port.mac
201
        d['status'] = port.state
202
        d['device_owner'] = port.device_owner
203
        d['network_id'] = str(port.network.id)
204
        d['updated'] = api.utils.isoformat(port.updated)
205
        d['created'] = api.utils.isoformat(port.created)
206
        d['fixed_ips'] = []
207
        for ip in port.ips.all():
208
            d['fixed_ips'].append({"ip_address": ip.address,
209
                                   "subnet": str(ip.subnet.id)})
210
        sg_list = list(port.security_groups.values_list('id', flat=True))
211
        d['security_groups'] = map(str, sg_list)
212

    
213
    return d
214

    
215

    
216
def render_port(request, portdict, status=200):
217
    if request.serialization == 'xml':
218
        data = render_to_string('port.xml', {'port': portdict})
219
    else:
220
        data = json.dumps({'port': portdict})
221
    return HttpResponse(data, status=status)