mirror of
https://github.com/DeBrosOfficial/orama.git
synced 2026-03-17 06:43:01 +00:00
Bump version to 0.109.0 and add tests for TCP port waiting and Olric config YAML parsing
This commit is contained in:
parent
bb98418ac9
commit
aa2da83969
2
Makefile
2
Makefile
@ -63,7 +63,7 @@ test-e2e-quick:
|
|||||||
|
|
||||||
.PHONY: build clean test deps tidy fmt vet lint install-hooks redeploy-devnet redeploy-testnet release health
|
.PHONY: build clean test deps tidy fmt vet lint install-hooks redeploy-devnet redeploy-testnet release health
|
||||||
|
|
||||||
VERSION := 0.108.0
|
VERSION := 0.109.0
|
||||||
COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
|
COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
|
||||||
DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
|
DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||||
LDFLAGS := -X 'main.version=$(VERSION)' -X 'main.commit=$(COMMIT)' -X 'main.date=$(DATE)'
|
LDFLAGS := -X 'main.version=$(VERSION)' -X 'main.commit=$(COMMIT)' -X 'main.date=$(DATE)'
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
@ -12,6 +13,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/DeBrosOfficial/network/pkg/constants"
|
"github.com/DeBrosOfficial/network/pkg/constants"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrServiceNotFound = errors.New("service not found")
|
var ErrServiceNotFound = errors.New("service not found")
|
||||||
@ -325,13 +327,25 @@ func StartServicesOrdered(services []string, action string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// After starting all Olric instances for all namespaces, wait for them
|
// After starting all Olric instances, wait for each one's memberlist
|
||||||
// to bind their HTTP ports and form memberlist clusters before starting
|
// port to accept TCP connections before starting gateways. Without this,
|
||||||
// gateways. Without this, gateways start before Olric is ready and the
|
// gateways start before Olric is ready and the Olric client initialization
|
||||||
// Olric client initialization fails permanently.
|
// fails permanently (no retry).
|
||||||
if svcType == "olric" && len(svcs) > 0 {
|
if svcType == "olric" && len(svcs) > 0 {
|
||||||
fmt.Printf(" Waiting for namespace Olric instances to become ready...\n")
|
fmt.Printf(" Waiting for namespace Olric instances to become ready...\n")
|
||||||
time.Sleep(5 * time.Second)
|
for _, svc := range svcs {
|
||||||
|
ns := strings.TrimPrefix(svc, "orama-namespace-olric@")
|
||||||
|
port := getOlricMemberlistPort(ns)
|
||||||
|
if port <= 0 {
|
||||||
|
fmt.Printf(" ⚠️ Could not determine Olric memberlist port for namespace %s\n", ns)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := waitForTCPPort(port, 30*time.Second); err != nil {
|
||||||
|
fmt.Printf(" ⚠️ Olric memberlist port %d not ready for namespace %s: %v\n", port, ns, err)
|
||||||
|
} else {
|
||||||
|
fmt.Printf(" ✓ Olric ready for namespace %s (port %d)\n", ns, port)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,3 +359,62 @@ func StartServicesOrdered(services []string, action string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getOlricMemberlistPort reads a namespace's Olric config and returns the
|
||||||
|
// memberlist bind port. Returns 0 if the config cannot be read or parsed.
|
||||||
|
func getOlricMemberlistPort(namespace string) int {
|
||||||
|
envFile := filepath.Join("/opt/orama/.orama/data/namespaces", namespace, "olric.env")
|
||||||
|
f, err := os.Open(envFile)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
// Read OLRIC_SERVER_CONFIG path from env file
|
||||||
|
var configPath string
|
||||||
|
scanner := bufio.NewScanner(f)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := strings.TrimSpace(scanner.Text())
|
||||||
|
if strings.HasPrefix(line, "OLRIC_SERVER_CONFIG=") {
|
||||||
|
configPath = strings.TrimPrefix(line, "OLRIC_SERVER_CONFIG=")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if configPath == "" {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the YAML config to extract memberlist.bindPort
|
||||||
|
configData, err := os.ReadFile(configPath)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var cfg struct {
|
||||||
|
Memberlist struct {
|
||||||
|
BindPort int `yaml:"bindPort"`
|
||||||
|
} `yaml:"memberlist"`
|
||||||
|
}
|
||||||
|
if err := yaml.Unmarshal(configData, &cfg); err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg.Memberlist.BindPort
|
||||||
|
}
|
||||||
|
|
||||||
|
// waitForTCPPort polls a TCP port until it accepts connections or the timeout expires.
|
||||||
|
func waitForTCPPort(port int, timeout time.Duration) error {
|
||||||
|
addr := fmt.Sprintf("localhost:%d", port)
|
||||||
|
deadline := time.Now().Add(timeout)
|
||||||
|
|
||||||
|
for time.Now().Before(deadline) {
|
||||||
|
conn, err := net.DialTimeout("tcp", addr, 2*time.Second)
|
||||||
|
if err == nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("port %d did not become ready within %s", port, timeout)
|
||||||
|
}
|
||||||
|
|||||||
119
pkg/cli/utils/systemd_test.go
Normal file
119
pkg/cli/utils/systemd_test.go
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWaitForTCPPort_Success(t *testing.T) {
|
||||||
|
// Start a TCP listener on a random port
|
||||||
|
ln, err := net.Listen("tcp", "localhost:0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to start listener: %v", err)
|
||||||
|
}
|
||||||
|
defer ln.Close()
|
||||||
|
|
||||||
|
port := ln.Addr().(*net.TCPAddr).Port
|
||||||
|
|
||||||
|
err = waitForTCPPort(port, 5*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("expected success, got error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWaitForTCPPort_Timeout(t *testing.T) {
|
||||||
|
// Use a port that nothing is listening on
|
||||||
|
ln, err := net.Listen("tcp", "localhost:0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to get free port: %v", err)
|
||||||
|
}
|
||||||
|
port := ln.Addr().(*net.TCPAddr).Port
|
||||||
|
ln.Close() // Close immediately so nothing is listening
|
||||||
|
|
||||||
|
err = waitForTCPPort(port, 3*time.Second)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected timeout error, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWaitForTCPPort_DelayedStart(t *testing.T) {
|
||||||
|
// Get a free port
|
||||||
|
ln, err := net.Listen("tcp", "localhost:0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to get free port: %v", err)
|
||||||
|
}
|
||||||
|
port := ln.Addr().(*net.TCPAddr).Port
|
||||||
|
ln.Close()
|
||||||
|
|
||||||
|
// Start listening after a delay
|
||||||
|
go func() {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
newLn, err := net.Listen("tcp", ln.Addr().String())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer newLn.Close()
|
||||||
|
// Keep it open long enough for the test
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = waitForTCPPort(port, 10*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("expected success after delayed start, got error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOlricConfigYAMLParsing(t *testing.T) {
|
||||||
|
// Verify that the YAML parsing struct matches the format
|
||||||
|
// generated by pkg/namespace/systemd_spawner.go
|
||||||
|
configContent := `server:
|
||||||
|
bindAddr: 10.0.0.1
|
||||||
|
bindPort: 10002
|
||||||
|
memberlist:
|
||||||
|
environment: lan
|
||||||
|
bindAddr: 10.0.0.1
|
||||||
|
bindPort: 10003
|
||||||
|
peers:
|
||||||
|
- 10.0.0.2:10003
|
||||||
|
partitionCount: 12
|
||||||
|
`
|
||||||
|
|
||||||
|
var cfg struct {
|
||||||
|
Memberlist struct {
|
||||||
|
BindPort int `yaml:"bindPort"`
|
||||||
|
} `yaml:"memberlist"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := yaml.Unmarshal([]byte(configContent), &cfg); err != nil {
|
||||||
|
t.Fatalf("failed to parse Olric config YAML: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Memberlist.BindPort != 10003 {
|
||||||
|
t.Errorf("expected memberlist port 10003, got %d", cfg.Memberlist.BindPort)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOlricConfigYAMLParsing_MissingMemberlist(t *testing.T) {
|
||||||
|
// Config without memberlist section should return zero port
|
||||||
|
configContent := `server:
|
||||||
|
bindAddr: 10.0.0.1
|
||||||
|
bindPort: 10002
|
||||||
|
`
|
||||||
|
|
||||||
|
var cfg struct {
|
||||||
|
Memberlist struct {
|
||||||
|
BindPort int `yaml:"bindPort"`
|
||||||
|
} `yaml:"memberlist"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := yaml.Unmarshal([]byte(configContent), &cfg); err != nil {
|
||||||
|
t.Fatalf("unexpected parse error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Memberlist.BindPort != 0 {
|
||||||
|
t.Errorf("expected port 0 for missing memberlist, got %d", cfg.Memberlist.BindPort)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user