#!/usr/bin/env bash
#
# Authors:: Chef Support Team <support-team@chef.io>
#

[ -r /etc/opscode/private-chef.sh ] && source /etc/opscode/private-chef.sh
POSTGRESQL_UNIX_USER=${POSTGRESQL_UNIX_USER:=opscode-pgsql}

modified_within_last_x_minutes=180
tail_lines=10000

#Lets have a way to avoid things that take a while, like DNS
if [[ -n $1  ]]; then
    testing=true
fi

config_name='*chef*.rb'

if [[ ! -e "/opt/opscode/bin/chef-server-ctl" ]]; then
    echo "ERROR: Chef Infra Server may not be installed."
    exit 1
fi
config_file_path="/etc/opscode/$config_name"

hostname=$(hostname)
timestamp=$(date +%F_%H.%M.%S-%Z)
tmpdir="$(mktemp -d)/$hostname/$timestamp"
#RHEL5 has ip and other tools here
PATH=$PATH:/bin:/sbin

PATH=/opt/opscode/embedded/bin:$PATH

mkdir -p "$tmpdir"
# make sure we have the full path in /proc created for the gather-logs bundle
mkdir -p "$tmpdir/proc/sys/crypto/"
# create the connectivity dir for proxy / supermarket access checks
mkdir -p "$tmpdir/connectivity/"

for i in /opt/{chef,opscode}*/version-manifest.txt \
              /opt/opscode/pc-version.txt \
              /etc/opscode/$config_name \
              /etc/{chef,opscode}*/*-running.json \
              /var/opt/opscode*/etc/*-running.json \
              /etc/{chef,opscode,opscode-manage}*/*.rb \
              /var/log/syslog \
              /var/log/messages; do
    if [[ -e "$i" ]]; then
        mkdir -p "$tmpdir/`dirname ${i:1}`"
        tail -"$tail_lines" "$i" > "$tmpdir/${i:1}"
    fi
done

for i in `find -L /var/log/${path}* -type f -mmin -"$modified_within_last_x_minutes"`; do
    if [[ -e "$i" ]]; then
        mkdir -p "$tmpdir/`dirname ${i:1}`"
        tail -"$tail_lines" "$i" > "$tmpdir/${i:1}"
    fi
done

# Add signing proxy log and elastic info from RDS if system is configured using https://github.com/chef-customers/aws_native_chef_server
if [[ -f "/var/log/aws-signing-proxy/proxy.log" ]]; then
    mkdir -p "$tmpdir/var/log/aws-signing-proxy"
    tail -"$tail_lines" "/var/log/aws-signing-proxy/proxy.log" > "$tmpdir/var/log/aws-signing-proxy/proxy.log"
fi

# Gather some information from Elasticsearch, if it's available
gather_es() {
    curl -sS -X GET "http://localhost:$1/_cluster/health?pretty" > "$tmpdir/elasticsearch_cluster_health.txt"
    curl -sS -X GET "http://localhost:$1/_cluster/state?pretty" > "$tmpdir/elasticsearch_cluster_state.txt"
    curl -sS -X GET "http://localhost:$1/_cat/indices?v" > "$tmpdir/elasticsearch_cat_indices.txt"
    curl -sS -X GET "http://localhost:$1/_cat/shards?h=index,shard,prirep,state,unassigned.reason&pretty" > "$tmpdir/elasticsearch_cat_shards.txt"
    curl -sS -X GET "http://localhost:$1/_cluster/allocation/explain?pretty" > "$tmpdir/elasticsearch_cluster_shards_explain.txt"
}
ES_9200="$(curl -s -XGET 'http://localhost:9200/' | grep 'for Search')"
ES_10144="$(curl -s -XGET 'http://localhost:10144/' | grep 'for Search')"
if [[ -n $ES_9200 ]]; then
    gather_es 9200
elif [[ -n $ES_10144 ]]; then
    gather_es 10144
fi

chef-server-ctl status > "$tmpdir/chef-server-ctl"_status.txt


STATSPW=$(chef-server-ctl show-secret opscode_erchef stats_password)
if [ -n "$STATSPW" ]; then
    curl -k -s -X GET "https://statsuser:$STATSPW@localhost/_stats?format=text" status > "$tmpdir/chef_server_stats_endpoint.txt"
else
    curl -k -s -X GET "https://localhost/_stats?format=text" status > "$tmpdir/chef_server_stats_endpoint.txt"
fi

