update: Added Longhorn installation process and updated memory allocation for VMs
update: Added 'git' and 'vagrant' to required tools in pre-flight checks fix: configured k3s install to use internal nic for flanel network update: Added Longhorn installation process and updated memory allocation for VMs update: Added 'git' and 'vagrant' to required tools in pre-flight checks fix: configured k3s install to use internal nic for flanel network fix: corrected JSON formatting for config json update: reduce VM memory allocation to 2GB, add Longhorn installation scripts and prerequisites, and implement checks for existing pods fix: merge issues fix: merge issues update: Added Longhorn installation process and updated memory allocation for VMs update: Added 'git' and 'vagrant' to required tools in pre-flight checks fix: configured k3s install to use internal nic for flanel network update: Added Longhorn installation process and updated memory allocation for VMs update: Added 'git' and 'vagrant' to required tools in pre-flight checks fix: configured k3s install to use internal nic for flanel network fix: corrected JSON formatting for config json update: reduce VM memory allocation to 2GB, add Longhorn installation scripts and prerequisites, and implement checks for existing pods update: improve error logging in RunJsonDeployment and RunCommand functions update: add jq installation to provision script update: add version flag bump version fix: improve error messages for config file reading feat: add Windows gitbash installation support and improve binary download process clean up tmp code fix: increase timeout for some slower windows clients feat: add Ingress and Service configurations for nginx deployment, and implement MetalLB and Traeik installation scripts refactor: remove obsolete Traefik installation script feat: add environment checks and configurations for Vagrant setup, including dnsmasq MetalLB and ingress feat: add deployment and installation scripts for infmon-cli, including Kubernetes configurations feat: refactor customer project creation and add success/failure job scripts refactor: rename customer references to project in configuration and application logic feat: enhance JSON deployment handling with retry logic and command execution improvements feat: enhance RunJsonDeployment with error handling and retry logic; add tests for configuration reading feat: add automatic creation of base and config JSON files from examples if they do not exist refactor: remove database package and related functionality; update app state initialization and error handling refactor: update deployment handling to use ProjectConfig; improve error messages and logging feat: enhance RunJsonDeployment retry logic with configurable delay; improve logging for retries feat: implement LoadConfigs function for improved configuration loading; add logger setup refactor: remove unused fields from BaseConfig and ProjectConfig structs for cleaner configuration management refactor: clean up tests by removing obsolete functions and simplifying test cases chore: update version to v0.0.5 in install script feat: implement default configuration creation for BaseConfig and ProjectConfig; enhance validation logic fix: enhance configuration parsing and loading; streamline flag handling and error reporting refactor: remove obsolete configuration download logic from installation script
This commit is contained in:
parent
d839fd5687
commit
11b1f1b637
61 changed files with 1573 additions and 761 deletions
218
app/app.go
218
app/app.go
|
|
@ -1,22 +1,21 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
"headshed/infctl-cli/config"
|
||||
"headshed/infctl-cli/database"
|
||||
)
|
||||
|
||||
type AppState struct {
|
||||
Config config.BaseConfig
|
||||
Customer config.CustomerConfig
|
||||
DB *sql.DB
|
||||
Config config.BaseConfig
|
||||
Project config.ProjectConfig
|
||||
}
|
||||
|
||||
type PipelineStep struct {
|
||||
|
|
@ -62,27 +61,31 @@ func (app *AppState) ToDoDeployment() []PipelineStep {
|
|||
return []PipelineStep{}
|
||||
}
|
||||
|
||||
func (app *AppState) RunJsonDeployment() []PipelineStep {
|
||||
// func (app *AppState) RunJsonDeployment() []PipelineStep {
|
||||
func (app *AppState) RunJsonDeployment() error {
|
||||
|
||||
jsonFile := app.Config.DeploymentFile
|
||||
jsonFile := app.Project.DeploymentFile
|
||||
if jsonFile == "" {
|
||||
log.Fatal("no config specified with --deployment-file=<path_to_config_file>")
|
||||
return fmt.Errorf("no config specified with [-f|-deployment-file]=<path_to_config_file> => for all options see help with -h")
|
||||
}
|
||||
|
||||
file, err := os.Open(jsonFile)
|
||||
if err != nil {
|
||||
slog.Error(fmt.Sprintf("Failed to open JSON file: %s", err))
|
||||
return fmt.Errorf("failed to open JSON file: %w", err)
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
// fmt.Printf("jsonFile is : %s\n", jsonFile)
|
||||
slog.Info(fmt.Sprintf("Using jsonFile: %s", jsonFile))
|
||||
steps, err := parseStepsFromJSON(jsonFile)
|
||||
if err != nil {
|
||||
slog.Error(fmt.Sprintf("Failed to parse JSON file: %s", err))
|
||||
return fmt.Errorf("failed to parse JSON file: %w", err)
|
||||
}
|
||||
|
||||
for _, step := range steps {
|
||||
slog.Info(fmt.Sprintf("🔄 Running step: %s", step.Name))
|
||||
slog.Info(fmt.Sprintf("run json deployment => 🔄 %s", step.Name))
|
||||
function, exists := functionMap[step.Function]
|
||||
if !exists {
|
||||
slog.Error(fmt.Sprintf("Unknown function: %s", step.Function))
|
||||
|
|
@ -90,136 +93,121 @@ func (app *AppState) RunJsonDeployment() []PipelineStep {
|
|||
}
|
||||
|
||||
err := function(step.Params)
|
||||
|
||||
if err != nil {
|
||||
slog.Error(fmt.Sprintf("❌ Step failed: %s, error: %v", step.Name, err))
|
||||
var innerErr error
|
||||
if step.RetryCount > 0 {
|
||||
for i := 0; i < step.RetryCount; i++ {
|
||||
|
||||
sleep := app.Config.RetryDelaySenconds
|
||||
|
||||
slog.Info(fmt.Sprintf("Retrying step: %s (attempt %d/%d) after waiting for %d seconds...", step.Name, i+1, step.RetryCount, sleep))
|
||||
time.Sleep(time.Duration(sleep) * time.Second)
|
||||
|
||||
if innerErr = function(step.Params); innerErr == nil {
|
||||
slog.Info(fmt.Sprintf("✅ Step completed: %s\n", step.Name))
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
if innerErr != nil {
|
||||
if !step.ShouldAbort {
|
||||
slog.Info(fmt.Sprintf("Not going to abort, step: %s", step.Name))
|
||||
} else {
|
||||
return fmt.Errorf("critical failure at step: %s", step.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if step.ShouldAbort {
|
||||
log.Fatalf("🚨Critical failure at step: %s", step.Name)
|
||||
return fmt.Errorf("critical failure at step: %s", step.Name)
|
||||
}
|
||||
} else {
|
||||
slog.Info(fmt.Sprintf("✅ Step completed: %s", step.Name))
|
||||
}
|
||||
}
|
||||
return steps
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *AppState) getPipeline() []PipelineStep {
|
||||
|
||||
switch app.Config.DeploymentType {
|
||||
|
||||
func (app *AppState) getPipeline() error {
|
||||
switch app.Project.DeploymentMode {
|
||||
case "api":
|
||||
return app.ToDoDeployment()
|
||||
|
||||
return fmt.Errorf("api mode is not yet implemented")
|
||||
case "json":
|
||||
return app.RunJsonDeployment()
|
||||
|
||||
default:
|
||||
return app.RunJsonDeployment()
|
||||
// return app.RunJsonDeployment()
|
||||
return fmt.Errorf("unknown mode: %s", app.Project.DeploymentMode)
|
||||
}
|
||||
}
|
||||
|
||||
func NewAppState(cust config.CustomerConfig, config config.BaseConfig, dbPath string) (*AppState, error) {
|
||||
db, err := database.NewDatabase(dbPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func NewAppState(cust config.ProjectConfig, config config.BaseConfig) (*AppState, error) {
|
||||
return &AppState{
|
||||
Config: config,
|
||||
Customer: cust,
|
||||
DB: db,
|
||||
Config: config,
|
||||
Project: cust,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (app *AppState) runPipeline(steps []PipelineStep) error {
|
||||
for _, step := range steps {
|
||||
slog.Info(fmt.Sprintf("🔄 Running step: %s\n", step.Name))
|
||||
func RunCommand(command string) error {
|
||||
slog.Debug(fmt.Sprintf("🐞 Running command: %s", command))
|
||||
cmd := exec.Command("sh", "-c", command)
|
||||
|
||||
// Look up the function in the functionMap
|
||||
function, exists := functionMap[step.Function]
|
||||
if !exists {
|
||||
slog.Error(fmt.Sprintf("❌ Unknown function: %s", step.Function))
|
||||
if step.ShouldAbort {
|
||||
return fmt.Errorf("🚨critical failure: unknown function %s", step.Function)
|
||||
}
|
||||
continue
|
||||
}
|
||||
var stdout, stderr bytes.Buffer
|
||||
|
||||
// Execute the function with the provided parameters
|
||||
err := function(step.Params)
|
||||
if err != nil {
|
||||
slog.Error(fmt.Sprintf("❌ Step failed: %s, error: %v", step.Name, err))
|
||||
|
||||
// Retry logic
|
||||
if step.RetryCount > 0 {
|
||||
for i := 0; i < step.RetryCount; i++ {
|
||||
slog.Info("Waiting for 20 seconds before retrying...")
|
||||
time.Sleep(20 * time.Second)
|
||||
if innerErr := function(step.Params); innerErr == nil {
|
||||
slog.Info(fmt.Sprintf("✅ Step completed: %s\n", step.Name))
|
||||
err = nil
|
||||
break
|
||||
} else {
|
||||
err = innerErr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle failure after retries
|
||||
if err != nil {
|
||||
if step.ShouldAbort {
|
||||
return fmt.Errorf("🚨critical failure at step: %s", step.Name)
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info(fmt.Sprintf("✅ Step completed: %s\n", step.Name))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *AppState) SetUpNewCustomer() error {
|
||||
|
||||
/*
|
||||
| --------------------------
|
||||
| main pipeline
|
||||
| --------------------------
|
||||
*/
|
||||
|
||||
steps := app.getPipeline()
|
||||
app.runPipeline(steps)
|
||||
slog.Info(fmt.Sprintln("🎉 Pipeline setup complete!"))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *AppState) CreatePipeline() error {
|
||||
isNew, err := database.CheckProjectName(app.DB, app.Customer.Project)
|
||||
// Get pipes for real-time reading
|
||||
stdoutPipe, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check project name: %w", err)
|
||||
return fmt.Errorf("failed to create stdout pipe: %w", err)
|
||||
}
|
||||
|
||||
if isNew {
|
||||
|
||||
port, err := database.GetNextPortNumber(app.DB)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get next port number: %w", err)
|
||||
}
|
||||
err = database.AddProjectName(app.DB, app.Customer.Project, port)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add project name: %w", err)
|
||||
}
|
||||
slog.Info(fmt.Sprintln("Project name added:", app.Customer.Project))
|
||||
fmt.Printf("Port number assigned: %d\n", port)
|
||||
app.Config.Port = port
|
||||
} else {
|
||||
slog.Info(fmt.Sprintln("Project name already exists:", app.Customer.Project))
|
||||
}
|
||||
|
||||
err = app.SetUpNewCustomer()
|
||||
stderrPipe, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set up new customer: %w", err)
|
||||
return fmt.Errorf("failed to create stderr pipe: %w", err)
|
||||
}
|
||||
|
||||
// Start the command
|
||||
if err := cmd.Start(); err != nil {
|
||||
return fmt.Errorf("failed to start command: %w", err)
|
||||
}
|
||||
|
||||
// Read stdout line by line and log through slog
|
||||
go func() {
|
||||
scanner := bufio.NewScanner(stdoutPipe)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
stdout.WriteString(line + "\n")
|
||||
slog.Info(line)
|
||||
}
|
||||
}()
|
||||
|
||||
// Read stderr line by line and log through slog
|
||||
go func() {
|
||||
scanner := bufio.NewScanner(stderrPipe)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
stderr.WriteString(line + "\n")
|
||||
slog.Info(line)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for command to complete
|
||||
err = cmd.Wait()
|
||||
if err != nil {
|
||||
slog.Error(fmt.Sprintf("❌ Command failed with error: %v", err))
|
||||
slog.Debug(fmt.Sprintf("🐞 Stdout: %s\n", stdout.String()))
|
||||
slog.Debug(fmt.Sprintf("🐞 Stderr: %s\n", stderr.String()))
|
||||
return fmt.Errorf("failed to run script command: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *AppState) SetUpNewProject() error {
|
||||
return app.getPipeline()
|
||||
}
|
||||
|
||||
func (app *AppState) CreateProjectAndRunPipeline() error {
|
||||
err := app.SetUpNewProject()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Pipeline error: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue