Слияние конфигов
Mar. 13th, 2010 11:17 amНаписал в uanog и подумал, что заслуживает отдельного постинга.
Wed, Mar 10, 2010 at 21:27:29, basil wrote about "Re: [uanog] apache dummy question":
> ну давайте поофтопим :)
>
> нормальные дистрибутивы конфиги не затирают
>
> в частности федора: создает файл-конфиг с расширением rpmnew (кажись так,
> ибо пользую федору сугубо на десктопе)
> во фре: если софт ставиться из портов, то каждый ментейнер заботиться о том,
> чтобы конфиги не затирались, а если не получается у ментейнера - то
> коммитеры всегда помогают, даже русского коммитера находят если надо :)
_Нормального_ подхода по-настоящему я не видел нигде. Потому что
единственный нормальный подход, jIMHO - это использование VCS, при
котором есть ветка канонической формы конфигов (в CVS такое
называется vendor branch) и ветка текущих конфигов, и при накате
нового состояния выполняется слияние (merge) правок из текущей
ветки и ветки канонической формы.
При любом другом подходе, не обладая комплектом из двух разностей
(diffs)
1) между прошлым каноническим состоянием (C0) и текущим
содержанием (A0)
2) между прошлым и текущим каноническими (C0 и C1)
невозможно гарантированно вычислить A1 (то, что должно получиться
в результате).
Подход RPM даёт A0 и C1, но не даёт C0.
В случае отсутствия конфликта слияния должно выполняться
A1 = A0 + (C1 - C0)
или же
A1 = C1 + (A0 - C0)
а лучше оба одновременно, это означает, что диффы C1-C0 и A0-C0
взаимно коммутативны, и это идеальный случай. Но если хотя бы один
из этих вариантов выполнился без проблем (при текущем уровне
интеллекта системы слияния в VCS) - это уже достаточный аргумент
ставить такой конфиг как результат слияния.
Остаются случаи, когда автоматическое слияние ломается. Например,
если у нас в C0 было написано
Port 34567
а админ заменил в A0 на
Port 45555
приход C1 с записями
ListeningPort 34567
OutgoingPort 34567
не может быть автоматически обработан. Понятно, что A1 должен в
этом месте получить как минимум следующее:
ListeningPort 45555
OutgoingPort 45555
для достижения той же функциональности, что была при апгрейде. Но
грамотный админ, видя обе разницы, с этим справится.
Замечания по реализации:
1. Применяемая для этого VCS должна быть максимально лёгкой, не иметь в идеале собственных конфигов и поддерживать слияние при перемещении файлов. На первую прикидку, один из лучших вариантов для этого - Git, но я не уверен в первом (какая часть делается через C код?) и последнем (чтобы гарантированно).
2. Пакетный менеджер, даже если оставляет работу админу на потом, должен позволять общий учёт файлов для слияния. Искать .rpmnew или аналог по всему файловому дереву мне не улыбается.
Wed, Mar 10, 2010 at 21:27:29, basil wrote about "Re: [uanog] apache dummy question":
> ну давайте поофтопим :)
>
> нормальные дистрибутивы конфиги не затирают
>
> в частности федора: создает файл-конфиг с расширением rpmnew (кажись так,
> ибо пользую федору сугубо на десктопе)
> во фре: если софт ставиться из портов, то каждый ментейнер заботиться о том,
> чтобы конфиги не затирались, а если не получается у ментейнера - то
> коммитеры всегда помогают, даже русского коммитера находят если надо :)
_Нормального_ подхода по-настоящему я не видел нигде. Потому что
единственный нормальный подход, jIMHO - это использование VCS, при
котором есть ветка канонической формы конфигов (в CVS такое
называется vendor branch) и ветка текущих конфигов, и при накате
нового состояния выполняется слияние (merge) правок из текущей
ветки и ветки канонической формы.
При любом другом подходе, не обладая комплектом из двух разностей
(diffs)
1) между прошлым каноническим состоянием (C0) и текущим
содержанием (A0)
2) между прошлым и текущим каноническими (C0 и C1)
невозможно гарантированно вычислить A1 (то, что должно получиться
в результате).
Подход RPM даёт A0 и C1, но не даёт C0.
В случае отсутствия конфликта слияния должно выполняться
A1 = A0 + (C1 - C0)
или же
A1 = C1 + (A0 - C0)
а лучше оба одновременно, это означает, что диффы C1-C0 и A0-C0
взаимно коммутативны, и это идеальный случай. Но если хотя бы один
из этих вариантов выполнился без проблем (при текущем уровне
интеллекта системы слияния в VCS) - это уже достаточный аргумент
ставить такой конфиг как результат слияния.
Остаются случаи, когда автоматическое слияние ломается. Например,
если у нас в C0 было написано
Port 34567
а админ заменил в A0 на
Port 45555
приход C1 с записями
ListeningPort 34567
OutgoingPort 34567
не может быть автоматически обработан. Понятно, что A1 должен в
этом месте получить как минимум следующее:
ListeningPort 45555
OutgoingPort 45555
для достижения той же функциональности, что была при апгрейде. Но
грамотный админ, видя обе разницы, с этим справится.
Замечания по реализации:
1. Применяемая для этого VCS должна быть максимально лёгкой, не иметь в идеале собственных конфигов и поддерживать слияние при перемещении файлов. На первую прикидку, один из лучших вариантов для этого - Git, но я не уверен в первом (какая часть делается через C код?) и последнем (чтобы гарантированно).
2. Пакетный менеджер, даже если оставляет работу админу на потом, должен позволять общий учёт файлов для слияния. Искать .rpmnew или аналог по всему файловому дереву мне не улыбается.
no subject
Date: 2010-03-13 10:59 am (UTC)1. Отличия касаются только синтаксиса конфига и не влияют на функциональность.
2. Merge делается вручную (как у фрёвого mergemaster).
Иначе возможны глюки. Если есть функциональные отличия между C0 и С1, при их автоматическом добавлении в A0 в любом случае можно получить не то, что нужно админу, и что-то может оказаться поломано.
А в случае изменения синтаксиса можно и скриптом в postinstall конвертнуть старый конфиг в новый - вполне подходит для описанного тобой случая с ListeningPort.
no subject
Date: 2010-03-13 12:50 pm (UTC)См. соседний комментарий. При современном стиле разделения конфигов значительно вероятнее получить "не то" не из смерженного конфига, а из соседнего, который вообще локально не правился. Поэтому в любом случае важен контроль результирующих изменений.
> А в случае изменения синтаксиса можно и скриптом в postinstall конвертнуть старый конфиг в новый - вполне подходит для описанного тобой случая с ListeningPort.
Согласен, но это частный случай. Чуть более сложную правку скрипт уже не осилит.
> Merge делается вручную (как у фрёвого mergemaster).
Сейчас мы это и так имеем - ищи все .rpmnew и своди руками.