# Copyright 2018 AT&T Intellectual Property. All other rights reserved. # # Licensed under the Apache License, Version 2.0 (the 'License'); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an 'AS IS' BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import json import logging import os import sys import click import yaml from flask import Flask, request, render_template, send_from_directory from flask_bootstrap import Bootstrap app_path = os.path.dirname(os.path.abspath(__file__)) app = Flask('Yaml Editor!', template_folder=os.path.join(app_path, 'templates'), static_folder=os.path.join(app_path, 'static')) Bootstrap(app) logging.getLogger('werkzeug').setLevel(logging.ERROR) LOG = app.logger @app.route('/favicon.ico') def favicon(): return send_from_directory(app.static_folder, 'favicon.ico') @app.route('/', methods=['GET', 'POST']) def index(): """Renders index page to edit provided yaml file.""" LOG.info('Rendering yaml file for editing') with open(app.config['YAML_FILE']) as file_obj: data = yaml.safe_load(file_obj) return render_template('yaml.html', data=json.dumps(data), change_str=app.config['STRING_TO_CHANGE']) @app.route('/save', methods=['POST']) def save(): """Save current progress on file.""" LOG.info('Saving edited inputs from user to yaml file') out = request.json.get('yaml_data') with open(app.config['YAML_FILE'], 'w') as file_obj: yaml.safe_dump(out, file_obj, default_flow_style=False) return "Data saved successfully!" @app.route('/saveExit', methods=['POST']) def save_exit(): """Save current progress on file and shuts down the server.""" LOG.info('Saving edited inputs from user to yaml file and shutting' ' down server') out = request.json.get('yaml_data') with open(app.config['YAML_FILE'], 'w') as file_obj: yaml.safe_dump(out, file_obj, default_flow_style=False) func = request.environ.get('werkzeug.server.shutdown') if func: func() return "Saved successfully, Shutting down app! You may close the tab!" @app.errorhandler(404) def page_not_found(e): """Serves 404 error.""" LOG.info('User tried to access unavailable page.') return '

404: Page not Found!

' def run(*args, **kwargs): """Starts the server.""" LOG.info('Initiating web server for yaml editing') port = kwargs.get('port', None) if not port: port = 8161 app.run(host='0.0.0.0', port=port, debug=False) @click.command() @click.option( '--file', '-f', required=True, type=click.File(), multiple=False, help="Path with file name to the intermediary yaml file." ) @click.option( '--host', '-h', default='0.0.0.0', type=click.STRING, multiple=False, help="Optional port parameter to run Flask on." ) @click.option( '--port', '-p', default=8161, type=click.INT, multiple=False, help="Optional port parameter to run Flask on." ) @click.option( '--string', '-s', default='#CHANGE_ME', type=click.STRING, multiple=False, help="Text which is required to be changed on yaml file." ) def main(*args, **kwargs): LOG.setLevel(logging.INFO) LOG.info('Initiating yaml-editor') try: yaml.safe_load(kwargs['file']) except yaml.YAMLError as e: LOG.error('EXITTING - Please provide a valid yaml file.') if hasattr(e, 'problem_mark'): mark = e.problem_mark LOG.error("Error position: ({0}:{1})".format( mark.line + 1, mark.column + 1)) sys.exit(2) except Exception: LOG.error('EXITTING - Please provide a valid yaml file.') sys.exit(2) LOG.info(""" ############################################################################## Please go to http://{0}:{1}/ to edit your yaml file. ############################################################################## """.format(kwargs['host'], kwargs['port'])) app.config['YAML_FILE'] = kwargs['file'].name app.config['STRING_TO_CHANGE'] = kwargs['string'] run(*args, **kwargs) if __name__ == '__main__': """Invoked when used as a script.""" main()