Перейти до вмісту

Блог ·

Слово можливості для старого наказу

Коли раунд додає поле protobuf, старий агент падає гучно. Коли він лише змінює значення позначки, той самий агент відповідає правдоподібно і хибно.

Автор: Provibr

Наш агент працює всередині власної мережі клієнта і додзвонюється назовні до нас. Він оновлює себе, але не миттєво і не завжди, тож будь-якої миті флот є розкидом версій, і платформа мусить знати, що вміє кожна з них.

Вона знає, бо агент їй каже. На кожній сесії агент надсилає перелік коротких слів, по одному на можливість, і платформа відмовляє наказові, чийого слова бракує, замість надіслати його й сподіватися.

Цей раунд додав третє таке слово для контейнерів Proxmox, і воно є першим, де цікавим питанням було не те, чи його додавати, а те, що сталося б без нього.

Навіщо ці слова взагалі існують

Механізм захищає від однієї конкретної властивості protobuf: невідоме поле в oneof відкидають.

Коли раунд додає новий наказ як нове поле, агент, старіший за той раунд, розбирає повідомлення, не впізнає номера поля, викидає його і лишається з ProxmoxCommand без наказу всередині. Тоді він каже рівно це. Повідомлення є чесним і цілком некорисним: оператор бачить скаргу на порожній конверт, а причина лежить за чотири шари звідти, у розбіжності версій, про яку ніхто не згадав.

Тож платформа відмовляє першою. Якщо слова бракує, наказ ніколи не вирушає, а відмова називає можливість і версію агента. Це є гіршим наслідком, ніж наказ, що спрацював, і значно кращим, ніж наказ, що падає у спосіб, на простеження якого йде ціле пообіддя.

У будь-якому разі це є гучною відмовою. Виявляється, що саме це має значення.

Третє слово не є новим полем

Зміною цього раунду було те, що контейнер тепер може показати своє обладнання. Наказ, який це робить, GetHardware, не є новим. Кожен агент аж до ранніх робіт над життєвим циклом віртуальних машин знає це повідомлення і знає, як на нього відповісти.

Змінилася позначка поруч із ним, що каже, до якого роду ресурсу належить ідентифікатор. Агент, старіший за цей раунд, отримує ту позначку, не знає її і викидає, рівно так, як каже protobuf. Тоді він робить те, що завжди робив із запитом про обладнання: питає в Proxmox конфігурацію машини на шляху QEMU.

Ніщо не є порожнім. Ніщо не скаржиться. Агент вважає, що йому поставили питання, яке він розуміє, і відповідає.

Є два способи, якими це приземляється, і жоден із них не є гучним. Якщо в Proxmox за тим ідентифікатором на шляху віртуальної машини немає нічого, клієнтові кажуть, що машини не існує, про контейнер, який працює просто перед ним. А якщо конфігурація таки повертається і потрапляє до парсера, побудованого для віртуальних машин, відповідь є не порожньою, вона є хибною.

Хибна відповідь є конкретною, і вона має добрий вигляд

Два формати конфігурації є досить близькими, щоб розібратися, і досить різними, щоб це важило. Віртуальна машина записує свою першу мережеву карту як модель і MAC-адресу, зʼєднані знаком рівності. Контейнер записує спершу імʼя інтерфейсу, а тоді MAC в окремому полі з ключем.

Парсер для віртуальних машин бере першу пару ключа і значення як модель і адресу. Тож, отримавши рядок контейнера, він повідомляє про мережеву карту, чиєю моделлю є name, а чиєю MAC-адресою є ETH0.

Це є правдоподібним на вигляд рядком у таблиці. У нього є модель, у нього є адреса, його малюють без застереження. Саме тому шляхові контейнерів знадобився власний парсер, і це є рівно тим класом дефектів, про які ніхто не повідомляє, бо в них немає про що повідомляти. Хтось дивиться на екран, думає, що стовпець моделі якийсь дивний, і йде далі.

Тож наказ, що вже існує, є небезпечнішим родом зміни, ніж наказ, що є новим. Новий падає на конверті, привселюдно. Цей падає на значенні, потайки.

Чому нічого не розширювати, а додати один рядок

Очевидною альтернативою є розширити слово, яке вже існує. Є слово, що каже, що агент узагалі розуміє шлях контейнерів, і роботи на один символ вистачило б, щоб воно означало ще й новішу річ.

