Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (7.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.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
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
        machine__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
    ipaddress = None
111
    if network.public:
112
        fixed_ips = api.utils.get_attribute(port_dict, "fixed_ips",
113
                                            required=True)
114
        fip_address = api.utils.get_attribute(fixed_ips[0], 'ip_address',
115
                                              required=True)
116
        ipaddress = util.get_floating_ip_by_address(user_id, fip_address,
117
                                                      for_update=True)
118
        if ipaddress.network.id != network.id:
119
            raise api.faults.Conflict("The given ip is not on the \
120
                                       given network")
121

    
122
    vm = util.get_vm(dev_id, user_id, non_deleted=True, non_suspended=True)
123

    
124
    name = api.utils.get_attribute(port_dict, "name", required=False)
125
    if name is None:
126
        name = ""
127

    
128
    security_groups = api.utils.get_attribute(port_dict,
129
                                              "security_groups",
130
                                              required=False)
131
    #validate security groups
132
    # like get security group from db
133
    sg_list = []
134
    if security_groups:
135
        for gid in security_groups:
136
            sg = util.get_security_group(int(gid))
137
            sg_list.append(sg)
138

    
139
    new_port = ports.create(network, vm, ipaddress, security_groups=sg_list)
140

    
141
    response = render_port(request, port_to_dict(new_port), status=201)
142

    
143
    return response
144

    
145

    
146
@api.api_method(http_method='GET', user_required=True, logger=log)
147
def get_port_details(request, port_id):
148
    log.debug('get_port_details %s', port_id)
149
    port = util.get_port(port_id, request.user_uniq)
150
    return render_port(request, port_to_dict(port))
151

    
152

    
153
@api.api_method(http_method='PUT', user_required=True, logger=log)
154
def update_port(request, port_id):
155
    '''
156
    You can update only name, security_groups
157
    '''
158
    port = util.get_port(port_id, request.user_uniq, for_update=True)
159
    req = api.utils.get_request_dict(request)
160

    
161
    port_info = api.utils.get_attribute(req, "port", required=True)
162
    name = api.utils.get_attribute(port_info, "name", required=False)
163

    
164
    if name:
165
        port.name = name
166

    
167
    security_groups = api.utils.get_attribute(port_info, "security_groups",
168
                                              required=False)
169
    if security_groups:
170
        sg_list = []
171
        #validate security groups
172
        for gid in security_groups:
173
            sg = util.get_security_group(int(gid))
174
            sg_list.append(sg)
175

    
176
        #clear the old security groups
177
        port.security_groups.clear()
178

    
179
        #add the new groups
180
        port.security_groups.add(*sg_list)
181

    
182
    port.save()
183
    return render_port(request, port_to_dict(port), 200)
184

    
185

    
186
@api.api_method(http_method='DELETE', user_required=True, logger=log)
187
@transaction.commit_on_success
188
def delete_port(request, port_id):
189
    log.info('delete_port %s', port_id)
190
    user_id = request.user_uniq
191
    port = util.get_port(port_id, user_id, for_update=True)
192
    ports.delete(port)
193
    return HttpResponse(status=204)
194

    
195
#util functions
196

    
197

    
198
def port_to_dict(port, detail=True):
199
    d = {'id': str(port.id), 'name': port.name}
200
    if detail:
201
        user_id = port.machine.id
202
        d['user_id'] = user_id
203
        d['tenant_id'] = user_id
204
        d['device_id'] = str(port.machine.id)
205
        # TODO: Change this based on the status of VM
206
        d['admin_state_up'] = True
207
        d['mac_address'] = port.mac
208
        d['status'] = port.state
209
        d['device_owner'] = port.device_owner
210
        d['network_id'] = str(port.network.id)
211
        d['updated'] = api.utils.isoformat(port.updated)
212
        d['created'] = api.utils.isoformat(port.created)
213
        d['fixed_ips'] = []
214
        for ip in port.ips.all():
215
            d['fixed_ips'].append({"ip_address": ip.address,
216
                                   "subnet": str(ip.subnet.id)})
217
        sg_list = list(port.security_groups.values_list('id', flat=True))
218
        d['security_groups'] = map(str, sg_list)
219

    
220
    return d
221

    
222

    
223
def render_port(request, portdict, status=200):
224
    if request.serialization == 'xml':
225
        data = render_to_string('port.xml', {'port': portdict})
226
    else:
227
        data = json.dumps({'port': portdict})
228
    return HttpResponse(data, status=status)