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

Merge branch 'belanger/agent-v3-integration' into dev

Alexander Belanger 3 жил өмнө
parent
commit
6d842da75c

+ 65 - 0
api/server/handlers/cluster/get_porter_job_events.go

@@ -0,0 +1,65 @@
+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"
+	"github.com/porter-dev/porter/internal/models"
+
+	porter_agent "github.com/porter-dev/porter/internal/kubernetes/porter_agent/v2"
+)
+
+type GetPorterJobEventsHandler struct {
+	handlers.PorterHandlerReadWriter
+	authz.KubernetesAgentGetter
+}
+
+func NewGetPorterJobEventsHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *GetPorterJobEventsHandler {
+	return &GetPorterJobEventsHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+		KubernetesAgentGetter:   authz.NewOutOfClusterAgentGetter(config),
+	}
+}
+
+func (c *GetPorterJobEventsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
+
+	request := &types.ListJobEventsRequest{}
+
+	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
+	}
+
+	events, err := porter_agent.ListPorterJobEvents(agent.Clientset, agentSvc, request)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	c.WriteResult(w, r, events)
+}

+ 1 - 9
api/server/handlers/cluster/list_incident_events.go

@@ -8,7 +8,6 @@ import (
 	"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/server/shared/requestutils"
 	"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"
@@ -33,13 +32,6 @@ func NewListIncidentEventsHandler(
 func (c *ListIncidentEventsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
 
-	incidentID, reqErr := requestutils.GetURLParamString(r, types.URLParamIncidentID)
-
-	if reqErr != nil {
-		c.HandleAPIError(w, r, reqErr)
-		return
-	}
-
 	request := &types.ListIncidentEventsRequest{}
 
 	if ok := c.DecodeAndValidate(w, r, request); !ok {
@@ -61,7 +53,7 @@ func (c *ListIncidentEventsHandler) ServeHTTP(w http.ResponseWriter, r *http.Req
 		return
 	}
 
-	events, err := porter_agent.ListIncidentEvents(agent.Clientset, agentSvc, incidentID, request)
+	events, err := porter_agent.ListIncidentEvents(agent.Clientset, agentSvc, request)
 
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))

+ 31 - 2
api/server/router/cluster.go

@@ -1121,14 +1121,14 @@ func getClusterRoutes(
 		Router:   r,
 	})
 
-	// GET /api/projects/{project_id}/clusters/{cluster_id}/incidents/{incident_id}/events -> cluster.NewListIncidentEventsHandler
+	// GET /api/projects/{project_id}/clusters/{cluster_id}/incidents/events -> cluster.NewListIncidentEventsHandler
 	listIncidentEventsEndpoint := factory.NewAPIEndpoint(
 		&types.APIRequestMetadata{
 			Verb:   types.APIVerbGet,
 			Method: types.HTTPVerbGet,
 			Path: &types.Path{
 				Parent:       basePath,
-				RelativePath: fmt.Sprintf("%s/incidents/{%s}/events", relPath, types.URLParamIncidentID),
+				RelativePath: fmt.Sprintf("%s/incidents/events", relPath),
 			},
 			Scopes: []types.PermissionScope{
 				types.UserScope,
@@ -1266,6 +1266,35 @@ func getClusterRoutes(
 		Router:   r,
 	})
 
+	// GET /api/projects/{project_id}/clusters/{cluster_id}/events/job -> cluster.NewGetPorterJobEventsHandler
+	getPorterJobEventsEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: fmt.Sprintf("%s/events/job", relPath),
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.ClusterScope,
+			},
+		},
+	)
+
+	getPorterJobEventsHandler := cluster.NewGetPorterJobEventsHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &router.Route{
+		Endpoint: getPorterJobEventsEndpoint,
+		Handler:  getPorterJobEventsHandler,
+		Router:   r,
+	})
+
 	// GET /api/projects/{project_id}/clusters/{cluster_id}/k8s_events -> cluster.NewGetEventsHandler
 	getK8sEventsEndpoint := factory.NewAPIEndpoint(
 		&types.APIRequestMetadata{

+ 10 - 0
api/types/incident.go

@@ -86,9 +86,11 @@ type IncidentEvent struct {
 
 type ListIncidentEventsRequest struct {
 	*PaginationRequest
+	IncidentID   *string `schema:"incident_id"`
 	PodName      *string `schema:"pod_name"`
 	PodNamespace *string `schema:"pod_namespace"`
 	Summary      *string `schema:"summary"`
+	PodPrefix    *string `schema:"pod_prefix"`
 }
 
 type ListIncidentEventsResponse struct {
@@ -180,3 +182,11 @@ type ListEventsResponse struct {
 	Events     []*Event            `json:"events" form:"required"`
 	Pagination *PaginationResponse `json:"pagination"`
 }
+
+type ListJobEventsRequest struct {
+	*PaginationRequest
+	ReleaseName      *string `schema:"release_name"`
+	ReleaseNamespace *string `schema:"release_namespace"`
+	Type             *string `schema:"type"`
+	JobName          string  `schema:"job_name" form:"required"`
+}

+ 1 - 0
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx

@@ -843,6 +843,7 @@ const ExpandedChart: React.FC<Props> = (props) => {
               isFullscreen={true}
               setIsFullscreen={setIsFullscreen}
               currentChart={currentChart}
+              setInitData={() => {}}
             />
           ) : (
             <StyledExpandedChart>

+ 3 - 2
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedJobChart.tsx

@@ -1,4 +1,4 @@
-import React, { useContext, useMemo, useState } from "react";
+import React, { useContext, useEffect, useMemo, useState } from "react";
 import styled from "styled-components";
 import yaml from "js-yaml";
 
@@ -28,6 +28,7 @@ import CronParser from "cron-parser";
 import CronPrettifier from "cronstrue";
 import BuildSettingsTab from "./build-settings/BuildSettingsTab";
 import { useStackEnvGroups } from "./useStackEnvGroups";
+import api from "shared/api";
 
 const readableDate = (s: string) => {
   let ts = new Date(s);
@@ -46,7 +47,7 @@ export const ExpandedJobChartFC: React.FC<{
   closeChart: () => void;
   setSidebar: (x: boolean) => void;
 }> = ({ currentChart: oldChart, closeChart, currentCluster }) => {
-  const { setCurrentOverlay } = useContext(Context);
+  const { currentProject, setCurrentOverlay } = useContext(Context);
   const [isAuthorized] = useAuth();
   const {
     chart,

+ 49 - 13
dashboard/src/main/home/cluster-dashboard/expanded-chart/events/EventList.tsx

@@ -30,15 +30,27 @@ const EventList: React.FC<Props> = ({ filters, setLogData }) => {
   const [isLoading, setIsLoading] = useState(true);
 
   useEffect(() => {
-    api
-      .listPorterEvents("<token>", filters, {
-        project_id: currentProject.id,
-        cluster_id: currentCluster.id,
-      })
-      .then((res) => {
-        setEvents(res.data.events);
-        setIsLoading(false);
-      });
+    if (filters.job_name) {
+      api
+        .listPorterJobEvents("<token>", filters, {
+          project_id: currentProject.id,
+          cluster_id: currentCluster.id,
+        })
+        .then((res) => {
+          setEvents(res.data.events);
+          setIsLoading(false);
+        });
+    } else {
+      api
+        .listPorterEvents("<token>", filters, {
+          project_id: currentProject.id,
+          cluster_id: currentCluster.id,
+        })
+        .then((res) => {
+          setEvents(res.data.events);
+          setIsLoading(false);
+        });
+    }
   }, []);
 
   useEffect(() => {
@@ -49,11 +61,12 @@ const EventList: React.FC<Props> = ({ filters, setLogData }) => {
     api
       .getIncidentEvents(
         "<token>",
-        {},
+        {
+          incident_id: expandedEvent.id,
+        },
         {
           project_id: currentProject.id,
           cluster_id: currentCluster.id,
-          incident_id: expandedEvent.id,
         }
       )
       .then((res) => {
@@ -65,11 +78,12 @@ const EventList: React.FC<Props> = ({ filters, setLogData }) => {
     api
       .getIncidentEvents(
         "<token>",
-        {},
+        {
+          incident_id: incident.id,
+        },
         {
           project_id: currentProject.id,
           cluster_id: currentCluster.id,
-          incident_id: incident.id,
         }
       )
       .then((res) => {
@@ -121,6 +135,24 @@ const EventList: React.FC<Props> = ({ filters, setLogData }) => {
     );
   };
 
+  const renderJobStartedCell = (timestamp: any) => {
+    return (
+      <NameWrapper>
+        <AlertIcon src={time} />
+        The job started at {readableDate(timestamp)}
+      </NameWrapper>
+    );
+  };
+
+  const renderJobFinishedCell = (timestamp: any) => {
+    return (
+      <NameWrapper>
+        <AlertIcon src={time} />
+        The job finished at {readableDate(timestamp)}
+      </NameWrapper>
+    );
+  };
+
   const columns = React.useMemo(
     () => [
       {
@@ -135,6 +167,10 @@ const EventList: React.FC<Props> = ({ filters, setLogData }) => {
                 return renderIncidentSummaryCell(row.original.data);
               } else if (row.original.type == "deployment_finished") {
                 return renderDeploymentFinishedCell(row.original.data);
+              } else if (row.original.type == "job_started") {
+                return renderJobStartedCell(row.original.timestamp);
+              } else if (row.original.type == "job_finished") {
+                return renderJobFinishedCell(row.original.timestamp);
               }
 
               return null;

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

@@ -11,9 +11,14 @@ import { InitLogData } from "../logs-section/LogsSection";
 type Props = {
   currentChart: any;
   setLogData?: (logData: InitLogData) => void;
+  overridingJobName?: string;
 };
 
-const EventsTab: React.FC<Props> = ({ currentChart, setLogData }) => {
+const EventsTab: React.FC<Props> = ({
+  currentChart,
+  setLogData,
+  overridingJobName,
+}) => {
   const [hasPorterAgent, setHasPorterAgent] = useState(true);
   const { currentProject, currentCluster } = useContext(Context);
   const [isLoading, setIsLoading] = useState(true);
@@ -55,6 +60,21 @@ const EventsTab: React.FC<Props> = ({ currentChart, setLogData }) => {
     installAgent();
   };
 
+  const getFilters = () => {
+    if (overridingJobName) {
+      return {
+        release_name: currentChart.name,
+        release_namespace: currentChart.namespace,
+        job_name: overridingJobName,
+      };
+    }
+
+    return {
+      release_name: currentChart.name,
+      release_namespace: currentChart.namespace,
+    };
+  };
+
   if (isLoading) {
     return (
       <Placeholder>
@@ -79,13 +99,7 @@ const EventsTab: React.FC<Props> = ({ currentChart, setLogData }) => {
 
   return (
     <EventsPageWrapper>
-      <EventList
-        setLogData={setLogData}
-        filters={{
-          release_name: currentChart.name,
-          release_namespace: currentChart.namespace,
-        }}
-      />
+      <EventList setLogData={setLogData} filters={getFilters()} />
     </EventsPageWrapper>
   );
 };

+ 73 - 44
dashboard/src/main/home/cluster-dashboard/expanded-chart/jobs/ExpandedJobRun.tsx

@@ -14,6 +14,9 @@ import DeploymentType from "../DeploymentType";
 import JobMetricsSection from "../metrics/JobMetricsSection";
 import Logs from "../status/Logs";
 import { useRouting } from "shared/routing";
+import Banner from "components/Banner";
+import LogsSection from "../logs-section/LogsSection";
+import EventsTab from "../events/EventsTab";
 
 const readableDate = (s: string) => {
   let ts = new Date(s);
@@ -54,36 +57,7 @@ const renderStatus = (job: any, pods: any[], time: string) => {
   }
 
   if (job.status?.failed >= 1) {
-    const appPod = getLatestPod(pods);
-
-    if (appPod) {
-      const appContainerStatus = appPod?.status?.containerStatuses?.find(
-        (container: any) =>
-          container?.state?.terminated?.reason !== "Completed" &&
-          !container?.state?.running
-      );
-
-      if (appContainerStatus) {
-        const reason = appContainerStatus.state.terminated.reason;
-        const exitCode = appContainerStatus.state.terminated.exitCode;
-        const finishTime = appContainerStatus.state.terminated.finishedAt;
-
-        return (
-          <Status color="#cc3d42">
-            Failed at {time ? time : readableDate(finishTime)} - Reason:{" "}
-            {reason} - Exit Code: {exitCode}
-          </Status>
-        );
-      }
-    }
-
-    return (
-      <Status color="#cc3d42">
-        Failed {time}
-        {job.status.conditions.length > 0 &&
-          `: ${job.status.conditions[0].reason}`}
-      </Status>
-    );
+    return <Status color="#cc3d42">Failed</Status>;
   }
 
   return <Status color="#ffffff11">Running</Status>;
@@ -102,11 +76,12 @@ const ExpandedJobRun = ({
     Context
   );
   const [currentTab, setCurrentTab] = useState<
-    "logs" | "metrics" | "config" | string
-  >("logs");
+    "events" | "logs" | "metrics" | "config" | string
+  >("events");
   const [pods, setPods] = useState<any>(null);
   const [isLoading, setIsLoading] = useState(true);
   const { pushQueryParams } = useRouting();
+  const [useDeprecatedLogs, setUseDeprecatedLogs] = useState(false);
 
   let chart = currentChart;
   let run = jobRun;
@@ -191,6 +166,52 @@ const ExpandedJobRun = ({
     );
   };
 
+  const renderEventsSection = () => {
+    return (
+      <EventsTab
+        currentChart={currentChart}
+        overridingJobName={jobRun.metadata?.name}
+      />
+    );
+  };
+
+  const renderLogsSection = () => {
+    if (useDeprecatedLogs) {
+      return (
+        <JobLogsWrapper>
+          <Logs
+            selectedPod={pods[0]}
+            podError={!pods[0] ? "Pod no longer exists." : ""}
+            rawText={true}
+          />
+        </JobLogsWrapper>
+      );
+    }
+
+    return (
+      <JobLogsWrapper>
+        <DeprecatedWarning>
+          Not seeing your logs? Switch back to{" "}
+          <DeprecatedSelect
+            onClick={() => {
+              setUseDeprecatedLogs(true);
+            }}
+          >
+            {" "}
+            deprecated logging.
+          </DeprecatedSelect>
+        </DeprecatedWarning>
+        <LogsSection
+          isFullscreen={false}
+          setIsFullscreen={() => {}}
+          overridingPodName={pods[0].metadata.name}
+          setInitData={() => {}}
+          currentChart={currentChart}
+        />
+      </JobLogsWrapper>
+    );
+  };
+
   if (isLoading) {
     return <Loading />;
   }
@@ -207,7 +228,6 @@ const ExpandedJobRun = ({
         <TitleSection icon={currentChart.chart.metadata.icon} iconWidth="33px">
           {chart.name} <Gray>at {readableDate(run.status.startTime)}</Gray>
         </TitleSection>
-
         <InfoWrapper>
           <LastDeployed>
             {renderStatus(
@@ -229,6 +249,10 @@ const ExpandedJobRun = ({
           currentTab={currentTab}
           setCurrentTab={(x: string) => setCurrentTab(x)}
           options={[
+            {
+              label: "Events",
+              value: "events",
+            },
             {
               label: "Logs",
               value: "logs",
@@ -243,15 +267,8 @@ const ExpandedJobRun = ({
             },
           ]}
         >
-          {currentTab === "logs" && (
-            <JobLogsWrapper>
-              <Logs
-                selectedPod={pods[0]}
-                podError={!pods[0] ? "Pod no longer exists." : ""}
-                rawText={true}
-              />
-            </JobLogsWrapper>
-          )}
+          {currentTab === "events" && renderEventsSection()}
+          {currentTab === "logs" && renderLogsSection()}
           {currentTab === "config" && <>{renderConfigSection(run)}</>}
           {currentTab === "metrics" && (
             <JobMetricsSection jobChart={currentChart} jobRun={run} />
@@ -323,10 +340,9 @@ const ConfigSection = styled.div`
 
 const JobLogsWrapper = styled.div`
   min-height: 450px;
-  height: 55vh;
+  height: 65vh;
   width: 100%;
   border-radius: 8px;
-  background-color: black;
   overflow-y: auto;
 `;
 
@@ -468,3 +484,16 @@ const StyledExpandedChart = styled.div`
     }
   }
 `;
+
+const DeprecatedWarning = styled.div`
+  font-size: 12px;
+  color: #ccc;
+  text-align: right;
+  width: 100%;
+  margin-bottom: 20px;
+`;
+
+const DeprecatedSelect = styled.span`
+  cursor: pointer;
+  color: #949effff;
+`;

+ 14 - 2
dashboard/src/main/home/cluster-dashboard/expanded-chart/logs-section/LogsSection.tsx

@@ -33,6 +33,7 @@ type Props = {
   setIsFullscreen: (x: boolean) => void;
   initData?: InitLogData;
   setInitData: (initData: InitLogData) => void;
+  overridingPodName?: string;
 };
 
 const escapeRegExp = (str: string) => {
@@ -99,12 +100,19 @@ const LogsSection: React.FC<Props> = ({
   setIsFullscreen,
   initData = {},
   setInitData,
+  overridingPodName,
 }) => {
   const scrollToBottomRef = useRef<HTMLDivElement | undefined>(undefined);
   const { currentProject, currentCluster } = useContext(Context);
-  const [podFilter, setPodFilter] = useState(initData.podName);
+  const [podFilter, setPodFilter] = useState(
+    initData.podName || overridingPodName
+  );
   const [podFilterOpts, setPodFilterOpts] = useState<string[]>(
-    _.compact([initData.podName])
+    initData?.podName
+      ? _.compact([initData.podName])
+      : overridingPodName
+      ? _.compact([overridingPodName])
+      : []
   );
   const [scrollToBottomEnabled, setScrollToBottomEnabled] = useState(true);
   const [searchText, setSearchText] = useState("");
@@ -122,6 +130,10 @@ const LogsSection: React.FC<Props> = ({
   );
 
   useEffect(() => {
+    if (overridingPodName) {
+      return;
+    }
+
     api
       .getLogPodValues(
         "<TOKEN>",

+ 24 - 4
dashboard/src/shared/api.tsx

@@ -2045,6 +2045,23 @@ const listPorterEvents = baseApi<
     `/api/projects/${project_id}/clusters/${cluster_id}/events`
 );
 
+const listPorterJobEvents = baseApi<
+  {
+    release_name?: number;
+    release_namespace?: string;
+    type?: string;
+    job_name: string;
+  },
+  {
+    project_id: number;
+    cluster_id: number;
+  }
+>(
+  "GET",
+  ({ project_id, cluster_id }) =>
+    `/api/projects/${project_id}/clusters/${cluster_id}/events/job`
+);
+
 const listIncidents = baseApi<
   {
     release_name?: number;
@@ -2075,16 +2092,18 @@ const getIncident = baseApi<
 );
 
 const getIncidentEvents = baseApi<
-  {},
+  {
+    incident_id?: string;
+    pod_prefix?: string;
+  },
   {
     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`
+  ({ project_id, cluster_id }) =>
+    `/api/projects/${project_id}/clusters/${cluster_id}/incidents/events`
 );
 
 // STACKS
@@ -2522,6 +2541,7 @@ export default {
   getLogPodValues,
   getLogs,
   listPorterEvents,
+  listPorterJobEvents,
   listIncidents,
   getIncident,
   getIncidentEvents,

+ 58 - 2
internal/kubernetes/porter_agent/v2/agent_server.go

@@ -67,6 +67,54 @@ func ListPorterEvents(
 	return eventsResp, nil
 }
 
+func ListPorterJobEvents(
+	clientset kubernetes.Interface,
+	service *v1.Service,
+	req *types.ListJobEventsRequest,
+) (*types.ListEventsResponse, error) {
+	vals := make(map[string]string)
+
+	vals["job_name"] = req.JobName
+
+	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/job",
+		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,
@@ -143,11 +191,14 @@ func GetIncidentByID(
 func ListIncidentEvents(
 	clientset kubernetes.Interface,
 	service *v1.Service,
-	incidentID string,
 	req *types.ListIncidentEventsRequest,
 ) (*types.ListIncidentEventsResponse, error) {
 	vals := make(map[string]string)
 
+	if req.IncidentID != nil {
+		vals["incident_id"] = *req.IncidentID
+	}
+
 	if req.PodName != nil {
 		vals["pod_name"] = *req.PodName
 	}
@@ -159,15 +210,20 @@ func ListIncidentEvents(
 	if req.Summary != nil {
 		vals["summary"] = *req.Summary
 	}
+
 	if req.PaginationRequest != nil {
 		vals["page"] = fmt.Sprintf("%d", req.PaginationRequest.Page)
 	}
 
+	if req.PodPrefix != nil {
+		vals["pod_prefix"] = *req.PodPrefix
+	}
+
 	resp := clientset.CoreV1().Services(service.Namespace).ProxyGet(
 		"http",
 		service.Name,
 		fmt.Sprintf("%d", service.Spec.Ports[0].Port),
-		fmt.Sprintf("/incidents/%s/events", incidentID),
+		"/incidents/events",
 		vals,
 	)