Files
HellreigN/backend/internal/ansible/executor.go
T
d3m0k1d b516a54c17
ci-agent / build (push) Failing after 2m42s
fixsess and logic for web ide
2026-04-04 23:56:28 +03:00

150 lines
3.3 KiB
Go

package ansible
import (
"bytes"
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
"sync"
)
// Executor handles running Ansible playbooks
type Executor struct {
workDir string
grpcServerHost string
grpcServerPort string
backendURL string
}
// ExecutorConfig holds configuration for the Executor
type ExecutorConfig struct {
WorkDir string
GRPCServerHost string
GRPCServerPort string
BackendURL string
}
// NewExecutor creates a new Ansible executor
func NewExecutor(cfg ExecutorConfig) *Executor {
return &Executor{
workDir: cfg.WorkDir,
grpcServerHost: cfg.GRPCServerHost,
grpcServerPort: cfg.GRPCServerPort,
backendURL: cfg.BackendURL,
}
}
// DeployResult holds the result of a deployment
type DeployResult struct {
Host string
Success bool
Stdout string
Stderr string
Err error
}
// WorkDir returns the work directory path
func (e *Executor) WorkDir() string {
return e.workDir
}
// GRPCURL returns the gRPC server URL (host:port)
func (e *Executor) GRPCURL() string {
return e.grpcServerHost + ":" + e.grpcServerPort
}
// Deploy runs Ansible playbook for the given inventory
func (e *Executor) Deploy(
ctx context.Context,
inventoryPath string,
deployType string,
) ([]DeployResult, error) {
playbookName := "binary_deploy.yml"
if deployType == "docker" {
playbookName = "docker_deploy.yml"
}
playbookPath := filepath.Join(e.workDir, playbookName)
cmd := exec.CommandContext(ctx, "ansible-playbook",
"-i", inventoryPath,
"-e", fmt.Sprintf("backend_url=%s", e.backendURL),
"-e", fmt.Sprintf("grpc_url=%s", e.grpcServerHost+":"+e.grpcServerPort),
playbookPath,
)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
runErr := cmd.Run()
// Parse results per host (simplified - returns single result for all)
return []DeployResult{
{
Host: "all",
Success: runErr == nil,
Stdout: stdout.String(),
Stderr: stderr.String(),
Err: runErr,
},
}, nil
}
// DeployParallel runs Ansible playbook for multiple inventories in parallel
func (e *Executor) DeployParallel(
ctx context.Context,
inventoryPaths []string,
deployType string,
) (map[string][]DeployResult, error) {
var wg sync.WaitGroup
results := make(map[string][]DeployResult)
errCh := make(chan error, len(inventoryPaths))
for _, path := range inventoryPaths {
wg.Add(1)
go func(p string) {
defer wg.Done()
res, err := e.Deploy(ctx, p, deployType)
if err != nil {
errCh <- err
}
results[p] = res
}(path)
}
wg.Wait()
close(errCh)
// Collect errors
var errs []error
for err := range errCh {
errs = append(errs, err)
}
if len(errs) > 0 {
return results, fmt.Errorf("some deployments failed: %v", errs)
}
return results, nil
}
// WritePlaybook writes a playbook to the work directory
func (e *Executor) WritePlaybook(name string, content string) error {
path := filepath.Join(e.workDir, name)
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
return err
}
return os.WriteFile(path, []byte(content), 0644)
}
// WriteAllPlaybooks writes all playbooks to the work directory
func (e *Executor) WriteAllPlaybooks() error {
if err := e.WritePlaybook("binary_deploy.yml", BinaryDeployPlaybook); err != nil {
return err
}
return e.WritePlaybook("docker_deploy.yml", DockerDeployPlaybook)
}