Skip to content

Commit fc6194b

Browse files
feat: Rest endoint /health for rln (#2011)
* Rest endoint /health added * Remove dev-debug echo * Changed not ready message * Update waku/node/rest/health/handlers.nim Co-authored-by: Ivan Folgueira Bande <128452529+Ivansete-status@users.noreply.github.com> * Various fixes on PR foundings, added comments --------- Co-authored-by: Ivan Folgueira Bande <128452529+Ivansete-status@users.noreply.github.com>
1 parent a8095d8 commit fc6194b

File tree

6 files changed

+196
-1
lines changed

6 files changed

+196
-1
lines changed

apps/wakunode2/app.nim

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import
4747
../../waku/node/rest/relay/topic_cache,
4848
../../waku/node/rest/filter/handlers as rest_filter_api,
4949
../../waku/node/rest/store/handlers as rest_store_api,
50+
../../waku/node/rest/health/handlers as rest_health_api,
5051
../../waku/node/jsonrpc/admin/handlers as rpc_admin_api,
5152
../../waku/node/jsonrpc/debug/handlers as rpc_debug_api,
5253
../../waku/node/jsonrpc/filter/handlers as rpc_filter_api,
@@ -569,6 +570,9 @@ proc startRestServer(app: App, address: ValidIpAddress, port: Port, conf: WakuNo
569570
## Debug REST API
570571
installDebugApiHandlers(server.router, app.node)
571572

573+
## Health REST API
574+
installHealthApiHandler(server.router, app.node)
575+
572576
## Relay REST API
573577
if conf.relay:
574578
let relayCache = TopicCache.init(capacity=conf.restRelayCacheCapacity)

tests/all_tests_waku.nim

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,5 @@ when defined(rln):
102102
./waku_rln_relay/test_waku_rln_relay,
103103
./waku_rln_relay/test_wakunode_rln_relay,
104104
./waku_rln_relay/test_rln_group_manager_onchain,
105-
./waku_rln_relay/test_rln_group_manager_static
105+
./waku_rln_relay/test_rln_group_manager_static,
106+
./wakunode_rest/test_rest_health
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
{.used.}
2+
3+
import
4+
std/tempfiles,
5+
stew/shims/net,
6+
testutils/unittests,
7+
presto,
8+
presto/client as presto_client,
9+
libp2p/peerinfo,
10+
libp2p/multiaddress,
11+
libp2p/crypto/crypto
12+
import
13+
../../waku/waku_node,
14+
../../waku/node/waku_node as waku_node2, # TODO: Remove after moving `git_version` to the app code.
15+
../../waku/node/rest/server,
16+
../../waku/node/rest/client,
17+
../../waku/node/rest/responses,
18+
../../waku/node/rest/health/handlers as health_api,
19+
../../waku/node/rest/health/client as health_api_client,
20+
../../waku/waku_rln_relay,
21+
../testlib/common,
22+
../testlib/wakucore,
23+
../testlib/wakunode
24+
25+
26+
proc testWakuNode(): WakuNode =
27+
let
28+
privkey = crypto.PrivateKey.random(Secp256k1, rng[]).tryGet()
29+
bindIp = ValidIpAddress.init("0.0.0.0")
30+
extIp = ValidIpAddress.init("127.0.0.1")
31+
port = Port(0)
32+
33+
newTestWakuNode(privkey, bindIp, port, some(extIp), some(port))
34+
35+
36+
suite "Waku v2 REST API - health":
37+
asyncTest "Get node health info - GET /health":
38+
# Given
39+
let node = testWakuNode()
40+
await node.start()
41+
await node.mountRelay()
42+
43+
let restPort = Port(58001)
44+
let restAddress = ValidIpAddress.init("0.0.0.0")
45+
let restServer = RestServerRef.init(restAddress, restPort).tryGet()
46+
47+
installHealthApiHandler(restServer.router, node)
48+
restServer.start()
49+
let client = newRestHttpClient(initTAddress(restAddress, restPort))
50+
51+
# When
52+
var response = await client.healthCheck()
53+
54+
# Then
55+
check:
56+
response.status == 503
57+
$response.contentType == $MIMETYPE_TEXT
58+
response.data == "Node is not ready"
59+
60+
# now kick in rln (currently the only check for health)
61+
await node.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false,
62+
rlnRelayCredIndex: some(1.uint),
63+
rlnRelayTreePath: genTempPath("rln_tree", "wakunode"),
64+
))
65+
66+
# When
67+
response = await client.healthCheck()
68+
69+
# Then
70+
check:
71+
response.status == 200
72+
$response.contentType == $MIMETYPE_TEXT
73+
response.data == "Node is healthy"
74+
75+
await restServer.stop()
76+
await restServer.closeWait()
77+
await node.stop()

