mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 09:01:31 +00:00
108 lines
2.8 KiB
Go
108 lines
2.8 KiB
Go
//go:build e2e
|
|
|
|
package harness
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
// Node identifies a single cluster member addressable over SSH and HTTPS.
|
|
// Index is 1-based; scenarios reference nodes by index so ordering is fixed.
|
|
type Node struct {
|
|
Index int // 1-based position in the cluster
|
|
Name string // human-readable tag, e.g. "node1"
|
|
Addr string // IP or hostname; used for SSH and as peer address for partition rules
|
|
}
|
|
|
|
// Cluster is an ordered set of Nodes plus shared SSH credentials.
|
|
type Cluster struct {
|
|
Nodes []Node
|
|
SSHUser string
|
|
SSHKeyPath string
|
|
}
|
|
|
|
// Peers returns every node in the cluster except target. The result is used
|
|
// by fault.PartitionNode to build per-peer iptables DROP rules.
|
|
func (c *Cluster) Peers(target Node) []Node {
|
|
out := make([]Node, 0, len(c.Nodes)-1)
|
|
for _, n := range c.Nodes {
|
|
if n.Index == target.Index {
|
|
continue
|
|
}
|
|
out = append(out, n)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// ClusterFromEnv builds a Cluster from SPINIFEX_NODES / SPINIFEX_SSH_USER /
|
|
// SPINIFEX_SSH_KEY. Returns an error if any required variable is missing.
|
|
func ClusterFromEnv() (*Cluster, error) {
|
|
nodesRaw := envWithLegacy("SPINIFEX_NODES", "DDIL_NODES")
|
|
user := envWithLegacy("SPINIFEX_SSH_USER", "DDIL_SSH_USER")
|
|
key := envWithLegacy("SPINIFEX_SSH_KEY", "DDIL_SSH_KEY")
|
|
|
|
var missing []string
|
|
if nodesRaw == "" {
|
|
missing = append(missing, "SPINIFEX_NODES")
|
|
}
|
|
if user == "" {
|
|
missing = append(missing, "SPINIFEX_SSH_USER")
|
|
}
|
|
if key == "" {
|
|
missing = append(missing, "SPINIFEX_SSH_KEY")
|
|
}
|
|
if len(missing) > 0 {
|
|
return nil, fmt.Errorf("e2e harness: missing required env: %s", strings.Join(missing, ", "))
|
|
}
|
|
|
|
var nodes []Node
|
|
for i, addr := range strings.Split(nodesRaw, ",") {
|
|
addr = strings.TrimSpace(addr)
|
|
if addr == "" {
|
|
continue
|
|
}
|
|
nodes = append(nodes, Node{
|
|
Index: i + 1,
|
|
Name: fmt.Sprintf("node%d", i+1),
|
|
Addr: addr,
|
|
})
|
|
}
|
|
if len(nodes) == 0 {
|
|
return nil, errors.New("e2e harness: SPINIFEX_NODES contained no addresses")
|
|
}
|
|
|
|
return &Cluster{
|
|
Nodes: nodes,
|
|
SSHUser: user,
|
|
SSHKeyPath: key,
|
|
}, nil
|
|
}
|
|
|
|
// NodeFromEnv returns the Nth node (1-based) from the cluster in SPINIFEX_NODES.
|
|
func NodeFromEnv(index int) (Node, error) {
|
|
c, err := ClusterFromEnv()
|
|
if err != nil {
|
|
return Node{}, err
|
|
}
|
|
if index < 1 || index > len(c.Nodes) {
|
|
return Node{}, fmt.Errorf("e2e harness: node index %d out of range (have %d nodes)", index, len(c.Nodes))
|
|
}
|
|
return c.Nodes[index-1], nil
|
|
}
|
|
|
|
// envWithLegacy returns os.Getenv(canonical), falling back to legacy on miss.
|
|
// A stderr note flags use of the deprecated DDIL_* names.
|
|
func envWithLegacy(canonical, legacy string) string {
|
|
if v := os.Getenv(canonical); v != "" {
|
|
return v
|
|
}
|
|
if v := os.Getenv(legacy); v != "" {
|
|
fmt.Fprintf(os.Stderr, "e2e harness: %s is deprecated; set %s instead\n", legacy, canonical)
|
|
return v
|
|
}
|
|
return ""
|
|
}
|