Це відмовляло б кожному наказові про контейнер від кожного агента, який ще не оновився, зокрема й тим, які сьогодні працюють бездоганно. Флот, що зараз обслуговує контейнери, згас би для можливості, яку він справді має, бо ми змінили значення нашого слова в нього під ногами.

Слово є обіцянкою про те, що збудовано, і обіцянка мусить тримати своє значення доти, доки хтось її ще тримає. Додати третє слово коштує однієї сталої з кожного боку і відмовляє рівно тим наказам, яким треба відмовити, і більше нічому. Воно ще й кладе міркування туди, де людина його знайде, тобто поруч зі сталою, а не в повідомленні комміту.

Двома боками є дві сталі, одна в джерелі мовою Rust і одна у спільному TypeScript, кожна з яких називає іншу. Ця пара не є елегантною, і кожна спроба зробити її елегантною закінчується кроком збірки між двома мовами, які мають читатися незалежно.

Заглушка каже два з трьох навмисно

Є агент-заглушка, що дає нам керувати шлюзом без гіпервізора, і він теж оголошує слова контейнерів.

Він оголошує два з них. Він каже, що знає шлях контейнерів, і каже, що читає обладнання контейнера, і навмисно не заявляє третього, бо перевстановити контейнер він не може.

Це варто сказати, бо заглушка, що заявляє все, є заглушкою, яка робить кожен шлях відмови невипробовуваним. І протилежне важить рівно стільки ж: без слова про обладнання шлюз відмовив би, і слушно, а перевірка тихо зміряла б відмову замість відповіді. Випробувальна оснастка, що бреше про власні можливості, дає зелені результати про не ту річ.

Що ми б записали

  1. Protobuf викидає невідомі поля мовчки, тож новий наказ доходить до старого агента порожнім конвертом.
  2. Відмовляйте, перш ніж надсилати. Відмова, що називає можливість і версію, є кращою за скаргу з чотирьох шарів нижче.
  3. Небезпечною є зміна без нового поля. Ніщо не викидають, тож ніщо не скаржиться.
  4. Спосіб відмови, якого ви хочете, є гучним. Про правдоподібну відповідь, яка є хибною, вам ніколи не повідомлять.
  5. Два формати конфігурації, що обидва розбираються, є гіршими за два, які ні.
  6. Ніколи не розширюйте наявного слова можливості. Це є обіцянкою, яку тримають агенти, до яких вам не дістатися.
  7. Одне зайве слово коштує однієї сталої з кожного боку, і відмовляє лише тому, чому треба відмовити.
  8. Кладіть міркування поруч зі сталою, там, де насправді стоятиме наступна людина.
  9. Заглушка мусить відмовлятися від того, чого не може, інакше кожен шлях відмови стає невипробовуваним.
  10. Оснастка, що заявляє забагато, дає зелені результати про не ту річ.

Для ясності про те, чим це є: третє слово можливості для контейнерів Proxmox, додане поряд зі зміною, яка не ввела жодного нового поля протоколу, з міркуваннями, записаними при обох сталих, і агентом-заглушкою, що оголошує два з трьох; раунд посунув тестовий модуль контейнерів із тридцяти пʼяти тестів до тридцяти девʼяти, з чистими форматуванням і цільовою платформою релізу, і завершився спільними пакунками зеленими на 5347, шлюзом на 1467, інструментами-заглушками на 489 і набором вебу на 4593, без жодної невдачі, і ще пʼятдесятьма браузерними перевірками зеленими двома мовами. Не доведено: ніщо тут не запускали проти справжнього Proxmox, тож поведінку старішого агента на ідентифікаторі контейнера встановлено з двох форматів конфігурації і парсера, а не спостережено, а ланцюг у дії випробувано проти нашої власної заглушки.

Із платформної роботи над Provibr. Що стається, коли два раунди тягнуться по той самий номер поля, описано в Два раунди, один номер поля, раунд, що вперше навчив агента про контейнери, описано в Перевстановлення контейнера є заміною, а те, як агент узагалі вирішує, чи довіряти новій збірці, описано в Як підписане оновлення агента себе відхиляє.

Почніть з одного хоста й одного агента

Створіть обліковий запис, встановіть агента однією командою та підключіть свій перший хост Proxmox. Пробний період триває 14 днів і не потребує платіжних даних.