mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-09-05 22:32:55 +02:00
Implements structured JSON diagnostic output for node state export with full schema documentation. This feature provides machine-readable diagnostics for automated analysis, monitoring, and AI/MCP integration. Key changes: - Add `zerotier-cli diagnostic` command for JSON node state export - Add `zerotier-cli dump -j` as alias for JSON output - Add `zerotier-cli diagnostic --schema` to print JSON schema - Implement platform-specific interface collection (Linux, BSD, macOS, Windows) - Create modular diagnostic/ directory with isolated try/catch error handling - Add comprehensive JSON schema (diagnostic_schema.json) for validation - Include build-time schema embedding for offline access - Add Python and Rust scripts for schema embedding during build - Update build systems to compile new diagnostic modules The diagnostic output includes: - Node configuration and identity - Network memberships and settings - Interface states and IP addresses - Peer connections and statistics - Moon orbits - Controller networks (if applicable) All diagnostic collection is wrapped in try/catch blocks to ensure partial failures don't prevent overall output generation. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
97 lines
No EOL
3.9 KiB
C++
97 lines
No EOL
3.9 KiB
C++
#include "diagnostic/node_state_sections.hpp"
|
|
#include "osdep/Http.hpp"
|
|
#include "osdep/OSUtils.hpp"
|
|
#include <string>
|
|
#include <map>
|
|
|
|
void addNodeStateStatusJson(nlohmann::json& j, const ZeroTier::InetAddress& addr, std::map<std::string,std::string>& requestHeaders) {
|
|
try {
|
|
std::map<std::string, std::string> responseHeaders;
|
|
std::string responseBody;
|
|
unsigned int scode = ZeroTier::Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/status",requestHeaders,responseHeaders,responseBody);
|
|
if (scode == 200) {
|
|
try {
|
|
nlohmann::json status_json = ZeroTier::OSUtils::jsonParse(responseBody);
|
|
j["status"] = status_json;
|
|
if (status_json.contains("address")) {
|
|
j["nodeId"] = status_json["address"];
|
|
} else {
|
|
j["nodeId"] = nullptr;
|
|
}
|
|
} catch (const std::exception& e) {
|
|
j["status"] = { {"error", std::string("JSON parse error: ") + e.what()} };
|
|
j["nodeId"] = nullptr;
|
|
} catch (...) {
|
|
j["status"] = { {"error", "Unknown JSON parse error"} };
|
|
j["nodeId"] = nullptr;
|
|
}
|
|
} else {
|
|
j["status"] = { {"error", std::string("HTTP error ") + std::to_string(scode) + ": " + responseBody} };
|
|
j["nodeId"] = nullptr;
|
|
}
|
|
} catch (const std::exception& e) {
|
|
j["status"] = { {"error", std::string("Exception: ") + e.what()} };
|
|
j["nodeId"] = nullptr;
|
|
} catch (...) {
|
|
j["status"] = { {"error", "Unknown error retrieving /status"} };
|
|
j["nodeId"] = nullptr;
|
|
}
|
|
}
|
|
|
|
void addNodeStateNetworksJson(nlohmann::json& j, const ZeroTier::InetAddress& addr, std::map<std::string,std::string>& requestHeaders) {
|
|
try {
|
|
std::map<std::string, std::string> responseHeaders;
|
|
std::string responseBody;
|
|
unsigned int scode = ZeroTier::Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/network",requestHeaders,responseHeaders,responseBody);
|
|
if (scode == 200) {
|
|
try {
|
|
j["networks"] = ZeroTier::OSUtils::jsonParse(responseBody);
|
|
} catch (...) {
|
|
j["networks"] = responseBody;
|
|
}
|
|
} else {
|
|
j["networks_error"] = responseBody;
|
|
}
|
|
} catch (const std::exception& e) {
|
|
j["networks_error"] = std::string("Exception: ") + e.what();
|
|
} catch (...) {
|
|
j["networks_error"] = "Unknown error retrieving /network";
|
|
}
|
|
}
|
|
|
|
void addNodeStatePeersJson(nlohmann::json& j, const ZeroTier::InetAddress& addr, std::map<std::string,std::string>& requestHeaders) {
|
|
try {
|
|
std::map<std::string, std::string> responseHeaders;
|
|
std::string responseBody;
|
|
unsigned int scode = ZeroTier::Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/peer",requestHeaders,responseHeaders,responseBody);
|
|
if (scode == 200) {
|
|
try {
|
|
j["peers"] = ZeroTier::OSUtils::jsonParse(responseBody);
|
|
} catch (...) {
|
|
j["peers"] = responseBody;
|
|
}
|
|
} else {
|
|
j["peers_error"] = responseBody;
|
|
}
|
|
} catch (const std::exception& e) {
|
|
j["peers_error"] = std::string("Exception: ") + e.what();
|
|
} catch (...) {
|
|
j["peers_error"] = "Unknown error retrieving /peer";
|
|
}
|
|
}
|
|
|
|
void addNodeStateLocalConfJson(nlohmann::json& j, const std::string& homeDir) {
|
|
try {
|
|
std::string localConf;
|
|
ZeroTier::OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "local.conf").c_str(), localConf);
|
|
if (localConf.empty()) {
|
|
j["local_conf"] = nullptr;
|
|
} else {
|
|
j["local_conf"] = localConf;
|
|
}
|
|
} catch (const std::exception& e) {
|
|
j["local_conf"] = std::string("Exception: ") + e.what();
|
|
} catch (...) {
|
|
j["local_conf"] = "Unknown error retrieving local.conf";
|
|
}
|
|
}
|