Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (7.9 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("Floating IP address %s does not belong"
120
                                      " to network %s."
121
                                      % (fip_address, net_id))
122

    
123
    vm = util.get_vm(dev_id, user_id, for_update=True, non_deleted=True,
124
                     non_suspended=True)
125

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

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

    
141
    new_port = ports.create(network, vm, ipaddress, security_groups=sg_list)
142

    
143
    response = render_port(request, port_to_dict(new_port), status=201)
144

    
145
    return response
146

    
147

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

    
154

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

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

    
166
    if name:
167
        port.name = name
168

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

    
178
        #clear the old security groups
179
        port.security_groups.clear()
180

    
181
        #add the new groups
182
        port.security_groups.add(*sg_list)
183

    
184
    port.save()
185
    return render_port(request, port_to_dict(port), 200)
186

    
187

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

    
197
#util functions
198

    
199

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

    
222
    return d
223

    
224

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