Время начала и окончания действия сертификата

Как узнать время начала действия и окончания (истечения) сертификата?

echo | openssl s_client -connect google.com:443 2>/dev/null | openssl x509 -noout -dates | cut -d '=' -f2- | xargs -I{} date --date="{}" '+%F %T'

Для того чтобы после взаимодействия с сервером в пакетном режиме openssl завершился необходимо передать ему перевод строки. Иногда можно встретить, что ему передают файл перенаправлением из /dev/null. Оба варианта работают одинаково.
Второй вызов openssl работает уже с полученным через pipe сертификатом и достаёт из него дату начала его дествия и дату окончания действия. Затем командой cut из сертификата извлекается только дата, и наконец дата передаётся в качестве параметра команде date которая из него может сформировать дату в различных форматах.
Continue reading Время начала и окончания действия сертификата

bash script для запуска vncviewer на выбранную из списка виртуалку

Этот баш-скрипт я написал так как был недоволен утилитой Virtual Machine Manager которая имеет ошибку и не поддерживает у меня соединения через ssh туннель и её нужно патчить после каждого обновления. Но главное, что меня раздражает это тормоза работы Virtual Machine Manager так как он получает много зачастую ненужной информации от всех виртуальных машин. Данный скрипт работает сравнительно быстро потому, что запрашивает на сервере только самое необходимое, а именно список запущенных машин и смещение vnc порта для каждой.

#!/bin/bash

  # bash script to connect to virtual machine vnc port (over ssh tunnel)
  # баш скрипт выводит список виртуальных машин и предлагает выбрать с какой соединиться по VNC

function GETVNCPORTS {
  NODE=$1
  echo -e "Reading info from \"${NODE}\"" >&2
  awk -v node="${NODE}" '{print node" "$0}' < <(ssh -T "root@${NODE}" <<'END'
while read -r DOMAIN ; do PORT=`virsh vncdisplay "${DOMAIN}" | sed -e '/^[ \t]*$/d' | awk -F: '{printf "59%02d\n",$2}'`; [ -n "${PORT}" ] && echo "${PORT} ${DOMAIN}"; done < <(virsh list | sed -n '/^-\+$/,/^$/p' | sed -e '/^ *-\+ *$/d' | awk '{print $2}' | sed -e '/^[ \t]*$/d')
END
)
}

# file descriptions IPADDRES<spaces>group1<spaces>group2<spaces>groupN
# файл описывающий все хосты и группы в которые они входят
CONFIG=$(cat <<EOF
10.55.24.156     v03-a v_cluster all
10.55.24.157     v03-b v_cluster all
10.55.24.158     v03-c v_cluster all
10.55.24.159     v03-t           all sergey
10.55.24.253     h01             all
10.55.24.249     s01-0 s_cluster all
10.55.24.251     s01-1 s_cluster all
EOF
)

  HOSTGROUPS=`echo "${CONFIG}" | awk '{for (i=2;i<=NF;i++) {printf("%s\n", $i);}}' | sort -u`

  while [ true ] ; do
    PS3="Type a group number or 'q' to quit: "
    select HOSTGROUP in ${HOSTGROUPS} ; do
      if [ -n "${HOSTGROUP}" ] ; then
        break
      else
        if [[ ${REPLY} =~ [Qq] ]] ; then
          echo -e "Quit."
          exit 0
        fi
      fi
    done

    LOOPLEVEL="1"

    while [ "${LOOPLEVEL}" -eq "1" ] ; do

      FULLLIST=""
      # получить список хостов
      while read HOST1 GROUPNAME ; do
        echo -e "${GROUPNAME}"
        FMT="ssh -L localhost:%d:localhost:%d -N root@%s& pid=\$!;sleep 2;vncviewer localhost:%d;kill \$pid;sleep 1;echo \" \" # %s(%s)\n"
        ITEM=`GETVNCPORTS "${HOST1}"  | awk -v fmt="${FMT}" -v hst="${GROUPNAME}" '{printf(fmt, $2, $2, $1, $2, $3, hst)}'`
        FULLLIST=`echo -e "${FULLLIST}\n${ITEM}"`
      done < <(echo -e "${CONFIG}" | awk -v group="${HOSTGROUP}" '{if ($0 ~ group) {print $1" "$2}}')
      # убрать пустые строки
      FULLLIST=`echo -e "${FULLLIST}" | sed -e '/^$/d'`

      VMLIST=`echo -e "${FULLLIST}" | sed -e 's/^[^#]*# \([^ ]*\)$/\1/g' | sort`

      if [ -z "${VMLIST}" ] ; then
        echo -e "No VM is running on host group \"${HOSTGROUP}\""
        LOOPLEVEL="0"
        break
      fi

      PS3="Type a number or 'q' to return to previous menu, 'r' to reread list: "
      select VMNAME in ${VMLIST} ; do
        if [ -n "${VMNAME}" ] ; then
          break
        else
          if [[ ${REPLY} =~ [Qq] ]] ; then
            echo -e "Quit."
            LOOPLEVEL="0"
            break
          elif [[ ${REPLY} =~ [Rr] ]] ; then
            # next loop with reread
            break
          fi
        fi
      done
      if [ -n "${VMNAME}" ] ; then
        COMMANDSTR=`echo -e "${FULLLIST}" | sed -n 's/^\([^#]*\)# '${VMNAME}'$/\1/p'`
        echo -e "${COMMANDSTR}"
        eval "${COMMANDSTR}"
        echo -e "All done."
      fi
    done
  done
