set Cache-Control header for restricted views
[qcg-portal.git] / qcg / utils.py
1 # coding=utf-8
2
3 from functools import wraps
4
5 import os
6 import string
7 import random
8
9 from django.contrib.auth.decorators import login_required
10 from django.core.paginator import Paginator
11 from django.utils.formats import date_format
12 from django.utils.timezone import localtime
13 from django.views.decorators.cache import cache_control
14 from pyqcg import QCG
15 from pyqcg.utils import Credential
16 from pyqcg.description import JobDescription
17
18 from filex.ftp import FTPOperation
19 from qcg import constants
20
21 from django.utils import encoding
22
23 def get_attributes(obj, attrs):
24     return {name: getattr(obj, name) for name in attrs if getattr(obj, name) is not None}
25
26
27 def username_from_dn(dn):
28     _, username = dn.rsplit('=', 1)
29
30     return username
31
32
33 def try_parse_int(s, default=None, base=10):
34     try:
35         return int(s, base)
36     except (TypeError, ValueError):
37         return default
38
39
40 def paginator_context(request, objects, per_page=constants.PER_PAGE):
41     paginator = Paginator(objects, per_page)
42
43     page_num = try_parse_int(request.GET.get('page'), 1)
44     if not (1 <= page_num <= paginator.num_pages):
45         page_num = 1
46
47     pages_range = range(max(2, min(page_num - 2, paginator.num_pages - 4)),
48                         min(max(page_num + 2, 5), paginator.num_pages) + 1)
49
50     return {'page': paginator.page(page_num), 'num_pages': paginator.num_pages, 'pages_range': pages_range}
51
52
53 def localtime_str(datetime):
54     return date_format(localtime(datetime), 'DATETIME_FORMAT')
55
56
57 def random_id(size=8, chars=string.ascii_uppercase + string.digits):
58     return ''.join(random.choice(chars) for _ in range(size))
59
60
61 def chunks(seq, size):
62     return (seq[pos:pos + size] for pos in xrange(0, len(seq), size))
63
64 def generate_md_inputfile(params):
65     md_input = list()
66     # Opis pliku wyjsciowego
67     opis=params['note'][:80]
68     md_input.append(encoding.smart_str(opis, encoding='ascii', errors='ignore'))
69     # Dane kontrolne obliczen
70     md_input.append('SEED=-3059743 PDBREF ONE_LETTER MD EXTCONF RESCALE_MODE=2')
71     ctl_data='nstep='+str(params['nstep'])+' ntwe='+str(params['ntwe'])
72     ctl_data+=' ntwx='+str(params['ntwx'])+' dt='+str(params['dt'])+' damax='+str(params['damax'])+'lang=0 tbf'
73     md_input.append('{:<79}&'.format(ctl_data))
74     md_input.append('tau_bath=1.0 t_bath=300 reset_vel=10000 respa ntime_split=1 maxtime_split=512')
75     # Paramatry pól siłowych
76     if params['force_field'] == 'GAB':
77         # Wagi pola GAB
78         md_input.append('WLONG=1.35279 WSCP=1.59304 WELEC=0.71534 WBOND=1.00000 WANG=1.13873            &')
79         md_input.append('WSCLOC=0.16258 WTOR=1.98599 WTORD=1.57069 WCORRH=0.42887 WCORR5=0.00000        &')
80         md_input.append('WCORR6=0.00000 WEL_LOC=0.16036 WTURN3=1.68722 WTURN4=0.66230 WTURN6=0.00000    &')
81         md_input.append('WVDWPP=0.11371 WHPB=1.00000                                                    &')
82         md_input.append('CUTOFF=7.00000 WCORR4=0.00000 WSCCOR=0.0')
83     else:
84         # Wagi pola E0LLY
85         md_input.append('WLONG=1.00000 WSCP=1.23315 WELEC=0.84476 WBOND=1.00000 WANG=0.62954            &')
86         md_input.append('WSCLOC=0.10554 WTOR=1.84316 WTORD=1.26571 WCORRH=0.19212 WCORR5=0.00000        &')
87         md_input.append('WCORR6=0.00000 WEL_LOC=0.37357 WTURN3=1.40323 WTURN4=0.64673 WTURN6=0.00000    &')
88         md_input.append('WVDWPP=0.23173 WHPB=1.00000 WSCCOR=0.0                                         &')
89         md_input.append('CUTOFF=7.00000 WCORR4=0.00000')
90     # Plik PDB    
91     md_input.append(params['pdb_file'].split('/')[-1])
92     # Sekwencja aminokwasów
93     md_input.append(len(params['sequence']))
94     seq_str=params['sequence']
95     while seq_str:
96         md_input.append(seq_str[:80])
97         seq_str=seq_str[80:]
98     md_input.append(' 0')
99     md_input.append(' 0')
100     
101     return md_input
102
103
104 def to_job_desc(params, proxy):
105     QCG.start()
106     desc = JobDescription(Credential(proxy))
107
108     direct_map = ('env_variables', 'executable', 'arguments', 'note', 'grant', 'hosts', 'properties', 'queue', 'procs',
109                   'wall_time', 'memory', 'memory_per_slot', 'modules', 'input', 'stage_in', 'native', 'notify',
110                   'preprocess', 'postprocess', 'persistent')
111
112     for name in direct_map:
113         if params[name]:
114             setattr(desc, name, params[name])
115
116     if params['application']:
117         desc.set_application(*params['application'])
118         desc.stage_in += [params['master_file']]
119         desc.arguments.insert(0, os.path.basename(params['master_file']))
120     if params['script']:
121         ftp = FTPOperation(proxy)
122
123         ftp.mkdir(constants.QCG_DATA_URL, parents=True)
124         url = os.path.join(constants.QCG_DATA_URL, 'script.{}.sh'.format(random_id()))
125         ftp.put(url)
126
127         for chunk in chunks(params['script'], 4096):
128             ftp.stream.put(chunk)
129         ftp.stream.put(None)
130         ftp.wait()
131
132         desc.executable = url
133     if params['nodes']:
134         desc.set_nodes(*params['nodes'])
135     if params['reservation']:
136         desc.set_reservation(params['reservation'])
137     if params['watch_output']:
138         desc.set_watch_output(params['watch_output'], params['watch_output_pattern'])
139
140     # TODO monitoring
141     
142     return desc
143
144
145 def to_form_data(xml):
146     # prevent circular import errors
147     from forms import JobDescriptionForm
148
149     QCG.start()
150     desc = JobDescription()
151     desc.xml_description = xml
152
153     direct_map = ('env_variables', 'executable', 'arguments', 'note', 'grant', 'hosts', 'properties', 'queue', 'procs',
154                   'wall_time', 'memory', 'memory_per_slot', 'modules', 'input', 'stage_in', 'native', 'persistent')
155
156     params = {}
157     for name in direct_map:
158         attr = getattr(desc, name)
159         if isinstance(attr, bool) or attr:
160             params[name] = attr
161
162     if desc.application is not None:
163         app_name, app_ver = desc.application
164         params['application'] = app_name if app_ver is None else app_name + '/' + app_name
165         stage_in = params['stage_in']
166         params['stage_in'], params['master_file'] = stage_in[:-1], stage_in[-1]
167         params['arguments'] = params['arguments'][1:]
168     if desc.nodes is not None:
169         params['nodes'] = ':'.join(map(str, desc.nodes))
170     if desc.reservation is not None:
171         res_id, res_type = desc.reservation
172         params['reservation'] = res_id
173     if desc.notify is not None:
174         params['notify_type'], params['notify_address'] = desc.notify.split(':')
175     if desc.watch_output is not None:
176         watch_output, params['watch_output_pattern'] = desc.watch_output
177         params['watch_output_type'], params['watch_output_address'] = watch_output.split(':')
178     if desc.preprocess is not None:
179         if desc.preprocess.startswith('gsiftp://'):
180             params['preprocess_type'] = JobDescriptionForm.Process.SCRIPT
181             params['preprocess_script'] = desc.preprocess
182         else:
183             params['preprocess_type'] = JobDescriptionForm.Process.CMD
184             params['preprocess_cmd'] = desc.preprocess
185     if desc.postprocess is not None:
186         if desc.postprocess.startswith('gsiftp://'):
187             params['postprocess_type'] = JobDescriptionForm.Process.SCRIPT
188             params['postprocess_script'] = desc.postprocess
189         else:
190             params['postprocess_type'] = JobDescriptionForm.Process.CMD
191             params['postprocess_cmd'] = desc.postprocess
192
193     return params
194
195
196 def restricted(view):
197     return wraps(view)(cache_control(no_cache=True, must_revalidate=True, no_store=True)(login_required(view)))