From 2765e6b02b985ff59b5b9250cef48526508a99cd Mon Sep 17 00:00:00 2001
From: Arie Peterson <arie@greenhost.nl>
Date: Thu, 8 Feb 2024 16:28:31 +0100
Subject: [PATCH] Handle failure in resources module

---
 backend/areas/resources/resources_service.py  | 34 +++++++++-----
 frontend/src/modules/resources/Resources.tsx  | 45 ++++++++++++++-----
 .../src/services/resources/transformations.ts |  5 ++-
 3 files changed, 61 insertions(+), 23 deletions(-)

diff --git a/backend/areas/resources/resources_service.py b/backend/areas/resources/resources_service.py
index 1b5238d6..4ef91a0a 100644
--- a/backend/areas/resources/resources_service.py
+++ b/backend/areas/resources/resources_service.py
@@ -5,6 +5,7 @@
 # from kubernetes.client import CustomObjectsApi
 # import re
 import requests
+from requests.exceptions import ConnectionError
 
 from flask import current_app
 # import helpers.kubernetes
@@ -25,18 +26,27 @@ class ResourcesService:
         #         "memory_raw": node["usage"]["memory"],
         #         "memory_used": cls.parse_memory(node["usage"]["memory"]),
         #     })
-        cores = cls.get_prometheus('machine_cpu_cores')
-        return {
-            # Number of cores in use. So average usage times number of cores.
-            "cpu": cores * cls.get_prometheus('1 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[8m])))', 'float'),
-            "cpu_total": cores,
-        #         "memory_raw": node["usage"]["memory"],
-        #         "memory_used": cls.parse_memory(node["usage"]["memory"]),
-            "memory_total": cls.get_prometheus('machine_memory_bytes'),
-            "memory_available": cls.get_prometheus('node_memory_MemAvailable_bytes'),
-            "disk_free": cls.get_prometheus('node_filesystem_free_bytes{mountpoint="/"}'),
-            "disk_total": cls.get_prometheus('node_filesystem_size_bytes{mountpoint="/"}'),
-        }
+        try:
+            cores = cls.get_prometheus('machine_cpu_cores')
+            current_app.logger.info(f"Number of cores: {cores}")
+            result = {
+                "success": True,
+                # Number of cores in use. So average usage times number of cores.
+                "cpu": cores * cls.get_prometheus('1 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[8m])))', 'float'),
+                "cpu_total": cores,
+            #         "memory_raw": node["usage"]["memory"],
+            #         "memory_used": cls.parse_memory(node["usage"]["memory"]),
+                "memory_total": cls.get_prometheus('machine_memory_bytes'),
+                "memory_available": cls.get_prometheus('node_memory_MemAvailable_bytes'),
+                "disk_free": cls.get_prometheus('node_filesystem_free_bytes{mountpoint="/"}'),
+                "disk_total": cls.get_prometheus('node_filesystem_size_bytes{mountpoint="/"}'),
+            }
+        except ConnectionError:
+            return {
+                "success": False,
+                "message": "Could not contact prometheus; perhaps monitoring is not enabled.",
+            }
+        return result
 
     # @staticmethod
     # def parse_cpu(s):
diff --git a/frontend/src/modules/resources/Resources.tsx b/frontend/src/modules/resources/Resources.tsx
index 2414e92f..c39fdbc8 100644
--- a/frontend/src/modules/resources/Resources.tsx
+++ b/frontend/src/modules/resources/Resources.tsx
@@ -8,6 +8,7 @@
 import React, { useEffect } from 'react';
 import { ResourceCard } from './components/ResourceCard';
 import { useResources } from 'src/services/resources';
+import { useApps } from 'src/services/apps';
 
 const metrics = [
   {
@@ -26,31 +27,55 @@ const metrics = [
 
 export const ResourcesDashboard: React.FC = () => {
   const { resources, loadResources } = useResources();
+  const { apps, loadApps } = useApps();
   window.console.log(resources);
 
   useEffect(() => {
     loadResources();
+    loadApps();
   }, []);
 
+  const grafanaUrl = apps
+    .filter((app) => app.slug === 'monitoring')
+    .map((app) => app.url)
+    .join();
+
   return (
     <div className="relative">
       <div className="max-w-7xl mx-auto py-4 px-3 sm:px-6 lg:px-8 h-full flex-grow">
         <div className="pb-5 mt-6 border-b border-gray-200 sm:flex sm:items-center sm:justify-between">
           <h1 className="text-3xl leading-6 font-bold text-gray-900">System resources</h1>
         </div>
-        <div className="flex flex-col">
-          <div className="-my-2 sm:-mx-6 lg:-mx-8">
-            <div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
-              <div className="max-w-7xl mx-auto py-4 px-3 sm:px-6 lg:px-8 h-full flex-grow">
-                <div className=" mt-5 grid grid-cols-1 md:grid-cols-2 md:gap-4 lg:grid-cols-3 mb-10">
-                  {metrics.map((metric) => (
-                    <ResourceCard key={metric.id} metric={metric} resources={resources} />
-                  ))}
+        {resources && (
+          <>
+            <div className="flex flex-col">
+              <div className="-my-2 sm:-mx-6 lg:-mx-8">
+                <div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
+                  <div className="max-w-7xl mx-auto py-4 px-3 sm:px-6 lg:px-8 h-full flex-grow">
+                    <div className=" mt-5 grid grid-cols-1 md:grid-cols-2 md:gap-4 lg:grid-cols-3 mb-10">
+                      {metrics.map((metric) => (
+                        <ResourceCard key={metric.id} metric={metric} resources={resources} />
+                      ))}
+                    </div>
+                  </div>
                 </div>
               </div>
             </div>
-          </div>
-        </div>
+            <p>
+              For further details and system resource history, see&nbsp;
+              <a className="text-primary-700 hover:underline" href={grafanaUrl}>
+                Grafana
+              </a>
+              .
+            </p>
+          </>
+        )}
+        {!resources && (
+          <p>
+            Monitoring of system resources is not available. Perhaps the monitoring app is not installed or not
+            functioning properly.
+          </p>
+        )}
       </div>
     </div>
   );
diff --git a/frontend/src/services/resources/transformations.ts b/frontend/src/services/resources/transformations.ts
index 49816729..6b465406 100644
--- a/frontend/src/services/resources/transformations.ts
+++ b/frontend/src/services/resources/transformations.ts
@@ -1,6 +1,9 @@
 import { Resources } from './types';
 
-export const transformResources = (response: any): Resources => {
+export const transformResources = (response: any): Resources | null => {
+  if (!response.success) {
+    return null;
+  }
   return {
     cpu: (response.cpu / response.cpu_total) * 100,
     memory_used: (response.memory_total - response.memory_available) / 1e9,
-- 
GitLab