mirror of
https://codeberg.org/scip/esctl.git
synced 2026-08-24 13:14:18 +02:00
175 lines
3.6 KiB
Go
175 lines
3.6 KiB
Go
/*
|
|
Copyright © 2026 Thomas von Dein
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package cfg
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
type Automator struct {
|
|
IsReachable bool
|
|
Error error
|
|
Env []string
|
|
Cluster *Cluster
|
|
|
|
// all bash commands, .name must succeed first
|
|
Name string `yaml:"name"`
|
|
User string `yaml:"user"`
|
|
Pass string `yaml:"pass"`
|
|
Uri string `yaml:"uri"`
|
|
}
|
|
|
|
type AutomatorRunner struct {
|
|
Output string
|
|
Error error
|
|
}
|
|
|
|
func NewAutoEnv() []string {
|
|
return []string{
|
|
"PATH=" + os.Getenv("PATH"),
|
|
"HOME=" + os.Getenv("HOME"),
|
|
"SHELL=" + os.Getenv("SHELL"),
|
|
"KUBECONFIG=" + os.Getenv("KUBECONFIG"),
|
|
}
|
|
}
|
|
|
|
func NewAutomator() Automator {
|
|
autocfg := filepath.Join([]string{os.Getenv("HOME"), ".config", "esctl", "automate.yaml"}...)
|
|
|
|
auto := Automator{Env: NewAutoEnv()}
|
|
|
|
if !fileExists(autocfg) {
|
|
return auto
|
|
}
|
|
|
|
data, err := os.ReadFile(autocfg)
|
|
if err != nil {
|
|
auto.Error = fmt.Errorf("failed to read config file: %w", err)
|
|
return auto
|
|
}
|
|
|
|
err = yaml.Unmarshal(data, &auto)
|
|
if err != nil {
|
|
auto.Error = fmt.Errorf("failed to unmarshal config file: %w", err)
|
|
return auto
|
|
}
|
|
|
|
hasname := execute(auto.Name, auto.Env)
|
|
if hasname.Error != nil {
|
|
auto.Error = hasname.Error
|
|
return auto
|
|
}
|
|
auto.Name = hasname.Output
|
|
|
|
hasuser := execute(auto.User, auto.Env)
|
|
if hasuser.Error != nil {
|
|
auto.Error = hasuser.Error
|
|
return auto
|
|
}
|
|
auto.User = hasuser.Output
|
|
|
|
haspass := execute(auto.Pass, auto.Env)
|
|
if haspass.Error != nil {
|
|
auto.Error = haspass.Error
|
|
return auto
|
|
}
|
|
auto.Pass = haspass.Output
|
|
|
|
hasuri := execute(auto.Uri, auto.Env)
|
|
if hasuri.Error != nil {
|
|
auto.Error = hasuri.Error
|
|
return auto
|
|
}
|
|
auto.Uri = hasuri.Output
|
|
|
|
auto.IsReachable = true
|
|
|
|
auto.Cluster = &Cluster{
|
|
Name: auto.Name,
|
|
Uri: auto.Uri,
|
|
User: auto.User,
|
|
Pass: auto.Pass,
|
|
}
|
|
|
|
return auto
|
|
}
|
|
|
|
// FIXME: execute auto.Exec, if defined, in a go routine and let it run forever, might be a tunnel
|
|
func (auto *Automator) Exec() {}
|
|
|
|
// FIXME: cache automator results, only check auto.Name and if it matches the cache use those vars, but run auto.Exec anyway
|
|
func (auto *Automator) Cache() {}
|
|
|
|
func execute(code string, env []string) *AutomatorRunner {
|
|
timeoutCtx, cancel := context.WithTimeout(context.Background(),
|
|
time.Duration(10)*time.Second)
|
|
defer cancel()
|
|
|
|
var cmd *exec.Cmd
|
|
|
|
// pipe code into bash
|
|
cmd = exec.CommandContext(timeoutCtx, "bash")
|
|
cmd.Stdin = strings.NewReader(code)
|
|
|
|
cmd.Env = env
|
|
errbuf := &bytes.Buffer{}
|
|
cmd.Stderr = errbuf
|
|
|
|
done := make(chan bool)
|
|
out := AutomatorRunner{}
|
|
|
|
go func() {
|
|
output, err := cmd.Output()
|
|
|
|
out.Output = strings.TrimSpace(string(output))
|
|
|
|
switch {
|
|
case err != nil:
|
|
out.Error = err
|
|
case errbuf.Len() > 0:
|
|
out.Error = fmt.Errorf(errbuf.String())
|
|
case timeoutCtx.Err() == context.DeadlineExceeded:
|
|
out.Error = errors.New("timed out")
|
|
}
|
|
|
|
slog.Debug("executed automator",
|
|
"code", code,
|
|
"output", out.Output,
|
|
"error", out.Error)
|
|
|
|
done <- true
|
|
}()
|
|
|
|
for {
|
|
select {
|
|
case <-done:
|
|
return &out
|
|
}
|
|
}
|
|
}
|