#!/bin/bash

# Supportconfig Plugin for SUSE Public Cloud Images
#
# Copyright (C) 2024 SUSE LLC
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA  02110-1301, USA.

# Gathers important troubleshooting information about
# SUSE Public Cloud Instances

set +o noglob

SVER="1.0"
RCFILE="/usr/lib/supportconfig/resources/scplugin.rc"

# Collect all the public cloud relevant data in a directory
# $LOG is exported by supportconfig script and is the data collection
# directory
DATA_LOCATION="${LOG}/public_cloud"
mkdir -p $DATA_LOCATION

if [ -s $RCFILE ]; then
    if ! source "$RCFILE"; then
        echo "ERROR: Initializing resource file: $RCFILE" >&2
        exit 1
    fi
fi

function _collect_all_file_data() {
    dir=$1
    dest_file=$2
    for f in "$dir/*"; do
        echo "#==[ $f ]====================================#" >> $dest_file
        echo "# cat $f" >> $dest_file
        cat $f >> $dest_file
        echo "" >> $dest_file
        echo "" >> $dest_file
    done
}

function _collect_service_log() {
    service=$1
    dest_file=$2
    echo "#==[ service: $service ]====================#" >> $dest_file
    journalctl --unit $service >> $dest_file
    echo "" >> $dest_file
    echo "" >> $dest_file
}

function _collect_services_logs() {
    services=$1
    dest_file=$2
    for service in ${services[@]}; do
        _collect_service_log $service $dest_file
    done
}

function _sanitize_data() {
    local INFO_FILE=$1 && shift
    local data_to_remove=($@)
    for data in "${data_to_remove[@]}";do
	sed "/$data/d" $INFO_FILE | sudo tee $INFO_FILE > /dev/null
    done
}

function csp_billing_adapter_cfg() {
    local INFO_FILE="$DATA_LOCATION/csp_billing_adapter_config.txt"
    local BA_CONFIG_FILE="/etc/csp_billing_adapter/config.yaml"
    echo "#==[ CSP billing adapter config ]========================#" > $INFO_FILE
    if [ -e $BA_CONFIG_FILE ]; then
        echo "# cat $BA_CONFIG_FILE" >> $INFO_FILE
        cat $BA_CONFIG_FILE >> $INFO_FILE
    else
        echo "# not found" >> $INFO_FILE
    fi
}

function csp_billing_adapter_log() {
    local INFO_FILE="$DATA_LOCATION/csp_billing_adapter_log.txt"
    local BA_LOG_FILE="/var/log/csp_billing_adapter.log"
    echo "#==[ CSP billing adapter log ]========================#" > $INFO_FILE
    if [ -e $BA_LOG_FILE ]; then
        echo "# cat $BA_LOG_FILE" >> $INFO_FILE
        cat $BA_LOG_FILE >> $INFO_FILE
    else
        echo "# not found" >> $INFO_FILE
    fi
}

function csp_billing_adapter_meter_data() {
    local INFO_ARCHIVE="$DATA_LOCATION/csp_billing_adapter_metering_archive.json"
    local INFO_CACHE="$DATA_LOCATION/csp_billing_adapter_current_cycle.json"
    local ARCHIVE="/var/lib/csp-billing-adapter/archive.json"
    local CACHE="/var/lib/csp-billing-adapter/cache.json"
    if [ -e $ARCHIVE ]; then
        cp $ARCHIVE $INFO_ARCHIVE
    fi
    if [ -e $CACHE ]; then
        cp $CACHE $INFO_CACHE
    fi
}

function billing_flavor() {
    local INFO_FILE="$DATA_LOCATION/billingflavor.txt"
    if [ -e /usr/bin/instance-flavor-check ]; then
        /usr/bin/instance-flavor-check >& $INFO_FILE
        echo $? >> $INFO_FILE
    fi
}

function credentials() {
    local INFO_FILE="$DATA_LOCATION/credentials.txt"
    _collect_all_file_data "/etc/zypp/credentials.d" $INFO_FILE
}

function framework() {
    local INFO_FILE="$DATA_LOCATION/framework.txt"
    echo "#==[ Determine Framework ]================================#" > $INFO_FILE
    echo "# dmidecode | grep -q amazon|Google|Microsoft" >> $INFO_FILE

    if dmidecode | grep -q -i amazon; then
        FRAMEWORK="EC2"
    fi
    if dmidecode | grep -q Google; then
        FRAMEWORK="GCE"
    fi
    if dmidecode | grep -q Microsoft; then
        FRAMEWORK="Azure"
    fi
    echo $FRAMEWORK >> $INFO_FILE
}

function hosts() {
    local INFO_FILE="$DATA_LOCATION/hosts.txt"
    echo "#==[ Hosts ]=============================================#" > $INFO_FILE
    echo "# cat /etc/hosts" >> $INFO_FILE
    cat /etc/hosts >> $INFO_FILE
}

