Statistics
| Branch: | Tag: | Revision:

root / admin / views.py @ 404ccab2

History | View | Annotate | Download (12.1 kB)

1
# Copyright 2011 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 functools import wraps
35

    
36
from django.http import HttpResponse
37
from django.shortcuts import redirect
38
from django.template.loader import render_to_string
39

    
40
from synnefo.db import models
41
from synnefo.invitations.invitations import add_invitation, send_invitation
42
from synnefo.logic import backend, log, users
43

    
44

    
45
_log = log.get_logger('synnefo.admin')
46

    
47

    
48
def render(template, tab, **kwargs):
49
    kwargs.setdefault('tab', tab)
50
    return render_to_string(template, kwargs)
51

    
52

    
53
def requires_admin(func):
54
    @wraps(func)
55
    def wrapper(request, *args):
56
        if not request.user or request.user.type != 'ADMIN':
57
            return HttpResponse('Forbidden', status=403)
58
        return func(request, *args)
59
    return wrapper
60

    
61

    
62
def get_filters(request, session_key, all_filters, default=None):
63
    if default is None:
64
        default = all_filters
65
    filters = request.session.get(session_key, default)
66
    filter = request.GET.get('toggle_filter')
67
    if filter:
68
        if filter in filters:
69
            filters.remove(filter)
70
        elif filter in all_filters:
71
            filters.add(filter)
72
        request.session[session_key] = filters
73
    return filters
74

    
75

    
76
@requires_admin
77
def index(request):
78
    stats = {}
79
    stats['users'] = models.SynnefoUser.objects.count()
80
    stats['images'] = models.Image.objects.exclude(state='DELETED').count()
81
    stats['flavors'] = models.Flavor.objects.count()
82
    stats['vms'] = models.VirtualMachine.objects.filter(deleted=False).count()
83
    stats['networks'] = models.Network.objects.exclude(state='DELETED').count()
84
    stats['invitations'] = models.Invitations.objects.count()
85

    
86
    stats['ganeti_instances'] = len(backend.get_ganeti_instances())
87
    stats['ganeti_nodes'] = len(backend.get_ganeti_nodes())
88
    stats['ganeti_jobs'] = len(backend.get_ganeti_jobs())
89

    
90
    images = []
91
    for image in models.Image.objects.exclude(state='DELETED'):
92
        vms = models.VirtualMachine.objects.filter(sourceimage=image)
93
        count = vms.filter(deleted=False).count()
94
        images.append((count, image.name))
95
    images.sort(reverse=True)
96

    
97
    html = render('index.html', 'home', stats=stats, images=images)
98
    return HttpResponse(html)
99

    
100

    
101
@requires_admin
102
def flavors_list(request):
103
    all_states = set(['DELETED'])
104
    default = set()
105
    filters = get_filters(request, 'flavors_filters', all_states, default)
106
    
107
    flavors = models.Flavor.objects.all()
108
    if 'DELETED' not in filters:
109
        flavors = flavors.exclude(deleted=True)
110
    
111
    html = render('flavors_list.html', 'flavors',
112
                    flavors=flavors,
113
                    all_states=sorted(all_states),
114
                    filters=filters)
115
    return HttpResponse(html)
116

    
117

    
118
@requires_admin
119
def flavors_create(request):
120
    if request.method == 'GET':
121
        html = render('flavors_create.html', 'flavors')
122
        return HttpResponse(html)
123
    if request.method == 'POST':
124
        flavor = models.Flavor()
125
        flavor.cpu = int(request.POST.get('cpu'))
126
        flavor.ram = int(request.POST.get('ram'))
127
        flavor.disk = int(request.POST.get('disk'))
128
        flavor.save()
129
        _log.info('User %s created Flavor %s', request.user.name, flavor.name)
130
        return redirect(flavors_info, flavor.id)
131

    
132

    
133
@requires_admin
134
def flavors_info(request, flavor_id):
135
    flavor = models.Flavor.objects.get(id=flavor_id)
136
    html = render('flavors_info.html', 'flavors', flavor=flavor)
137
    return HttpResponse(html)
