|
|
@@ -0,0 +1,102 @@
|
|
|
+package datastore
|
|
|
+
|
|
|
+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"
|
|
|
+)
|
|
|
+
|
|
|
+// StatusRequest describes an inbound datastore status request
|
|
|
+type StatusRequest struct {
|
|
|
+ Type string `json:"type"`
|
|
|
+ Name string `json:"name"`
|
|
|
+}
|
|
|
+
|
|
|
+// StatusResponse describes an outbound datastore status response
|
|
|
+type StatusResponse struct {
|
|
|
+ Status string `json:"status"`
|
|
|
+}
|
|
|
+
|
|
|
+// StatusHandler is a struct for handling datastore status requests
|
|
|
+type StatusHandler struct {
|
|
|
+ handlers.PorterHandlerReadWriter
|
|
|
+ authz.KubernetesAgentGetter
|
|
|
+}
|
|
|
+
|
|
|
+// NewStatusHandler constructs a datastore StatusHandler
|
|
|
+func NewStatusHandler(
|
|
|
+ config *config.Config,
|
|
|
+ decoderValidator shared.RequestDecoderValidator,
|
|
|
+ writer shared.ResultWriter,
|
|
|
+) *StatusHandler {
|
|
|
+ return &StatusHandler{
|
|
|
+ PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
|
|
|
+ KubernetesAgentGetter: authz.NewOutOfClusterAgentGetter(config),
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (h *StatusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
+ ctx, span := telemetry.NewSpan(r.Context(), "serve-datastore-status")
|
|
|
+ defer span.End()
|
|
|
+ // read the project from context
|
|
|
+ project, _ := ctx.Value(types.ProjectScope).(*models.Project)
|
|
|
+ cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)
|
|
|
+
|
|
|
+ request := &StatusRequest{}
|
|
|
+ if ok := h.DecodeAndValidate(w, r, request); !ok {
|
|
|
+ err := telemetry.Error(ctx, span, nil, "error decoding request")
|
|
|
+ h.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ telemetry.WithAttributes(span,
|
|
|
+ telemetry.AttributeKV{Key: "datastore-name", Value: request.Name},
|
|
|
+ telemetry.AttributeKV{Key: "datastore-type", Value: request.Type},
|
|
|
+ )
|
|
|
+
|
|
|
+ var datastoreType porterv1.EnumDatastore
|
|
|
+ switch request.Type {
|
|
|
+ case "rds-postgresql":
|
|
|
+ datastoreType = porterv1.EnumDatastore_ENUM_DATASTORE_RDS_POSTGRESQL
|
|
|
+ case "rds-postgresql-aurora":
|
|
|
+ datastoreType = porterv1.EnumDatastore_ENUM_DATASTORE_RDS_AURORA_POSTGRESQL
|
|
|
+ default:
|
|
|
+ err := telemetry.Error(ctx, span, nil, "invalid datastore specified")
|
|
|
+ h.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ req := connect.NewRequest(&porterv1.DatastoreStatusRequest{
|
|
|
+ ProjectId: int64(project.ID),
|
|
|
+ ClusterId: int64(cluster.ID),
|
|
|
+ Type: datastoreType,
|
|
|
+ Name: request.Name,
|
|
|
+ })
|
|
|
+
|
|
|
+ resp, err := h.Config().ClusterControlPlaneClient.DatastoreStatus(ctx, req)
|
|
|
+ if err != nil {
|
|
|
+ err := telemetry.Error(ctx, span, err, "error fetching datastore status from ccp")
|
|
|
+ h.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if resp.Msg == nil {
|
|
|
+ err := telemetry.Error(ctx, span, err, "missing response message from ccp")
|
|
|
+ h.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "datastore-status", Value: resp.Msg.Status})
|
|
|
+ h.WriteResult(w, r, StatusResponse{
|
|
|
+ Status: resp.Msg.Status,
|
|
|
+ })
|
|
|
+}
|