]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/cephadm: add NodeProxyCache class
authorGuillaume Abrioux <gabrioux@ibm.com>
Fri, 6 Oct 2023 11:10:39 +0000 (11:10 +0000)
committerGuillaume Abrioux <gabrioux@ibm.com>
Thu, 25 Jan 2024 14:59:35 +0000 (14:59 +0000)
This is for tracking and caching any node-proxy data.
The node-proxy API now uses this class to serve its data.

Signed-off-by: Guillaume Abrioux <gabrioux@ibm.com>
(cherry picked from commit a48c34ef0034de335c1ec5d599272fc9d958a506)

src/pybind/mgr/cephadm/agent.py
src/pybind/mgr/cephadm/inventory.py
src/pybind/mgr/cephadm/module.py
src/pybind/mgr/cephadm/serve.py

index 0228d73f8285bcde1860359a4f873642e183e5a2..648b3b58d49b4b46281fb777256c3cbec634634a 100644 (file)
@@ -198,85 +198,36 @@ class NodeProxy:
 
         data: Dict[str, Any] = cherrypy.request.json
         if self.validate_node_proxy_data(data):
-            self.mgr.set_store(f'node_proxy/data/{data["host"]}', json.dumps(data['data']))
+            host = data['host']
+            self.mgr.node_proxy.save(host, data['data'])
             self.raise_alert(data)
 
         results["result"] = self.validate_msg
 
         return results
 
-    def get_full_report(self) -> Dict[str, Any]:
-        results: Dict[str, Any] = {}
-
-        for k, v in self.mgr.get_store_prefix('node_proxy/data').items():
-            host = k.split('/')[-1:][0]
-            results[host] = json.loads(v)
-        return results
-
     @cherrypy.expose
     @cherrypy.tools.allow(methods=['GET'])
-    @cherrypy.tools.json_in()
     @cherrypy.tools.json_out()
     def fullreport(self, **kw: Any) -> Dict[str, Any]:
-        results: Dict[str, Any] = {}
-        results = self.get_full_report()
-        hostname = kw.get('hostname',)
+        return self.mgr.node_proxy.fullreport(**kw)
 
-        if hostname not in results.keys():
-            return results
-        else:
-            return results[hostname]
+    @cherrypy.expose
+    @cherrypy.tools.allow(methods=['GET'])
+    @cherrypy.tools.json_out()
+    def criticals(self, **kw: Any) -> Dict[str, Any]:
+        return self.mgr.node_proxy.criticals()
 
     @cherrypy.expose
     @cherrypy.tools.allow(methods=['GET'])
-    @cherrypy.tools.json_in()
     @cherrypy.tools.json_out()
     def summary(self, **kw: Any) -> Dict[str, Any]:
-        results: Dict[str, Any] = {}
-        status: List[str] = []
-        hostname = kw.get('hostname',)
-
-        results = self.get_full_report()
+        return self.mgr.node_proxy.summary(**kw)
 
-        mapper: Dict[bool, str] = {
-            True: 'error',
-            False: 'ok'
-        }
-
-        _result = {}
-
-        for host, data in results.items():
-            _result[host] = {}
-            for component, details in data.items():
-                res = any([member['status']['health'].lower() != 'ok' for member in data[component].values()])
-                _result[host][component] = mapper[res]
-
-        if hostname and hostname in results.keys():
-            return _result[hostname]
-        else:
-            return _result
-
-    @cherrypy.tools.json_in()
+    @cherrypy.tools.allow(methods=['GET'])
     @cherrypy.tools.json_out()
     def common(self, **kw) -> Dict[str, Any]:
-        results: Dict[str, Any] = {}
-        status: List[str] = []
-        hostname = kw.get('hostname',)
-        cmd = kw.get('cmd',)
-        results = self.get_full_report()
-
-        _result = {}
-
-        for host, data in results.items():
-            try:
-                _result[host] = data[cmd]
-            except KeyError:
-                raise RuntimeError(f'invalid endpoint {cmd}')
-
-        if hostname and hostname in results.keys():
-            return _result[hostname]
-        else:
-            return _result
+        return self.mgr.node_proxy.common(**kw)
 
     def dispatch(self, hostname='', cmd=''):
         kw = dict(hostname=hostname, cmd=cmd)
index 7153ca6dcde37e34bfba87a932b04acfc8263fe8..c19099af6014fd4ebae1c1541c50c845ec7a9ce4 100644 (file)
@@ -29,6 +29,7 @@ logger = logging.getLogger(__name__)
 HOST_CACHE_PREFIX = "host."
 SPEC_STORE_PREFIX = "spec."
 AGENT_CACHE_PREFIX = 'agent.'
