retry_create.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package infra
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "net/http"
  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. ptypes "github.com/porter-dev/porter/provisioner/types"
  14. "gorm.io/gorm"
  15. )
  16. type InfraRetryCreateHandler struct {
  17. handlers.PorterHandlerReadWriter
  18. }
  19. func NewInfraRetryCreateHandler(config *config.Config, decoderValidator shared.RequestDecoderValidator, writer shared.ResultWriter) *InfraRetryCreateHandler {
  20. return &InfraRetryCreateHandler{
  21. PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  22. }
  23. }
  24. func (c *InfraRetryCreateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  25. proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
  26. infra, _ := r.Context().Value(types.InfraScope).(*models.Infra)
  27. req := &types.RetryInfraRequest{}
  28. if ok := c.DecodeAndValidate(w, r, req); !ok {
  29. return
  30. }
  31. var cluster *models.Cluster
  32. var err error
  33. if infra.ParentClusterID != 0 {
  34. cluster, err = c.Repo().Cluster().ReadCluster(proj.ID, infra.ParentClusterID)
  35. if err != nil {
  36. if err == gorm.ErrRecordNotFound {
  37. c.HandleAPIError(w, r, apierrors.NewErrForbidden(
  38. fmt.Errorf("cluster with id %d not found in project %d", infra.ParentClusterID, proj.ID),
  39. ))
  40. } else {
  41. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  42. }
  43. return
  44. }
  45. }
  46. // verify the credentials
  47. err = checkInfraCredentials(c.Config(), proj, infra, req.InfraCredentials)
  48. if err != nil {
  49. c.HandleAPIError(w, r, apierrors.NewErrForbidden(err))
  50. return
  51. }
  52. lastOperation, err := c.Repo().Infra().GetLatestOperation(infra)
  53. if err != nil {
  54. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  55. return
  56. }
  57. // if the last operation is in a "starting" state, block apply
  58. if lastOperation.Status == "starting" {
  59. c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
  60. fmt.Errorf("Operation currently in progress. Please try again when latest operation has completed."),
  61. http.StatusBadRequest,
  62. ))
  63. return
  64. }
  65. // if the values are nil, get the last applied values and marshal them
  66. if req.Values == nil || len(req.Values) == 0 {
  67. rawValues := lastOperation.LastApplied
  68. err = json.Unmarshal(rawValues, &req.Values)
  69. if err != nil {
  70. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  71. return
  72. }
  73. }
  74. vals := req.Values
  75. // if this is cluster-scoped and the kind is RDS, run the postrenderer
  76. if infra.ParentClusterID != 0 && infra.Kind == "rds" {
  77. var ok bool
  78. pr := &InfraRDSPostrenderer{
  79. config: c.Config(),
  80. }
  81. if vals, ok = pr.Run(w, r, &Opts{
  82. Cluster: cluster,
  83. Values: vals,
  84. }); !ok {
  85. return
  86. }
  87. }
  88. // call apply on the provisioner service
  89. resp, err := c.Config().ProvisionerClient.Apply(context.Background(), proj.ID, infra.ID, &ptypes.ApplyBaseRequest{
  90. Kind: string(infra.Kind),
  91. Values: vals,
  92. OperationKind: "retry_create",
  93. })
  94. if err != nil {
  95. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  96. return
  97. }
  98. c.WriteResult(w, r, resp)
  99. }