Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/umar #4

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 45 additions & 2 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
from flask import Flask, render_template, request, jsonify, session # external
from werkzeug.security import generate_password_hash # built-in
from flask_session import Session # external
import logging
from logging.handlers import RotatingFileHandler


import os, shutil, signal, atexit, json, yaml, logging, tempfile # built-in
import docker, ansible_runner # external
Expand Down Expand Up @@ -125,7 +128,7 @@ def cleanup_files(file_paths):
if os.path.exists(file_path):
os.unlink(file_path) # removes the file


def run_ansible(hosts, command, type): # [NOTE] shell command execution will not work with other shells like zsh, fish, etc.
"""
Runs an Ansible playbook on specified hosts with a given command.
Expand Down Expand Up @@ -206,6 +209,30 @@ def cleanup(action='stop'):

app.logger.info("Cleanup complete.")

import logging
from logging.handlers import RotatingFileHandler

# Set up logging
log_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')

# Create a file handler for logging to a file (overwrite the file each time)
log_file = "app.log" # The log file name
file_handler = logging.FileHandler(log_file, mode='w') # 'w' mode will overwrite the file each time
file_handler.setFormatter(log_formatter)
file_handler.setLevel(logging.DEBUG) # Adjust the level as needed (DEBUG, INFO, WARNING, ERROR, CRITICAL)

# Create a console handler for logging to the terminal
console_handler = logging.StreamHandler()
console_handler.setFormatter(log_formatter)
console_handler.setLevel(logging.DEBUG) # Adjust the level as needed

# Get the app logger and set the log level
app.logger.setLevel(logging.DEBUG)
app.logger.addHandler(file_handler)
app.logger.addHandler(console_handler)

# Log a message to verify setup
app.logger.info("Logging setup complete. Logs will be saved to 'app.log' and displayed on the console.")

## ROUTES (FOR RENDERING HTML PAGES) ##
@app.route('/')
Expand Down Expand Up @@ -253,6 +280,16 @@ def SPAWN_MACHINES_ROUTE():
app.logger.error(f"Error in spawn_machines: {str(e)}")
return jsonify({"error": str(e)}), 500

@app.route('/logs', methods=['GET'])
def display_logs_from_file():
"""Render the logs HTML page with logs read directly from the log file."""
log_file_path = 'app.log' # Path to your log file
try:
with open(log_file_path, 'r') as f:
logs = f.readlines() # Read all lines from the log file
except FileNotFoundError:
logs = ["Log file not found. Please ensure the application is running and generating logs."]
return render_template('logs.html', logs=logs)

@app.route('/run_command', methods=['POST'])
def RUN_COMMAND_ROUTE():
Expand Down Expand Up @@ -391,6 +428,11 @@ def SAVE_CONFIG_ROUTE(): # [NOTE] needs more testing, [IMPROVEMENT] add error ha
with open('nginx_config.yml', 'w') as file:
yaml.dump(config, file)

# Get the list of spawned containers
machine_info = session.get('machine_info', [])
if not machine_info:
return jsonify({"message": "No machines spawned. Please spawn machines first."})

# Create a temporary inventory file
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.yml') as temp_inventory:
inventory = {
Expand Down Expand Up @@ -550,6 +592,7 @@ def SAVE_CONFIG_ROUTE(): # [NOTE] needs more testing, [IMPROVEMENT] add error ha

else:
return jsonify({"message": "Invalid configuration option."})



## [NOTE] SOME IMPORTANT POINTS (FOR ROUTES): ##
Expand Down Expand Up @@ -585,4 +628,4 @@ def handle_sigterm(signum, frame):

## MAIN ENTRY POINT ##
if __name__ == '__main__':
app.run(debug=True) # start the Flask app in debug mode, [NOTE] to disable auto-reload, set 'use_reloader=False'
app.run(debug=True, use_reloader=False) # start the Flask app in debug mode (with auto-reload disabled)
1 change: 1 addition & 0 deletions templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
<div class="space-x-4">
<a href="/" class="text-gray-700 hover:text-primary transition duration-300">HOME</a>
<a href="/configure" class="text-gray-700 hover:text-primary transition duration-300">CONFIGURE</a>
<a href="/logs" class="text-gray-700 hover:text-primary transition duration-300">LOGGING</a>
</div>
</div>
</div>
Expand Down
103 changes: 103 additions & 0 deletions templates/logs.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Application Logs</title>

<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
background-image: url('https://images.unsplash.com/photo-1557683316-973673baf926?ixlib=rb-1.2.1&auto=format&fit=crop&w=1920&q=80');
background-size: cover;
background-position: center;
background-attachment: fixed;
}
</style>
</head>

<body class="bg-background min-h-screen font-sans text-gray-900">
<header>
<nav class="bg-white shadow-md">
<div class="container mx-auto px-6 py-3">
<div class="flex justify-between items-center">
<a href="/" class="text-2xl font-bold text-primary">CONFIGURATION MANAGEMENT</a>
<div class="space-x-4">
<a href="/" class="text-gray-700 hover:text-primary transition duration-300">HOME</a>
<a href="/configure" class="text-gray-700 hover:text-primary transition duration-300">CONFIGURE</a>
<a href="/logs" class="text-gray-700 hover:text-primary transition duration-300">LOGGING</a>
</div>
</div>
</div>
</nav>
</header>

<section class="container mx-auto px-6 py-8">
<h1 class="text-4xl font-bold text-center mb-8 text-white shadow-text">Application Logs</h1>

<!-- Toggle for System Monitoring / Machine Monitoring -->
<div class="flex justify-center items-center space-x-4 mb-6">
<button id="systemToggle" class="px-6 py-2 bg-primary text-white font-semibold rounded-md shadow-md hover:bg-blue-600 transition duration-300">System Monitoring</button>
<button id="machineToggle" class="px-6 py-2 bg-gray-300 text-gray-700 font-semibold rounded-md shadow-md hover:bg-gray-400 transition duration-300">Machine Monitoring</button>
</div>

<div class="bg-white rounded-lg shadow-xl overflow-hidden p-6">
<div class="log-container">
{% if logs %}
{% for log in logs %}
<div class="log-entry
{% if 'INFO' in log %}log-info{% elif 'DEBUG' in log %}log-debug{%
elif 'WARNING' in log %}log-warning{% elif 'ERROR' in log %}log-error{% endif %}
bg-gray-100 p-4 rounded-lg mb-4 shadow-md transition duration-300 ease-in-out transform hover:scale-105">
{{ log }}
</div>
{% endfor %}
{% else %}
<p class="text-center text-xl font-semibold text-gray-600">No logs available.</p>
{% endif %}
</div>
</div>
</section>

<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#3B82F6',
secondary: '#10B981',
danger: '#EF4444',
background: '#F3F4F6',
},
fontFamily: {
sans: ['Inter', 'sans-serif']
}
}
}
}

// Toggle button functionality
const systemToggle = document.getElementById('systemToggle');
const machineToggle = document.getElementById('machineToggle');

systemToggle.addEventListener('click', () => {
systemToggle.classList.add('bg-primary', 'text-white');
machineToggle.classList.remove('bg-primary', 'text-white');
machineToggle.classList.add('bg-gray-300', 'text-gray-700');
systemToggle.classList.remove('bg-gray-300', 'text-gray-700');
systemToggle.innerText = "System Monitoring";
machineToggle.innerText = "Machine Monitoring";
});

machineToggle.addEventListener('click', () => {
machineToggle.classList.add('bg-primary', 'text-white');
systemToggle.classList.remove('bg-primary', 'text-white');
systemToggle.classList.add('bg-gray-300', 'text-gray-700');
machineToggle.classList.remove('bg-gray-300', 'text-gray-700');
machineToggle.innerText = "Machine Monitoring";
systemToggle.innerText = "System Monitoring";
});
</script>
</body>
</html>