Commit ed637679 authored by jan.koester's avatar jan.koester
Browse files

test

parent c20437ad
Loading
Loading
Loading
Loading
Loading
+55 −0
Changes for data/admin.html: 55 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
                <li><a href="#" onclick="loadServices(); return false;">Services</a></li>
                <li><a href="#" onclick="loadGpos(); return false;">Policies</a></li>
                <li><a href="#" onclick="loadSessions(); return false;">Sessions</a></li>
                <li id="nav-cluster" style="display:none"><a href="#" onclick="loadClusterStatus(); return false;">Cluster</a></li>
                <li><a href="#" onclick="doLogout(); return false;">Logout</a></li>
            </ul>
        </div>
@@ -50,6 +51,7 @@
<script>
var currentDomain = "admin";
var currentView = null;
var g_clusterEnabled = false;

function ajaxGet(url, callback) {
    var xhr = new XMLHttpRequest();
@@ -992,6 +994,52 @@ function submitEditGpo(gpid) {
    });
}

/* ---- Cluster Status ---- */
function loadClusterStatus() {
    currentView = loadClusterStatus;
    loadDomainSelector(function() {
        ajaxGet("/settings/" + currentDomain + "/api/clusterstatus", function(err, data) {
            if (err) { showError(err); return; }
            if (!data.enabled) {
                setContent('<p>Cluster mode is not enabled.</p>');
                return;
            }
            var statusClass = 'msg-ok';
            if (data.status === 'DEGRADED') statusClass = 'msg-error';
            else if (data.status === 'REBUILD') statusClass = 'msg-error';

            var html = '<h3>Cluster Status</h3>';
            html += '<table class="admin-table">';
            html += '<tr><th>Property</th><th>Value</th></tr>';
            html += '<tr><td>Overall Status</td><td class="' + statusClass + '">' + data.status + '</td></tr>';
            html += '<tr><td>Nodes Total</td><td>' + data.nodes_total + '</td></tr>';
            html += '<tr><td>Nodes Online</td><td>' + data.nodes_online + '</td></tr>';
            html += '</table>';

            if (data.nodes && data.nodes.length > 0) {
                html += '<h4>Node Details</h4>';
                html += '<table class="admin-table">';
                html += '<tr><th>Node</th><th>Status</th><th>Blocks</th><th>Groups</th><th>Peers Online</th></tr>';
                for (var i = 0; i < data.nodes.length; i++) {
                    var n = data.nodes[i];
                    var nclass = (n.status === 'OK') ? 'msg-ok' : 'msg-error';
                    html += '<tr>';
                    html += '<td>Node ' + n.index + '</td>';
                    html += '<td class="' + nclass + '">' + n.status + '</td>';
                    html += '<td>' + n.blocks + '</td>';
                    html += '<td>' + n.groups + '</td>';
                    html += '<td>' + n.peers_online + ' / ' + n.peers_total + '</td>';
                    html += '</tr>';
                }
                html += '</table>';
            }

            html += '<p style="margin-top:1em"><a class="button" href="#" onclick="loadClusterStatus(); return false;">Refresh</a></p>';
            setContent(html);
        });
    });
}

/* ---- Logout ---- */
function doLogout() {
    ajaxPost("/settings/api/logout", {}, function(err, data) {
@@ -1001,6 +1049,13 @@ function doLogout() {

/* ---- Initial load ---- */
window.onload = function() {
    // Check if cluster mode is active, show nav item if so
    ajaxGet("/settings/admin/api/checkpermissions", function(err, data) {
        if (!err && data && data.cluster) {
            g_clusterEnabled = true;
            document.getElementById('nav-cluster').style.display = '';
        }
    });
    loadUsers();
};
</script>
+60 −0
Changes for src/admin.cpp: 60 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@
#include "import.h"
#include "plugin.h"
#include "service.h"
#include "cluster.h"

namespace authdb {

@@ -574,6 +575,63 @@ namespace authdb {
            // 0 = File, 2 = ClusterStore
            json_object_object_add(jobj, "backendtype", json_object_new_int(_AdminBackend.getType()));

            // Cluster info: indicate whether cluster mode is active
            bool clusterActive = (g_Cluster && g_Cluster->isRunning());
            json_object_object_add(jobj, "cluster", json_object_new_boolean(clusterActive));

            sendJson(curreq, jobj);
            json_object_put(jobj);
        }

        /* ---- JSON API: Cluster Status ---- */
        void apiClusterStatus(libhttppp::HttpRequest &curreq) {
            json_object *jobj = json_object_new_object();

            if (!g_Cluster || !g_Cluster->isRunning()) {
                json_object_object_add(jobj, "enabled", json_object_new_boolean(false));
                sendJson(curreq, jobj);
                json_object_put(jobj);
                return;
            }

            json_object_object_add(jobj, "enabled", json_object_new_boolean(true));

            auto &pclient = g_Cluster->getClient();
            if (pclient) {
                std::lock_guard<std::mutex> lock(g_Cluster->getClientMutex());
                auto health = pclient->get_cluster_status();

                const char *statusStr = "OK";
                if (health.overall == paritypp::node_status::DEGRADED)
                    statusStr = "DEGRADED";
                else if (health.overall == paritypp::node_status::REBUILD)
                    statusStr = "REBUILD";

                json_object_object_add(jobj, "status", json_object_new_string(statusStr));
                json_object_object_add(jobj, "nodes_total", json_object_new_int(health.nodes_total));
                json_object_object_add(jobj, "nodes_online", json_object_new_int(health.nodes_online));

                json_object *jnodes = json_object_new_array();
                for (const auto &[idx, info] : health.node_statuses) {
                    json_object *jn = json_object_new_object();
                    json_object_object_add(jn, "index", json_object_new_int(static_cast<int>(idx)));

                    const char *nstat = "OK";
                    if (info.status == paritypp::node_status::DEGRADED)
                        nstat = "DEGRADED";
                    else if (info.status == paritypp::node_status::REBUILD)
                        nstat = "REBUILD";

                    json_object_object_add(jn, "status", json_object_new_string(nstat));
                    json_object_object_add(jn, "blocks", json_object_new_int(info.block_count));
                    json_object_object_add(jn, "groups", json_object_new_int(info.group_count));
                    json_object_object_add(jn, "peers_total", json_object_new_int(info.peers_total));
                    json_object_object_add(jn, "peers_online", json_object_new_int(info.peers_online));
                    json_object_array_add(jnodes, jn);
                }
                json_object_object_add(jobj, "nodes", jnodes);
            }

            sendJson(curreq, jobj);
            json_object_put(jobj);
        }
@@ -1997,6 +2055,8 @@ namespace authdb {
                    } else if (strcmp(apiurl, "vacuum") == 0) {
                        checkDomainAccess(sdat, domain);
                        apiVacuum(curreq, domain);
                    } else if (strcmp(apiurl, "clusterstatus") == 0) {
                        apiClusterStatus(curreq);
                    } else {
                        sendJsonError(curreq, "Unknown API endpoint", 404);
                    }