Bash : SSH Skript mit eigener known_hosts

Problem : Wir arbeiten hier auf einem Server mit mehreren Usern, es kommt immer wieder vor das jemand die known_hosts überschreibt. Den Schuldigen haben wir noch nicht gefunden ;-) Also verwenden wir jetzt in unseren Skripts eigene known_hosts files.

Lösung :
Ich habe mir angewöhnt im Skript Ordner einen Ordner ssh anzulegen in dem dann die known_hosts liegt.
Somit bin ich unabhängig von anderen.
Setzen einer Variable im Skript
SSH_KNOWN_HOST="-o ConnectTimeout=30 -o UserKnownHostsFile=$(dirname $(readlink -f ${0}))/ssh/known_hosts"
Im Skript selbst kann man das so verwenden.
ssh ${SSH_KNOWN_HOST} USER@HOSTNAME
Da sftp und ssh die selben Parameter kennen kann man diese Variable beim Aufruf von ssh und sftp verwenden.

AWS : automatisierter start der aws instanzen

Problem : Automatisches Starten der Instanzen bei AWS
Lösung : Man lässt dieses Skript auf einer Maschine/Instanz laufen auf der die aws cli konfiguriert ist.
#!/bin/bash
set -o nounset
set -o pipefail
# Script startet alle definierten Maschinen
AWS_PATH="/root/.local/bin/"
# -----------------------------------------------------------
# Definieren der Maschinen die gestartet werden müssen
# -----------------------------------------------------------
# z.B. declare -a TO_START=("i-xxxxxxxxxxxxxxxxx" "i-xxxxxxxxxxxxxxxxx" "i-xxxxxxxxxxxxxxxxx" "i-xxxxxxxxxxxxxxxxx")
declare -a TO_START=("")
# ------------------------------------------------------------
# nichts mehr ändern
# ------------------------------------------------------------
LOG_PATH="$(dirname $(readlink -f $0))/logs"
LOG_FILE="$(date +%Y%m%d)-awscli.log"
# ------------------------------------------------------------
# Funktionen
# ------------------------------------------------------------
function logger () {
        mkdir -p ${LOG_PATH}
        if [ -z ${2} ]; then
                STATI="INFO"
        else
                STATI="${2}"
        fi
        echo "$(date +%Y-%m-%d) | $(date +%R) | ${STATI} | ${1}" >> ${LOG_PATH}/${LOG_FILE}
}
# ------------------------------------------------------------
logger "Starte -> ${0##*/}" "INFO"
cnt=${#TO_START[@]}
for ((i = 0 ; i < cnt ; i++ )); do
        logger "${TO_START[i]} wird gestartet" "INFO"
        ${AWS_PATH}aws ec2 start-instances --instance-ids ${TO_START[i]} > /dev/null 2>&1
done
logger "Beende -> ${0##*/}" "INFO"
exit 0

AWS : automatisierter shutdown der aws instanzen

Problem : Man hat ein paar Instanzen in der AWS installiert, diese werden aber nur für die Entwicklung bzw. Tests benötigt. Um zusätzliche Kosten zu sparen kann man diese automatisiert außerhalb der benötigten Zeiten herunterfahren.

Lösung : Man lässt dieses Skript auf einer Maschine/Instanz laufen auf der die aws cli konfiguriert ist. Das Beispiel hier läuft selbst eine AWS Instanz. Aus diesem Grund wird mit
OWN_INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
die eigene ID ermittelt.
Das Skript fährt alle Instanzen herunter außer diese die in DO_NOT_SHUTDOWN definiert sind.

#!/bin/bash
# ----------------------------------
set -o nounset
set -o pipefail
# ----------------------------------
#
# Script fährt alle Instanzen herunter bis auf die unter DO_NOT_SHUTDOWN definierten
# die eigene Maschine bleibt natürlich auch online
# PFAD zu awscli
AWS_PATH="/root/.local/bin/"
OWN_INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
# -----------------------------------------------------------
# Definieren der Maschinen die NICHT heruntergefahren werden
# -----------------------------------------------------------
# wenn die eigene Instanz geschützt werden soll diese mit ins Array aufnehmen. Nur so ist gewährleistet das alles abgearbeitet wird
# z.B. declare -a DO_NOT_SHUTDOWN=("${OWN_INSTANCE_ID}" "i-xxxxxxxxxxxxx" "i-xxxxxxxxxxxxx" "i-xxxxxxxxxxxxx")
#
declare -a DO_NOT_SHUTDOWN=("${OWN_INSTANCE_ID}")
# -----------------------------------------------------------
# nichts mehr ändern
# -----------------------------------------------------------
LOG_PATH="$(dirname $(readlink -f $0))/logs"
LOG_FILE="$(date +%Y%m%d)-awscli.log"
# -----------------------------------------------------------
# Funktionen
# -----------------------------------------------------------
function is_inList ()
{
  SERVER=${1}
  max=${#DO_NOT_SHUTDOWN[@]}
  RET=1

  for ((i = 0 ; i < max ; i++ )); do
    if [ "${DO_NOT_SHUTDOWN[i]}" = "${SERVER}" ]; then
      RET=0
      break
    fi
  done

  return $RET
}
function logger () {
        mkdir -p ${LOG_PATH}
        if [ -z ${2} ]; then
                STATI="INFO"
        else
                STATI="${2}"
        fi
        echo "$(date +%Y-%m-%d) | $(date +%R) | ${STATI} | ${1}" >> ${LOG_PATH}/${LOG_FILE}
}
# -----------------------------------------------------------
# Prüfen ob OWN_INSTANCE_ID einen Wert enthält
# -----------------------------------------------------------
logger "Starte -> ${0##*/}" "INFO"
if [ -z ${OWN_INSTANCE_ID} ]; then
        logger "OWN_INSTANCE_ID ist leer Skript wird nicht gestartet" "ERROR"
        logger "Beende AWS Script" "ERROR"
        exit 99
fi

for item in $(${AWS_PATH}aws ec2 describe-instances --query 'Reservations[].Instances[][InstanceId,Tags[?Key==`Name`].Value | [0],LaunchTime,State.Name]' --filters "Name=instance-state-name,Values=running" --output text | awk '{print $1}')
do
        is_inList ${item}
        RET=$?
        if [ $RET -eq 0 ]; then
                logger "${item} wird nicht heruntergefahren definiert in OWN_INSTANCE_ID oder DO_NOT_SHUTDOWN" "INFO"
                continue
        else
                logger "${item} wird heruntergerfahren" "INFO"
                #----  aws cli fährt kiste herunter
                ${AWS_PATH}aws ec2 stop-instances --instance-ids ${item} > /dev/null 2>&1
        fi
done
logger "Beende -> ${0##*/}" "INFO"
exit 0


Bash : Funktion um Files zu laden

Funktion um Dateien aus dem Internet zu laden. Prüft ob curl vorhanden ist , wenn nicht wird wget versucht. Wenn gar nichts von beiden gefunden wird wird das Skript beendet.

function get_remote_file () {
        # ------------------------- get_remote_file -------------------------------------------------------------------
        # download an file to local storage
        #
        # need 2 parameters : get_remote_file [URL_TO_FILE] [LOCAL_PATH]
        # -----------------------------------------------------------------------------------------------------------------

        if [[ ! -z "${1}" || ! -z "${2}" ]]; then
                bin_dl=""
                # check Local Path
                if [ ! -d "${2}" ]; then
                        mkdir "${2}"
                fi
                # check bins
                # using command instead of which to be posix comp.
		
		# ------ check curl
                command -v curl >/dev/null 2>&1
                if [ $? -eq 0 ]; then
                        bin_dl="curl -s -O "
                fi

		# ------ check wget
                command -v wget >/dev/null 2>&1
                if [[ ${bin_dl} = "" && $? -eq 0 ]]; then
                        bin_dl="wget -q "
                fi

		# ------ if emtpy curl and wget not found
                if [ ${bin_dl} = "" ]; then
                        echo "need curl or wget for work please install one of them"
                        exit 98
                fi

                # download file
                if [[ "${1}" =~ http:// || "${1}" =~ https:// || "${1}" =~ ftp:// ]]; then
                        # ${1} is an remote file will be downloaded to ${2}
                        cd "${2}" && { ${bin_dl} "${1}" ; cd -; }
                else
                        # ${1} is not an remote file EXIT !
                        exit 98
                fi
        else
                echo "check parameters for function #> get_remote_file"
                exit 9
        fi
}

Bash : Inhalt von ZIP Dateien vergleichen

Problem : Man möchte über Bash nur den Inhalt einer Zip Datei vergleichen. Die Zip Datei wird aber automatisiert auf einem Server über cron erstellt, was zur Folge hatte das der Zeitstempel und somit auch die md5 Summen unterschiedlich sind.

Lösung : Die Lösung ist mit unzip in die Datei zu schauen und diesen Output mit diff zu verleichen.
function check_files_in_zip () {
	# ------------------------ check_files_in_zip ---------------------------------------
	# compare the content of two zipfiles if equal the function return 0 otherwise 1 
	#
	# need 2 parameters : check_files_in_zip [NAME_OF_OLD_ZIPFILE] [NAME_OF_NEW_ZIPFILE]
	# -----------------------------------------------------------------------------------

	if [[ ! -z "${1}" || ! -z "${2}"  ]]; then
        	diff <(unzip -v -l "${1}" | awk '! /Archiv/ && /[0-9]/ { print $1,$5,$6,$7,$8 }' | sed '$d') <(unzip -v -l "${2}" | awk '! /Archiv/ && /[0-9]/ { print $1,$5,$6,$7,$8 }' | sed '$d') 1>/dev/null 2>&1
        	if [ $? -eq 0 ]; then
                	return 0
        	else
                	return 1
       		fi
	else
		echo "check parameters for function #> check_files_in_zip"
                exit 9
        fi
}

BASH: Nur eine Instanz eines Bash Skriptes starten

In einigen Fällen darf ein Skript nur eine Instanz starten, z.B. Aufbereitung für Backup. Für diesen Zweck hab ich hier das kleine Bespiel eingestellt.

Sollten mehrere Benutzer das Skript starten können ist natürlich darauf zu achten das sie alle Schreibrechte auf das PID File haben.
PIDFILE="$(dirname "$(readlink -f "$0")")/$(basename "${0}").pid"
Und hier das komplette Beispiel :
#!/bin/bash

function check_process () {
        # ------------------------- check_process -----------------------------
        # create an pid file for an bash script and check is it already running
        #
        # need 2 parameters : check_process [NAME_OF_PIDFILE] [NAME_OF_SCRIPT]
        # ---------------------------------------------------------------------

        cp_PID_FILE="${1}"
        cp_SCR_NAME="${2}"
        cp_RET=1
        if [[ -n "${cp_PID_FILE}" && -n "${cp_SCR_NAME}" ]]; then
                if [ -f "${cp_PID_FILE}" ]; then
                        # Pid File auslesen
                        pid=$(cat "${cp_PID_FILE}")
                        chkpid=$(ps -ax | grep "/bin/bash" | grep "/${cp_SCR_NAME}" | grep "${pid}" | grep -v grep)
                        if [ $? -ne 0 ]; then
                                rm "${cp_PID_FILE}"
                                cp_RET=0
                        else
                                # Skript läuft noch -> keine doppelte ausführung wird beendet
                                # Direkter Abbruch (auskommentieren)
                                # echo "the script is already running -> PID:${pid}"
                                # exit 1
                                # Rückgabewert
                                cp_RET=1

                        fi
                fi
        else
                echo "check parameters for function #> check_process"
                exit 9
        fi
        if [ ${cp_RET} -eq 0 ]; then
                echo $$ > "${cp_PID_FILE}"
        fi
        return ${cp_RET}
}
# --------------------------------------------------------------------
clear
PIDFILE="$(dirname "$(readlink -f "$0")")/$(basename "${0}").pid"
check_process "${PIDFILE}" "$(basename "${0}")"
if [ $? -eq 1 ]; then
        echo "Script läuft bereits"
        exit 99
fi
echo "readlink : " $(readlink -f "${0}")
echo "basename : " $(basename "${0}")
echo "pidfile  : " ${PIDFILE}
echo "---------------------------------"
# endlosschleife - debug
while true; do
printf "."
sleep 2
done


Vielleicht hilft das dem einen oder anderen ;-)
“Das einzig sichere System müsste ausgeschaltet, in einem versiegelten und von Stahlbeton ummantelten Raum und von bewaffneten Schutztruppen umstellt sein.”
Gene Spafford (Sicherheitsexperte)