# postgres server may be external - we'll go ahead and try to gather what we can in any case, and just capture errors to the output
# without showing them to the user
echo "SELECT CURRENT_TIMESTAMP; SELECT * FROM pg_stat_activity;" | chef-server-ctl psql oc_erchef --as-admin --options -tA > "$tmpdir/pg_stat_activity.txt" 2>&1
echo "SELECT * FROM sqitch.tags;" |  chef-server-ctl psql oc_erchef --as-admin --options -tA  > "$tmpdir/opscode_chef_sqitch_tags.txt" 2>&1
echo "SELECT * FROM sqitch.tags;" |  chef-server-ctl psql bifrost --as-admin --options -tA > "$tmpdir/bifrost_sqitch_tags.txt" 2>&1

# gather usage information
mkdir -p "$tmpdir/infra_server_usage"
echo "SELECT count(DISTINCT org_id) FROM nodes;" |  chef-server-ctl psql oc_erchef --as-admin --options -tA > "$tmpdir/infra_server_usage/consumed_orgs.txt" 2>&1
echo "SELECT count(DISTINCT environment) FROM nodes WHERE NOT name='_default';" |  chef-server-ctl psql oc_erchef --as-admin --options -tA > "$tmpdir/infra_server_usage/consumed_environments.txt" 2>&1
echo "SELECT count(DISTINCT policy_group) FROM nodes;" |  chef-server-ctl psql oc_erchef --as-admin --options -tA > "$tmpdir/infra_server_usage/consumed_policy_group.txt" 2>&1
echo "SELECT count(DISTINCT policy_name) FROM nodes;" |  chef-server-ctl psql oc_erchef --as-admin --options -tA > "$tmpdir/infra_server_usage/consumed_policy_name.txt" 2>&1
echo "SELECT count(*) FROM nodes;" |  chef-server-ctl psql oc_erchef --as-admin --options -tA > "$tmpdir/infra_server_usage/consumed_nodes.txt" 2>&1
echo 'SELECT row_to_json(users) FROM (SELECT username, admin FROM "users") AS users;' |  chef-server-ctl psql oc_erchef --as-admin --options -tA > "$tmpdir/infra_server_usage/total_users.json" 2>&1

if [[ -S "/tmp/.s.PGSQL.5432" ]]; then
    su -m $POSTGRESQL_UNIX_USER -c 'ulimit -a' > "$tmpdir/ulimit_a_opscode-pgsql.txt"
fi

# Retrieve Platform and Platform Version
if [[ -f "/etc/lsb-release" ]] && grep -q DISTRIB_ID /etc/lsb-release; then
    cp "/etc/lsb-release" "$tmpdir/platform_version.txt"
    known_platform="ubuntu"
elif [[ -f "/etc/redhat-release" ]]; then
    cp "/etc/redhat-release" "$tmpdir/platform_version.txt"
    known_platform="rhel"
elif [[ -f "/etc/os-release" ]] && grep -q "Amazon Linux 2" /etc/os-release; then
    known_platform="amazon"
    cat "/etc/os-release" >> "$tmpdir/platform_version.txt"
    cat "/etc/system-release-cpe" >> "$tmpdir/platform_version.txt"
else
    echo "Platform and version are unknown." > "$tmpdir/platform_version.txt"
fi

# version / os information we want regardless of platform
cp "/proc/version" "$tmpdir/proc/version"
cp "/etc/os-release" "$tmpdir/etc/os-release"
cp "/etc/system-release" "$tmpdir/etc/system-release" 2>/dev/null
uname -a > "$tmpdir/uname_a.txt"

# gather the configured umask
umask > "$tmpdir/umask.txt"

# gather the system uptime
uptime > "$tmpdir/uptime.txt"

# gather FIPS mode enabled or not
cp "/proc/sys/crypto/fips_enabled" "$tmpdir/proc/sys/crypto/fips_enabled" 2>/dev/null

# gather information on CPU count and installed memory
cp "/proc/cpuinfo" "$tmpdir/proc/cpuinfo"
cp "/proc/meminfo" "$tmpdir/proc/meminfo"

# gather running processes
ps fauxww > "$tmpdir/ps_fauxww.txt"

# gather free memory
free -m > "$tmpdir/free_m.txt"

# gather disk usage information
df -h > "$tmpdir/df_h.txt"
df -i > "$tmpdir/df_i.txt"
df -k > "$tmpdir/df_k.txt"

# gather hostname and dns information
cp "/etc/resolv.conf" "$tmpdir/etc/resolv.conf"
cp "/etc/hosts" "$tmpdir/etc/hosts"
hostname > "$tmpdir/hostname.txt"
hostname --fqdn > "$tmpdir/hostname_--fqdn.txt"
dig `hostname --fqdn` > "$tmpdir/dig-fqdn.txt"
ping -c 2 `hostname --fqdn` > ping_-c_2_fqdn.txt
ping -c 2 `hostname` > ping_-c_2_hostname.txt

# gather everything ohai knows
/opt/opscode/bin/ohai > "$tmpdir/ohai.txt"

