provision_handler.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. package api
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. "strconv"
  6. "github.com/go-chi/chi"
  7. "github.com/porter-dev/porter/internal/forms"
  8. "github.com/porter-dev/porter/internal/kubernetes"
  9. "github.com/porter-dev/porter/internal/kubernetes/provisioner"
  10. "github.com/porter-dev/porter/internal/models"
  11. "github.com/porter-dev/porter/internal/adapter"
  12. )
  13. // HandleProvisionTest will create a test resource by deploying a provisioner
  14. // container pod
  15. func (app *App) HandleProvisionTest(w http.ResponseWriter, r *http.Request) {
  16. projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
  17. if err != nil || projID == 0 {
  18. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  19. return
  20. }
  21. // create a new agent
  22. agent, err := kubernetes.GetAgentInClusterConfig()
  23. if err != nil {
  24. app.handleErrorDataRead(err, w)
  25. return
  26. }
  27. _, err = agent.ProvisionTest(uint(projID), provisioner.Apply)
  28. if err != nil {
  29. app.handleErrorInternal(err, w)
  30. return
  31. }
  32. w.WriteHeader(http.StatusOK)
  33. }
  34. // HandleProvisionAWSECRInfra provisions a new aws ECR instance for a project
  35. func (app *App) HandleProvisionAWSECRInfra(w http.ResponseWriter, r *http.Request) {
  36. projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
  37. if err != nil || projID == 0 {
  38. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  39. return
  40. }
  41. form := &forms.CreateECRInfra{
  42. ProjectID: uint(projID),
  43. }
  44. // decode from JSON to form value
  45. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  46. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  47. return
  48. }
  49. // validate the form
  50. if err := app.validator.Struct(form); err != nil {
  51. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  52. return
  53. }
  54. // convert the form to an aws infra instance
  55. infra, err := form.ToAWSInfra()
  56. if err != nil {
  57. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  58. return
  59. }
  60. // handle write to the database
  61. infra, err = app.Repo.AWSInfra.CreateAWSInfra(infra)
  62. if err != nil {
  63. app.handleErrorDataWrite(err, w)
  64. return
  65. }
  66. awsInt, err := app.Repo.AWSIntegration.ReadAWSIntegration(infra.AWSIntegrationID)
  67. if err != nil {
  68. app.handleErrorDataRead(err, w)
  69. return
  70. }
  71. // launch provisioning pod
  72. agent, err := kubernetes.GetAgentInClusterConfig()
  73. if err != nil {
  74. app.handleErrorDataRead(err, w)
  75. return
  76. }
  77. _, err = agent.ProvisionECR(
  78. uint(projID),
  79. awsInt,
  80. form.ECRName,
  81. infra,
  82. provisioner.Apply,
  83. )
  84. if err != nil {
  85. app.handleErrorInternal(err, w)
  86. return
  87. }
  88. app.Logger.Info().Msgf("New aws ecr infra created: %d", infra.ID)
  89. w.WriteHeader(http.StatusCreated)
  90. infraExt := infra.Externalize()
  91. if err := json.NewEncoder(w).Encode(infraExt); err != nil {
  92. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  93. return
  94. }
  95. }
  96. // HandleDestroyAWSECRInfra destroys ecr infra
  97. func (app *App) HandleDestroyAWSECRInfra(w http.ResponseWriter, r *http.Request) {
  98. // get path parameters
  99. infraID, err := strconv.ParseUint(chi.URLParam(r, "infra_id"), 10, 64)
  100. if err != nil {
  101. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  102. return
  103. }
  104. // read infra to get id
  105. infra, err := app.Repo.AWSInfra.ReadAWSInfra(uint(infraID))
  106. if err != nil {
  107. app.handleErrorDataRead(err, w)
  108. return
  109. }
  110. awsInt, err := app.Repo.AWSIntegration.ReadAWSIntegration(infra.AWSIntegrationID)
  111. form := &forms.DestroyECRInfra{}
  112. // decode from JSON to form value
  113. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  114. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  115. return
  116. }
  117. // validate the form
  118. if err := app.validator.Struct(form); err != nil {
  119. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  120. return
  121. }
  122. // launch provisioning destruction pod
  123. agent, err := kubernetes.GetAgentInClusterConfig()
  124. if err != nil {
  125. app.handleErrorDataRead(err, w)
  126. return
  127. }
  128. // mark infra for deletion
  129. infra.Status = models.StatusDestroying
  130. infra, err = app.Repo.AWSInfra.UpdateAWSInfra(infra)
  131. if err != nil {
  132. app.handleErrorDataWrite(err, w)
  133. return
  134. }
  135. _, err = agent.ProvisionECR(
  136. infra.ProjectID,
  137. awsInt,
  138. form.ECRName,
  139. infra,
  140. provisioner.Destroy,
  141. )
  142. if err != nil {
  143. app.handleErrorInternal(err, w)
  144. return
  145. }
  146. app.Logger.Info().Msgf("AWS ECR infra marked for destruction: %d", infra.ID)
  147. w.WriteHeader(http.StatusOK)
  148. }
  149. // HandleProvisionAWSEKSInfra provisions a new aws EKS instance for a project
  150. func (app *App) HandleProvisionAWSEKSInfra(w http.ResponseWriter, r *http.Request) {
  151. projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
  152. if err != nil || projID == 0 {
  153. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  154. return
  155. }
  156. form := &forms.CreateEKSInfra{
  157. ProjectID: uint(projID),
  158. }
  159. // decode from JSON to form value
  160. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  161. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  162. return
  163. }
  164. // validate the form
  165. if err := app.validator.Struct(form); err != nil {
  166. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  167. return
  168. }
  169. // convert the form to an aws infra instance
  170. infra, err := form.ToAWSInfra()
  171. if err != nil {
  172. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  173. return
  174. }
  175. // handle write to the database
  176. infra, err = app.Repo.AWSInfra.CreateAWSInfra(infra)
  177. if err != nil {
  178. app.handleErrorDataWrite(err, w)
  179. return
  180. }
  181. awsInt, err := app.Repo.AWSIntegration.ReadAWSIntegration(infra.AWSIntegrationID)
  182. if err != nil {
  183. app.handleErrorDataRead(err, w)
  184. return
  185. }
  186. // launch provisioning pod
  187. agent, err := kubernetes.GetAgentInClusterConfig()
  188. if err != nil {
  189. app.handleErrorDataRead(err, w)
  190. return
  191. }
  192. _, err = agent.ProvisionEKS(
  193. uint(projID),
  194. awsInt,
  195. form.EKSName,
  196. infra,
  197. provisioner.Apply,
  198. )
  199. if err != nil {
  200. app.handleErrorInternal(err, w)
  201. return
  202. }
  203. app.Logger.Info().Msgf("New aws eks infra created: %d", infra.ID)
  204. w.WriteHeader(http.StatusCreated)
  205. infraExt := infra.Externalize()
  206. if err := json.NewEncoder(w).Encode(infraExt); err != nil {
  207. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  208. return
  209. }
  210. }
  211. // HandleDestroyAWSEKSInfra destroys eks infra
  212. func (app *App) HandleDestroyAWSEKSInfra(w http.ResponseWriter, r *http.Request) {
  213. // get path parameters
  214. infraID, err := strconv.ParseUint(chi.URLParam(r, "infra_id"), 10, 64)
  215. if err != nil {
  216. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  217. return
  218. }
  219. // read infra to get id
  220. infra, err := app.Repo.AWSInfra.ReadAWSInfra(uint(infraID))
  221. if err != nil {
  222. app.handleErrorDataRead(err, w)
  223. return
  224. }
  225. awsInt, err := app.Repo.AWSIntegration.ReadAWSIntegration(infra.AWSIntegrationID)
  226. form := &forms.DestroyEKSInfra{}
  227. // decode from JSON to form value
  228. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  229. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  230. return
  231. }
  232. // validate the form
  233. if err := app.validator.Struct(form); err != nil {
  234. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  235. return
  236. }
  237. // launch provisioning destruction pod
  238. agent, err := kubernetes.GetAgentInClusterConfig()
  239. if err != nil {
  240. app.handleErrorDataRead(err, w)
  241. return
  242. }
  243. // mark infra for deletion
  244. infra.Status = models.StatusDestroying
  245. infra, err = app.Repo.AWSInfra.UpdateAWSInfra(infra)
  246. if err != nil {
  247. app.handleErrorDataWrite(err, w)
  248. return
  249. }
  250. _, err = agent.ProvisionEKS(
  251. infra.ProjectID,
  252. awsInt,
  253. form.EKSName,
  254. infra,
  255. provisioner.Destroy,
  256. )
  257. if err != nil {
  258. app.handleErrorInternal(err, w)
  259. return
  260. }
  261. app.Logger.Info().Msgf("AWS EKS infra marked for destruction: %d", infra.ID)
  262. w.WriteHeader(http.StatusOK)
  263. }
  264. // HandleGetProvisioningLogs returns real-time logs of the provisioning process via websockets
  265. func (app *App) HandleGetProvisioningLogs(w http.ResponseWriter, r *http.Request) {
  266. // get path parameters
  267. infraID, err := strconv.ParseUint(chi.URLParam(r, "infra_id"), 10, 64)
  268. if err != nil {
  269. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  270. return
  271. }
  272. // read infra to get id
  273. infra, err := app.Repo.AWSInfra.ReadAWSInfra(uint(infraID))
  274. if err != nil {
  275. app.handleErrorDataRead(err, w)
  276. return
  277. }
  278. streamName := infra.GetID()
  279. upgrader.CheckOrigin = func(r *http.Request) bool { return true }
  280. // upgrade to websocket.
  281. conn, err := upgrader.Upgrade(w, r, nil)
  282. if err != nil {
  283. app.handleErrorUpgradeWebsocket(err, w)
  284. }
  285. client, err := adapter.NewRedisClient(app.RedisConf)
  286. if err != nil {
  287. app.handleErrorInternal(err, w)
  288. return
  289. }
  290. err = provisioner.ResourceStream(client, streamName, conn)
  291. if err != nil {
  292. app.handleErrorWebsocketWrite(err, w)
  293. return
  294. }
  295. }