--- /dev/null
+from fabric.api import *
+
+env.user = 'portal'
+env.hosts = ['agave5.man.poznan.pl']
+
+
+#################################################
+# server management (remote)
+#################################################
+
+PID_FILE = '/var/run/uwsgi.pid'
+
+
+@task
+def start():
+ with cd('qcg-portal'):
+ run("uwsgi --ini uwsgi.ini")
+
+
+@task
+def stop():
+ run("uwsgi --stop " + PID_FILE)
+
+
+@task
+def restart():
+ run("uwsgi --reload " + PID_FILE)
+
+
+def is_running():
+ with settings(hide('everything'), warn_only=True):
+ return not run("ps -p `cat {}`".format(PID_FILE), shell_escape=False).failed
+
+
+@task
+def status():
+ print "Server is",
+ print "running." if is_running() else "not running."
+
+
+#################################################
+# deployment (remote)
+#################################################
+
+@task
+def git_status():
+ with cd('qcg-portal'):
+ run("git status")
+
+
+@task
+def deploy(load_ex_data=False):
+ with cd('qcg-portal'):
+ run("git pull")
+
+ run("pip install -r requirements.txt")
+ run("python manage.py migrate qcg")
+ run("python manage.py collectstatic --noinput")
+
+ if is_running:
+ run("uwsgi --reload " + PID_FILE)
+ else:
+ run("uwsgi --ini uwsgi.ini")
\ No newline at end of file
--- /dev/null
+# coding=utf-8
+from datetime import timedelta
+from django import forms
+from django.core.exceptions import ValidationError
+
+
+class TimeRangeWidget(forms.MultiWidget):
+ def decompress(self, value):
+ if not value:
+ return [0, TimeRangeField.SECONDS]
+
+ seconds = value.seconds + 86400 * value.days
+
+ if seconds % 60 != 0:
+ return [seconds, TimeRangeField.SECONDS]
+ elif seconds % 3600 != 0:
+ return [seconds / 60, TimeRangeField.MINUTES]
+ elif seconds % 86400 != 0:
+ return [seconds / 3600, TimeRangeField.HOURS]
+ else:
+ return [seconds / 86400, TimeRangeField.DAYS]
+
+
+class TimeRangeField(forms.MultiValueField):
+ SECONDS, MINUTES, HOURS, DAYS = range(4)
+ UNIT_CHOICES = (
+ (SECONDS, u"Sekund"),
+ (MINUTES, u"Minut"),
+ (HOURS, u"Godzin"),
+ (DAYS, u"Dni"),
+ )
+
+ value = forms.IntegerField(min_value=0)
+ unit = forms.ChoiceField(choices=UNIT_CHOICES)
+
+ widget = TimeRangeWidget(widgets=(value.widget, unit.widget))
+
+ def __init__(self, *args, **kwargs):
+ super(TimeRangeField, self).__init__((self.value, self.unit), *args, **kwargs)
+
+ def compress(self, data_list):
+ try:
+ unit = int(data_list[1])
+ if unit == self.SECONDS:
+ return timedelta(seconds=data_list[0])
+ elif unit == self.MINUTES:
+ return timedelta(minutes=data_list[0])
+ elif unit == self.HOURS:
+ return timedelta(hours=data_list[0])
+ elif unit == self.DAYS:
+ return timedelta(days=data_list[0])
+ else:
+ raise ValidationError(u"Nieprawidłowa jednostka")
+ except ValueError:
+ raise ValidationError(u"Nieprawidłowa jednostka")
from django.template.defaultfilters import capfirst
from pyqcg.utils import TaskStatus
+from qcg.fields import TimeRangeField
from qcg.models import Task, Allocation
{% bootstrap_field form.modules layout="horizontal" form_group_class="form-group collapse" %}
{% bootstrap_field form.procs layout="horizontal" %}
{% bootstrap_field form.nodes layout="horizontal" form_group_class="form-group collapse" %}
- {% bootstrap_field form.wall_time layout="horizontal" %}
+ {% include 'qcg/time_range_field.html' with field_name='wall_time' field=form.wall_time %}
{% bootstrap_field form.memory layout="horizontal" form_group_class="form-group collapse" %}
{% bootstrap_field form.memory_per_slot layout="horizontal" form_group_class="form-group collapse" %}
{% bootstrap_field form.reservation layout="horizontal" form_group_class="form-group collapse" %}
--- /dev/null
+<div class="form-group">
+ <label class="col-sm-3 col-md-4 control-label" for="id_{{ field_name }}_0">{{ field.label }}</label>
+ <div class="col-sm-7 col-md-4">
+ <input class="form-control" id="id_{{ field_name }}_0" min="0" name="{{ field_name }}_0" value="{{ field.value.0 }}" type="number">
+ </div>
+ <div class="col-sm-2">
+ <select class="form-control" id="id_{{ field_name }}_1" name="{{ field_name }}_1">
+ <option value="0"{% if field.value.1 == 0 %} selected{% endif %}>Sekund</option>
+ <option value="1"{% if field.value.1 == 1 %} selected{% endif %}>Minut</option>
+ <option value="2"{% if field.value.1 == 2 %} selected{% endif %}>Godzin</option>
+ <option value="3"{% if field.value.1 == 3 %} selected{% endif %}>Dni</option>
+ </select>
+ </div>
+</div>
\ No newline at end of file
-r requirements.txt
django-sslserver
-django-debug-toolbar
\ No newline at end of file
+django-debug-toolbar
+Fabric
\ No newline at end of file
--- /dev/null
+[uwsgi]
+base-dir = /home/portal/qcg-portal
+
+uid = portal
+gid = portal
+
+cache2 = name=ssl,items=1000,keysize=128,blocksize=4096
+ssl-sessions-use-cache = ssl
+ssl-sessions-timeout = 300
+
+shared-socket = :80
+shared-socket = :443
+
+http-to-https = =0
+https = =1,%(base-dir)/certs/cert.crt,%(base-dir)/certs/cert.key,EECDH+aRSA+AES:EDH+aRSA+AES:kRSA+AES:@STRENGTH
+
+add-header = Strict-Transport-Security: max-age=31536000
+
+workers = 6
+enable-threads = True
+; this do not play well with ssl cache...
+; thunder-lock = True
+
+master = True
+vacuum = True
+umask = 022
+pidfile = /var/run/uwsgi.pid
+logfile-chmod = 644
+daemonize = %(base-dir)/uwsgi.master.log
+stats = %(base-dir)/uwsgi.stats.socket
+
+chdir = %(base-dir)
+virtualenv = /home/portal/venv
+module = plgng.wsgi:application
+env = DJANGO_SETTINGS_MODULE=plgng.settings_prod
+
+static-map = /static=%(base-dir)/server-static