if [[ -e /opt/opscode-manage/bin/opscode-manage-ctl ]]; then
    /opt/opscode-manage/bin/opscode-manage-ctl status > "$tmpdir/opscode-manage-ctl_status.txt"
    found_manage=true
fi

if [[ -e /opt/opscode-reporting/bin/opscode-reporting-ctl ]]; then
    /opt/opscode-reporting/bin/opscode-reporting-ctl status > "$tmpdir/opscode-reporting-ctl_status.txt"
    found_reporting=true
fi

su -m opscode -c 'ulimit -a' > "$tmpdir/ulimit_a_opscode.txt"

ip addr show > "$tmpdir/ip_addr_show.txt"

# ss(8) is the command for socket statistics that replaces netstat
ss -ontap > "$tmpdir/ss_ontap.txt"

sysctl -a > "$tmpdir/sysctl_a.txt" 2>&1

dmesg > "$tmpdir/dmesg.txt"

function add_footer (){
    echo "---" >> "$1"
    echo ""    >> "$1"
}

if [[ -z $testing ]]; then
    # in the future we should remove this file since the data is now
    # gathered one file at a time to match Automate output
    name_resolution_file="$tmpdir/name-resolution.txt"

    if which dig > /dev/null 2>&1; then
        echo '## dig hostname -f' > "$name_resolution_file"
        dig `hostname -f` >> "$name_resolution_file"
        add_footer "$name_resolution_file"
    fi

    echo '## /etc/resolv.conf' >> "$name_resolution_file"
    cat /etc/resolv.conf >> "$name_resolution_file"
    add_footer "$name_resolution_file"

    echo '## ping hostname' >> "$name_resolution_file"
    ping -c 2 `hostname` >> "$name_resolution_file"
    add_footer "$name_resolution_file"

    echo '## ping hostname -f' >> "$name_resolution_file"
    ping -c 2 `hostname -f` >> "$name_resolution_file"
    add_footer "$name_resolution_file"

    echo '## /etc/hosts' >> "$name_resolution_file"
    cat /etc/hosts >> "$name_resolution_file"
    add_footer "$name_resolution_file"

fi

fqdn="api_fqdn"
backend_vip="backend_vip"
tempname=`grep -E $fqdn $config_file_path | cut -d \" -f2`
backend_fqdn=`grep -E $backend_vip $config_file_path | cut -d \" -f2`

#Didnt find a hostname above, so fallback
if [[ -z $tempname ]]; then
    tempname=$hostname
fi

if [[ -z $testing ]]; then
    echo '## Resolved Name + Time' >> "$name_resolution_file"
    echo $tempname >> "$name_resolution_file"
    for interval in `seq 1 5`; do
        { time /opt/opscode/embedded/bin/ruby -e "require 'resolv'; start=Time.now; p Resolv.getaddress(\"$tempname\")" ; } >> "$name_resolution_file" 2>&1
        sleep 2;
    done

    echo $backend_fqdn >> "$name_resolution_file"
    for interval in `seq 1 5`; do
        { time /opt/opscode/embedded/bin/ruby -e "require 'resolv'; start=Time.now; p Resolv.getaddress(\"$backend_fqdn\")" ; } >> "$name_resolution_file" 2>&1
        sleep 2;
    done
fi

# gather important file permissions
for fileperms in \
    /var/opt/opscode* \
        /var/log/opscode*; do
    ls -altuhR "$fileperms" >> "$tmpdir/perms.txt"
done

# gather the db migration level
migration_level_file="$tmpdir/migration-level.txt"
migration_level_file_location="/var/opt/opscode/upgrades/migration-level"
if [[ -f $migration_level_file_location  ]]; then
    cat $migration_level_file_location >> "$migration_level_file"
else
    echo "!!! Migration level file not found  !!!">> "$migration_level_file";
fi

#What packages do we have installed on our supported platforms?
installed_packages_file="$tmpdir/installed-packages.txt"
installed_packages_grep="grep -i -E (chef|opscode)"
if [[ $known_platform == 'rhel' ]]; then
    rpm -qa | $installed_packages_grep >> "$installed_packages_file"
elif [[ $known_platform == 'amazon' ]]; then
    rpm -qa | $installed_packages_grep >> "$installed_packages_file"
elif [[ $known_platform == 'ubuntu' ]]; then
    dpkg -l | $installed_packages_grep >> "$installed_packages_file"
else
    echo "!!! Unknown platform !!!" >> "$installed_packages_file"
fi

##
## Plain entries to construct reporting passwords for comparison
## echo "select passwd from pg_shadow where usename='opscode_reporting';" | su - $POSTGRESQL_UNIX_USER -c 'psql -U opscode-pgsql postgres -t -A' | sed 's/md5//' >> "$service_passwords_file"
## echo "select passwd from pg_shadow where usename='opscode_reporting_ro';" | su - $POSTGRESQL_UNIX_USER -c 'psql -U opscode-pgsql postgres -t -A' | sed 's/md5//' >> "$service_passwords_file"
## grep sql_password /etc/opscode-reporting/opscode-reporting-running.json | sed -e 's/^.*"\(.*\)",$/\1opscode_reporting/' | tr -d '\n' | md5sum | cut -d ' ' -f1 >> "$service_passwords_file"
## grep db_pass /var/opt/opscode-reporting/opscode-reporting/etc/sys.config | sed 's/^.*, "\(.*\)".*/\1opscode_reporting/' |tr -d '\n' | md5sum | cut -d ' ' -f1 >> "$service_passwords_file"
## grep sql_ro_password /etc/opscode-reporting/opscode-reporting-running.json | sed -e 's/^.*"\(.*\)",$/\1opscode_reporting_ro/' | tr -d '\n' | md5sum | cut -d ' ' -f1 >> "$service_passwords_file"
##
##
if [[ $found_reporting ]]; then
    service_passwords_file="$tmpdir/service-passwords.txt"
    db_check="echo select passwd from pg_shadow where usename=\'first\'\; | su - $POSTGRESQL_UNIX_USER -c 'psql -U opscode-pgsql postgres -t -A' | sed 's/md5//'"
    opscode_reporting_password=`echo $db_check | sed s@first@opscode_reporting@`
    opscode_reporting_password_ro=`echo $db_check | sed s@first@opscode_reporting_ro@`

    file_check="grep passspot filename | sed 's/^.*\"\(.*\)\".*/\1sedfirst/' |tr -d '\n' | md5sum | cut -d ' ' -f1"
    opscode_reporting_service=`echo $file_check | sed 's@passspot@db_pass@;s@filename@/var/opt/opscode-reporting/opscode-reporting/etc/sys.config@;s@sedfirst@opscode_reporting@'`

    opscode_reporting_etc=`echo $file_check | sed 's@passspot@sql_password@;s@filename@/etc/opscode-reporting/opscode-reporting-running.json@;s@sedfirst@opscode_reporting@'`
    opscode_reporting_etc_ro=`echo $file_check | sed 's@passspot@sql_ro_password@;s@filename@/etc/opscode-reporting/opscode-reporting-running.json@;s@sedfirst@opscode_reporting_ro@'`

    echo '## opscode-reporting' >> "$service_passwords_file"
    echo '-- opscode-reporting pass in DB' >> "$service_passwords_file"
    echo `eval $opscode_reporting_password` >> "$service_passwords_file"
    add_footer "$service_passwords_file"

    echo '-- opscode-reporting_ro pass in DB' >> "$service_passwords_file"
    echo `eval $opscode_reporting_password_ro` >> "$service_passwords_file"
    add_footer "$service_passwords_file"

    echo '-- opscode-reporting pass service config file /var/opt/opscode-reporting/opscode-reporting/etc/sys.config' >> "$service_passwords_file"
    echo `eval $opscode_reporting_service` >> "$service_passwords_file"
    add_footer "$service_passwords_file"

    echo '-- opscode-reporting pass etc config file /etc/opscode-reporting/opscode-reporting-running.json' >> "$service_passwords_file"
    echo `eval $opscode_reporting_etc` >> "$service_passwords_file"
    add_footer "$service_passwords_file"

    echo '-- opscode-reporting_ro pass etc config file' >> "$service_passwords_file"
    echo `eval $opscode_reporting_etc_ro` >> "$service_passwords_file"
    add_footer "$service_passwords_file"

fi

# check if the system is proxied by checking if HTTPS_PROXY and HTTP_PROXY are unset or empty
if [[ -z "$HTTPS_PROXY" || -z "$HTTP_PROXY" ]]; then # proxy not set
    echo "0" > "${tmpdir}/connectivity/proxied.txt"
else
    echo "1" > "${tmpdir}/connectivity/proxied.txt"
fi

# check if a system can reach supermarket
if curl https://supermarket.chef.io > /dev/null 2>&1; then
    echo "1" > "${tmpdir}/connectivity/supermarket_accessible.txt"
elif wget https://supermarket.chef.io -O $tmpdir/connectivity/supermarket_accessible.txt > /dev/null 2>&1; then
    echo "1" > "${tmpdir}/connectivity/supermarket_accessible.txt"
else
    echo "0" > "${tmpdir}/connectivity/supermarket_accessible.txt"
fi

tar -C "${tmpdir%/*/*}" -czpf "$hostname-$timestamp.tar.gz" "$hostname/$timestamp/"

rm -rf "${tmpdir%/*/*}"

echo "Logs gathered in $hostname-$timestamp.tar.gz"
