52 lines
1.8 KiB
Go
52 lines
1.8 KiB
Go
package builtin
|
||
|
||
import (
|
||
"bytes"
|
||
"context"
|
||
"fmt"
|
||
|
||
"github.com/vladimir/goherence/internal/module"
|
||
"github.com/vladimir/goherence/internal/ssh"
|
||
)
|
||
|
||
// CopyModule — аналог ansible.builtin.copy: приводит файл на хосте
|
||
// к заданному содержимому. Идемпотентен: сначала читает текущее
|
||
// содержимое и сравнивает, "changed" выставляется только при реальном отличии.
|
||
type CopyModule struct{}
|
||
|
||
func (m *CopyModule) Name() string { return "copy" }
|
||
|
||
func (m *CopyModule) Run(ctx context.Context, in module.Input, conn *ssh.Conn) (module.Result, error) {
|
||
dest, ok := in.Args["dest"].(string)
|
||
if !ok {
|
||
return module.Result{}, fmt.Errorf("copy: аргумент dest обязателен")
|
||
}
|
||
content, ok := in.Args["content"].(string)
|
||
if !ok {
|
||
return module.Result{}, fmt.Errorf("copy: аргумент content обязателен (первая версия не читает src-файлы с control node)")
|
||
}
|
||
mode, _ := in.Args["mode"].(string)
|
||
if mode == "" {
|
||
mode = "0644"
|
||
}
|
||
|
||
current, err := conn.ReadFile(dest)
|
||
same := err == nil && bytes.Equal(current, []byte(content))
|
||
|
||
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(content), mode); err != nil {
|
||
return module.Result{}, fmt.Errorf("copy: запись %s: %w", dest, err)
|
||
}
|
||
|
||
return module.Result{
|
||
SchemaVersion: module.SchemaVersion,
|
||
Changed: true,
|
||
Msg: "файл записан: " + dest,
|
||
}, nil
|
||
}
|