create.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package cluster
  2. import (
  3. "encoding/base64"
  4. "fmt"
  5. "net/http"
  6. "regexp"
  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/kubernetes/resolver"
  13. "github.com/porter-dev/porter/internal/models"
  14. "github.com/porter-dev/porter/internal/repository"
  15. )
  16. type CreateClusterManualHandler struct {
  17. handlers.PorterHandlerReadWriter
  18. }
  19. func NewCreateClusterManualHandler(
  20. config *config.Config,
  21. decoderValidator shared.RequestDecoderValidator,
  22. writer shared.ResultWriter,
  23. ) *CreateClusterManualHandler {
  24. return &CreateClusterManualHandler{
  25. PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  26. }
  27. }
  28. func (c *CreateClusterManualHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  29. // read the project from context
  30. proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
  31. request := &types.CreateClusterManualRequest{}
  32. if ok := c.DecodeAndValidate(w, r, request); !ok {
  33. return
  34. }
  35. cluster, err := getClusterModelFromManualRequest(c.Repo(), proj, request)
  36. if err != nil {
  37. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  38. return
  39. }
  40. cluster, err = c.Repo().Cluster().CreateCluster(cluster)
  41. if err != nil {
  42. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  43. return
  44. }
  45. c.WriteResult(w, r, cluster.ToClusterType())
  46. }
  47. func getClusterModelFromManualRequest(
  48. repo repository.Repository,
  49. project *models.Project,
  50. request *types.CreateClusterManualRequest,
  51. ) (*models.Cluster, error) {
  52. var authMechanism models.ClusterAuth
  53. if request.GCPIntegrationID != 0 {
  54. authMechanism = models.GCP
  55. // check that the integration exists
  56. _, err := repo.GCPIntegration().ReadGCPIntegration(project.ID, request.GCPIntegrationID)
  57. if err != nil {
  58. return nil, fmt.Errorf("gcp integration not found")
  59. }
  60. } else if request.AWSIntegrationID != 0 {
  61. authMechanism = models.AWS
  62. // check that the integration exists
  63. _, err := repo.AWSIntegration().ReadAWSIntegration(project.ID, request.AWSIntegrationID)
  64. if err != nil {
  65. return nil, fmt.Errorf("aws integration not found")
  66. }
  67. } else {
  68. return nil, fmt.Errorf("must include aws or gcp integration id")
  69. }
  70. cert := make([]byte, 0)
  71. if request.CertificateAuthorityData != "" {
  72. // determine if data is base64 decoded using regex
  73. re := regexp.MustCompile(`^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$`)
  74. // if it matches the base64 regex, decode it
  75. if re.MatchString(request.CertificateAuthorityData) {
  76. decoded, err := base64.StdEncoding.DecodeString(request.CertificateAuthorityData)
  77. if err != nil {
  78. return nil, err
  79. }
  80. cert = []byte(decoded)
  81. }
  82. }
  83. return &models.Cluster{
  84. ProjectID: project.ID,
  85. AuthMechanism: authMechanism,
  86. Name: request.Name,
  87. Server: request.Server,
  88. GCPIntegrationID: request.GCPIntegrationID,
  89. AWSIntegrationID: request.AWSIntegrationID,
  90. CertificateAuthorityData: cert,
  91. }, nil
  92. }
  93. func createClusterFromCandidate(
  94. repo repository.Repository,
  95. project *models.Project,
  96. user *models.User,
  97. candidate *models.ClusterCandidate,
  98. clResolver *types.ClusterResolverAll,
  99. ) (*models.Cluster, *models.ClusterCandidate, error) {
  100. // we query the repo again to get the decrypted version of the cluster candidate
  101. cc, err := repo.Cluster().ReadClusterCandidate(project.ID, candidate.ID)
  102. if err != nil {
  103. return nil, nil, err
  104. }
  105. cResolver := &resolver.CandidateResolver{
  106. Resolver: clResolver,
  107. ClusterCandidateID: cc.ID,
  108. ProjectID: project.ID,
  109. UserID: user.ID,
  110. }
  111. err = cResolver.ResolveIntegration(repo)
  112. if err != nil {
  113. return nil, nil, err
  114. }
  115. cluster, err := cResolver.ResolveCluster(repo)
  116. if err != nil {
  117. return nil, nil, err
  118. }
  119. cc, err = repo.Cluster().UpdateClusterCandidateCreatedClusterID(cc.ID, cluster.ID)
  120. if err != nil {
  121. return nil, nil, err
  122. }
  123. return cluster, cc, nil
  124. }