Commit 0d188bd6 by Őry Máté

Merge branch 'release-13.03.1' into releases

parents e0757a88 a5e7ec7a
...@@ -34,6 +34,10 @@ nosetests.xml ...@@ -34,6 +34,10 @@ nosetests.xml
.project .project
.pydevproject .pydevproject
# Compiled CSS/JS resources
*.css
*.min.js
# Other # Other
*.swp *.swp
*~ *~
......
SHELL := /bin/bash SHELL := /bin/bash
jsfiles += one/static/script/cloud.min.js
jsfiles += one/static/script/util.min.js
jsfiles += one/static/script/store.min.js
cssfiles += one/static/style/style.css
default: migrate collectstatic mo restart default: migrate generatestatic collectstatic mo restart
pulldef: pull default pulldef: pull default
pull: pull:
...@@ -14,6 +18,8 @@ po: ...@@ -14,6 +18,8 @@ po:
migrate: migrate:
./manage.py migrate ./manage.py migrate
generatestatic: $(jsfiles) $(cssfiles)
collectstatic: collectstatic:
./manage.py collectstatic --noinput ./manage.py collectstatic --noinput
...@@ -22,4 +28,10 @@ mo: ...@@ -22,4 +28,10 @@ mo:
for i in */; do cd $$i; ls locale &>/dev/null && ../manage.py compilemessages || true; cd ..; done for i in */; do cd $$i; ls locale &>/dev/null && ../manage.py compilemessages || true; cd ..; done
restart: restart:
sudo /etc/init.d/apache2 reload sudo /etc/init.d/apache2 reload || sudo restart django
%.min.js: %.js
uglifyjs $< > $@
%.css: %.less
lessc one/static/style/style.less > one/static/style/style.css
from cloud.settings import DEBUG
def process_debug(req):
return {'DEBUG': DEBUG}
...@@ -5,7 +5,7 @@ DEBUG = True ...@@ -5,7 +5,7 @@ DEBUG = True
TEMPLATE_DEBUG = DEBUG TEMPLATE_DEBUG = DEBUG
ADMINS = ( ADMINS = (
('IK', 'cloud@iit.bme.hu'), ('IK', 'cloud@cloud.ik.bme.hu'),
) )
MANAGERS = ADMINS MANAGERS = ADMINS
...@@ -73,6 +73,7 @@ STATICFILES_DIRS = ( ...@@ -73,6 +73,7 @@ STATICFILES_DIRS = (
# Always use forward slashes, even on Windows. # Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths. # Don't forget to use absolute paths, not relative paths.
'/opt/webadmin/cloud/one/static', '/opt/webadmin/cloud/one/static',
'/opt/webadmin/cloud/cloud/static',
) )
# List of finder classes that know how to find static files in # List of finder classes that know how to find static files in
...@@ -109,6 +110,17 @@ ROOT_URLCONF = 'cloud.urls' ...@@ -109,6 +110,17 @@ ROOT_URLCONF = 'cloud.urls'
# Python dotted path to the WSGI application used by Django's runserver. # Python dotted path to the WSGI application used by Django's runserver.
WSGI_APPLICATION = 'cloud.wsgi.application' WSGI_APPLICATION = 'cloud.wsgi.application'
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.static',
'django.core.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'cloud.context_processors.process_debug',
)
TEMPLATE_DIRS = ( TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows. # Always use forward slashes, even on Windows.
...@@ -186,6 +198,8 @@ CELERY_ROUTES = { ...@@ -186,6 +198,8 @@ CELERY_ROUTES = {
'firewall.tasks.reload_firewall_task': {'queue': 'firewall'}, 'firewall.tasks.reload_firewall_task': {'queue': 'firewall'},
'firewall.tasks.reload_dhcp_task': {'queue': 'dhcp'}, 'firewall.tasks.reload_dhcp_task': {'queue': 'dhcp'},
'firewall.tasks.reload_blacklist_task': {'queue': 'firewall'}, 'firewall.tasks.reload_blacklist_task': {'queue': 'firewall'},
'firewall.tasks.Periodic': {'queue': 'local'},
'one.tasks.SendMailTask': {'queue': 'local'},
} }
store_settings = { store_settings = {
...@@ -200,7 +214,6 @@ store_settings = { ...@@ -200,7 +214,6 @@ store_settings = {
"store_public": "store.ik.bme.hu", "store_public": "store.ik.bme.hu",
} }
firewall_settings = { firewall_settings = {
"default_vlangroup": "publikus", "default_vlangroup": "publikus",
"reload_sleep": "10", "reload_sleep": "10",
...@@ -210,6 +223,9 @@ firewall_settings = { ...@@ -210,6 +223,9 @@ firewall_settings = {
"dns_ttl": "300", "dns_ttl": "300",
} }
EMAIL_HOST='152.66.243.92' # giccero ipv4
CLOUD_URL='https://cloud.ik.bme.hu/'
try: try:
from cloud.local_settings import * from cloud.local_settings import *
except: except:
......
<!DOCTYPE html>
<html lang="hu">
<head>
<title>IK Cloud</title>
<link href="https://fonts.googleapis.com/css?family=Titillium+Web&amp;subset=latin,latin-ext" rel="stylesheet" type="text/css" />
<link rel="icon" type="image/png" href="/static/favicon.png" />
<link href="/static/style/style.css" rel="stylesheet" type="text/css" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<div id="header">
<h1><a href="/">IK Cloud</a></h1>
</div>
<div id="content">
<div id="http-error">
<h1>Karbantartás – Maintenance</h1>
<p lang="hu">
Az oldal ideiglenesen nem érhető el karbantartás miatt. Elnézést kérünk a kellemetlenségekért.
</p>
<p lang="en">
The site is temporarily down for maintenance. We apologize for any inconvinience.
</p>
</div>
<div class="clear"></div>
</div>
<footer>
<a href="/sites/legal/">Impresszum</a> |
<a href="/sites/policy/">Szabályzat</a> |
<a href="/sites/help/">Súgó</a> |
<a href="/sites/support/">Támogatás</a> |
cloud <em>(kukac)</em> ik.bme.hu
</footer>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-39125666-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>
{% extends "base.html" %}
{% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block js %}
<script type="text/javascript" src="{% static "script/store.js" %}"></script>
<style>
.contentblock p{
margin: 15px;
text-align: justify;
}
.contentblock img{
margin: 0px auto;
display: block;
box-shadow: 0 0 30px rgba(0, 0, 0, 0.3);
border-radius: 5px;
text-align: center;
vertical-align: middle;
}
.boxes a:link,
a:visited {
color: black;
}
.boxes strong {
font-size: .9em;
}
</style>
{% endblock %}
{% block content %}
<div class="boxes">
<div class="contentblock" id="state">
<h2>A projektről</h2>
<div>
<p>Az <strong>IK Cloud</strong> a BME IK és IIT együttműködésében, a VIK
támogatásával hosszabb ideje folyó munka során jött létre.
A kutatás célja <strong>a cloud oktatási-kutatási célú felhasználásának</strong>
vonzóvá tétele.
</p>
<p>
A nagy kapacitású virtuális infrastruktúra azonban új lehetőséget is nyújt.
<strong>Igény szerint</strong> indíthatóak virtuális gépek:
gördülékennyé válik a tantermi és otthoni <strong>hallgatói munka,</strong>
a kutatási <strong>projektek dinamikus IT támogatása.</strong>
</p>
<p><img src="{% static "info/cloud-migration.png" %}" /></p>
<p>A rendszerünk segítségével <strong>kiváltható</strong> a tanszéken
működő öregedő szerverpark jelentős része.</p>
</div>
</div>
</div>
<div class="boxes">
<div class="contentblock" id="state">
<h2>Virtuális labor</h2>
<div>
<p><img src="{% static "info/cloud-lab.png" %}" /></p>
<p>Lehetőség van <strong>tantárgyra szabott környezet</strong> biztosítására
a tantermi mérések vagy az otthoni feladatok elvégzéséhez, vagy az
önkiszolgáló felületen pillanatok alatt indítható <strong>projektek, önálló
labor, szakdolgozat, diplomaterv, vagy TDK-munka</strong> segítéséhez
virtuális gép.</p>
<p style="text-align:center;"><a
href="{% url one.views.home %}">Próbálja ki a rendszert
most!</a></p>
</div>
</div>
<div class="contentblock" id="state" lang="en">
<h2>About the project</h2>
<div>
<p>The project aims to harness the power of cloud computing in
education and research. Our self service portal helps migrating
old servers, and on-demand launching appliances prepared by the
teacher.</p>
</p>
</div>
</div>
</div>
{% endblock %}
{% extends "base.html" %}
{% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
<div class="irasmu">
<p>A súgó elkészültéig kérjük szíves türelmüket.</p>
<p>Addig is ajánljuk figyelmükbe a rendszer <a href="/info/">rövid ismertetőjét</a>, a használat módját részletező <a href="/sites/policy/">szabályzatot</a>, valamint a felület számos pontján megjelenő <img src="{% static "icons/information-frame.png" %}" alt="Súgó" /> ikonnal jelölt információdobozokat.</p>
<p>Amennyiben kérdése maradt, örömmel segítünk a <a href="/sites/support/">támogatás</a> oldalon leírt elérhetőségeinken.</p>
</div>
{% endblock %}
{% extends "base.html" %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
<div class="irasmu">
<p>Az IK Cloud a BME IK és IIT együttműködésében, a VIK támogatásával létrejött rendszer, amelyben az IIT oktatói és hallgatói szükség szerint vehetnek igénybe virtuális erőforrásokat.
</p>
<p>Az oldal üzemeltetője a BME Közigazgatási Informatikai Központ.</p>
<p>A rendszer fejlesztésében részt vettek:
Bach Dániel,
Dányi Bence,
Dudás Ádám,
Guba Sándor,
Őry Máté és
dr. Szeberényi Imre.</p>
<p>A rendszer HP hardveren, Ubuntu operációs rendszeren, KVM virtualizációval, Open vSwitch virtuális hálózaton, libvirt köztes réteggel, OpenNebula cloud menedzserrel, Django alapú webportállal működik.</p>
<p>Some icons by <a href="http://p.yusukekamiyamane.com/">Yusuke Kamiyamane</a>. Licensed under a <a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 License</a>.</p>
</div>
{% endblock %}
{% extends "base.html" %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
<div class="irasmu">
<p>Az IK Cloud a BME IK és IIT együttműködésében, a VIK támogatásával létrejött rendszer, amelyben az IIT oktatói és hallgatói szükség szerint vehetnek igénybe <strong>virtuális erőforrásokat</strong>.</p>
<p>Az IIT géptermeiben telepített kliensszoftver segítségével az oktató által előkészített és kiajánlott <strong>virtuális környezetet a hallgató</strong> a számára megszabott <strong>kvóta keretein belül</strong> igény szerint indíthatja.</p>
<p>A HSZK géptermeiben a kliensszoftver jelenleg nincs telepítve, de a virtuális gépek indítása, a fájlok elérése webböngészővel is teljes értékű; míg a gépekhez való csatlakozás kézzel elvégezhető.</p>
<p>Lehetőség van a gépteremben elkezdett munka otthoni folytatására is a korábban elindított környezetben. A rendszer segítségével az otthoni feladatot végző hallgató is elkerülheti az összetett szoftverkörnyezet telepítésével járó kellemetlenségeket, figyelmét a szakmai munkára irányíthatja.</p>
<p>A rendszer segítséget nyújt önálló labor, szakdolgozat, diplomaterv vagy tdk-munka készítésénél is: a munkához szükséges virtuális gépeket az önkiszolgáló rendszeren keresztül azonnal használatba lehet venni.</p>
<p>Az elindított virtuális gépekre az adott operációs rendszeren szokásos módon lehet távolról csatlakozni: Windows esetén RDP (távoli asztal), Linux esetén SSH, vagy grafikusan NoMachine NX segítségével. A kapcsolódást a géptermekben telepített kliensszoftver még kényelmesebbé teszi.</p>
<p>Az elindított gépeken a <strong>felhasználói adattár</strong> automatikusan csatolásra kerül. Minden munkát itt érdemes végezni, mivel az a gép leállítása után is elérhető marad.</p>
<p>A felhasználók a rendszert jelen önkiszolgáló felületen keresztül érhetik el, amelybe az egyetemi címtárszolgáltatás (eduID) segítségével léphetnek be. A továbblépéssel elfogadják a következőekben összefoglalt <strong>felhasználási feltételeket</strong>.</p>
<ul>
<li>A rendszer <strong>nem használható</strong> semmilyen jogszabályba, vagy <a href="http://net.bme.hu/regula/">egyetemi</a> <strong>szabályzatba ütköző tevékenységre</strong>.</li>
<li><strong>Kizárólag tanulmányi</strong> vagy <strong>kutatási tevékenységhez</strong> használható erőforrás.</li>
<li>Bár a rendszer használata térítésmentes, a <strong>felesleges gépek leállítása</strong> a felhasználó kötelessége.</li>
<li>Minden gép indítása <strong>határidő kijelölésével</strong> történik. A határidő lejártával <strong>a gépet megállítjuk</strong>. Amennyiben a felhasználó a megállítást követően (a törlési határidő leteltéig) nem kéri meghosszabbítását, a gépet és <strong>minden rajta lévő adatot törlünk!</strong></li>
<li>A felhasználó felelőssége a futtatott rendszer biztonságos üzemeltetése, a hosszabb időn át futó gépek frissítése.</li>
<li>A rendszert üzemeltető BME IK lehetőségeihez mérten mindent megtesz a szolgáltatásbiztos üzemért, az egyetemi infrastruktúra sajátosságai miatt előforduló üzemszünetekre azonban számítani kell. A BME IK az üzemeltetés kapcsán a folyamatos üzem sérüléséért vagy adatvesztésért <strong>minden felelősséget kizár</strong>. Ezeknek megfelelően szükség esetén a biztonsági mentés és a magas rendelkezésre állású környezet kialakítása a felhasználóra hárul.</li>
</ul>
<p>A szabályok betartása közös érdekünk. Reméljük, hogy a rendszerünk használata megkönnyíti munkájukat, melyhez sok sikert kívánunk!</p>
</div>
{% endblock %}
{% extends "base.html" %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
<div class="irasmu">
<p>A rendszer használatával kapcsolatos kérdéseket, általános észrevételeket a <tt>cloud <em>(kukac)</em>
ik.bme.hu</tt> e-mail címen várjuk.
Ugyancsak örömmel fogadjuk a rendszer használatával kapcsolatos beszámolókat.</p>
<p>A rendszerben talált hibákat (vagy azok gyanúját), valamint ötleteit, javaslatait kérjük,
<a href="https://giccero.cloud.ik.bme.hu/trac/cloud/newticket" rel="nofollow">
hibajegy felvételével</a> jelezze.
</p>
</div>
{% endblock %}
...@@ -5,107 +5,91 @@ admin.autodiscover() ...@@ -5,107 +5,91 @@ admin.autodiscover()
import one.views import one.views
import firewall.views import firewall.views
#import store.views # import store.views
js_info_dict = { js_info_dict = {
'packages': ('one', ), 'packages': ('one', ),
} }
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^admin/doc/', include('django.contrib.admindocs.urls')), url(r'^admin/doc/', include('django.contrib.admindocs.urls'), ),
url(r'^admin/', include(admin.site.urls)), url(r'^admin/', include(admin.site.urls), ),
url(r'^$', 'one.views.home', name='home'),
url(r'^login/$', 'school.views.login', name='login'),
url(r'^logout/$', 'school.views.logout', name='logout'), url(r'^login/$', 'school.views.login', name='login', ),
url(r'^vm/new/(?P<template>\d+)/$', 'one.views.vm_new', name='vm_new'), url(r'^logout/$', 'school.views.logout', name='logout', ),
url(r'^ajax/vm/new/(?P<template>\d+)/$', 'one.views.vm_new_ajax',
name='vm_new_ajax'), url(r'^$', 'one.views.index', ),
url(r'^vm/new/s(?P<share>\d+)/$', 'one.views.vm_new', name='vm_new'), url(r'^info/$', 'one.views.info', ),
url(r'^vm/show/(?P<iid>\d+)/$', 'one.views.vm_show', name='vm_show'), url(r'^home/$', 'one.views.home', ),
url(r'^vm/delete/(?P<iid>\d+)/$', 'one.views.vm_delete', url(r'^vm/new/(?P<template>\d+)/$', 'one.views.vm_new',
name='vm_delete'), name='new_vm_from_template'),
url(r'^vm/stop/(?P<iid>\d+)/$', 'one.views.vm_stop', name='vm_stop'), url(r'^ajax/vm/new/(?P<template>\d+)/$', 'one.views.vm_new_ajax', ),
url(r'^vm/unshare/(?P<id>\d+)/$', 'one.views.vm_unshare', url(r'^vm/new/s(?P<share>\d+)/$', 'one.views.vm_new',
name='vm_unshare'), name='new_vm_form_share'),
url(r'^vm/resume/(?P<iid>\d+)/$', 'one.views.vm_resume', url(r'^vm/show/(?P<iid>\d+)/$', 'one.views.vm_show', ),
name='vm_resume'), url(r'^vm/delete/(?P<iid>\d+)/$', 'one.views.vm_delete', ),
url(r'^vm/power_off/(?P<iid>\d+)/$', 'one.views.vm_power_off', url(r'^vm/stop/(?P<iid>\d+)/$', 'one.views.vm_stop', ),
name='vm_power_off'), url(r'^vm/unshare/(?P<id>\d+)/$', 'one.views.vm_unshare', ),
url(r'^vm/restart/(?P<iid>\d+)/$', 'one.views.vm_restart', url(r'^vm/resume/(?P<iid>\d+)/$', 'one.views.vm_resume', ),
name='vm_restart'), url(r'^vm/power_off/(?P<iid>\d+)/$', 'one.views.vm_power_off', ),
url(r'^vm/restart/(?P<iid>\d+)/$', 'one.views.vm_restart', ),
url(r'^vm/renew/(?P<which>(suspend|delete))/(?P<iid>\d+)/$', url(r'^vm/renew/(?P<which>(suspend|delete))/(?P<iid>\d+)/$',
'one.views.vm_renew', name='vm_renew'), 'one.views.vm_renew', ),
url(r'^vm/port_add/(?P<iid>\d+)/$', 'one.views.vm_port_add', url(r'^vm/port_add/(?P<iid>\d+)/$', 'one.views.vm_port_add', ),
name='vm_port_add'),
url(r'^vm/port_del/(?P<iid>\d+)/(?P<proto>tcp|udp)/(?P<public>\d+)/$', url(r'^vm/port_del/(?P<iid>\d+)/(?P<proto>tcp|udp)/(?P<public>\d+)/$',
'one.views.vm_port_del', name='vm_port_del'), 'one.views.vm_port_del', ),
url(r'^vm/saveas/(?P<vmid>\d+)$', 'one.views.vm_saveas', url(r'^ajax/shareEdit/(?P<id>\d+)/$', 'one.views.ajax_share_edit_wizard',
name='vm_saveas'), name='ajax_share_edit_wizard'),
url(r'^vm/credentials/(?P<iid>\d+)$', 'one.views.vm_credentials', url(r'^vm/saveas/(?P<vmid>\d+)$', 'one.views.vm_saveas', ),
name='vm_credentials'), url(r'^vm/credentials/(?P<iid>\d+)$', 'one.views.vm_credentials', ),
url(r'^reload/$', 'firewall.views.reload_firewall', url(r'^ajax/templateWizard/$', 'one.views.ajax_template_wizard', ),
name='reload_firewall'), url(r'^ajax/templateEditWizard/(?P<id>\d+)/$', 'one.views.ajax_template_edit_wizard', ),
url(r'^fwapi/$', 'firewall.views.firewall_api', url(r'^ajax/share/(?P<id>\d+)/$', 'one.views.ajax_share_wizard', ),
name='firewall_api'),
url(r'^store/$', 'store.views.index', name='store_index'),
url(r'^store/gui/$', 'store.views.gui', name='store_gui'),
url(r'^store/top/$', 'store.views.toplist', name='store_top'),
url(r'^ajax/store/top/$', 'store.views.ajax_toplist',
name='axat_store_top'),
url(r'^ajax/templateWizard$', 'one.views.ajax_template_wizard',
name='ajax_template_wizard'),
url(r'^ajax/share/(?P<id>\d+)/$', 'one.views.ajax_share_wizard',
name='ajax_share_wizard'),
url(r'^ajax/share/(?P<id>\d+)/(?P<gid>\d+)$', url(r'^ajax/share/(?P<id>\d+)/(?P<gid>\d+)$',
'one.views.ajax_share_wizard', name='ajax_share_wizard'), 'one.views.ajax_share_wizard', ),
url(r'^ajax/template/delete/$', 'one.views.ajax_template_delete',
name='ajax_template_delete'),
url(r'^ajax/template_name_unique/(?P<name>.*)$',
'one.views.ajax_template_name_unique',
name='ajax_template_name_unique'),
url(r'^ajax/store/list$', 'store.views.ajax_listfolder',
name='store_ajax_listfolder'),
url(r'^ajax/store/download$', 'store.views.ajax_download',
name='store_ajax_download'),
url(r'^ajax/store/upload$', 'store.views.ajax_upload',
name='store_ajax_upload'),
url(r'^ajax/store/delete$', 'store.views.ajax_delete',
name='store_ajax_delete'),
url(r'^ajax/store/newFolder$', 'store.views.ajax_new_folder',
name='store_ajax_new_folder'),
url(r'^ajax/store/quota$', 'store.views.ajax_quota',
name='store_ajax_quota'),
url(r'^ajax/store/rename$', 'store.views.ajax_rename',
name='store_ajax_rename'),
url(r'^ajax/vm/status/(?P<iid>\d+)$', url(r'^ajax/vm/status/(?P<iid>\d+)$',
'one.views.vm_ajax_instance_status', 'one.views.vm_ajax_instance_status', ),
name='vm_ajax_instance_status'),
url(r'^ajax/vm/rename/(?P<iid>\d+)/$', url(r'^ajax/vm/rename/(?P<iid>\d+)/$',
'one.views.vm_ajax_rename', 'one.views.vm_ajax_rename', ),
name='vm_ajax_rename'), url(r'^key/add/$', 'one.views.key_add', ),
url(r'^language/(?P<lang>[-A-Za-z]+)/$', 'school.views.language', url(r'^ajax/key/delete/$', 'one.views.key_ajax_delete', ),
name='language'), url(r'^ajax/key/reset/$', 'one.views.key_ajax_reset', ),
url(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict), url(r'^ajax/template/delete/$', 'one.views.ajax_template_delete', ),
url(r'^b/(?P<token>.*)/$', 'one.views.boot_token', name='boot_token'), url(r'^ajax/template_name_unique/$',
'one.views.ajax_template_name_unique', ),
url(r'^reload/$', 'firewall.views.reload_firewall', ),
url(r'^fwapi/$', 'firewall.views.firewall_api', ),
url(r'^store/$', 'store.views.index', ),
url(r'^store/gui/$', 'store.views.gui', ),
url(r'^store/top/$', 'store.views.toplist', ),
url(r'^ajax/store/top/$', 'store.views.ajax_toplist', ),
url(r'^ajax/store/list$', 'store.views.ajax_listfolder', ),
url(r'^ajax/store/download$', 'store.views.ajax_download', ),
url(r'^ajax/store/upload$', 'store.views.ajax_upload', ),
url(r'^ajax/store/delete$', 'store.views.ajax_delete', ),
url(r'^ajax/store/newFolder$', 'store.views.ajax_new_folder', ),
url(r'^ajax/store/quota$', 'store.views.ajax_quota', ),
url(r'^ajax/store/rename$', 'store.views.ajax_rename', ),
url(r'^language/(?P<lang>[-A-Za-z]+)/$', 'school.views.language', ),
url(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict, ),
url(r'^b/(?P<token>.*)/$', 'one.views.boot_token', ),
url(r'^group/show/(?P<gid>\d+)/$', 'school.views.group_show', url(r'^group/show/(?P<gid>\d+)/$', 'school.views.group_show',
name='group_show'), name='group_show'),
url(r'^group/new/$', 'school.views.group_new', name='group_new'), url(r'^group/new/$', 'school.views.group_new', ),
url(r'^ajax/group/(?P<gid>\d+)/add/$', url(r'^ajax/group/(?P<gid>\d+)/add/$',
'school.views.group_ajax_add_new_member', 'school.views.group_ajax_add_new_member', ),
name='group_ajax_add_new_member'),
url(r'^ajax/group/(?P<gid>\d+)/addOwner/$', url(r'^ajax/group/(?P<gid>\d+)/addOwner/$',
'school.views.group_ajax_add_new_owner', 'school.views.group_ajax_add_new_owner', ),
name='group_ajax_add_new_owner'),
url(r'^ajax/group/(?P<gid>\d+)/remove/$', url(r'^ajax/group/(?P<gid>\d+)/remove/$',
'school.views.group_ajax_remove_member', 'school.views.group_ajax_remove_member', ),
name='group_ajax_remove_member'), url(r'^ajax/group/delete/$', 'school.views.group_ajax_delete', ),
url(r'^ajax/group/delete/$', 'school.views.group_ajax_delete', url(r'^ajax/group/autocomplete/$',
name='group_ajax_delete'), 'school.views.group_ajax_owner_autocomplete', ),
url(r'^ajax/group/autocomplete/$', 'school.views.group_ajax_owner_autocomplete', url(r'^stat/$', 'one.views.stat'),
name='group_ajax_autocomplete'), url(r'^sites/(?P<site>[a-zA-Z0-9]+)/$', 'one.views.sites'),
url(r'^key/add/$', 'one.views.key_add', name='key_add'), url(r'^accounts/(?P<site>profile)/$', 'one.views.sites'),
url(r'^ajax/key/delete/$', 'one.views.key_ajax_delete',
name='key_ajax_delete'),
url(r'^ajax/key/reset/$', 'one.views.key_ajax_reset',
name='key_ajax_reset'),
) )
...@@ -13,7 +13,7 @@ class RecordInline(contrib.admin.TabularInline): ...@@ -13,7 +13,7 @@ class RecordInline(contrib.admin.TabularInline):
class HostAdmin(admin.ModelAdmin): class HostAdmin(admin.ModelAdmin):
list_display = ('hostname', 'vlan', 'ipv4', 'ipv6', 'pub_ipv4', 'mac', list_display = ('hostname', 'vlan', 'ipv4', 'ipv6', 'pub_ipv4', 'mac',
'shared_ip', 'owner', 'description', 'reverse', 'groups_l') 'shared_ip', 'owner', 'description', 'reverse', 'list_groups')
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')
...@@ -21,7 +21,7 @@ class HostAdmin(admin.ModelAdmin): ...@@ -21,7 +21,7 @@ class HostAdmin(admin.ModelAdmin):
inlines = (RuleInline, RecordInline) inlines = (RuleInline, RecordInline)
@staticmethod @staticmethod
def groups_l(instance): def list_groups(instance):
"""Returns instance's groups' names as a comma-separated list.""" """Returns instance's groups' names as a comma-separated list."""
names = [group.name for group in instance.groups.all()] names = [group.name for group in instance.groups.all()]
return u', '.join(names) return u', '.join(names)
...@@ -45,34 +45,36 @@ class RuleAdmin(admin.ModelAdmin): ...@@ -45,34 +45,36 @@ class RuleAdmin(admin.ModelAdmin):
def color_desc(self, instance): def color_desc(self, instance):
"""Returns a colorful description of the instance.""" """Returns a colorful description of the instance."""
para = '</span>' return (u'<span style="color: #FF0000;">[%(type)s]</span> '
if instance.dport: u'%(src)s<span style="color: #0000FF;"> ▸ </span>%(dst)s '
para = 'dport=%s %s' % (instance.dport, para) u'%(para)s %(desc)s') % {
if instance.sport: 'type': instance.r_type,
para = 'sport=%s %s' % (instance.sport, para) 'src': (instance.foreign_network.name
if instance.proto: if instance.direction == '1' else instance.r_type),
para = 'proto=%s %s' % (instance.proto, para) 'dst': (instance.r_type if instance.direction == '1'
para = u'<span style="color: #00FF00;">' + para else instance.foreign_network.name),
return ( 'para': (u'<span style="color: #00FF00;">' +
u'<span style="color: #FF0000;">[%s]</span> ' % instance.r_type + (('proto=%s ' % instance.proto)
(u'%s<span style="color: #0000FF;"> ▸ </span>%s' % if instance.proto else '') +
((instance.foreign_network.name, instance.r_type) (('sport=%s ' % instance.sport)
if instance.direction == '1' else if instance.sport else '') +
(instance.r_type, instance.foreign_network.name))) + (('dport=%s ' % instance.dport)
' ' + para + ' ' + instance.description) if instance.dport else '') +
'</span>'),
'desc': instance.description}
color_desc.allow_tags = True color_desc.allow_tags = True
def vlan_l(self, instance): @staticmethod
def vlan_l(instance):
"""Returns instance's VLANs' names as a comma-separated list.""" """Returns instance's VLANs' names as a comma-separated list."""
retval = [] names = [vlan.name for vlan in instance.foreign_network.vlans.all()]
for vlan in instance.foreign_network.vlans.all(): return u', '.join(names)
retval.append(vlan.name)
return u', '.join(retval)
def used_in(self, instance): @staticmethod
def used_in(instance):
for field in [instance.vlan, instance.vlangroup, instance.host, for field in [instance.vlan, instance.vlangroup, instance.host,
instance.hostgroup, instance.firewall]: instance.hostgroup, instance.firewall]:
if field is not None: if field:
return unicode(field) + ' ' + field._meta.object_name return unicode(field) + ' ' + field._meta.object_name
...@@ -92,15 +94,15 @@ class DomainAdmin(admin.ModelAdmin): ...@@ -92,15 +94,15 @@ class DomainAdmin(admin.ModelAdmin):
class RecordAdmin(admin.ModelAdmin): class RecordAdmin(admin.ModelAdmin):
list_display = ('name_', 'type', 'address_', 'ttl', 'host', 'owner') list_display = ('name_', 'type', 'address_', 'ttl', 'host', 'owner')
def address_(self, instance): @staticmethod
def address_(instance):
a = instance.get_data() a = instance.get_data()
if a: return a['address'] if a else None
return a['address']
def name_(self, instance): @staticmethod
def name_(instance):
a = instance.get_data() a = instance.get_data()
if a: return a['name'] if a else None
return a['name']
class BlacklistAdmin(admin.ModelAdmin): class BlacklistAdmin(admin.ModelAdmin):
list_display = ('ipv4', 'reason', 'created_at', 'modified_at') list_display = ('ipv4', 'reason', 'created_at', 'modified_at')
......
...@@ -2,6 +2,7 @@ from django.core.exceptions import ValidationError ...@@ -2,6 +2,7 @@ from django.core.exceptions import ValidationError
from django.forms import fields from django.forms import fields
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.ipv6 import is_valid_ipv6_address
from south.modelsinspector import add_introspection_rules from south.modelsinspector import add_introspection_rules
import re import re
...@@ -35,26 +36,46 @@ class MACAddressField(models.Field): ...@@ -35,26 +36,46 @@ class MACAddressField(models.Field):
add_introspection_rules([], ["firewall\.fields\.MACAddressField"]) add_introspection_rules([], ["firewall\.fields\.MACAddressField"])
def val_alfanum(value): def val_alfanum(value):
"""Check whether the parameter is a valid alphanumeric value.""" """Validate whether the parameter is a valid alphanumeric value."""
if alfanum_re.search(value) is None: if not alfanum_re.match(value):
raise ValidationError( raise ValidationError(_(u'%s - only letters, numbers, underscores '
_(u'%s - only letters, numbers, underscores and hyphens are ' 'and hyphens are allowed!') % value)
'allowed!') % value)
def is_valid_domain(value):
"""Check whether the parameter is a valid domain name."""
return domain_re.match(value) is not None
def val_domain(value): def val_domain(value):
"""Check wheter the parameter is a valid domin.""" """Validate whether the parameter is a valid domin name."""
if domain_re.search(value) is None: if not is_valid_domain(value):
raise ValidationError(_(u'%s - invalid domain') % value) raise ValidationError(_(u'%s - invalid domain name') % value)
def is_valid_reverse_domain(value):
"""Check whether the parameter is a valid reverse domain name."""
return reverse_domain_re.match(value) is not None
def val_reverse_domain(value): def val_reverse_domain(value):
"""Check whether the parameter is a valid reverse domain.""" """Validate whether the parameter is a valid reverse domain name."""
if not reverse_domain_re.search(value): if not is_valid_reverse_domain(value):
raise ValidationError(u'%s - reverse domain' % value) raise ValidationError(u'%s - invalid reverse domain name' % value)
def is_valid_ipv4_address(value):
"""Check whether the parameter is a valid IPv4 address."""
return ipv4_re.match(value) is not None
def val_ipv4(value):
"""Validate whether the parameter is a valid IPv4 address."""
if not is_valid_ipv4_address(value):
raise ValidationError(_(u'%s - not an IPv4 address') % value)
def val_ipv6(value):
"""Validate whether the parameter is a valid IPv6 address."""
if not is_valid_ipv6_address(value):
raise ValidationError(_(u'%s - not an IPv6 address') % value)
def ipv4_2_ipv6(ipv4): def ipv4_2_ipv6(ipv4):
"""Convert IPv4 address string to IPv6 address string.""" """Convert IPv4 address string to IPv6 address string."""
val_ipv4(ipv4)
m = ipv4_re.match(ipv4) m = ipv4_re.match(ipv4)
if m is None:
raise ValidationError(_(u'%s - not an IPv4 address') % ipv4)
return ("2001:738:2001:4031:%s:%s:%s:0" % return ("2001:738:2001:4031:%s:%s:%s:0" %
(m.group(1), m.group(2), m.group(3))) (m.group(1), m.group(2), m.group(3)))
...@@ -10,7 +10,7 @@ from datetime import datetime, timedelta ...@@ -10,7 +10,7 @@ from datetime import datetime, timedelta
from django.db.models import Q from django.db.models import Q
class firewall: class Firewall:
IPV6=False IPV6=False
RULES = None RULES = None
RULES_NAT = [] RULES_NAT = []
...@@ -36,14 +36,15 @@ class firewall: ...@@ -36,14 +36,15 @@ class firewall:
def iptables(self, s): def iptables(self, s):
"""Append rule.""" """Append rule to filter table."""
self.RULES.append(s) self.RULES.append(s)
def iptablesnat(self, s): def iptablesnat(self, s):
"""Append rule to NAT table."""
self.RULES_NAT.append(s) self.RULES_NAT.append(s)
def host2vlan(self, host, rule): def host2vlan(self, host, rule):
if rule.foreign_network is None: if not rule.foreign_network:
return return
if self.IPV6 and host.ipv6: if self.IPV6 and host.ipv6:
...@@ -76,7 +77,7 @@ class firewall: ...@@ -76,7 +77,7 @@ class firewall:
def fw2vlan(self, rule): def fw2vlan(self, rule):
if rule.foreign_network is None: if not rule.foreign_network:
return return
dport_sport = self.dportsport(rule) dport_sport = self.dportsport(rule)
...@@ -92,7 +93,7 @@ class firewall: ...@@ -92,7 +93,7 @@ class firewall:
'LOG_ACC' if rule.accept else 'LOG_DROP')) 'LOG_ACC' if rule.accept else 'LOG_DROP'))
def vlan2vlan(self, l_vlan, rule): def vlan2vlan(self, l_vlan, rule):
if rule.foreign_network is None: if not rule.foreign_network:
return return
dport_sport = self.dportsport(rule) dport_sport = self.dportsport(rule)
......
...@@ -19,44 +19,47 @@ def reload_dhcp_task(data): ...@@ -19,44 +19,47 @@ def reload_dhcp_task(data):
def reload_blacklist_task(data): def reload_blacklist_task(data):
pass pass
class Periodic(PeriodicTask):
run_every = timedelta(seconds=10)
def run(self, **kwargs):
if cache.get('dns_lock'):
cache.delete("dns_lock")
reload_dns_task.delay(dns())
print "dns ujratoltese kesz"
if cache.get('dhcp_lock'):
cache.delete("dhcp_lock")
reload_dhcp_task.delay(dhcp())
print "dhcp ujratoltese kesz"
if cache.get('firewall_lock'):
cache.delete("firewall_lock")
ipv4 = Firewall().get()
ipv6 = Firewall(True).get()
reload_firewall_task.delay(ipv4, ipv6)
print "firewall ujratoltese kesz"
if cache.get('blacklist_lock'):
cache.delete("blacklist_lock")
reload_blacklist_task.delay(list(ipset()))
print "blacklist ujratoltese kesz"
class ReloadTask(Task): class ReloadTask(Task):
def run(self, type='Host'): def run(self, type='Host'):
sleep=False
if type in ["Host", "Records", "Domain", "Vlan"]: if type in ["Host", "Records", "Domain", "Vlan"]:
lock = lambda: cache.add("dns_lock", "true", 9) cache.add("dns_lock", "true", 30)
if lock():
if not sleep:
sleep = True
time.sleep(10)
reload_dns_task.delay(dns())
if type == "Host": if type == "Host":
lock = lambda: cache.add("dhcp_lock", "true", 9) cache.add("dhcp_lock", "true", 30)
if lock():
if not sleep:
sleep = True
time.sleep(10)
reload_dhcp_task.delay(dhcp())
if type in ["Host", "Rule", "Firewall"]: if type in ["Host", "Rule", "Firewall"]:
lock = lambda: cache.add("firewall_lock", "true", 9) cache.add("firewall_lock", "true", 30)
if lock():
if not sleep:
sleep = True
time.sleep(10)
ipv4 = firewall().get()
ipv6 = firewall(True).get()
reload_firewall_task.delay(ipv4, ipv6)
if type == "Blacklist": if type == "Blacklist":
lock = lambda: cache.add("blacklist_lock", "true", 9) cache.add("blacklist_lock", "true", 30)
if lock():
if not sleep:
sleep = True
time.sleep(10)
reload_blacklist_task.delay(list(ipset()))
print type print type
...@@ -16,21 +16,19 @@ class MockGroups: ...@@ -16,21 +16,19 @@ class MockGroups:
def all(self): def all(self):
return self.groups return self.groups
class HostAdminNoGroupTestCase(TestCase): class HostAdminTestCase(TestCase):
def runTest(self): def test_no_groups(self):
instance = MockInstance([]) instance = MockInstance([])
l = HostAdmin.groups_l(instance) l = HostAdmin.list_groups(instance)
self.assertEqual(l, "") self.assertEqual(l, "")
class HostAdminSingleGroupTestCase(TestCase): def test_sigle_group(self):
def runTest(self):
instance = MockInstance([MockGroup("alma")]) instance = MockInstance([MockGroup("alma")])
l = HostAdmin.groups_l(instance) l = HostAdmin.list_groups(instance)
self.assertEqual(l, "alma") self.assertEqual(l, "alma")
class HostAdminMultipleGroupsTestCase(TestCase): def test_multiple_groups(self):
def runTest(self):
instance = MockInstance([MockGroup("alma"), instance = MockInstance([MockGroup("alma"),
MockGroup("korte"), MockGroup("szilva")]) MockGroup("korte"), MockGroup("szilva")])
l = HostAdmin.groups_l(instance) l = HostAdmin.list_groups(instance)
self.assertEqual(l, "alma, korte, szilva") self.assertEqual(l, "alma, korte, szilva")
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
from django.http import HttpResponse from django.http import HttpResponse
from django.shortcuts import render_to_response
from firewall.models import * from firewall.models import *
from firewall.fw import * from firewall.fw import *
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
...@@ -9,23 +8,27 @@ from django.db import IntegrityError ...@@ -9,23 +8,27 @@ from django.db import IntegrityError
from tasks import * from tasks import *
from celery.task.control import inspect from celery.task.control import inspect
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.template.loader import render_to_string
from cloud.settings import CLOUD_URL as url
from django.utils import translation
import re import re
import base64 import base64
import json import json
import sys import sys
import datetime
from django.utils.timezone import utc
from one.tasks import SendMailTask
def reload_firewall(request): 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!<br />"
request.user.username) + "<br />" + "Reloading in 10 seconds...") % request.user.username)
_("Reloading in 10 seconds..."))
ReloadTask.delay() ReloadTask.delay()
else: else:
html = (_("Dear %s, you've signed in!") html = (_("Dear %s, you've signed in!") % request.user.username)
% request.user.username)
else: else:
html = _("Dear anonymous, you've not signed in yet!") html = _("Dear anonymous, you've not signed in yet!")
return HttpResponse(html) return HttpResponse(html)
...@@ -41,16 +44,29 @@ def firewall_api(request): ...@@ -41,16 +44,29 @@ def firewall_api(request):
if command == "blacklist": if command == "blacklist":
obj, created = Blacklist.objects.get_or_create(ipv4=data["ip"]) obj, created = Blacklist.objects.get_or_create(ipv4=data["ip"])
if created:
obj.reason=data["reason"] obj.reason=data["reason"]
obj.snort_message=data["snort_message"] obj.snort_message=data["snort_message"]
if created:
try:
obj.host = models.Host.objects.get(ipv4=data["ip"])
user = obj.host.owner
lang = user.person_set.all()[0].language
translation.activate(lang)
msg = render_to_string('mails/notification-ban-now.txt', { 'user': user, 'bl': obj, 'instance:': obj.host.instance_set.get(), 'url': url} )
SendMailTask.delay(to=obj.host.owner.email, subject='[IK Cloud] %s' % obj.host.instance_set.get().name, msg=msg, sender=u'cloud@ik.bme.hu')
except (Host.DoesNotExist, ValidationError, IntegrityError, AttributeError):
pass
print obj.modified_at + datetime.timedelta(minutes=5)
print datetime.datetime.utcnow().replace(tzinfo=utc)
if obj.type == 'tempwhite' and obj.modified_at + datetime.timedelta(minutes=1) < datetime.datetime.utcnow().replace(tzinfo=utc):
obj.type = 'tempban'
obj.save() obj.save()
return HttpResponse(unicode(_("OK"))); return HttpResponse(unicode(_("OK")))
if not (data["vlan"] == "vm-net" or data["vlan"] == "war"): if not (data["vlan"] == "vm-net" or data["vlan"] == "war"):
raise Exception(_("Only vm-net and war can be used.")) raise Exception(_("Only vm-net and war can be used."))
data["hostname"] = re.sub(r' ','_', data["hostname"]) data["hostname"] = re.sub(r' ', '_', data["hostname"])
if command == "create": if command == "create":
data["owner"] = "opennebula" data["owner"] = "opennebula"
...@@ -78,14 +94,13 @@ def firewall_api(request): ...@@ -78,14 +94,13 @@ def firewall_api(request):
host = models.Host.objects.get(hostname=data["hostname"], host = models.Host.objects.get(hostname=data["hostname"],
owner=owner) owner=owner)
host.del_rules()
host.delete() host.delete()
else: else:
raise Exception(_("Unknown command.")) raise Exception(_("Unknown command."))
except (ValidationError, IntegrityError, AttributeError, Exception) as e: except (ValidationError, IntegrityError, AttributeError, Exception) as e:
return HttpResponse(_("Something went wrong!\n%s\n") % e); return HttpResponse(_("Something went wrong!\n%s\n") % e)
except: except:
return HttpResponse(_("Something went wrong!\n")); return HttpResponse(_("Something went wrong!\n"))
return HttpResponse(unicode(_("OK"))); return HttpResponse(unicode(_("OK")))
...@@ -10,4 +10,4 @@ sed -i 's/^<volume user=.*//' /etc/security/pam_mount.conf.xml ...@@ -10,4 +10,4 @@ sed -i 's/^<volume user=.*//' /etc/security/pam_mount.conf.xml
rm -rf ~cloud/{.bash_history,.ssh/id_rsa} rm -rf ~cloud/{.bash_history,.ssh/id_rsa}
rm -rf ~root/{.bash_history} rm -rf ~root/{.bash_history}
rm -rf /etc/ssh/ssh_host_* rm -rf /etc/ssh/ssh_host_*
rm -rf /usr/NX/home/nx/.ssh/known_hosts
...@@ -3,6 +3,12 @@ ...@@ -3,6 +3,12 @@
echo "En vagyok a $0 !" echo "En vagyok a $0 !"
hostname "$HOSTNAME" hostname "$HOSTNAME"
echo "$HOSTNAME" > /etc/hostname
if [ "$DISTRO" == "ubuntu" ]; then
echo "$HOSTNAME" > /etc/hostname
fi
if [ "$DISTRO" == "redhat" ]; then
echo -e -n "NETWORKING=yes\nHOSTNAME=$HOSTNAME\n" > /etc/sysconfig/network
fi
sed "s/\(127\.0\.1\.1\).*/\1\t$HOSTNAME/" -i /etc/hosts sed "s/\(127\.0\.1\.1\).*/\1\t$HOSTNAME/" -i /etc/hosts
...@@ -13,6 +13,7 @@ echo ok "$ipv4 $ipv6 $gw4 $gw6" ...@@ -13,6 +13,7 @@ echo ok "$ipv4 $ipv6 $gw4 $gw6"
/etc/init.d/network-manager stop /etc/init.d/network-manager stop
ifdown eth0 || ifconfig eth0 0 down ifdown eth0 || ifconfig eth0 0 down
if [ "$DISTRO" == "ubuntu" ]; then
cat > /etc/network/interfaces << EOF cat > /etc/network/interfaces << EOF
auto lo auto lo
iface lo inet loopback iface lo inet loopback
...@@ -30,4 +31,28 @@ EOF ...@@ -30,4 +31,28 @@ EOF
ifup eth0 ifup eth0
fi
if [ "$DISTRO" == "redhat" ]; then
cat > /etc/sysconfig/network-scripts/ifcfg-eth0 << EOF
DEVICE="eth0"
BOOTPROTO="none"
IPV6INIT="yes"
NM_CONTROLLED="no"
ONBOOT="yes"
TYPE="Ethernet"
DNS1="152.66.243.60"
PEERDNS="yes"
IPADDR="$ipv4"
NETMASK="255.255.0.0"
GATEWAY=$gw4
IPV6ADDR="$ipv6/80"
IPV6_DEFAULTGW="$gw6"
EOF
ifup eth0
fi
...@@ -5,8 +5,14 @@ echo "En vagyok a $0 !" ...@@ -5,8 +5,14 @@ echo "En vagyok a $0 !"
mkdir -p "$HOME/.ssh" mkdir -p "$HOME/.ssh"
echo "$SSHPRIV" > $HOME/.ssh/id_rsa echo "$SSHPRIV" > $HOME/.ssh/id_rsa
chmod 600 "$HOME/.ssh/id_rsa" chmod 600 "$HOME/.ssh/id_rsa"
echo "$SSHPUB" >> "$HOME/.ssh/authorized_keys"
mkdir "$HOME/sshfs" mkdir "$HOME/sshfs"
chown "$USER:$USER" -R "$HOME" chown "$USER:$USER" -R "$HOME"
sed -i 's/^<volume user=.*//' /etc/security/pam_mount.conf.xml sed -i 's/^sshfs.*//' /etc/fstab
sed -i "s/^\(<\/pam_mount>.*\)/<volume user=\"$USER\" fstype=\"fuse\" path=\"sshfs#${NEPTUN}@${SERVER}:home\" mountpoint=\"~\/sshfs\" options=\"nonempty,reconnect,StrictHostKeyChecking=no\" \/>\n\1/" /etc/security/pam_mount.conf.xml cat >> /etc/fstab <<END
sshfs#${NEPTUN}@${SERVER}:home $HOME/sshfs fuse defaults,idmap=user,reconnect,_netdev,uid=1000,gid=1000,allow_other,StrictHostKeyChecking=no,IdentityFile=$HOME/.ssh/id_rsa 0 0
END
mount "$HOME/sshfs"
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
echo "En vagyok a $0 !" echo "En vagyok a $0 !"
wget -q -O /dev/null "$BOOTURL" ( while ! wget -T 2 -t 1 -q --no-check-certificate -O /dev/null "$BOOTURL" ; do sleep 5; done ) &
disown $!
...@@ -4,6 +4,15 @@ export BASEDIR=$(dirname $0) ...@@ -4,6 +4,15 @@ export BASEDIR=$(dirname $0)
export USER="cloud" export USER="cloud"
export HOME=$(awk -F: -v u=$USER '$1==u{print $6}' /etc/passwd) export HOME=$(awk -F: -v u=$USER '$1==u{print $6}' /etc/passwd)
if [ -f /etc/lsb-release ]; then
export DISTRO=ubuntu
fi
if [ -f /etc/redhat-release ]; then
export DISTRO=redhat
fi
echo $DISTRO
mkdir -p "$BASEDIR/mnt" mkdir -p "$BASEDIR/mnt"
cd "$BASEDIR" cd "$BASEDIR"
......
...@@ -16,40 +16,5 @@ ...@@ -16,40 +16,5 @@
"email": "", "email": "",
"date_joined": "2013-01-16T12:36:01Z" "date_joined": "2013-01-16T12:36:01Z"
} }
},
{
"pk": 9,
"model": "one.template",
"fields": {
"name": "Ubuntu 12.04 desktop",
"created_at": "2013-01-31T10:11:08Z",
"access_type": "nx",
"instance_type": 3,
"owner": 1,
"disk": 1,
"network": 2
}
},
{
"pk": 10,
"model": "one.template",
"fields": {
"name": "Windows 7",
"created_at": "2013-01-31T10:11:21Z",
"access_type": "rdp",
"instance_type": 2,
"owner": 1,
"disk": 1,
"network": 2
}
},
{
"pk": 2,
"model": "one.network",
"fields": {
"name": "VM-NET",
"nat": true,
"public": false
}
} }
] ]
...@@ -5,15 +5,15 @@ for i in cloudstore toplist django ...@@ -5,15 +5,15 @@ for i in cloudstore toplist django
do do
sudo stop $i || true sudo stop $i || true
done done
set -x
cd /opt/webadmin/cloud sudo apt-get install rabbitmq-server gettext
./manage.py syncdb --noinput sudo rabbitmqctl delete_user guest || true
./manage.py migrate sudo rabbitmqctl add_user nyuszi teszt || true
./manage.py loaddata miscellaneous/dump.json sudo rabbitmqctl add_vhost django || true
./manage.py loaddata miscellaneous/devenv/dev.json sudo rabbitmqctl set_permissions -p django nyuszi '.*' '.*' '.*' || true
./manage.py update
./manage.py loaddata miscellaneous/devenv/dev.json
set +x sudo cp /opt/webadmin/cloud/miscellaneous/devenv/boot_url.py /opt/
#Set up store server #Set up store server
rm -rf /var/www/* rm -rf /var/www/*
...@@ -44,6 +44,18 @@ do ...@@ -44,6 +44,18 @@ do
sudo start $i sudo start $i
done done
set -x
cd /opt/webadmin/cloud
./manage.py syncdb --noinput
./manage.py migrate
./manage.py loaddata miscellaneous/dump.json
./manage.py loaddata miscellaneous/devenv/dev.json
./manage.py update
./manage.py loaddata miscellaneous/devenv/dev.json
set +x
cd /opt/webadmin/cloud/miscellaneous/devenv cd /opt/webadmin/cloud/miscellaneous/devenv
sudo cp vimrc.local /etc/vim/vimrc.local sudo cp vimrc.local /etc/vim/vimrc.local
...@@ -52,16 +64,11 @@ sudo cp vimrc.local /etc/vim/vimrc.local ...@@ -52,16 +64,11 @@ sudo cp vimrc.local /etc/vim/vimrc.local
cd /opt/webadmin/cloud cd /opt/webadmin/cloud
./manage.py changepassword test ./manage.py changepassword test
git config --global alias.prettylog 'log --graph --all --decorate --date-order --pretty="%C(yellow)%h%Cred%d%Creset - %C(cyan)%an %Creset: %s %Cgreen(%cr)"' git config --global alias.prettylog 'log --graph --all --decorate --date-order --pretty="%C(yellow)%h%Cred%d%Creset - %C(cyan)%an %Creset: %s %Cgreen(%ar)"'
git config --global alias.civ 'commit --interactive --verbose'
git config --global color.ui true git config --global color.ui true
git config --global core.editor vim git config --global core.editor vim
true true
sudo apt-get install rabbitmq-server
sudo rabbitmqctl delete_user guest
sudo rabbitmqctl add_user nyuszi teszt
sudo rabbitmqctl add_vhost django
sudo rabbitmqctl set_permissions -p django nyuszi '.*' '.*' '.*'
...@@ -7,4 +7,6 @@ set et ...@@ -7,4 +7,6 @@ set et
set sw=4 set sw=4
set ai set ai
set smarttab set smarttab
set textwidth=76
set colorcolumn=76
#!/bin/bash #!/bin/bash
/opt/webadmin/cloud/manage.py dumpdata -e admin -e one.userclouddetails -e school -e auth.permission -e contenttypes -e sessions -e djcelery --format=json --indent=2|grep -v '"password":'|sed -e 's/^.*"smb_password":.*$/"smb_password": "kamu",/' -e 's/BEGIN RSA PRIVATE.*END RSA/xxx/' >/opt/webadmin/cloud/miscellaneous/dump.json /opt/webadmin/cloud/manage.py dumpdata -e admin -e auth.permission -e contenttypes -e sessions -e djcelery --format=json --indent=2|grep -v '"password":'|sed -e 's/^.*"smb_password":.*$/"smb_password": "kamu",/' -e 's/BEGIN RSA PRIVATE.*END RSA/xxx/' >/opt/webadmin/cloud/miscellaneous/dump.json
...@@ -6,11 +6,19 @@ import os ...@@ -6,11 +6,19 @@ import os
import sys import sys
import gtk import gtk
import gobject import gobject
from multiprocessing import Manager, Process
import threading
import signal
import time
class RDP: class RDP:
def __init__(self, uri): def __init__(self, uri):
gobject.threads_init() gobject.threads_init()
self.scheme, self.username, self.password, self.host, self.port = uri.split(':',4) self.scheme, self.username, self.password, self.host, self.port = uri.split(':',4)
self.manager = Manager()
self.global_vars = self.manager.Namespace()
self.global_vars.pid = 0
self.box = gtk.MessageDialog(parent=None, flags=gtk.DIALOG_MODAL, type=gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_CANCEL, message_format="Connecting to RDP...")
def dialog_box(self,text): def dialog_box(self,text):
# Window = gtk.Window() # Window = gtk.Window()
# Window.set_size_request(250, 100) # Window.set_size_request(250, 100)
...@@ -19,12 +27,27 @@ class RDP: ...@@ -19,12 +27,27 @@ class RDP:
# window.set_title("Message dialogs") # window.set_title("Message dialogs")
md = gtk.MessageDialog(parent=None, type=gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_CLOSE, message_format=text) md = gtk.MessageDialog(parent=None, type=gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_CLOSE, message_format=text)
md.run() md.run()
print "After run"
md.destroy() md.destroy()
def connect(self): def connect(self):
#rdp:cloud:qYSv3eQJYY:152.66.243.62:23037 #rdp:cloud:qYSv3eQJYY:152.66.243.62:23037
if self.scheme == "rdp": if self.scheme == "rdp":
self.connect_rdp() #print self.global_vars.pid
p = threading.Thread(target=self.connect_rdp, args=[self.global_vars])
p.start()
while self.global_vars.pid == 0:
time.sleep(1)
#print "Rdesktop pid: "+str(self.global_vars.pid)
#print self.box
return_value = self.box.run()
#print "Box return value: "+str(return_value)
if return_value != -5:
#p.terminate()
if self.global_vars.pid > 0:
os.kill(self.global_vars.pid, signal.SIGKILL)
#print "Join"
p.join()
elif self.scheme == "nx": elif self.scheme == "nx":
self.connect_nx() self.connect_nx()
elif self.scheme == "sshterm": elif self.scheme == "sshterm":
...@@ -49,15 +72,13 @@ class RDP: ...@@ -49,15 +72,13 @@ class RDP:
except: except:
self.dialog_box("Unable to connect to host: "+self.host+" at port "+self.port) self.dialog_box("Unable to connect to host: "+self.host+" at port "+self.port)
def connect_rdp(self): def connect_rdp(self,global_vars):
rdp_command = ["rdesktop", "-khu", "-E", "-P", "-0", "-f", "-u", self.username, "-p", self.password, self.host+":"+self.port] rdp_command = ["rdesktop", "-khu", "-E", "-P", "-0", "-f", "-u", self.username, "-p", self.password, self.host+":"+self.port]
try: proc = subprocess.Popen(rdp_command, stdout = subprocess.PIPE)
proc = subprocess.check_call(rdp_command, stdout = subprocess.PIPE) global_vars.pid = proc.pid
except subprocess.CalledProcessError as e: proc.wait()
if e.returncode != 1: self.box.response(-5)
print e global_vars.pid = 0
print e.returncode
self.dialog_box("Unable to connect to host: "+self.host+" at port "+self.port)
def connect_nx(self): def connect_nx(self):
#Generate temproary config #Generate temproary config
......
from setuptools import setup, find_packages from setuptools import setup, find_packages
setup( setup(
name = "CloudGUI", name = "CloudGUI",
version = "0.1", version = "0.2",
packages = ['cloudgui',], packages = ['cloudgui',],
scripts = ['cloud','rdp',], scripts = ['cloud','rdp',],
) )
#!/usr/bin/python
import xmltodict
import xml.dom.minidom as minidom
import sys
import json
import math
xml = sys.stdin.read()
data = minidom.parseString(xml)
node = data.documentElement
hosts = data.getElementsByTagName("HOST")
#CPU stat
cpu_usage = 0
used_cpu = 0
cpu_max = 0
#Memory stat
mem_usage = 0
used_mem = 0
mem_max = 0
#Running VMs
running_vms = 0
for host in hosts:
share = host.getElementsByTagName("HOST_SHARE")[0]
cpu_max += int(share.getElementsByTagName("MAX_CPU")[0].childNodes[0].data)
used_cpu += int(share.getElementsByTagName("USED_CPU")[0].childNodes[0].data)
cpu_usage += int(share.getElementsByTagName("CPU_USAGE")[0].childNodes[0].data)
mem_usage += int(share.getElementsByTagName("MEM_USAGE")[0].childNodes[0].data)
used_mem += int(share.getElementsByTagName("USED_MEM")[0].childNodes[0].data)
mem_max += int(share.getElementsByTagName("MAX_MEM")[0].childNodes[0].data)
running_vms += int(share.getElementsByTagName("RUNNING_VMS")[0].childNodes[0].data)
if cpu_usage < used_cpu:
alloc_cpu = 0
free_cpu = (cpu_max - used_cpu)
else:
alloc_cpu = (cpu_usage - used_cpu)
free_cpu = (cpu_max - alloc_cpu - used_cpu)
#Round memory values
mem_usage = mem_usage / 1024
used_mem = used_mem / 1024
mem_max = mem_max / 1024
if mem_max < (1024*5):
dimension = "MB"
else:
mem_usage = mem_usage / 1024
used_mem = used_mem / 1024
mem_max = mem_max / 1024
dimension = "GB"
mem_usage = round(mem_usage, 2)
used_mem = round(used_mem, 2)
mem_max = round(mem_max, 2)
if mem_usage < used_mem:
alloc_mem = 0
free_mem = (mem_max - used_mem)
else:
alloc_mem = (mem_usage - used_mem)
free_mem = (mem_max - alloc_mem - used_mem)
used_mem = used_mem
cpu_dict = {'FREE_CPU' : free_cpu, 'ALLOC_CPU' : alloc_cpu , 'USED_CPU' :
used_cpu}
mem_dict = {'FREE_MEM' : free_mem, 'ALLOC_MEM' : alloc_mem , 'USED_MEM' :
used_mem}
print json.dumps({ 'CPU' : cpu_dict, 'MEM' : mem_dict, 'VMS' : running_vms,
'DIMENSION' : dimension})
#!/bin/bash
export HOME='/var/www'
export LANG='en_US.UTF-8'
export LANGUAGE='en_US:en'
export LOGNAME='www-data'
export MAIL='/var/mail/www-data'
export PATH='/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games'
export PWD='/var/www'
export SHELL='/bin/sh'
export TERM='screen'
export USER='www-data'
#export ONE_LOCATION='/var/lib/opennebula'
export PATH="$PATH:$ONE_LOCATION/bin"
sudo -u oneadmin -i onehost list -x | /opt/webadmin/cloud/miscellaneous/stat/stat_dom.py
...@@ -8,6 +8,7 @@ import uuid ...@@ -8,6 +8,7 @@ import uuid
import subprocess import subprocess
import ConfigParser import ConfigParser
from pwd import getpwnam from pwd import getpwnam
import multiprocessing
# Get configuration file # Get configuration file
config = ConfigParser.ConfigParser() config = ConfigParser.ConfigParser()
...@@ -100,23 +101,13 @@ def cmd_download(request, neptun, home_path): ...@@ -100,23 +101,13 @@ def cmd_download(request, neptun, home_path):
if not dl_path.startswith(home_path): if not dl_path.startswith(home_path):
abort(400, 'Invalid download path.') abort(400, 'Invalid download path.')
dl_hash = str(uuid.uuid4()) dl_hash = str(uuid.uuid4())
if( os.path.isfile(dl_path) ): dl_pub = os.path.join(ROOT_WWW_FOLDER, dl_hash)
os.symlink(dl_path, ROOT_WWW_FOLDER+'/'+dl_hash) if os.path.isfile(dl_path):
# Debug os.symlink(dl_path, dl_pub)
# redirect('http://store.cloud.ik.bme.hu:8080/dl/'+dl_hash)
return json.dumps({'LINK' : SITE_URL+'/dl/'+dl_hash}) return json.dumps({'LINK' : SITE_URL+'/dl/'+dl_hash})
else: else:
try: shutil.make_archive(dl_pub, 'zip', dl_path)
os.makedirs(TEMP_DIR+'/'+neptun, 0700) return json.dumps({'LINK' : SITE_URL+'/dl/'+dl_hash+'.zip'})
except:
pass
folder_name = os.path.basename(dl_path)
temp_path = TEMP_DIR+'/'+neptun+'/'+folder_name+'.zip'
with open(os.devnull, "w") as fnull:
# zip -rqDj vmi.zip /home/tarokkk/vpn-ik
result = subprocess.call(['/usr/bin/zip', '-rqDj', temp_path, dl_path], stdout = fnull, stderr = fnull)
os.symlink(temp_path, ROOT_WWW_FOLDER+'/'+dl_hash)
return json.dumps({'LINK' : SITE_URL+'/dl/'+dl_hash})
COMMANDS['DOWNLOAD'] = cmd_download COMMANDS['DOWNLOAD'] = cmd_download
# UPLOAD # UPLOAD
...@@ -127,7 +118,10 @@ def cmd_upload(request, neptun, home_path): ...@@ -127,7 +118,10 @@ def cmd_upload(request, neptun, home_path):
abort(400, 'Invalid upload path.') abort(400, 'Invalid upload path.')
if os.path.exists(up_path) == True and os.path.isdir(up_path): if os.path.exists(up_path) == True and os.path.isdir(up_path):
up_hash = str(uuid.uuid4()) up_hash = str(uuid.uuid4())
os.symlink(up_path, ROOT_WWW_FOLDER+'/'+up_hash) link = ROOT_WWW_FOLDER + '/' + up_hash
os.symlink(up_path, link)
passwd = getpwnam(neptun)
os.lchown(link, passwd.pw_uid, passwd.pw_gid)
return json.dumps({ 'LINK' : SITE_URL+'/ul/'+up_hash}) return json.dumps({ 'LINK' : SITE_URL+'/ul/'+up_hash})
else: else:
abort(400, 'Upload directory not exists!') abort(400, 'Upload directory not exists!')
...@@ -285,40 +279,48 @@ def upload_allow(hash_num): ...@@ -285,40 +279,48 @@ def upload_allow(hash_num):
response.set_header('Access-Control-Allow-Headers', 'Content-Type, Content-Range, Content-Disposition, Content-Description') response.set_header('Access-Control-Allow-Headers', 'Content-Type, Content-Range, Content-Disposition, Content-Description')
return 'ok' return 'ok'
def _upload_save(uid, gid, input, path):
os.setegid(gid)
os.seteuid(uid)
try:
with open(path, 'wb', 0600) as output:
while True:
chunk = input.read(256*1024)
if not chunk:
break
output.write(chunk)
finally:
input.close()
@route('/ul/<hash_num>', method='POST') @route('/ul/<hash_num>', method='POST')
def upload(hash_num): def upload(hash_num):
if not os.path.exists(ROOT_WWW_FOLDER+'/'+hash_num): link = ROOT_WWW_FOLDER+'/'+hash_num
if not os.path.exists(link):
abort (404, 'Token not found!') abort (404, 'Token not found!')
try: try:
file_data = request.files.data file_data = request.files.data
file_name = file_data.filename file_name = file_data.filename
except: except:
if os.path.exists(ROOT_WWW_FOLDER+'/'+hash_num): if os.path.exists(link):
os.remove(ROOT_WWW_FOLDER+'/'+hash_num) os.remove(link)
abort(400, 'No file was specified!') abort(400, 'No file was specified!')
up_path = os.path.realpath(ROOT_WWW_FOLDER+'/'+hash_num+'/'+file_name) up_path = os.path.realpath(link + '/' + file_name)
if os.path.exists(up_path): if os.path.exists(up_path):
abort(400, 'File already exists') abort(400, 'File already exists')
# Check if upload path valid
if not up_path.startswith('/home'): if not up_path.startswith('/home'):
abort(400, 'Invalid path.') abort(400, 'Invalid path.')
linkstat = os.stat(link)
os.remove(ROOT_WWW_FOLDER+'/'+hash_num) os.remove(link)
# Get the real upload path p = multiprocessing.Process(target=_upload_save,
# Delete the hash link args=(linkstat.st_uid, linkstat.st_gid, file_data.file, up_path, ))
# Get the username from path for proper ownership try:
username=up_path.split('/', 3)[2] p.start()
# os.setegid(getpwnam(username).pw_gid) p.join()
# os.seteuid(getpwnam(username).pw_uid) finally:
# TODO setuid subcommand p.terminate()
# Check if file exist (root can overwrite anything not safe) if p.exitcode:
with open(up_path , 'wb') as f: abort(400, 'Write failed.')
datalength = 0
for chunk in fbuffer(file_data.file, chunk_size=1048576):
f.write(chunk)
datalength += len(chunk)
os.chown(up_path, getpwnam(username).pw_uid, getpwnam(username).pw_gid)
os.chmod(up_path, 0644)
try: try:
redirect_address = request.headers.get('Referer') redirect_address = request.headers.get('Referer')
except: except:
...@@ -327,19 +329,11 @@ def upload(hash_num): ...@@ -327,19 +329,11 @@ def upload(hash_num):
response.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS') response.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
response.set_header('Access-Control-Allow-Headers', 'Content-Type, Content-Range, Content-Disposition, Content-Description') response.set_header('Access-Control-Allow-Headers', 'Content-Type, Content-Range, Content-Disposition, Content-Description')
redirect(redirect_address) redirect(redirect_address)
#return 'Upload finished: '+file_name+' - '+str(datalength)+' Byte'
# Return hard quota from quota # Return hard quota from quota
def hard_quota(quota): def hard_quota(quota):
return str(int(int(quota)*1.25)) return str(int(int(quota)*1.25))
# Define filebuffer for big uploads
def fbuffer(f, chunk_size=4096):
while True:
chunk = f.read(chunk_size)
if not chunk: break
yield chunk
# Update users .ssh/authorized_keys # Update users .ssh/authorized_keys
def updateSSHAuthorizedKeys(username, key_list): def updateSSHAuthorizedKeys(username, key_list):
user_uid=getpwnam(username).pw_uid user_uid=getpwnam(username).pw_uid
......
...@@ -23,17 +23,30 @@ class DetailsInline(contrib.admin.StackedInline): ...@@ -23,17 +23,30 @@ 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', 'full_name', 'email', 'date_joined', 'instance_count') list_display = ('username', 'full_name', 'email', 'date_joined', 'instance_count', 'course_groups')
list_filter = ('is_superuser', 'is_active', 'groups', 'person__course_groups', )
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): def instance_count(self, obj):
return obj.instance_set.count() return _("%(sum)d (%(active)d active)") % { 'sum': obj.instance_set.count(),
'active' :obj.instance_set.filter(state='ACTIVE').count(), }
def course_groups(self, obj):
try:
return ", ".join(obj.person_set.all()[0].course_groups.all())
except:
return None
def full_name(self, obj): def full_name(self, obj):
return u"%s %s" % (obj.last_name, obj.first_name) return u"%s %s" % (obj.last_name, obj.first_name)
full_name.admin_order_field = 'last_name' full_name.admin_order_field = 'last_name'
ordering = ["-date_joined"]
contrib.admin.site.unregister(contrib.auth.models.User) contrib.admin.site.unregister(contrib.auth.models.User)
......
# -*- coding: utf-8 -*-
from django_extensions.management.jobs import HourlyJob from django_extensions.management.jobs import HourlyJob
import datetime
from django.utils.timezone import utc
from one.models import Instance
from django.template.loader import render_to_string
from one.tasks import SendMailTask
from django.utils.translation import ugettext_lazy as _
from cloud.settings import CLOUD_URL as url
from django.utils import translation
class Job(HourlyJob): class Job(HourlyJob):
help = "Suspend/delete expired Instances." help = "Suspend/delete expired Instances."
def calc(self, orig, days=0, hours=0):
return (orig + datetime.timedelta(days=days, hours=hours)).replace(minute=0, second=0, microsecond=0)
def execute(self): def execute(self):
# executing empty sample job TODO now = datetime.datetime.utcnow().replace(tzinfo=utc)
d = {
'1m': self.calc(orig=now, days=30),
'2w': self.calc(orig=now, days=14),
'1w': self.calc(orig=now, days=7),
'1d': self.calc(orig=now, days=1),
'1h': self.calc(orig=now, hours=1),
}
# for i in d:
# print i+':'+unicode(d[i])
# delete
for i in Instance.objects.filter(state__in=['ACTIVE', 'STOPPED'], time_of_delete__isnull=False):
try:
translation.activate(i.owner.person_set.get().language)
except:
pass
# print u'%s delete: %s' % (i.name, i.time_of_delete)
delete = i.time_of_delete.replace(minute=0, second=0, microsecond=0)
continue
if i.time_of_delete < now:
# msg = render_to_string('mails/notification-delete-now.txt', { 'user': i.owner, 'instance': i, 'url': url } )
# SendMailTask.delay(to=i.owner.email, subject='[IK Cloud] %s' % i.name, msg=msg)
pass pass
else:
for t in d:
if delete == d[t]:
msg = render_to_string('mails/notification-delete.txt', { 'user': i.owner, 'instance': i, 'url': url } )
SendMailTask.delay(to=i.owner.email, subject='[IK Cloud] %s' % i.name, msg=msg)
# suspend
for i in Instance.objects.filter(state='ACTIVE', time_of_suspend__isnull=False):
try:
translation.activate(i.owner.person_set.get().language)
except:
pass
# print u'%s suspend: %s' % (i.name, i.time_of_suspend)
suspend = i.time_of_suspend.replace(minute=0, second=0, microsecond=0)
if i.time_of_suspend < now:
msg = render_to_string('mails/notification-suspend-now.txt', { 'user': i.owner, 'instance': i, 'url': url } )
SendMailTask.delay(to=i.owner.email, subject='[IK Cloud] %s' % i.name, msg=msg)
i.stop()
else:
for t in d:
if suspend == d[t]:
msg = render_to_string('mails/notification-suspend.txt', { 'user': i.owner, 'instance': i, 'url': url } )
SendMailTask.delay(to=i.owner.email, subject='[IK Cloud] %s' % i.name, msg=msg)
...@@ -2,9 +2,11 @@ from one.models import * ...@@ -2,9 +2,11 @@ from one.models import *
from django_extensions.management.jobs import HourlyJob from django_extensions.management.jobs import HourlyJob
class Job(HourlyJob): class Job(HourlyJob):
help = "Update Disks and Networks from OpenNebula." help = "Update Disks, Networks and Instances from OpenNebula."
def execute(self): def execute(self):
Disk.update() Disk.update()
Network.update() Network.update()
for i in Instance.objects.filter(state__in=['ACTIVE', 'STOPPED'], time_of_delete__isnull=False):
i.update_state()
pass pass
...@@ -6,8 +6,8 @@ msgid "" ...@@ -6,8 +6,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-02-21 18:06+0100\n" "POT-Creation-Date: 2013-03-07 18:16+0100\n"
"PO-Revision-Date: 2013-02-21 18:09+0100\n" "PO-Revision-Date: 2013-03-07 17:02+0100\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Hungarian <cloud@ik.bme.hu>\n" "Language-Team: Hungarian <cloud@ik.bme.hu>\n"
"Language: hu\n" "Language: hu\n"
...@@ -17,108 +17,117 @@ msgstr "" ...@@ -17,108 +17,117 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
"X-Generator: Lokalize 1.4\n" "X-Generator: Lokalize 1.4\n"
#: static/script/cloud.js:24 #: static/script/cloud.js:24 static/script/cloud.min.js:1
msgid "Are you sure deleting key?" msgid "Are you sure deleting key?"
msgstr "Biztosan törli a kulcsot?" msgstr "Biztosan törli a kulcsot?"
#: static/script/cloud.js:24 static/script/cloud.js.c:246 #: static/script/cloud.js:24 static/script/cloud.js.c:296
#: static/script/cloud.js:320 static/script/cloud.js.c:533 #: static/script/cloud.js:370 static/script/cloud.js.c:623
#: static/script/store.js:273 #: static/script/cloud.min.js:1 static/script/store.js:288
#: static/script/store.min.js:1
msgid "Delete" msgid "Delete"
msgstr "Törlés" msgstr "Törlés"
#: static/script/cloud.js:36 #: static/script/cloud.js:36 static/script/cloud.min.js:1
msgid "" msgid ""
"Are you sure about reseting store credentials?<br /> You will lose your " "Are you sure about reseting store credentials?<br /> You will lose your "
"access to your store account on your existing virtual machines!" "access to your store account on your existing virtual machines!"
msgstr "" msgstr ""
"Biztosan újragenerálja az adattár-kulcsait?<br /> " "Biztosan újragenerálja az adattár-kulcsait?<br /> El fogja veszteni az "
"El fogja veszteni az adattár-hozzáférést a már futó virtuális gépekből!" "adattár-hozzáférést a már futó virtuális gépekből!"
#: static/script/cloud.js:36 #: static/script/cloud.js:36 static/script/cloud.min.js:1
msgid "Reset" msgid "Reset"
msgstr "Újragenerálás" msgstr "Újragenerálás"
#: static/script/cloud.js:65 static/script/store.js:309 #: static/script/cloud.js:75 static/script/cloud.min.js:1
#: static/script/store.js:323 static/script/store.min.js:1
msgid "Rename" msgid "Rename"
msgstr "Átnevezés" msgstr "Átnevezés"
#: static/script/cloud.js:221 static/script/store.js:273 #: static/script/cloud.js:271 static/script/cloud.min.js:1
#: static/script/store.js:288 static/script/store.min.js:1
msgid "Cancel" msgid "Cancel"
msgstr "Mégsem" msgstr "Mégsem"
#: static/script/cloud.js:235 #: static/script/cloud.js:285 static/script/cloud.min.js:1
#, c-format #, c-format
msgid "Are you sure stopping %s?" msgid "Are you sure stopping %s?"
msgstr "Biztosan felfüggeszti a következőt: %s?" msgstr "Biztosan felfüggeszti a következőt: %s?"
#: static/script/cloud.js:236 #: static/script/cloud.js:286 static/script/cloud.min.js:1
msgid "Stop" msgid "Stop"
msgstr "Felfüggesztés" msgstr "Felfüggesztés"
#: static/script/cloud.js:245 #: static/script/cloud.js:295 static/script/cloud.min.js:1
#, c-format #, c-format
msgid "Are you sure deleting %s?" msgid "Are you sure deleting %s?"
msgstr "Biztosan törli a következőt: %s?" msgstr "Biztosan törli a következőt: %s?"
#: static/script/cloud.js:255 #: static/script/cloud.js:305 static/script/cloud.min.js:1
#, c-format #, c-format
msgid "Are you sure restarting %s?" msgid "Are you sure restarting %s?"
msgstr "Biztosan újraindítja a következőt: %s?" msgstr "Biztosan újraindítja a következőt: %s?"
#: static/script/cloud.js:256 #: static/script/cloud.js:306 static/script/cloud.min.js:1
msgid "Restart" msgid "Restart"
msgstr "Újraindítás" msgstr "Újraindítás"
#: static/script/cloud.js:319 #: static/script/cloud.js:369 static/script/cloud.min.js:1
#, c-format #, c-format
msgid "Are you sure deleting this %s template?" msgid "Are you sure deleting this %s template?"
msgstr "Biztosan törli a következő sablont: %s?" msgstr "Biztosan törli a következő sablont: %s?"
#: static/script/cloud.js:452 static/script/cloud.js.c:459 #: static/script/cloud.js:547 static/script/cloud.js.c:550
#: static/script/cloud.min.js:1
msgid "Add owner" msgid "Add owner"
msgstr "Tulajdonos hozzáadása" msgstr "Tulajdonos hozzáadása"
#: static/script/cloud.js:457 #: static/script/cloud.js:550 static/script/cloud.min.js:1
msgid "Unknown" msgid "Unknown"
msgstr "Ismeretlen" msgstr "Ismeretlen"
#: static/script/cloud.js:533 #: static/script/cloud.js:623 static/script/cloud.min.js:1
#, c-format #, c-format
msgid "Are you sure deleting <strong>%s</strong>" msgid "Are you sure deleting <strong>%s</strong>"
msgstr "Törli a következő fájlt: <strong>%s</strong>" msgstr "Törli a következő fájlt: <strong>%s</strong>"
#: static/script/store.js:57 static/script/store.js.c:66 #: static/script/store.js:52 static/script/store.js.c:61
#: static/script/store.js:75 static/script/store.js.c:205 #: static/script/store.js:70 static/script/store.js.c:220
#: static/script/store.js:267 #: static/script/store.js:282 static/script/store.min.js:1
msgid "file" msgid "file"
msgstr "fájl" msgstr "fájl"
#: static/script/store.js:268 #: static/script/store.js:125 static/script/store.min.js:1
msgid "Toplist"
msgstr "Legújabb fájlok"
#: static/script/store.js:127 static/script/store.min.js:1
msgid "Back to the root folder"
msgstr "Vissza a gyökérmappába"
#: static/script/store.js:283 static/script/store.min.js:1
#, c-format #, c-format
msgid "You are removing the file <strong>%s</strong>." msgid "You are removing the file <strong>%s</strong>."
msgstr "Törli a következő fájlt: <strong>%s</strong>." msgstr "Törli a következő fájlt: <strong>%s</strong>."
#: static/script/store.js:270 #: static/script/store.js:285 static/script/store.min.js:1
#, c-format #, c-format
msgid "You are removing the folder <strong>%s</strong> (and its content)." msgid "You are removing the folder <strong>%s</strong> (and its content)."
msgstr "Törli a következő könyvtárat és tartalmát: <strong>%s</strong>." msgstr "Törli a következő könyvtárat és tartalmát: <strong>%s</strong>."
#: static/script/store.js:273 #: static/script/store.js:288 static/script/store.min.js:1
msgid "Are you sure?" msgid "Are you sure?"
msgstr "Biztos benne?" msgstr "Biztos benne?"
#: static/script/store.js:427 static/script/store.js.c:429 #: static/script/store.js:446 static/script/store.js.c:448
#: static/script/store.min.js:1
msgid "Upload" msgid "Upload"
msgstr "Feltöltés" msgstr "Feltöltés"
#: static/script/store.js:429 #: static/script/store.js:448 static/script/store.min.js:1
msgid "done, processing..." msgid "done, processing..."
msgstr "kész, feldolgozás..." msgstr "kész, feldolgozás..."
#, fuzzy
#~ msgid "Are you sure about reseting store credentials"
#~ msgstr "Biztosan újraindítja a következőt: %s?"
#~ msgid "Please choose a different name." #~ msgid "Please choose a different name."
#~ msgstr "Kérem, válasszon eltérő nevet." #~ msgstr "Kérem, válasszon eltérő nevet."
...@@ -14,7 +14,7 @@ from django.db.models.signals import post_save ...@@ -14,7 +14,7 @@ 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 from firewall.models import Host, Rule, Vlan, Record
from school.models import Person, Group from school.models import Person, Group
from store.api import StoreApi from store.api import StoreApi
from .util import keygen from .util import keygen
...@@ -224,7 +224,7 @@ class Disk(models.Model): ...@@ -224,7 +224,7 @@ class Disk(models.Model):
return u"%s (#%d)" % (self.name, self.id) return u"%s (#%d)" % (self.name, self.id)
@staticmethod @staticmethod
def update(): def update(delete=True):
"""Get and register virtual disks from OpenNebula.""" """Get and register virtual disks from OpenNebula."""
import subprocess import subprocess
proc = subprocess.Popen(["/opt/occi.sh", "storage", "list"], proc = subprocess.Popen(["/opt/occi.sh", "storage", "list"],
...@@ -244,6 +244,7 @@ class Disk(models.Model): ...@@ -244,6 +244,7 @@ class Disk(models.Model):
except: except:
Disk(id=id, name=name).save() Disk(id=id, name=name).save()
l.append(id) l.append(id)
if delete:
Disk.objects.exclude(id__in=l).delete() Disk.objects.exclude(id__in=l).delete()
class Network(models.Model): class Network(models.Model):
...@@ -400,34 +401,46 @@ class Instance(models.Model): ...@@ -400,34 +401,46 @@ class Instance(models.Model):
@models.permalink @models.permalink
def get_absolute_url(self): def get_absolute_url(self):
return ('vm_show', None, {'iid':self.id}) return ('one.views.vm_show', None, {'iid':self.id})
def get_port(self): def get_port(self, use_ipv6=False):
"""Get public port number for default access method.""" """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 and not use_ipv6:
return {"rdp": 23000, "nx": 22000, "ssh": 22000}[proto] + int(self.ip.split('.')[2]) * 256 + int(self.ip.split('.')[3]) return {"rdp": 23000, "nx": 22000, "ssh": 22000}[proto] + int(self.ip.split('.')[2]) * 256 + int(self.ip.split('.')[3])
else: else:
return {"rdp": 3389, "nx": 22, "ssh": 22}[proto] return {"rdp": 3389, "nx": 22, "ssh": 22}[proto]
def get_connect_host(self): def get_connect_host(self, use_ipv6=False):
"""Get public hostname.""" """Get public hostname."""
if self.firewall_host is None:
return _('None')
try:
if use_ipv6:
return self.firewall_host.record_set.filter(type='AAAA')[0].get_data()['name']
else:
if self.template.network.nat: if self.template.network.nat:
return 'cloud' ip = self.firewall_host.pub_ipv4
return Record.objects.filter(type='A', address=ip)[0].get_data()['name']
else: else:
return self.ip return self.firewall_host.record_set.filter(type='A')[0].get_data()['name']
except:
if self.template.network.nat:
return self.firewall_host.pub_ipv4
else:
return self.firewall_host.ipv4
def get_connect_uri(self): def get_connect_uri(self, use_ipv6=False):
"""Get access parameters in URI format.""" """Get access parameters in URI format."""
try: try:
proto = self.template.access_type proto = self.template.access_type
if proto == 'ssh': if proto == 'ssh':
proto = 'sshterm' proto = 'sshterm'
port = self.get_port() port = self.get_port(use_ipv6=use_ipv6)
host = self.get_connect_host() host = self.get_connect_host(use_ipv6=use_ipv6)
pw = self.pw pw = self.pw
return ("%(proto)s:cloud:%(pw)s:%(host)s:%(port)d" % return ("%(proto)s:cloud:%(pw)s:%(host)s:%(port)d" %
{"port": port, "proto": proto, "pw": pw, {"port": port, "proto": proto, "pw": pw,
"host": self.firewall_host.pub_ipv4}) "host": host})
except: except:
return return
...@@ -540,11 +553,13 @@ class Instance(models.Model): ...@@ -540,11 +553,13 @@ class Instance(models.Model):
inst.save() inst.save()
inst.update_state() inst.update_state()
host = Host(vlan=Vlan.objects.get(name=template.network.name), host = Host(vlan=Vlan.objects.get(name=template.network.name),
owner=owner, shared_ip=True) owner=owner)
host.hostname = hostname host.hostname = hostname
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
if inst.template.network.nat:
host.pub_ipv4 = Vlan.objects.get(name=template.network.name).snat_ip host.pub_ipv4 = Vlan.objects.get(name=template.network.name).snat_ip
host.shared_ip = True
host.ipv6 = "auto" host.ipv6 = "auto"
try: try:
host.save() host.save()
...@@ -575,7 +590,10 @@ class Instance(models.Model): ...@@ -575,7 +590,10 @@ class Instance(models.Model):
if self.firewall_host: if self.firewall_host:
h = self.firewall_host h = self.firewall_host
self.firewall_host = None self.firewall_host = None
try:
self.save() self.save()
except:
pass
h.delete() h.delete()
def _update_vm(self, template): def _update_vm(self, template):
...@@ -611,12 +629,12 @@ class Instance(models.Model): ...@@ -611,12 +629,12 @@ class Instance(models.Model):
self._change_state("POWEROFF") self._change_state("POWEROFF")
def restart(self): def restart(self):
self._change_state("RESET") self._change_state("RESET")
def renew(self, which): def renew(self, which='both'):
if which == 'suspend': if which in ['suspend', 'both']:
self.time_of_suspend = self.share.get_type()['suspendx'] self.time_of_suspend = self.share.get_type()['suspendx']
elif which == 'delete': if which in ['delete', 'both']:
self.time_of_delete = self.share.get_type()['deletex'] self.time_of_delete = self.share.get_type()['deletex']
else: if not (which in ['suspend', 'delete', 'both']):
raise ValueError('No such expiration type.') raise ValueError('No such expiration type.')
self.save() self.save()
def save_as(self): def save_as(self):
...@@ -633,7 +651,7 @@ class Instance(models.Model): ...@@ -633,7 +651,7 @@ class Instance(models.Model):
def check_if_is_save_as_done(self): def check_if_is_save_as_done(self):
if self.state != 'DONE': if self.state != 'DONE':
return False return False
Disk.update() Disk.update(delete=False)
imgname = "template-%d-%d" % (self.template.id, self.id) imgname = "template-%d-%d" % (self.template.id, self.id)
disks = Disk.objects.filter(name=imgname) disks = Disk.objects.filter(name=imgname)
if len(disks) != 1: if len(disks) != 1:
......
html
{
min-height: 100%;
position: relative;
}
body body
{ {
min-height:100%; min-height:100%;
...@@ -15,6 +20,7 @@ body ...@@ -15,6 +20,7 @@ body
width:970px; width:970px;
text-align:left; text-align:left;
margin:0 auto; margin:0 auto;
padding-bottom: 100px;
} }
.contentblock .contentblock
...@@ -198,6 +204,13 @@ input[type=submit], input[type=button], input[type=reset]{ ...@@ -198,6 +204,13 @@ input[type=submit], input[type=button], input[type=reset]{
background: rgba(0,0,0,0.2); background: rgba(0,0,0,0.2);
}; };
} }
input:disabled {
background-color: rgba(255,0,0,0.2);
color: #222;
&:hover {
background-color: rgba(255,0,0,0.5);
}
}
textarea { textarea {
border-radius: 2px; border-radius: 2px;
...@@ -263,3 +276,29 @@ textarea::-moz-placeholder{ ...@@ -263,3 +276,29 @@ textarea::-moz-placeholder{
textarea:-ms-input-placeholder{ textarea:-ms-input-placeholder{
color: @placeholderColor; color: @placeholderColor;
} }
body > footer {
z-index: 999;
position: absolute;
bottom: 0;
width: 100%;
text-align: center;
border-top: 1px solid #888;
box-shadow:0 0 30px rgba(0,0,0,0.4);
margin:0;
background-color: white;
}
#http-error {
margin: 20px auto;
width: 500px;
border-radius: 4px;
border: 1px solid #888;
background: #FFFF66;
box-shadow: 0 0 20px rgba(0,0,0,0.2);
padding: 20px;
}
.irasmu p {
margin-top: 20px;
}
from celery.task import Task, PeriodicTask
import logging
import celery
import os
import sys
import time
from django.core.mail import send_mail
logger = logging.getLogger(__name__)
class SendMailTask(Task):
def run(self, to, subject, msg, sender=u'noreply@cloud.ik.bme.hu'):
send_mail(subject, msg, sender, [ to ], fail_silently=False)
logger.info("[django][one][tasks.py] %s->%s [%s]" % (sender, to, subject) )
{% extends "base.html" %}
{% load i18n %} {% load i18n %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
<!doctype html>
<html lang="{{LANGUAGE_CODE}}">
<head> {% block content %}
<meta charset="UTF-8"> <div id="http-error">
<title>404 - {% trans ":(" %}</title>
</head>
<body>
<h1>404 - {% trans ":(" %}</h1> <h1>404 - {% trans ":(" %}</h1>
</body> <p>
</html> {% trans "The requested page does not exists... Please go away..." %}
</p>
</div>
{% endblock %}
{% extends "base.html" %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
<div id="http-error">
<h1>500 - {% trans ":(" %}</h1>
<p>
{% trans "Internal Server Error... Please leave the server alone..." %}
</p>
</div>
{% endblock %}
<!DOCTYPE html> <!DOCTYPE html>
{% load i18n %} {% load i18n %}
{% load staticfiles %}
{% get_current_language as lang %} {% get_current_language as lang %}
<html lang="{{lang}}"> <html lang="{{lang}}">
<head> <head>
<title>{% block title %}IK Cloud{% endblock %}</title> <title>{% block title %}IK Cloud{% endblock %}</title>
<link href="https://fonts.googleapis.com/css?family=Titillium+Web&amp;subset=latin,latin-ext" rel="stylesheet" type="text/css"> <link href="https://fonts.googleapis.com/css?family=Titillium+Web&amp;subset=latin,latin-ext" rel="stylesheet" type="text/css" />
<link rel="icon" type="image/png" href="/static/favicon.png" /> <link rel="icon" type="image/png" href="{% static "favicon.png" %}" />
<link rel="stylesheet/less" href="/static/style/style.less" /> {% if DEBUG %}<link rel="stylesheet/less" href="{% static "style/style.less" %}" />{% else %}
<link href="{% static "style/style.css" %}" rel="stylesheet" type="text/css" />{% endif %}
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script src="/static/script/jquery.min.js"></script> <script src="{% static "script/jquery.min.js" %}"></script>
<script type="text/javascript" src="{% url django.views.i18n.javascript_catalog %}"></script> <script type="text/javascript" src="{% url django.views.i18n.javascript_catalog %}"></script>
<script type="text/javascript"> <script type="text/javascript">
window.localStorage.removeItem('https://cloud.ik.bme.hu/static/style/style.less:timestamp'); {% if DEBUG %}window.localStorage.removeItem('https://cloud.ik.bme.hu/static/style/style.less:timestamp');{% endif %}
var current_user={{user.id}}; var current_user={{user.id}};
</script> </script>
<script src="/static/script/less.min.js"></script> {% if DEBUG %}<script src="{% static "script/less.min.js" %}"></script>{% endif %}
<script src="/static/script/knockout.min.js"></script> <script src="{% static "script/knockout.min.js" %}"></script>
<script type="text/javascript" src="/static/script/util.js"></script> {% if DEBUG %}<script type="text/javascript" src="{% static "script/util.js" %}"></script>
<script type="text/javascript" src="/static/script/cloud.js"></script> {% else %}<script type="text/javascript" src="{% static "script/util.min.js" %}"></script>
{% endif %}
{% if DEBUG %}<script type="text/javascript" src="{% static "script/cloud.js" %}"></script>
{% else %}<script type="text/javascript" src="{% static "script/cloud.min.js" %}"></script>
{% endif %}
{{ form.media }} {{ form.media }}
{% block js %}{% endblock %} {% block js %}{% endblock %}
</head> </head>
...@@ -26,25 +32,27 @@ ...@@ -26,25 +32,27 @@
{% block login %} {% block login %}
<div id="loginblock"><p> <div id="loginblock"><p>
{% if user.is_authenticated %} {% if user.is_authenticated %}
Bejelentkezve: {{ user.username }}. {% trans "Logged in:" %} {{ user.username }}.
<a href="/logout/">Kijelentkezés</a>. <a href="{% url logout %}">{% trans "Logout" %}</a>.
{% if user.is_staff %} {% if user.is_staff %}
<a href="/admin/">Admin</a>. <a href="{% url admin:index %}">{% trans "Admin" %}</a>.
{% endif %} {% endif %}
{% else %} {% else %}
<a href="/login/">Bejelentkezés</a>. <a href="{% url login %}">{% trans "Login" %}</a>.
{% endif %} {% endif %}
{% if user.is_authenticated %}
{% if lang == 'hu' %} {% if lang == 'hu' %}
<a href="/language/en/">In English</a>. <a href="{% url school.views.language "en" %}">In English</a>.
{% else %} {% else %}
<a href="/language/hu/">Magyarul</a>. <a href="{% url school.views.language "hu" %}">Magyarul</a>.
{% endif %}
{% endif %} {% endif %}
</p> </p>
</div> </div>
{% endblock %} {% endblock %}
{% block header %} {% block header %}
{% block header_title %} {% block header_title %}
<h1><a href="/">IK Cloud</a></h1> <h1><a href="{% url one.views.index %}">IK Cloud</a></h1>
{% endblock %} {% endblock %}
{% endblock %} {% endblock %}
</div> </div>
...@@ -61,11 +69,27 @@ ...@@ -61,11 +69,27 @@
{% block content %}{% endblock %} {% block content %}{% endblock %}
<div class="clear"></div> <div class="clear"></div>
</div> </div>
<footer>
<a href="/sites/legal/">{% trans "Legal notice" %}</a> |
<a href="/sites/policy/">{% trans "Policy" %}</a> |
<a href="/sites/help/">{% trans "Help" %}</a> |
<a href="/sites/support/">{% trans "Support" %}</a>
</footer>
<div id="modal" style="display: none"> <div id="modal" style="display: none">
<div id="shadow"></div> <div id="shadow"></div>
<div id="modal-container"> <div id="modal-container">
</div> </div>
</div> </div>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-39125666-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body> </body>
</html> </html>
{% extends "box/base/box.html" %} {% extends "box/base/box.html" %}
{% load i18n %} {% load i18n %}
{% load l10n %} {% load l10n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% block title %} {% block title %}
...@@ -8,8 +9,9 @@ ...@@ -8,8 +9,9 @@
{% endblock title %} {% endblock title %}
{% block boxhelp %} {% block boxhelp %}
<div class="boxhelp"> <div class="boxhelp">
<div class="help">
<div class="icon"> <div class="icon">
<img src="/static/icons/information-frame.png" alt="{% trans "Help" %}" /> <img src="{% static "icons/information-frame.png" %}" alt="{% trans "Help" %}" />
</div> </div>
<div class="boxhelp-box"> <div class="boxhelp-box">
<p>{% blocktrans %}This is your global data store.{% endblocktrans %}</p> <p>{% blocktrans %}This is your global data store.{% endblocktrans %}</p>
...@@ -24,6 +26,10 @@ ...@@ -24,6 +26,10 @@
WinSCP) to access your files at {{serv}}. You will need to register a WinSCP) to access your files at {{serv}}. You will need to register a
public key bellow.{% endblocktrans %}</p> public key bellow.{% endblocktrans %}</p>
</div> </div>
</div>
<div class="icon">
<img src="" alt="toggle" title="{% trans "Show/hide box" %}" class="toggle-box" data-id="files" id="toggle-box-files"/>
</div>
</div> </div>
{% endblock %} {% endblock %}
...@@ -80,7 +86,7 @@ ...@@ -80,7 +86,7 @@
</li> </li>
<li class="entry small-row"> <li class="entry small-row">
<div class="summary" id="new-folder"> <div class="summary" id="new-folder">
<div class="name toplist" data-bind="click: loadTopList">{% trans "Toplist" %}</div> <div class="name toplist" data-bind="click: toggleToplist, text: getToplistText"></div>
<div class="clear"></div> <div class="clear"></div>
</div> </div>
</li> </li>
...@@ -100,7 +106,7 @@ ...@@ -100,7 +106,7 @@
</div> </div>
<div class="details"> <div class="details">
<div class="container"> <div class="container">
<form style="padding-bottom: 10px" action="/key/add/" method="POST"> <form style="padding-bottom: 10px" action="{% url one.views.key_add %}" method="POST">
{% csrf_token %} {% csrf_token %}
<textarea style="margin-bottom: 5px" name="key" placeholder="{% trans "Public key in OpenSSH format" %}"></textarea><br /> <textarea style="margin-bottom: 5px" name="key" placeholder="{% trans "Public key in OpenSSH format" %}"></textarea><br />
<input type="submit" style="margin-left: 10px;" value="{% trans "Save" %}" /> <input type="submit" style="margin-left: 10px;" value="{% trans "Save" %}" />
...@@ -139,7 +145,7 @@ ...@@ -139,7 +145,7 @@
<p id="upload-error-unknown" style="display: none"></p> <p id="upload-error-unknown" style="display: none"></p>
</div> </div>
<div style="display: none" class="upload-zone" id="old-upload-form"> <div style="display: none" class="upload-zone" id="old-upload-form">
<form action="/" method="POST" data-bind="attr: {action: uploadURL}" enctype="multipart/form-data"> <form action="{% url one.views.home %}" method="POST" data-bind="attr: {action: uploadURL}" enctype="multipart/form-data">
<input type="file" name="data" /> <input type="file" name="data" />
<input type="submit" value="Feltöltés" /> <input type="submit" value="Feltöltés" />
</form> </form>
......
{% extends "box/base/entry.html" %} {% extends "box/base/entry.html" %}
{% load i18n %} {% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% block summary %} {% block summary %}
...@@ -8,13 +9,13 @@ ...@@ -8,13 +9,13 @@
<div class="info" data-bind="text: size"></div> <div class="info" data-bind="text: size"></div>
<div class="actions"> <div class="actions">
<a href="#" data-bind="click: $parent.rename, clickBubble: false"> <a href="#" data-bind="click: $parent.rename, clickBubble: false">
<img src="/static/icons/pencil.png" alt="{% trans "rename" %}" /> <img src="{% static "icons/pencil.png" %}" alt="{% trans "rename" %}" />
</a> </a>
<a href="#" data-bind="click: $parent.delete, clickBubble: false"> <a href="#" data-bind="click: $parent.delete, clickBubble: false">
<img src="/static/icons/minus-circle.png" alt="{% trans "remove" %}" /> <img src="{% static "icons/minus-circle.png" %}" alt="{% trans "remove" %}" />
</a> </a>
<a href="#" data-bind="click: $parent.download, clickBubble: false"> <a href="#" data-bind="click: $parent.download, clickBubble: false">
<img src="/static/icons/download-cloud.png" alt="{% trans "download" %}" /> <img src="{% static "icons/download-cloud.png" %}" alt="{% trans "download" %}" />
</a> </a>
</div> </div>
<div class="clear"></div> <div class="clear"></div>
......
{% extends "box/base/entry.html" %} {% extends "box/base/entry.html" %}
{% load i18n %} {% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% block content %} {% block content %}
...@@ -15,7 +16,7 @@ ...@@ -15,7 +16,7 @@
</div> </div>
<div class="actions"> <div class="actions">
<a href="#" class="remove delete-key" data-id="{{key.id}}"> <a href="#" class="remove delete-key" data-id="{{key.id}}">
<img src="/static/icons/minus-circle.png" alt="{% trans 'Remove' %}" /> <img src="{% static "icons/minus-circle.png" %}" alt="{% trans 'Remove' %}" />
</a> </a>
</div> </div>
<div class="clear"></div> <div class="clear"></div>
......
{% extends "box/base/box.html" %} {% extends "box/base/box.html" %}
{% load i18n %} {% load i18n %}
{% load l10n %} {% load l10n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% block title %} {% block title %}
...@@ -9,8 +10,9 @@ ...@@ -9,8 +10,9 @@
{% block boxhelp %} {% block boxhelp %}
<div class="boxhelp"> <div class="boxhelp">
<div class="help">
<div class="icon"> <div class="icon">
<img src="/static/icons/information-frame.png" alt="{% trans "Help" %}" /> <img src="{% static "icons/information-frame.png" %}" alt="{% trans "Help" %}" />
</div> </div>
<div class="boxhelp-box"> <div class="boxhelp-box">
<p>{% blocktrans %}This is the list of your own templates.{% endblocktrans %}</p> <p>{% blocktrans %}This is the list of your own templates.{% endblocktrans %}</p>
...@@ -19,6 +21,10 @@ ...@@ -19,6 +21,10 @@
machine, and it will be ready to run by your students in minutes. machine, and it will be ready to run by your students in minutes.
{% endblocktrans %}</p> {% endblocktrans %}</p>
</div> </div>
</div>
<div class="icon">
<img src="" alt="toggle" title="{% trans "Show/hide box" %}" class="toggle-box" data-id="templates" id="toggle-box-templates"/>
</div>
</div> </div>
{% endblock %} {% endblock %}
...@@ -53,17 +59,17 @@ ...@@ -53,17 +59,17 @@
<div class="summary public-template"> <div class="summary public-template">
<div class="name"> <div class="name">
{{t.name}} {{t.name}}
<img src="/static/icons/lock-small.png" alt="{% trans "locked" %}" <img src="{% static "icons/lock-small.png" %}" alt="{% trans "locked" %}"
title="{% trans "This is a shared template." %}" /> title="{% trans "This is a shared template." %}" />
</div> </div>
<div class="status">{{t.state}}</div> <div class="status">{{t.state}}</div>
<div class="actions"> <div class="actions">
{% if t.state == 'READY' %} {% if t.state == 'READY' %}
<a href="#" class="try-template-button" data-id="{{t.id}}" title="{% trans "Try" %}"> <a href="#" class="try-template-button" data-id="{{t.id}}" title="{% trans "Try" %}">
<img src="/static/icons/control.png" alt="{% trans "Start" %}"/> <img src="{% static "icons/control.png" %}" alt="{% trans "Start" %}"/>
</a> </a>
<a href="#" class="template-share" data-id="{{t.id}}" data-gid="{{group.id}}" title="{% trans "Share" %}"> <a href="#" class="template-share" data-id="{{t.id}}" data-gid="{{group.id}}" title="{% trans "Share" %}">
<img src="/static/icons/user-share.png" alt="{% trans "Share" %}" /> <img src="{% static "icons/user-share.png" %}" alt="{% trans "Share" %}" />
</a> </a>
{% endif %} {% endif %}
</div> </div>
...@@ -75,14 +81,24 @@ ...@@ -75,14 +81,24 @@
<div class="quota"> <div class="quota">
<div class="used" style="width: {{ i.get_instance_pc|unlocalize }}%"></div> <div class="used" style="width: {{ i.get_instance_pc|unlocalize }}%"></div>
</div> </div>
<form action="/vm/unshare/{{i.id}}/" method="post"> <form action="{% url one.views.vm_unshare i.id %}" method="post">
<span title="{{i.name}}">{{i.name|truncatechars:20}}</span> <span title="{{i.name}}">{{i.name|truncatechars:20}}</span>
({{i.get_running}}/{{i.instance_limit}}) ({{i.get_running}}/{{i.instance_limit}}) {{i.type}}
<a href="#" class="edit" data-id="{{i.id}}">
<img src="{% static "icons/pencil.png" %}" alt="{% trans "Edit" %}" title="{% trans "Edit" %}" />
</a>
{% csrf_token %} {% csrf_token %}
<input type="submit" class="template-unshare" value="{% trans "Delete" %}" style="float: right"/> <input type="submit" class="template-unshare" value="{% trans "Delete" %}" style="float: right"/>
</form> </form>
<div class="clear"></div> <div class="clear"></div>
</li> </li>
<li class="description{% if not i.description %} empty{% endif %}">
{% if i.description %}
{{i.description}}
{% else %}
{% trans "No description available" %}
{% endif %}
</li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}
......
{% extends "box/base/summary.html" %} {% extends "box/base/summary.html" %}
{% load i18n %} {% load i18n %}
{% load l10n %} {% load l10n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% block content %} {% block content %}
...@@ -13,14 +14,24 @@ ...@@ -13,14 +14,24 @@
<div class="quota"> <div class="quota">
<div class="used" style="width: {{ i.get_instance_pc|unlocalize }}%"></div> <div class="used" style="width: {{ i.get_instance_pc|unlocalize }}%"></div>
</div> </div>
<form action="/vm/unshare/{{i.id}}/" method="post"> <form action="{% url one.views.vm_unshare i.id %}" method="post">
<span title="{{i.name}}">{{i.name|truncatechars:20}}</span> <span title="{{i.name}}">{{i.name|truncatechars:20}}</span>
({{i.get_running}}/{{i.instance_limit}}) ({{i.get_running}}/{{i.instance_limit}}) {{i.type}}
<a href="#" class="edit" data-id="{{i.id}}">
<img src="{% static "icons/pencil.png" %}" alt="{% trans "Edit" %}" title="{% trans "Edit" %}" />
</a>
{% csrf_token %} {% csrf_token %}
<input class="template-unshare" type="submit" value="{% trans "Delete" %}" style="float: right"/> <input class="template-unshare" type="submit" value="{% trans "Delete" %}" style="float: right"/>
</form> </form>
<div class="clear"></div> <div class="clear"></div>
</li> </li>
<li class="description{% if not i.description %} empty{% endif %}">
{% if i.description %}
{{i.description}}
{% else %}
{% trans "No description available" %}
{% endif %}
</li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}
...@@ -32,25 +43,25 @@ ...@@ -32,25 +43,25 @@
{% endblock %} {% endblock %}
{% block status %} {% block status %}
{{vm.state}} {{t.state}}
{% endblock status %} {% endblock status %}
{% block actions %} {% block actions %}
<a href="#" class="edit-template" data-id="{{ t.id }}" title="{% trans "Edit" %}">
<img src="{% static "icons/pencil.png" %}" alt="{% trans "Edit" %}" />
</a>
{% if t.state == 'READY' %} {% if t.state == 'READY' %}
<a href="#" class="try-template" data-id="{{t.id}}" title="{% trans "Try" %}"> <a href="#" class="try-template" data-id="{{t.id}}" title="{% trans "Try" %}">
<img src="/static/icons/control.png" alt="{% trans "Start" %}"/> <img src="{% static "icons/control.png" %}" alt="{% trans "Start" %}"/>
</a> </a>
<!--<a href="#" title="{% trans "Edit" %}"> <!--<a href="#" title="{% trans "Edit" %}">
<img src="/static/icons/pencil.png" alt="{% trans "Edit" %}" /> <img src="{% static "icons/pencil.png" %}" alt="{% trans "Edit" %}" />
</a>--> </a>-->
<a href="#" class="template-share" data-id="{{t.id}}" data-gid="{{group.id}}" title="{% trans "Share" %}"> <a href="#" class="template-share" data-id="{{t.id}}" data-gid="{{group.id}}" title="{% trans "Share" %}">
<img src="/static/icons/user-share.png" alt="{% trans "Share" %}" /> <img src="{% static "icons/user-share.png" %}" alt="{% trans "Share" %}" />
</a> </a>
{% endif %} {% endif %}
<a href="#" class="delete-template" data-id="{{ t.id }}" data-name="{{ t.name }}" title="{% trans "Remove" %}"> <a href="#" class="delete-template" data-id="{{ t.id }}" data-name="{{ t.name }}" title="{% trans "Remove" %}">
<img src="/static/icons/minus-circle.png" alt="{% trans "Remove" %}" /> <img src="{% static "icons/minus-circle.png" %}" alt="{% trans "Remove" %}" />
</a> </a>
<!--<a href="#" class="edit-template" data-id="{{ t.id }}" title="{% trans "Edit" %}">
<img src="/static/icons/pencil.png" alt="{% trans "Edit" %}" />
</a>-->
{% endblock actions %} {% endblock actions %}
{% extends "box/base/box.html" %} {% extends "box/base/box.html" %}
{% load i18n %} {% load i18n %}
{% load l10n %} {% load l10n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% block title %} {% block title %}
...@@ -9,8 +10,9 @@ ...@@ -9,8 +10,9 @@
{% block boxhelp %} {% block boxhelp %}
<div class="boxhelp"> <div class="boxhelp">
<div class="help">
<div class="icon"> <div class="icon">
<img src="/static/icons/information-frame.png" alt="{% trans "Help" %}" /> <img class="help" src="{% static "icons/information-frame.png" %}" alt="{% trans "Help" %}" />
</div> </div>
<div class="boxhelp-box"> <div class="boxhelp-box">
<p>{% blocktrans %}This is the list of your running virtual machines.{% endblocktrans %}</p> <p>{% blocktrans %}This is the list of your running virtual machines.{% endblocktrans %}</p>
...@@ -19,6 +21,10 @@ ...@@ -19,6 +21,10 @@
<p>{% blocktrans %}Please note, that users and shares both have a limit <p>{% blocktrans %}Please note, that users and shares both have a limit
of launchable instances.{% endblocktrans %}</p> of launchable instances.{% endblocktrans %}</p>
</div> </div>
</div>
<div class="icon">
<img src="" alt="{% trans "Show/hide box" %}" class="toggle-box" data-id="vms" id="toggle-box-vms"/>
</div>
</div> </div>
{% endblock %} {% endblock %}
...@@ -103,7 +109,7 @@ ...@@ -103,7 +109,7 @@
<li> <li>
&nbsp; &nbsp;
<span class="value"> <span class="value">
<form method="POST" action="/vm/new/s{{s.pk}}/"> <form method="POST" action="{% url one.views.vm_new share=s.id %}">
{% csrf_token %} {% csrf_token %}
<input {% if s.running_shared >= s.per_user_limit or s.get_running >= s.instance_limit%}disabled="disabled" value="{% trans "Quota reached" %}" {%else%}value="{% trans "Launch" %}"{% endif %} type="submit" /> <input {% if s.running_shared >= s.per_user_limit or s.get_running >= s.instance_limit%}disabled="disabled" value="{% trans "Quota reached" %}" {%else%}value="{% trans "Launch" %}"{% endif %} type="submit" />
</form> </form>
......
{% extends "box/base/entry.html" %} {% extends "box/base/entry.html" %}
{% load i18n %} {% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% block content %} {% block content %}
...@@ -26,7 +27,7 @@ ...@@ -26,7 +27,7 @@
</li> </li>
<li class="template"> <li class="template">
{% trans "Type" %}: {% trans "Type" %}:
<span class="value">{{vm.share.type}}</span> <span class="value">{% if vm.share %}{{vm.share.type}}{% else %}{% trans "Try" %}{% endif %}</span>
<div class="clear"></div> <div class="clear"></div>
</li> </li>
<li class="template"> <li class="template">
...@@ -56,9 +57,9 @@ ...@@ -56,9 +57,9 @@
<li class="date"> <li class="date">
{% trans "time of suspend"|capfirst %}: {% trans "time of suspend"|capfirst %}:
<span class="value"> <abbr title="{{vm.time_of_suspend}}">{{vm.time_of_suspend|timeuntil}}</abbr> <span class="value"> <abbr title="{{vm.time_of_suspend}}">{{vm.time_of_suspend|timeuntil}}</abbr>
<a href="#" class="renew-vm-button renew-suspend-vm-button" data-id="{{ vm.id }}" title="{% trans "Renew suspend time" %}"> {% if vm.share %}<a href="#" class="renew-vm renew-suspend-vm" data-id="{{ vm.id }}" title="{% trans "Renew suspend time" %}">
<img src="/static/icons/control-double.png" alt="{% trans "Renew suspend time" %}" /> <img src="{% static "icons/control-double.png" %}" alt="{% trans "Renew suspend time" %}" />
</a> </a>{% endif %}
</span> </span>
</li> </li>
{% endif %} {% endif %}
...@@ -66,16 +67,16 @@ ...@@ -66,16 +67,16 @@
<li class="date"> <li class="date">
{% trans "time of delete"|capfirst %}: {% trans "time of delete"|capfirst %}:
<span class="value"> <abbr title="{{vm.time_of_delete}}">{{vm.time_of_delete|timeuntil}}</abbr> <span class="value"> <abbr title="{{vm.time_of_delete}}">{{vm.time_of_delete|timeuntil}}</abbr>
<a href="#" class="renew-vm-button renew-delete-vm-button" data-id="{{ vm.id }}" title="{% trans "Renew deletion time" %}"> {% if vm.share %}<a href="#" class="renew-vm renew-delete-vm" data-id="{{ vm.id }}" title="{% trans "Renew deletion time" %}">
<img src="/static/icons/control-double.png" alt="{% trans "Renew deletion time" %}" /> <img src="{% static "icons/control-double.png" %}" alt="{% trans "Renew deletion time" %}" />
</a> </a>{% endif %}
</span> </span>
</li> </li>
{% endif %} {% endif %}
<li> <li>
&nbsp; &nbsp;
<span class="value"> <span class="value">
<a href="/vm/show/{{vm.id}}/" title="{{vm.name}}">{% trans "More details" %}</a> <a href="{{ vm.get_absolute_url }}" title="{{vm.name}}">{% trans "More details" %}</a>
</span> </span>
</li> </li>
</ul> </ul>
......
{% extends "box/base/summary.html" %} {% extends "box/base/summary.html" %}
{% load staticfiles %}
{% load i18n %} {% load i18n %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
...@@ -12,53 +13,53 @@ ...@@ -12,53 +13,53 @@
<div class="name {% if vm.state == 'ACTIVE' %}vm-on{% else %}vm-off{% endif %}"> <div class="name {% if vm.state == 'ACTIVE' %}vm-on{% else %}vm-off{% endif %}">
<span id="vm-{{vm.id}}-name">{{vm.name|truncatechars:20}}</span> <span id="vm-{{vm.id}}-name">{{vm.name|truncatechars:20}}</span>
<small id="vm-{{vm.id}}-name-details" class="details"> <small id="vm-{{vm.id}}-name-details" class="details">
(<a href="/vm/show/{{vm.id}}/" title="{{vm.name}}">{% trans "More details" %}</a>) (<a href="{{ vm.get_absolute_url }}" title="{{vm.name}}">{% trans "More details" %}</a>)
</small> </small>
</div> </div>
{% endblock %} {% endblock %}
{% block status %} {% block status %}
{{vm.state}} {% if vm.template.state != "READY" %} {{vm.template.state}} {% else %} {{vm.state}} {% endif %}
{% endblock status %} {% endblock status %}
{% block actions %} {% block actions %}
<a href="#" class="rename-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Edit name" %}"> <a href="#" class="rename-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Edit name" %}">
<img src="/static/icons/pencil.png" alt="{% trans "Edit name" %}" /> <img src="{% static "icons/pencil.png" %}" alt="{% trans "Edit name" %}" />
</a> </a>
{% if vm.waiting %} {% if vm.waiting %}
<a href="#"> <a href="#">
<img src="/static/image/load.gif" /> <img src="{% static "image/load.gif" %}" />
</a> </a>
{% elif vm.state == 'ACTIVE' %} {% elif vm.state == 'ACTIVE' %}
<a href="{{vm.get_connect_uri}}" data-id="{{ vm.id }}" class="connect-vm" title="{% trans "Connect" %}"> <a href="{{vm.get_connect_uri}}" data-id="{{ vm.id }}" class="connect-vm" title="{% trans "Connect" %}">
<img src="/static/icons/plug.png" alt="{% trans "Connect" %}" /> <img src="{% static "icons/plug.png" %}" alt="{% trans "Connect" %}" />
</a> </a>
<a href="#" class="stop-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Pause" %}"> <a href="#" class="stop-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Pause" %}">
<img src="/static/icons/control-pause.png" alt="{% trans "Pause" %}" /> <img src="{% static "icons/control-pause.png" %}" alt="{% trans "Pause" %}" />
</a> </a>
<a href="#" class="delete-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Delete" %}"> <a href="#" class="delete-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Delete" %}">
<img src="/static/icons/minus-circle.png" alt="{% trans "Delete" %}" /> <img src="{% static "icons/minus-circle.png" %}" alt="{% trans "Delete" %}" />
</a> </a>
<a href="#" class="restart-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Restart" %}"> <a href="#" class="restart-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Restart" %}">
<img src="/static/icons/arrow-circle-double.png" alt="↺" /> <img src="{% static "icons/arrow-circle-double.png" %}" alt="↺" />
</a> </a>
{% elif vm.state == 'PENDING' %} {% elif vm.state == 'PENDING' %}
<a href="#"> <a href="#">
<img src="/static/image/load.gif" /> <img src="{% static "image/load.gif" %}" />
</a> </a>
<a style="float: right" href="#" class="delete-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Delete" %}"> <a style="float: right" href="#" class="delete-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Delete" %}">
<img src="/static/icons/minus-circle.png" alt="{% trans "Delete" %}" /> <img src="{% static "icons/minus-circle.png" %}" alt="{% trans "Delete" %}" />
</a> </a>
{% elif vm.state == 'STOPPED' %} {% elif vm.state == 'STOPPED' %}
<a href="#" class="resume-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Resume" %}"> <a href="#" class="resume-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Resume" %}">
<img src="/static/icons/control.png" alt="{% trans "Resume" %}" /> <img src="{% static "icons/control.png" %}" alt="{% trans "Resume" %}" />
</a> </a>
<a href="#" class="delete-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Delete" %}"> <a href="#" class="delete-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Delete" %}">
<img src="/static/icons/minus-circle.png" alt="{% trans "Delete" %}" /> <img src="{% static "icons/minus-circle.png" %}" alt="{% trans "Delete" %}" />
</a> </a>
{% elif vm.state == 'FAILED' %} {% elif vm.state == 'FAILED' %}
<a href="#" class="delete-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Delete" %}"> <a href="#" class="delete-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Delete" %}">
<img src="/static/icons/minus-circle.png" alt="{% trans "Delete" %}" /> <img src="{% static "icons/minus-circle.png" %}" alt="{% trans "Delete" %}" />
</a> </a>
{% endif %} {% endif %}
{% endblock actions %} {% endblock actions %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
<form action="{% url one.views.ajax_share_edit_wizard share.id %}" method="post" id="template-wizard">
{% csrf_token %}
<div id="new-share" class="wizard">
<h2>
{% blocktrans with t=share.name%}Editing share: {{t}}{% endblocktrans %}
</h2>
<p>{% trans "Change the parameters as needed." %}</p>
<ul>
<li>
<label for="share-name">{% trans "Name of share" %}</label>
<input type="text" name="name" id="share-name" value="{{share.name}}" />
<div class="clear"></div>
</li>
<li class="li-share-type">
<label for="share-type">{% trans "Type" %}</label>
<ul class="radio">
{% for s in types %}
<li>
<label>
<input type="radio" name="type" value="{{s.id}}" id="share-type-{{s.id}}"
{% if s.id == share.type %}checked="checked"{% endif %} />{{s.verbose_name}}
</label>
</li>
{% endfor %}
</ul>
{% for s in types %}
<p id="share-type-summary-{{s.id}}" class="type-summary clear"
{% if not s.id == share.type %}style="display:none"{% endif %}>
{{s.help_text}}
({% if s.suspend %}
<span class="suspend"
title="{% blocktrans with time=s.suspend %}Suspend after {{time}}.{%endblocktrans%}">{{s.suspendx|timeuntil}}</span>
{%endif%}{% if s.delete %}
<span class="delete"
title="{% blocktrans with time=s.delete %}Delete after {{time}}.{%endblocktrans%}">{{s.deletex|timeuntil}}</span>
{%endif%})
</p>
{% endfor %}
<div class="clear"></div>
</li>
<li>
<label for="share-instance-limit">{% trans "Maximal count of instances" %}</label>
<input type="number" name="instance_limit" id="share-instance-limit" value="{{share.instance_limit}}" />
<div class="clear"></div>
</li>
<li>
<label for="share-per-user-limit">{% trans "Maximal count of instaces/user" %}</label>
<input type="number" name="per_user_limit" id="share-per-user-limit" value="{{share.per_user_limit}}" />
<div class="clear"></div>
</li>
<li style="border: none" class="clear">
<label for="share-description">{% trans "Description" %}</label>
<textarea name="description" id="share-description" style="text-align: left">{{share.description}}</textarea>
<div class="clear"></div>
</li>
</ul>
<nav>
<input type="reset" class="prev" value="{% trans "Cancel" %}" />
<input type="submit" value="{% trans "Save" %}"/>
<div class="clear"></div>
</nav>
<script type="text/javascript">
$(function(){
$('#new-share nav .prev').click(function(){
$('#modal').hide();
})
$("#new-share input[name='type']").click(function(e){ /* TODO */
var v = $("#new-share input[name='type']:checked").val();
$("p.type-summary").hide();
$("#share-type-summary-" + v).show();
});
})
</script>
</div>
</form>
{% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
<form action="{% url one.views.ajax_template_edit_wizard template.id %}" method="post" id="template-wizard">
{% csrf_token %}
<div id="new-template-step-2" class="wizard">
<h2>{% trans "Edit template" %}</h2>
<p>{% trans "Change the parameters as needed." %}</p>
<ul>
<li>
<label for="new-template-name">{% trans "Name" %}</label>
<input type="text" name="name" id="new-template-name" value="{{template.name}}"
class="validated" />
<div class="clear"></div>
</li>
<li class="new-tpl-size">
<label for="new-template-size">{% trans "Size" %}</label>
<ul class="radio">
{% for s in sizes %}
<li>
<label>
<input type="radio" name="size" value="{{s.id}}" id="new-template-size-{{s.id}}"
{% if s == template.instance_type %}checked="checked"{% endif %} />
{{s.name}}
</label>
</li>
{% endfor %}
</ul>
{% for s in sizes %}
<p id="new-template-size-summary-{{s.id}}" class="size-summary clear"
{% if s != template.instance_type %}style="display:none"{% endif %}>
<span class="cpu">
{% blocktrans count n=s.CPU %}{{n}} core{% plural %}{{n}} cores{% endblocktrans %}
</span>
<span class="memory">{{s.RAM}} MiB</span>
<span class="credit">{{s.credit}}</span>
</p>
{% endfor %}
<div class="clear"></div>
</li>
<li style="border: none">
<label for="new-template-description">{% trans "Description" %}</label>
<textarea name="description" id="new-template-description" style="text-align: left">{{template.description}}</textarea>
<div class="clear"></div>
</li>
</ul>
<nav>
<input type="reset" class="prev" value="{% trans "Cancel" %}" />
<input type="submit" class="next" value="{% trans "Save" %}" />
<div class="clear"></div>
</nav>
<script type="text/javascript">
$(function(){
var original = '{{template.name}}';
$('#new-template-step-2 nav .prev').click(function(){
$('#modal').hide();
})
$(".new-tpl-size input[name='size']").click(function(e){
var v = $(".new-tpl-size input[name='size']:checked").val();
$("p.size-summary").hide();
$("#new-template-size-summary-" + v).show();
});
$("#new-template-name").keyup(function(){
var timer;
return function(e){
var self = this;
clearTimeout(timer);
timer=setTimeout(function(){
var s = $(self).val();
$.ajax({
'type': 'GET',
'url': '{% url one.views.ajax_template_name_unique %}?name=' + s,
'success': function(data, b, c) {
if (s != $("#new-template-name").val()) {
return true;
}
if (data == "True" || s == original) {
$('#new-template-name').removeClass("error");
$('#new-template-step-2 nav .next').removeAttr("disabled");
$('#new-template-name').removeProp("title");
}
else {
$('#new-template-name').addClass("error");
$('#new-template-step-2 nav .next').attr("disabled", "disabled");
$('#new-template-name').prop("title", gettext('Please choose a different name.'));
}
}
});
}, 1000)
}
}());
$("#template-wizard").submit(function(e){
e.preventDefault();
$.ajax({
'type': 'GET',
'url': '{% url one.views.ajax_template_name_unique %}?name=' + $("#new-template-name").val(),
'success': function(data, b, c) {
if (data == "True" || s == original) {
$("#template-wizard").unbind('submit').submit()
}
else {
$('#new-template-name').addClass("error");
$('#new-template-step-2 nav .next').attr("disabled", "disabled");
$('#new-template-name').prop("title", gettext('Please choose a different name.'));
}
}
});
});
})
</script>
</div>
</form>
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n %} {% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% block js %} {% block js %}
<script type="text/javascript" src="/static/script/store.js"></script> {% if DEBUG %}<script type="text/javascript" src="{% static "script/store.js" %}"></script>
{% else %}<script type="text/javascript" src="{% static "script/store.min.js" %}"></script>
{% endif %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="boxes"> <div class="boxes">
......
{% load i18n %}
{% blocktrans with name=user.get_full_name %}
Dear {{name}},
{% endblocktrans %}
{% block body %}
{% endblock %}
--
{{site}}
{% extends "mails/base.txt" %}
{% load i18n %}
{% block body %}
{% blocktrans with reason=bl.reason snort_message=bl.snort_message vm=instance.name %}
Our network intrusion detection system showed that your machine
"{{vm}}" pursues the following forbidden network activity: {{reason}}.
"{{vm}}" has been BANNED from all network activity
including remote desktop and shell connection.
Details:
{{snort_message}}
{% endblocktrans %}
{% blocktrans with url=url %}
Please, reply to this notification, or delete the instance on the
cloud portal: {{url}}
{% endblocktrans %}
{% endblock %}
{% extends "mails/base.txt" %}
{% load i18n %}
{% block body %}
{% blocktrans with vm=instance.name state=instance.state|lower date=instance.time_of_delete %}
Your {{state}} virtual machine "{{vm}}" has been DELETED
at {{date}}.
{% endblocktrans %}
{% blocktrans %}
The disk image is IRRECOVERABLY REMOVED.
{% endblocktrans %}
{% blocktrans with url=url %}
You can start a new instance of the template on the cloud portal:
{{url}}
{% endblocktrans %}
{% endblock %}
{% extends "mails/base.txt" %}
{% load i18n %}
{% block body %}
{% blocktrans with vm=instance.name state=instance.state|lower date=instance.time_of_delete time=exp|timeuntil %}
Your {{state}} virtual machine "{{vm}}" is going to be DELETED
at {{date}} (in {{time}}).
{% endblocktrans %}
{% blocktrans %}
The disk image will be IRRECOVERABLY REMOVED.
{% endblocktrans %}
{% blocktrans with url=url %}
You can renew or delete the instance on the cloud portal:
{{url}}
{% endblocktrans %}
{% endblock %}
{% extends "mails/base.txt" %}
{% load i18n %}
{% block body %}
{% blocktrans with vm=instance.name state=instance.state|lower date=instance.time_of_suspend %}
Your {{state}} virtual machine "{{vm}}" has been STOPPED
at {{date}}.
{% endblocktrans %}
{% blocktrans with deldate=instance.time_of_delete %}
The disk and memory image is stored, and you can resume it
until the final expiration time ({{deldate}}).
{% endblocktrans %}
{% blocktrans with url=url %}
You can also renew or delete the instance on the cloud portal:
{{url}}
{% endblocktrans %}
{% endblock %}
{% extends "mails/base.txt" %}
{% load i18n %}
{% block body %}
{% blocktrans with vm=instance.name state=instance.state|lower date=instance.time_of_suspend time=exp|timeuntil url=url %}
Your {{state}} virtual machine "{{vm}}" is going to be STOPPED
at {{date}} (in {{time}}).
{% endblocktrans %}
{% blocktrans with deldate=instance.time_of_delete %}
The disk and memory image will be stored, and you can resume it
until the final expiration time ({{deldate}}).
{% endblocktrans %}
{% blocktrans with url=url %}
You can also renew or delete the instance on the cloud portal:
{{url}}
{% endblocktrans %}
{% endblock %}
{% load i18n %} {% load i18n %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
<form action="/ajax/share/{{base.id}}/" method="post" id="template-wizard"> <form action="{% url one.views.ajax_share_wizard id=base.id %}" method="post" id="template-wizard">
{% csrf_token %} {% csrf_token %}
<div id="new-share" class="wizard"> <div id="new-share" class="wizard">
<h2> <h2>
......
{% load i18n %} {% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
<form action="/ajax/templateWizard" method="post" id="template-wizard"> <form action="{% url one.views.ajax_template_wizard %}" method="post" id="template-wizard">
{% csrf_token %} {% csrf_token %}
<div id="new-template-step-1" class="wizard"> <div id="new-template-step-1" class="wizard">
<div class="progress"> <div class="progress">
...@@ -28,7 +29,7 @@ ...@@ -28,7 +29,7 @@
<input type="radio" name="base" value="{{m.id}}" /> <input type="radio" name="base" value="{{m.id}}" />
{{m.name}} {{m.name}}
{% if m.public %} {% if m.public %}
<img src="/static/icons/lock-small.png" alt="{% trans "locked" %}" <img src="{% static "icons/lock-small.png" %}" alt="{% trans "locked" %}"
title="{% trans "This is a shared template." %}" /> title="{% trans "This is a shared template." %}" />
{% endif %} {% endif %}
</label> </label>
...@@ -56,7 +57,7 @@ ...@@ -56,7 +57,7 @@
else { else {
$.ajax({ $.ajax({
'type': 'POST', 'type': 'POST',
'url': '/ajax/templateWizard', 'url': '{% url one.views.ajax_template_wizard %}',
'data': $('#template-wizard').serialize(), 'data': $('#template-wizard').serialize(),
'success': function(data) { 'success': function(data) {
$('#modal-container').html(data); $('#modal-container').html(data);
......
{% load i18n %} {% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
<form action="/vm/new/{{base.id}}/" method="post" id="template-wizard"> <form action="{% url new_vm_from_template base.id %}" method="post" id="template-wizard">
{% csrf_token %} {% csrf_token %}
<div id="new-template-step-2" class="wizard"> <div id="new-template-step-2" class="wizard">
<div class="progress"> <div class="progress">
...@@ -75,7 +76,7 @@ ...@@ -75,7 +76,7 @@
var s = $(self).val(); var s = $(self).val();
$.ajax({ $.ajax({
'type': 'GET', 'type': 'GET',
'url': '/ajax/template_name_unique/' + s, 'url': '{% url one.views.ajax_template_name_unique %}?name=' + s,
'success': function(data, b, c) { 'success': function(data, b, c) {
if (s != $("#new-template-name").val()) { if (s != $("#new-template-name").val()) {
return true; return true;
...@@ -99,7 +100,7 @@ ...@@ -99,7 +100,7 @@
e.preventDefault(); e.preventDefault();
$.ajax({ $.ajax({
'type': 'GET', 'type': 'GET',
'url': '/ajax/template_name_unique/' + $("#new-template-name").val(), 'url': '{% url one.views.ajax_template_name_unique %}?name=' + $("#new-template-name").val(),
'success': function(data, b, c) { 'success': function(data, b, c) {
if (data == "True") { if (data == "True") {
$("#template-wizard").unbind('submit').submit() $("#template-wizard").unbind('submit').submit()
......
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n %} {% load i18n %}
{% load staticfiles %}
{% block js %} {% block js %}
<script type="text/javascript"> <script type="text/javascript">
...@@ -8,14 +9,28 @@ ...@@ -8,14 +9,28 @@
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
dataType: 'json', dataType: 'json',
url: '/ajax/vm/status/{{ id }}', url: '{% url one.views.vm_ajax_instance_status id %}',
success: function(data){ success: function(data){
if( !data.booting && data.state == 'ACTIVE'){ if (!data.booting && data.state == 'ACTIVE'){
window.location.reload(); window.location.reload();
} }
} }
}) });
},2000); }, 5000);
{% endif %}
{% if i.template.state == 'SAVING' %}
var savingTimer=setInterval(function(){
$.ajax({
type: 'GET',
dataType: 'json',
url: '{% url one.views.vm_ajax_instance_status id %}',
success: function(data){
if(data.template.state == 'READY'){
window.location.href='{% url one.views.home %}';
}
}
});
}, 10000);
{% endif %} {% endif %}
</script> </script>
{% endblock %} {% endblock %}
...@@ -61,13 +76,18 @@ ...@@ -61,13 +76,18 @@
<div class="content"> <div class="content">
{% if state == "PENDING" or state == "ACTIVE" and booting %} {% if state == "PENDING" or state == "ACTIVE" and booting %}
<p style="font-size:25px; line-height:2em;text-align:center;"> <p style="font-size:25px; line-height:2em;text-align:center;">
<img src="/static/image/load.gif" /> <img src="{% static "image/load.gif" %}" />
{% trans "Starting..." %} {% trans "Starting..." %}
</p> </p>
{% elif i.template.state == "SAVING" %}
<p style="font-size:25px; line-height:2em;text-align:center;">
<img src="{% static "image/load.gif" %}" />
{% trans "Saving..." %}
</p>
{% elif state == "ACTIVE" and not booting %} {% elif state == "ACTIVE" and not booting %}
<p id="connect" style="display:block; font-size:25px; line-height:2em;text-align:center;"> <p id="connect" style="display:block; font-size:25px; line-height:2em;text-align:center;">
<a href="{{uri}}" class="button" onclick="return connectbutton();"> <a href="{{uri}}" class="button" onclick="return connectbutton();">
<img src="/static/image/load.gif" id="connecting" style="display:none;" /> <img src="{% static "image/load.gif" %}" id="connecting" style="display:none;" />
{% trans "Running" %} {% trans "Running" %}
</a> </a>
</p> </p>
...@@ -90,8 +110,9 @@ ...@@ -90,8 +110,9 @@
<div class="contentblock" id="ports"> <div class="contentblock" id="ports">
<h2> <h2>
<div class="boxhelp"> <div class="boxhelp">
<div class="help">
<div class="icon"> <div class="icon">
<img src="/static/icons/information-frame.png" alt="{% trans "Help" %}" /> <img src="{% static "icons/information-frame.png" %}" alt="{% trans "Help" %}" />
</div> </div>
<div class="boxhelp-box"> <div class="boxhelp-box">
<p>{% blocktrans %}This is a list about the network ports <p>{% blocktrans %}This is a list about the network ports
...@@ -105,23 +126,24 @@ ...@@ -105,23 +126,24 @@
{% endblocktrans %}</p> {% endblocktrans %}</p>
</div> </div>
</div> </div>
</div>
{% trans "Port administration" %}</h2> {% trans "Port administration" %}</h2>
<div class="content"> <div class="content">
<form action="{% url vm_port_add i.id %}" method="post"> <form action="{% url one.views.vm_port_add i.id %}" method="post">
{% csrf_token %} {% csrf_token %}
<table> <table>
<tr> <tr>
<th>{% trans "Protocol" %}</th> <th>{% trans "Protocol" %}</th>
<th>{% trans "Public port" %}</th> <th>{% trans "Public port" %}</th>
<th colspan="2">{% trans "Private port" %}</th> {% if i.template.network.nat %}<th colspan="2">{% trans "Private port" %}</th>{%endif%}
</tr> </tr>
{% for port in ports %} {% for port in ports %}
<tr> <tr>
<td>{{port.proto}}</td> <td>{{port.proto}}</td>
<td>{{port.public}}</td> <td>{{port.public}}</td>
<td>{{port.private}}</td> {% if i.template.network.nat %}<td>{{port.private}}</td>{%endif%}
<td> <td>
<a href="/vm/port_del/{{i.id}}/{{port.proto}}/{{port.public}}/">{% trans "Delete" %}</a> <a href="{% url one.views.vm_port_del i.id port.proto port.public %}">{% trans "Delete" %}</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
...@@ -135,9 +157,11 @@ ...@@ -135,9 +157,11 @@
<td> <td>
<input style="min-width:70px;width:70px;" type="text" name="public"/> <input style="min-width:70px;width:70px;" type="text" name="public"/>
</td> </td>
{% if i.template.network.nat %}
<td> <td>
<input style="min-width:70px;width:70px;" type="text" name="private"/> <input style="min-width:70px;width:70px;" type="text" name="private"/>
</td> </td>
{% endif %}
<td> <td>
<input type="submit" style="min-width:3em" value="{% trans "Add" %}" /> <input type="submit" style="min-width:3em" value="{% trans "Add" %}" />
</td> </td>
......
{% load l10n %}
<html>
<head>
<!--Load the AJAX API-->
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
// Load the Visualization API and the piechart package.
google.load('visualization', '1.0', {'packages':['corechart']});
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(drawChart);
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function drawChart() {
// Create the data table.
var data_cpu = new google.visualization.DataTable();
data_cpu.addColumn('string', 'Topping');
data_cpu.addColumn('number', 'Slices');
data_cpu.addRows([
['Free CPU', {{STAT.CPU.FREE_CPU}}],
['Allocated CPU', {{STAT.CPU.ALLOC_CPU}}],
['Used CPU', {{STAT.CPU.USED_CPU}}],
]);
// Set chart options
var cpu_options = {'title':'Cloud CPU usage percent (100/CPU)',
'width':400,
'height':300,
slices: {0: {color: 'blue'}, 1:{color: 'orange'},
2:{color: 'red'}}
};
var data_mem = new google.visualization.DataTable();
data_mem.addColumn('string', 'Topping');
data_mem.addColumn('number', 'Slices');
data_mem.addRows([
['Free Memory', {{STAT.MEM.FREE_MEM|unlocalize}}],
['Allocated Memory', {{STAT.MEM.ALLOC_MEM|unlocalize}}],
['Used Memory', {{STAT.MEM.USED_MEM|unlocalize}}],
]);
// Set chart options
var mem_options = {'title':'Cloud Memory usage in {{STAT.DIMENSION}}',
'width':400,
'height':300,
slices: {0: {color: 'blue'}, 1:{color: 'orange'},
2:{color: 'red'}}
};
// Instantiate and draw our chart, passing in some options.
var chart = new
google.visualization.PieChart(document.getElementById('chart_cpu_div'));
chart.draw(data_cpu, cpu_options);
var chart = new
google.visualization.PieChart(document.getElementById('chart_mem_div'));
chart.draw(data_mem, mem_options);
}
</script>
</head>
<body>
<!--Div that will hold the pie chart-->
<div>Running VMs: {{STAT.VMS}}</div>
<div id="chart_cpu_div"></div>
<div id="chart_mem_div"></div>
</body>
</html>
{% load i18n %} {% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
<div class="content"> <div class="content">
<table> <table>
...@@ -7,8 +8,9 @@ ...@@ -7,8 +8,9 @@
<td> <td>
<div class="boxhelp"> <div class="boxhelp">
<div class="help">
<div class="icon"> <div class="icon">
<img src="/static/icons/information-frame.png" alt="{% trans "Help" %}" /> <img src="{% static "icons/information-frame.png" %}" alt="{% trans "Help" %}" />
</div> </div>
<div class="boxhelp-box"> <div class="boxhelp-box">
{% if i.template.os_type == 'linux' %} {% if i.template.os_type == 'linux' %}
...@@ -30,16 +32,17 @@ ...@@ -30,16 +32,17 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div>
{{i.template.access_type|upper}} {{i.template.access_type|upper}}
</td> </td>
</tr> </tr>
<tr> <tr>
<th>{% trans "IP" %}:</th> <th>{% trans "IP" %}:</th>
<td>{{ i.firewall_host.pub_ipv4 }}</td> <td>{{ i.hostname }}</td>
</tr> </tr>
<tr> <tr>
<th>{% trans "Port" %}:</th> <th>{% trans "Port" %}:</th>
<td>{{ i.get_port}}</td> <td>{{ i.port}}</td>
</tr> </tr>
<tr> <tr>
<th>{% trans "Username" %}:</th> <th>{% trans "Username" %}:</th>
......
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase from django.test import TestCase
class ViewsTestCase(TestCase):
class SimpleTest(TestCase): def test_index(self):
def test_basic_addition(self): '''Test whether index is reachable.'''
""" resp = self.client.get('/', follow=True)
Tests that 1 + 1 always equals 2. self.assertEqual(resp.status_code, 200)
"""
self.assertEqual(1 + 1, 2)
...@@ -6,10 +6,10 @@ msgid "" ...@@ -6,10 +6,10 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-02-21 18:06+0100\n" "POT-Creation-Date: 2013-03-07 18:16+0100\n"
"PO-Revision-Date: 2013-02-19 18:47+0100\n" "PO-Revision-Date: 2013-03-07 17:48+0100\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: American English <kde-l10n-hu@kde.org>\n" "Language-Team: American English <cloud@ik.bme.hu>\n"
"Language: en_US\n" "Language: en_US\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
...@@ -159,127 +159,179 @@ msgstr "Érvénytelen Neptun-kód." ...@@ -159,127 +159,179 @@ msgstr "Érvénytelen Neptun-kód."
msgid "Invalid NEPTUN code" msgid "Invalid NEPTUN code"
msgstr "Érvénytelen Neptun-kód" msgstr "Érvénytelen Neptun-kód"
#: templates/show-group.html:8 #: templates/show-group.html:9
msgid "Owners of" msgid "Owners of"
msgstr "Tulajdonosok" msgstr "Tulajdonosok"
#: templates/show-group.html:22 templates/box/person/entry.html:22 #: templates/show-group.html:23 templates/box/person/entry.html:23
msgid "Remove" msgid "Remove"
msgstr "Eltávolítás" msgstr "Eltávolítás"
#: templates/show-group.html:30 templates/box/person/entry.html:31 #: templates/show-group.html:31 templates/box/person/entry.html:32
msgid "This user never logged in, no data available" msgid "This user never logged in, no data available"
msgstr "Ez a felhasználó még nem lépett be, nincs adat róla" msgstr "Ez a felhasználó még nem lépett be, nincs adat róla"
#: templates/show-group.html:34 templates/box/person/entry.html:35 #: templates/show-group.html:35 templates/box/person/entry.html:36
msgid "Name" msgid "Name"
msgstr "Név" msgstr "Név"
#: templates/show-group.html:37 templates/box/person/entry.html:38 #: templates/show-group.html:38 templates/box/person/entry.html:39
msgid "NEPTUN" msgid "NEPTUN"
msgstr "NEPTUN" msgstr "NEPTUN"
#: templates/show-group.html:50 #: templates/show-group.html:51
msgid "Add owner" msgid "Add owner"
msgstr "Tulajdonos hozzáadása" msgstr "Tulajdonos hozzáadása"
#: templates/show-group.html:55 #: templates/show-group.html:56
msgid "Owner name/NEPTUN" msgid "Owner name/NEPTUN"
msgstr "Tulajdonos neve/NEPTUN-kódja" msgstr "Tulajdonos neve/NEPTUN-kódja"
#: templates/show-group.html:68 #: templates/show-group.html:69
msgid "This group has no shared templates." msgid "This group has no shared templates."
msgstr "Ennek a csoportnak egy sablon sincs megosztva." msgstr "Ennek a csoportnak egy sablon sincs megosztva."
#: templates/show-group.html:71 #: templates/show-group.html:72
msgid "Share one, and the group members can start their own virtual machine." msgid "Share one, and the group members can start their own virtual machine."
msgstr "" msgstr ""
"Osszon meg egyet, hogy a csoport tagjai is elindíthassák egy példányát." "Osszon meg egyet, hogy a csoport tagjai is elindíthassák egy példányát."
#: templates/box/group/box.html:7 #: templates/box/group/box.html:11 templates/box/person/box.html:11
msgid "Help"
msgstr "Segítség"
#: templates/box/group/box.html:14
msgid "This is the list of groups you own."
msgstr "Ez az ön csoportjainak felsorolása."
#: templates/box/group/box.html:15
msgid "Groups are collections of users."
msgstr "A csoportok felhasználók halmazai."
#: templates/box/group/box.html:16
msgid ""
"You can share templates with your groups, so\n"
" that they can run instances of those templates.\n"
" "
msgstr ""
"Megoszthatja a sablonokat csoportjaival, \n"
" így a tagok elindíthatják a sablonokból saját példányaikat.\n"
" "
#: templates/box/group/box.html:22 templates/box/person/box.html:21
msgid "Show/hide box"
msgstr "Doboz megjelenítése/rejtése"
#: templates/box/group/box.html:28
msgid "My Groups" msgid "My Groups"
msgstr "Saját csoportok" msgstr "Saját csoportok"
#: templates/box/group/box.html:19 #: templates/box/group/box.html:40
msgid "You have no groups." msgid "You have no groups."
msgstr "Nincs még csoportja." msgstr "Nincs még csoportja."
#: templates/box/group/box.html:21 #: templates/box/group/box.html:42
msgid "Create a new one, and add your students to the new group." msgid "Create a new one, and add your students to the new group."
msgstr "Hozzon létre egyet, és vegy fel hallgatóit." msgstr "Hozzon létre egyet, és vegy fel hallgatóit."
#: templates/box/group/box.html:29 #: templates/box/group/box.html:50
msgid "Show hidden groups" msgid "Show hidden groups"
msgstr "Elrejtett csoportok megjelenítése" msgstr "Elrejtett csoportok megjelenítése"
#: templates/box/group/box.html:35 templates/box/group/box.html.py:41 #: templates/box/group/box.html:56 templates/box/group/box.html.py:62
msgid "Create new group" msgid "Create new group"
msgstr "Új csoport létrehozása" msgstr "Új csoport létrehozása"
#: templates/box/group/box.html:44 #: templates/box/group/box.html:65
msgid "Group name" msgid "Group name"
msgstr "Csoport neve" msgstr "Csoport neve"
#: templates/box/group/box.html:48 templates/box/group/entry.html:42 #: templates/box/group/box.html:69 templates/box/group/entry.html:43
msgid "Semester" msgid "Semester"
msgstr "Félév" msgstr "Félév"
#: templates/box/group/box.html:56 #: templates/box/group/box.html:77
msgid "Members" msgid "Members"
msgstr "Tagok" msgstr "Tagok"
#: templates/box/group/box.html:57 #: templates/box/group/box.html:78
msgid "Student NEPTUN codes, one per line" msgid "Student NEPTUN codes, one per line"
msgstr "Hallgatók NEPTUN-kódja, soronként egy" msgstr "Hallgatók NEPTUN-kódja, soronként egy"
#: templates/box/group/box.html:62 #: templates/box/group/box.html:83
msgid "Cancel" msgid "Cancel"
msgstr "Mégsem" msgstr "Mégsem"
#: templates/box/group/box.html:63 #: templates/box/group/box.html:84
msgid "Done" msgid "Done"
msgstr "Kész" msgstr "Kész"
#: templates/box/group/entry.html:15 templates/box/group/entry.html.py:56 #: templates/box/group/entry.html:16 templates/box/group/entry.html.py:57
msgid "More details" msgid "More details"
msgstr "Részletek" msgstr "Részletek"
#: templates/box/group/entry.html:19 #: templates/box/group/entry.html:20
msgid "Delete" msgid "Delete"
msgstr "Törlés" msgstr "Törlés"
#: templates/box/group/entry.html:22 #: templates/box/group/entry.html:23
msgid "Hide" msgid "Hide"
msgstr "Elrejtés" msgstr "Elrejtés"
#: templates/box/group/entry.html:32 #: templates/box/group/entry.html:33
msgid "Course" msgid "Course"
msgstr "Tárgy" msgstr "Tárgy"
#: templates/box/group/entry.html:37 #: templates/box/group/entry.html:38
msgid "Not assigned" msgid "Not assigned"
msgstr "Nincs hozzárendelve" msgstr "Nincs hozzárendelve"
#: templates/box/group/entry.html:46 #: templates/box/group/entry.html:47
msgid "Owner(s)" msgid "Owner(s)"
msgstr "Tulajdonosok" msgstr "Tulajdonosok"
#: templates/box/group/entry.html:50 #: templates/box/group/entry.html:51
msgid "Member count" msgid "Member count"
msgstr "Tagok száma" msgstr "Tagok száma"
#: templates/box/person/box.html:7 #: templates/box/person/box.html:14
msgid "This is the list of this group's members."
msgstr "Ez a csoport tagjainak felsorolása."
#: templates/box/person/box.html:15
msgid ""
"Members are the people who can start new\n"
" instances of templates shared with the group.\n"
" "
msgstr ""
"A tagok azok a személyek, akik jogosultak a csoportnak\n"
" megosztott sablonok példányainak indítására.\n"
" "
#: templates/box/person/box.html:27
msgid "Members of" msgid "Members of"
msgstr "Tagok" msgstr "Tagok"
#: templates/box/person/box.html:17 templates/box/person/box.html.py:20 #: templates/box/person/box.html:37 templates/box/person/box.html.py:40
msgid "Add user" msgid "Add user"
msgstr "Felhasználó hozzáadása" msgstr "Felhasználó hozzáadása"
#: templates/box/person/box.html:19 #: templates/box/person/box.html:39
msgid "User NEPTUN code" msgid "User NEPTUN code"
msgstr "Felhasználó Neptun-kódja" msgstr "Felhasználó Neptun-kódja"
#~ msgid "Templates are customized versions of the base images."
#~ msgstr "A sablonok alaprendszerek testre szabott változatai."
#~ msgid ""
#~ "You can install all the needed software on a master\n"
#~ " machine, and it will be ready to run by your students in "
#~ "minutes.\n"
#~ " "
#~ msgstr ""
#~ "Telepítheti az összes szükséges szoftvert egy mestergépen, és az "
#~ "ígykészült sablon pár perc múltán készen is állhat a hallgatók számára."
#~ msgid "Templates" #~ msgid "Templates"
#~ msgstr "Sablonok" #~ msgstr "Sablonok"
......
{% extends "box/base/box.html" %} {% extends "box/base/box.html" %}
{% load i18n %} {% load i18n %}
{% load l10n %} {% load l10n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% block boxhelp %}
<div class="boxhelp">
<div class="help">
<div class="icon">
<img src="{% static "icons/information-frame.png" %}" alt="{% trans "Help" %}" />
</div>
<div class="boxhelp-box">
<p>{% blocktrans %}This is the list of groups you own.{% endblocktrans %}</p>
<p>{% blocktrans %}Groups are collections of users.{% endblocktrans %}</p>
<p>{% blocktrans %}You can share templates with your groups, so
that they can run instances of those templates.
{% endblocktrans %}</p>
</div>
</div>
<div class="icon">
<img src="" alt="toggle" title="{% trans "Show/hide box" %}" class="toggle-box" data-id="groups" id="toggle-box-groups"/>
</div>
</div>
{% endblock %}
{% block title %} {% block title %}
{% trans "My Groups" %} {% trans "My Groups" %}
{% endblock title %} {% endblock title %}
...@@ -36,7 +57,7 @@ ...@@ -36,7 +57,7 @@
<div class="clear"></div> <div class="clear"></div>
</div> </div>
<div id="new-group-wizard" style="display: none"> <div id="new-group-wizard" style="display: none">
<form action="/group/new/" method="POST" class="wizard"> <form action="{% url school.views.group_new %}" method="POST" class="wizard">
{% csrf_token %} {% csrf_token %}
<h3>{% trans "Create new group" %}</h3> <h3>{% trans "Create new group" %}</h3>
<ul> <ul>
......
{% extends "box/base/entry.html" %} {% extends "box/base/entry.html" %}
{% load i18n %} {% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% block content %} {% block content %}
...@@ -12,14 +13,14 @@ ...@@ -12,14 +13,14 @@
<div class="summary"> <div class="summary">
<div class="name"> <div class="name">
{{ group.name }} {{ group.name }}
<small class="details">(<a href="/group/show/{{group.id}}">{% trans "More details" %}</a>)</small> <small class="details">(<a href="{{ group.get_absolute_url }}">{% trans "More details" %}</a>)</small>
</div> </div>
<div class="actions"> <div class="actions">
<a href="#" class="delete" data-id="{{group.id}}" data-name="{{group.name}}"> <a href="#" class="delete" data-id="{{group.id}}" data-name="{{group.name}}">
<img src="/static/icons/minus-circle.png" alt="{% trans "Delete" %}" title="{% trans "Delete" %}" /> <img src="{% static "icons/minus-circle.png" %}" alt="{% trans "Delete" %}" title="{% trans "Delete" %}" />
</a> </a>
<a href="#" class="hide-group" data-id="{{group.id}}"> <a href="#" class="hide-group" data-id="{{group.id}}">
<img src="/static/icons/eye-half.png" alt="{% trans "Hide" %}" title="{% trans "Hide" %}" /> <img src="{% static "icons/eye-half.png" %}" alt="{% trans "Hide" %}" title="{% trans "Hide" %}" />
</a> </a>
</div> </div>
<div class="clear"></div> <div class="clear"></div>
...@@ -53,7 +54,7 @@ ...@@ -53,7 +54,7 @@
<li> <li>
&nbsp; &nbsp;
<span class="value"> <span class="value">
<a href="/group/show/{{group.id}}">{% trans "More details" %}</a> <a href="{{group.get_absolute_url}}">{% trans "More details" %}</a>
</span> </span>
</li> </li>
</ul> </ul>
......
{% extends "box/base/box.html" %} {% extends "box/base/box.html" %}
{% load i18n %} {% load i18n %}
{% load l10n %} {% load l10n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% block boxhelp %}
<div class="boxhelp">
<div class="help">
<div class="icon">
<img src="{% static "icons/information-frame.png" %}" alt="{% trans "Help" %}" />
</div>
<div class="boxhelp-box">
<p>{% blocktrans %}This is the list of this group's members.{% endblocktrans %}</p>
<p>{% blocktrans %}Members are the people who can start new
instances of templates shared with the group.
{% endblocktrans %}</p>
</div>
</div>
<div class="icon">
<img src="" alt="eye" title="{% trans "Show/hide box" %}" class="toggle-box" data-id="members" id="toggle-box-members"/>
</div>
</div>
{% endblock %}
{% block title %} {% block title %}
{% trans "Members of" %}: {{group.name}} {% trans "Members of" %}: {{group.name}}
{% endblock title %} {% endblock title %}
......
{% extends "box/base/entry.html" %} {% extends "box/base/entry.html" %}
{% load i18n %} {% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% block content %} {% block content %}
...@@ -19,7 +20,7 @@ ...@@ -19,7 +20,7 @@
</div> </div>
<div class="actions"> <div class="actions">
<a href="#" class="remove" data-gid="{{group.id}}" data-neptun="{{member.code}}"> <a href="#" class="remove" data-gid="{{group.id}}" data-neptun="{{member.code}}">
<img src="/static/icons/minus-circle.png" alt="{% trans 'Remove' %}" /> <img src="{% static "icons/minus-circle.png" %}" alt="{% trans 'Remove' %}" />
</a> </a>
</div> </div>
<div class="clear"></div> <div class="clear"></div>
......
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n %} {% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% block content %} {% block content %}
<div class="boxes"> <div class="boxes">
...@@ -19,7 +20,7 @@ ...@@ -19,7 +20,7 @@
</div> </div>
<!--<div class="actions"> <!--<div class="actions">
<a href="#" class="remove" data-gid="{{group.id}}" data-neptun="{{owner.code}}"> <a href="#" class="remove" data-gid="{{group.id}}" data-neptun="{{owner.code}}">
<img src="/static/icons/minus-circle.png" alt="{% trans 'Remove' %}" /> <img src="{% static "icons/minus-circle.png" %}" alt="{% trans 'Remove' %}" />
</a> </a>
</div>--> </div>-->
<div class="clear"></div> <div class="clear"></div>
......
...@@ -98,8 +98,10 @@ def login(request): ...@@ -98,8 +98,10 @@ def login(request):
co.save() co.save()
g.save() g.save()
try:
affiliation = request.META['affiliation'] affiliation = request.META['affiliation']
except KeyError:
affiliation = ''
if affiliation == '': if affiliation == '':
affiliation = [] affiliation = []
else: else:
......
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