Explorar o código

implemented first version of kube events display

jnfrati %!s(int64=4) %!d(string=hai) anos
pai
achega
821f5ffa61

+ 107 - 8
dashboard/src/main/home/cluster-dashboard/expanded-chart/events/EventsTab.tsx

@@ -24,6 +24,21 @@ export type EventContainer = {
   started_at: number;
 };
 
+export type KubeEvent = {
+  cluster_id: number;
+  event_type: string;
+  id: number;
+  message: string;
+  name: string;
+  namespace: string;
+  owner_name: string;
+  owner_type: string;
+  project_id: number;
+  reason: string;
+  resource_type: string;
+  timestamp: string;
+};
+
 type Props = {
   currentChart: ChartType;
 };
@@ -31,12 +46,15 @@ type Props = {
 const REFRESH_TIME = 15000;
 
 const EventsTab: React.FunctionComponent<Props> = (props) => {
+  const { currentChart } = props;
   const { currentCluster, currentProject } = useContext(Context);
   const [isLoading, setIsLoading] = useState(true);
   const [isError, setIsError] = useState(false);
   const [shouldRequest, setShouldRequest] = useState(true);
   const [eventData, setEventData] = useState<EventContainer[]>([]); // most recent event is last
   const [selectedEvent, setSelectedEvent] = useState<number | null>(null);
+  const [hasPorterAgent, setHasPorterAgent] = useState(false);
+  const [kubeEvents, setKubeEvents] = useState<KubeEvent[] | null>(null);
 
   // sort by time, ensure sequences are monotonically increasing by time, collapse by id
   const filterData = (data: Event[]) => {
@@ -93,9 +111,9 @@ const EventsTab: React.FunctionComponent<Props> = (props) => {
           {},
           {
             cluster_id: currentCluster.id,
-            namespace: props.currentChart.namespace,
+            namespace: currentChart.namespace,
             id: currentProject.id,
-            name: props.currentChart.name,
+            name: currentChart.name,
           }
         )
         .then((data) => {
@@ -111,18 +129,87 @@ const EventsTab: React.FunctionComponent<Props> = (props) => {
     };
 
     getData();
-    const id = window.setInterval(getData, REFRESH_TIME);
+    // const id = window.setInterval(getData, REFRESH_TIME);
 
     return () => {
       setIsLoading(true);
-      window.clearInterval(id);
+      // window.clearInterval(id);
+    };
+  }, [currentProject, currentCluster, currentChart]);
+
+  useEffect(() => {
+    let isSubscribed = true;
+
+    const project_id = currentProject?.id;
+    const cluster_id = currentCluster?.id;
+
+    api
+      .detectPorterAgent("<token>", {}, { project_id, cluster_id })
+      .then(() => {
+        setHasPorterAgent(true);
+      })
+      .catch(() => {
+        setHasPorterAgent(false);
+      });
+
+    return () => {
+      isSubscribed = false;
+    };
+  }, [currentProject, currentCluster]);
+
+  useEffect(() => {
+    let isSubscribed = true;
+
+    const project_id = currentProject?.id;
+    const cluster_id = currentCluster?.id;
+    if (hasPorterAgent) {
+      api
+        .getKubeEvents("<token>", {}, { project_id, cluster_id })
+        .then((res) => {
+          setKubeEvents(res.data);
+          setIsLoading(false);
+        })
+        .catch((error) => console.log(error));
+    }
+  }, [currentProject, currentCluster, hasPorterAgent]);
+
+  const installPorterAgent = () => {
+    const project_id = currentProject?.id;
+    const cluster_id = currentCluster?.id;
+
+    api
+      .installPorterAgent("<token>", {}, { project_id, cluster_id })
+      .then(() => {
+        setHasPorterAgent(true);
+      })
+      .catch(() => {
+        setHasPorterAgent(false);
+      });
+  };
+
+  const parseToEvent = (kubeEvent: KubeEvent, index: number): Event => {
+    return {
+      event_id: `${kubeEvent.id}`,
+      index,
+      info: kubeEvent.message,
+      name: kubeEvent.name,
+      status: 0,
+      time: new Date(kubeEvent.timestamp).getTime(),
     };
-  }, [currentProject, currentCluster, props.currentChart]);
+  };
 
-  if (isError) {
-    return <Placeholder>Error loading events.</Placeholder>;
+  if (!hasPorterAgent) {
+    return (
+      <InstallPorterAgentButton onClick={() => installPorterAgent()}>
+        Install porter agent
+      </InstallPorterAgentButton>
+    );
   }
 
+  // if (isError) {
+  //   return <Placeholder>Error loading events.</Placeholder>;
+  // }
+
   if (isLoading) {
     return (
       <Placeholder>
@@ -131,7 +218,7 @@ const EventsTab: React.FunctionComponent<Props> = (props) => {
     );
   }
 
-  if (eventData.length === 0) {
+  if (eventData.length === 0 && !kubeEvents?.length) {
     return (
       <Placeholder>
         <i className="material-icons">category</i>
@@ -154,6 +241,18 @@ const EventsTab: React.FunctionComponent<Props> = (props) => {
 
   return (
     <EventsGrid>
+      {kubeEvents.map(parseToEvent).map((event, i) => {
+        return (
+          <React.Fragment key={i}>
+            <EventCard
+              event={event}
+              selectEvent={() => {
+                console.log("SELECTED", event);
+              }}
+            />
+          </React.Fragment>
+        );
+      })}
       {eventData
         .slice(0)
         .reverse()

+ 37 - 0
dashboard/src/shared/api.tsx

@@ -1132,6 +1132,39 @@ const getOnboardingRegistry = baseApi<
     `/api/projects/${project_id}/registries/${registry_connection_id}`
 );
 
+const detectPorterAgent = baseApi<
+  {},
+  { project_id: number; cluster_id: number }
+>(
+  "GET",
+  ({ project_id, cluster_id }) =>
+    `/api/projects/${project_id}/clusters/${cluster_id}/agent/detect`
+);
+
+const installPorterAgent = baseApi<
+  {},
+  { project_id: number; cluster_id: number }
+>(
+  "POST",
+  ({ cluster_id, project_id }) =>
+    `/api/projects/${project_id}/clusters/${cluster_id}/agent/install`
+);
+
+const getKubeEvents = baseApi<{}, { project_id: number; cluster_id: number }>(
+  "GET",
+  ({ project_id, cluster_id }) =>
+    `/api/projects/${project_id}/clusters/${cluster_id}/kube_events`
+);
+
+const getKubeEvent = baseApi<
+  {},
+  { project_id: number; cluster_id: number; kube_event_id: number }
+>(
+  "GET",
+  ({ project_id, cluster_id, kube_event_id }) =>
+    `/api/projects/${project_id}/clusters/${cluster_id}/kube_events/${kube_event_id}`
+);
+
 // Bundle export to allow default api import (api.<method> is more readable)
 export default {
   checkAuth,
@@ -1249,4 +1282,8 @@ export default {
   saveOnboardingState,
   getOnboardingInfra,
   getOnboardingRegistry,
+  detectPorterAgent,
+  installPorterAgent,
+  getKubeEvents,
+  getKubeEvent,
 };