Ver código fonte

add logs endpoint

Alexander Belanger 4 anos atrás
pai
commit
c58b776810

+ 63 - 0
api/server/handlers/cluster/get_pods.go

@@ -0,0 +1,63 @@
+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"
+	v1 "k8s.io/api/core/v1"
+)
+
+type GetPodsHandler struct {
+	handlers.PorterHandlerReadWriter
+	authz.KubernetesAgentGetter
+}
+
+func NewGetPodsHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *GetPodsHandler {
+	return &GetPodsHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+		KubernetesAgentGetter:   authz.NewOutOfClusterAgentGetter(config),
+	}
+}
+
+func (c *GetPodsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	request := &types.GetPodsRequest{}
+
+	if ok := c.DecodeAndValidate(w, r, request); !ok {
+		return
+	}
+
+	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
+
+	agent, err := c.GetAgent(r, cluster)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	pods := []v1.Pod{}
+	for _, selector := range request.Selectors {
+		podsList, err := agent.GetPodsByLabel(selector, request.Namespace)
+
+		if err != nil {
+			c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+			return
+		}
+
+		for _, pod := range podsList.Items {
+			pods = append(pods, pod)
+		}
+	}
+
+	c.WriteResult(w, r, pods)
+}

+ 58 - 0
api/server/handlers/namespace/stream_pod_logs.go

@@ -0,0 +1,58 @@
+package namespace
+
+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/server/shared/requestutils"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+)
+
+type StreamPodLogsHandler struct {
+	handlers.PorterHandlerReadWriter
+	authz.KubernetesAgentGetter
+}
+
+func NewStreamPodLogsHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *StreamPodLogsHandler {
+	return &StreamPodLogsHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+		KubernetesAgentGetter:   authz.NewOutOfClusterAgentGetter(config),
+	}
+}
+
+func (c *StreamPodLogsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	conn, err := c.Config().WSUpgrader.Upgrade(w, r, nil)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	namespace := r.Context().Value(types.NamespaceScope).(string)
+	name, _ := requestutils.GetURLParamString(r, types.URLParamPodName)
+
+	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
+
+	agent, err := c.GetAgent(r, cluster)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	err = agent.GetPodLogs(namespace, name, conn)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+}

+ 29 - 0
api/server/router/cluster.go

@@ -339,5 +339,34 @@ func getClusterRoutes(
 		Router:   r,
 	})
 
+	// GET /api/projects/{project_id}/clusters/{cluster_id}/pods -> cluster.NewGetPodsHandler
+	getPodsEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/pods",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.ClusterScope,
+			},
+		},
+	)
+
+	getPodsHandler := cluster.NewGetPodsHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: getPodsEndpoint,
+		Handler:  getPodsHandler,
+		Router:   r,
+	})
+
 	return routes, newPath
 }

+ 36 - 0
api/server/router/namespace.go

@@ -1,6 +1,8 @@
 package router
 
 import (
+	"fmt"
+
 	"github.com/go-chi/chi"
 
 	"github.com/porter-dev/porter/api/server/handlers/namespace"
@@ -261,5 +263,39 @@ func getNamespaceRoutes(
 		Router:   r,
 	})
 
+	// GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/pod/{name}/logs -> namespace.NewStreamPodLogsHandler
+	streamPodLogsEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent: basePath,
+				RelativePath: fmt.Sprintf(
+					"%s/pod/{%s}/logs",
+					relPath,
+					types.URLParamPodName,
+				),
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.ClusterScope,
+				types.NamespaceScope,
+			},
+		},
+	)
+
+	streamPodLogsHandler := namespace.NewStreamPodLogsHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: streamPodLogsEndpoint,
+		Handler:  streamPodLogsHandler,
+		Router:   r,
+	})
+
 	return routes, newPath
 }

+ 5 - 0
api/types/cluster.go

@@ -73,3 +73,8 @@ type GetPodMetricsRequest struct {
 }
 
 type GetPodMetricsResponse *string
