-
Notifications
You must be signed in to change notification settings - Fork 239
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
Feroze Mohideen
authored
Sep 19, 2023
1 parent
f9eea61
commit e34ed7d
Showing
11 changed files
with
816 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package porter_app | ||
|
||
import ( | ||
"net/http" | ||
|
||
"connectrpc.com/connect" | ||
porterv1 "github.com/porter-dev/api-contracts/generated/go/porter/v1" | ||
"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" | ||
"github.com/porter-dev/porter/internal/telemetry" | ||
v1 "k8s.io/api/core/v1" | ||
) | ||
|
||
// PodStatusHandler is the handler for GET /apps/pods | ||
type PodStatusHandler struct { | ||
handlers.PorterHandlerReadWriter | ||
authz.KubernetesAgentGetter | ||
} | ||
|
||
// NewPodStatusHandler returns a new PodStatusHandler | ||
func NewPodStatusHandler( | ||
config *config.Config, | ||
decoderValidator shared.RequestDecoderValidator, | ||
writer shared.ResultWriter, | ||
) *PodStatusHandler { | ||
return &PodStatusHandler{ | ||
PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer), | ||
KubernetesAgentGetter: authz.NewOutOfClusterAgentGetter(config), | ||
} | ||
} | ||
|
||
// PodStatusRequest is the expected format for a request body on GET /apps/pods | ||
type PodStatusRequest struct { | ||
DeploymentTargetID string `schema:"deployment_target_id"` | ||
Selectors string `schema:"selectors"` | ||
} | ||
|
||
func (c *PodStatusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
ctx, span := telemetry.NewSpan(r.Context(), "serve-pod-status") | ||
defer span.End() | ||
|
||
request := &PodStatusRequest{} | ||
if ok := c.DecodeAndValidate(w, r, request); !ok { | ||
err := telemetry.Error(ctx, span, nil, "invalid request") | ||
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest)) | ||
return | ||
} | ||
|
||
cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster) | ||
project, _ := r.Context().Value(types.ProjectScope).(*models.Project) | ||
|
||
telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "selectors", Value: request.Selectors}) | ||
|
||
if request.DeploymentTargetID == "" { | ||
err := telemetry.Error(ctx, span, nil, "must provide deployment target id") | ||
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest)) | ||
return | ||
} | ||
telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "deployment-target-id", Value: request.DeploymentTargetID}) | ||
|
||
deploymentTargetDetailsReq := connect.NewRequest(&porterv1.DeploymentTargetDetailsRequest{ | ||
ProjectId: int64(project.ID), | ||
DeploymentTargetId: request.DeploymentTargetID, | ||
}) | ||
|
||
deploymentTargetDetailsResp, err := c.Config().ClusterControlPlaneClient.DeploymentTargetDetails(ctx, deploymentTargetDetailsReq) | ||
if err != nil { | ||
err := telemetry.Error(ctx, span, err, "error getting deployment target details from cluster control plane client") | ||
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest)) | ||
return | ||
} | ||
|
||
if deploymentTargetDetailsResp == nil || deploymentTargetDetailsResp.Msg == nil { | ||
err := telemetry.Error(ctx, span, err, "deployment target details resp is nil") | ||
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError)) | ||
return | ||
} | ||
|
||
if deploymentTargetDetailsResp.Msg.ClusterId != int64(cluster.ID) { | ||
err := telemetry.Error(ctx, span, err, "deployment target details resp cluster id does not match cluster id") | ||
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError)) | ||
return | ||
} | ||
|
||
namespace := deploymentTargetDetailsResp.Msg.Namespace | ||
telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "namespace", Value: namespace}) | ||
|
||
agent, err := c.GetAgent(r, cluster, "") | ||
if err != nil { | ||
err = telemetry.Error(ctx, span, err, "unable to get agent") | ||
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError)) | ||
return | ||
} | ||
|
||
pods := []v1.Pod{} | ||
|
||
podsList, err := agent.GetPodsByLabel(request.Selectors, namespace) | ||
if err != nil { | ||
err = telemetry.Error(ctx, span, err, "unable to get pods by label") | ||
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError)) | ||
return | ||
} | ||
|
||
pods = append(pods, podsList.Items...) | ||
|
||
c.WriteResult(w, r, pods) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package porter_app | ||
|
||
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/server/shared/websocket" | ||
"github.com/porter-dev/porter/api/types" | ||
"github.com/porter-dev/porter/internal/models" | ||
"github.com/porter-dev/porter/internal/telemetry" | ||
) | ||
|
||
// AppStatusHandler handles the /apps/{kind}/status endpoint | ||
type AppStatusHandler struct { | ||
handlers.PorterHandlerReadWriter | ||
authz.KubernetesAgentGetter | ||
} | ||
|
||
// NewAppStatusHandler returns a new AppStatusHandler | ||
func NewAppStatusHandler( | ||
config *config.Config, | ||
decoderValidator shared.RequestDecoderValidator, | ||
writer shared.ResultWriter, | ||
) *AppStatusHandler { | ||
return &AppStatusHandler{ | ||
PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer), | ||
KubernetesAgentGetter: authz.NewOutOfClusterAgentGetter(config), | ||
} | ||
} | ||
|
||
// AppStatusRequest represents the accepted fields on a request to the /apps/{kind}/status endpoint | ||
type AppStatusRequest struct { | ||
Selectors string `schema:"selectors"` | ||
} | ||
|
||
func (c *AppStatusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
ctx, span := telemetry.NewSpan(r.Context(), "serve-app-logs") | ||
defer span.End() | ||
|
||
safeRW := ctx.Value(types.RequestCtxWebsocketKey).(*websocket.WebsocketSafeReadWriter) | ||
request := &AppStatusRequest{} | ||
|
||
if ok := c.DecodeAndValidate(w, r, request); !ok { | ||
err := telemetry.Error(ctx, span, nil, "invalid request") | ||
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest)) | ||
return | ||
} | ||
|
||
cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster) | ||
|
||
agent, err := c.GetAgent(r, cluster, "") | ||
if err != nil { | ||
err = telemetry.Error(ctx, span, err, "unable to get agent") | ||
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError)) | ||
return | ||
} | ||
|
||
kind, _ := requestutils.GetURLParamString(r, types.URLParamKind) | ||
|
||
err = agent.StreamControllerStatus(kind, request.Selectors, safeRW) | ||
|
||
if err != nil { | ||
c.HandleAPIError(w, r, apierrors.NewErrInternal(err)) | ||
return | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.