This commit is contained in:
Zulqarnain 2024-11-14 02:47:38 -05:00
parent b3ee1052c7
commit f54a39aee8
5 changed files with 423 additions and 285 deletions

View File

@ -1,21 +1,27 @@
from flask import Flask, request, jsonify from flask import Flask, request, jsonify
import json import json
import subprocess import subprocess
from flask_jwt_extended import JWTManager, create_access_token
import os import os
import datetime import datetime
app = Flask(__name__) app = Flask(__name__)
# Setup the Flask-JWT-Extended extension # Load paths from config_paths.json for placeholder replacement
app.config["JWT_SECRET_KEY"] = os.environ.get("JWT_SECRET_KEY", "default-secret-key") with open('/opt/ticket-ai/src/config_paths.json') as paths_file:
jwt = JWTManager(app) paths = json.load(paths_file)
# Function to split directory and file
def split_directory_and_file(path): def split_directory_and_file(path):
directory, file_with_wildcard = os.path.split(path) directory, file_with_wildcard = os.path.split(path)
file_name = file_with_wildcard.split('*')[0] # Get the part before the wildcard file_name = file_with_wildcard.split('*')[0] # Get the part before the wildcard
return directory, file_name return directory, file_name
def replace_placeholders(text):
"""Replace placeholders in the text with paths from config_paths.json."""
for placeholder, actual_path in paths.items():
text = text.replace(f"{{{placeholder}}}", actual_path)
return text
def read_log_from_dir(dir_path, pattern, lines): def read_log_from_dir(dir_path, pattern, lines):
ret_var = "" ret_var = ""
three_hours_ago = datetime.datetime.now() - datetime.timedelta(hours=3) three_hours_ago = datetime.datetime.now() - datetime.timedelta(hours=3)
@ -26,53 +32,15 @@ def read_log_from_dir(dir_path, pattern, lines):
return ret_var return ret_var
def read_log(log_file, lines): def read_log(log_file, lines):
# Replace placeholder in log file path
log_file = replace_placeholders(log_file)
return subprocess.check_output(['tail', '-n', str(lines), log_file]).decode('utf-8') return subprocess.check_output(['tail', '-n', str(lines), log_file]).decode('utf-8')
def read_top():
return subprocess.check_output(['top', '-b', '-n', '1']).decode('utf-8')
@app.route('/login', methods=['POST'])
def login():
username = request.json.get("username")
password = request.json.get("password")
if username != "admin" or password != "password":
return jsonify({"msg": "Bad username or password"}), 401
access_token = create_access_token(identity=username)
return jsonify(access_token=access_token)
# Function to replace placeholders in the issue configuration
def replace_placeholders(issue_config, paths):
for log in issue_config.get('logs', []):
log_file = log.get('log_file')
if log_file:
for placeholder, actual_path in paths.items():
log['log_file'] = log['log_file'].replace(f"{{{placeholder}}}", actual_path)
for command in issue_config.get('commands', []):
comm = command.get('comm')
if comm:
for placeholder, actual_path in paths.items():
command['comm'] = command['comm'].replace(f"{{{placeholder}}}", actual_path)
# Function to merge custom config into main config
def merge_configs(main_config, custom_config):
for key, value in custom_config.items():
if key in main_config:
# Merge commands and logs if issue type already exists
main_config[key]['commands'].extend(value.get('commands', []))
main_config[key]['logs'].extend(value.get('logs', []))
else:
# Add new issue type if it doesn't exist
main_config[key] = value
@app.route('/get_logs', methods=['GET']) @app.route('/get_logs', methods=['GET'])
def get_logs(): def get_logs():
issue_type = request.args.get("issue_type") tags = request.args.getlist("tags")
try: try:
# Load config_paths.json for dynamic paths # Load main config-tags.json
with open('/opt/ticket-ai/src/config_paths.json') as paths_file:
paths = json.load(paths_file)
# Load main config.json
with open('/opt/ticket-ai/src/config.json') as config_file: with open('/opt/ticket-ai/src/config.json') as config_file:
config = json.load(config_file) config = json.load(config_file)
@ -81,30 +49,40 @@ def get_logs():
if os.path.exists(custom_config_path): if os.path.exists(custom_config_path):
with open(custom_config_path) as custom_file: with open(custom_config_path) as custom_file:
custom_config = json.load(custom_file) custom_config = json.load(custom_file)
merge_configs(config, custom_config) for key, value in custom_config.items():
if key in config:
config[key].extend(value)
else:
config[key] = value
if issue_type not in config: response = {}
return jsonify({"error": "Invalid issue type"})
# Get the specific configuration for the issue type # Process each tag in the list
issue_config = config[issue_type] for tag in tags:
# Search for the tag in commands and logs
tag_data = next((item for item in config["tags"] if item["tag"] == tag), None)
if not tag_data:
response[tag] = "Tag not found"
continue
# Replace placeholders in logs and commands # Determine if the tag is a command or a log
replace_placeholders(issue_config, paths) if tag_data["type"] == "command":
response[tag] = f"```\n{os.popen(tag_data['content']).read()}\n```"
# Process logs and commands elif tag_data["type"] == "log":
response = { log_file = tag_data["content"]
log.get('log_file').split('*')[0]: f"```\n{read_log_from_dir(*split_directory_and_file(log.get('log_file')), log['lines'])}\n```" if '*' in log.get('log_file') else f"```\n{read_log(log['log_file'], log['lines'])}\n```" # Replace any placeholders in the log file path
for log in issue_config['logs'] log_file = replace_placeholders(log_file)
} if "*" in log_file:
response.update({ # Handle wildcard in log file path
comm.get('tag'): f"```\n{os.popen(comm.get('comm')).read()}\n```" for comm in issue_config['commands'] response[tag] = f"```\n{read_log_from_dir(*split_directory_and_file(log_file), tag_data['lines'])}\n```"
}) else:
# Regular log file
response[tag] = f"```\n{read_log(log_file, tag_data['lines'])}\n```"
except Exception as e: except Exception as e:
return jsonify({"error": str(e)}) return jsonify({"error": str(e)})
return jsonify(response)
return jsonify(response)
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=True, host="0.0.0.0") app.run(debug=True, host="0.0.0.0")

