Нули
На планшете для работы умер кулер. Приплыли.
Ну, не совсем всё умерло - он включается, нагревается и троттлит 100% времени.
Windows-планшет, на котором жила вся моя рабочая среда: куб контексты, профили AWS и Azure, скрипты, IDEs. Да всё. Всё было там.
Надо быстро восстановить рабочее место.
Причём в изолированное окружение, чтобы ничего, связанного с работой не перемешалось с личным и не было лишних утечек.
Поднял виртуальную машину с Windows на Mac (да, я привык к Windows-среде, не осуждайте 🙃), начал по памяти восстанавливать инструменты.
Благо есть asdf с .tool-versions - всё задокументировано, стоишь раз за разом одни и те же версии. Скопировал файл, запустил инсталляцию.
Дохера всего, около 45 утилит.
Дальше надо запустить скрипты - клонировать весь GitLab компании разом, настроить контексты кластеров всех облаков и профили облаков. Всё это у меня было. Всё это я написал раньше. Надо просто запустить.
Запускаю скрипт клонирования GitLab.
Завис. Минута. Две. Пять.
Окей, Ctrl+C, думаю. Что-то с сетью? Или токен протух?
Иду в GitLab UI - токен живой. Проверяю вручную:
curl -s -H "PRIVATE-TOKEN: $TOKEN" "https://gl.company.com/api/v4/user"
Всё нормально, вернул мой профиль, HTTP 200. Хорошо.
Значит не токен.
Меняю токен на новый - на всякий случай. Запускаю скрипт. Снова завис.
Прошу нейронку помочь.
Та начинает советовать добавить таймаут в curl, добавить проверки пагинации, переписать функции...
Делаю всё это. Всё равно зависает или выдаёт нули:
Хотя вручную curl отдаёт нормальные данные.
Ни один совет нейронки не помог ни в чем.
Добавляю отладочный вывод.
Оборачиваю запрос в файл, читаю из файла, убираю BOM, убираю нулевые байты, убираю CR...
Нули.
Пишу отдельный дебаг-скрипт с пошаговыми запросами.
Каждый шаг - отдельный curl, каждый ответ - в переменную, потом проверяем jq -e 'type == "array"'...
И тут вижу странное:
API error на /groups page=1:
[{"id":10,"web_url":"https://gl.company.com/groups/all","name":"All"...Стоп. Там же чётко написано [{"id":10... - это массив.
Это валидный, сука, JSON. Ты чо, пёс.
Но проверка говорит "не массив".
Проверяю сам:
echo '[]' | jq -e 'type == "array"'; echo "exit: $?" exit: 1
echo '[1,2,3]' | jq -e 'type == "array"'; echo "exit: $?" exit: 1
jq возвращает 1 для валидного массива. На вопрос "это массив?" jq отвечает "нет".
Ладно, решаю - пофиг на GitLab, пофиг на jq, склоню вручную потом.
Сначала сделаю рабочую среду.
Иду настраивать kubectl-контексты. Запускаю скрипт - не работает.
Иду в AWS, пробую aws eks update-kubeconfig - зависает.
Пробую вручную aws sts get-caller-identity - зависает на несколько секунд, потом отрабатывает.
Что-то медленное и странное.
Пробую aws s3 ls - работает, но медленно.
Иду в Azure - az account list отрабатывает, но вывод странный. Где-то что-то парсится не так.
всё, что связано с обработкой JSON в CLI-инструментах, либо зависает, либо даёт неверный результат. awscli внутри гоняет Python и boto3, там свой парсер.
jq - отдельный бинарник.
Стоп. Какого лешего тут происходит.
Как мне может ВСЁ поломать всего-лишь одна утилита?????
which jq /home/alexk/.asdf/shims/jq file /home/alexk/.asdf/shims/jq /home/alexk/.asdf/shims/jq: Bourne-Again shell script, ASCII text executable
Шим asdf. Смотрю куда он ведёт:
ls /home/alexk/.asdf/installs/jq/ 1.8.1 file /home/alexk/.asdf/installs/jq/1.8.1/bin/jq ELF 64-bit LSB executable, x86-64
А теперь проверяем ещё раз для наглядности:
uname -m aarch64
Вот оно.
Система - ARM64. Бинарник jq - x86-64.
WSL2 на Windows ARM (в моём случае - Windows виртуалка на Mac с чипом Apple Silicon, WSL2 внутри неё) умеет запускать x86-64 бинарники через Microsoft Prism - встроенный эмулятор.
Запускает. Но нестабильно. Базовые операции типа jq '.field' или jq '.[]' работают.
А вот более сложные выражения, типа jq -e 'type == "array"' или даже jq --version - падают или зависают.
- скрипт клонирования GitLab зависал на первой же функции, которая проверяла тип ответа через jq
- echo
'[]' | jq -e 'type == "array"'возвращал 1 вместо 0 - счётчики были нулями - jq тихо ломался при подсчёте длины массива
- всё, что просто парсило JSON вручную через awscli/azure-cli, работало через собственные парсеры
Короче все скрипты подготовки среды на новом рабочем железе.
Понятно что сломалось.
Непонятно почему asdf поставил неправильный бинарник.
cat ~/.asdf/plugins/jq/bin/download
Нахожу функцию определения архитектуры:
get_arch(){
declare arch="$(uname -m)"
if [ "$arch" == 'x86_64' ]; then
echo '64'
elif [ "$arch" == 'aarch64' ]; then
echo '64' # <--- вот оно
elif [ "$arch" == 'arm64' ]; then
echo '64' # <--- и вот
elif [ "$arch" == 'i386' ]; then
echo '32'
...
}
И чуть ниже - как формируется имя файла для скачивания:
guessed_file="jq-linux$arch"
То есть: aarch64 -> get_arch() возвращает '64' -> скачивается jq-linux64 - это x86-64 бинарник.
Самое смешное - в том же файле есть функция guess_download_url(), которая это правильно обрабатывает:
guess_download_url() {
...
if [ "$arch" == 'aarch64' ]; then
arch="arm64"
fi
...
}Правильная логика есть. Но эта функция - мёртвый код.
Нигде не вызывается. Кто-то написал, не подключил и забыл.
А в download() используется старая get_arch(), которая для любой 64-битной архитектуры, включая ARM, выдаёт одинаковое '64'.
А на GitHub Releases у jq 1.7.1+ есть отдельный jq-linux-arm64.
Он существует.
Просто плагин про него не знает.
Правлю плагин (PR с фиксом позже сделаю в плагин):
elif [ "$arch" == 'aarch64' ]; then
echo '64'
elif [ "$arch" == 'arm64' ]; then
echo '64'elif [ "$arch" == 'aarch64' ]; then
echo 'arm64'
elif [ "$arch" == 'arm64' ]; then
echo 'arm64'guessed_file="jq-linux$arch"
case "$arch" in 64) guessed_file="jq-linux64" ;; 32) guessed_file="jq-linux32" ;; arm64) guessed_file="jq-linux-arm64" ;; *) guessed_file="jq-linux-$arch" ;; esac
asdf uninstall jq 1.8.1 asdf install jq 1.7.1 file ~/.asdf/installs/jq/1.7.1/bin/jq ELF 64-bit LSB executable, ARM aarch64 ✅ echo '[]' | jq -e 'type == "array"'; echo "exit: $?" exit: 0 ✅
Запускаю скрипт клонирования и контексты всех куберентисов.
Всё работает. Красота.
Итоги
- планшет умер, виртуалка поднялась, среда восстановлена. Полдня потрачено.
- из них часа два - на отладку того, что казалось сломанным скриптом или токеном.
- причина: jq x86-64 на aarch64-системе работает через эмуляцию, частично. Простые операции - норм. Чуть сложнее - всё, привет нулям и зависаниям.
- баг в asdf-плагине для jq: get_arch() возвращает 64 для любой 64-битной архитектуры, ARM в том числе. В итоге всегда скачивается jq-linux64 (x86-64).
- правильная логика в том же файле есть - в мёртвой функции guess_download_url(), которая никогда не вызывается.