Commit f2577fb3 by Őry Máté

one: enforce pep8 and others

parent 1b2fb7a6
from django.contrib import messages
from django.core.exceptions import ValidationError
from django import contrib
from django.utils.translation import ugettext_lazy as _
from one import models
import string
import school.models
def owner_person(obj):
p = obj.owner
return "%s %s (%s)" % (p.last_name, p.first_name, p.username)
owner_person.short_description = _('owner')
class PersonInline(contrib.admin.StackedInline):
model = models.Person
model = school.models.Person
max_num = 1
can_delete = False
class SshKeyInline(contrib.admin.TabularInline):
model = models.SshKey
extra = 2
class DetailsInline(contrib.admin.StackedInline):
model = models.UserCloudDetails
max_num = 1
can_delete = False
class MyUserAdmin(contrib.auth.admin.UserAdmin):
list_display = ('username', 'full_name', 'email', 'date_joined', 'instance_count', 'course_groups')
list_filter = ('is_superuser', 'is_active', 'groups', 'person__course_groups', )
class MyUserAdmin(contrib.auth.admin.UserAdmin):
list_display = ('username', 'full_name', 'email',
'date_joined', 'instance_count', 'course_groups')
list_filter = ('is_superuser', 'is_active',
'groups', 'person__course_groups', )
def __init__(self, *args, **kwargs):
super(MyUserAdmin, self).__init__(*args, **kwargs)
add = [PersonInline, SshKeyInline, DetailsInline, ]
try:
inlines = inlines + (PersonInline, SshKeyInline, DetailsInline)
inlines = self.inlines
except NameError:
inlines = (PersonInline, SshKeyInline, DetailsInline)
inlines = list()
self.inlines = inlines + add
def instance_count(self, obj):
return _("%(sum)d (%(active)d active)") % { 'sum': obj.instance_set.count(),
'active' :obj.instance_set.filter(state='ACTIVE').count(), }
return _("%(sum)d (%(active)d active)") % {
'sum': obj.instance_set.count(),
'active': obj.instance_set.filter(state='ACTIVE').count(), }
def course_groups(self, obj):
try:
......@@ -48,31 +61,35 @@ class MyUserAdmin(contrib.auth.admin.UserAdmin):
ordering = ["-date_joined"]
contrib.admin.site.unregister(contrib.auth.models.User)
contrib.admin.site.register(contrib.auth.models.User, MyUserAdmin)
def update_state(modeladmin, request, queryset):
for i in queryset.all():
i.update_state()
update_state.short_description = _('Update status')
def submit_vm(modeladmin, request, queryset):
for i in queryset.all():
i.submit(request.user)
i.update_state()
submit_vm.short_description = _('Submit VM')
def delete_vm(modeladmin, request, queryset):
for i in queryset.exclude(state='DONE').all():
i.one_delete()
delete_vm.short_description = _('Delete VM')
def suspend_vm(modeladmin, request, queryset):
for i in queryset.filter(state='ACTIVE').all():
i.stop()
suspend_vm.short_description = _('Suspend VM')
def resume_vm(modeladmin, request, queryset):
for i in queryset.filter(state__in=('STOPPED', 'SUSPENDED')).all():
i.resume()
......@@ -80,21 +97,24 @@ resume_vm.short_description = _('Resume VM')
class TemplateAdmin(contrib.admin.ModelAdmin):
model=models.Template
model = models.Template
list_display = ('name', 'state', owner_person, 'system', 'public')
list_filter = ('owner', 'public')
class InstanceAdmin(contrib.admin.ModelAdmin):
model=models.Instance
model = models.Instance
actions = [update_state, submit_vm, delete_vm, suspend_vm, resume_vm]
list_display = ('id', 'name', owner_person, 'state')
readonly_fields = ('ip', 'active_since', 'pw', 'template')
list_filter = ('owner', 'template', 'state')
def queryset(self, request):
return super(InstanceAdmin, self).queryset(request)
class DiskAdmin(contrib.admin.ModelAdmin):
model=models.Disk
model = models.Disk
list_display = ('name', 'used_by')
def used_by(self, obj):
......@@ -104,12 +124,14 @@ class DiskAdmin(contrib.admin.ModelAdmin):
return None
used_by.verbose_name = _('used by')
class NetworkAdmin(contrib.admin.ModelAdmin):
model=models.Network
model = models.Network
list_display = ('name', 'nat', 'public', 'get_vlan')
class ShareAdmin(contrib.admin.ModelAdmin):
model=models.Network
model = models.Network
list_filter = ('group', 'template', )
list_display = ('name', owner_person, 'template', 'group', )
......@@ -119,4 +141,3 @@ contrib.admin.site.register(models.Network, NetworkAdmin)
contrib.admin.site.register(models.Disk, DiskAdmin)
contrib.admin.site.register(models.Share, ShareAdmin)
contrib.admin.site.register(models.InstanceType)
......@@ -2,20 +2,21 @@
from datetime import datetime
from datetime import timedelta as td
import subprocess, tempfile, os, stat, re, base64, struct, logging
import base64
import struct
import logging
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.core import signing
from django.db import models
from django.db import transaction
from django.db.models.signals import post_delete, pre_delete
from django.db.models.signals import post_save
from django import forms
from django.db.models.signals import post_save, pre_delete
from django.template.defaultfilters import escape
from django.utils.translation import ugettext_lazy as _
from firewall.models import Host, Rule, Vlan, Record
from school.models import Person, Group
from firewall.models import Host, Vlan
from school.models import Group
from store.api import StoreApi
from .util import keygen
import django.conf
......@@ -25,6 +26,7 @@ CLOUD_URL = django.conf.settings.CLOUD_URL
logger = logging.getLogger(__name__)
pwgen = User.objects.make_random_password
def create_user_profile(sender, instance, created, **kwargs):
"""User creation hook: create cloud details object"""
if created:
......@@ -34,27 +36,33 @@ def create_user_profile(sender, instance, created, **kwargs):
post_save.connect(create_user_profile, sender=User)
class UserCloudDetails(models.Model):
"""Cloud related details of a user."""
user = models.OneToOneField(User, verbose_name=_('user'),
related_name='cloud_details')
smb_password = models.CharField(max_length=20,
verbose_name=_('Samba password'),
help_text=_('Generated password for accessing store from '
help_text=_('Generated password for '
'accessing store from '
'Windows.'))
ssh_key = models.ForeignKey('SshKey', verbose_name=_('SSH key (public)'),
null=True, blank=True, related_name='userclouddetails_set',
help_text=_('Generated SSH public key for accessing store from '
'Linux.'))
ssh_private_key = models.TextField(verbose_name=_('SSH key (private)'),
blank=True, help_text=_('Generated SSH private key for '
null=True, blank=True,
related_name='userclouddetails_set',
help_text=_('Generated SSH public key for '
'accessing store from Linux.'))
ssh_private_key = models.TextField(verbose_name=_('SSH key (private)'),
blank=True,
help_text=_('Generated SSH private key '
'for accessing store from '
'Linux.'))
share_quota = models.IntegerField(verbose_name=_('share quota'),
default=0)
instance_quota = models.IntegerField(verbose_name=_('instance quota'),
default=20)
disk_quota = models.IntegerField(verbose_name=_('disk quota'),
default=2048, help_text=_('Disk quota in mebibytes.'))
default=2048,
help_text=_('Disk quota in mebibytes.'))
def reset_keys(self):
"""Delete old SSH key pair and generate new one."""
......@@ -79,16 +87,20 @@ class UserCloudDetails(models.Model):
if i.state in ('ACTIVE', 'PENDING', ):
c = c + i.template.instance_type.credit
return c
def get_instance_pc(self):
return 100 * self.get_weighted_instance_count() / self.instance_quota
def get_weighted_share_count(self):
c = 0
for i in Share.objects.filter(owner=self.user).all():
c = c + i.template.instance_type.credit * i.instance_limit
return c
def get_share_pc(self):
return 100 * self.get_weighted_share_count() / self.share_quota
def set_quota(sender, instance, created, **kwargs):
if not StoreApi.userexist(instance.user.username):
try:
......@@ -108,6 +120,7 @@ def set_quota(sender, instance, created, **kwargs):
instance.disk_quota * 1024)
post_save.connect(set_quota, sender=UserCloudDetails)
def reset_keys(sender, instance, created, **kwargs):
if created:
instance.reset_smb()
......@@ -115,6 +128,7 @@ def reset_keys(sender, instance, created, **kwargs):
post_save.connect(reset_keys, sender=UserCloudDetails)
class OpenSshKeyValidator(object):
"""Validate OpenSSH keys (length and type)."""
valid_types = ['ssh-rsa', 'ssh-dsa']
......@@ -133,21 +147,23 @@ class OpenSshKeyValidator(object):
data = base64.decodestring(key_string)
int_len = 4
str_len = struct.unpack('>I', data[:int_len])[0]
if not data[int_len:int_len+str_len] == type:
if not data[int_len:(int_len + str_len)] == type:
raise
except ValidationError:
raise
except:
raise ValidationError(_('Invalid OpenSSH public key.'))
class SshKey(models.Model):
"""SSH public key (in OpenSSH format)."""
user = models.ForeignKey(User, related_name='sshkey_set')
key = models.TextField(verbose_name=_('SSH key'),
help_text=_('<a href="/info/ssh/">SSH public key in OpenSSH '
'format</a> used for shell and store login '
'(2048+ bit RSA preferred). Example: '
'<code>ssh-rsa AAAAB...QtQ== john</code>.'),
help_text=_('<a href="/info/ssh/">SSH public key '
'in OpenSSH format</a> used for shell '
'and store login (2048+ bit RSA '
'preferred). Example: <code>ssh-rsa '
'AAAAB...QtQ== john</code>.'),
validators=[OpenSshKeyValidator()])
def __unicode__(self):
......@@ -164,7 +180,7 @@ TYPES = {"LAB": {"verbose_name": _('lab'), "id": "LAB",
"suspend": td(hours=5), "delete": td(days=15),
"help_text": _('For lab or homework with short lifetime.')},
"PROJECT": {"verbose_name": _('project'), "id": "PROJECT",
"suspend": td(weeks=5), "delete": td(days=366/2),
"suspend": td(weeks=5), "delete": td(days=366 / 2),
"help_text": _('For project work.')},
"SERVER": {"verbose_name": _('server'), "id": "SERVER",
"suspend": td(days=365), "delete": None,
......@@ -174,6 +190,7 @@ DEFAULT_TYPE = TYPES['LAB']
TYPES_L = sorted(TYPES.values(), key=lambda m: m["suspend"])
TYPES_C = tuple([(i[0], i[1]["verbose_name"]) for i in TYPES.items()])
class Share(models.Model):
name = models.CharField(max_length=100, verbose_name=_('name'))
description = models.TextField(verbose_name=_('description'))
......@@ -183,12 +200,15 @@ class Share(models.Model):
verbose_name=_('created at'))
type = models.CharField(choices=TYPES_C, max_length=10)
instance_limit = models.IntegerField(verbose_name=_('instance limit'),
help_text=_('Maximal count of instances launchable for this '
'share.'))
help_text=_('Maximal count of '
'instances launchable '
'for this share.'))
per_user_limit = models.IntegerField(verbose_name=_('per user limit'),
help_text=_('Maximal count of instances launchable by a single '
'user.'))
owner = models.ForeignKey(User, null=True, blank=True, related_name='share_set')
help_text=_('Maximal count of '
'instances launchable by '
'a single user.'))
owner = models.ForeignKey(
User, null=True, blank=True, related_name='share_set')
class Meta:
ordering = ['group', 'template', 'owner', ]
......@@ -233,6 +253,7 @@ class Share(models.Model):
def get_used_quota(self):
return self.template.get_credits_per_instance() * self.instance_limit
class Disk(models.Model):
"""Virtual disks automatically synchronized with OpenNebula."""
name = models.CharField(max_length=100, unique=True,
......@@ -270,21 +291,23 @@ class Disk(models.Model):
if delete:
Disk.objects.exclude(id__in=l).delete()
class Network(models.Model):
"""Virtual networks automatically synchronized with OpenNebula."""
name = models.CharField(max_length=100, unique=True,
verbose_name=_('name'))
nat = models.BooleanField(verbose_name=_('NAT'),
help_text=_('If network address translation is done.'))
help_text=_('If network address translation is '
'done.'))
public = models.BooleanField(verbose_name=_('public'),
help_text=_('If internet gateway is available.'))
help_text=_('If internet gateway is '
'available.'))
class Meta:
ordering = ['name']
verbose_name = _('network')
verbose_name_plural = _('networks')
def __unicode__(self):
return self.name
......@@ -310,6 +333,7 @@ class Network(models.Model):
pass
l.append(id)
Network.objects.exclude(id__in=l).delete()
def get_vlan(self):
return Vlan.objects.get(vid=self.id)
......@@ -333,15 +357,20 @@ class InstanceType(models.Model):
TEMPLATE_STATES = (('NEW', _('new')), ('SAVING', _('saving')),
('READY', _('ready')), )
class Template(models.Model):
"""Virtual machine template specifying OS, disk, type and network."""
name = models.CharField(max_length=100, unique=True,
verbose_name=_('name'))
access_type = models.CharField(max_length=10,
choices=[('rdp', 'rdp'), ('nx', 'nx'), ('ssh', 'ssh')],
choices=[('rdp', 'rdp'), (
'nx', 'nx'), ('ssh', 'ssh')],
verbose_name=_('access method'))
disk = models.ForeignKey(Disk, verbose_name=_('disk'), related_name='template_set')
instance_type = models.ForeignKey(InstanceType, related_name='template_set',
disk = models.ForeignKey(Disk, verbose_name=_(
'disk'), related_name='template_set')
instance_type = models.ForeignKey(
InstanceType, related_name='template_set',
verbose_name=_('instance type'))
network = models.ForeignKey(Network, verbose_name=_('network'),
related_name='template_set')
......@@ -352,10 +381,12 @@ class Template(models.Model):
state = models.CharField(max_length=10, choices=TEMPLATE_STATES,
default='NEW')
public = models.BooleanField(verbose_name=_('public'), default=False,
help_text=_('If other users can derive templates of this one.'))
help_text=_('If other users can derive '
'templates of this one.'))
description = models.TextField(verbose_name=_('description'), blank=True)
system = models.TextField(verbose_name=_('operating system'), blank=True,
help_text=(_('Name of operating system in format like "%s".') %
help_text=(_('Name of operating system in '
'format like "%s".') %
"Ubuntu 12.04 LTS Desktop amd64"))
class Meta:
......@@ -363,7 +394,6 @@ class Template(models.Model):
verbose_name_plural = _('templates')
ordering = ['name', ]
def __unicode__(self):
return self.name
......@@ -396,20 +426,19 @@ class Template(models.Model):
else:
return shares
def get_share_quota_usage_for(self, user=None):
shares = self.get_shares_for(user)
usage = 0
for share in shares:
usage += share.instance_limit * self.get_credits_per_instance()
return usage
def get_share_quota_usage_for(self, user=None, type=None):
if type is None:
c = self.get_credits_per_instance()
else:
c = type.credit
def get_share_quota_usage_for_user_with_type(self, type, user=None):
shares = self.get_shares_for(user)
usage = 0
for share in shares:
usage += share.instance_limit * type.credit
usage += share.instance_limit * c
return usage
class Instance(models.Model):
"""Virtual machine instance."""
name = models.CharField(max_length=100,
......@@ -433,19 +462,24 @@ class Instance(models.Model):
default='DEPLOYABLE')
active_since = models.DateTimeField(null=True, blank=True,
verbose_name=_('active since'),
help_text=_('Time stamp of successful boot report.'))
help_text=_('Time stamp of successful '
'boot report.'))
firewall_host = models.ForeignKey(Host, blank=True, null=True,
verbose_name=_('host in firewall'), related_name='instance_set')
verbose_name=_('host in firewall'),
related_name='instance_set')
pw = models.CharField(max_length=20, verbose_name=_('password'),
help_text=_('Original password of instance'))
one_id = models.IntegerField(unique=True, blank=True, null=True,
verbose_name=_('OpenNebula ID'))
share = models.ForeignKey('Share', blank=True, null=True,
verbose_name=_('share'), related_name='instance_set')
verbose_name=_('share'),
related_name='instance_set')
time_of_suspend = models.DateTimeField(default=None,
verbose_name=_('time of suspend'), null=True, blank=True)
verbose_name=_('time of suspend'),
null=True, blank=True)
time_of_delete = models.DateTimeField(default=None,
verbose_name=_('time of delete'), null=True, blank=True)
verbose_name=_('time of delete'),
null=True, blank=True)
waiting = models.BooleanField(default=False)
class Meta:
......@@ -458,13 +492,15 @@ class Instance(models.Model):
@models.permalink
def get_absolute_url(self):
return ('one.views.vm_show', None, {'iid':self.id})
return ('one.views.vm_show', None, {'iid': self.id})
def get_port(self, use_ipv6=False):
"""Get public port number for default access method."""
proto = self.template.access_type
if self.nat and not use_ipv6:
return {"rdp": 23000, "nx": 22000, "ssh": 22000}[proto] + int(self.ip.split('.')[2]) * 256 + int(self.ip.split('.')[3])
return ({"rdp": 23000, "nx": 22000, "ssh": 22000}[proto] +
int(self.ip.split('.')[2]) * 256 +
int(self.ip.split('.')[3]))
else:
return {"rdp": 3389, "nx": 22, "ssh": 22}[proto]
......@@ -510,21 +546,10 @@ class Instance(models.Model):
pass
return age
@classmethod
def submit(cls, template, owner, extra="", share=None):
"""Submit a new instance to OpenNebula."""
from django.template.defaultfilters import escape
inst = Instance(pw=pwgen(), template=template, owner=owner,
share=share, state='PENDING')
inst.save()
hostname = u"%d" % (inst.id, )
token = signing.dumps(inst.id, salt='activate')
try:
details = owner.cloud_details
except:
details = UserCloudDetails(user=owner)
details.save()
@staticmethod
def _create_context(pw, hostname, smb_password, ssh_private_key, owner,
token, extra):
"""Return XML context configuration with given parameters."""
ctx = u'''
<SOURCE>web</SOURCE>
<HOSTNAME>%(hostname)s</HOSTNAME>
......@@ -536,14 +561,64 @@ class Instance(models.Model):
<SERVER>store.cloud.ik.bme.hu</SERVER>
%(extra)s
''' % {
"pw": escape(inst.pw),
"pw": escape(pw),
"hostname": escape(hostname),
"smbpw": escape(details.smb_password),
"sshkey": escape(details.ssh_private_key),
"neptun": escape(owner.username),
"booturl": "%sb/%s/" % ( CLOUD_URL, token ),
"smbpw": escape(smb_password),
"sshkey": escape(ssh_private_key),
"neptun": escape(owner),
"booturl": "%sb/%s/" % (CLOUD_URL, token),
"extra": extra
}
return ctx
def _create_host(self, hostname, occi_result):
"""Create firewall host for recently submitted Instance."""
host = Host(
vlan=Vlan.objects.get(name=self.template.network.name),
owner=self.owner, hostname=hostname,
mac=occi_result['interfaces'][0]['mac'],
ipv4=occi_result['interfaces'][0]['ip'], ipv6='auto',
)
if self.template.network.nat:
host.pub_ipv4 = Vlan.objects.get(
name=self.template.network.name).snat_ip
host.shared_ip = True
try:
host.save()
except:
for i in Host.objects.filter(ipv4=host.ipv4).all():
logger.warning('Delete orphan fw host (%s) of %s.' % (i, self))
i.delete()
for i in Host.objects.filter(mac=host.mac).all():
logger.warning('Delete orphan fw host (%s) of %s.' % (i, self))
i.delete()
host.save()
host.enable_net()
port = {"rdp": 3389, "nx": 22, "ssh": 22}[self.template.access_type]
host.add_port("tcp", self.get_port(), port)
self.firewall_host = host
self.save()
@classmethod
def submit(cls, template, owner, extra="", share=None):
"""Submit a new instance to OpenNebula."""
inst = Instance(pw=pwgen(), template=template, owner=owner,
share=share, state='PENDING', waiting=True)
inst.save()
hostname = u"%d" % (inst.id, )
token = signing.dumps(inst.id, salt='activate')
try:
details = owner.cloud_details
except:
details = UserCloudDetails(user=owner)
details.save()
ctx = cls._create_context(inst.pw, hostname, details.smb_password,
details.ssh_private_key, owner.username,
token, extra)
try:
from .tasks import CreateInstanceTask
x = CreateInstanceTask.delay(
......@@ -566,33 +641,7 @@ class Instance(models.Model):
'id': inst.one_id})
inst.save()
host = Host(
vlan=Vlan.objects.get(name=template.network.name),
owner=owner, hostname=hostname,
mac=res['interfaces'][0]['mac'],
ipv4=res['interfaces'][0]['ip'], ipv6='auto',
)
if inst.template.network.nat:
host.pub_ipv4 = Vlan.objects.get(name=template.network.name).snat_ip
host.shared_ip = True
try:
host.save()
except:
for i in Host.objects.filter(ipv4=host.ipv4).all():
logger.warning('Delete orphan fw host (%s) of %s.' % (i, inst))
i.delete()
for i in Host.objects.filter(mac=host.mac).all():
logger.warning('Delete orphan fw host (%s) of %s.' % (i, inst))
i.delete()
host.save()
host.enable_net()
host.add_port("tcp", inst.get_port(), {"rdp": 3389, "nx": 22,
"ssh": 22}[inst.template.access_type])
inst.firewall_host=host
inst.save()
inst._create_host(hostname)
return inst
def one_delete(self):
......@@ -678,6 +727,7 @@ class Instance(models.Model):
self.firewall_host_delete()
return True
def delete_instance_pre(sender, instance, using, **kwargs):
if instance.state != 'DONE':
instance.one_delete()
......
......@@ -37,27 +37,32 @@ class UpdateInstanceStateTask(Task):
# ezek csak azert vannak felveve, hogy szepen meg lehessen hivni oket
# ezeket a fejgepen futo celery futtatja
class CreateInstanceTask(Task):
def run(self, name, instance_type, disk_id, network_id, ctx):
pass
class DeleteInstanceTask(Task):
def run(self, one_id):
pass
class ChangeInstanceStateTask(Task):
def run(self, one_id, new_state):
pass
class SaveAsTask(Task):
def run(self, one_id, new_img):
pass
class UpdateDiskTask(Task):
def run(self):
pass
class UpdateNetworkTask(Task):
def run(self):
pass
def keygen(length=1024):
import os, base64
import os
import base64
from datetime import date
from Crypto.PublicKey import RSA
......
......@@ -3,26 +3,21 @@ from datetime import datetime
from django.conf import settings
from datetime import timedelta as td
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.contrib import messages
from django.core.exceptions import PermissionDenied
from django.core import signing, urlresolvers
from django.core.mail import mail_managers, send_mail
from django.db import transaction
from django.forms import ModelForm, Textarea
from django.http import Http404
from django.shortcuts import render, render_to_response, get_object_or_404, redirect
from django.core.exceptions import PermissionDenied, ValidationError
from django.core import signing
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.template import RequestContext
from django.template.loader import render_to_string
from django.utils.decorators import method_decorator
from django.utils.translation import get_language as lang
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.http import *
from django.views.generic import *
from firewall.tasks import *
from one.models import *
from school.models import *
import django.contrib.auth as auth
from django.utils.translation import ugettext_lazy as _, ugettext
from django.views.decorators.http import require_GET, require_POST
from django.views.decorators.http import require_safe
from django.http import HttpResponse
from django.views.generic import View
# from firewall.tasks import *
from one.models import Instance, UserCloudDetails, Template, Share
from one.models import InstanceType, TYPES_L, TYPES, SshKey
from school.models import Semester, Group
from store.api import StoreApi
import json
import logging
import subprocess
......@@ -30,14 +25,18 @@ import subprocess
store_settings = settings.STORE_SETTINGS
logger = logging.getLogger(__name__)
def _list_instances(request):
instances = Instance.objects.exclude(state='DONE').filter(owner=request.user)
instances = Instance.objects.exclude(
state='DONE').filter(owner=request.user)
instances = instances.exclude(state='DONE')
return instances
def info(request):
return render_to_response("info.html", RequestContext(request, {}))
def index(request):
if request.user.is_authenticated():
return redirect(home)
......@@ -51,7 +50,8 @@ def home(request):
instances = _list_instances(request)
shares = [s for s in request.user.person_set.all()[0].get_shares()]
for i, s in enumerate(shares):
s.running_shared = s.instance_set.all().exclude(state="DONE").filter(owner=request.user).count()
s.running_shared = s.instance_set.all().exclude(
state="DONE").filter(owner=request.user).count()
shares[i] = s
try:
details = UserCloudDetails.objects.get(user=request.user)
......@@ -74,6 +74,7 @@ def home(request):
'storeserv': store_settings['store_public'],
}))
@login_required
def ajax_template_delete(request):
try:
......@@ -82,16 +83,21 @@ def ajax_template_delete(request):
return HttpResponse(unicode(_("Invalid template ID.")), status=404)
template = get_object_or_404(Template, id=template_id)
if template.running_instances() > 0:
return HttpResponse(unicode(_("There are running instances of this template.")), status=404)
return HttpResponse(unicode(_('There are running instances of '
'this template.')), status=404)
elif template.share_set.exists():
return HttpResponse(unicode(_("Template is still shared.")), status=404)
return HttpResponse(unicode(_("Template is still shared.")),
status=404)
elif template.owner != request.user:
return HttpResponse(unicode(_("You don't have permission to delete this template.")), status=404)
return HttpResponse(unicode(_("You don't have permission to delete "
"this template.")), status=404)
else:
if template.safe_delete():
return HttpResponse(unicode(_("Template successfully deleted.")))
else:
return HttpResponse(unicode(_("Unexpected error happened.")), status=404)
return HttpResponse(unicode(_("Unexpected error happened.")),
status=404)
def ajax_template_name_unique(request):
name = request.GET['name']
......@@ -100,6 +106,7 @@ def ajax_template_name_unique(request):
s = "False"
return HttpResponse(s)
@login_required
def vm_credentials(request, iid):
try:
......@@ -110,54 +117,70 @@ def vm_credentials(request, iid):
vm.is_ipv6 = is_ipv6
vm.port_v4 = vm.get_port(use_ipv6=False)
vm.port_v6 = vm.get_port(use_ipv6=True)
return render_to_response('vm-credentials.html', RequestContext(request, { 'i' : vm }))
return render_to_response('vm-credentials.html',
RequestContext(request, {'i': vm}))
except:
return HttpResponse(_("Could not get Virtual Machine credentials."), status=404)
return HttpResponse(_("Could not get Virtual Machine credentials."),
status=404)
messages.error(request, _('Failed to power off virtual machine.'))
class AjaxTemplateWizard(View):
def get(self, request, *args, **kwargs):
return render_to_response('new-template-flow-1.html', RequestContext(request, {
'templates': [t for t in Template.objects.filter(public=True).all()] +
[t for t in Template.objects.filter(owner=request.user).all()],
}))
templates = ([t for t in Template.objects.filter(public=True).all()] +
[t for t
in Template.objects.filter(owner=request.user).all()])
ctx = RequestContext(request, {'templates': templates})
return render_to_response('new-template-flow-1.html', ctx)
def post(self, request, *args, **kwargs):
base = get_object_or_404(Template, id=request.POST['base'])
if base.owner != request.user and not base.public and not request.user.is_superuser:
if base.owner != request.user and (not base.public and
not request.user.is_superuser):
raise PermissionDenied()
try:
maxshare = Template.objects.order_by('-pk')[0].pk + 1
except:
maxshare = 1
return render_to_response('new-template-flow.html', RequestContext(request, {
'sizes': InstanceType.objects.all(),
ctx = {'sizes': InstanceType.objects.all(),
'base': base,
'maxshare': maxshare,
}))
}
return render_to_response('new-template-flow.html',
RequestContext(request, ctx))
ajax_template_wizard = login_required(AjaxTemplateWizard.as_view())
class AjaxTemplateEditWizard(View):
def get(self, request, id, *args, **kwargs):
template = get_object_or_404(Template, id=id)
if template.owner != request.user and not template.public and not request.user.is_superuser:
if template.owner != request.user and (not template.public and
not request.user.is_superuser):
raise PermissionDenied()
return render_to_response('edit-template-flow.html', RequestContext(request, {
'sizes': InstanceType.objects.all(),
ctx = {'sizes': InstanceType.objects.all(),
'template': template,
}))
}
return render_to_response('edit-template-flow.html',
RequestContext(request, ctx))
def post(self, request, id, *args, **kwargs):
template = get_object_or_404(Template, id=id)
user_details = UserCloudDetails.objects.get(user=request.user)
if template.owner != request.user and not template.public and not request.user.is_superuser:
if template.owner != request.user and (not template.public and
not request.user.is_superuser):
raise PermissionDenied()
instance_type = get_object_or_404(InstanceType, id=request.POST['size'])
current_used_share_quota = user_details.get_weighted_share_count()
current_used_share_quota_without_template = current_used_share_quota - template.get_share_quota_usage_for(request.user)
new_quota_for_current_template = template.get_share_quota_usage_for_user_with_type(instance_type, request.user)
new_used_share_quota = current_used_share_quota_without_template + new_quota_for_current_template
allow_type_modify = True if new_used_share_quota <= user_details.share_quota else False
if not allow_type_modify:
messages.error(request, _('You do not have enough free share quota.'))
instance_type = get_object_or_404(
InstanceType, id=request.POST['size'])
# calculate quota need with changed template type
q = user_details.get_weighted_share_count()
q -= template.get_share_quota_usage_for(request.user)
q += template.get_share_quota_usage_for(request.user,
type=instance_type)
if q > user_details.share_quota:
messages.error(request, _(
'You do not have enough free share quota.'))
return redirect(home)
template.instance_type = instance_type
template.description = request.POST['description']
......@@ -172,12 +195,15 @@ class AjaxShareWizard(View):
def get(self, request, id, gid=None, *args, **kwargs):
det = UserCloudDetails.objects.get(user=request.user)
if det.get_weighted_share_count() >= det.share_quota:
return HttpResponse(unicode(_('You do not have any free share quota.')))
msg = ugettext('You do not have any free share quota.')
return HttpResponse(msg)
types = TYPES_L
types[0]['default'] = True
for i, t in enumerate(types):
t['deletex'] = datetime.now() + td(seconds=1) + t['delete'] if t['delete'] else None
t['suspendx'] = datetime.now() + td(seconds=1) + t['suspend'] if t['suspend'] else None
t['deletex'] = datetime.now() + td(
seconds=1) + t['delete'] if t['delete'] else None
t['suspendx'] = datetime.now() + td(
seconds=1) + t['suspend'] if t['suspend'] else None
types[i] = t
if gid:
gid = get_object_or_404(Group, id=gid)
......@@ -188,10 +214,12 @@ class AjaxShareWizard(View):
'types': types,
'group': gid,
}))
def post(self, request, id, gid=None, *args, **kwargs):
det = UserCloudDetails.objects.get(user=request.user)
base = get_object_or_404(Template, id=id)
if base.owner != request.user and not base.public and not request.user.is_superuser:
if base.owner != request.user and (not base.public and
not request.user.is_superuser):
raise PermissionDenied()
group = None
if gid:
......@@ -205,35 +233,45 @@ class AjaxShareWizard(View):
if not stype in TYPES.keys():
raise PermissionDenied()
il = request.POST['instance_limit']
if det.get_weighted_share_count() + int(il)*base.instance_type.credit > det.share_quota:
messages.error(request, _('You do not have enough free share quota.'))
if det.share_quota < (det.get_weighted_share_count() +
int(il) * base.instance_type.credit):
messages.error(request, _(
'You do not have enough free share quota.'))
return redirect('/')
s = Share.objects.create(name=request.POST['name'], description=request.POST['description'],
type=stype, instance_limit=il, per_user_limit=request.POST['per_user_limit'],
Share.objects.create(
name=request.POST['name'], description=request.POST['description'],
type=stype, instance_limit=il, per_user_limit=request.POST[
'per_user_limit'],
group=group, template=base, owner=request.user)
messages.success(request, _('Successfully shared %s.') % base)
return redirect(group)
ajax_share_wizard = login_required(AjaxShareWizard.as_view())
class AjaxShareEditWizard(View):
def get(self, request, id, *args, **kwargs):
det = UserCloudDetails.objects.get(user=request.user)
if det.get_weighted_share_count() > det.share_quota:
logger.warning('[one] User %s ha more used share quota, than its limit, how is that possible? (%d > %d)',
str(request.user),
logger.warning(
'[one] User %s ha more used share quota, than its limit, how '
'is that possible? (%d > %d)', str(request.user),
det.get_weighted_share_count(),
det.share_quota)
return HttpResponse(unicode(_('You do not have any free share quota.')))
msg = ugettext('You do not have any free share quota.')
return HttpResponse(msg)
types = TYPES_L
for i, t in enumerate(types):
t['deletex'] = datetime.now() + td(seconds=1) + t['delete'] if t['delete'] else None
t['suspendx'] = datetime.now() + td(seconds=1) + t['suspend'] if t['suspend'] else None
t['deletex'] = datetime.now() + td(
seconds=1) + t['delete'] if t['delete'] else None
t['suspendx'] = datetime.now() + td(
seconds=1) + t['suspend'] if t['suspend'] else None
types[i] = t
share = get_object_or_404(Share, id=id)
return render_to_response('edit-share.html', RequestContext(request, {
'share': share,
'types': types,
}))
def post(self, request, id, *args, **kwargs):
det = UserCloudDetails.objects.get(user=request.user)
share = get_object_or_404(Share, id=id)
......@@ -243,13 +281,15 @@ class AjaxShareEditWizard(View):
if not stype in TYPES.keys():
raise PermissionDenied()
instance_limit = int(request.POST['instance_limit'])
current_used_share_quota = det.get_weighted_share_count()
current_used_share_quota_without_current_share = current_used_share_quota - share.get_used_quota()
new_quota_for_current_share = instance_limit * share.template.get_credits_per_instance()
new_used_share_quota = current_used_share_quota_without_current_share + new_quota_for_current_share
allow_stype_modify = True if new_used_share_quota <= det.share_quota else False
if not allow_stype_modify:
messages.error(request, _('You do not have enough free share quota.'))
# calculate quota need with changed share
q = det.get_weighted_share_count()
q -= share.get_used_quota()
q += instance_limit * share.template.get_credits_per_instance()
if det.share_quota < q:
messages.error(request,
_('You do not have enough free share quota.'))
return redirect(share.group)
share.name = request.POST['name']
share.description = request.POST['description']
......@@ -273,9 +313,11 @@ def vm_saveas(request, vmid):
messages.success(request, _("Template is being saved..."))
return redirect(inst)
def vm_new_ajax(request, template):
return vm_new(request, template, redir=False)
def _redirect_or_201(path, redir):
if redir:
return redirect(path)
......@@ -284,38 +326,80 @@ def _redirect_or_201(path, redir):
response['Location'] = path
return response
def _template_for_save(base, request):
if base.owner != request.user and not base.public and not request.user.is_superuser:
if base.owner != request.user and (not base.public and
not request.user.is_superuser):
raise PermissionDenied()
name = request.POST['name']
t = Template.objects.create(name=name, disk=base.disk, instance_type_id=request.POST['size'], network=base.network, owner=request.user)
t = Template.objects.create(name=name, disk=base.disk,
instance_type_id=request.POST['size'],
network=base.network, owner=request.user)
t.access_type = base.access_type
t.description = request.POST['description']
t.system = base.system
t.save()
return t
def _check_quota(request, template, share):
"""
Returns if the given request is permitted to run the new vm.
"""
det = UserCloudDetails.objects.get(user=request.user)
if det.get_weighted_instance_count() + template.instance_type.credit > det.instance_quota:
messages.error(request, _('You do not have any free quota. You can not launch this until you stop an other instance.'))
user = request.user
det = UserCloudDetails.objects.get(user=user)
q = det.get_weighted_instance_count() + template.instance_type.credit
if q > det.instance_quota:
messages.error(request,
_('You do not have any free quota. You can not launch '
'this until you stop an other instance.'))
return False
if share:
if share.get_running() + 1 > share.instance_limit:
messages.error(request, _('The share does not have any free quota. You can not launch this until someone stops an instance.'))
if share.instance_limit < share.get_running() + 1:
msg = _('The share does not have any free quota. You can '
'not launch this until someone stops an instance.')
messages.error(request, msg)
return False
elif share.get_running_or_stopped(request.user) + 1 > share.per_user_limit:
messages.error(request, _('You do not have any free quota for this share. You can not launch this until you stop an other instance.'))
if share.per_user_limit < share.get_running_or_stopped(user) + 1:
msg = _('You do not have any free quota for this share. You can '
'not launch this until you stop an other instance.')
messages.error(request, msg)
return False
if not share.group.members.filter(user=request.user) and not share.group.owners.filter(user=request.user):
messages.error(request, _('You are not a member of the share group.'))
if not share.group.members.filter(user=request.user) and \
not share.group.owners.filter(user=request.user):
msg = _('You are not a member of the share group.')
messages.error(request, msg)
return False
return True
@require_POST
def _check_permission(request, template, share):
"""
Returns if the given request is permitted to try the new vm.
"""
if not share and not template.public and template.owner != request.user:
msg = _('You have no permission to try this instance without a share. '
'Launch a new instance through a share.')
messages.error(request, msg)
return False
else:
return True
def _try_submit(base, request, extra, share):
try:
inst = Instance.submit(
base, request.user, extra=extra, share=share)
except Exception as e:
logger.error('Failed to create virtual machine.' + unicode(e))
messages.error(request, _('Failed to create virtual machine.'))
else:
inst.renew()
return inst
@login_required
def vm_new(request, template=None, share=None, redir=True):
base = None
......@@ -334,44 +418,14 @@ def vm_new(request, template=None, share=None, redir=True):
except:
messages.error(request, _('Can not create template.'))
go = False
go = go and _check_quota(request, base, share)
if not share and not base.public and base.owner != request.user:
messages.error(request, _('You have no permission to try this instance without a share. Launch a new instance through a share.'))
go = False
type = share.type if share else 'LAB'
TYPES[type]['suspend']
time_of_suspend = TYPES[type]['suspend']+datetime.now()
if TYPES[type]['delete']:
time_of_delete = TYPES[type]['delete']+datetime.now()
else:
time_of_delete = None
inst = None
go = go and (_check_quota(request, base, share) and
_check_permission(request, base, share))
if go:
try:
inst = Instance.submit(base, request.user, extra=extra, share=share)
except Exception as e:
logger.error('Failed to create virtual machine.' + unicode(e))
messages.error(request, _('Failed to create virtual machine.'))
inst = None
if inst:
inst.waiting = True
inst.time_of_suspend = time_of_suspend
inst.time_of_delete = time_of_delete
inst.save()
elif extra and base:
inst = _try_submit(base, request, extra, share)
elif extra and base: # clean up new template object
base.delete()
return _redirect_or_201(inst.get_absolute_url() if inst else '/', redir)
class VmListView(ListView):
context_object_name = 'instances'
template_name = 'list.html'
def get_queryset(self):
self.profile = request.user
return Instance.objects.filter(owner=self.profile)
vm_list = login_required(VmListView.as_view())
@require_safe
@login_required
......@@ -392,7 +446,7 @@ def vm_show(request, iid):
inst.hostname_v6 = inst.get_connect_host(use_ipv6=True)
inst.port_v4 = inst.get_port(use_ipv6=False)
inst.port_v6 = inst.get_port(use_ipv6=True)
return render_to_response("show.html", RequestContext(request,{
return render_to_response("show.html", RequestContext(request, {
'uri': inst.get_connect_uri(),
'state': inst.state,
'name': inst.name,
......@@ -400,11 +454,12 @@ def vm_show(request, iid):
'age': inst.get_age(),
'instances': _list_instances(request),
'i': inst,
'booting' : not inst.active_since,
'booting': not inst.active_since,
'ports': ports,
'userdetails': details
}))
@require_safe
@login_required
def vm_ajax_instance_status(request, iid):
......@@ -417,6 +472,7 @@ def vm_ajax_instance_status(request, iid):
'state': inst.template.state
}}))
@login_required
def vm_ajax_rename(request, iid):
inst = get_object_or_404(Instance, id=iid, owner=request.user)
......@@ -424,6 +480,7 @@ def vm_ajax_rename(request, iid):
inst.save()
return HttpResponse(json.dumps({'name': inst.name}))
def boot_token(request, token):
try:
id = signing.loads(token, salt='activate')
......@@ -437,6 +494,7 @@ def boot_token(request, token):
inst.save()
return HttpResponse("KTHXBYE")
class VmPortAddView(View):
def post(self, request, iid, *args, **kwargs):
try:
......@@ -460,6 +518,7 @@ class VmPortAddView(View):
vm_port_add = login_required(VmPortAddView.as_view())
@require_safe
@login_required
@require_GET
......@@ -473,14 +532,17 @@ def vm_port_del(request, iid, proto, private):
messages.error(request, _(u"Removing port failed."))
return redirect('/vm/show/%d/' % int(iid))
class VmDeleteView(View):
def post(self, request, iid, *args, **kwargs):
try:
inst = get_object_or_404(Instance, id=iid, owner=request.user)
if inst.template.state != 'READY' and inst.template.owner == request.user:
if inst.template.state != 'READY' and \
inst.template.owner == request.user:
inst.template.delete()
inst.one_delete()
messages.success(request, _('Virtual machine is successfully deleted.'))
messages.success(request, _(
'Virtual machine is successfully deleted.'))
except:
messages.error(request, _('Failed to delete virtual machine.'))
if request.is_ajax():
......@@ -490,13 +552,14 @@ class VmDeleteView(View):
def get(self, request, iid, *args, **kwargs):
i = get_object_or_404(Instance, id=iid, owner=request.user)
return render_to_response("confirm_delete.html", RequestContext(request, {
'i': i}))
ctx = RequestContext(request, {'i': i, })
return render_to_response("confirm_delete.html", ctx)
vm_delete = login_required(VmDeleteView.as_view())
@login_required
#@require_POST
# @require_POST
def vm_unshare(request, id, *args, **kwargs):
s = get_object_or_404(Share, id=id)
g = s.group
......@@ -504,7 +567,8 @@ def vm_unshare(request, id, *args, **kwargs):
raise PermissionDenied()
try:
if s.get_running_or_stopped() > 0:
messages.error(request, _('There are machines running of this share.'))
messages.error(request, _(
'There are machines running of this share.'))
else:
s.delete()
messages.success(request, _('Share is successfully removed.'))
......@@ -512,23 +576,27 @@ def vm_unshare(request, id, *args, **kwargs):
messages.error(request, _('Failed to remove share.'))
return redirect(g)
@login_required
@require_POST
def vm_stop(request, iid, *args, **kwargs):
try:
get_object_or_404(Instance, id=iid, owner=request.user).stop()
messages.success(request, _('Virtual machine is successfully stopped.'))
messages.success(request, _(
'Virtual machine is successfully stopped.'))
except:
messages.error(request, _('Failed to stop virtual machine.'))
return redirect('/')
@login_required
@require_POST
def vm_resume(request, iid, *args, **kwargs):
try:
obj = get_object_or_404(Instance, id=iid, owner=request.user)
obj.resume()
messages.success(request, _('Virtual machine is successfully resumed.'))
messages.success(request, _(
'Virtual machine is successfully resumed.'))
except:
messages.error(request, _('Failed to resume virtual machine.'))
try:
......@@ -537,6 +605,7 @@ def vm_resume(request, iid, *args, **kwargs):
pass
return redirect('/')
@login_required
@require_POST
def vm_renew(request, which, iid, *args, **kwargs):
......@@ -550,33 +619,38 @@ def vm_renew(request, which, iid, *args, **kwargs):
'vm': vm
}))
@login_required
@require_POST
def vm_power_off(request, iid, *args, **kwargs):
try:
get_object_or_404(Instance, id=iid, owner=request.user).poweroff()
messages.success(request, _('Virtual machine is successfully powered off.'))
messages.success(request, _(
'Virtual machine is successfully powered off.'))
except:
messages.error(request, _('Failed to power off virtual machine.'))
return redirect('/')
@login_required
@require_POST
def vm_restart(request, iid, *args, **kwargs):
try:
get_object_or_404(Instance, id=iid, owner=request.user).restart()
messages.success(request, _('Virtual machine is successfully restarted.'))
messages.success(request, _(
'Virtual machine is successfully restarted.'))
except:
messages.error(request, _('Failed to restart virtual machine.'))
return redirect('/')
@login_required
@require_POST
def key_add(request):
try:
key=SshKey()
key.key=request.POST['key']
key.user=request.user
key = SshKey()
key.key = request.POST['key']
key.user = request.user
key.full_clean()
key.save()
_update_keys(request.user)
......@@ -590,22 +664,25 @@ def key_add(request):
messages.success(request, _('Public key successfully added.'))
return redirect('/')
@login_required
@require_POST
def key_ajax_delete(request):
try:
key=get_object_or_404(SshKey, id=request.POST['id'], user=request.user)
key = get_object_or_404(SshKey, id=request.POST[
'id'], user=request.user)
key.delete()
_update_keys(request.user)
except:
messages.error(request, _('Failed to delete public key'))
return HttpResponse('OK')
@login_required
@require_POST
def key_ajax_reset(request):
try:
det=UserCloudDetails.objects.get(user=request.user)
det = UserCloudDetails.objects.get(user=request.user)
det.reset_smb()
det.reset_keys()
_update_keys(request.user)
......@@ -613,6 +690,7 @@ def key_ajax_reset(request):
messages.error(request, _('Failed to reset keys'))
return HttpResponse('OK')
def _update_keys(user):
details = user.cloud_details
password = details.smb_password
......@@ -622,22 +700,24 @@ def _update_keys(user):
user = user.username
StoreApi.updateauthorizationinfo(user, password, key_list)
def stat(request):
values = subprocess.check_output(['/opt/webadmin/cloud/miscellaneous/stat/stat_wrap.sh'])
values = subprocess.check_output(
['/opt/webadmin/cloud/miscellaneous/stat/stat_wrap.sh'])
# values = '''
# {"CPU": {"USED_CPU": 2, "ALLOC_CPU": 0,
# "FREE_CPU": 98}, "MEM": {"FREE_MEM": 1685432, "ALLOC_MEM":0,
# "USED_MEM": 366284}}'''
stat_dict = json.loads(values)
return HttpResponse(render_to_response("stat.html", RequestContext(
request, {
'STAT' : stat_dict,
}
request, {'STAT': stat_dict, }
)))
def sites(request, site):
if site in [ "legal", "policy", "help", "support", "changelog", ]:
return render_to_response("sites/%s.html" % site, RequestContext(request, {}))
if site in ["legal", "policy", "help", "support", "changelog", ]:
ctx = RequestContext(request, {})
return render_to_response("sites/%s.html" % site, ctx)
else:
return redirect(home)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment