From 1ffadf31def8892b4273532199d201bc5d940275 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 14 May 2025 15:06:24 -0700 Subject: [PATCH] Get node OS/Arch info into the CV2 db --- controller/CV1.cpp | 30 +++++++++++------- controller/CV1.hpp | 5 +-- controller/CV2.cpp | 31 ++++++++++++------- controller/CV2.hpp | 3 +- controller/DB.hpp | 1 + controller/DBMirrorSet.cpp | 8 +++-- controller/DBMirrorSet.hpp | 3 +- controller/FileDB.cpp | 8 +++-- controller/FileDB.hpp | 3 +- controller/LFDB.cpp | 7 ++++- controller/LFDB.hpp | 3 +- controller/PostgreSQL.hpp | 6 ++++ .../migrations/0002_os_arch.down.sql | 3 ++ .../migrations/0002_os_arch.up.sql | 3 ++ 14 files changed, 81 insertions(+), 33 deletions(-) create mode 100644 ext/central-controller-docker/migrations/0002_os_arch.down.sql create mode 100644 ext/central-controller-docker/migrations/0002_os_arch.up.sql diff --git a/controller/CV1.cpp b/controller/CV1.cpp index f5d819fa7..ca0164b7d 100644 --- a/controller/CV1.cpp +++ b/controller/CV1.cpp @@ -286,14 +286,20 @@ void CV1::eraseMember(const uint64_t networkId, const uint64_t memberId) _memberChanged(tmp.first, nullJson, true); } -void CV1::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress) +void CV1::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress, const char *osArch) { std::lock_guard l(_lastOnline_l); - std::pair &i = _lastOnline[std::pair(networkId, memberId)]; - i.first = OSUtils::now(); + NodeOnlineRecord &i = _lastOnline[std::pair(networkId, memberId)]; + i.lastSeen = OSUtils::now(); if (physicalAddress) { - i.second = physicalAddress; + i.physicalAddress = physicalAddress; } + i.osArch = std::string(osArch); +} + +void CV1::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress) +{ + this->nodeIsOnline(networkId, memberId, physicalAddress, "unknown/unknown"); } AuthInfo CV1::getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL) @@ -1643,7 +1649,7 @@ void CV1::onlineNotification_Postgres() auto c2 = _pool->borrow(); try { fprintf(stderr, "%s onlineNotification_Postgres\n", _myAddressStr.c_str()); - std::unordered_map< std::pair,std::pair,_PairHasher > lastOnline; + std::unordered_map< std::pair,NodeOnlineRecord,_PairHasher > lastOnline; { std::lock_guard l(_lastOnline_l); lastOnline.swap(_lastOnline); @@ -1684,9 +1690,10 @@ void CV1::onlineNotification_Postgres() continue; } - int64_t ts = i->second.first; - std::string ipAddr = i->second.second.toIpString(ipTmp); + int64_t ts = i->second.lastSeen; + std::string ipAddr = i->second.physicalAddress.toIpString(ipTmp); std::string timestamp = std::to_string(ts); + std::string osArch = i->second.osArch; std::stringstream memberUpdate; memberUpdate << "INSERT INTO ztc_member_status (network_id, member_id, address, last_updated) VALUES " @@ -1741,7 +1748,7 @@ void CV1::onlineNotification_Redis() auto start = std::chrono::high_resolution_clock::now(); uint64_t count = 0; - std::unordered_map< std::pair,std::pair,_PairHasher > lastOnline; + std::unordered_map< std::pair,NodeOnlineRecord,_PairHasher > lastOnline; { std::lock_guard l(_lastOnline_l); lastOnline.swap(_lastOnline); @@ -1771,7 +1778,7 @@ void CV1::onlineNotification_Redis() } uint64_t CV1::_doRedisUpdate(sw::redis::Transaction &tx, std::string &controllerId, - std::unordered_map< std::pair,std::pair,_PairHasher > &lastOnline) + std::unordered_map< std::pair,NodeOnlineRecord,_PairHasher > &lastOnline) { nlohmann::json jtmp1, jtmp2; @@ -1792,9 +1799,10 @@ uint64_t CV1::_doRedisUpdate(sw::redis::Transaction &tx, std::string &controller std::string networkId(nwidTmp); std::string memberId(memTmp); - int64_t ts = i->second.first; - std::string ipAddr = i->second.second.toIpString(ipTmp); + int64_t ts = i->second.lastSeen; + std::string ipAddr = i->second.physicalAddress.toIpString(ipTmp); std::string timestamp = std::to_string(ts); + std::string osArch = i->second.osArch; std::unordered_map record = { {"id", memberId}, diff --git a/controller/CV1.hpp b/controller/CV1.hpp index f21eeb546..753184a9c 100644 --- a/controller/CV1.hpp +++ b/controller/CV1.hpp @@ -57,6 +57,7 @@ public: virtual void eraseNetwork(const uint64_t networkId); virtual void eraseMember(const uint64_t networkId, const uint64_t memberId); virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress); + virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch); virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL); virtual bool ready() { @@ -93,7 +94,7 @@ private: void onlineNotification_Postgres(); void onlineNotification_Redis(); uint64_t _doRedisUpdate(sw::redis::Transaction &tx, std::string &controllerId, - std::unordered_map< std::pair,std::pair,_PairHasher > &lastOnline); + std::unordered_map< std::pair,NodeOnlineRecord,_PairHasher > &lastOnline); void configureSmee(); void notifyNewMember(const std::string &networkID, const std::string &memberID); @@ -118,7 +119,7 @@ private: std::thread _commitThread[ZT_CENTRAL_CONTROLLER_COMMIT_THREADS]; std::thread _onlineNotificationThread; - std::unordered_map< std::pair,std::pair,_PairHasher > _lastOnline; + std::unordered_map< std::pair,NodeOnlineRecord,_PairHasher > _lastOnline; mutable std::mutex _lastOnline_l; mutable std::mutex _readyLock; diff --git a/controller/CV2.cpp b/controller/CV2.cpp index c7ef02123..e3ac77b3c 100644 --- a/controller/CV2.cpp +++ b/controller/CV2.cpp @@ -197,14 +197,20 @@ void CV2::eraseMember(const uint64_t networkId, const uint64_t memberId) _memberChanged(tmp.first, nullJson, true); } -void CV2::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress) +void CV2::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress, const char *osArch) { std::lock_guard l(_lastOnline_l); - std::pair &i = _lastOnline[std::pair(networkId, memberId)]; - i.first = OSUtils::now(); + NodeOnlineRecord &i = _lastOnline[std::pair(networkId, memberId)]; + i.lastSeen = OSUtils::now(); if (physicalAddress) { - i.second = physicalAddress; + i.physicalAddress = physicalAddress; } + i.osArch = std::string(osArch); +} + +void CV2::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress) +{ + this->nodeIsOnline(networkId, memberId, physicalAddress, "unknown/unknown"); } AuthInfo CV2::getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL) @@ -940,7 +946,7 @@ void CV2::onlineNotificationThread() { try { fprintf(stderr, "%s onlineNotificationThread\n", _myAddressStr.c_str()); - std::unordered_map, std::pair,_PairHasher> lastOnline; + std::unordered_map, NodeOnlineRecord,_PairHasher> lastOnline; { std::lock_guard l(_lastOnline_l); lastOnline.swap(_lastOnline); @@ -980,18 +986,21 @@ void CV2::onlineNotificationThread() { continue; } - int64_t ts = i->second.first; - std::string ipAddr = i->second.second.toIpString(ipTmp); + int64_t ts = i->second.lastSeen; + std::string ipAddr = i->second.physicalAddress.toIpString(ipTmp); std::string timestamp = std::to_string(ts); + std::string osArch = i->second.osArch; + std::vector osArchSplit = split(osArch, '/'); json record = { {ipAddr, ts}, }; - - std::string device_network_insert = "INSERT INTO network_memberships_ctl (device_id, network_id, last_seen) " - "VALUES ('"+w2.esc(memberId)+"', '"+w2.esc(networkId)+"', '"+w2.esc(record.dump())+"'::JSONB) " - "ON CONFLICT (device_id, network_id) DO UPDATE SET last_seen = last_seen || EXCLUDED.last_seen"; + std::string device_network_insert = "INSERT INTO network_memberships_ctl (device_id, network_id, last_seen, os, arch) " + "VALUES ('"+w2.esc(memberId)+"', '"+w2.esc(networkId)+"', '"+w2.esc(record.dump())+"'::JSONB, " + "'"+w2.esc(osArchSplit[0])+"', '"+w2.esc(osArchSplit[1])+"') " + "ON CONFLICT (device_id, network_id) DO UPDATE SET last_seen = last_seen || EXCLUDED.last_seen " + "os = EXCLUDED.os, arch = EXCLUDED.arch"; pipe.insert(device_network_insert); Metrics::pgsql_node_checkin++; diff --git a/controller/CV2.hpp b/controller/CV2.hpp index f62bbd310..1c432bf25 100644 --- a/controller/CV2.hpp +++ b/controller/CV2.hpp @@ -44,6 +44,7 @@ public: virtual void eraseNetwork(const uint64_t networkId); virtual void eraseMember(const uint64_t networkId, const uint64_t memberId); virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress); + virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch); virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL); virtual bool ready() { @@ -95,7 +96,7 @@ private: std::thread _commitThread[ZT_CENTRAL_CONTROLLER_COMMIT_THREADS]; std::thread _onlineNotificationThread; - std::unordered_map< std::pair,std::pair,_PairHasher > _lastOnline; + std::unordered_map< std::pair,NodeOnlineRecord,_PairHasher > _lastOnline; mutable std::mutex _lastOnline_l; mutable std::mutex _readyLock; diff --git a/controller/DB.hpp b/controller/DB.hpp index 5683bcecf..827c30f09 100644 --- a/controller/DB.hpp +++ b/controller/DB.hpp @@ -141,6 +141,7 @@ public: virtual void eraseNetwork(const uint64_t networkId) = 0; virtual void eraseMember(const uint64_t networkId,const uint64_t memberId) = 0; virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) = 0; + virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch) = 0; virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL) { return AuthInfo(); } diff --git a/controller/DBMirrorSet.cpp b/controller/DBMirrorSet.cpp index 78fa82a4a..42af326e3 100644 --- a/controller/DBMirrorSet.cpp +++ b/controller/DBMirrorSet.cpp @@ -206,14 +206,18 @@ void DBMirrorSet::eraseMember(const uint64_t networkId,const uint64_t memberId) } } -void DBMirrorSet::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) -{ +void DBMirrorSet::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch) { std::shared_lock l(_dbs_l); for(auto d=_dbs.begin();d!=_dbs.end();++d) { (*d)->nodeIsOnline(networkId,memberId,physicalAddress); } } +void DBMirrorSet::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) +{ + this->nodeIsOnline(networkId,memberId,physicalAddress,"unknown/unknown"); +} + void DBMirrorSet::onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network) { nlohmann::json record(network); diff --git a/controller/DBMirrorSet.hpp b/controller/DBMirrorSet.hpp index 888144047..10a15ecca 100644 --- a/controller/DBMirrorSet.hpp +++ b/controller/DBMirrorSet.hpp @@ -44,7 +44,8 @@ public: bool save(nlohmann::json &record,bool notifyListeners); void eraseNetwork(const uint64_t networkId); void eraseMember(const uint64_t networkId,const uint64_t memberId); - void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress); + virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress); + virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch); // These are called by various DB instances when changes occur. virtual void onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network); diff --git a/controller/FileDB.cpp b/controller/FileDB.cpp index e410c1567..d039f00b7 100644 --- a/controller/FileDB.cpp +++ b/controller/FileDB.cpp @@ -155,8 +155,7 @@ void FileDB::eraseMember(const uint64_t networkId,const uint64_t memberId) this->_online[networkId].erase(memberId); } -void FileDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) -{ +void FileDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch) { char mid[32],atmp[64]; OSUtils::ztsnprintf(mid,sizeof(mid),"%.10llx",(unsigned long long)memberId); physicalAddress.toString(atmp); @@ -164,4 +163,9 @@ void FileDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const this->_online[networkId][memberId][OSUtils::now()] = physicalAddress; } +void FileDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) +{ + this->nodeIsOnline(networkId,memberId,physicalAddress,"unknown/unknown"); +} + } // namespace ZeroTier diff --git a/controller/FileDB.hpp b/controller/FileDB.hpp index 4e1bbe09e..e45be970e 100644 --- a/controller/FileDB.hpp +++ b/controller/FileDB.hpp @@ -31,7 +31,8 @@ public: virtual void eraseNetwork(const uint64_t networkId); virtual void eraseMember(const uint64_t networkId,const uint64_t memberId); virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress); - + virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch); + protected: std::string _path; std::string _networksPath; diff --git a/controller/LFDB.cpp b/controller/LFDB.cpp index efccff65c..29fe287e0 100644 --- a/controller/LFDB.cpp +++ b/controller/LFDB.cpp @@ -388,7 +388,7 @@ void LFDB::eraseMember(const uint64_t networkId,const uint64_t memberId) // TODO } -void LFDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) +void LFDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress,const char *osArch) { std::lock_guard l(_state_l); auto nw = _state.find(networkId); @@ -403,4 +403,9 @@ void LFDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const I } } +void LFDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) +{ + this->nodeIsOnline(networkId,memberId,physicalAddress,"unknown/unknown"); +} + } // namespace ZeroTier diff --git a/controller/LFDB.hpp b/controller/LFDB.hpp index 64933f7d8..f4895b494 100644 --- a/controller/LFDB.hpp +++ b/controller/LFDB.hpp @@ -47,7 +47,8 @@ public: virtual void eraseNetwork(const uint64_t networkId); virtual void eraseMember(const uint64_t networkId,const uint64_t memberId); virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress); - + virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch); + protected: const Identity _myId; diff --git a/controller/PostgreSQL.hpp b/controller/PostgreSQL.hpp index 4a8603b43..51f9c1848 100644 --- a/controller/PostgreSQL.hpp +++ b/controller/PostgreSQL.hpp @@ -79,6 +79,12 @@ private: DB *_psql; }; +struct NodeOnlineRecord { + uint64_t lastSeen; + InetAddress physicalAddress; + std::string osArch; +}; + } // namespace ZeroTier #endif // ZT_CONTROLLER_POSTGRESQL_HPP diff --git a/ext/central-controller-docker/migrations/0002_os_arch.down.sql b/ext/central-controller-docker/migrations/0002_os_arch.down.sql new file mode 100644 index 000000000..3c90f0a2e --- /dev/null +++ b/ext/central-controller-docker/migrations/0002_os_arch.down.sql @@ -0,0 +1,3 @@ +ALTER TABLE network_memberships_ctl + DROP COLUMN os, + DROP COLUMN arch; \ No newline at end of file diff --git a/ext/central-controller-docker/migrations/0002_os_arch.up.sql b/ext/central-controller-docker/migrations/0002_os_arch.up.sql new file mode 100644 index 000000000..095f7c698 --- /dev/null +++ b/ext/central-controller-docker/migrations/0002_os_arch.up.sql @@ -0,0 +1,3 @@ +ALTER TABLE network_memberships_ctl + ADD COLUMN os TEXT NOT NULL DEFAULT 'unknown', + ADD COLUMN arch TEXT NOT NULL DEFAULT 'unknown'; \ No newline at end of file