Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / neutron / network_views.py @ 0dae1b9f

History | View | Annotate | Download (8.5 kB)

1
from django.http import HttpResponse
2
from django.utils import simplejson as json
3
from django.db import transaction
4
from django.db.models import Q
5
from synnefo.db.pools import EmptyPool
6
from synnefo.db.utils import validate_mac
7
from django.conf import settings
8
from snf_django.lib import api
9
from snf_django.lib.api import utils
10
from synnefo.logic import backend
11
from django.template.loader import render_to_string
12
from synnefo.api import util
13
from models import Network
14

    
15
from logging import getLogger
16

    
17
from synnefo import quotas
18

    
19

    
20
log = getLogger(__name__)
21

    
22

    
23
def demux(request):
24
    if request.method == 'GET':
25
        #return HttpResponse("in network get")
26
        return list_networks(request)
27
    elif request.method == 'POST':
28
        return create_network(request)
29
        #return HttpResponse("in network post")
30
    else:
31
        return api.api_method_not_allowed(request)
32

    
33

    
34
def network_demux(request, offset):
35

    
36
    if request.method == 'GET':
37
        return get_network(request, offset)
38
        #return HttpResponse("in network det get")
39
    elif request.method == 'DELETE':
40
        return delete_network(request, offset)
41
        #return HttpResponse("in network det delete")
42
    elif request.method == 'PUT':
43
        return update_network(request, offset)
44
        #return HttpResponse("in network det put")
45
    else:
46
        return api.api_method_not_allowed(request)
47

    
48

    
49
@api.api_method(http_method='GET', user_required=True, logger=log)
50
def list_networks(request):
51
    log.debug('list_networks')
52

    
53
    user_networks = Network.objects.filter(
54
        Q(userid=request.user_uniq) | Q(public=True))
55

    
56
    user_networks = user_networks.filter(deleted=False)
57

    
58
    networks = [network_to_dict(network)
59
                for network in user_networks.order_by('id')]
60

    
61
    if request.serialization == 'xml':
62
        data = render_to_string('list_networks.xml', {
63
            'networks': networks})
64
    else:
65
        data = json.dumps({'networks': networks})
66

    
67
    return HttpResponse(data, status=200)
68

    
69

    
70
@api.api_method(http_method='POST', user_required=True, logger=log)
71
@transaction.commit_manually
72
def create_network(request):
73
    '''
74
    This operation does not require a rest body. If specified, the body might
75
    include one or more of the following attributes:
76

77
    name: a string specifying a symbolic name for the network, which is not
78
        required to be unique;
79

80
    admin_state_up: a bool value specifying the administrative status of
81
        the network;
82

83
    2 more attirbutes for administrative users (not supported)
84
    '''
85
    try:
86
        user_id = request.user_uniq
87
        if request.raw_post_data:
88
            req = utils.get_request_dict(request)
89
            log.info('create_network %s', req)
90
            try:
91
                d = req['network']
92
                name = d['name']
93
            except KeyError:
94
                raise api.faults.BadRequest("Malformed request")
95

    
96
            flavor = d.get("type", None)
97
            if flavor is None:
98
                #raise faults.BadRequest("Missing request parameter 'type'")
99
                # set default flavor
100
                #FIX ME!!!
101
                flavor = "MAC_FILTERED"
102
                log.info("not found flavor")
103
            elif flavor not in Network.FLAVORS.keys():
104
                raise api.faults.BadRequest("Invalid network type '%s'"
105
                                            % flavor)
106
                log.info("found flavor 1")
107
            elif flavor not in settings.API_ENABLED_NETWORK_FLAVORS:
108
                log.info("found flavor2")
109
                msg = "Can not create network of type '%s'"
110
                raise api.faults.Forbidden(msg % flavor)
111
            # Get and validate flavor. Flavors are still exposed
112
            #as 'type' in the API.
113
        else:
114
            name = ""
115
            flavor = "MAC_FILTERED"   # this is the default FIX ME
116

    
117
        try:
118
            #mode, link, mac_prefix, tags = util.values_from_flavor(flavor)
119

    
120
            #validate_mac(mac_prefix + "0:00:00:00")
121
            network = Network.objects.create(
122
                name=name,
123
                userid=user_id,
124
                flavor=flavor,
125
                #mode=mode,
126
                #link=link,
127
                #mac_prefix=mac_prefix,
128
                #tags=tags,
129
                action='CREATE',
130
                state='ACTIVE')
131
        except EmptyPool:
132
            msg = "Failed to allocate resources for network of type: %s"
133
            log.error(msg, flavor)