View File

@ -1,175 +1,162 @@
{ {
"APEX Upgrade Request": { "tags": [
"commands": [
{ {
"comm": "df -h | head -n 1 && df -h | grep '^/dev/sd'", "tag": "disk_usage",
"tag": "disk_usage" "type": "command",
"content": "df -h | head -n 1 && df -h | grep '^/dev/sd'"
}, },
{ {
"comm": "/opt/ticket-ai/src/scripts/tablespaceUsage.sh;sleep 5;cat /tmp/tablespace_usage.tmp", "tag": "tablespace_usage",
"tag": "tablespace_usage" "type": "command",
"content": "/opt/ticket-ai/src/scripts/tablespaceUsage.sh;sleep 5;cat /tmp/tablespace_usage.tmp"
}, },
{ {
"comm": "/opt/ticket-ai/src/scripts/apexUsage.sh;sleep 5;cat /tmp/apex_usage.tmp", "tag": "datafile_usage",
"tag": "apex_usage" "type": "command",
} "content": "/opt/ticket-ai/src/scripts/datafileUsage.sh;sleep 5;cat /tmp/datafile_usage.tmp"
],
"logs": [
{
"log_file": "{oracle_diag_log}",
"lines": 10
}
]
},
"Server Performance Problem": {
"commands": [
{
"comm": "top -b -n 1",
"tag": "top"
}, },
{ {
"comm": "iostat -x 1 3", "tag": "db_version_info",
"tag": "iostat" "type": "command",
"content": "/opt/ticket-ai/src/scripts/db_version_info.sh;sleep 5;cat /tmp/db_version_info.tmp"
}, },
{ {
"comm": "df -h | head -n 1 && df -h | grep '^/dev/sd'", "tag": "apex_usage",
"tag": "df" "type": "command",
"content": "/opt/ticket-ai/src/scripts/apexUsage.sh;sleep 5;cat /tmp/apex_usage.tmp"
}, },
{ {
"comm": "/opt/ticket-ai/src/scripts/processfinder.sh;sleep 5;cat /tmp/findsql.tmp", "tag": "top",
"tag": "processfinder" "type": "command",
"content": "top -b -n 1"
}, },
{ {
"comm": "/opt/ticket-ai/src/scripts/tablespaceUsage.sh;sleep 5;cat /tmp/tablespace_usage.tmp", "tag": "iostat",
"tag": "tablespaceusage" "type": "command",
"content": "iostat -x 1 3"
}, },
{ {
"comm": "cat /opt/ords/config/databases/default/pool.xml", "tag": "df",
"tag": "ordsconfig" "type": "command",
"content": "df -h | head -n 1 && df -h | grep '^/dev/sd'"
}, },
{ {
"comm": "echo Current Date and time on server: ; date", "tag": "processfinder",
"tag": "datetime" "type": "command",
"content": "/opt/ticket-ai/src/scripts/processfinder.sh;sleep 5;cat /tmp/findsql.tmp"
}, },
{ {
"comm": "find {virtualmin_error_log} -type f -name '*error_log*' -mmin -15 -exec sh -c 'echo \"===== {} =====\"; tail -n 50 {}' \\;", "tag": "ordsconfig",
"tag": "apacheerrorlogs" "type": "command",
} "content": "cat /opt/ords/config/databases/default/pool.xml"
],
"logs": [
{
"log_file": "{tomcat_catalina_log}",
"lines": 150
}, },
{ {
"log_file": "{oracle_diag_log}", "tag": "datetime",
"type": "command",
"content": "echo Current Date and time on server: ; date"
},
{
"tag": "apacheerrorlogs",
"type": "command",
"content": "find {virtualmin_error_log} -type f -name '*error_log*' -mmin -15 -exec sh -c 'echo \"===== {} =====\"; tail -n 50 {}' \\;"
},
{
"tag": "relay_connection",
"type": "command",
"content": "timeout 5 bash -c 'echo > /dev/tcp/relay.maxapex.net/2525' && echo 'Relay Connected' || echo 'Relay Connection failed'"
},
{
"tag": "banned_ips",
"type": "command",
"content": "for jail in $(sudo fail2ban-client status | grep \"Jail list\" | cut -d ':' -f2 | tr ',' ' '); do echo \"$jail:\"; sudo fail2ban-client status \"$jail\" | grep \"Banned IP list\"; done"
},
{
"tag": "wallet_certs",
"type": "command",
"content": "output=$(su - oracle -s /bin/bash -c 'orapki wallet display -wallet /home/oracle/wallet/') && echo \"$output\""
},
{
"tag": "journalctl",
"type": "command",
"content": "output=$(journalctl -p 3 -xb) && echo \"$output\""
},
{
"tag": "postqueue",
"type": "command",
"content": "output=$(/usr/sbin/postqueue -p) && echo \"$output\""
},
{
"tag": "postfix_status",
"type": "command",
"content": "output=$(systemctl is-active postfix) && echo \"$output\""
},
{
"tag": "dovecot_status",
"type": "command",
"content": "output=$(systemctl is-active dovecot) && echo \"$output\""
},
{
"tag": "ipv6_status",
"type": "command",
"content": "output=$(ip -6 addr show | grep -q 'inet6' && echo 'IPv6 is active' || echo 'IPv6 is not active') && echo \"$output\""
},
{
"tag": "iptables",
"type": "command",
"content": "output=$(iptables -L -n) && echo \"$output\""
},
{
"tag": "java_heap",
"type": "command",
"content": "output=$(ps aux | grep java | grep -E 'Xms|Xmx') && echo \"$output\""
},
{
"tag": "oracle_alert_logs",
"type": "log",
"content": "{oracle_alert_logs}",
"lines": 50 "lines": 50
}, },
{ {
"log_file": "/var/log/messages", "tag": "ords_logs",
"lines": 25 "type": "log",
} "content": "{ords_log}",
]
},
"Server Unavailable": {
"commands": [
{
"comm": "top -b -n 1",
"tag": "top"
},
{
"comm": "iostat -x 1 3",
"tag": "iostat"
},
{
"comm": "df -h | head -n 1 && df -h | grep '^/dev/sd'",
"tag": "df"
},
{
"comm": "/opt/ticket-ai/src/scripts/processfinder.sh;sleep 5;cat /tmp/findsql.tmp",
"tag": "processfinder"
},
{
"comm": "/opt/ticket-ai/src/scripts/tablespaceUsage.sh;sleep 5;cat /tmp/tablespace_usage.tmp",
"tag": "tablespaceusage"
},
{
"comm": "cat /opt/ords/config/databases/default/pool.xml",
"tag": "ordsconfig"
},
{
"comm": "echo Current Date and time on server: ; date",
"tag": "datetime"
},
{
"comm": "find {virtualmin_error_log} -type f -name '*error_log*' -mmin -15 -exec sh -c 'echo \"===== {} =====\"; tail -n 50 {}' \\;",
"tag": "apacheerrorlogs"
}
],
"logs": [
{
"log_file": "{tomcat_catalina_log}",
"lines": 150 "lines": 150
}, },
{ {
"log_file": "{oracle_diag_log}", "tag": "var_log_messages",
"lines": 50 "type": "log",
"content": "/var/log/messages",
"lines": 150
}, },
{ {
"log_file": "/var/log/messages", "tag": "var_log_secure",
"lines": 25 "type": "log",
} "content": "/var/log/secure",
] "lines": 150
},
"Email Problem": {
"commands": [
{
"comm": "timeout 5 bash -c 'echo > /dev/tcp/relay.maxapex.net/2525' && echo 'Relay Connected' || echo 'Relay Connection failed'",
"tag": "relay_connection"
}, },
{ {
"comm": "df -h", "tag": "os-release",
"tag": "df" "type": "log",
} "content": "/etc/os-release",
], "lines": 150
"logs": [ },
{ {
"log_file": "/var/log/messages", "tag": "var_log_maillog",
"type": "log",
"content": "/var/log/maillog",
"lines": 150
},
{
"tag": "var_log_fail2ban",
"type": "log",
"content": "/var/log/fail2ban.log",
"lines": 150
},
{
"tag": "var_log_mariadb",
"type": "log",
"content": "/var/log/mariadb/mariadb.log",
"lines": 150 "lines": 150
} }
] ]
},
"Password Problem": {
"commands": [
{
"comm": "for jail in $(sudo fail2ban-client status | grep \"Jail list\" | cut -d ':' -f2 | tr ',' ' '); do echo \"$jail:\"; sudo fail2ban-client status \"$jail\" | grep \"Banned IP list\"; done",
"tag": "banned_ips"
}
],
"logs": [
{
"log_file": "/var/log/secure",
"lines": 150
}
]
},
"Wallet Problem": {
"commands": [
{
"comm": "output=$(su - oracle -s /bin/bash -c 'orapki wallet display -wallet /home/oracle/wallet/') && echo \"$output\"",
"tag": "wallet_certs"
}
],
"logs": [
{
"log_file": "/var/log/secure",
"lines": 0
}
]
}
} }