138

    
139

    
140
@requires_admin
141
def flavors_modify(request, flavor_id):
142
    flavor = models.Flavor.objects.get(id=flavor_id)
143
    flavor.cpu = int(request.POST.get('cpu'))
144
    flavor.ram = int(request.POST.get('ram'))
145
    flavor.disk = int(request.POST.get('disk'))
146
    flavor.deleted = True if request.POST.get('deleted') else False
147
    flavor.save()
148
    _log.info('User %s modified Flavor %s', request.user.name, flavor.name)
149
    return redirect(flavors_info, flavor.id)
150

    
151

    
152
@requires_admin
153
def flavors_delete(request, flavor_id):
154
    flavor = models.Flavor.objects.get(id=flavor_id)
155
    flavor.delete()
156
    _log.info('User %s deleted Flavor %s', request.user.name, flavor.name)
157
    return redirect(flavors_list)
158

    
159

    
160
@requires_admin
161
def images_list(request):
162
    all_states = set(x[0] for x in models.Image.IMAGE_STATES)
163
    default = all_states - set(['DELETED'])
164
    filters = get_filters(request, 'images_filters', all_states, default)
165
    
166
    images = models.Image.objects.all()
167
    for state in all_states - filters:
168
        images = images.exclude(state=state)
169
    
170
    html = render('images_list.html', 'images',
171
                    images=images.order_by('id'),
172
                    all_states=sorted(all_states),
173
                    filters=filters)
174
    return HttpResponse(html)
175

    
176

    
177
@requires_admin
178
def images_register(request):
179
    if request.method == 'GET':
180
        formats = [x[0] for x in models.Image.FORMATS]
181
        html = render('images_register.html', 'images', formats=formats)
182
        return HttpResponse(html)
183
    elif request.method == 'POST':
184
        image = models.Image()
185
        image.state = 'ACTIVE'
186
        image.name = request.POST.get('name')
187
        owner_id = request.POST.get('owner') or None
188
        image.owner = owner_id and models.SynnefoUser.objects.get(id=owner_id)
189
        image.backend_id = request.POST.get('backend')
190
        image.format = request.POST.get('format')
191
        image.public = True if request.POST.get('public') else False
192
        image.save()
193
        _log.info('User %s registered Image %s', request.user.name, image.name)
194
        return redirect(images_info, image.id)
195

    
196

    
197
@requires_admin
198
def images_info(request, image_id):
199
    image = models.Image.objects.get(id=image_id)
200
    states = [x[0] for x in models.Image.IMAGE_STATES]
201
    if not image.state:
202
        states = [''] + states
203
    formats = [x[0] for x in models.Image.FORMATS]
204
    if not image.format:
205
        formats = [''] + formats
206
    
207
    metadata = image.imagemetadata_set.order_by('meta_key')
208
    html = render('images_info.html', 'images',
209
                    image=image,
210
                    states=states,
211
                    formats=formats,
212
                    metadata=metadata)
213
    return HttpResponse(html)
214

    
215

    
216
@requires_admin
217
def images_modify(request, image_id):
218
    image = models.Image.objects.get(id=image_id)
219
    image.name = request.POST.get('name')
220
    image.state = request.POST.get('state')
221
    owner_id = request.POST.get('owner') or None
222
    image.owner = owner_id and models.SynnefoUser.objects.get(id=owner_id)
223
    vm_id = request.POST.get('sourcevm') or None
224
    image.sourcevm = vm_id and models.VirtualMachine.objects.get(id=vm_id)
225
    image.backend_id = request.POST.get('backend')
226
    image.format = request.POST.get('format')
227
    image.public = True if request.POST.get('public') else False
228
    image.save()
229
    
230
    keys = request.POST.getlist('key')
231
    vals = request.POST.getlist('value')
232
    meta = dict(zip(keys, vals))
233
    image.imagemetadata_set.all().delete()
234
    for key, val in meta.items():
235
        if key:
236
            image.imagemetadata_set.create(meta_key=key, meta_value=val)
237
    
238
    _log.info('User %s modified Image %s', request.user.name, image.name)
