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.
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
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
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
}
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
}
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