View File

@ -1,5 +1,5 @@
{ {
"oracle_diag_log": "/opt/oracle/diag/rdbms/xe/XE/trace/alert_XE.log", "oracle_alert_logs": "/opt/oracle/diag/rdbms/xe/XE/trace/alert_XE.log",
"virtualmin_error_log": "/var/log/virtualmin/error_log", "virtualmin_error_log": "/var/log/virtualmin/error_log",
"tomcat_catalina_log": "/opt/tomcat/logs/catalina.out" "ords_log": "/opt/tomcat/logs/catalina.out"
} }

79
src/scripts/datafileUsage.sh Executable file
View File

@ -0,0 +1,79 @@
#!/bin/bash
# File paths for output
OUTPUT_FILE="/tmp/datafile_usage.tmp"
PDB_LIST_FILE="/tmp/pdb_list.tmp"
> "$OUTPUT_FILE" # Clear the output file before starting
touch $OUTPUT_FILE
chown oracle $OUTPUT_FILE
# Function to execute the datafile usage query in a specific container
run_query() {
local container_name="$1"
su - oracle -s /bin/bash -c "
sqlplus -s / as sysdba <<EOF >> \"$OUTPUT_FILE\"
whenever sqlerror exit sql.sqlcode;
set echo off
set heading on
SET UNDERLINE '='
set feedback off
set linesize 150
-- Switch to the specified container
ALTER SESSION SET CONTAINER = $container_name;
-- Print the container name for clarity
PROMPT Datafile usage for container: $container_name;
SELECT d.file_name AS datafile_path,
d.tablespace_name,
ROUND(d.bytes / 1024 / 1024, 2) AS allocated_mb,
ROUND((d.bytes - NVL(fs.bytes, 0)) / 1024 / 1024, 2) AS used_mb,
ROUND(NVL(fs.bytes, 0) / 1024 / 1024, 2) AS free_mb,
ROUND(((d.bytes - NVL(fs.bytes, 0)) / d.bytes) * 100, 2) AS pct_used
FROM dba_data_files d
LEFT JOIN (
SELECT file_id, SUM(bytes) AS bytes
FROM dba_free_space
GROUP BY file_id
) fs ON d.file_id = fs.file_id
ORDER BY d.tablespace_name, d.file_name;
exit;
EOF
"
}
# Run the query for the CDB (root container)
echo "Gathering datafile usage for CDB (root container)..." >> "$OUTPUT_FILE"
run_query 'CDB\$ROOT'
# Get a list of all PDBs, excluding PDB$SEED, and write to a temporary file
su - oracle -s /bin/bash -c "
sqlplus -s / as sysdba <<'EOF'
set heading off
set feedback off
set pagesize 0
spool $PDB_LIST_FILE
SELECT NAME FROM v\$pdbs WHERE NAME NOT IN ('PDB\$SEED');
spool off
exit;
EOF
"
# Verify that the PDB_LIST_FILE was created and contains data
if [[ -f "$PDB_LIST_FILE" && -s "$PDB_LIST_FILE" ]]; then
# Read each valid PDB name from the temporary file
while IFS= read -r PDB; do
PDB=$(echo "$PDB" | xargs) # Trim any leading/trailing whitespace
if [[ -n "$PDB" ]]; then
echo "Gathering datafile usage for PDB: $PDB..." >> "$OUTPUT_FILE"
run_query "$PDB"
fi
done < "$PDB_LIST_FILE"
else
echo "No PDBs found or could not access v\$pdbs view" >> "$OUTPUT_FILE"
fi
# Clean up the temporary file
rm -f "$PDB_LIST_FILE"

