refactor: rename config files, paths, and env vars from hive to spinifex

- Rename hive.toml template → spinifex.toml
- Update all default paths: /etc/hive → /etc/spinifex, ~/hive → ~/spinifex
- Rename all HIVE_* env vars → SPINIFEX_* (SetEnvPrefix, BindEnv calls)
- Update nats.conf template server_name
- Update admin.go init/join commands for new paths and names
- Update paths.go, paths_test.go, config.go, config_test.go
This commit is contained in:
Ben Duncan
2026-03-18 00:47:01 +00:00
parent 00f5b6590e
commit ee0b92c192
13 changed files with 115 additions and 115 deletions
+47 -47
View File
@@ -48,8 +48,8 @@ import (
"github.com/spf13/cobra"
)
//go:embed templates/hive.toml
var hiveTomlTemplate string
//go:embed templates/spinifex.toml
var spinifexTomlTemplate string
//go:embed templates/awsgw.toml
var awsgwTomlTemplate string
@@ -101,7 +101,7 @@ var adminInitCmd = &cobra.Command{
Short: "Initialize Hive platform configuration",
Long: `Initialize Hive platform by creating configuration files, generating SSL certificates,
and setting up AWS credentials. This creates the necessary directory structure and
configuration files in ~/hive/config.`,
configuration files in ~/spinifex/config.`,
Run: runAdminInit,
}
@@ -159,18 +159,18 @@ var accountListCmd = &cobra.Command{
/*
CLI ideas
hive admin images list
spx admin images list
- fetches from remote endpoint for common/trusted images to bootstrap environment, or baked in from compile.
// If --name specified, download
hive admin images import --name debian-12-x86_64
spx admin images import --name debian-12-x86_64
// List available images
hive admin images list
spx admin images list
// Manually import a path
hive admin images import --file /path/to/image --distro debian --version 12 --arch x86_64
spx admin images import --file /path/to/image --distro debian --version 12 --arch x86_64
-> x <-
*/
@@ -197,7 +197,7 @@ func init() {
accountCreateCmd.MarkFlagRequired("name")
rootCmd.PersistentFlags().String("config-dir", DefaultConfigDir(), "Configuration directory")
rootCmd.PersistentFlags().String("hive-dir", DefaultDataDir(), "Hive base directory")
rootCmd.PersistentFlags().String("spinifex-dir", DefaultDataDir(), "Spinifex base directory")
// Flags for admin init
adminInitCmd.Flags().Bool("force", false, "Force re-initialization (overwrites existing config)")
@@ -212,7 +212,7 @@ func init() {
adminInitCmd.Flags().String("cluster-routes", "", "NATS cluster hosts for routing specify multiple with comma (e.g., 10.11.12.1:4248,10.11.12.2:4248 for multi-node)")
adminInitCmd.Flags().String("predastore-nodes", "", "Comma-separated IPs for multi-node Predastore cluster (e.g., 10.11.12.1,10.11.12.2,10.11.12.3). Requires >= 3 nodes.")
adminInitCmd.Flags().String("formation-timeout", "10m", "Timeout for cluster formation (e.g., 5m, 30s)")
adminInitCmd.Flags().String("cluster-name", "hive", "NATS cluster name")
adminInitCmd.Flags().String("cluster-name", "spinifex", "NATS cluster name")
adminInitCmd.Flags().StringSlice("services", nil, "Services this node runs (default: all). Valid: nats,predastore,viperblock,daemon,awsgw,ui")
// Flags for admin join
@@ -220,7 +220,7 @@ func init() {
adminJoinCmd.Flags().String("az", "ap-southeast-2a", "Availability zone for this node")
adminJoinCmd.Flags().String("node", "", "Node name (required)")
adminJoinCmd.Flags().String("host", "", "Leader node host:port (e.g., node1.local:4432) (required)")
adminJoinCmd.Flags().String("data-dir", "", "Data directory for this node (default: ~/hive)")
adminJoinCmd.Flags().String("data-dir", "", "Data directory for this node (default: ~/spinifex)")
adminJoinCmd.Flags().Int("port", 4432, "Port to bind cluster services on")
adminJoinCmd.Flags().String("bind", "0.0.0.0", "IP address to bind services to (e.g., 10.11.12.2 for multi-node on single host)")
adminJoinCmd.Flags().String("cluster-bind", "", "IP address to bind NATS cluster services to (e.g., 10.11.12.1 for multi-node)")
@@ -259,7 +259,7 @@ func runimagesImportCmd(cmd *cobra.Command, args []string) {
}
//configDir, _ := cmd.Flags().GetString("config-dir")
baseDir, _ := cmd.Flags().GetString("hive-dir")
baseDir, _ := cmd.Flags().GetString("spinifex-dir")
// Strip trailing slash
baseDir = filepath.Clean(baseDir)
@@ -368,7 +368,7 @@ func runimagesImportCmd(cmd *cobra.Command, args []string) {
}
// Next, validate if the image is raw, tar, gz, xv, etc. We need to upload the raw image
tmpDir, err := os.MkdirTemp(ostmpDir, "hive-image-tmp-*")
tmpDir, err := os.MkdirTemp(ostmpDir, "spinifex-image-tmp-*")
if err != nil {
fmt.Fprintf(os.Stderr, "Could not create temp dir: %v\n", err)
@@ -515,14 +515,14 @@ func runimagesListCmd(cmd *cobra.Command, args []string) {
pterm.Println("To install a selected image as an AMI use:")
pterm.Println("hive admin images import --name <image-name>")
pterm.Println("spx admin images import --name <image-name>")
}
// TODO: Move all logic to a module, use minimal application logic in viper commands
func runAdminInit(cmd *cobra.Command, args []string) {
force, _ := cmd.Flags().GetBool("force")
configDir, _ := cmd.Flags().GetString("config-dir")
hiveRoot, _ := cmd.Flags().GetString("hive-dir")
spxRoot, _ := cmd.Flags().GetString("spinifex-dir")
region, _ := cmd.Flags().GetString("region")
az, _ := cmd.Flags().GetString("az")
node, _ := cmd.Flags().GetString("node")
@@ -568,12 +568,12 @@ func runAdminInit(cmd *cobra.Command, args []string) {
fmt.Printf("Configuration directory: %s\n\n", configDir)
// Check if already initialized
hiveTomlPath := filepath.Join(configDir, "hive.toml")
if !force && admin.FileExists(hiveTomlPath) {
spinifexTomlPath := filepath.Join(configDir, "spinifex.toml")
if !force && admin.FileExists(spinifexTomlPath) {
fmt.Println("⚠️ Hive already initialized!")
fmt.Printf("Config file exists: %s\n", hiveTomlPath)
fmt.Printf("Config file exists: %s\n", spinifexTomlPath)
fmt.Println("\nTo re-initialize, run with --force flag:")
fmt.Println(" hive admin init --force")
fmt.Println(" spx admin init --force")
os.Exit(0)
}
@@ -616,7 +616,7 @@ func runAdminInit(cmd *cobra.Command, args []string) {
fmt.Printf(" Access Key: %s\n", bootstrapResult.AdminAccessKey)
fmt.Printf(" Secret Key: %s\n", bootstrapResult.AdminSecretKey)
fmt.Printf(" Account: %s (%s)\n", admin.DefaultAccountName(), admin.DefaultAccountID())
fmt.Printf(" AWS Profile: hive\n")
fmt.Printf(" AWS Profile: spinifex\n")
// Generate SSL certificates (with bind IP in SANs for multi-node support)
certPath := admin.GenerateCertificatesIfNeeded(configDir, force, bindIP)
@@ -629,17 +629,17 @@ func runAdminInit(cmd *cobra.Command, args []string) {
}
fmt.Println("\n🔒 Generated NATS authentication token")
if hiveRoot == "" {
hiveRoot = DefaultDataDir()
if spxRoot == "" {
spxRoot = DefaultDataDir()
}
hiveRoot = filepath.Clean(hiveRoot)
spxRoot = filepath.Clean(spxRoot)
// Determine if this is a multi-node formation
isMultiNode := nodes >= 2 && bindIP != "0.0.0.0"
if isMultiNode {
runAdminInitMultiNode(cmd, accessKey, secretKey, accountID, natsToken, clusterName,
configDir, hiveRoot, certPath, region, az, node, bindIP, clusterBind,
configDir, spxRoot, certPath, region, az, node, bindIP, clusterBind,
port, nodes, formationTimeoutStr, services)
return
}
@@ -653,9 +653,9 @@ func runAdminInit(cmd *cobra.Command, args []string) {
awsgwDir := filepath.Join(configDir, "awsgw")
predastoreDir := filepath.Join(configDir, "predastore")
natsDir := filepath.Join(configDir, "nats")
hiveDir := filepath.Join(configDir, "hive")
spinifexDir := filepath.Join(configDir, "spinifex")
for _, dir := range []string{awsgwDir, predastoreDir, natsDir, hiveDir} {
for _, dir := range []string{awsgwDir, predastoreDir, natsDir, spinifexDir} {
if err := os.MkdirAll(dir, 0700); err != nil {
fmt.Fprintf(os.Stderr, "Error creating directory %s: %v\n", dir, err)
os.Exit(1)
@@ -713,7 +713,7 @@ func runAdminInit(cmd *cobra.Command, args []string) {
AccountID: accountID,
Region: region,
NatsToken: natsToken,
DataDir: hiveRoot,
DataDir: spxRoot,
ConfigDir: configDir,
Node: node,
@@ -730,7 +730,7 @@ func runAdminInit(cmd *cobra.Command, args []string) {
// Generate config files
configs := []admin.ConfigFile{
{Name: "hive.toml", Path: hiveTomlPath, Template: hiveTomlTemplate},
{Name: "spinifex.toml", Path: spinifexTomlPath, Template: spinifexTomlTemplate},
{Name: filepath.Join(awsgwDir, "awsgw.toml"), Path: filepath.Join(awsgwDir, "awsgw.toml"), Template: awsgwTomlTemplate},
{Name: filepath.Join(natsDir, "nats.conf"), Path: filepath.Join(natsDir, "nats.conf"), Template: natsConfTemplate},
}
@@ -754,7 +754,7 @@ func runAdminInit(cmd *cobra.Command, args []string) {
fmt.Println("✅ AWS credentials configured")
}
admin.CreateServiceDirectories(hiveRoot)
admin.CreateServiceDirectories(spxRoot)
// In production layout (running as root), fix ownership so the service user
// can read config and write data. SUDO_USER identifies the operator account.
@@ -762,7 +762,7 @@ func runAdminInit(cmd *cobra.Command, args []string) {
sudoUser := os.Getenv("SUDO_USER")
if sudoUser != "" {
admin.ChownRecursive(configDir, sudoUser)
admin.ChownRecursive(hiveRoot, sudoUser)
admin.ChownRecursive(spxRoot, sudoUser)
}
}
@@ -773,12 +773,12 @@ func runAdminInit(cmd *cobra.Command, args []string) {
fmt.Println(" ./scripts/start-dev.sh")
fmt.Println()
fmt.Println(" 2. Test with AWS CLI:")
fmt.Println(" export AWS_PROFILE=hive")
fmt.Println(" export AWS_PROFILE=spinifex")
fmt.Println(" aws ec2 describe-instances")
fmt.Println()
fmt.Println("🔗 Configuration:")
fmt.Printf(" Config file: %s\n", hiveTomlPath)
fmt.Printf(" Data directory: %s\n", hiveRoot)
fmt.Printf(" Config file: %s\n", spinifexTomlPath)
fmt.Printf(" Data directory: %s\n", spxRoot)
fmt.Println()
}
@@ -786,7 +786,7 @@ func runAdminInit(cmd *cobra.Command, args []string) {
// It starts a formation server, registers this node, waits for all nodes to join,
// then generates configs with complete cluster topology.
func runAdminInitMultiNode(cmd *cobra.Command, accessKey, secretKey, accountID, natsToken, clusterName,
configDir, hiveRoot, certPath, region, az, node, bindIP, clusterBind string,
configDir, spxRoot, certPath, region, az, node, bindIP, clusterBind string,
port, expectedNodes int, formationTimeoutStr string, services []string) {
formationTimeout, err := time.ParseDuration(formationTimeoutStr)
@@ -860,7 +860,7 @@ func runAdminInitMultiNode(cmd *cobra.Command, accessKey, secretKey, accountID,
fmt.Printf("\n📡 Formation server started on %s\n", formationAddr)
fmt.Printf(" Waiting for %d more node(s) to join...\n", expectedNodes-1)
fmt.Printf(" Other nodes should run: hive admin join --host %s --node <name> --bind <ip>\n\n", formationAddr)
fmt.Printf(" Other nodes should run: spx admin join --host %s --node <name> --bind <ip>\n\n", formationAddr)
// Wait for all nodes to register
if err := fs.WaitForCompletion(formationTimeout); err != nil {
@@ -882,9 +882,9 @@ func runAdminInitMultiNode(cmd *cobra.Command, accessKey, secretKey, accountID,
awsgwDir := filepath.Join(configDir, "awsgw")
predastoreDir := filepath.Join(configDir, "predastore")
natsDir := filepath.Join(configDir, "nats")
hiveDir := filepath.Join(configDir, "hive")
spinifexDir := filepath.Join(configDir, "spinifex")
for _, dir := range []string{awsgwDir, predastoreDir, natsDir, hiveDir} {
for _, dir := range []string{awsgwDir, predastoreDir, natsDir, spinifexDir} {
if err := os.MkdirAll(dir, 0700); err != nil {
fmt.Fprintf(os.Stderr, "Error creating directory %s: %v\n", dir, err)
os.Exit(1)
@@ -912,7 +912,7 @@ func runAdminInitMultiNode(cmd *cobra.Command, accessKey, secretKey, accountID,
fmt.Printf("✅ Created: multi-node predastore.toml (node ID: %d)\n", predastoreNodeID)
}
hiveTomlPath := filepath.Join(configDir, "hive.toml")
spinifexTomlPath := filepath.Join(configDir, "spinifex.toml")
configSettings := admin.ConfigSettings{
AccessKey: accessKey,
@@ -920,7 +920,7 @@ func runAdminInitMultiNode(cmd *cobra.Command, accessKey, secretKey, accountID,
AccountID: accountID,
Region: region,
NatsToken: natsToken,
DataDir: hiveRoot,
DataDir: spxRoot,
ConfigDir: configDir,
Node: node,
@@ -938,7 +938,7 @@ func runAdminInitMultiNode(cmd *cobra.Command, accessKey, secretKey, accountID,
// Generate config files
configs := []admin.ConfigFile{
{Name: "hive.toml", Path: hiveTomlPath, Template: hiveTomlTemplate},
{Name: "spinifex.toml", Path: spinifexTomlPath, Template: spinifexTomlTemplate},
{Name: filepath.Join(awsgwDir, "awsgw.toml"), Path: filepath.Join(awsgwDir, "awsgw.toml"), Template: awsgwTomlTemplate},
{Name: filepath.Join(natsDir, "nats.conf"), Path: filepath.Join(natsDir, "nats.conf"), Template: natsConfTemplate},
}
@@ -962,7 +962,7 @@ func runAdminInitMultiNode(cmd *cobra.Command, accessKey, secretKey, accountID,
fmt.Println("✅ AWS credentials configured")
}
admin.CreateServiceDirectories(hiveRoot)
admin.CreateServiceDirectories(spxRoot)
// Keep formation server running briefly so joining nodes can fetch complete status
fmt.Println("\n⏳ Waiting for joining nodes to fetch cluster data...")
@@ -1061,7 +1061,7 @@ func runAdminJoin(cmd *cobra.Command, args []string) {
resp, err := client.Post(joinURL, "application/json", bytes.NewBuffer(reqBody))
if err != nil {
fmt.Fprintf(os.Stderr, "❌ Error connecting to formation server: %v\n", err)
fmt.Fprintf(os.Stderr, "Make sure the leader node has run 'hive admin init' and is accessible at %s\n", leaderHost)
fmt.Fprintf(os.Stderr, "Make sure the leader node has run 'spx admin init' and is accessible at %s\n", leaderHost)
os.Exit(1)
}
@@ -1188,9 +1188,9 @@ func runAdminJoin(cmd *cobra.Command, args []string) {
awsgwDir := filepath.Join(configDir, "awsgw")
predastoreDir := filepath.Join(configDir, "predastore")
natsDir := filepath.Join(configDir, "nats")
hiveDir := filepath.Join(configDir, "hive")
spinifexDir := filepath.Join(configDir, "spinifex")
for _, dir := range []string{awsgwDir, predastoreDir, natsDir, hiveDir} {
for _, dir := range []string{awsgwDir, predastoreDir, natsDir, spinifexDir} {
if err := os.MkdirAll(dir, 0700); err != nil {
fmt.Fprintf(os.Stderr, "Error creating directory %s: %v\n", dir, err)
os.Exit(1)
@@ -1224,7 +1224,7 @@ func runAdminJoin(cmd *cobra.Command, args []string) {
fmt.Printf("✅ Created: multi-node predastore.toml (node ID: %d)\n", predastoreNodeID)
}
hiveTomlPath := filepath.Join(configDir, "hive.toml")
spinifexTomlPath := filepath.Join(configDir, "spinifex.toml")
configSettings := admin.ConfigSettings{
AccessKey: creds.AccessKey,
@@ -1250,7 +1250,7 @@ func runAdminJoin(cmd *cobra.Command, args []string) {
// Generate config files
configs := []admin.ConfigFile{
{Name: "hive.toml", Path: hiveTomlPath, Template: hiveTomlTemplate},
{Name: "spinifex.toml", Path: spinifexTomlPath, Template: spinifexTomlTemplate},
{Name: filepath.Join(awsgwDir, "awsgw.toml"), Path: filepath.Join(awsgwDir, "awsgw.toml"), Template: awsgwTomlTemplate},
{Name: filepath.Join(natsDir, "nats.conf"), Path: filepath.Join(natsDir, "nats.conf"), Template: natsConfTemplate},
}
@@ -1291,7 +1291,7 @@ func runAdminJoin(cmd *cobra.Command, args []string) {
}
// buildRemoteNodes converts formation NodeInfo into RemoteNode entries,
// excluding the local node. This puts all cluster members into hive.toml
// excluding the local node. This puts all cluster members into spinifex.toml
// so config is the source of truth for expected cluster membership.
func buildRemoteNodes(allNodes map[string]formation.NodeInfo, localNode string) []admin.RemoteNode {
var remote []admin.RemoteNode
@@ -1409,7 +1409,7 @@ func runAccountCreate(cmd *cobra.Command, args []string) {
}
// Configure AWS CLI profile automatically
profileName := "hive-" + strings.ToLower(strings.ReplaceAll(name, " ", "-"))
profileName := "spinifex-" + strings.ToLower(strings.ReplaceAll(name, " ", "-"))
homeDir, _ := os.UserHomeDir()
endpointHost := "localhost"
+1 -1
View File
@@ -75,7 +75,7 @@ func loadConfigAndConnect() (*config.ClusterConfig, *nats.Conn, error) {
}
// Backfill BaseDir from config file path when not set in the config.
// Config lives at <baseDir>/config/hive.toml, so baseDir is two levels up.
// Config lives at <baseDir>/config/spinifex.toml, so baseDir is two levels up.
if nodeConfig, ok := cfg.Nodes[cfg.Node]; ok && nodeConfig.BaseDir == "" {
nodeConfig.BaseDir = filepath.Dir(filepath.Dir(cfgPath))
cfg.Nodes[cfg.Node] = nodeConfig
+12 -12
View File
@@ -6,37 +6,37 @@ import (
)
// DefaultConfigDir returns the default configuration directory.
// Production: /etc/hive (when running as root or /etc/hive exists)
// Development: ~/hive/config
// Production: /etc/spinifex (when running as root or /etc/spinifex exists)
// Development: ~/spinifex/config
func DefaultConfigDir() string {
if isProductionLayout() {
return "/etc/hive"
return "/etc/spinifex"
}
homeDir, _ := os.UserHomeDir()
return filepath.Join(homeDir, "hive", "config")
return filepath.Join(homeDir, "spinifex", "config")
}
// DefaultDataDir returns the default data directory.
// Production: /var/lib/hive
// Development: ~/hive
// Production: /var/lib/spinifex
// Development: ~/spinifex
func DefaultDataDir() string {
if isProductionLayout() {
return "/var/lib/hive"
return "/var/lib/spinifex"
}
homeDir, _ := os.UserHomeDir()
return filepath.Join(homeDir, "hive")
return filepath.Join(homeDir, "spinifex")
}
// DefaultConfigFile returns the default path to hive.toml.
// DefaultConfigFile returns the default path to spinifex.toml.
func DefaultConfigFile() string {
return filepath.Join(DefaultConfigDir(), "hive.toml")
return filepath.Join(DefaultConfigDir(), "spinifex.toml")
}
// isProductionLayout returns true when running in a production install.
// Detected by: running as root, or /etc/hive directory exists.
// Detected by: running as root, or /etc/spinifex directory exists.
func isProductionLayout() bool {
if os.Getuid() == 0 {
if info, err := os.Stat("/etc/hive"); err == nil && info.IsDir() {
if info, err := os.Stat("/etc/spinifex"); err == nil && info.IsDir() {
return true
}
}
+4 -4
View File
@@ -7,13 +7,13 @@ import (
)
func TestDefaultConfigDir_Dev(t *testing.T) {
// Non-root user without /etc/hive should get dev paths
// Non-root user without /etc/spinifex should get dev paths
if os.Getuid() == 0 {
t.Skip("test requires non-root user")
}
homeDir, _ := os.UserHomeDir()
expected := filepath.Join(homeDir, "hive", "config")
expected := filepath.Join(homeDir, "spinifex", "config")
got := DefaultConfigDir()
if got != expected {
t.Errorf("DefaultConfigDir() = %q, want %q", got, expected)
@@ -26,7 +26,7 @@ func TestDefaultDataDir_Dev(t *testing.T) {
}
homeDir, _ := os.UserHomeDir()
expected := filepath.Join(homeDir, "hive")
expected := filepath.Join(homeDir, "spinifex")
got := DefaultDataDir()
if got != expected {
t.Errorf("DefaultDataDir() = %q, want %q", got, expected)
@@ -40,7 +40,7 @@ func TestDefaultConfigFile(t *testing.T) {
got := DefaultConfigFile()
homeDir, _ := os.UserHomeDir()
expected := filepath.Join(homeDir, "hive", "config", "hive.toml")
expected := filepath.Join(homeDir, "spinifex", "config", "spinifex.toml")
if got != expected {
t.Errorf("DefaultConfigFile() = %q, want %q", got, expected)
}
+8 -8
View File
@@ -64,38 +64,38 @@ func init() {
// Global flags
rootCmd.PersistentFlags().String("config", "", "config file (required)")
viper.BindEnv("config", "HIVE_CONFIG_PATH")
viper.BindEnv("config", "SPINIFEX_CONFIG_PATH")
viper.BindPFlag("config", rootCmd.PersistentFlags().Lookup("config"))
// Authentication (access_key, secret)
rootCmd.PersistentFlags().String("access-key", "", "AWS access key (overrides config file and env)")
viper.BindEnv("access-key", "HIVE_ACCESS_KEY")
viper.BindEnv("access-key", "SPINIFEX_ACCESS_KEY")
viper.BindPFlag("access-key", rootCmd.PersistentFlags().Lookup("access-key"))
rootCmd.PersistentFlags().String("secret-key", "", "AWS secret key (overrides config file and env)")
viper.BindEnv("secret-key", "HIVE_SECRET_KEY")
viper.BindEnv("secret-key", "SPINIFEX_SECRET_KEY")
viper.BindPFlag("secret-key", rootCmd.PersistentFlags().Lookup("secret-key"))
rootCmd.PersistentFlags().String("host", "", "AWS Endpoint (overrides config file and env)")
viper.BindEnv("host", "HIVE_HOST")
viper.BindEnv("host", "SPINIFEX_HOST")
viper.BindPFlag("host", rootCmd.PersistentFlags().Lookup("host"))
// Viperblock config
rootCmd.PersistentFlags().String("base-dir", "", "Viperblock base directory (overrides config file and env)")
viper.BindEnv("base-dir", "HIVE_BASE_DIR")
viper.BindEnv("base-dir", "SPINIFEX_BASE_DIR")
viper.BindPFlag("base-dir", rootCmd.PersistentFlags().Lookup("base-dir"))
// NATS specific flags
rootCmd.PersistentFlags().String("nats-host", "", "NATS server host (overrides config file and env)")
viper.BindEnv("nats-host", "HIVE_NATS_HOST")
viper.BindEnv("nats-host", "SPINIFEX_NATS_HOST")
viper.BindPFlag("nats-host", rootCmd.PersistentFlags().Lookup("nats-host"))
rootCmd.PersistentFlags().String("nats-token", "", "NATS authentication token (overrides config file and env)")
viper.BindEnv("nats-token", "HIVE_NATS_TOKEN")
viper.BindEnv("nats-token", "SPINIFEX_NATS_TOKEN")
viper.BindPFlag("nats-token", rootCmd.PersistentFlags().Lookup("nats-token"))
rootCmd.PersistentFlags().String("nats-subject", "", "NATS subscription subject (overrides config file and env)")
viper.BindEnv("nats-subject", "HIVE_NATS_SUBJECT")
viper.BindEnv("nats-subject", "SPINIFEX_NATS_SUBJECT")
viper.BindPFlag("nats-subject", rootCmd.PersistentFlags().Lookup("nats-subject"))
// Bind flags to viper
+28 -28
View File
@@ -745,7 +745,7 @@ var vpcdStatusCmd = &cobra.Command{
func init() {
viper.SetEnvPrefix("HIVE") // Prefix for environment variables
viper.SetEnvPrefix("SPINIFEX") // Prefix for environment variables
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
viper.AutomaticEnv() // Read environment variables automatically
@@ -756,47 +756,47 @@ func init() {
// Predastore Port
predastoreCmd.PersistentFlags().Int("port", 8443, "Predastore (S3) port")
viper.BindEnv("port", "HIVE_PREDASTORE_PORT")
viper.BindEnv("port", "SPINIFEX_PREDASTORE_PORT")
viper.BindPFlag("port", predastoreCmd.PersistentFlags().Lookup("port"))
// Predastore Host
predastoreCmd.PersistentFlags().String("host", "0.0.0.0", "Predastore (S3) host")
viper.BindEnv("host", "HIVE_PREDASTORE_HOST")
viper.BindEnv("host", "SPINIFEX_PREDASTORE_HOST")
viper.BindPFlag("host", predastoreCmd.PersistentFlags().Lookup("host"))
// Base path
predastoreCmd.PersistentFlags().String("base-path", "", "Predastore (S3) base path")
viper.BindEnv("base-path", "HIVE_PREDASTORE_BASE_PATH")
viper.BindEnv("base-path", "SPINIFEX_PREDASTORE_BASE_PATH")
viper.BindPFlag("base-path", predastoreCmd.PersistentFlags().Lookup("base-path"))
// Predastore Config Path
predastoreCmd.PersistentFlags().String("config-path", "", "Predastore (S3) config path")
viper.BindEnv("config-path", "HIVE_PREDASTORE_CONFIG_PATH")
viper.BindEnv("config-path", "SPINIFEX_PREDASTORE_CONFIG_PATH")
viper.BindPFlag("config-path", predastoreCmd.PersistentFlags().Lookup("config-path"))
// Predastore Debug
predastoreCmd.PersistentFlags().Bool("debug", false, "Predastore (S3) debug")
viper.BindEnv("debug", "HIVE_PREDASTORE_DEBUG")
viper.BindEnv("debug", "SPINIFEX_PREDASTORE_DEBUG")
viper.BindPFlag("debug", predastoreCmd.PersistentFlags().Lookup("debug"))
// Predastore TLS Cert
predastoreCmd.PersistentFlags().String("tls-cert", "", "Predastore (S3) TLS certificate")
viper.BindEnv("tls-cert", "HIVE_PREDASTORE_TLS_CERT")
viper.BindEnv("tls-cert", "SPINIFEX_PREDASTORE_TLS_CERT")
viper.BindPFlag("tls-cert", predastoreCmd.PersistentFlags().Lookup("tls-cert"))
// Predastore TLS Key
predastoreCmd.PersistentFlags().String("tls-key", "", "Predastore (S3) TLS key")
viper.BindEnv("tls-key", "HIVE_PREDASTORE_TLS_KEY")
viper.BindEnv("tls-key", "SPINIFEX_PREDASTORE_TLS_KEY")
viper.BindPFlag("tls-key", predastoreCmd.PersistentFlags().Lookup("tls-key"))
// Predastore Backend
predastoreCmd.PersistentFlags().String("backend", "distributed", "Predastore (S3) backend")
viper.BindEnv("backend", "HIVE_PREDASTORE_BACKEND")
viper.BindEnv("backend", "SPINIFEX_PREDASTORE_BACKEND")
viper.BindPFlag("backend", predastoreCmd.PersistentFlags().Lookup("backend"))
// Predastore Node ID
predastoreCmd.PersistentFlags().Int("node-id", 0, "Predastore (S3) node ID")
viper.BindEnv("node-id", "HIVE_PREDASTORE_NODE_ID")
viper.BindEnv("node-id", "SPINIFEX_PREDASTORE_NODE_ID")
viper.BindPFlag("node-id", predastoreCmd.PersistentFlags().Lookup("node-id"))
// Predastore CPU Profiling
@@ -816,19 +816,19 @@ func init() {
serviceCmd.AddCommand(viperblockCmd)
viperblockCmd.PersistentFlags().String("s3-host", "0.0.0.0:8443", "Predastore (S3) host URI")
viper.BindEnv("s3-host", "HIVE_VIPERBLOCK_S3_HOST")
viper.BindEnv("s3-host", "SPINIFEX_VIPERBLOCK_S3_HOST")
viper.BindPFlag("s3-host", predastoreCmd.PersistentFlags().Lookup("s3-host"))
viperblockCmd.PersistentFlags().String("s3-bucket", "predastore", "Predastore (S3) bucket")
viper.BindEnv("s3-bucket", "HIVE_VIPERBLOCK_S3_BUCKET")
viper.BindEnv("s3-bucket", "SPINIFEX_VIPERBLOCK_S3_BUCKET")
viper.BindPFlag("s3-bucket", predastoreCmd.PersistentFlags().Lookup("s3-bucket"))
viperblockCmd.PersistentFlags().String("s3-region", "ap-southeast-2", "Predastore (S3) region")
viper.BindEnv("s3-region", "HIVE_VIPERBLOCK_S3_REGION")
viper.BindEnv("s3-region", "SPINIFEX_VIPERBLOCK_S3_REGION")
viper.BindPFlag("s3-region", predastoreCmd.PersistentFlags().Lookup("s3-region"))
viperblockCmd.PersistentFlags().String("plugin-path", "/opt/spinifex/lib/nbdkit-viperblock-plugin.so", "Pathname to the nbdkit viperblockplugin")
viper.BindEnv("plugin-path", "HIVE_VIPERBLOCK_PLUGIN_PATH")
viper.BindEnv("plugin-path", "SPINIFEX_VIPERBLOCK_PLUGIN_PATH")
viper.BindPFlag("plugin-path", predastoreCmd.PersistentFlags().Lookup("plugin-path"))
viperblockCmd.AddCommand(viperblockStartCmd)
@@ -844,23 +844,23 @@ func init() {
// Add NATS flags
natsCmd.PersistentFlags().Int("port", 4222, "NATS server port")
viper.BindEnv("port", "HIVE_NATS_PORT")
viper.BindEnv("port", "SPINIFEX_NATS_PORT")
viper.BindPFlag("port", natsCmd.PersistentFlags().Lookup("port"))
natsCmd.PersistentFlags().String("host", "0.0.0.0", "NATS server host")
viper.BindEnv("host", "HIVE_NATS_HOST")
viper.BindEnv("host", "SPINIFEX_NATS_HOST")
viper.BindPFlag("host", natsCmd.PersistentFlags().Lookup("host"))
natsCmd.PersistentFlags().Bool("debug", false, "Enable debug logging")
viper.BindEnv("debug", "HIVE_NATS_DEBUG")
viper.BindEnv("debug", "SPINIFEX_NATS_DEBUG")
viper.BindPFlag("debug", natsCmd.PersistentFlags().Lookup("debug"))
natsCmd.PersistentFlags().String("data-dir", "", "NATS data directory")
viper.BindEnv("data-dir", "HIVE_NATS_DATA_DIR")
viper.BindEnv("data-dir", "SPINIFEX_NATS_DATA_DIR")
viper.BindPFlag("data-dir", natsCmd.PersistentFlags().Lookup("data-dir"))
natsCmd.PersistentFlags().Bool("jetstream", false, "Enable JetStream")
viper.BindEnv("jetstream", "HIVE_NATS_JETSTREAM")
viper.BindEnv("jetstream", "SPINIFEX_NATS_JETSTREAM")
viper.BindPFlag("jetstream", natsCmd.PersistentFlags().Lookup("jetstream"))
// Hive
@@ -871,28 +871,28 @@ func init() {
spinifexCmd.AddCommand(spinifexStatusCmd)
spinifexCmd.PersistentFlags().String("wal-dir", "", "Write-ahead log (WAL) directory. Place on high-speed NVMe disk, or tmpfs for development.")
viper.BindEnv("wal-dir", "HIVE_WAL_DIR")
viper.BindEnv("wal-dir", "SPINIFEX_WAL_DIR")
viper.BindPFlag("wal-dir", spinifexCmd.PersistentFlags().Lookup("wal-dir"))
// AWS GW
serviceCmd.AddCommand(awsgwCmd)
awsgwCmd.PersistentFlags().String("host", "0.0.0.0:9999", "AWS Gateway server host")
viper.BindEnv("host", "HIVE_AWSGW_HOST")
viper.BindEnv("host", "SPINIFEX_AWSGW_HOST")
viper.BindPFlag("host", awsgwCmd.PersistentFlags().Lookup("host"))
// AWS GW TLS Cert
awsgwCmd.PersistentFlags().String("tls-cert", "", "AWS Gateway TLS certificate")
viper.BindEnv("tls-cert", "HIVE_AWSGW_TLS_CERT")
viper.BindEnv("tls-cert", "SPINIFEX_AWSGW_TLS_CERT")
viper.BindPFlag("tls-cert", awsgwCmd.PersistentFlags().Lookup("tls-cert"))
// AWS GW TLS Key
awsgwCmd.PersistentFlags().String("tls-key", "", "AWS Gateway TLS key")
viper.BindEnv("tls-key", "HIVE_AWSGW_TLS_KEY")
viper.BindEnv("tls-key", "SPINIFEX_AWSGW_TLS_KEY")
viper.BindPFlag("tls-key", awsgwCmd.PersistentFlags().Lookup("tls-key"))
awsgwCmd.PersistentFlags().Bool("debug", false, "AWS Gateway Debug")
viper.BindEnv("debug", "HIVE_AWSGW_DEBUG")
viper.BindEnv("debug", "SPINIFEX_AWSGW_DEBUG")
viper.BindPFlag("debug", awsgwCmd.PersistentFlags().Lookup("debug"))
awsgwCmd.AddCommand(awsgwStartCmd)
@@ -903,19 +903,19 @@ func init() {
serviceCmd.AddCommand(spinifexUICmd)
spinifexUICmd.PersistentFlags().Int("port", 3000, "spinifex-ui server port")
viper.BindEnv("spinifex-ui-port", "HIVE_UI_PORT")
viper.BindEnv("spinifex-ui-port", "SPINIFEX_UI_PORT")
viper.BindPFlag("spinifex-ui-port", spinifexUICmd.PersistentFlags().Lookup("port"))
spinifexUICmd.PersistentFlags().String("host", "0.0.0.0", "spinifex-ui server host")
viper.BindEnv("spinifex-ui-host", "HIVE_UI_HOST")
viper.BindEnv("spinifex-ui-host", "SPINIFEX_UI_HOST")
viper.BindPFlag("spinifex-ui-host", spinifexUICmd.PersistentFlags().Lookup("host"))
spinifexUICmd.PersistentFlags().String("tls-cert", "", "TLS certificate path")
viper.BindEnv("spinifex-ui-tls-cert", "HIVE_UI_TLS_CERT")
viper.BindEnv("spinifex-ui-tls-cert", "SPINIFEX_UI_TLS_CERT")
viper.BindPFlag("spinifex-ui-tls-cert", spinifexUICmd.PersistentFlags().Lookup("tls-cert"))
spinifexUICmd.PersistentFlags().String("tls-key", "", "TLS key path")
viper.BindEnv("spinifex-ui-tls-key", "HIVE_UI_TLS_KEY")
viper.BindEnv("spinifex-ui-tls-key", "SPINIFEX_UI_TLS_KEY")
viper.BindPFlag("spinifex-ui-tls-key", spinifexUICmd.PersistentFlags().Lookup("tls-key"))
spinifexUICmd.AddCommand(spinifexUIStartCmd)
+2 -2
View File
@@ -1,5 +1,5 @@
# NATS Server Configuration
# Generated by Hive admin init
# Generated by Spinifex admin init
# Server configuration
{{- if .BindIP }}
@@ -22,7 +22,7 @@ cluster {
}
{{- end }}
server_name: hive-nats-{{.Node}}
server_name: spinifex-nats-{{.Node}}
# Authorization
authorization {
+1 -1
View File
@@ -145,7 +145,7 @@ func GenerateCertificatesIfNeeded(configDir string, force bool, bindIP string) (
// Print instructions for adding CA to system trust store
fmt.Println("\n📋 To trust the Hive CA system-wide (recommended):")
fmt.Printf(" sudo cp %s /usr/local/share/ca-certificates/hive-ca.crt\n", caCertPath)
fmt.Printf(" sudo cp %s /usr/local/share/ca-certificates/spinifex-ca.crt\n", caCertPath)
fmt.Println(" sudo update-ca-certificates")
fmt.Println("\n This allows AWS CLI and other tools to trust Hive services automatically.")
} else {
+2 -2
View File
@@ -12,7 +12,7 @@ import (
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
Version string `mapstructure:"version"` // spinifex version
Nodes map[string]Config `mapstructure:"nodes"` // full config for every node
}
@@ -134,7 +134,7 @@ func (c Config) GetServices() []string {
// LoadConfig loads the configuration from file and environment variables
func LoadConfig(configPath string) (*ClusterConfig, error) {
// Set environment variable prefix
viper.SetEnvPrefix("HIVE")
viper.SetEnvPrefix("SPINIFEX")
viper.AutomaticEnv()
// Try to load config file if it exists
+8 -8
View File
@@ -17,7 +17,7 @@ func resetViper(t *testing.T) {
func TestLoadConfig_ValidTOMLFile(t *testing.T) {
resetViper(t)
dir := t.TempDir()
path := filepath.Join(dir, "hive.toml")
path := filepath.Join(dir, "spinifex.toml")
toml := `
version = "1.0"
@@ -66,7 +66,7 @@ region = "us-east-1"
func TestLoadConfig_MultipleNodes(t *testing.T) {
resetViper(t)
dir := t.TempDir()
path := filepath.Join(dir, "hive.toml")
path := filepath.Join(dir, "spinifex.toml")
toml := `
epoch = 2
@@ -100,7 +100,7 @@ func TestLoadConfig_EmptyConfigPath(t *testing.T) {
func TestLoadConfig_NonexistentFile(t *testing.T) {
resetViper(t)
cfg, err := LoadConfig("/tmp/nonexistent-hive-config-test-12345.toml")
cfg, err := LoadConfig("/tmp/nonexistent-spinifex-config-test-12345.toml")
// Not an error - falls through to defaults
require.NoError(t, err)
require.NotNil(t, cfg)
@@ -137,7 +137,7 @@ epoch = 5
func TestLoadConfig_EnvVarOverrideWithFile(t *testing.T) {
resetViper(t)
dir := t.TempDir()
path := filepath.Join(dir, "hive.toml")
path := filepath.Join(dir, "spinifex.toml")
// Viper's AutomaticEnv only works for keys Viper already knows about
// (from a config file or explicit BindEnv). Provide a minimal config
@@ -146,7 +146,7 @@ func TestLoadConfig_EnvVarOverrideWithFile(t *testing.T) {
node = "file-node"
`), 0600))
t.Setenv("HIVE_NODE", "env-node")
t.Setenv("SPINIFEX_NODE", "env-node")
cfg, err := LoadConfig(path)
require.NoError(t, err)
@@ -305,7 +305,7 @@ func TestNodeBaseDir_EmptyBaseDir(t *testing.T) {
func TestLoadConfig_ViperblockShardWAL_Explicit(t *testing.T) {
resetViper(t)
dir := t.TempDir()
path := filepath.Join(dir, "hive.toml")
path := filepath.Join(dir, "spinifex.toml")
toml := `
node = "n1"
@@ -329,7 +329,7 @@ shardwal = false
func TestLoadConfig_ViperblockShardWAL_DefaultNil(t *testing.T) {
resetViper(t)
dir := t.TempDir()
path := filepath.Join(dir, "hive.toml")
path := filepath.Join(dir, "spinifex.toml")
toml := `
node = "n1"
@@ -349,7 +349,7 @@ region = "us-east-1"
func TestLoadConfig_ViperblockShardWAL_True(t *testing.T) {
resetViper(t)
dir := t.TempDir()
path := filepath.Join(dir, "hive.toml")
path := filepath.Join(dir, "spinifex.toml")
toml := `
node = "n1"
+1 -1
View File
@@ -15,7 +15,7 @@ import (
// pidDir returns the directory containing shell-level PID files for this node.
// start-dev.sh writes PID files to $DATA_DIR/logs/ and the daemon's BaseDir is
// always $DATA_DIR/hive/, so we derive the logs directory from that. Each node
// always $DATA_DIR/spinifex/, so we derive the logs directory from that. Each node
// has its own DATA_DIR, so this is safe for simulated multi-node on a single host.
func (d *Daemon) pidDir() string {
if d.config.BaseDir != "" {
+1 -1
View File
@@ -43,7 +43,7 @@ func GeneratePidFile(name string) (string, error) {
func WritePidFile(name string, pid int) error {
// Write PID to file, check XDG, otherwise user home directory ~/hive/
// Write PID to file, check XDG, otherwise user home directory ~/spinifex/
pidFilename, err := GeneratePidFile(name)
if err != nil {