Just a few more functions to rough in before we begin iterating. I'm going to bed now
This commit is contained in:
parent
303670e43a
commit
9c19c402c0
108
cmd/config.go
108
cmd/config.go
|
@ -1,82 +1,76 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"pixelridgesoftworks.com/BackGo/config"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const configDir = "/etc/PixelRidge/BackupGo"
|
||||
const configFile = "config.json"
|
||||
const configFilePath = "/etc/PixelRidge/BackGo/config.json"
|
||||
|
||||
// Config represents the application's configuration
|
||||
type Config struct {
|
||||
S3ConnectionInfo string `json:"s3_connection_info"`
|
||||
// Add other configuration options here, all as strings or booleans
|
||||
}
|
||||
|
||||
// LoadConfig loads the configuration from the JSON file
|
||||
func LoadConfig() (*Config, error) {
|
||||
configPath := filepath.Join(configDir, configFile)
|
||||
file, err := os.Open(configPath)
|
||||
// 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 nil, err
|
||||
return fmt.Errorf("error opening config in nano: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
config := &Config{}
|
||||
decoder := json.NewDecoder(file)
|
||||
if err := decoder.Decode(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// SaveConfig saves the modified configuration back to the JSON file
|
||||
func SaveConfig(config *Config) error {
|
||||
configPath := filepath.Join(configDir, configFile)
|
||||
file, err := os.Create(configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
encoder := json.NewEncoder(file)
|
||||
if err := encoder.Encode(config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EditConfigOption allows editing a specific configuration option from the CLI
|
||||
func EditConfigOption(optionName, newValue string) error {
|
||||
config, err := LoadConfig()
|
||||
// Load the current configuration from file
|
||||
cfg, err := config.LoadConfigFromFile()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("loading config: %v", err)
|
||||
}
|
||||
|
||||
// Reflect or a simple switch can be used to match the optionName to Config fields
|
||||
switch optionName {
|
||||
case "s3_connection_info":
|
||||
config.S3ConnectionInfo = newValue
|
||||
// Add cases for other options here
|
||||
default:
|
||||
// Use reflection to find and set the field in the Config struct
|
||||
rConfig := reflect.ValueOf(cfg).Elem()
|
||||
field := rConfig.FieldByNameFunc(func(s string) bool {
|
||||
return strings.EqualFold(s, optionName)
|
||||
})
|
||||
|
||||
if !field.IsValid() {
|
||||
return fmt.Errorf("unknown configuration option: %s", optionName)
|
||||
}
|
||||
|
||||
return SaveConfig(config)
|
||||
// Ensure the field can be set
|
||||
if !field.CanSet() {
|
||||
return fmt.Errorf("cannot set configuration option: %s", optionName)
|
||||
}
|
||||
|
||||
// OpenConfigInNano opens the configuration file in the nano editor
|
||||
func OpenConfigInNano() error {
|
||||
configPath := filepath.Join(configDir, configFile)
|
||||
cmd := exec.Command("nano", configPath)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
// Convert and set the field value based on its kind
|
||||
switch field.Kind() {
|
||||
case reflect.String:
|
||||
field.SetString(newValue)
|
||||
case reflect.Bool:
|
||||
boolVal, err := strconv.ParseBool(newValue)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid value for %s: %v", optionName, err)
|
||||
}
|
||||
field.SetBool(boolVal)
|
||||
case reflect.Int:
|
||||
intVal, err := strconv.Atoi(newValue)
|
||||
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))
|
||||
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
|
||||
}
|
||||
|
|
|
@ -77,16 +77,19 @@ func init() {
|
|||
configCmd := NewCommand("config", "Configuration management", nil)
|
||||
|
||||
editCmd := NewCommand("edit", "Edit a configuration option", func(cmd *Command, args []string) {
|
||||
// Ensure the flag is parsed before trying to access it
|
||||
cmd.FlagSet.Parse(args)
|
||||
configOption := cmd.FlagSet.Lookup("config-option").Value.String()
|
||||
if configOption == "" {
|
||||
fmt.Println("No config option specified")
|
||||
return
|
||||
}
|
||||
newValue := cmd.FlagSet.Arg(0) // Assumes the new value is the first argument after flags
|
||||
if newValue == "" {
|
||||
// The new value should be the first argument after the flags
|
||||
if len(cmd.FlagSet.Args()) == 0 {
|
||||
fmt.Println("No new value specified for the config option")
|
||||
return
|
||||
}
|
||||
newValue := cmd.FlagSet.Arg(0)
|
||||
if err := EditConfigOption(configOption, newValue); err != nil {
|
||||
fmt.Println("Error editing config option:", err)
|
||||
return
|
||||
|
|
177
config/config.go
177
config/config.go
|
@ -0,0 +1,177 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const configFilePath = "/etc/PixelRidge/BackGo/config.json"
|
||||
|
||||
type LogLevel int
|
||||
|
||||
const (
|
||||
LogLevelDebug LogLevel = iota
|
||||
LogLevelInfo
|
||||
LogLevelWarning
|
||||
LogLevelError
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
LogLevel LogLevel
|
||||
S3Enabled bool
|
||||
S3ConnectionAddress string
|
||||
S3AuthorizationInfo string
|
||||
S3Region string
|
||||
S3BucketInfo string
|
||||
SMBEnabled bool
|
||||
SMBConnectionAddress string
|
||||
SMBAuthorizationInfo string
|
||||
B2Enabled bool
|
||||
B2ConnectionAddress string
|
||||
B2AuthorizationInfo string
|
||||
B2BucketInfo string
|
||||
LocalStorageEnabled bool
|
||||
LocalStorageDirectory string
|
||||
APIServerBindAddress string
|
||||
APIServerPort string
|
||||
TransportServerBindAddress string
|
||||
TransportServerPort string
|
||||
Nodes []string
|
||||
}
|
||||
|
||||
func LoadConfig() *Config {
|
||||
return &Config{
|
||||
LogLevel: getEnvAsLogLevel("LOG_LEVEL", LogLevelInfo),
|
||||
S3Enabled: getEnvAsBool("S3_ENABLED", false),
|
||||
S3ConnectionAddress: os.Getenv("S3_CONNECTION_ADDRESS"),
|
||||
S3AuthorizationInfo: os.Getenv("S3_AUTHORIZATION_INFO"),
|
||||
S3Region: os.Getenv("S3_REGION"),
|
||||
S3BucketInfo: os.Getenv("S3_BUCKET_INFO"),
|
||||
SMBEnabled: getEnvAsBool("SMB_ENABLED", false),
|
||||
SMBConnectionAddress: os.Getenv("SMB_CONNECTION_ADDRESS"),
|
||||
SMBAuthorizationInfo: os.Getenv("SMB_AUTHORIZATION_INFO"),
|
||||
B2Enabled: getEnvAsBool("BACKBLAZE_B2_ENABLED", false),
|
||||
B2ConnectionAddress: os.Getenv("B2_CONNECTION_ADDRESS"),
|
||||
B2AuthorizationInfo: os.Getenv("B2_AUTHORIZATION_INFO"),
|
||||
B2BucketInfo: os.Getenv("BACKBLAZE_B2_BUCKET_INFO"),
|
||||
LocalStorageEnabled: getEnvAsBool("LOCAL_STORAGE_ENABLED", false),
|
||||
LocalStorageDirectory: os.Getenv("LOCAL_STORAGE_DIRECTORY"),
|
||||
APIServerBindAddress: os.Getenv("API_SERVER_BIND_ADDRESS"),
|
||||
APIServerPort: os.Getenv("API_SERVER_PORT"),
|
||||
TransportServerBindAddress: os.Getenv("TRANSPORT_SERVER_BIND_ADDRESS"),
|
||||
TransportServerPort: os.Getenv("TRANSPORT_SERVER_PORT"),
|
||||
Nodes: getEnvAsSlice("NODES", ",", []string{}),
|
||||
}
|
||||
}
|
||||
|
||||
func getEnvAsBool(name string, defaultVal bool) bool {
|
||||
valStr := os.Getenv(name)
|
||||
if valStr == "" {
|
||||
return defaultVal
|
||||
}
|
||||
val, err := strconv.ParseBool(valStr)
|
||||
if err != nil {
|
||||
log.Printf("Error parsing boolean for %s: %v\n", name, err)
|
||||
return defaultVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func getEnvAsSlice(name, sep string, defaultVal []string) []string {
|
||||
valStr := os.Getenv(name)
|
||||
if valStr == "" {
|
||||
return defaultVal
|
||||
}
|
||||
return strings.Split(valStr, sep)
|
||||
}
|
||||
|
||||
func getEnvAsLogLevel(name string, defaultVal LogLevel) LogLevel {
|
||||
valStr := os.Getenv(name)
|
||||
if valStr == "" {
|
||||
return defaultVal
|
||||
}
|
||||
if strings.EqualFold(valStr, "debug") {
|
||||
return LogLevelDebug
|
||||
} else if strings.EqualFold(valStr, "info") {
|
||||
return LogLevelInfo
|
||||
} else if strings.EqualFold(valStr, "warning") {
|
||||
return LogLevelWarning
|
||||
} else if strings.EqualFold(valStr, "error") {
|
||||
return LogLevelError
|
||||
}
|
||||
log.Printf("Unknown LOG_LEVEL '%s', defaulting to INFO.\n", valStr)
|
||||
return LogLevelInfo
|
||||
}
|
||||
|
||||
func UpdateConfig(key, value string) error {
|
||||
config, err := LoadConfigFromFile()
|
||||
if err != nil {
|
||||
return fmt.Errorf("loading config: %v", err)
|
||||
}
|
||||
|
||||
rConfig := reflect.ValueOf(config).Elem()
|
||||
field := rConfig.FieldByNameFunc(func(s string) bool {
|
||||
return strings.EqualFold(s, key)
|
||||
})
|
||||
|
||||
if !field.IsValid() {
|
||||
return fmt.Errorf("unknown configuration key: %s", key)
|
||||
}
|
||||
|
||||
if !field.CanSet() {
|
||||
return fmt.Errorf("cannot set configuration key: %s", key)
|
||||
}
|
||||
|
||||
switch field.Kind() {
|
||||
case reflect.String:
|
||||
field.SetString(value)
|
||||
case reflect.Bool:
|
||||
boolVal, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing boolean value for %s: %v", key, err)
|
||||
}
|
||||
field.SetBool(boolVal)
|
||||
case reflect.Int:
|
||||
intVal, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing integer value for %s: %v", key, err)
|
||||
}
|
||||
field.SetInt(int64(intVal))
|
||||
default:
|
||||
return fmt.Errorf("unsupported configuration type for: %s", key)
|
||||
}
|
||||
|
||||
return SaveConfigToFile(config)
|
||||
}
|
||||
|
||||
func LoadConfigFromFile() (*Config, error) {
|
||||
file, err := os.ReadFile(configFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var config Config
|
||||
if err := json.Unmarshal(file, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
func SaveConfigToFile(config *Config) error {
|
||||
data, err := json.MarshalIndent(config, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.WriteFile(configFilePath, data, 0644)
|
||||
}
|
||||
|
||||
func ReloadConfig() {
|
||||
fmt.Println("Configuration reloaded")
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SetDefaultConfig sets the default configuration by writing to environment variables
|
||||
// and create a default configuration file.
|
||||
func SetDefaultConfig() error {
|
||||
// Define default values with explanations
|
||||
defaults := map[string]string{
|
||||
// Logging level: DEBUG, INFO, WARNING, ERROR
|
||||
"LOG_LEVEL": "INFO",
|
||||
|
||||
// API server configuration
|
||||
"API_SERVER_BIND_ADDRESS": "0.0.0.0", // IP address to bind the API server
|
||||
"API_SERVER_PORT": "6678", // Port for the API server
|
||||
|
||||
// Transport server configuration for internal communication
|
||||
"TRANSPORT_SERVER_BIND_ADDRESS": "0.0.0.0", // IP address for the transport server
|
||||
"TRANSPORT_SERVER_PORT": "6679", // Port for the transport server
|
||||
|
||||
// S3 storage configuration
|
||||
"S3_ENABLED": "false", // Enable S3 storage (true/false)
|
||||
"S3_CONNECTION_ADDRESS": "", // S3 connection address in the format {IP}:{PORT}
|
||||
"S3_AUTHORIZATION_INFO": "", // S3 authorization information (e.g., access key and secret key)
|
||||
"S3_REGION": "us-east-1", // AWS region for S3
|
||||
"S3_BUCKET_INFO": "", // S3 bucket name
|
||||
|
||||
// SMB storage configuration
|
||||
"SMB_ENABLED": "false", // Enable SMB storage (true/false)
|
||||
"SMB_CONNECTION_ADDRESS": "", // SMB connection address in the format {IP}:{PORT}
|
||||
"SMB_AUTHORIZATION_INFO": "", // SMB authorization information (e.g., username and password)
|
||||
|
||||
// BackBlaze B2 storage configuration
|
||||
"B2_ENABLED": "false", // Enable BackBlaze B2 storage (true/false)
|
||||
"B2_CONNECTION_ADDRESS":"", // BackBlaze B2 connection address in the format {IP}:{PORT}
|
||||
"B2_AUTHORIZATION_INFO":"", // BackBlaze B2 authorization information
|
||||
"B2_BUCKET_INFO": "", // BackBlaze B2 bucket name
|
||||
|
||||
// Local storage configuration
|
||||
"LOCAL_STORAGE_ENABLED": "true", // Enable local storage (true/false)
|
||||
"LOCAL_STORAGE_DIRECTORY": fmt.Sprintf("/etc/PixelRidge/BackGo/local-data-storage/%s-%d", os.Getenv("HOSTNAME"), time.Now().Unix()), // Path for local storage directory
|
||||
|
||||
// Nodes configuration for cluster setup
|
||||
"NODES": "", // Comma-separated list of node addresses in the cluster
|
||||
}
|
||||
|
||||
// Write defaults to environment variables
|
||||
for key, value := range defaults {
|
||||
if err := os.Setenv(key, value); err != nil {
|
||||
return fmt.Errorf("failed to set default config for %s: %v", key, err)
|
||||
}
|
||||
}
|
||||
|
||||
// write these defaults to a file for persistence
|
||||
// write to a JSON or YAML file
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// include a function here to write the configuration to a file
|
29
go.mod
29
go.mod
|
@ -1,3 +1,32 @@
|
|||
module 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/service/s3 v1.53.0
|
||||
github.com/hirochachacha/go-smb2 v1.1.0
|
||||
golang.org/x/crypto v0.21.0
|
||||
)
|
||||
|
||||
require (
|
||||
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
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 // indirect
|
||||
github.com/aws/smithy-go v1.20.1 // indirect
|
||||
github.com/geoffgarside/ber v1.1.0 // indirect
|
||||
golang.org/x/net v0.21.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
)
|
||||
|
|
52
go.sum
Normal file
52
go.sum
Normal file
|
@ -0,0 +1,52 @@
|
|||
github.com/aws/aws-sdk-go-v2 v1.26.0 h1:/Ce4OCiM3EkpW7Y+xUnfAFpchU78K7/Ug01sZni9PgA=
|
||||
github.com/aws/aws-sdk-go-v2 v1.26.0/go.mod h1:35hUlJVYd+M++iLI3ALmVwMOyRYMmRqUXpTtRGW+K9I=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 h1:gTK2uhtAPtFcdRRJilZPx8uJLL2J85xK11nKtWL0wfU=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1/go.mod h1:sxpLb+nZk7tIfCWChfd+h4QwHNUR57d8hA1cleTkjJo=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.9 h1:gRx/NwpNEFSk+yQlgmk1bmxxvQ5TyJ76CWXs9XScTqg=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.9/go.mod h1:dK1FQfpwpql83kbD873E9vz4FyAxuJtR22wzoXn3qq0=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.9 h1:N8s0/7yW+h8qR8WaRlPQeJ6czVMNQVNtNdUqf6cItao=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.9/go.mod h1:446YhIdmSV0Jf/SLafGZalQo+xr2iw7/fzXGDPTU1yQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0 h1:af5YzcLf80tv4Em4jWVD75lpnOHSBkPUZxZfGkrI3HI=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0/go.mod h1:nQ3how7DMnFMWiU1SpECohgC82fpn4cKZ875NDMmwtA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 h1:0ScVK/4qZ8CIW0k8jOeFVsyS/sAiXpYxRBLolMkuLQM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4/go.mod h1:84KyjNZdHC6QZW08nfHI6yZgPd+qRgaWcYsyLUo3QY8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 h1:sHmMWWX5E7guWEFQ9SVo6A3S4xpPrWnd77a6y4WM6PU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4/go.mod h1:WjpDrhWisWOIoS9n3nk67A3Ll1vfULJ9Kq6h29HTD48=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.4 h1:SIkD6T4zGQ+1YIit22wi37CGNkrE7mXV1vNA5VpI3TI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.4/go.mod h1:XfeqbsG0HNedNs0GT+ju4Bs+pFAwsrlzcRdMvdNVf5s=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 h1:EyBZibRTVAs6ECHZOw5/wlylS9OcTzwyjeQMudmREjE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1/go.mod h1:JKpmtYhhPs7D97NL/ltqz7yCkERFW5dOlHyVl66ZYF8=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.6 h1:NkHCgg0Ck86c5PTOzBZ0JRccI51suJDg5lgFtxBu1ek=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.6/go.mod h1:mjTpxjC8v4SeINTngrnKFgm2QUi+Jm+etTbCxh8W4uU=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6 h1:b+E7zIUHMmcB4Dckjpkapoy47W6C9QBv/zoUP+Hn8Kc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6/go.mod h1:S2fNV0rxrP78NhPbCZeQgY8H9jdDMeGtwcfZIRxzBqU=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.4 h1:uDj2K47EM1reAYU9jVlQ1M5YENI1u6a/TxJpf6AeOLA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.4/go.mod h1:XKCODf4RKHppc96c2EZBGV/oCUC7OClxAo2MEyg4pIk=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.53.0 h1:r3o2YsgW9zRcIP3Q0WCmttFVhTuugeKIvT5z9xDspc0=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.53.0/go.mod h1:w2E4f8PUfNtyjfL6Iu+mWI96FGttE03z3UdNcUEC4tA=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 h1:mnbuWHOcM70/OFUlZZ5rcdfA8PflGXXiefU/O+1S3+8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.20.3/go.mod h1:5HFu51Elk+4oRBZVxmHrSds5jFXmFj8C3w7DVF2gnrs=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 h1:uLq0BKatTmDzWa/Nu4WO0M1AaQDaPpwTKAeByEc6WFM=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3/go.mod h1:b+qdhjnxj8GSR6t5YfphOffeoQSQ1KmpoVVuBn+PWxs=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 h1:J/PpTf/hllOjx8Xu9DMflff3FajfLxqM5+tepvVXmxg=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.5/go.mod h1:0ih0Z83YDH/QeQ6Ori2yGE2XvWYv/Xm+cZc01LC6oK0=
|
||||
github.com/aws/smithy-go v1.20.1 h1:4SZlSlMr36UEqC7XOyRVb27XMeZubNcBNN+9IgEPIQw=
|
||||
github.com/aws/smithy-go v1.20.1/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
|
||||
github.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w=
|
||||
github.com/geoffgarside/ber v1.1.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc=
|
||||
github.com/hirochachacha/go-smb2 v1.1.0 h1:b6hs9qKIql9eVXAiN0M2wSFY5xnhbHAQoCwRKbaRTZI=
|
||||
github.com/hirochachacha/go-smb2 v1.1.0/go.mod h1:8F1A4d5EZzrGu5R7PU163UcMRDJQl4FtcxjBfsY8TZE=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|
@ -0,0 +1,51 @@
|
|||
package backup
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
)
|
||||
|
||||
// GenerateCertForDomain generates an SSL certificate for a domain using Let's Encrypt
|
||||
func GenerateCertForDomain(domain string) {
|
||||
certManager := autocert.Manager{
|
||||
Prompt: autocert.AcceptTOS,
|
||||
Cache: autocert.DirCache("certs"), // Stores certificates in ./certs
|
||||
HostPolicy: autocert.HostWhitelist(domain), // Replace with your domain
|
||||
}
|
||||
|
||||
server := &http.Server{
|
||||
Addr: ":https", // Default HTTPS port
|
||||
TLSConfig: &tls.Config{
|
||||
GetCertificate: certManager.GetCertificate,
|
||||
},
|
||||
}
|
||||
|
||||
// Redirect HTTP to HTTPS
|
||||
go http.ListenAndServe(":http", certManager.HTTPHandler(nil))
|
||||
|
||||
log.Printf("Starting HTTPS server for %s\n", domain)
|
||||
log.Fatal(server.ListenAndServeTLS("", "")) // Keys are provided by Let's Encrypt
|
||||
}
|
||||
|
||||
// HandleJoinRequest handles a join request from a node
|
||||
func HandleJoinRequest(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO: Implement join request logic here
|
||||
fmt.Fprintf(w, "Join request received\n")
|
||||
}
|
||||
|
||||
// SendCommandToNode sends a CLI command to a specified node in the cluster
|
||||
func SendCommandToNode(nodeAddress, command string) {
|
||||
// TODO: Implement command sending logic here
|
||||
fmt.Printf("Sending command '%s' to node %s\n", command, nodeAddress)
|
||||
}
|
||||
|
||||
// StartMasterServer starts the master API server that listens for join requests and other commands
|
||||
func StartMasterServer(domain string) {
|
||||
http.HandleFunc("/join", HandleJoinRequest) // Endpoint for nodes to join the cluster
|
||||
|
||||
// Generate SSL certificate and start HTTPS server
|
||||
GenerateCertForDomain(domain)
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package backup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
)
|
||||
|
||||
// S3Client wraps the AWS S3 client
|
||||
type S3Client struct {
|
||||
Client *s3.Client
|
||||
Bucket string
|
||||
}
|
||||
|
||||
// NewS3Client initializes and returns a new S3 client
|
||||
func NewS3Client(bucket string) (*S3Client, error) {
|
||||
cfg, err := config.LoadDefaultConfig(context.TODO(),
|
||||
config.WithRegion("us-west-2"), // Specify your region
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to load SDK config, %w", err)
|
||||
}
|
||||
|
||||
s3Client := s3.NewFromConfig(cfg)
|
||||
return &S3Client{
|
||||
Client: s3Client,
|
||||
Bucket: bucket,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UploadFile uploads a file to the specified S3 bucket
|
||||
func (c *S3Client) UploadFile(key string, filePath string) error {
|
||||
// Implementation for uploading file to S3
|
||||
// need to open the file and use PutObject API call
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteFile deletes a file from the specified S3 bucket
|
||||
func (c *S3Client) DeleteFile(key string) error {
|
||||
// Implementation for deleting file from S3 using DeleteObject API call
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListFiles lists all files (backups) in the specified S3 bucket
|
||||
func (c *S3Client) ListFiles() ([]string, error) {
|
||||
// Implementation for listing files in S3 bucket using ListObjectsV2 API call
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// SetBucket sets the S3 bucket for the client
|
||||
func (c *S3Client) SetBucket(bucket string) {
|
||||
c.Bucket = bucket
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
package backup
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/hirochachacha/go-smb2"
|
||||
)
|
||||
|
||||
// SMBClient wraps the SMB client and session
|
||||
type SMBClient struct {
|
||||
Share string
|
||||
Session *smb2.Session
|
||||
}
|
||||
|
||||
// NewSMBClient initializes and returns a new SMB client
|
||||
func NewSMBClient(server, user, pass, domain, share string) (*SMBClient, error) {
|
||||
conn, err := net.Dial("tcp", server)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to dial: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
d := &smb2.Dialer{
|
||||
Initiator: &smb2.NTLMInitiator{
|
||||
User: user,
|
||||
Password: pass,
|
||||
Domain: domain,
|
||||
},
|
||||
}
|
||||
|
||||
session, err := d.Dial(conn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to start SMB session: %v", err)
|
||||
}
|
||||
|
||||
return &SMBClient{
|
||||
Share: share,
|
||||
Session: session,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UploadFile uploads a file to the specified SMB share
|
||||
func (c *SMBClient) UploadFile(remotePath, localPath string) error {
|
||||
fs, err := c.Session.Mount(c.Share)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to mount share: %v", err)
|
||||
}
|
||||
defer fs.Umount()
|
||||
|
||||
localFile, err := os.Open(localPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open local file: %v", err)
|
||||
}
|
||||
defer localFile.Close()
|
||||
|
||||
remoteFile, err := fs.Create(remotePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create remote file: %v", err)
|
||||
}
|
||||
defer remoteFile.Close()
|
||||
|
||||
_, err = io.Copy(remoteFile, localFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write to remote file: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteFile deletes a file from the specified SMB share
|
||||
func (c *SMBClient) DeleteFile(remotePath string) error {
|
||||
fs, err := c.Session.Mount(c.Share)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to mount share: %v", err)
|
||||
}
|
||||
defer fs.Umount()
|
||||
|
||||
err = fs.Remove(remotePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete remote file: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListFiles lists all files (backups) in the specified SMB share
|
||||
func (c *SMBClient) ListFiles(remoteDir string) ([]string, error) {
|
||||
fs, err := c.Session.Mount(c.Share)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to mount share: %v", err)
|
||||
}
|
||||
defer fs.Umount()
|
||||
|
||||
entries, err := fs.ReadDir(remoteDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read directory: %v", err)
|
||||
}
|
||||
|
||||
var files []string
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
files = append(files, entry.Name())
|
||||
}
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
// SetShare sets the SMB share for the client
|
||||
func (c *SMBClient) SetShare(share string) {
|
||||
c.Share = share
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package logger
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Logger holds the log package's Logger instance.
|
||||
type Logger struct {
|
||||
*log.Logger
|
||||
}
|
||||
|
||||
// NewLogger creates a new Logger instance. By default, it logs to stdout.
|
||||
func NewLogger() *Logger {
|
||||
return &Logger{
|
||||
Logger: log.New(os.Stdout, "", log.LstdFlags),
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l.SetOutput(file)
|
||||
return nil
|
||||
}
|
||||
|
||||
// LogToStdout configures the logger to log to stdout.
|
||||
func (l *Logger) LogToStdout() {
|
||||
l.SetOutput(os.Stdout)
|
||||
}
|
||||
|
||||
// LogToBoth configures the logger to log to both a file and stdout.
|
||||
func (l *Logger) LogToBoth(filePath string) error {
|
||||
file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
multi := io.MultiWriter(file, os.Stdout)
|
||||
l.SetOutput(multi)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
// Package utils contains utility functions for the application.
|
||||
package utils
|
||||
|
||||
// This file serves as a placeholder for future utility methods.
|
Loading…
Reference in New Issue
Block a user