Commit f6fdeffe by Őry Máté

Merge branch 'release-13.03.2' into releases

parents 0d188bd6 d9588334
...@@ -5,7 +5,7 @@ jsfiles += one/static/script/util.min.js ...@@ -5,7 +5,7 @@ jsfiles += one/static/script/util.min.js
jsfiles += one/static/script/store.min.js jsfiles += one/static/script/store.min.js
cssfiles += one/static/style/style.css cssfiles += one/static/style/style.css
default: migrate generatestatic collectstatic mo restart default: migrate generatestatic collectstatic mo setbranch restart
pulldef: pull default pulldef: pull default
pull: pull:
...@@ -23,6 +23,10 @@ generatestatic: $(jsfiles) $(cssfiles) ...@@ -23,6 +23,10 @@ generatestatic: $(jsfiles) $(cssfiles)
collectstatic: collectstatic:
./manage.py collectstatic --noinput ./manage.py collectstatic --noinput
setbranch:
sed -i cloud/local_settings.py -e '/RELEASE=/d' || true
echo "RELEASE='`git rev-parse --abbrev-ref HEAD`'" >>cloud/local_settings.py
mo: mo:
for i in */locale/*/*/*.po; do echo -ne "$$i:\t"; msgfmt --statistics $$i;done for i in */locale/*/*/*.po; do echo -ne "$$i:\t"; msgfmt --statistics $$i;done
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
......
from cloud.settings import DEBUG from cloud.settings import DEBUG, STAT_DEBUG, RELEASE
from django.core.cache import cache
import subprocess
import json
def process_debug(req): def process_debug(req):
return {'DEBUG': DEBUG} return {'DEBUG': DEBUG}
def process_stat(req):
if STAT_DEBUG:
stat = {
'CPU': {
'USED_CPU': 10,
'ALLOC_CPU': 20,
'FREE_CPU': 70
},
'MEM': {
'USED_MEM': 567,
'ALLOC_MEM': 371,
'FREE_MEM': 2048-567-371
}
}
else:
stat = cache.get('cloud_stat')
return {
'STAT_DEBUG': STAT_DEBUG,
'cloud_stat': stat,
}
def process_release(req):
return {
'release': RELEASE,
}
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
DEBUG = True DEBUG = True
TEMPLATE_DEBUG = DEBUG TEMPLATE_DEBUG = DEBUG
STAT_DEBUG = True
ADMINS = ( ADMINS = (
('IK', 'cloud@cloud.ik.bme.hu'), ('IK', 'cloud@cloud.ik.bme.hu'),
...@@ -119,6 +120,8 @@ TEMPLATE_CONTEXT_PROCESSORS = ( ...@@ -119,6 +120,8 @@ TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.tz', 'django.core.context_processors.tz',
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'cloud.context_processors.process_debug', 'cloud.context_processors.process_debug',
'cloud.context_processors.process_stat',
'cloud.context_processors.process_release',
) )
TEMPLATE_DIRS = ( TEMPLATE_DIRS = (
...@@ -200,8 +203,17 @@ CELERY_ROUTES = { ...@@ -200,8 +203,17 @@ CELERY_ROUTES = {
'firewall.tasks.reload_blacklist_task': {'queue': 'firewall'}, 'firewall.tasks.reload_blacklist_task': {'queue': 'firewall'},
'firewall.tasks.Periodic': {'queue': 'local'}, 'firewall.tasks.Periodic': {'queue': 'local'},
'one.tasks.SendMailTask': {'queue': 'local'}, 'one.tasks.SendMailTask': {'queue': 'local'},
'one.tasks.UpdateInstanceStateTask': {'queue': 'local'}
} }
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
store_settings = { store_settings = {
"basic_auth": "True", "basic_auth": "True",
"verify_ssl": "False", "verify_ssl": "False",
...@@ -225,6 +237,7 @@ firewall_settings = { ...@@ -225,6 +237,7 @@ firewall_settings = {
EMAIL_HOST='152.66.243.92' # giccero ipv4 EMAIL_HOST='152.66.243.92' # giccero ipv4
CLOUD_URL='https://cloud.ik.bme.hu/' CLOUD_URL='https://cloud.ik.bme.hu/'
RELEASE='master'
try: try:
from cloud.local_settings import * from cloud.local_settings import *
......
{% extends "base.html" %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
<div class="irasmu">
<h2>Változtatások listája</h2>
<section>
<p>Az IK Cloud fejlesztése kéthetes ciklusokban történik, az rendes kiadások élesítése
páros heteken csütörtök este zajlik. Alább foglaljuk össze az egyes
kiadások főbb, a felhasználók által is látható változtatásait.</p>
</section>
<a id="master"></a>
<section>
<h3 id="release-13.03.2"><a href="#13.03.2">13.03.2 (2013. március 21.)</a></h3>
<ul>
<li>Súgó.</li>
<li>Változáslista.</li>
<li>Reszponzív és folyékony elrendezés.</li>
<li>Statikus oldalak új külalakja.</li>
<li>Gyorsabb oldalbetöltés.</li>
<li>Statisztika a cluster állapotáról.</li>
</ul>
</section>
<section>
<h3 id="release-13.03.1"><a href="#13.03.1">13.03.1 (2013. március 7.)</a></h3>
<ul>
<li>Határidős felfüggesztés élesítve.</li>
<li>Csatlakozási adatoknál IP cím helyett DNS név jelenik meg.</li>
<li>Ha a portált IPV6-on érik el, a csatlakozási adatoknál egyedi DNS név és publikus port jelenik meg.</li>
<li>Legújabb fájloktól vissza lehet lépni az összeshez.</li>
<li>Bemutató képernyő elérhető bejelentkezve is.</li>
<li>Megosztás adatai szerkeszthetőek.</li>
<li>Sablon adatai szerkeszthetőek.</li>
<li>Lábléc; impresszum, szabályzat, támogatás oldalak.</li>
<li>Megosztásnál is látszik a géptípus.</li>
<li>Dobozok rejthetőek.</li>
<li>Sablon mentésének menete gördülékenyebb.</li>
<li>Jelszómegjelenítés javítva.</li>
<li>Fájlok rendezése működik.</li>
<li>Segítség-dobozok bővítve.</li>
<li>Szebb HTTP hibaüzenetek.</li>
<li>Kulcs hozzáadásának visszaigazolása.</li>
<li>Sablonok állapotának helyes kijelzése.</li>
<li>Minimalizált js és css kód.</li>
</ul>
</section>
<section>
<h3 id="release-13.02.2"><a href="#13.02.2">13.02.2 (2013. február 21.)</a></h3>
<ul>
<li>Felhasználói kvóták megvalósítása.</li>
<li>Publikus kulcsok kezelése.</li>
<li>További részletek gombok.</li>
<li>Saját csoportok rejthetőek.</li>
<li>Segítség-dobozok a legtöbb helyre.</li>
<li>Csoporttulajdonosok kezelése, több adat megjelenítése.</li>
<li>VM átnevezhető.</li>
</ul>
</section>
</div>
{% endblock %}
...@@ -5,10 +5,15 @@ ...@@ -5,10 +5,15 @@
{% block content %} {% block content %}
<div class="irasmu"> <div class="irasmu">
<h2>Impresszum</h2>
<section>
<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>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>
</section>
<section>
<p>Az oldal üzemeltetője a BME Közigazgatási Informatikai Központ.</p> <p>Az oldal üzemeltetője a BME Közigazgatási Informatikai Központ.</p>
<p>A rendszer fejlesztésében részt vettek: <p>A rendszer fejlesztésében részt vettek:
Bach Dániel, Bach Dániel,
Dányi Bence, Dányi Bence,
Dudás Ádám, Dudás Ádám,
...@@ -17,6 +22,7 @@ ...@@ -17,6 +22,7 @@
dr. Szeberényi Imre.</p> 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>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> <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>
</section>
</div> </div>
{% endblock %} {% endblock %}
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
{% block content %} {% block content %}
<div class="irasmu"> <div class="irasmu">
<h2>Felhasználási feltételek</h2>
<section>
<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 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>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>
...@@ -14,11 +16,15 @@ ...@@ -14,11 +16,15 @@
<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>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>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>
</section>
<section>
<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 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>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>
</section>
<section>
<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> <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> <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>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>
...@@ -29,6 +35,7 @@ ...@@ -29,6 +35,7 @@
<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> <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> </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> <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>
</section>
</div> </div>
{% endblock %} {% endblock %}
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
{% block content %} {% block content %}
<div class="irasmu"> <div class="irasmu">
<h2>Támogatás</h2>
<section>
<p>A rendszer használatával kapcsolatos kérdéseket, általános észrevételeket a <tt>cloud <em>(kukac)</em> <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. ik.bme.hu</tt> e-mail címen várjuk.
Ugyancsak örömmel fogadjuk a rendszer használatával kapcsolatos beszámolókat.</p> Ugyancsak örömmel fogadjuk a rendszer használatával kapcsolatos beszámolókat.</p>
...@@ -12,5 +14,7 @@ ...@@ -12,5 +14,7 @@
<a href="https://giccero.cloud.ik.bme.hu/trac/cloud/newticket" rel="nofollow"> <a href="https://giccero.cloud.ik.bme.hu/trac/cloud/newticket" rel="nofollow">
hibajegy felvételével</a> jelezze. hibajegy felvételével</a> jelezze.
</p> </p>
</section>
</div> </div>
{% endblock %} {% endblock %}
#!/usr/bin/env python
from celery import Celery, task
import subprocess
import time, re
import socket
import sys
BROKER_URL = 'amqp://nyuszi:teszt@localhost:5672/django'
try:
from local_settings import *
except:
pass
CELERY_CREATE_MISSING_QUEUES=True
celery = Celery('tasks', broker=BROKER_URL)
def main(argv):
celery.send_task('one.tasks.UpdateInstanceStateTask', [ int(sys.argv[1]),
], queue='local')
if __name__ == "__main__":
main(sys.argv)
...@@ -5,8 +5,16 @@ echo "En vagyok a $0 !" ...@@ -5,8 +5,16 @@ echo "En vagyok a $0 !"
arr=( $((echo 'ibase=16' ; ifconfig eth0 | awk '/HWaddr/ {print $5}' | tr ':a-z' '\nA-Z') | bc ) ) arr=( $((echo 'ibase=16' ; ifconfig eth0 | awk '/HWaddr/ {print $5}' | tr ':a-z' '\nA-Z') | bc ) )
ipv4="${arr[2]}.${arr[3]}.${arr[4]}.${arr[5]}" ipv4="${arr[2]}.${arr[3]}.${arr[4]}.${arr[5]}"
gw4="${arr[2]}.${arr[3]}.255.254" gw4="${arr[2]}.${arr[3]}.255.254"
net4="255.255.0.0"
ipv6="2001:738:2001:4031:${arr[3]}:${arr[4]}:${arr[5]}:0" ipv6="2001:738:2001:4031:${arr[3]}:${arr[4]}:${arr[5]}:0"
gw6="2001:738:2001:4031:${arr[3]}:255:254:0" gw6="2001:738:2001:4031:${arr[3]}:255:254:0"
net6="80"
if [ "${arr[2]}" == "152" ]; then
gw4="${arr[2]}.${arr[3]}.243.126"
net4="255.255.255.192"
gw6="2001:738:2001:4031:66:243:126:0"
fi
echo ok "$ipv4 $ipv6 $gw4 $gw6" echo ok "$ipv4 $ipv6 $gw4 $gw6"
...@@ -20,12 +28,12 @@ iface lo inet loopback ...@@ -20,12 +28,12 @@ iface lo inet loopback
auto eth0 auto eth0
iface eth0 inet static iface eth0 inet static
address $ipv4 address $ipv4
netmask 255.255.0.0 netmask $net4
gateway $gw4 gateway $gw4
dns-nameservers 152.66.243.60 dns-nameservers 152.66.243.60
iface eth0 inet6 static iface eth0 inet6 static
address $ipv6 address $ipv6
netmask 80 netmask $net6
gateway $gw6 gateway $gw6
EOF EOF
...@@ -46,10 +54,10 @@ DNS1="152.66.243.60" ...@@ -46,10 +54,10 @@ DNS1="152.66.243.60"
PEERDNS="yes" PEERDNS="yes"
IPADDR="$ipv4" IPADDR="$ipv4"
NETMASK="255.255.0.0" NETMASK="$net4"
GATEWAY=$gw4 GATEWAY=$gw4
IPV6ADDR="$ipv6/80" IPV6ADDR="$ipv6/$net6"
IPV6_DEFAULTGW="$gw6" IPV6_DEFAULTGW="$gw6"
EOF EOF
......
...@@ -6,12 +6,13 @@ do ...@@ -6,12 +6,13 @@ do
sudo stop $i || true sudo stop $i || true
done done
sudo apt-get install rabbitmq-server gettext sudo apt-get install rabbitmq-server gettext memcached
sudo rabbitmqctl delete_user guest || true sudo rabbitmqctl delete_user guest || true
sudo rabbitmqctl add_user nyuszi teszt || true sudo rabbitmqctl add_user nyuszi teszt || true
sudo rabbitmqctl add_vhost django || true sudo rabbitmqctl add_vhost django || true
sudo rabbitmqctl set_permissions -p django nyuszi '.*' '.*' '.*' || true sudo rabbitmqctl set_permissions -p django nyuszi '.*' '.*' '.*' || true
sudo pip install python-memcached
sudo cp /opt/webadmin/cloud/miscellaneous/devenv/boot_url.py /opt/ sudo cp /opt/webadmin/cloud/miscellaneous/devenv/boot_url.py /opt/
......
#!/bin/bash
# install xml.vim
mkdir -p ~/.vim/{ftplugin,indent}
cd ~/.vim
wget 'http://www.vim.org/scripts/download_script.php?src_id=16073' -O ftplugin/xml.vim
echo 'let b:did_indent = 1' > indent/xml.vim
for i in docbk xsl html xhtml
do
ln -s xml.vim ftplugin/$i.vim
echo 'let b:did_indent = 1' > indent/$i.vim
done
\documentclass[12pt,a4paper]{article}
\title{Harnessing Wasted Computing Power for Scientific Computing}
\author{S\'andor Guba, M\'at\'e \H{O}ry and Imre Szeber\'enyi\\
Budapest University of Technology and Economics, %\\
%Magyar Tud\'osok k\"or\'utja 2, H-1117 Budapest,
Hungary}
\date{\empty}
\begin{document}
\maketitle
Nowadays more and more general purpose workstations installed in a student
laboratory have built in multi-core CPU and graphics card providing significant
computing power. In most cases the utilization of these resources is low, and
limited to lecture hours. The concept of utility computing plays an important
role in nowadays technological development. As part of utility computing, cloud
computing offers greater flexibility and responsiveness to ICT users at lower
cost.
In  this paper, we introduce a cloud management system which enables the
simultaneous use of both dedicated resources and opportunistic environment. All
the free workstations (powered or not) are automatically added to a resource
pool, and can be used like ordinary cloud resources. Researchers can launch
various virtualized software appliances. Our solution leverages the advantages
of HTCondor and OpenNebula systems.
Modern graphics processing units (GPUs) with many-core architectures have
emerged as general-purpose parallel computing platforms that can dramatically
accelerate  scientific applications used for various simulations. Our business
model harnesses computing power of GPUs as well, using the needed amount of
unused machines. This makes the infrastructure flexible and power efficient.
Our pilot infrastructure consist of a high performance cluster and 28
workstations with dual-core CPUs and dedicated graphics cards. Altogether we
can use 10,752 CUDA cores through the network.
\end{document}
% clmomu01.ind
%-----------------------------------------------------------------------
% CLMoMu01 1.0: LaTeX style files for books
% Sample index file for User's guide
% (c) Springer-Verlag HD
%-----------------------------------------------------------------------
\begin{theindex}
\item Absorption\idxquad 327
\item Absorption of radiation \idxquad 289--292,\, 299,\,300
\item Actinides \idxquad 244
\item Aharonov-Bohm effect\idxquad 142--146
\item Angular momentum\idxquad 101--112
\subitem algebraic treatment\idxquad 391--396
\item Angular momentum addition\idxquad 185--193
\item Angular momentum commutation relations\idxquad 101
\item Angular momentum quantization\idxquad 9--10,\,104--106
\item Angular momentum states\idxquad 107,\,321,\,391--396
\item Antiquark\idxquad 83
\item $\alpha$-rays\idxquad 101--103
\item Atomic theory\idxquad 8--10,\,219--249,\,327
\item Average value\newline ({\it see also\/} Expectation value)
15--16,\,25,\,34,\,37,\,357
\indexspace
\item Baker-Hausdorff formula\idxquad 23
\item Balmer formula\idxquad 8
\item Balmer series\idxquad 125
\item Baryon\idxquad 220,\,224
\item Basis\idxquad 98
\item Basis system\idxquad 164,\,376
\item Bell inequality\idxquad 379--381,\,382
\item Bessel functions\idxquad 201,\,313,\,337
\subitem spherical\idxquad 304--306,\, 309,\, 313--314,\,322
\item Bound state\idxquad 73--74,\,78--79,\,116--118,\,202,\, 267,\,
273,\,306,\,348,\,351
\item Boundary conditions\idxquad 59,\, 70
\item Bra\idxquad 159
\item Breit-Wigner formula\idxquad 80,\,84,\,332
\item Brillouin-Wigner perturbation theory\idxquad 203
\indexspace
\item Cathode rays\idxquad 8
\item Causality\idxquad 357--359
\item Center-of-mass frame\idxquad 232,\,274,\,338
\item Central potential\idxquad 113--135,\,303--314
\item Centrifugal potential\idxquad 115--116,\,323
\item Characteristic function\idxquad 33
\item Clebsch-Gordan coefficients\idxquad 191--193
\item Cold emission\idxquad 88
\item Combination principle, Ritz's\idxquad 124
\item Commutation relations\idxquad 27,\,44,\,353,\,391
\item Commutator\idxquad 21--22,\,27,\,44,\,344
\item Compatibility of measurements\idxquad 99
\item Complete orthonormal set\idxquad 31,\,40,\,160,\,360
\item Complete orthonormal system, {\it see}\newline
Complete orthonormal set
\item Complete set of observables, {\it see\/} Complete
set of operators
\indexspace
\item Eigenfunction\idxquad 34,\,46,\,344--346
\subitem radial\idxquad 321
\subsubitem calculation\idxquad 322--324
\item EPR argument\idxquad 377--378
\item Exchange term\idxquad 228,\,231,\,237,\,241,\,268,\,272
\indexspace
\item $f$-sum rule\idxquad 302
\item Fermi energy\idxquad 223
\indexspace
\item H$^+_2$ molecule\idxquad 26
\item Half-life\idxquad 65
\item Holzwarth energies\idxquad 68
\end{theindex}
from one.models import *
from django_extensions.management.jobs import QuarterHourlyJob
from django.core.cache import cache
import json
class Job(QuarterHourlyJob):
help = "Update statistics from OpenNebula."
def execute(self):
stat = json.loads(subprocess.check_output(['/opt/webadmin/cloud/miscellaneous/stat/stat_wrap.sh']))
cache.set('cloud_stat', stat)
...@@ -6,7 +6,7 @@ msgid "" ...@@ -6,7 +6,7 @@ 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-03-07 18:16+0100\n" "POT-Creation-Date: 2013-03-22 10:43+0100\n"
"PO-Revision-Date: 2013-03-07 17:02+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"
...@@ -17,18 +17,17 @@ msgstr "" ...@@ -17,18 +17,17 @@ 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.min.js:1 #: static/script/cloud.js:24
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:296 #: static/script/cloud.js:24 static/script/cloud.js.c:301
#: static/script/cloud.js:370 static/script/cloud.js.c:623 #: static/script/cloud.js:373 static/script/cloud.js.c:600
#: static/script/cloud.min.js:1 static/script/store.js:288 #: 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.min.js:1 #: static/script/cloud.js:36
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!"
...@@ -36,96 +35,92 @@ msgstr "" ...@@ -36,96 +35,92 @@ msgstr ""
"Biztosan újragenerálja az adattár-kulcsait?<br /> El fogja veszteni az " "Biztosan újragenerálja az adattár-kulcsait?<br /> 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.min.js:1 #: static/script/cloud.js:36
msgid "Reset" msgid "Reset"
msgstr "Újragenerálás" msgstr "Újragenerálás"
#: static/script/cloud.js:75 static/script/cloud.min.js:1 #: static/script/cloud.js:76 static/script/store.js:323
#: 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:271 static/script/cloud.min.js:1 #: static/script/cloud.js:276 static/script/store.js:288
#: 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:285 static/script/cloud.min.js:1 #: static/script/cloud.js:290
#, 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:286 static/script/cloud.min.js:1 #: static/script/cloud.js:291
msgid "Stop" msgid "Stop"
msgstr "Felfüggesztés" msgstr "Felfüggesztés"
#: static/script/cloud.js:295 static/script/cloud.min.js:1 #: static/script/cloud.js:300
#, 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:305 static/script/cloud.min.js:1 #: static/script/cloud.js:310
#, 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:306 static/script/cloud.min.js:1 #: static/script/cloud.js:311
msgid "Restart" msgid "Restart"
msgstr "Újraindítás" msgstr "Újraindítás"
#: static/script/cloud.js:369 static/script/cloud.min.js:1 #: static/script/cloud.js:372
#, 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:547 static/script/cloud.js.c:550 #: static/script/cloud.js:551 static/script/cloud.js.c:554
#: 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:550 static/script/cloud.min.js:1 #: static/script/cloud.js:554
msgid "Unknown" msgid "Unknown"
msgstr "Ismeretlen" msgstr "Ismeretlen"
#: static/script/cloud.js:623 static/script/cloud.min.js:1 #: static/script/cloud.js:600
#, 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:52 static/script/store.js.c:61 #: static/script/store.js:52 static/script/store.js.c:61
#: static/script/store.js:70 static/script/store.js.c:220 #: static/script/store.js:70 static/script/store.js.c:220
#: static/script/store.js:282 static/script/store.min.js:1 #: static/script/store.js:282
msgid "file" msgid "file"
msgstr "fájl" msgstr "fájl"
#: static/script/store.js:125 static/script/store.min.js:1 #: static/script/store.js:125
msgid "Toplist" msgid "Toplist"
msgstr "Legújabb fájlok" msgstr "Legújabb fájlok"
#: static/script/store.js:127 static/script/store.min.js:1 #: static/script/store.js:127
msgid "Back to the root folder" msgid "Back to the root folder"
msgstr "Vissza a gyökérmappába" msgstr "Vissza a gyökérmappába"
#: static/script/store.js:283 static/script/store.min.js:1 #: static/script/store.js:283
#, 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:285 static/script/store.min.js:1 #: static/script/store.js:285
#, 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:288 static/script/store.min.js:1 #: static/script/store.js:288
msgid "Are you sure?" msgid "Are you sure?"
msgstr "Biztos benne?" msgstr "Biztos benne?"
#: static/script/store.js:446 static/script/store.js.c:448 #: 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:448 static/script/store.min.js:1 #: static/script/store.js:448
msgid "done, processing..." msgid "done, processing..."
msgstr "kész, feldolgozás..." msgstr "kész, feldolgozás..."
......
...@@ -18,6 +18,7 @@ from firewall.models import Host, Rule, Vlan, Record ...@@ -18,6 +18,7 @@ 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
from cloud.settings import CLOUD_URL
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
pwgen = User.objects.make_random_password pwgen = User.objects.make_random_password
...@@ -487,7 +488,8 @@ class Instance(models.Model): ...@@ -487,7 +488,8 @@ class Instance(models.Model):
"""Submit a new instance to OpenNebula.""" """Submit a new instance to OpenNebula."""
from django.template.defaultfilters import escape from django.template.defaultfilters import escape
out = "" out = ""
inst = Instance(pw=pwgen(), template=template, owner=owner, share=share) inst = Instance(pw=pwgen(), template=template, owner=owner,
share=share, state='PENDING')
inst.save() inst.save()
hostname = u"cloud-%d" % (inst.id, ) hostname = u"cloud-%d" % (inst.id, )
with tempfile.NamedTemporaryFile(delete=False) as f: with tempfile.NamedTemporaryFile(delete=False) as f:
...@@ -529,7 +531,7 @@ class Instance(models.Model): ...@@ -529,7 +531,7 @@ class Instance(models.Model):
"smbpw": escape(details.smb_password), "smbpw": escape(details.smb_password),
"sshkey": escape(details.ssh_private_key), "sshkey": escape(details.ssh_private_key),
"neptun": escape(owner.username), "neptun": escape(owner.username),
"booturl": "https://cloud.ik.bme.hu/b/%s/" % token, "booturl": "%sb/%s/" % ( CLOUD_URL, token ),
"extra": extra} "extra": extra}
f.write(tpl) f.write(tpl)
f.close() f.close()
...@@ -551,7 +553,6 @@ class Instance(models.Model): ...@@ -551,7 +553,6 @@ class Instance(models.Model):
{'neptun': owner.username, 'template': template.name, {'neptun': owner.username, 'template': template.name,
'id': inst.one_id}) 'id': inst.one_id})
inst.save() inst.save()
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) owner=owner)
host.hostname = hostname host.hostname = hostname
...@@ -618,17 +619,23 @@ class Instance(models.Model): ...@@ -618,17 +619,23 @@ class Instance(models.Model):
def _change_state(self, new_state): def _change_state(self, new_state):
"""Change host state in OpenNebula.""" """Change host state in OpenNebula."""
self._update_vm("<STATE>" + new_state + "</STATE>") self._update_vm("<STATE>" + new_state + "</STATE>")
self.waiting = True
self.save()
def stop(self): def stop(self):
self._change_state("STOPPED") self._change_state("STOPPED")
self.waiting = True
self.save()
def resume(self): def resume(self):
self._change_state("RESUME") self._change_state("RESUME")
def poweroff(self): def poweroff(self):
self._change_state("POWEROFF") self._change_state("POWEROFF")
def restart(self): def restart(self):
self._change_state("RESET") self._change_state("RESET")
self.waiting = False
self.save()
def renew(self, which='both'): def renew(self, which='both'):
if which in ['suspend', 'both']: if which in ['suspend', 'both']:
self.time_of_suspend = self.share.get_type()['suspendx'] self.time_of_suspend = self.share.get_type()['suspendx']
...@@ -637,12 +644,12 @@ class Instance(models.Model): ...@@ -637,12 +644,12 @@ class Instance(models.Model):
if not (which in ['suspend', 'delete', 'both']): 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):
"""Save image and shut down.""" """Save image and shut down."""
imgname = "template-%d-%d" % (self.template.id, self.id) imgname = "template-%d-%d" % (self.template.id, self.id)
self._update_vm('<DISK id="0"><SAVE_AS name="%s"/></DISK>' % imgname) self._update_vm('<DISK id="0"><SAVE_AS name="%s"/></DISK>' % imgname)
self._change_state("SHUTDOWN") self._change_state("SHUTDOWN")
self.waiting = True
self.save() self.save()
t = self.template t = self.template
t.state = 'SAVING' t.state = 'SAVING'
......
...@@ -15,7 +15,7 @@ $(function() { ...@@ -15,7 +15,7 @@ $(function() {
$('.delete-template').click(function(e) { $('.delete-template').click(function(e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
delete_template_confirm($(this).data('id'), $(this).data('name')); delete_template_confirm($(this).data('url'), $(this).data('id'), $(this).data('name'));
}); });
$('.delete-key').click(function(e) { $('.delete-key').click(function(e) {
var id = $(this).data('id'); var id = $(this).data('id');
...@@ -25,7 +25,7 @@ $(function() { ...@@ -25,7 +25,7 @@ $(function() {
$.ajax({ $.ajax({
'type': 'POST', 'type': 'POST',
'data': 'id=' + id, 'data': 'id=' + id,
'url': '/ajax/key/delete/', 'url': $(this).data('url'),
'success': function() { 'success': function() {
$('#key-' + id).slideUp(700); $('#key-' + id).slideUp(700);
} }
...@@ -36,7 +36,7 @@ $(function() { ...@@ -36,7 +36,7 @@ $(function() {
vm_confirm_popup(gettext('Are you sure about reseting store credentials?<br /> You will lose your access to your store account on your existing virtual machines!'), gettext('Reset'), function() { vm_confirm_popup(gettext('Are you sure about reseting store credentials?<br /> You will lose your access to your store account on your existing virtual machines!'), gettext('Reset'), function() {
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: '/ajax/key/reset/', url: $(this).data('url'),
success: function() { success: function() {
window.location.reload(); window.location.reload();
} }
...@@ -63,6 +63,7 @@ $(function() { ...@@ -63,6 +63,7 @@ $(function() {
var oldName = $(this).data('name'); var oldName = $(this).data('name');
var content = $('#vm-' + id + '-name').html(); var content = $('#vm-' + id + '-name').html();
var self=this; var self=this;
var url = $(this).data('url');
$(this).unbind('click').click(function(e){ $(this).unbind('click').click(function(e){
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
...@@ -72,7 +73,7 @@ $(function() { ...@@ -72,7 +73,7 @@ $(function() {
}) })
$('#vm-' + id + '-name-details').hide(); $('#vm-' + id + '-name-details').hide();
$('#vm-' + id + '-name').html('<input type="text" value="' + oldName + '" />\ $('#vm-' + id + '-name').html('<input type="text" value="' + oldName + '" />\
<input type="submit" value="' + gettext('Rename') + '" />'); <input type="submit" value="' + gettext('Rename') + '" data-url="'+url+'"/>');
$('#vm-' + id + '-name').find('input[type="text"]').click(function(f) { $('#vm-' + id + '-name').find('input[type="text"]').click(function(f) {
f.preventDefault(); f.preventDefault();
f.stopPropagation(); f.stopPropagation();
...@@ -85,7 +86,7 @@ $(function() { ...@@ -85,7 +86,7 @@ $(function() {
type: 'POST', type: 'POST',
data: 'name=' + newName, data: 'name=' + newName,
dataType: 'json', dataType: 'json',
url: '/ajax/vm/rename/' + id + '/', url: $(this).data('url'),
success: function(data) { success: function(data) {
$('#vm-' + id + '-name-details').removeAttr('style'); $('#vm-' + id + '-name-details').removeAttr('style');
$('#vm-' + id + '-name').text(data.name); $('#vm-' + id + '-name').text(data.name);
...@@ -97,7 +98,7 @@ $(function() { ...@@ -97,7 +98,7 @@ $(function() {
$('.try-template').click(function(e) { $('.try-template').click(function(e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
new_vm($(this).data('id')); new_vm($(this).data('url'));
}); });
$('.stop-vm').click(function(e) { $('.stop-vm').click(function(e) {
e.preventDefault(); e.preventDefault();
...@@ -135,7 +136,7 @@ $(function() { ...@@ -135,7 +136,7 @@ $(function() {
$('#modal-container .entry .summary').click(toggleDetails); $('#modal-container .entry .summary').click(toggleDetails);
}); });
$('#new-template-button').click(function() { $('#new-template-button').click(function() {
$.get('/ajax/templateWizard', function(data) { $.get($(this).data('url'), function(data) {
$('#modal-container').html(data); $('#modal-container').html(data);
}) })
$('#modal').show(); $('#modal').show();
...@@ -146,7 +147,7 @@ $(function() { ...@@ -146,7 +147,7 @@ $(function() {
var id=$(this).data('id'); var id=$(this).data('id');
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
url: '/ajax/templateEditWizard/'+id+'/', url: $(this).data('url'),
success: function(data){ success: function(data){
$('#modal').show(); $('#modal').show();
$('#modal-container').html(data); $('#modal-container').html(data);
...@@ -192,7 +193,11 @@ $(function() { ...@@ -192,7 +193,11 @@ $(function() {
$('#modal-container').html(content); $('#modal-container').html(content);
$('#shadow').click(function() { $('#shadow').click(function() {
$('#new-group-wizard').html(content); $('#new-group-wizard').html(content);
}) });
$('#modal .prev').click(function() {
$('#modal').hide();
$('#new-group-wizard').html(content);
});
function updateSummary() { function updateSummary() {
$('#new-group-summary-name').html($('#new-group-name').val()); $('#new-group-summary-name').html($('#new-group-name').val());
...@@ -210,8 +215,8 @@ $(function() { ...@@ -210,8 +215,8 @@ $(function() {
if ($(this).attr('type') == 'password') { if ($(this).attr('type') == 'password') {
$(this).attr('type', 'text'); $(this).attr('type', 'text');
$(this).addClass('shown'); $(this).addClass('shown');
this.select();
} else if (this.selectionStart - this.selectionEnd == 0) { } else if (this.selectionStart - this.selectionEnd == 0) {
$(this).attr('type', 'password'); $(this).attr('type', 'password');
$(this).removeClass('shown'); $(this).removeClass('shown');
} }
...@@ -235,7 +240,7 @@ $(function() { ...@@ -235,7 +240,7 @@ $(function() {
e.stopPropagation(); e.stopPropagation();
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
url: '/ajax/shareEdit/' + $(this).data('id') + '/', url: $(this).data('url'),
success: function(data) { success: function(data) {
$('#modal').show(); $('#modal').show();
$('#modal-container').html(data); $('#modal-container').html(data);
...@@ -349,13 +354,11 @@ $(function() { ...@@ -349,13 +354,11 @@ $(function() {
* New VM * New VM
*/ */
function new_vm(template_id) { function new_vm(url) {
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: '/ajax/vm/new/' + template_id + '/', url: url,
success: function(data, b, xhrRequest) { success: function(data, b, xhrRequest) {
window.location.href = '/'; //xhrRequest.getResponseHeader("Location");
//alert(xhrRequest.getResponseHeader("Location"));
window.location.href = xhrRequest.getResponseHeader("Location"); window.location.href = xhrRequest.getResponseHeader("Location");
} }
}) })
...@@ -365,7 +368,7 @@ $(function() { ...@@ -365,7 +368,7 @@ $(function() {
* Template delete * Template delete
*/ */
function delete_template_confirm(id, name) { function delete_template_confirm(url, id, name) {
confirm_message = interpolate(gettext("Are you sure deleting this %s template?"), ["<strong>" + name + "</strong>"]) confirm_message = interpolate(gettext("Are you sure deleting this %s template?"), ["<strong>" + name + "</strong>"])
vm_confirm_popup(confirm_message, gettext("Delete"), function() { vm_confirm_popup(confirm_message, gettext("Delete"), function() {
delete_template(id) delete_template(id)
...@@ -375,10 +378,10 @@ $(function() { ...@@ -375,10 +378,10 @@ $(function() {
* Template delete * Template delete
*/ */
function delete_template(id) { function delete_template(url, id) {
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: '/ajax/template/delete/', url: url,
data: 'id=' + id, data: 'id=' + id,
dataType: 'json', dataType: 'json',
statusCode: { statusCode: {
...@@ -508,7 +511,7 @@ $(function() { ...@@ -508,7 +511,7 @@ $(function() {
var neptun = $(this).prev().val(); var neptun = $(this).prev().val();
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: '/ajax/group/' + $(this).data('id') + '/add/', url: $(this).data('url'),
data: 'neptun=' + neptun, data: 'neptun=' + neptun,
dataType: 'json', dataType: 'json',
success: function(data) { success: function(data) {
...@@ -530,13 +533,14 @@ $(function() { ...@@ -530,13 +533,14 @@ $(function() {
var timer; var timer;
return function(e) { return function(e) {
var val = $(this).val().split(' ')[0]; var val = $(this).val().split(' ')[0];
var that = this;
clearTimeout(timer); clearTimeout(timer);
timer = setTimeout(function() { timer = setTimeout(function() {
if (val.length < 1) return; if (val.length < 1) return;
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
data: 'q=' + val, data: 'q=' + val,
url: '/ajax/group/autocomplete/', url: $(that).data('url'),
dataType: 'json', dataType: 'json',
success: function(data) { success: function(data) {
console.log(data); console.log(data);
...@@ -571,21 +575,6 @@ $(function() { ...@@ -571,21 +575,6 @@ $(function() {
e.stopPropagation(); e.stopPropagation();
} }
}()); }());
$('#new-owner-form input[type=submit]').click(function() {
var neptun = $(this).prev().val();
$.ajax({
type: 'POST',
url: '/ajax/group/' + $(this).data('id') + '/add/',
data: 'neptun=' + neptun,
dataType: 'json',
success: function(data) {
window.location.reload();
}
}).error(function(data) {
//TODO: fancy modal alert
alert(JSON.parse(data.responseText).status);
})
});
$('#group-members .remove').click(function(e) { $('#group-members .remove').click(function(e) {
e.preventDefault(); e.preventDefault();
...@@ -593,37 +582,25 @@ $(function() { ...@@ -593,37 +582,25 @@ $(function() {
var neptun = $(this).data('neptun'); var neptun = $(this).data('neptun');
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: '/ajax/group/' + $(this).data('gid') + '/remove/', url: $(this).data('url'),
data: 'neptun=' + neptun, data: 'neptun=' + neptun,
success: function(data) { success: function(data) {
$('#member-' + neptun).slideUp(700); $('#member-' + neptun).slideUp(700);
} }
}); });
}); });
/*$('#group-owners .remove').click(function(e) {
e.preventDefault();
e.stopPropagation();
var neptun = $(this).data('neptun');
$.ajax({
type: 'POST',
url: '/ajax/group/' + $(this).data('gid') + '/remove/',
data: 'neptun=' + neptun,
success: function(data) {
$('#member-' + neptun).slideUp(700);
}
});
});*/
$('#groups .delete').click(function(e) { $('#groups .delete').click(function(e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
var gid = $(this).data('id'); var gid = $(this).data('id');
var name = $(this).data('name'); var name = $(this).data('name');
var url = $(this).data('url');
vm_confirm_popup( vm_confirm_popup(
interpolate( interpolate(
gettext('Are you sure deleting <strong>%s</strong>'), [name]), gettext('Delete'), function() { gettext('Are you sure deleting <strong>%s</strong>'), [name]), gettext('Delete'), function() {
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: '/ajax/group/delete/', url: url,
data: 'gid=' + gid, data: 'gid=' + gid,
success: function() { success: function() {
$('#group-' + gid).slideUp(700); $('#group-' + gid).slideUp(700);
......
...@@ -12,12 +12,12 @@ body ...@@ -12,12 +12,12 @@ body
background-position:80px 0; background-position:80px 0;
margin:0; margin:0;
padding:0; padding:0;
overflow: scroll; overflow-y: scroll;
} }
#content #content
{ {
width:970px; width:80%;
text-align:left; text-align:left;
margin:0 auto; margin:0 auto;
padding-bottom: 100px; padding-bottom: 100px;
...@@ -62,6 +62,9 @@ body ...@@ -62,6 +62,9 @@ body
color: #aaa; color: #aaa;
} }
} }
img {
max-width: 100%;
}
} }
.big { .big {
font-size: 2em; font-size: 2em;
...@@ -287,6 +290,7 @@ body > footer { ...@@ -287,6 +290,7 @@ body > footer {
box-shadow:0 0 30px rgba(0,0,0,0.4); box-shadow:0 0 30px rgba(0,0,0,0.4);
margin:0; margin:0;
background-color: white; background-color: white;
height: 30px;
} }
#http-error { #http-error {
...@@ -299,6 +303,138 @@ body > footer { ...@@ -299,6 +303,138 @@ body > footer {
padding: 20px; padding: 20px;
} }
.irasmu p { .irasmu {
margin-top: 20px; line-height: 1.8em;
section {
border-radius: 4px;
border: 1px solid #888;
background: #ccc;
box-shadow: 0 0 20px rgba(0,0,0,0.2);
padding: 20px;
margin: 10px;
&.teacher {
border-left: 3px solid #0b4599;
}
}
p {
margin-bottom: 10px;
&:last-child {
margin-bottom: 0px;
}
&.desc {
margin-left: 2em;
}
}
p.teacher {
background: #ddd;
padding: 20px;
border-left-width: 3px;
border-left-style: solid;
border-left-color: #0b4599;
}
p.teacher + p.teacher {
margin-top: 0;
padding-top: 0;
}
h4 {
margin: 0;
padding: 0;
font-size: 1em;
float: left;
}
h4:after {
content: " ♦ ";
}
h4 + p {
margin-top: 0;
}
h2 {
background-color:#000;
background-image:url(/static/image/hexabar.png);
background-position: right center;
background-repeat:no-repeat;
color:#eee;
font-size:1.5em;
border-radius: 4px;
border: 1px solid #888;
box-shadow: 0 0 20px rgba(0,0,0,0.2);
padding: 10px;
margin: 10px;
margin-bottom: 0;
border-bottom-style: none;
}
h2 + section {
border-radius: 0 0 4px 4px;
border-top-style: none;
margin-top: 0;
}
p.figure {
text-align: center;
&.figure-small img {
height: 200px;
transition: 1s 300ms;
-webkit-transition: 1s 300ms;
-moz-transition: 1s 300ms;
-o-transition: 1s 300ms;
-ms-transition: 1s 300ms;
transform-origin: center center;
-webkit-transform-origin: center center;
-moz-transform-origin: center center;
-ms-transform-origin: center center;
-o-transform-origin: center center;
&:hover {
height: 390px;
}
}
}
ol, ul {
margin-left: 1em;
}
nav {
background: #ddd;
padding: 10px;
border-left-width: 3px;
border-left-style: solid;
border-left-color: #ff6;
line-height: 1.2em;
li {
list-style-type: none;
ul li {
list-style-type: square;
margin-left: 1em;
}
}
}
em {
white-space: nowrap;
}
strong {
background-image: url(/static/image/hilite.png);
background-repeat: repeat;
font-style: normal;
font-weight: normal;
padding: 0 .4em;
margin-bottom: 2px;
}
}
@media (max-width: 900px) {
#content {
width: 100%;
}
.boxes {
width: 100% !important;
}
#modal-container{
width: 90%;
left: 0 !important;
margin-left: 2% !important;
}
.contentblock {
margin:5px;
}
body {
font-size: 1.1em;
}
} }
.boxes { .boxes {
width:480px; width:50%;
float:left; float:left;
} }
...@@ -300,7 +300,6 @@ ...@@ -300,7 +300,6 @@
} }
.value { .value {
float: right; float: right;
width: 200px;
text-align: right; text-align: right;
} }
.description { .description {
...@@ -309,7 +308,7 @@ ...@@ -309,7 +308,7 @@
.value { .value {
font-size: 0.8em; font-size: 0.8em;
word-spacing: 3px; word-spacing: 3px;
width: 350px; max-width: 200px;
} }
} }
} }
...@@ -317,7 +316,7 @@ ...@@ -317,7 +316,7 @@
background-image: url(/static/icons/computer--plus.png); background-image: url(/static/icons/computer--plus.png);
} }
} }
#new-share .type-summary, .share-type .value { #modal, #new-share .type-summary, .share-type .value {
&.type-summary { &.type-summary {
font-size: .8em; font-size: .8em;
text-align: right; text-align: right;
...@@ -630,11 +629,12 @@ table { ...@@ -630,11 +629,12 @@ table {
.boxhelp { .boxhelp {
position: relative; position: relative;
font-weight: normal;
.boxhelp-box { .boxhelp-box {
color:#000; color:#000;
position: absolute; position: absolute;
left: -100px;
width: 500px; width: 500px;
max-width: 100%;
z-index: 1000000; z-index: 1000000;
font-size: .7em; font-size: .7em;
background-color: #ffc; background-color: #ffc;
...@@ -643,6 +643,7 @@ table { ...@@ -643,6 +643,7 @@ table {
box-shadow:0 0 30px rgba(0,0,0,0.3); box-shadow:0 0 30px rgba(0,0,0,0.3);
margin:20px; margin:20px;
display: none; display: none;
font-size: 14px;
} }
.help:hover .boxhelp-box { .help:hover .boxhelp-box {
display: block; display: block;
......
...@@ -4,6 +4,11 @@ ...@@ -4,6 +4,11 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
z-index: 999; z-index: 999;
p,dl
{
margin:0;
padding:5px;
}
} }
#shadow{ #shadow{
position: fixed; position: fixed;
...@@ -27,7 +32,6 @@ ...@@ -27,7 +32,6 @@
max-height: 60%; max-height: 60%;
overflow: auto; overflow: auto;
.container{ .container{
max-height: 400px;
overflow: auto; overflow: auto;
border-radius: 2px; border-radius: 2px;
border: 1px solid #888; border: 1px solid #888;
......
...@@ -5,6 +5,7 @@ import os ...@@ -5,6 +5,7 @@ import os
import sys import sys
import time import time
from django.core.mail import send_mail from django.core.mail import send_mail
from one.models import Instance
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -12,3 +13,17 @@ class SendMailTask(Task): ...@@ -12,3 +13,17 @@ class SendMailTask(Task):
def run(self, to, subject, msg, sender=u'noreply@cloud.ik.bme.hu'): def run(self, to, subject, msg, sender=u'noreply@cloud.ik.bme.hu'):
send_mail(subject, msg, sender, [ to ], fail_silently=False) send_mail(subject, msg, sender, [ to ], fail_silently=False)
logger.info("[django][one][tasks.py] %s->%s [%s]" % (sender, to, subject) ) logger.info("[django][one][tasks.py] %s->%s [%s]" % (sender, to, subject) )
class UpdateInstanceStateTask(Task):
def run(self, one_id):
print one_id
try:
inst = Instance.objects.get(one_id=one_id)
except:
print 'nincs ilyen'
return
inst.update_state()
inst.waiting = False
inst.save()
print inst.state
<!DOCTYPE html> <!DOCTYPE html>
{% load i18n %} {% load i18n %}
{% load l10n %}
{% load staticfiles %} {% load staticfiles %}
{% get_current_language as lang %} {% get_current_language as lang %}
<html lang="{{lang}}"> <html lang="{{lang}}">
...@@ -12,9 +13,11 @@ ...@@ -12,9 +13,11 @@
<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" src="https://www.google.com/jsapi"></script>
<script type="text/javascript"> <script type="text/javascript">
{% if DEBUG %}window.localStorage.removeItem('https://cloud.ik.bme.hu/static/style/style.less:timestamp');{% endif %} {% 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}};
google.load('visualization', '1.0', {'packages':['corechart']});
</script> </script>
{% if DEBUG %}<script src="{% static "script/less.min.js" %}"></script>{% endif %} {% 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>
...@@ -26,6 +29,7 @@ ...@@ -26,6 +29,7 @@
{% endif %} {% endif %}
{{ form.media }} {{ form.media }}
{% block js %}{% endblock %} {% block js %}{% endblock %}
<meta name="viewport" content="target-densitydpi=device-dpi, initial-scale=1.0" />
</head> </head>
<body> <body>
<div id="header"> <div id="header">
...@@ -70,16 +74,74 @@ ...@@ -70,16 +74,74 @@
<div class="clear"></div> <div class="clear"></div>
</div> </div>
<footer> <footer>
<a href="/sites/legal/">{% trans "Legal notice" %}</a> | <div>
<a href="/sites/policy/">{% trans "Policy" %}</a> | <div style="float: left" id="chart_cpu_div"></div>
<a href="/sites/help/">{% trans "Help" %}</a> | <a href="/sites/legal/">{% trans "Legal notice" %}</a> |
<a href="/sites/support/">{% trans "Support" %}</a> <a href="/sites/policy/">{% trans "Policy" %}</a> |
<a href="/sites/help/">{% trans "Help" %}</a> |
<a href="/sites/support/">{% trans "Support" %}</a> |
<a href="/sites/changelog/#{{release}}" title="{% trans "Change log" %}">{{release}}</a>
<div style="float: right" id="chart_mem_div"></div>
</div>
{% if cloud_stat %}
<script type="text/javascript">
google.setOnLoadCallback(drawChart);
function drawChart() {
var data_cpu = new google.visualization.DataTable();
data_cpu.addColumn('string', 'Topping');
data_cpu.addColumn('number', 'Used');
data_cpu.addColumn('number', 'Allocated');
data_cpu.addColumn('number', 'Free');
data_cpu.addRows([
['CPU',
{{cloud_stat.CPU.USED_CPU}},
{{cloud_stat.CPU.ALLOC_CPU}},
{{cloud_stat.CPU.FREE_CPU}},]
]);
var cpu_options = {
'width':400,
'height':20,
isStacked: true,
enableInteractivity: false,
colors: ['red', 'orange', 'blue']
};
var data_mem = new google.visualization.DataTable();
data_mem.addColumn('string', 'Topping');
data_mem.addColumn('number', 'Used');
data_mem.addColumn('number', 'Allocated');
data_mem.addColumn('number', 'Free');
data_mem.addRows([
['RAM',
{{cloud_stat.MEM.USED_MEM|unlocalize}},
{{cloud_stat.MEM.ALLOC_MEM|unlocalize}},
{{cloud_stat.MEM.FREE_MEM|unlocalize}},]
]);
var mem_options = {
'width':400,
'height':20,
isStacked: true,
enableInteractivity: false,
colors: ['red', 'orange', 'blue'],
hAxis : {
viewWindowMode: 'explicit',
viewWindow: {
min: 0,
max: {{cloud_stat.MEM.USED_MEM|unlocalize}}+{{cloud_stat.MEM.ALLOC_MEM|unlocalize}}+{{cloud_stat.MEM.FREE_MEM|unlocalize}}
}
},
};
var chart = new google.visualization.BarChart(document.getElementById('chart_cpu_div'));
chart.draw(data_cpu, cpu_options);
var chart = new google.visualization.BarChart(document.getElementById('chart_mem_div'));
chart.draw(data_mem, mem_options);
}
</script>
{% endif %}
</footer> </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"> <script type="text/javascript">
var _gaq = _gaq || []; var _gaq = _gaq || [];
......
...@@ -115,7 +115,7 @@ ...@@ -115,7 +115,7 @@
</div> </div>
</li> </li>
<li class="entry small-row key" style="display: none"> <li class="entry small-row key" style="display: none">
<div class="summary" id="reset-key"> <div class="summary" id="reset-key" data-url="{% url one.views.key_ajax_reset %}">
<div class="name">{% trans "Reset key" %}</div> <div class="name">{% trans "Reset key" %}</div>
<div class="clear"></div> <div class="clear"></div>
</div> </div>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
{{key}} {{key}}
</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-url="{% url one.views.key_ajax_delete %}" 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>
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
</div> </div>
{% endif %} {% endif %}
{% if not group %} {% if not group %}
<li id="new-template-button" class="entry new small-row"> <li id="new-template-button" class="entry new small-row" data-url="{% url one.views.ajax_template_wizard %}">
<div class="summary"> <div class="summary">
<div class="name">Új Sablon</div> <div class="name">Új Sablon</div>
<div class="clear"></div> <div class="clear"></div>
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
<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-url="{% url new_vm_from_template template=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" %}">
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
<form action="{% url one.views.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.type}} ({{i.get_running}}/{{i.instance_limit}}) {{i.type}}
<a href="#" class="edit" data-id="{{i.id}}"> <a href="#" class="edit" data-url="{% url ajax_share_edit_wizard id=i.id %}">
<img src="{% static "icons/pencil.png" %}" alt="{% trans "Edit" %}" title="{% trans "Edit" %}" /> <img src="{% static "icons/pencil.png" %}" alt="{% trans "Edit" %}" title="{% trans "Edit" %}" />
</a> </a>
{% csrf_token %} {% csrf_token %}
...@@ -47,21 +47,18 @@ ...@@ -47,21 +47,18 @@
{% endblock status %} {% endblock status %}
{% block actions %} {% block actions %}
<a href="#" class="edit-template" data-id="{{ t.id }}" title="{% trans "Edit" %}"> <a href="#" class="edit-template" title="{% trans "Edit" %}" data-url="{% url one.views.ajax_template_edit_wizard id=t.id %}">
<img src="{% static "icons/pencil.png" %}" alt="{% trans "Edit" %}" /> <img src="{% static "icons/pencil.png" %}" alt="{% trans "Edit" %}" />
</a> </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-url="{% url one.views.vm_new_ajax template=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" %}">
<img src="{% static "icons/pencil.png" %}" alt="{% trans "Edit" %}" />
</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-url="{% url one.views.ajax_template_delete %}" 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>
{% endblock actions %} {% endblock actions %}
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
{% 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" %}" data-url="{% url one.views.vm_ajax_rename iid=vm.id %}">
<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 %}
......
...@@ -4,15 +4,17 @@ ...@@ -4,15 +4,17 @@
{% block js %} {% block js %}
<script type="text/javascript"> <script type="text/javascript">
{% if booting or state != 'ACTIVE' %} {% if booting or state == 'PENDING' or i.waiting %}
var timer=setInterval(function(){ var timer=setInterval(function(){
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
dataType: 'json', dataType: 'json',
url: '{% url one.views.vm_ajax_instance_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.waiting && !data.booting && data.state != 'PENDING'){
window.location.reload(); window.location.reload();
} else if (!data.waiting) {
// window.location.reload();
} }
} }
}); });
...@@ -84,14 +86,20 @@ ...@@ -84,14 +86,20 @@
<img src="{% static "image/load.gif" %}" /> <img src="{% static "image/load.gif" %}" />
{% trans "Saving..." %} {% trans "Saving..." %}
</p> </p>
{% elif state == "ACTIVE" and not booting %} {% elif state == "ACTIVE" and not booting and not i.waiting %}
<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>
{% elif state == "STOPPED" %} {% elif state == "ACTIVE" and not booting and i.waiting %}
<p style="display:block; font-size:25px; line-height:2em;text-align:center;">
{% trans "Stopping..." %}
</p>
{% elif state == "STOPPED" and i.waiting %}
<p style="font-size:25px; line-height:2em;text-align:center;">{% trans "Starting..." %}</p>
{% elif state == "STOPPED"%}
<p style="font-size:25px; line-height:2em;text-align:center;">{% trans "Stopped" %}</p> <p style="font-size:25px; line-height:2em;text-align:center;">{% trans "Stopped" %}</p>
{% endif %} {% endif %}
{% if state == "DONE" %} {% if state == "DONE" %}
......
{% load l10n %} {% load l10n %}
<html> <html>
<head> <head>
<!--Load the AJAX API--> <script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script> <script type="text/javascript">
<script type="text/javascript"> google.load('visualization', '1.0', {'packages':['corechart']});
google.setOnLoadCallback(drawChart);
// Load the Visualization API and the piechart package. function drawChart() {
google.load('visualization', '1.0', {'packages':['corechart']}); var data_cpu = new google.visualization.DataTable();
data_cpu.addColumn('string', 'Topping');
// Set a callback to run when the Google Visualization API is loaded. data_cpu.addColumn('number', 'Free');
google.setOnLoadCallback(drawChart); data_cpu.addColumn('number', 'Allocated');
data_cpu.addColumn('number', 'Used');
// Callback that creates and populates a data table, data_cpu.addRows([
// instantiates the pie chart, passes in the data and ['CPU %', {{STAT.CPU.FREE_CPU}},{{STAT.CPU.ALLOC_CPU}},{{STAT.CPU.USED_CPU}}],
// draws it. ]);
function drawChart() { var cpu_options = {
'title':'Cloud CPU usage percent (100/CPU)',
// Create the data table. 'width':900,
var data_cpu = new google.visualization.DataTable(); 'height':50,
data_cpu.addColumn('string', 'Topping'); isStacked: true
data_cpu.addColumn('number', 'Slices'); };
data_cpu.addRows([ var data_mem = new google.visualization.DataTable();
['Free CPU', {{STAT.CPU.FREE_CPU}}], data_mem.addColumn('string', 'Topping');
['Allocated CPU', {{STAT.CPU.ALLOC_CPU}}], data_mem.addColumn('number', 'Slices');
['Used CPU', {{STAT.CPU.USED_CPU}}], data_mem.addRows([
]); ['Free Memory', {{STAT.MEM.FREE_MEM|unlocalize}}],
['Allocated Memory', {{STAT.MEM.ALLOC_MEM|unlocalize}}],
// Set chart options ['Used Memory', {{STAT.MEM.USED_MEM|unlocalize}}],
var cpu_options = {'title':'Cloud CPU usage percent (100/CPU)', ]);
'width':400, var mem_options = {
'height':300, 'title':'Cloud Memory usage in {{STAT.DIMENSION}}',
slices: {0: {color: 'blue'}, 1:{color: 'orange'}, 'width':400,
2:{color: 'red'}} 'height':300,
}; slices: {
0: {color: 'blue'},
var data_mem = new google.visualization.DataTable(); 1:{color: 'orange'},
data_mem.addColumn('string', 'Topping'); 2:{color: 'red'}
data_mem.addColumn('number', 'Slices'); },
data_mem.addRows([ };
['Free Memory', {{STAT.MEM.FREE_MEM|unlocalize}}], var chart = new google.visualization.BarChart(document.getElementById('chart_cpu_div'));
['Allocated Memory', {{STAT.MEM.ALLOC_MEM|unlocalize}}], chart.draw(data_cpu, cpu_options);
['Used Memory', {{STAT.MEM.USED_MEM|unlocalize}}], var chart = new google.visualization.PieChart(document.getElementById('chart_mem_div'));
]); chart.draw(data_mem, mem_options);
}
// Set chart options </script>
var mem_options = {'title':'Cloud Memory usage in {{STAT.DIMENSION}}', </head>
'width':400, <body>
'height':300, <div>Running VMs: {{STAT.VMS}}</div>
slices: {0: {color: 'blue'}, 1:{color: 'orange'}, <div id="chart_cpu_div"></div>
2:{color: 'red'}} <div id="chart_mem_div"></div>
}; </body>
// 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> </html>
...@@ -32,8 +32,6 @@ logger = logging.getLogger(__name__) ...@@ -32,8 +32,6 @@ logger = logging.getLogger(__name__)
def _list_instances(request): def _list_instances(request):
instances = Instance.objects.exclude(state='DONE').filter(owner=request.user) instances = Instance.objects.exclude(state='DONE').filter(owner=request.user)
for i in instances:
i.update_state()
instances = instances.exclude(state='DONE') instances = instances.exclude(state='DONE')
return instances return instances
...@@ -335,6 +333,7 @@ def vm_new(request, template=None, share=None, redir=True): ...@@ -335,6 +333,7 @@ def vm_new(request, template=None, share=None, redir=True):
messages.error(request, _('Failed to create virtual machine.')) messages.error(request, _('Failed to create virtual machine.'))
inst = None inst = None
if inst: if inst:
inst.waiting = True
inst.time_of_suspend = time_of_suspend inst.time_of_suspend = time_of_suspend
inst.time_of_delete = time_of_delete inst.time_of_delete = time_of_delete
inst.save() inst.save()
...@@ -356,9 +355,6 @@ vm_list = login_required(VmListView.as_view()) ...@@ -356,9 +355,6 @@ vm_list = login_required(VmListView.as_view())
@login_required @login_required
def vm_show(request, iid): def vm_show(request, iid):
inst = get_object_or_404(Instance, id=iid, owner=request.user) inst = get_object_or_404(Instance, id=iid, owner=request.user)
inst.update_state()
if inst.template.state == "SAVING":
inst.check_if_is_save_as_done()
try: try:
ports = inst.firewall_host.list_ports() ports = inst.firewall_host.list_ports()
except: except:
...@@ -388,10 +384,10 @@ def vm_show(request, iid): ...@@ -388,10 +384,10 @@ def vm_show(request, iid):
@login_required @login_required
def vm_ajax_instance_status(request, iid): def vm_ajax_instance_status(request, iid):
inst = get_object_or_404(Instance, id=iid, owner=request.user) inst = get_object_or_404(Instance, id=iid, owner=request.user)
inst.update_state()
return HttpResponse(json.dumps({ return HttpResponse(json.dumps({
'booting': not inst.active_since, 'booting': not inst.active_since,
'state': inst.state, 'state': inst.state,
'waiting': inst.waiting,
'template': { 'template': {
'state': inst.template.state 'state': inst.template.state
}})) }}))
...@@ -612,7 +608,7 @@ def stat(request): ...@@ -612,7 +608,7 @@ def stat(request):
))) )))
def sites(request, site): def sites(request, site):
if site in [ "legal", "policy", "help", "support" ]: if site in [ "legal", "policy", "help", "support", "changelog", ]:
return render_to_response("sites/%s.html" % site, RequestContext(request, {})) return render_to_response("sites/%s.html" % site, RequestContext(request, {}))
else: else:
return redirect(home) return redirect(home)
......
...@@ -6,7 +6,7 @@ msgid "" ...@@ -6,7 +6,7 @@ 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-03-07 18:16+0100\n" "POT-Creation-Date: 2013-03-22 10:43+0100\n"
"PO-Revision-Date: 2013-03-07 17:48+0100\n" "PO-Revision-Date: 2013-03-07 17:48+0100\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: American English <cloud@ik.bme.hu>\n" "Language-Team: American English <cloud@ik.bme.hu>\n"
...@@ -17,112 +17,108 @@ msgstr "" ...@@ -17,112 +17,108 @@ 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"
#: models.py:12 #: models.py:13
msgid "Hungarian" msgid "Hungarian"
msgstr "Magyar" msgstr "Magyar"
#: models.py:12 #: models.py:13
msgid "English" msgid "English"
msgstr "Angol" msgstr "Angol"
#: models.py:28 #: models.py:46
msgid "language" msgid "language"
msgstr "nyelv" msgstr "nyelv"
#: models.py:30 #: models.py:48
msgid "code" msgid "code"
msgstr "kód" msgstr "kód"
#: models.py:53 #: models.py:73
#, python-format #, python-format
msgid "%(first)s %(last)s" msgid "%(first)s %(last)s"
msgstr "%(last)s %(first)s" msgstr "%(last)s %(first)s"
#: models.py:59 #: models.py:82
msgid "person" msgid "person"
msgstr "személy" msgstr "személy"
#: models.py:60 #: models.py:83
msgid "persons" msgid "persons"
msgstr "személyek" msgstr "személyek"
#: models.py:64 #: models.py:87
msgid "course code" msgid "course code"
msgstr "tárgykód" msgstr "tárgykód"
#: models.py:66 models.py:68 models.py:120 models.py:146 #: models.py:89 models.py:91 models.py:143 models.py:169
msgid "name" msgid "name"
msgstr "név" msgstr "név"
#: models.py:70 #: models.py:93
msgid "default group" msgid "default group"
msgstr "alapértelmezett csoport" msgstr "alapértelmezett csoport"
#: models.py:71 #: models.py:94
msgid "New users will automatically get to this group." msgid "New users will be automatically assigned to this group."
msgstr "Az új hallgatók automatikusan ebbe a csoportba kerülnek." msgstr "Az új hallgatók automatikusan ebbe a csoportba kerülnek."
#: models.py:73 models.py:115 models.py:149 models.py:162 #: models.py:96 models.py:138 models.py:175 models.py:189
msgid "owners" msgid "owners"
msgstr "tulajdonosok" msgstr "tulajdonosok"
#: models.py:76 models.py:147 #: models.py:99 models.py:171
msgid "course" msgid "course"
msgstr "tárgy" msgstr "tárgy"
#: models.py:77 #: models.py:100
msgid "courses" msgid "courses"
msgstr "tárgyak" msgstr "tárgyak"
#: models.py:83 #: models.py:106
#, python-format #, python-format
msgid "%s (auto)" msgid "%s (auto)"
msgstr "%s (auto)" msgstr "%s (auto)"
#: models.py:108 #: models.py:131
msgid "short name" msgid "short name"
msgstr "rövid név" msgstr "rövid név"
#: models.py:114 #: models.py:137 models.py:188
msgid "(none)" msgid "(none)"
msgstr "(nincs)" msgstr "(nincs)"
#: models.py:121 #: models.py:144
msgid "start" msgid "start"
msgstr "kezdet" msgstr "kezdet"
#: models.py:122 #: models.py:145
msgid "end" msgid "end"
msgstr "vége" msgstr "vége"
#: models.py:125 models.py:148 #: models.py:148 models.py:173
msgid "semester" msgid "semester"
msgstr "félév" msgstr "félév"
#: models.py:126 #: models.py:149
msgid "semesters" msgid "semesters"
msgstr "félévek" msgstr "félévek"
#: models.py:139 #: models.py:162
msgid "There is no current semester." msgid "There is no current semester."
msgstr "Nincs aktuális félév." msgstr "Nincs aktuális félév."
#: models.py:150 #: models.py:177
msgid "members" msgid "members"
msgstr "tagok" msgstr "tagok"
#: models.py:154 #: models.py:181
msgid "group" msgid "group"
msgstr "csoport" msgstr "csoport"
#: models.py:155 #: models.py:182
msgid "groups" msgid "groups"
msgstr "csoportok" msgstr "csoportok"
#: models.py:161
msgid "n/a"
msgstr "n/a"
#: views.py:41 #: views.py:41
msgid "EduID is not available." msgid "EduID is not available."
msgstr "Az EduID nem elérhető." msgstr "Az EduID nem elérhető."
...@@ -147,15 +143,15 @@ msgstr "„%s” tárgy oktatóihoz felvéve." ...@@ -147,15 +143,15 @@ msgstr "„%s” tárgy oktatóihoz felvéve."
msgid "Failed to add course \"%s\" ownership." msgid "Failed to add course \"%s\" ownership."
msgstr "„%s” tárgy oktatóihoz felvétel sikertelen." msgstr "„%s” tárgy oktatóihoz felvétel sikertelen."
#: views.py:148 #: views.py:150
msgid "Could not found Person object." msgid "Could not found Person object."
msgstr "Nem található Személy objektum." msgstr "Nem található Személy objektum."
#: views.py:187 #: views.py:189
msgid "Invalid NEPTUN code found." msgid "Invalid NEPTUN code found."
msgstr "Érvénytelen Neptun-kód." msgstr "Érvénytelen Neptun-kód."
#: views.py:208 views.py:223 views.py:262 #: views.py:210 views.py:225 views.py:264
msgid "Invalid NEPTUN code" msgid "Invalid NEPTUN code"
msgstr "Érvénytelen Neptun-kód" msgstr "Érvénytelen Neptun-kód"
...@@ -320,6 +316,9 @@ msgstr "Felhasználó hozzáadása" ...@@ -320,6 +316,9 @@ msgstr "Felhasználó hozzáadása"
msgid "User NEPTUN code" msgid "User NEPTUN code"
msgstr "Felhasználó Neptun-kódja" msgstr "Felhasználó Neptun-kódja"
#~ msgid "n/a"
#~ msgstr "n/a"
#~ msgid "Templates are customized versions of the base images." #~ msgid "Templates are customized versions of the base images."
#~ msgstr "A sablonok alaprendszerek testre szabott változatai." #~ msgstr "A sablonok alaprendszerek testre szabott változatai."
......
...@@ -6,34 +6,56 @@ from django.core.exceptions import ValidationError ...@@ -6,34 +6,56 @@ from django.core.exceptions import ValidationError
from datetime import datetime from datetime import datetime
from django.conf import settings from django.conf import settings
import one.models import one.models
import logging
LANGUAGE_CODE = settings.LANGUAGE_CODE LANGUAGE_CODE = settings.LANGUAGE_CODE
LANGUAGE_CHOICES = (('hu', _('Hungarian')), ('en', _('English'))) LANGUAGE_CHOICES = (('hu', _('Hungarian')), ('en', _('English')))
logger = logging.getLogger(__name__)
def create_user_profile(sender, instance, created, **kwargs): def create_user_profile(sender, instance, created, **kwargs):
"""
User creation hook.
Ensure that the specified user has an associated profile.
@param sender: The model class.
@type instance: User
@param instance: The user to create a profile for (if necessary).
@type created: Boolean
@param created: True if a new record was created.
"""
if created: if created:
try: try:
p = Person.objects.get(code=instance.username) p = Person.objects.get(code=instance.username)
except Exception: except Person.DoesNotExist:
p = Person.objects.create(code=instance.username) p = Person.objects.create(code=instance.username)
except: except Exception as e:
logger.warning("Couldn't create profile for user: %(username)s"
"\nReason: %(exception)s",
{"username": instance.username,
"exception": e})
return return
p.code = instance.username p.clean()
p.save() p.save()
post_save.connect(create_user_profile, sender=User) post_save.connect(create_user_profile, sender=User)
class Person(models.Model): class Person(models.Model):
user = models.ForeignKey(User, null=True, blank=True, unique=True) user = models.ForeignKey(User, null=True, blank=True, unique=True)
language = models.CharField(verbose_name=_('language'), blank=False, max_length=10, language = models.CharField(verbose_name=_('language'), blank=False,
choices=LANGUAGE_CHOICES, default=LANGUAGE_CODE) max_length=10, choices=LANGUAGE_CHOICES, default=LANGUAGE_CODE)
code = models.CharField(_('code'), max_length=30, unique=True) code = models.CharField(_('code'), max_length=30, unique=True)
def get_owned_shares(self): def get_owned_shares(self):
return one.models.Share.objects.filter(group__in=self.owned_groups.all()) """Get the shares of the groups which the person owns."""
return one.models.Share.objects.filter(
group__in=self.owned_groups.all())
def get_shares(self): def get_shares(self):
return one.models.Share.objects.filter(group__in=self.course_groups.all()) """Get the shares of the groups which the person is a member of."""
return one.models.Share.objects.filter(
group__in=self.course_groups.all())
def short_name(self): def short_name(self):
if self.user: if self.user:
...@@ -45,15 +67,16 @@ class Person(models.Model): ...@@ -45,15 +67,16 @@ class Person(models.Model):
return self.code return self.code
def __unicode__(self): def __unicode__(self):
u = self.user if self.user:
if not u: if self.user.last_name and self.user.first_name:
return self.code # TRANSLATORS: full name format used in enumerations
if u.last_name and u.first_name: return _("%(first)s %(last)s") % {
# TRANSLATORS: full name format used in enumerations 'first': self.user.first_name,
return _("%(first)s %(last)s") % {'first': u.first_name, 'last': self.user.last_name}
'last': u.last_name} else:
return self.user.username
else: else:
return u.username return self.code
class Meta: class Meta:
verbose_name = _('person') verbose_name = _('person')
...@@ -68,7 +91,7 @@ class Course(models.Model): ...@@ -68,7 +91,7 @@ class Course(models.Model):
verbose_name=_('name')) verbose_name=_('name'))
default_group = models.ForeignKey('Group', null=True, blank=True, default_group = models.ForeignKey('Group', null=True, blank=True,
related_name='default_group_of', verbose_name=_('default group'), related_name='default_group_of', verbose_name=_('default group'),
help_text=_('New users will automatically get to this group.')) help_text=_('New users will be automatically assigned to this group.'))
owners = models.ManyToManyField(Person, blank=True, null=True, owners = models.ManyToManyField(Person, blank=True, null=True,
verbose_name=_('owners')) verbose_name=_('owners'))
...@@ -144,10 +167,14 @@ class Semester(models.Model): ...@@ -144,10 +167,14 @@ class Semester(models.Model):
class Group(models.Model): class Group(models.Model):
name = models.CharField(max_length=80, verbose_name=_('name')) name = models.CharField(max_length=80, verbose_name=_('name'))
course = models.ForeignKey('Course', null=True, blank=True, verbose_name=_('course')) course = models.ForeignKey('Course', null=True, blank=True,
semester = models.ForeignKey('Semester', null=False, blank=False, verbose_name=_('semester')) verbose_name=_('course'))
owners = models.ManyToManyField(Person, blank=True, null=True, related_name='owned_groups', verbose_name=_('owners')) semester = models.ForeignKey('Semester', null=False, blank=False,
members = models.ManyToManyField(Person, blank=True, null=True, related_name='course_groups', verbose_name=_('members')) verbose_name=_('semester'))
owners = models.ManyToManyField(Person, blank=True, null=True,
related_name='owned_groups', verbose_name=_('owners'))
members = models.ManyToManyField(Person, blank=True, null=True,
related_name='course_groups', verbose_name=_('members'))
class Meta: class Meta:
unique_together = (('name', 'course', 'semester', ), ) unique_together = (('name', 'course', 'semester', ), )
...@@ -155,10 +182,10 @@ class Group(models.Model): ...@@ -155,10 +182,10 @@ class Group(models.Model):
verbose_name_plural = _('groups') verbose_name_plural = _('groups')
def owner_list(self): def owner_list(self):
if self.owners: if self.owners and self.owners.count() > 0:
return ", ".join([p.short_name() for p in self.owners.all()]) return ", ".join([p.short_name() for p in self.owners.all()])
else: else:
return _("n/a") return _("(none)")
owner_list.verbose_name = _('owners') owner_list.verbose_name = _('owners')
def member_count(self): def member_count(self):
...@@ -172,4 +199,4 @@ class Group(models.Model): ...@@ -172,4 +199,4 @@ class Group(models.Model):
@models.permalink @models.permalink
def get_absolute_url(self): def get_absolute_url(self):
return ('group_show', None, {'gid':self.id}) return ('group_show', None, {'gid': self.id})
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
<small class="details">(<a href="{{ group.get_absolute_url }}">{% 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-url="{% url school.views.group_ajax_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}}">
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
<div class="name">{% trans "Add user" %}</div> <div class="name">{% trans "Add user" %}</div>
<div id="new-member-form"> <div id="new-member-form">
<input type="text" placeholder="{% trans "User NEPTUN code" %}" /> <input type="text" placeholder="{% trans "User NEPTUN code" %}" />
<input type="submit" value="{% trans "Add user" %}" data-id="{{group.id}}"/> <input type="submit" value="{% trans "Add user" %}" data-url="{% url school.views.group_ajax_add_new_member gid=group.id %}"/>
</div> </div>
<div class="clear"></div> <div class="clear"></div>
</div> </div>
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
{% endif %} {% endif %}
</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-url="{% url school.views.group_ajax_remove_member 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>
......
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
</div> </div>
<div class="details" id="new-owner-form"> <div class="details" id="new-owner-form">
<div class="container"> <div class="container">
<input type="text" placeholder="{% trans "Owner name/NEPTUN" %}" /> <input type="text" placeholder="{% trans "Owner name/NEPTUN" %}" data-url="{% url school.views.group_ajax_owner_autocomplete %}"/>
<div id="new-owner-autocomplete"></div> <div id="new-owner-autocomplete"></div>
</div> </div>
</div> </div>
......
""" from django.test import TestCase
This file demonstrates writing tests using the unittest module. These will pass from models import create_user_profile, Person
when you run "manage.py test".
Replace this with more appropriate tests for your application. class MockUser:
""" username = "testuser"
from django.test import TestCase class CreateUserProfileTestCase(TestCase):
def setUp(self):
self.user = MockUser()
for p in Person.objects.all():
p.delete()
def test_new_profile(self):
"""Test profile creation functionality for new user."""
create_user_profile(self.user.__class__, self.user, True)
self.assertEqual(Person.objects.filter(
code=self.user.username).count(), 1)
def test_existing_profile(self):
"""Test profile creation functionality when it already exists."""
Person.objects.create(code=self.user.username)
create_user_profile(self.user.__class__, self.user, True)
self.assertEqual(Person.objects.filter(
code=self.user.username).count(), 1)
class PersonTestCase(TestCase):
def setUp(self):
self.testperson = Person.objects.create(code='testperson')
def test_language_code_in_choices(self):
"""Test whether the default value for language is a valid choice."""
# TODO
language_field = self.testperson._meta.get_field('language')
choice_codes = [code for (code, _) in language_field.choices]
self.assertIn(language_field.default, choice_codes)
def test_get_owned_shares(self):
# TODO
self.testperson.get_owned_shares()
def test_get_shares(self):
# TODO
self.testperson.get_shares()
def test_short_name(self):
# TODO
self.testperson.short_name()
class SimpleTest(TestCase): def test_unicode(self):
def test_basic_addition(self): # TODO
""" self.testperson.__unicode__()
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)
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