Commit ac0e2797 by Kálmán Viktor

Merge branch 'master' into network-gui

Conflicts:
	cloud/urls.py
parents 689327cf 0e6e870e
import json
import subprocess
from django.conf import settings
from django.core.cache import cache
def process_debug(req):
return {'DEBUG': settings.DEBUG}
def process_stat(req):
if settings.STAT_DEBUG:
stat = {
......@@ -28,6 +27,7 @@ def process_stat(req):
'cloud_stat': stat,
}
def process_release(req):
return {
'release': settings.RELEASE,
......
......@@ -274,11 +274,14 @@ DELETE_VM = True
EMAIL_HOST = '152.66.243.92' # giccero ipv4
CLOUD_URL = 'https://cloud.ik.bme.hu/'
try:
current_dir = os.getcwd()
os.chdir('/opt/webadmin/cloud/')
RELEASE = subprocess.check_output(
['/usr/bin/git', 'describe', '--tags', '--abbrev=4'])
except:
RELEASE = 'n/a'
finally:
os.chdir(current_dir)
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
......
# coding=utf8
# Django development settings for cloud project.
from .base import *
from .base import * # NOQA
DEBUG = True
TEMPLATE_DEBUG = DEBUG
......@@ -8,11 +8,11 @@ EMAIL_HOST = "localhost"
EMAIL_PORT = 1025
ADMINS = (
('Ory, Mate', 'orymate@localhost'),
)
('Ory, Mate', 'orymate@localhost'),
)
MANAGERS = (
('Ory Mate', 'maat@localhost'),
)
('Ory Mate', 'maat@localhost'),
)
INSTALLED_APPS += ("debug_toolbar", )
MIDDLEWARE_CLASSES += ("debug_toolbar.middleware.DebugToolbarMiddleware", )
INTERNAL_IPS = [('2001:738:2001:4031:5:253:%d:0' % i) for i in xrange(1, 100)]
......
# coding=utf8
# Django production settings for cloud project.
from .base import *
from .base import * # NOQA
DEBUG = False
TEMPLATE_DEBUG = DEBUG
......
......@@ -3,6 +3,7 @@ from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
js_info_dict = {
'packages': ('one', ),
}
......
......@@ -23,6 +23,7 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cloud.settings.prod")
from django.core.wsgi import get_wsgi_application
_application = get_wsgi_application()
def application(environ, start_response):
# copy DJANGO_* wsgi-env vars to process-env
for i in environ.keys():
......
# -*- coding: utf8 -*-
from django.contrib import admin
from firewall.models import *
from firewall.models import (Rule, Host, Vlan, Group, VlanGroup, Firewall,
Domain, Record, Blacklist)
from django import contrib
class RuleInline(contrib.admin.TabularInline):
model = Rule
class RecordInline(contrib.admin.TabularInline):
model = Record
class HostAdmin(admin.ModelAdmin):
list_display = ('hostname', 'vlan', 'ipv4', 'ipv6', 'pub_ipv4', 'mac',
'shared_ip', 'owner', 'description', 'reverse', 'list_groups')
'shared_ip', 'owner', 'description', 'reverse',
'list_groups')
ordering = ('hostname', )
list_filter = ('owner', 'vlan', 'groups')
search_fields = ('hostname', 'description', 'ipv4', 'ipv6', 'mac')
......@@ -26,42 +30,46 @@ class HostAdmin(admin.ModelAdmin):
names = [group.name for group in instance.groups.all()]
return u', '.join(names)
class HostInline(contrib.admin.TabularInline):
model = Host
fields = ('hostname', 'ipv4', 'ipv6', 'pub_ipv4', 'mac', 'shared_ip',
'owner', 'reverse')
'owner', 'reverse')
class VlanAdmin(admin.ModelAdmin):
list_display = ('vid', 'name', 'ipv4', 'net_ipv4', 'ipv6', 'net_ipv6',
'description', 'domain', 'snat_ip', )
'description', 'domain', 'snat_ip', )
ordering = ('vid', )
inlines = (RuleInline, )
class RuleAdmin(admin.ModelAdmin):
list_display = ('r_type', 'color_desc', 'owner', 'extra', 'direction',
'accept', 'proto', 'sport', 'dport', 'nat', 'nat_dport', 'used_in')
'accept', 'proto', 'sport', 'dport', 'nat',
'nat_dport', 'used_in')
list_filter = ('r_type', 'vlan', 'owner', 'direction', 'accept',
'proto', 'nat')
'proto', 'nat')
def color_desc(self, instance):
"""Returns a colorful description of the instance."""
return (u'<span style="color: #FF0000;">[%(type)s]</span> '
u'%(src)s<span style="color: #0000FF;"> ▸ </span>%(dst)s '
u'%(para)s %(desc)s') % {
'type': instance.r_type,
'src': (instance.foreign_network.name
if instance.direction == '1' else instance.r_type),
'dst': (instance.r_type if instance.direction == '1'
else instance.foreign_network.name),
'para': (u'<span style="color: #00FF00;">' +
'type': instance.r_type,
'src': (instance.foreign_network.name
if instance.direction == '1' else instance.r_type),
'dst': (instance.r_type if instance.direction == '1'
else instance.foreign_network.name),
'para': (u'<span style="color: #00FF00;">' +
(('proto=%s ' % instance.proto)
if instance.proto else '') +
(('sport=%s ' % instance.sport)
if instance.sport else '') +
(('dport=%s ' % instance.dport)
if instance.dport else '') +
'</span>'),
'desc': instance.description}
'</span>'),
'desc': instance.description}
color_desc.allow_tags = True
@staticmethod
......@@ -73,7 +81,7 @@ class RuleAdmin(admin.ModelAdmin):
@staticmethod
def used_in(instance):
for field in [instance.vlan, instance.vlangroup, instance.host,
instance.hostgroup, instance.firewall]:
instance.hostgroup, instance.firewall]:
if field:
return unicode(field) + ' ' + field._meta.object_name
......@@ -81,16 +89,20 @@ class RuleAdmin(admin.ModelAdmin):
class AliasAdmin(admin.ModelAdmin):
list_display = ('alias', 'host')
class GroupAdmin(admin.ModelAdmin):
list_display = ('name', 'owner', 'description')
inlines = (RuleInline, )
class FirewallAdmin(admin.ModelAdmin):
inlines = (RuleInline, )
class DomainAdmin(admin.ModelAdmin):
list_display = ('name', 'owner')
class RecordAdmin(admin.ModelAdmin):
list_display = ('name_', 'type', 'address_', 'ttl', 'host', 'owner')
......@@ -104,6 +116,7 @@ class RecordAdmin(admin.ModelAdmin):
a = instance.get_data()
return a['name'] if a else None
class BlacklistAdmin(admin.ModelAdmin):
list_display = ('ipv4', 'reason', 'created_at', 'modified_at')
......@@ -116,4 +129,3 @@ admin.site.register(Firewall, FirewallAdmin)
admin.site.register(Domain, DomainAdmin)
admin.site.register(Record, RecordAdmin)
admin.site.register(Blacklist, BlacklistAdmin)
......@@ -6,12 +6,14 @@ from django.utils.ipv6 import is_valid_ipv6_address
from south.modelsinspector import add_introspection_rules
import re
mac_re = re.compile(r'^([0-9a-fA-F]{2}(:|$)){6}$')
alfanum_re = re.compile(r'^[A-Za-z0-9_-]+$')
domain_re = re.compile(r'^([A-Za-z0-9_-]\.?)+$')
ipv4_re = re.compile('^[0-9]+\.([0-9]+)\.([0-9]+)\.([0-9]+)$')
reverse_domain_re = re.compile(r'^(%\([abcd]\)d|[a-z0-9.-])+$')
class MACAddressFormField(fields.RegexField):
default_error_messages = {
'invalid': _(u'Enter a valid MAC address.'),
......@@ -20,8 +22,10 @@ class MACAddressFormField(fields.RegexField):
def __init__(self, *args, **kwargs):
super(MACAddressFormField, self).__init__(mac_re, *args, **kwargs)
class MACAddressField(models.Field):
empty_strings_allowed = False
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 17
super(MACAddressField, self).__init__(*args, **kwargs)
......@@ -35,58 +39,68 @@ class MACAddressField(models.Field):
return super(MACAddressField, self).formfield(**defaults)
add_introspection_rules([], ["firewall\.fields\.MACAddressField"])
def val_alfanum(value):
"""Validate whether the parameter is a valid alphanumeric value."""
if not alfanum_re.match(value):
raise ValidationError(_(u'%s - only letters, numbers, underscores '
'and hyphens are allowed!') % value)
'and hyphens are allowed!') % value)
def is_valid_domain(value):
"""Check whether the parameter is a valid domain name."""
return domain_re.match(value) is not None
def val_domain(value):
"""Validate whether the parameter is a valid domin name."""
if not is_valid_domain(value):
raise ValidationError(_(u'%s - invalid domain name') % value)
def is_valid_reverse_domain(value):
"""Check whether the parameter is a valid reverse domain name."""
return reverse_domain_re.match(value) is not None
def val_reverse_domain(value):
"""Validate whether the parameter is a valid reverse domain name."""
if not is_valid_reverse_domain(value):
raise ValidationError(u'%s - invalid reverse domain name' % value)
def is_valid_ipv4_address(value):
"""Check whether the parameter is a valid IPv4 address."""
return ipv4_re.match(value) is not None
def val_ipv4(value):
"""Validate whether the parameter is a valid IPv4 address."""
if not is_valid_ipv4_address(value):
raise ValidationError(_(u'%s - not an IPv4 address') % value)
def val_ipv6(value):
"""Validate whether the parameter is a valid IPv6 address."""
if not is_valid_ipv6_address(value):
raise ValidationError(_(u'%s - not an IPv6 address') % value)
def val_mx(value):
"""Validate whether the parameter is a valid MX address definition.
Expected form is <priority>:<hostname>.
"""
mx = self.address.split(':', 1)
mx = value.split(':', 1)
if not (len(mx) == 2 and mx[0].isdigit() and
domain_re.match(mx[1])):
raise ValidationError(_("Bad MX address format. "
"Should be: <priority>:<hostname>"))
def ipv4_2_ipv6(ipv4):
"""Convert IPv4 address string to IPv6 address string."""
val_ipv4(ipv4)
m = ipv4_re.match(ipv4)
return ("2001:738:2001:4031:%s:%s:%s:0" %
(m.group(1), m.group(2), m.group(3)))
(m.group(1), m.group(2), m.group(3)))
from django.contrib import auth
from firewall import models
import os
import django.conf
import subprocess
import re
import json
from datetime import datetime, timedelta
from django.db.models import Q
settings = django.conf.settings.FIREWALL_SETTINGS
class Firewall:
IPV6=False
IPV6 = False
RULES = None
RULES_NAT = []
vlans = None
......@@ -29,13 +28,12 @@ class Firewall:
retval += ' --sport %s ' % rule.sport
if rule.dport:
retval += ' --dport %s ' % (rule.nat_dport
if (repl and rule.nat and rule.direction == '1')
else rule.dport)
if (repl and rule.nat and rule.direction == '1')
else rule.dport)
elif rule.proto == 'icmp':
retval = '-p %s ' % rule.proto
return retval
def iptables(self, s):
"""Append rule to filter table."""
self.RULES.append(s)
......@@ -60,8 +58,8 @@ class Firewall:
if rule.direction == '0' and vlan.name == 'PUB':
if rule.dport == 25:
self.iptables('-A PUB_OUT -s %s %s -p tcp '
'--dport 25 -j LOG_ACC' %
(ipaddr, rule.extra))
'--dport 25 -j LOG_ACC' %
(ipaddr, rule.extra))
break
action = 'PUB_OUT'
else:
......@@ -69,13 +67,14 @@ class Firewall:
else:
action = 'LOG_DROP'
if rule.direction == '1': # going TO host
self.iptables('-A %s_%s -d %s %s %s -g %s' % (vlan,
host.vlan, ipaddr, dport_sport, rule.extra, action))
if rule.direction == '1': # going TO host
self.iptables('-A %s_%s -d %s %s %s -g %s' %
(vlan, host.vlan, ipaddr, dport_sport,
rule.extra, action))
else:
self.iptables('-A %s_%s -s %s %s %s -g %s' % (host.vlan,
vlan, ipaddr, dport_sport, rule.extra, action))
self.iptables('-A %s_%s -s %s %s %s -g %s' %
(host.vlan, vlan, ipaddr, dport_sport,
rule.extra, action))
def fw2vlan(self, rule):
if not rule.foreign_network:
......@@ -84,14 +83,14 @@ class Firewall:
dport_sport = self.dportsport(rule)
for vlan in rule.foreign_network.vlans.all():
if rule.direction == '1': # going TO host
if rule.direction == '1': # going TO host
self.iptables('-A INPUT -i %s %s %s -g %s' %
(vlan.interface, dport_sport, rule.extra,
'LOG_ACC' if rule.accept else 'LOG_DROP'))
(vlan.interface, dport_sport, rule.extra,
'LOG_ACC' if rule.accept else 'LOG_DROP'))
else:
self.iptables('-A OUTPUT -o %s %s %s -g %s' %
(vlan.interface, dport_sport, rule.extra,
'LOG_ACC' if rule.accept else 'LOG_DROP'))
(vlan.interface, dport_sport, rule.extra,
'LOG_ACC' if rule.accept else 'LOG_DROP'))
def vlan2vlan(self, l_vlan, rule):
if not rule.foreign_network:
......@@ -108,13 +107,13 @@ class Firewall:
else:
action = 'LOG_DROP'
if rule.direction == '1': # going TO host
self.iptables('-A %s_%s %s %s -g %s' % (vlan, l_vlan,
dport_sport, rule.extra, action))
if rule.direction == '1': # going TO host
self.iptables('-A %s_%s %s %s -g %s' %
(vlan, l_vlan, dport_sport, rule.extra, action))
else:
self.iptables('-A %s_%s %s %s -g %s' % (l_vlan, vlan,
dport_sport, rule.extra, action))
dport_sport,
rule.extra, action))
def prerun(self):
self.iptables('*filter')
......@@ -128,39 +127,39 @@ class Firewall:
self.iptables('-A LOG_DROP -p tcp --dport 445 -j DROP')
self.iptables('-A LOG_DROP -p udp --dport 137 -j DROP')
self.iptables('-A LOG_DROP -j LOG --log-level 7 '
'--log-prefix "[ipt][drop]"')
'--log-prefix "[ipt][drop]"')
self.iptables('-A LOG_DROP -j DROP')
self.iptables('-N LOG_ACC')
self.iptables('-A LOG_ACC -j LOG --log-level 7 '
'--log-prefix "[ipt][isok]"')
'--log-prefix "[ipt][isok]"')
self.iptables('-A LOG_ACC -j ACCEPT')
self.iptables('-N PUB_OUT')
self.iptables('-A FORWARD -m set --match-set blacklist src,dst -j DROP')
self.iptables('-A FORWARD -m set --match-set blacklist src,dst '
'-j DROP')
self.iptables('-A FORWARD -m state --state INVALID -g LOG_DROP')
self.iptables('-A FORWARD -m state --state ESTABLISHED,RELATED '
'-j ACCEPT')
'-j ACCEPT')
self.iptables('-A FORWARD -p icmp --icmp-type echo-request '
'-g LOG_ACC')
'-g LOG_ACC')
self.iptables('-A INPUT -m set --match-set blacklist src -j DROP')
self.iptables('-A INPUT -m state --state INVALID -g LOG_DROP')
self.iptables('-A INPUT -i lo -j ACCEPT')
self.iptables('-A INPUT -m state --state ESTABLISHED,RELATED '
'-j ACCEPT')
'-j ACCEPT')
self.iptables('-A OUTPUT -m state --state INVALID -g LOG_DROP')
self.iptables('-A OUTPUT -o lo -j ACCEPT')
self.iptables('-A OUTPUT -m state --state ESTABLISHED,RELATED '
'-j ACCEPT')
'-j ACCEPT')
def postrun(self):
self.iptables('-A PUB_OUT -s 152.66.243.160/27 -p tcp --dport 25 '
'-j LOG_ACC')
'-j LOG_ACC')
self.iptables('-A PUB_OUT -s 152.66.243.160/27 -p tcp --dport 445 '
'-j LOG_ACC')
'-j LOG_ACC')
self.iptables('-A PUB_OUT -p tcp --dport 25 -j LOG_DROP')
self.iptables('-A PUB_OUT -p tcp --dport 445 -j LOG_DROP')
self.iptables('-A PUB_OUT -p udp --dport 445 -j LOG_DROP')
......@@ -171,9 +170,6 @@ class Firewall:
self.iptables('-A OUTPUT -g LOG_DROP')
self.iptables('COMMIT')
def ipt_nat(self):
self.iptablesnat('*nat')
self.iptablesnat(':PREROUTING ACCEPT [0:0]')
......@@ -187,34 +183,37 @@ class Firewall:
dport_sport = self.dportsport(rule, False)
if host.vlan.snat_ip:
self.iptablesnat('-A PREROUTING -d %s %s %s -j DNAT '
'--to-destination %s:%s' % (host.pub_ipv4,
dport_sport, rule.extra, host.ipv4,
rule.nat_dport))
'--to-destination %s:%s' %
(host.pub_ipv4, dport_sport, rule.extra,
host.ipv4, rule.nat_dport))
# rules for machines with dedicated public IP
for host in self.hosts.exclude(shared_ip=True):
if host.pub_ipv4:
self.iptablesnat('-A PREROUTING -d %s -j DNAT '
'--to-destination %s' % (host.pub_ipv4, host.ipv4))
'--to-destination %s' %
(host.pub_ipv4, host.ipv4))
self.iptablesnat('-A POSTROUTING -s %s -j SNAT '
'--to-source %s' % (host.ipv4, host.pub_ipv4))
'--to-source %s' %
(host.ipv4, host.pub_ipv4))
# default NAT rules for VLANs
for s_vlan in self.vlans:
if s_vlan.snat_ip:
for d_vlan in s_vlan.snat_to.all():
self.iptablesnat('-A POSTROUTING -s %s -o %s -j SNAT '
'--to-source %s' % (s_vlan.net_ipv4(),
d_vlan.interface, s_vlan.snat_ip))
'--to-source %s' %
(s_vlan.net_ipv4(), d_vlan.interface,
s_vlan.snat_ip))
# hard-wired rules
self.iptablesnat('-A POSTROUTING -s 10.5.0.0/16 -o vlan0003 -j SNAT '
'--to-source 10.3.255.254') # man elerheto legyen
'--to-source 10.3.255.254') # man elerheto legyen
self.iptablesnat('-A POSTROUTING -o vlan0008 -j SNAT '
'--to-source 10.0.0.247') # wolf network for printing
self.iptablesnat('-A POSTROUTING -s 10.3.0.0/16 -p udp --dport 53 -o vlan0002 -j SNAT '
'--to-source %s' % self.pub.ipv4) # kulonben nem megy a dns man-ban
'--to-source 10.0.0.247') # wolf network for printing
self.iptablesnat('-A POSTROUTING -s 10.3.0.0/16 -p udp --dport 53 '
'-o vlan0002 -j SNAT ''--to-source %s' %
self.pub.ipv4) # kulonben nem megy a dns man-ban
self.iptablesnat('COMMIT')
......@@ -234,7 +233,8 @@ class Firewall:
for d_vlan in self.vlans:
self.iptables('-N %s_%s' % (s_vlan, d_vlan))
self.iptables('-A FORWARD -i %s -o %s -g %s_%s' %
(s_vlan.interface, d_vlan.interface, s_vlan, d_vlan))
(s_vlan.interface, d_vlan.interface, s_vlan,
d_vlan))
# hosts' rules
for i_vlan in self.vlans:
......@@ -263,8 +263,8 @@ class Firewall:
self.RULES = [x.replace('icmp', 'icmpv6') for x in self.RULES]
def __init__(self, IPV6=False):
self.RULES=[]
self.RULES_NAT=[]
self.RULES = []
self.RULES_NAT = []
self.IPV6 = IPV6
self.vlans = models.Vlan.objects.all()
self.hosts = models.Host.objects.all()
......@@ -277,32 +277,37 @@ class Firewall:
def reload(self):
if self.IPV6:
process = subprocess.Popen(['/usr/bin/ssh', 'fw2',
'/usr/bin/sudo', '/sbin/ip6tables-restore', '-c'],
shell=False, stdin=subprocess.PIPE)
'/usr/bin/sudo',
'/sbin/ip6tables-restore', '-c'],
shell=False, stdin=subprocess.PIPE)
process.communicate('\n'.join(self.RULES) + '\n')
else:
process = subprocess.Popen(['/usr/bin/ssh', 'fw2',
'/usr/bin/sudo', '/sbin/iptables-restore', '-c'],
shell=False, stdin=subprocess.PIPE)
'/usr/bin/sudo',
'/sbin/iptables-restore', '-c'],
shell=False, stdin=subprocess.PIPE)
process.communicate('\n'.join(self.RULES) + '\n' +
'\n'.join(self.RULES_NAT) + '\n')
'\n'.join(self.RULES_NAT) + '\n')
def get(self):
if self.IPV6:
return { 'filter': self.RULES, }
return {'filter': self.RULES, }
else:
return { 'filter': self.RULES, 'nat': self.RULES_NAT }
return {'filter': self.RULES, 'nat': self.RULES_NAT}
def show(self):
if self.IPV6:
return '\n'.join(self.RULES) + '\n'
else:
return ('\n'.join(self.RULES) + '\n' +
'\n'.join(self.RULES_NAT) + '\n')
'\n'.join(self.RULES_NAT) + '\n')
def ipset():
week = datetime.now()-timedelta(days=2)
return models.Blacklist.objects.filter(Q(type='tempban', modified_at__gte=week) | Q(type='permban')).values('ipv4', 'reason')
week = datetime.now() - timedelta(days=2)
filter_ban = (Q(type='tempban', modified_at__gte=week) |
Q(type='permban')).values('ipv4', 'reason')
return models.Blacklist.objects.filter(filter_ban)
def ipv6_to_octal(ipv6):
......@@ -319,14 +324,16 @@ def ipv6_to_octal(ipv6):
octets.append(int(part[2:], 16))
return '\\' + '\\'.join(['%03o' % x for x in octets])
def ipv4_to_arpa(ipv4, cname=False):
m2 = re.search(r'^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$', ipv4)
if cname:
return ('%s.dns1.%s.%s.%s.in-addr.arpa' %
(m2.group(4), m2.group(3), m2.group(2), m2.group(1)))
(m2.group(4), m2.group(3), m2.group(2), m2.group(1)))
else:
return ('%s.%s.%s.%s.in-addr.arpa' %
(m2.group(4), m2.group(3), m2.group(2), m2.group(1)))
(m2.group(4), m2.group(3), m2.group(2), m2.group(1)))
def ipv6_to_arpa(ipv6):
while len(ipv6.split(':')) < 8:
......@@ -355,11 +362,11 @@ def ipv6_to_arpa(ipv6):
def dns():
vlans = models.Vlan.objects.all()
regex = re.compile(r'^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$')
# regex = re.compile(r'^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$')
DNS = []
for i_vlan in vlans:
m = regex.search(i_vlan.net4)
# m = regex.search(i_vlan.net4)
rev = i_vlan.reverse_domain
for i_host in i_vlan.host_set.all():
......@@ -367,31 +374,32 @@ def dns():
not i_host.shared_ip else i_host.ipv4)
i = ipv4.split('.', 4)
reverse = (i_host.reverse if i_host.reverse and
len(i_host.reverse) else i_host.get_fqdn())
len(i_host.reverse) else i_host.get_fqdn())
# ipv4
if i_host.ipv4:
DNS.append("^%s:%s:%s" % (
(rev % { 'a': int(i[0]), 'b': int(i[1]), 'c': int(i[2]),
'd': int(i[3]) }),
(rev % {'a': int(i[0]), 'b': int(i[1]), 'c': int(i[2]),
'd': int(i[3])}),
reverse, models.settings['dns_ttl']))
# ipv6
if i_host.ipv6:
DNS.append("^%s:%s:%s" % (ipv6_to_arpa(i_host.ipv6),
reverse, models.settings['dns_ttl']))
reverse, models.settings['dns_ttl']))
for domain in models.Domain.objects.all():
DNS.append("Z%s:%s:support.ik.bme.hu::::::%s" % (domain.name,
settings['dns_hostname'], models.settings['dns_ttl']))
DNS.append("Z%s:%s:support.ik.bme.hu::::::%s" %
(domain.name, settings['dns_hostname'],
models.settings['dns_ttl']))
for r in models.Record.objects.all():
d = r.get_data()
if d['type'] == 'A':
DNS.append("+%s:%s:%s" % (d['name'], d['address'], d['ttl']))
elif d['type'] == 'AAAA':
DNS.append(":%s:28:%s:%s" % (d['name'],
ipv6_to_octal(d['address']), d['ttl']))
DNS.append(":%s:28:%s:%s" %
(d['name'], ipv6_to_octal(d['address']), d['ttl']))
elif d['type'] == 'NS':
DNS.append("&%s::%s:%s" % (d['name'], d['address'], d['ttl']))
elif d['type'] == 'CNAME':
......@@ -399,15 +407,16 @@ def dns():
elif d['type'] == 'MX':
mx = d['address'].split(':', 2)
DNS.append("@%(fqdn)s::%(mx)s:%(dist)s:%(ttl)s" %
{'fqdn': d['name'], 'mx': mx[1], 'dist': mx[0],
'ttl': d['ttl']})
{'fqdn': d['name'], 'mx': mx[1], 'dist': mx[0],
'ttl': d['ttl']})
elif d['type'] == 'PTR':
DNS.append("^%s:%s:%s" % (d['name'], d['address'], d['ttl']))
return DNS
process = subprocess.Popen(['/usr/bin/ssh', 'tinydns@%s' %
settings['dns_hostname']], shell=False, stdin=subprocess.PIPE)
process.communicate("\n".join(DNS)+"\n")
settings['dns_hostname']],
shell=False, stdin=subprocess.PIPE)
process.communicate("\n".join(DNS) + "\n")
# print "\n".join(DNS)+"\n"
......@@ -420,10 +429,11 @@ def prefix_to_mask(prefix):
t[i] = 256 - (2 ** ((i + 1) * 8 - prefix))
return ".".join([str(i) for i in t])
def dhcp():
vlans = models.Vlan.objects.all()
regex = re.compile(r'^([0-9]+)\.([0-9]+)\.[0-9]+\.[0-9]+\s+'
r'([0-9]+)\.([0-9]+)\.[0-9]+\.[0-9]+$')
r'([0-9]+)\.([0-9]+)\.[0-9]+\.[0-9]+$')
DHCP = []
# /tools/dhcp3/dhcpd.conf.generated
......@@ -432,7 +442,7 @@ def dhcp():
if(i_vlan.dhcp_pool):
m = regex.search(i_vlan.dhcp_pool)
if(m or i_vlan.dhcp_pool == "manual"):
DHCP.append ('''
DHCP.append('''
# %(name)s - %(interface)s
subnet %(net)s netmask %(netmask)s {
%(extra)s;
......@@ -444,7 +454,7 @@ def dhcp():
authoritative;
filename \"pxelinux.0\";
allow bootp; allow booting;
}''' % {
}''' % {
'net': i_vlan.net4,
'netmask': prefix_to_mask(i_vlan.prefix4),
'domain': i_vlan.domain,
......@@ -452,14 +462,14 @@ def dhcp():
'ntp': i_vlan.ipv4,
'dnsserver': settings['rdns_ip'],
'extra': ("range %s" % i_vlan.dhcp_pool
if m else "deny unknown-clients"),
if m else "deny unknown-clients"),
'interface': i_vlan.interface,
'name': i_vlan.name,
'tftp': i_vlan.ipv4
})
for i_host in i_vlan.host_set.all():
DHCP.append ('''
DHCP.append('''
host %(hostname)s {
hardware ethernet %(mac)s;
fixed-address %(ipv4)s;
......@@ -471,23 +481,8 @@ def dhcp():
return DHCP
process = subprocess.Popen(['/usr/bin/ssh', 'fw2',
'cat > /tools/dhcp3/dhcpd.conf.generated;'
'sudo /etc/init.d/isc-dhcp-server restart'], shell=False,
stdin=subprocess.PIPE)
'cat > /tools/dhcp3/dhcpd.conf.generated;'
'sudo /etc/init.d/isc-dhcp-server restart'],
shell=False, stdin=subprocess.PIPE)
# print "\n".join(DHCP)+"\n"
process.communicate("\n".join(DHCP)+"\n")
'''
i=2
for mac, name, ipend in [("18:a9:05:64:19:aa", "mega6", 16), ("00:1e:0b:e9:79:1e", "blade1", 21), ("00:22:64:9c:fd:34", "blade2", 22), ("00:1e:0b:ec:65:46", "blade3", 23), ("b4:b5:2f:61:d2:5a", "cloud-man", 1)]:
h1 = models.Host(hostname= name, vlan=models.Vlan.objects.get(vid=3), mac=mac, ipv4="10.3.1.%d" % ipend, ipv6="2001:738:2001:4031:3:1:%d:0" % ipend, owner=auth.models.User.objects.get(username="bd"))
try:
h1.save()
h1.groups.add(models.Group.objects.get(name="netezhet manbol"))
h1.save()
# i = i + 1
except:
print "nemok %s" % name
'''
process.communicate("\n".join(DHCP) + "\n")
......@@ -4,7 +4,9 @@ from django.contrib.auth.models import User
from django.db import models
from django.forms import ValidationError
from django.utils.translation import ugettext_lazy as _
from firewall.fields import *
from firewall.fields import (MACAddressField, val_alfanum, val_reverse_domain,
val_domain, val_ipv4, val_ipv6, val_mx,
ipv4_2_ipv6)
from django.core.validators import MinValueValidator, MaxValueValidator
import django.conf
from django.db.models.signals import post_save
......@@ -85,7 +87,7 @@ class Rule(models.Model):
"(if type is vlan)."))
vlangroup = models.ForeignKey('VlanGroup', related_name="rules",
blank=True, null=True, verbose_name=_(
"vlan group"),
"vlan group"),
help_text=_("Group of vlans the rule "
"applies to (if type is vlan)."))
host = models.ForeignKey('Host', related_name="rules", blank=True,
......@@ -185,15 +187,17 @@ class Vlan(models.Model):
ipv4 = models.GenericIPAddressField(protocol='ipv4', unique=True,
verbose_name=_('IPv4 address'),
help_text=_(
'The IPv4 address of the gateway. '
'Recommended value is the last valid '
'address of the subnet, for example '
'10.4.255.254 for 10.4.0.0/16.'))
'The IPv4 address of the gateway. '
'Recommended value is the last '
'valid address of the subnet, '
'for example '
'10.4.255.254 for 10.4.0.0/16.'))
ipv6 = models.GenericIPAddressField(protocol='ipv6',
unique=True,
verbose_name=_('IPv6 address'),
help_text=_(
'The IPv6 address of the gateway.'))
'The IPv6 address of the '
'gateway.'))
snat_ip = models.GenericIPAddressField(protocol='ipv4', blank=True,
null=True,
verbose_name=_('NAT IP address'),
......
from celery.task import Task, PeriodicTask
import celery
from django.core.cache import cache
import os
import time
from firewall.fw import *
import django.conf
settings = django.conf.settings.FIREWALL_SETTINGS
@celery.task
def reload_dns_task(data):
pass
@celery.task
def reload_firewall_task(data4, data6):
pass
@celery.task
def reload_dhcp_task(data):
pass
@celery.task
def reload_blacklist_task(data):
pass
class Periodic(PeriodicTask):
run_every = timedelta(seconds=10)
......@@ -48,6 +54,7 @@ class Periodic(PeriodicTask):
reload_blacklist_task.delay(list(ipset()))
print "blacklist ujratoltese kesz"
class ReloadTask(Task):
def run(self, type='Host'):
......@@ -64,4 +71,3 @@ class ReloadTask(Task):
cache.add("blacklist_lock", "true", 30)
print type
from django.test import TestCase
from admin import HostAdmin
class MockInstance:
def __init__(self, groups):
self.groups = MockGroups(groups)
class MockGroup:
def __init__(self, name):
self.name = name
class MockGroups:
def __init__(self, groups):
self.groups = groups
......@@ -16,6 +19,7 @@ class MockGroups:
def all(self):
return self.groups
class HostAdminTestCase(TestCase):
def test_no_groups(self):
instance = MockInstance([])
......@@ -29,6 +33,6 @@ class HostAdminTestCase(TestCase):
def test_multiple_groups(self):
instance = MockInstance([MockGroup("alma"),
MockGroup("korte"), MockGroup("szilva")])
MockGroup("korte"), MockGroup("szilva")])
l = HostAdmin.list_groups(instance)
self.assertEqual(l, "alma, korte, szilva")
......@@ -2,12 +2,10 @@ import base64
import datetime
import json
import re
import sys
from django.conf import settings
from django.db import IntegrityError
from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.template.loader import render_to_string
from django.utils import translation
from django.utils.timezone import utc
......@@ -15,13 +13,13 @@ from django.utils.translation import ugettext_lazy as _
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from celery.task.control import inspect
from tasks import *
from firewall.fw import *
from firewall.models import *
from one.tasks import SendMailTask
def reload_firewall(request):
if request.user.is_authenticated():
if request.user.is_superuser:
......@@ -34,34 +32,46 @@ def reload_firewall(request):
html = _("Dear anonymous, you've not signed in yet!")
return HttpResponse(html)
@csrf_exempt
@require_POST
def firewall_api(request):
try:
data=json.loads(base64.b64decode(request.POST["data"]))
data = json.loads(base64.b64decode(request.POST["data"]))
command = request.POST["command"]
if data["password"] != "bdmegintelrontottaanetet":
raise Exception(_("Wrong password."))
if command == "blacklist":
obj, created = Blacklist.objects.get_or_create(ipv4=data["ip"])
obj.reason=data["reason"]
obj.snort_message=data["snort_message"]
obj.reason = data["reason"]
obj.snort_message = data["snort_message"]
if created:
try:
obj.host = Host.objects.get(ipv4=data["ip"])
user = obj.host.owner
lang = user.person_set.all()[0].language
translation.activate(lang)
msg = render_to_string('mails/notification-ban-now.txt',
{ 'user': user,
'bl': obj,
'instance:': obj.host.instance_set.get(),
'url': settings.CLOUD_URL} )
SendMailTask.delay(to=obj.host.owner.email, subject='[IK Cloud] %s' % obj.host.instance_set.get().name, msg=msg, sender=u'cloud@ik.bme.hu')
except (Host.DoesNotExist, ValidationError, IntegrityError, AttributeError):
msg = render_to_string(
'mails/notification-ban-now.txt',
{
'user': user,
'bl': obj,
'instance:': obj.host.instance_set.get(),
'url': settings.CLOUD_URL
})
SendMailTask.delay(
to=obj.host.owner.email,
subject='[IK Cloud] %s' %
obj.host.instance_set.get().name,
msg=msg, sender=u'cloud@ik.bme.hu')
except (Host.DoesNotExist, ValidationError,
IntegrityError, AttributeError):
pass
if obj.type == 'tempwhite' and obj.modified_at + datetime.timedelta(minutes=1) < datetime.datetime.utcnow().replace(tzinfo=utc):
modified = obj.modified_at + datetime.timedelta(minutes=1)
now = datetime.dateime.utcnow().replace(tzinfo=utc)
if obj.type == 'tempwhite' and modified < now:
obj.type = 'tempban'
obj.save()
return HttpResponse(unicode(_("OK")))
......@@ -75,27 +85,26 @@ def firewall_api(request):
data["owner"] = "opennebula"
owner = auth.models.User.objects.get(username=data["owner"])
host = Host(hostname=data["hostname"],
vlan=Vlan.objects.get(name=data["vlan"]),
mac=data["mac"], ipv4=data["ip"], owner=owner,
description=data["description"], pub_ipv4=
vlan=Vlan.objects.get(name=data["vlan"]),
mac=data["mac"], ipv4=data["ip"], owner=owner,
description=data["description"], pub_ipv4=
Vlan.objects.get(name=data["vlan"]).snat_ip,
shared_ip=True)
shared_ip=True)
host.full_clean()
host.save()
host.enable_net()
for p in data["portforward"]:
host.add_port(proto=p["proto"],
public=int(p["public_port"]),
private=int(p["private_port"]))
host.add_port(proto=p["proto"], public=int(p["public_port"]),
private=int(p["private_port"]))
elif command == "destroy":
data["owner"] = "opennebula"
print data["hostname"]
owner = auth.models.User.objects.get(username=data["owner"])
host = Host.objects.get(hostname=data["hostname"],
owner=owner)
owner=owner)
host.delete()
else:
......
......@@ -9,4 +9,4 @@ setuid cloud
env DJANGO_SETTINGS_MODULE=cloud.settings.dev
env DJANGO_DB_PASSWORD=asjklddfjklqjf
env DJANGO_SECRET_KEY=asjklddfjklqjfasjklddfjklqjfasjklddfjklqjf
exec /opt/webadmin/cloud/manage.py celery worker --loglevel=info -c 1 -Q local
exec /opt/webadmin/cloud/manage.py celery worker --loglevel=info -c 1 -Q local -B
#!/bin/bash
nev=dev-$(hostname|tr -dc 0-9)
sudo sed -i /etc/hosts -e "/127.0.1.1/ s/.*/127.0.1.1 $nev.cloud.ik.bme.hu $nev/"
sudo tee /etc/hostname <<<$nev
sudo hostname $nev
sudo /etc/init.d/rabbitmq-server stop || true
sudo /etc/init.d/rabbitmq-server start
sudo pip install django_extensions
sudo pip install django-nose
sudo pip install django-debug-toolbar
......@@ -50,7 +57,13 @@ user_manager = FAKEUserManager.sh
temp_dir = /tmp/dl
EOF
for i in cloudstore toplist django
#Refresh oned config
sudo cp /opt/webadmin/cloud/miscellaneous/devenv/oned.conf /etc/one/oned.conf
sudo rm -f /opt/update_state
sudo ln -s /opt/webadmin/cloud/miscellaneous/celery/opennebula_celery.py /opt/update_state
sudo /etc/init.d/opennebula restart
for i in cloudstore toplist django celeryone celery
do
sudo cp /opt/webadmin/cloud/miscellaneous/devenv/$i.conf /etc/init/
sudo start $i
......
#*******************************************************************************
# OpenNebula Configuration file
#*******************************************************************************
#*******************************************************************************
# Daemon configuration attributes
#-------------------------------------------------------------------------------
# MANAGER_TIMER: Time in seconds the core uses to evaluate periodical functions.
# HOST_MONITORING_INTERVAL and VM_POLLING_INTERVAL can not have smaller values
# than MANAGER_TIMER.
#
# HOST_MONITORING_INTERVAL: Time in seconds between host monitorization.
# HOST_PER_INTERVAL: Number of hosts monitored in each interval.
# HOST_MONITORING_EXPIRATION_TIME: Time, in seconds, to expire monitoring
# information. Use 0 to disable HOST monitoring recording.
#
# VM_POLLING_INTERVAL: Time in seconds between virtual machine monitorization.
# Use 0 to disable VM monitoring.
# VM_PER_INTERVAL: Number of VMs monitored in each interval.
# VM_MONITORING_EXPIRATION_TIME: Time, in seconds, to expire monitoring
# information. Use 0 to disable VM monitoring recording.
#
# SCRIPTS_REMOTE_DIR: Remote path to store the monitoring and VM management
# scripts.
#
# PORT: Port where oned will listen for xmlrpc calls.
#
# DB: Configuration attributes for the database backend
# backend : can be sqlite or mysql (default is sqlite)
# server : (mysql) host name or an IP address for the MySQL server
# port : (mysql) port for the connection to the server.
# If set to 0, the default port is used.
# user : (mysql) user's MySQL login ID
# passwd : (mysql) the password for user
# db_name : (mysql) the database name
#
# VNC_BASE_PORT: VNC ports for VMs can be automatically set to VNC_BASE_PORT +
# VMID
#
# DEBUG_LEVEL: 0 = ERROR, 1 = WARNING, 2 = INFO, 3 = DEBUG
#*******************************************************************************
#MANAGER_TIMER = 30
HOST_MONITORING_INTERVAL = 600
#HOST_PER_INTERVAL = 15
#HOST_MONITORING_EXPIRATION_TIME = 86400
VM_POLLING_INTERVAL = 600
#VM_PER_INTERVAL = 5
#VM_MONITORING_EXPIRATION_TIME = 86400
SCRIPTS_REMOTE_DIR=/var/tmp/one
PORT = 2633
DB = [ backend = "sqlite" ]
# Sample configuration for MySQL
# DB = [ backend = "mysql",
# server = "localhost",
# port = 0,
# user = "oneadmin",
# passwd = "oneadmin",
# db_name = "opennebula" ]
VNC_BASE_PORT = 5900
DEBUG_LEVEL = 3
#*******************************************************************************
# Physical Networks configuration
#*******************************************************************************
# NETWORK_SIZE: Here you can define the default size for the virtual networks
#
# MAC_PREFIX: Default MAC prefix to be used to create the auto-generated MAC
# addresses is defined here (this can be overrided by the Virtual Network
# template)
#*******************************************************************************
NETWORK_SIZE = 254
MAC_PREFIX = "02:00"
#*******************************************************************************
# DataStore Configuration
#*******************************************************************************
# DATASTORE_LOCATION: *Default* Path for Datastores in the hosts. It IS the
# same for all the hosts in the cluster. DATASTORE_LOCATION IS ONLY FOR THE
# HOSTS AND *NOT* THE FRONT-END. It defaults to /var/lib/one/datastores (or
# $ONE_LOCATION/var/datastores in self-contained mode)
#
# You can define a different DATASTORE_LOCATION in each cluster by updating
# its properties with onecluster update.
#
# DEFAULT_IMAGE_TYPE: This can take values
# OS Image file holding an operating system
# CDROM Image file holding a CDROM
# DATABLOCK Image file holding a datablock,
# always created as an empty block
# DEFAULT_DEVICE_PREFIX: This can be set to
# hd IDE prefix
# sd SCSI
# xvd XEN Virtual Disk
# vd KVM virtual disk
#*******************************************************************************
DATASTORE_LOCATION = /var/lib/one/datastores
DEFAULT_IMAGE_TYPE = "OS"
DEFAULT_DEVICE_PREFIX = "hd"
#*******************************************************************************
# Information Driver Configuration
#*******************************************************************************
# You can add more information managers with different configurations but make
# sure it has different names.
#
# name : name for this information manager
#
# executable: path of the information driver executable, can be an
# absolute path or relative to $ONE_LOCATION/lib/mads (or
# /usr/lib/one/mads/ if OpenNebula was installed in /)
#
# arguments : for the driver executable, usually a probe configuration file,
# can be an absolute path or relative to $ONE_LOCATION/etc (or
# /etc/one/ if OpenNebula was installed in /)
#*******************************************************************************
#-------------------------------------------------------------------------------
# KVM Information Driver Manager Configuration
# -r number of retries when monitoring a host
# -t number of threads, i.e. number of hosts monitored at the same time
#-------------------------------------------------------------------------------
IM_MAD = [
name = "im_kvm",
executable = "one_im_ssh",
arguments = "-r 0 -t 15 kvm" ]
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# XEN Information Driver Manager Configuration
# -r number of retries when monitoring a host
# -t number of threads, i.e. number of hosts monitored at the same time
#-------------------------------------------------------------------------------
#IM_MAD = [
# name = "im_xen",
# executable = "one_im_ssh",
# arguments = "xen" ]
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# VMware Information Driver Manager Configuration
# -r number of retries when monitoring a host
# -t number of threads, i.e. number of hosts monitored at the same time
#-------------------------------------------------------------------------------
#IM_MAD = [
# name = "im_vmware",
# executable = "one_im_sh",
# arguments = "-c -t 15 -r 0 vmware" ]
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# EC2 Information Driver Manager Configuration
#-------------------------------------------------------------------------------
#IM_MAD = [
# name = "im_ec2",
# executable = "one_im_ec2",
# arguments = "im_ec2/im_ec2.conf" ]
#-------------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Ganglia Information Driver Manager Configuration
#-----------------------------------------------------------------------------
#IM_MAD = [
# name = "im_ganglia",
# executable = "one_im_sh",
# arguments = "ganglia" ]
#-----------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# Dummy Information Driver Manager Configuration
#-------------------------------------------------------------------------------
#IM_MAD = [ name="im_dummy", executable="one_im_dummy"]
#-------------------------------------------------------------------------------
#*******************************************************************************
# Virtualization Driver Configuration
#*******************************************************************************
# You can add more virtualization managers with different configurations but
# make sure it has different names.
#
# name : name of the virtual machine manager driver
#
# executable: path of the virtualization driver executable, can be an
# absolute path or relative to $ONE_LOCATION/lib/mads (or
# /usr/lib/one/mads/ if OpenNebula was installed in /)
#
# arguments : for the driver executable
#
# default : default values and configuration parameters for the driver, can
# be an absolute path or relative to $ONE_LOCATION/etc (or
# /etc/one/ if OpenNebula was installed in /)
#
# type : driver type, supported drivers: xen, kvm, xml
#*******************************************************************************
#-------------------------------------------------------------------------------
# KVM Virtualization Driver Manager Configuration
# -r number of retries when monitoring a host
# -t number of threads, i.e. number of hosts monitored at the same time
# -l <actions[=command_name]> actions executed locally, command can be
# overridden for each action.
# Valid actions: deploy, shutdown, cancel, save, restore, migrate, poll
# An example: "-l migrate,poll=poll_ganglia,save"
#-------------------------------------------------------------------------------
VM_MAD = [
name = "vmm_kvm",
executable = "one_vmm_exec",
arguments = "-t 15 -r 0 kvm",
default = "vmm_exec/vmm_exec_kvm.conf",
type = "kvm" ]
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# XEN Virtualization Driver Manager Configuration
# -r number of retries when monitoring a host
# -t number of threads, i.e. number of hosts monitored at the same time
# -l <actions[=command_name]> actions executed locally, command can be
# overridden for each action.
# Valid actions: deploy, shutdown, cancel, save, restore, migrate, poll
# An example: "-l migrate,poll=poll_ganglia,save"
#-------------------------------------------------------------------------------
#VM_MAD = [
# name = "vmm_xen",
# executable = "one_vmm_exec",
# arguments = "-t 15 -r 0 xen",
# default = "vmm_exec/vmm_exec_xen.conf",
# type = "xen" ]
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# VMware Virtualization Driver Manager Configuration
# -r number of retries when monitoring a host
# -t number of threads, i.e. number of hosts monitored at the same time
#-------------------------------------------------------------------------------
#VM_MAD = [
# name = "vmm_vmware",
# executable = "one_vmm_sh",
# arguments = "-t 15 -r 0 vmware -s sh",
# default = "vmm_exec/vmm_exec_vmware.conf",
# type = "vmware" ]
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# EC2 Virtualization Driver Manager Configuration
# arguments: default values for the EC2 driver, can be an absolute path or
# relative to $ONE_LOCATION/etc (or /etc/one/ if OpenNebula was
# installed in /).
#-------------------------------------------------------------------------------
#VM_MAD = [
# name = "vmm_ec2",
# executable = "one_vmm_ec2",
# arguments = "vmm_ec2/vmm_ec2.conf",
# type = "xml" ]
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# Dummy Virtualization Driver Configuration
#-------------------------------------------------------------------------------
#VM_MAD = [ name="vmm_dummy", executable="one_vmm_dummy", type="xml" ]
#-------------------------------------------------------------------------------
#*******************************************************************************
# Transfer Manager Driver Configuration
#*******************************************************************************
# You can add more transfer managers with different configurations but make
# sure it has different names.
# name : name for this transfer driver
#
# executable: path of the transfer driver executable, can be an
# absolute path or relative to $ONE_LOCATION/lib/mads (or
# /usr/lib/one/mads/ if OpenNebula was installed in /)
# arguments :
# -t: number of threads, i.e. number of transfers made at the same time
# -d: list of transfer drivers separated by commas, if not defined all the
# drivers available will be enabled
#*******************************************************************************
TM_MAD = [
executable = "one_tm",
arguments = "-t 15 -d dummy,lvm,shared,qcow2,ssh,vmfs,iscsi" ]
#*******************************************************************************
# Datastore Driver Configuration
#*******************************************************************************
# Drivers to manage the datastores, specialized for the storage backend
# executable: path of the transfer driver executable, can be an
# absolute path or relative to $ONE_LOCATION/lib/mads (or
# /usr/lib/one/mads/ if OpenNebula was installed in /)
#
# arguments : for the driver executable
# -t number of threads, i.e. number of repo operations at the same time
# -d datastore mads separated by commas
#*******************************************************************************
DATASTORE_MAD = [
executable = "one_datastore",
arguments = "-t 15 -d dummy,fs,vmware,vmfs,iscsi,lvm"
]
#*******************************************************************************
# Hook Manager Configuration
#*******************************************************************************
# The Driver (HM_MAD)
# -----------------------------------------------
#
# Used to execute the Hooks:
# executable: path of the hook driver executable, can be an
# absolute path or relative to $ONE_LOCATION/lib/mads (or
# /usr/lib/one/mads/ if OpenNebula was installed in /)
#
# arguments : for the driver executable, can be an absolute path or relative
# to $ONE_LOCATION/etc (or /etc/one/ if OpenNebula was installed
# in /)
#
# Virtual Machine Hooks (VM_HOOK)
# -------------------------------
#
# Defined by:
# name : for the hook, useful to track the hook (OPTIONAL)
# on : when the hook should be executed,
# - CREATE, when the VM is created (onevm create)
# - PROLOG, when the VM is in the prolog state
# - RUNNING, after the VM is successfully booted
# - UNKNOWN, when the VM is in the unknown state
# - SHUTDOWN, after the VM is shutdown
# - STOP, after the VM is stopped (including VM image transfers)
# - DONE, after the VM is deleted or shutdown
# - FAILED, when the VM enters the failed state
# command : path is relative to $ONE_LOCATION/var/remotes/hook
# (self-contained) or to /var/lib/one/remotes/hook (system-wide).
# That directory will be copied on the hosts under
# SCRIPTS_REMOTE_DIR. It can be an absolute path that must exist
# on the target host
# arguments : for the hook. You can access to VM information with $
# - $ID, the ID of the virtual machine
# - $TEMPLATE, the VM template in xml and base64 encoded
# remote : values,
# - YES, The hook is executed in the host where the VM was
# allocated
# - NO, The hook is executed in the OpenNebula server (default)
#
# Host Hooks (HOST_HOOK)
# -------------------------------
#
# Defined by:
# name : for the hook, useful to track the hook (OPTIONAL)
# on : when the hook should be executed,
# - CREATE, when the Host is created (onehost create)
# - ERROR, when the Host enters the error state
# - DISABLE, when the Host is disabled
# command : path is relative to $ONE_LOCATION/var/remotes/hook
# (self-contained) or to /var/lib/one/remotes/hook (system-wide).
# That directory will be copied on the hosts under
# SCRIPTS_REMOTE_DIR. It can be an absolute path that must exist
# on the target host.
# arguments : for the hook. You can use the following Host information:
# - $ID, the ID of the host
# - $TEMPLATE, the Host template in xml and base64 encoded
# remote : values,
# - YES, The hook is executed in the host
# - NO, The hook is executed in the OpenNebula server (default)
#
# Virtual Network (VNET_HOOK)
# User (USER_HOOK)
# Group (GROUP_HOOK)
# Image (IMAGE_HOOK)
# -------------------------------
#
# These hooks are executed when one of the referring entities are created or
# removed. Each hook is defined by:
# name : for the hook, useful to track the hook (OPTIONAL)
# on : when the hook should be executed,
# - CREATE, when the vnet is created
# - REMOVE, when the vnet is removed
# command : path is relative to $ONE_LOCATION/var/remotes/hook
# (self-contained) or to /var/lib/one/remotes/hook (system-wide).
# That directory will be copied on the hosts under
# SCRIPTS_REMOTE_DIR. It can be an absolute path that must exist
# on the target host.
# arguments : for the hook. You can use the following Host information:
# - $ID, the ID of the host
# - $TEMPLATE, the vnet template in xml and base64 encoded
#-------------------------------------------------------------------------------
HM_MAD = [
executable = "one_hm" ]
#*******************************************************************************
# Fault Tolerance Hooks
#*******************************************************************************
# This hook is used to perform recovery actions when a host fails.
# Script to implement host failure tolerance
# It can be set to
# -r resubmit VMs running in the host
# -d delete VMs running in the host
# Additional flags
# -f force resubmission of suspended VMs
# -p <n> avoid resubmission if host comes
# back after n monitoring cycles
#*******************************************************************************
#
#HOST_HOOK = [
# name = "error",
# on = "ERROR",
# command = "ft/host_error.rb",
# arguments = "$ID -r",
# remote = "no" ]
#-------------------------------------------------------------------------------
# These two hooks can be used to automatically delete or resubmit VMs that reach
# the "failed" state. This way, the administrator doesn't have to interact
# manually to release its resources or retry the deployment.
#
#
# Only one of them should be uncommented.
#-------------------------------------------------------------------------------
#
#VM_HOOK = [
# name = "on_failure_delete",
# on = "FAILED",
# command = "/usr/bin/env onevm delete",
# arguments = "$ID" ]
#
VM_HOOK = [
name = "boot_url_hook",
on = "RUNNING",
command = "/opt/boot_url.py",
arguments = "$TEMPLATE" ]
VM_HOOK = [
name = "django",
on = "CREATE",
command = "/opt/update_state",
arguments = "$ID"
]
VM_HOOK = [
name = "django",
on = "RUNNING",
command = "/opt/update_state",
arguments = "$ID"
]
VM_HOOK = [
name = "django",
on = "SHUTDOWN",
command = "/opt/update_state",
arguments = "$ID"
]
VM_HOOK = [
name = "django",
on = "STOP",
command = "/opt/update_state",
arguments = "$ID"
]
VM_HOOK = [
name = "django",
on = "DONE",
command = "/opt/update_state",
arguments = "$ID"
]
VM_HOOK = [
name = "django",
on = "FAILED",
command = "/opt/update_state",
arguments = "$ID"
]
VM_HOOK = [
name = "django",
on = "UNKNOWN",
command = "/opt/update_state",
arguments = "$ID UNKNOWN"
]
#-------------------------------------------------------------------------------
#*******************************************************************************
# Auth Manager Configuration
#*******************************************************************************
# AUTH_MAD: The Driver that will be used to authenticate (authn) and
# authorize (authz) OpenNebula requests. If defined OpenNebula will use the
# built-in auth policies.
#
# executable: path of the auth driver executable, can be an
# absolute path or relative to $ONE_LOCATION/lib/mads (or
# /usr/lib/one/mads/ if OpenNebula was installed in /)
#
# authn : list of authentication modules separated by commas, if not
# defined all the modules available will be enabled
# authz : list of authentication modules separated by commas
#
# SESSION_EXPIRATION_TIME: Time in seconds to keep an authenticated token as
# valid. During this time, the driver is not used. Use 0 to disable session
# caching
#
# ENABLE_OTHER_PERMISSIONS: Whether or not users can set the permissions for
# 'other', so publishing or sharing resources with others. Users in the oneadmin
# group will still be able to change these permissions. Values: YES or NO.
#*******************************************************************************
AUTH_MAD = [
executable = "one_auth_mad",
authn = "ssh,x509,ldap,server_cipher,server_x509"
]
SESSION_EXPIRATION_TIME = 900
#ENABLE_OTHER_PERMISSIONS = "YES"
#*******************************************************************************
# Restricted Attributes Configuration
#*******************************************************************************
# The following attributes are restricted to users outside the oneadmin group
#*******************************************************************************
VM_RESTRICTED_ATTR = "CONTEXT/FILES"
VM_RESTRICTED_ATTR = "NIC/MAC"
VM_RESTRICTED_ATTR = "NIC/VLAN_ID"
VM_RESTRICTED_ATTR = "RANK"
IMAGE_RESTRICTED_ATTR = "SOURCE"
......@@ -64,13 +64,17 @@ class UserCloudDetails(models.Model):
help_text=_('Disk quota in mebibytes.'))
def reset_keys(self):
"""Deprecated. Use reset_ssh_keys instead."""
self.reset_ssh_keys()
def reset_ssh_keys(self):
"""Delete old SSH key pair and generate new one."""
pri, pub = keygen()
self.ssh_private_key = pri
try:
self.ssh_key.key = pub
except:
except AttributeError:
self.ssh_key = SshKey(user=self.user, key=pub)
self.ssh_key.save()
self.ssh_key_id = self.ssh_key.id
......@@ -79,40 +83,45 @@ class UserCloudDetails(models.Model):
def reset_smb(self):
"""Generate new Samba password."""
self.smb_password = pwgen()
self.save()
def get_weighted_instance_count(self):
states = ['ACTIVE', 'PENDING']
credits = [i.template.instance_type.credit
for i in self.user.instance_set.all()
if i.state in ('ACTIVE', 'PENDING', )]
for i in self.user.instance_set.filter(state__in=states)]
return sum(credits)
def get_instance_pc(self):
return 100 * self.get_weighted_instance_count() / self.instance_quota
"""Get what percent of the user's instance quota is in use."""
inst_quota = self.instance_quota
if inst_quota <= 0:
return 100
else:
return 100 * self.get_weighted_instance_count() / inst_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
credits = [s.template.instance_type.credit * s.instance_limit
for s in Share.objects.filter(owner=self.user)]
return sum(credits)
def get_share_pc(self):
assert self.share_quota > 0
return 100 * self.get_weighted_share_count() / self.share_quota
"""Get what percent of the user's share quota is in use."""
share_quota = self.share_quota
if share_quota <= 0:
return 100
else:
return 100 * self.get_weighted_share_count() / share_quota
def set_quota(sender, instance, created, **kwargs):
try:
if not StoreApi.userexist(instance.user.username):
try:
password = instance.smb_password
quota = instance.disk_quota * 1024
key_list = [key.key for key in instance.user.sshkey_set.all()]
except:
pass
password = instance.smb_password
quota = instance.disk_quota * 1024
key_list = [k.key for k in instance.user.sshkey_set.all()]
# Create user
if not StoreApi.createuser(instance.user.username, password,
key_list, quota):
pass
StoreApi.createuser(instance.user.username, password, key_list,
quota)
else:
StoreApi.set_quota(instance.user.username,
instance.disk_quota * 1024)
......@@ -124,7 +133,7 @@ post_save.connect(set_quota, sender=UserCloudDetails)
def reset_keys(sender, instance, created, **kwargs):
if created:
instance.reset_smb()
instance.reset_keys()
instance.reset_ssh_keys()
post_save.connect(reset_keys, sender=UserCloudDetails)
......@@ -139,7 +148,7 @@ class OpenSshKeyValidator(object):
def __call__(self, value):
try:
value = "%s comment" % value
value = value + ' comment'
type, key_string, comment = value.split(None, 2)
if type not in self.valid_types:
raise ValidationError(_('OpenSSH key type %s is not '
......@@ -205,10 +214,10 @@ class Share(models.Model):
'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')
'instances launchable '
'by a single user.'))
owner = models.ForeignKey(User, null=True, blank=True,
related_name='share_set')
class Meta:
ordering = ['group', 'template', 'owner', ]
......@@ -217,6 +226,9 @@ class Share(models.Model):
@classmethod
def extend_type(cls, t):
"""Extend the share's type descriptor with absolute deletion and
suspension time values based on the current time and intervals
already set."""
t['deletex'] = (datetime.now() + td(seconds=1) + t['delete']
if t['delete'] else None)
t['suspendx'] = (datetime.now() + td(seconds=1) + t['suspend']
......
from django.test import TestCase
from django.contrib.auth.models import User
from models import Disk, Instance, InstanceType, Network, Template, UserCloudDetails
class ViewsTestCase(TestCase):
def test_index(self):
'''Test whether index is reachable.'''
resp = self.client.get('/', follow=True)
self.assertEqual(resp.status_code, 200)
class UserCloudDetailsTestCase(TestCase):
def setUp(self):
user = User.objects.create(username="testuser",
password="testpass", email="test@mail.com",
first_name="Test", last_name="User")
disk1 = Disk.objects.create(name="testdsk1")
insttype = InstanceType.objects.create(name="testtype", CPU=4,
RAM=4096, credit=4)
ntwrk = Network.objects.create(name="testntwrk", nat=False,
public=True)
tmplt1 = Template.objects.create(name="testtmplt1", disk=disk1,
instance_type=insttype, network=ntwrk, owner=user)
tmplt2 = Template.objects.create(name="testtmplt2", disk=disk1,
instance_type=insttype, network=ntwrk, owner=user)
self.testinst1 = Instance.objects.create(owner=user, template=tmplt1,
state="ACTIVE")
self.testinst2 = Instance.objects.create(owner=user, template=tmplt2,
state="ACTIVE")
self.testdetails = UserCloudDetails.objects.get(user=user)
def test_get_weighted_instance_count(self):
credits = (self.testinst1.template.instance_type.credit +
self.testinst2.template.instance_type.credit)
self.assertEqual(credits, self.testdetails
.get_weighted_instance_count())
self.testinst1.state = "STOPPED"
self.testinst1.save()
self.assertEqual(self.testinst2.template.instance_type.credit,
self.testdetails.get_weighted_instance_count())
self.testinst2.state = "STOPPED"
self.testinst2.save()
self.assertEqual(0, self.testdetails.get_weighted_instance_count())
from datetime import datetime, timedelta
from mock import Mock, patch
from nose import with_setup
from nose.tools import raises
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.test import TestCase
from ..models import (Disk, Instance, InstanceType, Network, Share,
Template, set_quota, reset_keys, OpenSshKeyValidator)
from ..util import keygen
from school.models import Course, Group, Semester
from store.api import StoreApi
class UserCloudDetailsTestCase(TestCase):
def setUp(self):
user = User.objects.create(username="testuser", password="testpass",
email="test@mail.com", first_name="Test",
last_name="User")
disk1 = Disk.objects.create(name="testdsk1")
insttype = InstanceType.objects.create(name="testtype", CPU=4,
RAM=4096, credit=4)
ntwrk = Network.objects.create(name="testntwrk", nat=False,
public=True)
tmplt1 = Template.objects.create(name="testtmplt1", disk=disk1,
instance_type=insttype, owner=user,
network=ntwrk)
tmplt2 = Template.objects.create(name="testtmplt2", disk=disk1,
instance_type=insttype, owner=user,
network=ntwrk)
self.testinst1 = Instance.objects.create(owner=user, state="ACTIVE",
template=tmplt1)
self.testinst2 = Instance.objects.create(owner=user, state="ACTIVE",
template=tmplt2)
self.userdetails = user.cloud_details
date = datetime.now().date()
delta = timedelta(weeks=7)
sem = Semester.objects.create(name="testsem", start=date-delta,
end=date+delta)
course1 = Course.objects.create(code='tccode1', name='testcourse1',
short_name='tc1')
grp1 = Group.objects.create(name="testgroup1", semester=sem,
course=course1)
self.share1 = Share.objects.create(name="testshare1", group=grp1,
template=tmplt1, owner=user,
instance_limit=2,
per_user_limit=1)
def test_reset_keys(self):
private_key = self.userdetails.ssh_private_key
public_key = self.userdetails.ssh_key.key
self.userdetails.reset_keys()
self.assertIsNotNone(self.userdetails.ssh_private_key)
self.assertNotEqual(private_key, self.userdetails.ssh_private_key)
self.assertIsNotNone(self.userdetails.ssh_key.key)
self.assertNotEqual(public_key, self.userdetails.ssh_key.key)
def test_reset_keys_without_key(self):
private_key = self.userdetails.ssh_private_key
self.userdetails.ssh_key = None
self.userdetails.save()
self.userdetails.reset_keys()
self.assertIsNotNone(self.userdetails.ssh_private_key)
self.assertNotEqual(private_key, self.userdetails.ssh_private_key)
self.assertIsNotNone(self.userdetails.ssh_key)
def test_reset_smb(self):
smb_password = self.userdetails.smb_password
self.userdetails.reset_smb()
self.assertIsNotNone(self.userdetails.smb_password)
self.assertNotEqual(smb_password, self.userdetails.smb_password)
def test_get_weighted_instance_count(self):
credits = (self.testinst1.template.instance_type.credit +
self.testinst2.template.instance_type.credit)
self.assertEqual(credits,
self.userdetails.get_weighted_instance_count())
self.testinst1.state = "STOPPED"
self.testinst1.save()
self.assertEqual(self.testinst2.template.instance_type.credit,
self.userdetails.get_weighted_instance_count())
self.testinst2.state = "STOPPED"
self.testinst2.save()
self.assertEqual(0, self.userdetails.get_weighted_instance_count())
def test_get_instance_pc(self):
instance_pc = self.userdetails.get_instance_pc()
self.assertTrue(instance_pc >= 0)
def test_get_instance_pc_with_zero_instance_quota(self):
self.userdetails.instance_quota = 0
self.userdetails.save()
self.assertEqual(100, self.userdetails.get_instance_pc())
def test_get_weighted_share_count(self):
share = self.share1
count = share.template.instance_type.credit * share.instance_limit
self.assertEqual(count, self.userdetails.get_weighted_share_count())
def test_get_share_pc(self):
self.userdetails.share_quota = 50
share_pc = self.userdetails.get_share_pc()
self.assertTrue(share_pc >= 0)
def test_get_share_pc_with_zero_share_quota(self):
self.userdetails.share_quota = 0
self.userdetails.save()
self.assertEqual(100, self.userdetails.get_share_pc())
def create_user():
return User.objects.create(username="testuser", password="testpass",
email="test@mail.com", first_name="Test",
last_name="User")
def delete_user():
User.objects.filter(username="testuser").delete()
@with_setup(create_user, delete_user)
def test_set_quota():
user = User.objects.get(username="testuser")
details = user.cloud_details
set_quota(None, details, None)
assert StoreApi.userexist(user.username)
# TODO check quota value
@with_setup(create_user, delete_user)
@patch('one.models.StoreApi')
def test_set_quota_without_store_user(MockStoreApi):
MockStoreApi.userexist = Mock(return_value=False)
MockStoreApi.createuser = Mock()
user = User.objects.get(username="testuser")
details = user.cloud_details
set_quota(None, details, None)
MockStoreApi.userexist.assert_called_once_with(user.username)
assert MockStoreApi.createuser.called
assert MockStoreApi.createuser.call_count == 1
@with_setup(create_user, delete_user)
def test_reset_keys_when_created():
mock_details = Mock()
mock_details.reset_smb = Mock(return_value=None)
mock_details.reset_ssh_keys = Mock(return_value=None)
reset_keys(None, mock_details, True)
mock_details.reset_smb.assert_called_once_with()
mock_details.reset_ssh_keys.assert_called_once_with()
@with_setup(create_user, delete_user)
def test_reset_keys_when_not_created():
mock_details = Mock()
mock_details.reset_smb = Mock(return_value=None)
mock_details.reset_ssh_keys = Mock(return_value=None)
reset_keys(None, mock_details, False)
assert not mock_details.reset_smb.called
assert not mock_details.reset_ssh_keys.called
def test_OpenSshKeyValidator_init_with_types():
key_types = ['my-key-type']
validator = OpenSshKeyValidator(types=key_types)
assert validator.valid_types == key_types
def test_OpenSshKeyValidator_with_valid_key():
validator = OpenSshKeyValidator()
_, public_key = keygen()
validator(public_key)
@raises(ValidationError)
def test_OpenSshKeyValidator_with_empty_string_as_key():
validator = OpenSshKeyValidator()
public_key = ""
validator(public_key)
@raises(ValidationError)
def test_OpenSshKeyValidator_with_invalid_key_type():
validator = OpenSshKeyValidator()
_, public_key = keygen()
_key_type, rest = public_key.split(None, 1)
public_key = 'my-key-type ' + rest
validator(public_key)
@raises(ValidationError)
def test_OpenSshKeyValidator_with_invalid_key_data():
validator = OpenSshKeyValidator()
_, public_key = keygen()
key_parts = public_key.split(None, 2)
key_parts[1] = key_parts[1][1:]
public_key = ' '.join(key_parts)
validator(public_key)
def test_Share_extend_type():
t = {'delete': timedelta(weeks=2), 'suspend': timedelta(weeks=1)}
Share.extend_type(t)
assert 'deletex' in t
assert 'suspendx' in t
assert t['deletex'] is not None
assert t['suspendx'] is not None
def test_Share_extend_type_with_no_deletion_interval():
t = {'delete': None, 'suspend': timedelta(weeks=1)}
Share.extend_type(t)
assert 'deletex' in t
assert 'suspendx' in t
assert t['deletex'] is None
assert t['suspendx'] is not None
def test_Share_extend_type_with_no_suspension_interval():
t = {'delete': timedelta(weeks=2), 'suspend': None}
Share.extend_type(t)
assert 'deletex' in t
assert 'suspendx' in t
assert t['deletex'] is not None
assert t['suspendx'] is None
from django.core.urlresolvers import reverse
from django.test import TestCase
class ViewsTestCase(TestCase):
def test_index(self):
'''Test whether index is reachable.'''
url = reverse('one.views.index')
resp = self.client.get(url, follow=True)
self.assertEqual(resp.status_code, 200)
from django.contrib import messages
from django.core.exceptions import ValidationError
from django import contrib
from django.utils.translation import ugettext_lazy as _
from school import models
import string
class GroupInline(contrib.admin.TabularInline):
model = models.Group
extra = 3
class CourseAdmin(contrib.admin.ModelAdmin):
model = models.Course
inlines = (GroupInline, )
......@@ -16,18 +14,20 @@ class CourseAdmin(contrib.admin.ModelAdmin):
list_display = ('code', 'name', 'short_name', 'owner_list')
list_editable = ('name', 'short_name')
class GroupAdmin(contrib.admin.ModelAdmin):
model = models.Group
filter_horizontal = ('owners', 'members', )
list_display = ('name', 'course', 'semester', 'owner_list', 'member_count')
list_filter = ('semester', 'course')
class SemesterAdmin(contrib.admin.ModelAdmin):
model = models.Semester
list_display = ('id', 'name', 'start', 'end')
list_editable = ('name', 'start', 'end')
contrib.admin.site.register(models.Course, CourseAdmin)
contrib.admin.site.register(models.Semester, SemesterAdmin)
contrib.admin.site.register(models.Group, GroupAdmin)
......@@ -14,6 +14,7 @@ LANGUAGE_CHOICES = (('hu', _('Hungarian')), ('en', _('English')))
logger = logging.getLogger(__name__)
def create_user_profile(sender, instance, created, **kwargs):
"""
User creation hook.
......@@ -33,32 +34,33 @@ def create_user_profile(sender, instance, created, **kwargs):
p = Person.objects.create(code=instance.username)
except Exception as e: # pragma: no cover
logger.warning("Couldn't create profile for user: %(username)s"
"\nReason: %(exception)s",
{"username": instance.username,
"exception": e})
"\nReason: %(exception)s",
{"username": instance.username, "exception": e})
return
p.clean()
p.save()
post_save.connect(create_user_profile, sender=User)
class Person(models.Model):
"""
Personal settings and attributes of a user.
"""
user = models.ForeignKey(User, null=True, blank=True, unique=True)
language = models.CharField(verbose_name=_('language'), blank=False,
max_length=10, choices=LANGUAGE_CHOICES, default=LANGUAGE_CODE)
max_length=10, choices=LANGUAGE_CHOICES,
default=LANGUAGE_CODE)
code = models.CharField(_('code'), max_length=30, unique=True)
def get_owned_shares(self):
"""Get the shares of the groups which the person owns."""
return one.models.Share.objects.filter(
group__in=self.owned_groups.all())
group__in=self.owned_groups.all())
def get_shares(self):
"""Get the shares of the groups which the person is a member of."""
return one.models.Share.objects.filter(
group__in=self.course_groups.all())
group__in=self.course_groups.all())
def short_name(self):
if self.user:
......@@ -74,29 +76,35 @@ class Person(models.Model):
if self.user.last_name and self.user.first_name:
# TRANSLATORS: full name format used in enumerations
return _("%(first)s %(last)s") % {
'first': self.user.first_name,
'last': self.user.last_name}
'first': self.user.first_name,
'last': self.user.last_name}
else:
return self.user.username
else:
return self.code
def save(self, *args, **kwargs):
self.full_clean()
super(Person, self).save(*args, **kwargs)
class Meta:
verbose_name = _('person')
verbose_name_plural = _('persons')
class Course(models.Model):
code = models.CharField(max_length=20, unique=True,
verbose_name=_('course code'))
verbose_name=_('course code'))
name = models.CharField(max_length=80, null=True, blank=True,
verbose_name=_('name'))
verbose_name=_('name'))
short_name = models.CharField(max_length=10, null=True, blank=True,
verbose_name=_('name'))
default_group = models.ForeignKey('Group', null=True, blank=True,
related_name='default_group_of', verbose_name=_('default group'),
help_text=_('New users will be automatically assigned to this group.'))
verbose_name=_('name'))
default_group = models.ForeignKey(
'Group', null=True, blank=True, related_name='default_group_of',
verbose_name=_('default group'), help_text=_('New users will be '
'automatically assigned to this group.'))
owners = models.ManyToManyField(Person, blank=True, null=True,
verbose_name=_('owners'))
verbose_name=_('owners'))
class Meta:
verbose_name = _('course')
......@@ -107,7 +115,8 @@ class Course(models.Model):
return self.default_group
else:
default_group = Group(name=_("%s (auto)") % self.short(),
semester=Semester.get_current(), course=self)
semester=Semester.get_current(),
course=self)
default_group.save()
self.default_group_id = default_group.id
self.save()
......@@ -143,7 +152,7 @@ class Course(models.Model):
class Semester(models.Model):
name = models.CharField(max_length=20, unique=True, null=False,
verbose_name=_('name'))
verbose_name=_('name'))
start = models.DateField(verbose_name=_('start'))
end = models.DateField(verbose_name=_('end'))
......@@ -171,13 +180,15 @@ class Semester(models.Model):
class Group(models.Model):
name = models.CharField(max_length=80, verbose_name=_('name'))
course = models.ForeignKey('Course', null=True, blank=True,
verbose_name=_('course'))
verbose_name=_('course'))
semester = models.ForeignKey('Semester', null=False, blank=False,
verbose_name=_('semester'))
verbose_name=_('semester'))
owners = models.ManyToManyField(Person, blank=True, null=True,
related_name='owned_groups', verbose_name=_('owners'))
related_name='owned_groups',
verbose_name=_('owners'))
members = models.ManyToManyField(Person, blank=True, null=True,
related_name='course_groups', verbose_name=_('members'))
related_name='course_groups',
verbose_name=_('members'))
class Meta:
unique_together = (('name', 'course', 'semester', ), )
......
from datetime import datetime, timedelta
from django.test import TestCase
from django.contrib.auth.models import User, Group as AuthGroup
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from ..models import create_user_profile, Person, Course, Semester, Group
class CreateUserProfileTestCase(TestCase):
def setUp(self):
self.user = User(username="testuser", password="testpass",
email="test@mail.com", first_name="Test", last_name="User")
email="test@mail.com", first_name="Test",
last_name="User")
Person.objects.all().delete()
with self.assertRaises(Person.DoesNotExist):
Person.objects.get(code=self.user.username)
......@@ -23,6 +25,7 @@ class CreateUserProfileTestCase(TestCase):
create_user_profile(self.user.__class__, self.user, True)
self.assertIsNotNone(Person.objects.get(code=self.user.username))
class PersonTestCase(TestCase):
"""Test 'static' Person facts."""
def test_language_code_in_choices(self):
......@@ -32,11 +35,13 @@ class PersonTestCase(TestCase):
choice_codes = [code for (code, _) in language_field.choices]
self.assertIn(language_field.default, choice_codes)
class PersonWithUserTestCase(TestCase):
"""Test Person entities which have their user attribute set."""
def setUp(self):
self.user = User(username="testuser", password="testpass",
email="test@mail.com", first_name="Test", last_name="User")
email="test@mail.com", first_name="Test",
last_name="User")
Person.objects.all().delete()
self.person = Person.objects.create(code='testcode', user=self.user)
......@@ -60,6 +65,7 @@ class PersonWithUserTestCase(TestCase):
self.person.user.last_name = None
self.assertIsNotNone(self.person.__unicode__())
class PersonWithoutUserTestCase(TestCase):
"""Test Person entities which doesn't have their user attribute set."""
def setUp(self):
......@@ -78,6 +84,7 @@ class PersonWithoutUserTestCase(TestCase):
def test_unicode(self):
self.assertIsNotNone(self.person.__unicode__())
class CourseTestCase(TestCase):
def setUp(self):
now = datetime.now()
......@@ -85,10 +92,10 @@ class CourseTestCase(TestCase):
delta = timedelta(weeks=7)
self.testperson1 = Person.objects.create(code="testperson1")
self.testperson2 = Person.objects.create(code="testperson2")
self.testsemester = Semester.objects.create(name="testsemester",
start=date-delta, end=date+delta)
self.testcourse = Course.objects.create(code="testcode",
name="testname", short_name="tn")
self.testsemester = Semester.objects.create(
name="testsemester", start=date-delta, end=date+delta)
self.testcourse = Course.objects.create(
code="testcode", name="testname", short_name="tn")
self.testcourse.owners.add(self.testperson1, self.testperson2)
def test_get_or_create_default_group(self):
......@@ -118,18 +125,19 @@ class CourseTestCase(TestCase):
self.testcourse.short_name = None
self.assertIsNotNone(self.testcourse.short())
class SemesterTestCase(TestCase):
def setUp(self):
now = datetime.now()
date = now.date()
self.now = now
delta = timedelta(weeks=7)
self.last_semester = Semester.objects.create(name="testsem1",
start=date-3*delta, end=date-delta)
self.current_semester = Semester.objects.create(name="testsem2",
start=date-delta, end=date+delta)
self.next_semester = Semester.objects.create(name="testsem3",
start=date+delta, end=date+3*delta)
self.last_semester = Semester.objects.create(
name="testsem1", start=date-3*delta, end=date-delta)
self.current_semester = Semester.objects.create(
name="testsem2", start=date-delta, end=date+delta)
self.next_semester = Semester.objects.create(
name="testsem3", start=date+delta, end=date+3*delta)
def test_is_on(self):
self.assertFalse(self.last_semester.is_on(self.now))
......@@ -146,16 +154,17 @@ class SemesterTestCase(TestCase):
def test_unicode(self):
self.current_semester.__unicode__()
class GroupTestCase(TestCase):
def setUp(self):
date = datetime.now().date()
delta = timedelta(weeks=7)
semester = Semester.objects.create(name="testsem",
start=date-delta, end=date+delta)
self.testcourse = Course.objects.create(code="testcode",
name="testname", short_name="tn")
self.testgroup = Group.objects.create(name="testgrp",
semester=semester, course=self.testcourse)
semester = Semester.objects.create(
name="testsem", start=date-delta, end=date+delta)
self.testcourse = Course.objects.create(
code="testcode", name="testname", short_name="tn")
self.testgroup = Group.objects.create(
name="testgrp", semester=semester, course=self.testcourse)
def test_owner_list(self):
self.assertIsNotNone(self.testgroup.owner_list())
......@@ -184,4 +193,3 @@ class GroupTestCase(TestCase):
def test_get_absolute_url(self):
self.assertIsNotNone(self.testgroup.get_absolute_url())
from datetime import datetime, timedelta
from django.test import TestCase
from django.test.client import Client
from django.contrib.auth.models import User, Group as AuthGroup
from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse
from django.utils.datastructures import MultiValueDictKeyError
from ..models import create_user_profile, Person, Course, Semester, Group
from one.models import UserCloudDetails
from ..models import Person, Course, Semester, Group
from one.models import (UserCloudDetails, Disk, InstanceType, Network,
Template)
import json
class ViewTestCase(TestCase):
def setUp(self):
self.client = Client()
date = datetime.now().date()
delta = timedelta(weeks=7)
semester= Semester.objects.create(name="testsem", start=date-delta,
end=date+delta)
course1 = Course.objects.create(code='tccode1',
name='testcourse1', short_name='tc1')
course2 = Course.objects.create(code='tccode2',
name='testcourse2', short_name='tc2')
self.semester = Semester.objects.create(
name="testsem", start=date-delta, end=date+delta)
course1 = Course.objects.create(
code='tccode1', name='testcourse1', short_name='tc1')
course2 = Course.objects.create(
code='tccode2', name='testcourse2', short_name='tc2')
nonexistent_course_code1 = 'vacationspotscouting'
nonexistent_course_code2 = 'caringforunicorns'
affiliation1 = AuthGroup.objects.create(name='chalktrademanager')
self.group1 = Group.objects.create(name=affiliation1.name,
semester=semester, course=course1)
self.group1 = Group.objects.create(
name=affiliation1.name, semester=self.semester, course=course1)
self.http_headers = {
'niifPersonOrgID': 'ABUZER',
'niifEduPersonHeldCourse': ';'.join(
[course1.code, nonexistent_course_code1]),
'niifEduPersonAttendedCourse': ';'.join(
[course2.code, nonexistent_course_code2]),
'givenName': 'User',
'sn': 'Test',
'givenName': 'Test',
'sn': 'User',
'email': 'test.user@testsite.hu',
'affiliation': ';'.join([affiliation1.name])}
def login(self, follow=False):
url = reverse('login')
resp = self.client.get(url, follow=follow, **self.http_headers)
......@@ -48,17 +47,20 @@ class ViewTestCase(TestCase):
pass
return resp
#
# school.views.logout
#
def test_logout(self):
resp = self.client.get(reverse('logout'), follow=False)
self.assertEqual(302, resp.status_code)
#
# school.views.login
#
def test_login(self):
resp = self.login(follow=True)
self.assertEqual(200, resp.status_code)
def test_login_without_id(self):
del self.http_headers['niifPersonOrgID']
resp = self.login(follow=True)
......@@ -66,25 +68,24 @@ class ViewTestCase(TestCase):
(url, _) = resp.redirect_chain[0]
self.assertIn('/admin', url)
def test_login_without_email(self):
del self.http_headers['email']
resp = self.login(follow=True)
self.assertEqual(403, resp.status_code)
def test_login_without_affiliation(self):
del self.http_headers['affiliation']
resp = self.login(follow=True)
self.assertEqual(200, resp.status_code)
def test_login_without_group_for_affiliation(self):
self.group1.delete()
resp = self.login(follow=True)
self.assertEqual(200, resp.status_code)
#
# school.views.language
#
def test_language(self):
self.login()
p = Person.objects.get(user=self.user)
......@@ -96,18 +97,16 @@ class ViewTestCase(TestCase):
p = Person.objects.get(user=self.user)
self.assertEqual(lang, p.language)
def test_language_with_invalid_parameter(self):
self.login()
lang_before = Person.objects.get(user=self.user).language
new_lang = u'nemvanez' # invalid language
url = reverse('school.views.language', kwargs={'lang': new_lang})
invalid_lang = u'nemvanez'
url = reverse('school.views.language', kwargs={'lang': invalid_lang})
self.http_headers['HTTP_REFERER'] = '/'
resp = self.client.get(url, follow=False, **self.http_headers)
self.assertEqual(302, resp.status_code)
p = Person.objects.get(user=self.user)
self.assertEqual(lang_before, p.language) # language didn't change
self.assertEqual(lang_before, p.language) # language didn't change
def test_language_without_person_for_user(self):
self.login()
......@@ -118,19 +117,28 @@ class ViewTestCase(TestCase):
resp = self.client.get(url, follow=False, **self.http_headers)
self.assertEqual(302, resp.status_code)
#
# school.views.group_show
#
def test_group_show(self):
self.login()
ucd = UserCloudDetails.objects.get(user=self.user)
ucd.share_quota = 10
ucd.save()
disk = Disk.objects.create(name="testdsk1")
insttype = InstanceType.objects.create(name="testtype", CPU=4,
RAM=4096, credit=4)
ntwrk = Network.objects.create(name="testntwrk", nat=False,
public=True)
Template.objects.create(
name="testtmplt1", disk=disk, instance_type=insttype,
network=ntwrk, owner=self.user, state='READY')
gid = self.group1.id
url = reverse('school.views.group_show', kwargs={'gid': gid})
resp = self.client.get(url)
self.assertEqual(200, resp.status_code)
def test_group_show_with_nonexistent_groupid(self):
def test_group_show_with_nonexistent_group_id(self):
self.login()
gid = 1337 # this should be the ID of a non-existent group,
Group.objects.filter(id=gid).delete() # so if it exists, delete it!
......@@ -138,57 +146,65 @@ class ViewTestCase(TestCase):
resp = self.client.get(url)
self.assertEqual(404, resp.status_code)
#
# school.views.group_new
#
def test_group_new(self):
self.login()
url = reverse('school.views.group_new')
member1 = Person.objects.create(code="A1B2C3")
members = [member1]
data = {
'name': 'myNewGrp',
data = {'name': 'myNewGrp',
'semester': Semester.get_current().id,
'members': '\n'.join([m.code for m in members]),
}
resp = self.client.post(url, data)
'members': '\n'.join([m.code for m in members])}
self.client.post(url, data)
group = Group.objects.get(name=data['name'])
self.assertEqual(Semester.get_current(), group.semester)
for member in members:
self.assertIn(member, group.members.all())
def test_group_new_without_members(self):
self.login()
url = reverse('school.views.group_new')
data = {
'name': 'myNewGrp',
data = {'name': 'myNewGrp',
'semester': Semester.get_current().id,
'members': '',
}
resp = self.client.post(url, data)
'members': ''}
self.client.post(url, data)
group = Group.objects.get(name=data['name'])
self.assertEqual(Semester.get_current(), group.semester)
self.assertFalse(group.members.exists())
def test_group_new_with_invalid_neptun(self):
self.login()
url = reverse('school.views.group_new')
data = {'name': 'myNewGrp',
'semester': Semester.get_current().id,
'members': '1ABC123'} # invalid neptun
self.client.post(url, data)
self.assertFalse(Group.objects.filter(name=data['name']).exists())
#
# school.views.group_ajax_add_new_member
#
def test_group_ajax_add_new_member(self):
self.login()
group = Group.objects.create(name="mytestgroup",
semester=Semester.get_current())
group = Group.objects.create(
name="mytestgroup", semester=Semester.get_current())
url = reverse('school.views.group_ajax_add_new_member',
kwargs={'gid': group.id})
kwargs={'gid': group.id})
new_member = Person.objects.get(user=self.user)
data = {'neptun': new_member.code}
resp = self.client.post(url, data)
self.assertEqual(200, resp.status_code)
group = Group.objects.get(id=group.id)
self.assertIn(new_member, group.members.all())
def test_group_ajax_add_new_member_with_nonexistent_groupid(self):
def test_group_ajax_add_new_member_with_nonexistent_group_id(self):
self.login()
gid = 1337 # this should be the ID of a non-existent group,
Group.objects.filter(id=gid).delete() # so if it exists, delete it!
url = reverse('school.views.group_ajax_add_new_member',
kwargs={'gid': gid})
kwargs={'gid': gid})
new_member = Person.objects.get(user=self.user)
data = {'neptun': new_member.code}
resp = self.client.post(url, data)
......@@ -196,10 +212,10 @@ class ViewTestCase(TestCase):
def test_group_ajax_add_new_member_without_neptun(self):
self.login()
group = Group.objects.create(name="mytestgroup",
semester=Semester.get_current())
group = Group.objects.create(
name="mytestgroup", semester=Semester.get_current())
url = reverse('school.views.group_ajax_add_new_member',
kwargs={'gid': group.id})
kwargs={'gid': group.id})
new_member = Person.objects.get(user=self.user)
data = {}
with self.assertRaises(MultiValueDictKeyError):
......@@ -207,13 +223,28 @@ class ViewTestCase(TestCase):
group = Group.objects.get(id=group.id)
self.assertNotIn(new_member, group.members.all())
def test_group_ajax_add_new_member_with_invalid_neptun(self):
self.login()
group = Group.objects.create(
name="mytestgroup", semester=Semester.get_current())
url = reverse('school.views.group_ajax_add_new_member',
kwargs={'gid': group.id})
new_member = Person.objects.get(user=self.user)
self.assertNotIn(new_member, group.members.all())
data = {'neptun': '1' + new_member.code}
resp = self.client.post(url, data)
self.assertEqual(200, resp.status_code)
content = json.loads(resp.content)
self.assertEqual('Error', content['status'])
group = Group.objects.get(id=group.id)
self.assertNotIn(new_member, group.members.all())
def test_group_ajax_add_new_member_with_nonexistent_member(self):
self.login()
group = Group.objects.create(name="mytestgroup",
semester=Semester.get_current())
group = Group.objects.create(
name="mytestgroup", semester=Semester.get_current())
url = reverse('school.views.group_ajax_add_new_member',
kwargs={'gid': group.id})
kwargs={'gid': group.id})
new_member_code = 'ZXY012' # this should be the ID of a
# non-existent person, so if it exists,
Person.objects.filter(code=new_member_code).delete() # delete it!
......@@ -225,59 +256,219 @@ class ViewTestCase(TestCase):
group = Group.objects.get(id=group.id)
self.assertIn(new_member, group.members.all())
#
# school.views.group_ajax_remove_member
#
def test_group_ajax_remove_member(self):
self.login()
group = Group.objects.create(name="mytestgroup",
semester=Semester.get_current())
group = Group.objects.create(
name="mytestgroup", semester=Semester.get_current())
member = Person.objects.get(user=self.user)
group.members.add(member)
group.save()
url = reverse('school.views.group_ajax_remove_member',
kwargs={'gid': group.id})
kwargs={'gid': group.id})
data = {'neptun': member.code}
resp = self.client.post(url, data)
self.assertEqual(200, resp.status_code)
group = Group.objects.get(id=group.id)
self.assertNotIn(member, group.members.all())
def test_group_ajax_remove_member_with_nonexistent_groupid(self):
def test_group_ajax_remove_member_with_nonexistent_group_id(self):
self.login()
gid = 1337 # this should be the ID of a non-existent group,
Group.objects.filter(id=gid).delete() # so if it exists, delete it!
member = Person.objects.get(user=self.user)
url = reverse('school.views.group_ajax_remove_member',
kwargs={'gid': gid})
kwargs={'gid': gid})
data = {'neptun': member.code}
resp = self.client.post(url, data)
self.assertEqual(404, resp.status_code)
def test_group_ajax_remove_member_without_neptun(self):
self.login()
group = Group.objects.create(name="mytestgroup",
semester=Semester.get_current())
group = Group.objects.create(
name="mytestgroup", semester=Semester.get_current())
member = Person.objects.get(user=self.user)
group.members.add(member)
group.save()
url = reverse('school.views.group_ajax_remove_member',
kwargs={'gid': group.id})
kwargs={'gid': group.id})
data = {}
with self.assertRaises(MultiValueDictKeyError):
self.client.post(url, data)
group = Group.objects.get(id=group.id)
self.assertIn(member, group.members.all())
def test_group_ajax_remove_member_with_invalid_neptun(self):
self.login()
group = Group.objects.create(
name="mytestgroup", semester=Semester.get_current())
member = Person.objects.get(user=self.user)
group.members.add(member)
group.save()
url = reverse('school.views.group_ajax_remove_member',
kwargs={'gid': group.id})
data = {'neptun': '1' + member.code} # invalid Neptun code
resp = self.client.post(url, data)
self.assertEqual(200, resp.status_code)
content = json.loads(resp.content)
self.assertEqual('Error', content['status'])
group = Group.objects.get(id=group.id)
self.assertIn(member, group.members.all())
def test_group_ajax_remove_member_with_nonexistent_member(self):
self.login()
group = Group.objects.create(name="mytestgroup",
semester=Semester.get_current())
group = Group.objects.create(
name="mytestgroup", semester=Semester.get_current())
member_code = 'ZXY012' # this should be the ID of a non-existent
# person, so if it exists,
Person.objects.filter(code=member_code).delete() # delete it!
url = reverse('school.views.group_ajax_remove_member',
kwargs={'gid': group.id})
kwargs={'gid': group.id})
data = {'neptun': member_code}
with self.assertRaises(Person.DoesNotExist):
self.client.post(url, data)
self.assertFalse(Person.objects.filter(code=member_code).exists())
#
# school.views.group_ajax_delete
#
def test_group_ajax_delete(self):
self.login()
group = Group.objects.create(
name="mytestgroup", semester=Semester.get_current())
url = reverse('school.views.group_ajax_delete')
data = {'gid': group.id}
resp = self.client.post(url, data)
self.assertEqual(200, resp.status_code)
self.assertFalse(Group.objects.filter(id=group.id).exists())
def test_group_ajax_delete_without_gid(self):
self.login()
url = reverse('school.views.group_ajax_delete')
data = {}
with self.assertRaises(MultiValueDictKeyError):
self.client.post(url, data)
def test_group_ajax_delete_with_nonexistent_group_id(self):
self.login()
gid = 1337 # this should be the ID of a non-existent group,
Group.objects.filter(id=gid).delete() # so if it exists, delete it!
url = reverse('school.views.group_ajax_delete')
data = {'gid': gid}
resp = self.client.post(url, data)
self.assertEqual(404, resp.status_code)
#
# school.views.group_ajax_owner_autocomplete
#
def test_group_ajax_owner_autocomplete(self):
self.login()
query = self.user.last_name[:2]
url = reverse('school.views.group_ajax_owner_autocomplete')
data = {'q': query}
resp = self.client.post(url, data)
self.assertEqual(200, resp.status_code)
content = json.loads(resp.content)
user_data = {'name': self.user.get_full_name(),
'neptun': self.user.username}
self.assertIn(user_data, content)
def test_group_ajax_owner_autocomplete_without_query(self):
self.login()
url = reverse('school.views.group_ajax_owner_autocomplete')
data = {}
with self.assertRaises(MultiValueDictKeyError):
self.client.post(url, data)
#
# school.views.group_ajax_add_new_owner
#
def test_group_ajax_add_new_owner(self):
self.login()
user_details = UserCloudDetails.objects.get(user=self.user)
user_details.share_quota = 10
user_details.save()
group = Group.objects.create(
name="mytestgroup", semester=Semester.get_current())
new_owner = Person.objects.get(code=self.user.username)
self.assertNotIn(new_owner, group.owners.all())
url = reverse('school.views.group_ajax_add_new_owner',
kwargs={'gid': group.id})
data = {'neptun': new_owner.code}
resp = self.client.post(url, data)
self.assertEqual(200, resp.status_code)
content = json.loads(resp.content)
self.assertEqual('OK', content['status'])
group = Group.objects.get(id=group.id)
self.assertIn(new_owner, group.owners.all())
def test_group_ajax_add_new_owner_without_enough_share_quota(self):
self.login()
user_details = UserCloudDetails.objects.get(user=self.user)
user_details.share_quota = 0
user_details.save()
group = Group.objects.create(
name="mytestgroup", semester=Semester.get_current())
new_owner = Person.objects.get(code=self.user.username)
self.assertNotIn(new_owner, group.owners.all())
url = reverse('school.views.group_ajax_add_new_owner',
kwargs={'gid': group.id})
data = {'neptun': new_owner.code}
resp = self.client.post(url, data)
self.assertEqual(200, resp.status_code)
content = json.loads(resp.content)
self.assertEqual('denied', content['status'])
group = Group.objects.get(id=group.id)
self.assertNotIn(new_owner, group.owners.all())
def test_group_ajax_add_new_owner_with_nonexistent_group_id(self):
self.login()
user_details = UserCloudDetails.objects.get(user=self.user)
user_details.share_quota = 10
user_details.save()
gid = 1337 # this should be the ID of a non-existent group,
Group.objects.filter(id=gid).delete() # so if it exists, delete it!
new_owner = Person.objects.get(code=self.user.username)
url = reverse('school.views.group_ajax_add_new_owner',
kwargs={'gid': gid})
data = {'neptun': new_owner.code}
resp = self.client.post(url, data)
self.assertEqual(404, resp.status_code)
def test_group_ajax_add_new_owner_without_neptun(self):
self.login()
user_details = UserCloudDetails.objects.get(user=self.user)
user_details.share_quota = 10
user_details.save()
group = Group.objects.create(
name="mytestgroup", semester=Semester.get_current())
new_owner = Person.objects.get(code=self.user.username)
self.assertNotIn(new_owner, group.owners.all())
url = reverse('school.views.group_ajax_add_new_owner',
kwargs={'gid': group.id})
data = {}
with self.assertRaises(MultiValueDictKeyError):
self.client.post(url, data)
group = Group.objects.get(id=group.id)
self.assertNotIn(new_owner, group.owners.all())
def test_group_ajax_add_new_owner_with_invalid_neptun(self):
self.login()
user_details = UserCloudDetails.objects.get(user=self.user)
user_details.share_quota = 10
user_details.save()
group = Group.objects.create(
name="mytestgroup", semester=Semester.get_current())
new_owner = Person.objects.get(code=self.user.username)
self.assertNotIn(new_owner, group.owners.all())
url = reverse('school.views.group_ajax_add_new_owner',
kwargs={'gid': group.id})
data = {'neptun': '1' + new_owner.code}
resp = self.client.post(url, data)
self.assertEqual(200, resp.status_code)
content = json.loads(resp.content)
self.assertEqual('Error', content['status'])
group = Group.objects.get(id=group.id)
self.assertNotIn(new_owner, group.owners.all())
from datetime import datetime
from itertools import chain
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User, Group as AGroup
from django.contrib import messages
from django.core import signing
from django.core.exceptions import PermissionDenied, ValidationError
from django.core.mail import mail_managers, send_mail
from django.core.urlresolvers import reverse
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.http import HttpResponse
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.http import is_safe_url
from django.utils.translation import get_language as lang
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.decorators.http import *
from django.views.generic import *
from one.models import *
from school.models import *
from one.models import Template, UserCloudDetails
from school.models import Person, Semester, Course, Group
import django.contrib.auth as auth
import logging
import json
import re
logger = logging.getLogger(__name__)
neptun_re = re.compile('^[a-zA-Z][a-zA-Z0-9]{5}$')
def logout(request):
auth.logout(request)
return redirect('/Shibboleth.sso/Logout?return=https%3a%2f%2fcloud.ik.bme.hu%2f')
url = '/Shibboleth.sso/Logout?return=https%3a%2f%2fcloud.ik.bme.hu%2f'
return redirect(url)
@ensure_csrf_cookie
......@@ -51,7 +47,9 @@ def login(request):
try:
user.email = request.META['email']
except KeyError:
messages.error(request, _("The identity provider did not pass the mandatory e-mail data."))
messages.error(request,
_("The identity provider did not pass the mandatory "
"e-mail data."))
raise PermissionDenied()
user.save()
p, created = Person.objects.get_or_create(code=user.username)
......@@ -73,12 +71,11 @@ def login(request):
try:
g.members.add(p)
g.save()
messages.info(request,
_('Course "%s" added.') % g.course)
messages.info(request, _('Course "%s" added.') % g.course)
logger.info('Django Course "%s" added.' % g.course)
except Exception as e:
messages.error(request,
_('Failed to add course "%s".') % g.course)
_('Failed to add course "%s".') % g.course)
logger.warning("Django ex %s" % e)
held = request.META['niifEduPersonHeldCourse']
......@@ -92,10 +89,11 @@ def login(request):
co.owners.add(p)
g.owners.add(p)
messages.info(request,
_('Course "%s" ownership added.') % g.course)
_('Course "%s" ownership added.') % g.course)
except Exception as e:
messages.error(request,
_('Failed to add course "%s" ownership.') % g.course)
_('Failed to add course "%s" ownership.')
% g.course)
logger.warning("Django ex %s" % e)
co.save()
g.save()
......@@ -116,7 +114,7 @@ def login(request):
logger.info("Django affiliation group %s added to %s" % (a, p))
except Exception as e:
logger.warning("Django FAILed to add affiliation group %s to %s."
" Reason: %s" % (a, p, e))
" Reason: %s" % (a, p, e))
user.save()
p.save()
......@@ -155,7 +153,7 @@ def group_show(request, gid):
user = request.user
group = get_object_or_404(Group, id=gid)
mytemplates = Template.objects.filter(owner=request.user, state='READY')
mytemplates = Template.objects.filter(owner=user, state='READY')
for t in mytemplates:
t.myshares = t.share_set.filter(group=group)
......@@ -172,7 +170,7 @@ def group_show(request, gid):
'mytemplates': mytemplates,
'publictemplates': publictemplates,
'noshare': not has_share,
'userdetails': UserCloudDetails.objects.get(user=request.user),
'userdetails': UserCloudDetails.objects.get(user=user),
'owners': group.owners.all(),
}))
......@@ -185,7 +183,7 @@ def group_new(request):
members_list = [m for m in members_list if m != '']
members = []
for member in members_list:
if re.match('^[a-zA-Z][a-zA-Z0-9]{5}$', member.strip()) is None:
if neptun_re.match(member.strip()) is None:
messages.error(request, _('Invalid NEPTUN code found.'))
return redirect('/')
person, created = Person.objects.get_or_create(code=member)
......@@ -207,7 +205,7 @@ def group_new(request):
def group_ajax_add_new_member(request, gid):
group = get_object_or_404(Group, id=gid)
member = request.POST['neptun']
if re.match('^[a-zA-Z][a-zA-Z0-9]{5}$', member.strip()) is None:
if neptun_re.match(member.strip()) is None:
status = json.dumps({'status': 'Error'})
messages.error(request, _('Invalid NEPTUN code'))
return HttpResponse(status)
......@@ -223,7 +221,7 @@ def group_ajax_add_new_member(request, gid):
def group_ajax_remove_member(request, gid):
group = get_object_or_404(Group, id=gid)
member = request.POST['neptun']
if re.match('^[a-zA-Z][a-zA-Z0-9]{5}$', member) is None:
if neptun_re.match(member.strip()) is None:
status = json.dumps({'status': 'Error'})
messages.error(request, _('Invalid NEPTUN code'))
return HttpResponse(status)
......@@ -237,7 +235,9 @@ def group_ajax_remove_member(request, gid):
@login_required
def group_ajax_delete(request):
group = get_object_or_404(Group, id=request.POST['gid'])
# TODO should take parameter in URL using DELETE command
gid = request.POST['gid']
group = get_object_or_404(Group, id=gid)
group.delete()
return HttpResponse(json.dumps({
'status': 'OK'
......@@ -246,30 +246,27 @@ def group_ajax_delete(request):
@login_required
def group_ajax_owner_autocomplete(request):
users = (
User.objects.filter(last_name__istartswith=request.POST['q'])[:5] +
User.objects.filter(first_name__istartswith=request.POST['q'])[:5] +
User.objects.filter(username__istartswith=request.POST['q'])[:5])
results = map(lambda u: {
'name': u.get_full_name(),
'neptun': u.username}, users)
# TODO should be renamed to something like 'user_ajax_autocomplete'
query = request.POST['q']
users = chain(User.objects.filter(last_name__istartswith=query)[:5],
User.objects.filter(first_name__istartswith=query)[:5],
User.objects.filter(username__istartswith=query)[:5])
results = [{'name': user.get_full_name(),
'neptun': user.username} for user in users]
return HttpResponse(json.dumps(results, ensure_ascii=False))
@login_required
def group_ajax_add_new_owner(request, gid):
if request.user.cloud_details.share_quota == 0:
return HttpResponse({'status': 'denied'})
if request.user.cloud_details.share_quota <= 0:
return HttpResponse(json.dumps({'status': 'denied'}))
group = get_object_or_404(Group, id=gid)
member = request.POST['neptun']
if re.match('^[a-zA-Z][a-zA-Z0-9]{5}$', member.strip()) is None:
if neptun_re.match(member.strip()) is None:
status = json.dumps({'status': 'Error'})
messages.error(request, _('Invalid NEPTUN code'))
return HttpResponse(status)
person, created = Person.objects.get_or_create(code=member)
group.owners.add(person)
group.save()
return HttpResponse(json.dumps({
'status': 'OK'
}))
return HttpResponse(json.dumps({'status': 'OK'}))
from django import contrib
# from django.utils.translation import ugettext_lazy as _
from .models import Disk, DataStore
class DiskAdmin(contrib.admin.ModelAdmin):
list_display = ('name', 'datastore')
class DataStoreAdmin(contrib.admin.ModelAdmin):
list_display = ('name', 'path')
contrib.admin.site.register(Disk, DiskAdmin)
contrib.admin.site.register(DataStore, DataStoreAdmin)
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'Disk'
db.create_table('storage_disk', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=100)),
('path', self.gf('django.db.models.fields.CharField')(unique=True, max_length=200)),
('format', self.gf('django.db.models.fields.CharField')(max_length=10)),
('size', self.gf('django.db.models.fields.IntegerField')()),
('type', self.gf('django.db.models.fields.CharField')(max_length=10)),
('base', self.gf('django.db.models.fields.related.ForeignKey')(related_name='snapshots', to=orm['storage.Disk'])),
('original_parent', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['storage.Disk'])),
))
db.send_create_signal('storage', ['Disk'])
def backwards(self, orm):
# Deleting model 'Disk'
db.delete_table('storage_disk')
models = {
'storage.disk': {
'Meta': {'ordering': "['name']", 'object_name': 'Disk'},
'base': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'snapshots'", 'to': "orm['storage.Disk']"}),
'format': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'original_parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storage.Disk']"}),
'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}),
'size': ('django.db.models.fields.IntegerField', [], {}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '10'})
}
}
complete_apps = ['storage']
\ No newline at end of file
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'Disk.original_parent'
db.alter_column('storage_disk', 'original_parent_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['storage.Disk'], null=True))
# Changing field 'Disk.base'
db.alter_column('storage_disk', 'base_id', self.gf('django.db.models.fields.related.ForeignKey')(null=True, to=orm['storage.Disk']))
def backwards(self, orm):
# User chose to not deal with backwards NULL issues for 'Disk.original_parent'
raise RuntimeError("Cannot reverse this migration. 'Disk.original_parent' and its values cannot be restored.")
# User chose to not deal with backwards NULL issues for 'Disk.base'
raise RuntimeError("Cannot reverse this migration. 'Disk.base' and its values cannot be restored.")
models = {
'storage.disk': {
'Meta': {'ordering': "['name']", 'object_name': 'Disk'},
'base': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'snapshots'", 'null': 'True', 'to': "orm['storage.Disk']"}),
'format': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'original_parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storage.Disk']", 'null': 'True', 'blank': 'True'}),
'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}),
'size': ('django.db.models.fields.IntegerField', [], {}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '10'})
}
}
complete_apps = ['storage']
\ No newline at end of file
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'DataStore'
db.create_table('storage_datastore', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=100)),
('path', self.gf('django.db.models.fields.CharField')(unique=True, max_length=200)),
))
db.send_create_signal('storage', ['DataStore'])
# Deleting field 'Disk.path'
db.delete_column('storage_disk', 'path')
# Adding field 'Disk.datastore'
db.add_column('storage_disk', 'datastore',
self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['storage.DataStore']),
keep_default=False)
def backwards(self, orm):
# Deleting model 'DataStore'
db.delete_table('storage_datastore')
# User chose to not deal with backwards NULL issues for 'Disk.path'
raise RuntimeError("Cannot reverse this migration. 'Disk.path' and its values cannot be restored.")
# Deleting field 'Disk.datastore'
db.delete_column('storage_disk', 'datastore_id')
models = {
'storage.datastore': {
'Meta': {'ordering': "['name']", 'object_name': 'DataStore'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'})
},
'storage.disk': {
'Meta': {'ordering': "['name']", 'object_name': 'Disk'},
'base': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'snapshots'", 'null': 'True', 'to': "orm['storage.Disk']"}),
'datastore': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storage.DataStore']"}),
'format': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'original_parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storage.Disk']", 'null': 'True', 'blank': 'True'}),
'size': ('django.db.models.fields.IntegerField', [], {}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '10'})
}
}
complete_apps = ['storage']
\ No newline at end of file
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Disk.created'
db.add_column('storage_disk', 'created',
self.gf('django.db.models.fields.BooleanField')(default=False),
keep_default=False)
def backwards(self, orm):
# Deleting field 'Disk.created'
db.delete_column('storage_disk', 'created')
models = {
'storage.datastore': {
'Meta': {'ordering': "['name']", 'object_name': 'DataStore'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'})
},
'storage.disk': {
'Meta': {'ordering': "['name']", 'object_name': 'Disk'},
'base': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'snapshots'", 'null': 'True', 'to': "orm['storage.Disk']"}),
'created': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'datastore': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storage.DataStore']"}),
'format': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'original_parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storage.Disk']", 'null': 'True', 'blank': 'True'}),
'size': ('django.db.models.fields.IntegerField', [], {}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '10'})
}
}
complete_apps = ['storage']
\ No newline at end of file
# coding=utf-8
import logging
import jsonpickle
import json
from django.db import models, transaction
from django.utils.translation import ugettext_lazy as _
from django.db.models.signals import post_save, post_delete
from .tasks import StorageDriver
logger = logging.getLogger(__name__)
class DataStore(models.Model):
name = models.CharField(max_length=100, unique=True,
verbose_name=_('name'))
path = models.CharField(max_length=200, unique=True,
verbose_name=_('path'))
class Meta:
ordering = ['name']
verbose_name = _('datastore')
verbose_name_plural = _('datastores')
def __unicode__(self):
return u'%s (%s)' % (self.name, self.path)
class Disk(models.Model):
"""Virtual disks automatically synchronized with OpenNebula."""
name = models.CharField(max_length=100, unique=True,
verbose_name=_('name'))
datastore = models.ForeignKey('DataStore')
format = models.CharField(max_length=10,
choices=(('qcow2', 'qcow2'), ('raw', 'raw')))
size = models.IntegerField()
type = models.CharField(max_length=10,
choices=(('snapshot', 'snapshot'),
('normal', 'normal')))
base = models.ForeignKey('Disk', related_name='snapshots',
null=True, blank=True)
original_parent = models.ForeignKey('Disk', null=True, blank=True)
created = models.BooleanField(default=False)
class Meta:
ordering = ['name']
verbose_name = _('disk')
verbose_name_plural = _('disks')
def to_json(self):
self.base_name = self.base.name if self.base else None
self.dir = self.datastore.path
return jsonpickle.encode(self, unpicklable=True)
def __unicode__(self):
return u"%s (#%d)" % (self.name, self.id)
@classmethod
def create_signal(cls, sender, instance, created, **kwargs):
if not instance.created:
StorageDriver.create_disk.delay(instance.to_json()).get()
instance.created = True
instance.save()
@classmethod
def delete_signal(cls, sender, instance, using, **kwargs):
StorageDriver.delete_disk.delay(instance.to_json()).get()
@classmethod
def update_disk(cls, disk):
name = disk['name']
modified = False
try:
base = cls.objects.get(name=disk['base_name'])
except cls.DoesNotExist:
base = None
try:
d = cls.objects.get(name=name)
except Disk.DoesNotExist:
d = Disk(name=name,
created=True,
datastore=DataStore.objects.get(path=disk['dir']),
format=disk['format'],
type=disk['type'])
modified = True
if d.size != disk['size'] or d.base != base:
d.size = disk['size']
d.base = base
modified = True
if modified:
d.full_clean()
d.save()
@classmethod
def update_disks(cls, delete=True):
"""Get and register virtual disks from OpenNebula."""
try:
json_data = StorageDriver.list_disks.delay().get(timeout=10)
disks = json.loads(json_data)
except:
return
with transaction.commit_on_success():
l = []
for disk in disks:
print disk
cls.update_disk(disk)
l.append(disk['name'])
if delete:
cls.objects.exclude(name__in=l).delete()
post_save.connect(Disk.create_signal, sender=Disk)
post_delete.connect(Disk.delete_signal, sender=Disk)
import celery
from celery.contrib.methods import task_method
import logging
logger = logging.getLogger(__name__)
class StorageDriver:
@celery.task(filter=task_method, name='storagedriver.list_disks')
def list_disks():
pass
@celery.task(filter=task_method, name='storagedriver.create_disk')
def create_disk(json_data):
pass
@celery.task(filter=task_method, name='storagedriver.delete_disk')
def delete_disk(json_data):
pass
@celery.task(filter=task_method, name='storagedriver.get_disk')
def get_disk(json_data):
pass
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)
# Create your views here.
# Create your views here.
from django.core.context_processors import csrf
from django.http import HttpResponse
from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
from store.api import StoreApi
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.views.decorators.csrf import csrf_exempt
from django.contrib import auth
import os
import json
import base64
def estabilish_store_user(request, user):
try:
details = request.user.cloud_details
......@@ -21,18 +20,19 @@ def estabilish_store_user(request, user):
key_list.append(key.key)
except:
return HttpResponse('Can not acces to django database!', status=404)
#Create user
# Create user
if not StoreApi.createuser(user, password, key_list, str(quota)):
return HttpResponse('User does not exist on store! And could not create!')
return HttpResponse('User does not exist on store!'
'And could not create!')
@login_required
def index(request):
user = request.user.username
if StoreApi.userexist(user) != True:
if StoreApi.userexist(user) is not True:
estabilish_store_user(request, user)
#UpdateAuthorizationInfo
# UpdateAuthorizationInfo
try:
auth=request.POST['auth']
try:
details = request.user.cloud_details
password = details.smb_password
......@@ -40,146 +40,181 @@ def index(request):
for key in request.user.sshkey_set.all():
key_list.append(key.key)
except:
return HttpResponse('Can not acces to django database!', status=404)
return HttpResponse('Can not acces to django database!',
status=404)
if not StoreApi.updateauthorizationinfo(user, password, key_list):
return HttpResponse('Can not update authorization information!')
return HttpResponse('Can not update authorization information!')
except:
pass
#Download handler
# Download handler
try:
dl = request.POST['dl']
return redirect(StoreApi.requestdownload(user, dl))
except:
pass
#Upload handler
# Upload handler
try:
ul = request.POST['ul']
url = StoreApi.requestupload(user,ul)
return render_to_response('store/upload.html', RequestContext(request,{'URL' : url}))
url = StoreApi.requestupload(user, ul)
return render_to_response('store/upload.html',
RequestContext(request, {'URL': url}))
except:
pass
#Remove handler
# Remove handler
try:
rm = request.POST['rm']
succes = StoreApi.requestremove(user,rm)
StoreApi.requestremove(user, rm)
except:
pass
#Remove handler
# Remove handler
try:
path = request.POST['path']
new = request.POST['new']
succes = StoreApi.requestnewfolder(user,path+'/'+new)
StoreApi.requestnewfolder(user, path + '/' + new)
except:
pass
#Simple file list
# Simple file list
path = '/'
try:
path = request.POST['path']
except:
pass
#Normalize path (Need double dirname /folder/ -> /folder -> /
# Normalize path (Need double dirname /folder/ -> /folder -> /
backpath = os.path.normpath(os.path.dirname(os.path.dirname(path)))
file_list = StoreApi.listfolder(user,path)
file_list = StoreApi.listfolder(user, path)
quota = StoreApi.requestquota(user)
return render_to_response('store/list.html', RequestContext(request, {'file_list': file_list, 'path' : path, 'backpath' : backpath, 'username' : user, 'quota' : quota}))
return render_to_response('store/list.html',
RequestContext(request,
{
'file_list': file_list,
'path': path,
'backpath': backpath,
'username': user,
'quota': quota
}
))
@login_required
def ajax_listfolder(request):
user = request.user.username
if StoreApi.userexist(user) != True:
if StoreApi.userexist(user) is not True:
estabilish_store_user(request, user)
path = '/'
try:
path = request.POST['path']
except:
pass
#Normalize path (Need double dirname /folder/ -> /folder -> /
backpath = os.path.normpath(os.path.dirname(os.path.dirname(path)))
file_list = StoreApi.listfolder(user,path)
# Normalize path (Need double dirname /folder/ -> /folder -> /
# backpath = os.path.normpath(os.path.dirname(os.path.dirname(path)))
file_list = StoreApi.listfolder(user, path)
return HttpResponse(json.dumps(file_list))
@login_required
def ajax_quota(request):
user = request.user.username
if StoreApi.userexist(user) != True:
if StoreApi.userexist(user) is not True:
estabilish_store_user(request, user)
return HttpResponse(json.dumps(StoreApi.requestquota(user)))
#return HttpResponse(json.dumps({'Used':20,'Soft':160,'Hard':200}))
# return HttpResponse(json.dumps({'Used':20,'Soft':160,'Hard':200}))
@login_required
def ajax_download(request):
user = request.user.username
try:
dl = request.POST['dl']
return HttpResponse(json.dumps({'url':StoreApi.requestdownload(user,dl)}))
return HttpResponse(json.dumps(
{'url': StoreApi.requestdownload(user, dl)}))
except:
pass
return HttpResponse('File not found!', status=404)
@login_required
def ajax_upload(request):
user = request.user.username
try:
ul = request.POST['ul']
url = StoreApi.requestupload(user,ul)
return HttpResponse(json.dumps({'url':url}))
url = StoreApi.requestupload(user, ul)
return HttpResponse(json.dumps({'url': url}))
except:
pass
return HttpResponse('Error!', status=404)
@login_required
def ajax_delete(request):
user = request.user.username
try:
rm = request.POST['rm']
return HttpResponse(json.dumps({'success':StoreApi.requestremove(user,rm)}))
return HttpResponse(json.dumps(
{'success': StoreApi.requestremove(user, rm)}))
except:
pass
return HttpResponse('File not found!', status=404)
@login_required
def ajax_new_folder(request):
user = request.user.username
try:
path = request.POST['path']
new = request.POST['new']
success = StoreApi.requestnewfolder(user,path+'/'+new)
return HttpResponse(json.dumps({'success':success}))
success = StoreApi.requestnewfolder(user, path + '/' + new)
return HttpResponse(json.dumps({'success': success}))
except:
pass
return HttpResponse('Error!', status=404)
@login_required
def ajax_rename(request):
user = request.user.username
try:
path = request.POST['path']
new = request.POST['new']
success = StoreApi.requestrename(user,path,new)
return HttpResponse(json.dumps({'success':success}))
success = StoreApi.requestrename(user, path, new)
return HttpResponse(json.dumps({'success': success}))
except:
pass
return HttpResponse('Error!', status=404)
@login_required
def toplist(request):
user = request.user.username
path = backpath = '/'
file_list = StoreApi.toplist(user)
return render_to_response('store/list.html', RequestContext(request, {'file_list': file_list, 'path' : path, 'backpath' : backpath, 'username' : user}))
return render_to_response('store/list.html',
RequestContext(request,
{
'file_list': file_list,
'path': path,
'backpath': backpath,
'username': user
}))
@login_required
def ajax_toplist(request):
user = request.user.username
path = backpath = '/'
file_list = StoreApi.toplist(user)
return HttpResponse(json.dumps(file_list))
@login_required
def gui(request):
user = request.user.username
if request.method == 'GET':
return render_to_response('store/gui.html', RequestContext(request, {'username' : user, 'host' : StoreApi.get_host()}))
return render_to_response('store/gui.html',
RequestContext(
request,
{
'username': user,
'host': StoreApi.get_host()
}))
elif request.method == 'POST':
try:
details = request.user.cloud_details
......@@ -188,7 +223,8 @@ def gui(request):
for key in request.user.sshkey_set.all():
key_list.append(key.key)
except:
return HttpResponse('Can not acces to django database!', status=404)
return HttpResponse('Can not acces to django database!',
status=404)
try:
lab_key_decoded = base64.b64decode(request.POST['KEY'])
key_list.append(lab_key_decoded)
......@@ -196,14 +232,18 @@ def gui(request):
if StoreApi.updateauthorizationinfo(user, password, key_list):
return HttpResponse('Keys resetted succesfully!')
else:
return HttpResponse('Can not update authorization information!')
return HttpResponse('Can not update authorization '
'information!')
if StoreApi.updateauthorizationinfo(user, password, key_list):
return HttpResponse('https://cloud.ik.bme.hu/home/'+'?neptun='+user+'&'+'host='+StoreApi.get_host())
return HttpResponse('https://cloud.ik.bme.hu/home/' +
'?neptun=' + user + '&' + 'host=' +
StoreApi.get_host())
else:
return HttpResponse('Can not update authorization information!')
else:
return HttpResponse('Method not found!', status=404)
def logout(request):
auth.logout(request)
return redirect('/')
auth.logout(request)
return redirect('/')
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