134
            raise api.faults.ServiceUnavailable("Failed to allocate network\
135
                  resources")
136

    
137
        # Issue commission to Quotaholder and accept it since at the end of
138
        # this transaction the Network object will be created in the DB.
139
        # Note: the following call does a commit!
140
        #quotas.issue_and_accept_commission(network)
141
        # COME BACK....
142

    
143
    except:
144
        transaction.rollback()
145
        log.info("roll")
146
        raise
147
    else:
148
        transaction.commit()
149
        log.info("commit")
150
    networkdict = network_to_dict(network)
151
    response = render_network(request, networkdict, status=201)
152

    
153
    return response
154

    
155

    
156
@api.api_method(http_method='GET', user_required=True, logger=log)
157
def get_network(request, network_id):
158
    log.debug('get_network_details %s', network_id)
159
    net = get_network_fromdb(network_id, request.user_uniq)
160

    
161
    #needs discussion
162
    if net.deleted:
163
        raise api.faults.BadRequest("Network has been deleted.")
164
    else:
165
        netdict = network_to_dict(net)
166
        return render_network(request, netdict)
167

    
168

    
169
@api.api_method(http_method='DELETE', user_required=True, logger=log)
170
@transaction.commit_on_success
171
def delete_network(request, network_id):
172
    log.info('delete_network %s', network_id)
173
    net = get_network_fromdb(network_id, request.user_uniq, for_update=True)
174

    
175
    log.info(net.name)
176
    if net.public:
177
        raise api.faults.Forbidden('Can not delete the public network.')
178

    
179
    if net.deleted:
180
        raise api.faults.BadRequest("Network has been deleted.")
181

    
182
    if net.machines.all():  # Nics attached on network
183
        #raise api.faults.NetworkInUse('Machines are connected to network.')
184
        return HttpResponse("Network in use", status=409)
185

    
186
    net.action = 'DESTROY'
187
    net.save()
188
    '''
189
    skip the backend part...
190
    backend_networks = net.backend_networks.exclude(operstate="DELETED")
191
    for bnet in backend_networks:
192
        backend.delete_network(net, bnet.backend)
193
    if not backend_networks:
194
        backend.update_network_state(net)
195
    '''
196

    
197
    #the following has to leave when fix the backend thing
198
    net.deleted = True
199
    net.save()
200

    
201
    return HttpResponse(status=204)
202

    
203

    
204
@api.api_method(http_method='PUT', user_required=True, logger=log)
205
def update_network(request, network_id):
206
    '''
207
    You can update only name and admin_state_up
208
    '''
209
    net = get_network_fromdb(network_id, request.user_uniq, for_update=True)
210
    info = utils.get_request_dict(request)
211

    
212
    updatable = set(["name", "admin_state_up"])
213
    try:
214
        new_vals = info["network"]
215
    except Keyerror:
216
        raise api.faults.BadRequest("Malformed request")
217

    
218
    for key, val in new_vals.iteritems():
219
        if key in updatable:
220
            setattr(net, key, val)
221
        else:
222
            raise api.faults.BadRequest("Wrong field update")
223
    net.save()
224
    netdict = network_to_dict(net)
225
    return render_network(request, netdict, 200)
226

    
227

    
228
def network_to_dict(network):
229
    d = {'id': str(network.id), 'name': network.name}
230
    d['links'] = util.network_to_links(network.id)
231
    d['user_id'] = network.userid
232
    d['tenant_id'] = network.userid
233
    d['type'] = network.flavor
234
    d['updated'] = utils.isoformat(network.updated)
235
    d['created'] = utils.isoformat(network.created)
236
    d['status'] = network.state
237
    d['public'] = network.public
238
    d['admin_state_up'] = "true"
239
    subnet_cidr = [s.id for s in network.subnet_set.all()]
240
    d['subnets'] = subnet_cidr
241
    return d
242

    
243

    
244
def render_network(request, networkdict, status=200):
245
    if request.serialization == 'xml':
246
        data = render_to_string('network.xml', {'network': networkdict})
247
    else:
248
        data = json.dumps({'network': networkdict})
249
    return HttpResponse(data, status=status)
250

    
251

    
252
def get_network_fromdb(network_id, user_id, for_update=False):
253
    """
254
    Return a Network instance or raise ItemNotFound.
255
    This is the same as util.get_network
256
    """
257
    try:
258
        network_id = int(network_id)
259
        objects = Network.objects
260
        if for_update:
261
            objects = objects.select_for_update()
262
        return objects.get(Q(userid=user_id) | Q(public=True), id=network_id)
263
    except (ValueError, Network.DoesNotExist):
264
        raise api.faults.ItemNotFound('Network not found.')