Мой сайт уже без малого 2 года крутится на неттопе с установленной Ubuntu 20.04 LTS. С некоторых пор неттоп начал испытывать проблемы при загрузке: например, ставишь обновления, перезагружаешь систему — и она уже не возвращается. Подключаешь монитор, чтобы посмотреть, в чём дело — и система загружается нормально. Какой-то бред, как будто железка издевается над тобой.
Я проверял настройки BIOS несколько раз, проверял блок питания на предмет нехватки мощности (хотя как в этом случае помогло бы подключение монитора?) — никаких проблем не обнаружил. Думал даже о покупке нового неттопа. Сегодня, когда в очередной раз, используя непарламентские выражения, я подключал монитор, чтобы загрузить железку после очередного невозврата из перезагрузки, решил поискать в интернете, мало ли, у кого-то такая же дурацкая проблема?
И нашёл! Оказалось, дело в настройках загрузчика GRUB. Нужно выключить у него графический режим и потом применить настройку:
sudo sed -i '/GRUB_TERMINAL=/c GRUB_TERMINAL=console' /etc/default/grub
sudo update-grub
Теперь перезагружается без проблем. И покупать ничего не потребовалось.
Обнаружил сайт demodb.org, где можно послушать демки со старых синтезаторов, меня интересовала Yamaha W7.
Сайт этот скачать аудиофайлы не даёт: при попытке открыть консоль разработчика в браузере закрывает свою вкладку или переадресует на другой сайт, а если всё-таки через плагин браузера выцепляешь прямой путь к аудиофайлу, то скачивается заглушка, где говорится, что по прямым ссылкам качать нельзя.
Оставался единственный вариант — запись на локальном компьютере. Я взял аудиоредактор Wavosaur, отрегулировал входной сигнал, выключил микрофон веб-камеры, чтобы он не фонил, записал все нужные мне треки, нормализовал всё до 0 дБ. Получилось следующая картина:
Теперь нужно было порезать получившуюся запись на части. Конечно, мне сразу же захотелось это автоматизировать. Очевидно, разделителями являются периоды тишины, и после недолгого поиска я обнаружил, что в великом и могучем ffmpeg обнаружением тишины в аудиосигнале занимается фильтр silencedetect.
Экспериментальным способом выяснилось, что подходящим порогом срабатывания является -50 дБ, и silencedetect выдаёт такое:
Полезный сигнал начинается с silence_end, а заканчивается на silence_start, поэтому нужно выбросить первый silence_start и последний silence_end, итого 5 треков. Перед началом трека делается отступ в 0,25 сек, а в конце добавляется 1 сек, чтобы треки в списке не игрались attacca и между ними была какая-то пауза. В ffmpeg указывается не конечное время, а длительность нужного куска, поэтому нужно для этого из конечного времени вычесть начальное.
Иногда, например, у альбомов на Youtube, звук начинается сразу и первая метка silence_end оказывается уже на втором треке, поэтому нужно предусмотреть такие ситуации. Здесь я предположил, что если метка позже 30-й секунды, то вставлять в начало списка silence_end ноль и не удалять первый silence_start, т. к. нужно знать, где первая дорожка кончается. Соответственно, команда ffmpeg будет без указания стартовой позиции.
# Исходный файл$file = 'D:\Музыка\Yamaha W7 demos.wav'# Отступ до и после полезного сигнала (чтобы треки не начинались сразу один за другим)$preSec = 0.25$postSec = 1# Формат файлов на выходе$outputExt = ".mp3"$file = get-item-literalpath$file$log = (& ffmpeg -i$file.FullName -af silencedetect=n=-50dB:d=1-f null - 2>&1) -match'^\[silencedetect'$starts,$ends = $log.where({$_-match'silence_end'}, 'Split')
[regex]$replOut = '.*?: (\d+\.\d+).*'$starts = $starts-replace$replOut,'$1' |select -SkipLast1$ends = $ends-replace$replOut,'$1'# Если в начале тишины нет (первое начало позднее 30-й секунды)if ([double]$starts[0] -gt30) {
$starts = ,"0" + $starts
}
else {
$ends = $ends |select -Skip1
}
$c = 0$starts |% {
if ($_-eq0) {
& ffmpeg -y-hide_banner `
-t ([double]$ends[$c] + $postSec) `
-i$file.FullName `
($file.DirectoryName + "\" + ($c+1).tostring("00") + " $($file.BaseName)" + $outputExt)
}
else {
& ffmpeg -y-hide_banner `
-ss ([double]$starts[$c] - $preSec) `
-t ([double]$ends[$c] - [double]$starts[$c] + $postSec) `
-i$file.FullName `
($file.DirectoryName + "\" + ($c+1).tostring("00") + " $($file.BaseName)" + $outputExt)
}
$c++
}
Получается просто отлично — больше ничего делать не потребовалось. Чуть позже я нашёл запись этих же демонстраций на Youtube, и скрипт так же хорошо работает и на ней.
Надо сказать, что тех демонстраций, которые я выкладывал, когда рассказывал о своей неудачной карьере аранжировщика, я нигде не нашёл; видимо, они были на какой-то дополнительно приобретаемой дискете и их никто не записал. Зато нашёл другие, которые я тоже вспомнил, и они великолепны, а Isn’t it hip и Halftime просто, я бы сказал, исключительны. Структура композиций, динамика, гармонизация, подголоски, выбор тембров и их обработка — всё на высшем уровне.
Сегодня на работе я выключил последнюю оставшуюся ноду после миграции всех виртуальных машин в кластер Hyper-V.
Последнее действие перед выключением
Сервер был ProLiant DL380 G6, его уже давно пора было выводить из эксплуатации, но дело в том, что на нём крутилась пара серверов, «защищённых» USB-токеном. Несколько недель назад, наконец, купили железку, которая пробрасывает USB-устройства по сети — это местная аппаратная адаптация недорогого зарубежного решения VirtualHere.
Железка представляет собой keepalived-кластер из двух Banana Pi с веб-интерфейсом на ajenti и 32 портами USB, заключённых в едином корпусе:
# dmesg
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 5.15.93 (oe-user@oe-host) (arm-poky-linux-gnueabi-gcc (GCC) 9.3.0, GNU ld (GNU Binutils) 2.34.0.20200220) #1 SMP Thu Feb 9 10:26:48 UTC 2023
[ 0.000000] CPU: ARMv7 Processor [410fc074] revision 4 (ARMv7), cr=10c5387d
[ 0.000000] CPU: div instructions available: patching division code
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[ 0.000000] OF: fdt: Machine model: LeMaker Banana Pi
# lsb_release -a
LSB Version: n/a
Distributor ID: poky
Description: Poky (Yocto Project Reference Distro) 3.1.17
Release: 3.1.17
Codename: dunfell
Документация написана не то чтобы очень и в настройке есть некоторые особенности, но техподдержка отвечает и в целом девайс работает хорошо.
На компьютерах, которым нужно подключение USB, ставится клиент, который устанавливает свои драйверы и может работать как служба. На очень старых системах, например, Windows 2003, драйверы нужно ставить самостоятельно, вытащив их из клиента с помощью командной строки. Потом, подмонтировав ключ, надо сделать так, чтобы служба сервера, зависящая от ключа (например, 1C:Enterprise 8.3 Server Agent), стартовала позже службы rhclient (USB Hub Over Network USB Sharing) — для этого нужно её перевести в режим автоматического отложенного запуска. В старых системах, где функции отложенного запуска нет, можно перевести службу сервера в ручной режим запуска и настроить планировщик задач, чтобы после загрузки ОС выполнялся скрипт наподобие
ping127.0.0.1 -n 30netstart hwserver
Вот как выглядят устройства USB на виртуальной машине Hyper-V, где крутится 1С (напоминаю, что Hyper-V не пробрасывает USB с хоста на виртуалки, и правильно делает):
А вот так ключи выглядят с клиента:
Доступ к самим ключам и к их администрированию через клиент может быть ограничен несколькими способами, я делал по IP-адресам и подсетям.
Собственно, возвращаясь к тому, с чего я начал — после переноса токенов на железку оставалось только мигрировать все виртуалки на Hyper-V и выключить ноду VMware, что я и проделал. Теперь, наконец, зоопарка систем виртуализации больше нет.
Принесли ноутбук 2015-го года выпуска (Celeron N3050/4GB RAM/500GB HDD), который нужно было привести в порядок. Судя по виду, он использовался мало, но, тем не менее, имел одну ярко выраженную проблему — при включении он оглушительно пищал и выдавал сообщение, что не может распознать, что за блок питания в него воткнули, поэтому он снижает производительность и не будет заряжать аккумулятор.
Оказалось, что фирма Делл делает блоки питания с микросхемкой, которая по центральному контакту в разъёме передаёт информацию о блоке ноутбуку. Блок питания был оригинальным, и я отнёс его на работу, где прекрасный коллега Геннадий, разобрав блок, прозвонил провод тестером и установил, что центральный провод оборван в районе разъёма. Видимо, за провод либо сильно дёрнули, либо изогнули.
Был заказан новый «кабель для блока питания Dell 4.5x3.0мм с центральным контактом» и впаян на место старого, а корпус блока питания аккуратно склеен изолентой. Ноутбук начал распознавать блок питания как родной, но громкий писк при запуске никуда не делся, к тому же оказалось, что аккумулятор сдох окончательно — он не заряжался, даже простояв воткнутым в розетку всю ночь.
Из-за неисправности аккумулятора нельзя прошить новый BIOS — для этого нужно как минимум 10% заряда. Я заказал новую батарею и SSD Samsung 870 EVO 500GB на замену медленной хрустящей штатной Тошибы. Но вернёмся к оглушительно громким сигналам POST.
Отдельного спикера на плате ноутбука нет, сигналы самотестирования после включения системы выведены на встроенные динамики и звучат во всю их мощь. То есть, если включить такой ноутбук ночью, то это разбудит не только всех домашних, но, наверное, и соседей.
Пять коротких сигналов означают, что разряжена батарейка CMOS (CR2032). После её замены, для чего пришлось разбирать ноутбук почти полностью, он, наконец, начал включаться бесшумно.
Жёсткий диск приехал, и я поставил в качестве системы Windows 10 Home 22H2 x64, которую собрал с помощью сайта uupdump.net. Что приятно, система активировалась сама без каких-либо действий с моей стороны. Всё вроде бы нормально, но операционка даже после всех обновлений почему-то ни в какую не видела микрофона. В BIOS никаких настроек по этому поводу нет, Xubuntu Linux, загруженный с флешки, тоже ничего не увидел, что косвенно указывает на то, что проблема может быть и аппаратной, хотя выглядит это очень странно. Я решил отложить вопрос с микрофоном до прошивки нового BIOS.
Наконец, я получил аккумулятор. Я брал не самый дешёвый, а тот, где было написано «оригинал» или что-то подобное, на Озоне есть такой фильтр. Установил его в ноутбук — и при загрузке получаю предупреждение, что батарея не рекомендована для этой системы и заряжаться она не будет.
Тем не менее, аккумулятор нормально работает и заряжается. Единственная проблема — для загрузки системы теперь нужно нажимать на кнопку Continue на экране этого предупреждения про батарею. Но фокус стоит уже на ней, поэтому надо просто нажать клавишу «ввод».
Информация о новом аккумуляторе из HWInfo:
Battery #0
[Общие свойства]
Имя устройства: DELL 991XP55
Имя производителя: Samsung SD
Серийный номер: 708
Уникальный идентификатор: 708Samsung SDDELL 991XP55
Химия:
Расчетная мощность: 32560 mWh
Полная заряженная емкость: 32560 mWh
Уровень износа: 0.0 %
[Текущее состояние питания]
Состояние питания: Разрядка
Текущая вместимость: 29230 mWh (89.8 %)
Текущее напряжение: 15.895 V
Скорость разряда: -5535 mW
Ну, батарейка есть, теперь можно и BIOS прошивать. Скачал последнюю версию 4.4.0, доступную для этого ноутбука, запускаю. Что?
Система несовместима сама с собой! Опять полез в поиск и нашёл обходной путь. Оказывается, есть недокументированный ключ запуска /writehdrfile, который извлекает из .exe файл .hdr, подходящий для прошивки альтернативным способом.
rem Перейти в рабочий каталог (здесь: C:\temp)cd C:\temp
rem Извлечение BIOS из exe-файла
Inspiron_3452_3552_4.4.0.EXE /writehdrfile
Потом нужно залезть на сайт American Megatrends, которая пишет биосы, зайти в раздел Developers → Tools & Utilities → BIOS / UEFI и скачать там Aptio V AMI Firmware Update Utility. Так как система у нас 64-битная, надо распаковать из скачанного архива afu\afuwin\64\AfuWin64.zip\AfuWin64\AFUWINx64.exe в каталог, где лежит наш .hdr. В оригинальном описании обходного пути прошивка запускается после загрузки компьютера под DOS, но в этом нет никакой необходимости, всё прекрасно делается и из-под Windows.
Наконец-то добрались и до самой прошивки:
rem Сохранить старый BIOS в файл
AFUWINx64.exe oldBios.rom /O
rem Сравнение GUID старого и нового биосов
AFUWINx64.exe /S
AFUWINx64.exe Inspiron_3452_3552_4.4.0.hdr /U
rem Проверить процесс без реальной прошивки
AFUWINx64.exe Inspiron_3452_3552_4.4.0.hdr /D
rem Прошить новый BIOS
AFUWINx64.exe Inspiron_3452_3552_4.4.0.hdr
После перезагрузки новый BIOS требует ввести номер модели, но вводить его некуда — это какой-то мелкий глюк, впоследствии не проявляющийся. Но главное — Windows, загрузившись с новой прошивкой, узрел микрофон и ещё несколько устройств, которые он спокойно установил самостоятельно без посторонней помощи.
Признаться, я не припомню в своей практике настолько капризной машинки. Тем не менее, остались только мелкие недостатки, а именно:
Предупреждение о неоригинальном аккумуляторе, требующее нажатия Enter для дальнейшей загрузки.
Не работают клавиши регулировки яркости (F11-F12). Советы в интернете включать-выключать устройства видеоадаптера и монитора ни к чему не приводят.
Вот он, этот тип гражданской наружности после всех манипуляций, лет 5-7 ещё может проработать:
Стоимость деталей:
Аккумулятор — 2857 руб.
Жёсткий диск — 3539 руб.
Провод БП — 335 руб.
Батарейка CR2032 — 159 руб.
Итого: 6890 руб.
P. S. Процессор N3050 по сегодняшним меркам очень медленный — Youtube, например, сильно тормозит. Дело в том, что стандартно вещание там идёт в формате VP9, для которого у этого процессора семейства Braswell (8 поколение) нет аппаратного декодера. Чтобы заставить браузер выбирать видео в формате H.264, для которого у N3050 декодер есть, я установил расширение h264ify. Не сказать, чтобы проблема вообще исчезла, но нагрузка на процессор упала на 15-20 процентных пунктов и работать стало получше.
Пересадить всю контору на сертификаты Let’s Encrypt оказалось не очень сложно — certbot на реверс-прокси работает, сертификаты после перевыпуска лепятся вместе со своими ключами и кладутся в нужный каталог скриптом, лежащим в /etc/letsencrypt/renewal-hooks/deploy, а в определённое время в cron срабатывает команда, которая при наличии новых сертификатов перечитывает конфигурацию сервера.
На некоторых сервисах, которые выставлены в интернет напрямую, например, сервера видеоконференций, работает свой бот и он обновляет сертификаты локально, но иногда есть нюансы — например, на сервере TrueConf 80-й порт, который требуется для обновления сертификата, занят, и приходится подкручивать /lib/systemd/system/certbot.timer на еженедельный запуск где-то в глухой ночи, а в юнит-файле /lib/systemd/system/certbot.service рисовать следующее, чтобы стопорить службу, занимающую порт, и после процедуры стартовать её заново:
Последним бастионом оставался довольно почтенного возраста аппаратный шлюз Cisco ASA, который со всеми этими новомодными удостоверяющими центрами работать не умеет. Так как раньше покупался wildcard-сертификат на год и вставлялся туда руками, проблем его менять не было, кроме оскорбления здравого смысла при виде очередного рассовывания этого несчастного сертификата по всем серверам и раздумий, куда его ещё забыли скопировать. Но так как Let’s Encrypt выпускает сертификаты на 90 дней, ручная установка выглядит совсем уж неуместной, и автоматизация совершенно необходима.
Let’s Encrypt даёт возможность выпускать и wildcard, но для него нужно автоматизировать ещё и создание TXT-записей в DNS через API, что усложняло задачу. Для нашего nic.ru существует программа, но эта схема мне показалось чересчур усложнённой, к тому же, у компании не так много доменов, в случае компрометации сертификата не будет затронуто сразу всё, тем более, что в один сертификат можно поместить сразу несколько альтернативных имён (SAN), что позволяет сократить общее количество выпускаемых сертификатов.
После небольшого гуглежа я обнаружил в некотором роде бриллиант — инструмент для автоматизации работы с интерактивным вводом expect. То есть, пишешь, что должно появиться в командной строке, а потом то, что нужно ввести в ответ. Так как это не bash, а другой интерпретатор, основанный на языке TCL (Tool Command Language), у него свой шебанг — #!/usr/bin/expect -f.
Перед началом работы нужно попросить сетевиков, чтобы ASA пробрасывала 80-й порт на сервер, на котором будет стоять сертбот, потом нужно завести отдельную учётку для входа по SSH и дать этой учётке права на некоторые команды, об этом ниже.
На сервере, куда будет приходить 80-й порт и где будет происходить всё последующее, понадобятся 3 файла: скрипт сборки сертификата в нужный формат (pkcs12, закодированный в base64), запускаемый сертботом после его перевыпуска, который, в свою очередь, запускает скрипт expect. Третий файл — это пароль экспорта/импорта сертификата: можно пароль и так захардкодить в первые два файла, но это неудобно. Предполагается, что все действия делаются от учётки root.
#!/usr/bin/expect -fset timeout 5
set send_slow {10 .001}
set sshUser "sshuser"set sshIP "192.168.1.254"set sshPass "sshPass12345"set exportPass [exec cat /scripts/vpncert-asa.txt]
spawn ssh -o KexAlgorithms=+diffie-hellman-group1-sha1 -o HostKeyAlgorithms=+ssh-rsa -o StrictHostKeyChecking=no $sshUser@$sshIP
expect "password:"
send -- "$sshPass\r"
expect ">"
send -- "enable\r"
expect "Password:"
send -- "$sshPass\r"
expect "#"
send -- "configure terminal\r"
expect "(config)#"
send -- "no crypto ca trustpoint ca_le\r"
expect {
"]:" {send -- "yes\r"; exp_continue}
"(config)#"
}
send -- "crypto ca trustpoint ca_le\r"
expect "trustpoint)#"
send -- "enrollment terminal\r"
expect "#"
send -- "exit\r"
expect "(config)#"
send -- "crypto ca import ca_le pkcs12 $exportPass\r"
expect "itself:"
send -- [exec cat /root/gate.base64]\n
send -s "quit\r"# % The CA cert is not self-signed.# % Do you also want to create trustpoints for CAs higher in the hierarchy? [yes/no]:# OR# % You already have RSA or ECDSA keys named ca_le.# % If you replace them, all device certs issued using these keys# % will be removed.# % Do you really want to replace them? [yes/no]:
expect {
"]:" {send -- "yes\r"; exp_continue}
"(config)#"
}
send -- "ssl trust-point ca_le outside\r"
expect "(config)#"
send -- "exit\r"
expect "#"
send -- "exit\r"
expect eof
После запуска всей конструкции скрипт изготавливает сертификат требуемого формата, лезет по SSH на железку, вводит все логины-пароли, вставляет полученный сертификат и делает всё прочее как если бы это делалось руками, но только быстро, точно и без забывчивости.
Вывод во время выполнения работы:
spawn ssh -o KexAlgorithms=+diffie-hellman-group1-sha1 -o HostKeyAlgorithms=+ssh-rsa -o StrictHostKeyChecking=no sshuser@192.168.1.254
sshuser@192.168.1.254's password:
User sshuser logged in to gate
Logins over the last 91 days: 54. Last login: 11:39:24 MSK Jan 9 2023 from 192.168.1.100
Failed logins since the last login: 0.
Type help or '?' for a list of available commands.
gate> enable
Password: **********
gate# configure terminal
gate(config)# no crypto ca trustpoint ca_le
WARNING: Removing an enrolled trustpoint will destroy all
certificates received from the related Certificate Authority.
Are you sure you want to do this? [yes/no]: yes
INFO: Be sure to ask the CA administrator to revoke your certificates.
gate(config)# crypto ca trustpoint ca_le
gate(config-ca-trustpoint)# enrollment terminal
gate(config-ca-trustpoint)# exit
gate(config)# crypto ca import ca_le pkcs12 verySecretPassword12345
Enter the base 64 encoded pkcs12.
End with the word "quit" on a line by itself:
MIIWzwIBAzCCFoUGCSqGSIb3DQEHAaCCFnYEghZyMIIWbjCCEOIGCSqGSIb3DQEH
BqCCENMwghDPAgEAMIIQyAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqG
...
dt/zTsIeIqQq05PLFpOTIzBBMDEwDQYJYIZIAWUDBAIBBQAEIMyVqqTQhaaqlHOH
D3XnctPJR1TYytiVRCaVWuZHz+G0BAiEKmqw9Y6C4AICCAA=
quit
% You already have RSA or ECDSA keys named ca_le.
% If you replace them, all device certs issued using these keys
% will be removed.
% Do you really want to replace them? [yes/no]: yes
Trustpoint 'ca_le' is a subordinate CA and holds a non self-signed certificate.
Trustpoint CA certificate accepted.
WARNING: CA certificates can be used to validate VPN connections,
by default. Please adjust the validation-usage of this
trustpoint to limit the validation scope, if necessary.
INFO: Import PKCS12 operation completed successfully.
gate(config)# ssl trust-point ca_le outside
gate(config)# exit
gate# exit
Logoff
Connection to 192.168.1.254 closed by remote host.
Connection to 192.168.1.254 closed.
Результат — компьютеры занимаются рутиной, а человек освободил время для чего-то более интересного.