Рекоментация!Для соединения ssh будет требоваться аутентификация на удалённом сервере. Сделать это удобнее используя сертификаты. Чтобы каждый раз не открывать сертификат паролем стоит добавить их один раз в ssh-agent при помощи ssh-add /home/user001/.ssh/id_rsa

Как узнать путь откуда запущен bash скрипт

BASEDIR=$(readlink -e "$0")
if [ $? -ne 0 ] ; then
  echo -e "Script path get error."
  exit 1
fi
BASEDIR="${BASEDIR%/*}"
echo "${BASEDIR}" 
exit 0

В дополнение к команде readlink есть ещё realpath и realname которые вернут полный путь и имя переданного им файла. Разумеется файл должен существовать.

Но внимание! Приведённые выше команды вернут путь на сам файл даже если скрипт запустили через симлинк (symlink). Например может понадобиться чтобы скрипт мог что либо записать в папку из которой был запущен даже через симлинк. Чтобы этого добиться необходимо поступить например вот так:

SAVEDIR=`pwd`
BASEDIR=`cd "$(dirname "$0")" && pwd`
cd "${SAVEDIR}"
echo -e "${BASEDIR}"
exit 0

Скрипт удаления старых томов для bacula

Я уже писал о том как вручную удалять старые тома из базы и с диска. Казалось что это однократная операция. Однако пришлось делать это во второй раз. Попутно выявилась проблема с приоритетом команды restore. Диск с бэкапами заполнился, задания застряли в очереди и команда restore создала задание которое послушно встало в хвост очереди. Приоритеты очереди работают только в том случае если очередь движется. Bacula не приостанавливает ткущее задание чтобы выполнить задание с более высоким приоритетом. А оно стоит в очереди и не может выполниться изза нехватки места на диске. Гугл не смог найти ответ как же запустить рестор вне очереди. Пришлось очистить очередь, при помощи команды cancel в bconsole после чего отработал рестор.

Это всё отступления, вернёмся-же к автоматизации:
Continue reading Скрипт удаления старых томов для bacula

Оператор цикла for в bash

Великая магия оператора for о которую приходится биться каждый раз пока не усвоишь урок, кроется в том что он рубит входные данные по символам разделителям которые перечислены в переменной IFS=

Не менее странным является и то, что этой переменной невозможно присвоить один байт-символ CR (возврат каретки) 0xA.
Никакие танцы с бубнами и операторы echo не дают этой возможности.
Два символа можно

IFS=$(echo -en "\n\b") # работает
echo -en "$IFS" | hexdump -C
00000000  0a 08                                             |..|
00000002

но один или много \n — не получается.

IFS=$(echo -en "\n\n\n\n\n") # не работает. Переменная будет пустой.
echo -en "$IFS" | hexdump -C # да говорю же следующая строка будет пустой

IFS=$(echo -en "A" | tr 'A' '\n') # не пойдёт!
IFS="\
\
" # тоже не будет работать

Continue reading Оператор цикла for в bash

ssh внутри while цикла который получает данные из stdin

Наткнулся я на то что скрипт запущенный локально — работает, а если его запустить на удалённой машине он вываливается из цикла while

#!/bin/bash

  SERVERS="10.10.1.6\n10.15.4.240"

  echo -e "${SERVERS}" | while read SERVER ; do
    echo -e "${SERVER}"
    ssh root@${SERVER} "uptime"
  done

Как оказалось проблема в том что ssh съедает stdin в первой итерации цикла.
Для меня это было неожиданно, однако лечится либо опцией -n либо перенаправлением stdin на < /dev/null .

#!/bin/bash

  SERVERS="10.10.1.6\n10.15.4.240"

  echo -e "${SERVERS}" | while read SERVER ; do
    echo -e "${SERVER}"
    ssh -n root@${SERVER} "uptime"
    ssh root@${SERVER} "uptime" < /dev/null
  done

