source: flex_extract.git/python/install.py @ e1228f3

ctbtodev
Last change on this file since e1228f3 was ff99eae, checked in by Anne Philipp <anne.philipp@…>, 6 years ago

completed application of pep8 style guide and pylint investigations. added documentation almost everywhere

  • Property mode set to 100755
File size: 16.5 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#************************************************************************
4# ToDo AP
5# - create a class Installation and divide installation in 3 subdefs for
6#   ecgate, local and cca seperatly
7# - Change History ist nicht angepasst ans File! Original geben lassen
8#************************************************************************
9#*******************************************************************************
10# @Author: Leopold Haimberger (University of Vienna)
11#
12# @Date: November 2015
13#
14# @Change History:
15#
16#    February 2018 - Anne Philipp (University of Vienna):
17#        - applied PEP8 style guide
18#        - added documentation
19#        - moved install_args_and_control in here
20#
21# @License:
22#    (C) Copyright 2015-2018.
23#
24#    This software is licensed under the terms of the Apache Licence Version 2.0
25#    which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
26#
27# @Program Functionality:
28#    Depending on the selected installation environment (locally or on the
29#    ECMWF server ecgate or cca) the program extracts the commandline
30#    arguments and the CONTROL file parameter and prepares the corresponding
31#    environment. The necessary files are collected in a tar-ball and placed
32#    at the target location. There its untared, the environment variables will
33#    be set and the Fortran code will be compiled. If the ECMWF environment is
34#    selected a job script is prepared and submitted for the remaining
35#    configurations after putting the tar-ball to the target ECMWF server.
36#
37# @Program Content:
38#    - main
39#    - install_args_and_control
40#    - install_via_gateway
41#
42#*******************************************************************************
43
44# ------------------------------------------------------------------------------
45# MODULES
46# ------------------------------------------------------------------------------
47import os
48import sys
49import glob
50import subprocess
51import inspect
52from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
53
54# software specific classes and modules from flex_extract
55from ControlFile import ControlFile
56
57# add path to pythonpath so that python finds its buddies
58LOCAL_PYTHON_PATH = os.path.dirname(os.path.abspath(
59    inspect.getfile(inspect.currentframe())))
60if LOCAL_PYTHON_PATH not in sys.path:
61    sys.path.append(LOCAL_PYTHON_PATH)
62
63# ------------------------------------------------------------------------------
64# FUNCTIONS
65# ------------------------------------------------------------------------------
66def main():
67    '''
68    @Description:
69        Controls the installation process. Calls the installation function
70        if target is specified.
71
72    @Intput:
73        <nothing>
74
75    @Return:
76        <nothing>
77    '''
78
79    os.chdir(LOCAL_PYTHON_PATH)
80    args, c = install_args_and_control()
81
82    if args.install_target is not None:
83        install_via_gateway(c, args.install_target)
84    else:
85        print 'Please specify installation target (local|ecgate|cca)'
86        print 'use -h or --help for help'
87
88    sys.exit()
89
90    return
91
92
93def install_args_and_control():
94    '''
95    @Description:
96        Assigns the command line arguments for installation and reads
97        CONTROL file content. Apply default values for non mentioned arguments.
98
99    @Input:
100        <nothing>
101
102    @Return:
103        args: instance of ArgumentParser
104            Contains the commandline arguments from script/program call.
105
106        c: instance of class ControlFile
107            Contains all necessary information of a CONTROL file. The parameters
108            are: DAY1, DAY2, DTIME, MAXSTEP, TYPE, TIME, STEP, CLASS, STREAM,
109            NUMBER, EXPVER, GRID, LEFT, LOWER, UPPER, RIGHT, LEVEL, LEVELIST,
110            RESOL, GAUSS, ACCURACY, OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA,
111            SMOOTH, FORMAT, ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS,
112            ECFSDIR, MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR
113            For more information about format and content of the parameter see
114            documentation.
115    '''
116    parser = ArgumentParser(description='Install ECMWFDATA software locally or \
117                            on ECMWF machines',
118                            formatter_class=ArgumentDefaultsHelpFormatter)
119
120    parser.add_argument('--target', dest='install_target',
121                        help="Valid targets: local | ecgate | cca , \
122                        the latter two are at ECMWF")
123    parser.add_argument("--makefile", dest="makefile",
124                        help='Name of Makefile to use for compiling CONVERT2')
125    parser.add_argument("--ecuid", dest="ecuid",
126                        help='user id at ECMWF')
127    parser.add_argument("--ecgid", dest="ecgid",
128                        help='group id at ECMWF')
129    parser.add_argument("--gateway", dest="gateway",
130                        help='name of local gateway server')
131    parser.add_argument("--destination", dest="destination",
132                        help='ecaccess destination, e.g. leo@genericSftp')
133
134    parser.add_argument("--flexpart_root_scripts", dest="flexpart_root_scripts",
135                        help="FLEXPART root directory on ECMWF servers \
136                        (to find grib2flexpart and COMMAND file)\n\
137                        Normally ECMWFDATA resides in the scripts directory \
138                        of the FLEXPART distribution, thus the:")
139
140# arguments for job submission to ECMWF, only needed by submit.py
141    parser.add_argument("--job_template", dest='job_template',
142                        default="job.temp.o",
143                        help="job template file for submission to ECMWF")
144
145    parser.add_argument("--controlfile", dest="controlfile",
146                        default='CONTROL.temp',
147                        help="file with CONTROL parameters")
148
149    args = parser.parse_args()
150
151    try:
152        c = ControlFile(args.controlfile)
153    except IOError:
154        print 'Could not read CONTROL file "' + args.controlfile + '"'
155        print 'Either it does not exist or its syntax is wrong.'
156        print 'Try "' + sys.argv[0].split('/')[-1] + \
157              ' -h" to print usage information'
158        exit(1)
159
160    if args.install_target != 'local':
161        if args.ecgid is None or args.ecuid is None or args.gateway is None \
162           or args.destination is None:
163            print 'Please enter your ECMWF user id and group id as well as \
164                   the \nname of the local gateway and the ectrans \
165                   destination '
166            print 'with command line options --ecuid --ecgid \
167                   --gateway --destination'
168            print 'Try "' + sys.argv[0].split('/')[-1] + \
169                  ' -h" to print usage information'
170            print 'Please consult ecaccess documentation or ECMWF user support \
171                   for further details'
172            sys.exit(1)
173        else:
174            c.ecuid = args.ecuid
175            c.ecgid = args.ecgid
176            c.gateway = args.gateway
177            c.destination = args.destination
178
179    if args.makefile:
180        c.makefile = args.makefile
181
182    if args.install_target == 'local':
183        if args.flexpart_root_scripts is None:
184            c.flexpart_root_scripts = '../'
185        else:
186            c.flexpart_root_scripts = args.flexpart_root_scripts
187
188    if args.install_target != 'local':
189        if args.flexpart_root_scripts is None:
190            c.ec_flexpart_root_scripts = '${HOME}'
191        else:
192            c.ec_flexpart_root_scripts = args.flexpart_root_scripts
193
194    return args, c
195
196
197def install_via_gateway(c, target):
198    '''
199    @Description:
200        Perform the actual installation on local machine or prepare data
201        transfer to remote gate and submit a job script which will
202        install everything on the remote gate.
203
204    @Input:
205        c: instance of class ControlFile
206            Contains all necessary information of a CONTROL file. The parameters
207            are: DAY1, DAY2, DTIME, MAXSTEP, TYPE, TIME, STEP, CLASS, STREAM,
208            NUMBER, EXPVER, GRID, LEFT, LOWER, UPPER, RIGHT, LEVEL, LEVELIST,
209            RESOL, GAUSS, ACCURACY, OMEGA, OMEGADIFF, ETA, ETADIFF, DPDETA,
210            SMOOTH, FORMAT, ADDPAR, WRF, CWC, PREFIX, ECSTORAGE, ECTRANS,
211            ECFSDIR, MAILOPS, MAILFAIL, GRIB2FLEXPART, FLEXPARTDIR
212            For more information about format and content of the parameter see
213            documentation.
214
215        target: string
216            The target where the installation should be processed.
217            E.g. "local", "ecgate" or "cca"
218
219    @Return:
220        <nothing>
221    '''
222    ecd = c.ecmwfdatadir
223    template = ecd + 'python/compilejob.temp'
224    job = ecd + 'python/compilejob.ksh'
225    fo = open(job, 'w')
226#AP could do with open(template) as f, open(job, 'w') as fo:
227#AP or nested with statements
228    with open(template) as f:
229        fdata = f.read().split('\n')
230        for data in fdata:
231            if 'MAKEFILE=' in data:
232                if c.makefile is not None:
233                    data = 'export MAKEFILE=' + c.makefile
234            if 'FLEXPART_ROOT_SCRIPTS=' in data:
235                if c.flexpart_root_scripts != '../':
236                    data = 'export FLEXPART_ROOT_SCRIPTS=' + \
237                            c.flexpart_root_scripts
238                else:
239                    data = 'export FLEXPART_ROOT_SCRIPTS=$HOME'
240            if target.lower() != 'local':
241                if '--workdir' in data:
242                    data = '#SBATCH --workdir=/scratch/ms/' + c.ecgid + \
243                            '/' + c.ecuid
244                if '##PBS -o' in data:
245                    data = '##PBS -o /scratch/ms/' + c.ecgid + '/' + c.ecuid + \
246                            'flex_ecmwf.$Jobname.$Job_ID.out'
247                if 'FLEXPART_ROOT_SCRIPTS=' in data:
248                    if c.ec_flexpart_root_scripts != '../':
249                        data = 'export FLEXPART_ROOT_SCRIPTS=' + \
250                                c.ec_flexpart_root_scripts
251                    else:
252                        data = 'export FLEXPART_ROOT_SCRIPTS=$HOME'
253            fo.write(data + '\n')
254    f.close()
255    fo.close()
256
257    if target.lower() != 'local':
258        template = ecd + 'python/job.temp.o'
259#AP hier eventuell Zeile für Zeile lesen und dann if Entscheidung
260        with open(template) as f:
261            fdata = f.read().split('\n')
262        f.close()
263        fo = open(template[:-2], 'w')
264        for data in fdata:
265            if '--workdir' in data:
266                data = '#SBATCH --workdir=/scratch/ms/' + c.ecgid + \
267                        '/' + c.ecuid
268            if '##PBS -o' in data:
269                data = '##PBS -o /scratch/ms/' + c.ecgid + '/' + \
270                        c.ecuid + 'flex_ecmwf.$Jobname.$Job_ID.out'
271            if  'export PATH=${PATH}:' in data:
272                data += c.ec_flexpart_root_scripts + '/ECMWFDATA7.1/python'
273            if 'cat>>' in data or 'cat >>' in data:
274                i = data.index('>')
275                fo.write(data[:i] + data[i+1:] + '\n')
276                fo.write('GATEWAY ' + c.gateway + '\n')
277                fo.write('DESTINATION ' + c.destination + '\n')
278                fo.write('EOF\n')
279
280            fo.write(data + '\n')
281        fo.close()
282
283        job = ecd + 'python/ECMWF_ENV'
284        with open(job, 'w') as fo:
285            fo.write('ECUID ' + c.ecuid + '\n')
286            fo.write('ECGID ' + c.ecgid + '\n')
287            fo.write('GATEWAY ' + c.gateway + '\n')
288            fo.write('DESTINATION ' + c.destination + '\n')
289        fo.close()
290
291    if target.lower() == 'local':
292        # compile CONVERT2
293        if c.flexpart_root_scripts is None or c.flexpart_root_scripts == '../':
294            print 'Warning: FLEXPART_ROOT_SCRIPTS has not been specified'
295            print 'Only CONVERT2 will be compiled in ' + ecd + '/../src'
296        else:
297            c.flexpart_root_scripts = os.path.expandvars(os.path.expanduser(
298                c.flexpart_root_scripts))
299            if os.path.abspath(ecd) != os.path.abspath(c.flexpart_root_scripts):
300                os.chdir('/')
301                p = subprocess.check_call(['tar', '-cvf',
302                                           ecd + '../ECMWFDATA7.1.tar',
303                                           ecd + 'python',
304                                           ecd + 'grib_templates',
305                                           ecd + 'src'])
306                try:
307                    os.makedirs(c.flexpart_root_scripts + '/ECMWFDATA7.1')
308                finally:
309                    pass
310                os.chdir(c.flexpart_root_scripts + '/ECMWFDATA7.1')
311                p = subprocess.check_call(['tar', '-xvf',
312                                           ecd + '../ECMWFDATA7.1.tar'])
313                os.chdir(c.flexpart_root_scripts + '/ECMWFDATA7.1/src')
314
315        os.chdir('../src')
316        print(('install ECMWFDATA7.1 software on ' + target + ' in directory '
317               + os.getcwd()))
318        if c.makefile is None:
319            makefile = 'Makefile.local.ifort'
320        else:
321            makefile = c.makefile
322        flist = glob.glob('*.mod') + glob.glob('*.o')
323        if flist:
324            p = subprocess.check_call(['rm'] + flist)
325        try:
326            print 'Using makefile: ' + makefile
327            p = subprocess.check_call(['make', '-f', makefile])
328            p = subprocess.check_call(['ls', '-l', 'CONVERT2'])
329        except subprocess.CalledProcessError as e:
330            print 'compile failed with the following error:'
331            print e.output
332            print 'please edit ' + makefile + \
333                  ' or try another Makefile in the src directory.'
334            print 'most likely GRIB_API_INCLUDE_DIR, GRIB_API_LIB  \
335                   and EMOSLIB must be adapted.'
336            print 'Available Makefiles:'
337            print glob.glob('Makefile*')
338    elif target.lower() == 'ecgate':
339        os.chdir('/')
340        p = subprocess.check_call(['tar', '-cvf',
341                                   ecd + '../ECMWFDATA7.1.tar',
342                                   ecd + 'python',
343                                   ecd + 'grib_templates',
344                                   ecd + 'src'])
345        try:
346            p = subprocess.check_call(['ecaccess-file-put',
347                                       ecd + '../ECMWFDATA7.1.tar',
348                                       'ecgate:/home/ms/' + c.ecgid + '/' +
349                                       c.ecuid + '/ECMWFDATA7.1.tar'])
350        except subprocess.CalledProcessError as e:
351            print 'ecaccess-file-put failed! \
352                   Probably the eccert key has expired.'
353            exit(1)
354
355        try:
356            p = subprocess.check_call(['ecaccess-job-submit',
357                                       '-queueName',
358                                       target,
359                                       ecd + 'python/compilejob.ksh'])
360            print 'compilejob.ksh has been submitted to ecgate for  \
361                   installation in ' + c.ec_flexpart_root_scripts + \
362                   '/ECMWFDATA7.1'
363            print 'You should get an email with subject flexcompile within  \
364                   the next few minutes'
365        except subprocess.CalledProcessError as e:
366            print 'ecaccess-job-submit failed!'
367            exit(1)
368
369    elif target.lower() == 'cca':
370        os.chdir('/')
371        p = subprocess.check_call(['tar', '-cvf',
372                                   ecd + '../ECMWFDATA7.1.tar',
373                                   ecd + 'python',
374                                   ecd + 'grib_templates',
375                                   ecd + 'src'])
376        try:
377            p = subprocess.check_call(['ecaccess-file-put',
378                                       ecd + '../ECMWFDATA7.1.tar',
379                                       'cca:/home/ms/' + c.ecgid + '/' +
380                                       c.ecuid + '/ECMWFDATA7.1.tar'])
381        except subprocess.CalledProcessError as e:
382            print 'ecaccess-file-put failed! \
383                   Probably the eccert key has expired.'
384            exit(1)
385
386        try:
387            p = subprocess.check_call(['ecaccess-job-submit',
388                                       '-queueName',
389                                       target,
390                                       ecd + 'python/compilejob.ksh'])
391            print 'compilejob.ksh has been submitted to cca for installation in ' +\
392                  c.ec_flexpart_root_scripts + '/ECMWFDATA7.1'
393            print 'You should get an email with subject flexcompile \
394                   within the next few minutes'
395        except subprocess.CalledProcessError as e:
396            print 'ecaccess-job-submit failed!'
397            exit(1)
398
399    else:
400        print 'ERROR: unknown installation target ', target
401        print 'Valid targets: ecgate, cca, local'
402
403    return
404
405
406if __name__ == "__main__":
407    main()
Note: See TracBrowser for help on using the repository browser.
hosted by ZAMG