# perfdata-fix - проверка и починка сборщика метрик ВМ на инсталляции vStack

Один скрипт, три режима. Сначала проверяет состояние, потом ( только по явной
команде ) применяет ровно те фиксы, условия которых выполнены, и по команде
revert возвращает всё как было.

## Затрагивает

- инсталляции vStackOS 3.x: сборщик метрик ВМ `/usr/local/sbin/vstack-vm-perfdata`
  ( пакет vStack-vm-perfdata )
- узлы с перловым сборщиком `/usr/local/bin/vStack-vm-perfdata-cpu-feeder`:
  линия 2.x и узлы, обновлённые через `pkg upgrade` без замены сборщика
- не применяется, если сборщика нет или в нём уже есть исправление - скрипт
  это распознаёт и ничего не делает

## Проблема

Раз в 10 секунд сборщик метрик читает у каждой ВМ полное состояние vCPU
( `bhyvectl --get-all` ), хотя берёт из него только число vCPU и объём памяти.
Каждое такое чтение останавливает vCPU гостя, за цикл их около сотни, и гость
стоит до сотен миллисекунд. Итог у партнёра - Linux-гости пишут
`clocksource: Marking clocksource 'tsc' as unstable` и переходят на часы HPET
( медленнее время в гостях, выше нагрузка ), любые гости коротко замирают раз
в 10 секунд.

## Что чинит

- cxx-collector - в бинаре сборщика вызов `bhyvectl --get-all` заменяется
  вызовом обёртки `/usr/local/sbin/vpd-bhyvectl`, которая читает только
  статистику и топологию ( `bhyvectl --get-stats --get-cpu-topology` ). Эти
  чтения vCPU не останавливают. Меняется только строка вызова, 36 байт той же
  длины; перед записью скрипт сверяет байты на месте и проверяет копию
- perl-feeder - та же замена в тексте перлового сборщика
- restart-service - перезапуск службы сборщика, если она работала

Метрики не меняются: те же ряды и те же значения. ВМ и узел не
перезагружаются.

## Как проверить подпись и запустить

От root на каждом узле кластера:

```
cd /tmp
fetch https://repo.vstack.com/hotfixes/perfdata-fix/perfdata-fix.sh
fetch https://repo.vstack.com/hotfixes/perfdata-fix/perfdata-fix.sh.sig
openssl dgst -sha256 -verify /usr/share/keys/vstack/vstackos.pub \
  -signature perfdata-fix.sh.sig perfdata-fix.sh
```

Дождаться `Verified OK` ( иначе файл повреждён или подменён - не запускать,
сообщить в поддержку ), затем:

```
sh perfdata-fix.sh          # режим check, только отчёт, ничего не меняет
sh perfdata-fix.sh apply    # применить найденные фиксы
sh perfdata-fix.sh revert   # вернуть как было
```

check и apply около 25 секунд измеряют остановки vCPU.

## Как читать отчёт

```
== perfdata-fix on node01, mode: apply ==
os release:         14.2-RELEASE
C++ collector:      needs-fix, running: yes
Perl CPU feeder:    absent, running: no
verdict: fixes needed: cxx-collector
applied: cxx-collector, backup: /usr/local/sbin/vstack-vm-perfdata.orig
service vstack_vm_perfdata:  restarted, running
measuring vCPU0 freezes on 5 VM(s) for 25 s ...
vCPU freezes:       0 in 25 s
result: OK
```

`vCPU freezes` - сколько раз за замер остановлен vCPU0 у первых пяти ВМ узла
( счётчик `number of times idle requested at exit` ). До фикса - сотни и
больше, после - 0.

Состояние сборщика: `needs-fix` - нужен фикс, `applied` - фикс уже стоит,
`not-affected` - сборщик без ошибки, `absent` - не установлен.

Вердикты:
- `everything is in order, nothing to do` - фиксы не нужны, ничего не менялось
- `fixes needed: ...` - перечень нужных фиксов; в режиме check ничего не
  меняется, в режиме apply каждый фикс отчитывается строкой `applied: ...`
- `fixes are not applicable` - сборщик не установлен, ничего не менялось

Коды возврата: 0 - порядок ( нечего чинить / неприменимо / фиксы применены ),
3 - check нашёл что чинить, 2 - сборщик исправлен, но vCPU всё ещё
останавливаются, 1 - ошибка или неуспешный apply ( выполнен откат ).

## Откат

Перед правкой исходный файл сохраняется рядом с суффиксом `.orig`. Если служба
после правки не поднялась - автоматический откат: файлы возвращаются из
`.orig`, обёртка удаляется, служба перезапускается, код возврата 1.

`sh perfdata-fix.sh revert` возвращает файлы из `.orig` и удаляет обёртку.

При отказе прислать в поддержку: полный вывод скрипта и вывод
`pkg query '%n-%v' | grep -i perfdata`.

## Известные ограничения

- Linux-гость, который уже переключился с TSC на HPET, обратно сам не
  вернётся: TSC вернётся после перезагрузки гостя. Новых переключений после
  фикса нет
- `pkg check -s` покажет несовпадение контрольной суммы бинаря сборщика - это
  и есть фикс. Переустановка пакета той же версии возвращает исходный бинарь:
  запустить скрипт снова. После обновления до версии с исправлением check
  покажет `not-affected`
- код возврата 2: vCPU останавливает что-то кроме сборщика - прислать вывод в
  поддержку
