Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (8.4 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
def demux(request):
23
    if request.method == 'GET':
24
        #return HttpResponse("in network get")
25
        return list_networks(request)
26
    elif request.method == 'POST':
27
        #return create_network(request)
28
        return HttpResponse("in network post")
29
    else:
30
        return api.api_method_not_allowed(request)
31

    
32
def network_demux(request,offset):
33

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

    
46
@api.api_method(http_method='GET', user_required=True, logger=log)
47
def list_networks(request):
48
    log.debug('list_networks')
49

    
50
    user_networks = Network.objects.filter(Q(userid=request.user_uniq) |
51
            Q(public=True))
52

    
53
    user_networks = user_networks.filter(deleted=False)
54

    
55
    networks = [network_to_dict(network)
56
                for network in user_networks.order_by('id')]
57

    
58
    if request.serialization == 'xml':
59
        data = render_to_string('list_networks.xml', {
60
            'networks': networks })
61
    else:
62
        data = json.dumps({'networks': networks})
63

    
64
    return HttpResponse(data, status=200)
65

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

73
    name: a string specifying a symbolic name for the network, which is not
74
        required to be unique;
75

76
    admin_state_up: a bool value specifying the administrative status of the network;
77

78
    2 more attirbutes for administrative users (not supported)
79
    '''
80

    
81
    try:
82
        user_id = request.user_uniq
83
        if request.raw_post_data:
84
            req = utils.get_request_dict(request)
85
            log.info('create_network %s', req)
86
            try:
87
                 d = req['network']
88
                 name = d['name']
89
            except KeyError:
90
                 raise api.faults.BadRequest("Malformed request")
91

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

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

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

    
136
    except:
137
        transaction.rollback()
138
        log.info("roll")
139
        raise
140
    else:
141
        transaction.commit()
142
        log.info("commit")
143
    networkdict = network_to_dict(network)
144
    response = render_network(request, networkdict, status=201)
145

    
146
    return response
147

    
148
@api.api_method(http_method='GET', user_required=True, logger=log)
149
def get_network(request,network_id):
150
    log.debug('get_network_details %s', network_id)
151
    net = get_network_fromdb(network_id, request.user_uniq)
152

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

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

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

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

    
173
    if net.machines.all():  # Nics attached on network
174
        raise api.faults.NetworkInUse('Machines are connected to network.')
175

    
176
    net.action = 'DESTROY'
177
    net.save()
178
    '''
179
    skip the backend part...
180
    backend_networks = net.backend_networks.exclude(operstate="DELETED")
181
    for bnet in backend_networks:
182
        backend.delete_network(net, bnet.backend)
183
    if not backend_networks:
184
        backend.update_network_state(net)
185
    '''
186

    
187
    #the following has to leave when fix the backend thing
188
    net.deleted = True
189
    net.save()
190

    
191
    return HttpResponse(status=204)
192

    
193

    
194
@api.api_method(http_method='PUT', user_required=True, logger=log)
195
def update_network(request,network_id):
196
    '''
197
    You can update only name and admin_state_up
198
    '''
199
    net = get_network_fromdb(network_id, request.user_uniq, for_update=True)
200
    info = utils.get_request_dict(request)
201

    
202
    updatable = set(["name","admin_state_up"])
203
    try:
204
                new_vals = info["network"]
205
    except Keyerror:
206
        raise api.faults.BadRequest("Malformed request")
207

    
208
    for key,val in new_vals.iteritems():
209
        if key in updatable:
210
            setattr(net,key,val)
211
        else:
212
            raise api.faults.BadRequest("Wrong field update")
213
        net.save()
214
    #net_dic = network_to_dict(net)
215
    #data = json.dumps({"network":net_dic})
216
    netdict = network_to_dict(net)
217
    return render_network(request, netdict, 200)
218

    
219
def network_to_dict(network):
220
    d = {'id': str(network.id), 'name': network.name}
221
    d['links'] = util.network_to_links(network.id)
222
    d['user_id'] = network.userid
223
    d['tenant_id'] = network.userid
224
    d['type'] = network.flavor
225
    d['updated'] = utils.isoformat(network.updated)
226
    d['created'] = utils.isoformat(network.created)
227
    d['status'] = network.state
228
    d['public'] = network.public
229
    d['admin_state_up'] = "true"
230
    subnet_cidr = [s.subnet_id for s in network.subnet_set.all()]
231
    d['subnets'] = subnet_cidr
232
    return d
233

    
234

    
235

    
236

    
237

    
238
def render_network(request, networkdict, status=200):
239
    if request.serialization == 'xml':
240
        data = render_to_string('network.xml', {'network': networkdict})
241
    else:
242
        data = json.dumps({'network': networkdict})
243
    return HttpResponse(data, status=status)
244

    
245

    
246

    
247

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