Healthcheck updates, UI to remove wierd bar
This commit is contained in:
@@ -317,6 +317,15 @@ func (app *App) nodesPatchHandler(writer http.ResponseWriter, request *http.Requ
|
||||
node,
|
||||
fmt.Sprintf("health_check_interval_seconds=%d", node.HealthCheckIntervalSeconds),
|
||||
)
|
||||
|
||||
if node.HealthCheckIntervalSeconds > 0 && app.HealthChecker != nil {
|
||||
nodeID := node.ID
|
||||
actor := user.Username
|
||||
go func() {
|
||||
_, _ = app.HealthChecker.CheckNodeByID(nodeID, actor)
|
||||
}()
|
||||
}
|
||||
|
||||
writeJSON(writer, http.StatusOK, nodeResponse{Node: node})
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@ import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"codeberg.org/SquidSE/ClusterCanvas/service/internal/auth"
|
||||
)
|
||||
@@ -171,6 +173,154 @@ func TestNodesPatchHealthInterval(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodesPatchHealthIntervalTriggersBackgroundCheck(t *testing.T) {
|
||||
configDir := t.TempDir()
|
||||
cookie := seedCompletedSetup(t, configDir)
|
||||
router, app := NewRouterWithApp(configDir)
|
||||
|
||||
app.HealthChecker.PingFn = func(hostIP string) auth.PingResult {
|
||||
return auth.PingResult{OK: true, Method: auth.PingMethodICMP}
|
||||
}
|
||||
app.HealthChecker.SSHFn = func(hostIP string, username string, privateKeyPEM string, passphrase string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
const nodeID = "ffffffff-bbbb-4ccc-8ddd-eeeeeeeeeeee"
|
||||
createBody := []byte(`{
|
||||
"id":"` + nodeID + `",
|
||||
"kind":"container",
|
||||
"name":"bg-check-node",
|
||||
"host_ip":"10.20.30.44",
|
||||
"group_name":"Administrators",
|
||||
"generate":{"algorithm":"ed25519"}
|
||||
}`)
|
||||
createRequest := withSession(
|
||||
httptest.NewRequest(http.MethodPost, "/api/v1/nodes", bytes.NewReader(createBody)),
|
||||
cookie,
|
||||
)
|
||||
createRecorder := httptest.NewRecorder()
|
||||
router.ServeHTTP(createRecorder, createRequest)
|
||||
if createRecorder.Code != http.StatusCreated {
|
||||
t.Fatalf("create status = %d body=%s", createRecorder.Code, createRecorder.Body.String())
|
||||
}
|
||||
|
||||
patchBody := []byte(`{"health_check_interval_seconds":60}`)
|
||||
patchRequest := withSession(
|
||||
httptest.NewRequest(
|
||||
http.MethodPatch,
|
||||
"/api/v1/nodes/"+nodeID,
|
||||
bytes.NewReader(patchBody),
|
||||
),
|
||||
cookie,
|
||||
)
|
||||
patchRecorder := httptest.NewRecorder()
|
||||
router.ServeHTTP(patchRecorder, patchRequest)
|
||||
if patchRecorder.Code != http.StatusOK {
|
||||
t.Fatalf("patch status = %d body=%s", patchRecorder.Code, patchRecorder.Body.String())
|
||||
}
|
||||
|
||||
deadline := time.Now().Add(2 * time.Second)
|
||||
for {
|
||||
getRequest := withSession(
|
||||
httptest.NewRequest(http.MethodGet, "/api/v1/nodes/"+nodeID, nil),
|
||||
cookie,
|
||||
)
|
||||
getRecorder := httptest.NewRecorder()
|
||||
router.ServeHTTP(getRecorder, getRequest)
|
||||
if getRecorder.Code != http.StatusOK {
|
||||
t.Fatalf("get status = %d body=%s", getRecorder.Code, getRecorder.Body.String())
|
||||
}
|
||||
|
||||
var response nodeResponse
|
||||
if err := json.Unmarshal(getRecorder.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("decode: %v", err)
|
||||
}
|
||||
if response.Node.HealthOK != nil && *response.Node.HealthOK {
|
||||
return
|
||||
}
|
||||
if time.Now().After(deadline) {
|
||||
t.Fatalf("timed out waiting for background health check, node=%#v", response.Node)
|
||||
}
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodesPatchHealthIntervalZeroSkipsBackgroundCheck(t *testing.T) {
|
||||
configDir := t.TempDir()
|
||||
cookie := seedCompletedSetup(t, configDir)
|
||||
router, app := NewRouterWithApp(configDir)
|
||||
|
||||
checked := atomic.Bool{}
|
||||
app.HealthChecker.PingFn = func(hostIP string) auth.PingResult {
|
||||
checked.Store(true)
|
||||
return auth.PingResult{OK: true, Method: auth.PingMethodICMP}
|
||||
}
|
||||
app.HealthChecker.SSHFn = func(hostIP string, username string, privateKeyPEM string, passphrase string) error {
|
||||
checked.Store(true)
|
||||
return nil
|
||||
}
|
||||
|
||||
const nodeID = "aaaaaaaa-cccc-4ddd-8eee-ffffffffffff"
|
||||
createBody := []byte(`{
|
||||
"id":"` + nodeID + `",
|
||||
"kind":"vm",
|
||||
"name":"no-bg-check-node",
|
||||
"host_ip":"10.20.30.45",
|
||||
"group_name":"Administrators",
|
||||
"generate":{"algorithm":"ed25519"}
|
||||
}`)
|
||||
createRequest := withSession(
|
||||
httptest.NewRequest(http.MethodPost, "/api/v1/nodes", bytes.NewReader(createBody)),
|
||||
cookie,
|
||||
)
|
||||
createRecorder := httptest.NewRecorder()
|
||||
router.ServeHTTP(createRecorder, createRequest)
|
||||
if createRecorder.Code != http.StatusCreated {
|
||||
t.Fatalf("create status = %d body=%s", createRecorder.Code, createRecorder.Body.String())
|
||||
}
|
||||
|
||||
patchBody := []byte(`{"health_check_interval_seconds":0}`)
|
||||
patchRequest := withSession(
|
||||
httptest.NewRequest(
|
||||
http.MethodPatch,
|
||||
"/api/v1/nodes/"+nodeID,
|
||||
bytes.NewReader(patchBody),
|
||||
),
|
||||
cookie,
|
||||
)
|
||||
patchRecorder := httptest.NewRecorder()
|
||||
router.ServeHTTP(patchRecorder, patchRequest)
|
||||
if patchRecorder.Code != http.StatusOK {
|
||||
t.Fatalf("patch status = %d body=%s", patchRecorder.Code, patchRecorder.Body.String())
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
getRequest := withSession(
|
||||
httptest.NewRequest(http.MethodGet, "/api/v1/nodes/"+nodeID, nil),
|
||||
cookie,
|
||||
)
|
||||
getRecorder := httptest.NewRecorder()
|
||||
router.ServeHTTP(getRecorder, getRequest)
|
||||
if getRecorder.Code != http.StatusOK {
|
||||
t.Fatalf("get status = %d body=%s", getRecorder.Code, getRecorder.Body.String())
|
||||
}
|
||||
|
||||
var response nodeResponse
|
||||
if err := json.Unmarshal(getRecorder.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("decode: %v", err)
|
||||
}
|
||||
if checked.Load() {
|
||||
t.Fatal("expected no background health check when interval is 0")
|
||||
}
|
||||
if response.Node.HealthOK != nil {
|
||||
t.Fatalf("expected health_ok unset, got %#v", response.Node.HealthOK)
|
||||
}
|
||||
if response.Node.HealthLastCheckedAt != nil {
|
||||
t.Fatalf("expected health_last_checked_at unset, got %#v", response.Node.HealthLastCheckedAt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodesPatchHealthIntervalRejectsNegative(t *testing.T) {
|
||||
configDir := t.TempDir()
|
||||
cookie := seedCompletedSetup(t, configDir)
|
||||
|
||||
Reference in New Issue
Block a user