ソースを参照

fix merge conflict

Alexander Belanger 3 年 前
コミット
3ecba21fe0

+ 64 - 0
api/server/handlers/cluster/get_k8s_events.go

@@ -0,0 +1,64 @@
+package cluster
+
+import (
+	"net/http"
+
+	"github.com/porter-dev/porter/api/server/authz"
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/types"
+	porter_agent "github.com/porter-dev/porter/internal/kubernetes/porter_agent/v2"
+	"github.com/porter-dev/porter/internal/models"
+)
+
+type GetKubernetesEventsHandler struct {
+	handlers.PorterHandlerReadWriter
+	authz.KubernetesAgentGetter
+}
+
+func NewGetKubernetesEventsHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *GetKubernetesEventsHandler {
+	return &GetKubernetesEventsHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+		KubernetesAgentGetter:   authz.NewOutOfClusterAgentGetter(config),
+	}
+}
+
+func (c *GetKubernetesEventsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
+
+	request := &types.GetKubernetesEventRequest{}
+
+	if ok := c.DecodeAndValidate(w, r, request); !ok {
+		return
+	}
+
+	agent, err := c.GetAgent(r, cluster, "")
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	// get agent service
+	agentSvc, err := porter_agent.GetAgentService(agent.Clientset)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	logs, err := porter_agent.GetHistoricalKubernetesEvents(agent.Clientset, agentSvc, request)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	c.WriteResult(w, r, logs)
+}

+ 10 - 9
api/server/handlers/cluster/get_events.go → api/server/handlers/cluster/get_porter_events.go

@@ -9,30 +9,31 @@ import (
 	"github.com/porter-dev/porter/api/server/shared/apierrors"
 	"github.com/porter-dev/porter/api/server/shared/config"
 	"github.com/porter-dev/porter/api/types"
-	porter_agent "github.com/porter-dev/porter/internal/kubernetes/porter_agent/v2"
 	"github.com/porter-dev/porter/internal/models"
+
+	porter_agent "github.com/porter-dev/porter/internal/kubernetes/porter_agent/v2"
 )
 
