Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / networks.py @ 0baa1e3d

History | View | Annotate | Download (7.9 kB)

1
from django.conf import settings
2
from django.conf.urls import patterns
3

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

    
18
from logging import getLogger
19

    
20
from synnefo import quotas
21

    
22
log = getLogger(__name__)
23

    
24
urlpatterns = patterns(
25
    'synnefo.api.networks',
26
     (r'^(?:/|.json|.xml)?$', 'demux'),
27
     (r'^/(\w+)(?:/|.json|.xml)?$', 'network_demux'))
28

    
29
def demux(request):
30
    if request.method == 'GET':
31
        #return HttpResponse("in network get")
32
        return list_networks(request)
33
    elif request.method == 'POST':
34
        return create_network(request)
35
        #return HttpResponse("in network post")
36
    else:
37
        return api.api_method_not_allowed(request)
38

    
39

    
40
def network_demux(request, offset):
41

    
42
    if request.method == 'GET':
43
        return get_network(request, offset)
44
        #return HttpResponse("in network det get")
45
    elif request.method == 'DELETE':
46
        return delete_network(request, offset)
47
        #return HttpResponse("in network det delete")
48
    elif request.method == 'PUT':
49
        return update_network(request, offset)
50
        #return HttpResponse("in network det put")
51
    else:
52
        return api.api_method_not_allowed(request)
53

    
54

    
55
@api.api_method(http_method='GET', user_required=True, logger=log)
56
def list_networks(request, detail=False):
57
    log.debug('list_networks detail=%s', detail)
58

    
59
    user_networks = Network.objects.filter(
60
        Q(userid=request.user_uniq) | Q(public=True))
61

    
62
    user_networks = utils.filter_modified_since(request, objects=user_networks)
63

    
64
    networks = [network_to_dict(network, detail)
65
                for network in user_networks.order_by('id')]
66

    
67
    if request.serialization == 'xml':
68
        data = render_to_string('list_networks.xml', {
69
            "networks": networks})
70
    else:
71
        data = json.dumps({'networks': networks})
72

    
73
    return HttpResponse(data, status=200)
74

    
75

    
76
@api.api_method(http_method='POST', user_required=True, logger=log)
77
@transaction.commit_manually
78
def create_network(request):
79
    try:
80
        user_id = request.user_uniq
81
        req = utils.get_request_dict(request)
82
        log.info('create_network %s', req)
83
        try:
84
            d = req['network']
85
        except KeyError:
86
            raise api.faults.BadRequest("Malformed request")
87

    
88
        try:
89
            flavor = d['type']
90
        except KeyError:
91
            raise faults.BadRequest("Missing request parameter 'type'")
92

    
93
        if flavor not in Network.FLAVORS.keys():
94
            raise api.faults.BadRequest("Invalid network type '%s'"
95
                                        % flavor)
96
        if flavor not in settings.API_ENABLED_NETWORK_FLAVORS:
97
            msg = "Can not create network of type '%s'"
98
            raise api.faults.Forbidden(msg % flavor)
99

    
100
        try:
101
            name = d['name']
102
        except KeyError:
103
            name = ""
104

    
105
        try:
106
            #mode, link, mac_prefix, tags = util.values_from_flavor(flavor)
107

    
108
            #validate_mac(mac_prefix + "0:00:00:00")
109
            network = Network.objects.create(
110
                name=name,
111
                userid=user_id,
112
                flavor=flavor,
113
                #mode=mode,
114
                #link=link,
115
                #mac_prefix=mac_prefix,
116
                #tags=tags,
117
                action='CREATE',
118
                state='ACTIVE')
119
        except EmptyPool:
120
            msg = "Failed to allocate resources for network of type: %s"
121
            log.error(msg, flavor)
122
            raise api.faults.ServiceUnavailable("Failed to allocate network\
123
                  resources")
124

    
125
        # Issue commission to Quotaholder and accept it since at the end of
126
        # this transaction the Network object will be created in the DB.
127
        # Note: the following call does a commit!
128
        #quotas.issue_and_accept_commission(network)
129
        # COME BACK....
130

    
131
    except:
132
        transaction.rollback()
133
        log.info("roll")
134
        raise
135
    else:
136
        transaction.commit()
137
        log.info("commit")
138
    networkdict = network_to_dict(network)
139
    response = render_network(request, networkdict, status=201)
140

    
141
    return response
142

    
143

    
144
@api.api_method(http_method='GET', user_required=True, logger=log)
145
def get_network(request, network_id):
146
    log.debug('get_network_details %s', network_id)
147
    net = util.get_network(network_id, request.user_uniq)
148

    
149
    #needs discussion
150
    if net.deleted:
151
        raise api.faults.BadRequest("Network has been deleted.")
152
    else:
153
        netdict = network_to_dict(net)
154
        return render_network(request, netdict)
155

    
156

    
157
@api.api_method(http_method='DELETE', user_required=True, logger=log)
158
@transaction.commit_on_success
159
def delete_network(request, network_id):
160
    log.info('delete_network %s', network_id)
161
    net = util.get_network(network_id, request.user_uniq, for_update=True)
162

    
163
    log.info(net.name)
164
    if net.public:
165
        raise api.faults.Forbidden('Can not delete the public network.')
166

    
167
    if net.deleted:
168
        raise api.faults.BadRequest("Network has been deleted.")
169

    
170
    if net.machines.all():  # Nics attached on network
171
        #raise api.faults.NetworkInUse('Machines are connected to network.')
172
        #edit to return with 409
173
        return HttpResponse("Network in use", status=409)
174

    
175
    #check if there are any floating ips reserved
176
    #if net.floating_ips.all():
177
    #    #raise api.faults.NetworkInUse('Machines are connected to network.')
178
    #    #edit to return with 409
179
    #    return HttpResponse("Network in use", status=409)
180

    
181
    net.action = 'DESTROY'
182
    '''
183
    skip the backend part...
184
    backend_networks = net.backend_networks.exclude(operstate="DELETED")
185
    for bnet in backend_networks:
186
        backend.delete_network(net, bnet.backend)
187
    if not backend_networks:
188
        backend.update_network_state(net)
189
    '''
190

    
191
    #delete all the subnets
192

    
193
    for s in net.subnets.all():
194
        s.deleted = True
195

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

    
200
    return HttpResponse(status=204)
201

    
202

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

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

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

    
226

    
227
def network_to_dict(network, detail=True):
228
    d = {'id': str(network.id), 'name': network.name}
229
    d['links'] = util.network_to_links(network.id)
230
    if detail:
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['external_router'] = network.external_router
239
        d['external_router'] = network.external_router
240
        d['admin_state_up'] = True
241
        subnet_cidr = [s.id for s in network.subnets.all()]
242
        d['subnets'] = subnet_cidr
243
    return d
244

    
245

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