diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..88611d8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +# Dockerfile +FROM python:3.9-slim + +WORKDIR /app + +# Update pip and setuptools +RUN pip install --no-cache-dir --upgrade pip setuptools + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY app.py . +COPY templates templates/ + +CMD ["python", "app.py"] \ No newline at end of file diff --git a/app.py b/app.py new file mode 100644 index 0000000..ad37924 --- /dev/null +++ b/app.py @@ -0,0 +1,71 @@ +# app.py +from flask import Flask, send_from_directory, jsonify, request +import yaml +import os +from dotenv import load_dotenv, set_key +import tempfile +import shutil + +app = Flask(__name__) + +CONFIG_DIR = '/app/config' +ENV_FILE = '/app/.env' +ENV_SECRETS_FILE = '/app/env.device-secrets' + +def load_yaml(filename): + try: + with open(os.path.join(CONFIG_DIR, filename), 'r') as file: + return yaml.safe_load(file) + except FileNotFoundError: + return {} + +def save_yaml(filename, data): + with open(os.path.join(CONFIG_DIR, filename), 'w') as file: + yaml.dump(data, file, default_flow_style=False) + +def load_env(filename): + if not os.path.exists(filename): + return {} + load_dotenv(filename) + return {key: os.getenv(key) for key in os.environ} + +def save_env(filename, data): + # Create a temporary file + fd, path = tempfile.mkstemp() + try: + with os.fdopen(fd, 'w') as temp: + for key, value in data.items(): + temp.write(f"{key}={value}\n") + + # Replace the original file with the temporary file + shutil.move(path, filename) + finally: + # Clean up the temporary file in case of an error + if os.path.exists(path): + os.unlink(path) + +@app.route('/') +def index(): + return send_from_directory('templates', 'index.html') + +@app.route('/api/config/', methods=['GET', 'POST']) +def handle_config(config_type): + if request.method == 'GET': + if config_type in ['ast_defaults', 'bigip_receivers']: + return jsonify(load_yaml(f'{config_type}.yaml')) + elif config_type == 'env': + return jsonify(load_env(ENV_FILE)) + elif request.method == 'POST': + data = request.json + try: + if config_type in ['ast_defaults', 'bigip_receivers']: + save_yaml(f'{config_type}.yaml', data) + elif config_type == 'env': + save_env(ENV_FILE, data) + return jsonify({"status": "success"}) + except Exception as e: + app.logger.error(f"Error saving configuration: {str(e)}") + return jsonify({"status": "error", "message": str(e)}), 500 + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..fa2044d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +flask==2.0.1 +werkzeug==2.0.1 +pyyaml==5.4.1 +python-dotenv==0.19.0 \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..063c1f6 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,252 @@ + + + + + + AST Configuration + + + + + +
+

AST Configuration

+ +
+

AST Defaults

+
+ + +
+
+ + +
+
+ +

The password is stored in the .env.device-secrets file for security reasons.

+
+
+ +
+ +
+
+
+ +
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+ +
+ +
+

F5 DataFabric Export Parameters

+

Optional Parameters Required for metrics export to F5 DataFabric

+
+ + +
+
+ + +
+ +
+ +
+

Grafana Environment Variables

+

These should be updated to more secure values outside of testing environments.

+
+ + +
+
+ + +
+ +
+ +
+

BIG-IP Receivers

+
+

Receiver {{ index + 1 }}

+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + +
+
+ +
+ + +
+ +
+

Environment Variables

+
+ + +
+ +
+
+ + + + \ No newline at end of file