goherence/internal/module/builtin/package.go
2026-09-11 10:17:25 +03:00

63 lines
3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package builtin
import (
"context"
"fmt"
"github.com/vladimir/goherence/internal/module"
"github.com/vladimir/goherence/internal/ssh"
)
// PackageModule — аналог puppet-style типизированного ресурса package:
// один модуль на все дистрибутивы, сам выбирающий провайдера (apt/dnf/yum),
// вместо того чтобы заставлять плейбук писать `when: os_family == ...`
// для каждой пары модуль/ОС. Выбор провайдера:
// 1. если в hostVars есть os_family (факты собраны) — используем его напрямую,
// без единого лишнего запроса на хост;
// 2. если фактов нет (gather_facts: false) — определяем прямо на месте
// через наличие apt-get/dnf/yum на хосте (одна дополнительная команда,
// но только в этом случае — не платим за это, когда факты уже есть).
type PackageModule struct {
// OSFamily — предвычисленный на этапе резолва переменных os_family
// (пусто, если факты не собирались). Заполняется executor'ом так же,
// как TemplateModule.Vars — см. builtin.RegisterAll.
OSFamily string
}
func (m *PackageModule) Name() string { return "package" }
func (m *PackageModule) Run(ctx context.Context, in module.Input, conn *ssh.Conn) (module.Result, error) {
family := m.OSFamily
if family == "" {
detected, err := detectOSFamily(conn)
if err != nil {
return module.Result{}, fmt.Errorf("package: не удалось определить дистрибутив " +
"(факты не собраны и автоопределение не удалось): " + err.Error())
}
family = detected
}
switch family {
case "Debian":
return (&AptModule{}).Run(ctx, in, conn)
case "RedHat":
return (&PackageRPMModule{}).Run(ctx, in, conn)
default:
return module.Result{}, fmt.Errorf(
"package: неизвестное семейство ОС %q — используй apt или rpm_package явно", family)
}
}
// detectOSFamily — резервный путь для случая gather_facts: false: одна
// команда на хосте вместо полноценного facts.Gather (который делает
// дополнительный `cat /etc/os-release`) — здесь достаточно проверить
// наличие пакетного менеджера, сам os-release не нужен.
func detectOSFamily(conn *ssh.Conn) (string, error) {
if res, err := conn.Run("command -v apt-get"); err == nil && res.ExitCode == 0 {
return "Debian", nil
}
if res, err := conn.Run("command -v dnf || command -v yum"); err == nil && res.ExitCode == 0 {
return "RedHat", nil
}
return "", fmt.Errorf("не найден ни apt-get, ни dnf/yum")
}