From 3c9227080eb22f119a8c848aa14422f6d02f763a Mon Sep 17 00:00:00 2001 From: Yaroslav Dynnikov <yaroslav.dynnikov@gmail.com> Date: Mon, 17 Oct 2022 11:10:35 +0300 Subject: [PATCH] feature: new lua api: whoami, peer_info Example: ```console tarantool> picolib.whoami() --- - raft_id: 1 cluster_id: demo instance_id: i1 ... tarantool> picolib.peer_info("i1") --- - raft_id: 1 instance_id: i1 instance_uuid: 68d4a766-4144-3248-aeb4-e212356716e4 replicaset_uuid: e0df68c5-e7f9-395f-86b3-30ad9e1b7b07 replicaset_id: r1 advertise_address: localhost:3301 target_grade: Online current_grade: Online ... ``` --- src/main.rs | 33 +++++++++++++++++++++++++ test/int/test_basics.py | 23 ++++++++++++++++++ test/int/test_uninitialized.py | 44 ++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 test/int/test_uninitialized.py diff --git a/src/main.rs b/src/main.rs index 969ed8ce29..b6b7bfcd58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,6 +56,39 @@ fn picolib_setup(args: &args::Run) { luamod.set("VERSION", env!("CARGO_PKG_VERSION")); luamod.set("args", args); + luamod.set( + "whoami", + tlua::function0(|| -> Result<_, Error> { + let node = traft::node::global()?; + let raft_storage = &node.storage.raft; + + Ok(tlua::AsTable(( + ("raft_id", raft_storage.raft_id()?), + ("cluster_id", raft_storage.cluster_id()?), + ("instance_id", raft_storage.instance_id()?), + ))) + }), + ); + + luamod.set( + "peer_info", + tlua::function1(|iid: String| -> Result<_, Error> { + let node = traft::node::global()?; + let peer = node.storage.peers.get(&InstanceId::from(iid))?; + + Ok(tlua::AsTable(( + ("raft_id", peer.raft_id), + ("advertise_address", peer.peer_address), + ("instance_id", peer.instance_id.0), + ("instance_uuid", peer.instance_uuid), + ("replicaset_id", peer.replicaset_id), + ("replicaset_uuid", peer.replicaset_uuid), + ("current_grade", peer.current_grade), + ("target_grade", peer.target_grade), + ))) + }), + ); + luamod.set( "raft_status", tlua::function0(|| traft::node::global().map(|n| n.status())), diff --git a/test/int/test_basics.py b/test/int/test_basics.py index 57c8f48fb3..0e199994e6 100644 --- a/test/int/test_basics.py +++ b/test/int/test_basics.py @@ -173,3 +173,26 @@ def test_graceful_stop(instance: Instance): ) with open(os.path.join(instance.data_dir, last_xlog), "rb") as f: assert f.read()[-4:] == b"\xd5\x10\xad\xed" + + +def test_whoami(instance: Instance): + assert instance.call("picolib.whoami") == { + "raft_id": 1, + "instance_id": "i1", + "cluster_id": instance.cluster_id, + } + + +def test_peer_info(instance: Instance): + def peer_info(iid: str): + return instance.call("picolib.peer_info", iid) + + # Don't compare entire structure, a couple of fields is enough + myself = peer_info("i1") + assert myself["raft_id"] == 1 + assert myself["instance_id"] == "i1" + assert myself["replicaset_id"] == "r1" + + with pytest.raises(ReturnError) as e: + peer_info("i2") + assert e.value.args == ('peer with id "i2" not found',) diff --git a/test/int/test_uninitialized.py b/test/int/test_uninitialized.py new file mode 100644 index 0000000000..9e16a994aa --- /dev/null +++ b/test/int/test_uninitialized.py @@ -0,0 +1,44 @@ +import funcy # type: ignore +import pytest + +from typing import Any, Callable, Generator + +from conftest import ( + eprint, + Cluster, + Instance, + ReturnError, +) + + +@pytest.fixture +def uninitialized_instance(cluster: Cluster) -> Generator[Instance, None, None]: + """Returns a running instance that is stuck in discovery phase.""" + + # Connecting TCP/0 always results in "Connection refused" + instance = cluster.add_instance(peers=[":0"], wait_online=False) + instance.start() + + @funcy.retry(tries=30, timeout=0.2) + def wait_running(): + assert instance.eval("return box.info.status") == "running" + eprint(f"{instance} is running (but stuck in discovery phase)") + + wait_running() + yield instance + + +def test_raft_api(uninitialized_instance: Instance): + functions: list[Callable[[Instance], Any]] = [ + lambda i: i._raft_status(), + lambda i: i.call("picolib.raft_propose_nop"), + lambda i: i.call("picolib.raft_propose_info", "who cares"), + lambda i: i.call("picolib.whoami"), + lambda i: i.call("picolib.peer_info", "i1"), + lambda i: i.call("picolib.peer_info", "i2"), + ] + + for f in functions: + with pytest.raises(ReturnError) as e: + f(uninitialized_instance) + assert e.value.args == ("uninitialized yet",) -- GitLab