Слияние конфигов
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:13 am (UTC)Вы грубо неправы. Отношение между проблемными ситуациями в предлагаемой схеме и в стандартной одностороннее: то, что решается в стандартной, решается и в предлагаемой, но не наоборот.
Стандартная схема сейчас по сути позволяет только одно: если конфиг не менялся (контрольная сумма совпадает с тем, что записано в базе на момент начала апгрейда пакета), то апгрейд пройдёт без проблем - заменой на новый. В моём описании это значит, что A0 == C0, и тогда будет A1 == C1.
Случай, когда A0 != C0, приводит к тому, что C1 кладётся как $name.rpmnew и мы имеем A0 и C1. (Это я не вспоминаю случай, когда майнтейнер - диверсант и .rpmnew не разрешает.) Стандартная схема это не решает совсем. Предлагаемая схема позволит вычислить слияние, когда оно не имеет конфликтов.
Наконец, при конфликтах слияния стандартная схема тем более не работает. Вывод - предлагаемая схема мощнее и позволяет больше, давая меньше необходимости вмешательства оператора.
no subject
Date: 2010-03-13 03:08 pm (UTC)no subject
Date: 2010-03-13 10:20 am (UTC)Конструктивный смысл из Вашего замечания я вижу только один - все изменения конфигов, неважно, от автомата или нет, должны контролироваться (как минимум вовремя получаться и анализироваться). По старым временам я для этого ставил cvsbackup. Сейчас CVS не в моде, надо бы переписать на git.
no subject
Date: 2010-03-15 07:20 am (UTC)no subject
Date: 2010-03-15 07:23 am (UTC)no subject
Date: 2010-03-15 10:30 am (UTC)Там для счастья с произвольным менеджером пакетов и vcs нужно две вещи:
1)Чтобы менеджер пакетов умел глобальные pre-install и post-install хуки
2)Чтоы vcs умел pre-commit и post-commit хуки
no subject
Date: 2010-03-13 09:45 am (UTC)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 и своди руками.
no subject
Date: 2010-03-13 12:13 pm (UTC)А я когда-то давно сделал git init в /etc и с тех пор после каждого dist-upgrade внимательно роюсь в diff'ах.
no subject
Date: 2010-03-13 09:06 pm (UTC)no subject
Date: 2010-03-13 09:57 pm (UTC)Копия предыдущего стандартного конфига - "VCS для бедных" по типу даже не CVS, а RCS.