94
src/scripts/db_version_info.sh Executable file
View File

@ -0,0 +1,94 @@
#!/bin/bash
# File path for output
OUTPUT_FILE="/tmp/db_version_info.tmp"
PDB_LIST_FILE="/tmp/pdb_list.tmp"
> "$OUTPUT_FILE" # Clear the output file before starting
touch $OUTPUT_FILE
chown oracle $OUTPUT_FILE
# Function to get the Oracle Database version
get_oracle_version() {
su - oracle -s /bin/bash -c "
sqlplus -s / as sysdba <<'EOF' >> \"$OUTPUT_FILE\"
whenever sqlerror exit sql.sqlcode;
set echo off
set heading on
SET UNDERLINE '='
set feedback off
set linesize 150
PROMPT Oracle Database Version:;
SELECT banner FROM v\$version WHERE banner LIKE 'Oracle%' AND ROWNUM = 1;
exit;
EOF
"
}
# Function to get APEX and ORDS versions within a specific container
get_apex_ords_versions() {
local container_name="$1"
su - oracle -s /bin/bash -c "
sqlplus -s / as sysdba <<EOF >> \"$OUTPUT_FILE\"
whenever sqlerror exit sql.sqlcode;
set echo off
set heading on
SET UNDERLINE '='
set feedback off
set linesize 150
-- Switch to the specified container
ALTER SESSION SET CONTAINER = $container_name;
-- Print the container name for clarity
PROMPT Version information for container: $container_name;
-- APEX version
PROMPT APEX Version:;
SELECT version_no AS version FROM apex_release;
-- ORDS version
PROMPT ORDS Version:;
SELECT 'ORDS is ' || version AS \"Version of ORDS\"
FROM ords_metadata.ords_schema_version;
exit;
EOF
"
}
# Run the Oracle version query
echo "Gathering Oracle Database version..." >> "$OUTPUT_FILE"
get_oracle_version
# Get a list of all PDBs, excluding PDB$SEED, and write to a temporary file
su - oracle -s /bin/bash -c "
sqlplus -s / as sysdba <<'EOF'
set heading off
set feedback off
set pagesize 0
spool $PDB_LIST_FILE
SELECT NAME FROM v\$pdbs WHERE NAME NOT IN ('PDB\$SEED');
spool off
exit;
EOF
"
# Verify that the PDB_LIST_FILE was created and contains data
if [[ -f "$PDB_LIST_FILE" && -s "$PDB_LIST_FILE" ]]; then
# Read each valid PDB name from the temporary file
while IFS= read -r PDB; do
PDB=$(echo "$PDB" | xargs) # Trim any leading/trailing whitespace
if [[ -n "$PDB" ]]; then
echo "Gathering APEX and ORDS versions for PDB: $PDB..." >> "$OUTPUT_FILE"
get_apex_ords_versions "$PDB"
fi
done < "$PDB_LIST_FILE"
else
echo "No PDBs found or could not access v\$pdbs view" >> "$OUTPUT_FILE"
fi
# Clean up the temporary file
rm -f "$PDB_LIST_FILE"