Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / networks.py @ 95a213d4

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

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

    
40

    
41
def network_demux(request, offset):
42

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

    
55

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

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

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

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

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

    
74
    return HttpResponse(data, status=200)
75

    
76

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

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

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

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

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

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

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

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

    
142
    return response
143

    
144

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

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

    
157

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

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

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

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

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

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

    
192
    #delete all the subnets
193

    
194
    for s in net.subnets.all():
195
        s.deleted = True
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
208
    '''
209
    net = util.get_network(network_id, request.user_uniq, for_update=True)
210
    info = utils.get_request_dict(request)
211

    
212
    updatable = set(["name"])
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, detail=True):
229
    d = {'id': str(network.id), 'name': network.name}
230
    d['links'] = util.network_to_links(network.id)
231
    if detail:
232
        d['user_id'] = network.userid
233
        d['tenant_id'] = network.userid
234
        d['type'] = network.flavor
235
        d['updated'] = utils.isoformat(network.updated)
236
        d['created'] = utils.isoformat(network.created)
237
        d['status'] = network.state
238
        d['public'] = network.public
239
        d['external_router'] = network.external_router
240
        d['external_router'] = network.external_router
241
        d['admin_state_up'] = True
242
        subnet_cidr = [s.id for s in network.subnets.all()]
243
        d['subnets'] = subnet_cidr
244
    return d
245

    
246

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