Трансляция окна своей консоли как WEB приложения

GoTTY позволяет устроить демонстрацию окна своей консоли как web приложения.

Для эмуляции терминала на JavaScript в интернет браузерах Gotty использует hterm. Gotty имеет свой websocket сервер перебрасывает PTY веб-клиентам и принимает ввод от клиентов и перебрасывает его на PTY. Идея hterm + websocket была навеяна Wetty.

Для каждого клиента подсоединяющегося к websocket GoTTY порождает новый процесс и это значит, что напрямую нельзя расшаривать терминал многим клиентам. Однако можно использовать мультиплексор терминала tmux. Но в этом случае клиенты будут находиться в режиме viewonly без передачи нажатий клавиатуры в терминал, а тот кто будет подключён локально сможет управлять терминалом.

Распространяется под лицензией MIT.
Исходники на https://github.com/yudai/gotty

Также имеется и утилита которая позволяет сделать легковесные файлы с записью работы в терминальной сессии и воспроизводить их в браузере.

Получение списка NS серверов для домена

Однострочный скрипт для получения списка ns сероверов домена.

DOMAIN="youngblog.hoster-ok.com"; TLD="${DOMAIN##*.}"; FLD="${DOMAIN%.*}"; FLD="${FLD##*.}"; echo -e "TLD:${TLD}\nFLD:${FLD}"; ROOTNS=`dig +short NS ${TLD}. | head -n 1 | sed -e 's/\.$//g'`; dig +authority +noadditional +nocomments +nostats +nocmd ${FLD}.${TLD}. @${ROOTNS} | sed -e 's/[;#%].*//g;s/^[ \t]*//g;s/[ \t]*$//g;/^$/d'
TLD:com
FLD:hoster-ok
hoster-ok.com.          172800  IN      NS      ns1.vds-ok.com.
hoster-ok.com.          172800  IN      NS      ns2.vds-ok.com.
hoster-ok.com.          172800  IN      NS      ns1.hoster-ok.com.

Принцип следующий:
Первая команда  dig +short NS ${TLD}.  (обратите внимание на точку на конце) получает корневые NS сервера которые обслуживают конкретный TLD (Top Level Domain) например .com .net .org .ru и т.д., а вторая команда  dig +authority +noadditional +nocomments +nostats +nocmd ${FLD}.${TLD}. @${ROOTNS}  получает из определённого NS @${ROOTNS} информацию по домену ${FLD}.${TLD}. (снова обратите внимание на точку на конце) информация, которую нужно включить или подавить, перечислена ключами.

Примечание!В целях балансировки нагрузки первая команда выдаёт список серверов в произвольном порядке для того чтобы те кто выбирает постоянно одну и ту же строку каждый раз получали другой сервер.

Обновление виртуальных квот Pure-FTP

Случается скопировать файлы в папку ftp пользователя или удалить в обход ftp сервера. Тоесть прямо с диска сервера, а не через FTP соединение. После этого наблюдается несоответствие суммарного размера файлов на диске в каталоге ftp с теми размерами которые вычисляет pureftp. В корне каждого ftp каталога при включённых виртуальных квотах размещаются файлы .ftpquota. Эти файлы содержат два числа: количество файлов и их суммарный размер. При каждом добавлении обновлении или удалении файла через FTP демон pure-ftpd вносит измненение в этот файл. И если каталоги FTP изменять (добавлять удалять файлы) в обход pure-ftpd изменения остаются неучтёнными в этом файле. Для того чтобы восстановить соответствие сожержимого папок ftp сервера и файла .ftpquota предназначается команда pure-quotacheck. Работает она только для одного выбранного пользователя. А если необходимо пробежаться по всем пользователям то можно воспользоваться таким скриптом:

#!/bin/bash

PUREPW="/usr/bin/pure-pw"
PUREQUOTACHECK="/usr/sbin/pure-quotacheck"
AWK="/bin/awk"
SED="/bin/sed"
XARGS="/usr/bin/xargs"

# update all virtual quotas with no messages
# "${PUREPW}" list | "${AWK}" '{print $2}' | "${SED}" -e 's|/\./$||g' | "${XARGS}" -I{} "${PUREQUOTACHECK}" -u pureftp -d "{}"

# update all virtual quotas with progress info
"${PUREPW}" list | "${AWK}" '{print gensub(/\.\/$/,"","g",$2)}' | while read FTPHOME ; do
  [ -e "${FTPHOME}" ] && (
    echo -en "${FTPHOME}:";
    [ -e "${FTPHOME}.ftpquota" ] && BEFORE=`cat "${FTPHOME}.ftpquota"` || BEFORE="";
    "${PUREQUOTACHECK}" -u pureftp -d "${FTPHOME}";
    AFTER=`cat "${FTPHOME}.ftpquota"`;
    [ "${BEFORE}" == "${AFTER}" ] && (echo -en " no changes ") || (
      echo -en " changed\n"
      echo -e "1 ${BEFORE}\n2 ${AFTER}" | "${AWK}" '{printf("files:%10d size:%14d", $2, $3); if($1==1){printf("\n");}}'
    )
    echo " [Done]"
  );