-type GetEventsHandler struct {
+type GetPorterEventsHandler struct {
 	handlers.PorterHandlerReadWriter
 	authz.KubernetesAgentGetter
 }
 
-func NewGetEventsHandler(
+func NewGetPorterEventsHandler(
 	config *config.Config,
 	decoderValidator shared.RequestDecoderValidator,
 	writer shared.ResultWriter,
-) *GetEventsHandler {
-	return &GetEventsHandler{
+) *GetPorterEventsHandler {
+	return &GetPorterEventsHandler{
 		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
 		KubernetesAgentGetter:   authz.NewOutOfClusterAgentGetter(config),
 	}
 }
 
-func (c *GetEventsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+func (c *GetPorterEventsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
 
-	request := &types.GetEventRequest{}
+	request := &types.ListEventsRequest{}
 
 	if ok := c.DecodeAndValidate(w, r, request); !ok {
 		return
@@ -53,12 +54,12 @@ func (c *GetEventsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	logs, err := porter_agent.GetHistoricalEvents(agent.Clientset, agentSvc, request)
+	events, err := porter_agent.ListPorterEvents(agent.Clientset, agentSvc, request)
 
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return
 	}
 
-	c.WriteResult(w, r, logs)
+	c.WriteResult(w, r, events)
 }

+ 33 - 4
api/server/router/cluster.go

@@ -1209,7 +1209,7 @@ func getClusterRoutes(
 	})
 
 	// GET /api/projects/{project_id}/clusters/{cluster_id}/events -> cluster.NewGetEventsHandler
-	getEventsEndpoint := factory.NewAPIEndpoint(
+	getPorterEventsEndpoint := factory.NewAPIEndpoint(
 		&types.APIRequestMetadata{
 			Verb:   types.APIVerbGet,
 			Method: types.HTTPVerbGet,
@@ -1225,15 +1225,44 @@ func getClusterRoutes(
 		},
 	)
 
-	getEventsHandler := cluster.NewGetEventsHandler(
+	getPorterEventsHandler := cluster.NewGetPorterEventsHandler(
 		config,
 		factory.GetDecoderValidator(),
 		factory.GetResultWriter(),
 	)
 
 	routes = append(routes, &router.Route{
-		Endpoint: getEventsEndpoint,
-		Handler:  getEventsHandler,
+		Endpoint: getPorterEventsEndpoint,
+		Handler:  getPorterEventsHandler,
+		Router:   r,
+	})
+
+	// GET /api/projects/{project_id}/clusters/{cluster_id}/k8s_events -> cluster.NewGetEventsHandler
+	getK8sEventsEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: fmt.Sprintf("%s/k8s_events", relPath),
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.ClusterScope,
+			},
+		},
+	)
+
+	getK8sEventsHandler := cluster.NewGetKubernetesEventsHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &router.Route{
+		Endpoint: getK8sEventsEndpoint,
+		Handler:  getK8sEventsHandler,
 		Router:   r,
 	})
 

+ 37 - 5
api/types/incident.go

@@ -131,20 +131,52 @@ type GetLogResponse struct {
 	Logs                 []LogLine  `json:"logs"`
 }
 
-type GetEventRequest struct {
+type GetKubernetesEventRequest struct {
 	Limit       uint       `schema:"limit"`
 	StartRange  *time.Time `schema:"start_range"`
 	EndRange    *time.Time `schema:"end_range"`
+	Revision    string     `schema:"revision"`
 	PodSelector string     `schema:"pod_selector" form:"required"`
 	Namespace   string     `schema:"namespace" form:"required"`
 }
 
-type EventLine struct {
+type KubernetesEventLine struct {
 	Timestamp *time.Time `json:"timestamp"`
 	Event     string     `json:"event"`
 }
 
-type GetEventResponse struct {
-	ContinueTime *time.Time  `json:"continue_time"`
-	Events       []EventLine `json:"events"`
+type GetKubernetesEventResponse struct {
+	ContinueTime *time.Time            `json:"continue_time"`
+	Events       []KubernetesEventLine `json:"events"`
+}
+
+type EventType string
+
+const (
+	EventTypeIncident           EventType = "incident"
+	EventTypeIncidentResolved   EventType = "incident_resolved"
+	EventTypeDeploymentStarted  EventType = "deployment_started"
+	EventTypeDeploymentFinished EventType = "deployment_finished"
+	EventTypeDeploymentErrored  EventType = "deployment_errored"
+)
+
+type Event struct {
+	Type             EventType              `json:"type"`
+	Version          string                 `json:"version"`
+	ReleaseName      string                 `json:"release_name"`
+	ReleaseNamespace string                 `json:"release_namespace"`
+	Timestamp        *time.Time             `json:"timestamp"`
+	Data             map[string]interface{} `json:"data"`
+}
+
+type ListEventsRequest struct {
+	*PaginationRequest
+	ReleaseName      *string `schema:"release_name"`
+	ReleaseNamespace *string `schema:"release_namespace"`
+	Type             *string `schema:"type"`
+}
+
+type ListEventsResponse struct {
+	Events     []*Event            `json:"events" form:"required"`
+	Pagination *PaginationResponse `json:"pagination"`
 }

+ 7 - 1
dashboard/src/components/porter-form/PorterFormWrapper.tsx

@@ -3,6 +3,7 @@ import React, { useEffect, useState } from "react";
 import PorterForm from "./PorterForm";
 import { InjectedProps, PorterFormData } from "./types";
 import { PorterFormContextProvider } from "./PorterFormContextProvider";
+import _ from "lodash";
 
 type PropsType = {
   formData: any;
@@ -25,6 +26,7 @@ type PropsType = {
   includeMetadata?: boolean;
   injectedProps?: InjectedProps;
   overrideCurrentTab?: string;
+  onTabChange?: (newTab: string) => void;
 };
 
 const PorterFormWrapper: React.FC<PropsType> = ({
@@ -48,6 +50,7 @@ const PorterFormWrapper: React.FC<PropsType> = ({
   includeMetadata,
   injectedProps,
   overrideCurrentTab,
+  onTabChange = _.noop,
 }) => {
   const hashCode = (s: string) => {
     return s?.split("").reduce(function (a, b) {
@@ -105,7 +108,10 @@ const PorterFormWrapper: React.FC<PropsType> = ({
           color={color}
           saveValuesStatus={saveValuesStatus}
           currentTab={currentTab}
-          setCurrentTab={setCurrentTab}
+          setCurrentTab={(newTab) => {
+            setCurrentTab(newTab);
+            onTabChange(newTab);
+          }}
           isLaunch={isLaunch}
           hideSpacer={hideBottomSpacer}
           redirectTabAfterSave={redirectTabAfterSave}

+ 83 - 16
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx

@@ -38,9 +38,9 @@ type Props = {
 };
 
 const getReadableDate = (s: string) => {
-  let ts = new Date(s);
-  let date = ts.toLocaleDateString();
-  let time = ts.toLocaleTimeString([], {
+  const ts = new Date(s);
+  const date = ts.toLocaleDateString();
+  const time = ts.toLocaleTimeString([], {
     hour: "numeric",
     minute: "2-digit",
   });
@@ -72,12 +72,12 @@ const ExpandedChart: React.FC<Props> = (props) => {
   const [imageIsPlaceholder, setImageIsPlaceholer] = useState<boolean>(false);
   const [newestImage, setNewestImage] = useState<string>(null);
   const [isLoadingChartData, setIsLoadingChartData] = useState<boolean>(true);
-  const [showRepoTooltip, setShowRepoTooltip] = useState(false);
   const [isAuthorized] = useAuth();
   const [fullScreenLogs, setFullScreenLogs] = useState<boolean>(false);
   const [isFullscreen, setIsFullscreen] = useState<boolean>(false);
-  const [logData, setLogData] = useState<InitLogData>();
+  const [logData, setLogData] = useState<InitLogData>({});
   const [overrideCurrentTab, setOverrideCurrentTab] = useState("");
+  const [isAgentInstalled, setIsAgentInstalled] = useState<boolean>(false);
 
   const {
     isStack,
@@ -180,7 +180,7 @@ const ExpandedChart: React.FC<Props> = (props) => {
     const wsConfig = {
       onmessage(evt: MessageEvent) {
         const event = JSON.parse(evt.data);
-        let object = event.Object;
+        const object = event.Object;
         object.metadata.kind = event.Kind;
 
         if (event.event_type != "UPDATE") {
@@ -247,11 +247,11 @@ const ExpandedChart: React.FC<Props> = (props) => {
       values = currentChart.config;
     }
 
-    for (let key in rawValues) {
+    for (const key in rawValues) {
       _.set(values, key, rawValues[key]);
     }
 
-    let valuesYaml = yaml.dump({
+    const valuesYaml = yaml.dump({
       ...values,
     });
 
@@ -364,9 +364,9 @@ const ExpandedChart: React.FC<Props> = (props) => {
   const handleUpgradeVersion = useCallback(
     async (version: string, cb: () => void) => {
       // convert current values to yaml
-      let values = currentChart.config;
+      const values = currentChart.config;
 
-      let valuesYaml = yaml.dump({
+      const valuesYaml = yaml.dump({
         ...values,
       });
 
@@ -398,7 +398,7 @@ const ExpandedChart: React.FC<Props> = (props) => {
 
         cb && cb();
       } catch (err) {
-        let parsedErr = err?.response?.data?.error;
+        const parsedErr = err?.response?.data?.error;
 
         if (parsedErr) {
           err = parsedErr;
@@ -418,16 +418,22 @@ const ExpandedChart: React.FC<Props> = (props) => {
   );
 
   const renderTabContents = (currentTab: string) => {
-    let { setSidebar } = props;
-    let chart = currentChart;
+    const { setSidebar } = props;
+    const chart = currentChart; // // Reset the logData when navigating to a different tab
+
     switch (currentTab) {
       case "logs":
+        if (!isAgentInstalled) {
+          return null;
+        }
+
         return (
           <LogsSection
             currentChart={chart}
             isFullscreen={isFullscreen}
             setIsFullscreen={setIsFullscreen}
             initData={logData}
+            setInitData={setLogData}
           />
         );
       case "metrics":
@@ -547,7 +553,10 @@ const ExpandedChart: React.FC<Props> = (props) => {
         currentChart.chart.metadata.name === "job")
     ) {
       leftTabOptions.push({ label: "Events", value: "events" });
-      leftTabOptions.push({ label: "Logs", value: "logs" });
+
+      if (isAgentInstalled) {
+        leftTabOptions.push({ label: "Logs", value: "logs" });
+      }
     }
     leftTabOptions.push({ label: "Status", value: "status" });
 
@@ -578,7 +587,7 @@ const ExpandedChart: React.FC<Props> = (props) => {
 
     // Filter tabs if previewing an old revision or updating the chart version
     if (isPreview) {
-      let liveTabs = ["status", "events", "settings", "deploy", "metrics"];
+      const liveTabs = ["status", "events", "settings", "deploy", "metrics"];
       rightTabOptions = rightTabOptions.filter(
         (tab: any) => !liveTabs.includes(tab.value)
       );
@@ -697,6 +706,58 @@ const ExpandedChart: React.FC<Props> = (props) => {
     }
   };
 
+  // Check if porter agent is installed. If not installed hide the `Logs` component
+  useEffect(() => {
+    api
+      .detectPorterAgent(
+        "<token>",
+        {},
+        {
+          project_id: currentProject.id,
+          cluster_id: currentCluster.id,
+        }
+      )
+      .then(() => setIsAgentInstalled(true))
+      .catch((err) => {
+        setIsAgentInstalled(false);
+
+        if (err.status !== 404) {
+          setCurrentError(
+            "We could not detect the Porter agent installation status, please try again."
+          );
+        }
+      });
+  }, []);
+
+  useEffect(() => {
+    if (logData.revision) {
+      api
+        .getRevisions(
+          "<token>",
+          {},
+          {
+            id: currentProject.id,
+            namespace: props.currentChart.namespace,
+            cluster_id: currentCluster.id,
+            name: props.currentChart.name,
+          }
+        )
+        .then((res) => {
+          const chart = res.data?.find(
+            (revision: ChartType) =>
+              revision.version.toString() === logData.revision
+          );
+
+          setCurrentChart(chart ?? props.currentChart);
+        })
+        .catch(console.log);
+
+      return;
+    }
+
+    setCurrentChart(props.currentChart);
+  }, [logData, props.currentChart]);
+
   useEffect(() => {
     window.analytics?.track("Opened Chart", {
       chart: currentChart.name,
@@ -723,7 +784,7 @@ const ExpandedChart: React.FC<Props> = (props) => {
   useEffect(() => {
     updateTabs();
     localStorage.setItem("devOpsMode", devOpsMode.toString());
-  }, [devOpsMode, currentChart?.form, isPreview]);
+  }, [devOpsMode, currentChart?.form, isPreview, isAgentInstalled]);
 
   useEffect((): any => {
     let isSubscribed = true;
@@ -908,6 +969,12 @@ const ExpandedChart: React.FC<Props> = (props) => {
                               },
                             }}
                             overrideCurrentTab={overrideCurrentTab}
+                            onTabChange={(newTab) => {
+                              if (newTab !== "logs") {
+                                setOverrideCurrentTab("");
+                                setLogData({});
+                              }
+                            }}
                           />
                         </BodyWrapper>
                       )}

+ 4 - 6
dashboard/src/main/home/cluster-dashboard/expanded-chart/RevisionSection.tsx

@@ -184,12 +184,10 @@ class RevisionSection extends Component<PropsType, StateType> {
   };
 
   handleClickRevision = (revision: ChartType) => {
-    let isCurrent = revision.version === this.state.maxVersion;
-    if (isCurrent) {
-      this.props.setRevision(revision, true);
-    } else {
-      this.props.setRevision(revision);
-    }
+    this.props.setRevision(
+      revision,
+      revision.version === this.state.maxVersion
+    );
   };
 
   renderRevisionList = () => {

+ 64 - 31
dashboard/src/main/home/cluster-dashboard/expanded-chart/events/EventList.tsx

@@ -5,6 +5,7 @@ import styled from "styled-components";
 import EventTable from "./EventTable";
 import Loading from "components/Loading";
 import danger from "assets/danger.svg";
+import rocket from "assets/rocket.png";
 import document from "assets/document.svg";
 import info from "assets/info-outlined.svg";
 import status from "assets/info-circle.svg";
@@ -30,12 +31,12 @@ const EventList: React.FC<Props> = ({ filters, setLogData }) => {
 
   useEffect(() => {
     api
-      .listIncidents("<token>", filters, {
+      .listPorterEvents("<token>", filters, {
         project_id: currentProject.id,
         cluster_id: currentCluster.id,
       })
       .then((res) => {
-        setEvents(res.data.incidents);
+        setEvents(res.data.events);
         setIsLoading(false);
       });
   }, []);
@@ -97,6 +98,29 @@ const EventList: React.FC<Props> = ({ filters, setLogData }) => {
     );
   };
 
+  const renderIncidentSummaryCell = (incident: any) => {
+    return (
+      <NameWrapper>
+        <AlertIcon src={danger} />
+        {incident.short_summary}
+        {incident.severity === "normal" ? (
+          <></>
+        ) : (
+          <Status color="#cc3d42">Critical</Status>
+        )}
+      </NameWrapper>
+    );
+  };
+
+  const renderDeploymentFinishedCell = (release: any) => {
+    return (
+      <NameWrapper>
+        <AlertIcon src={rocket} />
+        Revision {release.revision} was successfully deployed
+      </NameWrapper>
+    );
+  };
+
   const columns = React.useMemo(
     () => [
       {
@@ -104,28 +128,24 @@ const EventList: React.FC<Props> = ({ filters, setLogData }) => {
         columns: [
           {
             Header: "Description",
-            accessor: "short_summary",
+            accessor: "type",
             width: 500,
             Cell: ({ row }: CellProps<any>) => {
-              return (
-                <NameWrapper>
-                  <AlertIcon src={danger} />
-                  {row.original.short_summary}
-                  {row?.original && row.original.severity === "normal" ? (
-                    <></>
-                  ) : (
-                    <Status color="#cc3d42">Critical</Status>
-                  )}
-                </NameWrapper>
-              );
+              if (row.original.type == "incident") {
+                return renderIncidentSummaryCell(row.original.data);
+              } else if (row.original.type == "deployment_finished") {
+                return renderDeploymentFinishedCell(row.original.data);
+              }
+
+              return null;
             },
           },
           {
-            Header: "Last seen",
-            accessor: "updated_at",
+            Header: "Last Seen",
+            accessor: "timestamp",
             width: 140,
             Cell: ({ row }: CellProps<any>) => {
-              return <Flex>{relativeDate(row.original.updated_at)}</Flex>;
+              return <Flex>{relativeDate(row.original.timestamp)}</Flex>;
             },
           },
           {
@@ -133,16 +153,20 @@ const EventList: React.FC<Props> = ({ filters, setLogData }) => {
             accessor: "",
             width: 20,
             Cell: ({ row }: CellProps<any>) => {
-              return (
-                <TableButton
-                  onClick={() => {
-                    setExpandedEvent(row.original);
-                  }}
-                >
-                  <Icon src={info} />
-                  Details
-                </TableButton>
-              );
+              if (row.original.type == "incident") {
+                return (
+                  <TableButton
+                    onClick={() => {
+                      setExpandedEvent(row.original.data);
+                    }}
+                  >
+                    <Icon src={info} />
+                    Details
+                  </TableButton>
+                );
+              }
+
+              return null;
             },
           },
           {
@@ -150,7 +174,11 @@ const EventList: React.FC<Props> = ({ filters, setLogData }) => {
             accessor: "",
             width: 30,
             Cell: ({ row }: CellProps<any>) => {
-              if (!row.original.should_view_logs) {
+              if (row.original.type != "incident") {
+                return null;
+              }
+
+              if (!row.original.data.should_view_logs) {
                 return null;
               }
 
@@ -158,7 +186,7 @@ const EventList: React.FC<Props> = ({ filters, setLogData }) => {
                 <TableButton
                   width="102px"
                   onClick={() => {
-                    redirectToLogs(row.original);
+                    redirectToLogs(row.original.data);
                   }}
                 >
                   <Icon src={document} />
@@ -209,10 +237,10 @@ const EventList: React.FC<Props> = ({ filters, setLogData }) => {
             </TableWrapper>
           ) : (
             <Placeholder>
-              <div>
+              <NoResultsFoundWrapper>
                 <Title>No results found</Title>
                 There were no results found for this filter.
-              </div>
+              </NoResultsFoundWrapper>
             </Placeholder>
           )}
         </>
@@ -378,3 +406,8 @@ const StyledMonitorList = styled.div`
   border-radius: 5px;
   border: 1px solid #aaaabb33;
 `;
+
+const NoResultsFoundWrapper = styled(Flex)`
+  flex-direction: column;
+  justify-contents: center;
+`;

+ 3 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/logs-section/LogsSection.tsx

@@ -32,6 +32,7 @@ type Props = {
   isFullscreen: boolean;
   setIsFullscreen: (x: boolean) => void;
   initData?: InitLogData;
+  setInitData: (initData: InitLogData) => void;
 };
 
 const escapeRegExp = (str: string) => {
@@ -97,6 +98,7 @@ const LogsSection: React.FC<Props> = ({
   isFullscreen,
   setIsFullscreen,
   initData = {},
+  setInitData,
 }) => {
   const scrollToBottomRef = useRef<HTMLDivElement | undefined>(undefined);
   const { currentProject, currentCluster } = useContext(Context);
@@ -108,7 +110,7 @@ const LogsSection: React.FC<Props> = ({
   const [searchText, setSearchText] = useState("");
   const [enteredSearchText, setEnteredSearchText] = useState("");
   const [selectedDate, setSelectedDate] = useState<Date | undefined>(
-    initData ? dayjs(initData.timestamp).toDate() : undefined
+    initData.timestamp ? dayjs(initData.timestamp).toDate() : undefined
   );
 
   const { loading, logs, refresh, moveCursor, paginationInfo } = useLogs(

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

@@ -2029,6 +2029,22 @@ const getLogs = baseApi<
     `/api/projects/${project_id}/clusters/${cluster_id}/logs`
 );
 
+const listPorterEvents = baseApi<
+  {
+    release_name?: number;
+    release_namespace?: string;
+    type?: string;
+  },
+  {
+    project_id: number;
+    cluster_id: number;
+  }
+>(
+  "GET",
+  ({ project_id, cluster_id }) =>
+    `/api/projects/${project_id}/clusters/${cluster_id}/events`
+);
+
 const listIncidents = baseApi<
   {
     release_name?: number;
@@ -2505,6 +2521,7 @@ export default {
   getGitlabFolderContent,
   getLogPodValues,
   getLogs,
+  listPorterEvents,
   listIncidents,
   getIncident,
   getIncidentEvents,

+ 50 - 4
internal/kubernetes/porter_agent/v2/agent_server.go

@@ -21,6 +21,52 @@ func GetAgentService(clientset kubernetes.Interface) (*v1.Service, error) {
 	)
 }
 
+func ListPorterEvents(
+	clientset kubernetes.Interface,
+	service *v1.Service,
+	req *types.ListEventsRequest,
+) (*types.ListEventsResponse, error) {
+	vals := make(map[string]string)
+
+	if req.Type != nil {
+		vals["type"] = *req.Type
+	}
+
+	if req.ReleaseName != nil {
+		vals["release_name"] = *req.ReleaseName
+	}
+
+	if req.ReleaseNamespace != nil {
+		vals["release_namespace"] = *req.ReleaseNamespace
+	}
+
+	if req.PaginationRequest != nil {
+		vals["page"] = fmt.Sprintf("%d", req.PaginationRequest.Page)
+	}
+
+	resp := clientset.CoreV1().Services(service.Namespace).ProxyGet(
+		"http",
+		service.Name,
+		fmt.Sprintf("%d", service.Spec.Ports[0].Port),
+		"/events",
+		vals,
+	)
+
+	rawQuery, err := resp.DoRaw(context.Background())
+	if err != nil {
+		return nil, err
+	}
+
+	eventsResp := &types.ListEventsResponse{}
+
+	err = json.Unmarshal(rawQuery, eventsResp)
+	if err != nil {
+		return nil, err
+	}
+
+	return eventsResp, nil
+}
+
 func ListIncidents(
 	clientset kubernetes.Interface,
 	service *v1.Service,
@@ -310,11 +356,11 @@ func GetRevisionValues(
 	return valsResp, nil
 }
 
-func GetHistoricalEvents(
+func GetHistoricalKubernetesEvents(
 	clientset kubernetes.Interface,
 	service *v1.Service,
-	req *types.GetEventRequest,
-) (*types.GetEventResponse, error) {
+	req *types.GetKubernetesEventRequest,
+) (*types.GetKubernetesEventResponse, error) {
 	vals := make(map[string]string)
 
 	if req.Limit != 0 {
@@ -357,7 +403,7 @@ func GetHistoricalEvents(
 		return nil, err
 	}
 
-	eventsResp := &types.GetEventResponse{}
+	eventsResp := &types.GetKubernetesEventResponse{}
 
 	err = json.Unmarshal(rawQuery, eventsResp)
 	if err != nil {