Эффективный Контрибьюшн в OpenStack: На Примере Одной Neutron Фичи
Итак, у вас есть отличная идея для новой фичи в OpenStack, которая улучшит/упростит/ускорит/оптимизирует какой-либо бизнес сценарий. При этом вы хотите не только реализовать ее для downstream нужд (например в ваш кастомный дистрибутив), но и законтрибьютить в open source комьюнити.
Первое – для чего вам это нужно? Вот несколько возможных мотиваторов:
Вы хотите сэкономить ресурсы на поддержку и апгрейд в будущем;
Вы хотите получить ревью на вашу фичу, на ее дизайн и функционал (проверка на прочность);
Вы хотите использовать ресурсы комьюнити для верификации и нагрузочного тестирования;
Вы хотите поднять рейтинг/кредит доверия вашей компании в комьюнити;
Вы хотите улучшить собственный рейтинг (в том числе в компании).
Второе – как это делается. И наконец – как сделать это наиболее эффективно – с минимумом временных и психологических затрат. Эта статья посвящена последним двум вопросам. Как представитель Core команды проекта OpenStack Neutron, я бы хотел поделиться своим опытом участия в разработке open source продуктов. В качестве примера я возьму Neutron фичу представленную в начале 2021 года московской командой Cloud Technologies Research (Advanced Software Technologies Lab, Huawei) - Node Local Virtual IP. Хотя процесс может быть иногда специфичен для Neutron проекта – он более или менее схож для всех OpenStack проектов, и, пожалуй, в определенной степени для всего open source.
Представьте и «продайте» идею в комьюнити
Итак, руководство дало добро на open source’инг вашей фичи. Супер!
Здесь я подразумеваю, что вы достаточно исследовали существующие возможности проекта и уверены, что юзкейсы, поддерживаемые вашей новой фичей, не могут быть (оптимально) покрыты текущим функционалом. Теперь вам нужно убедить в этом комьюнити. И это наиболее важная и сложная часть.
Шаг 0: Ваш текущий статус и репутация (опционально)
Но прежде чем идти и предлагать что-то в open source проект, большим преимуществом будет, если вы не просто «человек с улицы» и уже имеете некий кредит доверия в этом комьюнити: чем больше тем лучше. Единственный путь заработать репутацию – уделять время, а именно делать код ревью и фиксить баги. Этим вы повысите доверие к себе со стороны других ревьюэров, и, что более важно, со стороны Core команды. Команда поймет, что:
Вы заботитесь не только о своих интересах, но и обо всем проекте;
Вы готовы заниматься поддержкой своей фичи, и связанных областей кода, так что –
Это не станет чужой головной болью сразу после мерджа.
Да, это опционально, но не стоит недооценивать! Эффективный контрибьютор это прежде всего хороший и грамотный код ревьюэр. Впрочем, что значит быть хорошим ревьюэром и участником комьюнити – выходит за рамки данной статьи.
Шаг 1: RFE (Request for Feature Extension)
RFE это по существу баг в OpenStack баг трекере - Launchpad, - помеченный специальным тегом «rfe». Этот баг должен содержать короткое, но при этом всестороннее описание новой фичи. Эффективный RFE будет также содержать описание основных юзкейсов. Таким образом, после прочтения каждый поймет - что он, как пользователь, сможет сделать с помощью этой фичи. В идеале юзкейсы должны быть достаточно «широкими», чтобы покрыть максимум пользовательской аудитории. Для примера, RFE по Node Local IP:
https://bugs.launchpad.net/neutron/+bug/1930200
После сабмита RFE внимательно следите за комментариями и ждите следующего Neutron Drivers митинга (Neutron Drivers - подгруппа Core команды, которая определяет roadmap проекта). В его расписание должны включить ваш топик. Если нет – можно напомнить об этом PTL’ю (Project Team Lead) в IRC канале openstack-neutron.
На митинге вам будут задавать больше вопросов с целью максимально прояснить предлагаемые изменения. В конце пройдет голосование, где члены Drivers Team решат принимать фичу или нет. Пример такого обсуждения для Node Local IP:
https://meetings.opendev.org/meetings/neutron_drivers/2021/neutron_drivers.2021-06-04-14.01.log.html
Если вы были убедительны, дружелюбны и немного удачливы – команда примет вашу идею, и RFE пометят как «rfe-approved». Здесь будем подразумевать, что фича достаточно большая – это означает, что следующим шагом является написание дизайн спецификации (не требуется для небольших фич).
Шаг 2: Дизайн Спецификация
Дизайн спека должна прояснить проблему и подход к ее решению. Не стесняйтесь использовать графику! В контексте подхода вы должны описать все изменения, которые собираетесь сделать: в API, модели данных, интерфейсе RPC, L2/L3 агентах и т.д. в зависимости от размера фичи. Эффективный дизайн это прежде всего неразрушающий (non-disruptive), с минимально возможными изменениями в core структурах и процессах: это означает использование расширений (extensions) – сервис плагинов на стороне сервера, и расширений на стороне L2/L3 агентов. Расширения можно конфигурировать, и они отключены по умолчанию для новых фич. Как только фича пройдет стадию «детских болезней» и станет достаточно надежной – команда рассмотрит возможность и необходимость включения ее по умолчанию. Таким образом расширения помогают Core ревьюэрам меньше «нервничать» и, следовательно, делают их более уступчивыми.
Хотя хорошая дизайн спецификация должна быть всесторонней, старайтесь все же делать ее «короткой и острой» (short and sharp)! Помните, что, как и все люди – ревьюэры ленивы. Чем больше патч или спека – тем больше шансы что ревьюэр отложит ее на завтра/понедельник/после_праздников/в_новом_году/никогда. То есть, нужен компромисс: лучше опустить какие-то низкоуровневые детали реализации, пока о них явно не спросят. Не пытайтесь предусмотреть абсолютно все заранее, оставьте немного пространства для импровизации во время кодинга. К тому же никто не запрещает обновлять спеку после мерджа, особенно в рамках одного релиза.
Технически спека это патч в *.rst формате в специальный *-specs репозиторий, такой как neutron-specs.
Дизайн спецификация Node Local IP:
https://review.opendev.org/c/openstack/neutron-specs/+/797798
Там можно увидеть полезные предложения от ревьюэров – один из плюсов open source, о которых я говорил в начале статьи. В данном случае это предложение об использовании статических NAT правил для Local IP, чтобы удовлетворить кейс OVS offloadings. Результат позднее был реализован тут.
Шаг 3: API спецификация
Каких то особых приемов в написании API спеки я, честно говоря, не подмечал. Только общего плана:
Согласованность с дизайном;
Старайтесь предусмотреть все возможные будущие изменения, так чтобы они всегда были обратно совместимыми и non-disruptive;
Используйте примеры запросов и подробно опишите параметры;
Прочитайте документацию по API расширениям.
API спека для Node Local IP: https://review.opendev.org/c/openstack/neutron-lib/+/803051
Структурируйте и декомпозируйте имплементацию
Большие патчи не приветствуются в комьюнити – сложно найти достаточно большое временное окно для ревью, чтобы оставаться в контексте. Эффективный путем будет разбить фичу на несколько логических компонентов, формируя цепочку патчей:
- где каждый патч в идеале <= 1000 строк кода.
Шаг 4: Изменения на стороне сервера
Серверный патч (или патчи, в зависимости от размера) может содержать:
API extension (реализация API спецификации);
Модели БД, миграции и плагин;
Модели OVO;
Сервис плагин (подключаемый через конфиг);
Policy правила.
Опять же, в любом contribution одной из основных задач является не посадить регрессию, включая регрессии по быстродействию. Ваш код должен быть максимально изолирован и по возможности никак не затрагивать существующий стабильный функционал. Например, добавляя таблицу в реляционную БД, убедитесь что ваши ORM relationships не влияют на быстродействие других моделей: одной из распространенных ошибок является использование «joined» или «subquery» lazy mode при добавлении обратной ссылки (backref) к ранее существующей ДБ модели – это сделает DB запросы к такой модели (например Port) более тяжеловесными и времязатратными. Пример тут: https://review.opendev.org/c/openstack/neutron/+/743142/comment/467735e2_714925fc/
Ну и как обычно, могут быть исключения: если все учтено и соответствует дизайну – это не баг, а фича!
Сервер патчи Node Local IP:
DB + API: https://review.opendev.org/c/openstack/neutron/+/804523;
Policy правила: https://review.opendev.org/c/openstack/neutron/+/816435.
Шаг 5: Изменения на стороне агентов
Необходимые доработки агентов также рекомендуется заворачивать в расширения. Это позволит изолировать новый (и скорее всего нестабильный) код, чтобы не задеть основной функционал. По умолчанию новое расширение будет отключено в конфиге.
В дополнение в этой части можно настроить канал связи между сервером и агентом, обычно через RPC интерфейс. В Neutron для этого рекомендовано использовать Push Notifications фреймворк: в двух словах он обеспечивает fanout рассылку всех изменений наблюдаемого объекта всем слушателям. Это позволяет избежать лишних раундтрипов (как в legacy схеме fanout-notification + multiple pull requests).
Node Local IP патчи на стороне агентов:
Extension “frontend” + RPC: https://review.opendev.org/c/openstack/neutron/+/807116;
Extension “backend”: https://review.opendev.org/c/openstack/neutron/+/815102;
Extension “backend” v2: https://review.opendev.org/c/openstack/neutron/+/817399.
Шаг 6: Изменения в CLI
Если ваша фича подразумевает какой-либо интерактив с пользователем, вам потребуются патчи в openstack CLI. В общем случае, если вы изменяете/дополняете API – нужны соответствующие изменения в CLI.
Исторически у каждого OpenStack проекта был свой CLI клиент. Это вело к несоответствиям между различными проектами и, как следствие, к плохому user experience. В итоге комьюнити решило унифицировать все CLI и как результат появилось 2 репозитория:
OpenStack SDK - a set of language bindings that provide a language-level API for accessing OpenStack in a manner consistent with language standards;
OpenStackClient - a command-line client for OpenStack that brings the command set for Compute, Identity, Image, Network, Object Store and Block Storage APIs together in a single shell with a uniform command structure.
Говоря по-русски, OpenStack SDK – это Python фреймворк для формирования и отсылки корректных REST запросов к различным OpenStack API; а OpenStackClient – собственно CLI клиент, принимающий запросы от пользователя и далее использующий SDK для взаимодействия с API.
Соответствующие патчи для Node Local IP:
SDK: https://review.opendev.org/c/openstack/openstacksdk/+/804988;
Client: https://review.opendev.org/c/openstack/python-openstackclient/+/805618.
Шаг 7: Интеграционные тесты
Весь функционал должен быть покрыт тестами – это, думаю, очевидно. Юнит и функциональные тесты обычно включены в патчи, которые и добавляют этот функционал. Интеграционные же тесты идут отдельно.
Помимо очевидной цели проверить фичу и предотвратить будущие регрессии, эти тесты также полезны во время код ревью – они помогают убедить ревьюэров, что фича действительно рабочая. Таким образом, иметь интеграционные тесты в конце цепочки патчей – отличный прием эффективного контрибьютора!
Для Neutron есть несколько репозиториев с интеграционными тестами:
Fullstack тесты находятся в главном Neutron репозитории – это такие лайтовые интеграционные тесты, но все же способные эмулировать создание виртуальных машин и проверку их сетевой доступности.
Tempest repo – общие тесты для всего OpenStack.
neutron-tempest-plugin – тесты, специфичные для Neutron фич, которые не входят в дефолтный core функционал.
Пример Node Local IP тестов: https://review.opendev.org/c/openstack/neutron/+/816327, - как можно увидеть, здесь создаются фейковые ВМ и проверяется их доступность по Local IP.
Шаг 8: Документация
Наверное, наиболее скучная, но тем не менее важная составляющая в имплементации каждой фичи. Хотя это частично покрывается дизайн и API спецификациями на предыдущих шагах – часто нужно дополнить и внутренние contributor docs:
Это поможет ревьюэрам и мейнтейнерам в будущем.
И конечно, релиз ноуты обязательны для каждого существенного изменения в проекте! Пример:
https://review.opendev.org/c/openstack/neutron/+/820031
Продвигайте свои патчи
Когда ваша цепочка патчей готова, единственное что остается – ждать ревью и комментариев. Иногда и ждать не приходится - зависит от вашего везения и (чаще) от размера изменений! Но в общем случае время ревью недетерминировано. Ниже я постарался привести все известные мне tips and tricks – как получить код ревью быстрее:
Ревьюйте патчи других! – я упоминал это на Шаге 0. Конкретно здесь – если хотите получить от кого-то ревью – наиболее деликатным намеком будет, если вы сделаете ревью его/ее патчей. Этим вы заработаете немного кредитов в свою копилку, они пригодятся в будущем. В дополнение, это напомнит о существовании вас и ваших патчей! J
Добавьте код ревьюэров – платформа Gerrit позволяет добавлять ревьюэров явно, по имени. Таким образом, вы можете взять список Core ревьюэров и добавить кого-то (или всех сразу) на свой патч. Я бы не советовал делать это для каждого патча в цепочке – лучше начать с малого (первого) и посмотреть – так меньше шансов слишком «напрячь» людей. Список Neutron Core ревьюэров можно найти тут.
Отвечайте быстро! – часто вы сами задаете темп ревью своих патчей скоростью своих ответов. Так что старайтесь отвечать и править быстро. Даже если модификация потребует времени – как минимум ответьте, что согласны и исправите в ближайшее время.
Ping fellow reviewers! – можно написать коммент в своем Gerrit патче (с учетом того, что какие-то ревьюэры там уже есть), к примеру «Hey folks, please reviewJ». Еще можно пинговать в IRC канале проекта – или просто попросить ревью своего патча, но лучше адресно обратиться к конкретным людям, например, кто уже комментил ранее, или кто является ответственным в данной области (подробнее про области ответственности тут). Здесь также надо быть осторожнее и не злоупотреблять – излишняя навязчивость может дать обратный эффект!
Добавить в агенду проект митинга – как правило, у каждого OpenStack проекта есть еженедельные team митинги. В их агенде обычно можно найти «On Demand» слот, где каждый волен предложить тему для обсуждения (https://wiki.openstack.org/wiki/Network/Meetings см. в конце). Так что, если фича готова и ждет ревью – добавьте этот топик, дайте команде апдейт и попросите ревью. Например как я сделал тут.
Будьте вежливы и согласны (agreeable)! – довольно очевидно, но все же – спорьте с ревьюэрами, только если на то есть очень веская причина, и вы точно уверены в несправедливости замечания/коммента. Отвечайте на все комментарии, уважайте труд и время ревьюэров.
Rebase может помочь! – простой rebase + update продвинет ваш патч наверх в общей таблице патчей и пошлет email напоминание ревьюэрам. К тому же, это не ведет к потере имеющихся оценок/голосов (когда к примеру уже есть несколько +1 и +2).
Поддержка и сопровождение
Итак, ваша фича замерджена, что дальше? Запилить новую? Конечно! Но помните: та что замерджена - теперь ваш «питомец», по крайней мере на несколько релизов. Учтите, что на это будет расходоваться часть вашего времени. Что это значит:
Следить за новыми багами, прямо или косвенно затрагивающими вашу фичу (можно даже добавить новый тег в Launchpad для удобства отслеживания). Это могут быть не только баги, но и запросы на изменения/улучшения.
Фиксить такие баги и давать обратную связь на предлагаемые улучшения.
Ревьюить чужие патчи, затрагивающие вашу фичу
Ответственные контрибьюторы более эффективны, так как у них повышается кредит доверия и репутация, что делает последующие contributions проще и быстрее!
Бонус: подводные камни в upstream процессе
Основываясь на своем опыте назову несколько подводных камней, которые могут существенно замедлить код ревью и мердж ваших патчей:
Нестабильный CI – патчи с «-1» от CI (упали тесты) имеют меньше шансов привлечь внимание, так что если CI нестабильный, это может отнять время (так почему бы не подебажить и не постараться помочь с CI? J).
Релиз зависимостей – бывает, что ваша фича затрагивает 2 и более репозиториев, и один из патчей становится зависим от релиза другой репы (куда ранее вошли нужные вам/ваши изменения). В Neutron это например релизы neutron-lib.
Низкий приоритет – если релиз сильно упакован новыми фичами, при этом ваша не имеет высокий приоритет – ожидайте postpone L.
Недостаток квалификации ревьюэров – когда идете в upstream с чем-то по настоящему новым – запаситесь терпением и не удивляйтесь, что Core команде может потребоваться время на изучение!
Праздники – Новый Год, Christmas, Thanksgiving и т.д. пожалуй не лучшие даты для ожидания код ревью! J
Примите это к сведению во время планирования и установки дедлайнов, потому что последние, как правило, нарушаются, когда речь касается апстрима!
Желаю удачи!
P.S.: Node Local Virtual IP успешно прошла все этапы, описанные в этой статье, и в феврале 2022 года полностью вошла в OpenStack Neutron. Она будет выпущена в релизе OpenStack Yoga.