done

pureftp – это локальный пользователь для демона pure-ftpd
Этот скрипт отчитается о изменении файлов .ftpquota для каждого пользователя ftp и выведет информацию из этого файла перед и после обновления, так что будет ясно где была разница. Внутри также есть закоментарованный “однострочник” которые обновить файлы .ftpquota без вывода каких либо сообщений.

В документации по PureFTP рекомендуется регулярно обновлять виртуальные квоты. Поэтому скрипт можно добавить в крон и в зависимости от количества и объёма всех FTP файлов запускать его один раз в сутки или в неделю.

А этот скрипт выводит текущие квоты всех пользователей.

pure-pw list | awk '{print gensub(/\.\/$/,".ftpquota","g",$2)}' | while read FN ; do [ -e "${FN}" ] && (echo -en "${FN}:"; cat "${FN}" | tr -d '\n'; echo ) ; done

Thunderbird – Sending of message failed

thunderbird-error-01После очередного обновления Fedora некоторые пользователи Thunderbird наткнулись на сообщение:

Send Message Error
Sending of message failed.
The message could not be sent using SMTP server smtp.***.com for an unknown reason. Please verify that your SMTP server settings are correct and try again, or contact your network administrator.
Continue reading Thunderbird – Sending of message failed

convert из пакета imagemagick не центровал картинку на A4 pdf

А с картинкой из моего сканера точно такого же размера не работало. Содержимое картинки куда-то улетало за пределы страницы.
Если же использовалась опция -extent то всё работало, но картинка растягивалась до размеров страницы A4 и файл становился большего размера чем возможно: pdf – 213275 байта (картинка 98738), а добился я размера pdf 110868

Вот этот скрип даёт нужный результат (картинка в центре страницы PDF файла) но файл получается больше чем нужно.

$ convert -page 2480x3508 -units PixelsPerInch -density 300x300 -extent 2480x3508 \( -gravity center 2015.06.09.jpg \) -format pdf out.pdf

Continue reading convert из пакета imagemagick не центровал картинку на A4 pdf

Получить список соответствия LV = dm-N

При мониторинге производительности дисковой подсистемы возникает необходимость воспользоваться командой iostat. Она выводит результат по утилизации дисков с использованием символических имёт из ядра вида vd[a-z]N sd[a-z]N и dm-N. Когда речь касается физических дисков например /dev/sdaN тут всё понятно. А вот когда используется LVM то чтобы узнать какоe имя dm-N соответствует какому логическому тому нужно посмотреть какие lv_kernel_major и lv_kernel_minor соответствуют данному dm устройству в ядре. Следующая команда делает это автоматически.

lvs -o lv_name,lv_kernel_major,lv_kernel_minor | while read LVNAME LVKMAJOR LVKMINOR ; do grep '^[ \t]*'${LVKMAJOR}'[ \t]\+'${LVKMINOR}'[ \t]\+' /proc/partitions | awk -v name="${LVNAME}" '{print $4" "name}'; done
dm-7 lv_log
dm-0 lv_root
dm-1 lv_swap
dm-5 empty
dm-6 lv_server_fm-disk0
dm-8 lv_server_fm-disk1
dm-2 lv_vm1_disk0
dm-3 lv_vm2_disk0
dm-4 lv_vm3_disk0

Если нужно получить полные имена то нужно использовать опцию lv_path

# lvs -o lv_path,lv_kernel_major,lv_kernel_minor | while read LVNAME LVKMAJOR LVKMINOR ; do grep '^[ \t]*'${LVKMAJOR}'[ \t]\+'${LVKMINOR}'[ \t]\+' /proc/partitions | awk -v name="${LVNAME}" '{print $4" "name}'; done
dm-7 /dev/vg_v03t/lv_log
dm-0 /dev/vg_v03t/lv_root
dm-1 /dev/vg_v03t/lv_swap
dm-5 /dev/vg_vm/empty
dm-6 /dev/vg_vm/lv_server_fm-disk0
dm-8 /dev/vg_vm/lv_server_fm-disk1
dm-2 /dev/vg_vm/lv_vm1_disk0
dm-3 /dev/vg_vm/lv_vm2_disk0
dm-4 /dev/vg_vm/lv_vm3_disk0

А если полные имена через /dev/mapper то опцию lv_dm_path

