From cc336624de8fa227d247f0e71bd24f829802deb6 Mon Sep 17 00:00:00 2001 From: Maciej Tronowski Date: Wed, 4 Mar 2015 10:15:36 +0100 Subject: [PATCH] initial work on submitting job logic --- qcg/fields.py | 11 ------- qcg/forms.py | 41 ++++++++++++------------ qcg/models.py | 4 +-- qcg/static/qcg/main.css | 1 + qcg/templates/qcg/job_new.html | 63 ++++++++++++++++-------------------- qcg/views.py | 69 +++++++++++++++++++++++++++++++++++++++- 6 files changed, 118 insertions(+), 71 deletions(-) delete mode 100644 qcg/fields.py diff --git a/qcg/fields.py b/qcg/fields.py deleted file mode 100644 index 3702aad..0000000 --- a/qcg/fields.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.forms import ChoiceField, MultipleChoiceField - - -class PredefinedChoiceField(ChoiceField): - def valid_value(self, value): - # any value is valid - return True - - -class MultiplePredefinedChoiceField(MultipleChoiceField, PredefinedChoiceField): - pass diff --git a/qcg/forms.py b/qcg/forms.py index 3109419..7c715d9 100644 --- a/qcg/forms.py +++ b/qcg/forms.py @@ -4,7 +4,6 @@ from django.core.validators import RegexValidator from django.template.defaultfilters import capfirst from pyqcg.utils import TaskStatus -from qcg.fields import PredefinedChoiceField, MultiplePredefinedChoiceField from qcg.models import Task, Allocation @@ -84,8 +83,9 @@ class JobDescriptionForm(forms.Form): APPLICATION_CHOICES = ( CHOICES_PLACEHOLDER, ('bash', 'BASH'), - ('python', 'Python'), + ('gromacs/4.6.3', 'GROMACS 4.6.3'), ('matlab', 'MATLAB'), + ('python', 'Python'), ) QUEUE_CHOICES = ( CHOICES_PLACEHOLDER, @@ -109,36 +109,28 @@ class JobDescriptionForm(forms.Form): ) application = forms.ChoiceField(choices=APPLICATION_CHOICES, label=u"Aplikacja", required=False) # TODO choices - executable = forms.CharField(label=u"Polecenie", max_length=500, required=False) # TODO grid ftp - arguments = forms.CharField(label=u"Argumenty", max_length=1000, required=False) - - name = forms.CharField(label=u"Nazwa", max_length=100, required=False) - note = forms.CharField(label=u"Notatka", widget=forms.Textarea(attrs={'rows': 2, 'cols': 40}), required=False) + executable = forms.CharField(label=u"Plik wykonywalny", max_length=500, required=False) # TODO grid ftp + script = forms.CharField(label=u"Skrypt", widget=forms.Textarea(attrs={'rows': 2, 'cols': 40}), required=False) # TODO saving to grid ftp + arguments = forms.MultipleChoiceField(label=u"Argumenty", required=False) + note = forms.CharField(label=u"Opis", widget=forms.Textarea(attrs={'rows': 2, 'cols': 40}), required=False) grant = forms.CharField(label=u"Grant", max_length=100, required=False) host = forms.ChoiceField(label=u"Host", choices=Host.CHOICES, required=False) - queue = PredefinedChoiceField(choices=QUEUE_CHOICES, label=u"Kolejka", required=False) + properties = forms.MultipleChoiceField(label=u"Właściwości węzłów", required=False) + queue = forms.ChoiceField(choices=QUEUE_CHOICES, label=u"Kolejka", required=False) procs = forms.IntegerField(label=u"Liczba procesów", min_value=0, required=False) nodes = forms.CharField(label=u"Topologia węzłów", max_length=10, validators=[nodes_validator], required=False) wall_time = forms.IntegerField(label=u"Wall time (s)", min_value=0, required=False) # TODO duration field memory = forms.IntegerField(label=u"Pamięć (MB)", min_value=0, required=False) memory_per_slot = forms.IntegerField(label=u"Pamięci per proces (MB)", min_value=0, required=False) + modules = forms.MultipleChoiceField(label=u"Moduły", choices=MODULES_CHOICES, required=False) # TODO choices + reservation = forms.CharField(label=u"Rezerwacja", max_length=100, required=False) # TODO grid ftp input = forms.CharField(label=u"Standardowe wejście", max_length=500, required=False) - output = forms.CharField(label=u"Standardowe wyjście", max_length=500, required=False) - error = forms.CharField(label=u"Standardowe wyjście błędów", max_length=500, required=False) stage_in = forms.CharField(label=u"Stage in", max_length=500, required=False) stage_out = forms.CharField(label=u"Stage out", max_length=500, required=False) - properties = MultiplePredefinedChoiceField(label=u"Właściwości węzłów", required=False) - modules = forms.MultipleChoiceField(label=u"Moduły", choices=MODULES_CHOICES, required=False) # TODO choices - - not_after = forms.DateTimeField(label=u"Nie później niż", required=False) - not_before = forms.DateTimeField(label=u"Nie wcześniej niż", required=False) - deadline = forms.IntegerField(label=u"Deadline (s)", min_value=0, required=False) # TODO duration field - reservation = forms.CharField(label=u"Rezerwacja", max_length=100, required=False) - monitoring = forms.BooleanField(label=u"Portal QCG-Monitoring", required=False) notify_type = forms.ChoiceField(label=u"Monitorowanie stanu", choices=NOTIFY_CHOICES, required=False, initial=0, widget=forms.RadioSelect) @@ -156,9 +148,18 @@ class JobDescriptionForm(forms.Form): widget=forms.RadioSelect) postprocess_cmd = forms.CharField(label=u"Polecenie", max_length=1000, required=False) postprocess_script = forms.CharField(label=u"Skrypt", max_length=500, required=False) # TODO grid ftp - native = MultiplePredefinedChoiceField(label=u"Parametry natywne", required=False) + native = forms.MultipleChoiceField(label=u"Opcje systemu kolejkowego", required=False) persistent = forms.BooleanField(label=u"Trwałe", required=False) - use_scratch = forms.BooleanField(label=u"Scratch", required=False) + + def __init__(self, data=None, *args, **kwargs): + super(JobDescriptionForm, self).__init__(data, *args, **kwargs) + + if data is not None: + # accept user defined choices + self.fields['queue'].choices += ((data.get('queue'), data.get('queue')), ) + self.fields['arguments'].choices += ((v, v) for v in data.getlist('arguments')) + self.fields['properties'].choices += ((v, v) for v in data.getlist('properties')) + self.fields['native'].choices += ((v, v) for v in data.getlist('native')) class EnvForm(forms.Form): diff --git a/qcg/models.py b/qcg/models.py index 451d7fb..b41fe85 100644 --- a/qcg/models.py +++ b/qcg/models.py @@ -235,6 +235,4 @@ class NodeInfo(models.Model): @staticmethod def qcg_map(qcg_node): - return {'name': qcg_node.name, - # FIXME - 'count': qcg_node.slots_count.intValue() if qcg_node.slots_count is not None else None} + return {'name': qcg_node.name, 'count': qcg_node.slots_count} diff --git a/qcg/static/qcg/main.css b/qcg/static/qcg/main.css index 4edc075..b3bdc3b 100644 --- a/qcg/static/qcg/main.css +++ b/qcg/static/qcg/main.css @@ -19,6 +19,7 @@ footer.navbar-fixed-bottom { textarea { resize: vertical; + min-height: 34px; } diff --git a/qcg/templates/qcg/job_new.html b/qcg/templates/qcg/job_new.html index d1e5de6..ad5652f 100644 --- a/qcg/templates/qcg/job_new.html +++ b/qcg/templates/qcg/job_new.html @@ -96,7 +96,6 @@
  • Zasoby
  • Pliki
  • Środowisko
  • -
  • Rezerwacja
  • Powiadomienia
  • Inne
  • @@ -111,9 +110,9 @@ - {% bootstrap_field form.executable layout="horizontal" form_group_class="form-group collapse" %} + {% bootstrap_field form.executable layout="horizontal" form_group_class="form-group collapse" %} + {% bootstrap_field form.script layout="horizontal" form_group_class="form-group collapse" %} {% bootstrap_field form.arguments layout="horizontal" %} - {% bootstrap_field form.name layout="horizontal" %} {% bootstrap_field form.note layout="horizontal" %} {% bootstrap_field form.grant layout="horizontal" %} @@ -121,23 +120,23 @@
    {% bootstrap_field form.host layout="horizontal" %} {% bootstrap_field form.queue layout="horizontal" %} + {% bootstrap_field form.properties layout="horizontal" form_group_class="form-group collapse" %} + {% 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" %} - {% bootstrap_field form.memory layout="horizontal" %} - {% bootstrap_field form.memory_per_slot layout="horizontal" %} + {% 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" %}
    {% bootstrap_field form.input layout="horizontal" %} - {% bootstrap_field form.output layout="horizontal" %} - {% bootstrap_field form.error layout="horizontal" %} {% bootstrap_field form.stage_in layout="horizontal" %} - {% bootstrap_field form.stage_out layout="horizontal" %} + {% bootstrap_field form.stage_out layout="horizontal" form_group_class="form-group collapse" %}
    - {% bootstrap_field form.properties layout="horizontal" %} {{ env_formset.management_form }}
    @@ -154,15 +153,6 @@
    - - {% bootstrap_field form.modules layout="horizontal" %} -
    - -
    - {% bootstrap_field form.not_before layout="horizontal" %} - {% bootstrap_field form.not_after layout="horizontal" %} - {% bootstrap_field form.deadline layout="horizontal" %} - {% bootstrap_field form.reservation layout="horizontal" form_group_class="form-group collapse" %}
    @@ -191,27 +181,29 @@ -
    - -
    -
    - {% for option in form.watch_output_type %} - - {% endfor %} +
    +
    + +
    +
    + {% for option in form.watch_output_type %} + + {% endfor %} +
    -
    -
    -
    +
    +
    -
    - {% bootstrap_field form.watch_output_address layout="horizontal" %} - {% bootstrap_field form.watch_output_pattern layout="horizontal" %} +
    + {% bootstrap_field form.watch_output_address layout="horizontal" %} + {% bootstrap_field form.watch_output_pattern layout="horizontal" %} +
    @@ -273,7 +265,6 @@ {% bootstrap_field form.native layout="horizontal" %} {% bootstrap_checkbox form.persistent %} - {% bootstrap_checkbox form.use_scratch %} diff --git a/qcg/views.py b/qcg/views.py index ed9eed4..c34af9b 100644 --- a/qcg/views.py +++ b/qcg/views.py @@ -12,6 +12,8 @@ from django.utils.timezone import UTC from django_openid_auth.views import make_consumer from openid.extensions import ax from pyqcg import QCG +from pyqcg.description import JobDescription +from pyqcg.utils import Credential from qcg.forms import FiltersForm, ColumnsForm, JobDescriptionForm, EnvFormSet from qcg.utils import update_user_data, paginator_context @@ -140,6 +142,7 @@ def job_details(request, job_id): return render(request, 'qcg/job.html', {'job': job}) +@login_required def task_details(request, job_id, task_id): task = get_object_or_404(request.user.tasks.select_related('job').prefetch_related('allocations'), job__job_id=job_id, task_id=task_id) @@ -147,5 +150,69 @@ def task_details(request, job_id, task_id): return render(request, 'qcg/task.html', {'task': task}) +@login_required def job_new(request): - return render(request, 'qcg/job_new.html', {'form': JobDescriptionForm(), 'env_formset': EnvFormSet()}) + if request.method == 'POST': + QCG.start() + + form = JobDescriptionForm(request.POST) + env_formset = EnvFormSet(request.POST) + + if form.is_valid() and env_formset.is_valid(): + print form.cleaned_data + + desc = JobDescription(Credential(request.session['proxy'])) + + application = form.cleaned_data['application'] + if '/' in application: + app, ver = application.split('1', 1) + desc.application.set_name(app) + desc.application.set_version(ver) + else: + desc.application.set_name(application) + + # TODO script + # TODO executable + desc.arguments = form.cleaned_data['arguments'] + desc.note = form.cleaned_data['note'] + desc.grant = form.cleaned_data['grant'] + desc.host_candidates = [(form.cleaned_data['host'], 'type?')] # FIXME WTF ?!? + desc.properties = form.cleaned_data['properties'] + # TODO queue + # TODO procs + # TODO nodes + desc.wall_time = timedelta(seconds=form.cleaned_data['wall_time']) # FIXME odpowiedni typ pola + desc.memory = form.cleaned_data['memory'] + desc.memory_per_slot = form.cleaned_data['memory_per_slot'] + desc.variable = [(env['name'], env['value']) for env in env_formset.cleaned_data if not env['DELETE']] + desc.modules = form.cleaned_data['modules'] + desc.natives = form.cleaned_data['native'] + desc.reservation = ("LOCAL", form.cleaned_data['reservation']) + # TODO input + # TODO stage_in + # TODO stage_out + # TODO monitoring + # TODO notify_type + # TODO notify_address + # TODO watch_output_type + # TODO watch_output_address + # TODO watch_output_pattern + # TODO preprocess_type + # TODO preprocess_cmd + # TODO preprocess_script + # TODO postprocess_type + # TODO postprocess_cmd + # TODO postprocess_script + desc.persistent = form.cleaned_data['persistent'] + + for prop in ('arguments', 'note', 'grant', 'host_candidates', 'wall_time', 'memory', + 'memory_per_slot', 'properties', 'variable', 'modules', 'natives', 'persistent', 'reservation'): + print prop, type(getattr(desc, prop)), repr(getattr(desc, prop)) + + print desc.xml_description + + else: + form = JobDescriptionForm() + env_formset = EnvFormSet() + + return render(request, 'qcg/job_new.html', {'form': form, 'env_formset': env_formset}) -- 1.7.9.5