58 lines
2.9 KiB
Go
58 lines
2.9 KiB
Go
// Package vars реализует единственную ответственность: для заданного
|
||
// хоста построить финальный набор переменных, накатывая слои строго
|
||
// в порядке приоритета Ansible (упрощённом до того, что реально нужно).
|
||
package vars
|
||
|
||
import "github.com/vladimir/goherence/internal/parser"
|
||
|
||
// Resolve строит финальные переменные для (хост, роль, play), от самого
|
||
// низкого приоритета к самому высокому. Порядок совпадает с комментарием
|
||
// в архитектурном документе — намеренно не абстрагирован дальше, чтобы
|
||
// последовательность накатывания оставалась видна с первого взгляда.
|
||
// facts — собранные internal/facts данные о хосте (os_family и
|
||
// т.п.); в реальном Ansible факты имеют высокий приоритет, но ниже
|
||
// явных play/role vars и extra-vars — этот порядок здесь и соблюдён.
|
||
func Resolve(
|
||
host string,
|
||
inv *parser.Inventory,
|
||
play *parser.Play,
|
||
role *parser.Role,
|
||
facts map[string]interface{},
|
||
extraVars map[string]interface{},
|
||
) map[string]interface{} {
|
||
result := map[string]interface{}{}
|
||
|
||
if role != nil {
|
||
merge(result, role.Defaults) // 1. role defaults — самый низкий приоритет
|
||
}
|
||
merge(result, inv.GroupVars("all")) // 2. group_vars/all
|
||
for _, g := range inv.GroupChain(host) {
|
||
if g == "all" {
|
||
continue
|
||
}
|
||
merge(result, inv.GroupVars(g)) // 3. group_vars/<group>, родители раньше потомков
|
||
}
|
||
merge(result, inv.HostVars(host)) // 4. host_vars/<host>
|
||
merge(result, facts) // 4.5. факты хоста (os_family и т.п.)
|
||
if play != nil {
|
||
merge(result, play.Vars) // 5. play vars
|
||
}
|
||
if role != nil {
|
||
merge(result, role.Vars) // 6. role vars/main.yml
|
||
}
|
||
// 7. set_fact / registered vars — накатываются executor'ом во время
|
||
// выполнения, а не здесь: Resolve вызывается один раз до старта таска.
|
||
merge(result, extraVars) // 8. extra-vars — самый высокий приоритет, всегда последний
|
||
|
||
return result
|
||
}
|
||
|
||
// merge — намеренно плоская перезапись по ключу (dst[k] = src[k]), БЕЗ
|
||
// рекурсивного deep-merge вложенных map. Ровно так себя ведёт и сам
|
||
// Ansible по умолчанию (hash_behaviour=replace) — это осознанное решение
|
||
// для совместимости ожиданий, а не недосмотр.
|
||
func merge(dst, src map[string]interface{}) {
|
||
for k, v := range src {
|
||
dst[k] = v
|
||
}
|
||
}
|