68 lines
2.4 KiB
Go
68 lines
2.4 KiB
Go
package builtin
|
||
|
||
import (
|
||
"bytes"
|
||
"context"
|
||
"fmt"
|
||
"os"
|
||
|
||
"github.com/vladimir/goherence/internal/module"
|
||
"github.com/vladimir/goherence/internal/ssh"
|
||
tmpl "github.com/vladimir/goherence/internal/template"
|
||
)
|
||
|
||
// TemplateModule — аналог ansible.builtin.template: рендерит файл шаблона
|
||
// (text/template + sprig, см. internal/template) с текущими переменными
|
||
// таска и приводит удалённый файл к результату — идемпотентно, как copy.
|
||
type TemplateModule struct {
|
||
// Vars — переменные, с которыми рендерится шаблон. Заполняется
|
||
// executor'ом перед вызовом Run (сам Module не знает про vars.Resolve,
|
||
// чтобы не тянуть в module-пакет зависимость на parser/vars).
|
||
Vars map[string]interface{}
|
||
}
|
||
|
||
func (m *TemplateModule) Name() string { return "template" }
|
||
|
||
func (m *TemplateModule) Run(ctx context.Context, in module.Input, conn *ssh.Conn) (module.Result, error) {
|
||
src, ok := in.Args["src"].(string)
|
||
if !ok {
|
||
return module.Result{}, fmt.Errorf("template: аргумент src обязателен")
|
||
}
|
||
dest, ok := in.Args["dest"].(string)
|
||
if !ok {
|
||
return module.Result{}, fmt.Errorf("template: аргумент dest обязателен")
|
||
}
|
||
mode, _ := in.Args["mode"].(string)
|
||
if mode == "" {
|
||
mode = "0644"
|
||
}
|
||
|
||
raw, err := os.ReadFile(src)
|
||
if err != nil {
|
||
return module.Result{}, fmt.Errorf("template: чтение шаблона %s: %w", src, err)
|
||
}
|
||
|
||
rendered, err := tmpl.Render(src, string(raw), m.Vars)
|
||
if err != nil {
|
||
return module.Result{}, fmt.Errorf("template: рендер %s: %w", src, err)
|
||
}
|
||
|
||
current, err := conn.ReadFile(dest)
|
||
same := err == nil && bytes.Equal(current, []byte(rendered))
|
||
if same {
|
||
return module.Result{SchemaVersion: module.SchemaVersion, Changed: false, Msg: "уже в нужном состоянии"}, nil
|
||
}
|
||
if in.CheckMode {
|
||
return module.Result{SchemaVersion: module.SchemaVersion, Changed: true, Msg: "check mode: файл был бы изменён: " + dest}, nil
|
||
}
|
||
|
||
if err := conn.WriteFile(dest, []byte(rendered), mode); err != nil {
|
||
return module.Result{}, fmt.Errorf("template: запись %s: %w", dest, err)
|
||
}
|
||
|
||
return module.Result{
|
||
SchemaVersion: module.SchemaVersion,
|
||
Changed: true,
|
||
Msg: "шаблон отрендерен и записан: " + dest,
|
||
}, nil
|
||
}
|