#!/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 - [email protected] $OUTPUT_FILE ------------------------------------------------------------------------------ "