+
+type GetPodsRequest struct {
+	Namespace string   `schema:"namespace"`
+	Selectors []string `schema:"selectors"`
+}

+ 4 - 0
api/types/namespace.go

@@ -6,6 +6,10 @@ import (
 	v1 "k8s.io/api/core/v1"
 )
 
+const (
+	URLParamPodName URLParam = "name"
+)
+
 // ReleaseListFilter is a struct that represents the various filter options used for
 // retrieving the releases
 type ReleaseListFilter struct {

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/metrics/MetricsSection.tsx

@@ -195,12 +195,12 @@ const MetricsSection: React.FunctionComponent<PropsType> = ({
       .getMatchingPods(
         "<token>",
         {
-          cluster_id: currentCluster.id,
           namespace: selectedController?.metadata?.namespace,
           selectors,
         },
         {
           id: currentProject.id,
+          cluster_id: currentCluster.id,
         }
       )
       .then((res) => {

+ 3 - 3
dashboard/src/main/home/cluster-dashboard/expanded-chart/status/ControllerTab.tsx

@@ -91,12 +91,12 @@ const ControllerTabFC: React.FunctionComponent<Props> = ({
       const res = await api.getMatchingPods(
         "<token>",
         {
-          cluster_id: currentCluster.id,
           namespace: controller?.metadata?.namespace,
           selectors: currentSelectors,
         },
         {
           id: currentProject.id,
+          cluster_id: currentCluster.id,
         }
       );
       const data = res?.data as any[];
@@ -293,9 +293,9 @@ const ControllerTabFC: React.FunctionComponent<Props> = ({
   };
 
   const setupWebsocket = (kind: string, controllerUid: string) => {
-    let apiEndpoint = `/api/projects/${currentProject.id}/clusters/${currentCluster.id}/${kind}/status`;
+    let apiEndpoint = `/api/projects/${currentProject.id}/clusters/${currentCluster.id}/${kind}/status?`;
     if (kind == "pod" && currentSelectors) {
-      apiEndpoint += `&selectors=${currentSelectors[0]}`;
+      apiEndpoint += `selectors=${currentSelectors[0]}`;
     }
 
     const options: NewWebsocketOptions = {};

+ 2 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/status/Logs.tsx

@@ -99,8 +99,9 @@ export default class Logs extends Component<PropsType, StateType> {
     let { selectedPod } = this.props;
     if (!selectedPod?.metadata?.name) return;
     let protocol = window.location.protocol == "https:" ? "wss" : "ws";
+
     this.ws = new WebSocket(
-      `${protocol}://${window.location.host}/api/projects/${currentProject.id}/k8s/${selectedPod?.metadata?.namespace}/pod/${selectedPod?.metadata?.name}/logs?cluster_id=${currentCluster.id}&service_account_id=${currentCluster.service_account_id}`
+      `${protocol}://${window.location.host}/api/projects/${currentProject.id}/clusters/${currentCluster.id}/namespaces/${selectedPod?.metadata?.namespace}/pod/${selectedPod?.metadata?.name}/logs`
     );
 
     this.ws.onopen = () => {};

+ 2 - 5
dashboard/src/shared/api.tsx

@@ -578,13 +578,12 @@ const getJobPods = baseApi<
 
 const getMatchingPods = baseApi<
   {
-    cluster_id: number;
     namespace: string;
     selectors: string[];
   },
-  { id: number }
+  { id: number, cluster_id: number; }
 >("GET", (pathParams) => {
-  return `/api/projects/${pathParams.id}/k8s/pods`;
+  return `/api/projects/${pathParams.id}/clusters/${pathParams.cluster_id}/pods`;
 });
 
 const getMetrics = baseApi<
@@ -731,8 +730,6 @@ const getRevisions = baseApi<
   },
   { id: number; cluster_id: number; namespace: string; name: string }
 >("GET", (pathParams) => {
-  console.log("PATH PARAMS", pathParams)
-
   let { id, cluster_id, namespace, name } = pathParams
 
   return `/api/projects/${id}/clusters/${cluster_id}/namespaces/${namespace}/releases/${name}/history`