239

    
240
    return redirect(images_info, image.id)
241

    
242

    
243
@requires_admin
244
def servers_list(request):
245
    all_states = set(x[0] for x in models.VirtualMachine.OPER_STATES)
246
    default = all_states - set(['DESTROYED'])
247
    filters = get_filters(request, 'servers_filters', all_states, default)
248
    
249
    servers = models.VirtualMachine.objects.all()
250
    for state in all_states - filters:
251
        servers = servers.exclude(operstate=state)
252
    
253
    html = render('servers_list.html', 'servers',
254
                    servers=servers.order_by('id'),
255
                    all_states=sorted(all_states),
256
                    filters=filters)
257
    return HttpResponse(html)
258

    
259

    
260
@requires_admin
261
def users_list(request):
262
    all_states = set(x[0] for x in models.SynnefoUser.ACCOUNT_STATE)
263
    default = all_states - set(['DELETED'])
264
    filters = get_filters(request, 'users_filters', all_states, default)
265
    
266
    users = models.SynnefoUser.objects.all()
267
    for state in all_states - filters:
268
        users = users.exclude(state=state)
269
    
270
    html = render('users_list.html', 'users',
271
                    users=users.order_by('id'),
272
                    all_states=sorted(all_states),
273
                    filters=filters)
274
    return HttpResponse(html)
275

    
276

    
277
@requires_admin
278
def users_invite(request):
279
    if request.method == 'GET':
280
        html = render('users_invite.html', 'users')
281
        return HttpResponse(html)
282
    elif request.method == 'POST':
283
        inviter_id = request.POST.get('inviter')
284
        realname = request.POST.get('realname')
285
        uniq = request.POST.get('uniq')
286
        inviter = models.SynnefoUser.objects.get(id=inviter_id)
287
        inv = add_invitation(inviter, realname, uniq)
288
        send_invitation(inv)
289
        _log.info('User %s sent Invitation to %s as %s', request.user.name,
290
                    uniq, inviter.name)
291
        return redirect(users_list)
292

    
293

    
294
@requires_admin
295
def users_info(request, user_id):
296
    user = models.SynnefoUser.objects.get(id=user_id)
297
    types = [x[0] for x in models.SynnefoUser.ACCOUNT_TYPE]
298
    if not user.type:
299
        types = [''] + types
300
    states = [x[0] for x in models.SynnefoUser.ACCOUNT_STATE]
301
    html = render('users_info.html', 'users',
302
                    user=user, types=types, states=states)
303
    return HttpResponse(html)
304

    
305

    
306
@requires_admin
307
def users_modify(request, user_id):
308
    user = models.SynnefoUser.objects.get(id=user_id)
309
    user.name = request.POST.get('name')
310
    user.realname = request.POST.get('realname')
311
    user.uniq = request.POST.get('uniq')
312
    user.credit = int(request.POST.get('credit'))
313
    user.type = request.POST.get('type')
314
    user.state = request.POST.get('state')
315
    invitations = request.POST.get('invitations')
316
    user.max_invitations = int(invitations) if invitations else None
317
    user.save()
318
    _log.info('User %s modified User %s', request.user.name, user.name)
319
    return redirect(users_info, user.id)
320

    
321

    
322
@requires_admin
323
def users_delete(request, user_id):
324
    user = models.SynnefoUser.objects.get(id=user_id)
325
    users.delete_user(user)
326
    _log.info('User %s deleted User %s', request.user.name, user.name)
327
    return redirect(users_list)
328

    
329

    
330
@requires_admin
331
def invitations_list(request):
332
    invitations = models.Invitations.objects.order_by('id')
333
    html = render('invitations_list.html', 'invitations',
334
                     invitations=invitations)
335
    return HttpResponse(html)
336

    
337

    
338
@requires_admin
339
def invitations_resend(request, invitation_id):
340
    invitation = models.Invitations.objects.get(id=invitation_id)
341
    send_invitation(invitation)
342
    _log.info('User %s resent Invitations from %s to %s', request.user.name,
343
                invitation.source.name, invitation.target.name)
344
    return redirect(invitations_list)