# lvs -o lv_dm_path,lv_kernel_major,lv_kernel_minor | while read LVNAME LVKMAJOR LVKMINOR ; do grep '^[ \t]*'${LVKMAJOR}'[ \t]\+'${LVKMINOR}'[ \t]\+' /proc/partitions | awk -v name="${LVNAME}" '{print $4" "name}'; done
dm-7 /dev/mapper/vg_v03t-lv_log
dm-0 /dev/mapper/vg_v03t-lv_root
dm-1 /dev/mapper/vg_v03t-lv_swap
dm-5 /dev/mapper/vg_vm-empty
dm-6 /dev/mapper/vg_vm-lv_server_fm--disk0
dm-8 /dev/mapper/vg_vm-lv_server_fm--disk1
dm-2 /dev/mapper/vg_vm-lv_vm1_disk0
dm-3 /dev/mapper/vg_vm-lv_vm2_disk0
dm-4 /dev/mapper/vg_vm-lv_vm3_disk0

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

Скрипт копирования нескольких LV

Однострочный скрипт копирования логических томов LV. Например для копирования дисков виртуальных машин.

Тестовый вариант отображает команду на экран:

# for VOL in "lv_vm3_disk0" "lv_server_fm-disk0" "lv_vm1_disk0" ; do echo -e "dd if=/dev/vg_vm/${VOL} of=/mnt/tmp1/${VOL} bs=2M iflag=direct oflag=direct" ; done
dd if=/dev/vg_vm/lv_vm3_disk0 of=/mnt/tmp1/lv_vm3_disk0 bs=2M iflag=direct oflag=direct
dd if=/dev/vg_vm/lv_server_fm-disk0 of=/mnt/tmp1/lv_server_fm-disk0 bs=2M iflag=direct oflag=direct
dd if=/dev/vg_vm/lv_vm1_disk0 of=/mnt/tmp1/lv_vm1_disk0 bs=2M iflag=direct oflag=direct

А это рабочий вариант:

# for VOL in "lv_vm3_disk0" "lv_server_fm-disk0" "lv_vm1_disk0" ; do dd if=/dev/vg_vm/${VOL} of=/mnt/tmp1/${VOL} bs=2M iflag=direct oflag=direct ; done
81920+0 records in
81920+0 records out
171798691840 bytes (172 GB) copied, 2433.05 s, 70.6 MB/s
75002+0 records in
75002+0 records out
157290594304 bytes (157 GB) copied, 2525.82 s, 62.3 MB/s
128000+0 records in
128000+0 records out
268435456000 bytes (268 GB) copied, 3628.6 s, 74.0 MB/s
Рекоментация!Так как копирование логических томов это длительная операция то такие команды лучше запускать в screen.

Как изменить разделитель полей команды ps

Команда ps имеет множество ключей один из которых позволяет определить свой разделитель полей, если требуется распарсить поля содержащие пробелы (например аргументы командной строки процессов)

ps -eo "%p\t%a"

Для того чтобы вставить табуляцию в качестве разделителя нужно либо воспользоваться sed для замены \t на табуляцию или воспользоваться echo -e но удобнее немного изменить строку исползуя хак:

ps -eo "%p"$'\011'"%a"

В использовании команды есть одна непонятная особенность: чтобы аргумент %a вывел полные параметры, а не обрезал их по ширине, он должен быть использован в самом конце форматной строки. Если после него встретится хотя бы один символ включая пробел то ширина поля args будет ограничена. Поле будет обрезано. Мне не удалось заставить вывести полный аргумент никакими перенаправлениями в pipe или переменными COLUMNS как это описано в документации.

ОБЫЧНЫЕ AIX коды описаны ниже.

       CODE   NORMAL   HEADER
       %C     pcpu     %CPU
       %G     group    GROUP
       %P     ppid     PPID
       %U     user     USER
       %a     args     COMMAND
       %c     comm     COMMAND
       %g     rgroup   RGROUP
       %n     nice     NI
       %p     pid      PID
       %r     pgid     PGID
       %t     etime    ELAPSED
       %u     ruser    RUSER
       %x     time     TIME
       %y     tty      TTY
       %z     vsz      VSZ

Дата и время старта сервера

Команда uptime показывает время прошедшее с момента старта сервера. Когда мне для разбора логов потребовалось узнать время старта сервера я не нашёл способа получить время старта сервера например в формате YYYY-MM-DD HH:MM.

Вот результат работы uptime

$ uptime
 18:01:18 up 473 days,  6:56,  1 user,  load average: 0.08, 0.03, 0.00

Распарсим его и сформируем строку для команды date

$ uptime | sed -e 's/,//g' | awk '{split($5,time,":"); printf("-%s days -%s hours -%s minutes\n", $3, time[1], time[2])}'
-473 days -7 hours -02 minutes

И получим следующий однострочный скрипт

$ DAYSAGO=`uptime | sed -e 's/,//g' | awk '{split($5,time,":"); printf("-%s days -%s hours -%s minutes\n", $3, time[1], time[2])}'`; date --date="${DAYSAGO}" +"%Y-%m-%d %H:%M"
2014-01-10 11:05
Примечание От запуска к запуску скрипта время будет плавать на ± одну минуту. Это связано с тем, что uptime возвращает время без секунд.