Starting refactor to improve how ghetto the object handling was

This commit is contained in:
VetheonGames 2024-03-28 15:45:20 -06:00
parent a63d615ad2
commit b6ad826204
9 changed files with 203 additions and 99 deletions

View File

@ -1,37 +1,45 @@
package cmd
import (
"context"
"reflect"
"strings"
"strconv"
"fmt"
"os"
"os/exec"
"pixelridgesoftworks.com/BackGo/config"
"reflect"
"strconv"
"strings"
"git.pixelridgesoftworks.com/BackGo/config"
)
const configFilePath = "/etc/PixelRidge/BackGo/config.json"
// OpenConfigInNano opens the configuration file in the nano editor.
func OpenConfigInNano() error {
cmd := exec.Command("nano", configFilePath)
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
err := cmd.Run()
if err != nil {
return fmt.Errorf("error opening config in nano: %v", err)
}
return nil
configFilePath := config.GetConfigFilePath()
cmd := exec.Command("nano", configFilePath)
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
err := cmd.Run()
if err != nil {
return fmt.Errorf("error opening config in nano: %v", err)
}
return nil
}
// EditConfigOption allows editing a specific configuration option from the CLI
func EditConfigOption(optionName, newValue string) error {
// Load the current configuration from file
func EditConfigOption(ctx context.Context, optionName, newValue string) error {
cfg, err := config.LoadConfigFromFile()
if err != nil {
return fmt.Errorf("loading config: %v", err)
}
// Use reflection to find and set the field in the Config struct
if err := setConfigOption(cfg, optionName, newValue); err != nil {
return err
}
if err := config.SaveConfigToFile(cfg); err != nil {
return fmt.Errorf("saving config: %v", err)
}
return nil
}
func setConfigOption(cfg *config.Config, optionName, newValue string) error {
rConfig := reflect.ValueOf(cfg).Elem()
field := rConfig.FieldByNameFunc(func(s string) bool {
return strings.EqualFold(s, optionName)
@ -41,12 +49,10 @@ func EditConfigOption(optionName, newValue string) error {
return fmt.Errorf("unknown configuration option: %s", optionName)
}
// Ensure the field can be set
if !field.CanSet() {
return fmt.Errorf("cannot set configuration option: %s", optionName)
}
// Convert and set the field value based on its kind
switch field.Kind() {
case reflect.String:
field.SetString(newValue)
@ -56,21 +62,15 @@ func EditConfigOption(optionName, newValue string) error {
return fmt.Errorf("invalid value for %s: %v", optionName, err)
}
field.SetBool(boolVal)
case reflect.Int:
intVal, err := strconv.Atoi(newValue)
case reflect.Int, reflect.Int64:
intVal, err := strconv.ParseInt(newValue, 10, 64)
if err != nil {
return fmt.Errorf("invalid value for %s: %v", optionName, err)
}
// Additional checks can be implemented here for specific int fields like LogLevel
field.SetInt(int64(intVal))
field.SetInt(intVal)
default:
return fmt.Errorf("unsupported configuration type for: %s", optionName)
}
// Save the updated configuration back to the file
if err := config.SaveConfigToFile(cfg); err != nil {
return fmt.Errorf("saving config: %v", err)
}
return nil
}

View File

@ -5,43 +5,38 @@ import (
"encoding/json"
"fmt"
"net/http"
"pixelridgesoftworks.com/BackGo/pkg/backup"
"git.pixelridgesoftworks.com/BackGo/pkg/backup"
)
// InterfaceCLI manages commands related to node interface operations
type InterfaceCLI struct {
NodeAddress string
DBManager *backup.DBManager // Assuming DBManager is part of the backup package
DBManager *backup.DBManager
}
// NewInterfaceCLI creates a new InterfaceCLI instance
func NewInterfaceCLI(nodeAddress string, dbManager *backup.DBManager) *InterfaceCLI {
if dbManager == nil {
panic("DBManager cannot be nil")
}
return &InterfaceCLI{
NodeAddress: nodeAddress,
DBManager: dbManager,
}
}
// TriggerCommand sends a trigger command to a node
func (cli *InterfaceCLI) TriggerCommand(action, value string) error {
return cli.sendCommandToNode("trigger", action, value)
return cli.sendCommandToNode("trigger", value)
}
// GetInfo sends a get_info command to a node
func (cli *InterfaceCLI) GetInfo(value string) error {
return cli.sendCommandToNode("get_info", cli.NodeAddress, value)
return cli.sendCommandToNode("get_info", value)
}
// AddNode handles adding a new node on the master node
func (cli *InterfaceCLI) AddNode(hostname, token string) error {
// Verify the hostname resolves to an expected IP before adding
// This might involve additional logic to determine what the expected IP is
expectedIP := "" // Placeholder for expected IP determination logic
expectedIP := "" // Implement IP determination logic here
if !cli.DBManager.VerifyHostname(hostname, expectedIP) {
return fmt.Errorf("hostname %s does not resolve to the expected IP %s", hostname, expectedIP)
}
// Create a token for the new node
if err := cli.DBManager.CreateToken(hostname, token); err != nil {
return fmt.Errorf("failed to create token for hostname %s: %v", hostname, err)
}
@ -50,16 +45,14 @@ func (cli *InterfaceCLI) AddNode(hostname, token string) error {
return nil
}
// GenCert generates a certificate for a node
func (cli *InterfaceCLI) GenCert(nodeName string) error {
return cli.sendCommandToNode("gencert", nodeName, "")
return cli.sendCommandToNode("gencert", nodeName)
}
// sendCommandToNode sends a command to the specified node
func (cli *InterfaceCLI) sendCommandToNode(action, node, value string) error {
func (cli *InterfaceCLI) sendCommandToNode(action, value string) error {
payload := backup.CommandPayload{
Action: action,
Node: node,
Node: cli.NodeAddress,
Value: value,
}
payloadBytes, err := json.Marshal(payload)
@ -69,10 +62,10 @@ func (cli *InterfaceCLI) sendCommandToNode(action, node, value string) error {
resp, err := http.Post(fmt.Sprintf("http://%s/api/command", cli.NodeAddress), "application/json", bytes.NewReader(payloadBytes))
if err != nil {
return fmt.Errorf("error sending command to node %s: %v", node, err)
return fmt.Errorf("error sending command to node %s: %v", cli.NodeAddress, err)
}
defer resp.Body.Close()
fmt.Printf("Command '%s' sent to node %s successfully\n", action, node)
fmt.Printf("Command '%s' sent to node %s successfully\n", action, cli.NodeAddress)
return nil
}

View File

@ -1,10 +1,11 @@
package cmd
import (
"context"
"flag"
"fmt"
"pixelridgesoftworks.com/BackGo/pkg/backup"
"pixelridgesoftworks.com/BackGo/config"
"git.pixelridgesoftworks.com/BackGo/pkg/backup"
"git.pixelridgesoftworks.com/BackGo/pkg/logger"
)
type Command struct {
@ -12,18 +13,12 @@ type Command struct {
Description string
FlagSet *flag.FlagSet
SubCommands map[string]*Command
Execute func(cmd *Command, args []string)
Execute func(ctx context.Context, cmd *Command, args []string)
}
var appConfig = config.LoadConfig()
var dbManager *backup.DBManager
var RootCmd = NewCommand("backup", "Main entry point for backup utility", nil)
func init() {
// Assuming NewDBManager is correctly implemented in the backup package and accepts *config.Config
dbManager = backup.NewDBManager(appConfig)
remoteCmd := NewCommand("interface", "Remote node management", nil)
triggerCmd := NewCommand("trigger", "Trigger an action on a node", handleTrigger)
@ -39,31 +34,48 @@ func init() {
RootCmd.AddSubCommand(remoteCmd)
}
func handleTrigger(cmd *Command, args []string) {
func handleTrigger(ctx context.Context, cmd *Command, args []string) {
log := ctx.Value("logger").(*logger.Logger)
dbManager := ctx.Value("dbManager").(*backup.DBManager)
nodeFlag := cmd.FlagSet.String("node", "", "Specify the node hostname")
actionFlag := cmd.FlagSet.String("action", "", "Specify the action to trigger")
cmd.FlagSet.Parse(args)
if *nodeFlag == "" || *actionFlag == "" {
fmt.Println("Both node hostname and action are required")
log.Println("Both node hostname and action are required")
return
}
// Since backup.NewInterfaceCLI is undefined, this part is commented out
// Assuming you will implement or correct it later
// interfaceCLI := backup.NewInterfaceCLI(*nodeFlag, dbManager)
// if err := interfaceCLI.TriggerCommand(*actionFlag, ""); err != nil {
// fmt.Printf("Error triggering command on node %s: %v\n", *nodeFlag, err)
// return
// }
// fmt.Printf("Command '%s' triggered successfully on node %s\n", *actionFlag, *nodeFlag)
cli := NewInterfaceCLI(*nodeFlag, dbManager)
if err := cli.TriggerCommand(*actionFlag, ""); err != nil {
log.Printf("Error triggering command on node %s: %v\n", *nodeFlag, err)
} else {
log.Printf("Command '%s' triggered successfully on node %s\n", *actionFlag, *nodeFlag)
}
}
func handleGetInfo(cmd *Command, args []string) {
// Implementation similar to handleTrigger, tailored for get_info
func handleGetInfo(ctx context.Context, cmd *Command, args []string) {
log := ctx.Value("logger").(*logger.Logger)
nodeFlag := cmd.FlagSet.String("node", "", "Specify the node address")
valueFlag := cmd.FlagSet.String("value", "", "Specify the value for get_info")
cmd.FlagSet.Parse(args)
if *nodeFlag == "" {
log.Println("Node address is required")
return
}
dbManager := ctx.Value("dbManager").(*backup.DBManager)
cli := NewInterfaceCLI(*nodeFlag, dbManager)
if err := cli.GetInfo(*valueFlag); err != nil {
log.Printf("Error getting info from node %s: %v\n", *nodeFlag, err)
} else {
log.Printf("Successfully got info from node %s\n", *nodeFlag)
}
}
func handleAddNode(cmd *Command, args []string) {
func handleAddNode(ctx context.Context, cmd *Command, args []string) {
dbManager := ctx.Value("dbManager").(*backup.DBManager)
nodeName := cmd.FlagSet.String("node", "", "Specify the node name")
cmd.FlagSet.Parse(args)
@ -72,19 +84,34 @@ func handleAddNode(cmd *Command, args []string) {
return
}
token := "some_generated_token" // Replace with actual token generation logic
token := "some_generated_token"
if err := dbManager.CreateToken(*nodeName, token); err != nil {
fmt.Printf("Error adding new node %s: %v\n", *nodeName, err)
} else {
fmt.Printf("New node %s added successfully with token %s\n", *nodeName, token)
}
}
func handleGenCert(ctx context.Context, cmd *Command, args []string) {
log := ctx.Value("logger").(*logger.Logger)
dbManager := ctx.Value("dbManager").(*backup.DBManager)
nodeNameFlag := cmd.FlagSet.String("node", "", "Specify the node name for which to generate a certificate")
cmd.FlagSet.Parse(args)
if *nodeNameFlag == "" {
log.Println("Node name is required")
return
}
fmt.Printf("New node %s added successfully with token %s\n", *nodeName, token)
cli := NewInterfaceCLI(*nodeNameFlag, dbManager)
if err := cli.GenCert(*nodeNameFlag); err != nil {
log.Printf("Error generating certificate for node %s: %v\n", *nodeNameFlag, err)
} else {
log.Printf("Certificate generated successfully for node %s\n", *nodeNameFlag)
}
}
func handleGenCert(cmd *Command, args []string) {
// Implementation for generating a certificate for a node
}
func NewCommand(name, description string, execute func(cmd *Command, args []string)) *Command {
func NewCommand(name, description string, execute func(ctx context.Context, cmd *Command, args []string)) *Command {
return &Command{
Name: name,
Description: description,
@ -103,7 +130,7 @@ func (c *Command) FindSubCommand(name string) (*Command, bool) {
return subCmd, found
}
func ExecuteCommand(rootCmd *Command, args []string) error {
func ExecuteCommandWithContext(ctx context.Context, rootCmd *Command, args []string) error {
if len(args) < 1 {
fmt.Println("No command provided")
return nil
@ -118,17 +145,11 @@ func ExecuteCommand(rootCmd *Command, args []string) error {
return nil
}
if len(subArgs) > 0 {
subCmdName := subArgs[0]
subCmd, found := cmd.FindSubCommand(subCmdName)
if found {
subCmd.FlagSet.Parse(subArgs[1:])
subCmd.Execute(subCmd, subCmd.FlagSet.Args())
return nil
}
if cmd.Execute != nil {
cmd.Execute(ctx, cmd, subArgs)
} else {
fmt.Println("No execute function provided for command:", cmdName)
}
cmd.FlagSet.Parse(subArgs)
cmd.Execute(cmd, cmd.FlagSet.Args())
return nil
}

View File

@ -185,3 +185,8 @@ func SaveConfigToFile(config *Config) error {
func ReloadConfig() {
fmt.Println("Configuration reloaded")
}
// GetConfigFilePath returns the path to the configuration file.
func GetConfigFilePath() string {
return configFilePath
}

4
go.mod
View File

@ -1,9 +1,10 @@
module pixelridgesoftworks.com/BackGo
module git.pixelridgesoftworks.com/BackGo
go 1.22.0
require (
github.com/aws/aws-sdk-go-v2/config v1.27.9
github.com/aws/aws-sdk-go-v2/credentials v1.17.9
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.13
github.com/aws/aws-sdk-go-v2/service/s3 v1.53.0
github.com/go-sql-driver/mysql v1.8.1
@ -15,7 +16,6 @@ require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.26.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.9 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 // indirect

54
main.go
View File

@ -3,13 +3,59 @@ package main
import (
"fmt"
"os"
"pixelridgesoftworks.com/BackGo/cmd"
"context"
"git.pixelridgesoftworks.com/BackGo/cmd"
backGoConfig "git.pixelridgesoftworks.com/BackGo/config"
"git.pixelridgesoftworks.com/BackGo/pkg/backup"
"git.pixelridgesoftworks.com/BackGo/pkg/logger"
)
func main() {
// Correctly pass RootCmd as it's already a *Command
if err := cmd.ExecuteCommand(cmd.RootCmd, os.Args[1:]); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
// Load configuration
cfg := backGoConfig.LoadConfig()
// Initialize Logger
log := logger.NewLogger()
// Set the logger level based on the configuration
log.SetLevel(mapConfigLogLevelToLoggerLogLevel(cfg.LogLevel))
// Adjust logger output based on configuration or environment variables
logFileEnv := os.Getenv("LOG_FILE")
if logFileEnv != "" {
if err := log.LogToFile(logFileEnv); err != nil {
fmt.Fprintf(os.Stderr, "Failed to set logger output to file: %v\n", err)
os.Exit(1)
}
}
// Initialize the database manager
dbManager := backup.NewDBManager(cfg)
// Create a context
ctx := context.Background()
// Attach the logger and DB manager to the context
ctx = context.WithValue(ctx, "logger", log)
ctx = context.WithValue(ctx, "dbManager", dbManager)
// Now, pass only the context (and any other necessary parameters) to your command execution
// Note: You'll need to adjust your application's command handling to work with context
if err := cmd.ExecuteCommandWithContext(ctx, cmd.RootCmd, os.Args[1:]); err != nil {
log.Error(fmt.Sprintf("Command execution failed: %v", err))
os.Exit(1)
}
}
func mapConfigLogLevelToLoggerLogLevel(lvl backGoConfig.LogLevel) logger.LogLevel {
switch lvl {
case backGoConfig.LogLevelInfo:
return logger.LogLevelInfo
case backGoConfig.LogLevelWarning:
return logger.LogLevelWarning
case backGoConfig.LogLevelError:
return logger.LogLevelError
default:
return logger.LogLevelInfo // Default to Info if unsure
}
}

View File

@ -5,7 +5,7 @@ import (
"fmt"
"log"
_ "github.com/go-sql-driver/mysql"
"pixelridgesoftworks.com/BackGo/config"
"git.pixelridgesoftworks.com/BackGo/config"
)
type DBManager struct {

View File

@ -9,7 +9,7 @@ import (
awsConfig "github.com/aws/aws-sdk-go-v2/config" // Aliased AWS config package
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
backGoConfig "pixelridgesoftworks.com/BackGo/config" // Aliased your config package
backGoConfig "git.pixelridgesoftworks.com/BackGo/config" // Aliased your config package
)
// S3Client wraps the AWS S3 client

View File

@ -6,18 +6,36 @@ import (
"os"
)
// Logger holds the log package's Logger instance.
// LogLevel type for defining different logging levels.
type LogLevel int
const (
// Define different log levels.
LogLevelInfo LogLevel = iota
LogLevelWarning
LogLevelError
)
// Logger wraps the standard log.Logger from the Go standard library.
// It adds additional functionality like setting log levels.
type Logger struct {
*log.Logger
level LogLevel
}
// NewLogger creates a new Logger instance. By default, it logs to stdout.
// NewLogger creates a new Logger instance. By default, it logs to stdout with LogLevelInfo.
func NewLogger() *Logger {
return &Logger{
Logger: log.New(os.Stdout, "", log.LstdFlags),
level: LogLevelInfo,
}
}
// SetLevel changes the logging level of the Logger.
func (l *Logger) SetLevel(level LogLevel) {
l.level = level
}
// LogToFile configures the logger to log to a specified file.
func (l *Logger) LogToFile(filePath string) error {
file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
@ -43,3 +61,24 @@ func (l *Logger) LogToBoth(filePath string) error {
l.SetOutput(multi)
return nil
}
// Info logs a message at level Info, respecting the set log level.
func (l *Logger) Info(msg string) {
if l.level <= LogLevelInfo {
l.Println("INFO: " + msg)
}
}
// Warning logs a message at level Warning, respecting the set log level.
func (l *Logger) Warning(msg string) {
if l.level <= LogLevelWarning {
l.Println("WARNING: " + msg)
}
}
// Error logs a message at level Error, respecting the set log level.
func (l *Logger) Error(msg string) {
if l.level <= LogLevelError {
l.Println("ERROR: " + msg)
}
}