function initialization_log() {
    local INFO_FILE="$DATA_LOCATION/instanceinit.txt"
    echo "#== [ instance initialization info ]=============================#" > $INFO_FILE
    if [ -e /var/log/cloud-init.log ]; then
        echo "#== [ cloud-init info ]=============================#" >> $INFO_FILE
        
        init_logs=( cloud-init.log cloud-init-output.log )
        for log in ${init_logs[@]}; do
            echo "#== [ $log  ]=============================#" >> $INFO_FILE
            cat /var/log/$log >> $INFO_FILE
            echo "" >> $INFO_FILE
            echo "" >> $INFO_FILE
        done

        echo "#==[ syslog messages ]====================#" >> $INFO_FILE
        if [ -e /usr/bin/journalctl ]; then
            services=( cloud-init-local cloud-init cloud-config cloud-final )
            _collect_services_logs $services $INFO_FILE
        else
            grep "CLOUDINIT" /var/log/messages  >> $INFO_FILE
            echo "" >> $INFO_FILE
            echo "" >> $INFO_FILE
        fi
    fi
    # Note order dependent, the framework function must be called first    
    if [ "$FRAMEWORK" = "Azure" ] && [ -e /var/log/waagent.log ]; then
        echo "#== [ waagent.log ]=================================#" >> $INFO_FILE
        cat /var/log/waagent.log >> $INFO_FILE
    fi
    if [ "$FRAMEWORK" = "EC2" ]; then
        if [ -e /var/log/ecs ]; then
            ecs_logs=( ecs-agent.log ecs-init.log )
            for log in ${ecs_logs[@]}; do
                echo "#== [ $log  ]=============================#" >> $INFO_FILE
                cat /var/log/ecs/$log >> $INFO_FILE
                echo "" >> $INFO_FILE
                echo "" >> $INFO_FILE
            done
        fi
    fi
    if [ "$FRAMEWORK" = "GCE" ]; then
        echo "#== [ google.log  ]=============================#" >> $INFO_FILE
        cat /var/log/google.log >> $INFO_FILE
        echo "" >> $INFO_FILE
        echo "" >> $INFO_FILE

        if [ -e /usr/bin/journalctl ]; then
            # google google-accounts-manager google-address-manager
            # should be removed in Dec 2025
            services=( google google-accounts-manager google-address-manager google-startup-scripts google-shutdown-scripts google-guest-agent google-osconfig-agent )
            _collect_services_logs $services $INFO_FILE
        else
            echo "#==[ syslog messages ]====================#" >> $INFO_FILE
            grep "google:" /var/log/messages  >> $INFO_FILE
            echo "" >> $INFO_FILE
            echo "" >> $INFO_FILE
        fi
    fi
}

function metadata() {
    local INFO_FILE="$DATA_LOCATION/metadata.txt"
    echo "#==[ Instance Metadata ]=================================#" > $INFO_FILE
    local EXEC=""
    if [ -e "/usr/bin/ec2metadata" ]; then
        echo "# /usr/bin/ec2metadata --api latest" >> $INFO_FILE
        /usr/bin/ec2metadata --api latest  >> $INFO_FILE
        remove=("AccessKeyId" "SecretAccessKey"  "Token")
        _sanitize_data "$INFO_FILE" "${remove[@]}"
    fi
    if [ -e "/usr/sbin/azuremetadata" ]; then
        echo "# /usr/sbin/azuremetadata -e" >> $INFO_FILE
        /usr/sbin/azuremetadata -e >> $INFO_FILE
        echo "" >> $INFO_FILE
        echo "# /usr/sbin/azuremetadata -i" >> $INFO_FILE
        /usr/sbin/azuremetadata -i >> $INFO_FILE
        echo "" >> $INFO_FILE
        echo "# /usr/sbin/azuremetadata -t" >> $INFO_FILE
        /usr/sbin/azuremetadata -t >> $INFO_FILE
    fi
    if [ -e "/usr/bin/azuremetadata" ]; then
        echo "# /usr/bin/azuremetadata --api latest" >> $INFO_FILE
        /usr/bin/azuremetadata --api latest >> $INFO_FILE
    fi
    if [ -e "/usr/bin/gcemetadata" ]; then
        echo "# /usr/bin/gcemetadata" >> $INFO_FILE
        /usr/bin/gcemetadata  >> $INFO_FILE
        remove=("token")
        _sanitize_data "$INFO_FILE" "${remove[@]}"
    fi
}