Fast HDD Eraser – Быстрое стирание дисков

Мне часто приходится затирать жёсткие диски пачками, например при модернизации стораджей, и мне был очень необходим скоростной источник потока данных которыми затирается целевой диск. Чтобы более менее надёжно затереть данные на диске неразрушив сам диск, недостаточно затереть его нулями из /dev/zero. В тоже время поток данных из /dev/urandom слишком медленный чтобы быстро затирать современные жёсткие диски.
Поскольку необходимый мне уровень стирания не претендовал на уровень военной разведки то я решил выкрутиться через большой массив случайных (псевдослучайных) чисел. А чтобы массив этот быстро работал я решил закинуть его в память. И /dev/shm – идеальное место.
Для стирания я использовал raid контроллер чтобы затирать сразу множество дисков. А для автоматизации процесса написал bash-скрипт. Скрипт имеет свой счётчик продвижения и его можно прервать Ctrl+C и затем продожить с той позиции где он был прерван.
Continue reading Fast HDD Eraser – Быстрое стирание дисков

Backup LV тома через snapshot

Лёгкий скрипт бэкапа тома на удалённый сервер.
Хочу подчеркнуть, что создание снимка (snapshot) на работающем read/write разделе не гарантирует целосность данных в создаваемом снимке. Кеш файловой системы оставшийся в памяти не отразится на snapshot и не попадёт в бэкап. Поэтому такой бэкап является упрощённой и быстрой возможностью сохранить максимум данных.

В скрипте три важных операции:

  • Создать снимок (snapshot) достаточного размера но не больше размера тома
  • Скопировать раздел в файл через сеть на другую машину на ходу немного сжимая
  • Удалить снимок

Continue reading Backup LV тома через snapshot

bash, парсинг имени файла и пути к нему

bash имеет встроенные функции манипуляции со строками. В частности функции удаления подстрок.

${string#substring} — удаляет кратчайшее вхождение подстроки $substring от начала строки $string.

${string##substring} — удаляет длиннейшее вхождение подстроки $substring от начала строки $string.

Аналогичным образом действует оператор % но действует от конца строки.

${string%substring} — удаляет кратчайшее вхождение подстроки $substring в конце строки $string.

${string%%substring} — удаляет длиннейшее вхождение подстроки $substring в конце строки $string.

При помощи этих функций можно получить имя файла, путь к файлу и его расширение:

# переменная для работы содержащая полное имя и путь к файлу
fullpathname="/root/temp/file.tar.gz"

# Получить путь (часть от начала строки до последнего слева слеша)
$ fullpathname="/root/temp/file.tar.gz"; echo "${fullpathname%/*}"
/root/temp

# Получить имя файла (часть от самого правого слеша до конца строки)
$ fullpathname="/root/temp/file.tar.gz"; echo "${fullpathname##*/}"
file.tar.gz

# Получить строку левее самой левой точки
# !!! Если точка будет находиться в пути, то отрежет по ней
$ fullpathname="/root/temp/file.tar.gz"; echo "${fullpathname%%.*}"
/root/temp/file

# Получить путь и имя файла без расширения (удаляет все правее самой правой точки)
$ fullpathname="/root/temp/file.tar.gz"; echo "${fullpathname%.*}"
/root/temp/file.tar

# Получить расширение (правая часть от последней слева точки в имени файла)
$ fullpathname="/root/temp/file.tar.gz"; echo "${fullpathname##*.}"
gz

# Все расширения (правая часть от первой слева точки в имени файла)
$ fullpathname="/root/temp/file.tar.gz"; echo "${fullpathname#*.}"
tar.gz

# Удаление любого расширения
$ fullpathname="/root/temp/file.tar.gz"; echo "${fullpathname%.*}"
/root/temp/file.tar

# Удаление расширения .gz
$ fullpathname="/root/temp/file.tar.gz"; echo "${fullpathname%.gz}"
/root/temp/file.tar

# Замена расширения .gz на .doc
$ fullpathname="/root/temp/file.tar.gz"; echo "${fullpathname%.gz}.doc"
/root/temp/file.tar.doc

Ниже для наглядности небольшой рисунок, который, возможно, поможет лучше запомнить работу этих операторов.

fullpathname="/root/temp/file.tar.gz"
              |--------------------|   - fullname
              ^--------^               - path
                         ^---------^   - name
                                  ^^   - extension
             #>>                       - от начала короткое удаление
            ##>>>>                     - от начала длинное удаление
                                  <<%  - от конца короткое удаление
                                <<<<%% - от конца длинное удаление

По материалам Advanced Bash-Scripting Guide