+NODE_PROXY_CACHE_PREFIX = 'node_proxy/data'
 
 
 class HostCacheStatus(enum.Enum):
@@ -1405,6 +1406,85 @@ class HostCache():
         return self.scheduled_daemon_actions.get(host, {}).get(daemon)
 
 
+class NodeProxyCache:
+    def __init__(self, mgr: "CephadmOrchestrator") -> None:
+        self.mgr = mgr
+        self.data: Dict[str, Any] = {}
+        self.idrac = {}
+
+    def load(self) -> None:
+        _idrac = self.mgr.get_store('node_proxy/idrac', "{}")
+        self.idrac = json.loads(_idrac)
+
+        for k, v in self.mgr.get_store_prefix(NODE_PROXY_CACHE_PREFIX).items():
+            host = k.split('/')[-1:][0]
+
+            if host not in self.mgr.inventory.keys():
+                # remove entry for host that no longer exists
+                self.mgr.set_store(f"{NODE_PROXY_CACHE_PREFIX}/{host}", None)
+                try:
+                    self.idrac.pop(host)
+                    self.data.pop(host)
+                except KeyError:
+                    pass
+                continue
+
+            self.data[host] = json.loads(v)
+
+    def save(self,
+             host: str = '',
+             data: Dict[str, Any] = {}) -> None:
+        self.mgr.set_store(f"{NODE_PROXY_CACHE_PREFIX}/{host}", json.dumps(data))
+
+    def fullreport(self, **kw: Any) -> Dict[str, Any]:
+        hostname = kw.get('hostname')
+        if hostname not in self.data.keys():
+            return self.data
+        else:
+            return self.data[hostname]
+
+    def summary(self, **kw: Any) -> Dict[str, Any]:
+        hostname = kw.get('hostname')
+        results = self.data
+
+        mapper: Dict[bool, str] = {
+            True: 'error',
+            False: 'ok'
+        }
+
+        _result: Dict[str, Any] = {}
+
+        for host, data in results.items():
+            _result[host] = {}
+            for component, details in data.items():
+                res = any([member['status']['health'].lower() != 'ok' for member in data[component].values()])
+                _result[host][component] = mapper[res]
+
+        if hostname and hostname in results.keys():
+            return _result[hostname]
+        else:
+            return _result
+
+    def common(self, **kw):
+        hostname = kw.get('hostname',)
+        cmd = kw.get('cmd',)
+        _result = {}
+
+        for host, data in self.data.items():
+            try:
+                _result[host] = data[cmd]
+            except KeyError:
+                raise RuntimeError(f'Invalid node-proxy category {cmd}')
+
+        if hostname and hostname in self.data.keys():
+            return _result[hostname]
+        else:
+            return _result
+
+    def criticals(self, **kw):
+        return {}
+
+
 class AgentCache():
     """
     AgentCache is used for storing metadata about agent daemons that must be kept
index 010aca85fa0850abbdee05806340158abcf80967..c0f04ecf1cbe2649380ca12bbe073552cb312537 100644 (file)
@@ -66,7 +66,7 @@ from .services.monitoring import GrafanaService, AlertmanagerService, Prometheus
 from .services.jaeger import ElasticSearchService, JaegerAgentService, JaegerCollectorService, JaegerQueryService
 from .schedule import HostAssignment
 from .inventory import Inventory, SpecStore, HostCache, AgentCache, EventStore, \
-    ClientKeyringStore, ClientKeyringSpec, TunedProfileStore
+    ClientKeyringStore, ClientKeyringSpec, TunedProfileStore, NodeProxyCache
 from .upgrade import CephadmUpgrade
 from .template import TemplateMgr
 from .utils import CEPH_IMAGE_TYPES, RESCHEDULE_FROM_OFFLINE_HOSTS_TYPES, forall_hosts, \
@@ -584,6 +584,9 @@ class CephadmOrchestrator(orchestrator.Orchestrator, MgrModule,
         self.cache = HostCache(self)
         self.cache.load()
 
+        self.node_proxy = NodeProxyCache(self)
+        self.node_proxy.load()
+
         self.agent_cache = AgentCache(self)
         self.agent_cache.load()
 
index 5dfdc27a3ff50377dcfadfdcba1778f63307e5da..2a95e5a9a1f38af7985d47173929837571289db3 100644 (file)
@@ -116,6 +116,9 @@ class CephadmServe:
                     if self.mgr.upgrade.continue_upgrade():
                         continue
 
+                    # refresh node-proxy cache
+                    self.mgr.node_proxy.load()
+
             except OrchestratorError as e:
                 if e.event_subject:
                     self.mgr.events.from_orch_error(e)