waku/node/rest/health/client.nim

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
when (NimMajor, NimMinor) < (1, 4):
2+
{.push raises: [Defect].}
3+
else:
4+
{.push raises: [].}
5+
6+
import
7+
chronicles,
8+
json_serialization,
9+
json_serialization/std/options,
10+
presto/[route, client]
11+
import
12+
../serdes,
13+
../responses
14+
15+
logScope:
16+
topics = "waku node rest health_api"
17+
18+
proc decodeBytes*(t: typedesc[string], value: openArray[byte],
19+
contentType: Opt[ContentTypeData]): RestResult[string] =
20+
if MediaType.init($contentType) != MIMETYPE_TEXT:
21+
error "Unsupported contentType value", contentType = contentType
22+
return err("Unsupported contentType")
23+
24+
var res: string
25+
if len(value) > 0:
26+
res = newString(len(value))
27+
copyMem(addr res[0], unsafeAddr value[0], len(value))
28+
return ok(res)
29+
30+
proc healthCheck*(): RestResponse[string] {.rest, endpoint: "/health", meth: HttpMethod.MethodGet.}

waku/node/rest/health/handlers.nim

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
when (NimMajor, NimMinor) < (1, 4):
2+
{.push raises: [Defect].}
3+
else:
4+
{.push raises: [].}
5+
6+
import
7+
chronicles,
8+
json_serialization,
9+
presto/route
10+
import
11+
../../waku_node,
12+
../responses,
13+
../serdes
14+
15+
logScope:
16+
topics = "waku node rest health_api"
17+
18+
const ROUTE_HEALTH* = "/health"
19+
20+
const FutIsReadyTimout = 5.seconds
21+
22+
proc installHealthApiHandler*(router: var RestRouter, node: WakuNode) =
23+
## /health endpoint provides information about node readiness to caller.
24+
## Currently it is restricted to checking RLN (if mounted) proper setup
25+
## TODO: Leter to extend it to a broader information about each subsystem state
26+
## report. Rest response to change to JSON structure that can hold exact detailed
27+
## information.
28+
29+
router.api(MethodGet, ROUTE_HEALTH) do () -> RestApiResponse:
30+
31+
let isReadyStateFut = node.isReady()
32+
if not await isReadyStateFut.withTimeout(FutIsReadyTimout):
33+
return RestApiResponse.internalServerError("Health check timed out")
34+
35+
var msg = "Node is healthy"
36+
var status = Http200
37+
38+
if not isReadyStateFut.read():
39+
msg = "Node is not ready"
40+
status = Http503
41+
42+
return RestApiResponse.textResponse(msg, status)

waku/node/rest/health/openapi.yaml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
openapi: 3.0.3
2+
info:
3+
title: Waku V2 node REST API
4+
version: 1.0.0
5+
contact:
6+
name: VAC Team
7+
url: https://forum.vac.dev/
8+
9+
tags:
10+
- name: health
11+
description: Healt check REST API for WakuV2 node
12+
13+
paths:
14+
/health:
15+
get:
16+
summary: Get node health status
17+
description: Retrieve readiness of a Waku v2 node.
18+
operationId: healthcheck
19+
tags:
20+
- health
21+
responses:
22+
'200':
23+
description: Waku v2 node is up and running.
24+
content:
25+
text/plain:
26+
schema:
27+
type: string
28+
example: Node is healty
29+
'500':
30+
description: Internal server error
31+
content:
32+
text/plain:
33+
schema:
34+
type: string
35+
'503':
36+
description: Node not initialized or having issues
37+
content:
38+
text/plain:
39+
schema:
40+
type: string
41+
example: Node is not initialized

0 commit comments

Comments
 (0)