Commit 825f8c1e by Őry Máté

Merge branch 'master' of vm-92.ik.bme.hu:cloud

parents 71672b2a b096549f
...@@ -124,6 +124,7 @@ INSTALLED_APPS = ( ...@@ -124,6 +124,7 @@ INSTALLED_APPS = (
'school', 'school',
'cloud', 'cloud',
'south', 'south',
#'django_bfm',
) )
# A sample logging configuration. The only tangible logging # A sample logging configuration. The only tangible logging
......
...@@ -18,11 +18,16 @@ class DetailsInline(contrib.admin.StackedInline): ...@@ -18,11 +18,16 @@ class DetailsInline(contrib.admin.StackedInline):
can_delete = False can_delete = False
class MyUserAdmin(contrib.auth.admin.UserAdmin): class MyUserAdmin(contrib.auth.admin.UserAdmin):
list_display = ('username', 'email', 'is_staff', 'date_joined', 'get_profile') list_display = ('username', 'full_name', 'email', 'date_joined', 'instance_count')
try: try:
inlines = inlines + (PersonInline, SshKeyInline, DetailsInline) inlines = inlines + (PersonInline, SshKeyInline, DetailsInline)
except NameError: except NameError:
inlines = (PersonInline, SshKeyInline, DetailsInline) inlines = (PersonInline, SshKeyInline, DetailsInline)
def instance_count(self, obj):
return obj.instance_set.count()
def full_name(self, obj):
return u"%s %s" % (obj.last_name, obj.first_name)
full_name.admin_order_field = 'last_name'
...@@ -49,6 +54,14 @@ class InstanceAdmin(contrib.admin.ModelAdmin): ...@@ -49,6 +54,14 @@ class InstanceAdmin(contrib.admin.ModelAdmin):
list_display = ['id', 'name', 'owner', 'state'] list_display = ['id', 'name', 'owner', 'state']
readonly_fields = ['ip', 'active_since', 'pw', 'template'] readonly_fields = ['ip', 'active_since', 'pw', 'template']
list_filter = ['owner', 'template', 'state'] list_filter = ['owner', 'template', 'state']
class DiskAdmin(contrib.admin.ModelAdmin):
model=models.Disk
class NetworkAdmin(contrib.admin.ModelAdmin):
model=models.Network
contrib.admin.site.register(models.Template, TemplateAdmin) contrib.admin.site.register(models.Template, TemplateAdmin)
contrib.admin.site.register(models.Instance, InstanceAdmin) contrib.admin.site.register(models.Instance, InstanceAdmin)
contrib.admin.site.register(models.Network, NetworkAdmin)
contrib.admin.site.register(models.Disk, DiskAdmin)
# coding=utf-8 # coding=utf-8
from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.core import signing from django.core import signing
from django.db import models
from django.db import transaction from django.db import transaction
from school.models import Person from django.db.models.signals import post_save
from django.core.exceptions import ValidationError from django import forms
import subprocess, tempfile, os, stat
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from one.util import keygen from one.util import keygen
from django.db.models.signals import post_save from school.models import Person
import subprocess, tempfile, os, stat
pwgen = User.objects.make_random_password pwgen = User.objects.make_random_password
...@@ -23,7 +25,7 @@ class UserCloudDetails(models.Model): ...@@ -23,7 +25,7 @@ class UserCloudDetails(models.Model):
user = models.ForeignKey(User, null=False, blank=False, unique=True) user = models.ForeignKey(User, null=False, blank=False, unique=True)
smb_password = models.CharField(max_length=20) smb_password = models.CharField(max_length=20)
ssh_key = models.ForeignKey('SshKey', null=True) ssh_key = models.ForeignKey('SshKey', null=True)
ssh_private_key = models.CharField(max_length=1024) ssh_private_key = models.TextField()
def reset_keys(self): def reset_keys(self):
...@@ -43,8 +45,8 @@ class UserCloudDetails(models.Model): ...@@ -43,8 +45,8 @@ class UserCloudDetails(models.Model):
super(UserCloudDetails, self).clean() super(UserCloudDetails, self).clean()
if not self.ssh_key: if not self.ssh_key:
self.reset_keys() self.reset_keys()
if not self.smb_password or len(self.smb_password) == 0: if not self.smb_password or len(self.smb_password) == 0:
self.reset_smb() self.reset_smb()
class OpenSshKeyValidator(object): class OpenSshKeyValidator(object):
valid_types = ['ssh-rsa', 'ssh-dsa'] valid_types = ['ssh-rsa', 'ssh-dsa']
...@@ -76,6 +78,13 @@ class SshKey(models.Model): ...@@ -76,6 +78,13 @@ class SshKey(models.Model):
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 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()])
def __unicode__(self):
try:
keycomment = self.key.split(None, 2)[2]
except:
keycomment = _("unnamed")
return u"%s (%s)" % (keycomment, self.user)
class Disk(models.Model): class Disk(models.Model):
...@@ -90,10 +99,18 @@ class Disk(models.Model): ...@@ -90,10 +99,18 @@ class Disk(models.Model):
from xml.dom.minidom import parse, parseString from xml.dom.minidom import parse, parseString
x = parseString(out) x = parseString(out)
with transaction.commit_on_success(): with transaction.commit_on_success():
Disk.objects.all().delete() l = []
for d in x.getElementsByTagName("STORAGE"): for d in x.getElementsByTagName("STORAGE"):
Disk(id=int(d.getAttributeNode('href').nodeValue.split('/')[-1]), id = int(d.getAttributeNode('href').nodeValue.split('/')[-1])
name=d.getAttributeNode('name').nodeValue).save() name=d.getAttributeNode('name').nodeValue
try:
d = Disk.objects.get(id=id)
d.name=name
d.save()
except:
Disk(id=id, name=name).save
l.append(id)
Disk.objects.exclude(id__in=l).delete()
def __unicode__(self): def __unicode__(self):
return u"%s (#%d)" % (self.name, self.id) return u"%s (#%d)" % (self.name, self.id)
...@@ -116,22 +133,39 @@ class Network(models.Model): ...@@ -116,22 +133,39 @@ class Network(models.Model):
from xml.dom.minidom import parse, parseString from xml.dom.minidom import parse, parseString
x = parseString(out) x = parseString(out)
with transaction.commit_on_success(): with transaction.commit_on_success():
cls.objects.all().delete() l = []
for d in x.getElementsByTagName("NETWORK"): for d in x.getElementsByTagName("NETWORK"):
Network(id=int(d.getAttributeNode('href').nodeValue.split('/')[-1]), id = int(d.getAttributeNode('href').nodeValue.split('/')[-1])
name=d.getAttributeNode('name').nodeValue).save() name=d.getAttributeNode('name').nodeValue
try:
n = Network.objects.get(id=id)
n.name = name
n.save()
except:
Network(id=id, name=name).save()
l.append(id)
cls.objects.exclude(id__in=l).delete()
def __unicode__(self): def __unicode__(self):
return u"%s (vlan%03d)" % (self.name, self.id) return u"%s (vlan%03d)" % (self.name, self.id)
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
class InstanceType(models.Model):
name = models.CharField(max_length=100, unique=True,
verbose_name=_('name'))
CPU = models.IntegerField()
RAM = models.IntegerField()
def __unicode__(self):
return u"%s" % self.name
class Template(models.Model): class Template(models.Model):
name = models.CharField(max_length=100, unique=True, name = models.CharField(max_length=100, unique=True,
verbose_name=_('név')) verbose_name=_('név'))
access_type = models.CharField(max_length=10, choices=[('rdp', 'rdp'), ('nx', 'nx'), ('ssh', 'ssh')]) access_type = models.CharField(max_length=10, choices=[('rdp', 'rdp'), ('nx', 'nx'), ('ssh', 'ssh')])
disk = models.ForeignKey(Disk) disk = models.ForeignKey(Disk)
instance_type = models.CharField(max_length=20, choices=[('small', 'small'), ('medium', 'medium'), ('large', 'large')]) instance_type = models.ForeignKey(InstanceType)
network = models.ForeignKey(Network) network = models.ForeignKey(Network)
owner = models.ForeignKey(User) owner = models.ForeignKey(User)
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
...@@ -157,15 +191,15 @@ class Instance(models.Model): ...@@ -157,15 +191,15 @@ class Instance(models.Model):
one_id = models.IntegerField(unique=True, blank=True, null=True) one_id = models.IntegerField(unique=True, blank=True, null=True)
def get_port(self): def get_port(self):
proto = self.template.access_type proto = self.template.access_type
if self.template.network.name == 'bmenet': if self.template.network.nat:
return {"rdp": 3389, "nx": 22, "ssh": 22}[proto]
if self.template.network.name == 'vmnet':
return {"rdp": 23000, "nx": 22000, "ssh": 22000}[proto] + int(self.ip.split('.')[3]) return {"rdp": 23000, "nx": 22000, "ssh": 22000}[proto] + int(self.ip.split('.')[3])
else:
return {"rdp": 3389, "nx": 22, "ssh": 22}[proto]
def get_connect_host(self): def get_connect_host(self):
if self.template.network.name == 'bmenet': if self.template.network.nat:
return self.ip
elif self.template.network.name == 'vmnet':
return 'cloud' return 'cloud'
else:
return self.ip
def get_connect_uri(self): def get_connect_uri(self):
try: try:
proto = self.template.access_type proto = self.template.access_type
...@@ -234,7 +268,7 @@ class Instance(models.Model): ...@@ -234,7 +268,7 @@ class Instance(models.Model):
tpl = u""" tpl = u"""
<COMPUTE> <COMPUTE>
<NAME>%(neptun)s %(name)s</NAME> <NAME>%(name)s</NAME>
<INSTANCE_TYPE href="http://www.opennebula.org/instance_type/%(instance)s"/> <INSTANCE_TYPE href="http://www.opennebula.org/instance_type/%(instance)s"/>
<DISK> <DISK>
<STORAGE href="http://www.opennebula.org/storage/%(disk)d"/> <STORAGE href="http://www.opennebula.org/storage/%(disk)d"/>
...@@ -244,10 +278,12 @@ class Instance(models.Model): ...@@ -244,10 +278,12 @@ class Instance(models.Model):
</NIC> </NIC>
<CONTEXT> <CONTEXT>
<HOSTNAME>cloud-$VMID</HOSTNAME> <HOSTNAME>cloud-$VMID</HOSTNAME>
<USERNAME>%(neptun)s</USERNAME> <NEPTUN>%(neptun)s</NEPTUN>
<USERPW>%(pw)s</USERPW> <USERPW>%(pw)s</USERPW>
<SMBPW>%(smbpw)s</SMBPW> <SMBPW>%(smbpw)s</SMBPW>
<SSHPRIV>%(sshkey)s</SSHPRIV> <SSHPRIV>%(sshkey)s</SSHPRIV>
<BOOTURL>%(booturl)s</BOOTURL>
<SERVER>152.66.243.73</SERVER>
</CONTEXT> </CONTEXT>
</COMPUTE>""" % {"name": u"%s %d" % (owner.username, inst.id), </COMPUTE>""" % {"name": u"%s %d" % (owner.username, inst.id),
"instance": template.instance_type, "instance": template.instance_type,
...@@ -255,10 +291,10 @@ class Instance(models.Model): ...@@ -255,10 +291,10 @@ class Instance(models.Model):
"net": template.network.id, "net": template.network.id,
"pw": escape(inst.pw), "pw": escape(inst.pw),
"smbpw": escape(details.smb_password), "smbpw": escape(details.smb_password),
"sshkey": escape(details.ssh_private_key), "sshkey": escape(details.ssh_private_key),
"neptun": escape(owner.username), "neptun": escape(owner.username),
"booturl": "http://cloud.ik.bme.hu/b/%s/" % token, "booturl": "http://cloud.ik.bme.hu/b/%s/" % token,
} }
f.write(tpl) f.write(tpl)
f.close() f.close()
import subprocess import subprocess
...@@ -280,9 +316,8 @@ class Instance(models.Model): ...@@ -280,9 +316,8 @@ class Instance(models.Model):
return inst return inst
def delete(self): def delete(self):
get_object_or_404(Instance, id=id, owner=request.user.get_profile())
proc = subprocess.Popen(["/var/lib/opennebula/bin/occi.sh", "compute", proc = subprocess.Popen(["/var/lib/opennebula/bin/occi.sh", "compute",
"delete", id], stdout=subprocess.PIPE) "delete", "%d"%self.one_id], stdout=subprocess.PIPE)
(out, err) = proc.communicate() (out, err) = proc.communicate()
class Meta: class Meta:
......
...@@ -306,7 +306,9 @@ width:400px; ...@@ -306,7 +306,9 @@ width:400px;
display:block; display:block;
cursor:pointer; cursor:pointer;
} }
.icon-delete { .icon-delete {
background-image: url(/static/icons/Edit-delete-2.png); background-image: url(/static/icons/Edit-delete-2.png);
background-repeat: no-repeat;
padding-left: 26px!important;
} }
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<div class="content"> <div class="content">
{% if instances %} {% if instances %}
<table style="width:388px"> <table style="width:388px">
<tr><th>#</th><th>Megnevezés</th><th>Állapot</th><th style="width: 96px">Műveletek</th></tr> <!--<tr><th>#</th><th>Megnevezés</th><th>Állapot</th><th style="width: 96px">Műveletek</th></tr>-->
{% for i in instances %} {% for i in instances %}
<tr style="line-height: 22px;"> <tr style="line-height: 22px;">
<td>{{i.id}}</td> <td>{{i.id}}</td>
......
{% extends "base.html" %}
{% block content %}
<div class="boxes">
<div class="contentblock" id="state">
<h2>Törlés</h2>
<div class="content">
<form action="{% url vm_delete i.id %}" method="post">
{% csrf_token %}
<p>Biztosan törli a gépet? <input type="submit" value="Törlés" /></p>
</form>
</div>
</div>
</div>
{% endblock %}
...@@ -26,16 +26,17 @@ ...@@ -26,16 +26,17 @@
{% endfor %} {% endfor %}
</div> </div>
<div class="boxes"> <div class="boxes">
{% for box in boxes %} <div class="contentblock">
{% if forloop.counter|divisibleby:2 %} <h2>Adattár</h2>
<div class="contentblock"> <div class="content">
<h2>{{ box.title }}</h2> <ul>
<div class="content"> <li>a.out <span class="file-size">4K</span> <span class="file-age">(5 perce)</span> <a href="" class="file-download">Letöltés</a></li>
{{ box.text|safe }} <li>a.out <span class="file-size">4K</span> <span class="file-age">(5 perce)</span> <a href="" class="file-download">Letöltés</a></li>
</div> <li class="file-details">Tovább</li>
<li class="file-upload">Fájl feltöltése</li>
</ul>
</div> </div>
{% endif %} </div>
{% endfor %}
<div class="contentblock" id="state"> <div class="contentblock" id="state">
<h2>A cluster állapota</h2> <h2>A cluster állapota</h2>
<div class="content"> <div class="content">
......
...@@ -3,23 +3,8 @@ ...@@ -3,23 +3,8 @@
{% block js %} {% block js %}
<script type="text/javascript"> <script type="text/javascript">
{% if state == "PENDING" %} {% if booting %}
setTimeout("location.reload(true);", 1500) setTimeout("location.reload(true);", 2000);
{% endif %}
{% if state == "ACTIVE" %}
{% if age < 15 %}
setTimeout("document.getElementById('wait').style.display='none';document.getElementById('connect').style.display='block';", 15000-{{age}}000);
{% endif %}
var meloading = false;
function connectbutton() {
if (meloading) {
return false;
}
meloading = true;
setTimeout("document.getElementById('connecting').style.display='none';meloading=false;", 15000);
document.getElementById('connecting').style.display='inline';
return true;
}
{% endif %} {% endif %}
</script> </script>
{% endblock %} {% endblock %}
...@@ -29,14 +14,14 @@ ...@@ -29,14 +14,14 @@
<div class="contentblock" id="state"> <div class="contentblock" id="state">
<h2>{{name}}</h2> <h2>{{name}}</h2>
<div class="content"> <div class="content">
{% if state == "PENDING" %} {% if state == "PENDING" or state == "ACTIVE" and booting %}
<p style="font-size:25px; line-height:2em;text-align:center;"><img src="/static/load-2.gif" /> Gép indítása..</p> <p style="font-size:25px; line-height:2em;text-align:center;"><img src="/static/load-2.gif" /> Gép indítása..</p>
<p style="font-size:25px; line-height:2em;text-align:center;"> <p style="font-size:25px; line-height:2em;text-align:center;">
<form action="{% url vm_delete id %}" method="post" onsubmit="return confirm('Biztosan törli a gépet?')">{% csrf_token %}<input type="submit" class="icon-delete" value="Törlés" /></form> <form action="{% url vm_delete id %}" method="post" onsubmit="return confirm('Biztosan törli a gépet?')">{% csrf_token %}<input type="submit" class="icon-delete" value="Törlés" /></form>
<a href="/"><img src="/static/icons/Go-home.png" alt="&lt;-" /></a> <a href="/"><img src="/static/icons/Go-home.png" alt="&lt;-" /></a>
</p> </p>
{% endif %} {% endif %}
{% if state == "ACTIVE" %} {% if state == "ACTIVE" and not booting %}
{% if age < 15 %} {% if age < 15 %}
<p id="wait" style="font-size:25px; line-height:2em;text-align:center;"><img src="/static/load-2.gif" /> Gép indítása...</p> <p id="wait" style="font-size:25px; line-height:2em;text-align:center;"><img src="/static/load-2.gif" /> Gép indítása...</p>
<p id="connect" style="display:none; font-size:25px; line-height:2em;text-align:center;"> <p id="connect" style="display:none; font-size:25px; line-height:2em;text-align:center;">
...@@ -89,7 +74,7 @@ ...@@ -89,7 +74,7 @@
<tr><th>Port:</th><td>{{ i.get_port}} <tr><th>Port:</th><td>{{ i.get_port}}
</td></tr> </td></tr>
<tr><th>Felhasználónév:</th><td>cloud</td></tr> <tr><th>Felhasználónév:</th><td>cloud</td></tr>
<tr><th>Jelszó:</th><td>ezmiez</td></tr> <tr><th>Jelszó:</th><td>{{ i.pw }}</td></tr>
</table> </table>
</div> </div>
</div> </div>
......
def keygen(len=1024): def keygen(length=1024):
import os import os, base64
from datetime import date
from Crypto.PublicKey import RSA from Crypto.PublicKey import RSA
key = RSA.generate(len, os.urandom) key = RSA.generate(length, os.urandom)
try: try:
pub = key.exportKey('OpenSSH') pub = key.exportKey('OpenSSH')
if not pub.startswith("ssh-"): if not pub.startswith("ssh-"):
raise ValueError(pub) raise ValueError(pub)
except ValueError: except:
ssh_rsa = '00000007' + base64.b16encode('ssh-rsa') ssh_rsa = '00000007' + base64.b16encode('ssh-rsa')
exponent = '%x' % (key.e, ) exponent = '%x' % (key.e, )
if len(exponent) % 2: if len(exponent) % 2:
...@@ -28,6 +29,6 @@ def keygen(len=1024): ...@@ -28,6 +29,6 @@ def keygen(len=1024):
pub = 'ssh-rsa %s' % ( pub = 'ssh-rsa %s' % (
base64.b64encode(base64.b16decode(ssh_rsa.upper())), ) base64.b64encode(base64.b16decode(ssh_rsa.upper())), )
return key.exportKey(), pub return key.exportKey(), "%s %s" % (pub, "cloud-%s" % date.today())
...@@ -105,14 +105,14 @@ def vm_show(request, iid): ...@@ -105,14 +105,14 @@ def vm_show(request, iid):
'id': iid, 'id': iid,
'age': inst.get_age(), 'age': inst.get_age(),
'instances': _list_instances(request), 'instances': _list_instances(request),
'i': inst 'i': inst,
'booting' : not inst.active_since,
})) }))
class VmDeleteView(View): class VmDeleteView(View):
def post(self, request, iid, *args, **kwargs): def post(self, request, iid, *args, **kwargs):
try: try:
get_object_or_404(Instance, id=id, owner=request.user).one_delete() get_object_or_404(Instance, id=iid, owner=request.user).delete()
messages.success(request, _('Virtual machine is successfully deleted.')) messages.success(request, _('Virtual machine is successfully deleted.'))
except: except:
messages.error(request, _('Failed to delete virtual machine.')) messages.error(request, _('Failed to delete virtual machine.'))
......
...@@ -12,7 +12,7 @@ post_save.connect(create_user_profile, sender=User) ...@@ -12,7 +12,7 @@ post_save.connect(create_user_profile, sender=User)
LANGS = [('hu', _('Hungarian')), ('en_US', _('US English'))] LANGS = [('hu', _('Hungarian')), ('en_US', _('US English'))]
class Person(models.Model): class Person(models.Model):
user = models.ForeignKey(User, null=False, blank=False, unique=True) user = models.ForeignKey(User, null=False, blank=False, unique=True)
language = models.CharField(max_length=6, choices=LANGS, language = models.CharField(max_length=6, choices=LANGS, default='hu',
verbose_name=_('Preferred language')) verbose_name=_('Preferred language'))
def __unicode__(self): def __unicode__(self):
......
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