Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (8.7 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, non_deleted=True)
112

    
113
        if network.public:
114
            raise api.faults.Forbidden('forbidden')
115

    
116
        if network.state != 'ACTIVE':
117
            raise api.faults.Conflict('Network build in process')
118

    
119
        vm = util.get_vm(dev_id, request.user_uniq)
120

    
121
        name = api.utils.get_attribute(port_dict, "name", required=False)
122

    
123
        if name is None:
124
            name = ""
125

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

    
140
        #create the port
141
        new_port = NetworkInterface.objects.create(name=name,
142
                                                   network=network,
143
                                                   machine=vm,
144
                                                   device_owner="vm",
145
                                                   state="BUILDING")
146
        #add the security groups
147
        new_port.security_groups.add(*sg_list)
148

    
149
        #add new port to every subnet of the network
150
        for subn in network.subnets.all():
151
            IPAddress.objects.create(subnet=subn,
152
                                     network=network,
153
                                     nic=new_port,
154
                                     userid=user_id,
155
                                     # FIXME
156
                                     address="192.168.0." + str(subn.id))
157

    
158
    except:
159
        transaction.rollback()
160
        log.info("roll")
161
        raise
162

    
163
    else:
164
        transaction.commit()
165
        log.info("commit")
166

    
167
    response = render_port(request, port_to_dict(new_port), status=201)
168

    
169
    return response
170

    
171

    
172
@api.api_method(http_method='GET', user_required=True, logger=log)
173
def get_port_details(request, port_id):
174
    log.debug('get_port_details %s', port_id)
175
    port = util.get_port(port_id, request.user_uniq)
176
    return render_port(request, port_to_dict(port))
177

    
178

    
179
@api.api_method(http_method='PUT', user_required=True, logger=log)
180
def update_port(request, port_id):
181
    '''
182
    You can update only name, security_groups
183
    '''
184
    port = util.get_port(port_id, request.user_uniq, for_update=True)
185
    req = api.utils.get_request_dict(request)
186

    
187
    port_info = api.utils.get_attribute(req, "port", required=True)
188
    name = api.utils.get_attribute(port_info, "name", required=False)
189

    
190
    if name:
191
        port.name = name
192

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

    
206
        #clear the old security groups
207
        port.security_groups.clear()
208

    
209
        #add the new groups
210
        port.security_groups.add(*sg_list)
211

    
212
    port.save()
213
    return render_port(request, port_to_dict(port), 200)
214

    
215

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

    
228
#util functions
229

    
230

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

    
251
    return d
252

    
253

    
254
def render_port(request, portdict, status=200):
255
    if request.serialization == 'xml':
256
        data = render_to_string('port.xml', {'port': portdict})
257
    else:
258
        data = json.dumps({'port': portdict})
259
    return HttpResponse(data, status=status)