mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-23 04:36:40 +00:00
208 lines
5.5 KiB
Go
208 lines
5.5 KiB
Go
package config
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log/slog"
|
|
"os"
|
|
"sync"
|
|
|
|
"github.com/nats-io/nats.go"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
type ClusterConfig struct {
|
|
Epoch uint64 `mapstructure:"epoch"` // bump when leader commits changes
|
|
Node string `mapstructure:"node"` // my node name
|
|
Version string `mapstructure:"version"` // hive version
|
|
Nodes map[string]Config `mapstructure:"nodes"` // full config for every node
|
|
}
|
|
|
|
// Config holds all configuration for the application
|
|
type Config struct {
|
|
// Node config
|
|
Node string `mapstructure:"node"`
|
|
Host string `mapstructure:"host"` // Unique hostname or IP of this node
|
|
Region string `mapstructure:"region"`
|
|
AZ string `mapstructure:"az"`
|
|
DataDir string `mapstructure:"data_dir"`
|
|
|
|
Daemon DaemonConfig `mapstructure:"daemon"`
|
|
NATS NATSConfig `mapstructure:"nats"`
|
|
Predastore PredastoreConfig `mapstructure:"predastore"`
|
|
AWSGW AWSGWConfig `mapstructure:"awsgw"`
|
|
|
|
// Authentication
|
|
// TODO: Move to more appropriate setting above
|
|
AccessKey string `mapstructure:"accesskey"`
|
|
SecretKey string `mapstructure:"secretkey"`
|
|
BaseDir string `mapstructure:"base_dir"`
|
|
WalDir string `mapstructure:"wal_dir"`
|
|
}
|
|
|
|
type AWSGWConfig struct {
|
|
Host string `mapstructure:"host"`
|
|
TLSKey string `mapstructure:"tlskey"`
|
|
TLSCert string `mapstructure:"tlscert"`
|
|
Config string `mapstructure:"config"`
|
|
|
|
Debug bool `mapstructure:"debug"`
|
|
ExpectedNodes int `mapstructure:"expected_nodes"` // TODO: Replace with root cluster config
|
|
}
|
|
|
|
type PredastoreConfig struct {
|
|
Host string `mapstructure:"host"`
|
|
Bucket string `mapstructure:"bucket"`
|
|
Region string `mapstructure:"region"`
|
|
AccessKey string `mapstructure:"accesskey"`
|
|
SecretKey string `mapstructure:"secretkey"`
|
|
BaseDir string `mapstructure:"base_dir"`
|
|
}
|
|
|
|
// DaemonConfig holds the daemon configuration
|
|
type DaemonConfig struct {
|
|
Host string `mapstructure:"host"`
|
|
TLSKey string `mapstructure:"tlskey"`
|
|
TLSCert string `mapstructure:"tlscert"`
|
|
}
|
|
|
|
// NATSConfig holds the NATS configuration
|
|
type NATSConfig struct {
|
|
Host string `mapstructure:"host"`
|
|
ACL NATSACL `mapstructure:"acl"`
|
|
Sub NATSSub `mapstructure:"sub"`
|
|
}
|
|
|
|
// NATSACL holds the NATS ACL configuration
|
|
type NATSACL struct {
|
|
Token string `mapstructure:"token"`
|
|
}
|
|
|
|
// NATSSub holds the NATS subscription configuration
|
|
type NATSSub struct {
|
|
Subject string `mapstructure:"subject"`
|
|
}
|
|
|
|
type EBSRequests struct {
|
|
Requests []EBSRequest `mapstructure:"ebs_requests"`
|
|
Mu sync.Mutex `json:"-"`
|
|
}
|
|
|
|
type EBSRequest struct {
|
|
Name string
|
|
VolType string
|
|
Boot bool
|
|
EFI bool
|
|
CloudInit bool
|
|
NBDURI string
|
|
}
|
|
|
|
type EBSMountResponse struct {
|
|
URI string
|
|
Mounted bool
|
|
Error string
|
|
}
|
|
|
|
type EBSUnMountResponse struct {
|
|
Volume string
|
|
Mounted bool
|
|
Error string
|
|
}
|
|
|
|
type EBSDeleteRequest struct {
|
|
Volume string
|
|
}
|
|
|
|
type EBSDeleteResponse struct {
|
|
Volume string
|
|
Success bool
|
|
Error string
|
|
}
|
|
|
|
// EC2, TODO: Move to vm.go or more applicable place
|
|
type EC2StartInstancesRequest struct {
|
|
InstanceID string
|
|
}
|
|
|
|
type EC2StartInstancesResponse struct {
|
|
InstanceID string
|
|
Status string
|
|
Error string
|
|
}
|
|
|
|
// TODO: Make a generic function for the response
|
|
func (ec2StartInstanceResponse EC2StartInstancesResponse) Respond(msg *nats.Msg) {
|
|
|
|
response, err := json.Marshal(ec2StartInstanceResponse)
|
|
if err != nil {
|
|
slog.Error("Failed to marshal response", "err", err)
|
|
return
|
|
}
|
|
|
|
msg.Respond(response)
|
|
|
|
}
|
|
|
|
// Cluster manager API types
|
|
type NodeJoinRequest struct {
|
|
Node string `json:"node"`
|
|
Region string `json:"region"`
|
|
AZ string `json:"az"`
|
|
DataDir string `json:"data_dir"`
|
|
DaemonHost string `json:"daemon_host"` // Host:port where this node's daemon is accessible
|
|
}
|
|
|
|
// SharedClusterData contains only the shared cluster information (no node-specific top-level fields)
|
|
type SharedClusterData struct {
|
|
Epoch uint64 `json:"epoch" toml:"epoch"`
|
|
Version string `json:"version" toml:"version"`
|
|
Nodes map[string]Config `json:"nodes" toml:"nodes"`
|
|
}
|
|
|
|
type NodeJoinResponse struct {
|
|
Success bool `json:"success"`
|
|
Message string `json:"message"`
|
|
SharedData *SharedClusterData `json:"shared_data,omitempty"`
|
|
ConfigHash string `json:"config_hash,omitempty"`
|
|
JoiningNode string `json:"joining_node,omitempty"` // The node name that is joining
|
|
}
|
|
|
|
type NodeHealthResponse struct {
|
|
Node string `json:"node"`
|
|
Status string `json:"status"`
|
|
ConfigHash string `json:"config_hash"`
|
|
Epoch uint64 `json:"epoch"`
|
|
Uptime int64 `json:"uptime"`
|
|
}
|
|
|
|
// LoadConfig loads the configuration from file and environment variables
|
|
func LoadConfig(configPath string) (*ClusterConfig, error) {
|
|
// Set environment variable prefix
|
|
viper.SetEnvPrefix("HIVE")
|
|
viper.AutomaticEnv()
|
|
|
|
// Try to load config file if it exists
|
|
if configPath != "" {
|
|
// Check if file exists
|
|
if _, err := os.Stat(configPath); err == nil {
|
|
viper.SetConfigFile(configPath)
|
|
viper.SetConfigType("toml")
|
|
|
|
if err := viper.ReadInConfig(); err != nil {
|
|
return nil, fmt.Errorf("error reading config file: %w", err)
|
|
}
|
|
fmt.Fprintf(os.Stderr, "Using config file: %s\n", viper.ConfigFileUsed())
|
|
} else {
|
|
fmt.Fprintf(os.Stderr, "Config file not found: %s, using environment variables and defaults\n", configPath)
|
|
}
|
|
}
|
|
|
|
// Create config struct
|
|
var config ClusterConfig
|
|
if err := viper.Unmarshal(&config); err != nil {
|
|
return nil, fmt.Errorf("error unmarshaling config: %w", err)
|
|
}
|
|
|
|
return &config, nil
|
|
}
|