2
0
Эх сурвалжийг харах

Merge branch 'belanger/agent-v3-integration' of github.com-meehawk:porter-dev/porter into meehawk/logs-improvement

Soham Parekh 3 жил өмнө
parent
commit
37e04890ca

+ 1 - 0
api/types/incident.go

@@ -36,6 +36,7 @@ type IncidentMeta struct {
 	LastSeen                *time.Time         `json:"last_seen" form:"required"`
 	Status                  IncidentStatus     `json:"status" form:"required"`
 	Summary                 string             `json:"summary" form:"required"`
+	ShortSummary            string             `json:"short_summary"`
 	Severity                SeverityType       `json:"severity" form:"required"`
 	InvolvedObjectKind      InvolvedObjectKind `json:"involved_object_kind" form:"required"`
 	InvolvedObjectName      string             `json:"involved_object_name" form:"required"`

+ 14 - 15
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx

@@ -419,7 +419,7 @@ const ExpandedChart: React.FC<Props> = (props) => {
     switch (currentTab) {
       case "logs":
         return (
-          <LogsSection 
+          <LogsSection
             currentChart={chart}
             isFullscreen={isFullscreen}
             setIsFullscreen={setIsFullscreen}
@@ -431,11 +431,7 @@ const ExpandedChart: React.FC<Props> = (props) => {
         if (DisabledNamespacesForIncidents.includes(currentChart.namespace)) {
           return null;
         }
-        return (
-          <EventsTab
-            controllers={controllers}
-          />
-        );
+        return <EventsTab currentChart={chart} />;
       case "status":
         if (isLoadingChartData) {
           return (
@@ -539,11 +535,9 @@ const ExpandedChart: React.FC<Props> = (props) => {
     let leftTabOptions = [] as any[];
     if (
       currentChart.chart.metadata.home === "https://getporter.dev/" &&
-      (
-        currentChart.chart.metadata.name === "web" || 
+      (currentChart.chart.metadata.name === "web" ||
         currentChart.chart.metadata.name === "worker" ||
-        currentChart.chart.metadata.name === "job"
-      )
+        currentChart.chart.metadata.name === "job")
     ) {
       leftTabOptions.push({ label: "Events", value: "events" });
       leftTabOptions.push({ label: "Logs", value: "logs" });
@@ -775,10 +769,10 @@ const ExpandedChart: React.FC<Props> = (props) => {
       ) : (
         <>
           {isFullscreen ? (
-            <LogsSection 
+            <LogsSection
               isFullscreen={true}
               setIsFullscreen={setIsFullscreen}
-              currentChart={currentChart} 
+              currentChart={currentChart}
             />
           ) : (
             <StyledExpandedChart>
@@ -796,7 +790,8 @@ const ExpandedChart: React.FC<Props> = (props) => {
                   {currentChart.name}
                   <DeploymentType currentChart={currentChart} />
                   <TagWrapper>
-                    Namespace <NamespaceTag>{currentChart.namespace}</NamespaceTag>
+                    Namespace{" "}
+                    <NamespaceTag>{currentChart.namespace}</NamespaceTag>
                   </TagWrapper>
                 </TitleSection>
 
@@ -821,7 +816,8 @@ const ExpandedChart: React.FC<Props> = (props) => {
                   <Placeholder>
                     <TextWrap>
                       <Header>
-                        <Spinner src={loadingSrc} /> Deleting "{currentChart.name}"
+                        <Spinner src={loadingSrc} /> Deleting "
+                        {currentChart.name}"
                       </Header>
                       You will be automatically redirected after deletion is
                       complete.
@@ -873,7 +869,10 @@ const ExpandedChart: React.FC<Props> = (props) => {
                             isReadOnly={
                               isPreview ||
                               imageIsPlaceholder ||
-                              !isAuthorized("application", "", ["get", "update"])
+                              !isAuthorized("application", "", [
+                                "get",
+                                "update",
+                              ])
                             }
                             onSubmit={onSubmit}
                             includeMetadata

+ 91 - 199
dashboard/src/main/home/cluster-dashboard/expanded-chart/events/EventList.tsx

@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from "react";
+import React, { useState, useEffect, useContext } from "react";
 import { CellProps } from "react-table";
 
 import styled from "styled-components";
@@ -13,165 +13,66 @@ import TitleSection from "components/TitleSection";
 import api from "shared/api";
 import Modal from "main/home/modals/Modal";
 import time from "assets/time.svg";
+import { Context } from "shared/Context";
 
-const iconDict: any = {
-};
+const iconDict: any = {};
 
 type Props = {
   filters: any;
-  setExpandedMonitor: any;
 };
 
-const EventList: React.FC<Props> = (props) => {
+const EventList: React.FC<Props> = ({ filters }) => {
+  const { currentProject, currentCluster } = useContext(Context);
   const [events, setEvents] = useState([]);
   const [expandedEvent, setExpandedEvent] = useState(null);
+  const [expandedEventDetails, setExpandedEventDetails] = useState(null);
+  const [expandedIncidentEvents, setExpandedIncidentEvents] = useState(null);
   const [isLoading, setIsLoading] = useState(true);
 
   useEffect(() => {
+    api
+      .listIncidents("<token>", filters, {
+        project_id: currentProject.id,
+        cluster_id: currentCluster.id,
+      })
+      .then((res) => {
+        setEvents(res.data.incidents);
+        setIsLoading(false);
+      });
+  }, []);
 
-    // Dummy event list query
-    setTimeout(() => {
-      const events = [
-        {
-          "id": "e0311c9231eea5c47e8bb83cc10faf2b",
-          "release_name": "deployment-invalid-image",
-          "release_namespace": "default",
-          "chart_name": "worker",
-          "created_at": "2022-10-06T17:56:06.834088422Z",
-          "updated_at": "2022-10-07T19:32:33.842552438Z",
-          "last_seen": "2022-10-06T17:55:50Z",
-          "status": "active",
-          "summary": "The application has an invalid image",
-          "severity": "normal",
-          "involved_object_kind": "pod",
-          "involved_object_name": "deployment-invalid-image-worker-cf976b476-h782c",
-          "involved_object_namespace": "default"
-        },
-        {
-          "id": "6818ee8df06db55c310c24a6b0c17cfd",
-          "release_name": "oom-killed",
-          "release_namespace": "default",
-          "chart_name": "web",
-          "created_at": "2022-10-05T17:13:45.563510898Z",
-          "updated_at": "2022-10-07T19:32:02.580935074Z",
-          "last_seen": "2022-10-05T17:59:10Z",
-          "status": "active",
-          "summary": "The application ran out of memory",
-          "severity": "critical",
-          "involved_object_kind": "Deployment",
-          "involved_object_name": "oom-killed-web",
-          "involved_object_namespace": "default"
-        },
-        {
-          "id": "00f3b38dd0b2adc2ce0bab9586d487b5",
-          "release_name": "non-zero-exit-code",
-          "release_namespace": "default",
-          "chart_name": "web",
-          "created_at": "2022-10-05T18:31:07.80325966Z",
-          "updated_at": "2022-10-07T19:31:34.591091925Z",
-          "last_seen": "2022-10-05T18:31:07Z",
-          "status": "active",
-          "summary": "The application exited with a non-zero exit code",
-          "severity": "normal",
-          "involved_object_kind": "pod",
-          "involved_object_name": "non-zero-exit-code-web-797d5ddb64-g5d7x",
-          "involved_object_namespace": "default"
-        },
-        {
-          "id": "c435fe96260e472af9808013687a876c",
-          "release_name": "multi-replica-failure-less",
-          "release_namespace": "default",
-          "chart_name": "worker",
-          "created_at": "2022-10-07T15:05:16.823354171Z",
-          "updated_at": "2022-10-07T19:31:29.840878022Z",
-          "last_seen": "2022-10-07T15:09:17Z",
-          "status": "active",
-          "summary": "The application exited with a non-zero exit code",
-          "severity": "critical",
-          "involved_object_kind": "Deployment",
-          "involved_object_name": "multi-replica-failure-less-worker",
-          "involved_object_namespace": "default"
-        },
-        {
-          "id": "d9aec89e437617f28de47ab700c92cb4",
-          "release_name": "multi-replica-failure-more",
-          "release_namespace": "default",
-          "chart_name": "worker",
-          "created_at": "2022-10-07T15:08:21.405351792Z",
-          "updated_at": "2022-10-07T19:31:14.773187536Z",
-          "last_seen": "2022-10-07T19:25:06Z",
-          "status": "active",
-          "summary": "The application exited with a non-zero exit code",
-          "severity": "critical",
-          "involved_object_kind": "Deployment",
-          "involved_object_name": "multi-replica-failure-more-worker",
-          "involved_object_namespace": "default"
-        },
-        {
-          "id": "f7f2021acb0e5fd104fb30b8c914a563",
-          "release_name": "oom-killed-2",
-          "release_namespace": "default",
-          "chart_name": "web",
-          "created_at": "2022-10-05T18:00:45.655719615Z",
-          "updated_at": "2022-10-07T19:28:38.571531252Z",
-          "last_seen": "2022-10-05T18:00:44Z",
-          "status": "active",
-          "summary": "The application ran out of memory",
-          "severity": "critical",
-          "involved_object_kind": "deployment",
-          "involved_object_name": "oom-killed-2-web",
-          "involved_object_namespace": "default"
-        },
-        {
-          "id": "fa76cfb2daa58649e6aa7dc47262f632",
-          "release_name": "deployment-bad-image-tag",
-          "release_namespace": "default",
-          "chart_name": "worker",
-          "created_at": "2022-10-06T17:51:04.846528578Z",
-          "updated_at": "2022-10-07T19:28:11.835881268Z",
-          "last_seen": "2022-10-06T17:50:46Z",
-          "status": "active",
-          "summary": "The application has an invalid image",
-          "severity": "normal",
-          "involved_object_kind": "pod",
-          "involved_object_name": "deployment-bad-image-tag-worker-5f676bdb9-q4d7w",
-          "involved_object_namespace": "default"
-        },
-        {
-          "id": "b58f6e28bc3884f50cb60c93b8427cb2",
-          "release_name": "deployment-stuck-longtime",
-          "release_namespace": "default",
-          "chart_name": "worker",
-          "created_at": "2022-10-07T15:04:23.807783654Z",
-          "updated_at": "2022-10-07T17:41:27.155369452Z",
-          "last_seen": "2022-10-07T15:04:23.695228777Z",
-          "status": "active",
-          "summary": "The application cannot be scheduled",
-          "severity": "critical",
-          "involved_object_kind": "deployment",
-          "involved_object_name": "deployment-stuck-longtime-worker",
-          "involved_object_namespace": "default"
-        },
+  useEffect(() => {
+    if (!expandedEvent) {
+      return;
+    }
+
+    api
+      .getIncidentEvents(
+        "<token>",
+        {},
         {
-          "id": "6c6cc62a398d831bfddb6ef5faceafa9",
-          "release_name": "failing-job-run",
-          "release_namespace": "default",
-          "chart_name": "job",
-          "created_at": "2022-10-07T16:43:06.025081995Z",
-          "updated_at": "2022-10-07T17:29:02.722048271Z",
-          "last_seen": "2022-10-07T16:43:48Z",
-          "status": "active",
-          "summary": "The application has an invalid start command",
-          "severity": "normal",
-          "involved_object_kind": "Job",
-          "involved_object_name": "failing-job-run-dr1vbs563d",
-          "involved_object_namespace": "default"
+          project_id: currentProject.id,
+          cluster_id: currentCluster.id,
+          incident_id: expandedEvent.id,
         }
-      ];
-      setEvents(events);
-      setIsLoading(false);
-    }, 1000);
-  }, []);
+      )
+      .then((res) => {
+        setExpandedIncidentEvents(res.data.events);
+      });
+  }, [expandedEvent]);
+
+  const renderExpandedEventMessage = () => {
+    if (!expandedIncidentEvents) {
+      return <Loading />;
+    }
+
+    return (
+      <Message>
+        <img src={document} />
+        {expandedIncidentEvents[0].detail}
+      </Message>
+    );
+  };
 
   const columns = React.useMemo(
     () => [
@@ -187,8 +88,7 @@ const EventList: React.FC<Props> = (props) => {
                 <NameWrapper>
                   <AlertIcon src={danger} />
                   {row.original.release_name}
-                  {row?.original &&
-                  row.original.severity === "normal" ? (
+                  {row?.original && row.original.severity === "normal" ? (
                     <></>
                   ) : (
                     <Status color="#cc3d42">Critical</Status>
@@ -199,7 +99,7 @@ const EventList: React.FC<Props> = (props) => {
           },
           {
             Header: "Summary",
-            accessor: "summary",
+            accessor: "short_summary",
             width: 270,
           },
           {
@@ -207,11 +107,7 @@ const EventList: React.FC<Props> = (props) => {
             accessor: "updated_at",
             width: 140,
             Cell: ({ row }: CellProps<any>) => {
-              return (
-                <Flex>
-                  {readableDate(row.original.updated_at)}
-                </Flex>
-              );
+              return <Flex>{readableDate(row.original.updated_at)}</Flex>;
             },
           },
           {
@@ -220,9 +116,11 @@ const EventList: React.FC<Props> = (props) => {
             width: 20,
             Cell: ({ row }: CellProps<any>) => {
               return (
-                <TableButton onClick={() => {
-                  setExpandedEvent(row.original);
-                }}>
+                <TableButton
+                  onClick={() => {
+                    setExpandedEvent(row.original);
+                  }}
+                >
                   <Icon src={info} />
                   Details
                 </TableButton>
@@ -250,52 +148,46 @@ const EventList: React.FC<Props> = (props) => {
 
   return (
     <>
-      {
-        expandedEvent && (
-          <Modal onRequestClose={() => setExpandedEvent(null)} height="auto">
-            <TitleSection icon={danger}>
-              <Text>{expandedEvent.release_name}</Text>
-            </TitleSection>
-            <InfoRow>
-              <InfoTab>
-                <img src={time} /> <Bold>Last updated:</Bold>
-                {readableDate(expandedEvent.updated_at)}
-              </InfoTab>
-              <InfoTab>
-                <img src={info} /> <Bold>Status:</Bold>
-                <Capitalize>{expandedEvent.status}</Capitalize>
-              </InfoTab>
-              <InfoTab>
-                <img src={status} /> <Bold>Priority:</Bold> <Capitalize>{expandedEvent.severity}</Capitalize>
-              </InfoTab>
-            </InfoRow>
-            <Message>
-              <img src={document} /> This is a placeholder message where event details should be.
-            </Message>
-          </Modal>
-        )
-      }
+      {expandedEvent && (
+        <Modal onRequestClose={() => setExpandedEvent(null)} height="auto">
+          <TitleSection icon={danger}>
+            <Text>{expandedEvent.release_name}</Text>
+          </TitleSection>
+          <InfoRow>
+            <InfoTab>
+              <img src={time} /> <Bold>Last updated:</Bold>
+              {readableDate(expandedEvent.updated_at)}
+            </InfoTab>
+            <InfoTab>
+              <img src={info} /> <Bold>Status:</Bold>
+              <Capitalize>{expandedEvent.status}</Capitalize>
+            </InfoTab>
+            <InfoTab>
+              <img src={status} /> <Bold>Priority:</Bold>{" "}
+              <Capitalize>{expandedEvent.severity}</Capitalize>
+            </InfoTab>
+          </InfoRow>
+          {renderExpandedEventMessage()}
+        </Modal>
+      )}
       {isLoading ? (
         <LoadWrapper>
           <Loading />
         </LoadWrapper>
       ) : (
         <>
-        {events.length > 0 ? (
-          <TableWrapper>
-            <EventTable 
-              columns={columns} 
-              data={events} 
-            />
-          </TableWrapper>
-        ) : (
-          <Placeholder>
-            <div>
-            <Title>No results found</Title>
-            There were no results found for this filter.
-            </div>
-          </Placeholder>
-        )}
+          {events?.length > 0 ? (
+            <TableWrapper>
+              <EventTable columns={columns} data={events} />
+            </TableWrapper>
+          ) : (
+            <Placeholder>
+              <div>
+                <Title>No results found</Title>
+                There were no results found for this filter.
+              </div>
+            </Placeholder>
+          )}
         </>
       )}
     </>
@@ -306,7 +198,7 @@ export default EventList;
 
 const Message = styled.div`
   padding: 20px;
-  background: #26292E;
+  background: #26292e;
   border-radius: 5px;
   line-height: 1.5em;
   border: 1px solid #aaaabb33;
@@ -364,7 +256,7 @@ const TableButton = styled.div<{ width?: string }>`
   border-radius: 5px;
   height: 30px;
   color: white;
-  width: ${props => props.width || "85px"};
+  width: ${(props) => props.width || "85px"};
   display: flex;
   align-items: center;
   justify-content: center;

+ 27 - 3
dashboard/src/main/home/cluster-dashboard/expanded-chart/events/EventsTab.tsx

@@ -7,13 +7,32 @@ import InfiniteScroll from "react-infinite-scroll-component";
 import { Context } from "shared/Context";
 import Dropdown from "components/Dropdown";
 
-const EventsTab: React.FC = () => {
+type Props = {
+  currentChart: any;
+};
+
+const EventsTab: React.FC<Props> = ({ currentChart }) => {
   const [hasPorterAgent, setHasPorterAgent] = useState(true);
   const { currentProject, currentCluster } = useContext(Context);
   const [isLoading, setIsLoading] = useState(true);
 
   useEffect(() => {
-    setIsLoading(false);
+    const project_id = currentProject?.id;
+    const cluster_id = currentCluster?.id;
+
+    // determine if the agent is installed properly - if not, render upgrade screen
+    api
+      .detectPorterAgent("<token>", {}, { project_id, cluster_id })
+      .then((res) => {
+        console.log(res.data);
+        setIsLoading(false);
+      })
+      .catch((err) => {
+        if (err.response?.status === 404) {
+          setHasPorterAgent(false);
+          setIsLoading(false);
+        }
+      });
   }, []);
 
   const installAgent = async () => {
@@ -58,7 +77,12 @@ const EventsTab: React.FC = () => {
 
   return (
     <EventsPageWrapper>
-      <EventList />
+      <EventList
+        filters={{
+          release_name: currentChart.name,
+          release_namespace: currentChart.namespace,
+        }}
+      />
     </EventsPageWrapper>
   );
 };

+ 45 - 60
dashboard/src/shared/api.tsx

@@ -1787,61 +1787,6 @@ const getPreviousLogsForContainer = baseApi<
     `/api/projects/${project_id}/clusters/${cluster_id}/namespaces/${namespace}/pod/${name}/previous_logs`
 );
 
-const getIncidents = baseApi<
-  {},
-  {
-    project_id: number;
-    cluster_id: number;
-  }
->(
-  "GET",
-  ({ project_id, cluster_id }) =>
-    `/api/projects/${project_id}/clusters/${cluster_id}/incidents`
-);
-
-const getIncidentsByReleaseName = baseApi<
-  {
-    namespace: string;
-    release_name: string;
-  },
-  {
-    project_id: number;
-    cluster_id: number;
-  }
->(
-  "GET",
-  ({ project_id, cluster_id }) =>
-    `/api/projects/${project_id}/clusters/${cluster_id}/incidents`
-);
-
-const getIncidentById = baseApi<
-  {
-    incident_id: string;
-  },
-  {
-    project_id: number;
-    cluster_id: number;
-  }
->(
-  "GET",
-  ({ project_id, cluster_id }) =>
-    `/api/projects/${project_id}/clusters/${cluster_id}/incidents`
-);
-
-const getIncidentLogsByLogId = baseApi<
-  {
-    log_id: string;
-  },
-  {
-    project_id: number;
-    cluster_id: number;
-  }
->(
-  "GET",
-  ({ project_id, cluster_id }) =>
-    `/api/projects/${project_id}/clusters/${cluster_id}/incidents/logs`
-);
-
 const upgradePorterAgent = baseApi<
   {},
   { project_id: number; cluster_id: number }
@@ -2041,6 +1986,48 @@ const getLogs = baseApi<
     `/api/projects/${project_id}/clusters/${cluster_id}/logs`
 );
 
+const listIncidents = baseApi<
+  {
+    release_name?: number;
+    release_namespace?: string;
+    status?: string;
+  },
+  {
+    project_id: number;
+    cluster_id: number;
+  }
+>(
+  "GET",
+  ({ project_id, cluster_id }) =>
+    `/api/projects/${project_id}/clusters/${cluster_id}/incidents`
+);
+
+const getIncident = baseApi<
+  {},
+  {
+    project_id: number;
+    cluster_id: number;
+    incident_id: string;
+  }
+>(
+  "GET",
+  ({ project_id, cluster_id, incident_id }) =>
+    `/api/projects/${project_id}/clusters/${cluster_id}/incidents/${incident_id}`
+);
+
+const getIncidentEvents = baseApi<
+  {},
+  {
+    project_id: number;
+    cluster_id: number;
+    incident_id: string;
+  }
+>(
+  "GET",
+  ({ project_id, cluster_id, incident_id }) =>
+    `/api/projects/${project_id}/clusters/${cluster_id}/incidents/${incident_id}/events`
+);
+
 // STACKS
 
 const createStack = baseApi<
@@ -2386,10 +2373,6 @@ export default {
   provisionDatabase,
   getDatabases,
   getPreviousLogsForContainer,
-  getIncidents,
-  getIncidentsByReleaseName,
-  getIncidentById,
-  getIncidentLogsByLogId,
   upgradePorterAgent,
   deletePRDeployment,
   updateBuildConfig,
@@ -2405,7 +2388,9 @@ export default {
   getGitlabFolderContent,
   getLogPodValues,
   getLogs,
-
+  listIncidents,
+  getIncident,
+  getIncidentEvents,
   // STACKS
   listStacks,
   getStack,