Commit 6c393877 by Dudás Ádám

one: enforcing guidelines

parent 059a0c45
...@@ -19,7 +19,7 @@ def reload_firewall(request): ...@@ -19,7 +19,7 @@ def reload_firewall(request):
if request.user.is_authenticated(): if request.user.is_authenticated():
if request.user.is_superuser: if request.user.is_superuser:
html = ((_("Dear %s, you've signed in as administrator!") % html = ((_("Dear %s, you've signed in as administrator!") %
request.user.username) + "<br>" + request.user.username) + "<br />" +
_("Reloading in 10 seconds...")) _("Reloading in 10 seconds..."))
ReloadTask.delay() ReloadTask.delay()
else: else:
......
...@@ -22,38 +22,39 @@ import subprocess, tempfile, os, stat, re, base64, struct ...@@ -22,38 +22,39 @@ import subprocess, tempfile, os, stat, re, base64, struct
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
pwgen = User.objects.make_random_password pwgen = User.objects.make_random_password
"""
User creation hook: create cloud details object
"""
def create_user_profile(sender, instance, created, **kwargs): def create_user_profile(sender, instance, created, **kwargs):
"""User creation hook: create cloud details object"""
if created: if created:
d = UserCloudDetails(user=instance) d = UserCloudDetails(user=instance)
d.clean() d.clean()
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
"""
class UserCloudDetails(models.Model): class UserCloudDetails(models.Model):
user = models.ForeignKey(User, null=False, blank=False, unique=True, verbose_name=_('user')) """Cloud related details of a user."""
user = models.ForeignKey(User, null=False, blank=False, unique=True,
verbose_name=_('user'))
smb_password = models.CharField(max_length=20, smb_password = models.CharField(max_length=20,
verbose_name=_('Samba password'), verbose_name=_('Samba password'),
help_text=_('Generated password for accessing store from Windows.')) help_text=_('Generated password for accessing store from '
ssh_key = models.ForeignKey('SshKey', null=True, verbose_name=_('SSH key (public)'), 'Windows.'))
help_text=_('Generated SSH public key for accessing store from Linux.')) ssh_key = models.ForeignKey('SshKey', null=True,
ssh_private_key = models.TextField(verbose_name=_('SSH key (private)'), null=True, verbose_name=_('SSH key (public)'),
help_text=_('Generated SSH private key for accessing store from Linux.')) help_text=_('Generated SSH public key for accessing store from '
share_quota = models.IntegerField(verbose_name=_('share quota'), default=0) 'Linux.'))
instance_quota = models.IntegerField(verbose_name=_('instance quota'), default=20) ssh_private_key = models.TextField(verbose_name=_('SSH key (private)'),
disk_quota = models.IntegerField(verbose_name=_('disk quota'), default=2048, null=True, help_text=_('Generated SSH private key for '
help_text=_('Disk quota in mebibytes.')) 'accessing store from Linux.'))
share_quota = models.IntegerField(verbose_name=_('share quota'),
""" default=0)
Delete old SSH key pair and generate new one. instance_quota = models.IntegerField(verbose_name=_('instance quota'),
""" default=20)
disk_quota = models.IntegerField(verbose_name=_('disk quota'),
default=2048, help_text=_('Disk quota in mebibytes.'))
def reset_keys(self): def reset_keys(self):
"""Delete old SSH key pair and generate new one."""
pri, pub = keygen() pri, pub = keygen()
self.ssh_private_key = pri self.ssh_private_key = pri
...@@ -65,10 +66,8 @@ class UserCloudDetails(models.Model): ...@@ -65,10 +66,8 @@ class UserCloudDetails(models.Model):
self.ssh_key_id = self.ssh_key.id self.ssh_key_id = self.ssh_key.id
self.save() self.save()
"""
Generate new Samba password.
"""
def reset_smb(self): def reset_smb(self):
"""Generate new Samba password."""
self.smb_password = pwgen() self.smb_password = pwgen()
def get_weighted_instance_count(self): def get_weighted_instance_count(self):
...@@ -78,15 +77,14 @@ class UserCloudDetails(models.Model): ...@@ -78,15 +77,14 @@ class UserCloudDetails(models.Model):
c = c + i.template.instance_type.credit c = c + i.template.instance_type.credit
return c return c
def get_instance_pc(self): def get_instance_pc(self):
return 100*self.get_weighted_instance_count()/self.instance_quota return 100 * self.get_weighted_instance_count() / self.instance_quota
def get_weighted_share_count(self): def get_weighted_share_count(self):
c = 0 c = 0
for i in Share.objects.filter(owner=self.user).all(): for i in Share.objects.filter(owner=self.user).all():
c = c + i.template.instance_type.credit * i.instance_limit c = c + i.template.instance_type.credit * i.instance_limit
return c return c
def get_share_pc(self): def get_share_pc(self):
return 100*self.get_weighted_share_count()/self.share_quota return 100 * self.get_weighted_share_count() / self.share_quota
def set_quota(sender, instance, created, **kwargs): def set_quota(sender, instance, created, **kwargs):
if not StoreApi.userexist(instance.user.username): if not StoreApi.userexist(instance.user.username):
...@@ -98,11 +96,13 @@ def set_quota(sender, instance, created, **kwargs): ...@@ -98,11 +96,13 @@ def set_quota(sender, instance, created, **kwargs):
key_list.append(key.key) key_list.append(key.key)
except: except:
pass pass
#Create user # Create user
if not StoreApi.createuser(instance.user.username, password, key_list, quota): if not StoreApi.createuser(instance.user.username, password,
key_list, quota):
pass pass
else: else:
StoreApi.set_quota(instance.user.username, instance.disk_quota*1024) StoreApi.set_quota(instance.user.username,
instance.disk_quota * 1024)
post_save.connect(set_quota, sender=UserCloudDetails) post_save.connect(set_quota, sender=UserCloudDetails)
def reset_keys(sender, instance, created, **kwargs): def reset_keys(sender, instance, created, **kwargs):
...@@ -112,10 +112,8 @@ def reset_keys(sender, instance, created, **kwargs): ...@@ -112,10 +112,8 @@ def reset_keys(sender, instance, created, **kwargs):
post_save.connect(reset_keys, sender=UserCloudDetails) post_save.connect(reset_keys, sender=UserCloudDetails)
"""
Validate OpenSSH keys (length and type).
"""
class OpenSshKeyValidator(object): class OpenSshKeyValidator(object):
"""Validate OpenSSH keys (length and type)."""
valid_types = ['ssh-rsa', 'ssh-dsa'] valid_types = ['ssh-rsa', 'ssh-dsa']
def __init__(self, types=None): def __init__(self, types=None):
...@@ -127,7 +125,8 @@ class OpenSshKeyValidator(object): ...@@ -127,7 +125,8 @@ class OpenSshKeyValidator(object):
value = "%s comment" % value value = "%s comment" % value
type, key_string, comment = value.split(None, 2) type, key_string, comment = value.split(None, 2)
if type not in self.valid_types: if type not in self.valid_types:
raise ValidationError(_('OpenSSH key type %s is not supported.') % type) raise ValidationError(_('OpenSSH key type %s is not '
'supported.') % type)
data = base64.decodestring(key_string) data = base64.decodestring(key_string)
int_len = 4 int_len = 4
str_len = struct.unpack('>I', data[:int_len])[0] str_len = struct.unpack('>I', data[:int_len])[0]
...@@ -138,15 +137,15 @@ class OpenSshKeyValidator(object): ...@@ -138,15 +137,15 @@ class OpenSshKeyValidator(object):
except: except:
raise ValidationError(_('Invalid OpenSSH public key.')) raise ValidationError(_('Invalid OpenSSH public key.'))
"""
SSH public key (in OpenSSH format).
"""
class SshKey(models.Model): class SshKey(models.Model):
"""SSH public key (in OpenSSH format)."""
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 and store login ' help_text=_('<a href="/info/ssh/">SSH public key in OpenSSH '
'(2048+ bit RSA preferred). Example: <code>ssh-rsa AAAAB...QtQ== ' 'format</a> used for shell and store login '
'john</code>.'), validators=[OpenSshKeyValidator()]) '(2048+ bit RSA preferred). Example: '
'<code>ssh-rsa AAAAB...QtQ== john</code>.'),
validators=[OpenSshKeyValidator()])
def __unicode__(self): def __unicode__(self):
try: try:
...@@ -156,62 +155,75 @@ class SshKey(models.Model): ...@@ -156,62 +155,75 @@ class SshKey(models.Model):
return u"%s (%s)" % (keycomment, self.user) return u"%s (%s)" % (keycomment, self.user)
TEMPLATE_STATES = (("INIT", _('init')), ("PREP", _('perparing')), ("SAVE", _('saving')), ("READY", _('ready'))) TEMPLATE_STATES = (("INIT", _('init')), ("PREP", _('perparing')),
("SAVE", _('saving')), ("READY", _('ready')))
TYPES = {"LAB": {"verbose_name": _('lab'), "id": "LAB", "suspend": td(hours=5), "delete": td(days=15), "help_text": _('For lab or home work with short life time.')}, TYPES = {"LAB": {"verbose_name": _('lab'), "id": "LAB",
"PROJECT": {"verbose_name": _('project'), "id": "PROJECT", "suspend": td(weeks=5), "delete": td(days=366/2), "help_text": _('For project work.')}, "suspend": td(hours=5), "delete": td(days=15),
"SERVER": {"verbose_name": _('server'), "id": "SERVER", "suspend": td(days=365), "delete": None, "help_text": _('For long term server use.')}, "help_text": _('For lab or homework with short lifetime.')},
"PROJECT": {"verbose_name": _('project'), "id": "PROJECT",
"suspend": td(weeks=5), "delete": td(days=366/2),
"help_text": _('For project work.')},
"SERVER": {"verbose_name": _('server'), "id": "SERVER",
"suspend": td(days=365), "delete": None,
"help_text": _('For long-term server use.')},
} }
TYPES_L = sorted(TYPES.values(), key=lambda m: m["suspend"]) TYPES_L = sorted(TYPES.values(), key=lambda m: m["suspend"])
TYPES_C = tuple([(i[0], i[1]["verbose_name"]) for i in TYPES.items()]) TYPES_C = tuple([(i[0], i[1]["verbose_name"]) for i in TYPES.items()])
class Share(models.Model): class Share(models.Model):
name = models.CharField(max_length=100, verbose_name=_('name')) name = models.CharField(max_length=100, verbose_name=_('name'))
description = models.TextField(verbose_name=_('description')) description = models.TextField(verbose_name=_('description'))
template = models.ForeignKey('Template', null=False, blank=False) template = models.ForeignKey('Template', null=False, blank=False)
group = models.ForeignKey(Group, null=False, blank=False) group = models.ForeignKey(Group, null=False, blank=False)
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at')) created_at = models.DateTimeField(auto_now_add=True,
type = models.CharField(choices=TYPES_C, max_length=10, blank=False, null=False) verbose_name=_('created at'))
type = models.CharField(choices=TYPES_C, max_length=10, blank=False,
null=False)
instance_limit = models.IntegerField(verbose_name=_('instance limit'), instance_limit = models.IntegerField(verbose_name=_('instance limit'),
help_text=_('Maximal count of instances launchable for this share.')) help_text=_('Maximal count of instances launchable for this '
'share.'))
per_user_limit = models.IntegerField(verbose_name=_('per user limit'), per_user_limit = models.IntegerField(verbose_name=_('per user limit'),
help_text=_('Maximal count of instances launchable by a single user.')) help_text=_('Maximal count of instances launchable by a single '
'user.'))
owner = models.ForeignKey(User, null=True, blank=True) owner = models.ForeignKey(User, null=True, blank=True)
def get_type(self): def get_type(self):
t = TYPES[self.type] t = TYPES[self.type]
t['deletex'] = datetime.now() + td(seconds=1) + t['delete'] if t['delete'] else None t['deletex'] = (datetime.now() + td(seconds=1) + t['delete']
t['suspendx'] = datetime.now() + td(seconds=1) + t['suspend'] if t['suspend'] else None if t['delete'] else None)
t['suspendx'] = (datetime.now() + td(seconds=1) + t['suspend']
if t['suspend'] else None)
return t return t
def get_running_or_stopped(self, user=None): def get_running_or_stopped(self, user=None):
running = Instance.objects.all().exclude(state='DONE').filter(share=self) running = (Instance.objects.all().exclude(state='DONE')
.filter(share=self))
if user: if user:
return running.filter(owner=user).count() return running.filter(owner=user).count()
else: else:
return running.count() return running.count()
def get_running(self, user=None): def get_running(self, user=None):
running = Instance.objects.all().exclude(state='DONE').exclude(state='STOPPED').filter(share=self) running = (Instance.objects.all().exclude(state='DONE')
.exclude(state='STOPPED').filter(share=self))
if user: if user:
return running.filter(owner=user).count() return running.filter(owner=user).count()
else: else:
return running.count() return running.count()
def get_instance_pc(self): def get_instance_pc(self):
return float(self.get_running()) / self.instance_limit * 100 return float(self.get_running()) / self.instance_limit * 100
"""
Virtual disks automatically synchronized with OpenNebula.
"""
class Disk(models.Model): class Disk(models.Model):
name = models.CharField(max_length=100, unique=True, verbose_name=_('name')) """Virtual disks automatically synchronized with OpenNebula."""
name = models.CharField(max_length=100, unique=True,
verbose_name=_('name'))
"""
Get and register virtual disks from OpenNebula.
"""
@classmethod @classmethod
def update(cls): def update(cls):
"""Get and register virtual disks from OpenNebula."""
import subprocess import subprocess
proc = subprocess.Popen(["/opt/occi.sh", proc = subprocess.Popen(["/opt/occi.sh", "storage", "list"],
"storage", "list"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = proc.communicate() (out, err) = proc.communicate()
from xml.dom.minidom import parse, parseString from xml.dom.minidom import parse, parseString
x = parseString(out) x = parseString(out)
...@@ -235,22 +247,21 @@ class Disk(models.Model): ...@@ -235,22 +247,21 @@ class Disk(models.Model):
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
"""
Virtual networks automatically synchronized with OpenNebula.
"""
class Network(models.Model): class Network(models.Model):
name = models.CharField(max_length=100, unique=True, verbose_name=_('name')) """Virtual networks automatically synchronized with OpenNebula."""
nat = models.BooleanField(verbose_name=_('NAT'), help_text=_('If network address translation is done.')) name = models.CharField(max_length=100, unique=True,
public = models.BooleanField(verbose_name=_('public'), help_text=_('If internet gateway is available.')) verbose_name=_('name'))
nat = models.BooleanField(verbose_name=_('NAT'),
help_text=_('If network address translation is done.'))
public = models.BooleanField(verbose_name=_('public'),
help_text=_('If internet gateway is available.'))
"""
Get and register virtual networks from OpenNebula.
"""
@classmethod @classmethod
def update(cls): def update(cls):
"""Get and register virtual networks from OpenNebula."""
import subprocess import subprocess
proc = subprocess.Popen(["/opt/occi.sh", proc = subprocess.Popen(["/opt/occi.sh", "network", "list"],
"network", "list"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = proc.communicate() (out, err) = proc.communicate()
from xml.dom.minidom import parse, parseString from xml.dom.minidom import parse, parseString
x = parseString(out) x = parseString(out)
...@@ -273,10 +284,8 @@ class Network(models.Model): ...@@ -273,10 +284,8 @@ class Network(models.Model):
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
"""
Instance types in OCCI configuration (manually synchronized).
"""
class InstanceType(models.Model): class InstanceType(models.Model):
"""Instance types in OCCI configuration (manually synchronized)."""
name = models.CharField(max_length=100, unique=True, name = models.CharField(max_length=100, unique=True,
verbose_name=_('name')) verbose_name=_('name'))
CPU = models.IntegerField(help_text=_('CPU cores.')) CPU = models.IntegerField(help_text=_('CPU cores.'))
...@@ -288,23 +297,24 @@ class InstanceType(models.Model): ...@@ -288,23 +297,24 @@ class InstanceType(models.Model):
class Meta: class Meta:
ordering = ['credit'] ordering = ['credit']
TEMPLATE_STATES = (('NEW', _('new')), TEMPLATE_STATES = (('NEW', _('new')), ('SAVING', _('saving')),
('SAVING', _('saving')), ('READY', _('ready')), ) ('READY', _('ready')), )
"""
Virtual machine template specifying OS, disk, type and network.
"""
class Template(models.Model): class Template(models.Model):
"""Virtual machine template specifying OS, disk, type and network."""
name = models.CharField(max_length=100, unique=True, name = models.CharField(max_length=100, unique=True,
verbose_name=_('name')) verbose_name=_('name'))
access_type = models.CharField(max_length=10, access_type = models.CharField(max_length=10,
choices=[('rdp', 'rdp'), ('nx', 'nx'), ('ssh', 'ssh')], choices=[('rdp', 'rdp'), ('nx', 'nx'), ('ssh', 'ssh')],
verbose_name=_('access method')) verbose_name=_('access method'))
disk = models.ForeignKey(Disk, verbose_name=_('disk')) disk = models.ForeignKey(Disk, verbose_name=_('disk'))
instance_type = models.ForeignKey(InstanceType, verbose_name=_('instance type')) instance_type = models.ForeignKey(InstanceType,
verbose_name=_('instance type'))
network = models.ForeignKey(Network, verbose_name=_('network')) network = models.ForeignKey(Network, verbose_name=_('network'))
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,
state = models.CharField(max_length=10, choices=TEMPLATE_STATES, default='NEW') verbose_name=_('created at'))
state = models.CharField(max_length=10, choices=TEMPLATE_STATES,
default='NEW')
public = models.BooleanField(verbose_name=_('public'), default=False, public = models.BooleanField(verbose_name=_('public'), default=False,
help_text=_('If other users can derive templates of this one.')) help_text=_('If other users can derive templates of this one.'))
description = models.TextField(verbose_name=_('description'), blank=True) description = models.TextField(verbose_name=_('description'), blank=True)
...@@ -336,56 +346,57 @@ class Template(models.Model): ...@@ -336,56 +346,57 @@ class Template(models.Model):
verbose_name = _('template') verbose_name = _('template')
verbose_name_plural = _('templates') verbose_name_plural = _('templates')
"""
Virtual machine instance.
"""
class Instance(models.Model): class Instance(models.Model):
"""Virtual machine instance."""
name = models.CharField(max_length=100, unique=True, name = models.CharField(max_length=100, unique=True,
verbose_name=_('name'), 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')),
('DONE', _('done')), ('DONE', _('done')),
('ACTIVE', _('active')), ('ACTIVE', _('active')),
('UNKNOWN', _('unknown')), ('UNKNOWN', _('unknown')),
('STOPPED', _('suspended')), ('STOPPED', _('suspended')),
('FAILED', _('failed'))], default='DEPLOYABLE') ('FAILED', _('failed'))],
default='DEPLOYABLE')
active_since = models.DateTimeField(null=True, blank=True, active_since = models.DateTimeField(null=True, blank=True,
verbose_name=_('active since'), verbose_name=_('active since'),
help_text=_('Time stamp of successful boot report.')) help_text=_('Time stamp of successful boot report.'))
firewall_host = models.ForeignKey(Host, blank=True, null=True, verbose_name=_('host in firewall')) firewall_host = models.ForeignKey(Host, blank=True, null=True,
pw = models.CharField(max_length=20, verbose_name=_('password'), help_text=_('Original password of instance')) verbose_name=_('host in firewall'))
one_id = models.IntegerField(unique=True, blank=True, null=True, verbose_name=_('OpenNebula ID')) pw = models.CharField(max_length=20, verbose_name=_('password'),
share = models.ForeignKey('Share', blank=True, null=True, verbose_name=_('share')) help_text=_('Original password of instance'))
time_of_suspend = models.DateTimeField(default=None, verbose_name=_('time of suspend'), null=True, blank=False) one_id = models.IntegerField(unique=True, blank=True, null=True,
time_of_delete = models.DateTimeField(default=None, verbose_name=_('time of delete'), null=True, blank=False) verbose_name=_('OpenNebula ID'))
share = models.ForeignKey('Share', blank=True, null=True,
verbose_name=_('share'))
time_of_suspend = models.DateTimeField(default=None,
verbose_name=_('time of suspend'), null=True, blank=False)
time_of_delete = models.DateTimeField(default=None,
verbose_name=_('time of delete'), null=True, blank=False)
waiting = models.BooleanField(default=False) waiting = models.BooleanField(default=False)
"""
Get public port number for default access method.
"""
def get_port(self): def get_port(self):
"""Get public port number for default access method."""
proto = self.template.access_type proto = self.template.access_type
if self.template.network.nat: if self.template.network.nat:
return {"rdp": 23000, "nx": 22000, "ssh": 22000}[proto] + int(self.ip.split('.')[2]) * 256 + int(self.ip.split('.')[3]) return {"rdp": 23000, "nx": 22000, "ssh": 22000}[proto] + int(self.ip.split('.')[2]) * 256 + int(self.ip.split('.')[3])
else: else:
return {"rdp": 3389, "nx": 22, "ssh": 22}[proto] return {"rdp": 3389, "nx": 22, "ssh": 22}[proto]
"""
Get public hostname.
"""
def get_connect_host(self): def get_connect_host(self):
"""Get public hostname."""
if self.template.network.nat: if self.template.network.nat:
return 'cloud' return 'cloud'
else: else:
return self.ip return self.ip
"""
Get access parameters in URI format.
"""
def get_connect_uri(self): def get_connect_uri(self):
"""Get access parameters in URI format."""
try: try:
proto = self.template.access_type proto = self.template.access_type
if proto == 'ssh': if proto == 'ssh':
...@@ -393,31 +404,31 @@ class Instance(models.Model): ...@@ -393,31 +404,31 @@ class Instance(models.Model):
port = self.get_port() port = self.get_port()
host = self.get_connect_host() host = self.get_connect_host()
pw = self.pw pw = self.pw
return "%(proto)s:cloud:%(pw)s:%(host)s:%(port)d" % {"port": port, return ("%(proto)s:cloud:%(pw)s:%(host)s:%(port)d" %
"proto": proto, "host": self.firewall_host.pub_ipv4, "pw": pw} {"port": port, "proto": proto, "pw": pw,
"host": self.firewall_host.pub_ipv4})
except: except:
return return
def __unicode__(self): def __unicode__(self):
return self.name return self.name
"""
Get and update VM state from OpenNebula.
"""
def update_state(self): def update_state(self):
"""Get and update VM state from OpenNebula."""
import subprocess import subprocess
if not self.one_id: if not self.one_id:
return return
proc = subprocess.Popen(["/opt/occi.sh", "compute", "show", proc = subprocess.Popen(["/opt/occi.sh", "compute", "show",
"%d"%self.one_id], stdout=subprocess.PIPE) "%d" % self.one_id], stdout=subprocess.PIPE)
(out, err) = proc.communicate() (out, err) = proc.communicate()
x = None x = None
old_state = self.state old_state = self.state
try: try:
from xml.dom.minidom import parse, parseString from xml.dom.minidom import parse, parseString
x = parseString(out) x = parseString(out)
self.vnet_ip = x.getElementsByTagName("IP")[0].childNodes[0].nodeValue.split('.')[3] self.vnet_ip = (x.getElementsByTagName("IP")[0].childNodes[0]
.nodeValue.split('.')[3])
state = x.getElementsByTagName("STATE")[0].childNodes[0].nodeValue state = x.getElementsByTagName("STATE")[0].childNodes[0].nodeValue
self.state = state self.state = state
except: except:
...@@ -429,10 +440,8 @@ class Instance(models.Model): ...@@ -429,10 +440,8 @@ class Instance(models.Model):
self.check_if_is_save_as_done() self.check_if_is_save_as_done()
return x return x
"""
Get age of VM in seconds.
"""
def get_age(self): def get_age(self):
"""Get age of VM in seconds."""
from datetime import datetime from datetime import datetime
age = 0 age = 0
try: try:
...@@ -446,11 +455,9 @@ class Instance(models.Model): ...@@ -446,11 +455,9 @@ class Instance(models.Model):
def get_absolute_url(self): def get_absolute_url(self):
return ('vm_show', None, {'iid':self.id}) return ('vm_show', None, {'iid':self.id})
"""
Submit a new instance to OpenNebula.
"""
@classmethod @classmethod
def submit(cls, template, owner, extra="", share=None): def submit(cls, template, owner, extra="", share=None):
"""Submit a new instance to OpenNebula."""
from django.template.defaultfilters import escape from django.template.defaultfilters import escape
out = "" out = ""
inst = Instance(pw=pwgen(), template=template, owner=owner, share=share) inst = Instance(pw=pwgen(), template=template, owner=owner, share=share)
...@@ -498,9 +505,8 @@ class Instance(models.Model): ...@@ -498,9 +505,8 @@ class Instance(models.Model):
f.write(tpl) f.write(tpl)
f.close() f.close()
import subprocess import subprocess
proc = subprocess.Popen(["/opt/occi.sh", proc = subprocess.Popen(["/opt/occi.sh", "compute", "create",
"compute", "create", f.name], stdout=subprocess.PIPE)
f.name], stdout=subprocess.PIPE)
(out, err) = proc.communicate() (out, err) = proc.communicate()
os.unlink(f.name) os.unlink(f.name)
from xml.dom.minidom import parse, parseString from xml.dom.minidom import parse, parseString
...@@ -508,12 +514,16 @@ class Instance(models.Model): ...@@ -508,12 +514,16 @@ class Instance(models.Model):
x = parseString(out) x = parseString(out)
except: except:
raise Exception("Unable to create VM instance.") raise Exception("Unable to create VM instance.")
inst.one_id = int(x.getElementsByTagName("ID")[0].childNodes[0].nodeValue) inst.one_id = int(x.getElementsByTagName("ID")[0].childNodes[0]
.nodeValue)
inst.ip = x.getElementsByTagName("IP")[0].childNodes[0].nodeValue inst.ip = x.getElementsByTagName("IP")[0].childNodes[0].nodeValue
inst.name = "%(neptun)s %(template)s (%(id)d)" % {'neptun': owner.username, 'template': template.name, 'id': inst.one_id} inst.name = ("%(neptun)s %(template)s (%(id)d)" %
{'neptun': owner.username, 'template': template.name,
'id': inst.one_id})
inst.save() inst.save()
inst.update_state() inst.update_state()
host = Host(vlan=Vlan.objects.get(name=template.network.name), owner=owner, shared_ip=True) host = Host(vlan=Vlan.objects.get(name=template.network.name),
owner=owner, shared_ip=True)
host.hostname = u"id-%d_user-%s" % (inst.id, owner.username) host.hostname = u"id-%d_user-%s" % (inst.id, owner.username)
host.mac = x.getElementsByTagName("MAC")[0].childNodes[0].nodeValue host.mac = x.getElementsByTagName("MAC")[0].childNodes[0].nodeValue
host.ipv4 = inst.ip host.ipv4 = inst.ip
...@@ -527,17 +537,16 @@ class Instance(models.Model): ...@@ -527,17 +537,16 @@ class Instance(models.Model):
i.delete() i.delete()
host.save() host.save()
host.enable_net() host.enable_net()
host.add_port("tcp", inst.get_port(), {"rdp": 3389, "nx": 22, "ssh": 22}[inst.template.access_type]) host.add_port("tcp", inst.get_port(), {"rdp": 3389, "nx": 22,
"ssh": 22}[inst.template.access_type])
inst.firewall_host=host inst.firewall_host=host
inst.save() inst.save()
return inst return inst
"""
Delete host in OpenNebula.
"""
def one_delete(self): def one_delete(self):
proc = subprocess.Popen(["/opt/occi.sh", "compute", """Delete host in OpenNebula."""
"delete", "%d"%self.one_id], stdout=subprocess.PIPE) proc = subprocess.Popen(["/opt/occi.sh", "compute", "delete",
"%d" % self.one_id], stdout=subprocess.PIPE)
(out, err) = proc.communicate() (out, err) = proc.communicate()
self.firewall_host_delete() self.firewall_host_delete()
...@@ -561,17 +570,14 @@ class Instance(models.Model): ...@@ -561,17 +570,14 @@ class Instance(models.Model):
f.write(tpl) f.write(tpl)
f.close() f.close()
import subprocess import subprocess
proc = subprocess.Popen(["/opt/occi.sh", proc = subprocess.Popen(["/opt/occi.sh", "compute", "update",
"compute", "update",
f.name], stdout=subprocess.PIPE) f.name], stdout=subprocess.PIPE)
(out, err) = proc.communicate() (out, err) = proc.communicate()
os.unlink(f.name) os.unlink(f.name)
print "out: " + out print "out: " + out
"""
Change host state in OpenNebula.
"""
def _change_state(self, new_state): def _change_state(self, new_state):
"""Change host state in OpenNebula."""
self._update_vm("<STATE>" + new_state + "</STATE>") self._update_vm("<STATE>" + new_state + "</STATE>")
def stop(self): def stop(self):
...@@ -593,9 +599,7 @@ class Instance(models.Model): ...@@ -593,9 +599,7 @@ class Instance(models.Model):
raise ValueError('No such expiration type.') raise ValueError('No such expiration type.')
self.save() self.save()
def save_as(self): def save_as(self):
""" """Save image and shut down."""
Save image and shut down.
"""
imgname = "template-%d-%d" % (self.template.id, self.id) imgname = "template-%d-%d" % (self.template.id, self.id)
self._update_vm('<DISK id="0"><SAVE_AS name="%s"/></DISK>' % imgname) self._update_vm('<DISK id="0"><SAVE_AS name="%s"/></DISK>' % imgname)
self._change_state("SHUTDOWN") self._change_state("SHUTDOWN")
...@@ -630,7 +634,8 @@ def delete_instance(sender, instance, using, **kwargs): ...@@ -630,7 +634,8 @@ def delete_instance(sender, instance, using, **kwargs):
instance.firewall_host_delete() instance.firewall_host_delete()
except: except:
pass pass
post_delete.connect(delete_instance, sender=Instance, dispatch_uid="delete_instance") post_delete.connect(delete_instance, sender=Instance,
dispatch_uid="delete_instance")
def delete_instance_pre(sender, instance, using, **kwargs): def delete_instance_pre(sender, instance, using, **kwargs):
try: try:
...@@ -638,5 +643,6 @@ def delete_instance_pre(sender, instance, using, **kwargs): ...@@ -638,5 +643,6 @@ def delete_instance_pre(sender, instance, using, **kwargs):
instance.check_if_is_save_as_done() instance.check_if_is_save_as_done()
except: except:
pass pass
pre_delete.connect(delete_instance_pre, sender=Instance, dispatch_uid="delete_instance_pre") pre_delete.connect(delete_instance_pre, sender=Instance,
dispatch_uid="delete_instance_pre")
...@@ -30,5 +30,3 @@ def keygen(length=1024): ...@@ -30,5 +30,3 @@ def keygen(length=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(), "%s %s" % (pub, "cloud-%s" % date.today()) return key.exportKey(), "%s %s" % (pub, "cloud-%s" % date.today())
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