From e6aaa45957f7730ac6eb2df04c57a93230f03299 Mon Sep 17 00:00:00 2001
From: Georgy Moshkin <gmoshkin@picodata.io>
Date: Tue, 23 Jan 2024 16:10:20 +0300
Subject: [PATCH] feat: .proc_runtime_info

---
 src/info.rs             | 58 +++++++++++++++++++++++++++++++++++++++++
 test/int/test_basics.py | 23 ++++++++++++++++
 2 files changed, 81 insertions(+)

diff --git a/src/info.rs b/src/info.rs
index c5b057c461..27c89fdf53 100644
--- a/src/info.rs
+++ b/src/info.rs
@@ -4,6 +4,8 @@ use crate::replicaset::ReplicasetId;
 use crate::traft::error::Error;
 use crate::traft::node;
 use crate::traft::RaftId;
+use crate::traft::RaftIndex;
+use crate::traft::RaftTerm;
 use std::borrow::Cow;
 use tarantool::proc;
 
@@ -180,3 +182,59 @@ pub fn proc_raft_info() -> Result<RaftInfo, Error> {
 
     Ok(RaftInfo::get(node))
 }
+
+////////////////////////////////////////////////////////////////////////////////
+// InternalInfo
+////////////////////////////////////////////////////////////////////////////////
+
+#[derive(Clone, Debug, ::serde::Serialize, ::serde::Deserialize)]
+pub struct InternalInfo<'a> {
+    pub main_loop_status: Cow<'a, str>,
+    pub governor_loop_status: Cow<'a, str>,
+}
+
+impl tarantool::tuple::Encode for InternalInfo<'_> {}
+
+impl InternalInfo<'static> {
+    pub fn get(node: &node::Node) -> Self {
+        InternalInfo {
+            main_loop_status: node.status().main_loop_status.into(),
+            governor_loop_status: node.governor_loop.status.get().governor_loop_status.into(),
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RuntimeInfo
+////////////////////////////////////////////////////////////////////////////////
+
+/// Info returned from [`.proc_runtime_info`].
+///
+/// [`.proc_runtime_info`]: proc_runtime_info
+#[derive(Clone, Debug, ::serde::Serialize, ::serde::Deserialize)]
+pub struct RuntimeInfo<'a> {
+    pub raft: RaftInfo,
+    pub internal: InternalInfo<'a>,
+}
+
+impl tarantool::tuple::Encode for RuntimeInfo<'_> {}
+
+impl RuntimeInfo<'static> {
+    pub fn try_get(node: &node::Node) -> Result<Self, Error> {
+        Ok(RuntimeInfo {
+            raft: RaftInfo::get(node),
+            internal: InternalInfo::get(node),
+        })
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// .proc_runtime_info
+////////////////////////////////////////////////////////////////////////////////
+
+#[proc]
+pub fn proc_runtime_info() -> Result<RuntimeInfo<'static>, Error> {
+    let node = node::global()?;
+
+    RuntimeInfo::try_get(node)
+}
diff --git a/test/int/test_basics.py b/test/int/test_basics.py
index 5dd78ad268..fa62c73c27 100644
--- a/test/int/test_basics.py
+++ b/test/int/test_basics.py
@@ -390,3 +390,26 @@ def test_proc_raft_info(instance: Instance):
         leader_id=1,
         state="Leader",
     )
+
+
+def test_proc_runtime_info(instance: Instance):
+    info = instance.call(".proc_runtime_info")
+
+    assert isinstance(info["raft"]["applied"], int)
+    # This field is super volatile, don't want to be updating it every time we
+    # add a bootstrap entry.
+    info["raft"]["applied"] = 69
+
+    assert info == dict(
+        raft=dict(
+            id=1,
+            term=2,
+            applied=69,
+            leader_id=1,
+            state="Leader",
+        ),
+        internal=dict(
+            main_loop_status="idle",
+            governor_loop_status="idle",
+        ),
+    )
-- 
GitLab