58 lines
2.4 KiB
Go
58 lines
2.4 KiB
Go
// Package external реализует расширяемость модулей без пересборки
|
||
// бинарника goherence: сторонний модуль — любой исполняемый файл,
|
||
// который читает JSON (module.Input) из stdin и пишет JSON (module.Result)
|
||
// в stdout. Контракт совпадает с тем, как устроены сами модули Ansible —
|
||
// осознанное решение, чтобы язык реализации модуля был не важен.
|
||
package external
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"os"
|
||
"path/filepath"
|
||
)
|
||
|
||
// Manifest — метаданные одного внешнего модуля, лежат в modules.d/<name>/manifest.json.
|
||
type Manifest struct {
|
||
Name string `json:"name"`
|
||
Version string `json:"version"`
|
||
SchemaVersion int `json:"schema_version"`
|
||
Architectures []string `json:"architectures"` // "linux/amd64", "linux/arm64"
|
||
Checksums map[string]string `json:"checksums"` // arch → sha256 (без префикса)
|
||
}
|
||
|
||
// LoadManifest читает и валидирует manifest.json.
|
||
func LoadManifest(path string) (*Manifest, error) {
|
||
data, err := os.ReadFile(path)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("читаю manifest.json: %w", err)
|
||
}
|
||
var m Manifest
|
||
if err := json.Unmarshal(data, &m); err != nil {
|
||
return nil, fmt.Errorf("парсинг manifest.json: %w", err)
|
||
}
|
||
if m.Name == "" || m.Version == "" {
|
||
return nil, fmt.Errorf("manifest.json: name и version обязательны")
|
||
}
|
||
if len(m.Architectures) == 0 {
|
||
return nil, fmt.Errorf("manifest.json: architectures не может быть пустым")
|
||
}
|
||
return &m, nil
|
||
}
|
||
|
||
// binaryPath — путь к локальному (control node) бинарнику модуля для
|
||
// конкретной архитектуры. Соглашение об именовании: <moduleDir>/<name>-<goos>-<goarch>,
|
||
// например modules.d/hello/hello-linux-amd64 для "linux/amd64".
|
||
func binaryPath(moduleDir, name, arch string) string {
|
||
goos, goarch := splitArch(arch)
|
||
return filepath.Join(moduleDir, fmt.Sprintf("%s-%s-%s", name, goos, goarch))
|
||
}
|
||
|
||
func splitArch(arch string) (goos, goarch string) {
|
||
for i := 0; i < len(arch); i++ {
|
||
if arch[i] == '/' {
|
||
return arch[:i], arch[i+1:]
|
||
}
|
||
}
|
||
return "linux", arch
|
||
}
|