quality / commitlint (push) Skipped
quality / changes (push) Successful in 8s
quality / docker-check (push) Skipped
quality / openapi (push) Successful in 26s
quality / web (push) Successful in 1m27s
quality / go (push) Successful in 1m18s
quality / bird2 (push) Successful in 16s
CD / quality (push) Successful in 3m43s
CD / publish (push) Successful in 3m11s
- Enhanced the speaker installation documentation to clarify the use of TCP port 179 and the logging commands for monitoring BIRD and evobgp-agent. - Updated the speaker form dialog to include additional information about MikroTik connections and logging commands. - Modified the BIRD configuration to include logging to stderr for better visibility during operations. - Adjusted the Docker Compose configuration to ensure proper network settings and sysctl configurations for BGP functionality.
199 lines
6.4 KiB
Go
199 lines
6.4 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestPostSpeaker_defaultsFromEndpointIP(t *testing.T) {
|
|
srv, err := New(Options{InsecureDev: true, SeedDemo: true, BundleSeedHex: testBundleSeed})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer srv.Close()
|
|
tenant, _, _, _, _ := srv.Store().DemoIDs()
|
|
mustSetTestAPIKeys(t, srv, "edkey|"+tenant+"|editor")
|
|
|
|
body := `{"endpoint":"https://203.0.113.55:8443","role":"replica"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/v1/speakers", strings.NewReader(body))
|
|
req.Header.Set("Authorization", "Bearer edkey")
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
srv.Handler().ServeHTTP(rec, req)
|
|
if rec.Code != http.StatusCreated {
|
|
t.Fatalf("status %d body %s", rec.Code, rec.Body.String())
|
|
}
|
|
var out map[string]any
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &out); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if out["agent_secret"] == nil || out["agent_secret"] == "" {
|
|
t.Fatal("expected agent_secret on create")
|
|
}
|
|
if out["node_token"] == nil || out["node_token"] == "" {
|
|
t.Fatal("expected node_token on replica create")
|
|
}
|
|
if out["node_ipv4"] != "203.0.113.55" {
|
|
t.Fatalf("node_ipv4: %#v", out["node_ipv4"])
|
|
}
|
|
if out["bird_bgp_source_ipv4"] != "203.0.113.55" {
|
|
t.Fatalf("bird_bgp_source_ipv4: %#v", out["bird_bgp_source_ipv4"])
|
|
}
|
|
install, _ := out["install"].(map[string]any)
|
|
if install == nil {
|
|
t.Fatal("expected install on replica create")
|
|
}
|
|
cmd, _ := install["docker_commands"].(string)
|
|
if !strings.Contains(cmd, "traefik") || !strings.Contains(cmd, "dnschallenge") {
|
|
t.Fatalf("docker_commands missing traefik dns challenge: %s", cmd[:min(200, len(cmd))])
|
|
}
|
|
}
|
|
|
|
func TestDeleteSpeaker(t *testing.T) {
|
|
srv, err := New(Options{InsecureDev: true, SeedDemo: true, BundleSeedHex: testBundleSeed})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer srv.Close()
|
|
tenant, _, _, _, demoSpk := srv.Store().DemoIDs()
|
|
mustSetTestAPIKeys(t, srv, "edkey|"+tenant+"|editor")
|
|
|
|
req := httptest.NewRequest(http.MethodDelete, "/v1/speakers/"+demoSpk, nil)
|
|
req.Header.Set("Authorization", "Bearer edkey")
|
|
rec := httptest.NewRecorder()
|
|
srv.Handler().ServeHTTP(rec, req)
|
|
if rec.Code != http.StatusNoContent {
|
|
t.Fatalf("status %d body %s", rec.Code, rec.Body.String())
|
|
}
|
|
if _, err := srv.Store().GetSpeaker(tenant, demoSpk); err == nil {
|
|
t.Fatal("speaker should be deleted")
|
|
}
|
|
}
|
|
|
|
func TestGetBundleSigningPublicKey(t *testing.T) {
|
|
srv, err := New(Options{InsecureDev: true, SeedDemo: true, BundleSeedHex: testBundleSeed})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer srv.Close()
|
|
tenant, _, _, _, _ := srv.Store().DemoIDs()
|
|
mustSetTestAPIKeys(t, srv, "vwkey|"+tenant+"|viewer")
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/v1/bundle/signing-public-key", nil)
|
|
req.Header.Set("Authorization", "Bearer vwkey")
|
|
rec := httptest.NewRecorder()
|
|
srv.Handler().ServeHTTP(rec, req)
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status %d body %s", rec.Code, rec.Body.String())
|
|
}
|
|
var out map[string]any
|
|
_ = json.Unmarshal(rec.Body.Bytes(), &out)
|
|
if out["public_key_base64"] == nil || out["public_key_base64"] == "" {
|
|
t.Fatalf("missing public_key_base64: %#v", out)
|
|
}
|
|
}
|
|
|
|
func TestPostSpeaker_installCommandsAndMetaObject(t *testing.T) {
|
|
srv, err := New(Options{InsecureDev: true, SeedDemo: true, BundleSeedHex: testBundleSeed})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer srv.Close()
|
|
tenant, _, _, _, _ := srv.Store().DemoIDs()
|
|
mustSetTestAPIKeys(t, srv, "edkey|"+tenant+"|editor")
|
|
|
|
body := `{
|
|
"endpoint":"https://bgp-dc2.example.com",
|
|
"role":"replica",
|
|
"meta_json":{"agent_domain":"bgp-dc2.example.com","node_ipv4":"203.0.113.10"},
|
|
"letsencrypt_email":"ops@example.com",
|
|
"cf_dns_api_token":"cf-token-xyz",
|
|
"panel_ip_whitelist":"203.0.113.1/32",
|
|
"control_plane_url":"https://cp.example.com"
|
|
}`
|
|
req := httptest.NewRequest(http.MethodPost, "/v1/speakers", strings.NewReader(body))
|
|
req.Header.Set("Authorization", "Bearer edkey")
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
h := srv.Handler()
|
|
h.ServeHTTP(rec, req)
|
|
if rec.Code != http.StatusCreated {
|
|
t.Fatalf("status %d body %s", rec.Code, rec.Body.String())
|
|
}
|
|
var out map[string]any
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &out); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
id, _ := out["id"].(string)
|
|
if id == "" {
|
|
t.Fatal("missing id")
|
|
}
|
|
secret, _ := out["agent_secret"].(string)
|
|
token, _ := out["node_token"].(string)
|
|
pub, _ := out["bundle_pubkey_base64"].(string)
|
|
if secret == "" || token == "" || pub == "" {
|
|
t.Fatalf("missing one-shot secrets: %#v", out)
|
|
}
|
|
install, _ := out["install"].(map[string]any)
|
|
cmd, _ := install["docker_commands"].(string)
|
|
for _, want := range []string{
|
|
"traefik",
|
|
"dnschallenge=true",
|
|
"dnschallenge.provider=cloudflare",
|
|
"CF_DNS_API_TOKEN",
|
|
"cf-token-xyz",
|
|
"Host(`bgp-dc2.example.com`)",
|
|
secret,
|
|
token,
|
|
"https://cp.example.com",
|
|
`"179:179/tcp"`,
|
|
} {
|
|
if !strings.Contains(cmd, want) {
|
|
t.Errorf("docker_commands missing %q", want)
|
|
}
|
|
}
|
|
|
|
get := httptest.NewRequest(http.MethodGet, "/v1/speakers/"+id, nil)
|
|
get.Header.Set("Authorization", "Bearer edkey")
|
|
grec := httptest.NewRecorder()
|
|
h.ServeHTTP(grec, get)
|
|
if grec.Code != http.StatusOK {
|
|
t.Fatalf("GET status %d body %s", grec.Code, grec.Body.String())
|
|
}
|
|
got := grec.Body.String()
|
|
if strings.Contains(got, secret) || strings.Contains(got, token) || strings.Contains(got, "docker_commands") {
|
|
t.Fatalf("GET must not leak install secrets: %s", got)
|
|
}
|
|
}
|
|
|
|
func TestPostSpeaker_masterSkipsInstall(t *testing.T) {
|
|
srv, err := New(Options{InsecureDev: true, SeedDemo: true, BundleSeedHex: testBundleSeed})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer srv.Close()
|
|
tenant, _, _, _, _ := srv.Store().DemoIDs()
|
|
mustSetTestAPIKeys(t, srv, "edkey|"+tenant+"|editor")
|
|
|
|
body := `{"endpoint":"https://127.0.0.1:8080","role":"master"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/v1/speakers", strings.NewReader(body))
|
|
req.Header.Set("Authorization", "Bearer edkey")
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
srv.Handler().ServeHTTP(rec, req)
|
|
if rec.Code != http.StatusCreated {
|
|
t.Fatalf("status %d body %s", rec.Code, rec.Body.String())
|
|
}
|
|
var out map[string]any
|
|
_ = json.Unmarshal(rec.Body.Bytes(), &out)
|
|
if out["node_token"] != nil {
|
|
t.Fatalf("master must not mint node_token: %#v", out["node_token"])
|
|
}
|
|
if out["install"] != nil {
|
|
t.Fatalf("master must not include install: %#v", out["install"])
|
|
}
|
|
}
|