status.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package datastore
  2. import (
  3. "net/http"
  4. "connectrpc.com/connect"
  5. porterv1 "github.com/porter-dev/api-contracts/generated/go/porter/v1"
  6. "github.com/porter-dev/porter/api/server/authz"
  7. "github.com/porter-dev/porter/api/server/handlers"
  8. "github.com/porter-dev/porter/api/server/shared"
  9. "github.com/porter-dev/porter/api/server/shared/apierrors"
  10. "github.com/porter-dev/porter/api/server/shared/config"
  11. "github.com/porter-dev/porter/api/types"
  12. "github.com/porter-dev/porter/internal/models"
  13. "github.com/porter-dev/porter/internal/telemetry"
  14. )
  15. // StatusRequest describes an inbound datastore status request
  16. type StatusRequest struct {
  17. Type string `json:"type"`
  18. Name string `json:"name"`
  19. }
  20. // StatusResponse describes an outbound datastore status response
  21. type StatusResponse struct {
  22. Status string `json:"status"`
  23. }
  24. // StatusHandler is a struct for handling datastore status requests
  25. type StatusHandler struct {
  26. handlers.PorterHandlerReadWriter
  27. authz.KubernetesAgentGetter
  28. }
  29. // NewStatusHandler constructs a datastore StatusHandler
  30. func NewStatusHandler(
  31. config *config.Config,
  32. decoderValidator shared.RequestDecoderValidator,
  33. writer shared.ResultWriter,
  34. ) *StatusHandler {
  35. return &StatusHandler{
  36. PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  37. KubernetesAgentGetter: authz.NewOutOfClusterAgentGetter(config),
  38. }
  39. }
  40. func (h *StatusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  41. ctx, span := telemetry.NewSpan(r.Context(), "serve-datastore-status")
  42. defer span.End()
  43. // read the project from context
  44. project, _ := ctx.Value(types.ProjectScope).(*models.Project)
  45. cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)
  46. request := &StatusRequest{}
  47. if ok := h.DecodeAndValidate(w, r, request); !ok {
  48. err := telemetry.Error(ctx, span, nil, "error decoding request")
  49. h.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
  50. return
  51. }
  52. telemetry.WithAttributes(span,
  53. telemetry.AttributeKV{Key: "datastore-name", Value: request.Name},
  54. telemetry.AttributeKV{Key: "datastore-type", Value: request.Type},
  55. )
  56. var datastoreType porterv1.EnumDatastore
  57. switch request.Type {
  58. case "rds-postgresql":
  59. datastoreType = porterv1.EnumDatastore_ENUM_DATASTORE_RDS_POSTGRESQL
  60. case "rds-postgresql-aurora":
  61. datastoreType = porterv1.EnumDatastore_ENUM_DATASTORE_RDS_AURORA_POSTGRESQL
  62. default:
  63. err := telemetry.Error(ctx, span, nil, "invalid datastore specified")
  64. h.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
  65. return
  66. }
  67. req := connect.NewRequest(&porterv1.DatastoreStatusRequest{
  68. ProjectId: int64(project.ID),
  69. ClusterId: int64(cluster.ID),
  70. Type: datastoreType,
  71. Name: request.Name,
  72. })
  73. resp, err := h.Config().ClusterControlPlaneClient.DatastoreStatus(ctx, req)
  74. if err != nil {
  75. err := telemetry.Error(ctx, span, err, "error fetching datastore status from ccp")
  76. h.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
  77. return
  78. }
  79. if resp.Msg == nil {
  80. err := telemetry.Error(ctx, span, err, "missing response message from ccp")
  81. h.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
  82. return
  83. }
  84. telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "datastore-status", Value: resp.Msg.Status})
  85. h.WriteResult(w, r, StatusResponse{
  86. Status: resp.Msg.Status,
  87. })
  88. }