from flask import current_app, g, jsonify, request, send_file
from flask_login import login_required
from fplaneserver.flask import app
import datetime as dt
import os
[docs]@app.route('/fplane/', methods=['GET'])
@app.route('/fplane/<string:datestr>', methods=['GET'])
def get_current_fplane(datestr=None):
"""Get the fplane file for a given date, or the current one of datestr
is not given or is one of latest or current
.. :quickref: Fplane; Get an fplane file
Retrieve the the fplane file for a given date or the current one.
"""
g.logger.debug('Connecting to database', extra=g.extra)
from awise.common.config.Profile import profiles
profiles.create_profile(username=current_app.config['DB_USERNAME'],
password=current_app.config['DB_PASSWORD'],
dbname=current_app.config['DB_NAME'],
project=current_app.config['DB_PROJECT'])
from awise.common.database.Database import database
if not database.connected(): # pragma: nocover
database.connect()
from hetwise.Spectrograph import write_fplane, NoIFUError
from fplaneserver.lib.helpers import get_bool
g.logger.debug('Retrieving fplane file', extra=g.extra)
try:
spooldir = current_app.config['SPOOL_DIR']
if not os.path.exists(spooldir) or not os.path.isdir(spooldir):
raise FileNotFoundError
except KeyError: # pragma: nocover
return jsonify({'error': 'Spooldir not configured!'}), 500
except FileNotFoundError:
return jsonify({'error': 'Spooldir not found!'}), 500
if datestr is None or datestr in ['latest', 'current']:
datestr = dt.datetime.utcnow().strftime('%Y%m%d')
g.logger.debug('Attempting to retrieve fplane file for %s' % datestr,
extra=g.extra)
data = request.args
fname = 'fplane'+datestr+'.txt'
pname = spooldir + '/' + fname
if os.path.exists(pname) and get_bool(data, 'cache', False):
# The use of cachedd version should be used carefully,
# the server doesn't know if the database was changed.
g.logger.debug('Sending cached file', extra=g.extra)
else:
try:
g.logger.info('Requesting for %s' % datestr, extra=g.extra)
write_fplane(pname, datestr, verbose=False,
full_fplane=get_bool(data, 'full_fplane', True),
use_ifupos=get_bool(data, 'actual_pos', False))
except IndexError:
emsg = 'Failed to find virus instrument in database'
g.logger.error(emsg, extra=g.extra)
return jsonify(emsg), 400
except NoIFUError as e:
g.logger.error('Writing fplane file %s failed with %s'
% (fname, str(e)), extra=g.extra)
return jsonify(str(e)), 400
except Exception as e: # pragma: nocover
g.logger.exception(e, extra=g.extra)
g.logger.error('Writing fplane file %s failed with %s'
% (fname, str(e)), extra=g.extra)
return jsonify(str(e)), 400
return send_file(pname, as_attachment=True)
[docs]@app.route('/fplane', methods=['POST'])
@login_required
def update_fplane():
"""Update the spectrograph configuration
.. :quickref: Fplane; Update spectrograph config
The datestr is used as the starting date of the new configuration
The data section of the request must be a json dictionary.
Its structure must be::
{config: config dictionary
commit: True | False}
The ``config`` is the dictionary retrieved from TCS using::
syscmd -V 'get_hardware_status'
The ``commit`` is boolean flag, specifying if the update should be
commited to the database
The fplaneserver updates the database tables and returns a new fplane file.
"""
g.logger.debug('Connecting to database', extra=g.extra)
from awise.common.config.Profile import profiles
profiles.create_profile(username=current_app.config['DB_USERNAME'],
password=current_app.config['DB_PASSWORD'],
dbname=current_app.config['DB_NAME'],
project=current_app.config['DB_PROJECT'])
from awise.common.database.Database import database
if not database.connected(): # pragma: nocover
database.connect()
from hetwise.util.MailHandler import send_mail
from fplaneserver.lib.helpers import parse_config, create_ifus, get_bool, \
ParserError, NoSpectrographError
g.logger.debug('Updating fplane', extra=g.extra)
data = request.get_json(force=True, silent=True)
if not data:
return jsonify({'error': 'No data in request'}), 400
g.logger.debug('Data is: %s' % str(data), extra=g.extra)
if 'config' not in data:
return jsonify({'error': 'No configuration dict in request'}), 400
config = data['config']
try:
if isinstance(config, str):
# Try to load from string, this might throw a ValueError
import ast
config = ast.literal_eval(config)
if not isinstance(config, dict):
raise ValueError()
except ValueError:
return jsonify({'error': 'configuration must be a dict or string'
' of a dict!'}), 400
g.logger.debug('Config is: %s' % str(config), extra=g.extra)
try:
dtime, specconf = parse_config(config)
except (ParserError, NoSpectrographError) as e:
g.logger.error('Failed to parse configuration!', extra=g.extra)
return jsonify(str(e)), 400
except Exception as e:
g.logger.exception(e, extra=g.extra)
g.logger.error('Failed to parse configuration!', extra=g.extra)
return jsonify(str(e)), 400
fromaddr = 'hetdex@mpe.mpg.de'
toaddr = 'snigula@mpe.mpg.de'
commit = get_bool(data, 'commit', False)
try:
logstr = create_ifus(specconf, dtime, commit=commit,
check_time=get_bool(data, 'check_time', True))
if len(logstr):
g.logger.info(logstr, extra=g.extra)
try:
if commit:
send_mail(fromaddr, toaddr, 'Fplane configuration updated',
logstr)
else:
send_mail(fromaddr, toaddr,
'Fplane configuration would be updated', logstr)
except ConnectionRefusedError: # pragma: nocover
g.logger.error('Failed to send mail!', extra=g.extra)
except Exception as e:
g.logger.exception(e.args[0], extra=g.extra)
g.logger.error('Failed to update configuration!', extra=g.extra)
try:
send_mail(fromaddr, toaddr, 'Fplane configuration update failed',
e.args[1]+e.args[0])
except ConnectionRefusedError: # pragma: nocover
g.logger.error('Failed to send mail!', extra=g.extra)
return jsonify(str(e)), 400
if len(logstr):
if commit:
return 'Spectrographs updated and commited', 200
else:
return 'Spectrographs updated and NOT commited', 200
else:
return 'No spectrographs updated, no changes found', 200