function packages() {
    # Note order dependent, the framework function must be called first
    local INFO_FILE="$DATA_LOCATION/frameworkpackages.txt"
    local COMMON_PACKAGE_LIST="/usr/lib/supportconfig/resources/rpmlist_pubcloud_common"
    local FRAMEWORK_PACKAGE_LIST="/usr/lib/supportconfig/resources/rpmlist_$FRAMEWORK"
    echo "#==[ Packages ]=================================#" > $INFO_FILE

    if [ -e $COMMON_PACKAGE_LIST ]; then
        COMMON_PACKAGES=$(cat $COMMON_PACKAGE_LIST)
    else
        echo "$COMMON_PACKAGE_LIST not found" > $INFO_FILE
        echo "Possible install problem of supportutils-plugin-suse-public-cloud" > $INFO_FILE
    fi

    if [ -e $FRAMEWORK_PACKAGE_LIST ]; then
        FRAMEWORK_PACKAGES=$(cat $FRAMEWORK_PACKAGE_LIST)
    else
        echo "$FRAMEWORK_PACKAGE_LIST not found" > $INFO_FILE
        echo "Possible install problem of supportutils-plugin-suse-public-cloud" > $INFO_FILE
    fi

    PACKAGE_QUERY=($COMMON_PACKAGES $FRAMEWORK_PACKAGES)

    for pack in ${PACKAGE_QUERY[@]};do
        echo "# rpm -qa $pack" >> $INFO_FILE
        rpm -qa $pack >> $INFO_FILE
    done
}

function region_sever_config() {
    local INFO_FILE="$DATA_LOCATION/regionserverclnt.txt"
    echo "#==[ Region Server Configuration ]=======================#" > $INFO_FILE
    local REGIONSERVER_CONFIG="/etc/regionserverclnt.cfg"
    echo "# $REGIONSERVER_CONFIG" >> $INFO_FILE
    if [ -e $REGIONSERVER_CONFIG ]; then
        cat $REGIONSERVER_CONFIG >> $INFO_FILE
    else
        echo "File not found" >> $INFO_FILE
        echo "This may not be an on demand instance" >> $INFO_FILE
    fi
}

function registration_cache() {
    local INFO_FILE="$DATA_LOCATION/registrationcache.txt"
    echo "#==[ Registration Cache Content ]========================#" > $INFO_FILE
    if [ -e /var/cache/cloudregister ]; then
        ls /var/cache/cloudregister/* >> $INFO_FILE
        mkdir "$DATA_LOCATION/regcache"
        cp /var/cache/cloudregister/* "$DATA_LOCATION/regcache"
    else
        echo "/var/cache/cloudregister does not exist" >> $INFO_FILE
    fi
}

function registration_data() {
    local INFO_FILE="$DATA_LOCATION/cloudregister.txt"
    echo "#==[ Registration Data ]=================================#" > $INFO_FILE
    local REGISTRATION_LOG="/var/log/cloudregister"
    echo "# $REGISTRATION_LOG" >> $INFO_FILE
    if [ -e $REGISTRATION_LOG ]; then
        cat $REGISTRATION_LOG >> $INFO_FILE
    else
        echo "File not found" >> $INFO_FILE
        echo "This may not be an on demand instance" >> $INFO_FILE
    fi
}

function registration_instance_args() {
    local INFO_FILE="$DATA_LOCATION/registrationinstanceargs.txt"
    echo "#==[ Instance Args For Registration ]====================#" > $INFO_FILE
    local HASINSTARGCMD=$(grep dataProvider /etc/regionserverclnt.cfg)
    if [ -n "$HASINSTARGCMD" ]; then
        local INSTARGCMD=$(grep dataProvider /etc/regionserverclnt.cfg | cut -d"=" -f2)
        $INSTARGCMD >> $INFO_FILE
    else
        echo "No instance arg command configured" >> $INFO_FILE
    fi
}
    
function repos() {
    local INFO_FILE="$DATA_LOCATION/repositories.txt"
    _collect_all_file_data "/etc/zypp/repos.d" $INFO_FILE
}

function services() {
    local INFO_FILE="$DATA_LOCATION/services.txt"
    _collect_all_file_data "/etc/zypp/services.d" $INFO_FILE
}

function os_release_data() {
    local INFO_FILE="$DATA_LOCATION/osrelease.txt"
    echo "#==[ OS Release Data ] =================================#" > $INFO_FILE
    echo "# cat /etc/os-release" >> $INFO_FILE
    cat /etc/os-release >> $INFO_FILE
}

function update_infra_data() {
    local INFO_FILE="$DATA_LOCATION/updateinfrastructure.txt"
    echo "#==[ Update Infrastructure ]=============================#" > $INFO_FILE
    echo "# zypper ref" >> $INFO_FILE
    zypper ref >> $INFO_FILE
}

# Collect all the data
framework
credentials
hosts
metadata
packages
region_sever_config
registration_data
initialization_log
repos
services
os_release_data
update_infra_data
registration_instance_args
registration_cache
billing_flavor
csp_billing_adapter_cfg
csp_billing_adapter_log
csp_billing_adapter_meter_data
