#!/bin/bash
# History
# 2011-12-2 SM Created
# 2011-12-4 AS Add functions to get info about the system/applications
# 2012-02-3 AS Add functions to collect php/php-fpm/mysql/apache/nginx configuration
# 2012-02-6 AS Reformat mysql output and other minor changes
# 2012-06-4 AS Get pci devices information
# Start script
OUTPUT_FILE=$(pwd)/nc_sales_audit.txt
VERSION="20120604"
if [ $EUID -ne 0 ]; then
echo "[ERROR]: Please run this script with root privileges."
exit 1
fi
if [ ! -f /etc/redhat-release ]; then
echo "[ERROR]: Sorry, this script is for CentOS/RHEL only."
# exit 1
fi
name_val() {
printf "%20s | %s\n" "$1" "$(echo $2)"
}
header() {
HEADER="$1"
echo "------------------------------"
echo ">>>>> $HEADER"
echo "------------------------------"
}
section () {
echo
echo "$1" | awk '{l=sprintf("#_%-88s", $0 "_"); print l}' | sed -e 's/ /#/g' -e 's/_/ /g'
}
group_concat () {
sed -e '{H; $!d}' -e 'x' -e 's/\n[[:space:]]*\([[:digit:]]*\)[[:space:]]*/, \1x/g' -e 's/[[:space:]][[:space:]]*/ /g' -e 's/, //' ${1}
}
# START
# Get basic system status
get_basic_info() {
> $OUTPUT_FILE
echo "------------------- ChinaNetCloud Sales Audit Script Start ------------------- " | tee -a $OUTPUT_FILE 1>&2
echo "+ Results Output File: $OUTPUT_FILE" >&2
echo "------------------------------------------------------------------------------" | tee -a $OUTPUT_FILE 1>&2
section "System_Summary_For_$(hostname)"
name_val "Script Version" "$VERSION"
name_val "Hostname" "$(hostname)"
name_val "Date" "`date -u +'%F %T UTC'` (local TZ: `date +'%Z %z'`)"
name_val "Uptime" "$(uptime | awk '{print substr($0, index($0, "up") + 3)}')"
if which dmidecode &> /dev/null; then
vendor="$(dmidecode -s system-manufacturer 2>/dev/null | sed 's/ *$//g')"
product="$(dmidecode -s system-product-name 2>/dev/null | sed 's/ *$//g')"
name_val "System" "${vendor} - ${product}";
fi
if which lsb_release &>/dev/null; then
release=$(lsb_release -a 2>/dev/null|awk -F: '/Description/ {print $2}')
elif [ -e /etc/redhat-release ]; then
release=$(cat /etc/redhat-release);
elif [ -e /etc/debian_version ]; then
release="Debian-based version $(cat /etc/debian_version)";
else
release="-"
fi
name_val Release "$release"
name_val Kernel "$(uname -r)"
CPU_ARCH='32-bit'
OS_ARCH='32-bit'
if grep -q ' lm ' /proc/cpuinfo; then
CPU_ARCH='64-bit'
fi
if file /bin/bash 2>/dev/null | grep -q '64-bit'; then
OS_ARCH='64-bit'
fi
name_val "Architecture" "CPU = $CPU_ARCH, OS = $OS_ARCH"
if getenforce >/dev/null 2>&1; then
getenforce="$(getenforce 2>&1)";
fi
name_val "SELinux" "${getenforce:-No SELinux detected}";
DMESG="/var/log/dmesg"
if grep -qi -e vmware -e vmxnet $DMESG; then
VIRT="VMWare";
elif grep -q -e 'Xen virtual console' -e 'Xen version' $DMESG; then
VIRT="Xen";
elif grep -q -e QEMU -e 'paravirtualized kernel on KVM' $DMESG; then
VIRT="KVM/QEMU";
elif grep -q VBOX $DMESG; then
VIRT="VirtualBox";
fi
if [ -n "$VIRT" ]; then
name_val "Virtualized" "${VIRT}";
fi
echo
name_val "LANGUAGE" "$LANG"
if which gcc &>/dev/null; then
name_val "GCC Version" "$(gcc -dumpversion)"
else
name_val "GCC Version" "Not Installed"
fi
name_val "Max open files" "$(ulimit -n)"
}
parse_proc_cpuinfo () {
section "CPU"
header "CPU - Information"
# Physical processors are indicated by distinct 'physical id'. Virtual CPUs
# are indicated by paragraphs -- one per paragraph. We assume that all
# processors are identical, i.e. that there are not some processors with dual
# cores and some with quad cores.
CPU_FILE=/proc/cpuinfo
cat /proc/cpuinfo > /tmp/aspersa
virtual=$(grep -c ^processor $CPU_FILE);
physical=$(grep 'physical id' $CPU_FILE | sort -u | wc -l);
cores=$(grep 'cpu cores' $CPU_FILE | head -n 1 | cut -d: -f2);
# Older kernel won't have 'physical id' or 'cpu cores'.
if [ "${physical}" = "0" ]; then physical=${virtual}; fi
if [ -z "${cores}" ]; then cores=0; fi
# Test for HTT; cannot trust the 'ht' flag. If physical * cores < virtual,
# then hyperthreading is in use.
cores=$((${cores} * ${physical}));
if [ ${cores} -gt 0 -a $cores -lt $virtual ]; then htt=yes; else htt=no; fi
name_val "Processors" "physical = ${physical}, cores = ${cores}, virtual = ${virtual}, hyperthreading = ${htt}"
awk -F: '/cpu MHz/{print $2}' /tmp/aspersa | sort | uniq -c > /tmp/aspersa2
name_val "Speeds" "$(group_concat /tmp/aspersa2)"
awk -F: '/model name/{print $2}' /tmp/aspersa | sort | uniq -c > /tmp/aspersa2
name_val "Models" "$(group_concat /tmp/aspersa2)"
awk -F: '/cache size/{print $2}' /tmp/aspersa | sort | uniq -c > /tmp/aspersa2
name_val "Caches" "$(group_concat /tmp/aspersa2)"
header "CPU - TOP 30"
echo " PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND"
top -b -n1|grep -E "^\s?[0-9]+"|sort -k9 -g|tail -30
}
parse_disk() {
section "DISK"
header "Fdisk"
fdisk -l 2>/dev/null
header "File Systems"
df -h -P 2>/dev/null | while read a b c d e f; do
printf "%-40s %-5s %-5s %-5s %-5s %-5s\n" "$a" "$b" "$c" "$d" "$e" "$f"
done
echo
header "/etc/fstab"
while read a b c d e f; do
printf "%-30s %-20s %-6s %-30s %-2s %-2s\n" "$a" "$b" "$c" "$d" "$e" "$f"
done < /etc/fstab
header "PV Information"
pvs 2>/dev/null
header "VG Information"
vgs 2>/dev/null
header "LV Information"
lvs 2>/dev/null
header "iostat"
iostat -Ndx 2 5 2>/dev/null
header "vmstat"
vmstat 2 5 2>/dev/null
section "Disk_Schedulers_And_Queue_Size"
echo "" > /tmp/aspersa
for disk in $(ls /sys/block/ | grep -v -e ram -e loop -e 'fd[0-9]'); do
if [ -e "/sys/block/${disk}/queue/scheduler" ]; then
name_val "${disk}" "$(cat /sys/block/${disk}/queue/scheduler | grep -o '\[.*\]') $(cat /sys/block/${disk}/queue/nr_requests)"
fdisk -l "/dev/${disk}" >> /tmp/aspersa 2>/dev/null
fi
done
}
parse_memory() {
section "MEMORY"
header "Free and used memory"
free -m
header "MEMORY - TOP 30"
echo " PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND"
top -b -n1|grep -E "^\s?[0-9]+"|sort -k10 -g|tail -30
}
parse_software() {
section "SOFTWARE"
if [ -f /etc/redhat-release ]; then
header "RPM Packages: (Total: $(rpm -qa|wc -l))"
rpm -qa|grep -Ei "^(php|mysql|nginx|httpd|apache|redis|memcache|mongo|postgre|tomcat|resin|haproxy|varnish|vsftp|gcc)"|sort
fi
header "Version Information:"
if which java &>/dev/null ; then
BIN_JAVA=$(which java)
VERSION_JAVA=$(java -version 2>&1|head -n 1|awk -F'"' '{print $2}')
name_val "Java Version" "$VERSION_JAVA ($BIN_JAVA)"
fi
if which perl &>/dev/null ; then
BIN_PERL=$(which perl)
VERSION_PERL=$(perl -V|perl -ne 'if (/.*revision (\d+) version (\d+) subversion (\d+)/) {print "$1.$2.$3\n"}')
name_val "Perl Version" "$VERSION_PERL ($BIN_PERL)"
fi
if which python &>/dev/null ; then
BIN_PYTHON=$(which python)
VERSION_PYTHON=$(python -V 2>&1 | awk '{print $2}')
name_val "Python Version" "$VERSION_PYTHON ($BIN_PYTHON)"
fi
if which httpd &>/dev/null ; then
BIN_APACHE=$(which httpd)
VERSION_APACHE=$(httpd -v| head -n 1|perl -pi -e 's/.*(\d+\.\d+.\d).*/$1/')
name_val "Apache Version" "$VERSION_APACHE ($BIN_APACHE)"
fi
if which nginx &>/dev/null ; then
BIN_NGINX=$(which nginx)
VERSION_NGINX=$(nginx -v 2>&1 | perl -pi -e 's/.*(\d+\.\d+.\d).*/$1/')
name_val "Nginx Version" "$VERSION_NGINX ($BIN_NGINX)"
fi
if which lighttpd &>/dev/null ; then
BIN_LIGHTTPD=$(which lighttpd)
VERSION_LIGHTTPD=$(lighttpd -v| head -n 1| perl -pi -e 's/.*(\d+\.\d+.\d).*/$1/')
name_val "Lighttpd Version" "$VERSION_LIGHTTPD ($BIN_LIGHTTPD)"
fi
if which vsftpd &>/dev/null ; then
BIN_VSFTPD=$(which vsftpd)
VERSION_VSFTPD=$(vsftpd -v 0>&1|perl -pi -e 's/.*(\d+\.\d+.\d).*/$1/')
name_val "Vsftpd Version" "$VERSION_VSFTPD ($BIN_VSFTPD)"
fi
if which php &>/dev/null ; then
BIN_PHP=$(which php)
VERSION_PHP=$(php -v 2>/dev/null | head -n 1 | perl -pi -e 's/.*(\d+\.\d+.\d).*/$1/')
name_val "PHP Version" "$VERSION_PHP ($BIN_PHP)"
fi
if which memcached &>/dev/null ; then
BIN_MEMCACHED=$(which memcached)
VERSION_MEMCACHED=$(memcached -h|head -n 1|awk '{print $2}')
name_val "Memcached Version" "$VERSION_MEMCACHED ($BIN_MEMCACHED)"
fi
if [ -n "$CATALINA_HOME" ]; then
VERSION_TOMCAT=$($CATALINA_HOME/bin/version.sh 2>/dev/null | awk -F: '/version/ {print $2}')
name_val "Tomcat Version" "$VERSION_TOMCAT ($CATALINA_HOME)"
fi
if which mysql &>/dev/null ; then
BIN_MYSQL_CLIENT=$(which mysql)
VERSION_MYSQL_CLIENT=$(mysql -V | perl -pi -e 's/.*(\d+\.\d+.\d).*/$1/')
name_val "MySQL Client Version" "$VERSION_MYSQL_CLIENT ($BIN_MYSQL_CLIENT)"
fi
if which mongod &>/dev/null; then
VERSION_MONGOD=$(/usr/bin/mongod --version|awk -F"(,| )" '/db version/ {print substr($3,2)}')
BIN_MONGOD=$(which mongod)
name_val "MongoDB Version" "$VERSION_MONGOD ($BIN_MONGOD)"
fi
if which psql &>/dev/null ; then
BIN_PSQL=$(which psql)
VERSION_PSQL=$(psql -V | head -n 1 | perl -pi -e 's/.*(\d+\.\d+.\d).*/$1/')
name_val "PostgreSQL Version" "$VERSION_PSQL ($BIN_PSQL)"
fi
echo
}
parse_iptables() {
section iptables
header "Iptables Rules"
iptables -nvL
echo
}
# GET INFORMATION ABOUT CRONTAB
parse_cron() {
section CRONTAB
for USER_LINE in `cat /etc/passwd | cut -d: -f1`; do
USER_CRON=$(crontab -l -u $USER_LINE 2>/dev/null)
if [ -n "$USER_CRON" ]; then
echo ">>>>> crontab for $USER_LINE" ;
crontab -l -u $USER_LINE
echo "-------------------------------"
fi
done
}
parse_network() {
section Network_Connections
header "Listening ports"
netstat -ntlpu
header "IP Address"
ifconfig
header "Ethernet Settings - eth0"
ethtool eth0 2>/dev/null
header "Ethernet Settings - eth1"
ethtool eth1 2>/dev/null
header "Ethernet Settings - eth2"
ethtool eth2 2>/dev/null
header "IP Routing"
route -n
if which ss &>/dev/null; then
header "Socket statistics"
ss -s
echo
fi
}
parse_others() {
section "PCI DEVICES"
lspci -tv 2>/dev/null
section "PROCESSES"
ps aux|sort -r -k10
section "KERNEL_PARAMETERS"
sysctl -a 2>/dev/null | grep -E "(somaxconn|backlog|file-max|ip_forward|tcp_tw|keepalive|tcp_fin|swappiness|tcp_syn)"|sort
section "USER_LOGIN"
header "Current Users"
/usr/bin/w
header "last logged in users"
last -10
header "Last bad login attempts"
lastb -10
}
# Apache section
get_httpd_info() {
section "APACHE"
header "Apache configuration"
for APACHE_INCLUDE_CONF in $(find /etc/httpd/ /etc/apache2/ /usr/local/apache2/ /usr/local/httpd/ -type f -name '*.conf' 2>/dev/null); do
if [ -s $APACHE_INCLUDE_CONF ]; then
header "Apache configuration - $APACHE_INCLUDE_CONF"
cat $APACHE_INCLUDE_CONF|sed -e '/^\s*$/d;/^\s*#/d;'
fi
done
}
# Nginx section
get_nginx_info() {
section "NGINX"
for NGINX_INCLUDE_CONF in $(find /etc/nginx /usr/local/nginx* -name '*.conf' 2>/dev/null); do
if [ -s $NGINX_INCLUDE_CONF ]; then
header "Nginx configuration - $NGINX_INCLUDE_CONF"
cat $NGINX_INCLUDE_CONF | sed -e '/^\s*$/d;/^\s*#/d;'
fi
done
}
# MySQL section
get_mysql_info() {
# Function - check and display config file
mysql_config_get() {
if [ -f "$1" ]; then
header "MySQL Configuration File - $1"
cat $1
fi
}
section "MYSQL"
# get options from running MySQL processes
header "MySQL Startup Options"
MYSQLD_BASEDIR=$(ps aux | grep -w '[m]ysqld' | perl -ne 'if ( /.*mysqld\s+.*--basedir=(.*?)\s+.*/ ) {print $1."\n"}')
if [ -n "$MYSQLD_BASEDIR" ]; then
echo "MySQL basedir: $MYSQLD_BASEDIR"
fi
MYSQLD_DATADIR=$(ps aux | grep -w '[m]ysqld' | perl -ne 'if ( /.*mysqld\s+.*--datadir=(.*?)\s+.*/ ) {print $1."\n"}')
if [ -n "$MYSQLD_DATADIR" ]; then
echo "MySQL datadir: $MYSQLD_DATADIR"
fi
MYSQLD_LOG_ERROR=$(ps aux | grep -w '[m]ysqld' | perl -ne 'if ( /.*mysqld\s+.*--log-error=(.*?)\s+.*/ ) {print $1."\n"}')
if [ -n "$MYSQLD_LOG_ERROR" ]; then
echo "MySQL error file: $MYSQLD_LOG_ERROR"
fi
MYSQLD_SOCKET=$(ps aux | grep -w '[m]ysqld' | perl -ne 'if ( /.*mysqld\s+.*--socket=(.*?)\s+.*/ ) {print $1."\n"}')
if [ -n "$MYSQLD_SOCKET" ]; then
echo "MySQL socket: $MYSQLD_SOCKET"
fi
# get MySQL configuration file
mysql_config_get /etc/my.cnf
mysql_config_get $MYSQLD_BASEDIR/my.cnf
MYSQLD_EXTRA_FILE=$(ps aux | grep -w '[m]ysqld' | perl -ne 'if ( /.*mysqld\s+.*--defaults-extra-file=(.*?)\s+.*/ ) {print $1."\n"}')
if [ -n "MYSQLD_EXTRA_FILE" ]; then
mysql_config_get $MYSQLD_EXTRA_FILE
fi
# get MySQL global variables / global status, etc
echo "Going to collect MySQL global variables and status,which are really helpful for tuning and optimization." >&2
MYSQL_RETRY_COUNT=1
MYSQL_OK="NO"
# skip if customer failed to provide valid user/passwd
while [ $MYSQL_RETRY_COUNT -lt 5 -a $MYSQL_OK != "YES" ]; do
echo -n "MySQL user name (root as default): " >&2
read MYSQL_USER
echo -n "MySQL password: " >&2
read -s MYSQL_PASSWD
if [ -z "$MYSQL_USER" ]; then
MYSQL_USER=root
fi
echo
mysql -u$MYSQL_USER -p$MYSQL_PASSWD -e "select now();" &>/dev/null
if [ $? -ne 0 ]; then
echo "MySQL - Access denied, please check your username and password" >&2
MYSQL_RETRY_COUNT=$((MYSQL_RETRY_COUNT+1))
else
MYSQL_OK="YES"
fi
done
if [ $MYSQL_OK != "YES" ]; then
echo "MySQL - Customer failed to provide valid username/password. Skipping .."
else
if [ -z "$MYSQLD_DATADIR" ]; then
MYSQLD_DATADIR=$(echo "show global variables like 'datadir';" | mysql -uroot -p$MYSQL_PASSWD | awk '/datadir/ {print $2}')
fi
if [ -z "$MYSQLD_LOG_ERROR" ]; then
MYSQLD_LOG_ERROR=$(echo "show global variables like 'log_error';" | mysql -uroot -p$MYSQL_PASSWD | awk '/log_error/ {print $2}')
fi
if [ -z "$MYSQLD_SLOW_LOG" ]; then
MYSQLD_SLOW_LOG=$(echo "show global variables like 'slow_query_log_file';" | mysql -uroot -p$MYSQL_PASSWD | awk '/slow_query_log_file/ {print $2}')
fi
header "MySQL - global status"
mysql -u$MYSQL_USER -p$MYSQL_PASSWD -e "show global status;" | perl -ne 'my ($a,$b)=split /\s+/,$_; printf ("| %-40s | %-12s |\n",$a,$b)'
header "MySQL - global variables"
mysql -u$MYSQL_USER -p$MYSQL_PASSWD -e "show global variables;" | perl -ne 'my ($a,$b)=split /\s+/,$_; printf ("| %-40s | %-36s |\n",$a,$b)'
header "MySQL - innodb status"
mysql -u$MYSQL_USER -p$MYSQL_PASSWD -e "show innodb status\G"
fi
# list files under mysql datadir
if [ -n "$MYSQLD_DATADIR" ]; then
header "Files under $MYSQLD_DATADIR"
ls -l $MYSQLD_DATADIR
# database size summary
header "Database size"
find $MYSQLD_DATADIR -maxdepth 1 -type d -exec du -sh {} \;
fi
# MySQL error logs
if [ -s "$MYSQLD_LOG_ERROR" ]; then
header "MySQL - error logs"
tail -100 $MYSQLD_LOG_ERROR
fi
# MySQL slow logs
if [ -s "$MYSQLD_SLOW_LOG" ]; then
header "MySQL - slow logs"
tail -100 $MYSQLD_SLOW_LOG
elif [ -s "$MYSQLD_DATADIR/slow.log" ]; then
header "MySQL - slow logs"
tail -100 $MYSQLD_DATADIR/slow.log
fi
# MySQL history
header "MySQL_History"
for USER_HOME in `awk -F: '{print $6}' /etc/passwd|sort|uniq`; do
if [ -s "$USER_HOME/.mysql_history" ]; then
echo ">>>>> MySQL history under $USER_HOME"
cat $USER_HOME/.mysql_history
echo "-------------------------------"
fi
done
}
get_php_info() {
section "PHP/PHP-FPM"
# php module information
for PHP_INI_CONF in $(find /usr/local/php* /etc/php* -type f -name '*.ini' 2>/dev/null); do
header "PHP - Configuration file $PHP_INI_CONF"
cat $PHP_INI_CONF|sed -e '/^\s*$/d;/^\s*;/d;'
done
PHP_CGI_CONF=$(ps aux|perl -ne 'if ( /.*--fpm-config\s(.*?)$/ ) {print $1."\n"}'|uniq)
# php-fpm version 5.2
if [ -s "$PHP_CGI_CONF" ]; then
header "PHP_FPM - Configuration file $PHP_CGI_CONF"
echo "listen_address: " $(perl -ne 'if (/^\s*<value name="listen_address">(\S+)<\/value>/) {print $1}' $PHP_CGI_CONF)
echo "user: " $(perl -ne 'if (/^\s*<value name="user">(\S+)<\/value>/) {print $1}' $PHP_CGI_CONF)
echo "group:" $(perl -ne 'if (/^\s*<value name="group">(\S+)<\/value>/) {print $1}' $PHP_CGI_CONF)
echo "style: " $(perl -ne 'if (/^\s*<value name="style">(\S+)<\/value>/) {print $1}' $PHP_CGI_CONF)
echo "StartServers: " $(perl -ne 'if (/^\s*<value name="StartServers">(\S+)<\/value>/) {print $1}' $PHP_CGI_CONF)
echo "MinSpareServers: " $(perl -ne 'if (/^\s*<value name="MinSpareServers">(\S+)<\/value>/) {print $1}' $PHP_CGI_CONF)
echo "MaxSpareServers: " $(perl -ne 'if (/^\s*<value name="MaxSpareServers">(\S+)<\/value>/) {print $1}' $PHP_CGI_CONF)
echo "request_terminate_timeout: " $(perl -ne 'if (/^\s*<value name="request_terminate_timeout">(\S+)<\/value>/) {print $1}' $PHP_CGI_CONF)
echo "request_slowlog_timeout: " $(perl -ne 'if (/^\s*<value name="request_slowlog_timeout">(\S+)<\/value>/) {print $1}' $PHP_CGI_CONF)
echo "rlimit_files: " $(perl -ne 'if (/^\s*<value name="rlimit_files">(\S+)<\/value>/) {print $1}' $PHP_CGI_CONF)
echo "max_requests: " $(perl -ne 'if (/^\s*<value name="max_requests">(\S+)<\/value>/) {print $1}' $PHP_CGI_CONF)
fi
# php-fpm version 5.3+
for PHP_FPM_CONF in $(find /usr/local/php* /etc/php* -type f -name '*.conf' 2>/dev/null); do
header "PHP_FPM - Configuration file - $PHP_FPM_CONF"
cat $PHP_FPM_CONF|sed -e '/^\s*$/d;/^\s*;/d;'
done
}
# main function
main() {
get_basic_info
parse_proc_cpuinfo
parse_memory
parse_disk
parse_software
parse_iptables
parse_cron
parse_network
parse_others
if [ $(ps aux|grep -E "[h]ttpd|[a]pache2"|wc -l) -gt 0 ]; then
get_httpd_info
fi
if [ $(ps aux|grep [n]ginx|wc -l) -gt 0 ]; then
get_nginx_info
fi
get_php_info
if [ $(ps aux|grep [m]ysql|wc -l) -gt 0 ]; then
get_mysql_info
fi
/bin/rm -f /tmp/aspersa /tmp/aspersa2
}
main >> $OUTPUT_FILE
## Email results
echo "
------------------------------------------------------------------------------
Done. Please send this file to ChinaNetCloud - sales_audit@chinanetcloud.com
$OUTPUT_FILE
------------------------------------------------------------------------------
"