get.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package datastore
  2. import (
  3. "net/http"
  4. "github.com/aws/aws-sdk-go/aws/arn"
  5. "github.com/google/uuid"
  6. porterv1 "github.com/porter-dev/api-contracts/generated/go/porter/v1"
  7. "github.com/porter-dev/porter/api/server/authz"
  8. "github.com/porter-dev/porter/api/server/handlers"
  9. "github.com/porter-dev/porter/api/server/handlers/cloud_provider"
  10. "github.com/porter-dev/porter/api/server/shared"
  11. "github.com/porter-dev/porter/api/server/shared/apierrors"
  12. "github.com/porter-dev/porter/api/server/shared/config"
  13. "github.com/porter-dev/porter/api/server/shared/requestutils"
  14. "github.com/porter-dev/porter/api/types"
  15. "github.com/porter-dev/porter/internal/models"
  16. "github.com/porter-dev/porter/internal/telemetry"
  17. )
  18. // GetDatastoreResponse describes the list datastores response body
  19. type GetDatastoreResponse struct {
  20. // Datastore is the datastore that has been retrieved
  21. Datastore Datastore `json:"datastore"`
  22. }
  23. // GetDatastoreHandler is a struct for retrieving a datastore
  24. type GetDatastoreHandler struct {
  25. handlers.PorterHandlerReadWriter
  26. authz.KubernetesAgentGetter
  27. }
  28. // NewGetDatastoreHandler returns a GetDatastoreHandler
  29. func NewGetDatastoreHandler(
  30. config *config.Config,
  31. decoderValidator shared.RequestDecoderValidator,
  32. writer shared.ResultWriter,
  33. ) *GetDatastoreHandler {
  34. return &GetDatastoreHandler{
  35. PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  36. KubernetesAgentGetter: authz.NewOutOfClusterAgentGetter(config),
  37. }
  38. }
  39. const (
  40. // SupportedDatastoreCloudProvider_AWS is the AWS cloud provider
  41. SupportedDatastoreCloudProvider_AWS string = "AWS"
  42. )
  43. // ServeHTTP retrieves the datastore in the given project
  44. func (c *GetDatastoreHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  45. ctx, span := telemetry.NewSpan(r.Context(), "serve-get-datastore")
  46. defer span.End()
  47. project, _ := ctx.Value(types.ProjectScope).(*models.Project)
  48. resp := GetDatastoreResponse{}
  49. datastoreName, reqErr := requestutils.GetURLParamString(r, types.URLParamDatastoreName)
  50. if reqErr != nil {
  51. err := telemetry.Error(ctx, span, nil, "error parsing datastore name")
  52. c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
  53. return
  54. }
  55. telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "datastore-name", Value: datastoreName})
  56. datastoreRecord, err := c.Repo().Datastore().GetByProjectIDAndName(ctx, project.ID, datastoreName)
  57. if err != nil {
  58. err = telemetry.Error(ctx, span, err, "datastore record not found")
  59. c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
  60. return
  61. }
  62. if datastoreRecord == nil || datastoreRecord.ID == uuid.Nil {
  63. err = telemetry.Error(ctx, span, nil, "datastore record does not exist")
  64. c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusNotFound))
  65. return
  66. }
  67. datastore := Datastore{
  68. Name: datastoreRecord.Name,
  69. Type: datastoreRecord.Type,
  70. Engine: datastoreRecord.Engine,
  71. CreatedAtUTC: datastoreRecord.CreatedAt,
  72. Status: string(datastoreRecord.Status),
  73. CloudProvider: datastoreRecord.CloudProvider,
  74. CloudProviderCredentialIdentifier: datastoreRecord.CloudProviderCredentialIdentifier,
  75. }
  76. if datastoreRecord.CloudProvider != SupportedDatastoreCloudProvider_AWS {
  77. err = telemetry.Error(ctx, span, nil, "unsupported datastore cloud provider")
  78. c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
  79. return
  80. }
  81. awsArn, err := arn.Parse(datastoreRecord.CloudProviderCredentialIdentifier)
  82. if err != nil {
  83. err = telemetry.Error(ctx, span, err, "error parsing aws account id")
  84. c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
  85. return
  86. }
  87. datastores, err := Datastores(ctx, DatastoresInput{
  88. ProjectID: project.ID,
  89. CloudProvider: cloud_provider.CloudProvider{
  90. AccountID: awsArn.AccountID,
  91. Type: porterv1.EnumCloudProvider_ENUM_CLOUD_PROVIDER_AWS,
  92. },
  93. Name: datastoreName,
  94. IncludeEnvGroup: true,
  95. IncludeMetadata: true,
  96. CCPClient: c.Config().ClusterControlPlaneClient,
  97. DatastoreRepository: c.Repo().Datastore(),
  98. })
  99. if err == nil && len(datastores) == 1 {
  100. datastore = datastores[0]
  101. }
  102. resp.Datastore = datastore
  103. c.WriteResult(w, r, resp)
  104. }