mirror of
https://codeberg.org/scip/esctl.git
synced 2026-08-24 23:34:18 +02:00
Compare commits
1 Commits
feature/es
...
feature/au
| Author | SHA1 | Date | |
|---|---|---|---|
| 489074da01 |
174
pkg/cfg/automate.go
Normal file
174
pkg/cfg/automate.go
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -223,8 +223,7 @@ func (cluster *Cluster) IsReachable() (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conf *Config) SetupES() error {
|
func (conf *Config) SetupElasticClient(name string, cluster *Cluster) error {
|
||||||
for name, cluster := range conf.Clusters {
|
|
||||||
cluster.Name = name
|
cluster.Name = name
|
||||||
cluster.DebugHTTP = conf.DebugHTTP
|
cluster.DebugHTTP = conf.DebugHTTP
|
||||||
|
|
||||||
@@ -244,6 +243,15 @@ func (conf *Config) SetupES() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cluster.SetClient(es)
|
cluster.SetClient(es)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conf *Config) SetupElasticClients() error {
|
||||||
|
for name, cluster := range conf.Clusters {
|
||||||
|
if err := conf.SetupElasticClient(name, cluster); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version string = `v0.0.24`
|
Version string = `v0.0.25`
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -133,7 +133,7 @@ func (conf *Config) Init() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := conf.SetupES(); err != nil {
|
if err := conf.SetupElasticClients(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,6 +153,9 @@ func (conf *Config) Init() error {
|
|||||||
conf.DefaultCluster.Default = true
|
conf.DefaultCluster.Default = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// load auto config, if any
|
||||||
|
auto := NewAutomator()
|
||||||
|
|
||||||
// we need to determine ourselfes
|
// we need to determine ourselfes
|
||||||
if len(conf.Clusters) == 1 {
|
if len(conf.Clusters) == 1 {
|
||||||
// ok, just one cluster configured, use this, of course
|
// ok, just one cluster configured, use this, of course
|
||||||
@@ -161,6 +164,14 @@ func (conf *Config) Init() error {
|
|||||||
conf.CurrentCluster = name
|
conf.CurrentCluster = name
|
||||||
conf.DefaultCluster.Default = true
|
conf.DefaultCluster.Default = true
|
||||||
}
|
}
|
||||||
|
} else if auto.Error == nil && auto.IsReachable {
|
||||||
|
// use auto conf
|
||||||
|
if err := conf.SetupElasticClient(auto.Name, auto.Cluster); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.DefaultCluster = auto.Cluster
|
||||||
|
conf.CurrentCluster = auto.Name
|
||||||
} else {
|
} else {
|
||||||
// multiple ones exists, look if one is set as default
|
// multiple ones exists, look if one is set as default
|
||||||
for name, cluster := range conf.Clusters {
|
for name, cluster := range conf.Clusters {
|
||||||
|
|||||||
Reference in New Issue
Block a user