Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b446860e6 | |||
| 68057dd986 | |||
|
|
b1ffd59111 | ||
|
|
3461a4582c | ||
|
|
1b4c924584 | ||
|
|
b7a31e7c01 | ||
| 66e20186f2 | |||
| 9d0b6b7a9e | |||
| fe39829fa2 | |||
| f54a39aee8 | |||
| b3ee1052c7 | |||
| e319eedf14 | |||
| ed7e9a7f00 | |||
| daaf5c74a5 | |||
| c244ff148e | |||
| 11647d2293 | |||
| 44be61274f | |||
| d6e72f638c | |||
|
|
be168c03ba | ||
|
|
df8e6bb79b | ||
|
|
4d3caf98c1 | ||
|
|
cc218af2e0 | ||
|
|
32cca430c3 | ||
|
|
0c59f9f5c5 | ||
|
|
13d395a49b | ||
|
|
3094f1a07a | ||
|
|
22769a4a3a | ||
|
|
0b4c2b1a64 | ||
|
|
375d58876f | ||
| 5057d6ca51 | |||
| 4288eaea31 | |||
| cf7940eeff | |||
| cd60e6024f | |||
| a3604cf80d | |||
| acb1239e2c | |||
| fe45a2ec09 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,3 +1,5 @@
|
||||
.vscode/
|
||||
playground/
|
||||
venv/
|
||||
venv/
|
||||
src/custom.json
|
||||
src/config_paths.json
|
||||
@ -1,190 +0,0 @@
|
||||
<?php
|
||||
|
||||
// Import necessary WHMCS classes
|
||||
use WHMCS\Database\Capsule;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
// Function to get ticket data and related information
|
||||
function getTicketData($tid) {
|
||||
try {
|
||||
// Perform database query
|
||||
$result = Capsule::table('tbltickets as tt')
|
||||
->join('tblhosting as th', Capsule::raw('SUBSTRING(tt.service, 2)'), '=', 'th.id')
|
||||
->join('tblservers as ts', 'th.server', '=', 'ts.id')
|
||||
->leftJoin('tblcustomfieldsvalues as cfv', function($join) {
|
||||
$join->on('tt.id', '=', 'cfv.relid')
|
||||
->where('cfv.fieldid', '=', function($query) {
|
||||
$query->select('id')
|
||||
->from('tblcustomfields')
|
||||
->where('fieldname', 'Issue Type (*)')
|
||||
->where('type', 'support')
|
||||
->limit(1);
|
||||
});
|
||||
})
|
||||
->where('tt.id', $tid)
|
||||
->select('tt.title', 'tt.message', 'th.domain', 'ts.name', 'ts.ipaddress', 'ts.hostname', 'cfv.value as issueType')
|
||||
->get();
|
||||
|
||||
if ($result->isEmpty()) {
|
||||
return "No data found for ticket ID: " . htmlspecialchars($tid);
|
||||
}
|
||||
|
||||
// Add ticket information to data array
|
||||
$data = [];
|
||||
foreach ($result as $row) {
|
||||
$data[] = [
|
||||
'Title' => $row->title,
|
||||
'Message' => $row->message,
|
||||
'Domain' => $row->domain,
|
||||
'ServerName' => $row->name,
|
||||
'IPAddress' => $row->ipaddress,
|
||||
'Hostname' => $row->hostname,
|
||||
'IssueType' => $row->issueType
|
||||
];
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return "An error occurred: " . $e->getMessage();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
// Get logs
|
||||
function getLogs($server, $issueType) {
|
||||
$client = new Client();
|
||||
try {
|
||||
// GET request with a 10-second timeout
|
||||
$response = $client->get('http://' . urlencode($server) . ':5000/get_logs?issue_type=' . urlencode($issueType), [
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
],
|
||||
'timeout' => 10, // Timeout set to 10 seconds
|
||||
]);
|
||||
|
||||
$responseBody = json_decode($response->getBody(), true);
|
||||
return $responseBody;
|
||||
} catch (Exception $e) {
|
||||
logActivity('error getLogsApi: '. $e->getMessage() );
|
||||
return null; // or return a specific structure indicating failure
|
||||
}
|
||||
}
|
||||
// Get OpenAI response
|
||||
function callOpenAI($apiKey, $apiEngine, $subject, $message, $logsData) {
|
||||
try {
|
||||
// Constructing the prompt
|
||||
$prompt = "We have received a Technical Support Ticket from a client. Having subject: $subject, ticket content: $message. Following are the server logs with file paths: $logsData. Please guide us solution of this with explanations.";
|
||||
|
||||
// Data for the OpenAI API call
|
||||
$requestData = array(
|
||||
"model" => $apiEngine,
|
||||
// "response_format" => array("type" => "json_object"),
|
||||
"messages" => array(
|
||||
array("role" => "system", "content" => "You are a helpful sysops. You have to guide a effective solution."),
|
||||
array("role" => "user", "content" => $prompt) // Using constructed prompt
|
||||
)
|
||||
);
|
||||
|
||||
$client = new Client();
|
||||
$response = $client->post('https://api.openai.com/v1/chat/completions', [
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
"Authorization" => "Bearer $apiKey"
|
||||
],
|
||||
'json' => $requestData,
|
||||
]);
|
||||
|
||||
$responseArray = json_decode($response->getBody(), true);
|
||||
|
||||
// Accessing choices
|
||||
$choice = $responseArray['choices'][0];
|
||||
$responseBody = $choice['message']['content'];
|
||||
|
||||
return $responseBody;
|
||||
} catch (Exception $e) {
|
||||
logActivity('error callOpenAI: '. $e->getMessage() );
|
||||
// return "Error: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// Add ticket notes
|
||||
function addNotesToTicket($ticketId, $note) {
|
||||
try {
|
||||
$command = 'AddTicketNote';
|
||||
$postData = array(
|
||||
'ticketid' => $ticketId,
|
||||
'message' => "Suggestion by ChatGPT.
|
||||
PLEASE NOTE THAT THIS MAY NOT BE CORRECT THEREFORE PLEASE READ AND UNDERSTAND CAREFULLY BEFORE DOING ANYTHING." . $note,
|
||||
'markdown' => true
|
||||
//,
|
||||
//'attachments' => base64_encode(json_encode([['name' => 'sample_text_file.txt', 'data' => base64_encode('This is a sample text file contents')]])),
|
||||
);
|
||||
|
||||
$results = localAPI($command, $postData);
|
||||
|
||||
logActivity("Ticket note added for ticket ID: {$ticketId}");
|
||||
|
||||
} catch (Exception $e) {
|
||||
logActivity("Error adding ticket note: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function openTicketHookFunc($vars) {
|
||||
|
||||
// Retrieve the Ticket ID and Display Data
|
||||
$tid = $vars['ticketid'] ?? '';
|
||||
|
||||
// Retrieve and display module configuration values
|
||||
$aiApiKey = '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';
|
||||
$aiEngine = "gpt-3.5-turbo-1106";
|
||||
|
||||
if (!empty($tid)) {
|
||||
$ticketData = getTicketData($tid);
|
||||
if (is_array($ticketData)) {
|
||||
foreach ($ticketData as $row) {
|
||||
|
||||
// get logs
|
||||
// $server = "localhost";
|
||||
// $issueType = "Demo";
|
||||
$server = htmlspecialchars($row['ServerName']);
|
||||
$issueType = htmlspecialchars($row['IssueType']);
|
||||
|
||||
$logsDataArray = getLogs($server, $issueType);
|
||||
|
||||
if ($logsDataArray !== null) {
|
||||
$logsData = '';
|
||||
|
||||
foreach ($logsDataArray as $key => $value) {
|
||||
$logsData .= "\n" . "file: " . $key . "\n" . "logs: " . $value;
|
||||
}
|
||||
|
||||
|
||||
// Call the ChatGPT API
|
||||
$openAIResponse = callOpenAI($aiApiKey, $aiEngine, $row['Title'], $row['Message'], $logsData);
|
||||
|
||||
|
||||
addNotesToTicket($tid, $openAIResponse);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
add_hook('TicketOpenAdmin', 1, function($vars) {
|
||||
|
||||
// logActivity('before hooks from ARH - TicketOpenAdmin');
|
||||
|
||||
openTicketHookFunc($vars);
|
||||
|
||||
// logActivity('after hooks from ARH - TicketOpenAdmin');
|
||||
});
|
||||
|
||||
|
||||
add_hook('TicketOpen', 1, function($vars) {
|
||||
|
||||
// logActivity('hooks from ARH - TicketOpen');
|
||||
|
||||
openTicketHookFunc($vars);
|
||||
});
|
||||
|
||||
68
installer.sh
68
installer.sh
@ -1,68 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Define variables for easier modifications and readability
|
||||
GIT_REPO="https://git.maxprint.io/MaxApex/ticket_ai_flask_app.git"
|
||||
APP_DIR="/opt/ticket-ai"
|
||||
VENV_DIR="$APP_DIR/venv"
|
||||
SERVICE_FILE="/etc/systemd/system/ticket-ai.service"
|
||||
PYTHON_BIN="$VENV_DIR/bin/python3"
|
||||
ACTIVATE_SCRIPT="$VENV_DIR/bin/activate"
|
||||
IPTABLES_RULES=("83.136.253.122") # Add IPs as needed
|
||||
|
||||
# Ensure the script is run as root
|
||||
if [ "$(id -u)" != "0" ]; then
|
||||
echo "This script must be run as root" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Installing git
|
||||
yum install -y git || { echo "Failed to install git. Exiting."; exit 1; }
|
||||
|
||||
# Clone the repository if it doesn't exist
|
||||
if [ ! -d "$APP_DIR" ]; then
|
||||
git clone $GIT_REPO $APP_DIR || { echo "Failed to clone repository. Exiting."; exit 1; }
|
||||
else
|
||||
echo "$APP_DIR already exists. Skipping clone."
|
||||
fi
|
||||
|
||||
# Navigate to the repo directory
|
||||
cd $APP_DIR || { echo "Failed to navigate to $APP_DIR. Exiting."; exit 1; }
|
||||
|
||||
# Create virtual environment if it doesn't exist
|
||||
if [ ! -d "$VENV_DIR" ]; then
|
||||
python3 -m venv $VENV_DIR
|
||||
else
|
||||
echo "$VENV_DIR already exists. Skipping virtual environment creation."
|
||||
fi
|
||||
|
||||
# Activate virtual environment and install dependencies
|
||||
source $ACTIVATE_SCRIPT
|
||||
pip install Flask flask_jwt_extended || { echo "Failed to install Flask or flask_jwt_extended. Exiting."; exit 1; }
|
||||
|
||||
# Create systemd service file
|
||||
cat <<EOF > $SERVICE_FILE
|
||||
[Unit]
|
||||
Description=Ticket AI
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=$PYTHON_BIN $APP_DIR/src/app.py
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
# Reload systemd to recognize the new service and start it
|
||||
systemctl daemon-reload
|
||||
systemctl start ticket-ai.service || { echo "Failed to start ticket-ai.service. Exiting."; exit 1; }
|
||||
|
||||
# Add firewall rules to accept traffic
|
||||
for IP in "${IPTABLES_RULES[@]}"; do
|
||||
iptables -A INPUT -p tcp -m tcp -s $IP --dport 5000 -j ACCEPT
|
||||
done
|
||||
|
||||
# Save iptables rules and restart the service to apply changes
|
||||
service iptables save
|
||||
service iptables restart || { echo "Failed to restart iptables. Exiting."; exit 1; }
|
||||
|
||||
echo "Setup completed successfully."
|
||||
162
src/app.py
162
src/app.py
@ -1,59 +1,103 @@
|
||||
from flask import Flask, request, jsonify
|
||||
import json
|
||||
import subprocess
|
||||
from flask_jwt_extended import JWTManager, create_access_token
|
||||
import os
|
||||
import datetime
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# Setup the Flask-JWT-Extended extension
|
||||
app.config["JWT_SECRET_KEY"] = os.environ.get("JWT_SECRET_KEY", "default-secret-key")
|
||||
jwt = JWTManager(app)
|
||||
|
||||
def split_directory_and_file(path):
|
||||
directory, file_with_wildcard = os.path.split(path)
|
||||
file_name = file_with_wildcard.split('*')[0] # Get the part before the wildcard
|
||||
return directory, file_name
|
||||
|
||||
def read_log_from_dir(dir_path, pattern, lines):
|
||||
ret_var = ""
|
||||
three_hours_ago = datetime.datetime.now() - datetime.timedelta(hours=3)
|
||||
log_files = [f for f in os.listdir(dir_path) if pattern in f and datetime.datetime.fromtimestamp(os.path.getmtime(os.path.join(dir_path, f))) > three_hours_ago]
|
||||
for file_name in log_files:
|
||||
file_path = os.path.join(dir_path, file_name)
|
||||
ret_var += f"{file_name}\n{subprocess.check_output(['tail', '-n', str(lines), file_path]).decode('utf-8')}\n\n"
|
||||
return ret_var
|
||||
|
||||
def read_log(log_file, lines):
|
||||
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)
|
||||
|
||||
@app.route('/get_logs', methods=['GET'])
|
||||
def get_logs():
|
||||
issue_type = request.args.get("issue_type")
|
||||
try:
|
||||
with open('/opt/ticket-ai/src/config.json') as config_file:
|
||||
config = json.load(config_file)
|
||||
if issue_type not in config:
|
||||
return jsonify({"error": "Invalid issue type"})
|
||||
issue_config = config[issue_type]
|
||||
response = {log.get('log_file').split('*')[0]: read_log_from_dir(*split_directory_and_file(log.get('log_file')), log['lines']) if '*' in log.get('log_file') else read_log(log['log_file'], log['lines']) for log in issue_config['logs']}
|
||||
response.update({comm.get('tag'): os.popen(comm.get('comm')).read() for comm in issue_config['commands']})
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)})
|
||||
return jsonify(response)
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True, host="0.0.0.0")
|
||||
from flask import Flask, request, jsonify
|
||||
import json
|
||||
import subprocess
|
||||
import os
|
||||
import datetime
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# Load paths from config_paths.json for placeholder replacement
|
||||
with open('/opt/ticket-ai/src/config_paths.json') as paths_file:
|
||||
paths = json.load(paths_file)
|
||||
|
||||
# Function to split directory and file
|
||||
def split_directory_and_file(path):
|
||||
directory, file_with_wildcard = os.path.split(path)
|
||||
file_name = file_with_wildcard.split('*')[0] # Get the part before the wildcard
|
||||
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):
|
||||
ret_var = ""
|
||||
three_hours_ago = datetime.datetime.now() - datetime.timedelta(hours=3)
|
||||
log_files = [f for f in os.listdir(dir_path) if pattern in f and datetime.datetime.fromtimestamp(os.path.getmtime(os.path.join(dir_path, f))) > three_hours_ago]
|
||||
for file_name in log_files:
|
||||
file_path = os.path.join(dir_path, file_name)
|
||||
ret_var += f"{file_name}\n{subprocess.check_output(['tail', '-n', str(lines), file_path]).decode('utf-8')}\n\n"
|
||||
return ret_var
|
||||
|
||||
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')
|
||||
|
||||
|
||||
@app.route('/get_logs', methods=['GET'])
|
||||
def get_logs():
|
||||
tags = request.args.getlist("tags") # Get tags in the order they appear in the query
|
||||
try:
|
||||
# Load main config.json
|
||||
with open('/opt/ticket-ai/src/config.json') as config_file:
|
||||
config = json.load(config_file)
|
||||
|
||||
# Check for custom.json and merge if it exists
|
||||
custom_config_path = '/opt/ticket-ai/src/custom.json'
|
||||
if os.path.exists(custom_config_path):
|
||||
with open(custom_config_path) as custom_file:
|
||||
custom_config = json.load(custom_file)
|
||||
for custom_tag in custom_config["tags"]:
|
||||
# Remove matching tags in config if custom.json supersedes
|
||||
config["tags"] = [tag for tag in config["tags"] if tag["tag"] != custom_tag["tag"]]
|
||||
config["tags"].append(custom_tag)
|
||||
|
||||
response_text = "" # Initialize an empty string for the plain text response
|
||||
tags_found = False
|
||||
|
||||
# Process each tag in the given order
|
||||
for tag in tags:
|
||||
try:
|
||||
# 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_text += f"Tag '{tag}' not found.\n\n"
|
||||
continue
|
||||
|
||||
tags_found = True # At least one valid tag is found
|
||||
|
||||
# Determine if the tag is a command or a log
|
||||
response_text += f"===== {tag.upper()} =====\n"
|
||||
if tag_data["type"] == "command":
|
||||
response_text += f"{os.popen(tag_data['content']).read()}\n"
|
||||
elif tag_data["type"] == "log":
|
||||
log_file = tag_data["content"]
|
||||
# Replace any placeholders in the log file path
|
||||
log_file = replace_placeholders(log_file)
|
||||
if "*" in log_file:
|
||||
# Handle wildcard in log file path
|
||||
response_text += f"{read_log_from_dir(*split_directory_and_file(log_file), tag_data['lines'])}\n"
|
||||
else:
|
||||
# Regular log file
|
||||
response_text += f"{read_log(log_file, tag_data['lines'])}\n"
|
||||
response_text += "\n" # Add spacing between entries
|
||||
except Exception as e:
|
||||
# Log the error and proceed
|
||||
response_text += f"Error for tag '{tag}': {str(e)}\n\n"
|
||||
|
||||
# If no tags were found, return HTTP 400 with an error message
|
||||
if not tags_found:
|
||||
return "None of the requested tags were found.", 400
|
||||
|
||||
except Exception as e:
|
||||
return f"Error: {str(e)}", 500
|
||||
|
||||
# Return the plain text response
|
||||
return response_text, 200, {'Content-Type': 'text/plain'}
|
||||
|
||||
if __name__ == '__main__':
|
||||
port = int(os.environ.get("TICKET_AI_PORT", 5000)) # Default to 5000 if no environment variable is set
|
||||
app.run(debug=True, host="0.0.0.0", port=port)
|
||||
|
||||
324
src/config.json
324
src/config.json
@ -1,111 +1,213 @@
|
||||
{
|
||||
"--Select Issue Type--": {
|
||||
"commands": [],
|
||||
"logs": []
|
||||
},
|
||||
"Password Reset Request": {
|
||||
"commands": [],
|
||||
"logs": []
|
||||
},
|
||||
"Domain Mapping": {
|
||||
"commands": [],
|
||||
"logs": []
|
||||
},
|
||||
"Wallet/Reverse Proxy Required": {
|
||||
"commands": [],
|
||||
"logs": []
|
||||
},
|
||||
"Others": {
|
||||
"commands": [],
|
||||
"logs": []
|
||||
},
|
||||
"Email Problem": {
|
||||
"commands": [],
|
||||
"logs": [
|
||||
{
|
||||
"log_file": "/var/log/messages",
|
||||
"lines": 50
|
||||
}
|
||||
]
|
||||
},
|
||||
"Jasper Reports": {
|
||||
"commands": [
|
||||
{
|
||||
"comm": "top -b -n 1",
|
||||
"tag": "top"
|
||||
}
|
||||
],
|
||||
"logs": [
|
||||
{
|
||||
"log_file": "/opt/tomcat/logs/catalina.out",
|
||||
"lines": 50
|
||||
},
|
||||
{
|
||||
"log_file": "/var/log/messages",
|
||||
"lines": 50
|
||||
}
|
||||
]
|
||||
},
|
||||
"Server Unavailable": {
|
||||
"commands": [],
|
||||
"logs": [
|
||||
{
|
||||
"log_file": "/opt/tomcat/logs/catalina.out",
|
||||
"lines": 50
|
||||
},
|
||||
{
|
||||
"log_file": "/opt/oracle/diag/rdbms/xe/XE/trace/alert_XE.log",
|
||||
"lines": 50
|
||||
},
|
||||
{
|
||||
"log_file": "/var/log/messages",
|
||||
"lines": 50
|
||||
}
|
||||
]
|
||||
},
|
||||
"Demo1": {
|
||||
"commands": [],
|
||||
"logs": [
|
||||
{
|
||||
"log_file": "/home/arehman/Documents/Projects/Python/Maxapex/ticket_ai_flask_app/logs/*_error.log",
|
||||
"lines": 50
|
||||
}
|
||||
]
|
||||
},
|
||||
"Demo2": {
|
||||
"commands": [],
|
||||
"logs": [
|
||||
{
|
||||
"log_file": "/home/arehman/Documents/Projects/Python/Maxapex/ticket_ai_flask_app/logs/a_error.log",
|
||||
"lines": 50
|
||||
}
|
||||
]
|
||||
},
|
||||
"Demo3": {
|
||||
"commands": [
|
||||
{
|
||||
"comm": "top -b -n 1",
|
||||
"tag": "top"
|
||||
}
|
||||
],
|
||||
"logs": []
|
||||
},
|
||||
"Demo": {
|
||||
"commands": [
|
||||
{
|
||||
"comm": "top -b -n 1",
|
||||
"tag": "top"
|
||||
}
|
||||
],
|
||||
"logs": [
|
||||
{
|
||||
"log_file": "/home/arehman/Documents/Projects/Python/Maxapex/ticket_ai_flask_app/logs/a_error.log",
|
||||
"lines": 50
|
||||
},
|
||||
{
|
||||
"log_file": "/home/arehman/Documents/Projects/Python/Maxapex/ticket_ai_flask_app/logs/*_error.log",
|
||||
"lines": 50
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
{
|
||||
"tags": [
|
||||
{
|
||||
"tag": "disk_usage",
|
||||
"type": "command",
|
||||
"content": "df -h | head -n 1 && df -h | grep '^/dev/sd'"
|
||||
},
|
||||
{
|
||||
"tag": "tablespace_usage",
|
||||
"type": "command",
|
||||
"content": "output=$(/opt/ticket-ai/src/scripts/tablespaceUsage.sh) && echo \"$output\""
|
||||
},
|
||||
{
|
||||
"tag": "datafile_usage",
|
||||
"type": "command",
|
||||
"content": "output=$(/opt/ticket-ai/src/scripts/datafileUsage.sh) && echo \"$output\""
|
||||
},
|
||||
{
|
||||
"tag": "db_version_info",
|
||||
"type": "command",
|
||||
"content": "output=$(/opt/ticket-ai/src/scripts/db_version_info.sh) && echo \"$output\""
|
||||
},
|
||||
{
|
||||
"tag": "pga_diagnostics",
|
||||
"type": "command",
|
||||
"content": "output=$(/opt/ticket-ai/src/scripts/pga_diagnostics.sh) && echo \"$output\""
|
||||
},
|
||||
{
|
||||
"tag": "sga_diagnostics",
|
||||
"type": "command",
|
||||
"content": "output=$(/opt/ticket-ai/src/scripts/sga_diagnostics.sh) && echo \"$output\""
|
||||
},
|
||||
|
||||
{
|
||||
"tag": "apex_usage",
|
||||
"type": "command",
|
||||
"content": "output=$(/opt/ticket-ai/src/scripts/apexUsage.sh) && echo \"$output\""
|
||||
},
|
||||
{
|
||||
"tag": "apex_mail_queue",
|
||||
"type": "command",
|
||||
"content": "output=$(/opt/ticket-ai/src/scripts/apex_mail_queue.sh) && echo \"$output\""
|
||||
},
|
||||
{
|
||||
"tag": "apex_smtp_settings",
|
||||
"type": "command",
|
||||
"content": "output=$(/opt/ticket-ai/src/scripts/apex_smtp_settings.sh) && echo \"$output\""
|
||||
},
|
||||
{
|
||||
"tag": "apex_bot_hits",
|
||||
"type": "command",
|
||||
"content": "output=$(/opt/ticket-ai/src/scripts/apexBots.sh) && echo \"$output\""
|
||||
},
|
||||
{
|
||||
"tag": "top_redo_sql",
|
||||
"type": "command",
|
||||
"content": "output=$(/opt/ticket-ai/src/scripts/topRedoSQL.sh) && echo \"$output\""
|
||||
},
|
||||
{
|
||||
"tag": "dbparameters",
|
||||
"type": "command",
|
||||
"content": "output=$(/opt/ticket-ai/src/scripts/showdbparameter.sh) && echo \"$output\""
|
||||
},
|
||||
{
|
||||
"tag": "top",
|
||||
"type": "command",
|
||||
"content": "top -b -n 1 | head -n 27"
|
||||
},
|
||||
{
|
||||
"tag": "iostat",
|
||||
"type": "command",
|
||||
"content": "iostat -x 1 3"
|
||||
},
|
||||
{
|
||||
"tag": "process_finder",
|
||||
"type": "command",
|
||||
"content": "output=$(/opt/ticket-ai/src/scripts/processfinder.sh) && echo \"$output\""
|
||||
},
|
||||
{
|
||||
"tag": "ords_config",
|
||||
"type": "command",
|
||||
"content": "cat /opt/ords/config/databases/default/pool.xml"
|
||||
},
|
||||
{
|
||||
"tag": "date_time",
|
||||
"type": "command",
|
||||
"content": "echo Current Date and time on server: ; date"
|
||||
},
|
||||
{
|
||||
"tag": "apache_error_logs",
|
||||
"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 | tail -n 200) && echo \"$output\""
|
||||
},
|
||||
{
|
||||
"tag": "apache_connections",
|
||||
"type": "command",
|
||||
"content": "output=$(/opt/ticket-ai/src/scripts/apache_connections.sh) && echo \"$output\""
|
||||
},
|
||||
{
|
||||
"tag": "os_session_summary",
|
||||
"type": "command",
|
||||
"content": "output=$(/opt/ticket-ai/src/scripts/os_session_summary.sh) && echo \"$output\""
|
||||
},
|
||||
{
|
||||
"tag": "check_email_ports",
|
||||
"type": "command",
|
||||
"content": "output=$(/opt/ticket-ai/src/scripts/check_email_ports.sh) && echo \"$output\""
|
||||
},
|
||||
{
|
||||
"tag": "apex_activity",
|
||||
"type": "command",
|
||||
"content": "output=$(/opt/ticket-ai/src/scripts/apex_activity.sh) && 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
|
||||
},
|
||||
{
|
||||
"tag": "ords_logs",
|
||||
"type": "log",
|
||||
"content": "{ords_log}",
|
||||
"lines": 150
|
||||
},
|
||||
{
|
||||
"tag": "var_log_messages",
|
||||
"type": "log",
|
||||
"content": "/var/log/messages",
|
||||
"lines": 150
|
||||
},
|
||||
{
|
||||
"tag": "var_log_secure",
|
||||
"type": "log",
|
||||
"content": "/var/log/secure",
|
||||
"lines": 150
|
||||
},
|
||||
{
|
||||
"tag": "os_release",
|
||||
"type": "log",
|
||||
"content": "/etc/os-release",
|
||||
"lines": 150
|
||||
},
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
5
src/config_paths.json
Normal file
5
src/config_paths.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"oracle_alert_logs": "/opt/oracle/diag/rdbms/xe/XE/trace/alert_XE.log",
|
||||
"virtualmin_error_log": "/var/log/virtualmin/error_log",
|
||||
"ords_log": "/opt/tomcat/logs/catalina.out"
|
||||
}
|
||||
9
src/scripts/apache_connections.sh
Executable file
9
src/scripts/apache_connections.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Count established connections on ports 80 and 443
|
||||
connections=$(netstat -an | grep ':80 ' | grep ESTABLISHED | wc -l)
|
||||
https_connections=$(netstat -an | grep ':443 ' | grep ESTABLISHED | wc -l)
|
||||
|
||||
echo "Active HTTP connections: $connections"
|
||||
echo "Active HTTPS connections: $https_connections"
|
||||
|
||||
112
src/scripts/apexBots.sh
Executable file
112
src/scripts/apexBots.sh
Executable file
@ -0,0 +1,112 @@
|
||||
#!/bin/bash
|
||||
|
||||
# File paths for output
|
||||
OUTPUT_FILE="/tmp/apex_bots.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 Bot Hits 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 ON
|
||||
SET HEADING ON
|
||||
SET UNDERLINE '='
|
||||
SET FEEDBACK OFF
|
||||
SET LINESIZE 150
|
||||
SET PAGESIZE 100
|
||||
COLUMN AGENT FORMAT A100
|
||||
COLUMN HIT_COUNT FORMAT 999999
|
||||
|
||||
-- Switch to the specified container
|
||||
ALTER SESSION SET CONTAINER = $container_name;
|
||||
|
||||
-- Print the container name for clarity
|
||||
PROMPT Bot Hits on APEX in last 1 hour for container: $container_name;
|
||||
|
||||
SELECT
|
||||
CASE
|
||||
WHEN UPPER(AGENT) LIKE '%AMAZON%' THEN 'Amazon Bot'
|
||||
WHEN UPPER(AGENT) LIKE '%GOOGLE%' THEN 'Google Bot'
|
||||
WHEN UPPER(AGENT) LIKE '%FACEBOOK%' THEN 'Facebook Bot'
|
||||
WHEN UPPER(AGENT) LIKE '%BING%' THEN 'Bing Bot'
|
||||
WHEN UPPER(AGENT) LIKE '%YANDEX%' THEN 'Yandex Bot'
|
||||
WHEN UPPER(AGENT) LIKE '%MJ12BOT%' THEN 'MJ12Bot'
|
||||
WHEN UPPER(AGENT) LIKE '%INDEX%' THEN 'Index Bot'
|
||||
WHEN UPPER(AGENT) LIKE '%DOTBOT%' THEN 'DotBot'
|
||||
WHEN UPPER(AGENT) LIKE '%SEMRUSH%' THEN 'Semrush Bot'
|
||||
ELSE 'Other Bot'
|
||||
END AS AGENT_NAME,
|
||||
COUNT(*) AS HIT_COUNT
|
||||
FROM
|
||||
APEX_WORKSPACE_ACTIVITY_LOG
|
||||
WHERE
|
||||
VIEW_DATE BETWEEN SYSDATE - (1/24) AND SYSDATE
|
||||
AND (
|
||||
UPPER(AGENT) LIKE '%BOT%' OR
|
||||
UPPER(AGENT) LIKE '%YANDEX%' OR
|
||||
UPPER(AGENT) LIKE '%MJ12BOT%' OR
|
||||
UPPER(AGENT) LIKE '%INDEX%' OR
|
||||
UPPER(AGENT) LIKE '%.RU%' OR
|
||||
UPPER(AGENT) LIKE '%GOOGLE%' OR
|
||||
UPPER(AGENT) LIKE '%FACEBOOK%'
|
||||
)
|
||||
GROUP BY
|
||||
CASE
|
||||
WHEN UPPER(AGENT) LIKE '%AMAZON%' THEN 'Amazon Bot'
|
||||
WHEN UPPER(AGENT) LIKE '%GOOGLE%' THEN 'Google Bot'
|
||||
WHEN UPPER(AGENT) LIKE '%FACEBOOK%' THEN 'Facebook Bot'
|
||||
WHEN UPPER(AGENT) LIKE '%BING%' THEN 'Bing Bot'
|
||||
WHEN UPPER(AGENT) LIKE '%YANDEX%' THEN 'Yandex Bot'
|
||||
WHEN UPPER(AGENT) LIKE '%MJ12BOT%' THEN 'MJ12Bot'
|
||||
WHEN UPPER(AGENT) LIKE '%INDEX%' THEN 'Index Bot'
|
||||
WHEN UPPER(AGENT) LIKE '%DOTBOT%' THEN 'DotBot'
|
||||
WHEN UPPER(AGENT) LIKE '%SEMRUSH%' THEN 'Semrush Bot'
|
||||
ELSE 'Other Bot'
|
||||
END
|
||||
ORDER BY
|
||||
HIT_COUNT DESC;
|
||||
|
||||
exit;
|
||||
EOF
|
||||
"
|
||||
}
|
||||
|
||||
# Run the query for the CDB (root container)
|
||||
# echo "Gathering Bot Hits 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 Bot Hits 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
|
||||
|
||||
cat "$OUTPUT_FILE"
|
||||
# Clean up the temporary file
|
||||
rm -f "$PDB_LIST_FILE"
|
||||
81
src/scripts/apexUsage.sh
Executable file
81
src/scripts/apexUsage.sh
Executable file
@ -0,0 +1,81 @@
|
||||
#!/bin/bash
|
||||
|
||||
# File paths for output
|
||||
OUTPUT_FILE="/tmp/apex_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 APEX 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 ON
|
||||
SET HEADING ON
|
||||
SET UNDERLINE '='
|
||||
SET FEEDBACK OFF
|
||||
SET LINESIZE 150
|
||||
SET PAGESIZE 100
|
||||
COLUMN OWNER FORMAT A20
|
||||
COLUMN MB_USED FORMAT 9999999.99
|
||||
|
||||
-- Switch to the specified container
|
||||
ALTER SESSION SET CONTAINER = $container_name;
|
||||
|
||||
-- Print the container name for clarity
|
||||
PROMPT APEX usage for container: $container_name;
|
||||
|
||||
SELECT
|
||||
OWNER,
|
||||
SUM(BYTES) / (1024 * 1024) AS MB_USED
|
||||
FROM
|
||||
DBA_SEGMENTS
|
||||
WHERE
|
||||
OWNER LIKE 'APEX%' -- Replace with your APEX schema name
|
||||
GROUP BY
|
||||
OWNER;
|
||||
|
||||
|
||||
exit;
|
||||
EOF
|
||||
"
|
||||
}
|
||||
|
||||
# Run the query for the CDB (root container)
|
||||
# echo "Gathering APEX 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 APEX 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
|
||||
|
||||
cat "$OUTPUT_FILE"
|
||||
# Clean up the temporary file
|
||||
rm -f "$PDB_LIST_FILE"
|
||||
82
src/scripts/apex_activity.sh
Executable file
82
src/scripts/apex_activity.sh
Executable file
@ -0,0 +1,82 @@
|
||||
#!/bin/bash
|
||||
|
||||
# File paths for output
|
||||
OUTPUT_FILE="/tmp/apex_activity.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 APEX User Hits 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 ON
|
||||
SET HEADING ON
|
||||
SET UNDERLINE '='
|
||||
SET FEEDBACK OFF
|
||||
SET LINESIZE 150
|
||||
SET PAGESIZE 100
|
||||
COLUMN WORKSPACE FORMAT A40
|
||||
COLUMN HIT_COUNT FORMAT 999999
|
||||
|
||||
-- Switch to the specified container
|
||||
ALTER SESSION SET CONTAINER = $container_name;
|
||||
|
||||
-- Print the container name for clarity
|
||||
PROMPT APEX Session Count in last 1 hour for container: $container_name;
|
||||
|
||||
SELECT
|
||||
WORKSPACE,
|
||||
COUNT(*) AS HIT_COUNT
|
||||
FROM
|
||||
APEX_WORKSPACE_ACTIVITY_LOG
|
||||
WHERE
|
||||
VIEW_DATE BETWEEN SYSDATE - (1/24) AND SYSDATE
|
||||
GROUP BY
|
||||
WORKSPACE
|
||||
ORDER BY
|
||||
HIT_COUNT DESC;
|
||||
|
||||
|
||||
exit;
|
||||
EOF
|
||||
"
|
||||
}
|
||||
|
||||
# Run the query for the CDB (root container)
|
||||
# echo "Gathering Hits 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 APEX User Hits 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
|
||||
cat "$OUTPUT_FILE"
|
||||
rm -f "$PDB_LIST_FILE"
|
||||
80
src/scripts/apex_mail_queue.sh
Executable file
80
src/scripts/apex_mail_queue.sh
Executable file
@ -0,0 +1,80 @@
|
||||
#!/bin/bash
|
||||
|
||||
# File paths for output
|
||||
OUTPUT_FILE="/tmp/apex_mail_queue.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 APEX Mail Queue 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 ON
|
||||
SET HEADING ON
|
||||
SET UNDERLINE '='
|
||||
SET FEEDBACK OFF
|
||||
SET LINESIZE 150
|
||||
SET PAGESIZE 100
|
||||
COLUMN WORKSPACE_NAME FORMAT A30
|
||||
COLUMN TOTAL_EMAILS FORMAT 99999999
|
||||
COLUMN UNSENT_EMAILS FORMAT 99999999
|
||||
COLUMN EMAILS_WITH_ERRORS FORMAT 99999999
|
||||
|
||||
-- Switch to the specified container
|
||||
ALTER SESSION SET CONTAINER = $container_name;
|
||||
|
||||
-- Print the container name for clarity
|
||||
PROMPT APEX Mail Queue for container: $container_name;
|
||||
|
||||
SELECT
|
||||
WORKSPACE_NAME,
|
||||
COUNT(*) AS TOTAL_EMAILS,
|
||||
SUM(CASE WHEN MAIL_SEND_COUNT = 0 THEN 1 ELSE 0 END) AS UNSENT_EMAILS,
|
||||
SUM(CASE WHEN MAIL_SEND_ERROR IS NOT NULL THEN 1 ELSE 0 END) AS EMAILS_WITH_ERRORS
|
||||
FROM
|
||||
APEX_MAIL_QUEUE
|
||||
GROUP BY
|
||||
WORKSPACE_NAME
|
||||
ORDER BY
|
||||
WORKSPACE_NAME;
|
||||
|
||||
|
||||
exit;
|
||||
EOF
|
||||
"
|
||||
}
|
||||
|
||||
# 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 Mail Queue 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
|
||||
|
||||
cat "$OUTPUT_FILE"
|
||||
# Clean up the temporary file
|
||||
rm -f "$PDB_LIST_FILE"
|
||||
93
src/scripts/apex_smtp_settings.sh
Executable file
93
src/scripts/apex_smtp_settings.sh
Executable file
@ -0,0 +1,93 @@
|
||||
#!/bin/bash
|
||||
|
||||
# File paths for output
|
||||
OUTPUT_FILE="/tmp/apex_smtp_settings.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 SMTP Settings 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 ON
|
||||
SET HEADING ON
|
||||
SET UNDERLINE '='
|
||||
SET FEEDBACK OFF
|
||||
SET LINESIZE 150
|
||||
SET PAGESIZE 100
|
||||
COLUMN PARAMETER_NAME FORMAT A20
|
||||
COLUMN PARAMETER_VALUE FORMAT A50
|
||||
|
||||
-- Switch to the specified container
|
||||
ALTER SESSION SET CONTAINER = $container_name;
|
||||
|
||||
-- Print the container name for clarity
|
||||
PROMPT APEX SMTP Settings for container: $container_name;
|
||||
|
||||
SELECT
|
||||
'SMTP_HOST_ADDRESS' AS PARAMETER_NAME, APEX_INSTANCE_ADMIN.GET_PARAMETER('SMTP_HOST_ADDRESS') AS PARAMETER_VALUE
|
||||
FROM
|
||||
DUAL
|
||||
UNION ALL
|
||||
SELECT
|
||||
'SMTP_PORT', APEX_INSTANCE_ADMIN.GET_PARAMETER('SMTP_HOST_PORT')
|
||||
FROM
|
||||
DUAL
|
||||
UNION ALL
|
||||
SELECT
|
||||
'SMTP_USERNAME', APEX_INSTANCE_ADMIN.GET_PARAMETER('SMTP_USERNAME')
|
||||
FROM
|
||||
DUAL
|
||||
UNION ALL
|
||||
SELECT
|
||||
'SMTP_PASSWORD' AS PARAMETER_NAME,
|
||||
CASE
|
||||
WHEN APEX_INSTANCE_ADMIN.GET_PARAMETER('SMTP_PASSWORD') IS NOT NULL THEN 'ABCDEFGHIJKLM'
|
||||
ELSE NULL
|
||||
END AS PARAMETER_VALUE
|
||||
FROM
|
||||
DUAL
|
||||
UNION ALL
|
||||
SELECT
|
||||
'SMTP_TLS_MODE', APEX_INSTANCE_ADMIN.GET_PARAMETER('SMTP_TLS_MODE')
|
||||
FROM
|
||||
DUAL;
|
||||
exit;
|
||||
EOF
|
||||
"
|
||||
}
|
||||
|
||||
# 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 SMTP Settings 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
|
||||
|
||||
cat "$OUTPUT_FILE"
|
||||
# Clean up the temporary file
|
||||
rm -f "$PDB_LIST_FILE"
|
||||
13
src/scripts/check_email_ports.sh
Executable file
13
src/scripts/check_email_ports.sh
Executable file
@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
ports="25 465 587 143 110 993 995"
|
||||
file="/etc/sysconfig/iptables"
|
||||
|
||||
echo "Checking iptables rules for required ports:"
|
||||
for port in $ports; do
|
||||
if grep -q -- "--dport $port" $file; then
|
||||
echo "Port $port is allowed in $file"
|
||||
else
|
||||
echo "Port $port is NOT allowed in $file"
|
||||
fi
|
||||
done
|
||||
|
||||
88
src/scripts/datafileUsage.sh
Executable file
88
src/scripts/datafileUsage.sh
Executable file
@ -0,0 +1,88 @@
|
||||
#!/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 ON
|
||||
SET HEADING ON
|
||||
SET UNDERLINE '='
|
||||
SET FEEDBACK OFF
|
||||
SET LINESIZE 200
|
||||
SET PAGESIZE 100
|
||||
COLUMN datafile_path FORMAT A50
|
||||
COLUMN tablespace_name FORMAT A20
|
||||
COLUMN allocated_mb FORMAT 9999999.99
|
||||
COLUMN used_mb FORMAT 9999999.99
|
||||
COLUMN free_mb FORMAT 9999999.99
|
||||
COLUMN pct_used FORMAT 999.99
|
||||
|
||||
-- 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
|
||||
|
||||
cat "$OUTPUT_FILE"
|
||||
# Clean up the temporary file
|
||||
rm -f "$PDB_LIST_FILE"
|
||||
97
src/scripts/db_version_info.sh
Executable file
97
src/scripts/db_version_info.sh
Executable file
@ -0,0 +1,97 @@
|
||||
#!/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 ON
|
||||
SET HEADING ON
|
||||
SET UNDERLINE '='
|
||||
SET FEEDBACK OFF
|
||||
SET LINESIZE 150
|
||||
SET PAGESIZE 100
|
||||
COLUMN BANNER FORMAT A80
|
||||
|
||||
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
|
||||
|
||||
cat "$OUTPUT_FILE"
|
||||
# Clean up the temporary file
|
||||
rm -f "$PDB_LIST_FILE"
|
||||
76
src/scripts/os_session_summary.sh
Executable file
76
src/scripts/os_session_summary.sh
Executable file
@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Declare an associative array for grouping
|
||||
declare -A summary
|
||||
|
||||
# Iterate through each running process
|
||||
while read -r process; do
|
||||
if [[ $process == ora_* || $process == oracle* ]]; then
|
||||
summary["Oracle"]=$((summary["Oracle"] + 1))
|
||||
elif [[ $process == php-fpm* ]]; then
|
||||
summary["PHP-FPM"]=$((summary["PHP-FPM"] + 1))
|
||||
elif [[ $process == httpd* ]]; then
|
||||
summary["HTTPD"]=$((summary["HTTPD"] + 1))
|
||||
elif [[ $process == sshd* ]]; then
|
||||
summary["SSHD"]=$((summary["SSHD"] + 1))
|
||||
elif [[ $process == systemd* ]]; then
|
||||
summary["SystemD"]=$((summary["SystemD"] + 1))
|
||||
elif [[ $process == zabbix* ]]; then
|
||||
summary["Zabbix"]=$((summary["Zabbix"] + 1))
|
||||
elif [[ $process == python* || $process == python3* ]]; then
|
||||
summary["Python"]=$((summary["Python"] + 1))
|
||||
elif [[ $process == node* ]]; then
|
||||
summary["Node.js"]=$((summary["Node.js"] + 1))
|
||||
elif [[ $process == bash* || $process == sh* ]]; then
|
||||
summary["Shell"]=$((summary["Shell"] + 1))
|
||||
elif [[ $process == java* ]]; then
|
||||
summary["Java"]=$((summary["Java"] + 1))
|
||||
elif [[ $process == tnslsnr* ]]; then
|
||||
summary["TNS Listener"]=$((summary["TNS Listener"] + 1))
|
||||
elif [[ $process == dovecot* || $process == postfix* || $process == saslauthd* ]]; then
|
||||
summary["Mail"]=$((summary["Mail"] + 1))
|
||||
elif [[ $process == NetworkManager* ]]; then
|
||||
summary["NetworkManager"]=$((summary["NetworkManager"] + 1))
|
||||
elif [[ $process == cron* || $process == crond* ]]; then
|
||||
summary["Cron"]=$((summary["Cron"] + 1))
|
||||
else
|
||||
summary["Uncategorized"]=$((summary["Uncategorized"] + 1))
|
||||
fi
|
||||
done < <(ps -eo comm=)
|
||||
|
||||
# Print the summary
|
||||
echo "Program-wise session summary:"
|
||||
for program in "${!summary[@]}"; do
|
||||
printf "%-15s %s\n" "$program" "${summary[$program]}"
|
||||
done
|
||||
|
||||
|
||||
|
||||
# Declare an associative array for user sessions
|
||||
declare -A user_sessions
|
||||
declare -A active_users
|
||||
|
||||
# Fetch loginctl session details and process them
|
||||
while read -r session user_id state; do
|
||||
# Get username from user ID using getent
|
||||
username=$(getent passwd "$user_id" | cut -d: -f1)
|
||||
# If username is valid, count sessions
|
||||
if [[ -n $username ]]; then
|
||||
user_sessions["$username"]=$((user_sessions["$username"] + 1))
|
||||
# Check if the session is active
|
||||
if [[ $state == "active" ]]; then
|
||||
active_users["$username"]=1
|
||||
fi
|
||||
fi
|
||||
done < <(loginctl list-sessions --no-legend | awk '{print $1, $2, $3}')
|
||||
|
||||
# Print the user-wise session summary
|
||||
echo "User-wise session summary from loginctl (with usernames):"
|
||||
printf "%-15s %-10s %-10s\n" "Username" "Sessions" "Connected"
|
||||
for username in "${!user_sessions[@]}"; do
|
||||
connected="No"
|
||||
if [[ ${active_users[$username]} -eq 1 ]]; then
|
||||
connected="Yes"
|
||||
fi
|
||||
printf "%-15s %-10s %-10s\n" "$username" "${user_sessions[$username]}" "$connected"
|
||||
done
|
||||
139
src/scripts/pga_diagnostics.sh
Executable file
139
src/scripts/pga_diagnostics.sh
Executable file
@ -0,0 +1,139 @@
|
||||
#!/bin/bash
|
||||
|
||||
# High PGA-Consuming Sessions
|
||||
echo "=== High PGA-Consuming Sessions and SQL Statements ==="
|
||||
echo "This query shows sessions and SQL statements consuming the most PGA memory, with values in MB."
|
||||
su - oracle -s /bin/bash -c "
|
||||
sqlplus -s / as sysdba <<EOF
|
||||
SET LINESIZE 200
|
||||
COLUMN USERNAME FORMAT A20
|
||||
COLUMN MODULE FORMAT A30
|
||||
COLUMN PGA_ALLOC_MB FORMAT 99999.99
|
||||
COLUMN PGA_USED_MB FORMAT 99999.99
|
||||
COLUMN SQL_TEXT FORMAT A50
|
||||
|
||||
SELECT
|
||||
s.SID,
|
||||
s.SERIAL#,
|
||||
s.USERNAME,
|
||||
s.MODULE,
|
||||
ROUND(p.PGA_ALLOC_MEM / 1024 / 1024, 2) AS PGA_ALLOC_MB,
|
||||
ROUND(p.PGA_USED_MEM / 1024 / 1024, 2) AS PGA_USED_MB,
|
||||
q.SQL_TEXT
|
||||
FROM
|
||||
V\\\$SESSION s
|
||||
JOIN
|
||||
V\\\$PROCESS p
|
||||
ON
|
||||
s.PADDR = p.ADDR
|
||||
LEFT JOIN
|
||||
V\\\$SQL q
|
||||
ON
|
||||
s.SQL_ID = q.SQL_ID
|
||||
WHERE
|
||||
p.PGA_ALLOC_MEM > (SELECT VALUE FROM V\\\$PGASTAT WHERE NAME = 'total PGA allocated') / 10
|
||||
ORDER BY
|
||||
p.PGA_ALLOC_MEM DESC;
|
||||
EOF
|
||||
"
|
||||
|
||||
# PGA Usage Overview
|
||||
echo "=== PGA Usage Overview ==="
|
||||
echo "This query provides a summary of current PGA usage statistics, with values in MB."
|
||||
su - oracle -s /bin/bash -c "
|
||||
sqlplus -s / as sysdba <<EOF
|
||||
SET LINESIZE 200
|
||||
COLUMN NAME FORMAT A40
|
||||
COLUMN VALUE_MB FORMAT 999999.99
|
||||
|
||||
SELECT
|
||||
NAME,
|
||||
ROUND(VALUE / 1024 / 1024, 2) AS VALUE_MB
|
||||
FROM
|
||||
V\\\$PGASTAT
|
||||
WHERE
|
||||
NAME IN ('total PGA allocated', 'total PGA inuse',
|
||||
'maximum PGA allocated', 'over allocation count');
|
||||
EOF
|
||||
"
|
||||
|
||||
# Sessions Using Temporary Tablespace
|
||||
echo "=== Sessions Using Temporary Tablespace ==="
|
||||
echo "This query identifies sessions that are spilling to temporary tablespaces, with values in MB."
|
||||
su - oracle -s /bin/bash -c "
|
||||
sqlplus -s / as sysdba <<EOF
|
||||
SET LINESIZE 200
|
||||
COLUMN USERNAME FORMAT A20
|
||||
COLUMN TABLESPACE FORMAT A20
|
||||
COLUMN TEMP_MB FORMAT 99999.99
|
||||
|
||||
SELECT
|
||||
s.SID,
|
||||
s.SERIAL#,
|
||||
s.USERNAME,
|
||||
tsu.TABLESPACE,
|
||||
ROUND(tsu.BLOCKS * (SELECT VALUE FROM V\\\$PARAMETER WHERE NAME = 'db_block_size') / 1024 / 1024, 2) AS TEMP_MB
|
||||
FROM
|
||||
V\\\$SESSION s
|
||||
JOIN
|
||||
V\\\$TEMPSEG_USAGE tsu
|
||||
ON
|
||||
s.SID = tsu.SESSION_NUM
|
||||
ORDER BY
|
||||
TEMP_MB DESC;
|
||||
EOF
|
||||
"
|
||||
|
||||
# Active Sessions Using Large Work Areas
|
||||
echo "=== Active Sessions Using Large Work Areas ==="
|
||||
echo "This query lists sessions using significant PGA memory for sorts, hash joins, or other large work areas."
|
||||
su - oracle -s /bin/bash -c "
|
||||
sqlplus -s / as sysdba <<EOF
|
||||
SET LINESIZE 200
|
||||
COLUMN SID FORMAT 99999
|
||||
COLUMN OPERATION_TYPE FORMAT A20
|
||||
COLUMN WORK_AREA_SIZE_MB FORMAT 99999.99
|
||||
COLUMN ACTUAL_MEM_USED_MB FORMAT 99999.99
|
||||
COLUMN NUMBER_PASSES FORMAT 99999
|
||||
|
||||
SELECT
|
||||
SID,
|
||||
OPERATION_TYPE,
|
||||
ROUND(WORK_AREA_SIZE / 1024 / 1024, 2) AS WORK_AREA_SIZE_MB,
|
||||
ROUND(ACTUAL_MEM_USED / 1024 / 1024, 2) AS ACTUAL_MEM_USED_MB,
|
||||
NUMBER_PASSES
|
||||
FROM
|
||||
V\\\$SQL_WORKAREA_ACTIVE
|
||||
WHERE
|
||||
ACTUAL_MEM_USED > 0
|
||||
ORDER BY
|
||||
ACTUAL_MEM_USED_MB DESC;
|
||||
EOF
|
||||
"
|
||||
|
||||
# Top Resource-Consuming SQL Statements
|
||||
echo "=== Top Resource-Consuming SQL Statements ==="
|
||||
echo "This query highlights the SQL statements with the highest disk reads, buffer gets, and elapsed times, all in MB."
|
||||
su - oracle -s /bin/bash -c "
|
||||
sqlplus -s / as sysdba <<EOF
|
||||
SET LINESIZE 200
|
||||
COLUMN SQL_ID FORMAT A15
|
||||
COLUMN DISK_READS_MB FORMAT 99999.99
|
||||
COLUMN BUFFER_GETS_MB FORMAT 999999.99
|
||||
COLUMN ELAPSED_TIME_SEC FORMAT 99999.99
|
||||
COLUMN SQL_TEXT FORMAT A50
|
||||
|
||||
SELECT
|
||||
SQL_ID,
|
||||
ROUND(DISK_READS / 1024 / 1024, 2) AS DISK_READS_MB,
|
||||
ROUND(BUFFER_GETS / 1024 / 1024, 2) AS BUFFER_GETS_MB,
|
||||
ROUND(ELAPSED_TIME / 1000000, 2) AS ELAPSED_TIME_SEC,
|
||||
SQL_TEXT
|
||||
FROM
|
||||
V\\\$SQL
|
||||
WHERE
|
||||
DISK_READS > 100
|
||||
ORDER BY
|
||||
DISK_READS DESC FETCH FIRST 10 ROWS ONLY;
|
||||
EOF
|
||||
"
|
||||
55
src/scripts/processfinder.sh
Executable file
55
src/scripts/processfinder.sh
Executable file
@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Define the CPU usage threshold
|
||||
CPU_THRESHOLD=50
|
||||
|
||||
# File path for output
|
||||
OUTPUT_FILE="/tmp/findsql.tmp"
|
||||
touch $OUTPUT_FILE
|
||||
chown oracle $OUTPUT_FILE
|
||||
|
||||
# Capture the PIDs of Oracle processes consuming over the specified CPU threshold
|
||||
pid=($(top -b -n 1 | awk -v threshold="$CPU_THRESHOLD" '$12 ~ /^oracle/ && $9 > threshold {print $1}'))
|
||||
echo $pid
|
||||
|
||||
# Check if there are any PIDs in the array
|
||||
if [ ${#pid[@]} -gt 0 ]; then
|
||||
echo "Following may be the SQL statements consuming top CPU" > "$OUTPUT_FILE"
|
||||
chown oracle "$OUTPUT_FILE"
|
||||
|
||||
# Construct a comma-separated list of PIDs
|
||||
pid_list=$(IFS=,; echo "${pid[*]}")
|
||||
|
||||
# Execute the SQL command as the oracle user
|
||||
su - oracle -s /bin/bash -c "
|
||||
sqlplus -s / as sysdba <<'EOF' >> \"$OUTPUT_FILE\"
|
||||
whenever sqlerror exit sql.sqlcode;
|
||||
|
||||
SET ECHO ON
|
||||
SET HEADING ON
|
||||
SET UNDERLINE '='
|
||||
SET FEEDBACK OFF
|
||||
SET LINESIZE 200
|
||||
SET PAGESIZE 100
|
||||
COLUMN datafile_path FORMAT A50
|
||||
COLUMN tablespace_name FORMAT A20
|
||||
COLUMN allocated_mb FORMAT 9999999.99
|
||||
COLUMN used_mb FORMAT 9999999.99
|
||||
COLUMN free_mb FORMAT 9999999.99
|
||||
COLUMN pct_used FORMAT 999.99
|
||||
|
||||
select DISTINCT
|
||||
s.CLIENT_IDENTIFIER, s.schemaname, s.module, s.action, q.sql_id, q.sql_text
|
||||
from v\$session s, v\$process p, v\$sql q
|
||||
where s.paddr = p.addr
|
||||
and p.spid IN ($pid_list)
|
||||
and q.sql_text is not null
|
||||
and s.sql_id = q.sql_id(+);
|
||||
exit;
|
||||
EOF
|
||||
"
|
||||
else
|
||||
echo "No Oracle processes consuming significant CPU" > "$OUTPUT_FILE"
|
||||
fi
|
||||
|
||||
cat "$OUTPUT_FILE"
|
||||
110
src/scripts/sga_diagnostics.sh
Executable file
110
src/scripts/sga_diagnostics.sh
Executable file
@ -0,0 +1,110 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Overall SGA Usage
|
||||
echo "=== Overall SGA Usage ==="
|
||||
echo "This query shows the sizes of all major SGA components (e.g., buffer cache, shared pool, redo log) in MB."
|
||||
su - oracle -s /bin/bash -c "
|
||||
sqlplus -s / as sysdba <<EOF
|
||||
SET LINESIZE 200
|
||||
COLUMN NAME FORMAT A40
|
||||
COLUMN VALUE_MB FORMAT 999999999.99
|
||||
|
||||
SELECT
|
||||
NAME,
|
||||
ROUND(BYTES / 1024 / 1024, 2) AS VALUE_MB
|
||||
FROM
|
||||
V\\\$SGAINFO;
|
||||
EOF
|
||||
"
|
||||
|
||||
# Shared Pool Usage
|
||||
echo "=== Shared Pool Usage ==="
|
||||
echo "This query provides details on the shared pool memory usage (session memory, UGA, shared pool) in MB."
|
||||
su - oracle -s /bin/bash -c "
|
||||
sqlplus -s / as sysdba <<EOF
|
||||
SET LINESIZE 200
|
||||
COLUMN NAME FORMAT A40
|
||||
COLUMN VALUE_MB FORMAT 9999999.99
|
||||
|
||||
SELECT
|
||||
NAME,
|
||||
ROUND(VALUE / 1024 / 1024, 2) AS VALUE_MB
|
||||
FROM
|
||||
V\\\$SYSSTAT
|
||||
WHERE
|
||||
NAME LIKE 'session%memory%'
|
||||
OR NAME LIKE 'session uga memory%'
|
||||
OR NAME LIKE 'shared pool%';
|
||||
EOF
|
||||
"
|
||||
|
||||
# Buffer Cache Statistics
|
||||
echo "=== Buffer Cache Statistics ==="
|
||||
echo "This query shows buffer cache usage and performance metrics, including logical and physical reads."
|
||||
su - oracle -s /bin/bash -c "
|
||||
sqlplus -s / as sysdba <<EOF
|
||||
SET LINESIZE 200
|
||||
COLUMN NAME FORMAT A40
|
||||
COLUMN VALUE FORMAT 9999999.99
|
||||
|
||||
SELECT
|
||||
NAME,
|
||||
ROUND(VALUE / 1024 / 1024, 2) AS VALUE_MB
|
||||
FROM
|
||||
V\\\$SYSSTAT
|
||||
WHERE
|
||||
NAME LIKE 'physical reads%'
|
||||
OR NAME LIKE 'buffer%'
|
||||
OR NAME LIKE 'cache%';
|
||||
EOF
|
||||
"
|
||||
|
||||
# Library Cache Usage
|
||||
echo "=== Library Cache Usage ==="
|
||||
echo "This query analyzes memory usage in the library cache, focusing on SQL and PL/SQL execution and reload rates."
|
||||
su - oracle -s /bin/bash -c "
|
||||
sqlplus -s / as sysdba <<EOF
|
||||
SET LINESIZE 200
|
||||
COLUMN NAMESPACE FORMAT A25
|
||||
COLUMN GETS FORMAT 999999999
|
||||
COLUMN PINS FORMAT 999999999
|
||||
COLUMN RELOADS FORMAT 999999999
|
||||
COLUMN PIN_HIT_RATIO FORMAT 999.99
|
||||
|
||||
SELECT
|
||||
NAMESPACE,
|
||||
ROUND(GETS / 1024 / 1024, 2) AS GETS_MB,
|
||||
ROUND(PINS / 1024 / 1024, 2) AS PINS_MB,
|
||||
ROUND(RELOADS / 1024 / 1024, 2) AS RELOADS_MB,
|
||||
ROUND((PINS - RELOADS) / DECODE(PINS, 0, 1, PINS) * 100, 2) AS PIN_HIT_RATIO
|
||||
FROM
|
||||
V\\\$LIBRARYCACHE
|
||||
ORDER BY
|
||||
PINS DESC;
|
||||
EOF
|
||||
"
|
||||
|
||||
# Top SQL Area Memory Consumers
|
||||
echo "=== Top SQL Area Memory Consumers ==="
|
||||
echo "This query lists SQL statements that consume the most memory in the shared pool, with disk reads and buffer gets in MB."
|
||||
su - oracle -s /bin/bash -c "
|
||||
sqlplus -s / as sysdba <<EOF
|
||||
SET LINESIZE 200
|
||||
COLUMN SQL_TEXT FORMAT A80
|
||||
COLUMN PARSE_CALLS FORMAT 9999999
|
||||
COLUMN DISK_READS_MB FORMAT 9999999.99
|
||||
COLUMN BUFFER_GETS_MB FORMAT 9999999.99
|
||||
|
||||
SELECT
|
||||
SQL_TEXT,
|
||||
PARSE_CALLS,
|
||||
ROUND(DISK_READS / 1024 / 1024, 2) AS DISK_READS_MB,
|
||||
ROUND(BUFFER_GETS / 1024 / 1024, 2) AS BUFFER_GETS_MB
|
||||
FROM
|
||||
V\\\$SQLAREA
|
||||
WHERE
|
||||
BUFFER_GETS > 10000
|
||||
ORDER BY
|
||||
BUFFER_GETS DESC FETCH FIRST 10 ROWS ONLY;
|
||||
EOF
|
||||
"
|
||||
58
src/scripts/showdbparameter.sh
Executable file
58
src/scripts/showdbparameter.sh
Executable file
@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
|
||||
# File path for output
|
||||
OUTPUT_FILE="/tmp/database_parameters.tmp"
|
||||
> "$OUTPUT_FILE" # Clear the output file before starting
|
||||
|
||||
touch $OUTPUT_FILE
|
||||
chown oracle $OUTPUT_FILE
|
||||
|
||||
# Execute the query to retrieve all database parameters
|
||||
su - oracle -s /bin/bash -c "
|
||||
sqlplus -s / as sysdba <<EOF >> \"$OUTPUT_FILE\"
|
||||
whenever sqlerror exit sql.sqlcode;
|
||||
|
||||
-- Set SQL*Plus Formatting
|
||||
SET LINESIZE 200
|
||||
SET PAGESIZE 50
|
||||
COLUMN parameter_name FORMAT A35
|
||||
COLUMN current_value FORMAT A25
|
||||
COLUMN is_default FORMAT A12
|
||||
COLUMN is_sys_modifiable FORMAT A18
|
||||
COLUMN description FORMAT A80
|
||||
|
||||
-- SQL Query for Important Parameters
|
||||
SELECT
|
||||
name AS parameter_name,
|
||||
value AS current_value,
|
||||
isdefault AS is_default,
|
||||
issys_modifiable AS is_sys_modifiable,
|
||||
description
|
||||
FROM
|
||||
v\\\$parameter
|
||||
WHERE
|
||||
name IN (
|
||||
-- Memory Management
|
||||
'sga_target', 'sga_max_size', 'pga_aggregate_target', 'memory_target',
|
||||
'memory_max_target', 'db_cache_size', 'shared_pool_size', 'large_pool_size',
|
||||
'log_buffer',
|
||||
-- Sessions and Processes
|
||||
'sessions', 'processes', 'transactions',
|
||||
-- Cursors
|
||||
'open_cursors', 'session_cached_cursors', 'cursor_sharing',
|
||||
-- Redo and Logs
|
||||
'log_checkpoint_interval', 'log_checkpoint_timeout', 'log_buffer',
|
||||
-- Other Important Performance Parameters
|
||||
'db_block_size', 'optimizer_mode', 'parallel_max_servers'
|
||||
)
|
||||
ORDER BY name;
|
||||
|
||||
|
||||
exit;
|
||||
EOF
|
||||
"
|
||||
|
||||
# Notify user about the location of the output file
|
||||
echo "Database parameters have been saved to $OUTPUT_FILE"
|
||||
|
||||
cat "$OUTPUT_FILE"
|
||||
91
src/scripts/tablespaceUsage.sh
Executable file
91
src/scripts/tablespaceUsage.sh
Executable file
@ -0,0 +1,91 @@
|
||||
#!/bin/bash
|
||||
|
||||
# File paths for output
|
||||
OUTPUT_FILE="/tmp/tablespace_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 tablespace 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 ON
|
||||
SET HEADING ON
|
||||
SET UNDERLINE '='
|
||||
SET FEEDBACK OFF
|
||||
SET LINESIZE 150
|
||||
SET PAGESIZE 100
|
||||
COLUMN tablespace_name FORMAT A25
|
||||
COLUMN allocated FORMAT 9999999.99
|
||||
COLUMN used FORMAT 9999999.99
|
||||
COLUMN free FORMAT 9999999.99
|
||||
COLUMN PCT_USED FORMAT 999.99
|
||||
|
||||
-- Switch to the specified container
|
||||
ALTER SESSION SET CONTAINER = $container_name;
|
||||
|
||||
-- Print the container name for clarity
|
||||
PROMPT Tablespace usage for container: $container_name;
|
||||
|
||||
SELECT a.tablespace_name,
|
||||
c.bytes/1024/1024 allocated,
|
||||
round(c.bytes/1024/1024 - nvl(b.bytes,0)/1024/1024, 2) used,
|
||||
round(nvl(b.bytes,0)/1024/1024, 2) free,
|
||||
ROUND(((c.bytes - nvl(b.bytes,0)) / c.bytes) * 100, 2) PCT_USED
|
||||
FROM dba_tablespaces a,
|
||||
(SELECT tablespace_name, SUM(bytes) bytes
|
||||
FROM dba_free_space
|
||||
GROUP BY tablespace_name) b,
|
||||
(SELECT COUNT(1) datafiles, SUM(bytes) bytes, tablespace_name
|
||||
FROM dba_data_files
|
||||
GROUP BY tablespace_name) c
|
||||
WHERE b.tablespace_name(+) = a.tablespace_name
|
||||
AND c.tablespace_name(+) = a.tablespace_name
|
||||
AND a.tablespace_name NOT LIKE 'UNDO%'
|
||||
AND a.tablespace_name NOT LIKE 'TEMP%'
|
||||
ORDER BY tablespace_name;
|
||||
|
||||
exit;
|
||||
EOF
|
||||
"
|
||||
}
|
||||
|
||||
# Run the query for the CDB (root container)
|
||||
echo "Gathering tablespace 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 tablespace 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
|
||||
|
||||
cat "$OUTPUT_FILE"
|
||||
# Clean up the temporary file
|
||||
rm -f "$PDB_LIST_FILE"
|
||||
108
src/scripts/topRedoSQL.sh
Executable file
108
src/scripts/topRedoSQL.sh
Executable file
@ -0,0 +1,108 @@
|
||||
#!/bin/bash
|
||||
|
||||
# File paths for output
|
||||
OUTPUT_FILE="/tmp/top_redo_sql.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 Redo Size 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 ON
|
||||
SET HEADING ON
|
||||
SET UNDERLINE '='
|
||||
SET FEEDBACK OFF
|
||||
SET LINESIZE 200
|
||||
SET PAGESIZE 100
|
||||
COLUMN SID FORMAT 99999
|
||||
COLUMN SERIAL# FORMAT 999999
|
||||
COLUMN SQL_TEXT FORMAT A100
|
||||
COLUMN USERNAME FORMAT A20
|
||||
COLUMN REDO_SIZE_MB FORMAT 999999.99
|
||||
|
||||
-- Switch to the specified container
|
||||
ALTER SESSION SET CONTAINER = $container_name;
|
||||
|
||||
-- Print the container name for clarity
|
||||
PROMPT Top redo size sessions for container: $container_name;
|
||||
|
||||
SELECT
|
||||
S.SID,
|
||||
S.SERIAL#,
|
||||
Q.SQL_TEXT,
|
||||
S.USERNAME,
|
||||
ROUND(R.VALUE / (1024 * 1024), 2) AS REDO_SIZE_MB
|
||||
FROM
|
||||
V\\\$SESSION S
|
||||
JOIN
|
||||
V\\\$SQL Q ON S.SQL_ADDRESS = Q.ADDRESS
|
||||
JOIN
|
||||
V\\\$SESSTAT R ON S.SID = R.SID
|
||||
JOIN
|
||||
V\\\$STATNAME N ON R.STATISTIC# = N.STATISTIC#
|
||||
WHERE
|
||||
N.NAME = 'redo size'
|
||||
AND NVL( R.VALUE, 0 ) <> 0
|
||||
AND S.LAST_CALL_ET < 7200 -- Filter sessions active within last 2 hours
|
||||
ORDER BY
|
||||
R.VALUE DESC
|
||||
FETCH FIRST 10 ROWS ONLY;
|
||||
|
||||
SELECT
|
||||
Q.PARSING_SCHEMA_NAME AS USERNAME,
|
||||
Q.EXECUTIONS,
|
||||
Q.ROWS_PROCESSED,
|
||||
Q.SQL_TEXT
|
||||
FROM
|
||||
V\\\$SQL Q
|
||||
WHERE
|
||||
Q.ROWS_PROCESSED > 10
|
||||
AND UPPER(Q.SQL_TEXT) NOT LIKE 'SELECT%'
|
||||
AND Q.PARSING_USER_ID != 0 -- Ignore SYS
|
||||
AND Q.COMMAND_TYPE != 47 -- Ignore PL/SQL
|
||||
ORDER BY
|
||||
Q.ROWS_PROCESSED DESC
|
||||
FETCH FIRST 10 ROWS ONLY;
|
||||
|
||||
|
||||
exit;
|
||||
EOF
|
||||
"
|
||||
}
|
||||
|
||||
# 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 top redo size sessions 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
|
||||
|
||||
cat "$OUTPUT_FILE"
|
||||
# Clean up the temporary file
|
||||
rm -f
|
||||
Loading…
x
Reference in New Issue
Block a user