Commit c6fc41fe by Dányi Bence

Merge branch 'master' of ssh://giccero.cloud.ik.bme.hu/cloud

parents 83a1a478 b83f3147
...@@ -175,6 +175,27 @@ import djcelery ...@@ -175,6 +175,27 @@ import djcelery
djcelery.setup_loader() djcelery.setup_loader()
BROKER_URL = 'django://' BROKER_URL = 'django://'
store_settings = {
"basic_auth": "True",
"verify_ssl": "False",
"ssl_auth": "False",
"store_client_pass": "IQu8Eice",
"store_client_user": "admin",
"store_client_key": "/opt/webadmin/cloud/client.key",
"store_client_cert": "/opt/webadmin/cloud/client.crt",
"store_url": "http://localhost:9000",
}
firewall_settings = {
"default_vlangroup": "publikus",
"reload_sleep": "10",
"dns_hostname": "dns1.ik.bme.hu",
"rdns_ip": "152.66.243.60",
"dns_ip": "152.66.243.60",
"dns_ttl": "300",
}
try: try:
from cloud.local_settings import * from cloud.local_settings import *
except: except:
......
...@@ -5,19 +5,19 @@ from firewall.models import * ...@@ -5,19 +5,19 @@ from firewall.models import *
from django import contrib from django import contrib
class AliasInline(contrib.admin.TabularInline):
model = Alias
class RuleInline(contrib.admin.TabularInline): class RuleInline(contrib.admin.TabularInline):
model = Rule model = Rule
class RecordInline(contrib.admin.TabularInline):
model = Record
class HostAdmin(admin.ModelAdmin): class HostAdmin(admin.ModelAdmin):
list_display = ('hostname', 'vlan', 'ipv4', 'ipv6', 'pub_ipv4', 'mac', 'shared_ip', 'owner', 'description', 'reverse', 'groups_l') list_display = ('hostname', 'vlan', 'ipv4', 'ipv6', 'pub_ipv4', 'mac', 'shared_ip', 'owner', 'description', 'reverse', 'groups_l')
ordering = ('hostname', ) ordering = ('hostname', )
list_filter = ('owner', 'vlan', 'groups') list_filter = ('owner', 'vlan', 'groups')
search_fields = ('hostname', 'description', 'ipv4', 'ipv6', 'mac') search_fields = ('hostname', 'description', 'ipv4', 'ipv6', 'mac')
filter_horizontal = ('groups', ) filter_horizontal = ('groups', )
inlines = (AliasInline, RuleInline) inlines = (RuleInline, RecordInline)
def groups_l(self, instance): def groups_l(self, instance):
retval = [] retval = []
...@@ -65,9 +65,6 @@ class RuleAdmin(admin.ModelAdmin): ...@@ -65,9 +65,6 @@ class RuleAdmin(admin.ModelAdmin):
class AliasAdmin(admin.ModelAdmin): class AliasAdmin(admin.ModelAdmin):
list_display = ('alias', 'host') list_display = ('alias', 'host')
class SettingAdmin(admin.ModelAdmin):
list_display = ('key', 'value', 'description')
class GroupAdmin(admin.ModelAdmin): class GroupAdmin(admin.ModelAdmin):
list_display = ('name', 'owner', 'description') list_display = ('name', 'owner', 'description')
inlines = (RuleInline, ) inlines = (RuleInline, )
...@@ -75,11 +72,28 @@ class GroupAdmin(admin.ModelAdmin): ...@@ -75,11 +72,28 @@ class GroupAdmin(admin.ModelAdmin):
class FirewallAdmin(admin.ModelAdmin): class FirewallAdmin(admin.ModelAdmin):
inlines = (RuleInline, ) inlines = (RuleInline, )
class DomainAdmin(admin.ModelAdmin):
list_display = ('name', 'owner')
class RecordAdmin(admin.ModelAdmin):
list_display = ('name_', 'type', 'address_', 'ttl', 'host', 'owner')
def address_(self, instance):
a = instance.get_data()
if(a):
return a['address']
def name_(self, instance):
a = instance.get_data()
if(a):
return a['name']
admin.site.register(Host, HostAdmin) admin.site.register(Host, HostAdmin)
admin.site.register(Vlan, VlanAdmin) admin.site.register(Vlan, VlanAdmin)
admin.site.register(Rule, RuleAdmin) admin.site.register(Rule, RuleAdmin)
admin.site.register(Alias, AliasAdmin)
admin.site.register(Setting, SettingAdmin)
admin.site.register(Group, GroupAdmin) admin.site.register(Group, GroupAdmin)
admin.site.register(VlanGroup) admin.site.register(VlanGroup)
admin.site.register(Firewall, FirewallAdmin) admin.site.register(Firewall, FirewallAdmin)
admin.site.register(Domain, DomainAdmin)
admin.site.register(Record, RecordAdmin)
...@@ -9,6 +9,7 @@ mac_re = re.compile(r'^([0-9a-fA-F]{2}([:-]?|$)){6}$') ...@@ -9,6 +9,7 @@ mac_re = re.compile(r'^([0-9a-fA-F]{2}([:-]?|$)){6}$')
alfanum_re = re.compile(r'^[A-Za-z0-9_-]+$') alfanum_re = re.compile(r'^[A-Za-z0-9_-]+$')
domain_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]+)$') 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): class MACAddressFormField(fields.RegexField):
default_error_messages = { default_error_messages = {
...@@ -41,6 +42,10 @@ def val_domain(value): ...@@ -41,6 +42,10 @@ def val_domain(value):
if not domain_re.search(value): if not domain_re.search(value):
raise ValidationError(u'%s - helytelen domain' % value) raise ValidationError(u'%s - helytelen domain' % value)
def val_reverse_domain(value):
if not reverse_domain_re.search(value):
raise ValidationError(u'%s - reverse domain' % value)
def ipv4_2_ipv6(ipv4): def ipv4_2_ipv6(ipv4):
m = ipv4_re.match(ipv4) m = ipv4_re.match(ipv4)
return "2001:738:2001:4031:%s:%s:%s:0" % (m.group(1), m.group(2), m.group(3)) return "2001:738:2001:4031:%s:%s:%s:0" % (m.group(1), m.group(2), m.group(3))
...@@ -2,6 +2,7 @@ from django.contrib import auth ...@@ -2,6 +2,7 @@ from django.contrib import auth
from firewall import models from firewall import models
from modeldict import * from modeldict import *
import os import os
from cloud.settings import firewall_settings as settings
import subprocess import subprocess
import re import re
...@@ -338,51 +339,36 @@ def dns(): ...@@ -338,51 +339,36 @@ def dns():
vlans = models.Vlan.objects.all() 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 = [] DNS = []
DNS.append("=cloud.ik.bme.hu:152.66.243.98:600::")
DNS.append(":cloud.ik.bme.hu:28:\040\001\007\070\040\001\100\061\000\002\000\000\000\007\000\000:600")
DNS.append("=r.cloud.ik.bme.hu:152.66.243.62:600::")
DNS.append("Z1.3.0.4.1.0.0.2.8.3.7.0.1.0.0.2.ip6.arpa:dns1.ik.bme.hu:support.ik.bme.hu::::::600") # soa
DNS.append("&1.3.0.4.1.0.0.2.8.3.7.0.1.0.0.2.ip6.arpa::dns1.ik.bme.hu:600::") # ns rekord
DNS.append("&1.3.0.4.1.0.0.2.8.3.7.0.1.0.0.2.ip6.arpa::nic.bme.hu:600::") # ns rekord
for i_vlan in vlans: for i_vlan in vlans:
m = regex.search(i_vlan.net4) m = regex.search(i_vlan.net4)
if(i_vlan.name != "DMZ" and i_vlan.name != "PUB"): rev = i_vlan.reverse_domain
DNS.append("Z%s.%s.in-addr.arpa:%s:support.ik.bme.hu::::::%s" % (m.group(2), m.group(1), models.settings['dns_hostname'], models.settings['dns_ttl']))
DNS.append("&%s.%s.in-addr.arpa::%s:%s:" % (m.group(2), m.group(1), models.settings['dns_hostname'], models.settings['dns_ttl']))
DNS.append("Z%s:%s:support.ik.bme.hu::::::%s" % (i_vlan.domain, models.settings['dns_hostname'], models.settings['dns_ttl']))
DNS.append("&%s::%s:%s" % (i_vlan.domain, models.settings['dns_hostname'], models.settings['dns_ttl']))
if(i_vlan.name == "WAR"):
DNS.append("Zdns1.%s.%s.%s.in-addr.arpa:%s:support.ik.bme.hu::::::%s" % (m.group(3), m.group(2), m.group(1), models.settings['dns_hostname'], models.settings['dns_ttl']))
DNS.append("&dns1.%s.%s.%s.in-addr.arpa::%s:%s::" % (m.group(3), m.group(2), m.group(1), models.settings['dns_hostname'], models.settings['dns_ttl']))
for i_host in i_vlan.host_set.all(): for i_host in i_vlan.host_set.all():
ipv4 = ( i_host.pub_ipv4 if i_host.pub_ipv4 and not i_host.shared_ip else i_host.ipv4 ) ipv4 = ( i_host.pub_ipv4 if i_host.pub_ipv4 and not i_host.shared_ip else i_host.ipv4 )
reverse = i_host.reverse if(i_host.reverse and len(i_host.reverse)) else i_host.hostname + u'.' + i_vlan.domain i = ipv4.split('.', 4)
hostname = i_host.get_fqdn() reverse = i_host.reverse if(i_host.reverse and len(i_host.reverse)) else i_host.get_fqdn()
# ipv4 # ipv4
if i_host.ipv4: if i_host.ipv4:
# A record DNS.append("^%s:%s:%s" % ((rev % { 'a': int(i[0]), 'b': int(i[1]), 'c': int(i[2]), 'd': int(i[3]) }), reverse, models.settings['dns_ttl']))
DNS.append("+%s:%s:%s" % (hostname, ipv4, models.settings['dns_ttl']))
# PTR record 4.3.2.1.in-addr.arpa
DNS.append("^%s:%s:%s" % (ipv4_to_arpa(ipv4), reverse, models.settings['dns_ttl']))
# PTR record 4.dns1.3.2.1.in-addr.arpa
DNS.append("^%s:%s:%s" % (ipv4_to_arpa(ipv4, cname=True), reverse, models.settings['dns_ttl']))
# ipv6 # ipv6
if i_host.ipv6: if i_host.ipv6:
# AAAA record
DNS.append(":%s:28:%s:%s" % (hostname, ipv6_to_octal(i_host.ipv6), models.settings['dns_ttl']))
# PTR record
DNS.append("^%s:%s:%s" % (ipv6_to_arpa(i_host.ipv6), reverse, models.settings['dns_ttl'])) DNS.append("^%s:%s:%s" % (ipv6_to_arpa(i_host.ipv6), reverse, models.settings['dns_ttl']))
# cname for r in models.Record.objects.all():
for i_alias in i_host.alias_set.all(): d = r.get_data()
DNS.append("C%s:%s:%s" % (i_alias.alias, hostname, models.settings['dns_ttl'])) if d['type'] == 'A':
DNS.append("+%s:%s:%s" % (d['name'], d['address'], d['ttl']))
process = subprocess.Popen(['/usr/bin/ssh', 'tinydns@%s' % models.settings['dns_hostname']], shell=False, stdin=subprocess.PIPE) elif d['type'] == 'AAAA':
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':
DNS.append("C%s:%s:%s" % (d['name'], d['address'], d['ttl']))
process = subprocess.Popen(['/usr/bin/ssh', 'tinydns@%s' % settings['dns_hostname']], shell=False, stdin=subprocess.PIPE)
process.communicate("\n".join(DNS)+"\n") process.communicate("\n".join(DNS)+"\n")
# print "\n".join(DNS)+"\n" # print "\n".join(DNS)+"\n"
...@@ -425,7 +411,7 @@ def dhcp(): ...@@ -425,7 +411,7 @@ def dhcp():
'domain': i_vlan.domain, 'domain': i_vlan.domain,
'router': i_vlan.ipv4, 'router': i_vlan.ipv4,
'ntp': i_vlan.ipv4, 'ntp': i_vlan.ipv4,
'dnsserver': models.settings['rdns_ip'], 'dnsserver': settings['rdns_ip'],
'extra': "range %s" % i_vlan.dhcp_pool if m else "deny unknown-clients", 'extra': "range %s" % i_vlan.dhcp_pool if m else "deny unknown-clients",
'interface': i_vlan.interface, 'interface': i_vlan.interface,
'name': i_vlan.name, 'name': i_vlan.name,
......
...@@ -7,14 +7,9 @@ from django.utils.translation import ugettext_lazy as _ ...@@ -7,14 +7,9 @@ from django.utils.translation import ugettext_lazy as _
from firewall.fields import * from firewall.fields import *
from south.modelsinspector import add_introspection_rules from south.modelsinspector import add_introspection_rules
from django.core.validators import MinValueValidator, MaxValueValidator from django.core.validators import MinValueValidator, MaxValueValidator
from modeldict import ModelDict from cloud.settings import firewall_settings as settings
from django.utils.ipv6 import is_valid_ipv6_address
class Setting(models.Model): import re
key = models.CharField(max_length=32)
value = models.CharField(max_length=200)
description = models.TextField(blank=True)
settings = ModelDict(Setting, key='key', value='value', instances=False)
class Rule(models.Model): class Rule(models.Model):
CHOICES_type = (('host', 'host'), ('firewall', 'firewall'), ('vlan', 'vlan')) CHOICES_type = (('host', 'host'), ('firewall', 'firewall'), ('vlan', 'vlan'))
...@@ -77,7 +72,8 @@ class Vlan(models.Model): ...@@ -77,7 +72,8 @@ class Vlan(models.Model):
snat_to = models.ManyToManyField('self', symmetrical=False, blank=True, null=True) snat_to = models.ManyToManyField('self', symmetrical=False, blank=True, null=True)
description = models.TextField(blank=True) description = models.TextField(blank=True)
comment = models.TextField(blank=True) comment = models.TextField(blank=True)
domain = models.TextField(blank=True, validators=[val_domain]) domain = models.ForeignKey('Domain')
reverse_domain = models.TextField(validators=[val_reverse_domain])
dhcp_pool = models.TextField(blank=True) dhcp_pool = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, blank=True, null=True) owner = models.ForeignKey(User, blank=True, null=True)
...@@ -113,22 +109,6 @@ class Group(models.Model): ...@@ -113,22 +109,6 @@ class Group(models.Model):
def __unicode__(self): def __unicode__(self):
return self.name return self.name
class Alias(models.Model):
host = models.ForeignKey('Host')
alias = models.CharField(max_length=40, unique=True, validators=[val_domain])
owner = models.ForeignKey(User, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
def clean(self):
# FIXME later: critical race condition
for h in Host.objects.all():
if h.get_fqdn() == self.alias:
raise ValidationError(_("Host name already used."))
class Meta:
verbose_name_plural = 'aliases'
class Host(models.Model): class Host(models.Model):
hostname = models.CharField(max_length=40, unique=True, validators=[val_alfanum]) hostname = models.CharField(max_length=40, unique=True, validators=[val_alfanum])
reverse = models.CharField(max_length=40, validators=[val_domain], blank=True, null=True) reverse = models.CharField(max_length=40, validators=[val_domain], blank=True, null=True)
...@@ -150,6 +130,7 @@ class Host(models.Model): ...@@ -150,6 +130,7 @@ class Host(models.Model):
return self.hostname return self.hostname
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
id = self.id
if not self.id and self.ipv6 == "auto": if not self.id and self.ipv6 == "auto":
self.ipv6 = ipv4_2_ipv6(self.ipv4) self.ipv6 = ipv4_2_ipv6(self.ipv4)
if not self.shared_ip and self.pub_ipv4 and Host.objects.exclude(id=self.id).filter(pub_ipv4=self.pub_ipv4): if not self.shared_ip and self.pub_ipv4 and Host.objects.exclude(id=self.id).filter(pub_ipv4=self.pub_ipv4):
...@@ -158,6 +139,10 @@ class Host(models.Model): ...@@ -158,6 +139,10 @@ class Host(models.Model):
raise ValidationError("Egy masik host natolt cimet nem hasznalhatod sajat ipv4-nek") raise ValidationError("Egy masik host natolt cimet nem hasznalhatod sajat ipv4-nek")
self.full_clean() self.full_clean()
super(Host, self).save(*args, **kwargs) super(Host, self).save(*args, **kwargs)
if(id is None):
Record(domain=self.vlan.domain, host=self, type='A', owner=self.owner).save()
if self.ipv6 == "auto":
Record(domain=self.vlan.domain, host=self, type='AAAA', owner=self.owner).save()
def enable_net(self): def enable_net(self):
self.groups.add(Group.objects.get(name="netezhet")) self.groups.add(Group.objects.get(name="netezhet"))
...@@ -186,14 +171,7 @@ class Host(models.Model): ...@@ -186,14 +171,7 @@ class Host(models.Model):
self.rules.filter(owner=self.owner).delete() self.rules.filter(owner=self.owner).delete()
def get_fqdn(self): def get_fqdn(self):
return self.hostname + u'.' + self.vlan.domain return self.hostname + u'.' + unicode(self.vlan.domain)
def clean(self):
# FIXME later: critical race condition
for a in Alias.objects.all():
if self.get_fqdn() == a.alias:
raise ValidationError(_("Host name already used as alias."))
class Firewall(models.Model): class Firewall(models.Model):
...@@ -202,3 +180,92 @@ class Firewall(models.Model): ...@@ -202,3 +180,92 @@ class Firewall(models.Model):
def __unicode__(self): def __unicode__(self):
return self.name return self.name
class Domain(models.Model):
name = models.CharField(max_length=40, validators=[val_domain])
owner = models.ForeignKey(User)
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
ttl = models.IntegerField(default=600)
description = models.TextField(blank=True)
def __unicode__(self):
return self.name
class Record(models.Model):
CHOICES_type = (('A', 'A'), ('CNAME', 'CNAME'), ('AAAA', 'AAAA'), ('MX', 'MX'), ('NS', 'NS'), ('PTR', 'PTR'), ('TXT', 'TXT'))
name = models.CharField(max_length=40, validators=[val_domain], blank=True, null=True)
domain = models.ForeignKey('Domain')
host = models.ForeignKey('Host', blank=True, null=True)
type = models.CharField(max_length=6, choices=CHOICES_type)
address = models.CharField(max_length=40, blank=True, null=True)
ttl = models.IntegerField(default=600)
owner = models.ForeignKey(User)
description = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.desc()
def desc(self):
a = self.get_data()
if a:
return a['name'] + u' ' + a['type'] + u' ' + a['address']
return '(nincs)'
def save(self, *args, **kwargs):
self.full_clean()
super(Record, self).save(*args, **kwargs)
def clean(self):
if not((not self.name and self.host) or self.name.endswith(u'.' + self.domain.name) or self.name == self.domain.name ):
raise ValidationError(u'nemok')
if self.host and self.type in ['CNAME', 'A', 'AAAA', 'PTR']:
if self.type == 'CNAME':
if not self.name or self.address:
raise ValidationError(u'CNAME rekordnal csak a name legyen kitoltve, ha van host beallitva')
elif self.type == 'PTR':
if not self.address or self.name:
raise ValidationError(u'PTR rekordnal csak a name legyen kitoltve, ha van host beallitva')
elif self.name or self.address:
raise ValidationError(u'A, AAAA rekord eseten nem szabad megadni name-t, address-t, ha tarsitva van host')
else:
if not (self.name and self.address):
raise ValidationError(u'name v address hianyzik')
if self.type == 'A':
if not ipv4_re.match(self.address):
raise ValidationError(u'ez nem ipcim, ez nudli!')
elif self.type in ['CNAME', 'NS', 'PTR', 'TXT']:
if not domain_re.match(self.address):
raise ValidationError(u'ez nem domain, ez nudli!')
elif self.type == 'AAAA':
if not is_valid_ipv6_address(self.address):
raise ValidationError(u'ez nem ipv6cim, ez nudli!')
elif self.type == 'MX':
mx = self.address.split(':', 1)
if not (len(mx) == 2 and mx[0].isdigit() and domain_re.match(mx[1])):
raise ValidationError(u'prioritas:hostname')
else:
raise ValidationError(u'ez ismeretlen rekord, ez nudli!')
def get_data(self):
retval = { 'name': self.name, 'type': self.type, 'ttl': self.ttl, 'address': self.address }
if self.host:
if self.type == 'A':
retval['address'] = self.host.pub_ipv4 if self.host.pub_ipv4 and not self.host.shared_ip else self.host.ipv4
retval['name'] = self.host.get_fqdn()
elif self.type == 'AAAA':
if not self.host.ipv6:
return None
retval['address'] = self.host.ipv6
retval['name'] = self.host.get_fqdn()
elif self.type == 'CNAME':
retval['address'] = self.host.get_fqdn()
if not (retval['address'] and retval['name']):
return None
return retval
...@@ -3,7 +3,7 @@ from django.core.cache import cache ...@@ -3,7 +3,7 @@ from django.core.cache import cache
import os import os
import time import time
from firewall.fw import * from firewall.fw import *
from firewall.models import settings from cloud.settings import firewall_settings as settings
def reload_firewall_lock(): def reload_firewall_lock():
acquire_lock = lambda: cache.add("reload_lock1", "true", 9) acquire_lock = lambda: cache.add("reload_lock1", "true", 9)
......
...@@ -5,4 +5,4 @@ stop on runlevel [!2345] ...@@ -5,4 +5,4 @@ stop on runlevel [!2345]
respawn respawn
exec /opt/webadmin/cloud/miscellaneous/store-server/CloudStore.py exec bash -c "LC_ALL=en_US.UTF-8 /opt/webadmin/cloud/miscellaneous/store-server/CloudStore.py >>/var/log/cloudstore.log 2>&1"
...@@ -44,70 +44,6 @@ ...@@ -44,70 +44,6 @@
} }
}, },
{ {
"pk": 1,
"model": "store.setting",
"fields": {
"value": "True",
"key": "basic_auth"
}
},
{
"pk": 2,
"model": "store.setting",
"fields": {
"value": "False",
"key": "verify_ssl"
}
},
{
"pk": 3,
"model": "store.setting",
"fields": {
"value": "False",
"key": "ssl_auth"
}
},
{
"pk": 4,
"model": "store.setting",
"fields": {
"value": "IQu8Eice",
"key": "store_client_pass"
}
},
{
"pk": 5,
"model": "store.setting",
"fields": {
"value": "admin",
"key": "store_client_user"
}
},
{
"pk": 6,
"model": "store.setting",
"fields": {
"value": "/opt/webadmin/cloud/client.key",
"key": "store_client_key"
}
},
{
"pk": 7,
"model": "store.setting",
"fields": {
"value": "/opt/webadmin/cloud/client.crt",
"key": "store_client_cert"
}
},
{
"pk": 8,
"model": "store.setting",
"fields": {
"value": "http://localhost:9000",
"key": "store_url"
}
},
{
"pk": 2, "pk": 2,
"model": "one.network", "model": "one.network",
"fields": { "fields": {
......
#!/usr/bin/env python
import gtk
import webkit
import gobject
import base64
import subprocess
import os
def keygen(length=1024):
import os, base64
from datetime import date
from Crypto.PublicKey import RSA
key = RSA.generate(length, os.urandom)
try:
pub = key.exportKey('OpenSSH')
if not pub.startswith("ssh-"):
raise ValueError(pub)
except:
ssh_rsa = '00000007' + base64.b16encode('ssh-rsa')
exponent = '%x' % (key.e, )
if len(exponent) % 2:
exponent = '0' + exponent
ssh_rsa += '%08x' % (len(exponent) / 2, )
ssh_rsa += exponent
modulus = '%x' % (key.n, )
if len(modulus) % 2:
modulus = '0' + modulus
if modulus[0] in '89abcdef':
modulus = '00' + modulus
ssh_rsa += '%08x' % (len(modulus) / 2, )
ssh_rsa += modulus
pub = 'ssh-rsa %s' % (
base64.b64encode(base64.b16decode(ssh_rsa.upper())), )
return key.exportKey(), "%s %s" % (pub, "cloud-%s" % date.today())
### Settings ###
KEY_DIR = "/tmp/"
KEY_FILE = KEY_DIR+"/id_rsa"
#Initalize keypair
private_key, public_key = keygen(2048)
#Saver private_key
with open(KEY_FILE,'w') as f:
f.write(private_key)
pub_key_string = base64.b64encode(public_key)
class Browser:
neptun = ""
host = ""
def __init__(self):
#Init window components
gobject.threads_init()
self.window = gtk.Window()
self.window.connect("destroy", self.destroy)
self.window.set_title("IK CloudStore Login")
#Init toolbar
self.toolbar = gtk.Toolbar()
#Init browser
self.browser = webkit.WebView()
self.browser.connect('onload-event', self.load_committed_cb)
# self.browser.open("http://10.9.1.86:8080")
self.browser.open("https://cloud.ik.bme.hu/store/gui/")
self.browser.connect("navigation-requested", self.on_navigation_requested)
#self.browser.open("http://index.hu")
#Sample button
self.help_button = gtk.ToolButton(gtk.STOCK_HELP)
self.help_button.connect("clicked",self.hello)
self.store_button = gtk.ToolButton(gtk.STOCK_HOME)
self.store_button.connect("clicked",self.store)
#Connect things
self.toolbar.add(self.store_button)
self.toolbar.add(self.help_button)
self.vbox = gtk.VBox(False, 0)
self.vbox.pack_start(self.toolbar, False, True, 0)
self.vbox.add(self.browser)
self.window.add(self.vbox)
#self.window.add(self.browser)
self.window.show_all()
def destroy(self, dummy):
self.browser.execute_script("resetKey()")
gtk.main_quit()
def on_navigation_requested(self, view, frame, req, data=None):
uri = req.get_uri()
#print "On nav: " + uri
scheme, rest = uri.split(':', 1)
#print scheme
try:
self.neptun, rest = rest.split(':', 1)
#print "Nep: "+neptun
self.host, values = rest.split('?', 1)
#print "Host: "+host
#print "Values: "+values
except:
pass
if scheme == 'login':
self.browser.execute_script("postKey(\"%s\")" % pub_key_string)
self.browser.execute_script("document.getElementById(\"login_button\").hidden=true ;")
self.browser.execute_script("document.getElementById(\"logout_button\").hidden=false ;")
self.browser.execute_script("document.getElementById(\"mount_button\").hidden=false ;")
return True
elif scheme == 'logout':
self.browser.execute_script("resetKey()")
self.browser.execute_script("document.getElementById(\"logout_button\").hidden=true ;")
self.browser.execute_script("document.getElementById(\"login_button\").hidden=false ;")
self.browser.execute_script("document.getElementById(\"mount_button\").hidden=true ;")
return True
elif scheme == "mount":
self.mount_sshfs_folder(self.neptun,self.host)
self.browser.execute_script("document.getElementById(\"mount_button\").hidden=true ;")
self.browser.execute_script("document.getElementById(\"umount_button\").hidden=false ;")
return True
elif scheme == "umount":
self.umount_sshfs_folder()
self.browser.execute_script("document.getElementById(\"mount_button\").hidden=false ;")
self.browser.execute_script("document.getElementById(\"umount_button\").hidden=true ;")
return True
else:
return False
def mount_sshfs_folder(self,neptun,host):
with open(os.devnull, "w") as fnull:
result = subprocess.call(['/usr/bin/sshfs', '-o', 'IdentityFile='+KEY_DIR+"/id_rsa", neptun+"@"+host+":home", "/home/tarokkk/sshfs"])
#print result
def umount_sshfs_folder(self):
with open(os.devnull, "w") as fnull:
result = subprocess.call(['/bin/fusermount', '-u', "/home/tarokkk/sshfs"])
def hello(self, widget):
self.browser.open("https://login.bme.hu/admin/")
def store(self, widget):
self.browser.open("https://cloud.ik.bme.hu/store/gui/")
def load_committed_cb(self,web_view, frame):
self.browser.execute_script('document.getElementsByTagName("a")[0].target="";')
#uri = frame.get_uri()
#print uri
#print web_view.get_title()
return
def main(self):
gtk.main()
if __name__ == "__main__":
browser = Browser()
browser.main()
...@@ -359,7 +359,7 @@ def file_dict(path, home): ...@@ -359,7 +359,7 @@ def file_dict(path, home):
is_dir = 'F' is_dir = 'F'
return {'NAME': basename, return {'NAME': basename,
'TYPE': is_dir, 'TYPE': is_dir,
'SIZE': os.path.getsize(path)/1024, 'SIZE': os.path.getsize(path),
'MTIME': os.path.getmtime(path), 'MTIME': os.path.getmtime(path),
'DIR': os.path.relpath(os.path.dirname(path), home)} 'DIR': os.path.relpath(os.path.dirname(path), home)}
......
# django-one module
# Copyright (C) 2013 BME IK
# This file is distributed under the same license as the django-one package.
# Mate Ory <orymate@iit.bme.hu>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-02-05 00:17+0100\n"
"PO-Revision-Date: 2013-02-05 00:18+0100\n"
"Last-Translator: Mate Ory <orymate@iit.bme.hu>\n"
"Language-Team: LANGUAGE <cloud@ik.bme.hu>\n"
"Language: hu\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: admin.py:40
msgid "Update status"
msgstr "Állapot frissítése"
#: admin.py:45
msgid "Submit VM"
msgstr "VM beküldése"
#: models.py:33
msgid "user"
msgstr "felhasználó"
#: models.py:35
msgid "Samba password"
msgstr "Samba jelszó"
#: models.py:36
msgid "Generated password for accessing store from Windows."
msgstr "Generált jelszó az adattár eléréséhez Windows alól."
#: models.py:37
msgid "SSH key (public)"
msgstr "SSH kulcs (nyilvános)"
#: models.py:38
msgid "Generated SSH public key for accessing store from Linux."
msgstr "Generált SSH publikus kulcs az adattár eléréséhez Linux alól."
#: models.py:39
msgid "SSH key (private)"
msgstr "SSH kulcs (magán)"
#: models.py:40
msgid "Generated SSH private key for accessing store from Linux."
msgstr "Generált SSH privát kulcs az adattár eléréséhez Linux alól."
#: models.py:86
#, python-format
msgid "OpenSSH key type %s is not supported."
msgstr "A következő OpenSSH kulcstípus nincs támogatva: %s."
#: models.py:95
msgid "Invalid OpenSSH public key."
msgstr "Érvénytelen OpenSSH nyilvános kulcs."
#: models.py:102
msgid "SSH key"
msgstr "SSH kulcs"
#: models.py:103
msgid ""
"<a href=\"/info/ssh/\">SSH public key in OpenSSH format</a> used for shell "
"login (2048+ bit RSA preferred). Example: <code>ssh-rsa AAAAB...QtQ== john</"
"code>."
msgstr ""
"<a href=\"/info/ssh/\">SSH nyilvános kulcs OpenSSH formátumban</a> az SSH "
"bejelentkezéshez – ajánlás: 2048+ bites RSA. Példa: <code><code>ssh-rsa "
"AAAAB...QtQ== jozsi</a>."
#: models.py:111
msgid "unnamed"
msgstr "névtelen"
#: models.py:119 models.py:156 models.py:195 models.py:206 models.py:228
msgid "name"
msgstr "név"
#: models.py:157
msgid "NAT"
msgstr "NAT"
#: models.py:157
msgid "If network address translation is done."
msgstr "Hálózati címfordítás történik-e."
#: models.py:158
msgid "public"
msgstr "publikus"
#: models.py:158
msgid "If internet gateway is available."
msgstr "Van-e elérheti internetes útválasztás."
#: models.py:196
msgid "CPU cores."
msgstr "CPU magok száma."
#: models.py:197
msgid "Mebibytes of memory."
msgstr "Memória mérete mebibyte-ban."
#: models.py:209
msgid "access method"
msgstr "elérési mód"
#: models.py:210
msgid "disk"
msgstr "lemez"
#: models.py:211
msgid "instance type"
msgstr "példánytípus"
#: models.py:212
msgid "network"
msgstr "hálózat"
#: models.py:213 models.py:231
msgid "owner"
msgstr "tulajdonos"
#: models.py:214 models.py:232
msgid "created at"
msgstr "létrehozás ideje"
#: models.py:220 models.py:230
msgid "template"
msgstr "sablon"
#: models.py:221
msgid "templates"
msgstr "sablonok"
#: models.py:229
msgid "IP address"
msgstr "IP cím"
#: models.py:234
msgid "deployable"
msgstr "beküldhető"
#: models.py:235
msgid "pending"
msgstr "várakozó"
#: models.py:236
msgid "done"
msgstr "kész"
#: models.py:237
msgid "active"
msgstr "aktív"
#: models.py:238
msgid "unknown"
msgstr "ismeretlen"
#: models.py:239
msgid "suspended"
msgstr "felfüggesztett"
#: models.py:240
msgid "failed"
msgstr "hiba"
#: models.py:242
msgid "active since"
msgstr "aktívvá válás ideje"
#: models.py:243
msgid "Time stamp of successful boot report."
msgstr "A sikeres indulás jelentésének időpontja."
#: models.py:244
msgid "host in firewall"
msgstr "gép a tűzfalban"
#: models.py:245
msgid "password"
msgstr "jelszó"
#: models.py:245
msgid "Original password of instance"
msgstr "A példány eredeti jelszava."
#: models.py:246
msgid "OpenNebula ID"
msgstr "OpenNebula ID"
#: models.py:451
msgid "instance"
msgstr "példány"
#: models.py:452
msgid "instances"
msgstr "példányok"
#: views.py:92
msgid "Failed to create virtual machine."
msgstr "A virtuális gép indítása sikertelen."
#: views.py:128
msgid "Port number is in a restricted domain (22000 to 24000)."
msgstr "A megadott port foglalt tartományba esik (22000-től 24000-ig)."
#: views.py:132
#, python-format
msgid "Port %d successfully added."
msgstr "%d számú port hozzáadása sikeres."
#: views.py:134
msgid "Adding port failed."
msgstr "Port hozzáadása sikertelen."
#: views.py:151
#, python-format
msgid "Port %d successfully removed."
msgstr "%d számú port eltávolítása sikeres."
#: views.py:153
msgid "Removing port failed."
msgstr "Port eltávolítása sikertelen."
#: views.py:160
msgid "Virtual machine is successfully deleted."
msgstr "A virtuális gép törlése sikeres."
#: views.py:162
msgid "Failed to delete virtual machine."
msgstr "A virtuális gép törlése sikertelen."
#: views.py:177
msgid "Virtual machine is successfully stopped."
msgstr "A virtuális gép sikeresen leállt."
#: views.py:179
msgid "Failed to stop virtual machine."
msgstr "A virtuális gép leállítása sikertelen."
#: views.py:187
msgid "Virtual machine is successfully resumed."
msgstr "A virtuális gép sikeresen folytatva."
#: views.py:189
msgid "Failed to resume virtual machine."
msgstr "A virtuális gép visszatöltése sikertelen."
#: views.py:197
msgid "Virtual machine is successfully powered off."
msgstr "A virtuális gép kikapcsolása sikeres."
#: views.py:199
msgid "Failed to power off virtual machine."
msgstr "A virtuális gép kikapcsolása sikertelen."
#: views.py:207
msgid "Virtual machine is successfully restarted."
msgstr "A virtuális gép újraindítása sikeres."
#: views.py:209
msgid "Failed to restart virtual machine."
msgstr "A virtuális gép újraindítása sikertelen."
...@@ -7,12 +7,12 @@ from django.db import transaction ...@@ -7,12 +7,12 @@ from django.db import transaction
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django import forms from django import forms
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from firewall.models import Host, Rule, Vlan, settings from firewall.models import Host, Rule, Vlan
from firewall.tasks import reload_firewall_lock from firewall.tasks import reload_firewall_lock
from one.util import keygen from one.util import keygen
from school.models import Person from school.models import Person
import subprocess, tempfile, os, stat, re import subprocess, tempfile, os, stat, re, base64, struct
pwgen = User.objects.make_random_password pwgen = User.objects.make_random_password
...@@ -26,6 +26,7 @@ def create_user_profile(sender, instance, created, **kwargs): ...@@ -26,6 +26,7 @@ def create_user_profile(sender, instance, created, **kwargs):
d.save() d.save()
post_save.connect(create_user_profile, sender=User) post_save.connect(create_user_profile, sender=User)
""" """
Cloud related details of a user Cloud related details of a user
""" """
...@@ -36,7 +37,7 @@ class UserCloudDetails(models.Model): ...@@ -36,7 +37,7 @@ class UserCloudDetails(models.Model):
help_text=_('Generated password for accessing store from Windows.')) help_text=_('Generated password for accessing store from Windows.'))
ssh_key = models.ForeignKey('SshKey', null=True, verbose_name=_('SSH key (public)'), ssh_key = models.ForeignKey('SshKey', null=True, verbose_name=_('SSH key (public)'),
help_text=_('Generated SSH public key for accessing store from Linux.')) help_text=_('Generated SSH public key for accessing store from Linux.'))
ssh_private_key = models.TextField(verbose_name=_('SSH key (private)'), ssh_private_key = models.TextField(verbose_name=_('SSH key (private)'), null=True,
help_text=_('Generated SSH private key for accessing store from Linux.')) help_text=_('Generated SSH private key for accessing store from Linux.'))
""" """
...@@ -51,6 +52,8 @@ class UserCloudDetails(models.Model): ...@@ -51,6 +52,8 @@ class UserCloudDetails(models.Model):
except: except:
self.ssh_key = SshKey(user=self.user, key=pub) self.ssh_key = SshKey(user=self.user, key=pub)
self.ssh_key.save() self.ssh_key.save()
self.ssh_key_id = self.ssh_key.id
self.save()
""" """
Generate new Samba password. Generate new Samba password.
...@@ -58,15 +61,12 @@ class UserCloudDetails(models.Model): ...@@ -58,15 +61,12 @@ class UserCloudDetails(models.Model):
def reset_smb(self): def reset_smb(self):
self.smb_password = pwgen() self.smb_password = pwgen()
""" def reset_keys(sender, instance, created, **kwargs):
Generate key pair and Samba password if needed. if created:
""" instance.reset_smb()
def clean(self): instance.reset_keys()
super(UserCloudDetails, self).clean()
if not self.ssh_key: post_save.connect(reset_keys, sender=UserCloudDetails)
self.reset_keys()
if not self.smb_password or len(self.smb_password) == 0:
self.reset_smb()
""" """
Validate OpenSSH keys (length and type). Validate OpenSSH keys (length and type).
...@@ -100,7 +100,7 @@ SSH public key (in OpenSSH format). ...@@ -100,7 +100,7 @@ SSH public key (in OpenSSH format).
class SshKey(models.Model): class SshKey(models.Model):
user = models.ForeignKey(User, null=False, blank=False) user = models.ForeignKey(User, null=False, blank=False)
key = models.CharField(max_length=2000, verbose_name=_('SSH key'), key = models.CharField(max_length=2000, verbose_name=_('SSH key'),
help_text=_('<a href="/info/ssh/">SSH public key in OpenSSH format</a> used for shell login ' help_text=_('<a href="/info/ssh/">SSH public key in OpenSSH format</a> used for shell and store login '
'(2048+ bit RSA preferred). Example: <code>ssh-rsa AAAAB...QtQ== ' '(2048+ bit RSA preferred). Example: <code>ssh-rsa AAAAB...QtQ== '
'john</code>.'), validators=[OpenSshKeyValidator()]) 'john</code>.'), validators=[OpenSshKeyValidator()])
...@@ -225,11 +225,11 @@ Virtual machine instance. ...@@ -225,11 +225,11 @@ Virtual machine instance.
""" """
class Instance(models.Model): class Instance(models.Model):
name = models.CharField(max_length=100, unique=True, name = models.CharField(max_length=100, unique=True,
verbose_name=_('név'), null=True, blank=True) verbose_name=_('name'), null=True, blank=True)
ip = models.IPAddressField(blank=True, null=True, verbose_name=_('IP address')) ip = models.IPAddressField(blank=True, null=True, verbose_name=_('IP address'))
template = models.ForeignKey(Template, verbose_name=_('template')) template = models.ForeignKey(Template, verbose_name=_('template'))
owner = models.ForeignKey(User, verbose_name=_('owner')) owner = models.ForeignKey(User, verbose_name=_('owner'))
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created_at')) created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at'))
state = models.CharField(max_length=20, state = models.CharField(max_length=20,
choices=[('DEPLOYABLE', _('deployable')), choices=[('DEPLOYABLE', _('deployable')),
('PENDING', _('pending')), ('PENDING', _('pending')),
...@@ -268,6 +268,8 @@ class Instance(models.Model): ...@@ -268,6 +268,8 @@ class Instance(models.Model):
def get_connect_uri(self): def get_connect_uri(self):
try: try:
proto = self.template.access_type proto = self.template.access_type
if proto == 'ssh':
proto = 'sshterm'
port = self.get_port() port = self.get_port()
host = self.get_connect_host() host = self.get_connect_host()
pw = self.pw pw = self.pw
......
<!DOCTYPE html>
{% load i18n %}
{% get_current_language as lang %}
<html lang="{{lang}}">
<head>
<title>{% block title %}Superman{% endblock %}</title>
<link rel="icon" type="image/png" href="/static/favicon.png" />
<link rel="stylesheet" href="/static/style.css" />
{{ form.media }}
{% block js %}{% endblock %}
</head>
<body>
<div id="header">
{% block login %}
<div id="loginblock"><p>
{% if user.is_authenticated %}
{% blocktrans with user.get_profile.name|default:user.username as name %}
Logged in: <a href="/me/">{{ name }}</a>.
{% endblocktrans %}
<a href="/logout/">{% trans "Log out" %}</a>.
<a href="{% url project_own %}">{% trans "My projects" %}</a>.
{% if user.is_staff %}
<a href="/admin/">Admin</a>.
{% endif %}
{% else %}
<a href="/secure/login/">{% trans "EduID login" %}</a>.
{% endif %}
{% if lang == 'hu' %}
<a href="/language/en-US/">In English</a>.
{% else %}
<a href="/language/hu/">Magyarul</a>.
{% if autolang %}
<p style="position: absolute; top: 40px; right: 1em;" class="triangle-border top">Böngészője kifejezetten angol tartalmat kért.<br/>A <a href="/language/hu/">magyar változat</a> részletesebb és frissebb!</p>
{% endif %}
{% endif %}
</p>
</div>
{% endblock %}
{% block header %}
{% block header_title %}
<h1><a href="/">{% trans "BME HPC Cluster" %}</a></h1>
{% endblock %}
{% endblock %}
</div>
{% block messages %}
{% if messages %}
<ul class="messagelist">{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}</ul>
{% endif %}
{% endblock messages %}
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
</html>
# -*- coding: utf8 -*- # -*- coding: utf-8 -*-
from datetime import datetime from datetime import datetime
from django.conf import settings from django.conf import settings
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
...@@ -125,13 +125,13 @@ class VmPortAddView(View): ...@@ -125,13 +125,13 @@ class VmPortAddView(View):
public = int(request.POST['public']) public = int(request.POST['public'])
if public >= 22000 and public < 24000: if public >= 22000 and public < 24000:
raise ValidationError("a port nem lehet 22000 es 24000 kozott") raise ValidationError(_("Port number is in a restricted domain (22000 to 24000)."))
inst = get_object_or_404(Instance, id=iid, owner=request.user) inst = get_object_or_404(Instance, id=iid, owner=request.user)
inst.firewall_host.add_port(proto=request.POST['proto'], public=public, private=int(request.POST['private'])) inst.firewall_host.add_port(proto=request.POST['proto'], public=public, private=int(request.POST['private']))
reload_firewall_lock() reload_firewall_lock()
messages.success(request, _(u"A port hozzáadása sikerült.")) messages.success(request, _(u"Port %d successfully added.") % public)
except: except:
messages.error(request, _(u"Nem sikerült a kért művelet")) messages.error(request, _(u"Adding port failed."))
# raise # raise
return redirect('/vm/show/%d/' % int(iid)) return redirect('/vm/show/%d/' % int(iid))
...@@ -148,9 +148,9 @@ def vm_port_del(request, iid, proto, public): ...@@ -148,9 +148,9 @@ def vm_port_del(request, iid, proto, public):
try: try:
inst.firewall_host.del_port(proto=proto, public=public) inst.firewall_host.del_port(proto=proto, public=public)
reload_firewall_lock() reload_firewall_lock()
messages.success(request, _(u"A port törlése sikerült.")) messages.success(request, _(u"Port %d successfully removed.") % public)
except: except:
messages.error(request, _(u"Nem sikerült a kért művelet")) messages.error(request, _(u"Removing port failed."))
return redirect('/vm/show/%d/' % int(iid)) return redirect('/vm/show/%d/' % int(iid))
class VmDeleteView(View): class VmDeleteView(View):
......
...@@ -44,7 +44,7 @@ class Course(models.Model): ...@@ -44,7 +44,7 @@ class Course(models.Model):
if self.default_group: if self.default_group:
return self.default_group return self.default_group
else: else:
default_group = Group(name=_("%s -- default") % self.short(), default_group = Group(name=_("%s (auto)") % self.short(),
semester=Semester.get_current(), course=self) semester=Semester.get_current(), course=self)
default_group.save() default_group.save()
self.default_group_id = default_group.id self.default_group_id = default_group.id
......
from django.contrib import admin from django.contrib import admin
from store.models import * from store.models import *
class SettingAdmin(admin.ModelAdmin):
list_display = ('key', 'value')
admin.site.register(Setting, SettingAdmin)
from django.db import models from django.db import models
from django.http import Http404 from django.http import Http404
import json, requests, time import json, requests, time
from modeldict import ModelDict from cloud.settings import store_settings as settings
from store.models import settings
# Create your models here. # Create your models here.
#TODO Handle exceptions locally #TODO Handle exceptions locally
......
# -*- 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):
# Deleting model 'Setting'
db.delete_table('store_setting')
def backwards(self, orm):
# Adding model 'Setting'
db.create_table('store_setting', (
('value', self.gf('django.db.models.fields.CharField')(max_length=200)),
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('key', self.gf('django.db.models.fields.CharField')(max_length=32)),
))
db.send_create_signal('store', ['Setting'])
models = {
}
complete_apps = ['store']
\ No newline at end of file
from django.db import models pass
from modeldict import ModelDict
class Setting(models.Model):
key = models.CharField(max_length=32)
value = models.CharField(max_length=200)
settings = ModelDict(Setting, key='key', value='value', instances=False)
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