Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / ports.py @ 5db2001a

History | View | Annotate | Download (8.5 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.db.models import Q
40
from django.template.loader import render_to_string
41

    
42
from snf_django.lib import api
43

    
44
from synnefo.api import util
45
from synnefo.db.models import NetworkInterface, SecurityGroup, IPAddress
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
@transaction.commit_manually
100
def create_port(request):
101
    '''
102
    '''
103
    user_id = request.user_uniq
104
    req = api.utils.get_request_dict(request)
105
    log.info('create_port %s', req)
106
    try:
107
        port_dict = api.utils.get_attribute(req, "port")
108
        net_id = api.utils.get_attribute(port_dict, "network_id")
109
        dev_id = api.utils.get_attribute(port_dict, "device_id")
110

    
111
        network = util.get_network(net_id, request.user_uniq)
112

    
113
        vm = util.get_vm(dev_id, request.user_uniq)
114

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

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

    
120
        sg_list = []
121
        security_groups = api.utils.get_attribute(port_dict,
122
                                                  "security_groups",
123
                                                  required=False)
124
        #validate security groups
125
        # like get security group from db
126
        if security_groups:
127
            for gid in security_groups:
128
                try:
129
                    sg = SecurityGroup.objects.get(id=int(gid))
130
                    sg_list.append(sg)
131
                except (ValueError, SecurityGroup.DoesNotExist):
132
                    raise api.faults.ItemNotFound("Not valid security group")
133

    
134
        #create the port
135
        new_port = NetworkInterface.objects.create(name=name,
136
                                                   network=network,
137
                                                   machine=vm,
138
                                                   device_owner="vm",
139
                                                   state="BUILDING")
140
        #add the security groups
141
        new_port.security_groups.add(*sg_list)
142

    
143
        #add new port to every subnet of the network
144
        for subn in network.subnets.all():
145
            IPAddress.objects.create(subnet=subn,
146
                                     network=network,
147
                                     nic=new_port,
148
                                     userid=user_id,
149
                                     # FIXME
150
                                     address="192.168.0." + str(subn.id))
151

    
152
    except:
153
        transaction.rollback()
154
        log.info("roll")
155
        raise
156

    
157
    else:
158
        transaction.commit()
159
        log.info("commit")
160

    
161
    response = render_port(request, port_to_dict(new_port), status=201)
162

    
163
    return response
164

    
165

    
166
@api.api_method(http_method='GET', user_required=True, logger=log)
167
def get_port_details(request, port_id):
168
    log.debug('get_port_details %s', port_id)
169
    port = util.get_port(port_id, request.user_uniq)
170
    return render_port(request, port_to_dict(port))
171

    
172

    
173
@api.api_method(http_method='PUT', user_required=True, logger=log)
174
def update_port(request, port_id):
175
    '''
176
    You can update only name, security_groups
177
    '''
178
    port = util.get_port(port_id, request.user_uniq, for_update=True)
179
    req = api.utils.get_request_dict(request)
180

    
181
    port_info = api.utils.get_attribute(req, "port", required=True)
182
    name = api.utils.get_attribute(port_info, "name", required=False)
183

    
184
    if name:
185
        port.name = name
186

    
187
    security_groups = api.utils.get_attribute(port_info, "security_groups",
188
                                              required=False)
189
    if security_groups:
190
        sg_list = []
191
        #validate security groups
192
        # like get security group from db
193
        for gid in security_groups:
194
            try:
195
                sg = SecurityGroup.objects.get(id=int(gid))
196
                sg_list.append(sg)
197
            except (ValueError, SecurityGroup.DoesNotExist):
198
                raise api.faults.ItemNotFound("Not valid security group")
199

    
200
        #clear the old security groups
201
        port.security_groups.clear()
202

    
203
        #add the new groups
204
        port.security_groups.add(*sg_list)
205

    
206
    port.save()
207
    return render_port(request, port_to_dict(port), 200)
208

    
209

    
210
@api.api_method(http_method='DELETE', user_required=True, logger=log)
211
@transaction.commit_on_success
212
def delete_port(request, port_id):
213
    log.info('delete_port %s', port_id)
214
    port = util.get_port(port_id, request.user_uniq, for_update=True)
215
    '''
216
    FIXME delete the port
217
    skip the backend part...
218
    release the ips associated with the port
219
    '''
220
    return HttpResponse(status=204)
221

    
222
#util functions
223

    
224

    
225
def port_to_dict(port, detail=True):
226
    d = {'id': str(port.id), 'name': port.name}
227
    if detail:
228
        d['user_id'] = port.network.userid
229
        d['tenant_id'] = port.network.userid
230
        d['device_id'] = str(port.machine.id)
231
        d['admin_state_up'] = True
232
        d['mac_address'] = port.mac
233
        d['status'] = port.state
234
        d['device_owner'] = port.device_owner
235
        d['network_id'] = str(port.network.id)
236
        d['updated'] = api.utils.isoformat(port.updated)
237
        d['created'] = api.utils.isoformat(port.created)
238
        d['fixed_ips'] = []
239
        for ip in port.ips.all():
240
            d['fixed_ips'].append({"ip_address": ip.address,
241
                                      "subnet": str(ip.subnet.id)})
242
        sg_list = list(port.security_groups.values_list('id', flat=True))
243
        d['security_groups'] = map(str, sg_list)
244

    
245
    return d
246

    
247

    
248
def render_port(request, portdict, status=200):
249
    if request.serialization == 'xml':
250
        data = render_to_string('port.xml', {'port': portdict})
251
    else:
252
        data = json.dumps({'port': portdict})
253
    return HttpResponse(data, status=status)